2 * Copyright (C) 2013-2017 Canonical Ltd.
3 * Copyright (C) 2020 UBports Foundation
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.
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.
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/>.
20import Lomiri.Components 1.3
21import Lomiri.Layouts 1.0
22import QtMir.Application 0.1
23import Lomiri.Indicators 0.1
25import Lomiri.ApplicationMenu 0.1
27import QtQuick.Window 2.2
29import "../../../ApplicationMenus"
30import "../../../Components"
32import "../../Indicators"
38 readonly property real panelHeight: panelArea.y + minimizedPanelHeight
39 readonly property bool fullyClosed: indicators.fullyClosed && applicationMenus.fullyClosed
41 property real minimizedPanelHeight: units.gu(3)
42 property real expandedPanelHeight: units.gu(7)
43 property real menuWidth: partialWidth ? units.gu(40) : width
44 property alias applicationMenuContentX: __applicationMenus.menuContentX
45 property int screenIndex: -1
47 property alias applicationMenus: __applicationMenus
48 property alias indicators: __indicators
49 property bool fullscreenMode: false
50 property real panelAreaShowProgress: 1.0
51 property bool greeterShown: false
52 property bool hasKeyboard: false
53 property bool supportsMultiColorLed: true
54 property var blurSource : null
56 // Whether our expanded menus should take up the full width of the panel
57 property bool partialWidth: width >= units.gu(60)
59 property string mode: "staged"
60 property var panelState
62 property bool temporarilyShown: false
64 function temporarilyShow() {
65 temporarilyShown = true
66 temporaryShowTimeout.restart()
70 id: temporaryShowTimeout
74 temporarilyShown = false
81 anchors.topMargin: panelHeight
82 visible: !indicators.fullyClosed || !applicationMenus.fullyClosed
84 hoverEnabled: true // should also eat hover events, otherwise they will pass through
87 __applicationMenus.hide();
94 restoreMode: Binding.RestoreBinding
95 property: "panelHeight"
96 value: minimizedPanelHeight
99 RegisteredApplicationMenuModel {
100 id: registeredMenuModel
101 persistentSurfaceId: panelState.focusedPersistentSurfaceId
107 property bool revealControls: !greeterShown &&
108 !applicationMenus.shown &&
110 (decorationMouseArea.containsMouse || menuBarLoader.menusRequested)
112 property bool showWindowDecorationControls: (revealControls && panelState.decorationsVisible) ||
113 panelState.decorationsAlwaysVisible
115 property bool showPointerMenu: revealControls &&
116 (panelState.decorationsVisible || mode == "windowed")
118 property bool enablePointerMenu: applicationMenus.available &&
119 applicationMenus.model
121 property bool showTouchMenu: !greeterShown &&
123 !showWindowDecorationControls
125 property bool enableTouchMenus: showTouchMenu &&
126 applicationMenus.available &&
127 applicationMenus.model
132 objectName: "panelArea"
136 transform: Translate {
137 y: indicators.state === "initial"
138 ? (1.0 - panelAreaShowProgress) * - minimizedPanelHeight
143 id: indicatorsDropShadow
146 margins: -units.gu(1)
148 visible: !__indicators.fullyClosed
149 source: "graphics/rectangular_dropshadow.sci"
153 id: appmenuDropShadow
155 fill: __applicationMenus
156 margins: -units.gu(1)
158 visible: !__applicationMenus.fullyClosed
159 source: "graphics/rectangular_dropshadow.sci"
165 fill: panelAreaBackground
166 bottomMargin: -units.gu(1)
168 visible: panelState.dropShadow
169 source: "graphics/rectangular_dropshadow.sci"
173 id: panelAreaBackground
174 color: callHint.visible ? theme.palette.normal.activity :
175 Qt.hsla(0, 0, Math.round(theme.palette.normal.background.hslLightness), 1)
181 height: minimizedPanelHeight
183 Behavior on color { ColorAnimation { duration: LomiriAnimation.FastDuration } }
187 id: decorationMouseArea
188 objectName: "windowControlArea"
193 height: minimizedPanelHeight
194 hoverEnabled: !__indicators.shown
196 if (callHint.visible) {
197 callHint.showLiveCall();
202 if (!callHint.visible) {
203 // let it fall through to the window decoration of the maximized window behind, if any
204 mouse.accepted = false;
206 var menubar = menuBarLoader.item;
208 menubar.invokeMenu(mouse);
216 // WindowControlButtons inside the mouse area, otherwise QML doesn't grok nested hover events :/
217 // cf. https://bugreports.qt.io/browse/QTBUG-32909
218 WindowControlButtons {
219 id: windowControlButtons
220 objectName: "panelWindowControlButtons"
221 height: indicators.minimizedPanelHeight
222 opacity: d.showWindowDecorationControls ? 1 : 0
223 visible: opacity != 0
224 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }
226 active: panelState.decorationsVisible || panelState.decorationsAlwaysVisible
227 windowIsMaximized: true
228 onCloseClicked: panelState.closeClicked()
229 onMinimizeClicked: panelState.minimizeClicked()
230 onMaximizeClicked: panelState.restoreClicked()
231 closeButtonShown: panelState.closeButtonShown
236 objectName: "menuBarLoader"
237 height: parent.height
238 enabled: d.enablePointerMenu
239 opacity: d.showPointerMenu ? 1 : 0
240 visible: opacity != 0
241 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }
242 active: d.showPointerMenu && !callHint.visible
244 width: parent.width - windowControlButtons.width - units.gu(2) - __indicators.barWidth
246 readonly property bool menusRequested: menuBarLoader.item ? menuBarLoader.item.showRequested : false
248 sourceComponent: MenuBar {
250 objectName: "menuBar"
251 anchors.left: menuBarLoader ? menuBarLoader.left : undefined
252 anchors.margins: units.gu(1)
253 height: menuBarLoader.height
254 enableKeyFilter: valid && panelState.decorationsVisible
255 lomiriMenuModel: __applicationMenus.model
256 panelState: root.panelState
259 target: __applicationMenus
260 function onShownChanged() { bar.dismiss(); }
265 function onShownChanged() { bar.dismiss(); }
268 onDoubleClicked: panelState.restoreClicked()
269 onPressed: mouse.accepted = false // let the parent mouse area handle this, so it can both unsnap window and show menu
276 objectName: "callHint"
278 anchors.centerIn: parent
279 height: minimizedPanelHeight
281 visible: active && indicators.state == "initial" && __applicationMenus.state == "initial"
282 greeterShown: root.greeterShown
287 id: __applicationMenus
290 model: registeredMenuModel.model
291 width: root.menuWidth
293 minimizedPanelHeight: root.minimizedPanelHeight
294 expandedPanelHeight: root.expandedPanelHeight
295 openedHeight: root.height
296 alignment: Qt.AlignLeft
297 enableHint: !callHint.active && !fullscreenMode
299 panelColor: panelAreaBackground.color
300 blurSource: root.blurSource
307 if (callHint.active) {
308 callHint.showLiveCall();
313 rowItemDelegate: ActionItem {
315 property int ownIndex: index
316 objectName: "appMenuItem"+index
317 enabled: model.sensitive
319 width: _title.width + units.gu(2)
320 height: parent.height
323 text: model.label.replace("_", "&")
328 anchors.centerIn: parent
329 text: actionItem.text
330 horizontalAlignment: Text.AlignLeft
331 color: enabled ? theme.palette.normal.backgroundText : theme.palette.disabled.backgroundText
335 pageDelegate: PanelMenuPage {
336 readonly property bool isCurrent: modelIndex == __applicationMenus.currentMenuIndex
337 onIsCurrentChanged: {
338 if (isCurrent && menuModel) {
339 menuModel.aboutToShow(modelIndex);
343 menuModel: __applicationMenus.model
344 submenuIndex: modelIndex
346 factory: ApplicationMenuItemFactory {
347 rootModel: __applicationMenus.model
351 enabled: d.enableTouchMenus
352 opacity: d.showTouchMenu ? 1 : 0
353 visible: opacity != 0
355 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }
358 if (!enabled) hide();
366 leftMargin: units.gu(1)
367 right: __indicators.left
368 rightMargin: units.gu(1)
370 height: root.minimizedPanelHeight
376 right: root.partialWidth ? parent.right : parent.left
377 rightMargin: touchMenuIcon.width
379 objectName: "panelTitle"
380 height: root.minimizedPanelHeight
381 verticalAlignment: Text.AlignVCenter
382 elide: Text.ElideRight
385 font.weight: Font.Medium
386 color: theme.palette.selected.backgroundText
387 text: (root.partialWidth && !callHint.visible) ? panelState.title : ""
388 opacity: __applicationMenus.visible && !__applicationMenus.expanded
389 Behavior on opacity { NumberAnimation { duration: LomiriAnimation.SnapDuration } }
390 visible: opacity !== 0
395 objectName: "touchMenuIcon"
398 leftMargin: rowLabel.contentWidth + units.dp(2)
399 verticalCenter: parent.verticalCenter
404 color: theme.palette.normal.backgroundText
405 opacity: !__applicationMenus.expanded && d.enableTouchMenus && !callHint.visible
406 Behavior on opacity { NumberAnimation { duration: LomiriAnimation.SnapDuration } }
407 visible: opacity !== 0
413 objectName: "indicators"
419 width: root.menuWidth
420 minimizedPanelHeight: root.minimizedPanelHeight
421 expandedPanelHeight: root.expandedPanelHeight
422 openedHeight: root.height
424 overFlowWidth: width - appMenuClear
425 enableHint: !callHint.active && !fullscreenMode
426 showOnClick: !callHint.visible
427 panelColor: panelAreaBackground.color
428 blurSource: root.blurSource
434 // On small screens, the Indicators' handle area is the entire top
435 // bar unless there is an application menu. In that case, our handle
436 // needs to allow for some room to clear the application menu.
437 property var appMenuClear: (d.enableTouchMenus && !partialWidth) ? units.gu(7) : 0
440 if (callHint.active) {
441 callHint.showLiveCall();
445 rowItemDelegate: IndicatorItem {
447 objectName: identifier+"-panelItem"
449 property int ownIndex: index
450 readonly property bool overflow: parent.width - (x - __indicators.rowContentX) > __indicators.overFlowWidth
451 readonly property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
452 // HACK for indicator-session
453 readonly property bool hideSessionIndicator: identifier == "ayatana-indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
454 // HACK for indicator-keyboard
455 readonly property bool hideKeyboardIndicator: identifier == "ayatana-indicator-keyboard" && !hasKeyboard
457 height: parent.height
458 expanded: indicators.expanded
459 selected: ListView.isCurrentItem
461 identifier: model.identifier
462 busName: indicatorProperties.busName
463 actionsObjectPath: indicatorProperties.actionsObjectPath
464 menuObjectPath: indicatorProperties.menuObjectPath
466 opacity: hidden ? 0.0 : 1.0
467 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }
469 width: ((expanded || indicatorVisible) && !hideSessionIndicator && !hideKeyboardIndicator) ? implicitWidth : 0
471 Behavior on width { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }
474 pageDelegate: PanelMenuPage {
475 objectName: modelData.identifier + "-page"
478 menuModel: delegate.menuModel
480 factory: IndicatorMenuItemFactory {
482 var context = modelData.identifier;
483 if (context && context.indexOf("fake-") === 0) {
484 context = context.substring("fake-".length)
488 rootModel: delegate.menuModel
493 busName: modelData.indicatorProperties.busName
494 actionsObjectPath: modelData.indicatorProperties.actionsObjectPath
495 menuObjectPath: modelData.indicatorProperties.menuObjectPath
499 enabled: !applicationMenus.expanded
500 opacity: !callHint.visible && !applicationMenus.expanded ? 1 : 0
502 Behavior on opacity { LomiriNumberAnimation { duration: LomiriAnimation.SnapDuration } }
505 if (!enabled) hide();
512 supportsMultiColorLed: root.supportsMultiColorLed
517 name: "onscreen" //fully opaque and visible at top edge of screen
518 when: !fullscreenMode || temporarilyShown
526 name: "offscreen" //pushed off screen
531 if (indicators.state !== "initial") return 0;
532 if (applicationMenus.state !== "initial") return 0;
533 return -minimizedPanelHeight;
535 opacity: indicators.fullyClosed && applicationMenus.fullyClosed ? 0.0 : 1.0
538 target: indicators.showDragHandle;
539 anchors.bottomMargin: -units.gu(1)
542 target: applicationMenus.showDragHandle;
543 anchors.bottomMargin: -units.gu(1)
551 LomiriNumberAnimation { target: panelArea; properties: "anchors.topMargin,opacity" }
555 LomiriNumberAnimation { target: panelArea; properties: "anchors.topMargin,opacity" }