summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim E. Real <termtech@rogers.com>2010-07-24 07:12:21 +0000
committerTim E. Real <termtech@rogers.com>2010-07-24 07:12:21 +0000
commit59585e989418316bdeeba2cb51776e76aec7e01a (patch)
tree731541051f763bb98ad5d0579f1c53920f698199
parentfa27945706de2f72c082b7157ffdc658f84f58bd (diff)
See ChangeLog
-rw-r--r--muse/ChangeLog4
-rw-r--r--muse/muse/app.cpp606
-rw-r--r--muse/muse/app.h12
-rw-r--r--muse/muse/arranger/arranger.h1
-rw-r--r--muse/muse/arranger/pcanvas.cpp2
-rw-r--r--muse/muse/arranger/trackinfo.cpp58
-rw-r--r--muse/muse/audioprefetch.cpp2
-rw-r--r--muse/muse/confmport.cpp25
-rw-r--r--muse/muse/globals.cpp5
-rw-r--r--muse/muse/globals.h12
-rw-r--r--muse/muse/marker/markerview.cpp3
-rw-r--r--muse/muse/mixer/astrip.cpp889
-rw-r--r--muse/muse/mixer/astrip.h15
-rw-r--r--muse/muse/mixer/mstrip.cpp57
-rw-r--r--muse/muse/mixer/mstrip.h5
-rw-r--r--muse/muse/mixer/strip.cpp6
-rw-r--r--muse/muse/mixer/strip.h5
-rw-r--r--muse/muse/song.cpp114
-rw-r--r--muse/muse/song.h2
-rw-r--r--muse/muse/widgets/Makefile.am2
-rw-r--r--muse/muse/widgets/popupmenu.cpp2760
-rw-r--r--muse/muse/widgets/popupmenu.h301
22 files changed, 4499 insertions, 387 deletions
diff --git a/muse/ChangeLog b/muse/ChangeLog
index cc28a4c4..24350f7b 100644
--- a/muse/ChangeLog
+++ b/muse/ChangeLog
@@ -1,3 +1,7 @@
+24.07.2010
+ * Feature: Audio and midi routing popup menus now stay open, for making rapid connections. (T356)
+ * Fixed: Delete some objects hanging around upon close like song, audio, midiSeq, and prefetch. (T356)
+ TODO: Find a way to delete the 'muse' object without causing problems like seg faults.
21.07.2010
* Improved: Note lanes in pianoroll and marking of C-notes (rj)
20.07.2010
diff --git a/muse/muse/app.cpp b/muse/muse/app.cpp
index be1d53b4..38b1b120 100644
--- a/muse/muse/app.cpp
+++ b/muse/muse/app.cpp
@@ -37,6 +37,7 @@
#include <qobject.h>
#include "app.h"
+#include "popupmenu.h"
#include "transport.h"
#include "bigtime.h"
#include "arranger.h"
@@ -624,7 +625,7 @@ QPopupMenu* populateAddSynth(QWidget* parent, QObject* obj = 0, const char* slot
asmap mapVST;
#endif
- // Not neccessary, but what the heck.
+ // Not necessary, but what the heck.
QPopupMenu* synpOther = 0;
asmap mapOther;
@@ -829,7 +830,8 @@ MusE::MusE(int argc, char** argv) : QMainWindow(0, "mainwindow")
mixer2 = 0;
watchdogThread = 0;
editInstrument = 0;
-
+ routingPopupMenu = 0;
+
appName = QString("MusE");
song = new Song("song");
@@ -1586,7 +1588,7 @@ void MusE::loadProjectFile1(const QString& name, bool songTemplate, bool loadAll
showBigtime(config.bigTimeVisible);
//showMixer(config.mixerVisible);
showMixer1(config.mixer1Visible);
- showMixer2(config.mixer1Visible);
+ showMixer2(config.mixer2Visible);
// Added p3.3.43 Make sure the geometry is correct because showMixerX() will NOT
// set the geometry if the mixer has already been created, which caused a very
@@ -1873,6 +1875,11 @@ void MusE::closeEvent(QCloseEvent*)
printf("Muse: Exiting Metronome\n");
exitMetronome();
+ // p3.3.47
+ // Make sure to clear the menu, which deletes any sub menus.
+ if(routingPopupMenu)
+ routingPopupMenu->clear();
+
// Changed by Tim. p3.3.14
//SynthIList* sl = song->syntis();
//for (iSynthI i = sl->begin(); i != sl->end(); ++i)
@@ -1911,6 +1918,12 @@ void MusE::closeEvent(QCloseEvent*)
printf("Muse: Exiting OSC\n");
exitOSC();
+ // p3.3.47
+ delete audioPrefetch;
+ delete audio;
+ delete midiSeq;
+ delete song;
+
qApp->quit();
}
@@ -1975,6 +1988,585 @@ void MusE::showTransport(bool flag)
}
//---------------------------------------------------------
+// getRoutingPopupMenu
+//---------------------------------------------------------
+
+PopupMenu* MusE::getRoutingPopupMenu()
+{
+ if(!routingPopupMenu)
+ routingPopupMenu = new PopupMenu(this);
+ return routingPopupMenu;
+}
+
+//---------------------------------------------------------
+// updateRouteMenus
+//---------------------------------------------------------
+
+void MusE::updateRouteMenus(Track* track)
+{
+ //if(!track || track != gRoutingPopupMenuMaster || track->type() == Track::AUDIO_AUX)
+ if(!track || track->type() == Track::AUDIO_AUX)
+ return;
+
+ //QPopupMenu* pup = muse->getORoutesPopup();
+ PopupMenu* pup = muse->getRoutingPopupMenu();
+
+ if(pup->count() == 0)
+ return;
+
+ //AudioTrack* t = (AudioTrack*)track;
+ RouteList* rl = gIsOutRoutingPopupMenu ? track->outRoutes() : track->inRoutes();
+
+ /*
+ iRoute iorl = orl->begin();
+ for(; iorl != orl->end(); ++iorl)
+ {
+ iRouteMenuMap imm = ormm->begin();
+ for(; imm != ormm->end(); ++imm)
+ {
+ if(*iorl == imm->second)
+ {
+ orpup->setItemChecked(imm->first, true);
+ break;
+ }
+ }
+ //if(imm == ormm->end())
+ //{
+ //}
+
+ }
+ //if (iorl == orl->end())
+ //{
+ //}
+ */
+
+ iRouteMenuMap imm = gRoutingMenuMap.begin();
+ for(; imm != gRoutingMenuMap.end(); ++imm)
+ {
+ bool found = false;
+ iRoute irl = rl->begin();
+ for(; irl != rl->end(); ++irl)
+ {
+ if(*irl == imm->second)
+ {
+ found = true;
+ break;
+ }
+ }
+ pup->setItemChecked(imm->first, found);
+ }
+
+ return;
+}
+
+//---------------------------------------------------------
+// routingPopupMenuActivated
+//---------------------------------------------------------
+
+void MusE::routingPopupMenuActivated(Track* track, int n)
+{
+ //if(!track || (track != gRoutingPopupMenuMaster))
+ if(!track)
+ return;
+
+ if(track->isMidiTrack())
+ {
+ PopupMenu* pup = getRoutingPopupMenu();
+
+ //printf("MusE::routingPopupMenuActivated midi n:%d count:%d\n", n, pup->count());
+
+ if(pup->count() == 0)
+ return;
+
+ //MidiTrack* t = (MidiTrack*)track;
+ RouteList* rl = gIsOutRoutingPopupMenu ? track->outRoutes() : track->inRoutes();
+
+ if(n == -1)
+ {
+ //printf("MusE::routingPopupMenuActivated midi n = -1\n");
+ ///delete pup;
+ ///pup = 0;
+ return;
+ }
+ else
+ {
+ int mdidx = n / MIDI_CHANNELS;
+ int ch = n % MIDI_CHANNELS;
+
+ //if(debugMsg)
+ //printf("MusE::routingPopupMenuActivated mdidx:%d ch:%d\n", mdidx, ch);
+
+ MidiPort* mp = &midiPorts[mdidx];
+ MidiDevice* md = mp->device();
+ if(!md)
+ {
+ ///delete pup;
+ return;
+ }
+
+ //if(!(md->rwFlags() & 2))
+ if(!(md->rwFlags() & (gIsOutRoutingPopupMenu ? 1 : 2)))
+ {
+ ///delete pup;
+ return;
+ }
+
+ //QString s(pup->text(n));
+ //QT_TR_NOOP(md->name())
+
+ //Route srcRoute(s, false, -1);
+ Route aRoute(md, ch);
+ //Route srcRoute(md, -1);
+ //Route dstRoute(track, -1);
+ Route bRoute(track, ch);
+
+ //if (track->type() == Track::AUDIO_INPUT)
+ // srcRoute.channel = dstRoute.channel = n & 0xf;
+ iRoute iir = rl->begin();
+ for (; iir != rl->end(); ++iir)
+ {
+ //if(*iir == (dst ? bRoute : aRoute))
+ if(*iir == aRoute)
+ break;
+ }
+ if (iir != rl->end())
+ {
+ // disconnect
+ if(gIsOutRoutingPopupMenu)
+ {
+ //printf("MusE::routingPopupMenuActivated removing route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1());
+ audio->msgRemoveRoute(bRoute, aRoute);
+ }
+ else
+ {
+ //printf("MusE::routingPopupMenuActivated removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgRemoveRoute(aRoute, bRoute);
+ }
+ }
+ else
+ {
+ // connect
+ if(gIsOutRoutingPopupMenu)
+ {
+ //printf("MusE::routingPopupMenuActivated adding route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1());
+ audio->msgAddRoute(bRoute, aRoute);
+ }
+ else
+ {
+ //printf("MusE::routingPopupMenuActivated adding route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgAddRoute(aRoute, bRoute);
+ }
+ }
+
+ //printf("MusE::routingPopupMenuActivated calling msgUpdateSoloStates\n");
+ audio->msgUpdateSoloStates();
+ //printf("MusE::routingPopupMenuActivated calling song->update\n");
+ song->update(SC_ROUTE);
+ }
+ }
+ else
+ {
+ // TODO: Try to move code from AudioStrip::routingPopupMenuActivated into here.
+
+ /*
+ PopupMenu* pup = getRoutingPopupMenu();
+
+ printf("MusE::routingPopupMenuActivated audio n:%d count:%d\n", n, pup->count());
+
+ if(pup->count() == 0)
+ return;
+
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* rl = gIsOutRoutingPopupMenu ? t->outRoutes() : t->inRoutes();
+
+ //QPoint ppt = QCursor::pos();
+
+ if(n == -1)
+ {
+ //printf("MusE::routingPopupMenuActivated audio n = -1 deleting popup...\n");
+ printf("MusE::routingPopupMenuActivated audio n = -1\n");
+ ///delete pup;
+ ///pup = 0;
+ return;
+ }
+ else
+ //if(n == 0)
+ //{
+ //printf("MusE::routingPopupMenuActivated audio n = 0 = tearOffHandle\n");
+ //oR->setDown(false);
+ // return;
+ //}
+ //else
+ {
+ if(gIsOutRoutingPopupMenu)
+ {
+ QString s(pup->text(n));
+
+ //printf("AudioStrip::routingPopupMenuActivated audio text:%s\n", s.latin1());
+
+ if(track->type() == Track::AUDIO_OUTPUT)
+ {
+ ///delete orpup;
+
+ int chan = n & 0xf;
+
+ //Route srcRoute(t, -1);
+ //Route srcRoute(t, chan, chans);
+ //Route srcRoute(t, chan, 1);
+ Route srcRoute(t, chan);
+
+ //Route dstRoute(s, true, -1);
+ Route dstRoute(s, true, -1, Route::JACK_ROUTE);
+ //Route dstRoute(s, true, 0, Route::JACK_ROUTE);
+
+ //srcRoute.channel = dstRoute.channel = chan;
+ dstRoute.channel = chan;
+ //dstRoute.channels = 1;
+
+ // check if route src->dst exists:
+ iRoute irl = rl->begin();
+ for (; irl != rl->end(); ++irl) {
+ if (*irl == dstRoute)
+ break;
+ }
+ if (irl != rl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+
+ // p3.3.47
+ //pup->popup(ppt, 0);
+
+ //oR->setDown(false);
+ return;
+
+ // p3.3.46
+ ///goto _redisplay;
+ }
+
+ iRouteMenuMap imm = gRoutingMenuMap.find(n);
+ if(imm == gRoutingMenuMap.end())
+ {
+ ///delete orpup;
+ //oR->setDown(false); // orpup->exec() catches mouse release event
+ return;
+ }
+
+ //int chan = n >> 16;
+ //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
+ //chan &= 0xffff;
+ //int chan = imm->second.channel;
+ //int chans = imm->second.channels;
+
+ //Route srcRoute(t, -1);
+ //srcRoute.remoteChannel = chan;
+ //Route srcRoute(t, chan, chans);
+ Route srcRoute(t, imm->second.channel, imm->second.channels);
+ //Route srcRoute(t, imm->second.channel);
+ srcRoute.remoteChannel = imm->second.remoteChannel;
+
+ //Route dstRoute(s, true, -1);
+ //Route dstRoute(s, true, -1, Route::TRACK_ROUTE);
+ Route &dstRoute = imm->second;
+
+ // check if route src->dst exists:
+ iRoute irl = rl->begin();
+ for (; irl != rl->end(); ++irl) {
+ if (*irl == dstRoute)
+ break;
+ }
+ if (irl != rl->end()) {
+ // disconnect if route exists
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect if route does not exist
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+
+ // p3.3.46
+ //oR->setDown(false);
+ ///goto _redisplay;
+
+ // p3.3.47
+ //pup->popup(ppt, 0);
+ }
+ else
+ {
+ QString s(pup->text(n));
+
+ if(track->type() == Track::AUDIO_INPUT)
+ {
+ ///delete pup;
+ int chan = n & 0xf;
+
+ Route srcRoute(s, false, -1, Route::JACK_ROUTE);
+ Route dstRoute(t, chan);
+
+ srcRoute.channel = chan;
+
+ iRoute irl = rl->begin();
+ for(; irl != rl->end(); ++irl)
+ {
+ if(*irl == srcRoute)
+ break;
+ }
+ if(irl != rl->end())
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ else
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ //iR->setDown(false); // pup->exec() catches mouse release event
+ return;
+
+ // p3.3.46
+ ///goto _redisplay;
+ }
+
+ iRouteMenuMap imm = gRoutingMenuMap.find(n);
+ if(imm == gRoutingMenuMap.end())
+ {
+ //delete pup;
+ //iR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ //int chan = n >> 16;
+ //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
+ //chan &= 0xffff;
+ //int chan = imm->second.channel;
+ //int chans = imm->second.channels;
+
+ //Route srcRoute(s, false, -1);
+ //Route srcRoute(s, false, -1, Route::TRACK_ROUTE);
+ Route &srcRoute = imm->second;
+
+ //Route dstRoute(t, -1);
+ //Route dstRoute(t, chan, chans);
+ Route dstRoute(t, imm->second.channel, imm->second.channels);
+ //Route dstRoute(t, imm->second.channel);
+ dstRoute.remoteChannel = imm->second.remoteChannel;
+
+ iRoute irl = rl->begin();
+ for (; irl != rl->end(); ++irl) {
+ if (*irl == srcRoute)
+ break;
+ }
+ if (irl != rl->end()) {
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ }
+ else {
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+ }
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+
+ // p3.3.46
+ //iR->setDown(false);
+ ///goto _redisplay;
+
+
+
+
+ }
+
+ }
+ */
+
+ }
+ //else
+ //{
+ //}
+
+ ///delete pup;
+ //oR->setDown(false);
+}
+
+//---------------------------------------------------------
+// routingPopupMenuAboutToHide
+//---------------------------------------------------------
+
+void MusE::routingPopupMenuAboutToHide()
+{
+ // p3.3.47
+ //printf("MusE::routingPopupMenuAboutToHide\n");
+ //if(track)
+ // printf("%s", track->name().latin1());
+ //printf("\n");
+
+ // Hmm, can't do this? Sub-menus stay open with this. Re-arranged, testing... Nope.
+ //PopupMenu* pup = muse->getRoutingPopupMenu();
+ //pup->disconnect();
+ //pup->clear();
+ gRoutingMenuMap.clear();
+ gRoutingPopupMenuMaster = 0;
+}
+
+//---------------------------------------------------------
+// prepareRoutingPopupMenu
+//---------------------------------------------------------
+
+PopupMenu* MusE::prepareRoutingPopupMenu(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);
+
+ PopupMenu* pup = getRoutingPopupMenu();
+ 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 wth 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);
+ PopupMenu* subp = new PopupMenu();
+ connect(subp, SIGNAL(activated(int)), pup, SIGNAL(activated(int)));
+ //connect(subp, SIGNAL(aboutToHide()), pup, SIGNAL(aboutToHide()));
+
+ for(int ch = 0; ch < MIDI_CHANNELS; ++ch)
+ {
+ //QAction* a = m->addAction(QString("Channel %1").arg(ch+1));
+ //subp->insertItem(QT_TR_NOOP(QString("Channel %1").arg(ch+1)), i * MIDI_CHANNELS + ch);
+ gid = i * MIDI_CHANNELS + ch;
+
+ //printf("MusE::prepareRoutingPopupMenu inserting gid:%d\n", gid);
+
+ int id = subp->insertItem(QString("Channel %1").arg(ch+1), gid);
+ //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);
+ gRoutingMenuMap.insert( pRouteMenuMap(id, srcRoute) );
+ for(iRoute ir = rl->begin(); ir != rl->end(); ++ir)
+ {
+ //if(*ir == dst)
+ if(*ir == srcRoute)
+ {
+ subp->setItemChecked(id, true);
+ break;
+ }
+ }
+ }
+ pup->insertItem(QT_TR_NOOP(md->name()), subp);
+ }
+
+ /*
+ 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").latin1(), 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->insertSeparator();
+ }
+ */
+
+ if(pup->count() == 0)
+ {
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ //pup->clear();
+ //pup->disconnect();
+ gRoutingMenuMap.clear();
+ //oR->setDown(false);
+ return 0;
+ }
+
+ gIsOutRoutingPopupMenu = dst;
+ return pup;
+ }
+
+ return 0;
+}
+
+//---------------------------------------------------------
// saveAs
//---------------------------------------------------------
@@ -2758,7 +3350,15 @@ int main(int argc, char* argv[])
}
#endif /* HAVE_LASH */
QTimer::singleShot(100, muse, SLOT(showDidYouKnowDialog()));
+
return app.exec();
+ // p3.3.47
+ //int rv = app.exec();
+ // FIXME: Can't do, seg fault at MarkerView::~MarkerView()
+ // due to already deleted undoRedo.
+ //delete muse;
+ //return rv;
+
}
#if 0
diff --git a/muse/muse/app.h b/muse/muse/app.h
index 64f10085..b1128400 100644
--- a/muse/muse/app.h
+++ b/muse/muse/app.h
@@ -29,6 +29,7 @@ class QListView;
class QListViewItem;
class QPoint;
class QToolButton;
+class PopupMenu;
class Track;
class PrinterConfig;
class MidiSyncConfig;
@@ -106,6 +107,9 @@ class MusE : public QMainWindow
QPopupMenu* menu_functions, *menuScriptPlugins;
QPopupMenu* select, *master, *midiEdit, *addTrack;
+ // Special 'stay-open' menu for routes.
+ PopupMenu* routingPopupMenu;
+
int aid1a, aid1b, aid2, aid3, autoId;
int tr_id, bt_id, mr_id;
int cc_id;
@@ -277,6 +281,9 @@ class MusE : public QMainWindow
void importMidi(const QString &file);
void setUsedTool(int);
void showDidYouKnowDialog();
+
+ void updateRouteMenus(Track* track);
+ void routingPopupMenuAboutToHide();
public:
MusE(int argc, char** argv);
@@ -300,6 +307,11 @@ class MusE : public QMainWindow
void showTransport(bool flag);
+ // Special 'stay-open' menu for routes.
+ PopupMenu* getRoutingPopupMenu();
+ PopupMenu* prepareRoutingPopupMenu(Track* /*track*/, bool /*dst*/);
+ void routingPopupMenuActivated(Track* /*track*/, int /*id*/);
+
#ifdef HAVE_LASH
void lash_idle_cb ();
#endif
diff --git a/muse/muse/arranger/arranger.h b/muse/muse/arranger/arranger.h
index ce738c11..360fad0c 100644
--- a/muse/muse/arranger/arranger.h
+++ b/muse/muse/arranger/arranger.h
@@ -169,6 +169,7 @@ class Arranger : public QWidget {
void verticalScrollSetYpos(unsigned);
void inRoutesPressed();
void outRoutesPressed();
+ void routingPopupMenuActivated(int /*id*/);
signals:
void redirectWheelEvent(QWheelEvent*);
diff --git a/muse/muse/arranger/pcanvas.cpp b/muse/muse/arranger/pcanvas.cpp
index 0027516c..acfa0464 100644
--- a/muse/muse/arranger/pcanvas.cpp
+++ b/muse/muse/arranger/pcanvas.cpp
@@ -19,7 +19,7 @@
#include <qpoint.h>
#include <qlineedit.h>
#include <qmessagebox.h>
-#include <qdragobject.h>>
+#include <qdragobject.h>
#include <qpopupmenu.h>
#include <qurl.h>
#include <qmenudata.h>
diff --git a/muse/muse/arranger/trackinfo.cpp b/muse/muse/arranger/trackinfo.cpp
index bc1cf939..b94dec43 100644
--- a/muse/muse/arranger/trackinfo.cpp
+++ b/muse/muse/arranger/trackinfo.cpp
@@ -41,6 +41,7 @@
#include "icons.h"
#include "app.h"
#include "route.h"
+#include "popupmenu.h"
//---------------------------------------------------------
@@ -563,6 +564,18 @@ void Arranger::iInputPortChanged(const QString& s)
*/
//---------------------------------------------------------
+// routingPopupMenuActivated
+//---------------------------------------------------------
+
+void Arranger::routingPopupMenuActivated(int n)
+{
+ //if(gRoutingPopupMenuMaster != this || !track || !track->isMidiTrack())
+ if(!midiTrackInfo || gRoutingPopupMenuMaster != midiTrackInfo || !selected || !selected->isMidiTrack())
+ return;
+ muse->routingPopupMenuActivated(selected, n);
+}
+
+//---------------------------------------------------------
// inRoutesPressed
//---------------------------------------------------------
@@ -571,7 +584,25 @@ void Arranger::inRoutesPressed()
if(!selected)
return;
- song->chooseMidiRoutes(midiTrackInfo->iRButton, (MidiTrack*)selected, false);
+ ///song->chooseMidiRoutes(midiTrackInfo->iRButton, (MidiTrack*)selected, false);
+
+ if(!selected->isMidiTrack())
+ return;
+
+ //song->chooseMidiRoutes(iR, (MidiTrack*)track, false);
+ PopupMenu* pup = muse->prepareRoutingPopupMenu(selected, false);
+ if(!pup)
+ return;
+
+ //pup->disconnect();
+ //gRoutingPopupMenuMaster = this;
+ gRoutingPopupMenuMaster = midiTrackInfo;
+ connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
+ // Nope, can't clear menu and mm list in there, sub-menus stay open. Never mind for now...
+ connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ pup->popup(QCursor::pos(), 0);
+ midiTrackInfo->iRButton->setDown(false);
+ return;
}
//---------------------------------------------------------
@@ -583,7 +614,25 @@ void Arranger::outRoutesPressed()
if(!selected)
return;
- song->chooseMidiRoutes(midiTrackInfo->oRButton, (MidiTrack*)selected, true);
+ ///song->chooseMidiRoutes(midiTrackInfo->oRButton, (MidiTrack*)selected, true);
+
+ if(!selected->isMidiTrack())
+ return;
+
+ //song->chooseMidiRoutes(iR, (MidiTrack*)track, false);
+ PopupMenu* pup = muse->prepareRoutingPopupMenu(selected, true);
+ if(!pup)
+ return;
+
+ //pup->disconnect();
+ //gRoutingPopupMenuMaster = this;
+ gRoutingPopupMenuMaster = midiTrackInfo;
+ connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
+ // Nope, can't clear menu and mm list in there, sub-menus stay open. Never mind for now...
+ connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ pup->popup(QCursor::pos(), 0);
+ midiTrackInfo->oRButton->setDown(false);
+ return;
}
//---------------------------------------------------------
@@ -1206,6 +1255,11 @@ void Arranger::updateMidiTrackInfo(int flags)
if(flags == SC_MIDI_CONTROLLER)
return;
+ // p3.3.47 Update the routing popup menu if anything relevant changes.
+ if(gRoutingPopupMenuMaster == midiTrackInfo && selected && (flags & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)))
+ // Use this handy shared routine.
+ muse->updateRouteMenus(selected);
+
// Added by Tim. p3.3.9
setTrackInfoLabelText();
setTrackInfoLabelFont();
diff --git a/muse/muse/audioprefetch.cpp b/muse/muse/audioprefetch.cpp
index e31dcc93..b2ddab8c 100644
--- a/muse/muse/audioprefetch.cpp
+++ b/muse/muse/audioprefetch.cpp
@@ -189,7 +189,7 @@ void AudioPrefetch::prefetch(bool doSeek)
float* bp[ch];
// printf("prefetch %d\n", writePos);
if (track->prefetchFifo()->getWriteBuffer(ch, segmentSize, bp, writePos)) {
- printf("AudioPrefetch::prefetch No write buffer!\n");
+ // printf("AudioPrefetch::prefetch No write buffer!\n"); // p3.3.46 Was getting this...
continue;
}
//track->fetchData(writePos, segmentSize, bp);
diff --git a/muse/muse/confmport.cpp b/muse/muse/confmport.cpp
index f03fe361..81c66c71 100644
--- a/muse/muse/confmport.cpp
+++ b/muse/muse/confmport.cpp
@@ -28,6 +28,7 @@
#include <qfiledialog.h>
#include <qtoolbutton.h>
#include <qmessagebox.h>
+#include <qpoint.h>
#include "confmport.h"
#include "app.h"
@@ -190,14 +191,16 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint& cpt, int col)
int gid = 0;
std::list<QString> sl;
- _redisplay:
- // Jack input ports if device is writable, and jack output ports if device is readable.
- sl = (dev->rwFlags() & 1) ? audioDevice->inputPorts(true, _showAliases) : audioDevice->outputPorts(true, _showAliases);
-
pup = new QPopupMenu(this);
pup->setCheckable(true);
+ _redisplay:
+ pup->clear();
gid = 0;
+
+ // Jack input ports if device is writable, and jack output ports if device is readable.
+ sl = (dev->rwFlags() & 1) ? audioDevice->inputPorts(true, _showAliases) : audioDevice->outputPorts(true, _showAliases);
+
//for (int i = 0; i < channel; ++i)
//{
//char buffer[128];
@@ -239,7 +242,7 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint& cpt, int col)
{
if(n == 0) // Show first aliases
{
- delete pup;
+ ///delete pup;
if(_showAliases == 0)
_showAliases = -1;
else
@@ -249,7 +252,7 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint& cpt, int col)
else
if(n == 1) // Show second aliases
{
- delete pup;
+ ///delete pup;
if(_showAliases == 1)
_showAliases = -1;
else
@@ -299,12 +302,18 @@ void MPConfig::rbClicked(QListViewItem* item, const QPoint& cpt, int col)
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
+
+ // p3.3.46
+ //delete pup;
+ // FIXME:
+ // Routes can't be re-read until the message sent from msgAddRoute1()
+ // has had time to be sent and actually affected the routes.
+ ///goto _redisplay; // Go back
+
}
delete pup;
//iR->setDown(false); // pup->exec() catches mouse release event
-
-
}
//break;
return;
diff --git a/muse/muse/globals.cpp b/muse/muse/globals.cpp
index 0c6c1dfa..68b704cf 100644
--- a/muse/muse/globals.cpp
+++ b/muse/muse/globals.cpp
@@ -10,6 +10,7 @@
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
+#include <qobject.h>
#include "globals.h"
#include "config.h"
@@ -339,6 +340,10 @@ unsigned char rcGotoLeftMarkNote = 33;
unsigned char rcPlayNote = 29;
bool automation = true;
+QObject* gRoutingPopupMenuMaster = 0;
+RouteMenuMap gRoutingMenuMap;
+bool gIsOutRoutingPopupMenu = false;
+
uid_t euid, ruid; // effective user id, real user id
bool midiSeqRunning = false;
diff --git a/muse/muse/globals.h b/muse/muse/globals.h
index 771769a2..e851264b 100644
--- a/muse/muse/globals.h
+++ b/muse/muse/globals.h
@@ -16,6 +16,7 @@
//#include <qaction.h>
#include "value.h"
#include "mtc.h"
+#include "route.h"
#include <unistd.h>
@@ -140,7 +141,7 @@ extern QAction* punchoutAction;
extern QAction* recordAction;
extern QAction* panicAction;
-class AudioMixerApp;
+//class AudioMixerApp;
class MusE;
//extern AudioMixerApp* audioMixer;
extern MusE* muse;
@@ -171,6 +172,15 @@ extern unsigned char rcPlayNote;
extern bool midiSeqRunning;
extern bool automation;
+class QObject;
+// Which audio strip, midi strip, or midi track info strip
+// was responsible for popping up the routing menu.
+extern QObject* gRoutingPopupMenuMaster;
+// Map of routing popup menu item IDs to Routes.
+extern RouteMenuMap gRoutingMenuMap;
+// Whether the routes popup was shown by clicking the output routes button, or input routes button.
+extern bool gIsOutRoutingPopupMenu;
+
extern uid_t euid, ruid;
extern void doSetuid();
extern void undoSetuid();
diff --git a/muse/muse/marker/markerview.cpp b/muse/muse/marker/markerview.cpp
index 75ee1a06..8cd9f0eb 100644
--- a/muse/muse/marker/markerview.cpp
+++ b/muse/muse/marker/markerview.cpp
@@ -261,6 +261,9 @@ MarkerView::MarkerView(QWidget* parent)
MarkerView::~MarkerView()
{
+ // p3.3.47
+ //printf("MarkerView::~MarkerView() before undoRedo->removeFrom(tools)\n");
+
undoRedo->removeFrom(tools);
}
diff --git a/muse/muse/mixer/astrip.cpp b/muse/muse/mixer/astrip.cpp
index da06ad63..a565e7d4 100644
--- a/muse/muse/mixer/astrip.cpp
+++ b/muse/muse/mixer/astrip.cpp
@@ -17,12 +17,15 @@
#include <qcombobox.h>
#include <qtooltip.h>
#include <qtimer.h>
-#include <qpopupmenu.h>
+//#include <qpopupmenu.h>
#include <qcursor.h>
-#include <qmenudata.h>
#include <qpainter.h>
#include <qstring.h>
+#include <qpoint.h>
+#include <qevent.h>
+#include <qwidget.h>
+#include "app.h"
#include "globals.h"
#include "audio.h"
#include "driver/audiodev.h"
@@ -34,7 +37,7 @@
#include "astrip.h"
#include "track.h"
#include "synth.h"
-#include "route.h"
+//#include "route.h"
#include "doublelabel.h"
#include "rack.h"
#include "node.h"
@@ -43,6 +46,7 @@
#include "gconfig.h"
#include "ttoolbutton.h"
#include "menutitleitem.h"
+#include "popupmenu.h"
/*
//---------------------------------------------------------
@@ -141,6 +145,12 @@ void AudioStrip::songChanged(int val)
// Do channels before config...
if (val & SC_CHANNELS)
updateChannels();
+
+ // p3.3.47
+ // Update the routing popup menu if anything relevant changed.
+ if (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG))
+ updateRouteMenus();
+
// Catch when label font, or configuration min slider and meter values change.
if (val & SC_CONFIG)
{
@@ -247,7 +257,6 @@ void AudioStrip::updateVolume()
double vol = ((AudioTrack*)track)->volume();
if (vol != volume)
{
- // Added by Tim. p3.3.6
//printf("AudioStrip::updateVolume setting slider and label\n");
slider->blockSignals(true);
@@ -270,7 +279,6 @@ void AudioStrip::updatePan()
double v = ((AudioTrack*)track)->pan();
if (v != panVal)
{
- // Added by Tim. p3.3.6
//printf("AudioStrip::updatePan setting slider and label\n");
pan->blockSignals(true);
@@ -551,7 +559,6 @@ void AudioStrip::updateChannels()
{
AudioTrack* t = (AudioTrack*)track;
int c = t->channels();
- // Added by Tim. p3.3.6
//printf("AudioStrip::updateChannels track channels:%d current channels:%d\n", c, channel);
if (c > channel) {
@@ -676,8 +683,9 @@ AudioStrip::~AudioStrip()
AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at)
: Strip(parent, at)
{
- iR = 0;
- oR = 0;
+ //iR = 0;
+ //oR = 0;
+
off = 0;
volume = -1.0;
@@ -963,7 +971,7 @@ AudioStrip::AudioStrip(QWidget* parent, AudioTrack* at)
// addMenuItem
//---------------------------------------------------------
-static int addMenuItem(QButton* /*parent*/, AudioTrack* track, Track* route_track, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addMenuItem(AudioTrack* track, Track* route_track, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
// totalInChannels is only used by syntis.
//int channels = (!isOutput || route_track->type() != Track::AUDIO_SOFTSYNTH) ? ((AudioTrack*)route_track)->totalOutChannels() : ((AudioTrack*)route_track)->totalInChannels();
@@ -974,7 +982,7 @@ static int addMenuItem(QButton* /*parent*/, AudioTrack* track, Track* route_trac
toch = 1;
// totalInChannels is only used by syntis.
- int chans = (isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels();
+ ///int chans = (isOutput || track->type() != Track::AUDIO_SOFTSYNTH) ? toch : ((AudioTrack*)track)->totalInChannels();
// Don't add the last stray mono route if the track is stereo.
//if(route_track->channels() > 1 && (channel+1 == chans))
@@ -1050,15 +1058,15 @@ static int addMenuItem(QButton* /*parent*/, AudioTrack* track, Track* route_trac
// addAuxPorts
//---------------------------------------------------------
-//static void addAuxPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
-static int addAuxPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addAuxPorts(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
AuxList* al = song->auxs();
for (iAudioAux i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
- id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ //id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ id = addMenuItem(t, track, lb, id, mm, channel, channels, isOutput);
/*
QString s(track->name());
@@ -1083,15 +1091,15 @@ static int addAuxPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, R
// addInPorts
//---------------------------------------------------------
-//static void addInPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
-static int addInPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addInPorts(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
InputList* al = song->inputs();
for (iAudioInput i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
- id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ //id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ id = addMenuItem(t, track, lb, id, mm, channel, channels, isOutput);
/*
QString s(track->name());
@@ -1116,15 +1124,15 @@ static int addInPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, Ro
// addOutPorts
//---------------------------------------------------------
-//static void addOutPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
-static int addOutPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addOutPorts(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
OutputList* al = song->outputs();
for (iAudioOutput i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
- id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ //id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ id = addMenuItem(t, track, lb, id, mm, channel, channels, isOutput);
/*
QString s(track->name());
@@ -1149,15 +1157,15 @@ static int addOutPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, R
// addGroupPorts
//---------------------------------------------------------
-//static void addGroupPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
-static int addGroupPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addGroupPorts(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
GroupList* al = song->groups();
for (iAudioGroup i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
- id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ //id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ id = addMenuItem(t, track, lb, id, mm, channel, channels, isOutput);
/*
QString s(track->name());
@@ -1182,15 +1190,15 @@ static int addGroupPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id,
// addWavePorts
//---------------------------------------------------------
-//static void addWavePorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
-static int addWavePorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addWavePorts(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
WaveTrackList* al = song->waves();
for (iWaveTrack i = al->begin(); i != al->end(); ++i) {
Track* track = *i;
if (t == track)
continue;
- id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ //id = addMenuItem(parent, t, track, lb, id, mm, channel, channels, isOutput);
+ id = addMenuItem(t, track, lb, id, mm, channel, channels, isOutput);
/*
QString s(track->name());
@@ -1215,8 +1223,8 @@ static int addWavePorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id,
// addSyntiPorts
//---------------------------------------------------------
-//static void addSyntiPorts(AudioTrack* t, QPopupMenu* lb, RouteList* r)
-static int addSyntiPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
+static int addSyntiPorts(AudioTrack* t, PopupMenu* lb, int id,
+ RouteMenuMap& mm, int channel, int channels, bool isOutput)
{
RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes();
@@ -1269,7 +1277,12 @@ static int addSyntiPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id,
if(chans > 0)
{
- QPopupMenu* chpup = new QPopupMenu(parent);
+ //QPopupMenu* chpup = new QPopupMenu(parent);
+ //PopupMenu* chpup = new PopupMenu(parent);
+ //PopupMenu* chpup = new PopupMenu(lb->parent());
+ PopupMenu* chpup = new PopupMenu();
+ //strip->connect(chpup, SIGNAL(activated(int)), strip, SLOT(routingPopupMenuActivated(int)));
+ lb->connect(chpup, SIGNAL(activated(int)), lb, SIGNAL(activated(int)));
chpup->setCheckable(true);
for(int ch = 0; ch < chans; ++ch)
{
@@ -1337,7 +1350,7 @@ static int addSyntiPorts(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id,
// addMultiChannelOutPorts
//---------------------------------------------------------
-static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup, int id, RouteMenuMap& mm, bool isOutput)
+static int addMultiChannelPorts(AudioTrack* t, PopupMenu* pup, int id, RouteMenuMap& mm, bool isOutput)
{
int toch = t->totalOutChannels();
// If track channels = 1, it must be a mono synth. And synti channels cannot be changed by user.
@@ -1365,14 +1378,21 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
// If it's more than one channel, create a sub-menu. If it's just one channel, don't bother with a sub-menu...
//
- QPopupMenu* chpup = pup;
+ //QPopupMenu* chpup = pup;
+ PopupMenu* chpup = pup;
for(int ch = 0; ch < chans; ++ch)
{
// If more than one channel, create the sub-menu.
if(chans > 1)
{
- chpup = new QPopupMenu(parent);
+ //chpup = new QPopupMenu(parent);
+ //chpup = new PopupMenu(parent);
+ //chpup = new PopupMenu(pup->parent());
+ chpup = new PopupMenu();
+ //connect(chpup, SIGNAL(activated(int)), strip, SLOT(oRouteMenuActivated(int)));
+ //strip->connect(chpup, SIGNAL(activated(int)), strip, SLOT(routingPopupMenuActivated(int)));
+ pup->connect(chpup, SIGNAL(activated(int)), pup, SIGNAL(activated(int)));
chpup->setCheckable(true);
}
@@ -1382,16 +1402,22 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
{
case Track::AUDIO_INPUT:
- id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput);
case Track::WAVE:
case Track::AUDIO_GROUP:
case Track::AUDIO_SOFTSYNTH:
- id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addOutPorts(t, chpup, id, mm, ch, 1, isOutput);
+ id = addGroupPorts(t, chpup, id, mm, ch, 1, isOutput);
+ //id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addSyntiPorts(strip, parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addSyntiPorts(t, chpup, id, mm, ch, 1, isOutput);
break;
case Track::AUDIO_AUX:
- id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addOutPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addOutPorts(t, chpup, id, mm, ch, 1, isOutput);
break;
default:
break;
@@ -1420,21 +1446,33 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
{
case Track::AUDIO_OUTPUT:
- id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addAuxPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addAuxPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput);
+ id = addInPorts(t, chpup, id, mm, ch, 1, isOutput);
+ id = addGroupPorts(t, chpup, id, mm, ch, 1, isOutput);
+ id = addAuxPorts(t, chpup, id, mm, ch, 1, isOutput);
+ //id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addSyntiPorts(strip, parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addSyntiPorts(t, chpup, id, mm, ch, 1, isOutput);
break;
case Track::WAVE:
- id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addInPorts(t, chpup, id, mm, ch, 1, isOutput);
break;
case Track::AUDIO_SOFTSYNTH:
case Track::AUDIO_GROUP:
- id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
- id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addWavePorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addInPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addGroupPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addWavePorts(t, chpup, id, mm, ch, 1, isOutput);
+ id = addInPorts(t, chpup, id, mm, ch, 1, isOutput);
+ id = addGroupPorts(t, chpup, id, mm, ch, 1, isOutput);
+ //id = addSyntiPorts(parent, t, chpup, id, mm, ch, 1, isOutput);
+ //id = addSyntiPorts(strip, parent, t, chpup, id, mm, ch, 1, isOutput);
+ id = addSyntiPorts(t, chpup, id, mm, ch, 1, isOutput);
break;
default:
break;
@@ -1499,7 +1537,12 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
// If more than two channels, create the sub-menu.
if(chans > 2)
{
- chpup = new QPopupMenu(parent);
+ //chpup = new QPopupMenu(parent);
+ //chpup = new PopupMenu(parent);
+ //chpup = new PopupMenu(pup->parent());
+ chpup = new PopupMenu();
+ //strip->connect(chpup, SIGNAL(activated(int)), strip, SLOT(routingPopupMenuActivated(int)));
+ pup->connect(chpup, SIGNAL(activated(int)), pup, SIGNAL(activated(int)));
chpup->setCheckable(true);
}
@@ -1508,16 +1551,22 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
switch(t->type())
{
case Track::AUDIO_INPUT:
- id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput);
case Track::WAVE:
case Track::AUDIO_GROUP:
case Track::AUDIO_SOFTSYNTH:
- id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addOutPorts(t, chpup, id, mm, ch, 2, isOutput);
+ id = addGroupPorts(t, chpup, id, mm, ch, 2, isOutput);
+ //id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addSyntiPorts(strip, parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addSyntiPorts(t, chpup, id, mm, ch, 2, isOutput);
break;
case Track::AUDIO_AUX:
- id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addOutPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addOutPorts(t, chpup, id, mm, ch, 2, isOutput);
break;
default:
break;
@@ -1528,21 +1577,33 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
switch(t->type())
{
case Track::AUDIO_OUTPUT:
- id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addAuxPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addAuxPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput);
+ id = addInPorts(t, chpup, id, mm, ch, 2, isOutput);
+ id = addGroupPorts(t, chpup, id, mm, ch, 2, isOutput);
+ id = addAuxPorts(t, chpup, id, mm, ch, 2, isOutput);
+ //id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addSyntiPorts(strip, parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addSyntiPorts(t, chpup, id, mm, ch, 2, isOutput);
break;
case Track::WAVE:
- id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addInPorts(t, chpup, id, mm, ch, 2, isOutput);
break;
case Track::AUDIO_SOFTSYNTH:
case Track::AUDIO_GROUP:
- id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
- id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addWavePorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addInPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addGroupPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addWavePorts(t, chpup, id, mm, ch, 2, isOutput);
+ id = addInPorts(t, chpup, id, mm, ch, 2, isOutput);
+ id = addGroupPorts(t, chpup, id, mm, ch, 2, isOutput);
+ //id = addSyntiPorts(parent, t, chpup, id, mm, ch, 2, isOutput);
+ //id = addSyntiPorts(strip, parent, t, chpup, id, mm, ch, 2, isOutput);
+ id = addSyntiPorts(t, chpup, id, mm, ch, 2, isOutput);
break;
default:
break;
@@ -1566,8 +1627,7 @@ static int addMultiChannelPorts(QButton* parent, AudioTrack* t, QPopupMenu* pup,
// nonSyntiTrackAddSyntis
//---------------------------------------------------------
-//static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, int channel, int channels, bool isOutput)
-static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb, int id, RouteMenuMap& mm, bool isOutput)
+static int nonSyntiTrackAddSyntis(AudioTrack* t, PopupMenu* lb, int id, RouteMenuMap& mm, bool isOutput)
{
RouteList* rl = isOutput ? t->outRoutes() : t->inRoutes();
@@ -1621,7 +1681,12 @@ static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb
if(chans > 0)
{
- QPopupMenu* chpup = new QPopupMenu(parent);
+ //QPopupMenu* chpup = new QPopupMenu(parent);
+ //PopupMenu* chpup = new PopupMenu(parent);
+ //PopupMenu* chpup = new PopupMenu(lb->parent());
+ PopupMenu* chpup = new PopupMenu();
+ //strip->connect(chpup, SIGNAL(activated(int)), strip, SLOT(routingPopupMenuActivated(int)));
+ lb->connect(chpup, SIGNAL(activated(int)), lb, SIGNAL(activated(int)));
chpup->setCheckable(true);
if(chans > 1)
@@ -1777,16 +1842,39 @@ static int nonSyntiTrackAddSyntis(QButton* parent, AudioTrack* t, QPopupMenu* lb
void AudioStrip::iRoutePressed()
{
//if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH))
- if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX))
+ if(!track || track->isMidiTrack() || track->type() == Track::AUDIO_AUX)
+ {
+ //_isRoutingPopupMenuMaster = false;
+ gRoutingPopupMenuMaster = 0;
return;
+ }
- QPopupMenu* pup = new QPopupMenu(iR);
+ QPoint ppt = QCursor::pos();
+
+ //QPopupMenu* pup = new QPopupMenu(iR);
+ //PopupMenu* pup = new PopupMenu(iR);
//pup->setCheckable(true);
+
+ PopupMenu* pup = muse->getRoutingPopupMenu();
+ pup->disconnect();
+
AudioTrack* t = (AudioTrack*)track;
RouteList* irl = t->inRoutes();
int gid = 0;
- RouteMenuMap mm;
+ //int n;
+ ///RouteMenuMap mm;
+
+ // Routes can't be re-read until the message sent from msgAddRoute1()
+ // has had time to be sent and actually affected the routes.
+ ///_redisplay:
+
+ //QPopupMenu* pup = new QPopupMenu(iR);
+ //RouteList* irl = t->inRoutes();
+
+ pup->clear();
+ gRoutingMenuMap.clear();
+ gid = 0;
switch(track->type())
{
@@ -1803,7 +1891,11 @@ void AudioStrip::iRoutePressed()
if(!checkAudioDevice())
{
- delete pup;
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ pup->clear();
+ gRoutingMenuMap.clear();
+ iR->setDown(false);
return;
}
std::list<QString> ol = audioDevice->outputPorts();
@@ -1812,6 +1904,7 @@ void AudioStrip::iRoutePressed()
int id = pup->insertItem(*ip, (gid * 16) + i);
//Route dst(*ip, true, i);
Route dst(*ip, true, i, Route::JACK_ROUTE);
+ gRoutingMenuMap.insert( pRouteMenuMap(id, dst) );
++gid;
for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)
{
@@ -1827,53 +1920,85 @@ void AudioStrip::iRoutePressed()
}
}
break;
- /*
- case Track::AUDIO_OUTPUT:
- case Track::WAVE:
- case Track::AUDIO_GROUP:
- */
+ //case Track::AUDIO_OUTPUT:
+ //case Track::WAVE:
+ //case Track::AUDIO_GROUP:
case Track::AUDIO_OUTPUT:
- gid = addWavePorts( iR, t, pup, gid, mm, -1, -1, false);
- gid = addInPorts( iR, t, pup, gid, mm, -1, -1, false);
- gid = addGroupPorts(iR, t, pup, gid, mm, -1, -1, false);
- gid = addAuxPorts( iR, t, pup, gid, mm, -1, -1, false);
- //gid = addSyntiPorts(iR, t, pup, gid, mm, -1, -1, false);
- gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, mm, false);
+ //gid = addWavePorts( iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addInPorts( iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addGroupPorts(iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addAuxPorts( iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addInPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addGroupPorts(t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addAuxPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addSyntiPorts(iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, gRoutingMenuMap, false);
+ //gid = nonSyntiTrackAddSyntis(this, iR, t, pup, gid, gRoutingMenuMap, false);
+ gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, false);
break;
case Track::WAVE:
- gid = addInPorts( iR, t, pup, gid, mm, -1, -1, false);
+ //gid = addInPorts( iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addInPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false);
break;
case Track::AUDIO_GROUP:
- gid = addWavePorts( iR, t, pup, gid, mm, -1, -1, false);
- gid = addInPorts( iR, t, pup, gid, mm, -1, -1, false);
- gid = addGroupPorts(iR, t, pup, gid, mm, -1, -1, false);
- //gid = addSyntiPorts(iR, t, pup, gid, mm, -1, -1, false);
- gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, mm, false);
+ //gid = addWavePorts( iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addInPorts( iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addGroupPorts(iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addInPorts( t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ gid = addGroupPorts(t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = addSyntiPorts(iR, t, pup, gid, gRoutingMenuMap, -1, -1, false);
+ //gid = nonSyntiTrackAddSyntis(iR, t, pup, gid, gRoutingMenuMap, false);
+ //gid = nonSyntiTrackAddSyntis(this, iR, t, pup, gid, gRoutingMenuMap, false);
+ gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, false);
break;
case Track::AUDIO_SOFTSYNTH:
- gid = addMultiChannelPorts(iR, t, pup, gid, mm, false);
+ //gid = addMultiChannelPorts(iR, t, pup, gid, gRoutingMenuMap, false);
+ //gid = addMultiChannelPorts(this, iR, t, pup, gid, gRoutingMenuMap, false);
+ gid = addMultiChannelPorts(t, pup, gid, gRoutingMenuMap, false);
break;
default:
- delete pup;
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ pup->clear();
+ gRoutingMenuMap.clear();
+ iR->setDown(false);
return;
}
if(pup->count() == 0)
{
- delete pup;
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ gRoutingMenuMap.clear();
+ iR->setDown(false);
return;
}
- int n = pup->exec(QCursor::pos());
+ gIsOutRoutingPopupMenu = false;
+ gRoutingPopupMenuMaster = this;
+ connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
+ connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ pup->popup(ppt, 0);
+ iR->setDown(false);
+ return;
+
+
+
+ /*
+ //int n = pup->exec(QCursor::pos());
+ // For some reason, after the first display, it won't redisplay at the same point if the menu is too high.
+ n = pup->exec(ppt, 0);
if(n != -1)
{
QString s(pup->text(n));
if(track->type() == Track::AUDIO_INPUT)
{
- delete pup;
+ ///delete pup;
int chan = n & 0xf;
Route srcRoute(s, false, -1, Route::JACK_ROUTE);
@@ -1898,6 +2023,9 @@ void AudioStrip::iRoutePressed()
song->update(SC_ROUTE);
iR->setDown(false); // pup->exec() catches mouse release event
return;
+
+ // p3.3.46
+ ///goto _redisplay;
}
iRouteMenuMap imm = mm.find(n);
@@ -1939,112 +2067,140 @@ void AudioStrip::iRoutePressed()
}
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
+
+ // p3.3.46
+ //iR->setDown(false); // pup->exec() catches mouse release event
+ ///goto _redisplay;
+
}
+
delete pup;
iR->setDown(false); // pup->exec() catches mouse release event
+ */
+
}
//---------------------------------------------------------
-// oRoutePressed
+// updateRouteMenus
//---------------------------------------------------------
-void AudioStrip::oRoutePressed()
+void AudioStrip::updateRouteMenus()
{
- if(track->isMidiTrack())
+ //if(!_isRoutingPopupMenuMaster || track->isMidiTrack() || (track->type() == Track::AUDIO_AUX))
+ if(!track || gRoutingPopupMenuMaster != this || track->isMidiTrack() || track->type() == Track::AUDIO_AUX)
+ return;
+
+ ///QPopupMenu* pup = new QPopupMenu(oR);
+ // p3.3.47
+ //if(!orpup)
+ // return;
+
+ //QPopupMenu* pup = muse->getORoutesPopup();
+ PopupMenu* pup = muse->getRoutingPopupMenu();
+
+ if(pup->count() == 0)
return;
- QPopupMenu* pup = new QPopupMenu(oR);
//pup->setCheckable(true);
AudioTrack* t = (AudioTrack*)track;
- RouteList* orl = t->outRoutes();
+ RouteList* rl = gIsOutRoutingPopupMenu ? t->outRoutes() : t->inRoutes();
- int gid = 0;
- RouteMenuMap mm;
+ //int gid = 0;
+ //int n;
+ ///RouteMenuMap mm;
- switch(track->type())
+ //QPoint ppt = QCursor::pos();
+
+
+ /*
+ iRoute iorl = orl->begin();
+ for(; iorl != orl->end(); ++iorl)
{
- case Track::AUDIO_OUTPUT:
+ iRouteMenuMap imm = ormm->begin();
+ for(; imm != ormm->end(); ++imm)
{
- pup->setCheckable(true);
- //int gid = 0;
- for(int i = 0; i < channel; ++i)
+ if(*iorl == imm->second)
{
- char buffer[128];
- snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
- MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
- pup->insertItem(titel);
-
- if(!checkAudioDevice())
- {
- delete pup;
- return;
- }
- std::list<QString> ol = audioDevice->inputPorts();
- 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);
- Route dst(*ip, true, i, Route::JACK_ROUTE);
- ++gid;
- for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)
- {
- if(*ir == dst)
- {
- pup->setItemChecked(id, true);
- break;
- }
- }
- }
- if(i+1 != channel)
- pup->insertSeparator();
- }
+ orpup->setItemChecked(imm->first, true);
+ break;
+ }
}
- break;
- /*
- case Track::AUDIO_INPUT:
- case Track::WAVE:
- case Track::AUDIO_GROUP:
- case Track::AUDIO_AUX:
- */
-
- case Track::AUDIO_SOFTSYNTH:
- //addOutPorts(t, pup, orl);
- //addGroupPorts(t, pup, orl);
- gid = addMultiChannelPorts(oR, t, pup, gid, mm, true);
- break;
+ //if(imm == ormm->end())
+ //{
+ //}
- case Track::AUDIO_INPUT:
- gid = addWavePorts( oR, t, pup, gid, mm, -1, -1, true);
- case Track::WAVE:
- case Track::AUDIO_GROUP:
- //case Track::AUDIO_SOFTSYNTH:
- gid = addOutPorts( oR, t, pup, gid, mm, -1, -1, true);
- gid = addGroupPorts( oR, t, pup, gid, mm, -1, -1, true);
- //gid = addSyntiPorts( oR, t, pup, gid, mm, -1, -1, true);
- gid = nonSyntiTrackAddSyntis(oR, t, pup, gid, mm, true);
- break;
- case Track::AUDIO_AUX:
- gid = addOutPorts( oR, t, pup, gid, mm, -1, -1, true);
- break;
-
- default:
- delete pup;
- return;
}
+ //if (iorl == orl->end())
+ //{
+ //}
+ */
+
+ iRouteMenuMap imm = gRoutingMenuMap.begin();
+ for(; imm != gRoutingMenuMap.end(); ++imm)
+ {
+ bool found = false;
+ iRoute irl = rl->begin();
+ for(; irl != rl->end(); ++irl)
+ {
+ if(*irl == imm->second)
+ {
+ found = true;
+ break;
+ }
+ }
+ pup->setItemChecked(imm->first, found);
+ }
+
+ return;
+}
+
+//---------------------------------------------------------
+// routingPopupMenuActivated
+//---------------------------------------------------------
+
+void AudioStrip::routingPopupMenuActivated(int n)
+{
+ if(!track || gRoutingPopupMenuMaster != this || track->isMidiTrack() || track->type() == Track::AUDIO_AUX)
+ return;
+
+ PopupMenu* pup = muse->getRoutingPopupMenu();
+
+ //printf("AudioStrip::routingPopupMenuActivated n:%d count:%d\n", n, pup->count());
if(pup->count() == 0)
+ return;
+
+ AudioTrack* t = (AudioTrack*)track;
+ RouteList* rl = gIsOutRoutingPopupMenu ? t->outRoutes() : t->inRoutes();
+
+ //QPoint ppt = QCursor::pos();
+
+ // p3.3.47
+ if (n == -1)
{
- delete pup;
+ //printf("AudioStrip::routingPopupMenuActivated n = -1\n");
+ ///delete pup;
return;
}
-
- int n = pup->exec(QCursor::pos());
- if (n != -1) {
+ else
+ //if(n == 0)
+ //{
+ //printf("AudioStrip::routingPopupMenuActivated n = 0 = tearOffHandle\n");
+ //oR->setDown(false);
+ // return;
+ //}
+ //else
+ {
+ if(gIsOutRoutingPopupMenu)
+ {
QString s(pup->text(n));
+ //printf("AudioStrip::routingPopupMenuActivated text:%s\n", s.latin1());
+
if(track->type() == Track::AUDIO_OUTPUT)
{
- delete pup;
+ ///delete orpup;
+
int chan = n & 0xf;
//Route srcRoute(t, -1);
@@ -2061,12 +2217,12 @@ void AudioStrip::oRoutePressed()
//dstRoute.channels = 1;
// check if route src->dst exists:
- iRoute iorl = orl->begin();
- for (; iorl != orl->end(); ++iorl) {
- if (*iorl == dstRoute)
+ iRoute irl = rl->begin();
+ for (; irl != rl->end(); ++irl) {
+ if (*irl == dstRoute)
break;
}
- if (iorl != orl->end()) {
+ if (irl != rl->end()) {
// disconnect if route exists
audio->msgRemoveRoute(srcRoute, dstRoute);
}
@@ -2076,15 +2232,22 @@ void AudioStrip::oRoutePressed()
}
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
- oR->setDown(false); // pup->exec() catches mouse release event
+
+ // p3.3.47
+ //pup->popup(ppt, 0);
+
+ //oR->setDown(false);
return;
+
+ // p3.3.46
+ ///goto _redisplay;
}
- iRouteMenuMap imm = mm.find(n);
- if(imm == mm.end())
+ iRouteMenuMap imm = gRoutingMenuMap.find(n);
+ if(imm == gRoutingMenuMap.end())
{
- delete pup;
- oR->setDown(false); // pup->exec() catches mouse release event
+ ///delete orpup;
+ //oR->setDown(false); // orpup->exec() catches mouse release event
return;
}
@@ -2106,12 +2269,12 @@ void AudioStrip::oRoutePressed()
Route &dstRoute = imm->second;
// check if route src->dst exists:
- iRoute iorl = orl->begin();
- for (; iorl != orl->end(); ++iorl) {
- if (*iorl == dstRoute)
+ iRoute irl = rl->begin();
+ for (; irl != rl->end(); ++irl) {
+ if (*irl == dstRoute)
break;
}
- if (iorl != orl->end()) {
+ if (irl != rl->end()) {
// disconnect if route exists
audio->msgRemoveRoute(srcRoute, dstRoute);
}
@@ -2121,83 +2284,80 @@ void AudioStrip::oRoutePressed()
}
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
- }
- delete pup;
- oR->setDown(false); // pup->exec() catches mouse release event
-}
-
-/*
-//---------------------------------------------------------
-// iRoutePressed
-//---------------------------------------------------------
-
-void AudioStrip::iRoutePressed()
- {
- if(track->isMidiTrack() || (track->type() == Track::AUDIO_AUX) || (track->type() == Track::AUDIO_SOFTSYNTH))
- return;
-
- QPopupMenu* pup = new QPopupMenu(iR);
- //pup->setCheckable(true);
- AudioTrack* t = (AudioTrack*)track;
- RouteList* irl = t->inRoutes();
-
- RouteMenuMap mm;
-
- if(track->type() == Track::AUDIO_INPUT)
- {
- pup->setCheckable(true);
- int gid = 0;
- for(int i = 0; i < channel; ++i)
- {
- char buffer[128];
- snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
- MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
- pup->insertItem(titel);
-
- if(!checkAudioDevice())
- {
- delete pup;
- return;
- }
- std::list<QString> ol = audioDevice->outputPorts();
- for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
+
+ // p3.3.46
+ //oR->setDown(false);
+ ///goto _redisplay;
+
+ // p3.3.47
+ //pup->popup(ppt, 0);
+ }
+ else
{
- int id = pup->insertItem(*ip, (gid * 16) + i);
- //Route dst(*ip, true, i);
- Route dst(*ip, true, i, Route::JACK_ROUTE);
- ++gid;
- for(iRoute ir = irl->begin(); ir != irl->end(); ++ir)
+ QString s(pup->text(n));
+
+ if(track->type() == Track::AUDIO_INPUT)
{
- if(*ir == dst)
+ ///delete pup;
+ int chan = n & 0xf;
+
+ Route srcRoute(s, false, -1, Route::JACK_ROUTE);
+ Route dstRoute(t, chan);
+
+ srcRoute.channel = chan;
+
+ iRoute irl = rl->begin();
+ for(; irl != rl->end(); ++irl)
{
- pup->setItemChecked(id, true);
- break;
+ if(*irl == srcRoute)
+ break;
}
+ if(irl != rl->end())
+ // disconnect
+ audio->msgRemoveRoute(srcRoute, dstRoute);
+ else
+ // connect
+ audio->msgAddRoute(srcRoute, dstRoute);
+
+ audio->msgUpdateSoloStates();
+ song->update(SC_ROUTE);
+ //iR->setDown(false); // pup->exec() catches mouse release event
+ return;
+
+ // p3.3.46
+ ///goto _redisplay;
}
- }
- if(i+1 != channel)
- pup->insertSeparator();
- }
- }
- else
- addMultiChannelOutPorts(iR, t, pup, irl, mm, false);
-
- int n = pup->exec(QCursor::pos());
- if (n != -1) {
- QString s(pup->text(n));
+
+ iRouteMenuMap imm = gRoutingMenuMap.find(n);
+ if(imm == gRoutingMenuMap.end())
+ {
+ //delete pup;
+ //iR->setDown(false); // pup->exec() catches mouse release event
+ return;
+ }
+
+ //int chan = n >> 16;
+ //int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
+ //chan &= 0xffff;
+ //int chan = imm->second.channel;
+ //int chans = imm->second.channels;
//Route srcRoute(s, false, -1);
- Route srcRoute(s, false, -1, (track->type() == Track::AUDIO_INPUT) ? Route::JACK_ROUTE : Route::TRACK_ROUTE);
- Route dstRoute(t, -1);
+ //Route srcRoute(s, false, -1, Route::TRACK_ROUTE);
+ Route &srcRoute = imm->second;
+
+ //Route dstRoute(t, -1);
+ //Route dstRoute(t, chan, chans);
+ Route dstRoute(t, imm->second.channel, imm->second.channels);
+ //Route dstRoute(t, imm->second.channel);
+ dstRoute.remoteChannel = imm->second.remoteChannel;
- if (track->type() == Track::AUDIO_INPUT)
- srcRoute.channel = dstRoute.channel = n & 0xf;
- iRoute iir = irl->begin();
- for (; iir != irl->end(); ++iir) {
- if (*iir == srcRoute)
+ iRoute irl = rl->begin();
+ for (; irl != rl->end(); ++irl) {
+ if (*irl == srcRoute)
break;
}
- if (iir != irl->end()) {
+ if (irl != rl->end()) {
// disconnect
audio->msgRemoveRoute(srcRoute, dstRoute);
}
@@ -2207,80 +2367,190 @@ void AudioStrip::iRoutePressed()
}
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
- }
- delete pup;
- iR->setDown(false); // pup->exec() catches mouse release event
+
+ // p3.3.46
+ //iR->setDown(false);
+ ///goto _redisplay;
+
+ }
+
}
-*/
+
+ ///delete pup;
+ //oR->setDown(false);
+}
-/*
//---------------------------------------------------------
// oRoutePressed
//---------------------------------------------------------
void AudioStrip::oRoutePressed()
{
- if(track->isMidiTrack())
+ if(!track || track->isMidiTrack() || track->type() == Track::AUDIO_AUX)
+ {
+ gRoutingPopupMenuMaster = 0;
return;
+ }
- QPopupMenu* pup = new QPopupMenu(oR);
+ QPoint ppt = QCursor::pos();
+
+ ///QPopupMenu* pup = new QPopupMenu(oR);
+
+ PopupMenu* pup = muse->getRoutingPopupMenu();
+ pup->disconnect();
+
//pup->setCheckable(true);
AudioTrack* t = (AudioTrack*)track;
RouteList* orl = t->outRoutes();
- RouteMenuMap mm;
+ int gid = 0;
+ //int n;
+ ///RouteMenuMap mm;
+
+ // Routes can't be re-read until the message sent from msgAddRoute1()
+ // has had time to be sent and actually affected the routes.
+/// _redisplay:
+
+ //QPopupMenu* pup = new QPopupMenu(oR);
+ //RouteList* orl = t->outRoutes();
- if(track->type() == Track::AUDIO_OUTPUT)
+ pup->clear();
+ gRoutingMenuMap.clear();
+ gid = 0;
+
+ // p3.3.47
+ //orpup->insertTearOffHandle(gid);
+ //gid++;
+
+ switch(track->type())
{
- pup->setCheckable(true);
- int gid = 0;
- for(int i = 0; i < channel; ++i)
+ case Track::AUDIO_OUTPUT:
{
- char buffer[128];
- snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
- MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
- pup->insertItem(titel);
-
- if(!checkAudioDevice())
- {
- delete pup;
- return;
- }
- std::list<QString> ol = audioDevice->inputPorts();
- for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
+ pup->setCheckable(true);
+ //int gid = 0;
+ for(int i = 0; i < channel; ++i)
{
- int id = pup->insertItem(*ip, (gid * 16) + i);
- //Route dst(*ip, true, i);
- Route dst(*ip, true, i, Route::JACK_ROUTE);
- ++gid;
- for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)
+ char buffer[128];
+ snprintf(buffer, 128, "%s %d", tr("Channel").latin1(), i+1);
+ MenuTitleItem* titel = new MenuTitleItem(QString(buffer));
+ pup->insertItem(titel);
+
+ if(!checkAudioDevice())
+ {
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ pup->clear();
+ gRoutingMenuMap.clear();
+ oR->setDown(false);
+ return;
+ }
+ std::list<QString> ol = audioDevice->inputPorts();
+ for(std::list<QString>::iterator ip = ol.begin(); ip != ol.end(); ++ip)
{
- if(*ir == dst)
+ int id = pup->insertItem(*ip, (gid * 16) + i);
+ //Route dst(*ip, true, i);
+ Route dst(*ip, true, i, Route::JACK_ROUTE);
+ gRoutingMenuMap.insert( pRouteMenuMap(id, dst) );
+ ++gid;
+ for(iRoute ir = orl->begin(); ir != orl->end(); ++ir)
{
- pup->setItemChecked(id, true);
- break;
+ if(*ir == dst)
+ {
+ pup->setItemChecked(id, true);
+ break;
+ }
}
}
- }
- if(i+1 != channel)
- pup->insertSeparator();
- }
+ if(i+1 != channel)
+ pup->insertSeparator();
+ }
+ }
+ break;
+ //case Track::AUDIO_INPUT:
+ //case Track::WAVE:
+ //case Track::AUDIO_GROUP:
+ //case Track::AUDIO_AUX:
+
+ case Track::AUDIO_SOFTSYNTH:
+ //addOutPorts(t, pup, orl);
+ //addGroupPorts(t, pup, orl);
+ //gid = addMultiChannelPorts(oR, t, pup, gid, gRoutingMenuMap, true);
+ //gid = addMultiChannelPorts(this, oR, t, pup, gid, gRoutingMenuMap, true);
+ gid = addMultiChannelPorts(t, pup, gid, gRoutingMenuMap, true);
+ break;
+
+ case Track::AUDIO_INPUT:
+ //gid = addWavePorts( oR, t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ gid = addWavePorts( t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ case Track::WAVE:
+ case Track::AUDIO_GROUP:
+ //case Track::AUDIO_SOFTSYNTH:
+ //gid = addOutPorts( oR, t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ //gid = addGroupPorts( oR, t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ gid = addOutPorts( t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ gid = addGroupPorts( t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ //gid = addSyntiPorts( oR, t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ //gid = nonSyntiTrackAddSyntis(oR, t, pup, gid, gRoutingMenuMap, true);
+ //gid = nonSyntiTrackAddSyntis(this, oR, t, pup, gid, gRoutingMenuMap, true);
+ gid = nonSyntiTrackAddSyntis(t, pup, gid, gRoutingMenuMap, true);
+ break;
+ case Track::AUDIO_AUX:
+ //gid = addOutPorts( oR, t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ gid = addOutPorts( t, pup, gid, gRoutingMenuMap, -1, -1, true);
+ break;
+
+ default:
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ pup->clear();
+ gRoutingMenuMap.clear();
+ oR->setDown(false);
+ return;
}
- else
- addMultiChannelOutPorts(oR, t, pup, orl, mm, true);
- int n = pup->exec(QCursor::pos());
+ if(pup->count() == 0)
+ {
+ ///delete pup;
+ gRoutingPopupMenuMaster = 0;
+ gRoutingMenuMap.clear();
+ oR->setDown(false);
+ return;
+ }
+
+ //int n = pup->exec(QCursor::pos());
+ ///n = pup->exec(ppt);
+ gIsOutRoutingPopupMenu = true;
+ gRoutingPopupMenuMaster = this;
+ connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
+ connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ pup->popup(ppt, 0);
+ oR->setDown(false);
+ return;
+
+
+ /*
+ // p3.3.47
+ if(n == 0)
+ {
+ printf("AudioStrip::oRoutePressed n = 0 = tearOffHandle\n");
+ oR->setDown(false); // orpup->exec() catches mouse release event
+ return;
+ }
+ else
+
if (n != -1) {
- QString s(pup->text(n));
+ QString s(orpup->text(n));
if(track->type() == Track::AUDIO_OUTPUT)
{
- delete pup;
+ delete orpup;
+
int chan = n & 0xf;
//Route srcRoute(t, -1);
//Route srcRoute(t, chan, chans);
- Route srcRoute(t, chan, 1);
+ //Route srcRoute(t, chan, 1);
+ Route srcRoute(t, chan);
//Route dstRoute(s, true, -1);
Route dstRoute(s, true, -1, Route::JACK_ROUTE);
@@ -2288,7 +2558,7 @@ void AudioStrip::oRoutePressed()
//srcRoute.channel = dstRoute.channel = chan;
dstRoute.channel = chan;
- dstRoute.channels = 1;
+ //dstRoute.channels = 1;
// check if route src->dst exists:
iRoute iorl = orl->begin();
@@ -2306,29 +2576,38 @@ void AudioStrip::oRoutePressed()
}
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
- oR->setDown(false); // pup->exec() catches mouse release event
+
+ oR->setDown(false); // orpup->exec() catches mouse release event
return;
+
+ // p3.3.46
+ ///goto _redisplay;
}
- iRouteMenuMap imm = mm.find(n);
- if(imm == mm.end())
+ iRouteMenuMap imm = ormm.find(n);
+ if(imm == ormm.end())
{
- delete pup;
- oR->setDown(false); // pup->exec() catches mouse release event
+ delete orpup;
+ oR->setDown(false); // orpup->exec() catches mouse release event
return;
}
//int chan = n >> 16;
//int chans = (chan >> 15) + 1; // Bit 31 MSB: Mono or stereo.
//chan &= 0xffff;
- int chan = imm->second.channel;
- int chans = imm->second.channels;
-
+ //int chan = imm->second.channel;
+ //int chans = imm->second.channels;
+
//Route srcRoute(t, -1);
- Route srcRoute(t, chan, chans);
+ //srcRoute.remoteChannel = chan;
+ //Route srcRoute(t, chan, chans);
+ Route srcRoute(t, imm->second.channel, imm->second.channels);
+ //Route srcRoute(t, imm->second.channel);
+ srcRoute.remoteChannel = imm->second.remoteChannel;
//Route dstRoute(s, true, -1);
- Route dstRoute(s, true, -1, Route::TRACK_ROUTE);
+ //Route dstRoute(s, true, -1, Route::TRACK_ROUTE);
+ Route &dstRoute = imm->second;
// check if route src->dst exists:
iRoute iorl = orl->begin();
@@ -2346,11 +2625,17 @@ void AudioStrip::oRoutePressed()
}
audio->msgUpdateSoloStates();
song->update(SC_ROUTE);
+
+ // p3.3.46
+ //oR->setDown(false); // orpup->exec() catches mouse release event
+ ///goto _redisplay;
+
}
- delete pup;
+
+ delete orpup;
oR->setDown(false); // pup->exec() catches mouse release event
+ */
}
-*/
/*
//---------------------------------------------------------
diff --git a/muse/muse/mixer/astrip.h b/muse/muse/mixer/astrip.h
index e7b81538..29425fc4 100644
--- a/muse/muse/mixer/astrip.h
+++ b/muse/muse/mixer/astrip.h
@@ -12,11 +12,15 @@
#include <vector>
#include "strip.h"
+#include "route.h"
class Slider;
class Knob;
class QDialog;
class QToolButton;
+//class QPopupMenu;
+class PopupMenu;
+class QButton;
class TransparentToolButton;
class AudioTrack;
class DoubleLabel;
@@ -40,19 +44,21 @@ class AudioStrip : public Strip {
QToolButton* stereo;
QToolButton* pre;
+ TransparentToolButton* off;
double volume;
double panVal;
+ //QToolButton* iR;
+ //QToolButton* oR;
+
Knob* addKnob(int, int, DoubleLabel**);
- QToolButton* iR;
- QToolButton* oR;
- TransparentToolButton* off;
+
void updateOffState();
-
void updateVolume();
void updatePan();
void updateChannels();
+ void updateRouteMenus();
private slots:
void stereoToggled(bool);
@@ -60,6 +66,7 @@ class AudioStrip : public Strip {
void offToggled(bool);
void iRoutePressed();
void oRoutePressed();
+ void routingPopupMenuActivated(int /*id*/);
void auxChanged(double, int);
void volumeChanged(double);
void volumePressed();
diff --git a/muse/muse/mixer/mstrip.cpp b/muse/muse/mixer/mstrip.cpp
index a2cd26dd..eb656d4e 100644
--- a/muse/muse/mixer/mstrip.cpp
+++ b/muse/muse/mixer/mstrip.cpp
@@ -17,10 +17,11 @@
#include <qcombobox.h>
#include <qtooltip.h>
#include <qtimer.h>
-#include <qpopupmenu.h>
+//#include <qpopupmenu.h>
#include <qcursor.h>
#include <math.h>
+#include "app.h"
#include "midi.h"
#include "midictrl.h"
#include "mstrip.h"
@@ -41,6 +42,7 @@
#include "gconfig.h"
#include "ttoolbutton.h"
//#include "utils.h"
+#include "popupmenu.h"
enum { KNOB_PAN, KNOB_VAR_SEND, KNOB_REV_SEND, KNOB_CHO_SEND };
@@ -457,6 +459,11 @@ void MidiStrip::songChanged(int val)
//label->setFont(config.fonts[1]);
setLabelFont();
}
+
+ // p3.3.47 Update the routing popup menu if anything relevant changes.
+ if(gRoutingPopupMenuMaster == this && track && (val & (SC_ROUTE | SC_CHANNELS | SC_CONFIG)))
+ // Use this handy shared routine.
+ muse->updateRouteMenus(track);
}
//---------------------------------------------------------
@@ -611,7 +618,6 @@ void MidiStrip::updateControls()
//slider->blockSignals(true);
if(double(nvolume) != slider->value())
{
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting volume slider\n");
slider->setValue(double(nvolume));
@@ -623,7 +629,6 @@ void MidiStrip::updateControls()
int ivol = nvolume;
nvolume -= ctrl->bias();
if(nvolume != volume) {
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting volume slider\n");
//slider->blockSignals(true);
@@ -631,7 +636,6 @@ void MidiStrip::updateControls()
//sl->setValue(double(nvolume));
if(ivol == 0)
{
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting volume slider label\n");
sl->setValue(sl->minValue() - 0.5 * (sl->minValue() - sl->off()));
@@ -641,14 +645,12 @@ void MidiStrip::updateControls()
double v = -fast_log10(float(127*127)/float(ivol*ivol))*20.0;
if(v > sl->maxValue())
{
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting volume slider label\n");
sl->setValue(sl->maxValue());
}
else
{
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting volume slider label\n");
sl->setValue(v);
@@ -678,7 +680,6 @@ void MidiStrip::updateControls()
npan -= ctrl->bias();
if(double(npan) != gcon->knob->value())
{
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting pan knob\n");
gcon->knob->setValue(double(npan));
@@ -690,7 +691,6 @@ void MidiStrip::updateControls()
npan -= ctrl->bias();
if(npan != pan)
{
- // Added by Tim. p3.3.6
//printf("MidiStrip::updateControls setting pan label and knob\n");
//controller[KNOB_PAN].knob->blockSignals(true);
@@ -957,15 +957,37 @@ void MidiStrip::updateOffState() // Ripped from AudioStrip, hehh(mg)
}
//---------------------------------------------------------
+// routingPopupMenuActivated
+//---------------------------------------------------------
+
+void MidiStrip::routingPopupMenuActivated(int n)
+{
+ if(gRoutingPopupMenuMaster != this || !track || !track->isMidiTrack())
+ return;
+ muse->routingPopupMenuActivated(track, n);
+}
+
+//---------------------------------------------------------
// iRoutePressed
//---------------------------------------------------------
void MidiStrip::iRoutePressed()
{
- if(!track->isMidiTrack())
+ if(!track || !track->isMidiTrack())
+ return;
+
+ //song->chooseMidiRoutes(iR, (MidiTrack*)track, false);
+ PopupMenu* pup = muse->prepareRoutingPopupMenu(track, false);
+ if(!pup)
return;
- song->chooseMidiRoutes(iR, (MidiTrack*)track, false);
+ //pup->disconnect();
+ gRoutingPopupMenuMaster = this;
+ connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
+ connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ pup->popup(QCursor::pos(), 0);
+ iR->setDown(false);
+ return;
/*
RouteList* irl = track->inRoutes();
@@ -1087,10 +1109,21 @@ void MidiStrip::iRoutePressed()
void MidiStrip::oRoutePressed()
{
- if(!track->isMidiTrack())
+ if(!track || !track->isMidiTrack())
+ return;
+
+ //song->chooseMidiRoutes(oR, (MidiTrack*)track, true);
+ PopupMenu* pup = muse->prepareRoutingPopupMenu(track, true);
+ if(!pup)
return;
- song->chooseMidiRoutes(oR, (MidiTrack*)track, true);
+ //pup->disconnect();
+ gRoutingPopupMenuMaster = this;
+ connect(pup, SIGNAL(activated(int)), SLOT(routingPopupMenuActivated(int)));
+ connect(pup, SIGNAL(aboutToHide()), muse, SLOT(routingPopupMenuAboutToHide()));
+ pup->popup(QCursor::pos(), 0);
+ oR->setDown(false);
+ return;
/*
QPopupMenu* pup = new QPopupMenu(oR);
diff --git a/muse/muse/mixer/mstrip.h b/muse/muse/mixer/mstrip.h
index 460a7d65..65a0da86 100644
--- a/muse/muse/mixer/mstrip.h
+++ b/muse/muse/mixer/mstrip.h
@@ -29,8 +29,8 @@ class MidiStrip : public Strip {
Slider* slider;
DoubleLabel* sl;
//QToolButton* route;
- QToolButton* iR;
- QToolButton* oR;
+ //QToolButton* iR;
+ //QToolButton* oR;
struct KNOB {
Knob* knob;
@@ -54,6 +54,7 @@ class MidiStrip : public Strip {
//void routeClicked();
void iRoutePressed();
void oRoutePressed();
+ void routingPopupMenuActivated(int /*id*/);
void setVolume(double);
void setPan(double);
void setChorusSend(double);
diff --git a/muse/muse/mixer/strip.cpp b/muse/muse/mixer/strip.cpp
index e07f1d10..c4ab704b 100644
--- a/muse/muse/mixer/strip.cpp
+++ b/muse/muse/mixer/strip.cpp
@@ -167,10 +167,12 @@ void Strip::soloToggled(bool val)
Strip::Strip(QWidget* parent, Track* t)
: QFrame(parent, "Strip", Qt::WDestructiveClose)
{
+ iR = 0;
+ oR = 0;
+
setBackgroundMode(PaletteMid);
setFrameStyle(Panel | Raised);
setLineWidth(2);
-
useSoloIconSet2 = false;
track = t;
@@ -189,7 +191,6 @@ Strip::Strip(QWidget* parent, Track* t)
//setLabelText();
//label->setFont(config.fonts[1]);
- // Added by Tim. p3.3.9
//printf("Strip::Strip w:%d frw:%d layoutmarg:%d lx:%d ly:%d lw:%d lh:%d\n", STRIP_WIDTH, frameWidth(), layout->margin(), label->x(), label->y(), label->width(), label->height());
// Tested: The label's width is 100. It does not become STRIP_WIDTH - 2*layout->margin
@@ -232,4 +233,3 @@ void Strip::setAutomationType(int t,int)
song->update(SC_AUTOMATION);
}
-
diff --git a/muse/muse/mixer/strip.h b/muse/muse/mixer/strip.h
index 451a141d..3b2f7815 100644
--- a/muse/muse/mixer/strip.h
+++ b/muse/muse/mixer/strip.h
@@ -13,6 +13,7 @@
#include <qiconset.h>
#include "globaldefs.h"
+//#include "route.h"
class Track;
class QLabel;
@@ -37,10 +38,12 @@ class Strip : public QFrame {
QVBoxLayout* layout;
Meter* meter[MAX_CHANNELS];
bool useSoloIconSet2;
-
+
QToolButton* record;
QToolButton* solo;
QToolButton* mute;
+ QToolButton* iR; // Input routing button
+ QToolButton* oR; // Output routing button
QGridLayout* sliderGrid;
ComboBox* autoType;
void setLabelText();
diff --git a/muse/muse/song.cpp b/muse/muse/song.cpp
index bba86eb3..1b216e75 100644
--- a/muse/muse/song.cpp
+++ b/muse/muse/song.cpp
@@ -15,6 +15,7 @@
#include <qdir.h>
#include <qaction.h>
#include <qcursor.h>
+#include <qpoint.h>
#include <qbutton.h>
#include "app.h"
@@ -2790,6 +2791,7 @@ void Song::connectJackRoutes(AudioTrack* track, bool disconnect)
}
}
+/*
//---------------------------------------------------------
// chooseMidiRoutes
//---------------------------------------------------------
@@ -2802,6 +2804,9 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
//if(!track->isMidiTrack())
// return;
+ QPoint ppt = QCursor::pos();
+ //QPoint ppt = parent->rect().bottomLeft();
+
//if(dst)
//{
// TODO
@@ -2816,6 +2821,15 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
pup->setCheckable(true);
int gid = 0;
+ int n;
+
+ // FIXME:
+ // 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();
+ gid = 0;
//MidiInPortList* tl = song->midiInPorts();
//for(iMidiInPort i = tl->begin();i != tl->end(); ++i)
@@ -2865,38 +2879,36 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
pup->insertItem(QT_TR_NOOP(md->name()), subp);
}
- /*
- QPopupMenu* pup = new QPopupMenu(iR);
- pup->setCheckable(true);
+// 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").latin1(), 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->insertSeparator();
- }
- */
+// 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").latin1(), 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->insertSeparator();
+// }
if(pup->count() == 0)
{
@@ -2904,8 +2916,9 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
return;
}
- int n = pup->exec(QCursor::pos());
- delete pup;
+ //n = pup->exec(QCursor::pos());
+ n = pup->exec(ppt);
+ ///delete pup;
if (n != -1)
{
int mdidx = n / MIDI_CHANNELS;
@@ -2917,12 +2930,17 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
MidiPort* mp = &midiPorts[mdidx];
MidiDevice* md = mp->device();
if(!md)
+ {
+ delete pup;
return;
+ }
//if(!(md->rwFlags() & 2))
if(!(md->rwFlags() & (dst ? 1 : 2)))
+ {
+ delete pup;
return;
-
+ }
//QString s(pup->text(n));
//QT_TR_NOOP(md->name())
@@ -2944,17 +2962,17 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
}
if (iir != rl->end())
{
- // disconnect
- if(dst)
- {
- //printf("Song::chooseMidiRoutes removing route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1());
- audio->msgRemoveRoute(bRoute, aRoute);
- }
- else
- {
- //printf("Song::chooseMidiRoutes removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
- audio->msgRemoveRoute(aRoute, bRoute);
- }
+ // disconnect
+ if(dst)
+ {
+ //printf("Song::chooseMidiRoutes removing route src track name: %s dst device name: %s\n", track->name().latin1(), md->name().latin1());
+ audio->msgRemoveRoute(bRoute, aRoute);
+ }
+ else
+ {
+ //printf("Song::chooseMidiRoutes removing route src device name: %s dst track name: %s\n", md->name().latin1(), track->name().latin1());
+ audio->msgRemoveRoute(aRoute, bRoute);
+ }
}
else
{
@@ -2975,13 +2993,17 @@ void Song::chooseMidiRoutes(QButton* parent, MidiTrack* track, bool dst)
audio->msgUpdateSoloStates();
//printf("Song::chooseMidiRoutes calling song->update\n");
song->update(SC_ROUTE);
+
+ // p3.3.46
+ ///goto _redisplay;
}
- //delete pup;
+ delete pup;
parent->setDown(false); // pup->exec() catches mouse release event
//printf("Song::chooseMidiRoutes end\n");
//}
}
+*/
//---------------------------------------------------------
// insertTrack0
diff --git a/muse/muse/song.h b/muse/muse/song.h
index 369042b4..3a1d10cf 100644
--- a/muse/muse/song.h
+++ b/muse/muse/song.h
@@ -302,7 +302,7 @@ class Song : public QObject {
int execMidiAutomationCtlPopup(MidiTrack*, MidiPart*, const QPoint&, int);
void connectJackRoutes(AudioTrack* track, bool disconnect);
void updateSoloStates();
- void chooseMidiRoutes(QButton* /*parent*/, MidiTrack* /*track*/, bool /*dst*/);
+ //void chooseMidiRoutes(QButton* /*parent*/, MidiTrack* /*track*/, bool /*dst*/);
//-----------------------------------------
// undo, redo
diff --git a/muse/muse/widgets/Makefile.am b/muse/muse/widgets/Makefile.am
index f9c10037..9a551264 100644
--- a/muse/muse/widgets/Makefile.am
+++ b/muse/muse/widgets/Makefile.am
@@ -75,6 +75,7 @@ dist_libwidgets_a_SOURCES = \
combobox.cpp combobox.h \
checkbox.cpp checkbox.h \
aboutbox_impl.cpp aboutbox_impl.h \
+ popupmenu.cpp popupmenu.h \
listitem.h \
menutitleitem.h \
\
@@ -126,6 +127,7 @@ nodist_libwidgets_a_SOURCES = \
moc_swidget.cpp \
moc_tempolabel.cpp \
moc_tools.cpp \
+ moc_popupmenu.cpp \
moc_fontsel.cpp \
moc_ctrlcombo.cpp \
moc_sliderbase.cpp \
diff --git a/muse/muse/widgets/popupmenu.cpp b/muse/muse/widgets/popupmenu.cpp
new file mode 100644
index 00000000..27ad8b19
--- /dev/null
+++ b/muse/muse/widgets/popupmenu.cpp
@@ -0,0 +1,2760 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: popupmenu.cpp,v 1.1.1.1 2010/07/18 03:21:00 terminator356 Exp $
+//
+// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
+//
+// PopupMenu sub-class of QPopupMenu created by Tim.
+//=========================================================
+
+
+
+//=========================================================
+//
+// NOTICE: This sub-class of QPopupMenu *automatically* deletes
+// and *clears* any sub popup menus, when clear() is called.
+// Therefore a parent widget is *not* necessary when
+// creating sub popup menus to add to the popup.
+//
+//=========================================================
+
+
+// MusE: want no menu bar here. Can't use, not needed for now anyway.
+#define QT_NO_MENUBAR
+#define QT_NO_WHATSTHIS
+
+#include <qapplication.h>
+//#include <qtimer.h>
+#include <qguardedptr.h>
+//#include <qmenubar.h>
+//#include <qstyle.h>
+//#include <qdatetime.h>
+
+#include "popupmenu.h"
+
+// used to provide ONE single-shot timer
+//static QTimer * singleSingleShot = 0;
+//static bool preventAnimation = FALSE;
+// Used to detect motion prior to mouse-release
+static int motion;
+static PopupMenu* active_popup_menu = 0;
+
+/*
+static void cleanup()
+{
+ delete singleSingleShot;
+ singleSingleShot = 0;
+}
+
+static void popupSubMenuLater( int msec, QPopupMenu * receiver ) {
+//static void popupSubMenuLater( int msec, PopupMenu * receiver ) {
+ if ( !singleSingleShot ) {
+ singleSingleShot = new QTimer( qApp, "popup submenu timer" );
+ qAddPostRoutine( cleanup );
+ }
+
+ singleSingleShot->disconnect( SIGNAL(timeout()) );
+ QObject::connect( singleSingleShot, SIGNAL(timeout()),
+ receiver, SLOT(subMenuTimer()) );
+ singleSingleShot->start( msec, TRUE );
+}
+*/
+
+/*
+//======================
+// MenuDataData
+//======================
+
+class QMenuDataData {
+public:
+ QMenuDataData();
+ QGuardedPtr<QWidget> aWidget;
+ int aInt;
+};
+
+//======================
+// QPopupMenuPrivate
+//======================
+
+class QPopupMenuPrivate {
+public:
+ struct Scroll {
+ enum { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
+ uint scrollable : 2;
+ uint direction : 1;
+ int topScrollableIndex, scrollableSize;
+ QTime lastScroll;
+ QTimer *scrolltimer;
+ } scroll;
+ QSize calcSize;
+ QRegion mouseMoveBuffer;
+};
+*/
+
+//======================
+// PopupMenu
+//======================
+
+PopupMenu::PopupMenu(QWidget* parent, const char* name)
+ : QPopupMenu(parent, name)
+{
+ // It's too bad QPopupMenu::d is private.
+ // It will be redundant and this will be our own private member.
+ //d = new QPopupMenuPrivate;
+ //d->scroll.scrollableSize = d->scroll.topScrollableIndex = 0;
+ //d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ //d->scroll.scrolltimer = 0;
+}
+
+PopupMenu::~PopupMenu()
+{
+ //if(d->scroll.scrolltimer)
+ // delete d->scroll.scrolltimer;
+
+ //preventAnimation = FALSE;
+ //delete d;
+
+ // Make sure to clear the popup so that any child popups are also deleted !
+ //popup->clear();
+}
+
+void PopupMenu::menuDelPopup(QPopupMenu *popup)
+{
+ //printf("PopupMenu::menuDelPopup deleting popup...\n");
+
+ // Make sure to clear the popup so that any child popups are also deleted !
+ // Tested OK. All the popups are deleted.
+ popup->clear();
+
+ popup->disconnect( SIGNAL(activatedRedirect(int)) );
+ popup->disconnect( SIGNAL(highlightedRedirect(int)) );
+ disconnect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+ delete popup;
+}
+
+/*
+void PopupMenu::setFirstItemActive()
+{
+ QMenuItemListIt it(*QPopupMenu::mitems);
+ register QMenuItem *mi;
+ int ai = 0;
+ //if(d->scroll.scrollable)
+ // ai = d->scroll.topScrollableIndex;
+ while ( (mi=it.current()) )
+ {
+ ++it;
+ if(!mi->isSeparator() && mi->id() != QMenuData::d->aInt &&
+ (style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this) || mi->isEnabledAndVisible()))
+ {
+ setActiveItem( ai );
+ return;
+ }
+ ai++;
+ }
+ QPopupMenu::actItem = -1;
+}
+*/
+
+/*
+void PopupMenu::hideAllPopups()
+{
+ //register QMenuData *top = this; // find top level popup
+ register MenuData *top = this; // find top level popup
+ if ( !preventAnimation )
+ QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ if ( !isPopup() )
+ return; // nothing to do
+
+ //while ( top->parentMenu && top->parentMenu->isPopupMenu
+ while ( top->parentMenu && ((MenuData*)top->parentMenu)->isPopupMenu
+ //&& ((QPopupMenu*)top->parentMenu)->isPopup() )
+ && ((PopupMenu*)((MenuData*)top->parentMenu))->isPopup() )
+ //top = top->parentMenu;
+ top = (MenuData*)top->parentMenu;
+ //((QPopupMenu*)top)->hide(); // cascade from top level
+ ((PopupMenu*)top)->hide(); // cascade from top level
+
+#ifndef QT_NO_WHATSTHIS
+ if (whatsThisItem) {
+ qWhatsThisBDH();
+ whatsThisItem = 0;
+ }
+#endif
+
+}
+*/
+
+/*
+void PopupMenu::hidePopups()
+{
+ if ( !preventAnimation )
+ QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ //QMenuItemListIt it(*mitems);
+ QMenuItemListIt it(*MenuData::mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( mi->popup() && mi->popup()->parentMenu == this ) //avoid circularity
+ mi->popup()->hide();
+ }
+ popupActive = -1; // no active sub menu
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+
+ QRect mfrect = itemGeometry( actItem );
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+}
+*/
+
+bool PopupMenu::tryMenuBar( QMouseEvent *e )
+{
+ register QMenuData *top = this; // find top level
+ //register PopupMenu *top = this; // find top level
+ //while ( top->parentMenu )
+ while ( ((PopupMenu*)top)->parentMenu )
+ //top = top->parentMenu;
+ //top = (MenuData*)top->parentMenu;
+ top = ((PopupMenu*)top)->parentMenu;
+#ifndef QT_NO_MENUBAR
+ return top->isMenuBar ?
+ ((QMenuBar *)top)->tryMouseEvent( this, e ) :
+ ((QPopupMenu*)top)->tryMouseEvent(this, e );
+#else
+ //return ((QPopupMenu*)top)->tryMouseEvent(this, e );
+ return ((PopupMenu*)top)->tryMouseEvent(this, e );
+#endif
+}
+
+//bool PopupMenu::tryMouseEvent( QPopupMenu *p, QMouseEvent * e)
+bool PopupMenu::tryMouseEvent( PopupMenu *p, QMouseEvent * e)
+{
+ if ( p == this )
+ return FALSE;
+ QPoint pos = mapFromGlobal( e->globalPos() );
+ if ( !rect().contains( pos ) ) // outside
+ return FALSE;
+ QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
+ event( &ee );
+ return TRUE;
+}
+
+/*
+void PopupMenu::byeMenuBar()
+{
+#ifndef QT_NO_MENUBAR
+ //register QMenuData *top = this; // find top level
+ register MenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+#endif
+ hideAllPopups();
+#ifndef QT_NO_MENUBAR
+ if ( top->isMenuBar )
+ ((QMenuBar *)top)->goodbye();
+#endif
+}
+*/
+
+void PopupMenu::actSig(int id, bool inwhatsthis)
+{
+ if(!inwhatsthis)
+ {
+ emit activated( id );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if(!fromAccel)
+ QAccessible::updateAccessibility(this, indexOf(id)+1, QAccessible::MenuCommand);
+#endif
+ }
+ else
+ {
+#ifndef QT_NO_WHATSTHIS
+ QRect r(itemGeometry(indexOf(id)));
+ QPoint p(r.center().x(), r.bottom());
+ QString whatsThis = findItem(id)->whatsThis();
+ if(whatsThis.isNull())
+ whatsThis = QWhatsThis::textFor(this, p);
+ QWhatsThis::leaveWhatsThisMode(whatsThis, mapToGlobal(p), this);
+#endif
+ }
+
+ emit activatedRedirect(id);
+}
+
+/*
+void PopupMenu::mousePressEvent(QMouseEvent *e)
+{
+ printf("PopupMenu::mousePressEvent\n");
+
+
+ //int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ //if (rect().contains(e->pos()) &&
+ // ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
+ // (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ // e->pos().y() >= contentsRect().height() - sh))) //down
+ // return;
+
+ mouseBtDn = TRUE; // mouse button down
+ int item = itemAtPos( e->pos() );
+ if ( item == -1 ) {
+ //if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) {
+ // byeMenuBar();
+ //}
+ return;
+ }
+ register QMenuItem *mi = mitems->at(item);
+ ///if ( item != actItem ) // new item activated
+ /// setActiveItem( item );
+
+ QPopupMenu *popup = mi->popup();
+ if(popup)
+ {
+ if(popup->isVisible()) // sub menu already open
+ {
+ //int pactItem = popup->actItem;
+ //popup->actItem = -1;
+ //popup->hidePopups();
+ //popup->updateRow( pactItem );
+ }
+ else // open sub menu
+ {
+ //hidePopups();
+ popupSubMenuLater( 20, this );
+ }
+ }
+ else
+ {
+ //hidePopups();
+ }
+}
+*/
+
+void PopupMenu::mouseReleaseEvent(QMouseEvent *e)
+{
+ // do not hide a standalone context menu on press-release, unless
+ // the user moved the mouse significantly
+ //if(!parentMenu && !mouseBtDn && actItem < 0 && motion < 6)
+ // return;
+
+ //mouseBtDn = FALSE;
+ //MenuData::mouseBtDn = FALSE;
+ QPopupMenu::mouseBtDn = FALSE;
+
+ // if the user released the mouse outside the menu, pass control
+ // to the menubar or our parent menu
+ //int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(!rect().contains(e->pos()) && tryMenuBar(e))
+ return;
+ //else
+ //if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
+ // (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ // e->pos().y() >= contentsRect().height() - sh)) //down
+ // return;
+
+ if(QPopupMenu::actItem < 0)
+ {
+ // we do not have an active item
+ // if the release is inside without motion (happens with
+ // oversized popup menus on small screens), ignore it
+ if(rect().contains(e->pos()) && motion < 6)
+ return;
+ ///else
+ /// byeMenuBar();
+ }
+ else
+ {
+ // selected menu item!
+ register QMenuItem *mi = QPopupMenu::mitems->at(QPopupMenu::actItem);
+ if(mi->widget())
+ {
+ QWidget* widgetAt = QApplication::widgetAt(e->globalPos(), TRUE);
+ if(widgetAt && widgetAt != this)
+ {
+ QMouseEvent me(e->type(), widgetAt->mapFromGlobal(e->globalPos()),
+ e->globalPos(), e->button(), e->state());
+ QApplication::sendEvent( widgetAt, &me );
+ }
+ }
+ //QPopupMenu *popup = mi->popup();
+ PopupMenu *popup = (PopupMenu*)mi->popup();
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if(!mi->isEnabledAndVisible())
+ {
+#ifndef QT_NO_WHATSTHIS
+ if(b)
+ {
+ actItem = -1;
+ updateItem(mi->id());
+ byeMenuBar();
+ actSig(mi->id(), b);
+ }
+#endif
+ }
+ else
+ if(popup)
+ {
+ //popup->setFirstItemActive();
+ }
+ else
+ {
+ // normal menu item
+ ///byeMenuBar(); // deactivate menu bar
+ if(mi->isEnabledAndVisible())
+ {
+ ///QPopupMenu::actItem = -1;
+ QPopupMenu::updateItem(mi->id());
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig(mi->id(), b);
+ if(signal && !b)
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+}
+
+
+
+
+
+
+/****************************************************************************
+**
+** Implementation of QPopupMenu class
+**
+** Created : 941128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+/*
+#include "popupmenu.h"
+#ifndef QT_NO_POPUPMENU
+#include <qmenubar.h>
+#include <qaccel.h>
+#include <qpainter.h>
+#include <qdrawutil.h>
+#include <qapplication.h>
+#include <qpixmap.h>
+#include <qpixmapcache.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qobjectlist.h>
+#include <qguardedptr.h>
+//#include <qeffects_p.h>
+#include <qcursor.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include <qdatetime.h>
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+#include <qaccessible.h>
+#endif
+
+//#define ANIMATED_POPUP
+//#define BLEND_POPUP
+
+// Motif style parameters
+
+static const int motifArrowHMargin = 6; // arrow horizontal margin
+static const int motifArrowVMargin = 2; // arrow vertical margin
+
+#if 0
+# define DEBUG_SLOPPY_SUBMENU
+#endif
+
+// used for internal communication
+static PopupMenu * syncMenu = 0;
+static int syncMenuId = 0;
+
+// Used to detect motion prior to mouse-release
+static int motion;
+
+// used to provide ONE single-shot timer
+static QTimer * singleSingleShot = 0;
+
+static bool supressAboutToShow = FALSE;
+
+static void cleanup()
+{
+ delete singleSingleShot;
+ singleSingleShot = 0;
+}
+
+static void popupSubMenuLater( int msec, PopupMenu * receiver ) {
+ if ( !singleSingleShot ) {
+ singleSingleShot = new QTimer( qApp, "popup submenu timer" );
+ qAddPostRoutine( cleanup );
+ }
+
+ singleSingleShot->disconnect( SIGNAL(timeout()) );
+ QObject::connect( singleSingleShot, SIGNAL(timeout()),
+ receiver, SLOT(subMenuTimer()) );
+ singleSingleShot->start( msec, TRUE );
+}
+
+static bool preventAnimation = FALSE;
+
+#ifndef QT_NO_WHATSTHIS
+extern void qWhatsThisBDH();
+static QMenuItem* whatsThisItem = 0;
+#endif
+
+class QMenuDataData {
+ // attention: also defined in qmenudata.cpp
+public:
+ QMenuDataData();
+ QGuardedPtr<QWidget> aWidget;
+ int aInt;
+};
+
+class QPopupMenuPrivate {
+public:
+ struct Scroll {
+ enum { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
+ uint scrollable : 2;
+ uint direction : 1;
+ int topScrollableIndex, scrollableSize;
+ QTime lastScroll;
+ QTimer *scrolltimer;
+ } scroll;
+ QSize calcSize;
+ QRegion mouseMoveBuffer;
+};
+
+static PopupMenu* active_popup_menu = 0;
+
+PopupMenu::PopupMenu( QWidget *parent, const char *name )
+ : QFrame( parent, name, WType_Popup | WNoAutoErase )
+{
+ d = new QPopupMenuPrivate;
+ d->scroll.scrollableSize = d->scroll.topScrollableIndex = 0;
+ d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ d->scroll.scrolltimer = 0;
+ isPopupMenu = TRUE;
+#ifndef QT_NO_ACCEL
+ autoaccel = 0;
+ accelDisabled = FALSE;
+#endif
+ popupActive = -1;
+ snapToMouse = TRUE;
+ tab = 0;
+ checkable = 0;
+ tornOff = 0;
+ pendingDelayedContentsChanges = 0;
+ pendingDelayedStateChanges = 0;
+ maxPMWidth = 0;
+
+ tab = 0;
+ ncols = 1;
+ setFrameStyle( QFrame::PopupPanel | QFrame::Raised );
+ setMouseTracking(style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this));
+ //style().polishPopupMenu( this );
+ style().polishPopupMenu( (QPopupMenu*)this );
+ setBackgroundMode( PaletteButton );
+ connectModalRecursionSafety = 0;
+
+ setFocusPolicy( StrongFocus );
+}
+
+PopupMenu::~PopupMenu()
+{
+ if ( syncMenu == this && qApp ) {
+ qApp->exit_loop();
+ syncMenu = 0;
+ }
+
+ if(d->scroll.scrolltimer)
+ delete d->scroll.scrolltimer;
+
+ if ( isVisible() ) {
+ parentMenu = 0;
+ hidePopups();
+ }
+
+ delete (QWidget*) QMenuData::d->aWidget; // tear-off menu
+
+ preventAnimation = FALSE;
+ delete d;
+}
+
+
+void PopupMenu::updateItem( int id ) // update popup menu item
+{
+ updateRow( indexOf(id) );
+}
+
+
+void PopupMenu::setCheckable( bool enable )
+{
+ if ( isCheckable() != enable ) {
+ checkable = enable;
+ badSize = TRUE;
+ if ( QMenuData::d->aWidget )
+ ( (PopupMenu*)(QWidget*)QMenuData::d->aWidget)->setCheckable( enable );
+ }
+}
+
+bool PopupMenu::isCheckable() const
+{
+ return checkable;
+}
+
+void PopupMenu::menuContentsChanged()
+{
+ // here the part that can't be delayed
+ QMenuData::menuContentsChanged();
+ badSize = TRUE; // might change the size
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ mac_dirty_popup = 1;
+#endif
+ if( pendingDelayedContentsChanges )
+ return;
+ pendingDelayedContentsChanges = 1;
+ if( !pendingDelayedStateChanges ) // if the timer hasn't been started yet
+ QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
+}
+
+void PopupMenu::performDelayedContentsChanged()
+{
+ pendingDelayedContentsChanges = 0;
+ // here the part the can be delayed
+#ifndef QT_NO_ACCEL
+ // if performDelayedStateChanged() will be called too,
+ // it will call updateAccel() too, no need to do it twice
+ if( !pendingDelayedStateChanges )
+ updateAccel( 0 );
+#endif
+ if ( isVisible() ) {
+ if ( tornOff )
+ return;
+ updateSize(TRUE);
+ update();
+ }
+ PopupMenu* p = (PopupMenu*)(QWidget*)QMenuData::d->aWidget;
+ if ( p && p->isVisible() ) {
+ p->updateSize(TRUE);
+ p->update();
+ }
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ mac_dirty_popup = 1;
+#endif
+}
+
+
+void PopupMenu::menuStateChanged()
+{
+ // here the part that can't be delayed
+ if( pendingDelayedStateChanges )
+ return;
+ pendingDelayedStateChanges = 1;
+ if( !pendingDelayedContentsChanges ) // if the timer hasn't been started yet
+ QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
+}
+
+void PopupMenu::performDelayedStateChanged()
+{
+ pendingDelayedStateChanges = 0;
+ // here the part that can be delayed
+#ifndef QT_NO_ACCEL
+ updateAccel( 0 ); // ### when we have a good solution for the accel vs. focus widget problem, remove that. That is only a workaround
+ // if you remove this, see performDelayedContentsChanged()
+#endif
+ update();
+ if ( QMenuData::d->aWidget )
+ QMenuData::d->aWidget->update();
+}
+
+void PopupMenu::performDelayedChanges()
+{
+ if( pendingDelayedContentsChanges )
+ performDelayedContentsChanged();
+ if( pendingDelayedStateChanges )
+ performDelayedStateChanged();
+}
+
+void PopupMenu::menuInsPopup( PopupMenu *popup )
+{
+ connect( popup, SIGNAL(activatedRedirect(int)),
+ SLOT(subActivated(int)) );
+ connect( popup, SIGNAL(highlightedRedirect(int)),
+ SLOT(subHighlighted(int)) );
+ connect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+}
+
+void PopupMenu::menuDelPopup( PopupMenu *popup )
+{
+ popup->disconnect( SIGNAL(activatedRedirect(int)) );
+ popup->disconnect( SIGNAL(highlightedRedirect(int)) );
+ disconnect( popup, SIGNAL(destroyed(QObject*)),
+ this, SLOT(popupDestroyed(QObject*)) );
+}
+
+
+void PopupMenu::frameChanged()
+{
+ menuContentsChanged();
+}
+
+void PopupMenu::popup( const QPoint &pos, int indexAtPoint )
+{
+ if ( !isPopup() && isVisible() )
+ hide();
+
+ //avoid circularity
+ if ( isVisible() || !isEnabled() )
+ return;
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ if( macPopupMenu(pos, indexAtPoint ))
+ return;
+#endif
+
+#if (QT_VERSION-0 >= 0x040000)
+#error "Fix this now"
+ // #### should move to QWidget - anything might need this functionality,
+ // #### since anything can have WType_Popup window flag.
+ // #### This includes stuff in QPushButton and some stuff for setting
+ // #### the geometry of QDialog.
+ // QPopupMenu
+ // ::exec()
+ // ::popup()
+ // QPushButton (shouldn't require QMenuPopup)
+ // ::popupPressed
+ // Some stuff in qwidget.cpp for dialogs... can't remember exactly.
+ // Also the code here indicatets the parameter should be a rect, not a
+ // point.
+#endif
+
+ if(d->scroll.scrollable) {
+ d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ d->scroll.topScrollableIndex = d->scroll.scrollableSize = 0;
+ badSize = TRUE;
+ }
+ updateSize();
+
+ QPoint mouse = QCursor::pos();
+ snapToMouse = pos == mouse;
+
+ // have to emit here as a menu might be setup in a slot connected
+ // to aboutToShow which will change the size of the menu
+ bool s = supressAboutToShow;
+ supressAboutToShow = TRUE;
+ if ( !s) {
+ emit aboutToShow();
+ updateSize(TRUE);
+ }
+
+ int screen_num;
+ if (QApplication::desktop()->isVirtualDesktop())
+ screen_num =
+ QApplication::desktop()->screenNumber( QApplication::reverseLayout() ?
+ pos+QPoint(width(),0) : pos );
+ else
+ screen_num = QApplication::desktop()->screenNumber( this );
+#ifdef Q_WS_MAC
+ QRect screen = QApplication::desktop()->availableGeometry( screen_num );
+#else
+ QRect screen = QApplication::desktop()->screenGeometry( screen_num );
+#endif
+ int sw = screen.width(); // screen width
+ int sh = screen.height(); // screen height
+ int sx = screen.x(); // screen pos
+ int sy = screen.y();
+ int x = pos.x();
+ int y = pos.y();
+ if ( indexAtPoint >= 0 ) // don't subtract when < 0
+ y -= itemGeometry( indexAtPoint ).y(); // (would subtract 2 pixels!)
+ int w = width();
+ int h = height();
+
+ if ( snapToMouse ) {
+ if ( qApp->reverseLayout() )
+ x -= w;
+ if ( x+w > sx+sw )
+ x = mouse.x()-w;
+ if ( y+h > sy+sh )
+ y = mouse.y()-h;
+ if ( x < sx )
+ x = mouse.x();
+ if ( y < sy )
+ y = sy;
+ }
+
+ if ( x+w > sx+sw ) // the complete widget must
+ x = sx+sw - w; // be visible
+ if ( y+h > sy+sh )
+ y = sy+sh - h;
+ if ( x < sx )
+ x = sx;
+ if ( y < sy )
+ y = sy;
+
+ if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
+ int off_top = 0, off_bottom = 0;
+ if(y+h > sy+sh)
+ off_bottom = (y+h) - (sy+sh);
+ if(y < sy)
+ off_top = sy - y;
+ if(off_bottom || off_top) {
+ int ch = updateSize().height(); //store the old height, before setting scrollable --Sam
+ const int vextra = style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this);
+ d->scroll.scrollableSize = h - off_top - off_bottom - 2*vextra;
+ if(off_top) {
+ move( x, y = sy );
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollUp;
+ }
+ if( off_bottom )
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollDown;
+ if( off_top != off_bottom && indexAtPoint >= 0 ) {
+ ch -= (vextra * 2);
+ if(ch > sh) //no bigger than the screen!
+ ch = sh;
+ if( ch > d->scroll.scrollableSize )
+ d->scroll.scrollableSize = ch;
+ }
+
+ updateSize(TRUE); //now set the size using the scrollable/scrollableSize as above
+ w = width();
+ h = height();
+ if(indexAtPoint >= 0) {
+ if(off_top) { //scroll to it
+ register QMenuItem *mi = NULL;
+ QMenuItemListIt it(*mitems);
+ for(int tmp_y = 0; tmp_y < off_top && (mi=it.current()); ) {
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemHeight( mi )),
+ QStyleOption(mi,maxPMWidth,0));
+ tmp_y += sz.height();
+ d->scroll.topScrollableIndex++;
+ }
+ }
+ }
+ }
+ }
+ move( x, y );
+ motion=0;
+ actItem = -1;
+
+#ifndef QT_NO_EFFECTS
+ int hGuess = qApp->reverseLayout() ? QEffects::LeftScroll : QEffects::RightScroll;
+ int vGuess = QEffects::DownScroll;
+ if ( qApp->reverseLayout() ) {
+ if ( snapToMouse && ( x + w/2 > mouse.x() ) ||
+ ( parentMenu && parentMenu->isPopupMenu &&
+ ( x + w/2 > ((PopupMenu*)parentMenu)->x() ) ) )
+ hGuess = QEffects::RightScroll;
+ } else {
+ if ( snapToMouse && ( x + w/2 < mouse.x() ) ||
+ ( parentMenu && parentMenu->isPopupMenu &&
+ ( x + w/2 < ((PopupMenu*)parentMenu)->x() ) ) )
+ hGuess = QEffects::LeftScroll;
+ }
+
+#ifndef QT_NO_MENUBAR
+ if ( snapToMouse && ( y + h/2 < mouse.y() ) ||
+ ( parentMenu && parentMenu->isMenuBar &&
+ ( y + h/2 < ((QMenuBar*)parentMenu)->mapToGlobal( ((QMenuBar*)parentMenu)->pos() ).y() ) ) )
+ vGuess = QEffects::UpScroll;
+#endif
+
+ if ( QApplication::isEffectEnabled( UI_AnimateMenu ) &&
+ preventAnimation == FALSE ) {
+ if ( QApplication::isEffectEnabled( UI_FadeMenu ) )
+ qFadeEffect( this );
+ else if ( parentMenu )
+ qScrollEffect( this, parentMenu->isPopupMenu ? hGuess : vGuess );
+ else
+ qScrollEffect( this, hGuess | vGuess );
+ } else
+#endif
+ {
+ show();
+ }
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::PopupMenuStart );
+#endif
+}
+
+void PopupMenu::subActivated( int id )
+{
+ emit activatedRedirect( id );
+}
+
+void PopupMenu::subHighlighted( int id )
+{
+ emit highlightedRedirect( id );
+}
+
+static bool fromAccel = FALSE;
+
+#ifndef QT_NO_ACCEL
+void PopupMenu::accelActivated( int id )
+{
+ QMenuItem *mi = findItem( id );
+ if ( mi && mi->isEnabledAndVisible() ) {
+ QGuardedPtr<QSignal> signal = mi->signal();
+ fromAccel = TRUE;
+ actSig( mi->id() );
+ fromAccel = FALSE;
+ if ( signal )
+ signal->activate();
+ }
+}
+
+void PopupMenu::accelDestroyed() // accel about to be deleted
+{
+ autoaccel = 0; // don't delete it twice!
+}
+#endif //QT_NO_ACCEL
+
+void PopupMenu::popupDestroyed( QObject *o )
+{
+ removePopup( (PopupMenu*)o );
+}
+
+void PopupMenu::actSig( int id, bool inwhatsthis )
+{
+ if ( !inwhatsthis ) {
+ emit activated( id );
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ if ( !fromAccel )
+ QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::MenuCommand );
+#endif
+ } else {
+#ifndef QT_NO_WHATSTHIS
+ QRect r( itemGeometry( indexOf( id ) ) );
+ QPoint p( r.center().x(), r.bottom() );
+ QString whatsThis = findItem( id )->whatsThis();
+ if ( whatsThis.isNull() )
+ whatsThis = QWhatsThis::textFor( this, p );
+ QWhatsThis::leaveWhatsThisMode( whatsThis, mapToGlobal( p ), this );
+#endif
+ }
+
+ emit activatedRedirect( id );
+}
+
+void PopupMenu::hilitSig( int id )
+{
+ emit highlighted( id );
+ emit highlightedRedirect( id );
+
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::Focus );
+ QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::Selection );
+#endif
+}
+
+void PopupMenu::setFirstItemActive()
+{
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ int ai = 0;
+ if(d->scroll.scrollable)
+ ai = d->scroll.topScrollableIndex;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( !mi->isSeparator() && mi->id() != QMenuData::d->aInt &&
+ ( style().styleHint( QStyle::SH_PopupMenu_AllowActiveAndDisabled, this ) || mi->isEnabledAndVisible() )) {
+ setActiveItem( ai );
+ return;
+ }
+ ai++;
+ }
+ actItem = -1;
+}
+
+void PopupMenu::hideAllPopups()
+{
+ register QMenuData *top = this; // find top level popup
+ if ( !preventAnimation )
+ QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ if ( !isPopup() )
+ return; // nothing to do
+
+ while ( top->parentMenu && top->parentMenu->isPopupMenu
+ && ((PopupMenu*)top->parentMenu)->isPopup() )
+ top = top->parentMenu;
+ ((PopupMenu*)top)->hide(); // cascade from top level
+
+#ifndef QT_NO_WHATSTHIS
+ if (whatsThisItem) {
+ qWhatsThisBDH();
+ whatsThisItem = 0;
+ }
+#endif
+
+}
+
+void PopupMenu::hidePopups()
+{
+ if ( !preventAnimation )
+ QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
+ preventAnimation = TRUE;
+
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( mi->popup() && mi->popup()->parentMenu == this ) //avoid circularity
+ mi->popup()->hide();
+ }
+ popupActive = -1; // no active sub menu
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+
+ QRect mfrect = itemGeometry( actItem );
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+}
+
+bool PopupMenu::tryMenuBar( QMouseEvent *e )
+{
+ register QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+#ifndef QT_NO_MENUBAR
+ return top->isMenuBar ?
+ ((QMenuBar *)top)->tryMouseEvent( this, e ) :
+ ((PopupMenu*)top)->tryMouseEvent(this, e );
+#else
+ return ((PopupMenu*)top)->tryMouseEvent(this, e );
+#endif
+}
+
+bool PopupMenu::tryMouseEvent( PopupMenu *p, QMouseEvent * e)
+{
+ if ( p == this )
+ return FALSE;
+ QPoint pos = mapFromGlobal( e->globalPos() );
+ if ( !rect().contains( pos ) ) // outside
+ return FALSE;
+ QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
+ event( &ee );
+ return TRUE;
+}
+
+void PopupMenu::byeMenuBar()
+{
+#ifndef QT_NO_MENUBAR
+ register QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+#endif
+ hideAllPopups();
+#ifndef QT_NO_MENUBAR
+ if ( top->isMenuBar )
+ ((QMenuBar *)top)->goodbye();
+#endif
+}
+
+int PopupMenu::itemAtPos( const QPoint &pos, bool ignoreSeparator ) const
+{
+ if ( !contentsRect().contains(pos) )
+ return -1;
+
+ int row = 0;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ QMenuItem *mi;
+ QMenuItemListIt it( *mitems );
+ if(d->scroll.scrollable) {
+ if(d->scroll.topScrollableIndex) {
+ for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi) {
+ row = 0;
+ it.toFirst();
+ }
+ y += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ }
+ }
+ int itemw = contentsRect().width() / ncols;
+ QSize sz;
+ while ( (mi=it.current()) ) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ y >= contentsRect().height() - style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this))
+ return -1;
+ ++it;
+ if ( !mi->isVisible() ) {
+ ++row;
+ continue;
+ }
+ int itemh = itemHeight( mi );
+
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(mi,maxPMWidth));
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if ( QRect( x, y, itemw, itemh ).contains( pos ) )
+ break;
+ y += itemh;
+ ++row;
+ }
+
+ if ( mi && ( !ignoreSeparator || !mi->isSeparator() ) )
+ return row;
+ return -1;
+}
+
+QRect PopupMenu::itemGeometry( int index )
+{
+ QMenuItem *mi;
+ QSize sz;
+ int row = 0, scrollh = 0;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ QMenuItemListIt it( *mitems );
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) {
+ scrollh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ y += scrollh;
+ if(d->scroll.topScrollableIndex) {
+ for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi) {
+ row = 0;
+ it.toFirst();
+ }
+ }
+ }
+ int itemw = contentsRect().width() / ncols;
+ while ( (mi=it.current()) ) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ y >= contentsRect().height() - scrollh)
+ break;
+ ++it;
+ if ( !mi->isVisible() ) {
+ ++row;
+ continue;
+ }
+ int itemh = itemHeight( mi );
+
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(mi,maxPMWidth));
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ (y + itemh > contentsRect().height() - scrollh))
+ itemh -= (y + itemh) - (contentsRect().height() - scrollh);
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if ( row == index )
+ return QRect( x,y,itemw,itemh );
+ y += itemh;
+ ++row;
+ }
+
+ return QRect(0,0,0,0);
+}
+
+QSize PopupMenu::updateSize(bool force_update, bool do_resize)
+{
+ polish();
+ if ( count() == 0 ) {
+ QSize ret = QSize( 50, 8 );
+ if(do_resize)
+ setFixedSize( ret );
+ badSize = TRUE;
+ return ret;
+ }
+
+ int scrheight = 0;
+ if(d->scroll.scrollableSize) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp)
+ scrheight += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown)
+ scrheight += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ }
+
+ if(badSize || force_update) {
+#ifndef QT_NO_ACCEL
+ updateAccel( 0 );
+#endif
+ int height = 0;
+ int max_width = 0, max_height = 0;
+ QFontMetrics fm = fontMetrics();
+ register QMenuItem *mi;
+ maxPMWidth = 0;
+ int maxWidgetWidth = 0;
+ tab = 0;
+
+ for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
+ mi = it.current();
+ QWidget *miw = mi->widget();
+ if (miw) {
+ if ( miw->parentWidget() != this )
+ miw->reparent( this, QPoint(0,0), TRUE );
+ // widget items musn't propgate mouse events
+ ((PopupMenu*)miw)->setWFlags(WNoMousePropagation);
+ }
+ if ( mi->custom() )
+ mi->custom()->setFont( font() );
+ if ( mi->iconSet() != 0)
+ maxPMWidth = QMAX( maxPMWidth,
+ mi->iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4 );
+ }
+
+ int dh = QApplication::desktop()->height();
+ ncols = 1;
+
+ for ( QMenuItemListIt it2( *mitems ); it2.current(); ++it2 ) {
+ mi = it2.current();
+ if ( !mi->isVisible() )
+ continue;
+ int w = 0;
+ int itemHeight = PopupMenu::itemHeight( mi );
+
+ if ( mi->widget() ) {
+ QSize s( mi->widget()->sizeHint() );
+ s = s.expandedTo( mi->widget()->minimumSize() );
+ mi->widget()->resize( s );
+ if ( s.width() > maxWidgetWidth )
+ maxWidgetWidth = s.width();
+ itemHeight = s.height();
+ } else {
+ if( ! mi->isSeparator() ) {
+ if ( mi->custom() ) {
+ if ( mi->custom()->fullSpan() ) {
+ maxWidgetWidth = QMAX( maxWidgetWidth,
+ mi->custom()->sizeHint().width() );
+ } else {
+ QSize s ( mi->custom()->sizeHint() );
+ w += s.width();
+ }
+ }
+
+ w += maxPMWidth;
+
+ if (! mi->text().isNull()) {
+ QString s = mi->text();
+ int t;
+ if ( (t = s.find('\t')) >= 0 ) { // string contains tab
+ w += fm.width( s, t );
+ w -= s.contains('&') * fm.width('&');
+ w += s.contains("&&") * fm.width('&');
+ int tw = fm.width( s.mid(t + 1) );
+ if ( tw > tab)
+ tab = tw;
+ } else {
+ w += fm.width( s );
+ w -= s.contains('&') * fm.width('&');
+ w += s.contains("&&") * fm.width('&');
+ }
+ } else if (mi->pixmap())
+ w += mi->pixmap()->width();
+ } else {
+ if ( mi->custom() ) {
+ QSize s ( mi->custom()->sizeHint() );
+ w += s.width();
+ } else {
+ w = itemHeight = 2;
+ }
+ }
+
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(w, itemHeight),
+ QStyleOption(mi,maxPMWidth));
+
+ w = sz.width();
+ itemHeight = sz.height();
+
+#if defined(QT_CHECK_NULL)
+ if ( mi->text().isNull() && !mi->pixmap() && !mi->iconSet() &&
+ !mi->isSeparator() && !mi->widget() && !mi->custom() )
+ qWarning( "PopupMenu: (%s) Popup has invalid menu item",
+ name( "unnamed" ) );
+#endif
+ }
+ height += itemHeight;
+ if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
+ if(scrheight && height >= d->scroll.scrollableSize - scrheight) {
+ height = d->scroll.scrollableSize - scrheight;
+ break;
+ }
+ } else if( height + 2*frameWidth() >= dh ) {
+ ncols++;
+ max_height = QMAX(max_height, height - itemHeight);
+ height = itemHeight;
+ }
+ if ( w > max_width )
+ max_width = w;
+ }
+ if( ncols == 1 && !max_height )
+ max_height = height;
+
+ if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
+ height += scrheight;
+ setMouseTracking(TRUE);
+ }
+
+ if ( tab )
+ tab -= fontMetrics().minRightBearing();
+ else
+ max_width -= fontMetrics().minRightBearing();
+
+ if ( max_width + tab < maxWidgetWidth )
+ max_width = maxWidgetWidth - tab;
+
+ const int fw = frameWidth();
+ int extra_width = (fw+style().pixelMetric(QStyle::PM_PopupMenuFrameHorizontalExtra, this)) * 2,
+ extra_height = (fw+style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this)) * 2;
+ if ( ncols == 1 )
+ d->calcSize = QSize( QMAX( minimumWidth(), max_width + tab + extra_width ),
+ QMAX( minimumHeight() , height + extra_height ) );
+ else
+ d->calcSize = QSize( QMAX( minimumWidth(), (ncols*(max_width + tab)) + extra_width ),
+ QMAX( minimumHeight(), QMIN( max_height + extra_height + 1, dh ) ) );
+ badSize = FALSE;
+ }
+
+ {
+ // Position the widget items. It could be done in drawContents
+ // but this way we get less flicker.
+ QSize sz;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ int itemw = contentsRect().width() / ncols;
+ for(QMenuItemListIt it(*mitems); it.current(); ++it) {
+ QMenuItem *mi = it.current();
+ if ( !mi->isVisible() )
+ continue;
+
+ int itemh = itemHeight( mi );
+
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh), QStyleOption(mi,maxPMWidth));
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if ( mi->widget() )
+ mi->widget()->setGeometry( x, y, itemw, mi->widget()->height() );
+ y += itemh;
+ }
+ }
+
+ if( do_resize && size() != d->calcSize ) {
+ setMaximumSize( d->calcSize );
+ d->calcSize = maximumSize(); //let the max size adjust it (virtual)
+ resize( d->calcSize );
+ }
+ return d->calcSize;
+}
+
+#ifndef QT_NO_ACCEL
+void PopupMenu::updateAccel( QWidget *parent )
+{
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+
+ if ( parent ) {
+ delete autoaccel;
+ autoaccel = 0;
+ } else if ( !autoaccel ) {
+ // we have no parent. Rather than ignoring any accelerators we try to find this popup's main window
+ if ( tornOff ) {
+ parent = this;
+ } else {
+ QWidget *w = (QWidget *) this;
+ parent = w->parentWidget();
+ while ( (!w->testWFlags(WType_TopLevel) || !w->testWFlags(WType_Popup)) && parent ) {
+ w = parent;
+ parent = parent->parentWidget();
+ }
+ }
+ }
+
+ if ( parent == 0 && autoaccel == 0 )
+ return;
+
+ if ( autoaccel ) // build it from scratch
+ autoaccel->clear();
+ else {
+ // create an autoaccel in any case, even if we might not use
+ // it immediately. Maybe the user needs it later.
+ autoaccel = new QAccel( parent, this );
+ connect( autoaccel, SIGNAL(activated(int)),
+ SLOT(accelActivated(int)) );
+ connect( autoaccel, SIGNAL(activatedAmbiguously(int)),
+ SLOT(accelActivated(int)) );
+ connect( autoaccel, SIGNAL(destroyed()),
+ SLOT(accelDestroyed()) );
+ if ( accelDisabled )
+ autoaccel->setEnabled( FALSE );
+ }
+ while ( (mi=it.current()) ) {
+ ++it;
+ QKeySequence k = mi->key();
+ if ( (int)k ) {
+ int id = autoaccel->insertItem( k, mi->id() );
+#ifndef QT_NO_WHATSTHIS
+ autoaccel->setWhatsThis( id, mi->whatsThis() );
+#endif
+ }
+ if ( !mi->text().isNull() || mi->custom() ) {
+ QString s = mi->text();
+ int i = s.find('\t');
+
+ // Note: Only looking at the first key in the sequence!
+ if ( (int)k && (int)k != Key_unknown ) {
+ QString t = (QString)mi->key();
+ if ( i >= 0 )
+ s.replace( i+1, s.length()-i, t );
+ else {
+ s += '\t';
+ s += t;
+ }
+ } else if ( !k ) {
+ if ( i >= 0 )
+ s.truncate( i );
+ }
+ if ( s != mi->text() ) {
+ mi->setText( s );
+ badSize = TRUE;
+ }
+ }
+ if ( mi->popup() && parent ) { // call recursively
+ // reuse
+ PopupMenu* popup = mi->popup();
+ if (!popup->avoid_circularity) {
+ popup->avoid_circularity = 1;
+ popup->updateAccel( parent );
+ popup->avoid_circularity = 0;
+ }
+ }
+ }
+}
+
+void PopupMenu::enableAccel( bool enable )
+{
+ if ( autoaccel )
+ autoaccel->setEnabled( enable );
+ accelDisabled = !enable; // rememeber when updateAccel
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) { // do the same for sub popups
+ ++it;
+ if ( mi->popup() ) // call recursively
+ mi->popup()->enableAccel( enable );
+ }
+}
+#endif
+
+void PopupMenu::setFont( const QFont &font )
+{
+ QWidget::setFont( font );
+ badSize = TRUE;
+ if ( isVisible() ) {
+ updateSize();
+ update();
+ }
+}
+
+void PopupMenu::show()
+{
+ if ( !isPopup() && isVisible() )
+ hide();
+
+ if ( isVisible() ) {
+ supressAboutToShow = FALSE;
+ QWidget::show();
+ return;
+ }
+ if (!supressAboutToShow)
+ emit aboutToShow();
+ else
+ supressAboutToShow = FALSE;
+ performDelayedChanges();
+ updateSize(TRUE);
+ QWidget::show();
+ popupActive = -1;
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+}
+
+void PopupMenu::hide()
+{
+ if ( syncMenu == this && qApp ) {
+ qApp->exit_loop();
+ syncMenu = 0;
+ }
+
+ if ( !isVisible() ) {
+ QWidget::hide();
+ return;
+ }
+ emit aboutToHide();
+
+ actItem = popupActive = -1;
+ if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
+ d->mouseMoveBuffer = QRegion();
+ mouseBtDn = FALSE; // mouse button up
+#if defined(QT_ACCESSIBILITY_SUPPORT)
+ QAccessible::updateAccessibility( this, 0, QAccessible::PopupMenuEnd );
+#endif
+ parentMenu = 0;
+ hidePopups();
+ QWidget::hide();
+}
+
+int PopupMenu::itemHeight( int row ) const
+{
+ return itemHeight( mitems->at( row ) );
+}
+
+int PopupMenu::itemHeight( QMenuItem *mi ) const
+{
+ if ( mi->widget() )
+ return mi->widget()->height();
+ if ( mi->custom() && mi->custom()->fullSpan() )
+ return mi->custom()->sizeHint().height();
+
+ QFontMetrics fm(fontMetrics());
+ int h = 0;
+ if ( mi->isSeparator() ) // separator height
+ h = 2;
+ else if ( mi->pixmap() ) // pixmap height
+ h = mi->pixmap()->height();
+ else // text height
+ h = fm.height();
+
+ if ( !mi->isSeparator() && mi->iconSet() != 0 )
+ h = QMAX(h, mi->iconSet()->pixmap( QIconSet::Small,
+ QIconSet::Normal ).height());
+ if ( mi->custom() )
+ h = QMAX(h, mi->custom()->sizeHint().height());
+
+ return h;
+}
+
+void PopupMenu::drawItem( QPainter* p, int tab_, QMenuItem* mi,
+ bool act, int x, int y, int w, int h)
+{
+ QStyle::SFlags flags = QStyle::Style_Default;
+ if (isEnabled() && mi->isEnabledAndVisible() && (!mi->popup() || mi->popup()->isEnabled()) )
+ flags |= QStyle::Style_Enabled;
+ if (act)
+ flags |= QStyle::Style_Active;
+ if (mouseBtDn)
+ flags |= QStyle::Style_Down;
+
+ const QColorGroup &cg = ((flags&QStyle::Style_Enabled) ? colorGroup() : palette().disabled() );
+
+ if ( mi->custom() && mi->custom()->fullSpan() ) {
+ QMenuItem dummy;
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, QRect(x, y, w, h), cg,
+ flags, QStyleOption(&dummy,maxPMWidth,tab_));
+ mi->custom()->paint( p, cg, act, flags&QStyle::Style_Enabled, x, y, w, h );
+ } else
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, QRect(x, y, w, h), cg,
+ flags, QStyleOption(mi,maxPMWidth,tab_));
+}
+
+void PopupMenu::drawContents( QPainter* p )
+{
+ QMenuItemListIt it(*mitems);
+ QMenuItem *mi = 0;
+ int row = 0;
+ int x = contentsRect().x();
+ int y = contentsRect().y();
+ if(d->scroll.scrollable) {
+ if(d->scroll.topScrollableIndex) {
+ for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi)
+ it.toFirst();
+ }
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) {
+ QRect rect(x, y, contentsRect().width(),
+ style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this));
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ QStyle::SFlags flags = QStyle::Style_Up;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuScroller, p, this, rect,
+ colorGroup(), flags, QStyleOption(maxPMWidth));
+ }
+ y += rect.height();
+ }
+ }
+
+ int itemw = contentsRect().width() / ncols;
+ QSize sz;
+ QStyle::SFlags flags;
+ while ( (mi=it.current()) ) {
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ y >= contentsRect().height() - style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this))
+ break;
+ ++it;
+ if ( !mi->isVisible() ) {
+ ++row;
+ continue;
+ }
+ int itemh = itemHeight( mi );
+ sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(mi,maxPMWidth,0)
+ );
+ sz = sz.expandedTo(QSize(itemw, sz.height()));
+ itemw = sz.width();
+ itemh = sz.height();
+
+ if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
+ if ( y < contentsRect().bottom() ) {
+ QRect rect(x, y, itemw, contentsRect().bottom() - y);
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ flags = QStyle::Style_Default;
+ if (isEnabled() && mi->isEnabledAndVisible())
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, rect,
+ colorGroup(), flags, QStyleOption((QMenuItem*)0,maxPMWidth));
+ }
+ }
+ y = contentsRect().y();
+ x +=itemw;
+ }
+ if (!mi->widget() && (!p->hasClipping() || p->clipRegion().contains(QRect(x, y, itemw, itemh))))
+ drawItem( p, tab, mi, row == actItem, x, y, itemw, itemh );
+ y += itemh;
+ ++row;
+ }
+ if ( y < contentsRect().bottom() ) {
+ QRect rect(x, y, itemw, contentsRect().bottom() - y);
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ flags = QStyle::Style_Default;
+ if ( isEnabled() )
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuItem, p, this, rect,
+ colorGroup(), flags, QStyleOption((QMenuItem*)0,maxPMWidth));
+ }
+ }
+ if( d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown ) {
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ QRect rect(x, contentsRect().height() - sh, contentsRect().width(), sh);
+ if(!p->hasClipping() || p->clipRegion().contains(rect)) {
+ QStyle::SFlags flags = QStyle::Style_Down;
+ if (isEnabled())
+ flags |= QStyle::Style_Enabled;
+ style().drawControl(QStyle::CE_PopupMenuScroller, p, this, rect,
+ colorGroup(), flags, QStyleOption(maxPMWidth));
+ }
+ }
+#if defined( DEBUG_SLOPPY_SUBMENU )
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
+ p->setClipRegion( d->mouseMoveBuffer );
+ p->fillRect( d->mouseMoveBuffer.boundingRect(), colorGroup().brush( QColorGroup::Highlight ) );
+ }
+#endif
+}
+
+void PopupMenu::paintEvent( QPaintEvent *e )
+{
+ QFrame::paintEvent( e );
+}
+
+void PopupMenu::closeEvent( QCloseEvent * e) {
+ e->accept();
+ byeMenuBar();
+}
+
+void PopupMenu::mousePressEvent( QMouseEvent *e )
+{
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if (rect().contains(e->pos()) &&
+ ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
+ (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ e->pos().y() >= contentsRect().height() - sh))) //down
+ return;
+
+ mouseBtDn = TRUE; // mouse button down
+ int item = itemAtPos( e->pos() );
+ if ( item == -1 ) {
+ if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) {
+ byeMenuBar();
+ }
+ return;
+ }
+ register QMenuItem *mi = mitems->at(item);
+ if ( item != actItem ) // new item activated
+ setActiveItem( item );
+
+ PopupMenu *popup = mi->popup();
+ if ( popup ) {
+ if ( popup->isVisible() ) { // sub menu already open
+ int pactItem = popup->actItem;
+ popup->actItem = -1;
+ popup->hidePopups();
+ popup->updateRow( pactItem );
+ } else { // open sub menu
+ hidePopups();
+ popupSubMenuLater( 20, this );
+ }
+ } else {
+ hidePopups();
+ }
+}
+
+void PopupMenu::mouseReleaseEvent( QMouseEvent *e )
+{
+ // do not hide a standalone context menu on press-release, unless
+ // the user moved the mouse significantly
+ if ( !parentMenu && !mouseBtDn && actItem < 0 && motion < 6 )
+ return;
+
+ mouseBtDn = FALSE;
+
+ // if the user released the mouse outside the menu, pass control
+ // to the menubar or our parent menu
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if ( !rect().contains( e->pos() ) && tryMenuBar(e) )
+ return;
+ else if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
+ (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ e->pos().y() >= contentsRect().height() - sh)) //down
+ return;
+
+ if ( actItem < 0 ) { // we do not have an active item
+ // if the release is inside without motion (happens with
+ // oversized popup menus on small screens), ignore it
+ if ( rect().contains( e->pos() ) && motion < 6 )
+ return;
+ else
+ byeMenuBar();
+ } else { // selected menu item!
+ register QMenuItem *mi = mitems->at(actItem);
+ if ( mi ->widget() ) {
+ QWidget* widgetAt = QApplication::widgetAt( e->globalPos(), TRUE );
+ if ( widgetAt && widgetAt != this ) {
+ QMouseEvent me( e->type(), widgetAt->mapFromGlobal( e->globalPos() ),
+ e->globalPos(), e->button(), e->state() );
+ QApplication::sendEvent( widgetAt, &me );
+ }
+ }
+ PopupMenu *popup = mi->popup();
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if ( !mi->isEnabledAndVisible() ) {
+#ifndef QT_NO_WHATSTHIS
+ if ( b ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ byeMenuBar();
+ actSig( mi->id(), b);
+ }
+#endif
+ } else if ( popup ) {
+ popup->setFirstItemActive();
+ } else { // normal menu item
+ byeMenuBar(); // deactivate menu bar
+ if ( mi->isEnabledAndVisible() ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+}
+
+void PopupMenu::mouseMoveEvent( QMouseEvent *e )
+{
+ motion++;
+
+ if ( parentMenu && parentMenu->isPopupMenu ) {
+ PopupMenu* p = (PopupMenu*)parentMenu;
+ int myIndex;
+
+ p->findPopup( this, &myIndex );
+ QPoint pPos = p->mapFromParent( e->globalPos() );
+ if ( p->actItem != myIndex && !p->rect().contains( pPos ) )
+ p->setActiveItem( myIndex );
+
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
+ p->d->mouseMoveBuffer = QRegion();
+#ifdef DEBUG_SLOPPY_SUBMENU
+ p->repaint();
+#endif
+ }
+ }
+
+ if ( (e->state() & Qt::MouseButtonMask) == 0 &&
+ !hasMouseTracking() )
+ return;
+
+ if(d->scroll.scrollable && e->pos().x() >= rect().x() && e->pos().x() <= rect().width()) {
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) ||
+ (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown && e->pos().y() >= height()-sh)) {
+ if(!d->scroll.scrolltimer) {
+ d->scroll.scrolltimer = new QTimer(this, "popup scroll timer");
+ QObject::connect( d->scroll.scrolltimer, SIGNAL(timeout()),
+ this, SLOT(subScrollTimer()) );
+ }
+ if(!d->scroll.scrolltimer->isActive())
+ d->scroll.scrolltimer->start(40);
+ return;
+ }
+ }
+
+ int item = itemAtPos( e->pos() );
+ if ( item == -1 ) { // no valid item
+ int lastActItem = actItem;
+ actItem = -1;
+ if ( lastActItem >= 0 )
+ updateRow( lastActItem );
+ if ( lastActItem > 0 ||
+ ( !rect().contains( e->pos() ) && !tryMenuBar( e ) ) ) {
+ popupSubMenuLater(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay,
+ this), this);
+ }
+ } else { // mouse on valid item
+ // but did not register mouse press
+ if ( (e->state() & Qt::MouseButtonMask) && !mouseBtDn )
+ mouseBtDn = TRUE; // so mouseReleaseEvent will pop down
+
+ register QMenuItem *mi = mitems->at( item );
+
+ if ( mi->widget() ) {
+ QWidget* widgetAt = QApplication::widgetAt( e->globalPos(), TRUE );
+ if ( widgetAt && widgetAt != this ) {
+ QMouseEvent me( e->type(), widgetAt->mapFromGlobal( e->globalPos() ),
+ e->globalPos(), e->button(), e->state() );
+ QApplication::sendEvent( widgetAt, &me );
+ }
+ }
+
+ if ( actItem == item )
+ return;
+
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this) &&
+ d->mouseMoveBuffer.contains( e->pos() ) ) {
+ actItem = item;
+ popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this) * 6,
+ this );
+ return;
+ }
+
+ if ( mi->popup() || ( popupActive >= 0 && popupActive != item ))
+ popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this),
+ this );
+ else if ( singleSingleShot )
+ singleSingleShot->stop();
+
+ if ( item != actItem )
+ setActiveItem( item );
+ }
+}
+
+void PopupMenu::keyPressEvent( QKeyEvent *e )
+{
+ QMenuItem *mi = 0;
+ PopupMenu *popup;
+ int dy = 0;
+ bool ok_key = TRUE;
+
+ int key = e->key();
+ if ( QApplication::reverseLayout() ) {
+ // in reverse mode opening and closing keys for submenues are reversed
+ if ( key == Key_Left )
+ key = Key_Right;
+ else if ( key == Key_Right )
+ key = Key_Left;
+ }
+
+ switch ( key ) {
+ case Key_Tab:
+ // ignore tab, otherwise it will be passed to the menubar
+ break;
+
+ case Key_Up:
+ dy = -1;
+ break;
+
+ case Key_Down:
+ dy = 1;
+ break;
+
+ case Key_Alt:
+ if ( style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) )
+ byeMenuBar();
+ break;
+
+ case Key_Escape:
+ if ( tornOff ) {
+ close();
+ return;
+ }
+ // just hide one
+ {
+ QMenuData* p = parentMenu;
+ hide();
+#ifndef QT_NO_MENUBAR
+ if ( p && p->isMenuBar )
+ ((QMenuBar*) p)->goodbye( TRUE );
+#endif
+ }
+ break;
+
+ case Key_Left:
+ if ( ncols > 1 && actItem >= 0 ) {
+ QRect r( itemGeometry( actItem ) );
+ int newActItem = itemAtPos( QPoint( r.left() - 1, r.center().y() ) );
+ if ( newActItem >= 0 ) {
+ setActiveItem( newActItem );
+ break;
+ }
+ }
+ if ( parentMenu && parentMenu->isPopupMenu ) {
+ ((PopupMenu *)parentMenu)->hidePopups();
+ if ( singleSingleShot )
+ singleSingleShot->stop();
+ break;
+ }
+
+ ok_key = FALSE;
+ break;
+
+ case Key_Right:
+ if ( actItem >= 0 && ( mi=mitems->at(actItem) )->isEnabledAndVisible() && (popup=mi->popup()) ) {
+ hidePopups();
+ if ( singleSingleShot )
+ singleSingleShot->stop();
+ // ### The next two lines were switched to fix the problem with the first item of the
+ // submenu not being highlighted...any reason why they should have been the other way??
+ subMenuTimer();
+ popup->setFirstItemActive();
+ break;
+ } else if ( actItem == -1 && ( parentMenu && !parentMenu->isMenuBar )) {
+ dy = 1;
+ break;
+ }
+ if ( ncols > 1 && actItem >= 0 ) {
+ QRect r( itemGeometry( actItem ) );
+ int newActItem = itemAtPos( QPoint( r.right() + 1, r.center().y() ) );
+ if ( newActItem >= 0 ) {
+ setActiveItem( newActItem );
+ break;
+ }
+ }
+ ok_key = FALSE;
+ break;
+
+ case Key_Space:
+ if (! style().styleHint(QStyle::SH_PopupMenu_SpaceActivatesItem, this))
+ break;
+ // for motif, fall through
+
+ case Key_Return:
+ case Key_Enter:
+ {
+ if ( actItem < 0 )
+ break;
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ mi = mitems->at( actItem );
+ if ( !mi->isEnabled() && !b )
+ break;
+ popup = mi->popup();
+ if ( popup ) {
+ hidePopups();
+ popupSubMenuLater( 20, this );
+ popup->setFirstItemActive();
+ } else {
+ actItem = -1;
+ updateItem( mi->id() );
+ byeMenuBar();
+ if ( mi->isEnabledAndVisible() || b ) {
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+ break;
+#ifndef QT_NO_WHATSTHIS
+ case Key_F1:
+ if ( actItem < 0 || e->state() != ShiftButton)
+ break;
+ mi = mitems->at( actItem );
+ if ( !mi->whatsThis().isNull() ){
+ if ( !QWhatsThis::inWhatsThisMode() )
+ QWhatsThis::enterWhatsThisMode();
+ QRect r( itemGeometry( actItem) );
+ QWhatsThis::leaveWhatsThisMode( mi->whatsThis(), mapToGlobal( r.bottomLeft()) );
+ }
+ //fall-through!
+#endif
+ default:
+ ok_key = FALSE;
+
+ }
+ if ( !ok_key &&
+ ( !e->state() || e->state() == AltButton || e->state() == ShiftButton ) &&
+ e->text().length()==1 ) {
+ QChar c = e->text()[0].upper();
+
+ QMenuItemListIt it(*mitems);
+ QMenuItem* first = 0;
+ QMenuItem* currentSelected = 0;
+ QMenuItem* firstAfterCurrent = 0;
+
+ register QMenuItem *m;
+ mi = 0;
+ int indx = 0;
+ int clashCount = 0;
+ while ( (m=it.current()) ) {
+ ++it;
+ QString s = m->text();
+ if ( !s.isEmpty() ) {
+ int i = s.find( '&' );
+ while ( i >= 0 && i < (int)s.length() - 1 ) {
+ if ( s[i+1].upper() == c ) {
+ ok_key = TRUE;
+ clashCount++;
+ if ( !first )
+ first = m;
+ if ( indx == actItem )
+ currentSelected = m;
+ else if ( !firstAfterCurrent && currentSelected )
+ firstAfterCurrent = m;
+ break;
+ } else if ( s[i+1] == '&' ) {
+ i = s.find( '&', i+2 );
+ } else {
+ break;
+ }
+ }
+ }
+ if ( mi )
+ break;
+ indx++;
+ }
+
+ if ( 1 == clashCount ) { // No clashes, continue with selection
+ mi = first;
+ popup = mi->popup();
+ if ( popup ) {
+ setActiveItem( indexOf(mi->id()) );
+ hidePopups();
+ popupSubMenuLater( 20, this );
+ popup->setFirstItemActive();
+ } else {
+ byeMenuBar();
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if ( mi->isEnabledAndVisible() || b ) {
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ } else if ( clashCount > 1 ) { // Clashes, highlight next...
+ // If there's clashes and no one is selected, use first one
+ // or if there is no clashes _after_ current, use first one
+ if ( !currentSelected || (currentSelected && !firstAfterCurrent))
+ dy = indexOf( first->id() ) - actItem;
+ else
+ dy = indexOf( firstAfterCurrent->id() ) - actItem;
+ }
+ }
+#ifndef QT_NO_MENUBAR
+ if ( !ok_key ) { // send to menu bar
+ register QMenuData *top = this; // find top level
+ while ( top->parentMenu )
+ top = top->parentMenu;
+ if ( top->isMenuBar ) {
+ int beforeId = top->actItem;
+ ((QMenuBar*)top)->tryKeyEvent( this, e );
+ if ( beforeId != top->actItem )
+ ok_key = TRUE;
+ }
+ }
+#endif
+ if ( actItem < 0 ) {
+ if ( dy > 0 ) {
+ setFirstItemActive();
+ } else if ( dy < 0 ) {
+ QMenuItemListIt it(*mitems);
+ it.toLast();
+ register QMenuItem *mi;
+ int ai = count() - 1;
+ while ( (mi=it.current()) ) {
+ --it;
+ if ( !mi->isSeparator() && mi->id() != QMenuData::d->aInt ) {
+ setActiveItem( ai );
+ return;
+ }
+ ai--;
+ }
+ actItem = -1;
+ }
+ return;
+ }
+
+ if ( dy ) { // highlight next/prev
+ register int i = actItem;
+ int c = mitems->count();
+ for(int n = c; n; n--) {
+ i = i + dy;
+ if(d->scroll.scrollable) {
+ if(d->scroll.scrolltimer)
+ d->scroll.scrolltimer->stop();
+ if(i < 0)
+ i = 0;
+ else if(i >= c)
+ i = c - 1;
+ } else {
+ if ( i == c )
+ i = 0;
+ else if ( i < 0 )
+ i = c - 1;
+ }
+ mi = mitems->at( i );
+ if ( !mi || !mi->isVisible() )
+ continue;
+
+ if ( !mi->isSeparator() &&
+ ( style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this)
+ || mi->isEnabledAndVisible() ) )
+ break;
+ }
+ if ( i != actItem )
+ setActiveItem( i );
+ if(d->scroll.scrollable) { //need to scroll to make it visible?
+ QRect r = itemGeometry(actItem);
+ if(r.isNull() || r.height() < itemHeight(mitems->at(actItem))) {
+ bool refresh = FALSE;
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && dy == -1) { //up
+ if(d->scroll.topScrollableIndex >= 0) {
+ d->scroll.topScrollableIndex--;
+ refresh = TRUE;
+ }
+ } else if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown) { //down
+ QMenuItemListIt it(*mitems);
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ for(int i = 0, y = ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) ? sh : 0); it.current(); i++, ++it) {
+ if(i >= d->scroll.topScrollableIndex) {
+ int itemh = itemHeight(it.current());
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemh),
+ QStyleOption(it.current(),maxPMWidth,0));
+ y += sz.height();
+ if(y > (contentsRect().height()-sh)) {
+ if(sz.height() > sh || !it.atLast())
+ d->scroll.topScrollableIndex++;
+ refresh = TRUE;
+ break;
+ }
+ }
+ }
+ }
+ if(refresh) {
+ updateScrollerState();
+ update();
+ }
+ }
+ }
+ }
+
+#ifdef Q_OS_WIN32
+ if ( !ok_key &&
+ !( e->key() == Key_Control || e->key() == Key_Shift || e->key() == Key_Meta ) )
+ qApp->beep();
+#endif // Q_OS_WIN32
+}
+
+void PopupMenu::timerEvent( QTimerEvent *e )
+{
+ QFrame::timerEvent( e );
+}
+
+void PopupMenu::leaveEvent( QEvent * )
+{
+ if ( testWFlags( WStyle_Tool ) && style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this) ) {
+ int lastActItem = actItem;
+ actItem = -1;
+ if ( lastActItem >= 0 )
+ updateRow( lastActItem );
+ }
+}
+
+void PopupMenu::styleChange( QStyle& old )
+{
+ QFrame::styleChange( old );
+ setMouseTracking(style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this));
+ style().polishPopupMenu( this );
+ updateSize(TRUE);
+}
+
+void PopupMenu::enabledChange( bool )
+{
+ if ( QMenuData::d->aWidget ) // torn-off menu
+ QMenuData::d->aWidget->setEnabled( isEnabled() );
+}
+
+int PopupMenu::columns() const
+{
+ return ncols;
+}
+
+// This private slot handles the scrolling popupmenu
+void PopupMenu::subScrollTimer() {
+ QPoint pos = QCursor::pos();
+ if(!d->scroll.scrollable || !isVisible()) {
+ if(d->scroll.scrolltimer)
+ d->scroll.scrolltimer->stop();
+ return;
+ } else if(pos.x() > x() + width() || pos.x() < x()) {
+ return;
+ }
+ int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(!d->scroll.lastScroll.isValid()) {
+ d->scroll.lastScroll = QTime::currentTime();
+ } else {
+ int factor=0;
+ if(pos.y() < y())
+ factor = y() - pos.y();
+ else if(pos.y() > y() + height())
+ factor = pos.y() - (y() + height());
+ int msecs = 250 - ((factor / 10) * 40);
+ if(d->scroll.lastScroll.msecsTo(QTime::currentTime()) < QMAX(0, msecs))
+ return;
+ d->scroll.lastScroll = QTime::currentTime();
+ }
+ if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && pos.y() <= y() + sh) { //up
+ if(d->scroll.topScrollableIndex > 0) {
+ d->scroll.topScrollableIndex--;
+ updateScrollerState();
+ update(contentsRect());
+ }
+ } else if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
+ pos.y() >= (y() + contentsRect().height()) - sh) { //down
+ QMenuItemListIt it(*mitems);
+ for(int i = 0, y = contentsRect().y() + sh; it.current(); i++, ++it) {
+ if(i >= d->scroll.topScrollableIndex) {
+ int itemh = itemHeight(it.current());
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this, QSize(0, itemh),
+ QStyleOption(it.current(),maxPMWidth,0));
+ y += sz.height();
+ if(y > contentsRect().height() - sh) {
+ d->scroll.topScrollableIndex++;
+ updateScrollerState();
+ update(contentsRect());
+ break;
+ }
+ }
+ }
+ }
+}
+
+// This private slot handles the delayed submenu effects
+
+void PopupMenu::subMenuTimer() {
+
+ if ( !isVisible() || (actItem < 0 && popupActive < 0) || actItem == popupActive )
+ return;
+
+ if ( popupActive >= 0 ) {
+ hidePopups();
+ popupActive = -1;
+ }
+
+ // hidePopups() may change actItem etc.
+ if ( !isVisible() || actItem < 0 || actItem == popupActive )
+ return;
+
+ QMenuItem *mi = mitems->at(actItem);
+ if ( !mi || !mi->isEnabledAndVisible() )
+ return;
+
+ PopupMenu *popup = mi->popup();
+ if ( !popup || !popup->isEnabled() )
+ return;
+
+ //avoid circularity
+ if ( popup->isVisible() )
+ return;
+
+ Q_ASSERT( popup->parentMenu == 0 );
+ popup->parentMenu = this; // set parent menu
+
+ emit popup->aboutToShow();
+ supressAboutToShow = TRUE;
+
+
+ QRect r( itemGeometry( actItem ) );
+ QPoint p;
+ QSize ps = popup->sizeHint();
+ if( QApplication::reverseLayout() ) {
+ p = QPoint( r.left() + motifArrowHMargin - ps.width(), r.top() + motifArrowVMargin );
+ p = mapToGlobal( p );
+
+ bool right = FALSE;
+ if ( ( parentMenu && parentMenu->isPopupMenu &&
+ ((PopupMenu*)parentMenu)->geometry().x() < geometry().x() ) ||
+ p.x() < 0 )
+ right = TRUE;
+ if ( right && (ps.width() > QApplication::desktop()->width() - mapToGlobal( r.topRight() ).x() ) )
+ right = FALSE;
+ if ( right )
+ p.setX( mapToGlobal( r.topRight() ).x() );
+ } else {
+ p = QPoint( r.right() - motifArrowHMargin, r.top() + motifArrowVMargin );
+ p = mapToGlobal( p );
+
+ bool left = FALSE;
+ if ( ( parentMenu && parentMenu->isPopupMenu &&
+ ((PopupMenu*)parentMenu)->geometry().x() > geometry().x() ) ||
+ p.x() + ps.width() > QApplication::desktop()->width() )
+ left = TRUE;
+ if ( left && (ps.width() > mapToGlobal( r.topLeft() ).x() ) )
+ left = FALSE;
+ if ( left )
+ p.setX( mapToGlobal( r.topLeft() ).x() - ps.width() );
+ }
+ QRect pr = popup->itemGeometry(popup->count() - 1);
+ if (p.y() + ps.height() > QApplication::desktop()->height() &&
+ p.y() - ps.height() + (QCOORD) pr.height() >= 0)
+ p.setY( p.y() - ps.height() + (QCOORD) pr.height());
+
+ if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
+ QPoint cur = QCursor::pos();
+ if ( r.contains( mapFromGlobal( cur ) ) ) {
+ QPoint pts[4];
+ pts[0] = QPoint( cur.x(), cur.y() - 2 );
+ pts[3] = QPoint( cur.x(), cur.y() + 2 );
+ if ( p.x() >= cur.x() ) {
+ pts[1] = QPoint( geometry().right(), p.y() );
+ pts[2] = QPoint( geometry().right(), p.y() + ps.height() );
+ } else {
+ pts[1] = QPoint( p.x() + ps.width(), p.y() );
+ pts[2] = QPoint( p.x() + ps.width(), p.y() + ps.height() );
+ }
+ QPointArray points( 4 );
+ for( int i = 0; i < 4; i++ )
+ points.setPoint( i, mapFromGlobal( pts[i] ) );
+ d->mouseMoveBuffer = QRegion( points );
+ repaint();
+ }
+ }
+
+ popupActive = actItem;
+ popup->popup( p );
+}
+
+void PopupMenu::allowAnimation()
+{
+ preventAnimation = FALSE;
+}
+
+void PopupMenu::updateRow( int row )
+{
+ if ( !isVisible() )
+ return;
+
+ if ( badSize ) {
+ updateSize();
+ update();
+ return;
+ }
+ updateSize();
+ QRect r = itemGeometry( row );
+ if ( !r.isNull() ) // can happen via the scroller
+ repaint( r );
+}
+
+int PopupMenu::exec( const QPoint & pos, int indexAtPoint )
+{
+ snapToMouse = TRUE;
+ if ( !qApp )
+ return -1;
+
+ PopupMenu* priorSyncMenu = syncMenu;
+
+ syncMenu = this;
+ syncMenuId = -1;
+
+ QGuardedPtr<PopupMenu> that = this;
+ connectModal( that, TRUE );
+ popup( pos, indexAtPoint );
+ qApp->enter_loop();
+ connectModal( that, FALSE );
+
+ syncMenu = priorSyncMenu;
+ return syncMenuId;
+}
+
+
+
+// Connect the popup and all its submenus to modalActivation() if
+// \a doConnect is true, otherwise disconnect.
+void PopupMenu::connectModal( PopupMenu* receiver, bool doConnect )
+{
+ if ( !receiver )
+ return;
+
+ connectModalRecursionSafety = doConnect;
+
+ if ( doConnect )
+ connect( this, SIGNAL(activated(int)),
+ receiver, SLOT(modalActivation(int)) );
+ else
+ disconnect( this, SIGNAL(activated(int)),
+ receiver, SLOT(modalActivation(int)) );
+
+ QMenuItemListIt it(*mitems);
+ register QMenuItem *mi;
+ while ( (mi=it.current()) ) {
+ ++it;
+ if ( mi->popup() && mi->popup() != receiver
+ && (bool)(mi->popup()->connectModalRecursionSafety) != doConnect )
+ mi->popup()->connectModal( receiver, doConnect ); //avoid circular
+ }
+}
+
+int PopupMenu::exec()
+{
+ return exec(mapToGlobal(QPoint(0,0)));
+}
+
+
+// Internal slot used for exec().
+
+void PopupMenu::modalActivation( int id )
+{
+ syncMenuId = id;
+}
+
+void PopupMenu::setActiveItem( int i )
+{
+ int lastActItem = actItem;
+ actItem = i;
+ if ( lastActItem >= 0 )
+ updateRow( lastActItem );
+ if ( i >= 0 && i != lastActItem )
+ updateRow( i );
+ QMenuItem *mi = mitems->at( actItem );
+ if ( !mi )
+ return;
+
+ if ( mi->widget() && mi->widget()->isFocusEnabled() ) {
+ mi->widget()->setFocus();
+ } else {
+ setFocus();
+ QRect mfrect = itemGeometry( actItem );
+ setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
+ }
+ if ( mi->id() != -1 )
+ hilitSig( mi->id() );
+#ifndef QT_NO_WHATSTHIS
+ if (whatsThisItem && whatsThisItem != mi) {
+ qWhatsThisBDH();
+ }
+ whatsThisItem = mi;
+#endif
+}
+
+QSize PopupMenu::sizeHint() const
+{
+ constPolish();
+ PopupMenu* that = (PopupMenu*) this;
+ //We do not need a resize here, just the sizeHint..
+ return that->updateSize(FALSE, FALSE).expandedTo( QApplication::globalStrut() );
+}
+
+int PopupMenu::idAt( const QPoint& pos ) const
+{
+ return idAt( itemAtPos( pos ) );
+}
+
+bool PopupMenu::customWhatsThis() const
+{
+ return TRUE;
+}
+
+bool PopupMenu::focusNextPrevChild( bool next )
+{
+ register QMenuItem *mi;
+ int dy = next? 1 : -1;
+ if ( dy && actItem < 0 ) {
+ setFirstItemActive();
+ } else if ( dy ) { // highlight next/prev
+ register int i = actItem;
+ int c = mitems->count();
+ int n = c;
+ while ( n-- ) {
+ i = i + dy;
+ if ( i == c )
+ i = 0;
+ else if ( i < 0 )
+ i = c - 1;
+ mi = mitems->at( i );
+ if ( mi && !mi->isSeparator() &&
+ ( ( style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this)
+ && mi->isVisible() )
+ || mi->isEnabledAndVisible() ) )
+ break;
+ }
+ if ( i != actItem )
+ setActiveItem( i );
+ }
+ return TRUE;
+}
+
+void PopupMenu::focusInEvent( QFocusEvent * )
+{
+}
+
+void PopupMenu::focusOutEvent( QFocusEvent * )
+{
+}
+
+class QTearOffMenuItem : public QCustomMenuItem
+{
+public:
+ QTearOffMenuItem()
+ {
+ }
+ ~QTearOffMenuItem()
+ {
+ }
+ void paint( QPainter* p, const QColorGroup& cg, bool,
+ bool, int x, int y, int w, int h )
+ {
+ p->setPen( QPen( cg.dark(), 1, DashLine ) );
+ p->drawLine( x+2, y+h/2-1, x+w-4, y+h/2-1 );
+ p->setPen( QPen( cg.light(), 1, DashLine ) );
+ p->drawLine( x+2, y+h/2, x+w-4, y+h/2 );
+ }
+ bool fullSpan() const
+ {
+ return TRUE;
+ }
+
+ QSize sizeHint()
+ {
+ return QSize( 20, 6 );
+ }
+};
+
+int PopupMenu::insertTearOffHandle( int id, int index )
+{
+ int myid = insertItem( new QTearOffMenuItem, id, index );
+ connectItem( myid, this, SLOT( toggleTearOff() ) );
+ QMenuData::d->aInt = myid;
+ return myid;
+}
+
+void PopupMenu::toggleTearOff()
+{
+ if ( active_popup_menu && active_popup_menu->tornOff ) {
+ active_popup_menu->close();
+ } else if (QMenuData::d->aWidget ) {
+ delete (QWidget*) QMenuData::d->aWidget; // delete the old one
+ } else {
+ // create a tear off menu
+ PopupMenu* p = new PopupMenu( parentWidget(), "tear off menu" );
+ connect( p, SIGNAL( activated(int) ), this, SIGNAL( activated(int) ) );
+ connect( p, SIGNAL( highlighted(int) ), this, SIGNAL( highlighted(int) ) );
+#ifndef QT_NO_WIDGET_TOPEXTRA
+ p->setCaption( caption() );
+#endif
+ p->setCheckable( isCheckable() );
+ p->reparent( parentWidget(), WType_TopLevel | WStyle_Tool |
+ WNoAutoErase | WDestructiveClose,
+ geometry().topLeft(), FALSE );
+ p->mitems->setAutoDelete( FALSE );
+ p->tornOff = TRUE;
+ for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
+ if ( it.current()->id() != QMenuData::d->aInt && !it.current()->widget() )
+ p->mitems->append( it.current() );
+ }
+ p->show();
+ QMenuData::d->aWidget = p;
+ }
+}
+
+void PopupMenu::activateItemAt( int index )
+{
+ if ( index >= 0 && index < (int) mitems->count() ) {
+ QMenuItem *mi = mitems->at( index );
+ if ( index != actItem ) // new item activated
+ setActiveItem( index );
+ PopupMenu *popup = mi->popup();
+ if ( popup ) {
+ if ( popup->isVisible() ) { // sub menu already open
+ int pactItem = popup->actItem;
+ popup->actItem = -1;
+ popup->hidePopups();
+ popup->updateRow( pactItem );
+ } else { // open sub menu
+ hidePopups();
+ actItem = index;
+ subMenuTimer();
+ popup->setFirstItemActive();
+ }
+ } else {
+ byeMenuBar(); // deactivate menu bar
+
+#ifndef QT_NO_WHATSTHIS
+ bool b = QWhatsThis::inWhatsThisMode();
+#else
+ const bool b = FALSE;
+#endif
+ if ( !mi->isEnabledAndVisible() ) {
+#ifndef QT_NO_WHATSTHIS
+ if ( b ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ byeMenuBar();
+ actSig( mi->id(), b);
+ }
+#endif
+ } else {
+ byeMenuBar(); // deactivate menu bar
+ if ( mi->isEnabledAndVisible() ) {
+ actItem = -1;
+ updateItem( mi->id() );
+ active_popup_menu = this;
+ QGuardedPtr<QSignal> signal = mi->signal();
+ actSig( mi->id(), b );
+ if ( signal && !b )
+ signal->activate();
+ active_popup_menu = 0;
+ }
+ }
+ }
+ } else {
+ if ( tornOff ) {
+ close();
+ } else {
+ QMenuData* p = parentMenu;
+ hide();
+#ifndef QT_NO_MENUBAR
+ if ( p && p->isMenuBar )
+ ((QMenuBar*) p)->goodbye( TRUE );
+#endif
+ }
+ }
+
+}
+
+void
+PopupMenu::updateScrollerState()
+{
+ uint old_scrollable = d->scroll.scrollable;
+ d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
+ if(!style().styleHint(QStyle::SH_PopupMenu_Scrollable, this))
+ return;
+
+ QMenuItem *mi;
+ QMenuItemListIt it( *mitems );
+ if(d->scroll.topScrollableIndex) {
+ for(int row = 0; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
+ ++it;
+ if(!mi)
+ it.toFirst();
+ }
+ int y = 0, sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
+ if(!it.atFirst()) {
+ // can't use |= because of a bug/feature in IBM xlC 5.0.2
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollUp;
+ y += sh;
+ }
+ while ( (mi=it.current()) ) {
+ ++it;
+ int myheight = contentsRect().height();
+ QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
+ QSize(0, itemHeight( mi )),
+ QStyleOption(mi,maxPMWidth));
+ if(y + sz.height() >= myheight) {
+ d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollDown;
+ break;
+ }
+ y += sz.height();
+ }
+ if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) &&
+ !(old_scrollable & QPopupMenuPrivate::Scroll::ScrollUp))
+ d->scroll.topScrollableIndex++;
+}
+
+#endif // QT_NO_POPUPMENU
+
+*/ \ No newline at end of file
diff --git a/muse/muse/widgets/popupmenu.h b/muse/muse/widgets/popupmenu.h
new file mode 100644
index 00000000..559a1ef4
--- /dev/null
+++ b/muse/muse/widgets/popupmenu.h
@@ -0,0 +1,301 @@
+//=========================================================
+// MusE
+// Linux Music Editor
+// $Id: popupmenu.h,v 1.1.1.1 2010/07/18 03:18:00 terminator356 Exp $
+//
+// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
+//
+// PopupMenu sub-class of QPopupMenu created by Tim.
+//=========================================================
+
+
+
+//=========================================================
+//
+// NOTICE: This sub-class of QPopupMenu *automatically* deletes
+// and *clears* any sub popup menus, when clear() is called.
+// Therefore a parent widget is *not* necessary when
+// creating sub popup menus to add to the popup.
+//
+//=========================================================
+
+
+
+#ifndef __POPUPMENU_H__
+#define __POPUPMENU_H__
+
+#include <qpopupmenu.h>
+//#include <qmenudata.h>
+
+class QWidget;
+class QMouseEvent;
+
+//class MenuData : public QMenuData
+//{
+ //friend class QMenuBar;
+// friend class QPopupMenu;
+// friend class PopupMenu;
+
+// Q_OBJECT
+ //private:
+//};
+
+/*
+// Internal class to get access to protected QMenuData members.
+class MenuData : public QMenuData
+{
+ friend class QPopupMenu;
+ friend class QMenuData;
+ friend class PopupMenu;
+
+private:
+
+public:
+ MenuData() : QMenuData() { }
+ virtual ~MenuData() { }
+};
+*/
+
+//class Q_EXPORT PopupMenu : public QPopupMenu
+class PopupMenu : public QPopupMenu
+//class PopupMenu : public QPopupMenu, public MenuData
+{
+ friend class QMenuData;
+ //friend class QMenuBar;
+ friend class QPopupMenu;
+ friend class QMenuBar;
+ //friend class MenuData;
+
+ Q_OBJECT
+ private:
+ // QPopupMenu::d is private, so this is our own private.
+ //QPopupMenuPrivate *d;
+
+ //virtual void setFirstItemActive();
+ //void hideAllPopups();
+ //void hidePopups();
+ bool tryMenuBar(QMouseEvent *);
+ //bool tryMouseEvent(QPopupMenu *, QMouseEvent *);
+ bool tryMouseEvent(PopupMenu *, QMouseEvent *);
+ //void byeMenuBar();
+ void actSig(int, bool = FALSE);
+ virtual void menuDelPopup(QPopupMenu *);
+
+ protected:
+ //int actItem;
+
+ //void mousePressEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
+
+ public:
+ PopupMenu(QWidget* parent=0, const char* name=0);
+ ~PopupMenu();
+};
+
+#endif
+
+
+
+
+/****************************************************************************
+**
+** Definition of QPopupMenu class
+**
+** Created : 941128
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the widgets module of the Qt GUI Toolkit.
+**
+** This file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free
+** Software Foundation and appearing in the files LICENSE.GPL2
+** and LICENSE.GPL3 included in the packaging of this file.
+** Alternatively you may (at your option) use any later version
+** of the GNU General Public License if such license has been
+** publicly approved by Trolltech ASA (or its successors, if any)
+** and the KDE Free Qt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing requirements will be met:
+** http://trolltech.com/products/qt/licenses/licensing/opensource/.
+** If you are unsure which license is appropriate for your use, please
+** review the following information:
+** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
+** or contact the sales department at sales@trolltech.com.
+**
+** This file may be used under the terms of the Q Public License as
+** defined by Trolltech ASA and appearing in the file LICENSE.QPL
+** included in the packaging of this file. Licensees holding valid Qt
+** Commercial licenses may use this file in accordance with the Qt
+** Commercial License Agreement provided with the Software.
+**
+** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
+** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
+** herein.
+**
+**********************************************************************/
+
+/*
+#ifndef __POPUPMENU_H__
+#define __POPUPMENU_H__
+
+#ifndef QT_H
+#include <qframe.h>
+#include <qmenudata.h>
+#endif // QT_H
+
+#ifndef QT_NO_POPUPMENU
+class QPopupMenuPrivate;
+
+class Q_EXPORT PopupMenu : public QFrame, public QMenuData
+{
+ Q_OBJECT
+ Q_PROPERTY( bool checkable READ isCheckable WRITE setCheckable )
+public:
+ PopupMenu( QWidget* parent=0, const char* name=0 );
+ ~PopupMenu();
+
+ void popup( const QPoint & pos, int indexAtPoint = -1 ); // open
+ void updateItem( int id );
+
+ virtual void setCheckable( bool );
+ bool isCheckable() const;
+
+ void setFont( const QFont & );
+ void show();
+ void hide();
+
+ int exec();
+ int exec( const QPoint & pos, int indexAtPoint = 0 ); // modal
+
+ virtual void setActiveItem( int );
+ QSize sizeHint() const;
+
+ int idAt( int index ) const { return QMenuData::idAt( index ); }
+ int idAt( const QPoint& pos ) const;
+
+ bool customWhatsThis() const;
+
+ int insertTearOffHandle( int id=-1, int index=-1 );
+
+ void activateItemAt( int index );
+ QRect itemGeometry( int index );
+
+
+signals:
+ void activated( int itemId );
+ void highlighted( int itemId );
+ void activatedRedirect( int itemId ); // to parent menu
+ void highlightedRedirect( int itemId );
+ void aboutToShow();
+ void aboutToHide();
+
+protected:
+ int itemHeight( int ) const;
+ int itemHeight( QMenuItem* mi ) const;
+ void drawItem( QPainter* p, int tab, QMenuItem* mi,
+ bool act, int x, int y, int w, int h);
+
+ void drawContents( QPainter * );
+
+ void closeEvent( QCloseEvent *e );
+ void paintEvent( QPaintEvent * );
+ void mousePressEvent( QMouseEvent * );
+ void mouseReleaseEvent( QMouseEvent * );
+ void mouseMoveEvent( QMouseEvent * );
+ void keyPressEvent( QKeyEvent * );
+ void focusInEvent( QFocusEvent * );
+ void focusOutEvent( QFocusEvent * );
+ void timerEvent( QTimerEvent * );
+ void leaveEvent( QEvent * );
+ void styleChange( QStyle& );
+ void enabledChange( bool );
+ int columns() const;
+
+ bool focusNextPrevChild( bool next );
+
+ int itemAtPos( const QPoint &, bool ignoreSeparator = TRUE ) const;
+
+private slots:
+ void subActivated( int itemId );
+ void subHighlighted( int itemId );
+#ifndef QT_NO_ACCEL
+ void accelActivated( int itemId );
+ void accelDestroyed();
+#endif
+ void popupDestroyed( QObject* );
+ void modalActivation( int );
+
+ void subMenuTimer();
+ void subScrollTimer();
+ void allowAnimation();
+ void toggleTearOff();
+
+ void performDelayedChanges();
+
+private:
+ void updateScrollerState();
+ void menuContentsChanged();
+ void menuStateChanged();
+ void performDelayedContentsChanged();
+ void performDelayedStateChanged();
+ void menuInsPopup( PopupMenu * );
+ void menuDelPopup( PopupMenu * );
+ void frameChanged();
+
+ void actSig( int, bool = FALSE );
+ void hilitSig( int );
+ virtual void setFirstItemActive();
+ void hideAllPopups();
+ void hidePopups();
+ bool tryMenuBar( QMouseEvent * );
+ void byeMenuBar();
+
+ QSize updateSize(bool force_recalc=FALSE, bool do_resize=TRUE);
+ void updateRow( int row );
+#ifndef QT_NO_ACCEL
+ void updateAccel( QWidget * );
+ void enableAccel( bool );
+#endif
+ QPopupMenuPrivate *d;
+#ifndef QT_NO_ACCEL
+ QAccel *autoaccel;
+#endif
+
+#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
+ bool macPopupMenu(const QPoint &, int);
+ uint mac_dirty_popup : 1;
+#endif
+
+ int popupActive;
+ int tab;
+ uint accelDisabled : 1;
+ uint checkable : 1;
+ uint connectModalRecursionSafety : 1;
+ uint tornOff : 1;
+ uint pendingDelayedContentsChanges : 1;
+ uint pendingDelayedStateChanges : 1;
+ int maxPMWidth;
+ int ncols;
+ bool snapToMouse;
+ bool tryMouseEvent( PopupMenu *, QMouseEvent * );
+
+ friend class QMenuData;
+ friend class QMenuBar;
+
+ void connectModal(PopupMenu* receiver, bool doConnect);
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ PopupMenu( const PopupMenu & );
+ PopupMenu &operator=( const PopupMenu & );
+#endif
+};
+
+
+#endif // QT_NO_POPUPMENU
+
+#endif // QPOPUPMENU_H
+*/ \ No newline at end of file