-
Notifications
You must be signed in to change notification settings - Fork 0
/
QTopMenuTab.hpp
191 lines (147 loc) · 6.35 KB
/
QTopMenuTab.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* This file is part of Escain QTopMenu library
*
* QTopMenu library is free software: you can redistribute it and/or modify
* it under ther terms of the GNU General Public License as published by
* the Free Software Foundation, version 3 of the License.
*
* Escain Documentor is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this library. If not, see <https://www.gnu.org/licenses/>.
*
* Author: Adrian Maire escain (at) gmail.com
*/
#ifndef QTOPMENUTAB_HPP
#define QTOPMENUTAB_HPP
#include <string>
#include <unordered_map>
#include <QShortcut>
#include <QStaticText>
#include <QVariantAnimation>
#include <QWidget>
#include <QClickManager.hpp>
#include "QTopMenuWidgetTypes.hpp"
class QPainter;
namespace Escain
{
/**
* @brief QTopMenuTab
*
* Tab (label) component of the QTopMenu.
*
*/
class QTopMenuTab: public QWidget
{
Q_OBJECT
public:
using Id = std::string;
explicit QTopMenuTab( QWidget* parent=nullptr );
virtual ~QTopMenuTab() = default;
virtual void direction(DisplaySide dir);
virtual DisplaySide direction() const;
class TopMenuTabItem
{
friend QTopMenuTab;
QRectF m_cacheTabTextRect;
QString m_label; //QStaticText is not able to manage mnemonic, use standard QPainter drawText
qreal m_cacheLabelWidth; //cache value for the text width from mStaticText
size_t m_clickableRectangleId;
bool m_pressed = false; //Cache if the cursor is pressed on that tab
bool m_hovered = false; //Cache if the cursor is hovering that tab
std::unique_ptr<QShortcut> m_shortcut;
public:
void tabRect( const QRectF& r) { m_cacheTabTextRect = r; }
const QRectF& tabRect() const { return m_cacheTabTextRect; }
};
/// @brief Create a new tab in the widget
/// @param tabId an id to identify the tab, must be unused for this widget.
/// @param name any label
/// @param pos: where to insert the tab, -1 indicate at the end
/// @return if the insert were successful, (not already existing)
virtual bool insertTab(const Id& tabId, const QString& name, int pos = -1);
/// @brief Remove an existing tab and all it content.
/// @param tabId an id to identify the tab.
/// @return if the removal were successful.
virtual bool removeTab(const Id& tabId);
/// Make the given tab to be selected
virtual void switchToTabById( const Id& idToSelect);
/// Returns the Id of the currently selected tab
const Id& selectedId() const;
/// Space around text in tab
qreal tabMargin() const;
virtual void tabMargin( qreal margin );
/// Percentil of the tabs (label) widths, used as minimal tab size:
/// 0%: all tabs takes exactly their label width + tabMargin*2
/// 100%: all tabs adjust to the same size as the largest + tabMargin*2
qreal tabMinSizePercentil() const;
virtual void tabMinSizePercentil( qreal percentil);
/// Set or retrieve the shortcut to trigger a tab. Underline is applied if one of the
/// characters of the lable match.
const QKeySequence tabShortcut( const Id& id ) const;
virtual bool tabShortcut( const Id& id, const QKeySequence& seq);
/// Label for the given tab
const std::optional<std::string> tabLabel( const Id& menuId ) const;
/// Set the label for the given tab
/// @return true if set properly (false if the menu does not exist)
virtual bool tabLabel( const Id& menuId, const std::string& label);
/// See Qt sizeHint
QSize sizeHint() const override;
signals:
void tabChanged( const Id& prevSelected, const Id& newSelected);
void updateGeometryEvent();
protected:
void resizeEvent(QResizeEvent * event) override;
void paintEvent(QPaintEvent* e) override;
bool event(QEvent* e) override;
virtual void paintTab( QPainter& p, TopMenuTabItem& tab, bool hover, bool press, bool selected ) ;
virtual void paintText( QPainter& p, const TopMenuTabItem& tab, const QRectF& rotatedRect);
/// Set/update the minimum/maximum size
virtual void updateMinMaxSizes();
/// Update cached position of tabs (just the title bar)
virtual void updateTabLabelPos();
/// Update cached size of tabs (just the title bar)
virtual void updateTabLabelSizes();
/// Setup the font to the proper size, weight, etc...
virtual void setupFontForLabel( QFont& f) const;
/// Convert a coordinate/size to it transposed if the widget is at left side (vertical)
static QPointF transposeIfVert(DisplaySide dir, const QPointF& p);
static QSizeF transposeIfVert(DisplaySide dir, const QSizeF& s);
static QRectF transposeIfVert(DisplaySide dir, const QRectF& s);
std::unordered_map<Id, TopMenuTabItem> m_tabs; // Assume all Ids are there and valid.
std::vector<Id> m_tabOrder;
///@brief In which side of the window the tab is shown
DisplaySide m_direction = DisplaySide::Top;
/* The tabs size is calculated in the following way:
* Text is used to get a per-tab required size + margin for aesthetic.
* The mTabSizePercentil set the percentil of tab sizes to which all smaller tabs is
* adjusted: e.g. if percentil 0, all tabs take custom sizes, if percentil 80, 80%
* smaller part of tabs will take the same size, and only 20% will have custom size.*/
///@brief mTabSizePercentil
qreal m_tabSizePercentil = 0.6;
///@brief relative height of tabs, equivalent to an arbitrary font size/dpi
qreal m_tabHeight=40.0;
///@brief margin around texts, or half the minimum width for a tab, and between/around widgets
qreal m_margin=15.0;
///@brief currently selected tab ID
Id m_selectedTab = "";
QClickManager m_clickManager;
///@brief update the minimum and maximum size of this widget
bool m_needUpdateMinMaxSizes = true;
///@brief cache the size of tab labels
bool m_needUpdateTabLabelSizes = true;
///@brief cache the position of tab labels
bool m_needUpdateTabLabelPos = true;
///@brief cache sizeHint value
QSize m_cachedSizeHint = QSize(0,0);
QRect m_underlineAnimated;
QVariantAnimation m_underlineAnimator;
static constexpr qreal UNDERLINE_HEIGHT = 30.0;
static constexpr qreal UNDERLINE_WIDTH = 2.0;
static constexpr qreal UNDERLINE_ANIMATION_TIME_S = 0.4;
};
}
#endif //QTOPMENUTAB_HPP