on 5ea3c69 help sign in
unity8/qml/Panel/Panel.qml
522 lines 19 kB history raw
1/*
2 * Copyright (C) 2013-2017 Canonical, Ltd.
3 * Copyright (C) 2020 UBports Foundation
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; version 3.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
18import QtQuick 2.4
19import Ubuntu.Components 1.3
20import Ubuntu.Layouts 1.0
21import Unity.Application 0.1
22import Unity.Indicators 0.1
23import Utils 0.1
24import Unity.ApplicationMenu 0.1
26import QtQuick.Window 2.2
28import "../ApplicationMenus"
29import "../Components"
30import "../Components/PanelState"
31import ".."
32import "Indicators"
34Item {
35 id: root
36 readonly property real panelHeight: panelArea.y + minimizedPanelHeight
37 readonly property bool fullyClosed: indicators.fullyClosed && applicationMenus.fullyClosed
39 property real minimizedPanelHeight: units.gu(3)
40 property real expandedPanelHeight: units.gu(7)
41 property real menuWidth: partialWidth ? units.gu(40) : width
42 property alias applicationMenuContentX: __applicationMenus.menuContentX
44 property alias applicationMenus: __applicationMenus
45 property alias indicators: __indicators
46 property bool fullscreenMode: false
47 property real panelAreaShowProgress: 1.0
48 property bool greeterShown: false
49 property bool hasKeyboard: false
50 property bool supportsMultiColorLed: true
52 // Whether our expanded menus should take up the full width of the panel
53 property bool partialWidth: width >= units.gu(60)
55 property string mode: "staged"
57 MouseArea {
58 id: backMouseEater
59 anchors.fill: parent
60 anchors.topMargin: panelHeight
61 visible: !indicators.fullyClosed || !applicationMenus.fullyClosed
62 enabled: visible
63 hoverEnabled: true // should also eat hover events, otherwise they will pass through
65 onClicked: {
66 __applicationMenus.hide();
67 __indicators.hide();
68 }
69 }
71 Binding {
72 target: PanelState
73 property: "panelHeight"
74 value: minimizedPanelHeight
75 }
77 RegisteredApplicationMenuModel {
78 id: registeredMenuModel
79 persistentSurfaceId: PanelState.focusedPersistentSurfaceId
80 }
82 QtObject {
83 id: d
85 property bool revealControls: !greeterShown &&
86 !applicationMenus.shown &&
87 !indicators.shown &&
88 (decorationMouseArea.containsMouse || menuBarLoader.menusRequested)
90 property bool showWindowDecorationControls: (revealControls && PanelState.decorationsVisible) ||
91 PanelState.decorationsAlwaysVisible
93 property bool showPointerMenu: revealControls && enablePointerMenu &&
94 (PanelState.decorationsVisible || mode == "windowed")
96 property bool enablePointerMenu: applicationMenus.available &&
97 applicationMenus.model
99 property bool showTouchMenu: !greeterShown &&
100 !showPointerMenu &&
101 !showWindowDecorationControls
103 property bool enableTouchMenus: showTouchMenu &&
104 applicationMenus.available &&
105 applicationMenus.model
106 }
108 Item {
109 id: panelArea
110 objectName: "panelArea"
112 anchors.fill: parent
114 transform: Translate {
115 y: indicators.state === "initial"
116 ? (1.0 - panelAreaShowProgress) * - minimizedPanelHeight
117 : 0
118 }
120 BorderImage {
121 id: indicatorsDropShadow
122 anchors {
123 fill: __indicators
124 margins: -units.gu(1)
125 }
126 visible: !__indicators.fullyClosed
127 source: "graphics/rectangular_dropshadow.sci"
128 }
130 BorderImage {
131 id: appmenuDropShadow
132 anchors {
133 fill: __applicationMenus
134 margins: -units.gu(1)
135 }
136 visible: !__applicationMenus.fullyClosed
137 source: "graphics/rectangular_dropshadow.sci"
138 }
140 BorderImage {
141 id: panelDropShadow
142 anchors {
143 fill: panelAreaBackground
144 bottomMargin: -units.gu(1)
145 }
146 visible: PanelState.dropShadow
147 source: "graphics/rectangular_dropshadow.sci"
148 }
150 Rectangle {
151 id: panelAreaBackground
152 color: callHint.visible ? theme.palette.normal.positive : theme.palette.normal.background
153 anchors {
154 top: parent.top
155 left: parent.left
156 right: parent.right
157 }
158 height: minimizedPanelHeight
160 Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
161 }
163 MouseArea {
164 id: decorationMouseArea
165 objectName: "windowControlArea"
166 anchors {
167 left: parent.left
168 right: parent.right
169 }
170 height: minimizedPanelHeight
171 hoverEnabled: !__indicators.shown
172 onClicked: {
173 if (callHint.visible) {
174 callHint.showLiveCall();
175 }
176 }
178 onPressed: {
179 if (!callHint.visible) {
180 // let it fall through to the window decoration of the maximized window behind, if any
181 mouse.accepted = false;
182 }
183 var menubar = menuBarLoader.item;
184 if (menubar) {
185 menubar.invokeMenu(mouse);
186 }
187 }
189 Row {
190 anchors.fill: parent
191 spacing: units.gu(2)
193 // WindowControlButtons inside the mouse area, otherwise QML doesn't grok nested hover events :/
194 // cf. https://bugreports.qt.io/browse/QTBUG-32909
195 WindowControlButtons {
196 id: windowControlButtons
197 objectName: "panelWindowControlButtons"
198 height: indicators.minimizedPanelHeight
199 opacity: d.showWindowDecorationControls ? 1 : 0
200 visible: opacity != 0
201 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
203 active: PanelState.decorationsVisible || PanelState.decorationsAlwaysVisible
204 windowIsMaximized: true
205 onCloseClicked: PanelState.closeClicked()
206 onMinimizeClicked: PanelState.minimizeClicked()
207 onMaximizeClicked: PanelState.restoreClicked()
208 closeButtonShown: PanelState.closeButtonShown
209 }
211 Loader {
212 id: menuBarLoader
213 objectName: "menuBarLoader"
214 height: parent.height
215 enabled: d.enablePointerMenu
216 opacity: d.showPointerMenu ? 1 : 0
217 visible: opacity != 0
218 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
219 active: d.showPointerMenu && !callHint.visible
221 width: parent.width - windowControlButtons.width - units.gu(2) - __indicators.barWidth
223 readonly property bool menusRequested: menuBarLoader.item ? menuBarLoader.item.showRequested : false
225 sourceComponent: MenuBar {
226 id: bar
227 objectName: "menuBar"
228 anchors.left: parent ? parent.left : undefined
229 anchors.margins: units.gu(1)
230 height: menuBarLoader.height
231 enableKeyFilter: valid && PanelState.decorationsVisible
232 unityMenuModel: __applicationMenus.model
234 Connections {
235 target: __applicationMenus
236 onShownChanged: bar.dismiss();
237 }
239 Connections {
240 target: __indicators
241 onShownChanged: bar.dismiss();
242 }
244 onDoubleClicked: PanelState.restoreClicked()
245 onPressed: mouse.accepted = false // let the parent mouse area handle this, so it can both unsnap window and show menu
246 }
247 }
248 }
250 ActiveCallHint {
251 id: callHint
252 objectName: "callHint"
254 anchors.centerIn: parent
255 height: minimizedPanelHeight
257 visible: active && indicators.state == "initial" && __applicationMenus.state == "initial"
258 greeterShown: root.greeterShown
259 }
260 }
262 PanelMenu {
263 id: __applicationMenus
265 x: menuContentX
266 model: registeredMenuModel.model
267 width: root.menuWidth
268 overFlowWidth: width
269 minimizedPanelHeight: root.minimizedPanelHeight
270 expandedPanelHeight: root.expandedPanelHeight
271 openedHeight: root.height
272 alignment: Qt.AlignLeft
273 enableHint: !callHint.active && !fullscreenMode
274 showOnClick: false
275 panelColor: panelAreaBackground.color
277 onShowTapped: {
278 if (callHint.active) {
279 callHint.showLiveCall();
280 }
281 }
283 hideRow: !expanded
284 rowItemDelegate: ActionItem {
285 id: actionItem
286 property int ownIndex: index
287 objectName: "appMenuItem"+index
288 enabled: model.sensitive
290 width: _title.width + units.gu(2)
291 height: parent.height
293 action: Action {
294 text: model.label.replace("_", "&")
295 }
297 Label {
298 id: _title
299 anchors.centerIn: parent
300 text: actionItem.text
301 horizontalAlignment: Text.AlignLeft
302 color: enabled ? theme.palette.normal.backgroundText : theme.palette.disabled.backgroundText
303 }
304 }
306 pageDelegate: PanelMenuPage {
307 readonly property bool isCurrent: modelIndex == __applicationMenus.currentMenuIndex
308 onIsCurrentChanged: {
309 if (isCurrent && menuModel) {
310 menuModel.aboutToShow(modelIndex);
311 }
312 }
314 menuModel: __applicationMenus.model
315 submenuIndex: modelIndex
317 factory: ApplicationMenuItemFactory {
318 rootModel: __applicationMenus.model
319 }
320 }
322 enabled: d.enableTouchMenus
323 opacity: d.showTouchMenu ? 1 : 0
324 visible: opacity != 0
325 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
327 onEnabledChanged: {
328 if (!enabled) hide();
329 }
330 }
332 Item {
333 id: panelTitleHolder
334 anchors {
335 left: parent.left
336 leftMargin: units.gu(1)
337 right: __indicators.left
338 rightMargin: units.gu(1)
339 }
340 height: root.minimizedPanelHeight
342 Label {
343 id: rowLabel
344 anchors {
345 left: parent.left
346 right: root.partialWidth ? parent.right : parent.left
347 rightMargin: touchMenuIcon.width
348 }
349 objectName: "panelTitle"
350 height: root.minimizedPanelHeight
351 verticalAlignment: Text.AlignVCenter
352 elide: Text.ElideRight
353 maximumLineCount: 1
354 fontSize: "medium"
355 font.weight: Font.Medium
356 color: theme.palette.selected.backgroundText
357 text: (root.partialWidth && !callHint.visible) ? PanelState.title : ""
358 opacity: __applicationMenus.visible && !__applicationMenus.expanded
359 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
360 visible: opacity !== 0
361 }
363 Icon {
364 id: touchMenuIcon
365 objectName: "touchMenuIcon"
366 anchors {
367 left: parent.left
368 leftMargin: rowLabel.contentWidth + units.dp(2)
369 verticalCenter: parent.verticalCenter
370 }
371 width: units.gu(2)
372 height: units.gu(2)
373 name: "down"
374 color: theme.palette.normal.backgroundText
375 opacity: !__applicationMenus.expanded && d.enableTouchMenus && !callHint.visible
376 Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
377 visible: opacity !== 0
378 }
379 }
381 PanelMenu {
382 id: __indicators
383 objectName: "indicators"
385 anchors {
386 top: parent.top
387 right: parent.right
388 }
389 width: root.menuWidth
390 minimizedPanelHeight: root.minimizedPanelHeight
391 expandedPanelHeight: root.expandedPanelHeight
392 openedHeight: root.height
394 overFlowWidth: width - appMenuClear
395 enableHint: !callHint.active && !fullscreenMode
396 showOnClick: !callHint.visible
397 panelColor: panelAreaBackground.color
399 // On small screens, the Indicators' handle area is the entire top
400 // bar unless there is an application menu. In that case, our handle
401 // needs to allow for some room to clear the application menu.
402 property var appMenuClear: (d.enableTouchMenus && !partialWidth) ? units.gu(7) : 0
404 onShowTapped: {
405 if (callHint.active) {
406 callHint.showLiveCall();
407 }
408 }
410 rowItemDelegate: IndicatorItem {
411 id: indicatorItem
412 objectName: identifier+"-panelItem"
414 property int ownIndex: index
415 readonly property bool overflow: parent.width - (x - __indicators.rowContentX) > __indicators.overFlowWidth
416 readonly property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
417 // HACK for indicator-session
418 readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
419 // HACK for indicator-keyboard
420 readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && !hasKeyboard
422 height: parent.height
423 expanded: indicators.expanded
424 selected: ListView.isCurrentItem
426 identifier: model.identifier
427 busName: indicatorProperties.busName
428 actionsObjectPath: indicatorProperties.actionsObjectPath
429 menuObjectPath: indicatorProperties.menuObjectPath
431 opacity: hidden ? 0.0 : 1.0
432 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
434 width: ((expanded || indicatorVisible) && !hideSessionIndicator && !hideKeyboardIndicator) ? implicitWidth : 0
436 Behavior on width { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
437 }
439 pageDelegate: PanelMenuPage {
440 objectName: modelData.identifier + "-page"
441 submenuIndex: 0
443 menuModel: delegate.menuModel
445 factory: IndicatorMenuItemFactory {
446 indicator: {
447 var context = modelData.identifier;
448 if (context && context.indexOf("fake-") === 0) {
449 context = context.substring("fake-".length)
450 }
451 return context;
452 }
453 rootModel: delegate.menuModel
454 }
456 IndicatorDelegate {
457 id: delegate
458 busName: modelData.indicatorProperties.busName
459 actionsObjectPath: modelData.indicatorProperties.actionsObjectPath
460 menuObjectPath: modelData.indicatorProperties.menuObjectPath
461 }
462 }
464 enabled: !applicationMenus.expanded
465 opacity: !callHint.visible && !applicationMenus.expanded ? 1 : 0
466 Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
468 onEnabledChanged: {
469 if (!enabled) hide();
470 }
471 }
472 }
474 IndicatorsLight {
475 id: indicatorLights
476 supportsMultiColorLed: root.supportsMultiColorLed
477 }
479 states: [
480 State {
481 name: "onscreen" //fully opaque and visible at top edge of screen
482 when: !fullscreenMode
483 PropertyChanges {
484 target: panelArea;
485 anchors.topMargin: 0
486 opacity: 1;
487 }
488 },
489 State {
490 name: "offscreen" //pushed off screen
491 when: fullscreenMode
492 PropertyChanges {
493 target: panelArea;
494 anchors.topMargin: {
495 if (indicators.state !== "initial") return 0;
496 if (applicationMenus.state !== "initial") return 0;
497 return -minimizedPanelHeight;
498 }
499 opacity: indicators.fullyClosed && applicationMenus.fullyClosed ? 0.0 : 1.0
500 }
501 PropertyChanges {
502 target: indicators.showDragHandle;
503 anchors.bottomMargin: -units.gu(1)
504 }
505 PropertyChanges {
506 target: applicationMenus.showDragHandle;
507 anchors.bottomMargin: -units.gu(1)
508 }
509 }
510 ]
512 transitions: [
513 Transition {
514 to: "onscreen"
515 UbuntuNumberAnimation { target: panelArea; properties: "anchors.topMargin,opacity" }
516 },
517 Transition {
518 to: "offscreen"
519 UbuntuNumberAnimation { target: panelArea; properties: "anchors.topMargin,opacity" }
520 }
521 ]