diff options
| author | Tim E. Real <termtech@rogers.com> | 2011-05-19 07:43:06 +0000 | 
|---|---|---|
| committer | Tim E. Real <termtech@rogers.com> | 2011-05-19 07:43:06 +0000 | 
| commit | 0f3ed66e83d6639452a5aa219b9a6bf2bfd54897 (patch) | |
| tree | 950c324e7301f657cba543d8ccbb268ca40e418f /muse2/muse | |
| parent | 0792c2ec66dacfff10899cbe171cb661871617f1 (diff) | |
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. 
Diffstat (limited to 'muse2/muse')
| -rw-r--r-- | muse2/muse/app.cpp | 301 | ||||
| -rw-r--r-- | muse2/muse/app.h | 3 | ||||
| -rw-r--r-- | muse2/muse/arranger/tlist.cpp | 18 | ||||
| -rw-r--r-- | muse2/muse/arranger/tlist.h | 6 | ||||
| -rw-r--r-- | muse2/muse/confmport.cpp | 4 | ||||
| -rw-r--r-- | muse2/muse/ctrl/ctrledit.cpp | 10 | ||||
| -rw-r--r-- | muse2/muse/ctrl/ctrlpanel.cpp | 265 | ||||
| -rw-r--r-- | muse2/muse/ctrl/ctrlpanel.h | 3 | ||||
| -rw-r--r-- | muse2/muse/dssihost.cpp | 6 | ||||
| -rw-r--r-- | muse2/muse/dssihost.h | 6 | ||||
| -rw-r--r-- | muse2/muse/instruments/minstrument.cpp | 9 | ||||
| -rw-r--r-- | muse2/muse/instruments/minstrument.h | 6 | ||||
| -rw-r--r-- | muse2/muse/liste/editevent.cpp | 27 | ||||
| -rw-r--r-- | muse2/muse/midictrl.cpp | 78 | ||||
| -rw-r--r-- | muse2/muse/midictrl.h | 3 | ||||
| -rw-r--r-- | muse2/muse/mixer/astrip.cpp | 16 | ||||
| -rw-r--r-- | muse2/muse/synth.cpp | 5 | ||||
| -rw-r--r-- | muse2/muse/synth.h | 12 | ||||
| -rw-r--r-- | muse2/muse/ticksynth.cpp | 6 | ||||
| -rw-r--r-- | muse2/muse/vst.h | 6 | ||||
| -rw-r--r-- | muse2/muse/widgets/mtrackinfo.cpp | 46 | ||||
| -rw-r--r-- | muse2/muse/widgets/mtrackinfo.h | 1 | ||||
| -rw-r--r-- | muse2/muse/widgets/popupmenu.cpp | 221 | ||||
| -rw-r--r-- | muse2/muse/widgets/popupmenu.h | 30 | 
24 files changed, 723 insertions, 365 deletions
| diff --git a/muse2/muse/app.cpp b/muse2/muse/app.cpp index c42a1a7c..5b8da28e 100644 --- a/muse2/muse/app.cpp +++ b/muse2/muse/app.cpp @@ -2303,7 +2303,7 @@ void MusE::showTransport(bool flag)  PopupMenu* MusE::getRoutingPopupMenu()  {    if(!routingPopupMenu) -    routingPopupMenu = new PopupMenu(this); +    routingPopupMenu = new PopupMenu(this, true);    return routingPopupMenu;  } @@ -2884,7 +2884,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)            pup->addSeparator();            pup->addAction(new MenuTitleItem(tr("Soloing chain"), pup));  -          PopupMenu* subp = new PopupMenu(pup); +          PopupMenu* subp = new PopupMenu(pup, true);            subp->setTitle(tr("Audio returns"));             pup->addMenu(subp); @@ -2978,7 +2978,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)          if(!md && ir == rl->end())            continue; -        PopupMenu* subp = new PopupMenu(pup); +        PopupMenu* subp = new PopupMenu(pup, true);          subp->setTitle(QString("%1:").arg(i+1) + (md ? md->name() : tr("<none>")));           for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  @@ -3009,7 +3009,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)        #if 0        // p4.0.17 List ports with no device and no in routes, in a separate popup. -      PopupMenu* morep = new PopupMenu(pup); +      PopupMenu* morep = new PopupMenu(pup, true);        morep->setTitle(tr("More..."));         for(int i = 0; i < MIDI_PORTS; ++i)        { @@ -3017,7 +3017,7 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)          if(mp->device())            continue; -        PopupMenu* subp = new PopupMenu(morep); +        PopupMenu* subp = new PopupMenu(morep, true);          subp->setTitle(QString("%1:").arg(i) + tr("<none>"));           // MusE-2: Check this - needed with QMenu? Help says no. No - verified, it actually causes double triggers! @@ -3080,297 +3080,6 @@ PopupMenu* MusE::prepareRoutingPopupMenu(Track* track, bool dst)    return 0;  } -#if 0 -//--------------------------------------------------------- -//   getRoutingPopupView -//--------------------------------------------------------- - -PopupView* MusE::getRoutingPopupView() -{ -  if(!routingPopupView) -    //routingPopupView = new PopupView(this); -    routingPopupView = new PopupView(); -  return routingPopupView; -} - -//--------------------------------------------------------- -//   routingPopupViewActivated -//--------------------------------------------------------- - -void MusE::routingPopupViewActivated(Track* track, int n) -{ -      //if(!track || (track != gRoutingPopupMenuMaster)) -      if(!track) -        return; -         -      if(track->isMidiTrack()) -      { -        PopupView* pup = getRoutingPopupView(); -         -        //printf("MusE::routingPopupMenuActivated midi n:%d count:%d\n", n, pup->count()); -         -        if(pup->model()->rowCount() == 0) -          return; -           -        //MidiTrack* t = (MidiTrack*)track; -        RouteList* rl = gIsOutRoutingPopupMenu ? track->outRoutes() : track->inRoutes(); -         -        if(n == -1)  -          return; -           -        iRouteMenuMap imm = gRoutingMenuMap.find(n); -        if(imm == gRoutingMenuMap.end()) -          return; -        if(imm->second.type != Route::MIDI_PORT_ROUTE) -          return; -        Route &aRoute = imm->second; -        int chbit = aRoute.channel; -        Route bRoute(track, chbit); -        int mdidx = aRoute.midiPort; - -        MidiPort* mp = &midiPorts[mdidx]; -        MidiDevice* md = mp->device(); -        if(!md) -          return; -         -        //if(!(md->rwFlags() & 2)) -        if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2))) -          return; -         -        int chmask = 0;                    -        iRoute iir = rl->begin(); -        for (; iir != rl->end(); ++iir)  -        { -          //if(*iir == (dst ? bRoute : aRoute)) -          //if(*iir == aRoute) -          if(iir->type == Route::MIDI_PORT_ROUTE && iir->midiPort == mdidx)    // p3.3.50 Is there already a route to this port? -          { -                chmask = iir->channel;  // p3.3.50 Grab the channel mask. -                break; -          }       -        } -        //if (iir != rl->end())  -        if ((chmask & chbit) == chbit)             // p3.3.50 Is the channel's bit(s) set? -        { -          // disconnect -          if(gIsOutRoutingPopupMenu) -            audio->msgRemoveRoute(bRoute, aRoute); -          else -            audio->msgRemoveRoute(aRoute, bRoute); -        } -        else  -        { -          // connect -          if(gIsOutRoutingPopupMenu) -            audio->msgAddRoute(bRoute, aRoute); -          else -            audio->msgAddRoute(aRoute, bRoute); -        } -         -        audio->msgUpdateSoloStates(); -        song->update(SC_ROUTE); -      } -      else -      { -        // TODO: Try to move code from AudioStrip::routingPopupMenuActivated into here. -      } -      //else -      //{ -      //} -} - -//--------------------------------------------------------- -//   prepareRoutingPopupView -//--------------------------------------------------------- - -PopupView* MusE::prepareRoutingPopupView(Track* track, bool dst) -{ -  if(!track) -    return 0; -     -  //QPoint ppt = QCursor::pos(); -   -  if(track->isMidiTrack()) -  { -   -    //QPoint ppt = parent->rect().bottomLeft(); -       -    //if(dst) -    //{ -      // TODO  -       -    //} -    //else -    //{ -      RouteList* rl = dst ? track->outRoutes() : track->inRoutes(); -      //Route dst(track, -1); -     -      ///QPopupMenu* pup = new QPopupMenu(parent); -       -      PopupView* pup = getRoutingPopupView(); -      pup->disconnect(); -      //connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int))); -      //connect(pup, SIGNAL(aboutToHide()), SLOT(routingPopupMenuAboutToHide())); -         -      ///pup->setCheckable(true); -       -      int gid = 0; -      //int n;     -       -    // Routes can't be re-read until the message sent from msgAddRoute1()  -    //  has had time to be sent and actually affected the routes. -    ///_redisplay: -       -      pup->clear(); -      gRoutingMenuMap.clear(); -      gid = 0; -       -      //MidiInPortList* tl = song->midiInPorts(); -      //for(iMidiInPort i = tl->begin();i != tl->end(); ++i)  -      for(int i = 0; i < MIDI_PORTS; ++i) -      { -        //MidiInPort* track = *i; -        // NOTE: Could possibly list all devices, bypassing ports, but no, let's stick with ports. -        MidiPort* mp = &midiPorts[i]; -        MidiDevice* md = mp->device(); -        if(!md) -          continue; -         -        if(!(md->rwFlags() & (dst ? 1 : 2))) -          continue; -           -        //printf("MusE::prepareRoutingPopupMenu adding submenu portnum:%d\n", i); -         -        //QMenu* m = menu->addMenu(track->name()); -        //QPopupMenu* subp = new QPopupMenu(parent); -        //PopupMenu* subp = new PopupMenu(this); -        QStandardItem* subp = new QStandardItem(QT_TRANSLATE_NOOP("@default", md->name())); -///        connect(subp, SIGNAL(activated(int)), pup, SIGNAL(activated(int))); -        //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide())); -         -        int chanmask = 0; -        // p3.3.50 To reduce number of routes required, from one per channel to just one containing a channel mask.  -        // Look for the first route to this midi port. There should always be only a single route for each midi port, now. -        for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)    -        { -          if(ir->type == Route::MIDI_PORT_ROUTE && ir->midiPort == i)  -          { -            // We have a route to the midi port. Grab the channel mask. -            chanmask = ir->channel; -            break; -          } -        } -         -        for(int ch = 0; ch < MIDI_CHANNELS; ++ch)  -        { -          //QAction* a = m->addAction(QString("Channel %1").arg(ch+1)); -          //subp->insertItem(QT_TRANSLATE_NOOP("@default", QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch); -          gid = i * MIDI_CHANNELS + ch; -           -          //printf("MusE::prepareRoutingPopupMenu inserting gid:%d\n", gid); -           -///          subp->insertItem(QString("Channel %1").arg(ch+1), gid); -          QStandardItem* sti = new QStandardItem(QString("Channel %1").arg(ch+1)); -          sti->setCheckable(true); -          sti->setData(gid); -          subp->appendRow(sti); -           -          //a->setCheckable(true); -          //Route src(track, ch, RouteNode::TRACK); -          //Route src(md, ch); -          //Route r = Route(src, dst); -          //a->setData(QVariant::fromValue(r)); -          //a->setChecked(rl->indexOf(r) != -1); -           -          //Route srcRoute(md, ch); -          //Route srcRoute(i, ch);     // p3.3.49 New: Midi port route. -          int chbit = 1 << ch; -          Route srcRoute(i, chbit);    // p3.3.50 In accordance with new channel mask, use the bit position. -           -          gRoutingMenuMap.insert( pRouteMenuMap(gid, srcRoute) ); -           -          //for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)   // p3.3.50 Removed. -          //{ -            //if(*ir == dst)  -          //  if(*ir == srcRoute)  -          //  { -          //    subp->setItemChecked(id, true); -          //    break; -          //  } -          //} -          if(chanmask & chbit)                  // p3.3.50 Is the channel already set? Show item check mark. -///            subp->setItemChecked(gid, true); -            sti->setCheckState(Qt::Checked); -        } -        //subp->insertItem(QString("Toggle all"), 1000+i); -        // p3.3.50 One route with all channel bits set. -        gid = MIDI_PORTS * MIDI_CHANNELS + i;           // Make sure each 'toggle' item gets a unique id. -///        subp->insertItem(QString("Toggle all"), gid);       -        QStandardItem* sti = new QStandardItem(QString("Toggle all")); -        sti->setData(gid); -        subp->appendRow(sti); -         -        Route togRoute(i, (1 << MIDI_CHANNELS) - 1);    // Set all channel bits. -        gRoutingMenuMap.insert( pRouteMenuMap(gid, togRoute) ); -         -///        pup->insertItem(QT_TRANSLATE_NOOP("@default", md->name()), subp); -        pup->model()->appendRow(subp); -        pup->updateView(); -      } -           -      /* -      QPopupMenu* pup = new QPopupMenu(iR); -      pup->setCheckable(true); -      //MidiTrack* t = (MidiTrack*)track; -      RouteList* irl = track->inRoutes(); -   -      MidiTrack* t = (MidiTrack*)track; -      int gid = 0; -      for (int i = 0; i < channel; ++i)  -      { -            char buffer[128]; -            snprintf(buffer, 128, "%s %d", tr("Channel").toLatin1().constData(), i+1); -            MenuTitleItem* titel = new MenuTitleItem(QString(buffer)); -            pup->insertItem(titel); -   -            if (!checkAudioDevice()) return; -            std::list<QString> ol = audioDevice->outputPorts(); -            for (std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip) { -                  int id = pup->insertItem(*ip, (gid * 16) + i); -                  Route dst(*ip, true, i); -                  ++gid; -                  for (iRoute ir = irl->begin(); ir != irl->end(); ++ir) { -                        if (*ir == dst) { -                              pup->setItemChecked(id, true); -                              break; -                              } -                        } -                  } -            if (i+1 != channel) -                  pup->addSeparator(); -      } -      */ -       -///      if(pup->count() == 0) -      if(pup->model()->rowCount() == 0) -      { -        ///delete pup; -        gRoutingPopupMenuMaster = 0; -        //pup->clear(); -        //pup->disconnect(); -        gRoutingMenuMap.clear(); -        //oR->setDown(false);      -        return 0; -      } -       -      gIsOutRoutingPopupMenu = dst; -      return pup; -    } -     -    return 0; -} -#endif -  //---------------------------------------------------------  //   saveAs  //--------------------------------------------------------- diff --git a/muse2/muse/app.h b/muse2/muse/app.h index e940c1ad..45b2efff 100644 --- a/muse2/muse/app.h +++ b/muse2/muse/app.h @@ -287,7 +287,7 @@ class MusE : public QMainWindow        void startMidiTransformer();        void writeGlobalConfiguration() const; -      void startEditInstrument(); +      //void startEditInstrument();        void startClipList(bool);        void openRecentMenu(); @@ -359,6 +359,7 @@ class MusE : public QMainWindow        void importMidi(const QString &file);        void setUsedTool(int);        void showDidYouKnowDialog(); +      void startEditInstrument();        void routingPopupMenuAboutToHide();        void configMidiPorts(); diff --git a/muse2/muse/arranger/tlist.cpp b/muse2/muse/arranger/tlist.cpp index b907b555..ccd213da 100644 --- a/muse2/muse/arranger/tlist.cpp +++ b/muse2/muse/arranger/tlist.cpp @@ -11,7 +11,7 @@  #include <QKeyEvent>  #include <QLineEdit> -#include <QMenu> +//#include <QMenu>  #include <QMessageBox>  #include <QMouseEvent>  #include <QPainter> @@ -44,6 +44,7 @@  #include "midiedit/drummap.h"  #include "synth.h"  #include "config.h" +#include "popupmenu.h"  #ifdef DSSI_SUPPORT  #include "dssihost.h" @@ -348,7 +349,7 @@ void TList::paint(const QRect& r)                                          if (cl->isVisible())                                              countVisible++;                                      } -                                    int count = ((AudioTrack*)track)->controller()->size(); +                                    //int count = ((AudioTrack*)track)->controller()->size();                                      s.sprintf(" %d(%d) visible",countVisible, countAll);                                      } @@ -883,9 +884,11 @@ void TList::changeAutomationColor(QAction* act)  //---------------------------------------------------------  //   colorMenu  //--------------------------------------------------------- -QMenu* TList::colorMenu(QColor c, int id) +//QMenu* TList::colorMenu(QColor c, int id) +PopupMenu* TList::colorMenu(QColor c, int id)  { -  QMenu * m = new QMenu(this); +  //QMenu * m = new QMenu(this); +  PopupMenu * m = new PopupMenu(this);  //, true);  TODO    for (int i = 0; i< 6; i++) {      QPixmap pix(10,10);      QPainter p(&pix); @@ -1058,7 +1061,7 @@ void TList::mousePressEvent(QMouseEvent* ev)                  {                  if (!t->isMidiTrack()) {                      editAutomation = t; -                    PopupMenu* p = new PopupMenu(); +                    PopupMenu* p = new PopupMenu(true);                      p->disconnect();                      p->clear();                      p->setTitle(tr("Viewable automation")); @@ -1075,12 +1078,11 @@ void TList::mousePressEvent(QMouseEvent* ev)                        int data = cl->id() * 256; // shift 8 bits                        data += 150; // illegal color > 100                        act->setData(data); -                      QMenu *m = colorMenu(cl->color(), cl->id()); +                      //QMenu *m = colorMenu(cl->color(), cl->id()); +                      PopupMenu *m = colorMenu(cl->color(), cl->id());                        act->setMenu(m);                      }                      connect(p, SIGNAL(triggered(QAction*)), SLOT(changeAutomation(QAction*))); -                    //connect(p, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide())); -                    //p->popup(QCursor::pos());                      p->exec(QCursor::pos());                      delete p; diff --git a/muse2/muse/arranger/tlist.h b/muse2/muse/arranger/tlist.h index 8bebef95..4d787030 100644 --- a/muse2/muse/arranger/tlist.h +++ b/muse2/muse/arranger/tlist.h @@ -19,7 +19,8 @@ class QPaintEvent;  class QResizeEvent;  class QScrollBar;  class QWheelEvent; -class QMenu; +//class QMenu; +class PopupMenu;  class ScrollScale;  class Track; @@ -85,7 +86,8 @@ class TList : public QWidget {        void classesPopupMenu(Track*, int x, int y);        TrackList getRecEnabledTracks();        void setHeaderToolTips(); -      QMenu* colorMenu(QColor c, int id); +      //QMenu* colorMenu(QColor c, int id); +      PopupMenu* colorMenu(QColor c, int id);     private slots:        void returnPressed(); diff --git a/muse2/muse/confmport.cpp b/muse2/muse/confmport.cpp index 8c27d9eb..fc005923 100644 --- a/muse2/muse/confmport.cpp +++ b/muse2/muse/confmport.cpp @@ -609,7 +609,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)                    return;                    #else                    { -                    defpup = new PopupMenu(this); +                    defpup = new PopupMenu(this, true);                      defpup->addAction(new MenuTitleItem("Channel", defpup));                       QAction* act = 0;                      int chbits = midiPorts[no].defaultInChannels(); @@ -649,7 +649,7 @@ void MPConfig::rbClicked(QTableWidgetItem* item)                    return;                    #else                    { -                    defpup = new PopupMenu(this); +                    defpup = new PopupMenu(this, true);                      defpup->addAction(new MenuTitleItem("Channel", defpup));                       QAction* act = 0;                      int chbits = midiPorts[no].defaultOutChannels(); diff --git a/muse2/muse/ctrl/ctrledit.cpp b/muse2/muse/ctrl/ctrledit.cpp index 8842ba97..c4e33822 100644 --- a/muse2/muse/ctrl/ctrledit.cpp +++ b/muse2/muse/ctrl/ctrledit.cpp @@ -69,7 +69,8 @@ void CtrlEdit::writeStatus(int level, Xml& xml)        {        if (canvas->controller()) {              xml.tag(level++, "ctrledit"); -            xml.strTag(level, "ctrl", canvas->controller()->name()); +            //xml.strTag(level, "ctrl", canvas->controller()->name()); +            xml.intTag(level, "ctrlnum", canvas->controller()->num());              xml.tag(level, "/ctrledit");              }        } @@ -89,6 +90,8 @@ void CtrlEdit::readStatus(Xml& xml)                          return;                    case Xml::TagStart:                          if (tag == "ctrl") { +                              xml.parse1();  // Obsolete.  +                              /*                                QString name = xml.parse1();                                int portno = canvas->track()->outPort();                                MidiPort* port = &midiPorts[portno]; @@ -101,6 +104,11 @@ void CtrlEdit::readStatus(Xml& xml)                                            break;                                            }                                      } +                              */       +                              } +                        else if (tag == "ctrlnum") { +                              int num = xml.parseInt(); +                              canvas->setController(num);                                }                          else                                xml.unknown("CtrlEdit"); diff --git a/muse2/muse/ctrl/ctrlpanel.cpp b/muse2/muse/ctrl/ctrlpanel.cpp index 9e990861..b23ce855 100644 --- a/muse2/muse/ctrl/ctrlpanel.cpp +++ b/muse2/muse/ctrl/ctrlpanel.cpp @@ -11,7 +11,8 @@  #include "ctrlpanel.h"  #include "ctrlcanvas.h" -#include <QMenu> +//#include <QMenu> +#include <QAction>  #include <QPushButton>  #include <QSizePolicy>  #include <QHBoxLayout> @@ -20,10 +21,12 @@  #include <math.h> +#include "app.h"  #include "globals.h"  #include "midictrl.h"  #include "instruments/minstrument.h"  #include "midiport.h" +#include "mididev.h"  #include "xml.h"  #include "icons.h"  #include "event.h" @@ -37,6 +40,8 @@  #include "doublelabel.h"  #include "midi.h"  #include "audio.h" +#include "menutitleitem.h" +#include "popupmenu.h"  //---------------------------------------------------------  //   CtrlPanel @@ -47,6 +52,8 @@ CtrlPanel::CtrlPanel(QWidget* parent, MidiEditor* e, const char* name)        {        setObjectName(name);        inHeartBeat = true; +      //ctrlMainPop = 0; +      //ctrlSubPop = 0;        editor = e;        setSizePolicy(QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding));        QVBoxLayout* vbox = new QVBoxLayout; @@ -514,6 +521,7 @@ void CtrlPanel::setHeight(int h)        setFixedHeight(h);        } +#if 0  struct CI {              QString s;              bool used; @@ -673,6 +681,261 @@ void CtrlPanel::ctrlPopup()              }        } +#else               // p4.0.25 Tim +struct CI { +            int num; +            QString s; +            bool used; +            bool instrument; +            CI(int n, const QString& ss, bool u, bool i) : num(n), s(ss), used(u), instrument(i) {} +            }; + +void CtrlPanel::ctrlPopup() +      { +      //--------------------------------------------------- +      // build list of midi controllers for current +      // MidiPort/channel +      //--------------------------------------------------- + +      PartList* parts  = editor->parts(); +      Part* part       = editor->curCanvasPart(); +      MidiTrack* track = (MidiTrack*)(part->track()); +      int channel      = track->outChannel(); +      MidiPort* port   = &midiPorts[track->outPort()]; +      int curDrumInstrument = editor->curDrumInstrument(); +      bool isDrum      = track->type() == Track::DRUM; +      MidiInstrument* instr = port->instrument(); +      MidiControllerList* mcl = instr->controller(); + +      MidiCtrlValListList* cll = port->controller(); +      int min = channel << 24; +      int max = min + 0x1000000; + +      std::list<CI> sList; +      typedef std::list<CI>::iterator isList; + +      for (iMidiCtrlValList i = cll->lower_bound(min); i != cll->lower_bound(max); ++i) { +            MidiCtrlValList* cl = i->second; +            MidiController* c   = port->midiController(cl->num()); +            // dont show drum specific controller if not a drum track +            if ((c->num() & 0xff) == 0xff) { +                  if (!isDrum) +                        continue; +                  // only show controller for curDrumInstrument: +                  if ((cl->num() & 0xff) != drumMap[curDrumInstrument].anote) { +                        continue; +                        } +                  } +            isList i = sList.begin(); +            for (; i != sList.end(); ++i) { +                  //if (i->s == c->name()) +                  if (i->num == c->num()) +                        break; +                  } +            if (i == sList.end()) { +                  bool used = false; +                  for (iPart ip = parts->begin(); ip != parts->end(); ++ip) { +                        EventList* el = ip->second->events(); +                        for (iEvent ie = el->begin(); ie != el->end(); ++ie) { +                              Event e = ie->second; +                              if ((e.type() == Controller) && (e.dataA() == cl->num())) { +                                    used = true; +                                    break; +                                    } +                              } +                        if (used) +                              break; +                        } +                  //sList.push_back(CI(c->name(), used)); +                  bool isinstr = ( mcl->find(c->num()) != mcl->end() ); +                  int cnum = c->num(); +                  // Need to distinguish between global default controllers and  +                  //  instrument defined controllers. Instrument takes priority over global +                  //  ie they 'overtake' definition of a global controller such that the +                  //  global def is no longer available. +                  sList.push_back(CI(cnum,  +                                  isinstr ? midiCtrlNumString(cnum, true) + c->name() : midiCtrlName(cnum, true),  +                                  used, isinstr)); +                  } +            } +       +      PopupMenu* ctrlMainPop = new PopupMenu; +       +      //ctrlMainPop->addSeparator(); +      ctrlMainPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlMainPop)); +       +      //ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 1); +       +      // Add instrument-defined controllers. +      for (isList i = sList.begin(); i != sList.end(); ++i)  +      { +        if(!i->instrument) +          continue; +        if (i->used) +          ctrlMainPop->addAction(QIcon(*greendotIcon), i->s)->setData(i->num); +        else +          ctrlMainPop->addAction(i->s)->setData(i->num); +      } + +      ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 1); +      //ctrlMainPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instruments"))->setData(max + 2); + +      ctrlMainPop->addSeparator(); +      ctrlMainPop->addAction(new MenuTitleItem(tr("Others"), ctrlMainPop)); +       +      //ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 3); +       +      ctrlMainPop->addAction(tr("Velocity"))->setData(max); +       +      // Add global default controllers (all controllers not found in instrument). +      for (isList i = sList.begin(); i != sList.end(); ++i)  +      { +        if(i->instrument) +          continue; +        if (i->used) +          ctrlMainPop->addAction(QIcon(*greendotIcon), i->s)->setData(i->num); +        else +          ctrlMainPop->addAction(i->s)->setData(i->num); +      } +       +      ctrlMainPop->addAction(QIcon(*configureIcon), tr("Add ..."))->setData(max + 3); + +      //connect(ctrlMainPop, SIGNAL(hovered(QAction*)), SLOT(ctrlMainPopHovered(QAction*))); +       +      QAction *act = ctrlMainPop->exec(selCtrl->mapToGlobal(QPoint(0,0))); +      selCtrl->setDown(false); +       +      if (!act) +      { +        delete ctrlMainPop; +        return; +      } +       +      int rv = act->data().toInt(); +      delete ctrlMainPop; +       +      if (rv == max) {    // special case velocity +            emit controllerChanged(CTRL_VELOCITY); +            } +      else if (rv == max + 1) {  // add new instrument controller +             +            PopupMenu * ctrlSubPop = new PopupMenu(this); +            ctrlSubPop->addAction(new MenuTitleItem(tr("Instrument-defined"), ctrlSubPop)); +             +            // +            // populate popup with all controllers available for +            // current instrument +            // +             +            //ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instruments"))->setData(max + 2); +             +            for (iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci) +            { +                int num = ci->second->num(); +                if((num & 0xff) == 0xff) +                { +                  // dont show drum specific controller if not a drum track +                  if(!isDrum) +                    continue; +                  num = (num & ~0xff) + drumMap[curDrumInstrument].anote; +                }     + +                if(cll->find(channel, num) == cll->end()) +                  ctrlSubPop->addAction(midiCtrlNumString(num, true) + ci->second->name())->setData(num); +            } +             +            // Don't allow editing instrument if it's a synth +            if(!port->device() || port->device()->deviceType() != MidiDevice::SYNTH_MIDI) +              ctrlSubPop->addAction(QIcon(*midi_edit_instrumentIcon), tr("Edit instrument ..."))->setData(max + 2); +             +            //connect(ctrlSubPop, SIGNAL(hovered(QAction*)), SLOT(ctrlSubPopHovered(QAction*))); +             +            QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0))); +            if (act2)  +            { +              int rv2 = act2->data().toInt(); +               +              if (rv2 == max + 2)            // edit instrument +                muse->startEditInstrument(); +              else                           // select new instrument control +              { +                MidiController* c; +                for (iMidiController ci = mcl->begin(); ci != mcl->end(); ++ci)  +                { +                      c = ci->second; +                      int num = c->num(); +                      if (isDrum && ((num & 0xff) == 0xff)) +                        num = (num & ~0xff) + drumMap[curDrumInstrument].anote; +                       +                      if(num != rv2) +                        continue; +                         +                      if(cll->find(channel, num) == cll->end()) +                      { +                        MidiCtrlValList* vl = new MidiCtrlValList(num); +                         +                        cll->add(channel, vl); +                        emit controllerChanged(c->num()); +                        //song->update(SC_MIDI_CONTROLLER_ADD); +                      } +                      else  +                        emit controllerChanged(c->num()); +                      break; +                } +              }   +            } +            delete ctrlSubPop;    +            } +       +      //else if (rv == max + 2)             // edit instrument +      //      muse->startEditInstrument(); +       +      else if (rv == max + 3) {             // add new other controller +            PopupMenu* ctrlSubPop = new PopupMenu(this); +            ctrlSubPop->addAction(new MenuTitleItem(tr("Common Controls"), ctrlSubPop)); +             +            for(int num = 0; num < 127; ++num) +              if(cll->find(channel, num) == cll->end()) +                ctrlSubPop->addAction(midiCtrlName(num, true))->setData(num); +            QAction *act2 = ctrlSubPop->exec(selCtrl->mapToGlobal(QPoint(0,0))); +            if (act2) { +                  int rv2 = act2->data().toInt(); +                  int num = rv2; +                  if (isDrum && ((num & 0xff) == 0xff)) +                    num = (num & ~0xff) + drumMap[curDrumInstrument].anote; +                  if(cll->find(channel, num) == cll->end()) +                  { +                    MidiCtrlValList* vl = new MidiCtrlValList(num); +                     +                    cll->add(channel, vl); +                    emit controllerChanged(rv2); +                    //song->update(SC_MIDI_CONTROLLER_ADD); +                  } +                  else  +                    emit controllerChanged(rv2); +                  } +            delete ctrlSubPop;    +            } +      else {                           // Select a control +            //QString s = act->text(); +            iMidiCtrlValList i = cll->begin(); +            for (; i != cll->end(); ++i) { +                  MidiCtrlValList* cl = i->second; +                  MidiController* c   = port->midiController(cl->num()); +                  //if (c->name() == s) { +                  if (c->num() == rv) { +                        emit controllerChanged(c->num()); +                        break; +                        } +                  } +            if (i == cll->end()) { +                  //printf("CtrlPanel: controller %s not found!", s.toLatin1().constData()); +                  printf("CtrlPanel: controller number %d not found!", rv); +                  } +            } +      } +#endif +  //---------------------------------------------------------  //   ctrlRightClicked  //--------------------------------------------------------- diff --git a/muse2/muse/ctrl/ctrlpanel.h b/muse2/muse/ctrl/ctrlpanel.h index a0e5f915..92911b8e 100644 --- a/muse2/muse/ctrl/ctrlpanel.h +++ b/muse2/muse/ctrl/ctrlpanel.h @@ -12,7 +12,6 @@  class MidiController; -class QMenu;  class QPushButton;  class MidiEditor; @@ -26,7 +25,7 @@ class MidiTrack;  //---------------------------------------------------------  class CtrlPanel: public QWidget { -      ///QMenu* pop; +      //QMenu* pop;        QPushButton* selCtrl;        MidiEditor* editor; diff --git a/muse2/muse/dssihost.cpp b/muse2/muse/dssihost.cpp index 49a63643..2384ed02 100644 --- a/muse2/muse/dssihost.cpp +++ b/muse2/muse/dssihost.cpp @@ -37,7 +37,7 @@  #include <QDir>  #include <QFileInfo> -#include <QMenu> +//#include <QMenu>  #include "dssihost.h"  #include "synth.h" @@ -61,6 +61,8 @@  #include "globaldefs.h"  //#include "al/dsp.h"  #include "gconfig.h" +#include "popupmenu.h" +  /*  static lo_server_thread serverThread; @@ -3388,7 +3390,7 @@ const char* DssiSynthIF::getPatchName(int /*chan*/, int prog, MType /*type*/, bo  //---------------------------------------------------------  //void DssiSynthIF::populatePatchPopup(QMenu* menu, int) -void DssiSynthIF::populatePatchPopup(QMenu* menu, int /*ch*/, MType /*type*/, bool /*drum*/) +void DssiSynthIF::populatePatchPopup(PopupMenu* menu, int /*ch*/, MType /*type*/, bool /*drum*/)        {        // The plugin can change the programs, patches etc.        // So make sure we're up to date by calling queryPrograms. diff --git a/muse2/muse/dssihost.h b/muse2/muse/dssihost.h index 096c84c7..b917bbf6 100644 --- a/muse2/muse/dssihost.h +++ b/muse2/muse/dssihost.h @@ -42,7 +42,8 @@  #include "plugin.h" -#include <QMenu> +//#include <QMenu> +#include "popupmenu.h"  #define DSSI_PARAMSAVE_VERSION_MAJOR  0  #define DSSI_PARAMSAVE_VERSION_MINOR  1 @@ -199,7 +200,8 @@ class DssiSynthIF : public SynthIF, public PluginIBase        virtual const char* getPatchName(int, int, MType, bool);        //virtual void populatePatchPopup(QMenu*, int); -      virtual void populatePatchPopup(QMenu*, int, MType, bool); +      //virtual void populatePatchPopup(QMenu*, int, MType, bool); +      virtual void populatePatchPopup(PopupMenu*, int, MType, bool);        //virtual void write(Xml& xml) const;        virtual void write(int level, Xml& xml) const; diff --git a/muse2/muse/instruments/minstrument.cpp b/muse2/muse/instruments/minstrument.cpp index 4fde7bf3..10cb3ec2 100644 --- a/muse2/muse/instruments/minstrument.cpp +++ b/muse2/muse/instruments/minstrument.cpp @@ -11,7 +11,7 @@  #include <QAction>  #include <QDir>  #include <QFileInfo> -#include <QMenu> +//#include <QMenu>  #include <QMessageBox>  #include "minstrument.h" @@ -25,6 +25,7 @@  #include "mpevent.h"  #include "midictrl.h"  #include "gconfig.h" +#include "popupmenu.h"  MidiInstrumentList midiInstruments;  MidiInstrument* genericMidiInstrument; @@ -881,7 +882,7 @@ QString MidiInstrument::getPatchName(int channel, int prog, MType mode, bool dru  //   populatePatchPopup  //--------------------------------------------------------- -void MidiInstrument::populatePatchPopup(QMenu* menu, int chan, MType songType, bool drum) +void MidiInstrument::populatePatchPopup(PopupMenu* menu, int chan, MType songType, bool drum)        {        menu->clear();        int mask = 0; @@ -905,7 +906,9 @@ void MidiInstrument::populatePatchPopup(QMenu* menu, int chan, MType songType, b        if (pg.size() > 1) {              for (ciPatchGroup i = pg.begin(); i != pg.end(); ++i) {                    PatchGroup* pgp = *i; -                  QMenu* pm = menu->addMenu(pgp->name); +                  //QMenu* pm = menu->addMenu(pgp->name); +                  PopupMenu* pm = new PopupMenu(pgp->name, menu, menu->stayOpen());  // Use the parent stayOpen here. +                  menu->addMenu(pm);                    pm->setFont(config.fonts[0]);                    const PatchList& pl = pgp->patches;                    for (ciPatch ipl = pl.begin(); ipl != pl.end(); ++ipl) { diff --git a/muse2/muse/instruments/minstrument.h b/muse2/muse/instruments/minstrument.h index a8fb1168..15942537 100644 --- a/muse2/muse/instruments/minstrument.h +++ b/muse2/muse/instruments/minstrument.h @@ -14,7 +14,8 @@  #include <vector>  class MidiPort; -class QMenu; +//class QMenu; +class PopupMenu;  class MidiPlayEvent;  class Xml;  class EventList; @@ -118,7 +119,8 @@ class MidiInstrument {        virtual void reset(int, MType);        virtual QString getPatchName(int,int,MType,bool); -      virtual void populatePatchPopup(QMenu*, int, MType, bool); +      //virtual void populatePatchPopup(QMenu*, int, MType, bool); +      virtual void populatePatchPopup(PopupMenu*, int, MType, bool);        void read(Xml&);        void write(int level, Xml&); diff --git a/muse2/muse/liste/editevent.cpp b/muse2/muse/liste/editevent.cpp index b162a3e6..0643c34d 100644 --- a/muse2/muse/liste/editevent.cpp +++ b/muse2/muse/liste/editevent.cpp @@ -36,6 +36,7 @@  #include "midiedit/drummap.h"  #include "instruments/minstrument.h"  #include "midi.h" +#include "popupmenu.h"  //---------------------------------------------------------  //   string2qhex @@ -715,7 +716,9 @@ void EditCtrlDialog::newController()                            cll->add(channel, vl);                            //song->update(SC_MIDI_CONTROLLER_ADD);                          } -                        for (int idx = 0; ;++idx) { +                        //for (int idx = 0; ;++idx) { +                        int idx = 0; +                        for (; idx < ctrlList->count() ;++idx) {   // p4.0.25 Fix segfault   			  QString str = ctrlList->item(idx)->text();                                if (s == str)                                { @@ -723,14 +726,21 @@ void EditCtrlDialog::newController()                                      ctrlListClicked(ctrlList->item(idx));                                      break;                                }       -                              if (str.isNull()) { -                                    ctrlList->addItem(s); -                                    ctrlList->item(idx)->setSelected(true); -                                    ctrlListClicked(ctrlList->item(idx)); -                                    break; -                                    } +                              //if (str.isNull()) { +                              //      ctrlList->addItem(s); +                              //      ctrlList->item(idx)->setSelected(true); +                              //      ctrlListClicked(ctrlList->item(idx)); +                              //      break; +                              //      } +                              } +                        if (idx >= ctrlList->count()) {                       // p4.0.25 Fix segfault  +                              ctrlList->addItem(s); +                              ctrlList->item(idx)->setSelected(true); +                              ctrlListClicked(ctrlList->item(idx)); +                              break;                                } +                                                        break;                          }                    } @@ -844,7 +854,8 @@ void EditCtrlDialog::instrPopup()        MidiInstrument* instr = midiPorts[port].instrument();        ///instr->populatePatchPopup(pop, channel, song->mtype(), track->type() == Track::DRUM); -      QMenu* pup = new QMenu(this); +      //QMenu* pup = new QMenu(this); +      PopupMenu* pup = new PopupMenu(this);        instr->populatePatchPopup(pup, channel, song->mtype(), track->type() == Track::DRUM);        ///if(pop->actions().count() == 0) diff --git a/muse2/muse/midictrl.cpp b/muse2/muse/midictrl.cpp index 66f8d87e..4cf1886a 100644 --- a/muse2/muse/midictrl.cpp +++ b/muse2/muse/midictrl.cpp @@ -139,15 +139,85 @@ void initMidiController()        }  //--------------------------------------------------------- +//   midiCtrlNumString +//--------------------------------------------------------- + +QString midiCtrlNumString(int ctrl, bool fullyQualified) +{ +      int h = (ctrl >> 8) & 0xff; +      int l = ctrl & 0xff; +      QString s1 = QString("%1").arg(h); +      QString s2 = ( l == 0xff ? QString("* ") : QString("%1 ").arg(l) ); +      MidiController::ControllerType type = midiControllerType(ctrl); +      switch (type) +      { +        case MidiController::Controller7: +          if(fullyQualified) +            return s2; +          else   +            return QString(); +        case MidiController::Controller14: +          return s1 + QString("CF") + s2; +        case MidiController::RPN: +          return s1 + QString("R") + s2; +        case MidiController::NRPN: +          return s1 + QString("N") + s2; +        case MidiController::Pitch:    // Don't show internal controller numbers.  +          return QString(); +        case MidiController::Program: +          return QString(); +        case MidiController::Velo: +          return QString(); +        case MidiController::RPN14: +          return s1 + QString("RF") + s2; +        case MidiController::NRPN14: +          return s1 + QString("NF") + s2; +      } +      return s1 + QString("?") + s2; +} + +//---------------------------------------------------------  //   midiCtrlName  //--------------------------------------------------------- -QString midiCtrlName(int ctrl) +QString midiCtrlName(int ctrl, bool fullyQualified) +{ +      //if (ctrl < 0x10000) +      //      return QString(ctrlName[ctrl]); +      //return QString("?N?"); +       +      // p4.0.25 Tim +      int h = (ctrl >> 8) & 0xff; +      int l = ctrl & 0xff; +      QString s1 = QString("%1").arg(h); +      QString s2 = ( l == 0xff ? QString("*") : QString("%1").arg(l) ); +      MidiController::ControllerType type = midiControllerType(ctrl); +      switch (type)        { -      if (ctrl < 0x10000) -            return QString(ctrlName[ctrl]); -      return QString("?N?"); +        case MidiController::Controller7: +          if(fullyQualified) +            return s2 + QString(" ") + QString(ctrlName[l]); +          else   +            return QString(ctrlName[l]); +        case MidiController::Controller14: +          return s1 + QString("CF") + s2; +        case MidiController::RPN: +          return s1 + QString("R") + s2; +        case MidiController::NRPN: +          return s1 + QString("N") + s2; +        case MidiController::Pitch: +          return QString("Pitch"); +        case MidiController::Program: +          return QString("Program"); +        case MidiController::Velo: +          return QString("Velocity"); +        case MidiController::RPN14: +          return s1 + QString("RF") + s2; +        case MidiController::NRPN14: +          return s1 + QString("NF") + s2;        } +      return s1 + QString("?") + s2; +}  //---------------------------------------------------------  //   MidiController diff --git a/muse2/muse/midictrl.h b/muse2/muse/midictrl.h index 27f8e7be..3b18ba91 100644 --- a/muse2/muse/midictrl.h +++ b/muse2/muse/midictrl.h @@ -243,7 +243,8 @@ extern MidiController::ControllerType midiControllerType(int num);  extern const QString& int2ctrlType(int n);  extern MidiController::ControllerType ctrlType2Int(const QString& s); -extern QString midiCtrlName(int ctrl); +extern QString midiCtrlName(int ctrl, bool fullyQualified = false); +extern QString midiCtrlNumString(int ctrl, bool fullyQualified = false);  extern MidiController veloCtrl; diff --git a/muse2/muse/mixer/astrip.cpp b/muse2/muse/mixer/astrip.cpp index 265061ad..c1e92e59 100644 --- a/muse2/muse/mixer/astrip.cpp +++ b/muse2/muse/mixer/astrip.cpp @@ -1185,7 +1185,7 @@ static int addSyntiPorts(AudioTrack* t, PopupMenu* lb, int id,              if(chans > 0)              { -              PopupMenu* chpup = new PopupMenu(lb); +              PopupMenu* chpup = new PopupMenu(lb, true);                chpup->setTitle(track->name());                for(int ch = 0; ch < chans; ++ch)                { @@ -1270,7 +1270,7 @@ static int addMultiChannelPorts(AudioTrack* t, PopupMenu* pup, int id, RouteMenu    {      // If more than one channel, create the sub-menu.      if(chans > 1) -      chpup = new PopupMenu(pup); +      chpup = new PopupMenu(pup, true);      if(isOutput)      { @@ -1356,7 +1356,7 @@ static int addMultiChannelPorts(AudioTrack* t, PopupMenu* pup, int id, RouteMenu      {        // If more than two channels, create the sub-menu.        if(chans > 2) -        chpup = new PopupMenu(pup); +        chpup = new PopupMenu(pup, true);        if(isOutput)        { @@ -1460,7 +1460,7 @@ static int nonSyntiTrackAddSyntis(AudioTrack* t, PopupMenu* lb, int id, RouteMen              if(chans > 0)              { -              PopupMenu* chpup = new PopupMenu(lb); +              PopupMenu* chpup = new PopupMenu(lb, true);                chpup->setTitle(track->name());                if(chans > 1)                  chpup->addAction(new MenuTitleItem("<Mono>", chpup)); @@ -1597,7 +1597,7 @@ static int addMidiPorts(AudioTrack* t, PopupMenu* pup, int id, RouteMenuMap& mm,     RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes(); -    PopupMenu* subp = new PopupMenu(pup); +    PopupMenu* subp = new PopupMenu(pup, true);      subp->setTitle(md->name());       int chanmask = 0; @@ -1830,11 +1830,11 @@ void AudioStrip::iRoutePressed()            //            pup->addSeparator();            pup->addAction(new MenuTitleItem(tr("Soloing chain"), pup));  -          PopupMenu* subp = new PopupMenu(pup); +          PopupMenu* subp = new PopupMenu(pup, true);            subp->setTitle(tr("Audio sends"));             pup->addMenu(subp);            gid = addOutPorts(t, subp, gid, gRoutingMenuMap, -1, -1, false);   -          subp = new PopupMenu(pup); +          subp = new PopupMenu(pup, true);            subp->setTitle(tr("Midi port sends"));             pup->addMenu(subp);            addMidiPorts(t, subp, gid, gRoutingMenuMap, false); @@ -1980,7 +1980,7 @@ void AudioStrip::oRoutePressed()            //            pup->addSeparator();            pup->addAction(new MenuTitleItem(tr("Soloing chain"), pup));  -          PopupMenu* subp = new PopupMenu(pup); +          PopupMenu* subp = new PopupMenu(pup, true);            subp->setTitle(tr("Audio returns"));             pup->addMenu(subp);            gid = addInPorts(t, subp, gid, gRoutingMenuMap, -1, -1, true);   diff --git a/muse2/muse/synth.cpp b/muse2/muse/synth.cpp index 521c7d63..4f43a02a 100644 --- a/muse2/muse/synth.cpp +++ b/muse2/muse/synth.cpp @@ -17,7 +17,7 @@  #include <dlfcn.h>  #include <QDir> -#include <QMenu> +//#include <QMenu>  #include "app.h"  #include "synth.h" @@ -35,6 +35,7 @@  #include "midiseq.h"  #include "midictrl.h"  //#include "stringparam.h" +#include "popupmenu.h"  std::vector<Synth*> synthis;  // array of available synthis @@ -864,7 +865,7 @@ const char* MessSynthIF::getPatchName(int channel, int prog, MType type, bool dr  //   populatePatchPopup  //--------------------------------------------------------- -void MessSynthIF::populatePatchPopup(QMenu* menu, int ch, MType, bool) +void MessSynthIF::populatePatchPopup(PopupMenu* menu, int ch, MType, bool)        {        menu->clear();        const MidiPatch* mp = _mess->getPatchInfo(ch, 0); diff --git a/muse2/muse/synth.h b/muse2/muse/synth.h index b11ea2d9..88fa70b8 100644 --- a/muse2/muse/synth.h +++ b/muse2/muse/synth.h @@ -22,7 +22,8 @@  #include <QFileInfo> -class QMenu; +//class QMenu; +class PopupMenu;  //class MidiEvent;  class MidiPlayEvent; @@ -147,7 +148,8 @@ class SynthIF {        virtual void deactivate3() = 0;        virtual const char* getPatchName(int, int, int, bool) const = 0;        virtual const char* getPatchName(int, int, MType, bool) = 0; -      virtual void populatePatchPopup(QMenu*, int, MType, bool) = 0; +      //virtual void populatePatchPopup(QMenu*, int, MType, bool) = 0; +      virtual void populatePatchPopup(PopupMenu*, int, MType, bool) = 0;        virtual void write(int level, Xml& xml) const = 0;        virtual float getParameter(unsigned long idx) const = 0;                virtual void setParameter(unsigned long idx, float value) = 0;   @@ -231,7 +233,8 @@ class SynthI : public AudioTrack, public MidiDevice,              return _sif->getPatchName(ch, prog, t, dr);              } -      virtual void populatePatchPopup(QMenu* m, int i, MType t, bool d) { +      //virtual void populatePatchPopup(QMenu* m, int i, MType t, bool d) { +      virtual void populatePatchPopup(PopupMenu* m, int i, MType t, bool d) {              _sif->populatePatchPopup(m, i, t, d);              } @@ -313,7 +316,8 @@ class MessSynthIF : public SynthIF {        virtual void deactivate3();        virtual const char* getPatchName(int, int, int, bool) const { return ""; }        virtual const char* getPatchName(int, int, MType, bool); -      virtual void populatePatchPopup(QMenu*, int, MType, bool); +      //virtual void populatePatchPopup(QMenu*, int, MType, bool); +      virtual void populatePatchPopup(PopupMenu*, int, MType, bool);        virtual void write(int level, Xml& xml) const;        virtual float getParameter(unsigned long) const { return 0.0; }        virtual void setParameter(unsigned long, float) {} diff --git a/muse2/muse/ticksynth.cpp b/muse2/muse/ticksynth.cpp index c5d3a1e7..7456b856 100644 --- a/muse2/muse/ticksynth.cpp +++ b/muse2/muse/ticksynth.cpp @@ -9,7 +9,8 @@  #include "ticksynth.h"  #include "default_click.h" -#include <QMenu> +//#include <QMenu> +#include "popupmenu.h"  // Added by Tim. p3.3.18  //#define METRONOME_DEBUG @@ -90,7 +91,8 @@ class MetronomeSynthIF : public SynthIF        virtual void deactivate3() {}        virtual const char* getPatchName(int, int, int, bool) const { return ""; }        virtual const char* getPatchName(int, int, MType, bool) { return ""; } -      virtual void populatePatchPopup(QMenu*, int, MType, bool) {}; +      //virtual void populatePatchPopup(QMenu*, int, MType, bool) {}; +      virtual void populatePatchPopup(PopupMenu*, int, MType, bool) {};        virtual void write(int, Xml&) const {}        virtual float getParameter(unsigned long) const  { return 0.0; }        virtual void setParameter(unsigned long, float) {} diff --git a/muse2/muse/vst.h b/muse2/muse/vst.h index d41502e5..bb675c22 100644 --- a/muse2/muse/vst.h +++ b/muse2/muse/vst.h @@ -10,7 +10,8 @@  #include "synth.h" -class QMenu; +//class QMenu; +class PopupMenu;  struct _FSTHandle;  struct _FST; @@ -76,7 +77,8 @@ class VstSynthIF : public SynthIF        virtual void deactivate3();        virtual const char* getPatchName(int, int, int, bool) const { return ""; }        virtual const char* getPatchName(int, int, MType, bool) { return ""; } -      virtual void populatePatchPopup(QMenu*, int, MType, bool) {}; +      //virtual void populatePatchPopup(QMenu*, int, MType, bool) {}; +      virtual void populatePatchPopup(PopupMenu*, int, MType, bool) {};        virtual void write(int level, Xml& xml) const;        virtual float getParameter(unsigned long idx) const;        virtual void setParameter(unsigned long idx, float value); diff --git a/muse2/muse/widgets/mtrackinfo.cpp b/muse2/muse/widgets/mtrackinfo.cpp index acdfb42f..47576823 100644 --- a/muse2/muse/widgets/mtrackinfo.cpp +++ b/muse2/muse/widgets/mtrackinfo.cpp @@ -1036,6 +1036,29 @@ void MidiTrackInfo::iPanChanged(int val)      }  //--------------------------------------------------------- +//   instrPopupActivated +//--------------------------------------------------------- + +void MidiTrackInfo::instrPopupActivated(QAction* act) +{ +  printf("MidiTrackInfo::instrPopupActivated\n"); // REMOVE Tim +   +  if(act && selected)  +  { +    int rv = act->data().toInt(); +    if(rv != -1) +    { +      MidiTrack* track = (MidiTrack*)selected; +      int channel = track->outChannel(); +      int port    = track->outPort(); +      MidiPlayEvent ev(0, port, channel, ME_CONTROLLER, CTRL_PROGRAM, rv); +      audio->msgPlayMidiEvent(&ev); +      updateTrackInfo(-1); +    }   +  } +} + +//---------------------------------------------------------  //   instrPopup  //--------------------------------------------------------- @@ -1047,7 +1070,9 @@ void MidiTrackInfo::instrPopup()        int channel = track->outChannel();        int port    = track->outPort();        MidiInstrument* instr = midiPorts[port].instrument(); -      QMenu* pup = new QMenu; +      //QMenu* pup = new QMenu; +      PopupMenu* pup = new PopupMenu(true); +              ///instr->populatePatchPopup(pop, channel, song->mtype(), track->type() == Track::DRUM);        instr->populatePatchPopup(pup, channel, song->mtype(), track->type() == Track::DRUM); @@ -1059,14 +1084,21 @@ void MidiTrackInfo::instrPopup()          return;        }   +      connect(pup, SIGNAL(triggered(QAction*)), SLOT(instrPopupActivated(QAction*))); +      //connect(pup, SIGNAL(hovered(QAction*)), SLOT(instrPopupActivated(QAction*))); +              ///QAction *act = pop->exec(iPatch->mapToGlobal(QPoint(10,5)));        QAction *act = pup->exec(iPatch->mapToGlobal(QPoint(10,5))); -      if (act) { -            int rv = act->data().toInt(); -            MidiPlayEvent ev(0, port, channel, ME_CONTROLLER, CTRL_PROGRAM, rv); -            audio->msgPlayMidiEvent(&ev); -            updateTrackInfo(-1); -            } +      if(act)  +      { +        int rv = act->data().toInt(); +        if(rv != -1) +        { +          MidiPlayEvent ev(0, port, channel, ME_CONTROLLER, CTRL_PROGRAM, rv); +          audio->msgPlayMidiEvent(&ev); +          updateTrackInfo(-1); +        }   +      }        delete pup;              } diff --git a/muse2/muse/widgets/mtrackinfo.h b/muse2/muse/widgets/mtrackinfo.h index 4e06f1d0..0e559f33 100644 --- a/muse2/muse/widgets/mtrackinfo.h +++ b/muse2/muse/widgets/mtrackinfo.h @@ -48,6 +48,7 @@ class MidiTrackInfo : public QWidget, public Ui::MidiTrackInfoBase        void outRoutesPressed();        void routingPopupMenuActivated(QAction*);        //void routingPopupViewActivated(const QModelIndex&); +      void instrPopupActivated(QAction*);     protected slots:        virtual void heartBeat(); 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 <stdio.h>  #include <QMouseEvent> +#include <QHoverEvent>  #include <QAction> +#include <QPoint> +#include <QDesktopWidget> +#include <QApplication> +//#include <QTimer> +  #include <stdio.h>  //#include <QStandardItemModel>  #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<QAction*> 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<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());  // 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<QHoverEvent*>(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   }  /* diff --git a/muse2/muse/widgets/popupmenu.h b/muse2/muse/widgets/popupmenu.h index c06d51f4..4982d199 100644 --- a/muse2/muse/widgets/popupmenu.h +++ b/muse2/muse/widgets/popupmenu.h @@ -11,7 +11,15 @@  #ifndef __POPUPMENU_H__  #define __POPUPMENU_H__ +// Just in case Qt ever adds these features natively, we would need to turn our features off! +//#define POPUP_MENU_DISABLE_STAY_OPEN     +//#define POPUP_MENU_DISABLE_AUTO_SCROLL +  #include <QMenu> +#ifndef POPUP_MENU_DISABLE_AUTO_SCROLL   +  #include <QTimer> +#endif +  //#include <QMouseEvent>  //#include <QColumnView> @@ -19,20 +27,40 @@ class QWidget;  class QMouseEvent;  class QVariant;  class QAction; +class QEvent; +//class QTimer;  //class QStandardItemModel;  class PopupMenu : public QMenu  {    Q_OBJECT +    bool _stayOpen; +    #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL   +    QTimer* timer; +    #endif +    int moveDelta; +    void init(); +     +  private slots: +    #ifndef POPUP_MENU_DISABLE_AUTO_SCROLL   +    void popHovered(QAction*); +    void timerHandler(); +    #endif +      protected:      void mouseReleaseEvent(QMouseEvent *); +    bool event(QEvent*);       public: -    PopupMenu(QWidget* parent=0); +    //PopupMenu(); +    PopupMenu(bool stayOpen); +    PopupMenu(QWidget* parent=0, bool stayOpen = false); +    PopupMenu(const QString& title, QWidget* parent = 0, bool stayOpen = false);      ~PopupMenu();      void clear();      QAction* findActionFromData(QVariant); +    bool stayOpen() { return _stayOpen; }  }; | 
