File indexing completed on 2025-04-27 10:04:07
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 * @since 5.81 0093 */ 0094 class KCONFIGWIDGETS_EXPORT KHamburgerMenu : public QWidgetAction 0095 { 0096 Q_OBJECT 0097 Q_DECLARE_PRIVATE(KHamburgerMenu) 0098 0099 public: 0100 explicit KHamburgerMenu(QObject *parent); 0101 0102 ~KHamburgerMenu() override; 0103 0104 /** 0105 * Associates this KHamburgerMenu with @p menuBar. The KHamburgerMenu will from now 0106 * on only be visible when @p menuBar is hidden. 0107 * (Menu bars with QMenuBar::isNativeMenuBar() == true are considered hidden.) 0108 * 0109 * Furthermore the KHamburgerMenu will have the help menu from the @p menuBar added 0110 * at the end. There will also be a special sub-menu advertising actions which are 0111 * only available in the menu bar unless advertiseMenuBar(false) was called. 0112 * 0113 * @param menuBar The QMenuBar the KHamburgerMenu should be associated with. 0114 * This can be set to nullptr. 0115 */ 0116 void setMenuBar(QMenuBar *menuBar); 0117 0118 /** @see setMenuBar() */ 0119 QMenuBar *menuBar() const; 0120 0121 /** 0122 * By default the KHamburgerMenu contains a special sub-menu that advertises actions 0123 * of the menu bar which would otherwise not be visible or discoverable for the user. 0124 * This method removes or re-adds that sub-menu. 0125 * 0126 * @param advertise sets whether the special sub-menu that advertises menu bar only 0127 * actions should exist. 0128 */ 0129 void setMenuBarAdvertised(bool advertise); 0130 0131 /** @see setMenuBarAdvertised() */ 0132 bool menuBarAdvertised() const; 0133 0134 /** 0135 * Adds the @p showMenuBarAction as the first item of the sub-menu which advertises actions 0136 * from the menu bar. 0137 * @see setMenuBarAdvertised() 0138 */ 0139 void setShowMenuBarAction(QAction *showMenuBarAction); 0140 0141 /** 0142 * Adds this KHamburgerMenu to @p menu. 0143 * It will only be visible in the menu if both the menu bar and all of this 0144 * QWidgetAction's createdWidgets() are invisible. 0145 * If it is visible in the menu, then opening the menu emits the aboutToShowMenu 0146 * signal. 0147 * 0148 * @param menu The menu this KHamburgerMenu is supposed to appear in. 0149 */ 0150 void addToMenu(QMenu *menu); 0151 0152 /** 0153 * Inserts this KHamburgerMenu to @p menu's list of actions, before the action @p before. 0154 * It will only be visible in the menu if both the menu bar and all of this 0155 * QWidgetAction's createdWidgets() are invisible. 0156 * If it is visible in the menu, then opening the menu emits the aboutToShowMenu 0157 * signal. 0158 * 0159 * @param before The action before which KHamburgerMenu should be inserted. 0160 * @param menu The menu this KHamburgerMenu is supposed to appear in. 0161 * 0162 * @see QWidget::insertAction(), QMenu::insertMenu() 0163 * 0164 * @since 5.99 0165 */ 0166 void insertIntoMenuBefore(QMenu *menu, QAction *before); 0167 0168 /** 0169 * Adds @p widget to a list of widgets that should be monitored for their actions(). 0170 * If the widget is a QMenu, its actions will be treated as known to the user. 0171 * If the widget isn't a QMenu, its actions will only be treated as known to the user 0172 * when the widget is actually visible. 0173 * @param widget A widget that contains actions which should not show up in the 0174 * KHamburgerMenu redundantly. 0175 */ 0176 void hideActionsOf(QWidget *widget); 0177 0178 /** 0179 * Reverses a hideActionsOf(widget) method call. 0180 * @see hideActionsOf() 0181 */ 0182 void showActionsOf(QWidget *widget); 0183 0184 Q_SIGNALS: 0185 /** 0186 * This signal is emitted when a hamburger menu button is about to be pressed down. 0187 * It is also emitted when a QMenu that contains a visible KHamburgerMenu emits 0188 * QMenu::aboutToShow. 0189 */ 0190 void aboutToShowMenu(); 0191 0192 protected: 0193 /** 0194 * @see QWidgetAction::createWidget 0195 */ 0196 virtual QWidget *createWidget(QWidget *parent) override; 0197 0198 private: 0199 std::unique_ptr<KHamburgerMenuPrivate> const d_ptr; 0200 }; 0201 0202 #endif // KHamburgerMenu_H