summaryrefslogtreecommitdiff
path: root/muse2/muse
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2011-05-19 07:43:06 +0000
committerTim E. Real <termtech@rogers.com>2011-05-19 07:43:06 +0000
commit0f3ed66e83d6639452a5aa219b9a6bf2bfd54897 (patch)
tree950c324e7301f657cba543d8ccbb268ca40e418f /muse2/muse
parent0792c2ec66dacfff10899cbe171cb661871617f1 (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.cpp301
-rw-r--r--muse2/muse/app.h3
-rw-r--r--muse2/muse/arranger/tlist.cpp18
-rw-r--r--muse2/muse/arranger/tlist.h6
-rw-r--r--muse2/muse/confmport.cpp4
-rw-r--r--muse2/muse/ctrl/ctrledit.cpp10
-rw-r--r--muse2/muse/ctrl/ctrlpanel.cpp265
-rw-r--r--muse2/muse/ctrl/ctrlpanel.h3
-rw-r--r--muse2/muse/dssihost.cpp6
-rw-r--r--muse2/muse/dssihost.h6
-rw-r--r--muse2/muse/instruments/minstrument.cpp9
-rw-r--r--muse2/muse/instruments/minstrument.h6
-rw-r--r--muse2/muse/liste/editevent.cpp27
-rw-r--r--muse2/muse/midictrl.cpp78
-rw-r--r--muse2/muse/midictrl.h3
-rw-r--r--muse2/muse/mixer/astrip.cpp16
-rw-r--r--muse2/muse/synth.cpp5
-rw-r--r--muse2/muse/synth.h12
-rw-r--r--muse2/muse/ticksynth.cpp6
-rw-r--r--muse2/muse/vst.h6
-rw-r--r--muse2/muse/widgets/mtrackinfo.cpp46
-rw-r--r--muse2/muse/widgets/mtrackinfo.h1
-rw-r--r--muse2/muse/widgets/popupmenu.cpp221
-rw-r--r--muse2/muse/widgets/popupmenu.h30
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; }
};