From 0f3ed66e83d6639452a5aa219b9a6bf2bfd54897 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Thu, 19 May 2011 07:43:06 +0000 Subject: Popup menus now auto-scroll if too large to fit on desktop. Midi track info patch popup now stays open for auditioning patches. Editor 'ctrl' controller popups: Split instrument/other (+ common controls!) + show ctrl numbers. --- muse2/muse/widgets/popupmenu.cpp | 221 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 217 insertions(+), 4 deletions(-) (limited to 'muse2/muse/widgets/popupmenu.cpp') diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp index 862bda91..b59e8d43 100644 --- a/muse2/muse/widgets/popupmenu.cpp +++ b/muse2/muse/widgets/popupmenu.cpp @@ -10,21 +10,44 @@ //#include #include +#include #include +#include +#include +#include +//#include + #include //#include #include "popupmenu.h" + //====================== // PopupMenu //====================== -PopupMenu::PopupMenu(QWidget* parent) - : QMenu(parent) +//PopupMenu::PopupMenu() +//{ +// init(); +//} + +PopupMenu::PopupMenu(bool stayOpen) + : _stayOpen(stayOpen) { - // Menus will trigger! Set to make sure our trigger handlers ignore menus. - menuAction()->setData(-1); + init(); +} + +PopupMenu::PopupMenu(QWidget* parent, bool stayOpen) + : QMenu(parent), _stayOpen(stayOpen) +{ + init(); +} + +PopupMenu::PopupMenu(const QString& title, QWidget* parent, bool stayOpen) + : QMenu(title, parent), _stayOpen(stayOpen) +{ + init(); } PopupMenu::~PopupMenu() @@ -32,6 +55,23 @@ PopupMenu::~PopupMenu() //printf("PopupMenu::~PopupMenu\n"); } +void PopupMenu::init() +{ + // Menus will trigger! Set to make sure our trigger handlers ignore menus. + menuAction()->setData(-1); + + //_stayOpen = false; + moveDelta = 0; + + #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL + timer = new QTimer(this); + timer->setInterval(100); + timer->setSingleShot(false); + connect(this, SIGNAL(hovered(QAction*)), SLOT(popHovered(QAction*))); + connect(timer, SIGNAL(timeout()), SLOT(timerHandler())); + #endif // POPUP_MENU_DISABLE_AUTO_SCROLL +} + void PopupMenu::clear() { QList list = actions(); @@ -49,6 +89,11 @@ void PopupMenu::clear() // Now let QT remove and delete this menu's actions. QMenu::clear(); + + #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL + connect(this, SIGNAL(hovered(QAction*)), SLOT(popHovered(QAction*))); + connect(timer, SIGNAL(timeout()), SLOT(timerHandler())); + #endif // POPUP_MENU_DISABLE_AUTO_SCROLL } QAction* PopupMenu::findActionFromData(QVariant v) @@ -69,8 +114,175 @@ QAction* PopupMenu::findActionFromData(QVariant v) return 0; } +bool PopupMenu::event(QEvent* event) +{ + //printf("PopupMenu::event type:%d\n", event->type()); // REMOVE Tim. + + #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL + if(event->type() == QEvent::MouseMove) + { + QMouseEvent* e = static_cast(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()); // REMOVE Tim. + + /* + //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()); // REMOVE Tim. + + //action->hover(); + } + */ + + if(x() < 0 && globPos.x() <= 0) // If on the very first pixel (or beyond) + { + moveDelta = 32; + if(!timer->isActive()) + timer->start(); + event->accept(); + return true; + } + else + if(x() + width() >= dw && globPos.x() >= (dw -1)) // If on the very last pixel (or beyond) + { + moveDelta = -32; + if(!timer->isActive()) + timer->start(); + event->accept(); + return true; + } + + if(timer->isActive()) + timer->stop(); + + //event->accept(); + //return true; + + event->ignore(); // Pass it on + //return QMenu::event(event); + } + #endif // POPUP_MENU_DISABLE_AUTO_SCROLL + /* + else + if(event->type() == QEvent::HoverEnter) + { + // Nope! Hovering over menu items did not invoke this. + printf("PopupMenu::event hover\n"); // REMOVE Tim. + QHoverEvent* he = static_cast(event); + QPoint oldPos = he->oldPos(); + QPoint pos = he->pos(); + + QAction* action = actionAt(pos); + + if(action) + { + QRect r = actionGeometry(action); + printf("PopupMenu::event hover: 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()); // REMOVE Tim. + printf(" pos x:%d y:%d oldPos px:%d py:%d\n", + pos.x(), pos.y(), oldPos.x(), oldPos.y()); // REMOVE Tim. + + + } + + + //return true; + } + */ + + return QMenu::event(event); +} + +#ifndef POPUP_MENU_DISABLE_AUTO_SCROLL +void PopupMenu::timerHandler() +{ + // printf("PopupMenu::timerHandler\n"); // REMOVE Tim. + + //if(!isVisible() || !hasFocus()) + if(!isVisible()) + { + timer->stop(); + return; + } + + int dw = QApplication::desktop()->width(); // We want the whole thing if multiple monitors. + int nx = x() + moveDelta; + if(moveDelta < 0 && nx + width() < dw) + { + timer->stop(); + nx = dw - width(); + } + else + if(moveDelta > 0 && nx > 0) + { + timer->stop(); + nx = 0; + } + + move(nx, y()); +} + +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()); // REMOVE Tim. + //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); // REMOVE Tim. + //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 + void PopupMenu::mouseReleaseEvent(QMouseEvent *e) { + #ifdef POPUP_MENU_DISABLE_STAY_OPEN + QMenu::mouseReleaseEvent(e); + return; + + #else + if(!_stayOpen) + { + QMenu::mouseReleaseEvent(e); + return; + } + + //printf("PopupMenu::mouseReleaseEvent\n"); // REMOVE Tim. + //Q_D(QMenu); //if (d->mouseEventTaken(e)) // return; @@ -106,6 +318,7 @@ void PopupMenu::mouseReleaseEvent(QMouseEvent *e) // d->hideUpToMenuBar(); // } QMenu::mouseReleaseEvent(e); + #endif // POPUP_MENU_DISABLE_STAY_OPEN } /* -- cgit v1.2.3 From b5bdb59699abd38a3aa90dfb4d9882b2be7f5be0 Mon Sep 17 00:00:00 2001 From: "Tim E. Real" Date: Fri, 20 May 2011 03:59:53 +0000 Subject: Popup menus: If stay-open mode, space triggers item and double-click simulates return (closing). --- muse2/ChangeLog | 2 + muse2/muse/audioconvert.cpp | 3 +- muse2/muse/audioconvert.h | 3 +- muse2/muse/liste/editevent.cpp | 5 +- muse2/muse/widgets/popupmenu.cpp | 166 ++++++++++++++++++++++----------------- muse2/muse/widgets/popupmenu.h | 5 +- 6 files changed, 105 insertions(+), 79 deletions(-) (limited to 'muse2/muse/widgets/popupmenu.cpp') diff --git a/muse2/ChangeLog b/muse2/ChangeLog index 956b0c3f..01e6645d 100644 --- a/muse2/ChangeLog +++ b/muse2/ChangeLog @@ -1,3 +1,5 @@ +20.05.2011: + - Popup menus: If stay-open mode, space triggers item and double-click simulates return (closing). (Tim) 19.05.2011: * Feature: Popup menus now auto-scroll if too large to fit on desktop. (p4.0.25 Tim) Added auto-scroll to my class PopupMenu. Added selectable stay-open. TODO: Use it more, where needed. diff --git a/muse2/muse/audioconvert.cpp b/muse2/muse/audioconvert.cpp index 552b5e95..ced8e703 100644 --- a/muse2/muse/audioconvert.cpp +++ b/muse2/muse/audioconvert.cpp @@ -5,7 +5,8 @@ // // (C) Copyright 1999-2009 Werner Schweer (ws@seh.de) // -// Audio converter module created by Tim terminator356 +// Audio converter module created by Tim +// (C) Copyright 2009-2011 Tim E. Real (terminator356 A T sourceforge D O T net) //========================================================= #include diff --git a/muse2/muse/audioconvert.h b/muse2/muse/audioconvert.h index 039af912..0933de60 100644 --- a/muse2/muse/audioconvert.h +++ b/muse2/muse/audioconvert.h @@ -5,7 +5,8 @@ // // (C) Copyright 1999-2009 Werner Schweer (ws@seh.de) // -// Audio converter module created by Tim terminator356 +// Audio converter module created by Tim +// (C) Copyright 2009-2011 Tim E. Real (terminator356 A T sourceforge D O T net) //========================================================= #ifndef __AUDIOCONVERT_H__ diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp index 0643c34d..fd74d5d3 100644 --- a/muse2/muse/liste/editevent.cpp +++ b/muse2/muse/liste/editevent.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +//#include #include #include #include @@ -680,7 +680,8 @@ EditCtrlDialog::EditCtrlDialog(int tick, const Event& event, void EditCtrlDialog::newController() { - QMenu* pup = new QMenu(this); + //QMenu* pup = new QMenu(this); + PopupMenu* pup = new PopupMenu(this); //pup->setCheckable(this);//not necessary in Qt4 // // populate popup with all controllers available for diff --git a/muse2/muse/widgets/popupmenu.cpp b/muse2/muse/widgets/popupmenu.cpp index b59e8d43..263c8475 100644 --- a/muse2/muse/widgets/popupmenu.cpp +++ b/muse2/muse/widgets/popupmenu.cpp @@ -6,6 +6,7 @@ // (C) Copyright 1999-2010 Werner Schweer (ws@seh.de) // // PopupMenu sub-class of QMenu created by Tim. +// (C) Copyright 2010-2011 Tim E. Real (terminator356 A T sourceforge D O T net) //========================================================= //#include @@ -96,7 +97,7 @@ void PopupMenu::clear() #endif // POPUP_MENU_DISABLE_AUTO_SCROLL } -QAction* PopupMenu::findActionFromData(QVariant v) +QAction* PopupMenu::findActionFromData(QVariant v) const { QList list = actions(); for(int i = 0; i < list.size(); ++i) @@ -118,86 +119,105 @@ bool PopupMenu::event(QEvent* event) { //printf("PopupMenu::event type:%d\n", event->type()); // REMOVE Tim. - #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL - if(event->type() == QEvent::MouseMove) + switch(event->type()) { - QMouseEvent* e = static_cast(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()); // REMOVE Tim. - - /* - //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()); // REMOVE Tim. - - //action->hover(); - } - */ - - if(x() < 0 && globPos.x() <= 0) // If on the very first pixel (or beyond) - { - moveDelta = 32; - if(!timer->isActive()) - timer->start(); - event->accept(); - return true; + #ifndef POPUP_MENU_DISABLE_STAY_OPEN + case QEvent::MouseButtonDblClick: + { + if(_stayOpen) + { + QMouseEvent* e = static_cast(event); + if(e->modifiers() == Qt::NoModifier) + { + event->accept(); + // Convert into a return press, which selects the item and closes the menu. + // Note that with double click, it's a press followed by release followed by double click. + // That would toggle our item twice eg on->off->on, which is hopefully OK. + QKeyEvent ke(QEvent::KeyPress, Qt::Key_Return, Qt::NoModifier); + //ke.ignore(); // Pass it on + return QMenu::event(&ke); + } + } } - else - if(x() + width() >= dw && globPos.x() >= (dw -1)) // If on the very last pixel (or beyond) + break; + case QEvent::KeyPress: { - moveDelta = -32; - if(!timer->isActive()) - timer->start(); - event->accept(); - return true; + if(_stayOpen) + { + QKeyEvent* e = static_cast(event); + if(e->modifiers() == Qt::NoModifier && e->key() == Qt::Key_Space) + { + QAction* act = activeAction(); + if(act) + { + act->trigger(); + event->accept(); + return true; // We handled it. + } + } + } } - - if(timer->isActive()) - timer->stop(); + break; + #endif // POPUP_MENU_DISABLE_STAY_OPEN - //event->accept(); - //return true; - - event->ignore(); // Pass it on - //return QMenu::event(event); - } - #endif // POPUP_MENU_DISABLE_AUTO_SCROLL - /* - else - if(event->type() == QEvent::HoverEnter) - { - // Nope! Hovering over menu items did not invoke this. - printf("PopupMenu::event hover\n"); // REMOVE Tim. - QHoverEvent* he = static_cast(event); - QPoint oldPos = he->oldPos(); - QPoint pos = he->pos(); - - QAction* action = actionAt(pos); - - if(action) + #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL + case QEvent::MouseMove: { - QRect r = actionGeometry(action); - printf("PopupMenu::event hover: 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()); // REMOVE Tim. - printf(" pos x:%d y:%d oldPos px:%d py:%d\n", - pos.x(), pos.y(), oldPos.x(), oldPos.y()); // REMOVE Tim. - - - } - + QMouseEvent* e = static_cast(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()); // REMOVE Tim. + + /* + //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()); // REMOVE Tim. + + //action->hover(); + } + */ + + if(x() < 0 && globPos.x() <= 0) // If on the very first pixel (or beyond) + { + moveDelta = 32; + if(!timer->isActive()) + timer->start(); + event->accept(); + return true; + } + else + if(x() + width() >= dw && globPos.x() >= (dw -1)) // If on the very last pixel (or beyond) + { + moveDelta = -32; + if(!timer->isActive()) + timer->start(); + event->accept(); + return true; + } + + if(timer->isActive()) + timer->stop(); + + //event->accept(); + //return true; + + event->ignore(); // Pass it on + //return QMenu::event(event); + } + break; + #endif // POPUP_MENU_DISABLE_AUTO_SCROLL - //return true; + default: + break; } - */ - + return QMenu::event(event); } diff --git a/muse2/muse/widgets/popupmenu.h b/muse2/muse/widgets/popupmenu.h index 4982d199..47be57ae 100644 --- a/muse2/muse/widgets/popupmenu.h +++ b/muse2/muse/widgets/popupmenu.h @@ -6,6 +6,7 @@ // (C) Copyright 1999-2010 Werner Schweer (ws@seh.de) // // PopupMenu sub-class of QMenu created by Tim. +// (C) Copyright 2010-2011 Tim E. Real (terminator356 A T sourceforge D O T net) //========================================================= #ifndef __POPUPMENU_H__ @@ -59,8 +60,8 @@ class PopupMenu : public QMenu PopupMenu(const QString& title, QWidget* parent = 0, bool stayOpen = false); ~PopupMenu(); void clear(); - QAction* findActionFromData(QVariant); - bool stayOpen() { return _stayOpen; } + QAction* findActionFromData(QVariant) const; + bool stayOpen() const { return _stayOpen; } }; -- cgit v1.2.3