on xenial help sign in
initial take on making the launcher resizable and locked visible
673a125Michael Zanetti
qml/Launcher/Launcher.qml+33−10
@@ -25,11 +25,12 @@ FocusScope {
25 id: root
25 id: root
26
26
27 property bool autohideEnabled: false
27 property bool autohideEnabled: false
28+ property bool lockedVisible: false
28 property bool available: true // can be used to disable all interactions
29 property bool available: true // can be used to disable all interactions
29 property alias inverted: panel.inverted
30 property alias inverted: panel.inverted
30 property bool shadeBackground: true // can be used to disable background shade when launcher is visible
31 property bool shadeBackground: true // can be used to disable background shade when launcher is visible
31
32
32− property int panelWidth: units.gu(8)
33+ property int panelWidth: units.gu(10)
33 property int dragAreaWidth: units.gu(1)
34 property int dragAreaWidth: units.gu(1)
34 property int minimizeDistance: units.gu(26)
35 property int minimizeDistance: units.gu(26)
35 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
36 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
@@ -54,6 +55,7 @@ FocusScope {
54 signal showDashHome()
55 signal showDashHome()
55
56
56 onStateChanged: {
57 onStateChanged: {
58+ print("state changed", state)
57 if (state == "") {
59 if (state == "") {
58 dismissTimer.stop()
60 dismissTimer.stop()
59 } else {
61 } else {
@@ -92,12 +94,25 @@ FocusScope {
92 }
94 }
93 }
95 }
94
96
97+ onLockedVisibleChanged: {
98+ if (lockedVisible && state == "") {
99+ print("have to show")
100+ dismissTimer.stop();
101+ fadeOutAnimation.stop();
102+ switchToNextState("visible")
103+ } else if (!lockedVisible && state == "visible") {
104+ hide();
105+ }
106+ }
107+
95 function hide() {
108 function hide() {
96 switchToNextState("")
109 switchToNextState("")
97 }
110 }
98
111
99 function fadeOut() {
112 function fadeOut() {
113+ if (!root.lockedVisible) {
100− fadeOutAnimation.start();
114+ fadeOutAnimation.start();
115+ }
101 }
116 }
102
117
103 function switchToNextState(state) {
118 function switchToNextState(state) {
@@ -173,7 +188,7 @@ FocusScope {
173 } else if (panel.highlightIndex >= 0) {
188 } else if (panel.highlightIndex >= 0) {
174 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
189 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
175 }
190 }
176− root.state = ""
191+ root.hide();
177 event.accepted = true;
192 event.accepted = true;
178 root.focus = false;
193 root.focus = false;
179 }
194 }
@@ -207,9 +222,9 @@ FocusScope {
207 objectName: "dismissTimer"
222 objectName: "dismissTimer"
208 interval: 500
223 interval: 500
209 onTriggered: {
224 onTriggered: {
210− if (root.autohideEnabled) {
225+ if (root.autohideEnabled && !root.lockedVisible) {
211 if (!panel.preventHiding) {
226 if (!panel.preventHiding) {
212− root.state = ""
227+ root.hide();
213 } else {
228 } else {
214 dismissTimer.restart()
229 dismissTimer.restart()
215 }
230 }
@@ -227,6 +242,13 @@ FocusScope {
227 interval: 1
242 interval: 1
228 property string nextState: ""
243 property string nextState: ""
229 onTriggered: {
244 onTriggered: {
245+ if (root.lockedVisible && nextState == "") {
246+ // Due to binding updates when switching between modes
247+ // it could happen that our request to show will be overwritten
248+ // with a hide request. Rewrite it when we know hiding is not allowed.
249+ nextState = "visible"
250+ }
251+
230 // switching to an intermediate state here to make sure all the
252 // switching to an intermediate state here to make sure all the
231 // values are restored, even if we were already in the target state
253 // values are restored, even if we were already in the target state
232 root.state = "tmp"
254 root.state = "tmp"
@@ -262,6 +284,7 @@ FocusScope {
262 script: {
284 script: {
263 panel.layer.enabled = false
285 panel.layer.enabled = false
264 panel.animate = false;
286 panel.animate = false;
287+ print("setting state to \"\"")
265 root.state = "";
288 root.state = "";
266 panel.x = -panel.width
289 panel.x = -panel.width
267 panel.opacity = 1;
290 panel.opacity = 1;
@@ -298,10 +321,10 @@ FocusScope {
298 right: parent.right
321 right: parent.right
299 bottom: parent.bottom
322 bottom: parent.bottom
300 }
323 }
301− enabled: root.shadeBackground && root.state == "visible"
324+ enabled: root.shadeBackground && root.state == "visible" && !root.lockedVisible
302 visible: enabled // otherwise it will get in the way of cursor selection for some reason
325 visible: enabled // otherwise it will get in the way of cursor selection for some reason
303 onPressed: {
326 onPressed: {
304− root.state = ""
327+ root.hide();
305 }
328 }
306 }
329 }
307
330
@@ -309,7 +332,7 @@ FocusScope {
309 id: backgroundShade
332 id: backgroundShade
310 anchors.fill: parent
333 anchors.fill: parent
311 color: "black"
334 color: "black"
312− opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0
335+ opacity: root.shadeBackground && root.state == "visible" && !root.lockedVisible ? 0.6 : 0
313
336
314 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
337 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
315 }
338 }
@@ -352,11 +375,11 @@ FocusScope {
352 property bool animate: true
375 property bool animate: true
353
376
354 onApplicationSelected: {
377 onApplicationSelected: {
355− root.state = ""
378+ root.hide();
356 launcherApplicationSelected(appId)
379 launcherApplicationSelected(appId)
357 }
380 }
358 onShowDashHome: {
381 onShowDashHome: {
359− root.state = ""
382+ root.hide();
360 root.showDashHome();
383 root.showDashHome();
361 }
384 }
362
385
qml/Launcher/LauncherDelegate.qml+5−9
@@ -124,7 +124,7 @@ Item {
124
124
125 Item {
125 Item {
126 id: iconItem
126 id: iconItem
127− width: parent.itemWidth + units.gu(1)
127+ width: root.width
128 height: parent.itemHeight + units.gu(1)
128 height: parent.itemHeight + units.gu(1)
129 anchors.centerIn: parent
129 anchors.centerIn: parent
130
130
@@ -141,7 +141,7 @@ Item {
141 ProportionalShape {
141 ProportionalShape {
142 id: iconShape
142 id: iconShape
143 anchors.centerIn: parent
143 anchors.centerIn: parent
144− width: parent.width - units.gu(2)
144+ width: root.itemWidth
145 aspect: UbuntuShape.DropShadow
145 aspect: UbuntuShape.DropShadow
146 source: Image {
146 source: Image {
147 id: iconImage
147 id: iconImage
@@ -157,6 +157,7 @@ Item {
157 anchors {
157 anchors {
158 right: parent.right
158 right: parent.right
159 bottom: parent.bottom
159 bottom: parent.bottom
160+ rightMargin: (iconItem.width - root.itemWidth) / 2 - units.dp(2)
160 margins: units.dp(3)
161 margins: units.dp(3)
161 }
162 }
162 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
163 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
@@ -185,13 +186,8 @@ Item {
185 id: progressOverlay
186 id: progressOverlay
186 objectName: "progressOverlay"
187 objectName: "progressOverlay"
187
188
188− anchors {
189+ anchors.centerIn: parent
189− left: iconItem.left
190+ width: root.itemWidth * .8
190− right: iconItem.right
191− verticalCenter: parent.verticalCenter
192− leftMargin: units.gu(1.5)
193− rightMargin: units.gu(1.5)
194− }
195 height: units.gu(1)
191 height: units.gu(1)
196 visible: root.progress > -1
192 visible: root.progress > -1
197 color: UbuntuColors.darkGrey
193 color: UbuntuColors.darkGrey
qml/Launcher/LauncherPanel.qml+16−16
@@ -82,13 +82,13 @@ Rectangle {
82 Rectangle {
82 Rectangle {
83 objectName: "buttonShowDashHome"
83 objectName: "buttonShowDashHome"
84 width: parent.width
84 width: parent.width
85− height: units.gu(7)
85+ height: width * .9
86 color: UbuntuColors.orange
86 color: UbuntuColors.orange
87 readonly property bool highlighted: root.highlightIndex == -1;
87 readonly property bool highlighted: root.highlightIndex == -1;
88
88
89 Image {
89 Image {
90 objectName: "dashItem"
90 objectName: "dashItem"
91− width: units.gu(5)
91+ width: parent.width * .6
92 height: width
92 height: width
93 anchors.centerIn: parent
93 anchors.centerIn: parent
94 source: "graphics/home.png"
94 source: "graphics/home.png"
@@ -124,10 +124,8 @@ Rectangle {
124 objectName: "launcherListView"
124 objectName: "launcherListView"
125 anchors {
125 anchors {
126 fill: parent
126 fill: parent
127− topMargin: -extensionSize + units.gu(0.5)
127+ topMargin: -extensionSize + width * .15
128− bottomMargin: -extensionSize + units.gu(1)
128+ bottomMargin: -extensionSize + width * .15
129− leftMargin: units.gu(0.5)
130− rightMargin: units.gu(0.5)
131 }
129 }
132 topMargin: extensionSize
130 topMargin: extensionSize
133 bottomMargin: extensionSize
131 bottomMargin: extensionSize
@@ -138,6 +136,7 @@ Rectangle {
138 highlightRangeMode: ListView.ApplyRange
136 highlightRangeMode: ListView.ApplyRange
139 preferredHighlightBegin: (height - itemHeight) / 2
137 preferredHighlightBegin: (height - itemHeight) / 2
140 preferredHighlightEnd: (height + itemHeight) / 2
138 preferredHighlightEnd: (height + itemHeight) / 2
139+ spacing: units.gu(1)
141
140
142 // for the single peeking icon, when alert-state is set on delegate
141 // for the single peeking icon, when alert-state is set on delegate
143 property int peekingIndex: -1
142 property int peekingIndex: -1
@@ -162,11 +161,11 @@ Rectangle {
162 }
161 }
163
162
164 // The height of the area where icons start getting folded
163 // The height of the area where icons start getting folded
165− property int foldingStartHeight: units.gu(6.5)
164+ property int foldingStartHeight: itemHeight
166 // The height of the area where the items reach the final folding angle
165 // The height of the area where the items reach the final folding angle
167 property int foldingStopHeight: foldingStartHeight - itemHeight - spacing
166 property int foldingStopHeight: foldingStartHeight - itemHeight - spacing
168− property int itemWidth: units.gu(7)
167+ property int itemWidth: width * .75
169− property int itemHeight: units.gu(6.5)
168+ property int itemHeight: itemWidth * 15 / 16
170 property int clickFlickSpeed: units.gu(60)
169 property int clickFlickSpeed: units.gu(60)
171 property int draggedIndex: dndArea.draggedIndex
170 property int draggedIndex: dndArea.draggedIndex
172 property real realContentY: contentY - originY + topMargin
171 property real realContentY: contentY - originY + topMargin
@@ -202,13 +201,14 @@ Rectangle {
202 start();
201 start();
203 }
202 }
204 function moveToIndex(index) {
203 function moveToIndex(index) {
204+ var totalItemHeight = launcherListView.itemHeight + launcherListView.spacing
205− var itemPosition = index * launcherListView.itemHeight;
205+ var itemPosition = index * totalItemHeight;
206 var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
206 var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
207− var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
207+ var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : totalItemHeight
208− if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
208+ if (itemPosition + totalItemHeight + distanceToEnd > launcherListView.contentY + launcherListView.originY + launcherListView.topMargin + height) {
209− moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
209+ moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd - launcherListView.originY);
210− } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
210+ } else if (itemPosition - distanceToEnd < launcherListView.contentY - launcherListView.originY + launcherListView.topMargin) {
211− moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
211+ moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin + launcherListView.originY);
212 }
212 }
213 }
213 }
214 }
214 }
@@ -227,7 +227,7 @@ Rectangle {
227 itemIndex: index
227 itemIndex: index
228 itemHeight: launcherListView.itemHeight
228 itemHeight: launcherListView.itemHeight
229 itemWidth: launcherListView.itemWidth
229 itemWidth: launcherListView.itemWidth
230− width: itemWidth
230+ width: parent.width
231 height: itemHeight
231 height: itemHeight
232 iconName: model.icon
232 iconName: model.icon
233 count: model.count
233 count: model.count
qml/Shell.qml+7
@@ -336,6 +336,11 @@ Item {
336 property: "altTabPressed"
336 property: "altTabPressed"
337 value: physicalKeysMapper.altTabPressed
337 value: physicalKeysMapper.altTabPressed
338 }
338 }
339+ Binding {
340+ target: applicationsDisplayLoader.item
341+ property: "leftMargin"
342+ value: launcher.lockedVisible ? launcher.panelWidth: 0
343+ }
339 }
344 }
340
345
341 Tutorial {
346 Tutorial {
@@ -552,6 +557,8 @@ Item {
552 shadeBackground: !tutorial.running
557 shadeBackground: !tutorial.running
553 superPressed: physicalKeysMapper.superPressed
558 superPressed: physicalKeysMapper.superPressed
554 superTabPressed: physicalKeysMapper.superTabPressed
559 superTabPressed: physicalKeysMapper.superTabPressed
560+ panelWidth: shell.usageScenario == "desktop" ? units.gu(10) : units.gu(8)
561+ lockedVisible: shell.usageScenario == "desktop"
555
562
556 onShowDashHome: showHome()
563 onShowDashHome: showHome()
557 onDash: showDash()
564 onDash: showDash()
qml/Stages/AbstractStage.qml+2
@@ -39,6 +39,8 @@ Rectangle {
39 property int shellOrientationAngle
39 property int shellOrientationAngle
40 property bool spreadEnabled: true // If false, animations and right edge will be disabled
40 property bool spreadEnabled: true // If false, animations and right edge will be disabled
41 property bool suspended
41 property bool suspended
42+ // A Stage should paint a wallpaper etc over its full size but not use the margins for window placement
43+ property int leftMargin: 0
42
44
43 // To be read from outside
45 // To be read from outside
44 property var mainApp: null
46 property var mainApp: null
qml/Stages/DesktopStage.qml+8−6
@@ -219,11 +219,13 @@ AbstractStage {
219 id: appContainer
219 id: appContainer
220 objectName: "appContainer"
220 objectName: "appContainer"
221 anchors.fill: parent
221 anchors.fill: parent
222+ anchors.leftMargin: root.leftMargin
222 focus: spread.state !== "altTab"
223 focus: spread.state !== "altTab"
223
224
224 CrossFadeImage {
225 CrossFadeImage {
225 id: wallpaper
226 id: wallpaper
226 anchors.fill: parent
227 anchors.fill: parent
228+ anchors.leftMargin: -root.leftMargin
227 source: root.background
229 source: root.background
228 sourceSize { height: root.height; width: root.width }
230 sourceSize { height: root.height; width: root.width }
229 fillMode: Image.PreserveAspectCrop
231 fillMode: Image.PreserveAspectCrop
@@ -354,7 +356,7 @@ AbstractStage {
354 PropertyChanges {
356 PropertyChanges {
355 target: appDelegate;
357 target: appDelegate;
356 x: 0; y: 0;
358 x: 0; y: 0;
357− requestedWidth: root.width; requestedHeight: root.height;
359+ requestedWidth: appContainer.width; requestedHeight: appContainer.height;
358 visuallyMinimized: false;
360 visuallyMinimized: false;
359 visuallyMaximized: true
361 visuallyMaximized: true
360 }
362 }
@@ -362,12 +364,12 @@ AbstractStage {
362 State {
364 State {
363 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
365 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
364 PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
366 PropertyChanges { target: appDelegate; x: 0; y: PanelState.panelHeight;
365− requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
367+ requestedWidth: appContainer.width/2; requestedHeight: appContainer.height - PanelState.panelHeight }
366 },
368 },
367 State {
369 State {
368 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
370 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
369− PropertyChanges { target: appDelegate; x: root.width/2; y: PanelState.panelHeight;
371+ PropertyChanges { target: appDelegate; x: appContainer.width/2; y: PanelState.panelHeight;
370− requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
372+ requestedWidth: appContainer.width/2; requestedHeight: appContainer.height - PanelState.panelHeight }
371 },
373 },
372 State {
374 State {
373 name: "minimized"; when: appDelegate.minimized
375 name: "minimized"; when: appDelegate.minimized
@@ -430,8 +432,8 @@ AbstractStage {
430 minHeight: units.gu(10)
432 minHeight: units.gu(10)
431 borderThickness: units.gu(2)
433 borderThickness: units.gu(2)
432 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
434 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
433− screenWidth: root.width
435+ screenWidth: appContainer.width
434− screenHeight: root.height
436+ screenHeight: appContainer.height
435
437
436 onPressed: { ApplicationManager.focusApplication(model.appId) }
438 onPressed: { ApplicationManager.focusApplication(model.appId) }
437 }
439 }
tests/qmltests/Launcher/tst_Launcher.qml+30−1
@@ -28,7 +28,7 @@ import Utils 0.1 // For EdgeBarrierSettings
28 launcher. */
28 launcher. */
29Item {
29Item {
30 id: root
30 id: root
31− width: units.gu(50)
31+ width: units.gu(70)
32 height: units.gu(55)
32 height: units.gu(55)
33
33
34 Loader {
34 Loader {
@@ -79,11 +79,40 @@ Item {
79 }
79 }
80 }
80 }
81
81
82+ Binding {
83+ target: launcherLoader.item
84+ property: "lockedVisible"
85+ value: lockedVisibleCheckBox.checked
86+ }
87+ Binding {
88+ target: launcherLoader.item
89+ property: "panelWidth"
90+ value: units.gu(Math.round(widthSlider.value))
91+ }
92+
82 ColumnLayout {
93 ColumnLayout {
83 anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
94 anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
84 spacing: units.gu(1)
95 spacing: units.gu(1)
85 width: childrenRect.width
96 width: childrenRect.width
86
97
98+ RowLayout {
99+ CheckBox {
100+ id: lockedVisibleCheckBox
101+ checked: false
102+ }
103+ Label {
104+ text: "Launcher always visible"
105+ }
106+ }
107+
108+ Slider {
109+ id: widthSlider
110+ Layout.fillWidth: true
111+ minimumValue: 6
112+ maximumValue: 12
113+ value: 10
114+ }
115+
87 MouseTouchEmulationCheckbox {}
116 MouseTouchEmulationCheckbox {}
88
117
89 EdgeBarrierControls {
118 EdgeBarrierControls {