1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#ifndef QMENU_P_H
43#define QMENU_P_H
44
45//
46// W A R N I N G
47// -------------
48//
49// This file is not part of the Qt API. It exists purely as an
50// implementation detail. This header file may change from version to
51// version without notice, or even be removed.
52//
53// We mean it.
54//
55
56#include "QtGui/qmenubar.h"
57#include "QtGui/qstyleoption.h"
58#include "QtCore/qdatetime.h"
59#include "QtCore/qmap.h"
60#include "QtCore/qhash.h"
61#include "QtCore/qbasictimer.h"
62#include "private/qwidget_p.h"
63
64#ifdef Q_WS_S60
65class CEikMenuPane;
66#define QT_SYMBIAN_FIRST_MENU_ITEM 32000
67#define QT_SYMBIAN_LAST_MENU_ITEM 41999 // 10000 items ought to be enough for anybody...
68#endif
69QT_BEGIN_NAMESPACE
70
71#ifndef QT_NO_MENU
72
73#ifdef Q_WS_S60
74void qt_symbian_next_menu_from_action(QWidget* actionContainer);
75void qt_symbian_show_toplevel(CEikMenuPane* menuPane);
76void qt_symbian_show_submenu(CEikMenuPane* menuPane, int id);
77#endif // Q_WS_S60
78
79class QTornOffMenu;
80class QEventLoop;
81
82#ifdef Q_WS_MAC
83# ifdef __OBJC__
84QT_END_NAMESPACE
85@class NSMenuItem;
86QT_BEGIN_NAMESPACE
87# else
88typedef void NSMenuItem;
89# endif //__OBJC__
90struct QMacMenuAction {
91 QMacMenuAction()
92#ifndef QT_MAC_USE_COCOA
93 : command(0)
94#else
95 : menuItem(0)
96#endif
97 , ignore_accel(0), merged(0), menu(0)
98 {
99 }
100 ~QMacMenuAction();
101#ifndef QT_MAC_USE_COCOA
102 uint command;
103#else
104 NSMenuItem *menuItem;
105#endif
106 uchar ignore_accel : 1;
107 uchar merged : 1;
108 QPointer<QAction> action;
109 OSMenuRef menu;
110};
111
112struct QMenuMergeItem
113{
114#ifndef QT_MAC_USE_COCOA
115 inline QMenuMergeItem(MenuCommand c, QMacMenuAction *a) : command(c), action(a) { }
116 MenuCommand command;
117#else
118 inline QMenuMergeItem(NSMenuItem *c, QMacMenuAction *a) : menuItem(c), action(a) { }
119 NSMenuItem *menuItem;
120#endif
121 QMacMenuAction *action;
122};
123typedef QList<QMenuMergeItem> QMenuMergeList;
124#endif
125
126#ifdef Q_WS_WINCE
127struct QWceMenuAction {
128 uint command;
129 QPointer<QAction> action;
130 HMENU menuHandle;
131 QWceMenuAction() : menuHandle(0), command(0) {}
132};
133#endif
134#ifdef Q_WS_S60
135struct QSymbianMenuAction {
136 uint command;
137 int parent;
138 CEikMenuPane* menuPane;
139 QPointer<QAction> action;
140 QSymbianMenuAction() : command(0) {}
141};
142#endif
143
144class QMenuPrivate : public QWidgetPrivate
145{
146 Q_DECLARE_PUBLIC(QMenu)
147public:
148 QMenuPrivate() : itemsDirty(0), maxIconWidth(0), tabWidth(0), ncols(0),
149 collapsibleSeparators(true), activationRecursionGuard(false), hasHadMouse(0), aboutToHide(0), motions(0),
150 currentAction(0),
151#ifdef QT_KEYPAD_NAVIGATION
152 selectAction(0),
153 cancelAction(0),
154#endif
155 scroll(0), eventLoop(0), tearoff(0), tornoff(0), tearoffHighlighted(0),
156 hasCheckableItems(0), sloppyDelayTimer(0), sloppyAction(0), doChildEffects(false)
157#ifdef QT3_SUPPORT
158 ,emitHighlighted(false)
159#endif
160#ifdef Q_WS_MAC
161 ,mac_menu(0)
162#endif
163#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
164 ,wce_menu(0)
165#endif
166#ifdef Q_WS_S60
167 ,symbian_menu(0)
168#endif
169 { }
170 ~QMenuPrivate()
171 {
172 delete scroll;
173#ifdef Q_WS_MAC
174 delete mac_menu;
175#endif
176#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
177 delete wce_menu;
178#endif
179#ifdef Q_WS_S60
180 delete symbian_menu;
181#endif
182
183 }
184 void init();
185
186 static QMenuPrivate *get(QMenu *m) { return m->d_func(); }
187 int scrollerHeight() const;
188
189 //item calculations
190 mutable uint itemsDirty : 1;
191 mutable uint maxIconWidth, tabWidth;
192 QRect actionRect(QAction *) const;
193
194 mutable QVector<QRect> actionRects;
195 mutable QHash<QAction *, QWidget *> widgetItems;
196 void updateActionRects() const;
197 void updateActionRects(const QRect &screen) const;
198 QRect popupGeometry(const QWidget *widget) const;
199 QRect popupGeometry(int screen = -1) const;
200 mutable uint ncols : 4; //4 bits is probably plenty
201 uint collapsibleSeparators : 1;
202 QSize adjustMenuSizeForScreen(const QRect & screen);
203 int getLastVisibleAction() const;
204
205 bool activationRecursionGuard;
206
207 //selection
208 static QMenu *mouseDown;
209 QPoint mousePopupPos;
210 uint hasHadMouse : 1;
211 uint aboutToHide : 1;
212 int motions;
213 QAction *currentAction;
214#ifdef QT_KEYPAD_NAVIGATION
215 QAction *selectAction;
216 QAction *cancelAction;
217#endif
218 QBasicTimer menuDelayTimer;
219 enum SelectionReason {
220 SelectedFromKeyboard,
221 SelectedFromElsewhere
222 };
223 QWidget *topCausedWidget() const;
224 QAction *actionAt(QPoint p) const;
225 void setFirstActionActive();
226 void setCurrentAction(QAction *, int popup = -1, SelectionReason reason = SelectedFromElsewhere, bool activateFirst = false);
227 void popupAction(QAction *, int, bool);
228 void setSyncAction();
229
230 //scrolling support
231 struct QMenuScroller {
232 enum ScrollLocation { ScrollStay, ScrollBottom, ScrollTop, ScrollCenter };
233 enum ScrollDirection { ScrollNone=0, ScrollUp=0x01, ScrollDown=0x02 };
234 uint scrollFlags : 2, scrollDirection : 2;
235 int scrollOffset;
236 QBasicTimer scrollTimer;
237
238 QMenuScroller() : scrollFlags(ScrollNone), scrollDirection(ScrollNone), scrollOffset(0) { }
239 ~QMenuScroller() { }
240 } *scroll;
241 void scrollMenu(QMenuScroller::ScrollLocation location, bool active=false);
242 void scrollMenu(QMenuScroller::ScrollDirection direction, bool page=false, bool active=false);
243 void scrollMenu(QAction *action, QMenuScroller::ScrollLocation location, bool active=false);
244
245 //synchronous operation (ie exec())
246 QEventLoop *eventLoop;
247 QPointer<QAction> syncAction;
248
249 //search buffer
250 QString searchBuffer;
251 QBasicTimer searchBufferTimer;
252
253 //passing of mouse events up the parent hierarchy
254 QPointer<QMenu> activeMenu;
255 bool mouseEventTaken(QMouseEvent *);
256
257 //used to walk up the popup list
258 struct QMenuCaused {
259 QPointer<QWidget> widget;
260 QPointer<QAction> action;
261 };
262 virtual QList<QPointer<QWidget> > calcCausedStack() const;
263 QMenuCaused causedPopup;
264 void hideUpToMenuBar();
265 void hideMenu(QMenu *menu, bool justRegister = false);
266
267 //index mappings
268 inline QAction *actionAt(int i) const { return q_func()->actions().at(i); }
269 inline int indexOf(QAction *act) const { return q_func()->actions().indexOf(act); }
270
271 //tear off support
272 uint tearoff : 1, tornoff : 1, tearoffHighlighted : 1;
273 QPointer<QTornOffMenu> tornPopup;
274
275 mutable bool hasCheckableItems;
276
277 //sloppy selection
278 int sloppyDelayTimer;
279 mutable QAction *sloppyAction;
280 QRegion sloppyRegion;
281
282 //default action
283 QPointer<QAction> defaultAction;
284
285 QAction *menuAction;
286 QAction *defaultMenuAction;
287
288 void setOverrideMenuAction(QAction *);
289 void _q_overrideMenuActionDestroyed();
290
291 //firing of events
292 void activateAction(QAction *, QAction::ActionEvent, bool self=true);
293 void activateCausedStack(const QList<QPointer<QWidget> > &, QAction *, QAction::ActionEvent, bool);
294
295 void _q_actionTriggered();
296 void _q_actionHovered();
297
298 bool hasMouseMoved(const QPoint &globalPos);
299
300 void updateLayoutDirection();
301
302 //menu fading/scrolling effects
303 bool doChildEffects;
304
305#ifdef Q_WS_MAC
306 //mac menu binding
307 struct QMacMenuPrivate {
308 QList<QMacMenuAction*> actionItems;
309 OSMenuRef menu;
310 QMacMenuPrivate();
311 ~QMacMenuPrivate();
312
313 bool merged(const QAction *action) const;
314 void addAction(QAction *, QMacMenuAction* =0, QMenuPrivate *qmenu = 0);
315 void addAction(QMacMenuAction *, QMacMenuAction* =0, QMenuPrivate *qmenu = 0);
316 void syncAction(QMacMenuAction *);
317 inline void syncAction(QAction *a) { syncAction(findAction(a)); }
318 void removeAction(QMacMenuAction *);
319 inline void removeAction(QAction *a) { removeAction(findAction(a)); }
320 inline QMacMenuAction *findAction(QAction *a) {
321 for(int i = 0; i < actionItems.size(); i++) {
322 QMacMenuAction *act = actionItems[i];
323 if(a == act->action)
324 return act;
325 }
326 return 0;
327 }
328 } *mac_menu;
329 OSMenuRef macMenu(OSMenuRef merge);
330#ifndef QT_MAC_USE_COCOA
331 void setMacMenuEnabled(bool enable = true);
332#endif
333 void syncSeparatorsCollapsible(bool collapsible);
334 static QHash<OSMenuRef, OSMenuRef> mergeMenuHash;
335 static QHash<OSMenuRef, QMenuMergeList*> mergeMenuItemsHash;
336#endif
337
338 QPointer<QAction> actionAboutToTrigger;
339#ifdef QT3_SUPPORT
340 bool emitHighlighted;
341#endif
342
343#if defined(Q_WS_WINCE) && !defined(QT_NO_MENUBAR)
344 struct QWceMenuPrivate {
345 QList<QWceMenuAction*> actionItems;
346 HMENU menuHandle;
347 QWceMenuPrivate();
348 ~QWceMenuPrivate();
349 void addAction(QAction *, QWceMenuAction* =0);
350 void addAction(QWceMenuAction *, QWceMenuAction* =0);
351 void syncAction(QWceMenuAction *);
352 inline void syncAction(QAction *a) { syncAction(findAction(a)); }
353 void removeAction(QWceMenuAction *);
354 void rebuild();
355 inline void removeAction(QAction *a) { removeAction(findAction(a)); }
356 inline QWceMenuAction *findAction(QAction *a) {
357 for(int i = 0; i < actionItems.size(); i++) {
358 QWceMenuAction *act = actionItems[i];
359 if(a == act->action)
360 return act;
361 }
362 return 0;
363 }
364 } *wce_menu;
365 HMENU wceMenu();
366 QAction* wceCommands(uint command);
367#endif
368#if defined(Q_WS_S60)
369 struct QSymbianMenuPrivate {
370 QList<QSymbianMenuAction*> actionItems;
371 QSymbianMenuPrivate();
372 ~QSymbianMenuPrivate();
373 void addAction(QAction *, QSymbianMenuAction* =0);
374 void addAction(QSymbianMenuAction *, QSymbianMenuAction* =0);
375 void syncAction(QSymbianMenuAction *);
376 inline void syncAction(QAction *a) { syncAction(findAction(a)); }
377 void removeAction(QSymbianMenuAction *);
378 void rebuild(bool reCreate = false);
379 inline void removeAction(QAction *a) { removeAction(findAction(a)); }
380 inline QSymbianMenuAction *findAction(QAction *a) {
381 for(int i = 0; i < actionItems.size(); i++) {
382 QSymbianMenuAction *act = actionItems[i];
383 if(a == act->action)
384 return act;
385 }
386 return 0;
387 }
388 } *symbian_menu;
389#endif
390 QPointer<QWidget> noReplayFor;
391};
392
393#endif // QT_NO_MENU
394
395QT_END_NAMESPACE
396
397#endif // QMENU_P_H
398