File indexing completed on 2024-09-29 03:35:29
0001 /* 0002 This file is part of the KDE project 0003 SPDX-FileCopyrightText: 2021 Felix Ernst <fe.a.ernst@gmail.com> 0004 0005 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL 0006 */ 0007 0008 #ifndef KHamburgerMenu_H 0009 #define KHamburgerMenu_H 0010 0011 #include <kconfigwidgets_export.h> 0012 0013 #include <QWidgetAction> 0014 0015 #include <memory> 0016 0017 class KHamburgerMenuPrivate; 0018 0019 class QMenuBar; 0020 0021 /** 0022 * @class KHamburgerMenu khamburgermenu.h KHamburgerMenu 0023 * 0024 * @short A menu that substitutes a menu bar when necessary 0025 * 0026 * Allowing users to toggle the visibility of the menu bar and/or toolbars, 0027 * while pretty/"simple by default", can lead to various grave usability issues. 0028 * This class makes it easy to prevent all of them. 0029 * 0030 * Simply add a KHamburgerMenu to your UI (typically to a QToolBar) and make 0031 * it aware of a QMenuBar like this: 0032 * 0033 * \code 0034 * auto hamburgerMenu = KStandardAction::hamburgerMenu(nullptr, nullptr, actionCollection()); 0035 * toolBar()->addAction(hamburgerMenu); 0036 * hamburgerMenu->hideActionsOf(toolBar()); 0037 * // after the QMenuBar has been initialised 0038 * hamburgerMenu->setMenuBar(menuBar()); // line not needed if there is no QMenuBar 0039 * \endcode 0040 * 0041 * The added menu button will only be visible when the QMenuBar is hidden. 0042 * With this minimal initialisation it will contain the contents of the menu bar. 0043 * If a user (also) hides the container the KHamburgerMenu was added to they 0044 * might find themselves without a way to get a menu back. To prevent this, it is 0045 * recommended to add the hamburgerMenu to prominent context menus like the one 0046 * of your central widget preferably at the first position. Simply write: 0047 * 0048 * \code 0049 * hamburgerMenu->addActionToMenu(contextMenu); 0050 * \endcode 0051 * 0052 * The added menu will only be visible if the QMenuBar is hidden and the 0053 * hamburgerMenu->createdWidgets() are all invisible to the user. 0054 * 0055 * **Populating the KHamburgerMenu** 0056 * 0057 * This is easy: 0058 * 0059 * \code 0060 * auto menu = new QMenu(this); 0061 * menu->addAction(action); 0062 * // Add actions, separators, etc. like usual. 0063 * hamburgerMenu->setMenu(menu); 0064 * \endcode 0065 * 0066 * You probably do not want this to happen on startup. Therefore KHamburgerMenu 0067 * provides the signal aboutToShowMenu that you can connect to a function containing 0068 * the previous statements. 0069 * 0070 * \code 0071 * connect(hamburgerMenu, &KHamburgerMenu::aboutToShowMenu, 0072 * this, &MainWindow::updateHamburgerMenu); 0073 * // You might want to disconnect the signal after initial creation if the contents never change. 0074 * \endcode 0075 * 0076 * **Deciding what to put on the hamburger menu** 0077 * 0078 * 1. Be sure to add all of the most important actions. Actions which are already 0079 * visible on QToolBars, etc. will not show up in the hamburgerMenu. To manage 0080 * which containers KHamburgerMenu should watch for redundancy use 0081 * hideActionsOf(QWidget *) and showActionsOf(QWidget *). 0082 * When a KHamburgerMenu is added to a widget, hideActionsOf(that widget) 0083 * will automatically be called. 0084 * 2. Do not worry about adding all actions the application has to offer. 0085 * The KHamburgerMenu will automatically have a section advertising excluded 0086 * actions which can be found in the QMenuBar. There will also be the 0087 * showMenuBarAction if you set it with setShowMenuBarAction(). 0088 * 3. Do not worry about the help menu. KHamburgerMenu will automatically contain 0089 * a help menu as the second to last item (if you set a QMenuBar which is 0090 * expected to have the help menu as the last action). 0091 * 0092 * **Open menu by shortcut** 0093 * 0094 * For visually impaired users it is important to have a consistent way to open a general-purpose 0095 * menu. Triggering the keyboard shortcut bound to KHamburgerMenu will always open a menu. 0096 * - If setMenuBar() was called and that menu bar is visible, the shortcut will open the first menu 0097 * of that menu bar. 0098 * - Otherwise, if there is a visible KHamburgerMenu button in the user interface, that menu will 0099 * open. 0100 * - Otherwise, KHamburgerMenu's menu will open at the mouse cursor position. 0101 * 0102 * @since 5.81 0103 */ 0104 class KCONFIGWIDGETS_EXPORT KHamburgerMenu : public QWidgetAction 0105 { 0106 Q_OBJECT 0107 Q_DECLARE_PRIVATE(KHamburgerMenu) 0108 0109 public: 0110 explicit KHamburgerMenu(QObject *parent); 0111 0112 ~KHamburgerMenu() override; 0113 0114 /** 0115 * Associates this KHamburgerMenu with @p menuBar. The KHamburgerMenu will from now 0116 * on only be visible when @p menuBar is hidden. 0117 * (Menu bars with QMenuBar::isNativeMenuBar() == true are considered hidden.) 0118 * 0119 * Furthermore the KHamburgerMenu will have the help menu from the @p menuBar added 0120 * at the end. There will also be a special sub-menu advertising actions which are 0121 * only available in the menu bar unless advertiseMenuBar(false) was called. 0122 * 0123 * @param menuBar The QMenuBar the KHamburgerMenu should be associated with. 0124 * This can be set to nullptr. 0125 */ 0126 void setMenuBar(QMenuBar *menuBar); 0127 0128 /** @see setMenuBar() */ 0129 QMenuBar *menuBar() const; 0130 0131 /** 0132 * By default the KHamburgerMenu contains a special sub-menu that advertises actions 0133 * of the menu bar which would otherwise not be visible or discoverable for the user. 0134 * This method removes or re-adds that sub-menu. 0135 * 0136 * @param advertise sets whether the special sub-menu that advertises menu bar only 0137 * actions should exist. 0138 */ 0139 void setMenuBarAdvertised(bool advertise); 0140 0141 /** @see setMenuBarAdvertised() */ 0142 bool menuBarAdvertised() const; 0143 0144 /** 0145 * Adds the @p showMenuBarAction as the first item of the sub-menu which advertises actions 0146 * from the menu bar. 0147 * @see setMenuBarAdvertised() 0148 */ 0149 void setShowMenuBarAction(QAction *showMenuBarAction); 0150 0151 /** 0152 * Adds this KHamburgerMenu to @p menu. 0153 * It will only be visible in the menu if both the menu bar and all of this 0154 * QWidgetAction's createdWidgets() are invisible. 0155 * If it is visible in the menu, then opening the menu emits the aboutToShowMenu 0156 * signal. 0157 * 0158 * @param menu The menu this KHamburgerMenu is supposed to appear in. 0159 */ 0160 void addToMenu(QMenu *menu); 0161 0162 /** 0163 * Inserts this KHamburgerMenu to @p menu's list of actions, before the action @p before. 0164 * It will only be visible in the menu if both the menu bar and all of this 0165 * QWidgetAction's createdWidgets() are invisible. 0166 * If it is visible in the menu, then opening the menu emits the aboutToShowMenu 0167 * signal. 0168 * 0169 * @param before The action before which KHamburgerMenu should be inserted. 0170 * @param menu The menu this KHamburgerMenu is supposed to appear in. 0171 * 0172 * @see QWidget::insertAction(), QMenu::insertMenu() 0173 * 0174 * @since 5.99 0175 */ 0176 void insertIntoMenuBefore(QMenu *menu, QAction *before); 0177 0178 /** 0179 * Adds @p widget to a list of widgets that should be monitored for their actions(). 0180 * If the widget is a QMenu, its actions will be treated as known to the user. 0181 * If the widget isn't a QMenu, its actions will only be treated as known to the user 0182 * when the widget is actually visible. 0183 * @param widget A widget that contains actions which should not show up in the 0184 * KHamburgerMenu redundantly. 0185 */ 0186 void hideActionsOf(QWidget *widget); 0187 0188 /** 0189 * Reverses a hideActionsOf(widget) method call. 0190 * @see hideActionsOf() 0191 */ 0192 void showActionsOf(QWidget *widget); 0193 0194 Q_SIGNALS: 0195 /** 0196 * This signal is emitted when a hamburger menu button is about to be pressed down. 0197 * It is also emitted when a QMenu that contains a visible KHamburgerMenu emits 0198 * QMenu::aboutToShow. 0199 */ 0200 void aboutToShowMenu(); 0201 0202 protected: 0203 /** 0204 * @see QWidgetAction::createWidget 0205 */ 0206 virtual QWidget *createWidget(QWidget *parent) override; 0207 0208 private: 0209 std::unique_ptr<KHamburgerMenuPrivate> const d_ptr; 0210 }; 0211 0212 #endif // KHamburgerMenu_H