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 KHAMBURGERMENUHELPERS_P_H 0009 #define KHAMBURGERMENUHELPERS_P_H 0010 0011 #include "khamburgermenu_p.h" 0012 0013 #include <QObject> 0014 0015 #include <memory> 0016 #include <vector> 0017 0018 class QFont; 0019 class QMenuBar; 0020 class QWidget; 0021 0022 /** 0023 * @brief Makes sure there are no redundant event listeners. 0024 * 0025 * Functionally identical event listeners are needed throughout khamburgermenu.cpp. 0026 * This class makes sure only one of each is created when needed and then reused. 0027 * This also simplifies the removal of event listeners. 0028 * \internal 0029 */ 0030 class ListenerContainer : private QObject 0031 { 0032 public: 0033 explicit ListenerContainer(KHamburgerMenuPrivate *hamburgerMenuPrivate); 0034 ~ListenerContainer() override; 0035 0036 /** 0037 * @return an object of class @p Listener with the same parent as ListenerContainer. 0038 */ 0039 template<class Listener> 0040 Listener *get() 0041 { 0042 for (auto &i : m_listeners) { 0043 if (auto existingListener = qobject_cast<Listener *>(i.get())) { 0044 return existingListener; 0045 } 0046 } 0047 0048 KHamburgerMenuPrivate *hamburgerMenuPrivate = static_cast<KHamburgerMenuPrivate *>(parent()); 0049 m_listeners.push_back(std::unique_ptr<QObject>(new Listener(hamburgerMenuPrivate))); 0050 return static_cast<Listener *>(m_listeners.back().get()); 0051 } 0052 0053 protected: 0054 std::vector<std::unique_ptr<QObject>> m_listeners; 0055 }; 0056 0057 /** 0058 * When an action is added or removed, calls KHamburgerMenuPrivate::notifyMenuResetNeeded(). 0059 * \internal 0060 */ 0061 class AddOrRemoveActionListener : public QObject 0062 { 0063 Q_OBJECT 0064 0065 protected: 0066 inline AddOrRemoveActionListener(QObject *parent) 0067 : QObject{parent} {}; 0068 0069 bool eventFilter(QObject * /*watched*/, QEvent *event) override; 0070 0071 friend class ListenerContainer; 0072 }; 0073 0074 /** 0075 * When the button is pressed, emits KHamburgerMenu::aboutToShowMenu(), then calls 0076 * KHamburgerMenuPrivate::resetMenu() (which will only actually reset the menu if 0077 * a menu reset is needed). 0078 * \internal 0079 */ 0080 class ButtonPressListener : public QObject 0081 { 0082 Q_OBJECT 0083 0084 public: 0085 /** 0086 * Makes sure the button can show the expected menu in the expected way when pressed. 0087 * A button that hasn't been prepared yet will have no menu at all because the menu is only 0088 * created when it is needed. 0089 */ 0090 void prepareHamburgerButtonForPress(QObject *button); 0091 0092 protected: 0093 inline ButtonPressListener(QObject *parent) 0094 : QObject{parent} {}; 0095 0096 /** Calls prepareButtonForPress() when an event that presses the button is detected. */ 0097 bool eventFilter(QObject *watched, QEvent *event) override; 0098 0099 friend class ListenerContainer; 0100 }; 0101 0102 /** 0103 * When either 0104 * - the visibility of the widget changes or 0105 * - actions are added or removed from the widget while it isVisible() 0106 * calls KHamburgerMenuPrivate::notifyMenuResetNeeded(). 0107 * \internal 0108 */ 0109 class VisibleActionsChangeListener : public QObject 0110 { 0111 Q_OBJECT 0112 0113 protected: 0114 inline VisibleActionsChangeListener(QObject *parent) 0115 : QObject{parent} {}; 0116 0117 /** 0118 * Listen for events that potentially lead to a change in user-visible actions. 0119 * Examples: Adding an action or hiding a toolbar. 0120 */ 0121 bool eventFilter(QObject *watched, QEvent *event) override; 0122 0123 friend class ListenerContainer; 0124 }; 0125 0126 /** 0127 * When the visibility of the widget changes calls KHamburgerMenuPrivate::updateVisibility(). 0128 * \internal 0129 */ 0130 class VisibilityChangesListener : public QObject 0131 { 0132 Q_OBJECT 0133 0134 protected: 0135 inline VisibilityChangesListener(QObject *parent) 0136 : QObject{parent} {}; 0137 0138 bool eventFilter(QObject * /*watched*/, QEvent *event) override; 0139 0140 friend class ListenerContainer; 0141 }; 0142 0143 /* 0144 * We only consider a visible m_menuBar as actually visible if it is not a native 0145 * menu bar because native menu bars can come in many shapes and sizes which don't necessarily 0146 * have the same usability benefits as a traditional in-window menu bar. 0147 */ 0148 bool isMenuBarVisible(const QMenuBar *menuBar); 0149 0150 /** 0151 * Is the widget and all of its ancestors visible? 0152 */ 0153 bool isWidgetActuallyVisible(const QWidget *widget); 0154 0155 /* 0156 * Call this on menus that don't have a parent or don't want to belong to a singular parent() so 0157 * those menus won't be treated like their own separate windows. 0158 * @param menu Any menu. Though calling this doesn't make sense if the menu has a parent(). 0159 * @param surrogateParent The widget that is logically closest to be considered a parent at this 0160 * point in time. Pass nullptr if this function is supposed to guess. 0161 */ 0162 void prepareParentlessMenuForShowing(QMenu *menu, const QWidget *surrogateParent); 0163 0164 /** 0165 * Use this instead of QWidget::isVisible() to work around a peculiarity of QToolBar/QToolButton. 0166 */ 0167 void setToolButtonVisible(QWidget *toolButton, bool visible); 0168 0169 /** 0170 * Does the @p list contain the @p widget? 0171 */ 0172 bool listContainsWidget(const std::forward_list<QPointer<const QWidget>> &list, const QWidget *widget); 0173 0174 #endif // KHAMBURGERMENUHELPERS_P_H