Changeset View
Changeset View
Standalone View
Standalone View
src/controls/templates/OverlaySheet.qml
Show All 12 Lines | |||||
13 | * | 13 | * | ||
14 | * You should have received a copy of the GNU Library General Public | 14 | * You should have received a copy of the GNU Library General Public | ||
15 | * License along with this program; if not, write to the | 15 | * License along with this program; if not, write to the | ||
16 | * Free Software Foundation, Inc., | 16 | * Free Software Foundation, Inc., | ||
17 | * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. | 17 | * 51 Franklin Street, Fifth Floor, Boston, MA 2.010-1301, USA. | ||
18 | */ | 18 | */ | ||
19 | 19 | | |||
20 | import QtQuick 2.5 | 20 | import QtQuick 2.5 | ||
21 | import QtQuick.Controls 1.3 as Controls | 21 | import org.kde.kirigami 2.0 | ||
22 | import org.kde.kirigami 1.0 | | |||
23 | import QtGraphicalEffects 1.0 | 22 | import QtGraphicalEffects 1.0 | ||
23 | import QtQuick.Templates 2.0 as T2 | ||||
24 | import "private" | 24 | import "private" | ||
25 | 25 | | |||
26 | /** | 26 | /** | ||
27 | * An overlay sheet that covers the current Page content. | 27 | * An overlay sheet that covers the current Page content. | ||
28 | * Its contents can be scrolled up or down, scrolling all the way up or | 28 | * Its contents can be scrolled up or down, scrolling all the way up or | ||
29 | * all the way down, dismisses it. | 29 | * all the way down, dismisses it. | ||
30 | * Use this for big, modal dialogs or information display, that can't be | 30 | * Use this for big, modal dialogs or information display, that can't be | ||
31 | * logically done as a new separate Page, even if potentially | 31 | * logically done as a new separate Page, even if potentially | ||
32 | * are taller than the screen space. | 32 | * are taller than the screen space. | ||
33 | */ | 33 | */ | ||
34 | Item { | 34 | QtObject { | ||
35 | id: root | 35 | id: root | ||
36 | 36 | | |||
37 | z: 999 | | |||
38 | | ||||
39 | anchors.fill: parent | | |||
40 | visible: false | | |||
41 | | ||||
42 | /** | 37 | /** | ||
43 | * contentItem: Item | 38 | * contentItem: Item | ||
44 | * This property holds the visual content item. | 39 | * This property holds the visual content item. | ||
45 | * | 40 | * | ||
46 | * Note: The content item is automatically resized inside the | 41 | * Note: The content item is automatically resized inside the | ||
47 | * padding of the control. | 42 | * padding of the control. | ||
48 | */ | 43 | */ | ||
49 | default property Item contentItem | 44 | default property Item contentItem | ||
50 | 45 | | |||
51 | /** | 46 | /** | ||
52 | * opened: bool | 47 | * sheetOpen: bool | ||
53 | * If true the sheet is open showing the contents of the OverlaySheet | 48 | * If true the sheet is open showing the contents of the OverlaySheet | ||
54 | * component. | 49 | * component. | ||
55 | */ | 50 | */ | ||
56 | property bool opened | 51 | property bool sheetOpen | ||
57 | 52 | | |||
58 | /** | 53 | /** | ||
59 | * leftPadding: int | 54 | * leftPadding: int | ||
60 | * default contents padding at left | 55 | * default contents padding at left | ||
61 | */ | 56 | */ | ||
62 | property int leftPadding: Units.gridUnit | 57 | property int leftPadding: Units.gridUnit | ||
63 | 58 | | |||
64 | /** | 59 | /** | ||
Show All 20 Lines | |||||
85 | * | 80 | * | ||
86 | * Note: If the background item has no explicit size specified, | 81 | * Note: If the background item has no explicit size specified, | ||
87 | * it automatically follows the control's size. | 82 | * it automatically follows the control's size. | ||
88 | * In most cases, there is no need to specify width or | 83 | * In most cases, there is no need to specify width or | ||
89 | * height for a background item. | 84 | * height for a background item. | ||
90 | */ | 85 | */ | ||
91 | property Item background | 86 | property Item background | ||
92 | 87 | | |||
88 | property Item parent | ||||
89 | | ||||
93 | 90 | | |||
94 | function open() { | 91 | function open() { | ||
95 | root.visible = true; | 92 | mainItem.visible = true; | ||
96 | openAnimation.from = -root.height; | 93 | openAnimation.from = -mainItem.height; | ||
97 | openAnimation.to = openAnimation.topOpenPosition; | 94 | openAnimation.to = openAnimation.topOpenPosition; | ||
98 | openAnimation.running = true; | 95 | openAnimation.running = true; | ||
99 | root.opened = true; | 96 | root.sheetOpen = true; | ||
100 | } | 97 | } | ||
101 | 98 | | |||
102 | function close() { | 99 | function close() { | ||
103 | if (scrollView.flickableItem.contentY < 0) { | 100 | if (scrollView.flickableItem.contentY < 0) { | ||
104 | closeAnimation.to = -height; | 101 | closeAnimation.to = -height; | ||
105 | } else { | 102 | } else { | ||
106 | closeAnimation.to = scrollView.flickableItem.contentHeight; | 103 | closeAnimation.to = scrollView.flickableItem.contentHeight; | ||
107 | } | 104 | } | ||
108 | closeAnimation.running = true; | 105 | closeAnimation.running = true; | ||
109 | } | 106 | } | ||
110 | 107 | | |||
111 | Rectangle { | | |||
112 | anchors.fill: parent | | |||
113 | color: Theme.textColor | | |||
114 | opacity: 0.6 * Math.min( | | |||
115 | (Math.min(scrollView.flickableItem.contentY + scrollView.flickableItem.height, scrollView.flickableItem.height) / scrollView.flickableItem.height), | | |||
116 | (2 + (scrollView.flickableItem.contentHeight - scrollView.flickableItem.contentY - scrollView.flickableItem.topMargin - scrollView.flickableItem.bottomMargin)/scrollView.flickableItem.height)) | | |||
117 | } | | |||
118 | | ||||
119 | 108 | | |||
120 | Component.onCompleted: { | | |||
121 | scrollView.flickableItem.interactive = true; | | |||
122 | } | | |||
123 | onBackgroundChanged: { | 109 | onBackgroundChanged: { | ||
124 | background.parent = flickableContents; | 110 | background.parent = flickableContents; | ||
125 | background.z = -1; | 111 | background.z = -1; | ||
126 | } | 112 | } | ||
127 | onContentItemChanged: { | 113 | onContentItemChanged: { | ||
128 | if (contentItem.hasOwnProperty("contentY") && // Check if flickable | 114 | if (contentItem.hasOwnProperty("contentY") && // Check if flickable | ||
129 | contentItem.hasOwnProperty("contentHeight")) { | 115 | contentItem.hasOwnProperty("contentHeight")) { | ||
130 | contentItem.parent = scrollView; | 116 | contentItem.parent = scrollView; | ||
131 | scrollView.contentItem = contentItem; | 117 | scrollView.contentItem = contentItem; | ||
132 | } else { | 118 | } else { | ||
133 | contentItem.parent = contentItemParent; | 119 | contentItem.parent = contentItemParent; | ||
134 | scrollView.contentItem = flickableContents; | 120 | scrollView.contentItem = flickableContents; | ||
135 | contentItem.anchors.left = contentItemParent.left; | 121 | contentItem.anchors.left = contentItemParent.left; | ||
136 | contentItem.anchors.right = contentItemParent.right; | 122 | contentItem.anchors.right = contentItemParent.right; | ||
137 | } | 123 | } | ||
138 | scrollView.flickableItem.flickableDirection = Flickable.VerticalFlick; | 124 | scrollView.flickableItem.flickableDirection = Flickable.VerticalFlick; | ||
139 | } | 125 | } | ||
140 | onOpenedChanged: { | 126 | onSheetOpenChanged: { | ||
141 | if (opened) { | 127 | if (sheetOpen) { | ||
142 | open(); | 128 | open(); | ||
143 | } else { | 129 | } else { | ||
144 | close(); | 130 | close(); | ||
145 | Qt.inputMethod.hide(); | 131 | Qt.inputMethod.hide(); | ||
146 | } | 132 | } | ||
147 | } | 133 | } | ||
134 | | ||||
135 | Component.onCompleted: { | ||||
136 | scrollView.flickableItem.interactive = true; | ||||
137 | if (!root.parent) { | ||||
138 | root.parent = applicationWindow().overlay | ||||
139 | } | ||||
140 | } | ||||
141 | | ||||
142 | readonly property Item rootItem: MouseArea { | ||||
143 | id: mainItem | ||||
144 | //we want to be over any possible OverlayDrawers, including handles | ||||
145 | parent: root.parent == applicationWindow().overlay ? root.parent.parent : root.parent | ||||
146 | anchors.fill: parent | ||||
147 | z: 2000000 | ||||
148 | visible: false | ||||
149 | drag.filterChildren: true | ||||
150 | hoverEnabled: true | ||||
151 | | ||||
152 | onClicked: { | ||||
153 | var pos = mapToItem(flickableContents, mouse.x, mouse.y); | ||||
154 | if (!flickableContents.contains(pos)) { | ||||
155 | root.close(); | ||||
156 | } | ||||
157 | } | ||||
158 | | ||||
148 | onWidthChanged: { | 159 | onWidthChanged: { | ||
149 | if (!contentItem.contentItem) | 160 | if (!contentItem.contentItem) | ||
150 | return | 161 | return | ||
151 | 162 | | |||
152 | var width = Math.max(root.width/2, Math.min(root.width, root.contentItem.implicitWidth)); | 163 | var width = Math.max(mainItem.width/2, Math.min(mainItem.width, root.contentItem.implicitWidth)); | ||
153 | contentItem.contentItem.x = (root.width - width)/2 | 164 | contentItem.contentItem.x = (mainItem.width - width)/2 | ||
154 | contentItem.contentItem.width = width; | 165 | contentItem.contentItem.width = width; | ||
155 | } | 166 | } | ||
156 | onHeightChanged: { | 167 | onHeightChanged: { | ||
157 | var focusItem; | 168 | var focusItem; | ||
158 | 169 | | |||
159 | if (typeof applicationWindow !== "undefined") { | 170 | if (typeof applicationWindow !== "undefined") { | ||
160 | focusItem = applicationWindow().activeFocusItem; | 171 | focusItem = applicationWindow().activeFocusItem; | ||
161 | //fallback: hope activeFocusItem is in context | 172 | //fallback: hope activeFocusItem is in context | ||
Show All 29 Lines | |||||
191 | var pos = focusItem.mapToItem(flickableContents, 0, cursorY - Units.gridUnit*3); | 202 | var pos = focusItem.mapToItem(flickableContents, 0, cursorY - Units.gridUnit*3); | ||
192 | //focused item alreqady visible? add some margin for the space of the action buttons | 203 | //focused item alreqady visible? add some margin for the space of the action buttons | ||
193 | if (pos.y >= scrollView.flickableItem.contentY && pos.y <= scrollView.flickableItem.contentY + scrollView.flickableItem.height - Units.gridUnit * 8) { | 204 | if (pos.y >= scrollView.flickableItem.contentY && pos.y <= scrollView.flickableItem.contentY + scrollView.flickableItem.height - Units.gridUnit * 8) { | ||
194 | return; | 205 | return; | ||
195 | } | 206 | } | ||
196 | scrollView.flickableItem.contentY = pos.y; | 207 | scrollView.flickableItem.contentY = pos.y; | ||
197 | } | 208 | } | ||
198 | 209 | | |||
199 | | ||||
200 | NumberAnimation { | 210 | NumberAnimation { | ||
201 | id: openAnimation | 211 | id: openAnimation | ||
202 | property int topOpenPosition: Math.min(-root.height*0.15, scrollView.flickableItem.contentHeight - root.height + Units.gridUnit * 5) | 212 | property int topOpenPosition: Math.min(-mainItem.height*0.15, scrollView.flickableItem.contentHeight - mainItem.height + Units.gridUnit * 5) | ||
203 | property int bottomOpenPosition: (scrollView.flickableItem.contentHeight - root.height) + (Units.gridUnit * 5) | 213 | property int bottomOpenPosition: (scrollView.flickableItem.contentHeight - mainItem.height) + (Units.gridUnit * 5) | ||
204 | target: scrollView.flickableItem | 214 | target: scrollView.flickableItem | ||
205 | properties: "contentY" | 215 | properties: "contentY" | ||
206 | from: -root.height | 216 | from: -mainItem.height | ||
207 | to: topOpenPosition | 217 | to: topOpenPosition | ||
208 | duration: Units.longDuration | 218 | duration: Units.longDuration | ||
209 | easing.type: Easing.OutQuad | 219 | easing.type: Easing.OutQuad | ||
210 | onRunningChanged: { | 220 | onRunningChanged: { | ||
211 | if (!running && contentItem.contentItem) { | 221 | if (!running && contentItem.contentItem) { | ||
212 | var width = Math.max(root.width/2, Math.min(root.width, root.contentItem.implicitWidth)); | 222 | var width = Math.max(mainItem.width/2, Math.min(mainItem.width, root.contentItem.implicitWidth)); | ||
213 | contentItem.contentItem.x = (root.width - width)/2 | 223 | contentItem.contentItem.x = (mainItem.width - width)/2 | ||
214 | contentItem.contentItem.width = width; | 224 | contentItem.contentItem.width = width; | ||
215 | } | 225 | } | ||
216 | } | 226 | } | ||
217 | } | 227 | } | ||
218 | 228 | | |||
219 | SequentialAnimation { | 229 | SequentialAnimation { | ||
220 | id: closeAnimation | 230 | id: closeAnimation | ||
221 | property int to: -root.height | 231 | property int to: -mainItem.height | ||
222 | NumberAnimation { | 232 | NumberAnimation { | ||
223 | target: scrollView.flickableItem | 233 | target: scrollView.flickableItem | ||
224 | properties: "contentY" | 234 | properties: "contentY" | ||
225 | to: closeAnimation.to | 235 | to: closeAnimation.to | ||
226 | duration: Units.longDuration | 236 | duration: Units.longDuration | ||
227 | easing.type: Easing.InQuad | 237 | easing.type: Easing.InQuad | ||
228 | } | 238 | } | ||
229 | ScriptAction { | 239 | ScriptAction { | ||
230 | script: { | 240 | script: { | ||
231 | scrollView.flickableItem.contentY = -root.height; | 241 | scrollView.flickableItem.contentY = -mainItem.height; | ||
232 | root.visible = root.opened = false; | 242 | mainItem.visible = root.sheetOpen = false; | ||
233 | } | 243 | } | ||
234 | } | 244 | } | ||
235 | } | 245 | } | ||
236 | 246 | Rectangle { | |||
237 | MouseArea { | | |||
238 | anchors.fill: parent | 247 | anchors.fill: parent | ||
239 | z: 2 | 248 | color: Theme.textColor | ||
240 | drag.filterChildren: true | 249 | opacity: 0.6 * Math.min( | ||
241 | hoverEnabled: true | 250 | (Math.min(scrollView.flickableItem.contentY + scrollView.flickableItem.height, scrollView.flickableItem.height) / scrollView.flickableItem.height), | ||
242 | 251 | (2 + (scrollView.flickableItem.contentHeight - scrollView.flickableItem.contentY - scrollView.flickableItem.topMargin - scrollView.flickableItem.bottomMargin)/scrollView.flickableItem.height)) | |||
243 | onClicked: { | | |||
244 | var pos = mapToItem(flickableContents, mouse.x, mouse.y); | | |||
245 | if (!flickableContents.contains(pos)) { | | |||
246 | root.close(); | | |||
247 | } | | |||
248 | } | 252 | } | ||
249 | 253 | | |||
250 | Item { | 254 | Item { | ||
251 | id: flickableContents | 255 | id: flickableContents | ||
252 | //anchors.horizontalCenter: parent.horizontalCenter | 256 | //anchors.horizontalCenter: parent.horizontalCenter | ||
253 | x: (root.width - width) / 2 | 257 | x: (mainItem.width - width) / 2 | ||
254 | y: scrollView.flickableItem && root.contentItem.hasOwnProperty("contentY") ? -scrollView.flickableItem.contentY : 0 | 258 | y: scrollView.flickableItem && root.contentItem.hasOwnProperty("contentY") ? -scrollView.flickableItem.contentY : 0 | ||
255 | width: root.contentItem.implicitWidth <= 0 ? root.width : Math.max(root.width/2, Math.min(root.width, root.contentItem.implicitWidth)) | 259 | width: root.contentItem.implicitWidth <= 0 ? mainItem.width : Math.max(mainItem.width/2, Math.min(mainItem.width, root.contentItem.implicitWidth)) | ||
256 | height: scrollView.flickableItem && root.contentItem.hasOwnProperty("contentY") ? scrollView.flickableItem.contentHeight : (root.contentItem.height + topPadding + bottomPadding + Units.iconSizes.medium + Units.gridUnit) | 260 | height: scrollView.flickableItem && root.contentItem.hasOwnProperty("contentY") ? scrollView.flickableItem.contentHeight : (root.contentItem.height + topPadding + bottomPadding + Units.iconSizes.medium + Units.gridUnit) | ||
257 | Item { | 261 | Item { | ||
258 | id: contentItemParent | 262 | id: contentItemParent | ||
259 | anchors { | 263 | anchors { | ||
260 | fill: parent | 264 | fill: parent | ||
261 | leftMargin: leftPadding | 265 | leftMargin: leftPadding | ||
262 | topMargin: topPadding | 266 | topMargin: topPadding | ||
263 | rightMargin: rightPadding | 267 | rightMargin: rightPadding | ||
Show All 13 Lines | 278 | Binding { | |||
277 | property: "bottomMargin" | 281 | property: "bottomMargin" | ||
278 | value: scrollView.height | 282 | value: scrollView.height | ||
279 | } | 283 | } | ||
280 | 284 | | |||
281 | Connections { | 285 | Connections { | ||
282 | target: scrollView.flickableItem | 286 | target: scrollView.flickableItem | ||
283 | function movementEnded() { | 287 | function movementEnded() { | ||
284 | //close | 288 | //close | ||
285 | if ((root.height + scrollView.flickableItem.contentY) < root.height/2) { | 289 | if ((mainItem.height + scrollView.flickableItem.contentY) < mainItem.height/2) { | ||
286 | closeAnimation.to = -root.height; | 290 | closeAnimation.to = -mainItem.height; | ||
287 | closeAnimation.running = true; | 291 | closeAnimation.running = true; | ||
288 | } else if ((root.height*0.6 + scrollView.flickableItem.contentY) > scrollView.flickableItem.contentHeight) { | 292 | } else if ((mainItem.height*0.6 + scrollView.flickableItem.contentY) > scrollView.flickableItem.contentHeight) { | ||
289 | closeAnimation.to = scrollView.flickableItem.contentHeight | 293 | closeAnimation.to = scrollView.flickableItem.contentHeight | ||
290 | closeAnimation.running = true; | 294 | closeAnimation.running = true; | ||
291 | 295 | | |||
292 | //reset to the default opened position | 296 | //reset to the default sheetOpen position | ||
293 | } else if (scrollView.flickableItem.contentY < openAnimation.topOpenPosition) { | 297 | } else if (scrollView.flickableItem.contentY < openAnimation.topOpenPosition) { | ||
294 | openAnimation.from = scrollView.flickableItem.contentY; | 298 | openAnimation.from = scrollView.flickableItem.contentY; | ||
295 | openAnimation.to = openAnimation.topOpenPosition; | 299 | openAnimation.to = openAnimation.topOpenPosition; | ||
296 | openAnimation.running = true; | 300 | openAnimation.running = true; | ||
297 | //reset to the default "bottom" opened position | 301 | //reset to the default "bottom" sheetOpen position | ||
298 | } else if (scrollView.flickableItem.contentY > openAnimation.bottomOpenPosition) { | 302 | } else if (scrollView.flickableItem.contentY > openAnimation.bottomOpenPosition) { | ||
299 | openAnimation.from = scrollView.flickableItem.contentY; | 303 | openAnimation.from = scrollView.flickableItem.contentY; | ||
300 | openAnimation.to = openAnimation.bottomOpenPosition; | 304 | openAnimation.to = openAnimation.bottomOpenPosition; | ||
301 | openAnimation.running = true; | 305 | openAnimation.running = true; | ||
302 | } | 306 | } | ||
303 | } | 307 | } | ||
304 | onMovementEnded: movementEnded(); | 308 | onMovementEnded: movementEnded(); | ||
305 | onFlickEnded: movementEnded(); | 309 | onFlickEnded: movementEnded(); | ||
306 | onContentHeightChanged: { | 310 | onContentHeightChanged: { | ||
307 | if (openAnimation.running) { | 311 | if (openAnimation.running) { | ||
308 | openAnimation.running = false; | 312 | openAnimation.running = false; | ||
309 | open(); | 313 | open(); | ||
310 | } | 314 | } | ||
311 | } | 315 | } | ||
312 | } | 316 | } | ||
313 | Controls.ScrollView { | 317 | | ||
318 | //add an extra background for the scrollbar | ||||
319 | Rectangle { | ||||
320 | z: -1 | ||||
321 | parent: scrollView.verticalScrollBar.background | ||||
322 | anchors.fill:parent | ||||
323 | color: Theme.viewBackgroundColor | ||||
324 | } | ||||
325 | Binding { | ||||
326 | target: scrollView.verticalScrollBar | ||||
327 | property: "visible" | ||||
328 | value: scrollView.flickableItem.contentHeight > mainItem.height*0.8 | ||||
329 | } | ||||
330 | Connections { | ||||
331 | target: scrollView.verticalScrollBar | ||||
332 | onActiveChanged: { | ||||
333 | if (!scrollView.verticalScrollBar.active) { | ||||
334 | scrollView.flickableItem.movementEnded(); | ||||
335 | } | ||||
336 | } | ||||
337 | } | ||||
338 | ScrollView { | ||||
314 | id: scrollView | 339 | id: scrollView | ||
315 | anchors.fill: parent | 340 | anchors.fill: parent | ||
316 | horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff | 341 | horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff | ||
317 | } | 342 | } | ||
318 | } | 343 | } | ||
319 | } | 344 | } |