on xenial help sign in
initial take on making the launcher resizable and locked visible
commit673a12542ae78f328f892135c0be801eae0fba59 authorMichael Zanetti <michael.zanetti@canonical.com> dateWed 9 Dec 2015, 20:27 (11 years ago) parent6f5ed99
7 files changed+101−42
qml/Launcher/Launcher.qml+33−10 qml/Launcher/LauncherDelegate.qml+5−9 qml/Launcher/LauncherPanel.qml+16−16 qml/Shell.qml+7 qml/Stages/AbstractStage.qml+2 qml/Stages/DesktopStage.qml+8−6 tests/qmltests/Launcher/tst_Launcher.qml+30−1
qml/Launcher/Launcher.qml+33−10
@@ -25,11 +25,12 @@ FocusScope {
2525 id: root
2626
2727 property bool autohideEnabled: false
28+ property bool lockedVisible: false
2829 property bool available: true // can be used to disable all interactions
2930 property alias inverted: panel.inverted
3031 property bool shadeBackground: true // can be used to disable background shade when launcher is visible
3132
32− property int panelWidth: units.gu(8)
33+ property int panelWidth: units.gu(10)
3334 property int dragAreaWidth: units.gu(1)
3435 property int minimizeDistance: units.gu(26)
3536 property real progress: dragArea.dragging && dragArea.touchX > panelWidth ?
@@ -54,6 +55,7 @@ FocusScope {
5455 signal showDashHome()
5556
5657 onStateChanged: {
58+ print("state changed", state)
5759 if (state == "") {
5860 dismissTimer.stop()
5961 } else {
@@ -92,12 +94,25 @@ FocusScope {
9294 }
9395 }
9496
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+
95108 function hide() {
96109 switchToNextState("")
97110 }
98111
99112 function fadeOut() {
100− fadeOutAnimation.start();
113+ if (!root.lockedVisible) {
114+ fadeOutAnimation.start();
115+ }
101116 }
102117
103118 function switchToNextState(state) {
@@ -173,7 +188,7 @@ FocusScope {
173188 } else if (panel.highlightIndex >= 0) {
174189 launcherApplicationSelected(LauncherModel.get(panel.highlightIndex).appId);
175190 }
176− root.state = ""
191+ root.hide();
177192 event.accepted = true;
178193 root.focus = false;
179194 }
@@ -207,9 +222,9 @@ FocusScope {
207222 objectName: "dismissTimer"
208223 interval: 500
209224 onTriggered: {
210− if (root.autohideEnabled) {
225+ if (root.autohideEnabled && !root.lockedVisible) {
211226 if (!panel.preventHiding) {
212− root.state = ""
227+ root.hide();
213228 } else {
214229 dismissTimer.restart()
215230 }
@@ -227,6 +242,13 @@ FocusScope {
227242 interval: 1
228243 property string nextState: ""
229244 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+
230252 // switching to an intermediate state here to make sure all the
231253 // values are restored, even if we were already in the target state
232254 root.state = "tmp"
@@ -262,6 +284,7 @@ FocusScope {
262284 script: {
263285 panel.layer.enabled = false
264286 panel.animate = false;
287+ print("setting state to \"\"")
265288 root.state = "";
266289 panel.x = -panel.width
267290 panel.opacity = 1;
@@ -298,10 +321,10 @@ FocusScope {
298321 right: parent.right
299322 bottom: parent.bottom
300323 }
301− enabled: root.shadeBackground && root.state == "visible"
324+ enabled: root.shadeBackground && root.state == "visible" && !root.lockedVisible
302325 visible: enabled // otherwise it will get in the way of cursor selection for some reason
303326 onPressed: {
304− root.state = ""
327+ root.hide();
305328 }
306329 }
307330
@@ -309,7 +332,7 @@ FocusScope {
309332 id: backgroundShade
310333 anchors.fill: parent
311334 color: "black"
312− opacity: root.shadeBackground && root.state == "visible" ? 0.6 : 0
335+ opacity: root.shadeBackground && root.state == "visible" && !root.lockedVisible ? 0.6 : 0
313336
314337 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.BriskDuration } }
315338 }
@@ -352,11 +375,11 @@ FocusScope {
352375 property bool animate: true
353376
354377 onApplicationSelected: {
355− root.state = ""
378+ root.hide();
356379 launcherApplicationSelected(appId)
357380 }
358381 onShowDashHome: {
359− root.state = ""
382+ root.hide();
360383 root.showDashHome();
361384 }
362385
qml/Launcher/LauncherDelegate.qml+5−9
@@ -124,7 +124,7 @@ Item {
124124
125125 Item {
126126 id: iconItem
127− width: parent.itemWidth + units.gu(1)
127+ width: root.width
128128 height: parent.itemHeight + units.gu(1)
129129 anchors.centerIn: parent
130130
@@ -141,7 +141,7 @@ Item {
141141 ProportionalShape {
142142 id: iconShape
143143 anchors.centerIn: parent
144− width: parent.width - units.gu(2)
144+ width: root.itemWidth
145145 aspect: UbuntuShape.DropShadow
146146 source: Image {
147147 id: iconImage
@@ -157,6 +157,7 @@ Item {
157157 anchors {
158158 right: parent.right
159159 bottom: parent.bottom
160+ rightMargin: (iconItem.width - root.itemWidth) / 2 - units.dp(2)
160161 margins: units.dp(3)
161162 }
162163 width: Math.min(root.itemWidth, Math.max(units.gu(2), countLabel.implicitWidth + units.gu(1)))
@@ -185,13 +186,8 @@ Item {
185186 id: progressOverlay
186187 objectName: "progressOverlay"
187188
188− anchors {
189− left: iconItem.left
190− right: iconItem.right
191− verticalCenter: parent.verticalCenter
192− leftMargin: units.gu(1.5)
193− rightMargin: units.gu(1.5)
194− }
189+ anchors.centerIn: parent
190+ width: root.itemWidth * .8
195191 height: units.gu(1)
196192 visible: root.progress > -1
197193 color: UbuntuColors.darkGrey
qml/Launcher/LauncherPanel.qml+16−16
@@ -82,13 +82,13 @@ Rectangle {
8282 Rectangle {
8383 objectName: "buttonShowDashHome"
8484 width: parent.width
85− height: units.gu(7)
85+ height: width * .9
8686 color: UbuntuColors.orange
8787 readonly property bool highlighted: root.highlightIndex == -1;
8888
8989 Image {
9090 objectName: "dashItem"
91− width: units.gu(5)
91+ width: parent.width * .6
9292 height: width
9393 anchors.centerIn: parent
9494 source: "graphics/home.png"
@@ -124,10 +124,8 @@ Rectangle {
124124 objectName: "launcherListView"
125125 anchors {
126126 fill: parent
127− topMargin: -extensionSize + units.gu(0.5)
128− bottomMargin: -extensionSize + units.gu(1)
129− leftMargin: units.gu(0.5)
130− rightMargin: units.gu(0.5)
127+ topMargin: -extensionSize + width * .15
128+ bottomMargin: -extensionSize + width * .15
131129 }
132130 topMargin: extensionSize
133131 bottomMargin: extensionSize
@@ -138,6 +136,7 @@ Rectangle {
138136 highlightRangeMode: ListView.ApplyRange
139137 preferredHighlightBegin: (height - itemHeight) / 2
140138 preferredHighlightEnd: (height + itemHeight) / 2
139+ spacing: units.gu(1)
141140
142141 // for the single peeking icon, when alert-state is set on delegate
143142 property int peekingIndex: -1
@@ -162,11 +161,11 @@ Rectangle {
162161 }
163162
164163 // The height of the area where icons start getting folded
165− property int foldingStartHeight: units.gu(6.5)
164+ property int foldingStartHeight: itemHeight
166165 // The height of the area where the items reach the final folding angle
167166 property int foldingStopHeight: foldingStartHeight - itemHeight - spacing
168− property int itemWidth: units.gu(7)
169− property int itemHeight: units.gu(6.5)
167+ property int itemWidth: width * .75
168+ property int itemHeight: itemWidth * 15 / 16
170169 property int clickFlickSpeed: units.gu(60)
171170 property int draggedIndex: dndArea.draggedIndex
172171 property real realContentY: contentY - originY + topMargin
@@ -202,13 +201,14 @@ Rectangle {
202201 start();
203202 }
204203 function moveToIndex(index) {
205− var itemPosition = index * launcherListView.itemHeight;
204+ var totalItemHeight = launcherListView.itemHeight + launcherListView.spacing
205+ var itemPosition = index * totalItemHeight;
206206 var height = launcherListView.height - launcherListView.topMargin - launcherListView.bottomMargin
207− var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : launcherListView.itemHeight
208− if (itemPosition + launcherListView.itemHeight + distanceToEnd > launcherListView.contentY + launcherListView.topMargin + height) {
209− moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd);
210− } else if (itemPosition - distanceToEnd < launcherListView.contentY + launcherListView.topMargin) {
211− moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin);
207+ var distanceToEnd = index == 0 || index == launcherListView.count - 1 ? 0 : totalItemHeight
208+ if (itemPosition + totalItemHeight + distanceToEnd > launcherListView.contentY + launcherListView.originY + launcherListView.topMargin + height) {
209+ moveAnimation.moveTo(itemPosition + launcherListView.itemHeight - launcherListView.topMargin - height + distanceToEnd - launcherListView.originY);
210+ } else if (itemPosition - distanceToEnd < launcherListView.contentY - launcherListView.originY + launcherListView.topMargin) {
211+ moveAnimation.moveTo(itemPosition - distanceToEnd - launcherListView.topMargin + launcherListView.originY);
212212 }
213213 }
214214 }
@@ -227,7 +227,7 @@ Rectangle {
227227 itemIndex: index
228228 itemHeight: launcherListView.itemHeight
229229 itemWidth: launcherListView.itemWidth
230− width: itemWidth
230+ width: parent.width
231231 height: itemHeight
232232 iconName: model.icon
233233 count: model.count
qml/Shell.qml+7
@@ -336,6 +336,11 @@ Item {
336336 property: "altTabPressed"
337337 value: physicalKeysMapper.altTabPressed
338338 }
339+ Binding {
340+ target: applicationsDisplayLoader.item
341+ property: "leftMargin"
342+ value: launcher.lockedVisible ? launcher.panelWidth: 0
343+ }
339344 }
340345
341346 Tutorial {
@@ -552,6 +557,8 @@ Item {
552557 shadeBackground: !tutorial.running
553558 superPressed: physicalKeysMapper.superPressed
554559 superTabPressed: physicalKeysMapper.superTabPressed
560+ panelWidth: shell.usageScenario == "desktop" ? units.gu(10) : units.gu(8)
561+ lockedVisible: shell.usageScenario == "desktop"
555562
556563 onShowDashHome: showHome()
557564 onDash: showDash()
qml/Stages/AbstractStage.qml+2
@@ -39,6 +39,8 @@ Rectangle {
3939 property int shellOrientationAngle
4040 property bool spreadEnabled: true // If false, animations and right edge will be disabled
4141 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
4244
4345 // To be read from outside
4446 property var mainApp: null
qml/Stages/DesktopStage.qml+8−6
@@ -219,11 +219,13 @@ AbstractStage {
219219 id: appContainer
220220 objectName: "appContainer"
221221 anchors.fill: parent
222+ anchors.leftMargin: root.leftMargin
222223 focus: spread.state !== "altTab"
223224
224225 CrossFadeImage {
225226 id: wallpaper
226227 anchors.fill: parent
228+ anchors.leftMargin: -root.leftMargin
227229 source: root.background
228230 sourceSize { height: root.height; width: root.width }
229231 fillMode: Image.PreserveAspectCrop
@@ -354,7 +356,7 @@ AbstractStage {
354356 PropertyChanges {
355357 target: appDelegate;
356358 x: 0; y: 0;
357− requestedWidth: root.width; requestedHeight: root.height;
359+ requestedWidth: appContainer.width; requestedHeight: appContainer.height;
358360 visuallyMinimized: false;
359361 visuallyMaximized: true
360362 }
@@ -362,12 +364,12 @@ AbstractStage {
362364 State {
363365 name: "maximizedLeft"; when: appDelegate.maximizedLeft && !appDelegate.minimized
364366 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 }
366368 },
367369 State {
368370 name: "maximizedRight"; when: appDelegate.maximizedRight && !appDelegate.minimized
369− PropertyChanges { target: appDelegate; x: root.width/2; y: PanelState.panelHeight;
370− requestedWidth: root.width/2; requestedHeight: root.height - PanelState.panelHeight }
371+ PropertyChanges { target: appDelegate; x: appContainer.width/2; y: PanelState.panelHeight;
372+ requestedWidth: appContainer.width/2; requestedHeight: appContainer.height - PanelState.panelHeight }
371373 },
372374 State {
373375 name: "minimized"; when: appDelegate.minimized
@@ -430,8 +432,8 @@ AbstractStage {
430432 minHeight: units.gu(10)
431433 borderThickness: units.gu(2)
432434 windowId: model.appId // FIXME: Change this to point to windowId once we have such a thing
433− screenWidth: root.width
434− screenHeight: root.height
435+ screenWidth: appContainer.width
436+ screenHeight: appContainer.height
435437
436438 onPressed: { ApplicationManager.focusApplication(model.appId) }
437439 }
tests/qmltests/Launcher/tst_Launcher.qml+30−1
@@ -28,7 +28,7 @@ import Utils 0.1 // For EdgeBarrierSettings
2828 launcher. */
2929Item {
3030 id: root
31− width: units.gu(50)
31+ width: units.gu(70)
3232 height: units.gu(55)
3333
3434 Loader {
@@ -79,11 +79,40 @@ Item {
7979 }
8080 }
8181
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+
8293 ColumnLayout {
8394 anchors { bottom: parent.bottom; right: parent.right; margins: units.gu(1) }
8495 spacing: units.gu(1)
8596 width: childrenRect.width
8697
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+
87116 MouseTouchEmulationCheckbox {}
88117
89118 EdgeBarrierControls {