on xenial help sign in
Implement window controls overlay activatable with 3 fingers tap (LP: #1489020)
55a3c1bLukáš Tinkl
plugins/Ubuntu/Gestures/TouchGestureArea.cpp+7−9
@@ -375,7 +375,7 @@ void TouchGestureArea::unownedTouchEvent_waitingForMoreTouches(QTouchEvent *even
375 }
375 }
376 }
376 }
377
377
378− if (m_candidateTouches.count() == 0) {
378+ if (m_candidateTouches.isEmpty()) {
379 setInternalStatus(InternalStatus::WaitingForTouch);
379 setInternalStatus(InternalStatus::WaitingForTouch);
380 }
380 }
381}
381}
@@ -439,7 +439,7 @@ void TouchGestureArea::unownedTouchEvent_rejected(QTouchEvent *event)
439 }
439 }
440 }
440 }
441
441
442− if (m_watchedTouches.count() == 0) {
442+ if (m_watchedTouches.isEmpty()) {
443 setInternalStatus(InternalStatus::WaitingForTouch);
443 setInternalStatus(InternalStatus::WaitingForTouch);
444 }
444 }
445}
445}
@@ -527,7 +527,7 @@ void TouchGestureArea::updateTouchPoints(QTouchEvent *touchEvent)
527 if (updateable) {
527 if (updateable) {
528 if (!dragging() && m_status == InternalStatus::Recognized) {
528 if (!dragging() && m_status == InternalStatus::Recognized) {
529 bool allWantDrag = !m_liveTouchPoints.isEmpty();
529 bool allWantDrag = !m_liveTouchPoints.isEmpty();
530− Q_FOREACH(auto point, m_liveTouchPoints) {
530+ Q_FOREACH(const auto &point, m_liveTouchPoints) {
531 allWantDrag &= point->dragging();
531 allWantDrag &= point->dragging();
532 }
532 }
533 // only dragging if all points are dragging.
533 // only dragging if all points are dragging.
@@ -646,11 +646,9 @@ bool TouchGestureArea::dragging() const
646QQmlListProperty<GestureTouchPoint> TouchGestureArea::touchPoints()
646QQmlListProperty<GestureTouchPoint> TouchGestureArea::touchPoints()
647{
647{
648 return QQmlListProperty<GestureTouchPoint>(this,
648 return QQmlListProperty<GestureTouchPoint>(this,
649− 0,
650− nullptr,
649+ nullptr,
651− TouchGestureArea::touchPoint_count,
650+ TouchGestureArea::touchPoint_count,
652− TouchGestureArea::touchPoint_at,
651+ TouchGestureArea::touchPoint_at);
653− 0);
654}
652}
655
653
656int TouchGestureArea::minimumTouchPoints() const
654int TouchGestureArea::minimumTouchPoints() const
@@ -721,7 +719,7 @@ void TouchGestureArea::rejectGesture()
721 }
719 }
722 m_candidateTouches.clear();
720 m_candidateTouches.clear();
723
721
724− if (m_watchedTouches.count() == 0) {
722+ if (m_watchedTouches.isEmpty()) {
725 setInternalStatus(InternalStatus::WaitingForTouch);
723 setInternalStatus(InternalStatus::WaitingForTouch);
726 } else {
724 } else {
727 setInternalStatus(InternalStatus::Rejected);
725 setInternalStatus(InternalStatus::Rejected);
plugins/Ubuntu/Gestures/TouchGestureArea.h+7−7
@@ -105,8 +105,8 @@ private:
105/*
105/*
106 An area that detects multi-finger gestures.
106 An area that detects multi-finger gestures.
107
107
108− We can use this to detect gestures contstrained by a minimim and/or maximum number of touch points.
108+ We can use this to detect gestures constrained by a minimum and/or maximum number of touch points.
109− This components uses the touch registry to apply for ownership of touch points.
109+ This component uses the touch registry to apply for ownership of touch points.
110 This way we can use the component in conjuntion with the directional drag area to compete for ownwership
110 This way we can use the component in conjuntion with the directional drag area to compete for ownwership
111 or gestures; unlike the MultiPointTouchArea.
111 or gestures; unlike the MultiPointTouchArea.
112 */
112 */
@@ -136,7 +136,7 @@ public:
136 Recognized,
136 Recognized,
137 Rejected
137 Rejected
138 };
138 };
139− TouchGestureArea(QQuickItem* parent = NULL);
139+ TouchGestureArea(QQuickItem* parent = nullptr);
140 ~TouchGestureArea();
140 ~TouchGestureArea();
141
141
142 bool event(QEvent *e) override;
142 bool event(QEvent *e) override;
@@ -164,10 +164,10 @@ Q_SIGNALS:
164
164
165 void touchPointsUpdated();
165 void touchPointsUpdated();
166 void draggingChanged(bool dragging);
166 void draggingChanged(bool dragging);
167− void minimumTouchPointsChanged(bool value);
167+ void minimumTouchPointsChanged(int value);
168− void maximumTouchPointsChanged(bool value);
168+ void maximumTouchPointsChanged(int value);
169− void recognitionPeriodChanged(bool value);
169+ void recognitionPeriodChanged(int value);
170− void releaseRejectPeriodChanged(bool value);
170+ void releaseRejectPeriodChanged(int value);
171
171
172 void pressed(const QList<QObject*>& points);
172 void pressed(const QList<QObject*>& points);
173 void released(const QList<QObject*>& points);
173 void released(const QList<QObject*>& points);
qml/Components/PanelState/PanelState.qml+1
@@ -22,6 +22,7 @@ QtObject {
22
22
23 property string title: ""
23 property string title: ""
24 property bool buttonsVisible: false
24 property bool buttonsVisible: false
25+ property bool buttonsAlwaysVisible: false
25 property bool closeButtonShown: true
26 property bool closeButtonShown: true
26 property bool dropShadow: false
27 property bool dropShadow: false
27 property int panelHeight: 0
28 property int panelHeight: 0
qml/Components/WindowControlButtons.qml+21−27
@@ -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
@@ -19,11 +19,17 @@ import Ubuntu.Components 1.3
19
19
20Row {
20Row {
21 id: root
21 id: root
22− spacing: units.gu(1)
22+ spacing: overlayShown ? units.gu(2) : units.gu(1)
23+ Behavior on spacing {
24+ UbuntuNumberAnimation {}
25+ }
23
26
24 // to be set from outside
27 // to be set from outside
28+ property Item target
25 property bool active: false
29 property bool active: false
30+ property bool windowIsMaximized: false
26 property bool closeButtonShown: true
31 property bool closeButtonShown: true
32+ property bool overlayShown
27
33
28 signal closeClicked()
34 signal closeClicked()
29 signal minimizeClicked()
35 signal minimizeClicked()
@@ -41,20 +47,16 @@ Row {
41 visible: root.closeButtonShown
47 visible: root.closeButtonShown
42
48
43 Rectangle {
49 Rectangle {
44− anchors.centerIn: parent
50+ anchors.fill: parent
45− width: units.gu(2)
46− height: units.gu(2)
47 radius: height / 2
51 radius: height / 2
48 color: theme.palette.normal.negative
52 color: theme.palette.normal.negative
49− visible: parent.containsMouse
53+ visible: parent.containsMouse && !overlayShown
50 }
54 }
51 Icon {
55 Icon {
52− width: height
56+ anchors.fill: parent
53− height: parent.height *.5
57+ anchors.margins: units.dp(3)
54− anchors.centerIn: parent
55 source: "graphics/window-close.svg"
58 source: "graphics/window-close.svg"
56 color: root.active ? "white" : UbuntuColors.slate
59 color: root.active ? "white" : UbuntuColors.slate
57− keyColor: "black"
58 }
60 }
59 }
61 }
60
62
@@ -67,20 +69,16 @@ Row {
67 onClicked: root.minimizeClicked()
69 onClicked: root.minimizeClicked()
68
70
69 Rectangle {
71 Rectangle {
70− anchors.centerIn: parent
72+ anchors.fill: parent
71− width: units.gu(2)
72− height: units.gu(2)
73 radius: height / 2
73 radius: height / 2
74 color: root.active ? UbuntuColors.graphite : UbuntuColors.ash
74 color: root.active ? UbuntuColors.graphite : UbuntuColors.ash
75− visible: parent.containsMouse
75+ visible: parent.containsMouse && !overlayShown
76 }
76 }
77 Icon {
77 Icon {
78− width: height
78+ anchors.fill: parent
79− height: parent.height *.5
79+ anchors.margins: units.dp(3)
80− anchors.centerIn: parent
81 source: "graphics/window-minimize.svg"
80 source: "graphics/window-minimize.svg"
82 color: root.active ? "white" : UbuntuColors.slate
81 color: root.active ? "white" : UbuntuColors.slate
83− keyColor: "black"
84 }
82 }
85 }
83 }
86
84
@@ -102,20 +100,16 @@ Row {
102 }
100 }
103
101
104 Rectangle {
102 Rectangle {
105− anchors.centerIn: parent
103+ anchors.fill: parent
106− width: units.gu(2)
107− height: units.gu(2)
108 radius: height / 2
104 radius: height / 2
109 color: root.active ? UbuntuColors.graphite : UbuntuColors.ash
105 color: root.active ? UbuntuColors.graphite : UbuntuColors.ash
110− visible: parent.containsMouse
106+ visible: parent.containsMouse && !overlayShown
111 }
107 }
112 Icon {
108 Icon {
113− width: height
109+ anchors.fill: parent
114− height: parent.height *.5
110+ anchors.margins: units.dp(3)
115− anchors.centerIn: parent
116− source: "graphics/window-maximize.svg"
111+ source: root.windowIsMaximized ? "graphics/window-window.svg" : "graphics/window-maximize.svg"
117 color: root.active ? "white" : UbuntuColors.slate
112 color: root.active ? "white" : UbuntuColors.slate
118− keyColor: "black"
119 }
113 }
120 }
114 }
121}
115}
qml/Components/graphics/window-close.svg+164−14
@@ -1,14 +1,164 @@
1−<?xml version="1.0" encoding="iso-8859-1"?>
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2−<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3−<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3+
4−<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4+<svg
5− width="94.926px" height="94.926px" viewBox="0 0 94.926 94.926" style="enable-background:new 0 0 94.926 94.926;"
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6− xml:space="preserve">
6+ xmlns:cc="http://creativecommons.org/ns#"
7−<g>
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8− <path d="M55.931,47.463L94.306,9.09c0.826-0.827,0.826-2.167,0-2.994L88.833,0.62C88.436,0.224,87.896,0,87.335,0
8+ xmlns:svg="http://www.w3.org/2000/svg"
9− c-0.562,0-1.101,0.224-1.498,0.62L47.463,38.994L9.089,0.62c-0.795-0.795-2.202-0.794-2.995,0L0.622,6.096
9+ xmlns="http://www.w3.org/2000/svg"
10− c-0.827,0.827-0.827,2.167,0,2.994l38.374,38.373L0.622,85.836c-0.827,0.827-0.827,2.167,0,2.994l5.473,5.476
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11− c0.397,0.396,0.936,0.62,1.498,0.62s1.1-0.224,1.497-0.62l38.374-38.374l38.374,38.374c0.397,0.396,0.937,0.62,1.498,0.62
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12− s1.101-0.224,1.498-0.62l5.473-5.476c0.826-0.827,0.826-2.167,0-2.994L55.931,47.463z"/>
12+ width="96"
13+ height="96"
14+ id="svg4874"
15+ version="1.1"
16+ inkscape:version="0.91+devel r"
17+ viewBox="0 0 96 96.000001"
18+ sodipodi:docname="window-close.svg">
19+ <defs
20+ id="defs4876" />
21+ <sodipodi:namedview
22+ id="base"
23+ pagecolor="#ffffff"
24+ bordercolor="#666666"
25+ borderopacity="1.0"
26+ inkscape:pageopacity="0.0"
27+ inkscape:pageshadow="2"
28+ inkscape:zoom="6.9749997"
29+ inkscape:cx="17.584231"
30+ inkscape:cy="74.637978"
31+ inkscape:document-units="px"
32+ inkscape:current-layer="g4780"
33+ showgrid="true"
34+ showborder="true"
35+ fit-margin-top="0"
36+ fit-margin-left="0"
37+ fit-margin-right="0"
38+ fit-margin-bottom="0"
39+ inkscape:snap-bbox="true"
40+ inkscape:bbox-paths="true"
41+ inkscape:bbox-nodes="true"
42+ inkscape:snap-bbox-edge-midpoints="true"
43+ inkscape:snap-bbox-midpoints="true"
44+ inkscape:object-paths="true"
45+ inkscape:snap-intersection-paths="true"
46+ inkscape:object-nodes="true"
47+ inkscape:snap-smooth-nodes="true"
48+ inkscape:snap-midpoints="true"
49+ inkscape:snap-object-midpoints="true"
50+ inkscape:snap-center="true"
51+ showguides="true"
52+ inkscape:guide-bbox="true"
53+ inkscape:snap-global="true">
54+ <inkscape:grid
55+ type="xygrid"
56+ id="grid5451"
57+ empspacing="8" />
58+ <sodipodi:guide
59+ orientation="1,0"
60+ position="8,-8.0000001"
61+ id="guide4063" />
62+ <sodipodi:guide
63+ orientation="1,0"
64+ position="4,-8.0000001"
65+ id="guide4065" />
66+ <sodipodi:guide
67+ orientation="0,1"
68+ position="-8,88.000001"
69+ id="guide4067" />
70+ <sodipodi:guide
71+ orientation="0,1"
72+ position="-8,92.000001"
73+ id="guide4069" />
74+ <sodipodi:guide
75+ orientation="0,1"
76+ position="104,4"
77+ id="guide4071" />
78+ <sodipodi:guide
79+ orientation="0,1"
80+ position="-5,8.0000001"
81+ id="guide4073" />
82+ <sodipodi:guide
83+ orientation="1,0"
84+ position="92,-8.0000001"
85+ id="guide4075" />
86+ <sodipodi:guide
87+ orientation="1,0"
88+ position="88,-8.0000001"
89+ id="guide4077" />
90+ <sodipodi:guide
91+ orientation="0,1"
92+ position="-8,84.000001"
93+ id="guide4074" />
94+ <sodipodi:guide
95+ orientation="1,0"
96+ position="12,-8.0000001"
97+ id="guide4076" />
98+ <sodipodi:guide
99+ orientation="0,1"
100+ position="-5,12"
101+ id="guide4078" />
102+ <sodipodi:guide
103+ orientation="1,0"
104+ position="84,-9.0000001"
105+ id="guide4080" />
106+ <sodipodi:guide
107+ position="48,-8.0000001"
108+ orientation="1,0"
109+ id="guide4170" />
110+ <sodipodi:guide
111+ position="-8,48"
112+ orientation="0,1"
113+ id="guide4172" />
114+ </sodipodi:namedview>
115+ <metadata
116+ id="metadata4879">
117+ <rdf:RDF>
118+ <cc:Work
119+ rdf:about="">
120+ <dc:format>image/svg+xml</dc:format>
121+ <dc:type
122+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
123+ <dc:title />
124+ </cc:Work>
125+ </rdf:RDF>
126+ </metadata>
127+ <g
128+ inkscape:label="Layer 1"
129+ inkscape:groupmode="layer"
130+ id="layer1"
131+ transform="translate(67.857146,-78.50504)">
132+ <g
133+ transform="matrix(0,-1,-1,0,373.50506,516.50504)"
134+ id="g4845"
135+ style="display:inline">
136+ <g
137+ inkscape:export-ydpi="90"
138+ inkscape:export-xdpi="90"
139+ inkscape:export-filename="next01.png"
140+ transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
141+ id="g4778"
142+ inkscape:label="Layer 1">
143+ <g
144+ transform="matrix(-1,0,0,1,575.99999,611)"
145+ id="g4780"
146+ style="display:inline">
147+ <rect
148+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
149+ id="rect4782"
150+ width="96.037987"
151+ height="96"
152+ x="-438.00244"
153+ y="345.36221"
154+ transform="scale(-1,1)" />
155+ <path
156+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:none;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:3.99999976;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
157+ d="M 14.828125 12.001953 L 12 14.828125 L 45.171875 48 L 12 81.171875 L 14.828125 83.998047 L 48 50.828125 L 81.169922 83.998047 L 84 81.171875 L 50.828125 48 L 84 14.828125 L 81.169922 12.001953 L 48 45.171875 L 14.828125 12.001953 z "
158+ transform="matrix(0,-1,-1.0003957,0,438.00245,441.36222)"
159+ id="path4159" />
160+ </g>
161+ </g>
162+ </g>
13−</g>
163+ </g>
14−</svg>
164+</svg>
qml/Components/graphics/window-maximize.svg+164−12
@@ -1,12 +1,164 @@
1−<?xml version="1.0" encoding="iso-8859-1"?>
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2−<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3−<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3+
4−<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4+<svg
5− width="459px" height="459px" viewBox="0 0 459 459" style="enable-background:new 0 0 459 459;" xml:space="preserve">
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6−<g>
6+ xmlns:cc="http://creativecommons.org/ns#"
7− <g id="check-box-outline-blank">
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8− <path d="M408,51v357H51V51H408 M408,0H51C22.95,0,0,22.95,0,51v357c0,28.05,22.95,51,51,51h357c28.05,0,51-22.95,51-51V51
8+ xmlns:svg="http://www.w3.org/2000/svg"
9− C459,22.95,436.05,0,408,0L408,0z"/>
9+ xmlns="http://www.w3.org/2000/svg"
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ width="96"
13+ height="96"
14+ id="svg4874"
15+ version="1.1"
16+ inkscape:version="0.91+devel r"
17+ viewBox="0 0 96 96.000001"
18+ sodipodi:docname="window-maximize.svg">
19+ <defs
20+ id="defs4876" />
21+ <sodipodi:namedview
22+ id="base"
23+ pagecolor="#ffffff"
24+ bordercolor="#666666"
25+ borderopacity="1.0"
26+ inkscape:pageopacity="0.0"
27+ inkscape:pageshadow="2"
28+ inkscape:zoom="13.623046"
29+ inkscape:cx="24.473234"
30+ inkscape:cy="67.851922"
31+ inkscape:document-units="px"
32+ inkscape:current-layer="g4780"
33+ showgrid="true"
34+ showborder="true"
35+ fit-margin-top="0"
36+ fit-margin-left="0"
37+ fit-margin-right="0"
38+ fit-margin-bottom="0"
39+ inkscape:snap-bbox="true"
40+ inkscape:bbox-paths="true"
41+ inkscape:bbox-nodes="true"
42+ inkscape:snap-bbox-edge-midpoints="true"
43+ inkscape:snap-bbox-midpoints="true"
44+ inkscape:object-paths="true"
45+ inkscape:snap-intersection-paths="true"
46+ inkscape:object-nodes="true"
47+ inkscape:snap-smooth-nodes="true"
48+ inkscape:snap-midpoints="true"
49+ inkscape:snap-object-midpoints="true"
50+ inkscape:snap-center="true"
51+ showguides="true"
52+ inkscape:guide-bbox="true"
53+ inkscape:snap-global="true">
54+ <inkscape:grid
55+ type="xygrid"
56+ id="grid5451"
57+ empspacing="8" />
58+ <sodipodi:guide
59+ orientation="1,0"
60+ position="8,-8.0000001"
61+ id="guide4063" />
62+ <sodipodi:guide
63+ orientation="1,0"
64+ position="4,-8.0000001"
65+ id="guide4065" />
66+ <sodipodi:guide
67+ orientation="0,1"
68+ position="-8,88.000001"
69+ id="guide4067" />
70+ <sodipodi:guide
71+ orientation="0,1"
72+ position="-8,92.000001"
73+ id="guide4069" />
74+ <sodipodi:guide
75+ orientation="0,1"
76+ position="104,4"
77+ id="guide4071" />
78+ <sodipodi:guide
79+ orientation="0,1"
80+ position="-5,8.0000001"
81+ id="guide4073" />
82+ <sodipodi:guide
83+ orientation="1,0"
84+ position="92,-8.0000001"
85+ id="guide4075" />
86+ <sodipodi:guide
87+ orientation="1,0"
88+ position="88,-8.0000001"
89+ id="guide4077" />
90+ <sodipodi:guide
91+ orientation="0,1"
92+ position="-8,84.000001"
93+ id="guide4074" />
94+ <sodipodi:guide
95+ orientation="1,0"
96+ position="12,-8.0000001"
97+ id="guide4076" />
98+ <sodipodi:guide
99+ orientation="0,1"
100+ position="-5,12"
101+ id="guide4078" />
102+ <sodipodi:guide
103+ orientation="1,0"
104+ position="84,-9.0000001"
105+ id="guide4080" />
106+ <sodipodi:guide
107+ position="48,-8.0000001"
108+ orientation="1,0"
109+ id="guide4170" />
110+ <sodipodi:guide
111+ position="-8,48"
112+ orientation="0,1"
113+ id="guide4172" />
114+ </sodipodi:namedview>
115+ <metadata
116+ id="metadata4879">
117+ <rdf:RDF>
118+ <cc:Work
119+ rdf:about="">
120+ <dc:format>image/svg+xml</dc:format>
121+ <dc:type
122+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
123+ <dc:title />
124+ </cc:Work>
125+ </rdf:RDF>
126+ </metadata>
127+ <g
128+ inkscape:label="Layer 1"
129+ inkscape:groupmode="layer"
130+ id="layer1"
131+ transform="translate(67.857146,-78.50504)">
132+ <g
133+ transform="matrix(0,-1,-1,0,373.50506,516.50504)"
134+ id="g4845"
135+ style="display:inline">
136+ <g
137+ inkscape:export-ydpi="90"
138+ inkscape:export-xdpi="90"
139+ inkscape:export-filename="next01.png"
140+ transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
141+ id="g4778"
142+ inkscape:label="Layer 1">
143+ <g
144+ transform="matrix(-1,0,0,1,575.99999,611)"
145+ id="g4780"
146+ style="display:inline">
147+ <rect
148+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
149+ id="rect4782"
150+ width="96.037987"
151+ height="96"
152+ x="-438.00244"
153+ y="345.36221"
154+ transform="scale(-1,1)" />
155+ <path
156+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.23618174;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
157+ d="m 425.99805,429.36328 h -2.11914 -69.91016 v -72.00195 h 72.0293 z m -4.23633,-4.23633 v -63.52929 h -63.55664 v 63.52929 z"
158+ id="rect4198"
159+ inkscape:connector-curvature="0" />
10− </g>
160+ </g>
161+ </g>
162+ </g>
11−</g>
163+ </g>
12−</svg>
164+</svg>
qml/Components/graphics/window-minimize.svg+164−13
@@ -1,13 +1,164 @@
1−<?xml version="1.0" encoding="iso-8859-1"?>
1+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2−<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
2+<!-- Created with Inkscape (http://www.inkscape.org/) -->
3−<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
3+
4−<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
4+<svg
5− width="121.805px" height="121.804px" viewBox="0 0 121.805 121.804" style="enable-background:new 0 0 121.805 121.804;"
5+ xmlns:dc="http://purl.org/dc/elements/1.1/"
6− xml:space="preserve">
6+ xmlns:cc="http://creativecommons.org/ns#"
7−<g>
7+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8− <g>
8+ xmlns:svg="http://www.w3.org/2000/svg"
9− <path d="M7.308,68.211h107.188c4.037,0,7.309-3.272,7.309-7.31c0-4.037-3.271-7.309-7.309-7.309H7.308
9+ xmlns="http://www.w3.org/2000/svg"
10− C3.272,53.593,0,56.865,0,60.902C0,64.939,3.272,68.211,7.308,68.211z"/>
10+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12+ width="96"
13+ height="96"
14+ id="svg4874"
15+ version="1.1"
16+ inkscape:version="0.91+devel r"
17+ viewBox="0 0 96 96.000001"
18+ sodipodi:docname="window-minimize.svg">
19+ <defs
20+ id="defs4876" />
21+ <sodipodi:namedview
22+ id="base"
23+ pagecolor="#ffffff"
24+ bordercolor="#666666"
25+ borderopacity="1.0"
26+ inkscape:pageopacity="0.0"
27+ inkscape:pageshadow="2"
28+ inkscape:zoom="13.623046"
29+ inkscape:cx="24.473234"
30+ inkscape:cy="61.97952"
31+ inkscape:document-units="px"
32+ inkscape:current-layer="g4780"
33+ showgrid="true"
34+ showborder="true"
35+ fit-margin-top="0"
36+ fit-margin-left="0"
37+ fit-margin-right="0"
38+ fit-margin-bottom="0"
39+ inkscape:snap-bbox="true"
40+ inkscape:bbox-paths="true"
41+ inkscape:bbox-nodes="true"
42+ inkscape:snap-bbox-edge-midpoints="true"
43+ inkscape:snap-bbox-midpoints="true"
44+ inkscape:object-paths="true"
45+ inkscape:snap-intersection-paths="true"
46+ inkscape:object-nodes="true"
47+ inkscape:snap-smooth-nodes="true"
48+ inkscape:snap-midpoints="true"
49+ inkscape:snap-object-midpoints="true"
50+ inkscape:snap-center="true"
51+ showguides="true"
52+ inkscape:guide-bbox="true"
53+ inkscape:snap-global="true">
54+ <inkscape:grid
55+ type="xygrid"
56+ id="grid5451"
57+ empspacing="8" />
58+ <sodipodi:guide
59+ orientation="1,0"
60+ position="8,-8.0000001"
61+ id="guide4063" />
62+ <sodipodi:guide
63+ orientation="1,0"
64+ position="4,-8.0000001"
65+ id="guide4065" />
66+ <sodipodi:guide
67+ orientation="0,1"
68+ position="-8,88.000001"
69+ id="guide4067" />
70+ <sodipodi:guide
71+ orientation="0,1"
72+ position="-8,92.000001"
73+ id="guide4069" />
74+ <sodipodi:guide
75+ orientation="0,1"
76+ position="104,4"
77+ id="guide4071" />
78+ <sodipodi:guide
79+ orientation="0,1"
80+ position="-5,8.0000001"
81+ id="guide4073" />
82+ <sodipodi:guide
83+ orientation="1,0"
84+ position="92,-8.0000001"
85+ id="guide4075" />
86+ <sodipodi:guide
87+ orientation="1,0"
88+ position="88,-8.0000001"
89+ id="guide4077" />
90+ <sodipodi:guide
91+ orientation="0,1"
92+ position="-8,84.000001"
93+ id="guide4074" />
94+ <sodipodi:guide
95+ orientation="1,0"
96+ position="12,-8.0000001"
97+ id="guide4076" />
98+ <sodipodi:guide
99+ orientation="0,1"
100+ position="-5,12"
101+ id="guide4078" />
102+ <sodipodi:guide
103+ orientation="1,0"
104+ position="84,-9.0000001"
105+ id="guide4080" />
106+ <sodipodi:guide
107+ position="48,-8.0000001"
108+ orientation="1,0"
109+ id="guide4170" />
110+ <sodipodi:guide
111+ position="-8,48"
112+ orientation="0,1"
113+ id="guide4172" />
114+ </sodipodi:namedview>
115+ <metadata
116+ id="metadata4879">
117+ <rdf:RDF>
118+ <cc:Work
119+ rdf:about="">
120+ <dc:format>image/svg+xml</dc:format>
121+ <dc:type
122+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
123+ <dc:title />
124+ </cc:Work>
125+ </rdf:RDF>
126+ </metadata>
127+ <g
128+ inkscape:label="Layer 1"
129+ inkscape:groupmode="layer"
130+ id="layer1"
131+ transform="translate(67.857146,-78.50504)">
132+ <g
133+ transform="matrix(0,-1,-1,0,373.50506,516.50504)"
134+ id="g4845"
135+ style="display:inline">
136+ <g
137+ inkscape:export-ydpi="90"
138+ inkscape:export-xdpi="90"
139+ inkscape:export-filename="next01.png"
140+ transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)"
141+ id="g4778"
142+ inkscape:label="Layer 1">
143+ <g
144+ transform="matrix(-1,0,0,1,575.99999,611)"
145+ id="g4780"
146+ style="display:inline">
147+ <rect
148+ style="color:#000000;display:inline;overflow:visible;visibility:visible;fill:none;stroke:none;stroke-width:4;marker:none;enable-background:accumulate"
149+ id="rect4782"
150+ width="96.037987"
151+ height="96"
152+ x="-438.00244"
153+ y="345.36221"
154+ transform="scale(-1,1)" />
155+ <path
156+ style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#808080;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4.00079155;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
157+ d="m 387.98242,357.36133 v 72 h 4.00196 v -72 z"
158+ id="path4219"
159+ inkscape:connector-curvature="0" />
160+ </g>
161+ </g>
11− </g>
162+ </g>
12−</g>
163+ </g>
13−</svg>
164+</svg>
qml/Components/graphics/window-window.svgnew file+41
@@ -0,0 +1,41 @@
1+<?xml version="1.0" encoding="utf-8"?>
2+<!-- Generator: Adobe Illustrator 19.2.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3+<svg version="1.1"
4+ id="svg4874" inkscape:version="0.91+devel r" sodipodi:docname="window-maximize.svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:svg="http://www.w3.org/2000/svg"
5+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 96 96"
6+ style="enable-background:new 0 0 96 96;" xml:space="preserve">
7+<style type="text/css">
8+ .st0{fill:none;}
9+ .st1{fill:#808080;}
10+</style>
11+<sodipodi:namedview bordercolor="#666666" borderopacity="1.0" fit-margin-bottom="0" fit-margin-left="0" fit-margin-right="0" fit-margin-top="0" id="base" inkscape:bbox-nodes="true" inkscape:bbox-paths="true" inkscape:current-layer="g4780" inkscape:cx="24.473234" inkscape:cy="67.851922" inkscape:document-units="px" inkscape:guide-bbox="true" inkscape:object-nodes="true" inkscape:object-paths="true" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:snap-bbox="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:snap-center="true" inkscape:snap-global="true" inkscape:snap-intersection-paths="true" inkscape:snap-midpoints="true" inkscape:snap-object-midpoints="true" inkscape:snap-smooth-nodes="true" inkscape:zoom="13.623046" pagecolor="#ffffff" showborder="true" showgrid="true" showguides="true">
12+ <inkscape:grid empspacing="8" id="grid5451" type="xygrid"></inkscape:grid>
13+ <sodipodi:guide id="guide4063" orientation="1,0" position="8,-8.0000001"></sodipodi:guide>
14+ <sodipodi:guide id="guide4065" orientation="1,0" position="4,-8.0000001"></sodipodi:guide>
15+ <sodipodi:guide id="guide4067" orientation="0,1" position="-8,88.000001"></sodipodi:guide>
16+ <sodipodi:guide id="guide4069" orientation="0,1" position="-8,92.000001"></sodipodi:guide>
17+ <sodipodi:guide id="guide4071" orientation="0,1" position="104,4"></sodipodi:guide>
18+ <sodipodi:guide id="guide4073" orientation="0,1" position="-5,8.0000001"></sodipodi:guide>
19+ <sodipodi:guide id="guide4075" orientation="1,0" position="92,-8.0000001"></sodipodi:guide>
20+ <sodipodi:guide id="guide4077" orientation="1,0" position="88,-8.0000001"></sodipodi:guide>
21+ <sodipodi:guide id="guide4074" orientation="0,1" position="-8,84.000001"></sodipodi:guide>
22+ <sodipodi:guide id="guide4076" orientation="1,0" position="12,-8.0000001"></sodipodi:guide>
23+ <sodipodi:guide id="guide4078" orientation="0,1" position="-5,12"></sodipodi:guide>
24+ <sodipodi:guide id="guide4080" orientation="1,0" position="84,-9.0000001"></sodipodi:guide>
25+ <sodipodi:guide id="guide4170" orientation="1,0" position="48,-8.0000001"></sodipodi:guide>
26+ <sodipodi:guide id="guide4172" orientation="0,1" position="-8,48"></sodipodi:guide>
27+</sodipodi:namedview>
28+<g id="layer1" transform="translate(67.857146,-78.50504)" inkscape:groupmode="layer" inkscape:label="Layer 1">
29+ <g id="g4845" transform="matrix(0,-1,-1,0,373.50506,516.50504)">
30+
31+ <g id="g4778" transform="matrix(-0.9996045,0,0,1,575.94296,-611.00001)" inkscape:export-filename="next01.png" inkscape:export-xdpi="90" inkscape:export-ydpi="90" inkscape:label="Layer 1">
32+ <g id="g4780" transform="matrix(-1,0,0,1,575.99999,611)">
33+
34+ <rect id="rect4782" x="340.5" y="424.9" transform="matrix(-2.535182e-06 -1 1 -2.535182e-06 -4.8782 781.8463)" class="st0" width="96" height="-63"/>
35+ <path id="rect4198" inkscape:connector-curvature="0" class="st1" d="M408,429.4h-2.1H369v-72h39V429.4z M403.8,425.1v-63.5
36+ h-30.5v63.5H403.8z"/>
37+ </g>
38+ </g>
39+ </g>
40+</g>
41+</svg>
qml/Panel/Panel.qml+5−2
@@ -125,8 +125,11 @@ Item {
125 bottomMargin: units.gu(0.5)
125 bottomMargin: units.gu(0.5)
126 }
126 }
127 height: indicators.minimizedPanelHeight - anchors.topMargin - anchors.bottomMargin
127 height: indicators.minimizedPanelHeight - anchors.topMargin - anchors.bottomMargin
128+
128− visible: PanelState.buttonsVisible && parent.containsMouse && !root.locked && !callHint.visible
129+ visible: ((PanelState.buttonsVisible && parent.containsMouse) || PanelState.buttonsAlwaysVisible)
130+ && !root.locked && !callHint.visible
129− active: PanelState.buttonsVisible
131+ active: PanelState.buttonsVisible || PanelState.buttonsAlwaysVisible
132+ windowIsMaximized: true
130 onCloseClicked: PanelState.closeClicked()
133 onCloseClicked: PanelState.closeClicked()
131 onMinimizeClicked: PanelState.minimizeClicked()
134 onMinimizeClicked: PanelState.minimizeClicked()
132 onMaximizeClicked: PanelState.restoreClicked()
135 onMaximizeClicked: PanelState.restoreClicked()
qml/Stages/DecoratedWindow.qml+2
@@ -49,6 +49,8 @@ FocusScope {
49 readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
49 readonly property int widthIncrement: !counterRotate ? applicationWindow.widthIncrement : applicationWindow.heightIncrement
50 readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
50 readonly property int heightIncrement: !counterRotate ? applicationWindow.heightIncrement : applicationWindow.widthIncrement
51
51
52+ property alias overlayShown: decoration.overlayShown
53+
52 signal closeClicked()
54 signal closeClicked()
53 signal maximizeClicked()
55 signal maximizeClicked()
54 signal maximizeHorizontallyClicked()
56 signal maximizeHorizontallyClicked()
qml/Stages/DesktopStage.qml+20−2
@@ -316,6 +316,7 @@ AbstractStage {
316 property bool visuallyMinimized: false
316 property bool visuallyMinimized: false
317
317
318 readonly property var surface: model.surface
318 readonly property var surface: model.surface
319+ readonly property alias resizeArea: resizeArea
319
320
320 function claimFocus() {
321 function claimFocus() {
321 if (spread.state == "altTab") {
322 if (spread.state == "altTab") {
@@ -345,13 +346,13 @@ AbstractStage {
345 return;
346 return;
346
347
347 if (focus) {
348 if (focus) {
348− priv.focusedAppDelegate = appDelegate;
349−
350 // If we're orphan (!parent) it means this stage is no longer the current one
349 // If we're orphan (!parent) it means this stage is no longer the current one
351 // and will be deleted shortly. So we should no longer have a say over the model
350 // and will be deleted shortly. So we should no longer have a say over the model
352 if (root.parent) {
351 if (root.parent) {
353 topLevelSurfaceList.raiseId(model.id);
352 topLevelSurfaceList.raiseId(model.id);
354 }
353 }
354+
355+ priv.focusedAppDelegate = appDelegate;
355 } else if (!focus && priv.focusedAppDelegate === appDelegate) {
356 } else if (!focus && priv.focusedAppDelegate === appDelegate) {
356 priv.focusedAppDelegate = null;
357 priv.focusedAppDelegate = null;
357 // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
358 // FIXME: No idea why the Binding{} doens't update when focusedAppDelegate turns null
@@ -600,9 +601,19 @@ AbstractStage {
600 when: index == spread.highlightedIndex && spread.ready
601 when: index == spread.highlightedIndex && spread.ready
601 }
602 }
602
603
604+ Binding {
605+ target: PanelState
606+ property: "buttonsAlwaysVisible"
607+ value: appDelegate && appDelegate.maximized && touchControls.overlayShown
608+ }
609+
603 WindowResizeArea {
610 WindowResizeArea {
604 id: resizeArea
611 id: resizeArea
605 objectName: "windowResizeArea"
612 objectName: "windowResizeArea"
613+
614+ // workaround so that it chooses the correct resize borders when you drag from a corner ResizeGrip
615+ anchors.margins: touchControls.overlayShown ? borderThickness/2 : -borderThickness
616+
606 target: appDelegate
617 target: appDelegate
607 minWidth: units.gu(10)
618 minWidth: units.gu(10)
608 minHeight: units.gu(10)
619 minHeight: units.gu(10)
@@ -643,6 +654,7 @@ AbstractStage {
643 surface: model.surface
654 surface: model.surface
644 active: appDelegate.focus
655 active: appDelegate.focus
645 focus: true
656 focus: true
657+ overlayShown: touchControls.overlayShown
646
658
647 requestedWidth: appDelegate.requestedWidth
659 requestedWidth: appDelegate.requestedWidth
648 requestedHeight: appDelegate.requestedHeight
660 requestedHeight: appDelegate.requestedHeight
@@ -657,6 +669,12 @@ AbstractStage {
657 onDecorationPressed: { appDelegate.focus = true; }
669 onDecorationPressed: { appDelegate.focus = true; }
658 }
670 }
659
671
672+ WindowControlsOverlay {
673+ id: touchControls
674+ anchors.fill: appDelegate
675+ target: appDelegate
676+ }
677+
660 WindowedFullscreenPolicy {
678 WindowedFullscreenPolicy {
661 id: fullscreenPolicy
679 id: fullscreenPolicy
662 active: true
680 active: true
qml/Stages/ResizeGrip.qmlnew file+46
@@ -0,0 +1,46 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
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
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+
20+Rectangle {
21+ width: units.gu(4)
22+ height: width
23+ radius: height / 2
24+ color: theme.palette.normal.background
25+ opacity: 0.95
26+
27+ // to be set from outside
28+ property Item resizeTarget
29+
30+ Image {
31+ source: "graphics/arrows.png"
32+ anchors.centerIn: parent
33+ width: units.gu(2)
34+ height: width
35+ fillMode: Image.PreserveAspectFit
36+ }
37+
38+ MouseArea {
39+ anchors.fill: parent
40+ anchors.margins: -units.gu(1.5)
41+ hoverEnabled: true
42+
43+ Mouse.enabled: resizeTarget
44+ Mouse.forwardTo: resizeTarget
45+ }
46+}
qml/Stages/TabletSideStageTouchGesture.qml+3
@@ -106,6 +106,9 @@ TouchGestureArea {
106 }
106 }
107
107
108 onDragStarted: {
108 onDragStarted: {
109+ if (!dragComponent)
110+ return;
111+
109 if (dragComponentProperties) {
112 if (dragComponentProperties) {
110 priv.dragObject = dragComponent.createObject(root, dragComponentProperties);
113 priv.dragObject = dragComponent.createObject(root, dragComponentProperties);
111 } else {
114 } else {
qml/Stages/TabletStage.qml−1
@@ -1035,7 +1035,6 @@ AbstractStage {
1035 id: triGestureArea
1035 id: triGestureArea
1036 anchors.fill: parent
1036 anchors.fill: parent
1037 enabled: priv.sideStageEnabled && !spreadView.active
1037 enabled: priv.sideStageEnabled && !spreadView.active
1038− property var dragObject: null
1039
1038
1040 property Item spreadDelegate
1039 property Item spreadDelegate
1041
1040
qml/Stages/WindowControlsOverlay.qmlnew file+219
@@ -0,0 +1,219 @@
1+/*
2+ * Copyright (C) 2016 Canonical, Ltd.
3+ *
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
6+ * the Free Software Foundation; version 3.
7+ *
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
12+ *
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
15+ */
16+
17+import QtQuick 2.4
18+import Ubuntu.Components 1.3
19+import Ubuntu.Gestures 0.1
20+import Unity.Application 0.1
21+import "../Components/PanelState"
22+
23+Item {
24+ id: root
25+ enabled: target && !target.fullscreen
26+
27+ // to be set from outside
28+ property Item target // appDelegate
29+
30+ // to be read from outside
31+ readonly property alias overlayShown: overlay.visible
32+
33+ TouchGestureArea {
34+ id: gestureArea
35+ anchors.fill: parent
36+
37+ // NB: for testing set to 2, not to clash with unity7 touch overlay controls
38+ minimumTouchPoints: 3
39+ maximumTouchPoints: minimumTouchPoints
40+
41+ readonly property bool recognizedPress: status == TouchGestureArea.Recognized &&
42+ touchPoints.length >= minimumTouchPoints &&
43+ touchPoints.length <= maximumTouchPoints
44+ onRecognizedPressChanged: {
45+ if (recognizedPress) {
46+ target.focus = true;
47+ overlayTimer.start();
48+ }
49+ }
50+
51+ readonly property bool recognizedDrag: recognizedPress && dragging
52+ onRecognizedDragChanged: {
53+ if (recognizedDrag) {
54+ priv.handlePressedChanged(true, tp.x, tp.y);
55+ } else if (!moveHandler.containsPress) { // prevent interfering with the central piece drag/move
56+ priv.dragging = false;
57+ }
58+ }
59+
60+ readonly property point tp: recognizedPress ? Qt.point(touchPoints[0].x, touchPoints[0].y) : Qt.point(-1, -1)
61+ onUpdated: {
62+ if (recognizedDrag) {
63+ priv.handlePositionChanged(tp.x, tp.y);
64+ }
65+ }
66+ }
67+
68+ // dismiss timer
69+ Timer {
70+ id: overlayTimer
71+ interval: 2000
72+ repeat: priv.dragging || (priv.resizeArea && priv.resizeArea.dragging)
73+ }
74+
75+ QtObject {
76+ id: priv
77+ property real distanceX
78+ property real distanceY
79+ property bool dragging
80+
81+ readonly property var resizeArea: root.target && root.target.resizeArea ? root.target.resizeArea : null
82+
83+ function handlePressedChanged(pressed, mouseX, mouseY) {
84+ if (pressed) {
85+ var pos = mapToItem(root.target, mouseX, mouseY);
86+ priv.distanceX = pos.x;
87+ priv.distanceY = pos.y;
88+ priv.dragging = true;
89+ } else {
90+ priv.dragging = false;
91+ }
92+ }
93+
94+ function handlePositionChanged(mouseX, mouseY) {
95+ if (priv.dragging) {
96+ var pos = mapToItem(root.target.parent, mouseX, mouseY);
97+ root.target.x = Math.round(pos.x - priv.distanceX);
98+ root.target.y = Math.round(Math.max(pos.y - priv.distanceY, PanelState.panelHeight));
99+ }
100+ }
101+ }
102+
103+ // the visual overlay
104+ Item {
105+ id: overlay
106+ objectName: "windowControlsOverlay"
107+ anchors.fill: parent
108+ enabled: overlayTimer.running
109+ visible: opacity > 0
110+ opacity: enabled ? 0.95 : 0
111+
112+ Behavior on opacity {
113+ UbuntuNumberAnimation {}
114+ }
115+
116+ readonly property bool anyMaximized: target && (target.maximized || target.maximizedLeft || target.maximizedRight)
117+
118+ Image {
119+ source: "graphics/arrows-centre.png"
120+ width: units.gu(10)
121+ height: width
122+ sourceSize: Qt.size(width, height)
123+ anchors.centerIn: parent
124+ visible: target && target.width > units.gu(12) && target.height > units.gu(12)
125+
126+ // move handler
127+ MouseArea {
128+ id: moveHandler
129+ anchors.fill: parent
130+ visible: overlay.visible
131+ enabled: visible
132+ hoverEnabled: true
133+ cursorShape: priv.dragging ? Qt.ClosedHandCursor : (overlay.visible ? Qt.OpenHandCursor : Qt.ArrowCursor)
134+
135+ onPressedChanged: priv.handlePressedChanged(pressed, mouseX, mouseY)
136+ onPositionChanged: priv.handlePositionChanged(mouseX, mouseY)
137+ }
138+
139+ // dismiss area
140+ InverseMouseArea {
141+ anchors.fill: parent
142+ visible: overlay.visible
143+ enabled: visible
144+ onPressed: {
145+ if (gestureArea.recognizedPress || gestureArea.recognizedDrag) {
146+ mouse.accepted = false;
147+ return;
148+ }
149+
150+ overlayTimer.stop();
151+ mouse.accepted = root.contains(Qt.point(mouse.x, mouse.y));
152+ }
153+ propagateComposedEvents: true
154+ }
155+ }
156+
157+ ResizeGrip { // top left
158+ anchors.horizontalCenter: parent.left
159+ anchors.verticalCenter: parent.top
160+ visible: target && !overlay.anyMaximized && !target.maximizedHorizontally && !target.maximizedVertically
161+ resizeTarget: priv.resizeArea
162+ }
163+
164+ ResizeGrip { // top center
165+ anchors.horizontalCenter: parent.horizontalCenter
166+ anchors.verticalCenter: parent.top
167+ rotation: 45
168+ visible: target && !overlay.anyMaximized && !target.maximizedVertically
169+ resizeTarget: priv.resizeArea
170+ }
171+
172+ ResizeGrip { // top right
173+ anchors.horizontalCenter: parent.right
174+ anchors.verticalCenter: parent.top
175+ rotation: 90
176+ visible: target && !overlay.anyMaximized && !target.maximizedHorizontally && !target.maximizedVertically
177+ resizeTarget: priv.resizeArea
178+ }
179+
180+ ResizeGrip { // right
181+ anchors.horizontalCenter: parent.right
182+ anchors.verticalCenter: parent.verticalCenter
183+ rotation: 135
184+ visible: target && !target.maximizedRight && !target.maximized && !target.maximizedHorizontally
185+ resizeTarget: priv.resizeArea
186+ }
187+
188+ ResizeGrip { // bottom right
189+ anchors.horizontalCenter: parent.right
190+ anchors.verticalCenter: parent.bottom
191+ visible: target && !overlay.anyMaximized && !target.maximizedHorizontally && !target.maximizedVertically
192+ resizeTarget: priv.resizeArea
193+ }
194+
195+ ResizeGrip { // bottom center
196+ anchors.horizontalCenter: parent.horizontalCenter
197+ anchors.verticalCenter: parent.bottom
198+ rotation: 45
199+ visible: target && !overlay.anyMaximized && !target.maximizedVertically
200+ resizeTarget: priv.resizeArea
201+ }
202+
203+ ResizeGrip { // bottom left
204+ anchors.horizontalCenter: parent.left
205+ anchors.verticalCenter: parent.bottom
206+ rotation: 90
207+ visible: target && !overlay.anyMaximized && !target.maximizedHorizontally && !target.maximizedVertically
208+ resizeTarget: priv.resizeArea
209+ }
210+
211+ ResizeGrip { // left
212+ anchors.horizontalCenter: parent.left
213+ anchors.verticalCenter: parent.verticalCenter
214+ rotation: 135
215+ visible: target && !target.maximizedLeft && !target.maximized && !target.maximizedHorizontally
216+ resizeTarget: priv.resizeArea
217+ }
218+ }
219+}
qml/Stages/WindowDecoration.qml+13−1
@@ -27,6 +27,8 @@ MouseArea {
27 property Item target
27 property Item target
28 property alias title: titleLabel.text
28 property alias title: titleLabel.text
29 property bool active: false
29 property bool active: false
30+ property alias overlayShown: buttons.overlayShown
31+
30 hoverEnabled: true
32 hoverEnabled: true
31
33
32 signal closeClicked()
34 signal closeClicked()
@@ -78,11 +80,15 @@ MouseArea {
78 Row {
80 Row {
79 anchors {
81 anchors {
80 fill: parent
82 fill: parent
81− leftMargin: units.gu(1)
83+ leftMargin: overlayShown ? units.gu(5) : units.gu(1)
82 rightMargin: units.gu(1)
84 rightMargin: units.gu(1)
83 topMargin: units.gu(0.5)
85 topMargin: units.gu(0.5)
84 bottomMargin: units.gu(0.5)
86 bottomMargin: units.gu(0.5)
85 }
87 }
88+ Behavior on anchors.leftMargin {
89+ UbuntuNumberAnimation {}
90+ }
91+
86 spacing: units.gu(3)
92 spacing: units.gu(3)
87
93
88 WindowControlButtons {
94 WindowControlButtons {
@@ -95,6 +101,7 @@ MouseArea {
95 onMaximizeHorizontallyClicked: root.maximizeHorizontallyClicked();
101 onMaximizeHorizontallyClicked: root.maximizeHorizontallyClicked();
96 onMaximizeVerticallyClicked: root.maximizeVerticallyClicked();
102 onMaximizeVerticallyClicked: root.maximizeVerticallyClicked();
97 closeButtonShown: root.target.application.appId !== "unity8-dash"
103 closeButtonShown: root.target.application.appId !== "unity8-dash"
104+ target: root.target
98 }
105 }
99
106
100 Label {
107 Label {
@@ -107,6 +114,11 @@ MouseArea {
107 fontSize: "medium"
114 fontSize: "medium"
108 font.weight: root.active ? Font.Light : Font.Medium
115 font.weight: root.active ? Font.Light : Font.Medium
109 elide: Text.ElideRight
116 elide: Text.ElideRight
117+ opacity: overlayShown ? 0 : 1
118+ visible: opacity == 1
119+ Behavior on opacity {
120+ OpacityAnimator { duration: UbuntuAnimation.FastDuration; easing: UbuntuAnimation.StandardEasing }
121+ }
110 }
122 }
111 }
123 }
112}
124}
qml/Stages/WindowResizeArea.qml+4−4
@@ -22,15 +22,17 @@ import "../Components/PanelState"
22
22
23MouseArea {
23MouseArea {
24 id: root
24 id: root
25+
25 anchors.fill: target
26 anchors.fill: target
26 anchors.margins: -borderThickness
27 anchors.margins: -borderThickness
27
28
28 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
29 hoverEnabled: target && !target.maximized // don't grab the resize under the panel
29
30
30 property var windowStateStorage: WindowStateStorage
31 property var windowStateStorage: WindowStateStorage
32+ readonly property alias dragging: d.dragging
31
33
32 // The target item managed by this. Must be a parent or a sibling
34 // The target item managed by this. Must be a parent or a sibling
33− // The area will anchor to it and manage move and resize events
35+ // The area will anchor to it and manage resize events
34 property Item target: null
36 property Item target: null
35 property string windowId: ""
37 property string windowId: ""
36 property int borderThickness: 0
38 property int borderThickness: 0
@@ -200,7 +202,7 @@ MouseArea {
200 property real currentWidth
202 property real currentWidth
201 property real currentHeight
203 property real currentHeight
202
204
203− property string cursorName: {
205+ readonly property string cursorName: {
204 if (root.containsMouse || root.pressed) {
206 if (root.containsMouse || root.pressed) {
205 if (leftBorder && !topBorder && !bottomBorder) {
207 if (leftBorder && !topBorder && !bottomBorder) {
206 return "left_side";
208 return "left_side";
@@ -247,8 +249,6 @@ MouseArea {
247 }
249 }
248
250
249 onPressedChanged: {
251 onPressedChanged: {
250− var pos = mapToItem(target.parent, mouseX, mouseY);
251−
252 if (pressed) {
252 if (pressed) {
253 d.updateBorders();
253 d.updateBorders();
254 resetBordersToMoveTimer.stop();
254 resetBordersToMoveTimer.stop();
qml/Stages/graphics/arrows-centre.pngnew file

Binary file not shown.

qml/Stages/graphics/arrows.pngnew file

Binary file not shown.

tests/qmltests/Stages/SurfaceManagerControls.qml+1−1
@@ -21,7 +21,7 @@ import Unity.Application 0.1
21Column {
21Column {
22 id: root
22 id: root
23
23
24− Label {text: "Size hints for new surface:"; color: root.textColor; font.bold: true}
24+ Label {text: "Size hints for new surface:"; font.bold: true}
25
25
26 SurfaceManagerField { text: "min width"; propertyName: "newSurfaceMinimumWidth"; }
26 SurfaceManagerField { text: "min width"; propertyName: "newSurfaceMinimumWidth"; }
27 SurfaceManagerField { text: "max width"; propertyName: "newSurfaceMaximumWidth"; }
27 SurfaceManagerField { text: "max width"; propertyName: "newSurfaceMaximumWidth"; }
tests/qmltests/Stages/tst_DesktopStage.qml+23
@@ -648,6 +648,29 @@ Item {
648 tryCompare(PanelState, "dropShadow", false);
648 tryCompare(PanelState, "dropShadow", false);
649 }
649 }
650
650
651+ function test_threeFingerTapShowsWindowControls_data() {
652+ return [
653+ { tag: "1 finger", touchIds: [0], result: false },
654+ { tag: "2 finger", touchIds: [0, 1], result: false },
655+ { tag: "3 finger", touchIds: [0, 1, 2], result: true },
656+ { tag: "4 finger", touchIds: [0, 1, 2, 3], result: false },
657+ ];
658+ }
659+
660+ function test_threeFingerTapShowsWindowControls(data) {
661+ var facebookAppDelegate = startApplication("facebook-webapp");
662+ verify(facebookAppDelegate);
663+ var overlay = findChild(facebookAppDelegate, "windowControlsOverlay");
664+ verify(overlay);
665+
666+ multiTouchTap(data.touchIds, facebookAppDelegate);
667+ tryCompare(overlay, "visible", data.result);
668+
669+ if (data.result) { // if shown, try to hide it by clicking outside
670+ mouseClick(desktopStage);
671+ tryCompare(overlay, "visible", false);
672+ }
673+ }
651 function test_dashHasNoCloseButton() {
674 function test_dashHasNoCloseButton() {
652 var dashAppDelegate = startApplication("unity8-dash");
675 var dashAppDelegate = startApplication("unity8-dash");
653 verify(dashAppDelegate);
676 verify(dashAppDelegate);