~lukas-kde/unity8/dashboard

« back to all changes in this revision

Viewing changes to qml/ApplicationMenus/MenuPopup.qml

  • Committer: Lukáš Tinkl
  • Date: 2017-01-26 12:13:17 UTC
  • mfrom: (2749.1.49 unity8)
  • Revision ID: lukas.tinkl@canonical.com-20170126121317-qms39s9pikclidbe
merge trunk, fix conflicts

Show diffs side-by-side

added added

removed removed

Lines of Context:
26
26
    objectName: "menu"
27
27
    backgroundColor: theme.palette.normal.overlay
28
28
 
29
 
    property alias unityMenuModel: listView.model
30
 
 
31
 
    readonly property real __ajustedMinimumHeight: {
32
 
        if (listView.contentHeight > __minimumHeight) {
33
 
            return units.gu(30);
34
 
        }
35
 
        return Math.max(listView.contentHeight, units.gu(2));
36
 
    }
37
 
 
38
 
    readonly property real __minimumWidth: units.gu(20)
39
 
    readonly property real __minimumHeight: units.gu(30)
40
 
    readonly property real __maximumWidth: Screen.width * 0.7
41
 
    readonly property real __maximumHeight: Screen.height * 0.7
 
29
    property alias unityMenuModel: repeater.model
42
30
 
43
31
    function show() {
44
32
        visible = true;
63
51
        d.dismissAll();
64
52
    }
65
53
 
66
 
    implicitWidth: container.width
67
 
    implicitHeight: MathUtils.clamp(listView.contentHeight, __ajustedMinimumHeight, __maximumHeight)
 
54
    implicitWidth: focusScope.width
 
55
    implicitHeight: focusScope.height
68
56
 
69
57
    MenuNavigator {
70
58
        id: d
71
59
        objectName: "d"
72
 
        itemView: listView
 
60
        itemView: repeater
73
61
 
74
62
        property Item currentItem: null
75
63
        property Item hoveredItem: null
76
64
        readonly property int currentIndex: currentItem ? currentItem.__ownIndex : -1
77
65
 
 
66
        property real __minimumWidth: units.gu(20)
 
67
        property real __maximumWidth: Screen.width * 0.7
 
68
        property real __minimumHeight: units.gu(2)
 
69
        property real __maximumHeight: Screen.height * 0.7
 
70
 
78
71
        signal dismissAll()
79
72
 
80
73
        onCurrentItemChanged: {
86
79
        }
87
80
 
88
81
        onSelect: {
89
 
            currentItem = listView.itemAt(index);
 
82
            currentItem = repeater.itemAt(index);
 
83
            if (currentItem) {
 
84
                if (currentItem.y < listView.contentY) {
 
85
                    listView.contentY = currentItem.y;
 
86
                } else if (currentItem.y + currentItem.height > listView.contentY + listView.height) {
 
87
                    listView.contentY = currentItem.y + currentItem.height - listView.height;
 
88
                }
 
89
            }
90
90
        }
91
91
    }
92
92
 
 
93
    MouseArea {
 
94
        // Eat events.
 
95
        anchors.fill: parent
 
96
    }
 
97
 
