diff options
-rw-r--r-- | muse/ChangeLog | 4 | ||||
-rw-r--r-- | muse/muse/app.cpp | 606 | ||||
-rw-r--r-- | muse/muse/app.h | 12 | ||||
-rw-r--r-- | muse/muse/arranger/arranger.h | 1 | ||||
-rw-r--r-- | muse/muse/arranger/pcanvas.cpp | 2 | ||||
-rw-r--r-- | muse/muse/arranger/trackinfo.cpp | 58 | ||||
-rw-r--r-- | muse/muse/audioprefetch.cpp | 2 | ||||
-rw-r--r-- | muse/muse/confmport.cpp | 25 | ||||
-rw-r--r-- | muse/muse/globals.cpp | 5 | ||||
-rw-r--r-- | muse/muse/globals.h | 12 | ||||
-rw-r--r-- | muse/muse/marker/markerview.cpp | 3 | ||||
-rw-r--r-- | muse/muse/mixer/astrip.cpp | 889 | ||||
-rw-r--r-- | muse/muse/mixer/astrip.h | 15 | ||||
-rw-r--r-- | muse/muse/mixer/mstrip.cpp | 57 | ||||
-rw-r--r-- | muse/muse/mixer/mstrip.h | 5 | ||||
-rw-r--r-- | muse/muse/mixer/strip.cpp | 6 | ||||
-rw-r--r-- | muse/muse/mixer/strip.h | 5 | ||||
-rw-r--r-- | muse/muse/song.cpp | 114 | ||||
-rw-r--r-- | muse/muse/song.h | 2 | ||||
-rw-r--r-- | muse/muse/widgets/Makefile.am | 2 | ||||
-rw-r--r-- | muse/muse/widgets/popupmenu.cpp | 2760 | ||||
-rw-r--r-- | muse/muse/widgets/popupmenu.h | 301 |
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 |