1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2021 Felix Ernst <fe.a.ernst@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
6*/
7
8#ifndef KHAMBURGERMENUHELPERS_P_H
9#define KHAMBURGERMENUHELPERS_P_H
10
11#include "khamburgermenu_p.h"
12
13#include <QObject>
14
15#include <memory>
16#include <vector>
17
18class QFont;
19class QMenuBar;
20class QWidget;
21
22/**
23 * @brief Makes sure there are no redundant event listeners.
24 *
25 * Functionally identical event listeners are needed throughout khamburgermenu.cpp.
26 * This class makes sure only one of each is created when needed and then reused.
27 * This also simplifies the removal of event listeners.
28 * \internal
29 */
30class ListenerContainer : private QObject
31{
32public:
33 explicit ListenerContainer(KHamburgerMenuPrivate *hamburgerMenuPrivate);
34 ~ListenerContainer() override;
35
36 /**
37 * @return an object of class @p Listener with the same parent as ListenerContainer.
38 */
39 template<class Listener>
40 Listener *get()
41 {
42 for (auto &i : m_listeners) {
43 if (auto existingListener = qobject_cast<Listener *>(i.get())) {
44 return existingListener;
45 }
46 }
47
48 KHamburgerMenuPrivate *hamburgerMenuPrivate = static_cast<KHamburgerMenuPrivate *>(parent());
49 m_listeners.push_back(x: std::unique_ptr<QObject>(new Listener(hamburgerMenuPrivate)));
50 return static_cast<Listener *>(m_listeners.back().get());
51 }
52
53protected:
54 std::vector<std::unique_ptr<QObject>> m_listeners;
55};
56
57/**
58 * When an action is added or removed, calls KHamburgerMenuPrivate::notifyMenuResetNeeded().
59 * \internal
60 */
61class AddOrRemoveActionListener : public QObject
62{
63 Q_OBJECT
64
65protected:
66 inline AddOrRemoveActionListener(QObject *parent)
67 : QObject{parent} {};
68
69 bool eventFilter(QObject * /*watched*/, QEvent *event) override;
70
71 friend class ListenerContainer;
72};
73
74/**
75 * When the button is pressed, emits KHamburgerMenu::aboutToShowMenu(), then calls
76 * KHamburgerMenuPrivate::resetMenu() (which will only actually reset the menu if
77 * a menu reset is needed).
78 * \internal
79 */
80class ButtonPressListener : public QObject
81{
82 Q_OBJECT
83
84public:
85 /**
86 * Makes sure the button can show the expected menu in the expected way when pressed.
87 * A button that hasn't been prepared yet will have no menu at all because the menu is only
88 * created when it is needed.
89 */
90 void prepareHamburgerButtonForPress(QObject *button);
91
92protected:
93 inline ButtonPressListener(QObject *parent)
94 : QObject{parent} {};
95
96 /** Calls prepareButtonForPress() when an event that presses the button is detected. */
97 bool eventFilter(QObject *watched, QEvent *event) override;
98
99 friend class ListenerContainer;
100};
101
102/**
103 * When either
104 * - the visibility of the widget changes or
105 * - actions are added or removed from the widget while it isVisible()
106 * calls KHamburgerMenuPrivate::notifyMenuResetNeeded().
107 * \internal
108 */
109class VisibleActionsChangeListener : public QObject
110{
111 Q_OBJECT
112
113protected:
114 inline VisibleActionsChangeListener(QObject *parent)
115 : QObject{parent} {};
116
117 /**
118 * Listen for events that potentially lead to a change in user-visible actions.
119 * Examples: Adding an action or hiding a toolbar.
120 */
121 bool eventFilter(QObject *watched, QEvent *event) override;
122
123 friend class ListenerContainer;
124};
125
126/**
127 * When the visibility of the widget changes calls KHamburgerMenuPrivate::updateVisibility().
128 * \internal
129 */
130class VisibilityChangesListener : public QObject
131{
132 Q_OBJECT
133
134protected:
135 inline VisibilityChangesListener(QObject *parent)
136 : QObject{parent} {};
137
138 bool eventFilter(QObject * /*watched*/, QEvent *event) override;
139
140 friend class ListenerContainer;
141};
142
143/*
144 * We only consider a visible m_menuBar as actually visible if it is not a native
145 * menu bar because native menu bars can come in many shapes and sizes which don't necessarily
146 * have the same usability benefits as a traditional in-window menu bar.
147 */
148bool isMenuBarVisible(const QMenuBar *menuBar);
149
150/**
151 * Is the widget and all of its ancestors visible?
152 */
153bool isWidgetActuallyVisible(const QWidget *widget);
154
155/*
156 * Call this on menus that don't have a parent or don't want to belong to a singular parent() so
157 * those menus won't be treated like their own separate windows.
158 * @param menu Any menu. Though calling this doesn't make sense if the menu has a parent().
159 * @param surrogateParent The widget that is logically closest to be considered a parent at this
160 * point in time. Pass nullptr if this function is supposed to guess.
161 */
162void prepareParentlessMenuForShowing(QMenu *menu, const QWidget *surrogateParent);
163
164/**
165 * Use this instead of QWidget::isVisible() to work around a peculiarity of QToolBar/QToolButton.
166 */
167void setToolButtonVisible(QWidget *toolButton, bool visible);
168
169/**
170 * Does the @p list contain the @p widget?
171 */
172bool listContainsWidget(const std::forward_list<QPointer<const QWidget>> &list, const QWidget *widget);
173
174#endif // KHAMBURGERMENUHELPERS_P_H
175

source code of kconfigwidgets/src/khamburgermenuhelpers_p.h