93
98
    Item {
94
99
        id: focusScope
95
 
        anchors.fill: parent
 
100
        width: container.width
 
101
        height: container.height
96
102
        focus: visible
97
103
 
98
104
        Keys.onUpPressed: d.selectPrevious(d.currentIndex)
108
114
            id: container
109
115
            objectName: "container"
110
116
 
111
 
            width: listView.contentWidth
112
 
            height: parent.height
 
117
            height: MathUtils.clamp(listView.contentHeight, d.__minimumHeight, d.__maximumHeight)
 
118
            width: menuColumn.width
113
119
            spacing: 0
114
120
 
115
 
            // FIXME use ListView.header - tried but was flaky with positionViewAtIndex.
 
121
            // Header - scroll up
116
122
            Item {
117
 
                Layout.fillWidth: true;
118
 
                Layout.maximumHeight: units.gu(3)
119
 
                Layout.minimumHeight: units.gu(3)
 
123
                Layout.fillWidth: true
 
124
                height: units.gu(3)
120
125
                visible: listView.contentHeight > root.height
121
126
                enabled: !listView.atYBeginning
 
127
                z: 1
122
128
 
123
129
                Rectangle {
124
130
                    color: enabled ? theme.palette.normal.overlayText :
143
149
                MouseArea {
144
150
                    anchors.fill: parent
145
151
                    onPressed: {
146
 
                        var index = listView.indexAt(0, listView.contentY);
147
 
                        listView.positionViewAtIndex(index-1, ListView.Beginning);
 
152
                        var item = menuColumn.childAt(0, listView.contentY);
 
153
                        if (item) {
 
154
                            var previousItem = item;
 
155
                            do {
 
156
                                previousItem = repeater.itemAt(previousItem.__ownIndex-1);
 
157
                                if (!previousItem) {
 
158
                                    listView.contentY = 0;
 
159
                                    return;
 
160
                                }
 
161
                            } while (previousItem.__isSeparator);
 
162
 
 
163
                            listView.contentY = previousItem.y
 
164
                        }
148
165
                    }
149
166
                }
150
167
            }
151
168
 
152
 
            ListView {
 
169
            // Menu Items
 
170
            Flickable {
153
171
                id: listView
154
 
                objectName: "listView"
 
172
                clip: interactive
 
173
 
155
174
                Layout.fillHeight: true
156
175
                Layout.fillWidth: true
157
 
                contentWidth: MathUtils.clamp(contentItem.childrenRect.width,
158
 
                                              __minimumWidth,
159
 
                                              __maximumWidth)
160
 
 
161
 
                orientation: Qt.Vertical
162
 
                interactive: contentHeight > height
163
 
                clip: interactive
164
 
                highlightFollowsCurrentItem: false
165
 
 
166
 
                highlight: Rectangle {
167
 
                    color: "transparent"
168
 
                    border.width: units.dp(1)
169
 
                    border.color: UbuntuColors.orange
170
 
                    z: 1
171
 
 
172
 
                    width: listView.width
173
 
                    height:  d.currentItem ? d.currentItem.height : 0
174
 
                    y:  d.currentItem ? d.currentItem.y : 0
175
 
                    visible: d.currentItem
176
 
                }
177
 
 
178
 
                function itemAt(index) {
179
 
                    if (index > count || index < 0) return null;
180
 
                    currentIndex = index;
181
 
                    return currentItem;
182
 
                }
 
176
                contentHeight: menuColumn.height
 
177
                interactive: height < contentHeight
183
178
 
184
179
                MouseArea {
185
 
                    id: menuMouseArea
186
 
                    anchors.fill: listView
 
180
                    anchors.fill: parent
187
181
                    hoverEnabled: true
188
182
                    propagateComposedEvents: true // propogate events so we send clicks to children.
189
183
                    z: 1 // on top so we override any other hovers
195
189
 
196
190
                        if (!d.hoveredItem || !d.currentItem ||
197
191
                                !d.hoveredItem.contains(Qt.point(pos.x - d.currentItem.x, pos.y - d.currentItem.y))) {
198
 
                            d.hoveredItem = listView.itemAt(listView.indexAt(pos.x, pos.y));
 
192
                            d.hoveredItem = menuColumn.childAt(pos.x, pos.y)
199
193
                            if (!d.hoveredItem || !d.hoveredItem.enabled)
200
194
                                return false;
201
195
                            d.currentItem = d.hoveredItem;
216
210
                    }
217
211
                }
218
212
 
219
 
                delegate: Loader {
220
 
                    id: loader
221
 
                    objectName: root.objectName + "-item" + __ownIndex
222
 
 
223
 
                    property int __ownIndex: index
224
 
 
225
 
                    width: root.width
226
 
                    enabled: model.isSeparator ? false : model.sensitive
227
 
 
228
 
                    sourceComponent: {
229
 
                        if (model.isSeparator) {
230
 
                            return separatorComponent;
231
 
                        }
232
 
                        return menuItemComponent;
233
 
                    }
234
 
 
235
 
                    property Item popup: null
236
 
 
237
 
                    Component {
238
 
                        id: menuItemComponent
239
 
                        MenuItem {
240
 
                            id: menuItem
241
 
                            menuData: model
242
 
                            objectName: loader.objectName + "-actionItem"
243
 
 
244
 
                            action.onTriggered: {
245
 
                                d.currentItem = loader;
246
 
 
247
 
                                if (hasSubmenu) {
248
 
                                    if (!popup) {
249
 
                                        var model = root.unityMenuModel.submenu(__ownIndex);
250
 
                                        popup = submenuComponent.createObject(focusScope, {
251
 
                                                                                  objectName: loader.objectName + "-",
252
 
                                                                                  unityMenuModel: model,
253
 
                                                                                  x: Qt.binding(function() { return root.width }),
254
 
                                                                                  y: Qt.binding(function() { return loader.y })
255
 
                                                                              });
256
 
                                    } else if (popup) {
257
 
                                        popup.visible = true;
258
 
                                    }
259
 
                                    popup.retreat.connect(function() {
260
 
                                        popup.destroy();
261
 
                                        popup = null;
262
 
                                        menuItem.forceActiveFocus();
263
 
                                    })
264
 
                                } else {
265
 
                                    root.unityMenuModel.activate(__ownIndex);
266
 
                                }
267
 
                            }
268
 
 
269
 
                            Connections {
270
 
                                target: d
271
 
                                onCurrentIndexChanged: {
272
 
                                    if (popup && d.currentIndex != __ownIndex) {
273
 
                                        popup.visible = false;
274
 
                                    }
275
 
                                }
276
 
                                onDismissAll: {
277
 
                                    if (popup) {
278
 
                                        popup.destroy();
279
 
                                        popup = null;
280
 
                                    }
281
 
                                }
282
 
                            }
283
 
                        }
284
 
                    }
285
 
 
286
 
                    Component {
287
 
                        id: separatorComponent
288
 
                        ListItems.ThinDivider {
289
 
                            objectName: loader.objectName + "-separator"
290
 
                        }
291
 
                    }
292
 
                }
293
 
            } // ListView
294
 
 
295
 
            // FIXME use ListView.footer - tried but was flaky with positionViewAtIndex.
 
213
                ColumnLayout {
 
214
                    id: menuColumn
 
215
                    spacing: 0
 
216
 
 
217
                    width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
 
218
 
 
219
                    Repeater {
 
220
                        id: repeater
 
221
 
 
222
                        Loader {
 
223
                            id: loader
 
224
                            objectName: root.objectName + "-item" + __ownIndex
 
225
 
 
226
                            property int __ownIndex: index
 
227
                            property bool __isSeparator: model.isSeparator
 
228
 
 
229
                            enabled: __isSeparator ? false : model.sensitive
 
230
 
 
231
                            sourceComponent: {
 
232
                                if (model.isSeparator) {
 
233
                                    return separatorComponent;
 
234
                                }
 
235
                                return menuItemComponent;
 
236
                            }
 
237
 
 
238
                            property Item popup: null
 
239
 
 
240
                            Layout.fillWidth: true
 
241
 
 
242
                            Component {
 
243
                                id: menuItemComponent
 
244
                                MenuItem {
 
245
                                    id: menuItem
 
246
                                    menuData: model
 
247
                                    objectName: loader.objectName + "-actionItem"
 
248
 
 
249
                                    width: MathUtils.clamp(implicitWidth, d.__minimumWidth, d.__maximumWidth)
 
250
 
 
251
                                    action.onTriggered: {
 
252
                                        d.currentItem = loader;
 
253
 
 
254
                                        if (hasSubmenu) {
 
255
                                            if (!popup) {
 
256
                                                var model = root.unityMenuModel.submenu(__ownIndex);
 
257
                                                popup = submenuComponent.createObject(focusScope, {
 
258
                                                                                          objectName: loader.objectName + "-",
 
259
                                                                                          unityMenuModel: model,
 
260
                                                                                          x: Qt.binding(function() { return root.width }),
 
261
                                                                                          y: Qt.binding(function() {
 
262
                                                                                              var dummy = listView.contentY; // force a recalc on contentY change.
 
263
                                                                                              return mapToItem(container, 0, y).y;
 
264
                                                                                          })
 
265
                                                                                      });
 
266
                                            } else if (popup) {
 
267
                                                popup.visible = true;
 
268
                                            }
 
269
                                            popup.retreat.connect(function() {
 
270
                                                popup.destroy();
 
271
                                                popup = null;
 
272
                                                menuItem.forceActiveFocus();
 
273
                                            })
 
274
                                        } else {
 
275
                                            root.unityMenuModel.activate(__ownIndex);
 
276
                                        }
 
277
                                    }
 
278
 
 
279
                                    Connections {
 
280
                                        target: d
 
281
                                        onCurrentIndexChanged: {
 
282
                                            if (popup && d.currentIndex != __ownIndex) {
 
283
                                                popup.visible = false;
 
284
                                            }
 
285
                                        }
 
286
                                        onDismissAll: {
 
287
                                            if (popup) {
 
288
                                                popup.destroy();
 
289
                                                popup = null;
 
290
                                            }
 
291
                                        }
 
292
                                    }
 
293
                                }
 
294
                            }
 
295
 
 
296
                            Component {
 
297
                                id: separatorComponent
 
298
                                ListItems.ThinDivider {
 
299
                                    objectName: loader.objectName + "-separator"
 
300
                                    implicitHeight: units.dp(2)
 
301
                                }
 
302
                            }
 
303
                        }
 
304
 
 
305
                    }
 
306
                }
 
307
 
 
308
                // Highlight
 
309
                Rectangle {
 
310
                    color: "transparent"
 
311
                    border.width: units.dp(1)
 
312
                    border.color: UbuntuColors.orange
 
313
                    z: 1
 
314
 
 
315
                    width: listView.width
 
316
                    height:  d.currentItem ? d.currentItem.height : 0
 
317
                    y:  d.currentItem ? d.currentItem.y : 0
 
318
                    visible: d.currentItem
 
319
                }
 
320
 
 
321
            } // Flickable
 
322
 
 
323
            // Header - scroll down
296
324
            Item {
297
 
                Layout.fillWidth: true;
298
 
                Layout.maximumHeight: units.gu(3)
299
 
                Layout.minimumHeight: units.gu(3)
 
325
                Layout.fillWidth: true
 
326
                height: units.gu(3)
300
327
                visible: listView.contentHeight > root.height
301
328
                enabled: !listView.atYEnd
 
329
                z: 1
302
330
 
303
331
                Rectangle {
304
332
                    color: enabled ? theme.palette.normal.overlayText :
323
351
                MouseArea {
324
352
                    anchors.fill: parent
325
353
                    onPressed: {
326
 
                        var index = listView.indexAt(0, listView.contentY);
327
 
                        listView.positionViewAtIndex(index+1, ListView.Beginning);
 
354
                        var item = menuColumn.childAt(0, listView.contentY + listView.height);
 
355
                        if (item) {
 
356
                            var nextItem = item;
 
357
                            do {
 
358
                                nextItem = repeater.itemAt(nextItem.__ownIndex+1);
 
359
                                if (!nextItem) {
 
360
                                    listView.contentY = listView.contentHeight - listView.height;
 
361
                                    return;
 
362
                                }
 
363
                            } while (nextItem.__isSeparator);
 
364
 
 
365
                            listView.contentY = nextItem.y - listView.height
 
366
                        }
328
367
                    }
329
368
                }
330
369
            }