1 /****************************************************************************
2 **
3 ** Copyright (C) 2017 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the plugins 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 The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QWINDOWSMENU_H
41 #define QWINDOWSMENU_H
42 
43 #include "qtwindowsglobal.h"
44 
45 #include <qpa/qplatformmenu.h>
46 
47 #include <QtCore/qvector.h>
48 #include <QtCore/qpair.h>
49 
50 QT_BEGIN_NAMESPACE
51 
52 class QDebug;
53 
54 class QWindowsMenu;
55 class QWindowsMenuBar;
56 class QWindowsWindow;
57 
58 class QWindowsMenuItem : public QPlatformMenuItem
59 {
60     Q_OBJECT
61 public:
62     explicit QWindowsMenuItem(QWindowsMenu *parentMenu = nullptr);
63     ~QWindowsMenuItem() override;
64 
65     void setText(const QString &text) override;
66     void setIcon(const QIcon &icon) override;
67     void setMenu(QPlatformMenu *menu) override;
68     void setVisible(bool isVisible) override;
69     void setIsSeparator(bool isSeparator) override;
setFont(const QFont &)70     void setFont(const QFont &) override {}
setRole(MenuRole)71     void setRole(MenuRole) override {}
72     void setCheckable(bool checkable) override;
73     void setChecked(bool isChecked) override;
74 #ifndef QT_NO_SHORTCUT
75     void setShortcut(const QKeySequence& shortcut) override;
76 #endif
77     void setEnabled(bool enabled) override;
78     void setIconSize(int size) override;
79 
parentMenu()80     const QWindowsMenu *parentMenu() const { return m_parentMenu; }
parentMenu()81     QWindowsMenu *parentMenu() { return m_parentMenu; }
82     HMENU parentMenuHandle() const;
subMenu()83     QWindowsMenu *subMenu() const { return m_subMenu; }
id()84     UINT_PTR id() const { return m_id; }
setId(uint id)85     void setId(uint id) { m_id = id; }
86     UINT state() const;
text()87     QString text() const { return m_text; }
88     QString nativeText() const;
isVisible()89     bool isVisible() const { return m_visible; }
90 
91     void insertIntoMenu(QWindowsMenu *menuItem, bool append, int index);
92     bool removeFromMenu();
93 
94 #ifndef QT_NO_DEBUG_STREAM
95     void formatDebug(QDebug &d) const;
96 #endif
97 
98 private:
99     void updateBitmap();
100     void freeBitmap();
101     void updateText();
102     void insertIntoMenuHelper(QWindowsMenu *menu, bool append, int index);
103 
104     QWindowsMenu *m_parentMenu = nullptr;
105     QWindowsMenu *m_subMenu = nullptr;
106     UINT_PTR m_id; // Windows Id sent as wParam with WM_COMMAND or submenu handle.
107     QString m_text;
108     QIcon m_icon;
109     HBITMAP m_hbitmap = nullptr;
110     int m_iconSize = 0;
111     bool m_separator = false;
112     bool m_visible = true;
113     bool m_checkable = false;
114     bool m_checked = false;
115     bool m_enabled = true;
116     QKeySequence m_shortcut;
117 };
118 
119 class QWindowsMenu : public QPlatformMenu
120 {
121     Q_OBJECT
122 public:
123     using MenuItems = QVector<QWindowsMenuItem *>;
124 
125     QWindowsMenu();
126     ~QWindowsMenu();
127 
128     void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) override;
129     void removeMenuItem(QPlatformMenuItem *menuItem) override;
syncMenuItem(QPlatformMenuItem *)130     void syncMenuItem(QPlatformMenuItem *) override {}
syncSeparatorsCollapsible(bool)131     void syncSeparatorsCollapsible(bool) override {}
132 
133     void setText(const QString &text) override;
134     void setIcon(const QIcon &icon) override;
135     void setEnabled(bool enabled) override;
isEnabled()136     bool isEnabled() const override { return m_enabled; }
137     void setVisible(bool visible) override;
138 
139     QPlatformMenuItem *menuItemAt(int position) const override;
140     QPlatformMenuItem *menuItemForTag(quintptr tag) const override;
141 
142     QPlatformMenuItem *createMenuItem() const override;
143     QPlatformMenu *createSubMenu() const override;
144 
menuHandle()145     HMENU menuHandle() const { return m_hMenu; }
id()146     UINT_PTR id() const { return reinterpret_cast<UINT_PTR>(m_hMenu); }
text()147     QString text() const { return m_text; }
menuItems()148     const MenuItems &menuItems() const { return m_menuItems; }
149     QWindowsMenuItem *itemForSubMenu(const QWindowsMenu *subMenu) const;
150 
parentMenuBar()151     const QWindowsMenuBar *parentMenuBar() const { return m_parentMenuBar; }
152     HMENU parentMenuBarHandle() const;
parentMenu()153     const QWindowsMenu *parentMenu() const { return m_parentMenu; }
154     void setAsItemSubMenu(QWindowsMenuItem *item);
notifyRemoved(QWindowsMenuItem * item)155     void notifyRemoved(QWindowsMenuItem *item) { m_menuItems.removeOne(item); }
156     HMENU parentMenuHandle() const;
157     HMENU parentHandle() const;
isVisible()158     bool isVisible() const { return m_visible; }
159     void insertIntoMenuBar(QWindowsMenuBar *bar, bool append, int index);
160     bool removeFromParent();
161 
162 #ifndef QT_NO_DEBUG_STREAM
163     void formatDebug(QDebug &d) const;
164 #endif
165 
166 protected:
167     explicit QWindowsMenu(QWindowsMenu *parentMenu, HMENU menu);
168 
169 private:
170     QWindowsMenuBar *m_parentMenuBar = nullptr;
171     QWindowsMenu *m_parentMenu = nullptr;
172     MenuItems m_menuItems;
173     HMENU m_hMenu = nullptr;
174     QString m_text;
175     QIcon m_icon;
176     bool m_visible = true;
177     bool m_enabled = true;
178 };
179 
180 class QWindowsPopupMenu : public QWindowsMenu
181 {
182     Q_OBJECT
183 public:
184     QWindowsPopupMenu();
185 
186     static bool notifyTriggered(uint id);
187     static bool notifyAboutToShow(HMENU hmenu);
188 
189     void showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item) override;
dismiss()190     void dismiss() override {}
191 
192     bool trackPopupMenu(HWND windowHandle, int x, int y);
193 };
194 
195 class QWindowsMenuBar : public QPlatformMenuBar
196 {
197     Q_OBJECT
198 public:
199     using Menus = QVector<QWindowsMenu *>;
200 
201     QWindowsMenuBar();
202     ~QWindowsMenuBar() override;
203 
204     void insertMenu(QPlatformMenu *menu, QPlatformMenu *before) override;
205     void removeMenu(QPlatformMenu *menu) override;
syncMenu(QPlatformMenu *)206     void syncMenu(QPlatformMenu *) override {}
207     void handleReparent(QWindow *newParentWindow) override;
208 
209     QPlatformMenu *menuForTag(quintptr tag) const override;
210     QPlatformMenu *createMenu() const override;
211 
menuBarHandle()212     HMENU menuBarHandle() const { return m_hMenuBar; }
menus()213     const Menus &menus() const { return m_menus; }
214     bool notifyTriggered(uint id);
215     bool notifyAboutToShow(HMENU hmenu);
notifyRemoved(QWindowsMenu * menu)216     void notifyRemoved(QWindowsMenu *menu) { m_menus.removeOne(menu); }
217     void redraw() const;
218 
219     void install(QWindowsWindow *window);
220 
221     static QWindowsMenuBar *menuBarOf(const QWindow *notYetCreatedWindow);
222 
223 #ifndef QT_NO_DEBUG_STREAM
224     void formatDebug(QDebug &d) const;
225 #endif
226 
227 private:
228     QWindowsWindow *platformWindow() const;
229     void removeFromWindow();
230 
231     Menus m_menus;
232     HMENU m_hMenuBar = nullptr;
233 };
234 
235 #ifndef QT_NO_DEBUG_STREAM
236 QDebug operator<<(QDebug d, const QPlatformMenuItem *);
237 QDebug operator<<(QDebug d, const QPlatformMenu *);
238 QDebug operator<<(QDebug d, const QPlatformMenuBar *);
239 #endif // !QT_NO_DEBUG_STREAM
240 
241 QT_END_NAMESPACE
242 
243 #endif // QWINDOWSMENU_H
244