on xenial help sign in
implement maximizing windows horizontally/vertically
2989086Lukáš Tinkl
plugins/Utils/windowstatestorage.h+12−2
@@ -25,9 +25,19 @@ class WindowStateStorage: public QObject
25 Q_ENUMS(WindowState)
25 Q_ENUMS(WindowState)
26public:
26public:
27 enum WindowState {
27 enum WindowState {
28− WindowStateNormal,
28+ WindowStateNormal = 1 << 0,
29− WindowStateMaximized
29+ WindowStateMaximized = 1 << 1,
30+ WindowStateMinimized = 1 << 2,
31+ WindowStateFullscreen = 1 << 3,
32+ WindowStateMaximizedLeft = 1 << 4,
33+ WindowStateMaximizedRight = 1 << 5,
34+ WindowStateMaximizedHorizontally = 1 << 6,
35+ WindowStateMaximizedVertically = 1 << 7
30 };
36 };
37+ Q_DECLARE_FLAGS(WindowStates, WindowState)
38+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
39+ Q_FLAG(WindowStates)
40+#endif
31
41
32 WindowStateStorage(QObject *parent = 0);
42 WindowStateStorage(QObject *parent = 0);
33 virtual ~WindowStateStorage();
43 virtual ~WindowStateStorage();
qml/Components/WindowControlButtons.qml+12−1
@@ -27,6 +27,8 @@ Row {
27 signal close()
27 signal close()
28 signal minimize()
28 signal minimize()
29 signal maximize()
29 signal maximize()
30+ signal maximizeVertically()
31+ signal maximizeHorizontally()
30
32
31 MouseArea {
33 MouseArea {
32 id: closeWindowButton
34 id: closeWindowButton
@@ -86,7 +88,16 @@ Row {
86 hoverEnabled: true
88 hoverEnabled: true
87 height: parent.height
89 height: parent.height
88 width: height
90 width: height
91+ acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
92+ onClicked: {
93+ if (mouse.button == Qt.LeftButton) {
89− onClicked: root.maximize()
94+ root.maximize();
95+ } else if (mouse.button == Qt.RightButton) {
96+ root.maximizeHorizontally();
97+ } else if (mouse.button == Qt.MiddleButton) {
98+ root.maximizeVertically();
99+ }
100+ }
90
101
91 Rectangle {
102 Rectangle {
92 anchors.centerIn: parent
103 anchors.centerIn: parent
qml/Stages/DecoratedWindow.qml+4
@@ -48,6 +48,8 @@ FocusScope {
48
48
49 signal close()
49 signal close()
50 signal maximize()
50 signal maximize()
51+ signal maximizeHorizontally()
52+ signal maximizeVertically()
51 signal minimize()
53 signal minimize()
52 signal decorationPressed()
54 signal decorationPressed()
53
55
@@ -88,6 +90,8 @@ FocusScope {
88
90
89 onClose: root.close();
91 onClose: root.close();
90 onMaximize: { root.decorationPressed(); root.maximize(); }
92 onMaximize: { root.decorationPressed(); root.maximize(); }
93+ onMaximizeHorizontally: { root.decorationPressed(); root.maximizeHorizontally(); }
94+ onMaximizeVertically: { root.decorationPressed(); root.maximizeVertically(); }
91 onMinimize: root.minimize();
95 onMinimize: root.minimize();
92 onPressed: root.decorationPressed();
96 onPressed: root.decorationPressed();
93 }
97 }
qml/Stages/DesktopStage.qml+39−33
@@ -89,7 +89,8 @@ AbstractStage {
89 GlobalShortcut {
89 GlobalShortcut {
90 id: minimizeRestoreShortcut
90 id: minimizeRestoreShortcut
91 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
91 shortcut: Qt.MetaModifier|Qt.ControlModifier|Qt.Key_Down
92− onTriggered: priv.focusedAppDelegate.maximized || priv.focusedAppDelegate.maximizedLeft || priv.focusedAppDelegate.maximizedRight
92+ onTriggered: priv.focusedAppDelegate.maximized || priv.focusedAppDelegate.maximizedLeft || priv.focusedAppDelegate.maximizedRight ||
93+ priv.focusedAppDelegate.maximizedHorizontally || priv.focusedAppDelegate.maximizedVertically
93 ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
94 ? priv.focusedAppDelegate.restoreFromMaximized() : priv.focusedAppDelegate.minimize()
94 active: priv.focusedAppDelegate !== null
95 active: priv.focusedAppDelegate !== null
95 }
96 }
@@ -262,19 +263,16 @@ AbstractStage {
262 property alias widthIncrement: decoratedWindow.widthIncrement
263 property alias widthIncrement: decoratedWindow.widthIncrement
263 property alias heightIncrement: decoratedWindow.heightIncrement
264 property alias heightIncrement: decoratedWindow.heightIncrement
264
265
265− QtObject {
266− id: appDelegatePrivate
267− property bool maximized: false
266+ readonly property bool maximized: windowState & WindowStateStorage.WindowStateMaximized
268− property bool maximizedLeft: false
267+ readonly property bool maximizedLeft: windowState & WindowStateStorage.WindowStateMaximizedLeft
269− property bool maximizedRight: false
268+ readonly property bool maximizedRight: windowState & WindowStateStorage.WindowStateMaximizedRight
270− property bool minimized: false
269+ readonly property bool maximizedHorizontally: windowState & WindowStateStorage.WindowStateMaximizedHorizontally
271− }
270+ readonly property bool maximizedVertically: windowState & WindowStateStorage.WindowStateMaximizedVertically
272− readonly property alias maximized: appDelegatePrivate.maximized
271+ readonly property bool minimized: windowState & WindowStateStorage.WindowStateMinimized
273− readonly property alias maximizedLeft: appDelegatePrivate.maximizedLeft
274− readonly property alias maximizedRight: appDelegatePrivate.maximizedRight
275− readonly property alias minimized: appDelegatePrivate.minimized
276 readonly property alias fullscreen: decoratedWindow.fullscreen
272 readonly property alias fullscreen: decoratedWindow.fullscreen
277
273
274+ property int windowState: WindowStateStorage.WindowStateNormal
275+
278 readonly property var application: model.application
276 readonly property var application: model.application
279 property bool animationsEnabled: true
277 property bool animationsEnabled: true
280 property alias title: decoratedWindow.title
278 property alias title: decoratedWindow.title
@@ -372,43 +370,41 @@ AbstractStage {
372
370
373 function maximize(animated) {
371 function maximize(animated) {
374 animationsEnabled = (animated === undefined) || animated;
372 animationsEnabled = (animated === undefined) || animated;
375− appDelegatePrivate.minimized = false;
373+ windowState = WindowStateStorage.WindowStateMaximized;
376− appDelegatePrivate.maximized = true;
377− appDelegatePrivate.maximizedLeft = false;
378− appDelegatePrivate.maximizedRight = false;
379 }
374 }
380 function maximizeLeft() {
375 function maximizeLeft() {
381− appDelegatePrivate.minimized = false;
376+ windowState = WindowStateStorage.WindowStateMaximizedLeft;
382− appDelegatePrivate.maximized = false;
383− appDelegatePrivate.maximizedLeft = true;
384− appDelegatePrivate.maximizedRight = false;
385 }
377 }
386 function maximizeRight() {
378 function maximizeRight() {
387− appDelegatePrivate.minimized = false;
379+ windowState = WindowStateStorage.WindowStateMaximizedRight;
388− appDelegatePrivate.maximized = false;
380+ }
389− appDelegatePrivate.maximizedLeft = false;
381+ function maximizeHorizontally() {
390− appDelegatePrivate.maximizedRight = true;
382+ windowState = WindowStateStorage.WindowStateMaximizedHorizontally;
383+ }
384+ function maximizeVertically() {
385+ windowState = WindowStateStorage.WindowStateMaximizedVertically;
391 }
386 }
392 function minimize(animated) {
387 function minimize(animated) {
393 animationsEnabled = (animated === undefined) || animated;
388 animationsEnabled = (animated === undefined) || animated;
394− appDelegatePrivate.minimized = true;
389+ windowState |= WindowStateStorage.WindowStateMinimized; // add the minimized bit
395 }
390 }
396 function restoreFromMaximized(animated) {
391 function restoreFromMaximized(animated) {
397 animationsEnabled = (animated === undefined) || animated;
392 animationsEnabled = (animated === undefined) || animated;
398− appDelegatePrivate.minimized = false;
393+ windowState = WindowStateStorage.WindowStateNormal;
399− appDelegatePrivate.maximized = false;
400− appDelegatePrivate.maximizedLeft = false;
401− appDelegatePrivate.maximizedRight = false;
402 }
394 }
403 function restore(animated) {
395 function restore(animated) {
404 animationsEnabled = (animated === undefined) || animated;
396 animationsEnabled = (animated === undefined) || animated;
405− appDelegatePrivate.minimized = false;
397+ windowState &= ~WindowStateStorage.WindowStateMinimized; // clear the minimized bit
406 if (maximized)
398 if (maximized)
407 maximize();
399 maximize();
408 else if (maximizedLeft)
400 else if (maximizedLeft)
409 maximizeLeft();
401 maximizeLeft();
410 else if (maximizedRight)
402 else if (maximizedRight)
411 maximizeRight();
403 maximizeRight();
404+ else if (maximizedHorizontally)
405+ maximizeHorizontally();
406+ else if (maximizedVertically)
407+ maximizeVertically();
412
408
413 focus = true;
409 focus = true;
414 }
410 }
@@ -439,8 +435,7 @@ AbstractStage {
439 },
435 },
440 State {
436 State {
441 name: "normal";
437 name: "normal";
442− when: !appDelegate.maximized && !appDelegate.minimized
438+ when: appDelegate.windowState == WindowStateStorage.WindowStateNormal
443− && !appDelegate.maximizedLeft && !appDelegate.maximizedRight
444 PropertyChanges {
439 PropertyChanges {
445 target: appDelegate;
440 target: appDelegate;
446 visuallyMinimized: false;
441 visuallyMinimized: false;
@@ -488,13 +483,21 @@ AbstractStage {
488 requestedHeight: appContainer.height - PanelState.panelHeight
483 requestedHeight: appContainer.height - PanelState.panelHeight
489 }
484 }
490 },
485 },
486+ State {
487+ name: "maximizedHorizontally"; when: appDelegate.maximizedHorizontally && !appDelegate.minimized
488+ PropertyChanges { target: appDelegate; x: root.leftMargin; requestedWidth: appContainer.width - root.leftMargin }
489+ },
490+ State {
491+ name: "maximizedVertically"; when: appDelegate.maximizedVertically && !appDelegate.minimized
492+ PropertyChanges { target: appDelegate; y: PanelState.panelHeight; requestedHeight: appContainer.height - PanelState.panelHeight }
493+ },
491 State {
494 State {
492 name: "minimized"; when: appDelegate.minimized
495 name: "minimized"; when: appDelegate.minimized
493 PropertyChanges {
496 PropertyChanges {
494 target: appDelegate;
497 target: appDelegate;
495 x: -appDelegate.width / 2;
498 x: -appDelegate.width / 2;
496 scale: units.gu(5) / appDelegate.width;
499 scale: units.gu(5) / appDelegate.width;
497− opacity: 0
500+ opacity: 0;
498 visuallyMinimized: true;
501 visuallyMinimized: true;
499 visuallyMaximized: false
502 visuallyMaximized: false
500 }
503 }
@@ -599,7 +602,10 @@ AbstractStage {
599
602
600 onClose: { appDelegate.close(); }
603 onClose: { appDelegate.close(); }
601 onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
604 onMaximize: appDelegate.maximized || appDelegate.maximizedLeft || appDelegate.maximizedRight
605+ || appDelegate.maximizedHorizontally || appDelegate.maximizedVertically
602 ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
606 ? appDelegate.restoreFromMaximized() : appDelegate.maximize()
607+ onMaximizeHorizontally: appDelegate.maximizedHorizontally ? appDelegate.restoreFromMaximized() : appDelegate.maximizeHorizontally()
608+ onMaximizeVertically: appDelegate.maximizedVertically ? appDelegate.restoreFromMaximized() : appDelegate.maximizeVertically()
603 onMinimize: appDelegate.minimize()
609 onMinimize: appDelegate.minimize()
604 onDecorationPressed: { appDelegate.focus = true; }
610 onDecorationPressed: { appDelegate.focus = true; }
605 }
611 }
qml/Stages/WindowDecoration.qml+4
@@ -32,6 +32,8 @@ MouseArea {
32 signal close()
32 signal close()
33 signal minimize()
33 signal minimize()
34 signal maximize()
34 signal maximize()
35+ signal maximizeHorizontally()
36+ signal maximizeVertically()
35
37
36 onDoubleClicked: root.maximize()
38 onDoubleClicked: root.maximize()
37
39
@@ -87,6 +89,8 @@ MouseArea {
87 onClose: root.close();
89 onClose: root.close();
88 onMinimize: root.minimize();
90 onMinimize: root.minimize();
89 onMaximize: root.maximize();
91 onMaximize: root.maximize();
92+ onMaximizeHorizontally: root.maximizeHorizontally();
93+ onMaximizeVertically: root.maximizeVertically();
90 }
94 }
91
95
92 Label {
96 Label {
qml/Stages/WindowResizeArea.qml+13−4
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014-2015 Canonical, Ltd.
2+ * Copyright (C) 2014-2016 Canonical, Ltd.
3 *
3 *
4 * This program is free software; you can redistribute it and/or modify
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
5 * it under the terms of the GNU General Public License as published by
@@ -82,14 +82,23 @@ MouseArea {
82
82
83 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
83 var windowState = windowStateStorage.getState(root.windowId, WindowStateStorage.WindowStateNormal)
84 if (windowState === WindowStateStorage.WindowStateMaximized) {
84 if (windowState === WindowStateStorage.WindowStateMaximized) {
85− target.maximize(false)
85+ target.maximize(false);
86+ } else if (windowState === WindowStateStorage.WindowStateMaximizedLeft) {
87+ target.maximizeLeft();
88+ } else if (windowState === WindowStateStorage.WindowStateMaximizedRight) {
89+ target.maximizeRight();
90+ } else if (windowState === WindowStateStorage.WindowStateMaximizedHorizontally) {
91+ target.maximizeHorizontally();
92+ } else if (windowState === WindowStateStorage.WindowStateMaximizedVertically) {
93+ target.maximizeVertically();
86 }
94 }
95+
87 priv.updateNormalGeometry();
96 priv.updateNormalGeometry();
88 }
97 }
89
98
90 function saveWindowState() {
99 function saveWindowState() {
91− windowStateStorage.saveState(root.windowId, target.state == "maximized" ? WindowStateStorage.WindowStateMaximized : WindowStateStorage.WindowStateNormal)
100+ windowStateStorage.saveState(root.windowId, target.windowState & ~WindowStateStorage.WindowStateMinimized); // clear the minimized bit when saving
92− windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight))
101+ windowStateStorage.saveGeometry(root.windowId, Qt.rect(priv.normalX, priv.normalY, priv.normalWidth, priv.normalHeight));
93 }
102 }
94
103
95 QtObject {
104 QtObject {
tests/mocks/Utils/windowstatestorage.h+13−2
@@ -25,9 +25,20 @@ class WindowStateStorage: public QObject
25 Q_ENUMS(WindowState)
25 Q_ENUMS(WindowState)
26public:
26public:
27 enum WindowState {
27 enum WindowState {
28− WindowStateNormal,
28+ WindowStateNormal = 1 << 0,
29− WindowStateMaximized
29+ WindowStateMaximized = 1 << 1,
30+ WindowStateMinimized = 1 << 2,
31+ WindowStateFullscreen = 1 << 3,
32+ WindowStateMaximizedLeft = 1 << 4,
33+ WindowStateMaximizedRight = 1 << 5,
34+ WindowStateMaximizedHorizontally = 1 << 6,
35+ WindowStateMaximizedVertically = 1 << 7
30 };
36 };
37+ Q_DECLARE_FLAGS(WindowStates, WindowState)
38+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
39+ Q_FLAG(WindowStates)
40+#endif
41+
31 WindowStateStorage(QObject *parent = 0);
42 WindowStateStorage(QObject *parent = 0);
32
43
33 Q_INVOKABLE void saveState(const QString &windowId, WindowState state);
44 Q_INVOKABLE void saveState(const QString &windowId, WindowState state);