2 * Copyright 2016 Canonical Ltd.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18import QtQuick.Layouts 1.1
20import Ubuntu.Components 1.3
21import GlobalShortcut 1.0
28 property alias unityMenuModel: rowRepeater.model
29 property bool enableKeyFilter: false
30 property real overflowWidth: width
33 readonly property bool valid: rowRepeater.count > 0
34 readonly property bool showRequested: d.longAltPressed || d.currentItem != null
36 implicitWidth: row.width
39 function select(index) {
48 shortcut: Qt.Key_Alt|Qt.AltModifier
49 active: enableKeyFilter
50 onTriggered: d.startShortcutTimer()
51 onReleased: d.stopSHortcutTimer()
53 // On an actual keyboard, the AltModifier is not supplied on release.
56 active: enableKeyFilter
57 onTriggered: d.startShortcutTimer()
58 onReleased: d.stopSHortcutTimer()
62 shortcut: Qt.AltModifier | Qt.Key_F10
63 active: enableKeyFilter && d.currentItem == null
65 for (var i = 0; i < rowRepeater.count; i++) {
66 var item = rowRepeater.itemAt(i);
76 acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
78 enabled: d.currentItem != null
79 hoverEnabled: enabled && d.currentItem && d.currentItem.__popup != null
80 onPressed: d.dismissAll()
90 objectName: "barContext"
91 active: !d.currentItem && enableKeyFilter
95 target: root.unityMenuModel
96 onModelReset: d.firstInvisibleIndex = undefined
102 onItemAdded: d.recalcFirstInvisibleIndexAdded(index, item)
103 onCountChanged: d.recalcFirstInvisibleIndex()
107 objectName: root.objectName + "-item" + __ownIndex
109 readonly property int __ownIndex: index
110 property Item __popup: null;
111 readonly property bool popupVisible: __popup && __popup.visible
112 readonly property bool shouldDisplay: x + width + ((__ownIndex < rowRepeater.count-1) ? units.gu(2) : 0) <
113 root.overflowWidth - ((__ownIndex < rowRepeater.count-1) ? overflowButton.width : 0)
115 implicitWidth: column.implicitWidth
116 implicitHeight: row.height
117 enabled: model.sensitive && shouldDisplay
118 opacity: shouldDisplay ? 1 : 0
122 __popup = menuComponent.createObject(root, { objectName: visualItem.objectName + "-menu" });
123 __popup.childActivated.connect(dismiss);
124 // force the current item to be the newly popped up menu
128 d.currentItem = visualItem;
134 if (d.currentItem === visualItem) {
135 d.currentItem = null;
144 if (d.currentItem === visualItem) {
145 d.currentItem = null;
151 if (!visible && __popup) dismiss();
154 onShouldDisplayChanged: {
155 if ((!shouldDisplay && d.firstInvisibleIndex == undefined) || __ownIndex <= d.firstInvisibleIndex) {
156 d.recalcFirstInvisibleIndex();
162 onDismissAll: visualItem.dismiss()
168 desiredX: visualItem.x - units.gu(1)
169 desiredY: parent.height
170 unityMenuModel: root.unityMenuModel.submenu(visualItem.__ownIndex)
172 Component.onCompleted: reset();
184 Layout.preferredWidth: units.gu(2)
185 Layout.preferredHeight: units.gu(2)
186 Layout.alignment: Qt.AlignVCenter
188 visible: model.icon || false
189 source: model.icon || ""
195 height: _title.height
198 enabled: visualItem.enabled
199 // FIXME - SDK Action:text modifies menu text with html underline for mnemonic
200 text: model.label.replace("_", "&").replace("<u>", "&").replace("</u>", "")
209 text: actionItem.text
210 horizontalAlignment: Text.AlignLeft
211 color: enabled ? theme.palette.normal.backgroundText : theme.palette.disabled.backgroundText
215 } // Item ( delegate )
221 hoverEnabled: d.currentItem
225 updateCurrentItemFromPosition(Qt.point(mouseX, mouseY))
230 updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
234 var prevItem = d.currentItem;
235 updateCurrentItemFromPosition(Qt.point(mouse.x, mouse.y))
236 if (prevItem && d.currentItem == prevItem) {
241 function updateCurrentItemFromPosition(point) {
242 var pos = mapToItem(row, point.x, point.y);
244 if (!d.hoveredItem || !d.currentItem || !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
245 d.hoveredItem = row.childAt(pos.x, pos.y);
246 if (!d.hoveredItem || !d.hoveredItem.enabled)
248 if (d.currentItem != d.hoveredItem) {
249 d.currentItem = d.hoveredItem;
257 objectName: "overflow"
259 hoverEnabled: d.currentItem
260 onEntered: d.currentItem = this
261 onPositionChanged: d.currentItem = this
262 onClicked: d.currentItem = this
264 property Item __popup: null;
265 readonly property bool popupVisible: __popup && __popup.visible
266 readonly property Item firstInvisibleItem: d.firstInvisibleIndex !== undefined ? rowRepeater.itemAt(d.firstInvisibleIndex) : null
268 visible: d.firstInvisibleIndex != undefined
269 x: firstInvisibleItem ? firstInvisibleItem.x : 0
271 height: parent.height
275 if (!visible && __popup) dismiss();
282 anchors.centerIn: parent
283 color: theme.palette.normal.backgroundText
284 name: "toolkit_chevron-down_2gu"
289 __popup = overflowComponent.createObject(root, { objectName: overflowButton.objectName + "-menu" });
290 __popup.childActivated.connect(dismiss);
291 // force the current item to be the newly popped up menu
295 d.currentItem = overflowButton;
301 if (d.currentItem === overflowButton) {
302 d.currentItem = null;
311 if (d.currentItem === overflowButton) {
312 d.currentItem = null;
319 onDismissAll: overflowButton.dismiss()
323 id: overflowComponent
326 desiredX: overflowButton.x - units.gu(1)
327 desiredY: parent.height
328 unityMenuModel: overflowModel
330 ExpressionFilterModel {
332 sourceModel: root.unityMenuModel
333 matchExpression: function(index) {
334 if (d.firstInvisibleIndex === undefined) return false;
335 return index >= d.firstInvisibleIndex;
338 function submenu(index) {
339 return sourceModel.submenu(mapRowToSource(index));
341 function activate(index) {
342 return sourceModel.activate(mapRowToSource(index));
348 onFirstInvisibleIndexChanged: overflowModel.invalidate()
359 x: d.currentItem ? row.x + d.currentItem.x - units.gu(1) : 0
360 width: d.currentItem ? d.currentItem.width + units.gu(2) : 0
362 color: UbuntuColors.orange
363 visible: d.currentItem
369 itemView: rowRepeater
370 hasOverflow: overflowButton.visible
372 property Item currentItem: null
373 property Item hoveredItem: null
374 property Item prevCurrentItem: null
375 property bool altPressed: false
376 property bool longAltPressed: false
377 property var firstInvisibleIndex: undefined
379 readonly property int currentIndex: currentItem && currentItem.hasOwnProperty("__ownIndex") ? currentItem.__ownIndex : -1
383 function recalcFirstInvisibleIndexAdded(index, item) {
384 if (firstInvisibleIndex === undefined) {
385 if (!item.shouldDisplay) {
386 firstInvisibleIndex = index;
388 } else if (index <= firstInvisibleIndex) {
389 if (!item.shouldDisplay) {
390 firstInvisibleIndex = index;
392 firstInvisibleIndex++;
397 function recalcFirstInvisibleIndex() {
398 for (var i = 0; i < rowRepeater.count; i++) {
399 if (!rowRepeater.itemAt(i).shouldDisplay) {
400 firstInvisibleIndex = i;
404 firstInvisibleIndex = undefined;
408 var delegate = rowRepeater.itemAt(index);
410 d.currentItem = delegate;
415 d.currentItem = overflowButton;
418 onCurrentItemChanged: {
419 if (prevCurrentItem && prevCurrentItem != currentItem) {
421 prevCurrentItem.hide();
423 prevCurrentItem.dismiss();
427 if (currentItem) currentItem.show();
428 prevCurrentItem = currentItem;
431 function startShortcutTimer() {
433 menuBarShortcutTimer.start();
436 function stopSHortcutTimer() {
437 menuBarShortcutTimer.stop();
438 d.altPressed = false;
439 d.longAltPressed = false;
444 id: menuBarShortcutTimer
448 d.longAltPressed = true;
452 Keys.onEscapePressed: {
454 event.accepted = true;
457 Keys.onLeftPressed: {
459 d.selectPrevious(d.currentIndex);
463 Keys.onRightPressed: {
465 d.selectNext(d.currentIndex);
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list