1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #ifndef QMDISUBWINDOW_P_H
41 #define QMDISUBWINDOW_P_H
42 
43 //
44 //  W A R N I N G
45 //  -------------
46 //
47 // This file is not part of the Qt API.  It exists purely as an
48 // implementation detail.  This header file may change from version to
49 // version without notice, or even be removed.
50 //
51 // We mean it.
52 //
53 
54 #include <QtWidgets/private/qtwidgetsglobal_p.h>
55 #include "qmdisubwindow.h"
56 
57 #include <QStyle>
58 #include <QStyleOptionTitleBar>
59 #if QT_CONFIG(menubar)
60 #include <QMenuBar>
61 #endif
62 #if QT_CONFIG(sizegrip)
63 #include <QSizeGrip>
64 #endif
65 #include <QPointer>
66 #include <QDebug>
67 #include <private/qwidget_p.h>
68 
69 QT_REQUIRE_CONFIG(mdiarea);
70 
71 QT_BEGIN_NAMESPACE
72 
73 class QVBoxLayout;
74 class QMouseEvent;
75 
76 namespace QMdi {
77 template<typename T>
78 class ControlElement : public T
79 {
80 public:
ControlElement(QMdiSubWindow * child)81     ControlElement(QMdiSubWindow *child) : T(child, nullptr)
82     {
83         Q_ASSERT(child);
84         mdiChild = child;
85     }
86 
qt_metacast(const char * classname)87     void *qt_metacast(const char *classname) override
88     {
89         if (classname && strcmp(classname, "ControlElement") == 0)
90             return this;
91         return nullptr;
92     }
93 
94     QPointer<QMdiSubWindow> mdiChild;
95 };
96 
97 class ControlContainer : public QObject
98 {
99 public:
100     ControlContainer(QMdiSubWindow *mdiChild);
101     ~ControlContainer();
102 
103 #if QT_CONFIG(menubar)
104     void showButtonsInMenuBar(QMenuBar *menuBar);
105     void removeButtonsFromMenuBar(QMenuBar *menuBar = nullptr);
menuBar()106     QMenuBar *menuBar() const { return m_menuBar; }
107 #endif
108     void updateWindowIcon(const QIcon &windowIcon);
controllerWidget()109     QWidget *controllerWidget() const { return m_controllerWidget; }
systemMenuLabel()110     QWidget *systemMenuLabel() const { return m_menuLabel; }
111 
112 private:
113     QPointer<QWidget> previousLeft;
114     QPointer<QWidget> previousRight;
115 #if QT_CONFIG(menubar)
116     QPointer<QMenuBar> m_menuBar;
117 #endif
118     QPointer<QWidget> m_controllerWidget;
119     QPointer<QWidget> m_menuLabel;
120     QPointer<QMdiSubWindow> mdiChild;
121 };
122 } // namespace QMdi
123 
124 class QMdiSubWindowPrivate : public QWidgetPrivate
125 {
126     Q_DECLARE_PUBLIC(QMdiSubWindow)
127 public:
128     // Enums and typedefs.
129     enum Operation {
130         None,
131         Move,
132         TopResize,
133         BottomResize,
134         LeftResize,
135         RightResize,
136         TopLeftResize,
137         TopRightResize,
138         BottomLeftResize,
139         BottomRightResize
140     };
141 
142     enum ChangeFlag {
143         HMove = 0x01,
144         VMove = 0x02,
145         HResize = 0x04,
146         VResize = 0x08,
147         HResizeReverse = 0x10,
148         VResizeReverse = 0x20
149     };
150 
151     enum WindowStateAction {
152         RestoreAction,
153         MoveAction,
154         ResizeAction,
155         MinimizeAction,
156         MaximizeAction,
157         StayOnTopAction,
158         CloseAction,
159         /* Add new states _above_ this line! */
160         NumWindowStateActions
161     };
162 
163     struct OperationInfo {
164         uint changeFlags;
165         Qt::CursorShape cursorShape;
166         QRegion region;
167         bool hover;
168         OperationInfo(uint changeFlags, Qt::CursorShape cursorShape, bool hover = true)
changeFlagsOperationInfo169             : changeFlags(changeFlags),
170               cursorShape(cursorShape),
171               hover(hover)
172         {}
173     };
174 
175     typedef QMap<Operation, OperationInfo> OperationInfoMap;
176 
177     QMdiSubWindowPrivate();
178 
179     // Variables.
180     QPointer<QWidget> baseWidget;
181     QPointer<QWidget> restoreFocusWidget;
182     QPointer<QMdi::ControlContainer> controlContainer;
183 #if QT_CONFIG(sizegrip)
184     QPointer<QSizeGrip> sizeGrip;
185 #endif
186 #if QT_CONFIG(rubberband)
187     QRubberBand *rubberBand;
188 #endif
189     QPoint mousePressPosition;
190     QRect oldGeometry;
191     QSize internalMinimumSize;
192     QSize userMinimumSize;
193     QSize restoreSize;
194     bool resizeEnabled;
195     bool moveEnabled;
196     bool isInInteractiveMode;
197 #if QT_CONFIG(rubberband)
198     bool isInRubberBandMode;
199 #endif
200     bool isShadeMode;
201     bool ignoreWindowTitleChange;
202     bool ignoreNextActivationEvent;
203     bool activationEnabled;
204     bool isShadeRequestFromMinimizeMode;
205     bool isMaximizeMode;
206     bool isWidgetHiddenByUs;
207     bool isActive;
208     bool isExplicitlyDeactivated;
209     int keyboardSingleStep;
210     int keyboardPageStep;
211     int resizeTimerId;
212     Operation currentOperation;
213     QStyle::SubControl hoveredSubControl;
214     QStyle::SubControl activeSubControl;
215     Qt::FocusReason focusInReason;
216     OperationInfoMap operationMap;
217     QPointer<QMenu> systemMenu;
218 #ifndef QT_NO_ACTION
219     QPointer<QAction> actions[NumWindowStateActions];
220 #endif
221     QMdiSubWindow::SubWindowOptions options;
222     QString lastChildWindowTitle;
223     QPalette titleBarPalette;
224     QString windowTitle;
225     QFont font;
226     QIcon menuIcon;
227     QStyleOptionTitleBar cachedStyleOptions;
228     QString originalTitle;
229 
230     // Slots.
231     void _q_updateStaysOnTopHint();
232     void _q_enterInteractiveMode();
233     void _q_processFocusChanged(QWidget *old, QWidget *now);
234 
235     // Functions.
236     void leaveInteractiveMode();
237     void removeBaseWidget();
238     void initOperationMap();
239 #if QT_CONFIG(menu)
240     void createSystemMenu();
241 #endif
242     void updateCursor();
243     void updateDirtyRegions();
244     void updateGeometryConstraints();
245     void updateMask();
246     void setNewGeometry(const QPoint &pos);
247     void setMinimizeMode();
248     void setNormalMode();
249     void setMaximizeMode();
250     void setActive(bool activate, bool changeFocus = true);
251     void processClickedSubControl();
252     QRegion getRegion(Operation operation) const;
253     Operation getOperation(const QPoint &pos) const;
254     QStyleOptionTitleBar titleBarOptions() const;
255     void ensureWindowState(Qt::WindowState state);
256     int titleBarHeight(const QStyleOptionTitleBar &options) const;
257     void sizeParameters(int *margin, int *minWidth) const;
258     bool drawTitleBarWhenMaximized() const;
259 #if QT_CONFIG(menubar)
260     QMenuBar *menuBar() const;
261     void showButtonsInMenuBar(QMenuBar *menuBar);
262     void removeButtonsFromMenuBar();
263 #endif
264     void updateWindowTitle(bool requestFromChild);
265 #if QT_CONFIG(rubberband)
266     void enterRubberBandMode();
267     void leaveRubberBandMode();
268 #endif
269     QPalette desktopPalette() const;
270     void updateActions();
271     void setFocusWidget();
272     bool restoreFocus();
273     void storeFocusWidget();
274     void setWindowFlags(Qt::WindowFlags windowFlags) override;
275     void setVisible(WindowStateAction, bool visible = true);
276 #ifndef QT_NO_ACTION
277     void setEnabled(WindowStateAction, bool enable = true);
278 #if QT_CONFIG(menu)
279     void addToSystemMenu(WindowStateAction, const QString &text, const char *slot);
280 #endif
281 #endif // QT_NO_ACTION
282     QSize iconSize() const;
283 #if QT_CONFIG(sizegrip)
284     void setSizeGrip(QSizeGrip *sizeGrip);
285     void setSizeGripVisible(bool visible = true) const;
286 #endif
287     void updateInternalWindowTitle();
288     QString originalWindowTitle();
289     void setNewWindowTitle();
290 
titleBarHeight()291     inline int titleBarHeight() const
292     {
293         Q_Q(const QMdiSubWindow);
294         if (!parent || q->windowFlags() & Qt::FramelessWindowHint
295             || (q->isMaximized() && !drawTitleBarWhenMaximized())) {
296             return 0;
297         }
298         QStyleOptionTitleBar options = titleBarOptions();
299         int height = options.rect.height();
300         if (hasBorder(options))
301             height += q->isMinimized() ? 8 : 4;
302         return height;
303     }
304 
getSubControl(const QPoint & pos)305     inline QStyle::SubControl getSubControl(const QPoint &pos) const
306     {
307         Q_Q(const QMdiSubWindow);
308         QStyleOptionTitleBar titleBarOptions = this->titleBarOptions();
309         return q->style()->hitTestComplexControl(QStyle::CC_TitleBar, &titleBarOptions, pos, q);
310     }
311 
setNewGeometry(QRect * geometry)312     inline void setNewGeometry(QRect *geometry)
313     {
314         Q_Q(QMdiSubWindow);
315         Q_ASSERT(parent);
316         geometry->setSize(geometry->size().expandedTo(internalMinimumSize));
317 #if QT_CONFIG(rubberband)
318         if (isInRubberBandMode)
319             rubberBand->setGeometry(*geometry);
320         else
321 #endif
322             q->setGeometry(*geometry);
323     }
324 
hasBorder(const QStyleOptionTitleBar & options)325     inline bool hasBorder(const QStyleOptionTitleBar &options) const
326     {
327         Q_Q(const QMdiSubWindow);
328         return !q->style()->styleHint(QStyle::SH_TitleBar_NoBorder, &options, q);
329     }
330 
autoRaise()331     inline bool autoRaise() const
332     {
333         Q_Q(const QMdiSubWindow);
334         return q->style()->styleHint(QStyle::SH_TitleBar_AutoRaise, nullptr, q);
335     }
336 
isResizeOperation()337     inline bool isResizeOperation() const
338     {
339         return currentOperation != None && currentOperation != Move;
340     }
341 
isMoveOperation()342     inline bool isMoveOperation() const
343     {
344         return currentOperation == Move;
345     }
346 };
347 
348 QT_END_NAMESPACE
349 
350 #endif // QMDISUBWINDOW_P_H
351