1 /*
2 * Copyright 2012, 2013 Thomas Schöps
3 * Copyright 2014 Thomas Schöps, Kai Pastor
4 *
5 * This file is part of OpenOrienteering.
6 *
7 * OpenOrienteering is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * OpenOrienteering is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with OpenOrienteering. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21
22 #ifndef OPENORIENTEERING_PIE_MENU_H
23 #define OPENORIENTEERING_PIE_MENU_H
24
25 #include <cmath>
26
27 #include <QtGlobal>
28 #include <QHash>
29 #include <QObject>
30 #include <QPoint>
31 #include <QPolygon>
32 #include <QWidget>
33
34 class QAction;
35 class QActionEvent;
36 class QHideEvent;
37 class QMouseEvent;
38 class QPaintEvent;
39
40 namespace OpenOrienteering {
41
42
43 /**
44 * Displays a pie menu.
45 *
46 * This class has an API and behavior similar to QMenu,
47 * but is neither a subclass nor a full replacement.
48 */
49 class PieMenu : public QWidget
50 {
51 Q_OBJECT
52 public:
53 /** Stores the geometry of a particular item in the PieMenu. */
54 struct ItemGeometry
55 {
56 /** The area covered by the item. */
57 QPolygon area;
58
59 /** The position of the center of the item. */
60 QPoint icon_pos;
61 };
62
63 /** Constructs a pie menu with default settings. */
64 PieMenu(QWidget* parent = nullptr);
65
66 /** Returns the minimum number of actions in the menu. */
67 int minimumActionCount() const;
68
69 /** Sets the minimum number of actions in the menu (must be at least three). */
70 void setMinimumActionCount(int count);
71
72 /** Returns the current number of visible actions. */
73 int visibleActionCount() const;
74
75 /** Removes all actions from the menu.
76 * Other than QMenu::clear(), this will not immediately delete any action,
77 * even if owned by this object. (Actions owned by this object will be
78 * deleted when this objected is deleted.)
79 * @see QMenu::clear() */
80 void clear();
81
82 /** Returns true if there are no visible actions in the menu,
83 * false otherwise.
84 * @see QMenu::isEmpty */
85 bool isEmpty() const;
86
87 /** Returns the icon size (single dimension). */
88 int iconSize() const;
89
90 /** Sets the icon size (single dimension).
91 * @param icon_size the new size (at least 1) */
92 void setIconSize(int icon_size);
93
94 /** Returns the action at pos.
95 * Returns nullptr if there is no action at this place. */
96 QAction* actionAt(const QPoint& pos) const;
97
98 /** Returns the geometry of the given action.
99 * The action must be enabled and visible.
100 * Otherwise the geometry will be empty.
101 * @see QMenu::actionGeometry */
102 ItemGeometry actionGeometry(QAction* action) const;
103
104 /** Returns the currently highlighted action.
105 * Returns nullptr if no action is highlighted.
106 * @see QMenu::activeAction */
107 QAction* activeAction() const;
108
109 /** Sets the currently highlighted action.
110 * The action must be enabled and visible.
111 * Otherwise there will be no highlighted action.
112 * @see QMenu::setActiveAction */
113 void setActiveAction(QAction* action);
114
115 /** Shows the menu at the given absolute position.
116 * @see QMenu::popup */
117 void popup(const QPoint& pos);
118
119 signals:
120 /** This signal is emitted just before the menu is shown.
121 * @see QMenu::aboutToShow */
122 void aboutToShow();
123
124 /** This signal is emitted just before the menu is hidden.
125 * @see QMenu::aboutToHide */
126 void aboutToHide();
127
128 /** This signal is emitted when a menu item is highlighted.
129 * @see QMenu::hovered */
130 void hovered(QAction* action);
131
132 /** This signal is emitted when a menu item's action is triggered.
133 * @see QMenu::triggered */
134 void triggered(QAction* action);
135
136 protected:
137 void actionEvent(QActionEvent* event) override;
138 void hideEvent(QHideEvent* event) override;
139 void mouseMoveEvent(QMouseEvent* event) override;
140 void mousePressEvent(QMouseEvent* event) override;
141 void mouseReleaseEvent(QMouseEvent* event) override;
142 void paintEvent(QPaintEvent* event) override;
143
144 void updateCachedState();
145
146 QPoint getPoint(double radius, double angle) const;
147
148 int minimum_action_count;
149 int icon_size;
150 QAction* active_action;
151
152 bool actions_changed;
153 bool clicked;
154 int total_radius;
155 QPolygon outer_border;
156 QPolygon inner_border;
157 QHash< QAction*, ItemGeometry > geometries;
158 };
159
160
161 // ### PieMenu inline code ###
162
163 inline
getPoint(double radius,double angle)164 QPoint PieMenu::getPoint(double radius, double angle) const
165 {
166 return QPoint(total_radius + qRound(radius * -sin(angle)), total_radius + qRound(radius * -cos(angle)));
167 }
168
169
170 } // namespace OpenOrienteering
171
172 #endif
173