@@ -44,6 +44,10 @@ UbuntuShape {
44 d.select(index)
44 d.select(index)
48+ d.currentItem = null;
47 function dismiss() {
51 function dismiss() {
48 d.dismissAll()
52 d.dismissAll()
@@ -51,37 +55,26 @@ UbuntuShape {
51 implicitWidth: container.width
55 implicitWidth: container.width
52 implicitHeight: MathUtils.clamp(listView.contentHeight, __ajustedMinimumHeight, __maximumHeight)
56 implicitHeight: MathUtils.clamp(listView.contentHeight, __ajustedMinimumHeight, __maximumHeight)
56− Keys.onUpPressed: d.selectPrevious(d.currentIndex)
57− Keys.onDownPressed: d.selectNext(d.currentIndex)
58− Keys.onRightPressed: {
59− // Don't let right keypresses fall through if the current item has a visible popup.
60− if (!d.currentItem || !d.currentItem.popup || !d.currentItem.popup.visible) {
61− event.accepted = false;
65 onVisibleChanged: {
58 onVisibleChanged: {
66 if (!visible) {
59 if (!visible) {
67 d.currentItem = null;
60 d.currentItem = null;
71− QtObject {
64+ MenuNavigator {
73 objectName: "d"
66 objectName: "d"
75 property Item currentItem: null
69 property Item currentItem: null
76 property Item hoveredItem: null
70 property Item hoveredItem: null
77 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
71 readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
79− signal select(int index)
80 signal dismissAll()
73 signal dismissAll()
82 onCurrentItemChanged: {
75 onCurrentItemChanged: {
83 if (currentItem) {
76 if (currentItem) {
84− currentItem.forceActiveFocus();
77+ currentItem.item.forceActiveFocus();
86 hoveredItem = null;
79 hoveredItem = null;
@@ -90,314 +83,272 @@ UbuntuShape {
90 onSelect: {
83 onSelect: {
91 currentItem = listView.itemAt(index);
84 currentItem = listView.itemAt(index);
93+ Keys.onUpPressed: d.selectPrevious(d.currentIndex)
94− function selectNext(currentIndex) {
94+ Keys.onDownPressed: d.selectNext(d.currentIndex)
95− var menu;
95+ Keys.onRightPressed: {
96− var newIndex = 0;
96+ // Don't let right keypresses fall through if the current item has a visible popup.
97− if (currentIndex === -1 && listView.count > 0) {
97+ if (!d.currentItem || !d.currentItem.popup || !d.currentItem.popup.visible) {
98− while (listView.count > newIndex) {
98+ event.accepted = false;
99− menu = listView.itemAt(newIndex);
100− if (!!menu["enabled"]) {
106− } else if (currentIndex !== -1 && listView.count > 1) {
107− var startIndex = (currentIndex + 1) % listView.count;
108− newIndex = startIndex;
110− menu = listView.itemAt(newIndex);
111− if (!!menu["enabled"]) {
115− newIndex = (newIndex + 1) % listView.count;
116− } while (newIndex !== startIndex)
120− function selectPrevious(currentIndex) {
102+ ColumnLayout {
121− var menu;
103+ id: container
122− var newIndex = listView.count-1;
104+ objectName: "container"
123− if (currentIndex === -1 && listView.count > 0) {
105+
124− while (listView.count > newIndex) {
106+ width: listView.contentWidth
125− menu = listView.itemAt(newIndex);
107+ height: parent.height
126− if (!!menu["enabled"]) {
108+ spacing: 0
127− select(newIndex);
109+
128− break;
110+ // FIXME use ListView.header - tried but was flaky with positionViewAtIndex.
112+ Layout.fillWidth: true;
113+ Layout.maximumHeight: units.gu(3)
114+ Layout.minimumHeight: units.gu(3)
115+ visible: listView.contentHeight > root.height
116+ enabled: !listView.atYBeginning
119+ color: enabled ? theme.palette.normal.overlayText :
120+ theme.palette.disabled.overlayText
123+ bottom: parent.bottom
132− } else if (currentIndex !== -1 && listView.count > 1) {
133− var startIndex = currentIndex - 1;
134− newIndex = startIndex;
137− newIndex = listView.count - 1;
139− menu = listView.itemAt(newIndex);
140− if (!!menu["enabled"]) {
145− } while (newIndex !== startIndex)
150− ColumnLayout {
129+ Icon {
151− id: container
130+ anchors.centerIn: parent
152− objectName: "container"
131+ width: units.gu(2)
153−
132+ height: units.gu(2)
154− width: listView.contentWidth
133+ name: "up"
155− height: parent.height
158− // FIXME use ListView.header - tried but was flaky with positionViewAtIndex.
160− Layout.fillWidth: true;
161− Layout.maximumHeight: units.gu(3)
162− Layout.minimumHeight: units.gu(3)
163− visible: listView.contentHeight > root.height
164− enabled: !listView.atYBeginning
167− color: enabled ? theme.palette.normal.overlayText :
134+ color: enabled ? theme.palette.normal.overlayText :
168− theme.palette.disabled.overlayText
135+ theme.palette.disabled.overlayText
171− bottom: parent.bottom
178− anchors.centerIn: parent
182− color: enabled ? theme.palette.normal.overlayText :
183− theme.palette.disabled.overlayText
186− MouseArea {
138+ MouseArea {
187− anchors.fill: parent
139+ anchors.fill: parent
188− onPressed: {
140+ onPressed: {
189− var index = listView.indexAt(0, listView.contentY);
141+ var index = listView.indexAt(0, listView.contentY);
190− listView.positionViewAtIndex(index-1, ListView.Beginning);
142+ listView.positionViewAtIndex(index-1, ListView.Beginning);
195− ListView {
147+ ListView {
196− id: listView
148+ id: listView
197− objectName: "listView"
149+ objectName: "listView"
198− Layout.fillHeight: true
150+ Layout.fillHeight: true
199− Layout.fillWidth: true
151+ Layout.fillWidth: true
200− contentWidth: MathUtils.clamp(contentItem.childrenRect.width,
152+ contentWidth: MathUtils.clamp(contentItem.childrenRect.width,
201− __minimumWidth,
153+ __minimumWidth,
202− __maximumWidth)
154+ __maximumWidth)
204− orientation: Qt.Vertical
156+ orientation: Qt.Vertical
205− interactive: contentHeight > height
157+ interactive: contentHeight > height
206− clip: interactive
158+ clip: interactive
207− highlightFollowsCurrentItem: false
159+ highlightFollowsCurrentItem: false
209− highlight: Rectangle {
161+ highlight: Rectangle {
210− color: "transparent"
162+ color: "transparent"
211− border.width: units.dp(1)
163+ border.width: units.dp(1)
212− border.color: UbuntuColors.orange
164+ border.color: UbuntuColors.orange
215− width: listView.width
167+ width: listView.width
216− height: d.currentItem ? d.currentItem.height : 0
168+ height: d.currentItem ? d.currentItem.height : 0
217− y: d.currentItem ? d.currentItem.y : 0
169+ y: d.currentItem ? d.currentItem.y : 0
218− visible: d.currentItem
170+ visible: d.currentItem
221− function itemAt(index) {
173+ function itemAt(index) {
222− if (index > count || index < 0) return null;
174+ if (index > count || index < 0) return null;
223− currentIndex = index;
175+ currentIndex = index;
224− return currentItem;
176+ return currentItem;
227− MouseArea {
179+ MouseArea {
228− id: menuMouseArea
180+ id: menuMouseArea
229− anchors.fill: parent
181+ anchors.fill: parent
230− hoverEnabled: true
182+ hoverEnabled: true
233− onPositionChanged: updateCurrentItemFromPosition(mouse)
185+ onPositionChanged: updateCurrentItemFromPosition(mouse)
235− function updateCurrentItemFromPosition(point) {
187+ function updateCurrentItemFromPosition(point) {
236− var pos = mapToItem(listView.contentItem, point.x, point.y);
188+ var pos = mapToItem(listView.contentItem, point.x, point.y);
238− if (!d.hoveredItem || !d.currentItem ||
190+ if (!d.hoveredItem || !d.currentItem ||
239− !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
191+ !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
240− d.hoveredItem = listView.itemAt(listView.indexAt(pos.x, pos.y));
192+ d.hoveredItem = listView.itemAt(listView.indexAt(pos.x, pos.y));
241− if (!d.hoveredItem || !d.hoveredItem.enabled)
193+ if (!d.hoveredItem || !d.hoveredItem.enabled)
242− return false;
194+ return false;
243− d.currentItem = d.hoveredItem;
195+ d.currentItem = d.hoveredItem;
249− ActionContext {
201+ ActionContext {
250− id: menuBarContext
202+ id: menuBarContext
251− objectName: "menuContext"
203+ objectName: "menuContext"
252− active: {
204+ active: {
253− if (!root.visible) return false;
205+ if (!root.visible) return false;
254− if (d.currentItem && d.currentItem.popup && d.currentItem.popup.visible) {
206+ if (d.currentItem && d.currentItem.popup && d.currentItem.popup.visible) {
255− return false;
207+ return false;
261− delegate: Loader {
213+ delegate: Loader {
262− id: loader
214+ id: loader
263− objectName: root.objectName + "-item" + __ownIndex
215+ objectName: root.objectName + "-item" + __ownIndex
265− property int __ownIndex: index
217+ property int __ownIndex: index
267− width: root.width
219+ width: root.width
268− enabled: model.isSeparator ? false : model.sensitive
220+ enabled: model.isSeparator ? false : model.sensitive
269− Keys.forwardTo: [ item ]
271− sourceComponent: {
222+ sourceComponent: {
272− if (model.isSeparator) {
223+ if (model.isSeparator) {
273− return separatorComponent;
224+ return separatorComponent;
226+ return menuItemComponent;
275− return menuItemComponent;
278− property Item popup: null
229+ property Item popup: null
280− Component {
231+ Component {
281− id: menuItemComponent
232+ id: menuItemComponent
282− MenuItem {
233+ MenuItem {
283− id: menuItem
234+ id: menuItem
284− menuData: model
235+ menuData: model
285− objectName: loader.objectName + "-actionItem"
236+ objectName: loader.objectName + "-actionItem"
287− action.onTriggered: {
238+ action.onTriggered: {
288− d.currentItem = loader;
239+ d.currentItem = loader;
290− if (hasSubmenu) {
241+ if (hasSubmenu) {
291− if (!popup) {
242+ if (!popup) {
292− var model = root.unityMenuModel.submenu(__ownIndex);
243+ var model = root.unityMenuModel.submenu(__ownIndex);
293− popup = submenuComponent.createObject(root, {
244+ popup = submenuComponent.createObject(focusScope, {
294− objectName: loader.objectName + "-",
245+ objectName: loader.objectName + "-",
295− unityMenuModel: model,
246+ unityMenuModel: model,
296− x: Qt.binding(function() { return root.width }),
247+ x: Qt.binding(function() { return root.width }),
297− y: Qt.binding(function() { return loader.y })
248+ y: Qt.binding(function() { return loader.y })
299− } else if (popup) {
250+ } else if (popup) {
300− popup.visible = true;
251+ popup.visible = true;
253+ popup.dismiss.connect(function() {
256+ menuItem.forceActiveFocus();
259+ root.unityMenuModel.activate(__ownIndex);
302− popup.forceActiveFocus();
303− popup.dismiss.connect(function() {
306− loader.forceActiveFocus();
309− root.unityMenuModel.activate(__ownIndex);
313− Connections {
263+ Connections {
314− target: d
264+ target: d
315− onCurrentIndexChanged: {
265+ onCurrentIndexChanged: {
316− if (popup && d.currentIndex != __ownIndex) {
266+ if (popup && d.currentIndex != __ownIndex) {
317− popup.visible = false;
267+ popup.visible = false;
324− Component {
274+ Component {
325− id: separatorComponent
275+ id: separatorComponent
326− ListItems.ThinDivider {
276+ ListItems.ThinDivider {
327− objectName: loader.objectName + "-separator"
277+ objectName: loader.objectName + "-separator"
331− } // ListView
281+ } // ListView
333− // FIXME use ListView.footer - tried but was flaky with positionViewAtIndex.
283+ // FIXME use ListView.footer - tried but was flaky with positionViewAtIndex.
335− Layout.fillWidth: true;
285+ Layout.fillWidth: true;
336− Layout.maximumHeight: units.gu(3)
286+ Layout.maximumHeight: units.gu(3)
337− Layout.minimumHeight: units.gu(3)
287+ Layout.minimumHeight: units.gu(3)
338− visible: listView.contentHeight > root.height
288+ visible: listView.contentHeight > root.height
339− enabled: !listView.atYEnd
289+ enabled: !listView.atYEnd
341− Rectangle {
291+ Rectangle {
342− color: enabled ? theme.palette.normal.overlayText :
292+ color: enabled ? theme.palette.normal.overlayText :
343− theme.palette.disabled.overlayText
293+ theme.palette.disabled.overlayText
344− height: units.dp(1)
294+ height: units.dp(1)
345− anchors {
295+ anchors {
346− top: parent.top
296+ top: parent.top
347− left: parent.left
297+ left: parent.left
348− right: parent.right
298+ right: parent.right
353− anchors.centerIn: parent
303+ anchors.centerIn: parent
354− width: units.gu(2)
304+ width: units.gu(2)
355− height: units.gu(2)
305+ height: units.gu(2)
356− name: "down"
306+ name: "down"
357− color: enabled ? theme.palette.normal.overlayText :
307+ color: enabled ? theme.palette.normal.overlayText :
358− theme.palette.disabled.overlayText
308+ theme.palette.disabled.overlayText
361− MouseArea {
311+ MouseArea {
362− anchors.fill: parent
312+ anchors.fill: parent
363− onPressed: {
313+ onPressed: {
364− var index = listView.indexAt(0, listView.contentY);
314+ var index = listView.indexAt(0, listView.contentY);
365− listView.positionViewAtIndex(index+1, ListView.Beginning);
315+ listView.positionViewAtIndex(index+1, ListView.Beginning);
369− } // Column
319+ } // Column
371− Component {
321+ Component {
372− id: submenuComponent
322+ id: submenuComponent
373− Loader {
323+ Loader {
374− id: submenuLoader
324+ id: submenuLoader
375− source: "MenuPopup.qml"
325+ source: "MenuPopup.qml"
377− property var unityMenuModel: null
327+ property var unityMenuModel: null
378− signal dismiss()
328+ signal dismiss()
380− Binding {
330+ Binding {
381− target: item
331+ target: item
382− property: "unityMenuModel"
332+ property: "unityMenuModel"
383− value: submenuLoader.unityMenuModel
333+ value: submenuLoader.unityMenuModel
386− Binding {
336+ Binding {
387− target: item
337+ target: item
388− property: "objectName"
338+ property: "objectName"
389− value: submenuLoader.objectName + "menu"
339+ value: submenuLoader.objectName + "menu"
392− Connections {
342+ Connections {
393− target: d
343+ target: d
394− onDismissAll: submenuLoader.dismiss()
344+ onDismissAll: submenuLoader.dismiss()
397− Keys.onLeftPressed: dismiss()
347+ Keys.onLeftPressed: dismiss()
399− Component.onCompleted: item.select(0);
349+ Component.onCompleted: item.select(0);
400− onVisibleChanged: if (visible) { item.select(0); }
350+ onVisibleChanged: if (visible) { item.select(0); }