summaryrefslogtreecommitdiff
path: root/muse2
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2012-11-16 04:47:11 +0000
committerTim E. Real <termtech@rogers.com>2012-11-16 04:47:11 +0000
commit499c8bfc244f631304fe0c15449a31b442ebe0d7 (patch)
tree0315e923fe1748f68990c38dbe9cdf0693d3fcc4 /muse2
parent817bdcfdf6512566f833360133fd70c9217436b2 (diff)
Improved: Popup menus: Auto-breakup too-wide menus in class PopupMenu.
Diffstat (limited to 'muse2')
-rw-r--r--muse2/ChangeLog4
-rw-r--r--muse2/muse/widgets/popupmenu.cpp160
-rw-r--r--muse2/muse/widgets/popupmenu.h15
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);
};