diff options
| author | Tim E. Real <termtech@rogers.com> | 2012-11-16 04:47:11 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2012-11-16 04:47:11 +0000 | 
| commit | 499c8bfc244f631304fe0c15449a31b442ebe0d7 (patch) | |
| tree | 0315e923fe1748f68990c38dbe9cdf0693d3fcc4 | |
| parent | 817bdcfdf6512566f833360133fd70c9217436b2 (diff) | |
Improved: Popup menus: Auto-breakup too-wide menus in class PopupMenu. 
| -rw-r--r-- | muse2/ChangeLog | 4 | ||||
| -rw-r--r-- | muse2/muse/widgets/popupmenu.cpp | 160 | ||||
| -rw-r--r-- | muse2/muse/widgets/popupmenu.h | 15 | 
3 files changed, 119 insertions, 60 deletions
| diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 0efcd0ca..30427798 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,7 @@ +15.11.2012: +         * Improved: Popup menus: Auto-breakup too-wide menus in class PopupMenu. (Tim) +           In some cases X/Qt was giving up if too wide AND/OR too many columns, menu would not appear. +           Tested OK with Deicsonze track info patch popup, and a synth plugin with > 2000 automation controls.  13.11.2012:           - Fix init of gain for duplicated audiotracks (rj)  12.11.2012: diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp index a34418a4..6cda1987 100644 --- a/muse2/muse/widgets/popupmenu.cpp +++ b/muse2/muse/widgets/popupmenu.cpp @@ -24,17 +24,12 @@  //  //========================================================= -//#include <stdio.h>  #include <QMouseEvent>  #include <QHoverEvent>  #include <QAction>  #include <QPoint>  #include <QDesktopWidget>  #include <QApplication> -//#include <QTimer> - -//#include <stdio.h> -//#include <QStandardItemModel>  #include "popupmenu.h"  #include "gconfig.h" @@ -47,11 +42,6 @@ namespace MusEGui {  // PopupMenu  //====================== -//PopupMenu::PopupMenu()  -//{ -//  init(); -//} -  PopupMenu::PopupMenu(bool stayOpen)             : _stayOpen(stayOpen)  { @@ -72,11 +62,14 @@ PopupMenu::PopupMenu(const QString& title, QWidget* parent, bool stayOpen)  void PopupMenu::init()  { -  //printf("PopupMenu::init this:%p\n", this);    -    // Menus will trigger! Set to make sure our trigger handlers ignore menus.    menuAction()->setData(-1); +  _cur_menu = this; +  _cur_menu_count = 1; +  _cur_item_width = 0; +  _cur_col_count = 0; +      //_stayOpen = false;    moveDelta = 0; @@ -91,7 +84,7 @@ void PopupMenu::init()  // NOTE: Tested all RoutePopupMenu and PopupMenu dtors and a couple of action dtors from our   //  PixmapButtonsHeaderWidgetAction and PixmapButtonsWidgetAction:  -// This does not appear to be required any more. All submenus and actions are being deleted now.  p4.0.43  +// This does not appear to be required any more. All submenus and actions are being deleted now.    /*  void PopupMenu::clear()  { @@ -171,8 +164,6 @@ QAction* PopupMenu::findActionFromData(const QVariant& v) const  bool PopupMenu::event(QEvent* event)  { -  //printf("PopupMenu::event type:%d\n", event->type());    -      switch(event->type())    {      #ifndef POPUP_MENU_DISABLE_STAY_OPEN   @@ -221,25 +212,7 @@ bool PopupMenu::event(QEvent* event)      {        QMouseEvent* e = static_cast<QMouseEvent*>(event);        QPoint globPos = e->globalPos(); -      //QPoint pos = e->pos();        int dw = QApplication::desktop()->width();  // We want the whole thing if multiple monitors. -       -      //printf("PopupMenu::event MouseMove: pos x:%d y:%d  globPos x:%d y:%d\n",  -      //      pos.x(), pos.y(), globPos.x(), globPos.y());   -       -      /* -      //QAction* action = actionAt(globPos); -      QAction* action = actionAt(pos); -      if(action) -      {  -        QRect r = actionGeometry(action); -        //printf(" act x:%d y:%d w:%d h:%d  popup px:%d py:%d pw:%d ph:%d\n",  -        //      r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height());   -               -        //action->hover();       -      } -      */ -              if(x() < 0 && globPos.x() <= 0)   // If on the very first pixel (or beyond)        {          moveDelta = 32; @@ -280,8 +253,6 @@ bool PopupMenu::event(QEvent* event)  #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL    void PopupMenu::timerHandler()  { -  // printf("PopupMenu::timerHandler\n");    -      //if(!isVisible() || !hasFocus())    if(!isVisible())    { @@ -308,39 +279,16 @@ void PopupMenu::timerHandler()  void PopupMenu::popHovered(QAction* action)  { -  //timer->stop(); -   -  //moveDelta = 0;    if(action)    {        int dw = QApplication::desktop()->width();  // We want the whole thing if multiple monitors. -          QRect r = actionGeometry(action); -    //printf("PopupMenu::popHovered x:%d y:%d w:%d h:%d px:%d py:%d pw:%d ph:%d\n",  -    //       r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height());   -    //printf("PopupMenu::popHovered x:%d y:%d w:%d h:%d px:%d py:%d pw:%d ph:%d dtw:%d\n",  -    //      r.x(), r.y(), r.width(), r.height(), x(), y(), width(), height(), dw);   -    //int x = r.x() + ctrlSubPop->x();      if(x() + r.x() < 0) -      //setGeometry(0, y(), width(), height());       -      //scroll(-x, 0);       -      //move(-r.x() + 32, y());   // Allow some of left column to show so that mouse can move over it.   -      //move(-r.x() + r.width(), y());   // Allow some of left column to show so that mouse can move over it.   -      //moveDelta = x() - r.x() + 32;        move(-r.x(), y());         else      if(r.x() + r.width() + x() > dw) -      //setGeometry(1200 - r.x() - r.width(), y(), width(), height());       -      //scroll(-x + 1200, 0);       -      //move(dw - r.x() - r.width() - 32, y());  // Allow some of right column to show so that mouse can move over it.        -      //move(dw - r.x(), y());  // Allow some of right column to show so that mouse can move over it.        -      //moveDelta = x() + dw - r.x() - r.width() - 32;        move(dw - r.x() - r.width(), y());      } -       -  //if(moveDelta == 0) -  //  timer->stop(); -      }  #endif    // POPUP_MENU_DISABLE_AUTO_SCROLL @@ -376,7 +324,6 @@ void PopupMenu::mouseReleaseEvent(QMouseEvent *e)        return;      }   -    //printf("PopupMenu::mouseReleaseEvent\n");        if (action)         action->activate(QAction::Trigger);      else  @@ -385,6 +332,101 @@ void PopupMenu::mouseReleaseEvent(QMouseEvent *e)      #endif   // POPUP_MENU_DISABLE_STAY_OPEN   } +//----------------------------------------- +// getMenu +// Auto-breakup a too-wide menu. +// NOTE This is a necessary catch-all because X doesn't like too-wide menus, but risky because +//       some callers might depend on all the items being in one menu (using ::actions or ::addActions). +//      So try to avoid that. The overwhelming rule of thumb is that too-wide menus are bad design anyway. +//------------------------------------------ +PopupMenu* PopupMenu::getMenu() +{ +  // We want the whole thing if multiple monitors. +  // Resonable to assume if X can show this desktop, it can show a menu with the same width? +  int dw = QApplication::desktop()->width(); +  // If we're still only at one column, not much we can do - some item(s) must have had reeeeally long text. +  // Not to worry. Hopefully the auto-scroll will handle it! +  // Use columnCount() + 2 to catch well BEFORE it widens beyond the edge, and leave room for many <More...> +  // TESTED: Not only does the system not appear to like too-wide menus, but also the column count was observed +  //          rolling over to zero repeatedly after it reached 15, simply when adding actions! The action width was 52 +  //          the number of items when it first rolled over was around 480 = 884, well below my desktop width of 1366. +  //         Apparently there is a limit on the number of columns - whatever, it made the col count limit necessary: +  if((_cur_col_count > 1 && ((_cur_col_count + 2) * _cur_item_width) >= dw) || _cur_col_count >= 8) +  { +    // This menu is too wide. So make a new one... +    _cur_item_width = 0; +    _cur_col_count = 1; +    QString s(tr("<More...> %1").arg(_cur_menu_count)); +    _cur_menu = new PopupMenu(s, this, _stayOpen); +    ++_cur_menu_count; +    addMenu(_cur_menu); +  } +  return _cur_menu; +} + +//---------------------------------------------------- +// Need to catch these to auto-breakup a too-big menu... +//---------------------------------------------------- + +QAction* PopupMenu::addAction(const QString& text) +{ +  QAction* act = static_cast<QMenu*>(getMenu())->addAction(text); +  int w = _cur_menu->actionGeometry(act).width(); +  if(w > _cur_item_width) +    _cur_item_width = w; +  int c = _cur_menu->columnCount(); +  if(c > _cur_col_count) +    _cur_col_count = c; +  return act; +} + +QAction* PopupMenu::addAction(const QIcon& icon, const QString& text) +{ +  QAction* act = static_cast<QMenu*>(getMenu())->addAction(icon, text); +  int w = _cur_menu->actionGeometry(act).width(); +  if(w > _cur_item_width) +    _cur_item_width = w; +  int c = _cur_menu->columnCount(); +  if(c > _cur_col_count) +    _cur_col_count = c; +  return act; +} + +QAction* PopupMenu::addAction(const QString& text, const QObject* receiver, const char* member, const QKeySequence& shortcut) +{ +  QAction* act = static_cast<QMenu*>(getMenu())->addAction(text, receiver, member, shortcut); +  int w = _cur_menu->actionGeometry(act).width(); +  if(w > _cur_item_width) +    _cur_item_width = w; +  int c = _cur_menu->columnCount(); +  if(c > _cur_col_count) +    _cur_col_count = c; +  return act; +} + +QAction* PopupMenu::addAction(const QIcon& icon, const QString& text, const QObject* receiver, const char* member, const QKeySequence& shortcut) +{ +  QAction* act = static_cast<QMenu*>(getMenu())->addAction(icon, text, receiver, member, shortcut); +  int w = _cur_menu->actionGeometry(act).width(); +  if(w > _cur_item_width) +    _cur_item_width = w; +  int c = _cur_menu->columnCount(); +  if(c > _cur_col_count) +    _cur_col_count = c; +  return act; +} + +void PopupMenu::addAction(QAction* action) +{ +  static_cast<QMenu*>(getMenu())->addAction(action); +  int w = _cur_menu->actionGeometry(action).width(); +  if(w > _cur_item_width) +    _cur_item_width = w; +  int c = _cur_menu->columnCount(); +  if(c > _cur_col_count) +    _cur_col_count = c; +} +  /*  //======================  // PopupView diff --git a/muse2/muse/widgets/popupmenu.h b/muse2/muse/widgets/popupmenu.h index d1d863e9..4c764fa8 100644 --- a/muse2/muse/widgets/popupmenu.h +++ b/muse2/muse/widgets/popupmenu.h @@ -58,7 +58,14 @@ Q_OBJECT      QTimer* timer;      #endif      int moveDelta; +    PopupMenu* _cur_menu; // For auto-breakup. +    int _cur_menu_count; +    int _cur_item_width; +    int _cur_col_count; +      void init(); +    // Auto-breakup a too-wide menu. +    PopupMenu* getMenu();    private slots:      #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL   @@ -71,7 +78,6 @@ Q_OBJECT      bool event(QEvent*);       public: -    //PopupMenu();      PopupMenu(bool stayOpen);      PopupMenu(QWidget* parent=0, bool stayOpen = false);      PopupMenu(const QString& title, QWidget* parent = 0, bool stayOpen = false); @@ -79,6 +85,13 @@ Q_OBJECT      QAction* findActionFromData(const QVariant&) const;      bool stayOpen() const { return _stayOpen; }      void clearAllChecks() const; + +    // Need to catch these to auto-breakup a too-big menu. +    QAction* addAction(const QString& text); +    QAction* addAction(const QIcon& icon, const QString& text); +    QAction* addAction(const QString& text, const QObject* receiver, const char* member, const QKeySequence& shortcut = 0); +    QAction* addAction(const QIcon& icon, const QString& text, const QObject* receiver, const char* member, const QKeySequence& shortcut = 0); +    void     addAction(QAction* action);  }; | 
