Merge lp:~ahayzen/ubuntu-ui-extras/tabs-add-dnd into lp:~phablet-team/ubuntu-ui-extras/tabs
- tabs-add-dnd
- Merge into tabs
Proposed by
Andrew Hayzen
Status: | Merged |
---|---|
Merged at revision: | 122 |
Proposed branch: | lp:~ahayzen/ubuntu-ui-extras/tabs-add-dnd |
Merge into: | lp:~phablet-team/ubuntu-ui-extras/tabs |
Diff against target: |
672 lines (+490/-7) 8 files modified
modules/Ubuntu/Components/Extras/TabsBar.qml (+147/-4) modules/Ubuntu/Components/Extras/TabsBar/DragAndDropSettings.qml (+32/-0) modules/Ubuntu/Components/Extras/TabsBar/Tab.qml (+1/-0) modules/Ubuntu/Components/Extras/plugin/CMakeLists.txt (+5/-1) modules/Ubuntu/Components/Extras/plugin/components.cpp (+6/-1) modules/Ubuntu/Components/Extras/plugin/components.h (+1/-1) modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.cpp (+205/-0) modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.h (+93/-0) |
To merge this branch: | bzr merge lp:~ahayzen/ubuntu-ui-extras/tabs-add-dnd |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Florian Boucault | Pending | ||
Review via email: mp+314003@code.launchpad.net |
Commit message
* Add drag and drop support to tabs component
Description of the change
* Add drag and drop support to tabs component
To post a comment you must log in.
Revision history for this message
Andrew Hayzen (ahayzen) wrote : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'modules/Ubuntu/Components/Extras/TabsBar.qml' | |||
2 | --- modules/Ubuntu/Components/Extras/TabsBar.qml 2016-12-08 14:26:41 +0000 | |||
3 | +++ modules/Ubuntu/Components/Extras/TabsBar.qml 2017-01-06 16:37:25 +0000 | |||
4 | @@ -1,5 +1,5 @@ | |||
5 | 1 | /* | 1 | /* |
7 | 2 | * Copyright (C) 2016 Canonical Ltd | 2 | * Copyright (C) 2016, 2017 Canonical Ltd |
8 | 3 | * | 3 | * |
9 | 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 |
10 | 5 | * it under the terms of the GNU General Public License version 3 as | 5 | * it under the terms of the GNU General Public License version 3 as |
11 | @@ -22,6 +22,8 @@ | |||
12 | 22 | import Ubuntu.Components 1.3 | 22 | import Ubuntu.Components 1.3 |
13 | 23 | import "TabsBar" as LocalTabs | 23 | import "TabsBar" as LocalTabs |
14 | 24 | 24 | ||
15 | 25 | import Ubuntu.Components.Extras 0.3 | ||
16 | 26 | |||
17 | 25 | Rectangle { | 27 | Rectangle { |
18 | 26 | id: tabsBar | 28 | id: tabsBar |
19 | 27 | 29 | ||
20 | @@ -35,15 +37,40 @@ | |||
21 | 35 | property color highlightColor: Qt.rgba(actionColor.r, actionColor.g, actionColor.b, 0.1) | 37 | property color highlightColor: Qt.rgba(actionColor.r, actionColor.g, actionColor.b, 0.1) |
22 | 36 | /* 'model' needs to have the following members: | 38 | /* 'model' needs to have the following members: |
23 | 37 | property int selectedIndex | 39 | property int selectedIndex |
24 | 40 | function addExistingTab(var tab) | ||
25 | 38 | function selectTab(int index) | 41 | function selectTab(int index) |
26 | 39 | function removeTab(int index) | 42 | function removeTab(int index) |
27 | 43 | function removeTabWithoutDestroying(int index) | ||
28 | 40 | function moveTab(int from, int to) | 44 | function moveTab(int from, int to) |
29 | 45 | |||
30 | 46 | removeTabWithoutDestroying is useful when a tab is being removed due | ||
31 | 47 | to moving, so you don't want the content to be destroyed | ||
32 | 41 | */ | 48 | */ |
33 | 42 | property var model | 49 | property var model |
34 | 43 | property list<Action> actions | 50 | property list<Action> actions |
35 | 51 | property bool dimmed: false | ||
36 | 52 | |||
37 | 53 | /* To enable drag and drop set to enabled | ||
38 | 54 | * | ||
39 | 55 | * Use expose to set any information you need the DropArea to access | ||
40 | 56 | * Then use drag.source.expose.myproperty | ||
41 | 57 | * | ||
42 | 58 | * Set mimeType to one of the keys in the DropArea's you want to accept | ||
43 | 59 | * | ||
44 | 60 | * Set a function for previewUrlFromIndex which is given the index | ||
45 | 61 | * and returns a url to an image, which will be shown in the handle | ||
46 | 62 | */ | ||
47 | 63 | readonly property alias dragAndDrop: dragAndDropImpl | ||
48 | 64 | |||
49 | 65 | LocalTabs.DragAndDropSettings { | ||
50 | 66 | id: dragAndDropImpl | ||
51 | 67 | } | ||
52 | 44 | 68 | ||
53 | 45 | property string fallbackIcon: "" | 69 | property string fallbackIcon: "" |
54 | 46 | 70 | ||
55 | 71 | property Component windowFactory: null | ||
56 | 72 | property var windowFactoryProperties: ({}) // any addition properties such as height, width | ||
57 | 73 | |||
58 | 47 | signal contextMenu(var tabDelegate, int index) | 74 | signal contextMenu(var tabDelegate, int index) |
59 | 48 | 75 | ||
60 | 49 | function iconNameFromModelItem(modelItem, index) { | 76 | function iconNameFromModelItem(modelItem, index) { |
61 | @@ -106,6 +133,7 @@ | |||
62 | 106 | right: tabs.overflow ? rightStepper.left : actions.left | 133 | right: tabs.overflow ? rightStepper.left : actions.left |
63 | 107 | } | 134 | } |
64 | 108 | interactive: false | 135 | interactive: false |
65 | 136 | objectName: "tabListView" | ||
66 | 109 | orientation: ListView.Horizontal | 137 | orientation: ListView.Horizontal |
67 | 110 | clip: true | 138 | clip: true |
68 | 111 | highlightMoveDuration: UbuntuAnimation.FastDuration | 139 | highlightMoveDuration: UbuntuAnimation.FastDuration |
69 | @@ -139,16 +167,21 @@ | |||
70 | 139 | model: tabsBar.model | 167 | model: tabsBar.model |
71 | 140 | delegate: MouseArea { | 168 | delegate: MouseArea { |
72 | 141 | id: tabMouseArea | 169 | id: tabMouseArea |
73 | 170 | objectName: "tabDelegate" | ||
74 | 142 | 171 | ||
75 | 172 | acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton | ||
76 | 143 | width: tab.width | 173 | width: tab.width |
77 | 144 | height: tab.height | 174 | height: tab.height |
78 | 145 | drag { | 175 | drag { |
81 | 146 | target: tabs.count > 1 && tab.isFocused ? tab : null | 176 | target: (tabs.count > 1 || dragAndDrop.enabled) && tab.isFocused ? tab : null |
82 | 147 | axis: Drag.XAxis | 177 | axis: dragAndDrop.enabled ? Drag.XAndYAxis : Drag.XAxis |
83 | 148 | minimumX: tab.isDragged ? -tab.width/2 : -Infinity | 178 | minimumX: tab.isDragged ? -tab.width/2 : -Infinity |
84 | 149 | maximumX: tab.isDragged ? tabs.width - tab.width/2 : Infinity | 179 | maximumX: tab.isDragged ? tabs.width - tab.width/2 : Infinity |
85 | 150 | } | 180 | } |
86 | 151 | z: tab.isFocused ? 1 : 0 | 181 | z: tab.isFocused ? 1 : 0 |
87 | 182 | |||
88 | 183 | readonly property int tabIndex: index // for autopilot | ||
89 | 184 | |||
90 | 152 | Binding { | 185 | Binding { |
91 | 153 | target: tabsBar | 186 | target: tabsBar |
92 | 154 | property: "selectedTabX" | 187 | property: "selectedTabX" |
93 | @@ -161,6 +194,13 @@ | |||
94 | 161 | value: tab.width | 194 | value: tab.width |
95 | 162 | when: tab.isFocused | 195 | when: tab.isFocused |
96 | 163 | } | 196 | } |
97 | 197 | NumberAnimation { | ||
98 | 198 | id: resetVerticalAnimation | ||
99 | 199 | target: tab | ||
100 | 200 | duration: 250 | ||
101 | 201 | property: "y" | ||
102 | 202 | to: 0 | ||
103 | 203 | } | ||
104 | 164 | 204 | ||
105 | 165 | onPressed: { | 205 | onPressed: { |
106 | 166 | if (mouse.button === Qt.LeftButton) { | 206 | if (mouse.button === Qt.LeftButton) { |
107 | @@ -171,6 +211,7 @@ | |||
108 | 171 | tabsBar.model.removeTab(index) | 211 | tabsBar.model.removeTab(index) |
109 | 172 | } | 212 | } |
110 | 173 | } | 213 | } |
111 | 214 | onReleased: resetVerticalAnimation.start() | ||
112 | 174 | onWheel: { | 215 | onWheel: { |
113 | 175 | if (wheel.angleDelta.y >= 0) { | 216 | if (wheel.angleDelta.y >= 0) { |
114 | 176 | tabsBar.model.selectTab(tabsBar.model.selectedIndex - 1); | 217 | tabsBar.model.selectTab(tabsBar.model.selectedIndex - 1); |
115 | @@ -183,12 +224,17 @@ | |||
116 | 183 | 224 | ||
117 | 184 | LocalTabs.Tab { | 225 | LocalTabs.Tab { |
118 | 185 | id: tab | 226 | id: tab |
119 | 227 | objectName: "tabItem" | ||
120 | 186 | 228 | ||
121 | 187 | anchors.left: tabMouseArea.left | 229 | anchors.left: tabMouseArea.left |
122 | 188 | implicitWidth: tabs.availableWidth / 2 | 230 | implicitWidth: tabs.availableWidth / 2 |
123 | 189 | width: tabs.overflow ? tabs.availableWidth / tabs.maximumTabsCount : Math.min(tabs.maximumTabWidth, implicitWidth) | 231 | width: tabs.overflow ? tabs.availableWidth / tabs.maximumTabsCount : Math.min(tabs.maximumTabWidth, implicitWidth) |
124 | 190 | height: tabs.height | 232 | height: tabs.height |
125 | 191 | 233 | ||
126 | 234 | // Reference the tab and window so that the dropArea can determine what to do | ||
127 | 235 | readonly property var thisTab: tabsBar.model.get(index) | ||
128 | 236 | readonly property var thisWindow: dragAndDrop.thisWindow | ||
129 | 237 | |||
130 | 192 | property bool isDragged: tabMouseArea.drag.active | 238 | property bool isDragged: tabMouseArea.drag.active |
131 | 193 | Drag.active: tab.isDragged | 239 | Drag.active: tab.isDragged |
132 | 194 | Drag.source: tabMouseArea | 240 | Drag.source: tabMouseArea |
133 | @@ -243,6 +289,67 @@ | |||
134 | 243 | } | 289 | } |
135 | 244 | } | 290 | } |
136 | 245 | } | 291 | } |
137 | 292 | |||
138 | 293 | DragHelper { | ||
139 | 294 | id: dragHelper | ||
140 | 295 | expectedAction: dragAndDrop.expectedAction | ||
141 | 296 | mimeType: dragAndDrop.mimeType | ||
142 | 297 | previewBorderWidth: dragAndDrop.previewBorderWidth | ||
143 | 298 | previewSize: dragAndDrop.previewSize | ||
144 | 299 | previewTopCrop: dragAndDrop.previewTopCrop | ||
145 | 300 | previewUrl: dragAndDrop.previewUrlFromIndex(index) | ||
146 | 301 | source: tab | ||
147 | 302 | } | ||
148 | 303 | |||
149 | 304 | onPositionChanged: { | ||
150 | 305 | if (!dragAndDrop.enabled || !tabMouseArea.drag.active) { | ||
151 | 306 | return; | ||
152 | 307 | } | ||
153 | 308 | |||
154 | 309 | // Keep the visual tab within maxYDiff of starting point when | ||
155 | 310 | // dragging vertically so that it doesn't cover other elements | ||
156 | 311 | // or appear to be detached | ||
157 | 312 | tab.y = Math.abs(tab.y) > dragAndDrop.maxYDiff ? (tab.y > 0 ? 1 : -1) * dragAndDrop.maxYDiff : tab.y | ||
158 | 313 | |||
159 | 314 | // Initiate drag and drop if mouse y has gone further than the height from the object | ||
160 | 315 | if (mouse.y > height * 2 || mouse.y < -height) { | ||
161 | 316 | // Reset visual position of tab delegate | ||
162 | 317 | resetVerticalAnimation.start(); | ||
163 | 318 | |||
164 | 319 | var dropAction = dragHelper.execDrag(index); | ||
165 | 320 | |||
166 | 321 | // IgnoreAction - no DropArea accepted so New Window | ||
167 | 322 | // MoveAction - DropArea accept but different window | ||
168 | 323 | // CopyAction - DropArea accept but same window | ||
169 | 324 | |||
170 | 325 | if (dropAction === Qt.MoveAction) { | ||
171 | 326 | // Moved into another window | ||
172 | 327 | |||
173 | 328 | // Just remove from model and do not destroy | ||
174 | 329 | // as webview is used in other window | ||
175 | 330 | tabsBar.model.removeTabWithoutDestroying(index); | ||
176 | 331 | } else if (dropAction === Qt.CopyAction) { | ||
177 | 332 | // Moved into the same window | ||
178 | 333 | |||
179 | 334 | // So no action | ||
180 | 335 | } else if (dropAction === Qt.IgnoreAction) { | ||
181 | 336 | // Moved outside of any window | ||
182 | 337 | |||
183 | 338 | // Create new window and add existing tab | ||
184 | 339 | var window = windowFactory.createObject(null, windowFactoryProperties); | ||
185 | 340 | window.model.addExistingTab(tab.thisTab); | ||
186 | 341 | window.model.selectTab(window.model.count - 1); | ||
187 | 342 | window.show(); | ||
188 | 343 | |||
189 | 344 | // Just remove from model and do not destroy | ||
190 | 345 | // as webview is used in other window | ||
191 | 346 | tabsBar.model.removeTabWithoutDestroying(index); | ||
192 | 347 | } else { | ||
193 | 348 | // Unknown state | ||
194 | 349 | console.debug("Unknown drop action:", dropAction); | ||
195 | 350 | } | ||
196 | 351 | } | ||
197 | 352 | } | ||
198 | 246 | } | 353 | } |
199 | 247 | } | 354 | } |
200 | 248 | 355 | ||
201 | @@ -290,6 +397,7 @@ | |||
202 | 290 | model: tabsBar.actions | 397 | model: tabsBar.actions |
203 | 291 | 398 | ||
204 | 292 | LocalTabs.TabButton { | 399 | LocalTabs.TabButton { |
205 | 400 | objectName: modelData.objectName | ||
206 | 293 | iconColor: tabsBar.actionColor | 401 | iconColor: tabsBar.actionColor |
207 | 294 | iconSource: modelData.iconSource | 402 | iconSource: modelData.iconSource |
208 | 295 | onClicked: modelData.trigger() | 403 | onClicked: modelData.trigger() |
209 | @@ -303,6 +411,41 @@ | |||
210 | 303 | anchors.fill: parent | 411 | anchors.fill: parent |
211 | 304 | color: backgroundColor | 412 | color: backgroundColor |
212 | 305 | opacity: 0.4 | 413 | opacity: 0.4 |
214 | 306 | visible: !Window.active | 414 | visible: !Window.active || (dimmed && !dropArea.containsDrag) |
215 | 415 | } | ||
216 | 416 | |||
217 | 417 | DropArea { | ||
218 | 418 | id: dropArea | ||
219 | 419 | anchors { | ||
220 | 420 | fill: parent | ||
221 | 421 | } | ||
222 | 422 | keys: [dragAndDrop.mimeType] | ||
223 | 423 | |||
224 | 424 | onDropped: { | ||
225 | 425 | // IgnoreAction - no DropArea accepted so New Window | ||
226 | 426 | // MoveAction - DropArea accept but different window | ||
227 | 427 | // CopyAction - DropArea accept but same window | ||
228 | 428 | if (drag.source.thisWindow === dragAndDrop.thisWindow) { | ||
229 | 429 | // Dropped in same window | ||
230 | 430 | drop.accept(Qt.CopyAction); | ||
231 | 431 | } else { | ||
232 | 432 | // Dropped in new window, moving tab | ||
233 | 433 | tabsBar.model.addExistingTab(drag.source.thisTab); | ||
234 | 434 | tabsBar.model.selectTab(tabsBar.model.count - 1); | ||
235 | 435 | |||
236 | 436 | drop.accept(Qt.MoveAction); | ||
237 | 437 | } | ||
238 | 438 | } | ||
239 | 439 | onEntered: { | ||
240 | 440 | thisWindow.raise() | ||
241 | 441 | thisWindow.requestActivate(); | ||
242 | 442 | } | ||
243 | 443 | onPositionChanged: { | ||
244 | 444 | if (drag.source.thisWindow === dragAndDrop.thisWindow) { | ||
245 | 445 | // tab drag is within same window and in chrome | ||
246 | 446 | // so reorder tabs by setting tab x position | ||
247 | 447 | drag.source.x = drag.x - (drag.source.width / 2); | ||
248 | 448 | } | ||
249 | 449 | } | ||
250 | 307 | } | 450 | } |
251 | 308 | } | 451 | } |
252 | 309 | 452 | ||
253 | === added file 'modules/Ubuntu/Components/Extras/TabsBar/DragAndDropSettings.qml' | |||
254 | --- modules/Ubuntu/Components/Extras/TabsBar/DragAndDropSettings.qml 1970-01-01 00:00:00 +0000 | |||
255 | +++ modules/Ubuntu/Components/Extras/TabsBar/DragAndDropSettings.qml 2017-01-06 16:37:25 +0000 | |||
256 | @@ -0,0 +1,32 @@ | |||
257 | 1 | /* | ||
258 | 2 | * Copyright (C) 2016 Canonical Ltd | ||
259 | 3 | * | ||
260 | 4 | * This program is free software: you can redistribute it and/or modify | ||
261 | 5 | * it under the terms of the GNU General Public License version 3 as | ||
262 | 6 | * published by the Free Software Foundation. | ||
263 | 7 | * | ||
264 | 8 | * This program is distributed in the hope that it will be useful, | ||
265 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
266 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
267 | 11 | * GNU General Public License for more details. | ||
268 | 12 | * | ||
269 | 13 | * You should have received a copy of the GNU General Public License | ||
270 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
271 | 15 | * | ||
272 | 16 | * Authored-by: Andrew Hayzen <andrew.hayzen@canonical.com> | ||
273 | 17 | */ | ||
274 | 18 | import QtQuick 2.4 | ||
275 | 19 | |||
276 | 20 | QtObject { | ||
277 | 21 | property bool enabled: false | ||
278 | 22 | property var expectedAction: Qt.IgnoreAction | Qt.CopyAction | Qt.MoveAction | ||
279 | 23 | property int maxYDiff: parent.height / 16 | ||
280 | 24 | property string mimeType: "x-tabsbar/tab" | ||
281 | 25 | property real previewBorderWidth: units.gu(1) | ||
282 | 26 | property var previewSize: Qt.size(units.gu(35), units.gu(22.5)) | ||
283 | 27 | property real previewTopCrop: 0 | ||
284 | 28 | property var previewUrlFromIndex: function(index) { | ||
285 | 29 | return ""; | ||
286 | 30 | } | ||
287 | 31 | property var thisWindow: null // Qt 5.7 retrieve from attached property | ||
288 | 32 | } | ||
289 | 0 | 33 | ||
290 | === modified file 'modules/Ubuntu/Components/Extras/TabsBar/Tab.qml' | |||
291 | --- modules/Ubuntu/Components/Extras/TabsBar/Tab.qml 2016-12-08 14:26:41 +0000 | |||
292 | +++ modules/Ubuntu/Components/Extras/TabsBar/Tab.qml 2017-01-06 16:37:25 +0000 | |||
293 | @@ -78,6 +78,7 @@ | |||
294 | 78 | 78 | ||
295 | 79 | MouseArea { | 79 | MouseArea { |
296 | 80 | id: tabCloseButton | 80 | id: tabCloseButton |
297 | 81 | objectName: "tabCloseButton" | ||
298 | 81 | 82 | ||
299 | 82 | anchors { | 83 | anchors { |
300 | 83 | top: parent.top | 84 | top: parent.top |
301 | 84 | 85 | ||
302 | === modified file 'modules/Ubuntu/Components/Extras/plugin/CMakeLists.txt' | |||
303 | --- modules/Ubuntu/Components/Extras/plugin/CMakeLists.txt 2016-07-06 08:26:51 +0000 | |||
304 | +++ modules/Ubuntu/Components/Extras/plugin/CMakeLists.txt 2017-01-06 16:37:25 +0000 | |||
305 | @@ -19,12 +19,16 @@ | |||
306 | 19 | photoeditor/photo-edit-thread.cpp | 19 | photoeditor/photo-edit-thread.cpp |
307 | 20 | ) | 20 | ) |
308 | 21 | 21 | ||
309 | 22 | set(TABS_BAR_PLUGIN_SRC | ||
310 | 23 | tabsbar/drag-helper.cpp | ||
311 | 24 | ) | ||
312 | 25 | |||
313 | 22 | include_directories( | 26 | include_directories( |
314 | 23 | ${CMAKE_BINARY_DIR} | 27 | ${CMAKE_BINARY_DIR} |
315 | 24 | ) | 28 | ) |
316 | 25 | 29 | ||
317 | 26 | add_library(ubuntu-ui-extras-plugin SHARED ${PLUGIN_SRC} ${PLUGIN_HDRS} | 30 | add_library(ubuntu-ui-extras-plugin SHARED ${PLUGIN_SRC} ${PLUGIN_HDRS} |
319 | 27 | ${EXAMPLE_PLUGIN_SRC} ${PHOTO_EDITOR_PLUGIN_SRC}) | 31 | ${EXAMPLE_PLUGIN_SRC} ${PHOTO_EDITOR_PLUGIN_SRC} ${TABS_BAR_PLUGIN_SRC}) |
320 | 28 | qt5_use_modules(ubuntu-ui-extras-plugin Core Qml Quick Xml Widgets) | 32 | qt5_use_modules(ubuntu-ui-extras-plugin Core Qml Quick Xml Widgets) |
321 | 29 | target_link_libraries(ubuntu-ui-extras-plugin | 33 | target_link_libraries(ubuntu-ui-extras-plugin |
322 | 30 | ${EXIV2_LIBRARIES} | 34 | ${EXIV2_LIBRARIES} |
323 | 31 | 35 | ||
324 | === modified file 'modules/Ubuntu/Components/Extras/plugin/components.cpp' | |||
325 | --- modules/Ubuntu/Components/Extras/plugin/components.cpp 2015-04-29 15:48:07 +0000 | |||
326 | +++ modules/Ubuntu/Components/Extras/plugin/components.cpp 2017-01-06 16:37:25 +0000 | |||
327 | @@ -1,5 +1,5 @@ | |||
328 | 1 | /* | 1 | /* |
330 | 2 | * Copyright (C) 2012-2013 Canonical, Ltd. | 2 | * Copyright (C) 2012-2013, 2016 Canonical, Ltd. |
331 | 3 | * | 3 | * |
332 | 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 |
333 | 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 |
334 | @@ -23,6 +23,8 @@ | |||
335 | 23 | #include "photoeditor/photo-image-provider.h" | 23 | #include "photoeditor/photo-image-provider.h" |
336 | 24 | #include "photoeditor/file-utils.h" | 24 | #include "photoeditor/file-utils.h" |
337 | 25 | 25 | ||
338 | 26 | #include "tabsbar/drag-helper.h" | ||
339 | 27 | |||
340 | 26 | void Components::registerTypes(const char *uri) | 28 | void Components::registerTypes(const char *uri) |
341 | 27 | { | 29 | { |
342 | 28 | // Example component | 30 | // Example component |
343 | @@ -32,6 +34,9 @@ | |||
344 | 32 | qmlRegisterType<PhotoData>(uri, 0, 2, "PhotoData"); | 34 | qmlRegisterType<PhotoData>(uri, 0, 2, "PhotoData"); |
345 | 33 | qmlRegisterSingletonType<FileUtils>(uri, 0, 2, "FileUtils", | 35 | qmlRegisterSingletonType<FileUtils>(uri, 0, 2, "FileUtils", |
346 | 34 | exportFileUtilsSingleton); | 36 | exportFileUtilsSingleton); |
347 | 37 | |||
348 | 38 | // TabsBar component | ||
349 | 39 | qmlRegisterType<DragHelper>(uri, 0, 3, "DragHelper"); | ||
350 | 35 | } | 40 | } |
351 | 36 | 41 | ||
352 | 37 | void Components::initializeEngine(QQmlEngine *engine, const char *uri) | 42 | void Components::initializeEngine(QQmlEngine *engine, const char *uri) |
353 | 38 | 43 | ||
354 | === modified file 'modules/Ubuntu/Components/Extras/plugin/components.h' | |||
355 | --- modules/Ubuntu/Components/Extras/plugin/components.h 2014-11-19 10:14:20 +0000 | |||
356 | +++ modules/Ubuntu/Components/Extras/plugin/components.h 2017-01-06 16:37:25 +0000 | |||
357 | @@ -1,5 +1,5 @@ | |||
358 | 1 | /* | 1 | /* |
360 | 2 | * Copyright (C) 2012-2013 Canonical, Ltd. | 2 | * Copyright (C) 2012-2013, 2016 Canonical, Ltd. |
361 | 3 | * | 3 | * |
362 | 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 |
363 | 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 |
364 | 6 | 6 | ||
365 | === added directory 'modules/Ubuntu/Components/Extras/plugin/tabsbar' | |||
366 | === added file 'modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.cpp' | |||
367 | --- modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.cpp 1970-01-01 00:00:00 +0000 | |||
368 | +++ modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.cpp 2017-01-06 16:37:25 +0000 | |||
369 | @@ -0,0 +1,205 @@ | |||
370 | 1 | /* | ||
371 | 2 | * Copyright 2016 Canonical Ltd. | ||
372 | 3 | * | ||
373 | 4 | * This file is part of webbrowser-app. | ||
374 | 5 | * | ||
375 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
376 | 7 | * it under the terms of the GNU General Public License as published by | ||
377 | 8 | * the Free Software Foundation; version 3. | ||
378 | 9 | * | ||
379 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
380 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
381 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
382 | 13 | * GNU General Public License for more details. | ||
383 | 14 | * | ||
384 | 15 | * You should have received a copy of the GNU General Public License | ||
385 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
386 | 17 | * | ||
387 | 18 | * Authored-by: Andrew Hayzen <andrew.hayzen@canonical.com> | ||
388 | 19 | */ | ||
389 | 20 | |||
390 | 21 | #include "drag-helper.h" | ||
391 | 22 | |||
392 | 23 | #include <QtCore/QMimeData> | ||
393 | 24 | #include <QtCore/QPoint> | ||
394 | 25 | #include <QtCore/QSize> | ||
395 | 26 | #include <QtCore/QString> | ||
396 | 27 | #include <QtGui/QDrag> | ||
397 | 28 | #include <QtGui/QDropEvent> | ||
398 | 29 | #include <QtGui/QPainter> | ||
399 | 30 | #include <QtGui/QPen> | ||
400 | 31 | #include <QtGui/QPixmap> | ||
401 | 32 | #include <QtQuick/QQuickItem> | ||
402 | 33 | |||
403 | 34 | DragHelper::DragHelper() | ||
404 | 35 | : QObject(), | ||
405 | 36 | m_active(false), | ||
406 | 37 | m_dragging(false), | ||
407 | 38 | m_expected_action(Qt::IgnoreAction), | ||
408 | 39 | m_mime_type(QStringLiteral("x-tabsbar/tab")), | ||
409 | 40 | m_preview_border_width(8), | ||
410 | 41 | m_preview_size(QSizeF(200, 150)), | ||
411 | 42 | m_preview_top_crop(0), | ||
412 | 43 | m_preview_url(""), | ||
413 | 44 | m_source(Q_NULLPTR) | ||
414 | 45 | { | ||
415 | 46 | |||
416 | 47 | } | ||
417 | 48 | |||
418 | 49 | QPixmap DragHelper::drawPixmapWithBorder(QPixmap pixmap, int borderWidth, QColor color) | ||
419 | 50 | { | ||
420 | 51 | // Create a transparent pixmap to draw to | ||
421 | 52 | QPixmap output(pixmap.width() + borderWidth * 2, pixmap.height() + borderWidth * 2); | ||
422 | 53 | output.fill(QColor(0, 0, 0, 0)); | ||
423 | 54 | |||
424 | 55 | // Draw the pixmap with space around the edge for a border | ||
425 | 56 | QPainter borderPainter(&output); | ||
426 | 57 | borderPainter.setRenderHint(QPainter::Antialiasing); | ||
427 | 58 | borderPainter.drawPixmap(borderWidth, borderWidth, pixmap); | ||
428 | 59 | |||
429 | 60 | // Define a pen to use for the border | ||
430 | 61 | QPen borderPen; | ||
431 | 62 | borderPen.setColor(color); | ||
432 | 63 | borderPen.setJoinStyle(Qt::MiterJoin); | ||
433 | 64 | borderPen.setStyle(Qt::SolidLine); | ||
434 | 65 | borderPen.setWidth(borderWidth); | ||
435 | 66 | |||
436 | 67 | // Set the pen and draw the border | ||
437 | 68 | borderPainter.setPen(borderPen); | ||
438 | 69 | borderPainter.drawRect(borderWidth / 2, borderWidth / 2, | ||
439 | 70 | output.width() - borderWidth, output.height() - borderWidth); | ||
440 | 71 | |||
441 | 72 | return output; | ||
442 | 73 | } | ||
443 | 74 | |||
444 | 75 | Qt::DropAction DragHelper::execDrag(QString tabId) | ||
445 | 76 | { | ||
446 | 77 | QDrag *drag = new QDrag(m_source); | ||
447 | 78 | |||
448 | 79 | // Create a mimedata object to use for the drag | ||
449 | 80 | QMimeData *mimeData = new QMimeData; | ||
450 | 81 | mimeData->setData(mimeType(), tabId.toLatin1()); | ||
451 | 82 | |||
452 | 83 | // Get a bordered pixmap of the previewUrl | ||
453 | 84 | QSize size = previewSize().toSize(); | ||
454 | 85 | |||
455 | 86 | QPixmap pixmap = drawPixmapWithBorder(getPreviewUrlAsPixmap(size.width(), size.height()), | ||
456 | 87 | previewBorderWidth(), QColor(205, 205, 205, 255 * 0.6)); // #cdcdcd | ||
457 | 88 | |||
458 | 89 | // Setup the drag and then execute it | ||
459 | 90 | drag->setHotSpot(QPoint(size.width() * 0.1, size.height() * 0.1)); | ||
460 | 91 | drag->setMimeData(mimeData); | ||
461 | 92 | drag->setPixmap(pixmap); | ||
462 | 93 | |||
463 | 94 | setDragging(true); | ||
464 | 95 | |||
465 | 96 | Qt::DropAction action = drag->exec(expectedAction()); | ||
466 | 97 | |||
467 | 98 | setDragging(false); | ||
468 | 99 | |||
469 | 100 | return action; | ||
470 | 101 | } | ||
471 | 102 | |||
472 | 103 | QPixmap DragHelper::getPreviewUrlAsPixmap(int width, int height) | ||
473 | 104 | { | ||
474 | 105 | QSize pixmapSize(width, height); | ||
475 | 106 | QPixmap pixmap(previewUrl()); | ||
476 | 107 | |||
477 | 108 | if (pixmap.isNull()) { | ||
478 | 109 | // If loading pixmap failed, draw a white rectangle | ||
479 | 110 | pixmap = QPixmap(pixmapSize); | ||
480 | 111 | QPainter painter(&pixmap); | ||
481 | 112 | painter.eraseRect(0, 0, pixmapSize.width(), pixmapSize.height()); | ||
482 | 113 | painter.fillRect(0, 0, pixmapSize.width(), pixmapSize.height(), QColor(255, 255, 255, 255)); | ||
483 | 114 | } else { | ||
484 | 115 | // Crop transparent part off the top of the image | ||
485 | 116 | pixmap = pixmap.copy(0, previewTopCrop(), pixmap.width(), pixmap.height() - previewTopCrop()); | ||
486 | 117 | |||
487 | 118 | // Scale image to fit the expected size | ||
488 | 119 | pixmap = pixmap.scaled(pixmapSize, Qt::KeepAspectRatio, Qt::SmoothTransformation); | ||
489 | 120 | } | ||
490 | 121 | |||
491 | 122 | return pixmap; | ||
492 | 123 | } | ||
493 | 124 | |||
494 | 125 | void DragHelper::setActive(bool active) | ||
495 | 126 | { | ||
496 | 127 | if (m_active != active) { | ||
497 | 128 | m_active = active; | ||
498 | 129 | |||
499 | 130 | Q_EMIT activeChanged(); | ||
500 | 131 | } | ||
501 | 132 | } | ||
502 | 133 | |||
503 | 134 | void DragHelper::setDragging(bool dragging) | ||
504 | 135 | { | ||
505 | 136 | if (m_dragging != dragging) { | ||
506 | 137 | m_dragging = dragging; | ||
507 | 138 | |||
508 | 139 | Q_EMIT draggingChanged(); | ||
509 | 140 | } | ||
510 | 141 | } | ||
511 | 142 | |||
512 | 143 | void DragHelper::setExpectedAction(Qt::DropAction expectedAction) | ||
513 | 144 | { | ||
514 | 145 | if (m_expected_action != expectedAction) { | ||
515 | 146 | m_expected_action = expectedAction; | ||
516 | 147 | |||
517 | 148 | Q_EMIT expectedActionChanged(); | ||
518 | 149 | } | ||
519 | 150 | } | ||
520 | 151 | |||
521 | 152 | void DragHelper::setMimeType(QString mimeType) | ||
522 | 153 | { | ||
523 | 154 | if (m_mime_type != mimeType) { | ||
524 | 155 | m_mime_type = mimeType; | ||
525 | 156 | |||
526 | 157 | Q_EMIT mimeTypeChanged(); | ||
527 | 158 | } | ||
528 | 159 | } | ||
529 | 160 | |||
530 | 161 | void DragHelper::setPreviewBorderWidth(int previewBorderWidth) | ||
531 | 162 | { | ||
532 | 163 | if (m_preview_border_width != previewBorderWidth) { | ||
533 | 164 | m_preview_border_width = previewBorderWidth; | ||
534 | 165 | |||
535 | 166 | Q_EMIT previewBorderWidthChanged(); | ||
536 | 167 | } | ||
537 | 168 | } | ||
538 | 169 | |||
539 | 170 | void DragHelper::setPreviewSize(QSizeF previewSize) | ||
540 | 171 | { | ||
541 | 172 | if (m_preview_size != previewSize) { | ||
542 | 173 | m_preview_size = previewSize; | ||
543 | 174 | |||
544 | 175 | Q_EMIT previewSizeChanged(); | ||
545 | 176 | } | ||
546 | 177 | } | ||
547 | 178 | |||
548 | 179 | void DragHelper::setPreviewTopCrop(int previewTopCrop) | ||
549 | 180 | { | ||
550 | 181 | if (m_preview_top_crop != previewTopCrop) { | ||
551 | 182 | m_preview_top_crop = previewTopCrop; | ||
552 | 183 | |||
553 | 184 | Q_EMIT previewTopCropChanged(); | ||
554 | 185 | } | ||
555 | 186 | } | ||
556 | 187 | |||
557 | 188 | void DragHelper::setPreviewUrl(QString previewUrl) | ||
558 | 189 | { | ||
559 | 190 | if (m_preview_url != previewUrl) { | ||
560 | 191 | m_preview_url = previewUrl; | ||
561 | 192 | |||
562 | 193 | Q_EMIT previewUrlChanged(); | ||
563 | 194 | } | ||
564 | 195 | } | ||
565 | 196 | |||
566 | 197 | void DragHelper::setSource(QQuickItem *source) | ||
567 | 198 | { | ||
568 | 199 | if (m_source != source) { | ||
569 | 200 | m_source = source; | ||
570 | 201 | |||
571 | 202 | Q_EMIT sourceChanged(); | ||
572 | 203 | } | ||
573 | 204 | } | ||
574 | 205 | |||
575 | 0 | 206 | ||
576 | === added file 'modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.h' | |||
577 | --- modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.h 1970-01-01 00:00:00 +0000 | |||
578 | +++ modules/Ubuntu/Components/Extras/plugin/tabsbar/drag-helper.h 2017-01-06 16:37:25 +0000 | |||
579 | @@ -0,0 +1,93 @@ | |||
580 | 1 | /* | ||
581 | 2 | * Copyright 2016 Canonical Ltd. | ||
582 | 3 | * | ||
583 | 4 | * This file is part of webbrowser-app. | ||
584 | 5 | * | ||
585 | 6 | * webbrowser-app is free software; you can redistribute it and/or modify | ||
586 | 7 | * it under the terms of the GNU General Public License as published by | ||
587 | 8 | * the Free Software Foundation; version 3. | ||
588 | 9 | * | ||
589 | 10 | * webbrowser-app is distributed in the hope that it will be useful, | ||
590 | 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
591 | 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
592 | 13 | * GNU General Public License for more details. | ||
593 | 14 | * | ||
594 | 15 | * You should have received a copy of the GNU General Public License | ||
595 | 16 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
596 | 17 | * | ||
597 | 18 | * Authored-by: Andrew Hayzen <andrew.hayzen@canonical.com> | ||
598 | 19 | */ | ||
599 | 20 | |||
600 | 21 | #ifndef __DRAGHELPER_H__ | ||
601 | 22 | #define __DRAGHELPER_H__ | ||
602 | 23 | |||
603 | 24 | #include <QtCore/QSizeF> | ||
604 | 25 | #include <QtCore/QObject> | ||
605 | 26 | #include <QtCore/QString> | ||
606 | 27 | #include <QtGui/QColor> | ||
607 | 28 | #include <QtGui/QMouseEvent> | ||
608 | 29 | |||
609 | 30 | class QQuickItem; | ||
610 | 31 | |||
611 | 32 | class DragHelper : public QObject | ||
612 | 33 | { | ||
613 | 34 | Q_OBJECT | ||
614 | 35 | |||
615 | 36 | Q_PROPERTY(bool active READ active WRITE setActive NOTIFY activeChanged) | ||
616 | 37 | Q_PROPERTY(bool dragging READ dragging NOTIFY draggingChanged) | ||
617 | 38 | Q_PROPERTY(Qt::DropAction expectedAction READ expectedAction WRITE setExpectedAction NOTIFY expectedActionChanged) | ||
618 | 39 | Q_PROPERTY(QString mimeType READ mimeType WRITE setMimeType NOTIFY mimeTypeChanged) | ||
619 | 40 | Q_PROPERTY(int previewBorderWidth READ previewBorderWidth WRITE setPreviewBorderWidth NOTIFY previewBorderWidthChanged) | ||
620 | 41 | Q_PROPERTY(QSizeF previewSize READ previewSize WRITE setPreviewSize NOTIFY previewSizeChanged) | ||
621 | 42 | Q_PROPERTY(int previewTopCrop READ previewTopCrop WRITE setPreviewTopCrop NOTIFY previewTopCropChanged) | ||
622 | 43 | Q_PROPERTY(QString previewUrl READ previewUrl WRITE setPreviewUrl NOTIFY previewUrlChanged) | ||
623 | 44 | Q_PROPERTY(QQuickItem* source READ source WRITE setSource NOTIFY sourceChanged) | ||
624 | 45 | public: | ||
625 | 46 | DragHelper(); | ||
626 | 47 | bool active() { return m_active; } | ||
627 | 48 | bool dragging() { return m_dragging; } | ||
628 | 49 | Qt::DropAction expectedAction() { return m_expected_action; } | ||
629 | 50 | QString mimeType() { return m_mime_type; } | ||
630 | 51 | int previewBorderWidth() { return m_preview_border_width; } | ||
631 | 52 | QSizeF previewSize() { return m_preview_size; } | ||
632 | 53 | int previewTopCrop() { return m_preview_top_crop; } | ||
633 | 54 | QString previewUrl() { return m_preview_url; } | ||
634 | 55 | QQuickItem *source() { return m_source; } | ||
635 | 56 | Q_SIGNALS: | ||
636 | 57 | void activeChanged(); | ||
637 | 58 | void draggingChanged(); | ||
638 | 59 | void expectedActionChanged(); | ||
639 | 60 | void mimeTypeChanged(); | ||
640 | 61 | void previewBorderWidthChanged(); | ||
641 | 62 | void previewSizeChanged(); | ||
642 | 63 | void previewTopCropChanged(); | ||
643 | 64 | void previewUrlChanged(); | ||
644 | 65 | void sourceChanged(); | ||
645 | 66 | public Q_SLOTS: | ||
646 | 67 | Q_INVOKABLE Qt::DropAction execDrag(QString tabId); | ||
647 | 68 | void setActive(bool active); | ||
648 | 69 | void setExpectedAction(Qt::DropAction expectedAction); | ||
649 | 70 | void setMimeType(QString mimeType); | ||
650 | 71 | void setPreviewBorderWidth(int previewBorderWidth); | ||
651 | 72 | void setPreviewSize(QSizeF previewSize); | ||
652 | 73 | void setPreviewTopCrop(int previewTopCrop); | ||
653 | 74 | void setPreviewUrl(QString previewUrl); | ||
654 | 75 | void setSource(QQuickItem *source); | ||
655 | 76 | private: | ||
656 | 77 | QPixmap drawPixmapWithBorder(QPixmap pixmap, int borderWidth, QColor color); | ||
657 | 78 | QPixmap getPreviewUrlAsPixmap(int width, int height); | ||
658 | 79 | void setDragging(bool dragging); | ||
659 | 80 | |||
660 | 81 | bool m_active; | ||
661 | 82 | bool m_dragging; | ||
662 | 83 | Qt::DropAction m_expected_action; | ||
663 | 84 | QString m_mime_type; | ||
664 | 85 | int m_preview_border_width; | ||
665 | 86 | QSizeF m_preview_size; | ||
666 | 87 | int m_preview_top_crop; | ||
667 | 88 | QString m_preview_url; | ||
668 | 89 | QQuickItem *m_source; | ||
669 | 90 | }; | ||
670 | 91 | |||
671 | 92 | #endif // __DRAGHELPER_H__ | ||
672 | 93 |
I wonder if it should be containsDrag)
visible: !Window.active || dimmed
or
visible: !Window.active || (dimmed && !dropArea.
For the Rectangle dimming the TabBar