1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QMDIAREA_P_H |
5 | #define QMDIAREA_P_H |
6 | |
7 | // |
8 | // W A R N I N G |
9 | // ------------- |
10 | // |
11 | // This file is not part of the Qt API. It exists purely as an |
12 | // implementation detail. This header file may change from version to |
13 | // version without notice, or even be removed. |
14 | // |
15 | // We mean it. |
16 | // |
17 | |
18 | #include <QtWidgets/private/qtwidgetsglobal_p.h> |
19 | #include "qmdiarea.h" |
20 | #include "qmdisubwindow.h" |
21 | |
22 | QT_REQUIRE_CONFIG(mdiarea); |
23 | |
24 | #include <QList> |
25 | #include <QList> |
26 | #include <QRect> |
27 | #include <QPoint> |
28 | #include <QtWidgets/qapplication.h> |
29 | #include <private/qmdisubwindow_p.h> |
30 | #include <private/qabstractscrollarea_p.h> |
31 | |
32 | QT_BEGIN_NAMESPACE |
33 | |
34 | namespace QMdi { |
35 | class Rearranger |
36 | { |
37 | public: |
38 | enum Type { |
39 | RegularTiler, |
40 | SimpleCascader, |
41 | IconTiler |
42 | }; |
43 | |
44 | // Rearranges widgets relative to domain. |
45 | virtual void rearrange(QList<QWidget *> &widgets, const QRect &domain) const = 0; |
46 | virtual Type type() const = 0; |
47 | virtual ~Rearranger() {} |
48 | }; |
49 | |
50 | class RegularTiler : public Rearranger |
51 | { |
52 | // Rearranges widgets according to a regular tiling pattern |
53 | // covering the entire domain. |
54 | // Both positions and sizes may change. |
55 | void rearrange(QList<QWidget *> &widgets, const QRect &domain) const override; |
56 | Type type() const override { return Rearranger::RegularTiler; } |
57 | }; |
58 | |
59 | class SimpleCascader : public Rearranger |
60 | { |
61 | // Rearranges widgets according to a simple, regular cascading pattern. |
62 | // Widgets are resized to minimumSize. |
63 | // Both positions and sizes may change. |
64 | void rearrange(QList<QWidget *> &widgets, const QRect &domain) const override; |
65 | Type type() const override { return Rearranger::SimpleCascader; } |
66 | }; |
67 | |
68 | class IconTiler : public Rearranger |
69 | { |
70 | // Rearranges icons (assumed to be the same size) according to a regular |
71 | // tiling pattern filling up the domain from the bottom. |
72 | // Only positions may change. |
73 | void rearrange(QList<QWidget *> &widgets, const QRect &domain) const override; |
74 | Type type() const override { return Rearranger::IconTiler; } |
75 | }; |
76 | |
77 | class Placer |
78 | { |
79 | public: |
80 | // Places the rectangle defined by 'size' relative to 'rects' and 'domain'. |
81 | // Returns the position of the resulting rectangle. |
82 | virtual QPoint place(const QSize &size, const QList<QRect> &rects, |
83 | const QRect &domain) const = 0; |
84 | virtual ~Placer() {} |
85 | }; |
86 | |
87 | class MinOverlapPlacer : public Placer |
88 | { |
89 | QPoint place(const QSize &size, const QList<QRect> &rects, const QRect &domain) const override; |
90 | static int accumulatedOverlap(const QRect &source, const QList<QRect> &rects); |
91 | static QRect findMinOverlapRect(const QList<QRect> &source, const QList<QRect> &rects); |
92 | static QList<QRect> getCandidatePlacements(const QSize &size, const QList<QRect> &rects, |
93 | const QRect &domain); |
94 | static QPoint findBestPlacement(const QRect &domain, const QList<QRect> &rects, |
95 | QList<QRect> &source); |
96 | static QList<QRect> findNonInsiders(const QRect &domain, QList<QRect> &source); |
97 | static QList<QRect> findMaxOverlappers(const QRect &domain, const QList<QRect> &source); |
98 | }; |
99 | } // namespace QMdi |
100 | |
101 | class QMdiAreaTabBar; |
102 | class QMdiAreaPrivate : public QAbstractScrollAreaPrivate |
103 | { |
104 | Q_DECLARE_PUBLIC(QMdiArea) |
105 | public: |
106 | QMdiAreaPrivate(); |
107 | |
108 | // Variables. |
109 | QMdi::Rearranger *cascader; |
110 | QMdi::Rearranger *regularTiler; |
111 | QMdi::Rearranger *iconTiler; |
112 | QMdi::Placer *placer; |
113 | #if QT_CONFIG(rubberband) |
114 | QRubberBand *rubberBand; |
115 | #endif |
116 | QMdiAreaTabBar *tabBar; |
117 | QList<QMdi::Rearranger *> pendingRearrangements; |
118 | QList<QPointer<QMdiSubWindow>> pendingPlacements; |
119 | QList<QPointer<QMdiSubWindow>> childWindows; |
120 | QList<int> indicesToActivatedChildren; |
121 | QPointer<QMdiSubWindow> active; |
122 | QPointer<QMdiSubWindow> aboutToBecomeActive; |
123 | QBrush background; |
124 | QMdiArea::WindowOrder activationOrder; |
125 | QMdiArea::AreaOptions options; |
126 | QMdiArea::ViewMode viewMode; |
127 | #if QT_CONFIG(tabbar) |
128 | bool documentMode; |
129 | bool tabsClosable; |
130 | bool tabsMovable; |
131 | #endif |
132 | #if QT_CONFIG(tabwidget) |
133 | QTabWidget::TabShape tabShape; |
134 | QTabWidget::TabPosition tabPosition; |
135 | #endif |
136 | bool ignoreGeometryChange; |
137 | bool ignoreWindowStateChange; |
138 | bool isActivated; |
139 | bool isSubWindowsTiled; |
140 | bool showActiveWindowMaximized; |
141 | bool tileCalledFromResizeEvent; |
142 | bool updatesDisabledByUs; |
143 | bool inViewModeChange; |
144 | int indexToNextWindow; |
145 | int indexToPreviousWindow; |
146 | int indexToHighlighted; |
147 | int indexToLastActiveTab; |
148 | int resizeTimerId; |
149 | int tabToPreviousTimerId; |
150 | |
151 | // Slots. |
152 | void _q_deactivateAllWindows(QMdiSubWindow *aboutToActivate = nullptr); |
153 | void _q_processWindowStateChanged(Qt::WindowStates oldState, Qt::WindowStates newState); |
154 | void _q_currentTabChanged(int index); |
155 | void _q_closeTab(int index); |
156 | void _q_moveTab(int from, int to); |
157 | |
158 | // Functions. |
159 | void appendChild(QMdiSubWindow *child); |
160 | void place(QMdi::Placer *placer, QMdiSubWindow *child); |
161 | void rearrange(QMdi::Rearranger *rearranger); |
162 | void arrangeMinimizedSubWindows(); |
163 | void activateWindow(QMdiSubWindow *child); |
164 | void activateCurrentWindow(); |
165 | void activateHighlightedWindow(); |
166 | void emitWindowActivated(QMdiSubWindow *child); |
167 | void resetActiveWindow(QMdiSubWindow *child = nullptr); |
168 | void updateActiveWindow(int removedIndex, bool activeRemoved); |
169 | void updateScrollBars(); |
170 | void internalRaise(QMdiSubWindow *child) const; |
171 | bool scrollBarsEnabled() const; |
172 | bool lastWindowAboutToBeDestroyed() const; |
173 | void setChildActivationEnabled(bool enable = true, bool onlyNextActivationEvent = false) const; |
174 | QRect resizeToMinimumTileSize(const QSize &minSubWindowSize, int subWindowCount); |
175 | void scrollBarPolicyChanged(Qt::Orientation, Qt::ScrollBarPolicy) override; // reimp |
176 | QMdiSubWindow *nextVisibleSubWindow(int increaseFactor, QMdiArea::WindowOrder, |
177 | int removed = -1, int fromIndex = -1) const; |
178 | void highlightNextSubWindow(int increaseFactor); |
179 | QList<QMdiSubWindow *> subWindowList(QMdiArea::WindowOrder, bool reversed = false) const; |
180 | void disconnectSubWindow(QObject *subWindow); |
181 | void setViewMode(QMdiArea::ViewMode mode); |
182 | #if QT_CONFIG(tabbar) |
183 | void updateTabBarGeometry(); |
184 | void refreshTabBar(); |
185 | #endif |
186 | |
187 | inline void startResizeTimer() |
188 | { |
189 | Q_Q(QMdiArea); |
190 | if (resizeTimerId > 0) |
191 | q->killTimer(id: resizeTimerId); |
192 | resizeTimerId = q->startTimer(interval: 200); |
193 | } |
194 | |
195 | inline void startTabToPreviousTimer() |
196 | { |
197 | Q_Q(QMdiArea); |
198 | if (tabToPreviousTimerId > 0) |
199 | q->killTimer(id: tabToPreviousTimerId); |
200 | tabToPreviousTimerId = q->startTimer(interval: QApplication::keyboardInputInterval()); |
201 | } |
202 | |
203 | inline bool windowStaysOnTop(QMdiSubWindow *subWindow) const |
204 | { |
205 | if (!subWindow) |
206 | return false; |
207 | return subWindow->windowFlags() & Qt::WindowStaysOnTopHint; |
208 | } |
209 | |
210 | inline bool isExplicitlyDeactivated(QMdiSubWindow *subWindow) const |
211 | { |
212 | if (!subWindow) |
213 | return true; |
214 | return subWindow->d_func()->isExplicitlyDeactivated; |
215 | } |
216 | |
217 | inline void setActive(QMdiSubWindow *subWindow, bool active = true, bool changeFocus = true) const |
218 | { |
219 | if (subWindow) |
220 | subWindow->d_func()->setActive(activate: active, changeFocus); |
221 | } |
222 | |
223 | #if QT_CONFIG(rubberband) |
224 | void showRubberBandFor(QMdiSubWindow *subWindow); |
225 | |
226 | inline void hideRubberBand() |
227 | { |
228 | if (rubberBand && rubberBand->isVisible()) |
229 | rubberBand->hide(); |
230 | indexToHighlighted = -1; |
231 | } |
232 | #endif // QT_CONFIG(rubberband) |
233 | }; |
234 | |
235 | QT_END_NAMESPACE |
236 | |
237 | #endif // QMDIAREA_P_H |
238 | |