1
//=========================================================
4
// $Id: popupmenu.cpp,v 1.1.1.1 2010/07/18 03:21:00 terminator356 Exp $
6
// (C) Copyright 1999-2010 Werner Schweer (ws@seh.de)
8
// PopupMenu sub-class of QPopupMenu created by Tim.
9
//=========================================================
13
//=========================================================
15
// NOTICE: This sub-class of QPopupMenu *automatically* deletes
16
// and *clears* any sub popup menus, when clear() is called.
17
// Therefore a parent widget is *not* necessary when
18
// creating sub popup menus to add to the popup.
20
//=========================================================
23
// MusE: want no menu bar here. Can't use, not needed for now anyway.
25
#define QT_NO_WHATSTHIS
27
#include <qapplication.h>
29
#include <qguardedptr.h>
30
//#include <qmenubar.h>
32
//#include <qdatetime.h>
34
#include "popupmenu.h"
36
// used to provide ONE single-shot timer
37
//static QTimer * singleSingleShot = 0;
38
//static bool preventAnimation = FALSE;
39
// Used to detect motion prior to mouse-release
41
static PopupMenu* active_popup_menu = 0;
46
delete singleSingleShot;
50
static void popupSubMenuLater( int msec, QPopupMenu * receiver ) {
51
//static void popupSubMenuLater( int msec, PopupMenu * receiver ) {
52
if ( !singleSingleShot ) {
53
singleSingleShot = new QTimer( qApp, "popup submenu timer" );
54
qAddPostRoutine( cleanup );
57
singleSingleShot->disconnect( SIGNAL(timeout()) );
58
QObject::connect( singleSingleShot, SIGNAL(timeout()),
59
receiver, SLOT(subMenuTimer()) );
60
singleSingleShot->start( msec, TRUE );
65
//======================
67
//======================
72
QGuardedPtr<QWidget> aWidget;
76
//======================
78
//======================
80
class QPopupMenuPrivate {
83
enum { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
86
int topScrollableIndex, scrollableSize;
91
QRegion mouseMoveBuffer;
95
//======================
97
//======================
99
PopupMenu::PopupMenu(QWidget* parent, const char* name)
100
: QPopupMenu(parent, name)
102
// It's too bad QPopupMenu::d is private.
103
// It will be redundant and this will be our own private member.
104
//d = new QPopupMenuPrivate;
105
//d->scroll.scrollableSize = d->scroll.topScrollableIndex = 0;
106
//d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
107
//d->scroll.scrolltimer = 0;
110
PopupMenu::~PopupMenu()
112
//if(d->scroll.scrolltimer)
113
// delete d->scroll.scrolltimer;
115
//preventAnimation = FALSE;
118
// Make sure to clear the popup so that any child popups are also deleted !
122
void PopupMenu::menuDelPopup(QPopupMenu *popup)
124
//printf("PopupMenu::menuDelPopup deleting popup...\n");
126
// Make sure to clear the popup so that any child popups are also deleted !
127
// Tested OK. All the popups are deleted.
130
popup->disconnect( SIGNAL(activatedRedirect(int)) );
131
popup->disconnect( SIGNAL(highlightedRedirect(int)) );
132
disconnect( popup, SIGNAL(destroyed(QObject*)),
133
this, SLOT(popupDestroyed(QObject*)) );
138
void PopupMenu::setFirstItemActive()
140
QMenuItemListIt it(*QPopupMenu::mitems);
141
register QMenuItem *mi;
143
//if(d->scroll.scrollable)
144
// ai = d->scroll.topScrollableIndex;
145
while ( (mi=it.current()) )
148
if(!mi->isSeparator() && mi->id() != QMenuData::d->aInt &&
149
(style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this) || mi->isEnabledAndVisible()))
156
QPopupMenu::actItem = -1;
161
void PopupMenu::hideAllPopups()
163
//register QMenuData *top = this; // find top level popup
164
register MenuData *top = this; // find top level popup
165
if ( !preventAnimation )
166
QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
167
preventAnimation = TRUE;
170
return; // nothing to do
172
//while ( top->parentMenu && top->parentMenu->isPopupMenu
173
while ( top->parentMenu && ((MenuData*)top->parentMenu)->isPopupMenu
174
//&& ((QPopupMenu*)top->parentMenu)->isPopup() )
175
&& ((PopupMenu*)((MenuData*)top->parentMenu))->isPopup() )
176
//top = top->parentMenu;
177
top = (MenuData*)top->parentMenu;
178
//((QPopupMenu*)top)->hide(); // cascade from top level
179
((PopupMenu*)top)->hide(); // cascade from top level
181
#ifndef QT_NO_WHATSTHIS
192
void PopupMenu::hidePopups()
194
if ( !preventAnimation )
195
QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
196
preventAnimation = TRUE;
198
//QMenuItemListIt it(*mitems);
199
QMenuItemListIt it(*MenuData::mitems);
200
register QMenuItem *mi;
201
while ( (mi=it.current()) ) {
203
if ( mi->popup() && mi->popup()->parentMenu == this ) //avoid circularity
206
popupActive = -1; // no active sub menu
207
if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
208
d->mouseMoveBuffer = QRegion();
210
QRect mfrect = itemGeometry( actItem );
211
setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
215
bool PopupMenu::tryMenuBar( QMouseEvent *e )
217
register QMenuData *top = this; // find top level
218
//register PopupMenu *top = this; // find top level
219
//while ( top->parentMenu )
220
while ( ((PopupMenu*)top)->parentMenu )
221
//top = top->parentMenu;
222
//top = (MenuData*)top->parentMenu;
223
top = ((PopupMenu*)top)->parentMenu;
224
#ifndef QT_NO_MENUBAR
225
return top->isMenuBar ?
226
((QMenuBar *)top)->tryMouseEvent( this, e ) :
227
((QPopupMenu*)top)->tryMouseEvent(this, e );
229
//return ((QPopupMenu*)top)->tryMouseEvent(this, e );
230
return ((PopupMenu*)top)->tryMouseEvent(this, e );
234
//bool PopupMenu::tryMouseEvent( QPopupMenu *p, QMouseEvent * e)
235
bool PopupMenu::tryMouseEvent( PopupMenu *p, QMouseEvent * e)
239
QPoint pos = mapFromGlobal( e->globalPos() );
240
if ( !rect().contains( pos ) ) // outside
242
QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
248
void PopupMenu::byeMenuBar()
250
#ifndef QT_NO_MENUBAR
251
//register QMenuData *top = this; // find top level
252
register MenuData *top = this; // find top level
253
while ( top->parentMenu )
254
top = top->parentMenu;
257
#ifndef QT_NO_MENUBAR
258
if ( top->isMenuBar )
259
((QMenuBar *)top)->goodbye();
264
void PopupMenu::actSig(int id, bool inwhatsthis)
268
emit activated( id );
269
#if defined(QT_ACCESSIBILITY_SUPPORT)
271
QAccessible::updateAccessibility(this, indexOf(id)+1, QAccessible::MenuCommand);
276
#ifndef QT_NO_WHATSTHIS
277
QRect r(itemGeometry(indexOf(id)));
278
QPoint p(r.center().x(), r.bottom());
279
QString whatsThis = findItem(id)->whatsThis();
280
if(whatsThis.isNull())
281
whatsThis = QWhatsThis::textFor(this, p);
282
QWhatsThis::leaveWhatsThisMode(whatsThis, mapToGlobal(p), this);
286
emit activatedRedirect(id);
290
void PopupMenu::mousePressEvent(QMouseEvent *e)
292
printf("PopupMenu::mousePressEvent\n");
295
//int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
296
//if (rect().contains(e->pos()) &&
297
// ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
298
// (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
299
// e->pos().y() >= contentsRect().height() - sh))) //down
302
mouseBtDn = TRUE; // mouse button down
303
int item = itemAtPos( e->pos() );
305
//if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) {
310
register QMenuItem *mi = mitems->at(item);
311
///if ( item != actItem ) // new item activated
312
/// setActiveItem( item );
314
QPopupMenu *popup = mi->popup();
317
if(popup->isVisible()) // sub menu already open
319
//int pactItem = popup->actItem;
320
//popup->actItem = -1;
321
//popup->hidePopups();
322
//popup->updateRow( pactItem );
324
else // open sub menu
327
popupSubMenuLater( 20, this );
337
void PopupMenu::mouseReleaseEvent(QMouseEvent *e)
339
// do not hide a standalone context menu on press-release, unless
340
// the user moved the mouse significantly
341
//if(!parentMenu && !mouseBtDn && actItem < 0 && motion < 6)
345
//MenuData::mouseBtDn = FALSE;
346
QPopupMenu::mouseBtDn = FALSE;
348
// if the user released the mouse outside the menu, pass control
349
// to the menubar or our parent menu
350
//int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
351
if(!rect().contains(e->pos()) && tryMenuBar(e))
354
//if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
355
// (d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
356
// e->pos().y() >= contentsRect().height() - sh)) //down
359
if(QPopupMenu::actItem < 0)
361
// we do not have an active item
362
// if the release is inside without motion (happens with
363
// oversized popup menus on small screens), ignore it
364
if(rect().contains(e->pos()) && motion < 6)
371
// selected menu item!
372
register QMenuItem *mi = QPopupMenu::mitems->at(QPopupMenu::actItem);
375
QWidget* widgetAt = QApplication::widgetAt(e->globalPos(), TRUE);
376
if(widgetAt && widgetAt != this)
378
QMouseEvent me(e->type(), widgetAt->mapFromGlobal(e->globalPos()),
379
e->globalPos(), e->button(), e->state());
380
QApplication::sendEvent( widgetAt, &me );
383
//QPopupMenu *popup = mi->popup();
384
PopupMenu *popup = (PopupMenu*)mi->popup();
385
#ifndef QT_NO_WHATSTHIS
386
bool b = QWhatsThis::inWhatsThisMode();
388
const bool b = FALSE;
390
if(!mi->isEnabledAndVisible())
392
#ifndef QT_NO_WHATSTHIS
396
updateItem(mi->id());
405
//popup->setFirstItemActive();
410
///byeMenuBar(); // deactivate menu bar
411
if(mi->isEnabledAndVisible())
413
///QPopupMenu::actItem = -1;
414
QPopupMenu::updateItem(mi->id());
415
active_popup_menu = this;
416
QGuardedPtr<QSignal> signal = mi->signal();
420
active_popup_menu = 0;
431
/****************************************************************************
433
** Implementation of QPopupMenu class
437
** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
439
** This file is part of the widgets module of the Qt GUI Toolkit.
441
** This file may be used under the terms of the GNU General
442
** Public License versions 2.0 or 3.0 as published by the Free
443
** Software Foundation and appearing in the files LICENSE.GPL2
444
** and LICENSE.GPL3 included in the packaging of this file.
445
** Alternatively you may (at your option) use any later version
446
** of the GNU General Public License if such license has been
447
** publicly approved by Trolltech ASA (or its successors, if any)
448
** and the KDE Free Qt Foundation.
450
** Please review the following information to ensure GNU General
451
** Public Licensing requirements will be met:
452
** http://trolltech.com/products/qt/licenses/licensing/opensource/.
453
** If you are unsure which license is appropriate for your use, please
454
** review the following information:
455
** http://trolltech.com/products/qt/licenses/licensing/licensingoverview
456
** or contact the sales department at sales@trolltech.com.
458
** This file may be used under the terms of the Q Public License as
459
** defined by Trolltech ASA and appearing in the file LICENSE.QPL
460
** included in the packaging of this file. Licensees holding valid Qt
461
** Commercial licenses may use this file in accordance with the Qt
462
** Commercial License Agreement provided with the Software.
464
** This file is provided "AS IS" with NO WARRANTY OF ANY KIND,
465
** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR
466
** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted
469
**********************************************************************/
472
#include "popupmenu.h"
473
#ifndef QT_NO_POPUPMENU
474
#include <qmenubar.h>
476
#include <qpainter.h>
477
#include <qdrawutil.h>
478
#include <qapplication.h>
480
#include <qpixmapcache.h>
482
#include <qwhatsthis.h>
483
#include <qobjectlist.h>
484
#include <qguardedptr.h>
485
//#include <qeffects_p.h>
489
#include <qdatetime.h>
490
#if defined(QT_ACCESSIBILITY_SUPPORT)
491
#include <qaccessible.h>
494
//#define ANIMATED_POPUP
495
//#define BLEND_POPUP
497
// Motif style parameters
499
static const int motifArrowHMargin = 6; // arrow horizontal margin
500
static const int motifArrowVMargin = 2; // arrow vertical margin
503
# define DEBUG_SLOPPY_SUBMENU
506
// used for internal communication
507
static PopupMenu * syncMenu = 0;
508
static int syncMenuId = 0;
510
// Used to detect motion prior to mouse-release
513
// used to provide ONE single-shot timer
514
static QTimer * singleSingleShot = 0;
516
static bool supressAboutToShow = FALSE;
518
static void cleanup()
520
delete singleSingleShot;
521
singleSingleShot = 0;
524
static void popupSubMenuLater( int msec, PopupMenu * receiver ) {
525
if ( !singleSingleShot ) {
526
singleSingleShot = new QTimer( qApp, "popup submenu timer" );
527
qAddPostRoutine( cleanup );
530
singleSingleShot->disconnect( SIGNAL(timeout()) );
531
QObject::connect( singleSingleShot, SIGNAL(timeout()),
532
receiver, SLOT(subMenuTimer()) );
533
singleSingleShot->start( msec, TRUE );
536
static bool preventAnimation = FALSE;
538
#ifndef QT_NO_WHATSTHIS
539
extern void qWhatsThisBDH();
540
static QMenuItem* whatsThisItem = 0;
543
class QMenuDataData {
544
// attention: also defined in qmenudata.cpp
547
QGuardedPtr<QWidget> aWidget;
551
class QPopupMenuPrivate {
554
enum { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
557
int topScrollableIndex, scrollableSize;
562
QRegion mouseMoveBuffer;
565
static PopupMenu* active_popup_menu = 0;
567
PopupMenu::PopupMenu( QWidget *parent, const char *name )
568
: QFrame( parent, name, WType_Popup | WNoAutoErase )
570
d = new QPopupMenuPrivate;
571
d->scroll.scrollableSize = d->scroll.topScrollableIndex = 0;
572
d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
573
d->scroll.scrolltimer = 0;
577
accelDisabled = FALSE;
584
pendingDelayedContentsChanges = 0;
585
pendingDelayedStateChanges = 0;
590
setFrameStyle( QFrame::PopupPanel | QFrame::Raised );
591
setMouseTracking(style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this));
592
//style().polishPopupMenu( this );
593
style().polishPopupMenu( (QPopupMenu*)this );
594
setBackgroundMode( PaletteButton );
595
connectModalRecursionSafety = 0;
597
setFocusPolicy( StrongFocus );
600
PopupMenu::~PopupMenu()
602
if ( syncMenu == this && qApp ) {
607
if(d->scroll.scrolltimer)
608
delete d->scroll.scrolltimer;
615
delete (QWidget*) QMenuData::d->aWidget; // tear-off menu
617
preventAnimation = FALSE;
622
void PopupMenu::updateItem( int id ) // update popup menu item
624
updateRow( indexOf(id) );
628
void PopupMenu::setCheckable( bool enable )
630
if ( isCheckable() != enable ) {
633
if ( QMenuData::d->aWidget )
634
( (PopupMenu*)(QWidget*)QMenuData::d->aWidget)->setCheckable( enable );
638
bool PopupMenu::isCheckable() const
643
void PopupMenu::menuContentsChanged()
645
// here the part that can't be delayed
646
QMenuData::menuContentsChanged();
647
badSize = TRUE; // might change the size
648
#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
651
if( pendingDelayedContentsChanges )
653
pendingDelayedContentsChanges = 1;
654
if( !pendingDelayedStateChanges ) // if the timer hasn't been started yet
655
QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
658
void PopupMenu::performDelayedContentsChanged()
660
pendingDelayedContentsChanges = 0;
661
// here the part the can be delayed
663
// if performDelayedStateChanged() will be called too,
664
// it will call updateAccel() too, no need to do it twice
665
if( !pendingDelayedStateChanges )
674
PopupMenu* p = (PopupMenu*)(QWidget*)QMenuData::d->aWidget;
675
if ( p && p->isVisible() ) {
679
#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
685
void PopupMenu::menuStateChanged()
687
// here the part that can't be delayed
688
if( pendingDelayedStateChanges )
690
pendingDelayedStateChanges = 1;
691
if( !pendingDelayedContentsChanges ) // if the timer hasn't been started yet
692
QTimer::singleShot( 0, this, SLOT(performDelayedChanges()));
695
void PopupMenu::performDelayedStateChanged()
697
pendingDelayedStateChanges = 0;
698
// here the part that can be delayed
700
updateAccel( 0 ); // ### when we have a good solution for the accel vs. focus widget problem, remove that. That is only a workaround
701
// if you remove this, see performDelayedContentsChanged()
704
if ( QMenuData::d->aWidget )
705
QMenuData::d->aWidget->update();
708
void PopupMenu::performDelayedChanges()
710
if( pendingDelayedContentsChanges )
711
performDelayedContentsChanged();
712
if( pendingDelayedStateChanges )
713
performDelayedStateChanged();
716
void PopupMenu::menuInsPopup( PopupMenu *popup )
718
connect( popup, SIGNAL(activatedRedirect(int)),
719
SLOT(subActivated(int)) );
720
connect( popup, SIGNAL(highlightedRedirect(int)),
721
SLOT(subHighlighted(int)) );
722
connect( popup, SIGNAL(destroyed(QObject*)),
723
this, SLOT(popupDestroyed(QObject*)) );
726
void PopupMenu::menuDelPopup( PopupMenu *popup )
728
popup->disconnect( SIGNAL(activatedRedirect(int)) );
729
popup->disconnect( SIGNAL(highlightedRedirect(int)) );
730
disconnect( popup, SIGNAL(destroyed(QObject*)),
731
this, SLOT(popupDestroyed(QObject*)) );
735
void PopupMenu::frameChanged()
737
menuContentsChanged();
740
void PopupMenu::popup( const QPoint &pos, int indexAtPoint )
742
if ( !isPopup() && isVisible() )
746
if ( isVisible() || !isEnabled() )
749
#if defined(Q_WS_MAC) && !defined(QMAC_QMENUBAR_NO_NATIVE)
750
if( macPopupMenu(pos, indexAtPoint ))
754
#if (QT_VERSION-0 >= 0x040000)
755
#error "Fix this now"
756
// #### should move to QWidget - anything might need this functionality,
757
// #### since anything can have WType_Popup window flag.
758
// #### This includes stuff in QPushButton and some stuff for setting
759
// #### the geometry of QDialog.
763
// QPushButton (shouldn't require QMenuPopup)
765
// Some stuff in qwidget.cpp for dialogs... can't remember exactly.
766
// Also the code here indicatets the parameter should be a rect, not a
770
if(d->scroll.scrollable) {
771
d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
772
d->scroll.topScrollableIndex = d->scroll.scrollableSize = 0;
777
QPoint mouse = QCursor::pos();
778
snapToMouse = pos == mouse;
780
// have to emit here as a menu might be setup in a slot connected
781
// to aboutToShow which will change the size of the menu
782
bool s = supressAboutToShow;
783
supressAboutToShow = TRUE;
790
if (QApplication::desktop()->isVirtualDesktop())
792
QApplication::desktop()->screenNumber( QApplication::reverseLayout() ?
793
pos+QPoint(width(),0) : pos );
795
screen_num = QApplication::desktop()->screenNumber( this );
797
QRect screen = QApplication::desktop()->availableGeometry( screen_num );
799
QRect screen = QApplication::desktop()->screenGeometry( screen_num );
801
int sw = screen.width(); // screen width
802
int sh = screen.height(); // screen height
803
int sx = screen.x(); // screen pos
807
if ( indexAtPoint >= 0 ) // don't subtract when < 0
808
y -= itemGeometry( indexAtPoint ).y(); // (would subtract 2 pixels!)
813
if ( qApp->reverseLayout() )
825
if ( x+w > sx+sw ) // the complete widget must
826
x = sx+sw - w; // be visible
834
if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
835
int off_top = 0, off_bottom = 0;
837
off_bottom = (y+h) - (sy+sh);
840
if(off_bottom || off_top) {
841
int ch = updateSize().height(); //store the old height, before setting scrollable --Sam
842
const int vextra = style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this);
843
d->scroll.scrollableSize = h - off_top - off_bottom - 2*vextra;
846
d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollUp;
849
d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollDown;
850
if( off_top != off_bottom && indexAtPoint >= 0 ) {
852
if(ch > sh) //no bigger than the screen!
854
if( ch > d->scroll.scrollableSize )
855
d->scroll.scrollableSize = ch;
858
updateSize(TRUE); //now set the size using the scrollable/scrollableSize as above
861
if(indexAtPoint >= 0) {
862
if(off_top) { //scroll to it
863
register QMenuItem *mi = NULL;
864
QMenuItemListIt it(*mitems);
865
for(int tmp_y = 0; tmp_y < off_top && (mi=it.current()); ) {
866
QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
867
QSize(0, itemHeight( mi )),
868
QStyleOption(mi,maxPMWidth,0));
869
tmp_y += sz.height();
870
d->scroll.topScrollableIndex++;
880
#ifndef QT_NO_EFFECTS
881
int hGuess = qApp->reverseLayout() ? QEffects::LeftScroll : QEffects::RightScroll;
882
int vGuess = QEffects::DownScroll;
883
if ( qApp->reverseLayout() ) {
884
if ( snapToMouse && ( x + w/2 > mouse.x() ) ||
885
( parentMenu && parentMenu->isPopupMenu &&
886
( x + w/2 > ((PopupMenu*)parentMenu)->x() ) ) )
887
hGuess = QEffects::RightScroll;
889
if ( snapToMouse && ( x + w/2 < mouse.x() ) ||
890
( parentMenu && parentMenu->isPopupMenu &&
891
( x + w/2 < ((PopupMenu*)parentMenu)->x() ) ) )
892
hGuess = QEffects::LeftScroll;
895
#ifndef QT_NO_MENUBAR
896
if ( snapToMouse && ( y + h/2 < mouse.y() ) ||
897
( parentMenu && parentMenu->isMenuBar &&
898
( y + h/2 < ((QMenuBar*)parentMenu)->mapToGlobal( ((QMenuBar*)parentMenu)->pos() ).y() ) ) )
899
vGuess = QEffects::UpScroll;
902
if ( QApplication::isEffectEnabled( UI_AnimateMenu ) &&
903
preventAnimation == FALSE ) {
904
if ( QApplication::isEffectEnabled( UI_FadeMenu ) )
906
else if ( parentMenu )
907
qScrollEffect( this, parentMenu->isPopupMenu ? hGuess : vGuess );
909
qScrollEffect( this, hGuess | vGuess );
915
#if defined(QT_ACCESSIBILITY_SUPPORT)
916
QAccessible::updateAccessibility( this, 0, QAccessible::PopupMenuStart );
920
void PopupMenu::subActivated( int id )
922
emit activatedRedirect( id );
925
void PopupMenu::subHighlighted( int id )
927
emit highlightedRedirect( id );
930
static bool fromAccel = FALSE;
933
void PopupMenu::accelActivated( int id )
935
QMenuItem *mi = findItem( id );
936
if ( mi && mi->isEnabledAndVisible() ) {
937
QGuardedPtr<QSignal> signal = mi->signal();
946
void PopupMenu::accelDestroyed() // accel about to be deleted
948
autoaccel = 0; // don't delete it twice!
952
void PopupMenu::popupDestroyed( QObject *o )
954
removePopup( (PopupMenu*)o );
957
void PopupMenu::actSig( int id, bool inwhatsthis )
959
if ( !inwhatsthis ) {
960
emit activated( id );
961
#if defined(QT_ACCESSIBILITY_SUPPORT)
963
QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::MenuCommand );
966
#ifndef QT_NO_WHATSTHIS
967
QRect r( itemGeometry( indexOf( id ) ) );
968
QPoint p( r.center().x(), r.bottom() );
969
QString whatsThis = findItem( id )->whatsThis();
970
if ( whatsThis.isNull() )
971
whatsThis = QWhatsThis::textFor( this, p );
972
QWhatsThis::leaveWhatsThisMode( whatsThis, mapToGlobal( p ), this );
976
emit activatedRedirect( id );
979
void PopupMenu::hilitSig( int id )
981
emit highlighted( id );
982
emit highlightedRedirect( id );
984
#if defined(QT_ACCESSIBILITY_SUPPORT)
985
QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::Focus );
986
QAccessible::updateAccessibility( this, indexOf(id)+1, QAccessible::Selection );
990
void PopupMenu::setFirstItemActive()
992
QMenuItemListIt it(*mitems);
993
register QMenuItem *mi;
995
if(d->scroll.scrollable)
996
ai = d->scroll.topScrollableIndex;
997
while ( (mi=it.current()) ) {
999
if ( !mi->isSeparator() && mi->id() != QMenuData::d->aInt &&
1000
( style().styleHint( QStyle::SH_PopupMenu_AllowActiveAndDisabled, this ) || mi->isEnabledAndVisible() )) {
1001
setActiveItem( ai );
1009
void PopupMenu::hideAllPopups()
1011
register QMenuData *top = this; // find top level popup
1012
if ( !preventAnimation )
1013
QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
1014
preventAnimation = TRUE;
1017
return; // nothing to do
1019
while ( top->parentMenu && top->parentMenu->isPopupMenu
1020
&& ((PopupMenu*)top->parentMenu)->isPopup() )
1021
top = top->parentMenu;
1022
((PopupMenu*)top)->hide(); // cascade from top level
1024
#ifndef QT_NO_WHATSTHIS
1025
if (whatsThisItem) {
1033
void PopupMenu::hidePopups()
1035
if ( !preventAnimation )
1036
QTimer::singleShot( 10, this, SLOT(allowAnimation()) );
1037
preventAnimation = TRUE;
1039
QMenuItemListIt it(*mitems);
1040
register QMenuItem *mi;
1041
while ( (mi=it.current()) ) {
1043
if ( mi->popup() && mi->popup()->parentMenu == this ) //avoid circularity
1044
mi->popup()->hide();
1046
popupActive = -1; // no active sub menu
1047
if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
1048
d->mouseMoveBuffer = QRegion();
1050
QRect mfrect = itemGeometry( actItem );
1051
setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
1054
bool PopupMenu::tryMenuBar( QMouseEvent *e )
1056
register QMenuData *top = this; // find top level
1057
while ( top->parentMenu )
1058
top = top->parentMenu;
1059
#ifndef QT_NO_MENUBAR
1060
return top->isMenuBar ?
1061
((QMenuBar *)top)->tryMouseEvent( this, e ) :
1062
((PopupMenu*)top)->tryMouseEvent(this, e );
1064
return ((PopupMenu*)top)->tryMouseEvent(this, e );
1068
bool PopupMenu::tryMouseEvent( PopupMenu *p, QMouseEvent * e)
1072
QPoint pos = mapFromGlobal( e->globalPos() );
1073
if ( !rect().contains( pos ) ) // outside
1075
QMouseEvent ee( e->type(), pos, e->globalPos(), e->button(), e->state() );
1080
void PopupMenu::byeMenuBar()
1082
#ifndef QT_NO_MENUBAR
1083
register QMenuData *top = this; // find top level
1084
while ( top->parentMenu )
1085
top = top->parentMenu;
1088
#ifndef QT_NO_MENUBAR
1089
if ( top->isMenuBar )
1090
((QMenuBar *)top)->goodbye();
1094
int PopupMenu::itemAtPos( const QPoint &pos, bool ignoreSeparator ) const
1096
if ( !contentsRect().contains(pos) )
1100
int x = contentsRect().x();
1101
int y = contentsRect().y();
1103
QMenuItemListIt it( *mitems );
1104
if(d->scroll.scrollable) {
1105
if(d->scroll.topScrollableIndex) {
1106
for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
1112
y += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1115
int itemw = contentsRect().width() / ncols;
1117
while ( (mi=it.current()) ) {
1118
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
1119
y >= contentsRect().height() - style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this))
1122
if ( !mi->isVisible() ) {
1126
int itemh = itemHeight( mi );
1128
sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
1130
QStyleOption(mi,maxPMWidth));
1131
sz = sz.expandedTo(QSize(itemw, sz.height()));
1133
itemh = sz.height();
1135
if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
1136
y = contentsRect().y();
1139
if ( QRect( x, y, itemw, itemh ).contains( pos ) )
1145
if ( mi && ( !ignoreSeparator || !mi->isSeparator() ) )
1150
QRect PopupMenu::itemGeometry( int index )
1154
int row = 0, scrollh = 0;
1155
int x = contentsRect().x();
1156
int y = contentsRect().y();
1157
QMenuItemListIt it( *mitems );
1158
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) {
1159
scrollh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1161
if(d->scroll.topScrollableIndex) {
1162
for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
1170
int itemw = contentsRect().width() / ncols;
1171
while ( (mi=it.current()) ) {
1172
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
1173
y >= contentsRect().height() - scrollh)
1176
if ( !mi->isVisible() ) {
1180
int itemh = itemHeight( mi );
1182
sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
1184
QStyleOption(mi,maxPMWidth));
1185
sz = sz.expandedTo(QSize(itemw, sz.height()));
1187
itemh = sz.height();
1188
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
1189
(y + itemh > contentsRect().height() - scrollh))
1190
itemh -= (y + itemh) - (contentsRect().height() - scrollh);
1191
if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
1192
y = contentsRect().y();
1196
return QRect( x,y,itemw,itemh );
1201
return QRect(0,0,0,0);
1204
QSize PopupMenu::updateSize(bool force_update, bool do_resize)
1207
if ( count() == 0 ) {
1208
QSize ret = QSize( 50, 8 );
1210
setFixedSize( ret );
1216
if(d->scroll.scrollableSize) {
1217
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp)
1218
scrheight += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1219
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown)
1220
scrheight += style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1223
if(badSize || force_update) {
1228
int max_width = 0, max_height = 0;
1229
QFontMetrics fm = fontMetrics();
1230
register QMenuItem *mi;
1232
int maxWidgetWidth = 0;
1235
for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
1237
QWidget *miw = mi->widget();
1239
if ( miw->parentWidget() != this )
1240
miw->reparent( this, QPoint(0,0), TRUE );
1241
// widget items musn't propgate mouse events
1242
((PopupMenu*)miw)->setWFlags(WNoMousePropagation);
1245
mi->custom()->setFont( font() );
1246
if ( mi->iconSet() != 0)
1247
maxPMWidth = QMAX( maxPMWidth,
1248
mi->iconSet()->pixmap( QIconSet::Small, QIconSet::Normal ).width() + 4 );
1251
int dh = QApplication::desktop()->height();
1254
for ( QMenuItemListIt it2( *mitems ); it2.current(); ++it2 ) {
1256
if ( !mi->isVisible() )
1259
int itemHeight = PopupMenu::itemHeight( mi );
1261
if ( mi->widget() ) {
1262
QSize s( mi->widget()->sizeHint() );
1263
s = s.expandedTo( mi->widget()->minimumSize() );
1264
mi->widget()->resize( s );
1265
if ( s.width() > maxWidgetWidth )
1266
maxWidgetWidth = s.width();
1267
itemHeight = s.height();
1269
if( ! mi->isSeparator() ) {
1270
if ( mi->custom() ) {
1271
if ( mi->custom()->fullSpan() ) {
1272
maxWidgetWidth = QMAX( maxWidgetWidth,
1273
mi->custom()->sizeHint().width() );
1275
QSize s ( mi->custom()->sizeHint() );
1282
if (! mi->text().isNull()) {
1283
QString s = mi->text();
1285
if ( (t = s.find('\t')) >= 0 ) { // string contains tab
1286
w += fm.width( s, t );
1287
w -= s.contains('&') * fm.width('&');
1288
w += s.contains("&&") * fm.width('&');
1289
int tw = fm.width( s.mid(t + 1) );
1294
w -= s.contains('&') * fm.width('&');
1295
w += s.contains("&&") * fm.width('&');
1297
} else if (mi->pixmap())
1298
w += mi->pixmap()->width();
1300
if ( mi->custom() ) {
1301
QSize s ( mi->custom()->sizeHint() );
1308
QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
1309
QSize(w, itemHeight),
1310
QStyleOption(mi,maxPMWidth));
1313
itemHeight = sz.height();
1315
#if defined(QT_CHECK_NULL)
1316
if ( mi->text().isNull() && !mi->pixmap() && !mi->iconSet() &&
1317
!mi->isSeparator() && !mi->widget() && !mi->custom() )
1318
qWarning( "PopupMenu: (%s) Popup has invalid menu item",
1319
name( "unnamed" ) );
1322
height += itemHeight;
1323
if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
1324
if(scrheight && height >= d->scroll.scrollableSize - scrheight) {
1325
height = d->scroll.scrollableSize - scrheight;
1328
} else if( height + 2*frameWidth() >= dh ) {
1330
max_height = QMAX(max_height, height - itemHeight);
1331
height = itemHeight;
1333
if ( w > max_width )
1336
if( ncols == 1 && !max_height )
1337
max_height = height;
1339
if(style().styleHint(QStyle::SH_PopupMenu_Scrollable, this)) {
1340
height += scrheight;
1341
setMouseTracking(TRUE);
1345
tab -= fontMetrics().minRightBearing();
1347
max_width -= fontMetrics().minRightBearing();
1349
if ( max_width + tab < maxWidgetWidth )
1350
max_width = maxWidgetWidth - tab;
1352
const int fw = frameWidth();
1353
int extra_width = (fw+style().pixelMetric(QStyle::PM_PopupMenuFrameHorizontalExtra, this)) * 2,
1354
extra_height = (fw+style().pixelMetric(QStyle::PM_PopupMenuFrameVerticalExtra, this)) * 2;
1356
d->calcSize = QSize( QMAX( minimumWidth(), max_width + tab + extra_width ),
1357
QMAX( minimumHeight() , height + extra_height ) );
1359
d->calcSize = QSize( QMAX( minimumWidth(), (ncols*(max_width + tab)) + extra_width ),
1360
QMAX( minimumHeight(), QMIN( max_height + extra_height + 1, dh ) ) );
1365
// Position the widget items. It could be done in drawContents
1366
// but this way we get less flicker.
1368
int x = contentsRect().x();
1369
int y = contentsRect().y();
1370
int itemw = contentsRect().width() / ncols;
1371
for(QMenuItemListIt it(*mitems); it.current(); ++it) {
1372
QMenuItem *mi = it.current();
1373
if ( !mi->isVisible() )
1376
int itemh = itemHeight( mi );
1378
sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
1379
QSize(0, itemh), QStyleOption(mi,maxPMWidth));
1380
sz = sz.expandedTo(QSize(itemw, sz.height()));
1382
itemh = sz.height();
1384
if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
1385
y = contentsRect().y();
1389
mi->widget()->setGeometry( x, y, itemw, mi->widget()->height() );
1394
if( do_resize && size() != d->calcSize ) {
1395
setMaximumSize( d->calcSize );
1396
d->calcSize = maximumSize(); //let the max size adjust it (virtual)
1397
resize( d->calcSize );
1403
void PopupMenu::updateAccel( QWidget *parent )
1405
QMenuItemListIt it(*mitems);
1406
register QMenuItem *mi;
1411
} else if ( !autoaccel ) {
1412
// we have no parent. Rather than ignoring any accelerators we try to find this popup's main window
1416
QWidget *w = (QWidget *) this;
1417
parent = w->parentWidget();
1418
while ( (!w->testWFlags(WType_TopLevel) || !w->testWFlags(WType_Popup)) && parent ) {
1420
parent = parent->parentWidget();
1425
if ( parent == 0 && autoaccel == 0 )
1428
if ( autoaccel ) // build it from scratch
1431
// create an autoaccel in any case, even if we might not use
1432
// it immediately. Maybe the user needs it later.
1433
autoaccel = new QAccel( parent, this );
1434
connect( autoaccel, SIGNAL(activated(int)),
1435
SLOT(accelActivated(int)) );
1436
connect( autoaccel, SIGNAL(activatedAmbiguously(int)),
1437
SLOT(accelActivated(int)) );
1438
connect( autoaccel, SIGNAL(destroyed()),
1439
SLOT(accelDestroyed()) );
1440
if ( accelDisabled )
1441
autoaccel->setEnabled( FALSE );
1443
while ( (mi=it.current()) ) {
1445
QKeySequence k = mi->key();
1447
int id = autoaccel->insertItem( k, mi->id() );
1448
#ifndef QT_NO_WHATSTHIS
1449
autoaccel->setWhatsThis( id, mi->whatsThis() );
1452
if ( !mi->text().isNull() || mi->custom() ) {
1453
QString s = mi->text();
1454
int i = s.find('\t');
1456
// Note: Only looking at the first key in the sequence!
1457
if ( (int)k && (int)k != Key_unknown ) {
1458
QString t = (QString)mi->key();
1460
s.replace( i+1, s.length()-i, t );
1469
if ( s != mi->text() ) {
1474
if ( mi->popup() && parent ) { // call recursively
1476
PopupMenu* popup = mi->popup();
1477
if (!popup->avoid_circularity) {
1478
popup->avoid_circularity = 1;
1479
popup->updateAccel( parent );
1480
popup->avoid_circularity = 0;
1486
void PopupMenu::enableAccel( bool enable )
1489
autoaccel->setEnabled( enable );
1490
accelDisabled = !enable; // rememeber when updateAccel
1491
QMenuItemListIt it(*mitems);
1492
register QMenuItem *mi;
1493
while ( (mi=it.current()) ) { // do the same for sub popups
1495
if ( mi->popup() ) // call recursively
1496
mi->popup()->enableAccel( enable );
1501
void PopupMenu::setFont( const QFont &font )
1503
QWidget::setFont( font );
1505
if ( isVisible() ) {
1511
void PopupMenu::show()
1513
if ( !isPopup() && isVisible() )
1516
if ( isVisible() ) {
1517
supressAboutToShow = FALSE;
1521
if (!supressAboutToShow)
1524
supressAboutToShow = FALSE;
1525
performDelayedChanges();
1529
if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
1530
d->mouseMoveBuffer = QRegion();
1533
void PopupMenu::hide()
1535
if ( syncMenu == this && qApp ) {
1540
if ( !isVisible() ) {
1546
actItem = popupActive = -1;
1547
if(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this))
1548
d->mouseMoveBuffer = QRegion();
1549
mouseBtDn = FALSE; // mouse button up
1550
#if defined(QT_ACCESSIBILITY_SUPPORT)
1551
QAccessible::updateAccessibility( this, 0, QAccessible::PopupMenuEnd );
1558
int PopupMenu::itemHeight( int row ) const
1560
return itemHeight( mitems->at( row ) );
1563
int PopupMenu::itemHeight( QMenuItem *mi ) const
1566
return mi->widget()->height();
1567
if ( mi->custom() && mi->custom()->fullSpan() )
1568
return mi->custom()->sizeHint().height();
1570
QFontMetrics fm(fontMetrics());
1572
if ( mi->isSeparator() ) // separator height
1574
else if ( mi->pixmap() ) // pixmap height
1575
h = mi->pixmap()->height();
1579
if ( !mi->isSeparator() && mi->iconSet() != 0 )
1580
h = QMAX(h, mi->iconSet()->pixmap( QIconSet::Small,
1581
QIconSet::Normal ).height());
1583
h = QMAX(h, mi->custom()->sizeHint().height());
1588
void PopupMenu::drawItem( QPainter* p, int tab_, QMenuItem* mi,
1589
bool act, int x, int y, int w, int h)
1591
QStyle::SFlags flags = QStyle::Style_Default;
1592
if (isEnabled() && mi->isEnabledAndVisible() && (!mi->popup() || mi->popup()->isEnabled()) )
1593
flags |= QStyle::Style_Enabled;
1595
flags |= QStyle::Style_Active;
1597
flags |= QStyle::Style_Down;
1599
const QColorGroup &cg = ((flags&QStyle::Style_Enabled) ? colorGroup() : palette().disabled() );
1601
if ( mi->custom() && mi->custom()->fullSpan() ) {
1603
style().drawControl(QStyle::CE_PopupMenuItem, p, this, QRect(x, y, w, h), cg,
1604
flags, QStyleOption(&dummy,maxPMWidth,tab_));
1605
mi->custom()->paint( p, cg, act, flags&QStyle::Style_Enabled, x, y, w, h );
1607
style().drawControl(QStyle::CE_PopupMenuItem, p, this, QRect(x, y, w, h), cg,
1608
flags, QStyleOption(mi,maxPMWidth,tab_));
1611
void PopupMenu::drawContents( QPainter* p )
1613
QMenuItemListIt it(*mitems);
1616
int x = contentsRect().x();
1617
int y = contentsRect().y();
1618
if(d->scroll.scrollable) {
1619
if(d->scroll.topScrollableIndex) {
1620
for( ; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
1625
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) {
1626
QRect rect(x, y, contentsRect().width(),
1627
style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this));
1628
if(!p->hasClipping() || p->clipRegion().contains(rect)) {
1629
QStyle::SFlags flags = QStyle::Style_Up;
1631
flags |= QStyle::Style_Enabled;
1632
style().drawControl(QStyle::CE_PopupMenuScroller, p, this, rect,
1633
colorGroup(), flags, QStyleOption(maxPMWidth));
1639
int itemw = contentsRect().width() / ncols;
1641
QStyle::SFlags flags;
1642
while ( (mi=it.current()) ) {
1643
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
1644
y >= contentsRect().height() - style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this))
1647
if ( !mi->isVisible() ) {
1651
int itemh = itemHeight( mi );
1652
sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
1654
QStyleOption(mi,maxPMWidth,0)
1656
sz = sz.expandedTo(QSize(itemw, sz.height()));
1658
itemh = sz.height();
1660
if ( ncols > 1 && y + itemh > contentsRect().bottom() ) {
1661
if ( y < contentsRect().bottom() ) {
1662
QRect rect(x, y, itemw, contentsRect().bottom() - y);
1663
if(!p->hasClipping() || p->clipRegion().contains(rect)) {
1664
flags = QStyle::Style_Default;
1665
if (isEnabled() && mi->isEnabledAndVisible())
1666
flags |= QStyle::Style_Enabled;
1667
style().drawControl(QStyle::CE_PopupMenuItem, p, this, rect,
1668
colorGroup(), flags, QStyleOption((QMenuItem*)0,maxPMWidth));
1671
y = contentsRect().y();
1674
if (!mi->widget() && (!p->hasClipping() || p->clipRegion().contains(QRect(x, y, itemw, itemh))))
1675
drawItem( p, tab, mi, row == actItem, x, y, itemw, itemh );
1679
if ( y < contentsRect().bottom() ) {
1680
QRect rect(x, y, itemw, contentsRect().bottom() - y);
1681
if(!p->hasClipping() || p->clipRegion().contains(rect)) {
1682
flags = QStyle::Style_Default;
1684
flags |= QStyle::Style_Enabled;
1685
style().drawControl(QStyle::CE_PopupMenuItem, p, this, rect,
1686
colorGroup(), flags, QStyleOption((QMenuItem*)0,maxPMWidth));
1689
if( d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown ) {
1690
int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1691
QRect rect(x, contentsRect().height() - sh, contentsRect().width(), sh);
1692
if(!p->hasClipping() || p->clipRegion().contains(rect)) {
1693
QStyle::SFlags flags = QStyle::Style_Down;
1695
flags |= QStyle::Style_Enabled;
1696
style().drawControl(QStyle::CE_PopupMenuScroller, p, this, rect,
1697
colorGroup(), flags, QStyleOption(maxPMWidth));
1700
#if defined( DEBUG_SLOPPY_SUBMENU )
1701
if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
1702
p->setClipRegion( d->mouseMoveBuffer );
1703
p->fillRect( d->mouseMoveBuffer.boundingRect(), colorGroup().brush( QColorGroup::Highlight ) );
1708
void PopupMenu::paintEvent( QPaintEvent *e )
1710
QFrame::paintEvent( e );
1713
void PopupMenu::closeEvent( QCloseEvent * e) {
1718
void PopupMenu::mousePressEvent( QMouseEvent *e )
1720
int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1721
if (rect().contains(e->pos()) &&
1722
((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
1723
(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
1724
e->pos().y() >= contentsRect().height() - sh))) //down
1727
mouseBtDn = TRUE; // mouse button down
1728
int item = itemAtPos( e->pos() );
1730
if ( !rect().contains(e->pos()) && !tryMenuBar(e) ) {
1735
register QMenuItem *mi = mitems->at(item);
1736
if ( item != actItem ) // new item activated
1737
setActiveItem( item );
1739
PopupMenu *popup = mi->popup();
1741
if ( popup->isVisible() ) { // sub menu already open
1742
int pactItem = popup->actItem;
1743
popup->actItem = -1;
1744
popup->hidePopups();
1745
popup->updateRow( pactItem );
1746
} else { // open sub menu
1748
popupSubMenuLater( 20, this );
1755
void PopupMenu::mouseReleaseEvent( QMouseEvent *e )
1757
// do not hide a standalone context menu on press-release, unless
1758
// the user moved the mouse significantly
1759
if ( !parentMenu && !mouseBtDn && actItem < 0 && motion < 6 )
1764
// if the user released the mouse outside the menu, pass control
1765
// to the menubar or our parent menu
1766
int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1767
if ( !rect().contains( e->pos() ) && tryMenuBar(e) )
1769
else if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) || //up
1770
(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
1771
e->pos().y() >= contentsRect().height() - sh)) //down
1774
if ( actItem < 0 ) { // we do not have an active item
1775
// if the release is inside without motion (happens with
1776
// oversized popup menus on small screens), ignore it
1777
if ( rect().contains( e->pos() ) && motion < 6 )
1781
} else { // selected menu item!
1782
register QMenuItem *mi = mitems->at(actItem);
1783
if ( mi ->widget() ) {
1784
QWidget* widgetAt = QApplication::widgetAt( e->globalPos(), TRUE );
1785
if ( widgetAt && widgetAt != this ) {
1786
QMouseEvent me( e->type(), widgetAt->mapFromGlobal( e->globalPos() ),
1787
e->globalPos(), e->button(), e->state() );
1788
QApplication::sendEvent( widgetAt, &me );
1791
PopupMenu *popup = mi->popup();
1792
#ifndef QT_NO_WHATSTHIS
1793
bool b = QWhatsThis::inWhatsThisMode();
1795
const bool b = FALSE;
1797
if ( !mi->isEnabledAndVisible() ) {
1798
#ifndef QT_NO_WHATSTHIS
1801
updateItem( mi->id() );
1803
actSig( mi->id(), b);
1806
} else if ( popup ) {
1807
popup->setFirstItemActive();
1808
} else { // normal menu item
1809
byeMenuBar(); // deactivate menu bar
1810
if ( mi->isEnabledAndVisible() ) {
1812
updateItem( mi->id() );
1813
active_popup_menu = this;
1814
QGuardedPtr<QSignal> signal = mi->signal();
1815
actSig( mi->id(), b );
1818
active_popup_menu = 0;
1824
void PopupMenu::mouseMoveEvent( QMouseEvent *e )
1828
if ( parentMenu && parentMenu->isPopupMenu ) {
1829
PopupMenu* p = (PopupMenu*)parentMenu;
1832
p->findPopup( this, &myIndex );
1833
QPoint pPos = p->mapFromParent( e->globalPos() );
1834
if ( p->actItem != myIndex && !p->rect().contains( pPos ) )
1835
p->setActiveItem( myIndex );
1837
if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
1838
p->d->mouseMoveBuffer = QRegion();
1839
#ifdef DEBUG_SLOPPY_SUBMENU
1845
if ( (e->state() & Qt::MouseButtonMask) == 0 &&
1846
!hasMouseTracking() )
1849
if(d->scroll.scrollable && e->pos().x() >= rect().x() && e->pos().x() <= rect().width()) {
1850
int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
1851
if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && e->pos().y() <= sh) ||
1852
(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown && e->pos().y() >= height()-sh)) {
1853
if(!d->scroll.scrolltimer) {
1854
d->scroll.scrolltimer = new QTimer(this, "popup scroll timer");
1855
QObject::connect( d->scroll.scrolltimer, SIGNAL(timeout()),
1856
this, SLOT(subScrollTimer()) );
1858
if(!d->scroll.scrolltimer->isActive())
1859
d->scroll.scrolltimer->start(40);
1864
int item = itemAtPos( e->pos() );
1865
if ( item == -1 ) { // no valid item
1866
int lastActItem = actItem;
1868
if ( lastActItem >= 0 )
1869
updateRow( lastActItem );
1870
if ( lastActItem > 0 ||
1871
( !rect().contains( e->pos() ) && !tryMenuBar( e ) ) ) {
1872
popupSubMenuLater(style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay,
1875
} else { // mouse on valid item
1876
// but did not register mouse press
1877
if ( (e->state() & Qt::MouseButtonMask) && !mouseBtDn )
1878
mouseBtDn = TRUE; // so mouseReleaseEvent will pop down
1880
register QMenuItem *mi = mitems->at( item );
1882
if ( mi->widget() ) {
1883
QWidget* widgetAt = QApplication::widgetAt( e->globalPos(), TRUE );
1884
if ( widgetAt && widgetAt != this ) {
1885
QMouseEvent me( e->type(), widgetAt->mapFromGlobal( e->globalPos() ),
1886
e->globalPos(), e->button(), e->state() );
1887
QApplication::sendEvent( widgetAt, &me );
1891
if ( actItem == item )
1894
if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this) &&
1895
d->mouseMoveBuffer.contains( e->pos() ) ) {
1897
popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this) * 6,
1902
if ( mi->popup() || ( popupActive >= 0 && popupActive != item ))
1903
popupSubMenuLater( style().styleHint(QStyle::SH_PopupMenu_SubMenuPopupDelay, this),
1905
else if ( singleSingleShot )
1906
singleSingleShot->stop();
1908
if ( item != actItem )
1909
setActiveItem( item );
1913
void PopupMenu::keyPressEvent( QKeyEvent *e )
1921
if ( QApplication::reverseLayout() ) {
1922
// in reverse mode opening and closing keys for submenues are reversed
1923
if ( key == Key_Left )
1925
else if ( key == Key_Right )
1931
// ignore tab, otherwise it will be passed to the menubar
1943
if ( style().styleHint(QStyle::SH_MenuBar_AltKeyNavigation, this) )
1954
QMenuData* p = parentMenu;
1956
#ifndef QT_NO_MENUBAR
1957
if ( p && p->isMenuBar )
1958
((QMenuBar*) p)->goodbye( TRUE );
1964
if ( ncols > 1 && actItem >= 0 ) {
1965
QRect r( itemGeometry( actItem ) );
1966
int newActItem = itemAtPos( QPoint( r.left() - 1, r.center().y() ) );
1967
if ( newActItem >= 0 ) {
1968
setActiveItem( newActItem );
1972
if ( parentMenu && parentMenu->isPopupMenu ) {
1973
((PopupMenu *)parentMenu)->hidePopups();
1974
if ( singleSingleShot )
1975
singleSingleShot->stop();
1983
if ( actItem >= 0 && ( mi=mitems->at(actItem) )->isEnabledAndVisible() && (popup=mi->popup()) ) {
1985
if ( singleSingleShot )
1986
singleSingleShot->stop();
1987
// ### The next two lines were switched to fix the problem with the first item of the
1988
// submenu not being highlighted...any reason why they should have been the other way??
1990
popup->setFirstItemActive();
1992
} else if ( actItem == -1 && ( parentMenu && !parentMenu->isMenuBar )) {
1996
if ( ncols > 1 && actItem >= 0 ) {
1997
QRect r( itemGeometry( actItem ) );
1998
int newActItem = itemAtPos( QPoint( r.right() + 1, r.center().y() ) );
1999
if ( newActItem >= 0 ) {
2000
setActiveItem( newActItem );
2008
if (! style().styleHint(QStyle::SH_PopupMenu_SpaceActivatesItem, this))
2010
// for motif, fall through
2017
#ifndef QT_NO_WHATSTHIS
2018
bool b = QWhatsThis::inWhatsThisMode();
2020
const bool b = FALSE;
2022
mi = mitems->at( actItem );
2023
if ( !mi->isEnabled() && !b )
2025
popup = mi->popup();
2028
popupSubMenuLater( 20, this );
2029
popup->setFirstItemActive();
2032
updateItem( mi->id() );
2034
if ( mi->isEnabledAndVisible() || b ) {
2035
active_popup_menu = this;
2036
QGuardedPtr<QSignal> signal = mi->signal();
2037
actSig( mi->id(), b );
2040
active_popup_menu = 0;
2045
#ifndef QT_NO_WHATSTHIS
2047
if ( actItem < 0 || e->state() != ShiftButton)
2049
mi = mitems->at( actItem );
2050
if ( !mi->whatsThis().isNull() ){
2051
if ( !QWhatsThis::inWhatsThisMode() )
2052
QWhatsThis::enterWhatsThisMode();
2053
QRect r( itemGeometry( actItem) );
2054
QWhatsThis::leaveWhatsThisMode( mi->whatsThis(), mapToGlobal( r.bottomLeft()) );
2063
( !e->state() || e->state() == AltButton || e->state() == ShiftButton ) &&
2064
e->text().length()==1 ) {
2065
QChar c = e->text()[0].upper();
2067
QMenuItemListIt it(*mitems);
2068
QMenuItem* first = 0;
2069
QMenuItem* currentSelected = 0;
2070
QMenuItem* firstAfterCurrent = 0;
2072
register QMenuItem *m;
2076
while ( (m=it.current()) ) {
2078
QString s = m->text();
2079
if ( !s.isEmpty() ) {
2080
int i = s.find( '&' );
2081
while ( i >= 0 && i < (int)s.length() - 1 ) {
2082
if ( s[i+1].upper() == c ) {
2087
if ( indx == actItem )
2088
currentSelected = m;
2089
else if ( !firstAfterCurrent && currentSelected )
2090
firstAfterCurrent = m;
2092
} else if ( s[i+1] == '&' ) {
2093
i = s.find( '&', i+2 );
2104
if ( 1 == clashCount ) { // No clashes, continue with selection
2106
popup = mi->popup();
2108
setActiveItem( indexOf(mi->id()) );
2110
popupSubMenuLater( 20, this );
2111
popup->setFirstItemActive();
2114
#ifndef QT_NO_WHATSTHIS
2115
bool b = QWhatsThis::inWhatsThisMode();
2117
const bool b = FALSE;
2119
if ( mi->isEnabledAndVisible() || b ) {
2120
active_popup_menu = this;
2121
QGuardedPtr<QSignal> signal = mi->signal();
2122
actSig( mi->id(), b );
2125
active_popup_menu = 0;
2128
} else if ( clashCount > 1 ) { // Clashes, highlight next...
2129
// If there's clashes and no one is selected, use first one
2130
// or if there is no clashes _after_ current, use first one
2131
if ( !currentSelected || (currentSelected && !firstAfterCurrent))
2132
dy = indexOf( first->id() ) - actItem;
2134
dy = indexOf( firstAfterCurrent->id() ) - actItem;
2137
#ifndef QT_NO_MENUBAR
2138
if ( !ok_key ) { // send to menu bar
2139
register QMenuData *top = this; // find top level
2140
while ( top->parentMenu )
2141
top = top->parentMenu;
2142
if ( top->isMenuBar ) {
2143
int beforeId = top->actItem;
2144
((QMenuBar*)top)->tryKeyEvent( this, e );
2145
if ( beforeId != top->actItem )
2150
if ( actItem < 0 ) {
2152
setFirstItemActive();
2153
} else if ( dy < 0 ) {
2154
QMenuItemListIt it(*mitems);
2156
register QMenuItem *mi;
2157
int ai = count() - 1;
2158
while ( (mi=it.current()) ) {
2160
if ( !mi->isSeparator() && mi->id() != QMenuData::d->aInt ) {
2161
setActiveItem( ai );
2171
if ( dy ) { // highlight next/prev
2172
register int i = actItem;
2173
int c = mitems->count();
2174
for(int n = c; n; n--) {
2176
if(d->scroll.scrollable) {
2177
if(d->scroll.scrolltimer)
2178
d->scroll.scrolltimer->stop();
2189
mi = mitems->at( i );
2190
if ( !mi || !mi->isVisible() )
2193
if ( !mi->isSeparator() &&
2194
( style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this)
2195
|| mi->isEnabledAndVisible() ) )
2200
if(d->scroll.scrollable) { //need to scroll to make it visible?
2201
QRect r = itemGeometry(actItem);
2202
if(r.isNull() || r.height() < itemHeight(mitems->at(actItem))) {
2203
bool refresh = FALSE;
2204
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && dy == -1) { //up
2205
if(d->scroll.topScrollableIndex >= 0) {
2206
d->scroll.topScrollableIndex--;
2209
} else if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown) { //down
2210
QMenuItemListIt it(*mitems);
2211
int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
2212
for(int i = 0, y = ((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) ? sh : 0); it.current(); i++, ++it) {
2213
if(i >= d->scroll.topScrollableIndex) {
2214
int itemh = itemHeight(it.current());
2215
QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
2217
QStyleOption(it.current(),maxPMWidth,0));
2219
if(y > (contentsRect().height()-sh)) {
2220
if(sz.height() > sh || !it.atLast())
2221
d->scroll.topScrollableIndex++;
2229
updateScrollerState();
2238
!( e->key() == Key_Control || e->key() == Key_Shift || e->key() == Key_Meta ) )
2240
#endif // Q_OS_WIN32
2243
void PopupMenu::timerEvent( QTimerEvent *e )
2245
QFrame::timerEvent( e );
2248
void PopupMenu::leaveEvent( QEvent * )
2250
if ( testWFlags( WStyle_Tool ) && style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this) ) {
2251
int lastActItem = actItem;
2253
if ( lastActItem >= 0 )
2254
updateRow( lastActItem );
2258
void PopupMenu::styleChange( QStyle& old )
2260
QFrame::styleChange( old );
2261
setMouseTracking(style().styleHint(QStyle::SH_PopupMenu_MouseTracking, this));
2262
style().polishPopupMenu( this );
2266
void PopupMenu::enabledChange( bool )
2268
if ( QMenuData::d->aWidget ) // torn-off menu
2269
QMenuData::d->aWidget->setEnabled( isEnabled() );
2272
int PopupMenu::columns() const
2277
// This private slot handles the scrolling popupmenu
2278
void PopupMenu::subScrollTimer() {
2279
QPoint pos = QCursor::pos();
2280
if(!d->scroll.scrollable || !isVisible()) {
2281
if(d->scroll.scrolltimer)
2282
d->scroll.scrolltimer->stop();
2284
} else if(pos.x() > x() + width() || pos.x() < x()) {
2287
int sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
2288
if(!d->scroll.lastScroll.isValid()) {
2289
d->scroll.lastScroll = QTime::currentTime();
2293
factor = y() - pos.y();
2294
else if(pos.y() > y() + height())
2295
factor = pos.y() - (y() + height());
2296
int msecs = 250 - ((factor / 10) * 40);
2297
if(d->scroll.lastScroll.msecsTo(QTime::currentTime()) < QMAX(0, msecs))
2299
d->scroll.lastScroll = QTime::currentTime();
2301
if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp && pos.y() <= y() + sh) { //up
2302
if(d->scroll.topScrollableIndex > 0) {
2303
d->scroll.topScrollableIndex--;
2304
updateScrollerState();
2305
update(contentsRect());
2307
} else if(d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollDown &&
2308
pos.y() >= (y() + contentsRect().height()) - sh) { //down
2309
QMenuItemListIt it(*mitems);
2310
for(int i = 0, y = contentsRect().y() + sh; it.current(); i++, ++it) {
2311
if(i >= d->scroll.topScrollableIndex) {
2312
int itemh = itemHeight(it.current());
2313
QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this, QSize(0, itemh),
2314
QStyleOption(it.current(),maxPMWidth,0));
2316
if(y > contentsRect().height() - sh) {
2317
d->scroll.topScrollableIndex++;
2318
updateScrollerState();
2319
update(contentsRect());
2327
// This private slot handles the delayed submenu effects
2329
void PopupMenu::subMenuTimer() {
2331
if ( !isVisible() || (actItem < 0 && popupActive < 0) || actItem == popupActive )
2334
if ( popupActive >= 0 ) {
2339
// hidePopups() may change actItem etc.
2340
if ( !isVisible() || actItem < 0 || actItem == popupActive )
2343
QMenuItem *mi = mitems->at(actItem);
2344
if ( !mi || !mi->isEnabledAndVisible() )
2347
PopupMenu *popup = mi->popup();
2348
if ( !popup || !popup->isEnabled() )
2352
if ( popup->isVisible() )
2355
Q_ASSERT( popup->parentMenu == 0 );
2356
popup->parentMenu = this; // set parent menu
2358
emit popup->aboutToShow();
2359
supressAboutToShow = TRUE;
2362
QRect r( itemGeometry( actItem ) );
2364
QSize ps = popup->sizeHint();
2365
if( QApplication::reverseLayout() ) {
2366
p = QPoint( r.left() + motifArrowHMargin - ps.width(), r.top() + motifArrowVMargin );
2367
p = mapToGlobal( p );
2370
if ( ( parentMenu && parentMenu->isPopupMenu &&
2371
((PopupMenu*)parentMenu)->geometry().x() < geometry().x() ) ||
2374
if ( right && (ps.width() > QApplication::desktop()->width() - mapToGlobal( r.topRight() ).x() ) )
2377
p.setX( mapToGlobal( r.topRight() ).x() );
2379
p = QPoint( r.right() - motifArrowHMargin, r.top() + motifArrowVMargin );
2380
p = mapToGlobal( p );
2383
if ( ( parentMenu && parentMenu->isPopupMenu &&
2384
((PopupMenu*)parentMenu)->geometry().x() > geometry().x() ) ||
2385
p.x() + ps.width() > QApplication::desktop()->width() )
2387
if ( left && (ps.width() > mapToGlobal( r.topLeft() ).x() ) )
2390
p.setX( mapToGlobal( r.topLeft() ).x() - ps.width() );
2392
QRect pr = popup->itemGeometry(popup->count() - 1);
2393
if (p.y() + ps.height() > QApplication::desktop()->height() &&
2394
p.y() - ps.height() + (QCOORD) pr.height() >= 0)
2395
p.setY( p.y() - ps.height() + (QCOORD) pr.height());
2397
if ( style().styleHint(QStyle::SH_PopupMenu_SloppySubMenus, this )) {
2398
QPoint cur = QCursor::pos();
2399
if ( r.contains( mapFromGlobal( cur ) ) ) {
2401
pts[0] = QPoint( cur.x(), cur.y() - 2 );
2402
pts[3] = QPoint( cur.x(), cur.y() + 2 );
2403
if ( p.x() >= cur.x() ) {
2404
pts[1] = QPoint( geometry().right(), p.y() );
2405
pts[2] = QPoint( geometry().right(), p.y() + ps.height() );
2407
pts[1] = QPoint( p.x() + ps.width(), p.y() );
2408
pts[2] = QPoint( p.x() + ps.width(), p.y() + ps.height() );
2410
QPointArray points( 4 );
2411
for( int i = 0; i < 4; i++ )
2412
points.setPoint( i, mapFromGlobal( pts[i] ) );
2413
d->mouseMoveBuffer = QRegion( points );
2418
popupActive = actItem;
2422
void PopupMenu::allowAnimation()
2424
preventAnimation = FALSE;
2427
void PopupMenu::updateRow( int row )
2438
QRect r = itemGeometry( row );
2439
if ( !r.isNull() ) // can happen via the scroller
2443
int PopupMenu::exec( const QPoint & pos, int indexAtPoint )
2449
PopupMenu* priorSyncMenu = syncMenu;
2454
QGuardedPtr<PopupMenu> that = this;
2455
connectModal( that, TRUE );
2456
popup( pos, indexAtPoint );
2458
connectModal( that, FALSE );
2460
syncMenu = priorSyncMenu;
2466
// Connect the popup and all its submenus to modalActivation() if
2467
// \a doConnect is true, otherwise disconnect.
2468
void PopupMenu::connectModal( PopupMenu* receiver, bool doConnect )
2473
connectModalRecursionSafety = doConnect;
2476
connect( this, SIGNAL(activated(int)),
2477
receiver, SLOT(modalActivation(int)) );
2479
disconnect( this, SIGNAL(activated(int)),
2480
receiver, SLOT(modalActivation(int)) );
2482
QMenuItemListIt it(*mitems);
2483
register QMenuItem *mi;
2484
while ( (mi=it.current()) ) {
2486
if ( mi->popup() && mi->popup() != receiver
2487
&& (bool)(mi->popup()->connectModalRecursionSafety) != doConnect )
2488
mi->popup()->connectModal( receiver, doConnect ); //avoid circular
2492
int PopupMenu::exec()
2494
return exec(mapToGlobal(QPoint(0,0)));
2498
// Internal slot used for exec().
2500
void PopupMenu::modalActivation( int id )
2505
void PopupMenu::setActiveItem( int i )
2507
int lastActItem = actItem;
2509
if ( lastActItem >= 0 )
2510
updateRow( lastActItem );
2511
if ( i >= 0 && i != lastActItem )
2513
QMenuItem *mi = mitems->at( actItem );
2517
if ( mi->widget() && mi->widget()->isFocusEnabled() ) {
2518
mi->widget()->setFocus();
2521
QRect mfrect = itemGeometry( actItem );
2522
setMicroFocusHint( mfrect.x(), mfrect.y(), mfrect.width(), mfrect.height(), FALSE );
2524
if ( mi->id() != -1 )
2525
hilitSig( mi->id() );
2526
#ifndef QT_NO_WHATSTHIS
2527
if (whatsThisItem && whatsThisItem != mi) {
2534
QSize PopupMenu::sizeHint() const
2537
PopupMenu* that = (PopupMenu*) this;
2538
//We do not need a resize here, just the sizeHint..
2539
return that->updateSize(FALSE, FALSE).expandedTo( QApplication::globalStrut() );
2542
int PopupMenu::idAt( const QPoint& pos ) const
2544
return idAt( itemAtPos( pos ) );
2547
bool PopupMenu::customWhatsThis() const
2552
bool PopupMenu::focusNextPrevChild( bool next )
2554
register QMenuItem *mi;
2555
int dy = next? 1 : -1;
2556
if ( dy && actItem < 0 ) {
2557
setFirstItemActive();
2558
} else if ( dy ) { // highlight next/prev
2559
register int i = actItem;
2560
int c = mitems->count();
2568
mi = mitems->at( i );
2569
if ( mi && !mi->isSeparator() &&
2570
( ( style().styleHint(QStyle::SH_PopupMenu_AllowActiveAndDisabled, this)
2571
&& mi->isVisible() )
2572
|| mi->isEnabledAndVisible() ) )
2581
void PopupMenu::focusInEvent( QFocusEvent * )
2585
void PopupMenu::focusOutEvent( QFocusEvent * )
2589
class QTearOffMenuItem : public QCustomMenuItem
2598
void paint( QPainter* p, const QColorGroup& cg, bool,
2599
bool, int x, int y, int w, int h )
2601
p->setPen( QPen( cg.dark(), 1, DashLine ) );
2602
p->drawLine( x+2, y+h/2-1, x+w-4, y+h/2-1 );
2603
p->setPen( QPen( cg.light(), 1, DashLine ) );
2604
p->drawLine( x+2, y+h/2, x+w-4, y+h/2 );
2606
bool fullSpan() const
2613
return QSize( 20, 6 );
2617
int PopupMenu::insertTearOffHandle( int id, int index )
2619
int myid = insertItem( new QTearOffMenuItem, id, index );
2620
connectItem( myid, this, SLOT( toggleTearOff() ) );
2621
QMenuData::d->aInt = myid;
2625
void PopupMenu::toggleTearOff()
2627
if ( active_popup_menu && active_popup_menu->tornOff ) {
2628
active_popup_menu->close();
2629
} else if (QMenuData::d->aWidget ) {
2630
delete (QWidget*) QMenuData::d->aWidget; // delete the old one
2632
// create a tear off menu
2633
PopupMenu* p = new PopupMenu( parentWidget(), "tear off menu" );
2634
connect( p, SIGNAL( activated(int) ), this, SIGNAL( activated(int) ) );
2635
connect( p, SIGNAL( highlighted(int) ), this, SIGNAL( highlighted(int) ) );
2636
#ifndef QT_NO_WIDGET_TOPEXTRA
2637
p->setCaption( caption() );
2639
p->setCheckable( isCheckable() );
2640
p->reparent( parentWidget(), WType_TopLevel | WStyle_Tool |
2641
WNoAutoErase | WDestructiveClose,
2642
geometry().topLeft(), FALSE );
2643
p->mitems->setAutoDelete( FALSE );
2645
for ( QMenuItemListIt it( *mitems ); it.current(); ++it ) {
2646
if ( it.current()->id() != QMenuData::d->aInt && !it.current()->widget() )
2647
p->mitems->append( it.current() );
2650
QMenuData::d->aWidget = p;
2654
void PopupMenu::activateItemAt( int index )
2656
if ( index >= 0 && index < (int) mitems->count() ) {
2657
QMenuItem *mi = mitems->at( index );
2658
if ( index != actItem ) // new item activated
2659
setActiveItem( index );
2660
PopupMenu *popup = mi->popup();
2662
if ( popup->isVisible() ) { // sub menu already open
2663
int pactItem = popup->actItem;
2664
popup->actItem = -1;
2665
popup->hidePopups();
2666
popup->updateRow( pactItem );
2667
} else { // open sub menu
2671
popup->setFirstItemActive();
2674
byeMenuBar(); // deactivate menu bar
2676
#ifndef QT_NO_WHATSTHIS
2677
bool b = QWhatsThis::inWhatsThisMode();
2679
const bool b = FALSE;
2681
if ( !mi->isEnabledAndVisible() ) {
2682
#ifndef QT_NO_WHATSTHIS
2685
updateItem( mi->id() );
2687
actSig( mi->id(), b);
2691
byeMenuBar(); // deactivate menu bar
2692
if ( mi->isEnabledAndVisible() ) {
2694
updateItem( mi->id() );
2695
active_popup_menu = this;
2696
QGuardedPtr<QSignal> signal = mi->signal();
2697
actSig( mi->id(), b );
2700
active_popup_menu = 0;
2708
QMenuData* p = parentMenu;
2710
#ifndef QT_NO_MENUBAR
2711
if ( p && p->isMenuBar )
2712
((QMenuBar*) p)->goodbye( TRUE );
2720
PopupMenu::updateScrollerState()
2722
uint old_scrollable = d->scroll.scrollable;
2723
d->scroll.scrollable = QPopupMenuPrivate::Scroll::ScrollNone;
2724
if(!style().styleHint(QStyle::SH_PopupMenu_Scrollable, this))
2728
QMenuItemListIt it( *mitems );
2729
if(d->scroll.topScrollableIndex) {
2730
for(int row = 0; (mi = it.current()) && row < d->scroll.topScrollableIndex; row++)
2735
int y = 0, sh = style().pixelMetric(QStyle::PM_PopupMenuScrollerHeight, this);
2737
// can't use |= because of a bug/feature in IBM xlC 5.0.2
2738
d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollUp;
2741
while ( (mi=it.current()) ) {
2743
int myheight = contentsRect().height();
2744
QSize sz = style().sizeFromContents(QStyle::CT_PopupMenuItem, this,
2745
QSize(0, itemHeight( mi )),
2746
QStyleOption(mi,maxPMWidth));
2747
if(y + sz.height() >= myheight) {
2748
d->scroll.scrollable = d->scroll.scrollable | QPopupMenuPrivate::Scroll::ScrollDown;
2753
if((d->scroll.scrollable & QPopupMenuPrivate::Scroll::ScrollUp) &&
2754
!(old_scrollable & QPopupMenuPrivate::Scroll::ScrollUp))
2755
d->scroll.topScrollableIndex++;
2758
#endif // QT_NO_POPUPMENU
b'\\ No newline at end of file'