on xenial help sign in
menus
a40eeb7Nick Dedekind
plugins/Utils/windowinputfilter.cpp+23−6
@@ -26,10 +26,14 @@ WindowInputFilter::WindowInputFilter(QQuickItem *parent)
26{
26{
27 connect(this, &QQuickItem::windowChanged,
27 connect(this, &QQuickItem::windowChanged,
28 this, &WindowInputFilter::setupFilterOnWindow);
28 this, &WindowInputFilter::setupFilterOnWindow);
29+ connect(this, &QQuickItem::enabledChanged,
30+ this, &WindowInputFilter::updateFilter);
29}
31}
30
32
31bool WindowInputFilter::eventFilter(QObject *watched, QEvent *event)
33bool WindowInputFilter::eventFilter(QObject *watched, QEvent *event)
32{
34{
35+ if (!isEnabled()) return false;
36+
33 Q_ASSERT(!m_filteredWindow.isNull());
37 Q_ASSERT(!m_filteredWindow.isNull());
34 Q_ASSERT(watched == static_cast<QObject*>(m_filteredWindow.data()));
38 Q_ASSERT(watched == static_cast<QObject*>(m_filteredWindow.data()));
35 Q_UNUSED(watched);
39 Q_UNUSED(watched);
@@ -53,14 +57,27 @@ bool WindowInputFilter::eventFilter(QObject *watched, QEvent *event)
53
57
54void WindowInputFilter::setupFilterOnWindow(QQuickWindow *window)
58void WindowInputFilter::setupFilterOnWindow(QQuickWindow *window)
55{
59{
60+ if (isEnabled()) {
56− if (!m_filteredWindow.isNull()) {
61+ if (!m_filteredWindow.isNull()) {
57− m_filteredWindow->removeEventFilter(this);
62+ m_filteredWindow->removeEventFilter(this);
58− m_filteredWindow.clear();
63+ m_filteredWindow.clear();
64+ }
65+
66+ if (window) {
67+ window->installEventFilter(this);
68+ }
59 }
69 }
70+ m_filteredWindow = window;
71+}
60
72
61− if (window) {
73+void WindowInputFilter::updateFilter()
74+{
75+ if (!m_filteredWindow.isNull()) {
76+ if (isEnabled()) {
62− window->installEventFilter(this);
77+ m_filteredWindow->installEventFilter(this);
63− m_filteredWindow = window;
78+ } else {
79+ m_filteredWindow->removeEventFilter(this);
80+ }
64 }
81 }
65}
82}
66
83
plugins/Utils/windowinputfilter.h+1
@@ -49,6 +49,7 @@ Q_SIGNALS:
49
49
50private Q_SLOTS:
50private Q_SLOTS:
51 void setupFilterOnWindow(QQuickWindow *window);
51 void setupFilterOnWindow(QQuickWindow *window);
52+ void updateFilter();
52
53
53private:
54private:
54 QPointer<QQuickWindow> m_filteredWindow;
55 QPointer<QQuickWindow> m_filteredWindow;
qml/CMakeLists.txt+1
@@ -5,6 +5,7 @@ install(FILES ${QML_JS_FILES}
5 )
5 )
6
6
7set(QML_DIRS
7set(QML_DIRS
8+ ApplicationMenus
8 Components
9 Components
9 Dash
10 Dash
10 graphics
11 graphics
qml/Components/PanelState/PanelState.qml+6−3
@@ -1,5 +1,5 @@
1/*
1/*
2− * Copyright (C) 2014 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
@@ -21,8 +21,8 @@ QtObject {
21 id: root
21 id: root
22
22
23 property string title: ""
23 property string title: ""
24− property bool buttonsVisible: false
24+ property bool decorationsVisible: false
25− property bool buttonsAlwaysVisible: false
25+ property bool decorationsAlwaysVisible: false
26 property bool closeButtonShown: true
26 property bool closeButtonShown: true
27 property bool dropShadow: false
27 property bool dropShadow: false
28 property int panelHeight: 0
28 property int panelHeight: 0
@@ -30,4 +30,7 @@ QtObject {
30 signal closeClicked()
30 signal closeClicked()
31 signal minimizeClicked()
31 signal minimizeClicked()
32 signal restoreClicked()
32 signal restoreClicked()
33+
34+ property string focusedPersistentSurfaceId: ""
35+ property bool focusedSurfaceMaximized: false
33}
36}
qml/Panel/IndicatorPage.qml+159−136
@@ -15,174 +15,197 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18−import Ubuntu.Components 1.3 as Components
18+import Ubuntu.Components 1.3
19+import Ubuntu.Components.ListItems 1.3 as ListItems
19import Unity.Indicators 0.1 as Indicators
20import Unity.Indicators 0.1 as Indicators
20import "../Components"
21import "../Components"
21import "Indicators"
22import "Indicators"
22
23
23−IndicatorBase {
24+PageStack {
24− id: main
25+ id: root
25−
26+
26− //const
27+ property var submenuIndex: undefined
27− property string title: rootActionState.title || rootActionState.accessibleName // some indicators don't expose a title but only the accessible-desc
28+ property string context
28− property alias highlightFollowsCurrentItem : mainMenu.highlightFollowsCurrentItem
29+ property QtObject menuModel: null
29− readonly property alias factory: _factory
30−
31− Indicators.UnityMenuModelStack {
32− id: menuStack
33− head: main.menuModel
34−
35− property var rootMenu: null
36−
37− onTailChanged: {
38− if (!tail) {
39− rootMenu = null;
40− } else if (rootMenu != tail) {
41− if (tail.get(0, "type") === rootMenuType) {
42− rootMenu = menuStack.tail.submenu(0);
43− push(rootMenu, 0);
44− } else {
45− rootMenu = null;
46− }
47− }
48− }
49− }
50
30
51 Connections {
31 Connections {
52− target: menuStack.tail
32+ target: root.menuModel
53
33
54 // fix async creation with signal from model before it's finished.
34 // fix async creation with signal from model before it's finished.
55− Component.onCompleted: update();
56− onRowsInserted: update();
35+ onRowsInserted: root.reset()
36+ onRowsRemoved: root.reset()
57− onModelReset: update();
37+ onModelReset: root.reset()
58−
59− function update() {
60− if (menuStack.rootMenu !== menuStack.tail && menuStack.tail.get(0, "type") === rootMenuType) {
61− menuStack.rootMenu = menuStack.tail.submenu(0);
62− menuStack.push(menuStack.rootMenu, 0);
63− }
64− }
65 }
38 }
66
39
67− ListView {
40+ Component.onCompleted: {
68− id: mainMenu
41+ reset();
69− objectName: "mainMenu"
42+ }
70− model: menuStack.rootMenu
71−
72− anchors {
73− fill: parent
74− bottomMargin: Qt.inputMethod.visible ? (Qt.inputMethod.keyboardRectangle.height - main.anchors.bottomMargin) : 0
75
43
76− Behavior on bottomMargin {
44+ function reset() {
77− NumberAnimation {
45+ clear();
78− duration: 175
46+ var model = submenuIndex == undefined ? menuModel : menuModel.submenu(submenuIndex)
79− easing.type: Easing.OutQuad
47+ push(pageComponent, { "menuModel": model });
80− }
81− }
82− // TODO - does ever frame.
83− onBottomMarginChanged: {
84− mainMenu.positionViewAtIndex(mainMenu.currentIndex, ListView.End)
85− }
86− }
48+ }
87
49
88− // Don't load all the delegates (only max of 3 pages worth -1/0/+1)
50+ Component {
89− cacheBuffer: Math.max(height * 3, units.gu(70))
51+ id: pageComponent
52+ Page {
53+ id: page
90
54
91− // Only allow flicking if the content doesn't fit on the page
55+ property alias menuModel: mainMenu.model
92− interactive: contentHeight > height
56+ property alias title: backLabel.title
57+ property bool isSubmenu: false
93
58
94− property int selectedIndex: -1
59+ MenuItemFactory {
95− property bool blockCurrentIndexChange: false
60+ id: factory
96− // for count = 0
61+ context: root.context
97− onCountChanged: {
62+ rootModel: root.menuModel ? root.menuModel : null
98− if (count == 0 && selectedIndex != -1) {
63+ menuModel: mainMenu.model ? mainMenu.model : null
99− selectedIndex = -1;
100 }
64 }
101− }
102− // for highlight following
103− onSelectedIndexChanged: {
104− if (currentIndex != selectedIndex) {
105− var blocked = blockCurrentIndexChange;
106− blockCurrentIndexChange = true;
107−
108− currentIndex = selectedIndex;
109
65
110− blockCurrentIndexChange = blocked;
66+ header: PageHeader {
111− }
67+ id: backLabel
112− }
68+ visible: page.isSubmenu
113− // for item addition/removal
69+ leadingActionBar.actions: [
114− onCurrentIndexChanged: {
70+ Action {
115− if (!blockCurrentIndexChange) {
71+ iconName: "back"
116− if (selectedIndex != -1 && selectedIndex != currentIndex) {
72+ text: "Back"
117− selectedIndex = currentIndex;
73+ onTriggered: {
118− }
74+ root.pop();
75+ }
76+ }
77+ ]
119 }
78 }
120− }
121
79
122− Connections {
80+ ListView {
123− target: mainMenu.model ? mainMenu.model : null
81+ id: mainMenu
124− onRowsAboutToBeRemoved: {
82+ objectName: "mainMenu"
125− // track current item deletion.
83+
126− if (mainMenu.selectedIndex >= first && mainMenu.selectedIndex <= last) {
84+ anchors {
127− mainMenu.selectedIndex = -1;
85+ top: page.isSubmenu ? backLabel.bottom : parent.top
86+ left: parent.left
87+ right: parent.right
88+ bottom: parent.bottom
89+ bottomMargin: Qt.inputMethod.visible ? (Qt.inputMethod.keyboardRectangle.height - root.anchors.bottomMargin) : 0
90+
91+ Behavior on bottomMargin {
92+ NumberAnimation {
93+ duration: 175
94+ easing.type: Easing.OutQuad
95+ }
96+ }
97+ // TODO - does ever frame.
98+ onBottomMarginChanged: {
99+ mainMenu.positionViewAtIndex(mainMenu.currentIndex, ListView.End)
100+ }
128 }
101 }
129− }
130− }
131
102
132− delegate: Loader {
103+ // Don't load all the delegates (only max of 3 pages worth -1/0/+1)
133− id: loader
104+ cacheBuffer: Math.max(height * 3, units.gu(70))
134− objectName: "menuItem" + index
135− width: ListView.view.width
136− visible: status == Loader.Ready
137
105
138− property int modelIndex: index
106+ // Only allow flicking if the content doesn't fit on the page
139− sourceComponent: factory.load(model, main.identifier)
107+ interactive: contentHeight > height
140
108
141− onLoaded: {
109+ property int selectedIndex: -1
142− if (item.hasOwnProperty("selected")) {
110+ property bool blockCurrentIndexChange: false
143− item.selected = mainMenu.selectedIndex == index;
111+ // for count = 0
144− }
112+ onCountChanged: {
145− if (item.hasOwnProperty("menuSelected")) {
113+ if (count == 0 && selectedIndex != -1) {
146− item.menuSelected.connect(function() { mainMenu.selectedIndex = index; });
114+ selectedIndex = -1;
115+ }
147 }
116 }
148− if (item.hasOwnProperty("menuDeselected")) {
117+ // for highlight following
149− item.menuDeselected.connect(function() { mainMenu.selectedIndex = -1; });
118+ onSelectedIndexChanged: {
119+ if (currentIndex != selectedIndex) {
120+ var blocked = blockCurrentIndexChange;
121+ blockCurrentIndexChange = true;
122+
123+ currentIndex = selectedIndex;
124+
125+ blockCurrentIndexChange = blocked;
126+ }
150 }
127 }
151− if (item.hasOwnProperty("menuData")) {
128+ // for item addition/removal
152− item.menuData = Qt.binding(function() { return model; });
129+ onCurrentIndexChanged: {
130+ if (!blockCurrentIndexChange) {
131+ if (selectedIndex != -1 && selectedIndex != currentIndex) {
132+ selectedIndex = currentIndex;
133+ }
134+ }
153 }
135 }
154− if (item.hasOwnProperty("menuIndex")) {
136+
155− item.menuIndex = Qt.binding(function() { return modelIndex; });
137+ Connections {
138+ target: mainMenu.model ? mainMenu.model : null
139+ onRowsAboutToBeRemoved: {
140+ // track current item deletion.
141+ if (mainMenu.selectedIndex >= first && mainMenu.selectedIndex <= last) {
142+ mainMenu.selectedIndex = -1;
143+ }
144+ }
156 }
145 }
157− }
158
146
159− Binding {
147+ delegate: Loader {
160− target: item ? item : null
148+ id: loader
161− property: "objectName"
149+ objectName: "menuItem" + index
162− value: model.action
150+ width: ListView.view.width
151+ visible: status == Loader.Ready
152+
153+ property int modelIndex: index
154+ sourceComponent: factory.load(model)
155+
156+ onLoaded: {
157+ if (item.hasOwnProperty("selected")) {
158+ item.selected = mainMenu.selectedIndex == index;
159+ }
160+ if (item.hasOwnProperty("menuSelected")) {
161+ item.menuSelected.connect(function() { mainMenu.selectedIndex = index; });
162+ }
163+ if (item.hasOwnProperty("menuDeselected")) {
164+ item.menuDeselected.connect(function() { mainMenu.selectedIndex = -1; });
165+ }
166+ if (item.hasOwnProperty("menuData")) {
167+ item.menuData = Qt.binding(function() { return model; });
168+ }
169+ if (item.hasOwnProperty("menuIndex")) {
170+ item.menuIndex = Qt.binding(function() { return modelIndex; });
171+ }
172+ if (item.hasOwnProperty("clicked")) {
173+ item.clicked.connect(function() {
174+ if (model.hasSubmenu) {
175+ root.push(pageComponent, {
176+ "isSubmenu": true,
177+ "title": model.label,
178+ "menuModel": page.menuModel.submenu(modelIndex)
179+ });
180+ }
181+ });
182+ }
163− }
183+ }
164
184
185+ Binding {
186+ target: item ? item : null
187+ property: "objectName"
188+ value: model.action
189+ }
190+
165− // TODO: Fixes lp#1243146
191+ // TODO: Fixes lp#1243146
166− // This is a workaround for a Qt bug. https://bugreports.qt-project.org/browse/QTBUG-34351
192+ // This is a workaround for a Qt bug. https://bugreports.qt-project.org/browse/QTBUG-34351
167− Connections {
193+ Connections {
168− target: mainMenu
194+ target: mainMenu
169− onSelectedIndexChanged: {
195+ onSelectedIndexChanged: {
170− if (loader.item && loader.item.hasOwnProperty("selected")) {
196+ if (loader.item && loader.item.hasOwnProperty("selected")) {
171− loader.item.selected = mainMenu.selectedIndex == index;
197+ loader.item.selected = mainMenu.selectedIndex == index;
198+ }
199+ }
172 }
200 }
173 }
201 }
174 }
202 }
175 }
203 }
176 }
204 }
177
205
178− MenuItemFactory {
179− id: _factory
180− rootModel: main.menuModel ? main.menuModel : null
181− menuModel: mainMenu.model ? mainMenu.model : null
182− }
183−
184− function reset()
206+// function reset()
185− {
207+// {
208+// menuStack.reset();
186− mainMenu.positionViewAtBeginning();
209+// mainMenu.positionViewAtBeginning();
187− }
210+// }
188}
211}
qml/Panel/Indicators/MenuItemFactory.qml+87−1
@@ -28,6 +28,7 @@ import Unity.Platform 1.0
28Item {
28Item {
29 id: menuFactory
29 id: menuFactory
30
30
31+ property string context
31 property var rootModel: null
32 property var rootModel: null
32 property var menuModel: null
33 property var menuModel: null
33
34
@@ -1041,7 +1042,92 @@ Item {
1041 }
1042 }
1042 }
1043 }
1043
1044
1045+ Component {
1046+ id: applicationMenu;
1047+
1048+ ListItem {
1049+ property QtObject menuData: null
1050+ property int menuIndex: -1
1051+
1052+ height: layout.height
1053+ enabled: menuData && menuData.sensitive || false
1054+ divider.visible: false
1055+
1056+ onClicked: {
1057+ menuModel.activate(menuIndex);
1058+ }
1059+
1060+ ListItemLayout {
1061+ id: layout
1062+ title.text: menuData && menuData.label || ""
1063+
1064+ Icon {
1065+ source: menuData && menuData.icon || ""
1066+ SlotsLayout.position: SlotsLayout.Leading
1067+ height: units.gu(3)
1068+ }
1069+
1070+ }
1071+ }
1072+ }
1073+
1074+ Component {
1075+ id: submenu
1076+
1077+ ListItem {
1078+ property QtObject menuData: null
1079+ property int menuIndex: -1
1080+
1081+ height: layout.height
1082+ enabled: menuData && menuData.sensitive || false
1083+ divider.visible: false
1084+
1085+ onClicked: {
1086+ menuModel.activate(menuIndex);
1087+ }
1088+
1089+ ListItemLayout {
1090+ id: layout
1091+ title.text: menuData && menuData.label || ""
1092+
1093+ Icon {
1094+ source: menuData && menuData.icon || ""
1095+ SlotsLayout.position: SlotsLayout.Leading
1096+ height: units.gu(3)
1097+ }
1098+
1099+ Icon {
1100+ name: "toolkit_chevron-ltr_1gu"
1101+ SlotsLayout.position: SlotsLayout.Trailing
1102+ width: units.gu(2)
1103+ }
1104+ }
1105+ }
1106+ }
1107+
1108+ Component {
1109+ id: applicationMenuSeparator;
1110+
1111+ ListItems.Divider {
1112+ }
1113+ }
1114+
1044− function load(modelData, context) {
1115+ function load(modelData) {
1116+ if (context == "application-menu") {
1117+ if (modelData.isSeparator) {
1118+ return applicationMenuSeparator;
1119+ }
1120+ if (modelData.isRadio) {
1121+ }
1122+ if (modelData.isCheck) {
1123+
1124+ }
1125+ if (modelData.hasSubmenu) {
1126+ return submenu;
1127+ }
1128+ return applicationMenu;
1129+ }
1130+
1045 // tweak indicator-session items
1131 // tweak indicator-session items
1046 if (context === "indicator-session") {
1132 if (context === "indicator-session") {
1047 if ((modelData.action === "indicator.logout" || modelData.action === "indicator.suspend" || modelData.action === "indicator.hibernate" ||
1133 if ((modelData.action === "indicator.logout" || modelData.action === "indicator.suspend" || modelData.action === "indicator.hibernate" ||
qml/Panel/MenuContent.qml+6−8
@@ -27,6 +27,8 @@ Rectangle {
27
27
28 property QtObject indicatorsModel: null
28 property QtObject indicatorsModel: null
29 property int currentMenuIndex: -1
29 property int currentMenuIndex: -1
30+ property Component pageDelegate
31+
30 color: theme.palette.normal.background
32 color: theme.palette.normal.background
31
33
32 width: units.gu(40)
34 width: units.gu(40)
@@ -59,18 +61,14 @@ Rectangle {
59
61
60 width: ListView.view.width
62 width: ListView.view.width
61 height: ListView.view.height
63 height: ListView.view.height
62− objectName: identifier
64+ objectName: item ? item.context : ""
63 asynchronous: true
65 asynchronous: true
64 visible: ListView.isCurrentItem
66 visible: ListView.isCurrentItem
65
67
66− sourceComponent: IndicatorPage {
68+ property var modelData: model
67− objectName: identifier + "-page"
69+ property var modelIndex: index
68
70
69− identifier: model.identifier
71+ sourceComponent: pageDelegate
70− busName: indicatorProperties.busName
71− actionsObjectPath: indicatorProperties.actionsObjectPath
72− menuObjectPath: indicatorProperties.menuObjectPath
73− }
74
72
75 onVisibleChanged: {
73 onVisibleChanged: {
76 // Reset the indicator states
74 // Reset the indicator states
qml/Panel/Panel.qml+364−99
@@ -16,19 +16,40 @@
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19+import Ubuntu.Layouts 1.0
19import Unity.Application 0.1
20import Unity.Application 0.1
21+import Unity.Indicators 0.1
22+import Utils 0.1
23+import Unity.ApplicationMenu 0.1
24+
25+import QtQuick.Window 2.2
26+// for indicator-keyboard
27+import AccountsService 0.1
28+import Unity.InputInfo 0.1
29+
30+import "../ApplicationMenus"
20import "../Components"
31import "../Components"
21import "../Components/PanelState"
32import "../Components/PanelState"
22import ".."
33import ".."
34+import "Indicators"
23
35
24Item {
36Item {
25 id: root
37 id: root
26− readonly property real panelHeight: indicatorArea.y + d.indicatorHeight
38+ readonly property real panelHeight: indicatorArea.y + minimizedPanelHeight
39+
40+ property real minimizedPanelHeight: units.gu(3)
41+ property real expandedPanelHeight: units.gu(7)
42+ property real indicatorMenuWidth: width
43+ property real applicationMenuWidth: width
44+
45+ property alias applicationMenus: fakeApplicationMenus
27 property alias indicators: __indicators
46 property alias indicators: __indicators
28− property alias callHint: __callHint
29 property bool fullscreenMode: false
47 property bool fullscreenMode: false
30 property real indicatorAreaShowProgress: 1.0
48 property real indicatorAreaShowProgress: 1.0
31 property bool locked: false
49 property bool locked: false
50+ property bool greeterShown: false
51+
52+ property string mode: "staged"
32
53
33 MouseArea {
54 MouseArea {
34 anchors.fill: parent
55 anchors.fill: parent
@@ -42,7 +63,17 @@ Item {
42 Binding {
63 Binding {
43 target: PanelState
64 target: PanelState
44 property: "panelHeight"
65 property: "panelHeight"
45− value: indicators.minimizedPanelHeight
66+ value: minimizedPanelHeight
67+ }
68+
69+ FakePanelMenu {
70+ id: fakeApplicationMenus
71+ model: registeredMenuModel.model
72+ }
73+
74+ RegisteredApplicationMenuModel {
75+ id: registeredMenuModel
76+ persistentSurfaceId: PanelState.focusedPersistentSurfaceId
46 }
77 }
47
78
48 Item {
79 Item {
@@ -53,25 +84,24 @@ Item {
53
84
54 transform: Translate {
85 transform: Translate {
55 y: indicators.state === "initial"
86 y: indicators.state === "initial"
56− ? (1.0 - indicatorAreaShowProgress) * -d.indicatorHeight
87+ ? (1.0 - indicatorAreaShowProgress) * - minimizedPanelHeight
57 : 0
88 : 0
58 }
89 }
59
90
60 BorderImage {
91 BorderImage {
61 id: indicatorsDropShadow
92 id: indicatorsDropShadow
62 anchors {
93 anchors {
63− fill: indicators
94+ fill: __indicators
64− leftMargin: -units.gu(1)
65− bottomMargin: -units.gu(1)
95+ margins: -units.gu(1)
66 }
96 }
67− visible: !indicators.fullyClosed
97+ visible: !__indicators.fullyClosed
68 source: "graphics/rectangular_dropshadow.sci"
98 source: "graphics/rectangular_dropshadow.sci"
69 }
99 }
70
100
71 BorderImage {
101 BorderImage {
72 id: panelDropShadow
102 id: panelDropShadow
73 anchors {
103 anchors {
74− fill: indicatorAreaBackground
104+ fill: panelAreaBackground
75 bottomMargin: -units.gu(1)
105 bottomMargin: -units.gu(1)
76 }
106 }
77 visible: PanelState.dropShadow && !callHint.visible
107 visible: PanelState.dropShadow && !callHint.visible
@@ -79,59 +109,289 @@ Item {
79 }
109 }
80
110
81 Rectangle {
111 Rectangle {
82− id: indicatorAreaBackground
112+ id: panelAreaBackground
83− color: callHint.visible ? theme.palette.normal.positive : theme.palette.normal.background
113+ color: theme.palette.normal.background
84 anchors {
114 anchors {
85 top: parent.top
115 top: parent.top
86 left: parent.left
116 left: parent.left
87 right: parent.right
117 right: parent.right
88 }
118 }
89− height: indicators.minimizedPanelHeight
119+ height: minimizedPanelHeight
90
120
91 Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
121 Behavior on color { ColorAnimation { duration: UbuntuAnimation.FastDuration } }
92 }
122 }
93
123
124+ Loader {
125+ id: apppMenuLoader
126+ sourceComponent: mode == "staged" ? stagedLeftPanelComponent : windowedLeftPanelComponent
127+ width: parent.width
128+ height: minimizedPanelHeight
129+
130+ opacity: root.locked ? 0 : 1
131+ visible: opacity != 0
132+ Behavior on opacity { UbuntuNumberAnimation {} }
133+ }
134+
135+ Component {
136+ id: stagedLeftPanelComponent
137+
94− MouseArea {
138+ MouseArea {
139+ id: decorationMouseArea
95− objectName: "windowControlArea"
140+ objectName: "windowControlArea"
96− anchors {
141+ anchors {
97− top: parent.top
98− left: parent.left
142+ left: parent.left
99− right: indicators.left
143+ right: parent.right
100− }
144+ }
101− height: indicators.minimizedPanelHeight
145+ height: minimizedPanelHeight
102− hoverEnabled: true
146+ hoverEnabled: !__indicators.shown
147+ onClicked: {
148+ if (callHint.visible) {
103− onClicked: if (callHint.visible) { callHint.showLiveCall(); }
149+ callHint.showLiveCall();
150+ }
151+ }
104
152
105− onPressed: {
153+ BorderImage {
154+ id: applicationMenusDropShadow
155+ anchors {
156+ fill: __applicationMenus
157+ margins: -units.gu(1)
158+ }
159+ visible: !__applicationMenus.fullyClosed
160+ source: "graphics/rectangular_dropshadow.sci"
161+ }
162+
163+ PanelMenu {
164+ id: __applicationMenus
165+
166+ hides: fakeApplicationMenus.hides
167+ model: fakeApplicationMenus.model
168+
169+ width: root.applicationMenuWidth
170+ minimizedPanelHeight: root.minimizedPanelHeight
171+ expandedPanelHeight: root.expandedPanelHeight
172+ openedHeight: root.height
173+ enableHint: !callHint.active && !fullscreenMode
106− if (!callHint.visible) {
174+ showOnClick: !callHint.visible
107− // let it fall through to the window decoration of the maximized window behind, if any
175+ panelColor: callHint.visible ? theme.palette.normal.positive : theme.palette.normal.background
108− mouse.accepted = false;
176+ alignment: Qt.AlignLeft
177+
178+ showRowTitle: !expanded
179+ rowTitle: PanelState.title
180+ rowItemDelegate: ActionItem {
181+ id: actionItem
182+ property int ownIndex: index
183+
184+ width: _title.width + units.gu(2)
185+ height: parent.height
186+
187+ action: Action {
188+ text: model.label.replace("_", "&")
189+ }
190+
191+ Label {
192+ id: _title
193+ anchors.centerIn: parent
194+ text: actionItem.text
195+ horizontalAlignment: Text.AlignLeft
196+ color: enabled ? "white" : "#5d5d5d"
197+ }
198+ }
199+
200+ pageDelegate: IndicatorPage {
201+ id: page
202+ context: "application-menu"
203+ menuModel: __applicationMenus.model
204+ submenuIndex: modelIndex
205+ }
206+
207+ enabled: !root.locked && model
208+ opacity: !indicators.expanded ? 1 : 0
209+ visible: opacity != 0
210+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
211+
212+ Binding {
213+ target: fakeApplicationMenus
214+ property: "expanded"
215+ value: __applicationMenus.expanded
216+ }
217+
218+ Connections {
219+ target: fakeApplicationMenus
220+ onHide: __applicationMenus.hide();
221+ onShow: __applicationMenus.show();
222+ }
223+ }
224+
225+ ActiveCallHint {
226+ id: callHint
227+ x: __applicationMenus.x + __applicationMenus.barWidth
228+ height: parent.height
229+
230+ visible: active && (indicators.state == "initial" && __applicationMenus.state == "initial")
231+ greeterShown: root.greeterShown
232+ }
233+
234+ Binding {
235+ target: __indicators
236+ property: "overFlowWidth"
237+ value: {
238+ var width = root.width;
239+ if (callHint.visible) {
240+ width -= callHint.width;
241+ }
242+ if (__applicationMenus.visible) {
243+ width -= __applicationMenus.barWidth;
244+ }
245+ return Math.max(width, 0);
246+ }
247+ }
248+ Binding {
249+ target: panelAreaBackground
250+ property: "color"
251+ value: callHint.visible ? theme.palette.normal.positive : theme.palette.normal.background
252+ }
253+ Binding {
254+ target: __indicators
255+ property: "enableHint"
256+ value: !callHint.active && !__indicators.fullscreenMode
257+ }
258+ Binding {
259+ target: __indicators
260+ property: "showOnClick"
261+ value: !callHint.visible
262+ }
263+ Connections {
264+ target: __indicators
265+ onShowTapped: {
266+ if (callHint.active) {
267+ callHint.showLiveCall();
268+ }
269+ }
109 }
270 }
110 }
271 }
272+ }
111
273
112− // WindowControlButtons inside the mouse area, otherwise QML doesn't grok nested hover events :/
274+ Component {
113− // cf. https://bugreports.qt.io/browse/QTBUG-32909
275+ id: windowedLeftPanelComponent
114− WindowControlButtons {
276+
115− id: windowControlButtons
277+ MouseArea {
116− objectName: "panelWindowControlButtons"
278+ id: decorationMouseArea
279+ objectName: "windowControlArea"
117 anchors {
280 anchors {
118 left: parent.left
281 left: parent.left
119− top: parent.top
282+ right: parent.right
120− }
283+ }
121− height: indicators.minimizedPanelHeight
284+ height: minimizedPanelHeight
122−
285+ hoverEnabled: !__indicators.shown
123− visible: ((PanelState.buttonsVisible && parent.containsMouse) || PanelState.buttonsAlwaysVisible)
286+ onClicked: if (callHint.visible) { callHint.showLiveCall(); }
124− && !root.locked && !callHint.visible
287+
288+ onPressed: {
289+ if (!callHint.visible) {
290+ // let it fall through to the window decoration of the maximized window behind, if any
291+ mouse.accepted = false;
292+ }
293+ }
294+
295+ property bool showWindowControls: (PanelState.decorationsVisible && (containsMouse || menuBarLoader.menusRequested)) || PanelState.decorationsAlwaysVisible
296+
297+ // WindowControlButtons inside the mouse area, otherwise QML doesn't grok nested hover events :/
298+ // cf. https://bugreports.qt.io/browse/QTBUG-32909
299+ WindowControlButtons {
300+ id: windowControlButtons
301+ objectName: "panelWindowControlButtons"
302+ anchors {
303+ left: parent.left
304+ top: parent.top
305+ }
306+ height: indicators.minimizedPanelHeight
307+ opacity: decorationMouseArea.showWindowControls ? 1 : 0
308+ visible: opacity != 0
309+ Behavior on opacity { UbuntuNumberAnimation {} }
310+
125− active: PanelState.buttonsVisible || PanelState.buttonsAlwaysVisible
311+ active: PanelState.decorationsVisible || PanelState.decorationsAlwaysVisible
126− windowIsMaximized: true
312+ windowIsMaximized: true
127− onCloseClicked: PanelState.closeClicked()
313+ onCloseClicked: PanelState.closeClicked()
128− onMinimizeClicked: PanelState.minimizeClicked()
314+ onMinimizeClicked: PanelState.minimizeClicked()
129− onMaximizeClicked: PanelState.restoreClicked()
315+ onMaximizeClicked: PanelState.restoreClicked()
130− closeButtonShown: PanelState.closeButtonShown
316+ closeButtonShown: PanelState.closeButtonShown
317+ }
318+
319+ Loader {
320+ id: menuBarLoader
321+ anchors {
322+ left: windowControlButtons.right
323+ leftMargin: units.gu(3)
324+ }
325+ height: parent.height
326+ opacity: windowControlButtons.opacity
327+ visible: opacity != 0
328+ active: fakeApplicationMenus.model
329+
330+ property bool menusRequested: menuBarLoader.item ? menuBarLoader.item.showRequested : false
331+
332+ sourceComponent: MenuBarLoader {
333+ height: menuBarLoader.height
334+ enableKeyFilter: valid && PanelState.decorationsVisible
335+ unityMenuModel: fakeApplicationMenus.model
336+ }
337+ }
338+
339+ Label {
340+ id: titleLabel
341+ objectName: "windowDecorationTitle"
342+ anchors {
343+ left: parent.left
344+ leftMargin: units.gu(1)
345+ verticalCenter: parent.verticalCenter
346+ }
347+ color: "white"
348+ opacity: !decorationMouseArea.showWindowControls ? 1 : 0
349+ visible: opacity != 0
350+ verticalAlignment: Text.AlignVCenter
351+ fontSize: "medium"
352+ font.weight: PanelState.decorationsVisible ? Font.Light : Font.Medium
353+ text: PanelState.title
354+ elide: Text.ElideRight
355+ maximumLineCount: 1
356+ Behavior on opacity { UbuntuNumberAnimation {} }
357+ }
358+
359+ ActiveCallHint {
360+ id: callHint
361+ anchors.centerIn: parent
362+ height: minimizedPanelHeight
363+
364+ visible: active && indicators.state == "initial"
365+ greeterShown: root.greeterShown
366+ }
367+
368+ Binding {
369+ target: panelAreaBackground
370+ property: "color"
371+ value: callHint.visible ? theme.palette.normal.positive : theme.palette.normal.background
372+ }
373+ Binding {
374+ target: __indicators
375+ property: "enableHint"
376+ value: !callHint.active && !__indicators.fullscreenMode
377+ }
378+ Binding {
379+ target: __indicators
380+ property: "showOnClick"
381+ value: !callHint.visible
382+ }
383+ Connections {
384+ target: __indicators
385+ onShowTapped: {
386+ if (callHint.active) {
387+ callHint.showLiveCall();
388+ }
389+ }
390+ }
131 }
391 }
132 }
392 }
133
393
134− IndicatorsMenu {
394+ PanelMenu {
135 id: __indicators
395 id: __indicators
136 objectName: "indicators"
396 objectName: "indicators"
137
397
@@ -139,72 +399,77 @@ Item {
139 top: parent.top
399 top: parent.top
140 right: parent.right
400 right: parent.right
141 }
401 }
142−
402+ width: root.indicatorMenuWidth
143− shown: false
144− width: root.width - (windowControlButtons.visible ? windowControlButtons.width + titleLabel.width : 0)
145− minimizedPanelHeight: units.gu(3)
403+ minimizedPanelHeight: root.minimizedPanelHeight
146− expandedPanelHeight: units.gu(7)
404+ expandedPanelHeight: root.expandedPanelHeight
147 openedHeight: root.height
405 openedHeight: root.height
148
406
149− overFlowWidth: {
407+ overFlowWidth: root.width
150− if (callHint.visible) {
151− return Math.max(root.width - (callHint.width + units.gu(2)), 0)
152− }
153− return root.width
154− }
155− enableHint: !callHint.active && !fullscreenMode
408+ enableHint: !fullscreenMode
156− showOnClick: !callHint.visible
409+ showOnClick: true
157− panelColor: indicatorAreaBackground.color
410+ panelColor: panelAreaBackground.color
158
411
159− onShowTapped: {
412+ onShownChanged: {
160− if (callHint.active) {
413+ if (d.menuBar) d.menuBar.close();
161− callHint.showLiveCall();
162− }
163 }
414 }
164− }
165
415
166− Label {
416+ rowItemDelegate: IndicatorItem {
167− id: titleLabel
417+ id: indicatorItem
168− objectName: "windowDecorationTitle"
418+ objectName: identifier+"-panelItem"
169− anchors {
419+
170− left: parent.left
420+ property int ownIndex: index
171− right: __indicators.left
421+ property bool overflow: parent.width - x > __indicators.overFlowWidth
172− top: parent.top
422+ property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
173− leftMargin: units.gu(1)
423+ // HACK for indicator-session
174− rightMargin: units.gu(1)
424+ readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
175− topMargin: units.gu(0.5)
425+ // HACK for indicator-keyboard
176− bottomMargin: units.gu(0.5)
426+ readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && (AccountsService.keymaps.length < 2 || keyboardsModel.count == 0)
427+
428+ height: parent.height
429+ expanded: indicators.expanded
430+ selected: ListView.isCurrentItem
431+
432+ identifier: model.identifier
433+ busName: indicatorProperties.busName
434+ actionsObjectPath: indicatorProperties.actionsObjectPath
435+ menuObjectPath: indicatorProperties.menuObjectPath
436+
437+ opacity: hidden ? 0.0 : 1.0
438+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
439+
440+ width: ((expanded || indicatorVisible) && !hideSessionIndicator && !hideKeyboardIndicator) ? implicitWidth : 0
441+
442+ Behavior on width { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
177 }
443 }
178− color: "white"
179− height: indicators.minimizedPanelHeight - anchors.topMargin - anchors.bottomMargin
180− opacity: !windowControlButtons.visible && !root.locked && !callHint.visible ? 1 : 0
181− visible: opacity != 0
182− verticalAlignment: Text.AlignVCenter
183− fontSize: "medium"
184− font.weight: PanelState.buttonsVisible ? Font.Light : Font.Medium
185− text: PanelState.title
186− elide: Text.ElideRight
187− maximumLineCount: 1
188− Behavior on opacity { UbuntuNumberAnimation {} }
189− }
190
444
191− // TODO here would the Locally integrated menus come
445+ pageDelegate: IndicatorPage {
446+ id: page
447+ objectName: context + "-page"
448+ context: modelData.identifier
449+ submenuIndex: 0
192
450
193− ActiveCallHint {
451+ menuModel: delegate.menuModel
194− id: __callHint
452+ IndicatorDelegate {
195− anchors {
453+ id: delegate
196− top: parent.top
454+ busName: modelData.indicatorProperties.busName
197− left: parent.left
455+ actionsObjectPath: modelData.indicatorProperties.actionsObjectPath
456+ menuObjectPath: modelData.indicatorProperties.menuObjectPath
457+ }
198 }
458 }
199− height: indicators.minimizedPanelHeight
459+
200− visible: active && indicators.state == "initial"
460+ enabled: !applicationMenus.expanded
461+ opacity: !applicationMenus.expanded ? 1 : 0
462+ Behavior on opacity { UbuntuNumberAnimation { duration: UbuntuAnimation.SnapDuration } }
201 }
463 }
202 }
464 }
203
465
204− QtObject {
466+ InputDeviceModel {
205− id: d
467+ id: keyboardsModel
206− objectName: "panelPriv"
468+ deviceFilter: InputInfo.Keyboard
207− readonly property real indicatorHeight: indicators.minimizedPanelHeight
469+ }
470+
471+ IndicatorsLight {
472+ id: indicatorLights
208 }
473 }
209
474
210 states: [
475 states: [
@@ -222,7 +487,7 @@ Item {
222 when: fullscreenMode
487 when: fullscreenMode
223 PropertyChanges {
488 PropertyChanges {
224 target: indicatorArea;
489 target: indicatorArea;
225− anchors.topMargin: indicators.state === "initial" ? -d.indicatorHeight : 0
490+ anchors.topMargin: indicators.state === "initial" ? - minimizedPanelHeight : 0
226 opacity: indicators.fullyClosed ? 0.0 : 1.0
491 opacity: indicators.fullyClosed ? 0.0 : 1.0
227 }
492 }
228 PropertyChanges {
493 PropertyChanges {
qml/Panel/IndicatorsBar.qml → qml/Panel/PanelBar.qmlrenamed+11−5
@@ -28,7 +28,13 @@ Item {
28 property alias overFlowWidth: row.overFlowWidth
28 property alias overFlowWidth: row.overFlowWidth
29 readonly property alias currentItemIndex: row.currentItemIndex
29 readonly property alias currentItemIndex: row.currentItemIndex
30 property real lateralPosition: -1
30 property real lateralPosition: -1
31− readonly property string currentIndicator: row.currentItem ? row.currentItem.identifier : ""
31+ property int alignment: Qt.AlignRight
32+
33+ property alias showRowTitle: row.showRowTitle
34+ property alias rowTitle: row.rowTitle
35+ property alias rowItemDelegate: row.itemDelegate
36+
37+ implicitWidth: flickable.contentWidth
32
38
33 function selectItemAt(lateralPosition) {
39 function selectItemAt(lateralPosition) {
34 if (!expanded) {
40 if (!expanded) {
@@ -140,10 +146,10 @@ Item {
140
146
141 // we rotate it because we want the Flickable to align its content item
147 // we rotate it because we want the Flickable to align its content item
142 // on the right instead of on the left
148 // on the right instead of on the left
143− rotation: 180
149+ rotation: root.alignment != Qt.AlignRight ? 0 : 180
144
150
145 anchors.fill: parent
151 anchors.fill: parent
146− contentWidth: row.width
152+ contentWidth: row.implicitWidth
147 contentX: d.combinedOffset
153 contentX: d.combinedOffset
148 interactive: false
154 interactive: false
149
155
@@ -161,7 +167,7 @@ Item {
161 }
167 }
162 }
168 }
163
169
164− IndicatorItemRow {
170+ PanelItemRow {
165 id: row
171 id: row
166 objectName: "indicatorItemRow"
172 objectName: "indicatorItemRow"
167 anchors {
173 anchors {
@@ -170,7 +176,7 @@ Item {
170 }
176 }
171
177
172 // Compensate for the Flickable rotation (ie, counter-rotate)
178 // Compensate for the Flickable rotation (ie, counter-rotate)
173− rotation: 180
179+ rotation: root.alignment != Qt.AlignRight ? 0 : 180
174
180
175 lateralPosition: {
181 lateralPosition: {
176 if (root.lateralPosition == -1) return -1;
182 if (root.lateralPosition == -1) return -1;
qml/Panel/IndicatorItemRow.qml → qml/Panel/PanelItemRow.qmlrenamed+65−93
@@ -15,29 +15,28 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18−import QtQuick.Window 2.2
19import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
20
19
21−// for indicator-keyboard
22−import AccountsService 0.1
23−import Unity.InputInfo 0.1
24−
25Item {
20Item {
26 id: root
21 id: root
27− width: row.width
22+ implicitWidth: rowLabel.text !== "" && !expanded ? rowLabel.width : row.width
28− height: units.gu(3)
23+ implicitHeight: units.gu(3)
29
24
25+ property bool showRowTitle: false
26+ property alias rowTitle: rowLabel.text
30 property QtObject indicatorsModel: null
27 property QtObject indicatorsModel: null
31 property real overFlowWidth: width
28 property real overFlowWidth: width
32 property bool expanded: false
29 property bool expanded: false
33− property var currentItem
30+ readonly property alias currentItem: row.currentItem
34− readonly property int currentItemIndex: currentItem ? currentItem.ownIndex : -1
31+ readonly property alias currentItemIndex: row.currentIndex
35
32
36 property real unitProgress: 0.0
33 property real unitProgress: 0.0
37 property real selectionChangeBuffer: units.gu(2)
34 property real selectionChangeBuffer: units.gu(2)
38 property bool enableLateralChanges: false
35 property bool enableLateralChanges: false
39 property color hightlightColor: "#ffffff"
36 property color hightlightColor: "#ffffff"
40
37
38+ property alias itemDelegate: row.delegate
39+
41 property real lateralPosition: -1
40 property real lateralPosition: -1
42 onLateralPositionChanged: {
41 onLateralPositionChanged: {
43 updateItemFromLateralPosition();
42 updateItemFromLateralPosition();
@@ -86,21 +85,21 @@ Item {
86 }
85 }
87
86
88 function indicatorAt(x, y) {
87 function indicatorAt(x, y) {
89− var item = row.childAt(x, y);
88+ var item = row.itemAt(x, y);
90 return item && item.hasOwnProperty("ownIndex") ? item : null;
89 return item && item.hasOwnProperty("ownIndex") ? item : null;
91 }
90 }
92
91
93 function resetCurrentItem() {
92 function resetCurrentItem() {
94 d.firstItemSwitch = true;
93 d.firstItemSwitch = true;
95− d.previousItem = undefined;
94+ d.previousItem = null;
96− currentItem = undefined;
95+ row.currentIndex = -1;
97 }
96 }
98
97
99 function setCurrentItemIndex(index) {
98 function setCurrentItemIndex(index) {
100− for (var i = 0; i < row.children.length; i++) {
99+ for (var i = 0; i < row.contentItem.children.length; i++) {
101− var item = row.children[i];
100+ var item = row.contentItem.children[i];
102 if (item.hasOwnProperty("ownIndex") && item.ownIndex === index) {
101 if (item.hasOwnProperty("ownIndex") && item.ownIndex === index) {
103− if (currentItem !== item) currentItem = item;
102+ if (currentItem !== item) row.currentIndex = index;
104 break;
103 break;
105 }
104 }
106 }
105 }
@@ -109,18 +108,18 @@ Item {
109 function selectItemAt(lateralPosition) {
108 function selectItemAt(lateralPosition) {
110 var item = indicatorAt(lateralPosition, 0);
109 var item = indicatorAt(lateralPosition, 0);
111 if (item && item.opacity > 0) {
110 if (item && item.opacity > 0) {
112− currentItem = item;
111+ row.currentIndex = item.ownIndex;
113 } else {
112 } else {
114 // Select default item.
113 // Select default item.
115− var searchIndex = lateralPosition > width ? repeater.count - 1 : 0;
114+ var searchIndex = lateralPosition >= width ? row.count - 1 : 0;
116
115
117− for (var i = 0; i < row.children.length; i++) {
116+ for (var i = 0; i < row.contentItem.children.length; i++) {
118− if (row.children[i].hasOwnProperty("ownIndex") && row.children[i].ownIndex === searchIndex) {
117+ if (row.contentItem.children[i].hasOwnProperty("ownIndex") && row.contentItem.children[i].ownIndex === searchIndex) {
119− item = row.children[i];
118+ item = row.contentItem.children[i];
120 break;
119 break;
121 }
120 }
122 }
121 }
123− if (currentItem !== item) currentItem = item;
122+ if (currentItem !== item) row.currentIndex = item ? item.ownIndex : -1;
124 }
123 }
125 }
124 }
126
125
@@ -131,11 +130,6 @@ Item {
131 property bool forceAlignmentAnimationDisabled: false
130 property bool forceAlignmentAnimationDisabled: false
132 }
131 }
133
132
134− InputDeviceModel {
135− id: keyboardsModel
136− deviceFilter: InputInfo.Keyboard
137− }
138−
139 onCurrentItemChanged: {
133 onCurrentItemChanged: {
140 if (d.previousItem) {
134 if (d.previousItem) {
141 d.firstItemSwitch = false;
135 d.firstItemSwitch = false;
@@ -143,8 +137,28 @@ Item {
143 d.previousItem = currentItem;
137 d.previousItem = currentItem;
144 }
138 }
145
139
146− Row {
140+ Label {
141+ id: rowLabel
142+ anchors {
143+ left: parent.left
144+ leftMargin: units.gu(1)
145+ verticalCenter: parent.verticalCenter
146+ }
147+ width: implicitWidth + units.gu(2)
148+ elide: Text.ElideRight
149+ maximumLineCount: 1
150+ fontSize: "medium"
151+ font.weight: Font.Medium
152+ color: Theme.palette.selected.backgroundText
153+ opacity: showRowTitle ? 1 : 0
154+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
155+ }
156+
157+ ListView {
147 id: row
158 id: row
159+ orientation: ListView.Horizontal
160+ model: indicatorsModel
161+ opacity: showRowTitle ? 0 : 1
148 anchors {
162 anchors {
149 top: parent.top
163 top: parent.top
150 bottom: parent.bottom
164 bottom: parent.bottom
@@ -153,7 +167,7 @@ Item {
153 // TODO: make this better
167 // TODO: make this better
154 // when the width changes, the highlight will lag behind due to animation, so we need to disable the animation
168 // when the width changes, the highlight will lag behind due to animation, so we need to disable the animation
155 // and adjust the highlight X immediately.
169 // and adjust the highlight X immediately.
156− width: implicitWidth
170+ width: childrenRect.width
157 Behavior on width {
171 Behavior on width {
158 SequentialAnimation {
172 SequentialAnimation {
159 ScriptAction {
173 ScriptAction {
@@ -166,71 +180,29 @@ Item {
166 }
180 }
167 }
181 }
168
182
169− Repeater {
170− id: repeater
171− model: indicatorsModel
172− visible: false
173−
174− onItemRemoved: {
175− // current item removed.
176− if (currentItem === item) {
177− var i = 0;
178− while (i < row.children.length) {
179− var childItem = row.children[i];
180− if (childItem !== item) {
181− setCurrentItemIndex(i);
182− break;
183− }
184− i++;
185− }
186− }
187− }
188−
189−
190− delegate: IndicatorItem {
191− id: indicatorItem
192− objectName: identifier+"-panelItem"
193−
194− property int ownIndex: index
195− property bool overflow: row.width - x > overFlowWidth
196− property bool hidden: !expanded && (overflow || !indicatorVisible || hideSessionIndicator || hideKeyboardIndicator)
197− // HACK for indicator-session
198− readonly property bool hideSessionIndicator: identifier == "indicator-session" && Math.min(Screen.width, Screen.height) <= units.gu(60)
199− // HACK for indicator-keyboard
200− readonly property bool hideKeyboardIndicator: identifier == "indicator-keyboard" && (AccountsService.keymaps.length < 2 || keyboardsModel.count == 0)
201−
202− height: row.height
203− expanded: root.expanded
204− selected: currentItem === this
205−
206− identifier: model.identifier
207− busName: indicatorProperties.busName
208− actionsObjectPath: indicatorProperties.actionsObjectPath
209− menuObjectPath: indicatorProperties.menuObjectPath
210−
211− opacity: hidden ? 0.0 : 1.0
212− Behavior on opacity {
213− NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing }
183+ Behavior on opacity { NumberAnimation { duration: UbuntuAnimation.SnapDuration } }
214− }
184+ }
215−
216− width: ((expanded || indicatorVisible) && !hideSessionIndicator && !hideKeyboardIndicator) ? implicitWidth : 0
217
185
218− Behavior on width {
186+ ListView {
219− NumberAnimation { duration: UbuntuAnimation.SnapDuration; easing: UbuntuAnimation.StandardEasing }
187+ orientation: ListView.Horizontal
188+ model: indicatorsModel
189+ anchors {
190+ top: parent.top
191+ bottom: parent.bottom
220− }
192+ }
193+ interactive: expanded
221
194
222− Component.onDestruction: {
195+ // TODO: make this better
223− // current item removed.
196+ // when the width changes, the highlight will lag behind due to animation, so we need to disable the animation
224− if (currentItem === this) {
197+ // and adjust the highlight X immediately.
225− var i = 0;
198+ width: implicitWidth
226− while (i < row.children.length) {
199+ Behavior on width {
227− var childItem = row.children[i];
200+ SequentialAnimation {
228− if (childItem !== this) {
201+ ScriptAction {
229− setCurrentItemIndex(i);
202+ script: {
230− break;
203+ d.forceAlignmentAnimationDisabled = true;
231− }
204+ highlight.currentItemX = Qt.binding(function() { return currentItem ? currentItem.x : 0 });
232− i++;
205+ d.forceAlignmentAnimationDisabled = false;
233− }
234 }
206 }
235 }
207 }
236 }
208 }
@@ -244,7 +216,7 @@ Item {
244 anchors.bottom: row.bottom
216 anchors.bottom: row.bottom
245 height: units.dp(2)
217 height: units.dp(2)
246 color: root.hightlightColor
218 color: root.hightlightColor
247− visible: currentItem !== undefined
219+ visible: currentItem !== null
248 opacity: 0.0
220 opacity: 0.0
249
221
250 width: currentItem ? currentItem.width : 0
222 width: currentItem ? currentItem.width : 0
@@ -269,7 +241,7 @@ Item {
269
241
270 if (currentItem && currentItem.ownIndex === 0 && distanceFromCenter < 0) {
242 if (currentItem && currentItem.ownIndex === 0 && distanceFromCenter < 0) {
271 return 0;
243 return 0;
272− } else if (currentItem && currentItem.ownIndex === repeater.count-1 & distanceFromCenter > 0) {
244+ } else if (currentItem && currentItem.ownIndex === row.count-1 & distanceFromCenter > 0) {
273 return 0;
245 return 0;
274 }
246 }
275 return (distanceFromCenter / (currentItem.width / 4)) * units.gu(1);
247 return (distanceFromCenter / (currentItem.width / 4)) * units.gu(1);
qml/Panel/IndicatorsMenu.qml → qml/Panel/PanelMenu.qmlrenamed+30−19
@@ -22,22 +22,30 @@ import "Indicators"
22
22
23Showable {
23Showable {
24 id: root
24 id: root
25− property alias indicatorsModel: bar.indicatorsModel
25+ property alias model: bar.indicatorsModel
26 property alias showDragHandle: __showDragHandle
26 property alias showDragHandle: __showDragHandle
27 property alias hideDragHandle: __hideDragHandle
27 property alias hideDragHandle: __hideDragHandle
28 property alias overFlowWidth: bar.overFlowWidth
28 property alias overFlowWidth: bar.overFlowWidth
29 property alias verticalVelocityThreshold: yVelocityCalculator.velocityThreshold
29 property alias verticalVelocityThreshold: yVelocityCalculator.velocityThreshold
30− property alias currentIndicator: bar.currentIndicator
31 property int minimizedPanelHeight: units.gu(3)
30 property int minimizedPanelHeight: units.gu(3)
32 property int expandedPanelHeight: units.gu(7)
31 property int expandedPanelHeight: units.gu(7)
33 property real openedHeight: units.gu(71)
32 property real openedHeight: units.gu(71)
33+ property bool enableHint: true
34+ property bool showOnClick: true
35+ property color panelColor: theme.palette.normal.background
36+
37+ property alias alignment: bar.alignment
38+ property alias rowTitle: bar.rowTitle
39+ property alias showRowTitle: bar.showRowTitle
40+ property alias rowItemDelegate: bar.rowItemDelegate
41+ property alias pageDelegate: content.pageDelegate
42+
34 readonly property real unitProgress: Math.max(0, (height - minimizedPanelHeight) / (openedHeight - minimizedPanelHeight))
43 readonly property real unitProgress: Math.max(0, (height - minimizedPanelHeight) / (openedHeight - minimizedPanelHeight))
35 readonly property bool fullyOpened: unitProgress >= 1
44 readonly property bool fullyOpened: unitProgress >= 1
36 readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0
45 readonly property bool partiallyOpened: unitProgress > 0 && unitProgress < 1.0
37 readonly property bool fullyClosed: unitProgress == 0
46 readonly property bool fullyClosed: unitProgress == 0
38− property bool enableHint: true
47+ readonly property alias expanded: bar.expanded
39− property bool showOnClick: true
48+ readonly property int barWidth: Math.min(bar.width, bar.implicitWidth)
40− property color panelColor: theme.palette.normal.background
41
49
42 signal showTapped()
50 signal showTapped()
43
51
@@ -67,21 +75,19 @@ Showable {
67 ScriptAction { script: root.height = Qt.binding( function(){ return root.minimizedPanelHeight; } ) }
75 ScriptAction { script: root.height = Qt.binding( function(){ return root.minimizedPanelHeight; } ) }
68 }
76 }
69
77
78+ shown: false
70 height: minimizedPanelHeight
79 height: minimizedPanelHeight
71−
72− onUnitProgressChanged: d.updateState()
73 clip: root.partiallyOpened
80 clip: root.partiallyOpened
74
81
75− IndicatorsLight {
82+ onUnitProgressChanged: d.updateState()
76− id: indicatorLights
77− }
78
83
79 // eater
84 // eater
80 MouseArea {
85 MouseArea {
81− anchors.fill: parent
86+ anchors.fill: content
82 hoverEnabled: true
87 hoverEnabled: true
83 acceptedButtons: Qt.AllButtons
88 acceptedButtons: Qt.AllButtons
84 onWheel: wheel.accepted = true;
89 onWheel: wheel.accepted = true;
90+ enabled: root.state != "initial"
85 }
91 }
86
92
87 MenuContent {
93 MenuContent {
@@ -94,7 +100,7 @@ Showable {
94 top: bar.bottom
100 top: bar.bottom
95 }
101 }
96 height: openedHeight - bar.height - handle.height
102 height: openedHeight - bar.height - handle.height
97− indicatorsModel: root.indicatorsModel
103+ indicatorsModel: root.model
98 visible: root.unitProgress > 0
104 visible: root.unitProgress > 0
99 currentMenuIndex: bar.currentItemIndex
105 currentMenuIndex: bar.currentItemIndex
100 }
106 }
@@ -109,6 +115,7 @@ Showable {
109 }
115 }
110 height: units.gu(2)
116 height: units.gu(2)
111 active: d.activeDragHandle ? true : false
117 active: d.activeDragHandle ? true : false
118+ visible: !root.fullyClosed
112
119
113 //small shadow gradient at bottom of menu
120 //small shadow gradient at bottom of menu
114 Rectangle {
121 Rectangle {
@@ -129,9 +136,10 @@ Showable {
129 Rectangle {
136 Rectangle {
130 anchors.fill: bar
137 anchors.fill: bar
131 color: panelColor
138 color: panelColor
139+ visible: !root.fullyClosed
132 }
140 }
133
141
134− IndicatorsBar {
142+ PanelBar {
135 id: bar
143 id: bar
136 objectName: "indicatorsBar"
144 objectName: "indicatorsBar"
137
145
@@ -178,12 +186,14 @@ Showable {
178
186
179 MouseArea {
187 MouseArea {
180 anchors.bottom: parent.bottom
188 anchors.bottom: parent.bottom
181− anchors.left: parent.left
189+ anchors.left: alignment == Qt.AlignLeft ? parent.left : undefined
182− anchors.right: parent.right
190+ anchors.right: alignment == Qt.AlignRight ? parent.right : undefined
191+ width: root.barWidth // show handle should only cover panel items.
183 height: minimizedPanelHeight
192 height: minimizedPanelHeight
184 enabled: __showDragHandle.enabled && showOnClick
193 enabled: __showDragHandle.enabled && showOnClick
185 onClicked: {
194 onClicked: {
195+ var barPosition = mapToItem(bar, mouseX, mouseY);
186− bar.selectItemAt(mouseX)
196+ bar.selectItemAt(barPosition.x)
187 root.show()
197 root.show()
188 }
198 }
189 }
199 }
@@ -192,8 +202,9 @@ Showable {
192 id: __showDragHandle
202 id: __showDragHandle
193 objectName: "showDragHandle"
203 objectName: "showDragHandle"
194 anchors.bottom: parent.bottom
204 anchors.bottom: parent.bottom
195− anchors.left: parent.left
205+ anchors.left: alignment == Qt.AlignLeft ? parent.left : undefined
196− anchors.right: parent.right
206+ anchors.right: alignment == Qt.AlignRight ? parent.right : undefined
207+ width: root.barWidth // show handle should only cover panel items.
197 height: minimizedPanelHeight
208 height: minimizedPanelHeight
198 direction: Direction.Downwards
209 direction: Direction.Downwards
199 enabled: !root.shown && root.available
210 enabled: !root.shown && root.available
@@ -311,7 +322,7 @@ Showable {
311 script: {
322 script: {
312 yVelocityCalculator.reset();
323 yVelocityCalculator.reset();
313 // initial item selection
324 // initial item selection
314− if (!d.hasCommitted) bar.selectItemAt(d.activeDragHandle ? d.activeDragHandle.touchPosition.x : -1);
325+ if (!d.hasCommitted) bar.selectItemAt(d.rowMappedLateralPosition);
315 d.hasCommitted = false;
326 d.hasCommitted = false;
316 }
327 }
317 }
328 }
qml/Shell.qml+12−8
@@ -456,7 +456,7 @@ StyledItem {
456 Greeter {
456 Greeter {
457
457
458 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
458 enabled: panel.indicators.fullyClosed // hides OSK when panel is open
459− hides: [launcher, panel.indicators]
459+ hides: [launcher, panel.indicators, panel.applicationMenus]
460 tabletMode: shell.usageScenario != "phone"
460 tabletMode: shell.usageScenario != "phone"
461 launcherOffset: launcher.progress
461 launcherOffset: launcher.progress
462 forcedUnlock: wizard.active || shell.mode === "full-shell"
462 forcedUnlock: wizard.active || shell.mode === "full-shell"
@@ -569,18 +569,21 @@ StyledItem {
569 id: panel
569 id: panel
570 objectName: "panel"
570 objectName: "panel"
571 anchors.fill: parent //because this draws indicator menus
571 anchors.fill: parent //because this draws indicator menus
572+
573+ mode: shell.usageScenario == "desktop" ? "windowed" : "staged"
574+ minimizedPanelHeight: units.gu(3)
575+ expandedPanelHeight: units.gu(7)
576+ indicatorMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
577+ applicationMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
578+
572 indicators {
579 indicators {
573 hides: [launcher]
580 hides: [launcher]
574 available: tutorial.panelEnabled
581 available: tutorial.panelEnabled
575 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
582 && ((!greeter || !greeter.locked) || AccountsService.enableIndicatorsWhileLocked)
576 && (!greeter || !greeter.hasLockedApp)
583 && (!greeter || !greeter.hasLockedApp)
577 && !shell.waitingOnGreeter
584 && !shell.waitingOnGreeter
578− width: parent.width > units.gu(60) ? units.gu(40) : parent.width
579
585
580− minimizedPanelHeight: units.gu(3)
581− expandedPanelHeight: units.gu(7)
582−
583− indicatorsModel: Indicators.IndicatorsModel {
586+ model: Indicators.IndicatorsModel {
584 // tablet and phone both use the same profile
587 // tablet and phone both use the same profile
585 // FIXME: use just "phone" for greeter too, but first fix
588 // FIXME: use just "phone" for greeter too, but first fix
586 // greeter app launching to either load the app inside the
589 // greeter app launching to either load the app inside the
@@ -592,8 +595,8 @@ StyledItem {
592 }
595 }
593 }
596 }
594
597
595− callHint {
598+ applicationMenus {
596− greeterShown: greeter.shown
599+ hides: [launcher]
597 }
600 }
598
601
599 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
602 readonly property bool focusedSurfaceIsFullscreen: MirFocusController.focusedSurface
@@ -602,6 +605,7 @@ StyledItem {
602 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
605 fullscreenMode: (focusedSurfaceIsFullscreen && !LightDMService.greeter.active && launcher.progress == 0)
603 || greeter.hasLockedApp
606 || greeter.hasLockedApp
604 locked: greeter && greeter.active
607 locked: greeter && greeter.active
608+ greeterShown: greeter && greeter.shown
605 }
609 }
606
610
607 Launcher {
611 Launcher {
qml/Stages/DecoratedWindow.qml+71−32
@@ -17,6 +17,9 @@
17import QtQuick 2.4
17import QtQuick 2.4
18import Ubuntu.Components 1.3
18import Ubuntu.Components 1.3
19import Unity.Application 0.1
19import Unity.Application 0.1
20+import Unity.ApplicationMenu 0.1
21+import Unity.Indicators 0.1 as Indicators
22+import "../Components/PanelState"
20
23
21FocusScope {
24FocusScope {
22 id: root
25 id: root
@@ -91,38 +94,6 @@ FocusScope {
91 visible: !fullscreen
94 visible: !fullscreen
92 }
95 }
93
96
94− WindowDecoration {
95− id: decoration
96− target: root.parent
97− objectName: "appWindowDecoration"
98− anchors { left: parent.left; top: parent.top; right: parent.right }
99− height: units.gu(3)
100− width: root.width
101− title: applicationWindow.title
102− visible: root.decorationShown
103−
104− onCloseClicked: root.closeClicked();
105− onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
106− onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
107− onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
108− onMinimizeClicked: root.minimizeClicked();
109− onPressed: root.decorationPressed();
110−
111− onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
112− onPositionChanged: moveHandler.handlePositionChanged(mouse)
113− onReleased: {
114− root.decorationReleased();
115− moveHandler.handleReleased();
116− }
117− }
118−
119− MoveHandler {
120− id: moveHandler
121− objectName: "moveHandler"
122− target: root.parent
123− buttonsWidth: decoration.buttonsWidth
124− }
125−
126 ApplicationWindow {
97 ApplicationWindow {
127 id: applicationWindow
98 id: applicationWindow
128 objectName: "appWindow"
99 objectName: "appWindow"
@@ -154,4 +125,72 @@ FocusScope {
154 angle: rotationAngle
125 angle: rotationAngle
155 }
126 }
156 }
127 }
128+
129+ MouseArea {
130+ anchors { left: parent.left; top: parent.top; right: parent.right }
131+ height: units.gu(3)
132+
133+ drag.target: Item {}
134+ drag.filterChildren: true
135+ drag.threshold: 0
136+
137+ onPressed: root.decorationPressed();
138+ onPressedChanged: moveHandler.handlePressedChanged(pressed, pressedButtons, mouseX, mouseY)
139+ onPositionChanged: moveHandler.handlePositionChanged(mouse)
140+ onReleased: {
141+ root.decorationReleased();
142+ moveHandler.handleReleased();
143+ }
144+
145+ WindowDecoration {
146+ id: decoration
147+ target: root.parent
148+ objectName: "appWindowDecoration"
149+ anchors.fill: parent
150+ title: applicationWindow.title
151+ visible: root.decorationShown
152+
153+ onCloseClicked: root.closeClicked();
154+ onMaximizeClicked: { root.decorationPressed(); root.maximizeClicked(); }
155+ onMaximizeHorizontallyClicked: { root.decorationPressed(); root.maximizeHorizontallyClicked(); }
156+ onMaximizeVerticallyClicked: { root.decorationPressed(); root.maximizeVerticallyClicked(); }
157+ onMinimizeClicked: root.minimizeClicked();
158+
159+ enableMenus: active &&
160+ (PanelState.focusedPersistentSurfaceId !== surface.persistentId ||
161+ (PanelState.focusedPersistentSurfaceId === surface.persistentId && !PanelState.focusedSurfaceMaximized))
162+ menu: sharedAppModel.model
163+
164+ Indicators.SharedUnityMenuModel {
165+ id: sharedAppModel
166+ property var menus: surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : []
167+ property var menuService: menus.length > 0 ? menus[0] : null
168+
169+ busName: menuService ? menuService.service : ""
170+ menuObjectPath: menuService && menuService.menuPath ? menuService.menuPath : ""
171+ actions: menuService && menuService.actionPath ? { "unity": menuService.actionPath } : {}
172+ }
173+
174+ Connections {
175+ target: ApplicationMenuRegistry
176+ onSurfaceMenuRegistered: {
177+ if (surface && surfaceId === surface.persistentId) {
178+ sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
179+ }
180+ }
181+ onSurfaceMenuUnregistered: {
182+ if (surface && surfaceId === surface.persistentId) {
183+ sharedAppModel.menus = Qt.binding(function() { return surface ? ApplicationMenuRegistry.getMenusForSurface(surface.persistentId) : [] });
184+ }
185+ }
186+ }
187+ }
188+ }
189+
190+ MoveHandler {
191+ id: moveHandler
192+ objectName: "moveHandler"
193+ target: root.parent
194+ buttonsWidth: decoration.buttonsWidth
195+ }
157}
196}
qml/Stages/DesktopStage.qml+19−5
@@ -176,8 +176,8 @@ AbstractStage {
176
176
177 Binding {
177 Binding {
178 target: PanelState
178 target: PanelState
179− property: "buttonsVisible"
179+ property: "decorationsVisible"
180− value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized // FIXME for Locally integrated menus
180+ value: priv.focusedAppDelegate !== null && priv.focusedAppDelegate.maximized
181 && spread.state == ""
181 && spread.state == ""
182 }
182 }
183
183
@@ -185,7 +185,7 @@ AbstractStage {
185 target: PanelState
185 target: PanelState
186 property: "title"
186 property: "title"
187 value: {
187 value: {
188− if (priv.focusedAppDelegate !== null && spread.state == "") {
188+ if (spread.state == "") {
189 if (priv.focusedAppDelegate.maximized)
189 if (priv.focusedAppDelegate.maximized)
190 return priv.focusedAppDelegate.title
190 return priv.focusedAppDelegate.title
191 else
191 else
@@ -196,6 +196,20 @@ AbstractStage {
196 when: priv.focusedAppDelegate
196 when: priv.focusedAppDelegate
197 }
197 }
198
198
199+ Binding {
200+ target: PanelState
201+ property: "focusedPersistentSurfaceId"
202+ value: {
203+ if (priv.focusedAppDelegate !== null && spread.state == "") {
204+ if (priv.focusedAppDelegate.surface) {
205+ return priv.focusedAppDelegate.surface.persistentId;
206+ }
207+ }
208+ return "";
209+ }
210+ when: priv.focusedAppDelegate
211+ }
212+
199 Binding {
213 Binding {
200 target: PanelState
214 target: PanelState
201 property: "dropShadow"
215 property: "dropShadow"
@@ -210,7 +224,7 @@ AbstractStage {
210
224
211 Component.onDestruction: {
225 Component.onDestruction: {
212 PanelState.title = "";
226 PanelState.title = "";
213− PanelState.buttonsVisible = false;
227+ PanelState.decorationsVisible = false;
214 PanelState.dropShadow = false;
228 PanelState.dropShadow = false;
215 }
229 }
216
230
@@ -678,7 +692,7 @@ AbstractStage {
678
692
679 Binding {
693 Binding {
680 target: PanelState
694 target: PanelState
681− property: "buttonsAlwaysVisible"
695+ property: "decorationsAlwaysVisible"
682 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
696 value: appDelegate && appDelegate.maximized && touchControls.overlayShown
683 }
697 }
684
698
qml/Stages/PhoneStage.qml+40−1
@@ -22,6 +22,7 @@ import Unity.Session 0.1
22import Utils 0.1
22import Utils 0.1
23import Powerd 0.1
23import Powerd 0.1
24import "../Components"
24import "../Components"
25+import "../Components/PanelState"
25
26
26AbstractStage {
27AbstractStage {
27 id: root
28 id: root
@@ -57,6 +58,39 @@ AbstractStage {
57 }
58 }
58 }
59 }
59
60
61+ Binding {
62+ target: PanelState
63+ property: "title"
64+ value: {
65+ if (priv.focusedAppDelegate !== null) {
66+ return priv.focusedAppDelegate.title
67+ }
68+ return ""
69+ }
70+ when: priv.focusedAppDelegate
71+ }
72+
73+ Binding {
74+ target: PanelState
75+ property: "focusedPersistentSurfaceId"
76+ value: {
77+ console.log("PLOP", priv.focusedAppDelegatem, priv.focusedAppDelegate.surface)
78+ if (priv.focusedAppDelegate && priv.fullyShowingFocusedApp) {
79+ if (priv.focusedAppDelegate.surface) {
80+ return priv.focusedAppDelegate.surface.persistentId;
81+ }
82+ }
83+ return "";
84+ }
85+ when: priv.focusedAppDelegate
86+ }
87+
88+ Binding {
89+ target: PanelState
90+ property: "decorationsVisible"
91+ value: priv.focusedAppDelegate && priv.fullyShowingFocusedApp
92+ }
93+
60 FocusScope {
94 FocusScope {
61 focus: root.altTabPressed
95 focus: root.altTabPressed
62
96
@@ -168,7 +202,7 @@ AbstractStage {
168
202
169 property bool focusedAppOrientationChangesEnabled: false
203 property bool focusedAppOrientationChangesEnabled: false
170 readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
204 readonly property int firstSpreadIndex: root.focusFirstApp ? 1 : 0
171− property var focusedAppDelegate
205+ property var focusedAppDelegate: null
172 // NB! This may differ from applicationManager.focusedApplicationId if focusedAppDelegate
206 // NB! This may differ from applicationManager.focusedApplicationId if focusedAppDelegate
173 // contains a screenshot instead of a surface.
207 // contains a screenshot instead of a surface.
174 property string focusedAppId: focusedAppDelegate ? focusedAppDelegate.application.appId : ""
208 property string focusedAppId: focusedAppDelegate ? focusedAppDelegate.application.appId : ""
@@ -509,6 +543,11 @@ AbstractStage {
509
543
510 readonly property bool isDash: model.application.appId == "unity8-dash"
544 readonly property bool isDash: model.application.appId == "unity8-dash"
511
545
546+ readonly property string title: {
547+ if (model.surface && model.surface.name !== "") return model.surface.name;
548+ return model.application.name;
549+ }
550+
512 Component.onCompleted: {
551 Component.onCompleted: {
513 // NB: We're differentiating if this delegate was created in response to a new entry in the model
552 // NB: We're differentiating if this delegate was created in response to a new entry in the model
514 // or if the Repeater is just populating itself with delegates to match the model it received.
553 // or if the Repeater is just populating itself with delegates to match the model it received.
qml/Stages/TabletStage.qml+13
@@ -21,6 +21,7 @@ import Unity.Application 0.1
21import Utils 0.1
21import Utils 0.1
22import Powerd 0.1
22import Powerd 0.1
23import "../Components"
23import "../Components"
24+import "../Components/PanelState"
24
25
25AbstractStage {
26AbstractStage {
26 id: root
27 id: root
@@ -311,6 +312,18 @@ AbstractStage {
311 when: root.parent && !spreadRepeater.startingUp
312 when: root.parent && !spreadRepeater.startingUp
312 }
313 }
313
314
315+ Binding {
316+ target: PanelState
317+ property: "title"
318+ value: {
319+ if (priv.focusedAppDelegate !== null) {
320+ return priv.focusedAppDelegate.title
321+ }
322+ return ""
323+ }
324+ when: priv.focusedAppDelegate
325+ }
326+
314 Flickable {
327 Flickable {
315 id: spreadView
328 id: spreadView
316 objectName: "spreadView"
329 objectName: "spreadView"
qml/Stages/WindowDecoration.qml+78−19
@@ -15,18 +15,23 @@
15 */
15 */
16
16
17import QtQuick 2.4
17import QtQuick 2.4
18+import QtQuick.Layouts 1.1
18import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20+import Unity.Application 0.1
19import "../Components"
21import "../Components"
22+import "../Components/PanelState"
23+import "../ApplicationMenus"
20
24
21MouseArea {
25MouseArea {
22 id: root
26 id: root
23− clip: true
24
27
25 property Item target // appDelegate
28 property Item target // appDelegate
26 property alias title: titleLabel.text
29 property alias title: titleLabel.text
27 property alias maximizeButtonShown: buttons.maximizeButtonShown
30 property alias maximizeButtonShown: buttons.maximizeButtonShown
28 property bool active: false
31 property bool active: false
29 property alias overlayShown: buttons.overlayShown
32 property alias overlayShown: buttons.overlayShown
33+ property var menu: undefined
34+ property bool enableMenus: true
30
35
31 readonly property real buttonsWidth: buttons.width + row.spacing
36 readonly property real buttonsWidth: buttons.width + row.spacing
32
37
@@ -48,21 +53,41 @@ MouseArea {
48 // do not let unhandled wheel event pass thru the decoration
53 // do not let unhandled wheel event pass thru the decoration
49 onWheel: wheel.accepted = true;
54 onWheel: wheel.accepted = true;
50
55
56+ QtObject {
57+ id: priv
58+ property var menuBar: menuBarLoader.item
59+
60+ property bool enableMenus: root.enableMenus &&
61+ menuBar &&
62+ menuBar.valid
63+
64+ property bool shouldShowMenus : enableMenus &&
65+ (menuBar.showRequested || root.containsMouse)
66+ }
67+
51 Rectangle {
68 Rectangle {
69+ id: background
52 anchors.fill: parent
70 anchors.fill: parent
53− anchors.bottomMargin: -radius
54 radius: units.gu(.5)
71 radius: units.gu(.5)
55 color: theme.palette.normal.background
72 color: theme.palette.normal.background
56 }
73 }
57
74
58− Row {
75+ Rectangle {
76+ anchors {
77+ bottom: background.bottom
78+ left: parent.left
79+ right: parent.right
80+ }
81+ height: background.radius
82+ color: theme.palette.normal.background
83+ }
84+
85+ RowLayout {
59 id: row
86 id: row
60 anchors {
87 anchors {
61 fill: parent
88 fill: parent
62 leftMargin: overlayShown ? units.gu(5) : units.gu(1)
89 leftMargin: overlayShown ? units.gu(5) : units.gu(1)
63 rightMargin: units.gu(1)
90 rightMargin: units.gu(1)
64− topMargin: units.gu(0.5)
65− bottomMargin: units.gu(0.5)
66 }
91 }
67 Behavior on anchors.leftMargin {
92 Behavior on anchors.leftMargin {
68 UbuntuNumberAnimation {}
93 UbuntuNumberAnimation {}
@@ -72,7 +97,12 @@ MouseArea {
72
97
73 WindowControlButtons {
98 WindowControlButtons {
74 id: buttons
99 id: buttons
100+ anchors {
75− height: parent.height
101+ top: parent.top
102+ bottom: parent.bottom
103+ topMargin: units.gu(0.5)
104+ bottomMargin: units.gu(0.5)
105+ }
76 active: root.active
106 active: root.active
77 onCloseClicked: root.closeClicked();
107 onCloseClicked: root.closeClicked();
78 onMinimizeClicked: root.minimizeClicked();
108 onMinimizeClicked: root.minimizeClicked();
@@ -82,19 +112,48 @@ MouseArea {
82 closeButtonShown: root.target.application.appId !== "unity8-dash"
112 closeButtonShown: root.target.application.appId !== "unity8-dash"
83 }
113 }
84
114
115+ Item {
116+ Layout.preferredHeight: parent.height
117+ Layout.fillWidth: true
118+
85− Label {
119+ Label {
86− id: titleLabel
120+ id: titleLabel
87− objectName: "windowDecorationTitle"
121+ objectName: "windowDecorationTitle"
88− color: root.active ? "white" : UbuntuColors.slate
122+ color: root.active ? "white" : UbuntuColors.slate
89− height: parent.height
123+ height: parent.height
90− width: parent.width - buttons.width - parent.anchors.rightMargin - parent.anchors.leftMargin
124+ width: parent.width
91− verticalAlignment: Text.AlignVCenter
125+ verticalAlignment: Text.AlignVCenter
92− fontSize: "medium"
126+ fontSize: "medium"
93− font.weight: root.active ? Font.Light : Font.Medium
127+ font.weight: root.active ? Font.Light : Font.Medium
94− elide: Text.ElideRight
128+ elide: Text.ElideRight
95− opacity: overlayShown ? 0 : 1
129+ opacity: overlayShown || priv.shouldShowMenus ? 0 : 1
96− visible: opacity != 0
130+ visible: opacity != 0
131+ Behavior on opacity { UbuntuNumberAnimation {} }
132+ }
133+
134+ Loader {
135+ id: menuBarLoader
136+ objectName: "menuBarLoader"
137+ anchors.bottom: parent.bottom
138+ height: parent.height
139+ width: parent.width
140+ sourceComponent: root.menu ? menuBarComponent : undefined
141+
142+ Component {
143+ id: menuBarComponent
144+ MenuBarLoader {
145+ id: menuBar
146+ height: menuBarLoader.height
147+ enableKeyFilter: priv.enableMenus
148+ unityMenuModel: root.menu
149+ }
150+ }
151+
152+ opacity: !overlayShown && priv.shouldShowMenus ? 1 : 0
153+ visible: opacity == 1
97− Behavior on opacity { UbuntuNumberAnimation {} }
154+ Behavior on opacity { UbuntuNumberAnimation {} }
155+ }
98 }
156 }
99 }
157 }
158+
100}
159}
src/main.cpp+2−2
@@ -23,8 +23,8 @@ int main(int argc, const char *argv[])
23{
23{
24 qSetMessagePattern("[%{time yyyy-MM-dd:hh:mm:ss.zzz}] %{if-category}%{category}: %{endif}%{message}");
24 qSetMessagePattern("[%{time yyyy-MM-dd:hh:mm:ss.zzz}] %{if-category}%{category}: %{endif}%{message}");
25
25
26− bool isMirServer = false;
26+ bool isMirServer = qgetenv("QT_QPA_PLATFORM") == "mirserver";
27− if (qgetenv("QT_QPA_PLATFORM") == "ubuntumirclient") {
27+ if (!isMirServer && qgetenv("QT_QPA_PLATFORM") == "ubuntumirclient") {
28 setenv("QT_QPA_PLATFORM", "mirserver", 1 /* overwrite */);
28 setenv("QT_QPA_PLATFORM", "mirserver", 1 /* overwrite */);
29 isMirServer = true;
29 isMirServer = true;
30 }
30 }
tests/mocks/QMenuModel/unitymenumodel.cpp+47−6
@@ -29,7 +29,9 @@ enum MenuRoles {
29 ActionStateRole,
29 ActionStateRole,
30 IsCheckRole,
30 IsCheckRole,
31 IsRadioRole,
31 IsRadioRole,
32− IsToggledRole
32+ IsToggledRole,
33+ ShortcutRole,
34+ HasSubmenuRole
33};
35};
34
36
35UnityMenuModel::UnityMenuModel(QObject *parent)
37UnityMenuModel::UnityMenuModel(QObject *parent)
@@ -141,7 +143,29 @@ int UnityMenuModel::columnCount(const QModelIndex&) const
141
143
142QVariant UnityMenuModel::data(const QModelIndex &index, int role) const
144QVariant UnityMenuModel::data(const QModelIndex &index, int role) const
143{
145{
144− return rowData(index.row())[roleNames()[role]];
146+ QVariantMap v = rowData(index.row());
147+ QString roleName = roleNames()[role];
148+
149+ if (v.contains(roleName)) return v[roleName];
150+
151+ // defaults
152+ switch (role) {
153+ case LabelRole: return QString();
154+ case SensitiveRole: return true;
155+ case IsSeparatorRole: return false;
156+ case IconRole: return QString();
157+ case TypeRole: return QString();
158+ case ExtendedAttributesRole: return QVariantMap();
159+ case ActionRole: return QString();
160+ case ActionStateRole: return QVariant();
161+ case IsCheckRole: return false;
162+ case IsRadioRole: return false;
163+ case IsToggledRole: return false;
164+ case ShortcutRole: return QString();
165+ case HasSubmenuRole: return subMenuData(index.row()).isValid();
166+ default: break;
167+ }
168+ return QVariant();
145}
169}
146
170
147QVariantMap UnityMenuModel::rowData(int row) const
171QVariantMap UnityMenuModel::rowData(int row) const
@@ -149,12 +173,14 @@ QVariantMap UnityMenuModel::rowData(int row) const
149 if (m_modelData.count() <= row) {
173 if (m_modelData.count() <= row) {
150 return QVariantMap();
174 return QVariantMap();
151 }
175 }
152− return m_modelData[row].toMap()["rowData"].toMap();
176+ QVariantMap vRow = m_modelData.value(row, QVariantMap()).toMap();
177+ return vRow["rowData"].toMap();
153}
178}
154
179
155QVariant UnityMenuModel::subMenuData(int row) const
180QVariant UnityMenuModel::subMenuData(int row) const
156{
181{
157− return m_modelData[row].toMap()["submenu"];
182+ QVariantMap v = m_modelData.value(row, QVariantMap()).toMap();
183+ return v.value("submenu", QVariant());
158}
184}
159
185
160QModelIndex UnityMenuModel::index(int row, int column, const QModelIndex&) const
186QModelIndex UnityMenuModel::index(int row, int column, const QModelIndex&) const
@@ -182,6 +208,8 @@ QHash<int, QByteArray> UnityMenuModel::roleNames() const
182 names[IsCheckRole] = "isCheck";
208 names[IsCheckRole] = "isCheck";
183 names[IsRadioRole] = "isRadio";
209 names[IsRadioRole] = "isRadio";
184 names[IsToggledRole] = "isToggled";
210 names[IsToggledRole] = "isToggled";
211+ names[ShortcutRole] = "shortcut";
212+ names[HasSubmenuRole] = "hasSubmenu";
185
213
186 return names;
214 return names;
187}
215}
@@ -201,6 +229,7 @@ QObject * UnityMenuModel::submenu(int position, QQmlComponent*)
201 UnityMenuModel*& model = submenus[position];
229 UnityMenuModel*& model = submenus[position];
202 if (!model) {
230 if (!model) {
203 model = new UnityMenuModel(this);
231 model = new UnityMenuModel(this);
232+ connect(model, &UnityMenuModel::activated, this, &UnityMenuModel::activated);
204 }
233 }
205 if (model->modelData() != submenuData) {
234 if (model->modelData() != submenuData) {
206 model->setModelData(submenuData);
235 model->setModelData(submenuData);
@@ -225,11 +254,23 @@ QVariant UnityMenuModel::get(int row, const QByteArray &role)
225 roles.insert(names[role], role);
254 roles.insert(names[role], role);
226 }
255 }
227
256
228− return this->data(this->index(row, 0), roles[role]);
257+ return data(index(row, 0), roles[role]);
229}
258}
230
259
231−void UnityMenuModel::activate(int, const QVariant&)
260+void UnityMenuModel::activate(int row, const QVariant&)
232{
261{
262+ QVariantMap vModelData = m_modelData.value(row, QVariantMap()).toMap();
263+ QVariantMap rd = vModelData["rowData"].toMap();
264+
265+ bool isCheckable = rd[roleNames()[IsCheckRole]].toBool() || rd[roleNames()[IsRadioRole]].toBool();
266+ if (isCheckable) {
267+ rd[roleNames()[IsToggledRole]] = !rd[roleNames()[IsToggledRole]].toBool();
268+ vModelData["rowData"] = rd;
269+ m_modelData[row] = vModelData;
270+
271+ dataChanged(index(row, 0), index(row, 0), QVector<int>() << IsToggledRole);
272+ }
273+ Q_EMIT activated(rd[roleNames()[ActionRole]].toString());
233}
274}
234
275
235void UnityMenuModel::changeState(int, const QVariant&)
276void UnityMenuModel::changeState(int, const QVariant&)
tests/mocks/QMenuModel/unitymenumodel.h+3−1
@@ -61,7 +61,7 @@ public:
61
61
62 QString nameOwner() const;
62 QString nameOwner() const;
63
63
64− int rowCount(const QModelIndex &parent = QModelIndex()) const override;
64+ Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override;
65 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
65 int columnCount(const QModelIndex &parent = QModelIndex()) const override;
66 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
66 QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
67 QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
67 QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
@@ -88,6 +88,8 @@ Q_SIGNALS:
88 // Internal mock usage
88 // Internal mock usage
89 void modelDataChanged();
89 void modelDataChanged();
90
90
91+ void activated(const QString& action);
92+
91private:
93private:
92 QVariantMap rowData(int row) const;
94 QVariantMap rowData(int row) const;
93 QVariant subMenuData(int row) const;
95 QVariant subMenuData(int row) const;
tests/qmltests/CMakeLists.txt+4
@@ -6,6 +6,8 @@ add_unity8_qmltest(. DisabledScreenNotice)
6add_unity8_qmltest(. Shell)
6add_unity8_qmltest(. Shell)
7add_unity8_qmltest(. ShellWithPin)
7add_unity8_qmltest(. ShellWithPin)
8add_unity8_qmltest(. DeviceConfiguration)
8add_unity8_qmltest(. DeviceConfiguration)
9+add_unity8_qmltest(ApplicationMenus MenuBar)
10+add_unity8_qmltest(ApplicationMenus MenuPage)
9add_unity8_qmltest(Components Background)
11add_unity8_qmltest(Components Background)
10add_unity8_qmltest(Components Carousel)
12add_unity8_qmltest(Components Carousel)
11add_unity8_qmltest(Components Dialogs)
13add_unity8_qmltest(Components Dialogs)
@@ -87,12 +89,14 @@ add_unity8_qmltest(Panel/Indicators IndicatorsLight)
87add_unity8_qmltest(Panel/Indicators MenuItemFactory)
89add_unity8_qmltest(Panel/Indicators MenuItemFactory)
88add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
90add_unity8_qmltest(Panel/Indicators MessageMenuItemFactory)
89add_unity8_qmltest(Stages ApplicationWindow)
91add_unity8_qmltest(Stages ApplicationWindow)
92+add_unity8_qmltest(Stages DecoratedWindow)
90add_unity8_qmltest(Stages DesktopStage)
93add_unity8_qmltest(Stages DesktopStage)
91add_unity8_qmltest(Stages PhoneStage)
94add_unity8_qmltest(Stages PhoneStage)
92add_unity8_qmltest(Stages SpreadDelegate)
95add_unity8_qmltest(Stages SpreadDelegate)
93add_unity8_qmltest(Stages SurfaceContainer)
96add_unity8_qmltest(Stages SurfaceContainer)
94add_unity8_qmltest(Stages TabletStage)
97add_unity8_qmltest(Stages TabletStage)
95add_unity8_qmltest(Stages WindowResizeArea)
98add_unity8_qmltest(Stages WindowResizeArea)
99+add_unity8_qmltest(Stages WindowDecoration)
96add_unity8_qmltest(Stages Splash)
100add_unity8_qmltest(Stages Splash)
97add_unity8_qmltest(Tutorial Tutorial)
101add_unity8_qmltest(Tutorial Tutorial)
98add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
102add_unity8_qmltest(Wizard Wizard ENVIRONMENT "OXIDE_NO_SANDBOX=1")
tests/qmltests/Panel/tst_Panel.qml+76−19
@@ -19,26 +19,42 @@ import QtQuick.Layouts 1.1
19import QtTest 1.0
19import QtTest 1.0
20import Unity.Test 0.1
20import Unity.Test 0.1
21import Ubuntu.Components 1.3
21import Ubuntu.Components 1.3
22+import Ubuntu.Components.ListItems 1.3 as ListItem
22import Unity.Application 0.1
23import Unity.Application 0.1
24+import Unity.ApplicationMenu 0.1
23import Unity.Indicators 0.1 as Indicators
25import Unity.Indicators 0.1 as Indicators
24import Ubuntu.Telephony 0.1 as Telephony
26import Ubuntu.Telephony 0.1 as Telephony
25import "../../../qml/Panel"
27import "../../../qml/Panel"
26import "../../../qml/Components/PanelState"
28import "../../../qml/Components/PanelState"
29+import "../Stages"
27
30
28IndicatorTest {
31IndicatorTest {
29 id: root
32 id: root
30− width: units.gu(100)
33+ width: units.gu(120)
31 height: units.gu(71)
34 height: units.gu(71)
32 color: "black"
35 color: "black"
33
36
34− Component.onCompleted: theme.name = "Ubuntu.Components.Themes.SuruDark"
35−
36 Binding {
37 Binding {
37 target: mouseEmulation
38 target: mouseEmulation
38 property: "checked"
39 property: "checked"
39 value: !windowControlsCB.checked
40 value: !windowControlsCB.checked
40 }
41 }
41
42
43+ DesktopMenuData { id: appMenuData }
44+
45+ Component.onCompleted: {
46+ QuickUtils.keyboardAttached = true;
47+ theme.name = "Ubuntu.Components.Themes.SuruDark"
48+
49+ ApplicationMenuRegistry.RegisterSurfaceMenu("dialerAppSurfaceId", "/dialerapp", "/dialerapp", ":2");
50+ Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
51+ }
52+
53+ Rectangle {
54+ anchors.fill: parent
55+ color: "darkgrey"
56+ }
57+
42 RowLayout {
58 RowLayout {
43 anchors.fill: parent
59 anchors.fill: parent
44 anchors.margins: units.gu(1)
60 anchors.margins: units.gu(1)
@@ -59,12 +75,28 @@ IndicatorTest {
59 Panel {
75 Panel {
60 id: panel
76 id: panel
61 anchors.fill: parent
77 anchors.fill: parent
78+ mode: "staged"
79+
80+ indicatorMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
81+ applicationMenuWidth: parent.width > units.gu(60) ? units.gu(40) : parent.width
82+
83+ applicationMenus {
84+ model: sharedAppModel.model
85+ hides: [ panel.indicators ]
86+ }
87+
62 indicators {
88 indicators {
63− width: parent.width > units.gu(60) ? units.gu(40) : parent.width
64− indicatorsModel: root.indicatorsModel
89+ model: root.indicatorsModel
90+ hides: [ panel.applicationMenus ]
65 }
91 }
66
92
67− property real panelAndSeparatorHeight: panel.indicators.minimizedPanelHeight
93+ Indicators.SharedUnityMenuModel {
94+ id: sharedAppModel
95+
96+ busName: ":2"
97+ menuObjectPath: "/dialerapp"
98+ actions: { "unity": "/dialerapp" }
99+ }
68 }
100 }
69 }
101 }
70 }
102 }
@@ -73,6 +105,16 @@ IndicatorTest {
73 Layout.alignment: Qt.AlignTop
105 Layout.alignment: Qt.AlignTop
74 Layout.fillWidth: false
106 Layout.fillWidth: false
75
107
108+ ListItem.ItemSelector {
109+ anchors { left: parent.left; right: parent.right }
110+ activeFocusOnPress: false
111+ text: "Mode"
112+ model: ["staged", "windowed" ]
113+ onSelectedIndexChanged: {
114+ panel.mode = model[selectedIndex];
115+ }
116+ }
117+
76 Button {
118 Button {
77 Layout.fillWidth: true
119 Layout.fillWidth: true
78 text: panel.indicators.shown ? "Hide" : "Show"
120 text: panel.indicators.shown ? "Hide" : "Show"
@@ -107,25 +149,22 @@ IndicatorTest {
107 Layout.fillWidth: true
149 Layout.fillWidth: true
108 CheckBox {
150 CheckBox {
109 id: windowControlsCB
151 id: windowControlsCB
110− onClicked: PanelState.buttonsVisible = checked
152+ onClicked: PanelState.decorationsVisible = checked
111 }
153 }
112 Label {
154 Label {
113− text: "Show window controls"
155+ text: "Show window decorations"
156+ color: "white"
114 }
157 }
115 }
158 }
116
159
117 RowLayout {
160 RowLayout {
118 Layout.fillWidth: true
161 Layout.fillWidth: true
119 CheckBox {
162 CheckBox {
120− onClicked: {
163+ onClicked: PanelState.title = checked ? "Fake window title" : ""
121− if (checked)
122− PanelState.title = "Fake window title"
123− else
124− PanelState.title = ""
125− }
126 }
164 }
127 Label {
165 Label {
128 text: "Show fake window title"
166 text: "Show fake window title"
167+ color: "white"
129 }
168 }
130 }
169 }
131
170
@@ -135,6 +174,19 @@ IndicatorTest {
135 color: "black"
174 color: "black"
136 }
175 }
137
176
177+ ApplicationCheckBox {
178+ id: applicationCheckBox
179+ Layout.fillWidth: true
180+ appId: "dialer-app"
181+ onCheckedChanged: PanelState.focusedPersistentSurfaceId = checked ? "dialer-app" : "";
182+ }
183+
184+ Rectangle {
185+ Layout.preferredHeight: units.dp(1);
186+ Layout.fillWidth: true;
187+ color: "black"
188+ }
189+
138 Repeater {
190 Repeater {
139 model: root.originalModelData
191 model: root.originalModelData
140 RowLayout {
192 RowLayout {
@@ -145,6 +197,7 @@ IndicatorTest {
145 Label {
197 Label {
146 Layout.fillWidth: true
198 Layout.fillWidth: true
147 text: modelData["identifier"]
199 text: modelData["identifier"]
200+ color: "white"
148 }
201 }
149
202
150 CheckBox {
203 CheckBox {
@@ -153,6 +206,7 @@ IndicatorTest {
153 }
206 }
154 Label {
207 Label {
155 text: "visible"
208 text: "visible"
209+ color: "white"
156 }
210 }
157 }
211 }
158 }
212 }
@@ -163,7 +217,10 @@ IndicatorTest {
163 color: "black"
217 color: "black"
164 }
218 }
165
219
166− MouseTouchEmulationCheckbox { id: mouseEmulation }
220+ MouseTouchEmulationCheckbox {
221+ id: mouseEmulation
222+ color: "white"
223+ }
167 }
224 }
168 }
225 }
169
226
@@ -229,11 +286,11 @@ IndicatorTest {
229 { tag: "pinned", fullscreen: false, call: null,
286 { tag: "pinned", fullscreen: false, call: null,
230 indicatorY: 0 },
287 indicatorY: 0 },
231 { tag: "fullscreen", fullscreen: true, call: null,
288 { tag: "fullscreen", fullscreen: true, call: null,
232− indicatorY: -panel.panelAndSeparatorHeight },
289+ indicatorY: -panel.indicators.minimizedPanelHeight },
233 { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
290 { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
234 indicatorY: 0},
291 indicatorY: 0},
235 { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
292 { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
236− indicatorY: -panel.panelAndSeparatorHeight }
293+ indicatorY: -panel.indicators.minimizedPanelHeight }
237 ];
294 ];
238 }
295 }
239
296
@@ -291,11 +348,11 @@ IndicatorTest {
291 { tag: "pinned", fullscreen: false, call: null,
348 { tag: "pinned", fullscreen: false, call: null,
292 indicatorY: 0 },
349 indicatorY: 0 },
293 { tag: "fullscreen", fullscreen: true, call: null,
350 { tag: "fullscreen", fullscreen: true, call: null,
294− indicatorY: -panel.panelAndSeparatorHeight },
351+ indicatorY: -panel.indicators.minimizedPanelHeight },
295 { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
352 { tag: "pinned-callActive", fullscreen: false, call: phoneCall,
296 indicatorY: 0},
353 indicatorY: 0},
297 { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
354 { tag: "fullscreen-callActive", fullscreen: true, call: phoneCall,
298− indicatorY: -panel.panelAndSeparatorHeight }
355+ indicatorY: -panel.indicators.minimizedPanelHeight }
299 ];
356 ];
300 }
357 }
301
358
tests/qmltests/Stages/tst_DesktopStage.qml+16
@@ -19,6 +19,8 @@ import QtTest 1.0
19import Ubuntu.Components 1.3
19import Ubuntu.Components 1.3
20import Ubuntu.Components.ListItems 1.3
20import Ubuntu.Components.ListItems 1.3
21import Unity.Application 0.1
21import Unity.Application 0.1
22+import Unity.ApplicationMenu 0.1
23+import Unity.Indicators 0.1 as Indicators
22import Unity.Test 0.1
24import Unity.Test 0.1
23import WindowManager 0.1
25import WindowManager 0.1
24import Utils 0.1
26import Utils 0.1
@@ -41,9 +43,23 @@ Item {
41 value: false
43 value: false
42 }
44 }
43
45
46+ DesktopMenuData {
47+ id: appMenuData
48+ }
49+
44 Component.onCompleted: {
50 Component.onCompleted: {
51+ QuickUtils.keyboardAttached = true;
45 theme.name = "Ubuntu.Components.Themes.SuruDark";
52 theme.name = "Ubuntu.Components.Themes.SuruDark";
46 resetGeometry();
53 resetGeometry();
54+
55+ ApplicationMenuRegistry.RegisterSurfaceMenu("DialerId", "/dialerapp", "/dialerapp", ":0");
56+ Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
57+
58+ ApplicationMenuRegistry.RegisterSurfaceMenu("CameraId", "/cameraapp", "/cameraapp", ":1");
59+ Indicators.UnityMenuModelCache.setCachedModelData("/cameraapp", appMenuData.cameraData);
60+
61+ ApplicationMenuRegistry.RegisterSurfaceMenu("GalleryId", "/galleryapp", "/galleryapp", ":2");
62+ Indicators.UnityMenuModelCache.setCachedModelData("/galleryapp", appMenuData.galleryData);
47 }
63 }
48
64
49 function resetGeometry() {
65 function resetGeometry() {
tests/qmltests/tst_Shell.qml+19−4
@@ -24,6 +24,7 @@ import Ubuntu.Components 1.3
24import Ubuntu.Components.ListItems 1.3 as ListItem
24import Ubuntu.Components.ListItems 1.3 as ListItem
25import Ubuntu.Telephony 0.1 as Telephony
25import Ubuntu.Telephony 0.1 as Telephony
26import Unity.Application 0.1
26import Unity.Application 0.1
27+import Unity.ApplicationMenu 0.1
27import Unity.Connectivity 0.1
28import Unity.Connectivity 0.1
28import Unity.Indicators 0.1
29import Unity.Indicators 0.1
29import Unity.Notifications 1.0
30import Unity.Notifications 1.0
@@ -32,6 +33,7 @@ import Unity.Test 0.1
32import Powerd 0.1
33import Powerd 0.1
33import Wizard 0.1 as Wizard
34import Wizard 0.1 as Wizard
34import Utils 0.1
35import Utils 0.1
36+import Unity.Indicators 0.1 as Indicators
35
37
36import "../../qml"
38import "../../qml"
37import "../../qml/Components"
39import "../../qml/Components"
@@ -49,6 +51,19 @@ Rectangle {
49 LightDM.Greeter.mockMode = "single";
51 LightDM.Greeter.mockMode = "single";
50 LightDM.Users.mockMode = "single";
52 LightDM.Users.mockMode = "single";
51 shellLoader.active = true;
53 shellLoader.active = true;
54+
55+ ApplicationMenuRegistry.RegisterSurfaceMenu("DialerId", "/dialerapp", "/dialerapp", ":0");
56+ Indicators.UnityMenuModelCache.setCachedModelData("/dialerapp", appMenuData.dialerData);
57+
58+ ApplicationMenuRegistry.RegisterSurfaceMenu("CameraId", "/cameraapp", "/cameraapp", ":1");
59+ Indicators.UnityMenuModelCache.setCachedModelData("/cameraapp", appMenuData.cameraData);
60+
61+ ApplicationMenuRegistry.RegisterSurfaceMenu("GalleryId", "/galleryapp", "/galleryapp", ":2");
62+ Indicators.UnityMenuModelCache.setCachedModelData("/galleryapp", appMenuData.galleryData);
63+ }
64+
65+ DesktopMenuData {
66+ id: appMenuData
52 }
67 }
53
68
54 Item {
69 Item {
@@ -1997,21 +2012,21 @@ Rectangle {
1997 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
2012 var maximizeButton = findChild(appDelegate, "maximizeWindowButton");
1998
2013
1999 tryCompare(appDelegate, "state", "normal");
2014 tryCompare(appDelegate, "state", "normal");
2000− tryCompare(PanelState, "buttonsVisible", false)
2015+ tryCompare(PanelState, "decorationsVisible", false)
2001
2016
2002 mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
2017 mouseClick(maximizeButton, maximizeButton.width / 2, maximizeButton.height / 2);
2003 tryCompare(appDelegate, "state", "maximized");
2018 tryCompare(appDelegate, "state", "maximized");
2004− tryCompare(PanelState, "buttonsVisible", true)
2019+ tryCompare(PanelState, "decorationsVisible", true)
2005
2020
2006 ApplicationManager.stopApplication(application.appId);
2021 ApplicationManager.stopApplication(application.appId);
2007− tryCompare(PanelState, "buttonsVisible", false)
2022+ tryCompare(PanelState, "decorationsVisible", false)
2008
2023
2009 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
2024 // wait until all zombie surfaces are gone. As MirSurfaceItems hold references over them.
2010 // They won't be gone until those surface items are destroyed.
2025 // They won't be gone until those surface items are destroyed.
2011 tryCompareFunction(function() { return application.surfaceList.count }, 0);
2026 tryCompareFunction(function() { return application.surfaceList.count }, 0);
2012
2027
2013 ApplicationManager.startApplication(application.appId);
2028 ApplicationManager.startApplication(application.appId);
2014− tryCompare(PanelState, "buttonsVisible", true)
2029+ tryCompare(PanelState, "decorationsVisible", true)
2015 }
2030 }
2016
2031
2017 function test_newAppHasValidGeometry() {
2032 function test_newAppHasValidGeometry() {