Merge lp:~loic.molinari/ubuntu-ui-toolkit/ubuntu-ui-toolkit-shape-rewrite into lp:ubuntu-ui-toolkit/staging

Proposed by Loïc Molinari
Status: Merged
Approved by: Zsombor Egri
Approved revision: 1340
Merged at revision: 1427
Proposed branch: lp:~loic.molinari/ubuntu-ui-toolkit/ubuntu-ui-toolkit-shape-rewrite
Merge into: lp:ubuntu-ui-toolkit/staging
Diff against target: 3415 lines (+1965/-1054)
13 files modified
.bzrignore (+1/-0)
components.api (+40/-15)
examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml (+26/-23)
modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml (+1/-1)
modules/Ubuntu/Components/plugin/plugin.cpp (+6/-5)
modules/Ubuntu/Components/plugin/plugin.pro (+10/-3)
modules/Ubuntu/Components/plugin/plugin.qrc (+6/-0)
modules/Ubuntu/Components/plugin/shaders/shape.frag (+57/-0)
modules/Ubuntu/Components/plugin/shaders/shape.vert (+43/-0)
modules/Ubuntu/Components/plugin/ucubuntushape.cpp (+1202/-820)
modules/Ubuntu/Components/plugin/ucubuntushape.h (+270/-183)
modules/Ubuntu/Components/plugin/ucubuntushapetexture.h (+4/-4)
tests/resources/ubuntushape/UbuntuShapeTest.qml (+299/-0)
To merge this branch: bzr merge lp:~loic.molinari/ubuntu-ui-toolkit/ubuntu-ui-toolkit-shape-rewrite
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Zsombor Egri Approve
Review via email: mp+242791@code.launchpad.net

Commit message

[UbuntuShape] Refactored the base component.

The UbuntuShape needed a rework in order to propose more features while keeping efficiency high and maintenance easy.

Description of the change

[UbuntuShape] Refactored the base component.

The UbuntuShape needed a rework in order to propose more features while keeping efficiency high and maintenance easy.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

I went through your MR, and I'd suggest to turn it on Needs Review unless you have anything to add.

Nice work!!! Will give a shot to see whether I can see any visual glitches. I was thinking whether we could add some unit tests or something to guard the current functionality, it is hard, as it mostly has visual feedback, no API driven ones...

Some of the comments below needs fixing, some not.

review: Needs Fixing
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

Thanks for the review Zsombor. See my replies in the diff.

Marking as NeedReview but I still have to instrument the OpenGL ES path on the device, so please don't approve for now.

Cheers ;)

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Problems with the revision. Please check them.

review: Needs Fixing
Revision history for this message
Zsombor Egri (zsombi) wrote :

> Problems with the revision. Please check them.

Ok, seems the revision number doesn't need to be in sync with the minor version, I understood it wrongly. And thinking of it, it shouldn't even be, as if the major changes, the revisions cannot be reset to 0, unless a new library is made resetting all revision API to 0. Which can be insane.

So then the only thing remaining to see why the components.api diff?

Revision history for this message
Loïc Molinari (loic.molinari) wrote :

> > Problems with the revision. Please check them.
>
> Ok, seems the revision number doesn't need to be in sync with the minor
> version, I understood it wrongly. And thinking of it, it shouldn't even be, as
> if the major changes, the revisions cannot be reset to 0, unless a new library
> is made resetting all revision API to 0. Which can be insane.
>
> So then the only thing remaining to see why the components.api diff?

Because I thought you requested it from a previous comment. removing it anyway.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Loïc Molinari (loic.molinari) wrote :

Tested successfully on Qt 5.4.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
Zsombor Egri (zsombi) wrote :

Job done :)

review: Approve
Revision history for this message
PS Jenkins bot (ps-jenkins) :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file '.bzrignore'
2--- .bzrignore 2015-02-02 14:40:18 +0000
3+++ .bzrignore 2015-03-02 15:41:23 +0000
4@@ -2,6 +2,7 @@
5 modules/Makefile.ubuntu-ui-toolkit
6 modules/Ubuntu/Components/Makefile.ubuntu-ui-toolkit
7 modules/Ubuntu/Components/plugin/Makefile.ubuntu-ui-toolkit
8+modules/Ubuntu/Components/plugin/qrc_plugin.cpp
9 documentation/html/*
10 *.moc
11 moc_*.cpp
12
13=== modified file 'components.api'
14--- components.api 2015-02-24 14:54:58 +0000
15+++ components.api 2015-03-02 15:41:23 +0000
16@@ -794,21 +794,6 @@
17 name: "get"
18 Parameter { name: "row"; type: "int" }
19 Method { name: "count"; type: "int" }
20- name: "ShapeItem"
21- prototype: "QQuickItem"
22- exports: [
23- name: "HAlignment"
24- name: "VAlignment"
25- Property { name: "color"; type: "QColor" }
26- Property { name: "gradientColor"; type: "QColor" }
27- Property { name: "radius"; type: "string" }
28- Property { name: "image"; type: "QVariant" }
29- Property { name: "stretched"; type: "bool" }
30- Property { name: "horizontalAlignment"; type: "HAlignment" }
31- Property { name: "verticalAlignment"; type: "VAlignment" }
32- Property { name: "borderSource"; type: "string" }
33- Signal { name: "borderChanged" }
34- Method { name: "gridUnitChanged" }
35 name: "SortBehavior"
36 prototype: "QObject"
37 exports: ["SortBehavior 1.1"]
38@@ -1073,6 +1058,46 @@
39 Property { name: "SleepyDuration"; type: "int"; isReadonly: true }
40 Property { name: "StandardEasing"; type: "QEasingCurve"; isReadonly: true }
41 Property { name: "StandardEasingReverse"; type: "QEasingCurve"; isReadonly: true }
42+ name: "UCUbuntuShape"
43+ prototype: "QQuickItem"
44+ exports: [
45+ name: "BackgroundMode"
46+ name: "HAlignment"
47+ name: "VAlignment"
48+ name: "FillMode"
49+ name: "WrapMode"
50+ Property { name: "radius"; type: "string" }
51+ Property { name: "borderSource"; type: "string" }
52+ Property { name: "source"; revision: 1; type: "QVariant" }
53+ Property { name: "sourceOpacity"; revision: 1; type: "float" }
54+ Property { name: "sourceFillMode"; revision: 1; type: "FillMode" }
55+ Property { name: "sourceHorizontalWrapMode"; revision: 1; type: "WrapMode" }
56+ Property { name: "sourceVerticalWrapMode"; revision: 1; type: "WrapMode" }
57+ Property { name: "sourceHorizontalAlignment"; revision: 1; type: "HAlignment" }
58+ Property { name: "sourceVerticalAlignment"; revision: 1; type: "VAlignment" }
59+ Property { name: "sourceTranslation"; revision: 1; type: "QVector2D" }
60+ Property { name: "sourceScale"; revision: 1; type: "QVector2D" }
61+ Property { name: "backgroundColor"; revision: 1; type: "QColor" }
62+ Property { name: "secondaryBackgroundColor"; revision: 1; type: "QColor" }
63+ Property { name: "backgroundMode"; revision: 1; type: "BackgroundMode" }
64+ Property { name: "color"; type: "QColor" }
65+ Property { name: "gradientColor"; type: "QColor" }
66+ Property { name: "image"; type: "QVariant" }
67+ Property { name: "stretched"; type: "bool" }
68+ Property { name: "horizontalAlignment"; type: "HAlignment" }
69+ Property { name: "verticalAlignment"; type: "VAlignment" }
70+ Signal { name: "sourceChanged"; revision: 1 }
71+ Signal { name: "sourceOpacityChanged"; revision: 1 }
72+ Signal { name: "sourceFillModeChanged"; revision: 1 }
73+ Signal { name: "sourceHorizontalWrapModeChanged"; revision: 1 }
74+ Signal { name: "sourceVerticalWrapModeChanged"; revision: 1 }
75+ Signal { name: "sourceHorizontalAlignmentChanged"; revision: 1 }
76+ Signal { name: "sourceVerticalAlignmentChanged"; revision: 1 }
77+ Signal { name: "sourceTranslationChanged"; revision: 1 }
78+ Signal { name: "sourceScaleChanged"; revision: 1 }
79+ Signal { name: "backgroundColorChanged"; revision: 1 }
80+ Signal { name: "secondaryBackgroundColorChanged"; revision: 1 }
81+ Signal { name: "backgroundModeChanged"; revision: 1 }
82 name: "UCUnits"
83 prototype: "QObject"
84 exports: ["UCUnits 0.1", "UCUnits 1.0"]
85
86=== modified file 'examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml'
87--- examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml 2014-11-19 11:10:00 +0000
88+++ examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml 2015-03-02 15:41:23 +0000
89@@ -14,8 +14,8 @@
90 * along with this program. If not, see <http://www.gnu.org/licenses/>.
91 */
92
93-import QtQuick 2.0
94-import Ubuntu.Components 0.1
95+import QtQuick 2.2
96+import Ubuntu.Components 1.2
97
98 Template {
99 objectName: "ubuntuShapesTemplate"
100@@ -30,18 +30,17 @@
101 height: units.gu(8)
102
103 UbuntuShape {
104- objectName: "ubuntushape_color_hex"
105- color: UbuntuColors.orange
106- }
107-
108- UbuntuShape {
109- objectName: "ubuntushape_color_lightaubergine"
110- color: UbuntuColors.lightAubergine
111- }
112-
113- UbuntuShape {
114- objectName: "ubuntushape_color_darkgray"
115- color: UbuntuColors.warmGrey
116+ objectName: "ubuntushape_backgroundcolor_orange"
117+ backgroundColor: UbuntuColors.orange
118+ }
119+
120+ UbuntuShape {
121+ objectName: "ubuntushape_verticalgradient"
122+ backgroundColor: UbuntuColors.lightAubergine
123+ secondaryBackgroundColor: Qt.rgba(
124+ UbuntuColors.lightAubergine.r, UbuntuColors.lightAubergine.g,
125+ UbuntuColors.lightAubergine.b, 0.25)
126+ backgroundMode: UbuntuShape.VerticalGradient
127 }
128 }
129
130@@ -51,12 +50,16 @@
131 height: units.gu(8)
132
133 UbuntuShape {
134- objectName: "ubuntushape_image"
135+ objectName: "ubuntushape_preserveaspectcrop"
136+ source: Image { source: "map_icon.png" }
137+ sourceFillMode: UbuntuShape.PreserveAspectCrop
138+ }
139
140- image: Image {
141- source: "map_icon.png"
142- fillMode: Image.PreserveAspectCrop
143- }
144+ UbuntuShape {
145+ objectName: "ubuntushape_pad"
146+ backgroundColor: UbuntuColors.warmGrey
147+ source: Image { source: "images.png" }
148+ sourceFillMode: UbuntuShape.Pad
149 }
150 }
151
152@@ -68,7 +71,7 @@
153 UbuntuShape {
154 objectName: "ubuntushape_radius_small"
155
156- color: Theme.palette.normal.foreground
157+ backgroundColor: Theme.palette.normal.foreground
158 radius: "small"
159
160 Label {
161@@ -81,7 +84,7 @@
162
163 UbuntuShape {
164 objectName: "ubuntushape_radius_medium"
165- color: Theme.palette.normal.foreground
166+ backgroundColor: Theme.palette.normal.foreground
167 radius: "medium"
168
169 Label {
170@@ -100,7 +103,7 @@
171
172 UbuntuShape {
173 objectName: "ubuntushape_sizes_15_6"
174- color: Theme.palette.normal.foreground
175+ backgroundColor: Theme.palette.normal.foreground
176 width: units.gu(15)
177 height: units.gu(6)
178 anchors.verticalCenter: parent.verticalCenter
179@@ -108,7 +111,7 @@
180
181 UbuntuShape {
182 objectName: "ubuntushape_sizes_10_14"
183- color: Theme.palette.normal.foreground
184+ backgroundColor: Theme.palette.normal.foreground
185 width: units.gu(10)
186 height: units.gu(14)
187 }
188
189=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml'
190--- modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml 2015-02-10 16:47:59 +0000
191+++ modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml 2015-03-02 15:41:23 +0000
192@@ -36,7 +36,7 @@
193 /* The color must be white for PartialColorizeUbuntuShape to accurately
194 replace the white with leftColor and rightColor
195 */
196- color: progressBar.indeterminate ? backgroundColor : "#FFFFFF"
197+ color: progressBar.indeterminate ? progressBarStyle.backgroundColor : "#FFFFFF"
198 }
199
200 property real progress: progressBar.indeterminate ? 0.0
201
202=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
203--- modules/Ubuntu/Components/plugin/plugin.cpp 2015-02-13 13:27:51 +0000
204+++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-03-02 15:41:23 +0000
205@@ -31,7 +31,7 @@
206 #include "ucscalingimageprovider.h"
207 #include "ucqquickimageextension.h"
208 #include "quickutils.h"
209-#include "shapeitem.h"
210+#include "ucubuntushape.h"
211 #include "inversemouseareatype.h"
212 #include "qquickclipboard.h"
213 #include "qquickmimedata.h"
214@@ -129,9 +129,9 @@
215 qmlRegisterUncreatableType<UbuntuI18n>(uri, major, minor, "i18n", "Singleton object");
216 qmlRegisterExtendedType<QQuickImageBase, UCQQuickImageExtension>(uri, major, minor, "QQuickImageBase");
217 qmlRegisterUncreatableType<UCUnits>(uri, major, minor, "UCUnits", "Not instantiable");
218- qmlRegisterType<ShapeItem>(uri, major, minor, "UbuntuShape");
219- // FIXME/DEPRECATED: Shape is exported for backwards compatibity only
220- qmlRegisterType<ShapeItem>(uri, major, minor, "Shape");
221+ qmlRegisterType<UCUbuntuShape>(uri, major, minor, "UbuntuShape");
222+ // FIXME/DEPRECATED: Shape is exported for backwards compatibility only
223+ qmlRegisterType<UCUbuntuShape>(uri, major, minor, "Shape");
224 qmlRegisterType<InverseMouseAreaType>(uri, major, minor, "InverseMouseArea");
225 qmlRegisterType<QQuickMimeData>(uri, major, minor, "MimeData");
226 qmlRegisterSingletonType<QQuickClipboard>(uri, major, minor, "Clipboard", registerClipboard);
227@@ -169,13 +169,14 @@
228 qmlRegisterUncreatableType<SortBehavior>(uri, 1, 1, "SortBehavior", "Not instantiable");
229 qmlRegisterType<UCServiceProperties, 1>(uri, 1, 1, "ServiceProperties");
230
231- // ListItem and related types, released to 1.2
232+ // register 1.2 only API
233 qmlRegisterType<UCListItem>(uri, 1, 2, "ListItem");
234 qmlRegisterType<UCListItemDivider>();
235 qmlRegisterUncreatableType<UCSwipeEvent>(uri, 1, 2, "SwipeEvent", "This is an event object.");
236 qmlRegisterUncreatableType<UCDragEvent>(uri, 1, 2, "ListItemDrag", "This is an event object");
237 qmlRegisterType<UCListItemActions>(uri, 1, 2, "ListItemActions");
238 qmlRegisterUncreatableType<UCViewItemsAttached>(uri, 1, 2, "ViewItems", "Not instantiable");
239+ qmlRegisterType<UCUbuntuShape, 1>(uri, 1, 2, "UbuntuShape");
240 }
241
242 void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
243
244=== modified file 'modules/Ubuntu/Components/plugin/plugin.pro'
245--- modules/Ubuntu/Components/plugin/plugin.pro 2015-02-17 12:21:52 +0000
246+++ modules/Ubuntu/Components/plugin/plugin.pro 2015-03-02 15:41:23 +0000
247@@ -33,8 +33,8 @@
248 ucunits.h \
249 ucqquickimageextension.h \
250 quickutils.h \
251- shapeitemtexture.h \
252- shapeitem.h \
253+ ucubuntushapetexture.h \
254+ ucubuntushape.h \
255 inversemouseareatype.h \
256 qquickclipboard.h \
257 qquickmimedata.h \
258@@ -88,7 +88,7 @@
259 ucunits.cpp \
260 ucqquickimageextension.cpp \
261 quickutils.cpp \
262- shapeitem.cpp \
263+ ucubuntushape.cpp \
264 inversemouseareatype.cpp \
265 qquickclipboard.cpp \
266 qquickmimedata.cpp \
267@@ -127,6 +127,13 @@
268 # adapters
269 SOURCES += adapters/alarmsadapter_organizer.cpp
270
271+RESOURCES += \
272+ plugin.qrc
273+
274+OTHER_FILES += \
275+ shaders/shape.vert \
276+ shaders/shape.frag
277+
278 # deployment rules for the plugin
279 installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
280 target.path = $$installPath
281
282=== added file 'modules/Ubuntu/Components/plugin/plugin.qrc'
283--- modules/Ubuntu/Components/plugin/plugin.qrc 1970-01-01 00:00:00 +0000
284+++ modules/Ubuntu/Components/plugin/plugin.qrc 2015-03-02 15:41:23 +0000
285@@ -0,0 +1,6 @@
286+<RCC>
287+ <qresource prefix="/uc">
288+ <file>shaders/shape.frag</file>
289+ <file>shaders/shape.vert</file>
290+ </qresource>
291+</RCC>
292
293=== added directory 'modules/Ubuntu/Components/plugin/shaders'
294=== added file 'modules/Ubuntu/Components/plugin/shaders/shape.frag'
295--- modules/Ubuntu/Components/plugin/shaders/shape.frag 1970-01-01 00:00:00 +0000
296+++ modules/Ubuntu/Components/plugin/shaders/shape.frag 2015-03-02 15:41:23 +0000
297@@ -0,0 +1,57 @@
298+// Copyright © 2015 Canonical Ltd.
299+//
300+// This program is free software; you can redistribute it and/or modify
301+// it under the terms of the GNU Lesser General Public License as published by
302+// the Free Software Foundation; version 3.
303+//
304+// This program is distributed in the hope that it will be useful,
305+// but WITHOUT ANY WARRANTY; without even the implied warranty of
306+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
307+// GNU Lesser General Public License for more details.
308+//
309+// You should have received a copy of the GNU Lesser General Public License
310+// along with this program. If not, see <http://www.gnu.org/licenses/>.
311+//
312+// Author: Loïc Molinari <loic.molinari@canonical.com>
313+
314+// Static flow control (branching on a uniform value) is fast on most GPUs (including ultra-low
315+// power ones) because it allows to use the same shader execution path for an entire draw call. We
316+// rely on that technique here (also known as "uber-shader" solution) to avoid the complexity of
317+// dealing with a multiple shaders solution.
318+// FIXME(loicm) Validate GPU behavior with regards to static flow control.
319+
320+uniform sampler2D shapeTexture;
321+uniform sampler2D sourceTexture;
322+uniform lowp float sourceOpacity;
323+uniform lowp float opacity;
324+uniform bool textured;
325+
326+varying mediump vec2 shapeCoord;
327+varying mediump vec4 sourceCoord;
328+varying lowp vec4 backgroundColor;
329+
330+void main(void)
331+{
332+ // Early texture fetch to cover latency as best as possible.
333+ lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord);
334+
335+ lowp vec4 color = backgroundColor;
336+
337+ // FIXME(loicm) Would be better to use a bitfield but bitwise ops have only been integrated in
338+ // GLSL 1.3 (OpenGL 3) and GLSL ES 3 (OpenGL ES 3).
339+ if (textured) {
340+ // Blend the source over the current color (static flow control prevents the texture fetch).
341+ lowp vec2 axisMask = -sign((sourceCoord.zw * sourceCoord.zw) - vec2(1.0));
342+ lowp float mask = clamp(axisMask.x + axisMask.y, 0.0, 1.0);
343+ lowp vec4 source = texture2D(sourceTexture, sourceCoord.st) * vec4(sourceOpacity * mask);
344+ color = vec4(1.0 - source.a) * color + source;
345+ }
346+
347+ // Shape the current color with the mask.
348+ color *= vec4(shapeData.b);
349+
350+ // Blend the border over the current color.
351+ color = vec4(1.0 - shapeData.r) * color + shapeData.gggr;
352+
353+ gl_FragColor = color * vec4(opacity);
354+}
355
356=== added file 'modules/Ubuntu/Components/plugin/shaders/shape.vert'
357--- modules/Ubuntu/Components/plugin/shaders/shape.vert 1970-01-01 00:00:00 +0000
358+++ modules/Ubuntu/Components/plugin/shaders/shape.vert 2015-03-02 15:41:23 +0000
359@@ -0,0 +1,43 @@
360+// Copyright © 2015 Canonical Ltd.
361+//
362+// This program is free software; you can redistribute it and/or modify
363+// it under the terms of the GNU Lesser General Public License as published by
364+// the Free Software Foundation; version 3.
365+//
366+// This program is distributed in the hope that it will be useful,
367+// but WITHOUT ANY WARRANTY; without even the implied warranty of
368+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
369+// GNU Lesser General Public License for more details.
370+//
371+// You should have received a copy of the GNU Lesser General Public License
372+// along with this program. If not, see <http://www.gnu.org/licenses/>.
373+//
374+// Author: Loïc Molinari <loic.molinari@canonical.com>
375+
376+uniform mediump mat4 matrix;
377+uniform bool textured;
378+
379+attribute mediump vec4 positionAttrib;
380+attribute mediump vec2 shapeCoordAttrib;
381+attribute mediump vec4 sourceCoordAttrib;
382+attribute lowp vec4 backgroundColorAttrib;
383+
384+// FIXME(loicm) Optimize by reducing/packing varyings.
385+varying mediump vec2 shapeCoord;
386+varying mediump vec4 sourceCoord;
387+varying lowp vec4 backgroundColor;
388+
389+void main()
390+{
391+ shapeCoord = shapeCoordAttrib;
392+
393+ // FIXME(loicm) Would be better to use a bitfield but bitwise ops have only been integrated in
394+ // GLSL 1.3 (OpenGL 3) and GLSL ES 3 (OpenGL ES 3).
395+ if (textured) {
396+ sourceCoord = sourceCoordAttrib;
397+ }
398+
399+ backgroundColor = backgroundColorAttrib;
400+
401+ gl_Position = matrix * positionAttrib;
402+}
403
404=== renamed file 'modules/Ubuntu/Components/plugin/shapeitem.cpp' => 'modules/Ubuntu/Components/plugin/ucubuntushape.cpp'
405--- modules/Ubuntu/Components/plugin/shapeitem.cpp 2014-11-19 12:23:05 +0000
406+++ modules/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-03-02 15:41:23 +0000
407@@ -1,5 +1,5 @@
408 /*
409- * Copyright 2013 Canonical Ltd.
410+ * Copyright 2013-2015 Canonical Ltd.
411 *
412 * This program is free software; you can redistribute it and/or modify
413 * it under the terms of the GNU Lesser General Public License as published by
414@@ -16,297 +16,803 @@
415 * Author: Loïc Molinari <loic.molinari@canonical.com>
416 */
417
418-#include "shapeitem.h"
419-#include "shapeitemtexture.h"
420+// FIXME(loicm) Storing lower precision data types in the vertex buffer could be more efficent. On
421+// PowerVR, for instance, that requires a conversion so the trade-off between shader cycles and
422+// bandwidth requirements must be benchmarked.
423+
424+#include "ucubuntushape.h"
425+#include "ucubuntushapetexture.h"
426 #include "ucunits.h"
427 #include <QtCore/QPointer>
428 #include <QtQuick/QQuickWindow>
429 #include <QtQuick/QSGTextureProvider>
430 #include <QtQuick/private/qquickimage_p.h>
431-
432-/*!
433- \qmltype UbuntuShape
434- \instantiates ShapeItem
435- \inqmlmodule Ubuntu.Components 1.1
436+#include <math.h>
437+
438+// --- Scene graph shader ---
439+
440+ShapeShader::ShapeShader()
441+{
442+ setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/uc/shaders/shape.vert"));
443+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shape.frag"));
444+}
445+
446+char const* const* ShapeShader::attributeNames() const
447+{
448+ static char const* const attributes[] = {
449+ "positionAttrib", "shapeCoordAttrib", "sourceCoordAttrib", "backgroundColorAttrib", 0
450+ };
451+ return attributes;
452+}
453+
454+void ShapeShader::initialize()
455+{
456+ QSGMaterialShader::initialize();
457+
458+ program()->bind();
459+ program()->setUniformValue("shapeTexture", 0);
460+ program()->setUniformValue("sourceTexture", 1);
461+
462+ m_functions = QOpenGLContext::currentContext()->functions();
463+ m_matrixId = program()->uniformLocation("matrix");
464+ m_opacityId = program()->uniformLocation("opacity");
465+ m_sourceOpacityId = program()->uniformLocation("sourceOpacity");
466+ m_texturedId = program()->uniformLocation("textured");
467+}
468+
469+void ShapeShader::updateState(
470+ const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect)
471+{
472+ Q_UNUSED(oldEffect);
473+
474+ const ShapeMaterial::Data* data = static_cast<ShapeMaterial*>(newEffect)->constData();
475+
476+ // Bind shape texture.
477+ QSGTexture* shapeTexture = data->shapeTexture;
478+ if (shapeTexture) {
479+ shapeTexture->setFiltering(static_cast<QSGTexture::Filtering>(data->shapeTextureFiltering));
480+ shapeTexture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
481+ shapeTexture->setVerticalWrapMode(QSGTexture::ClampToEdge);
482+ shapeTexture->bind();
483+ } else {
484+ glBindTexture(GL_TEXTURE_2D, 0);
485+ }
486+
487+ if (data->flags & ShapeMaterial::Data::Textured) {
488+ // Bind image texture.
489+ m_functions->glActiveTexture(GL_TEXTURE1);
490+ QSGTextureProvider* provider = data->sourceTextureProvider;
491+ QSGTexture* texture = provider ? provider->texture() : NULL;
492+ if (texture) {
493+ if (data->flags & ShapeMaterial::Data::Repeated) {
494+ if (texture->isAtlasTexture()) {
495+ // A texture in an atlas can't be repeated with builtin GPU facility (exposed by
496+ // GL_REPEAT with OpenGL), so we extract it and create a new dedicated one.
497+ texture = texture->removedFromAtlas();
498+ }
499+ texture->setHorizontalWrapMode(
500+ data->flags & ShapeMaterial::Data::HorizontallyRepeated ?
501+ QSGTexture::Repeat : QSGTexture::ClampToEdge);
502+ texture->setVerticalWrapMode(
503+ data->flags & ShapeMaterial::Data::VerticallyRepeated ?
504+ QSGTexture::Repeat : QSGTexture::ClampToEdge);
505+ }
506+ texture->bind();
507+ } else {
508+ glBindTexture(GL_TEXTURE_2D, 0);
509+ }
510+ m_functions->glActiveTexture(GL_TEXTURE0);
511+ // Update image uniform.
512+ const float u8toF32 = 1.0f / 255.0f;
513+ program()->setUniformValue(m_sourceOpacityId, data->sourceOpacity * u8toF32);
514+ }
515+
516+ program()->setUniformValue(m_texturedId, !!(data->flags & ShapeMaterial::Data::Textured));
517+
518+ // Update QtQuick engine uniforms.
519+ if (state.isMatrixDirty()) {
520+ program()->setUniformValue(m_matrixId, state.combinedMatrix());
521+ }
522+ if (state.isOpacityDirty()) {
523+ program()->setUniformValue(m_opacityId, state.opacity());
524+ }
525+}
526+
527+// --- Scene graph material ---
528+
529+ShapeMaterial::ShapeMaterial()
530+{
531+ // The whole struct (with the padding bytes) must be initialized for memcmp() to work as
532+ // expected in ShapeMaterial::compare().
533+ memset(&m_data, 0x00, sizeof(Data));
534+ setFlag(Blending);
535+}
536+
537+QSGMaterialType* ShapeMaterial::type() const
538+{
539+ static QSGMaterialType type;
540+ return &type;
541+}
542+
543+QSGMaterialShader* ShapeMaterial::createShader() const
544+{
545+ return new ShapeShader;
546+}
547+
548+int ShapeMaterial::compare(const QSGMaterial* other) const
549+{
550+ // Repeat wrap modes require textures to be extracted from their atlases. Since we just store
551+ // the texture provider in the material data (not the texture as we want to do the extraction at
552+ // QSGShader::updateState() time), we make the comparison fail when repeat wrapping is set.
553+ const ShapeMaterial::Data* otherData = static_cast<const ShapeMaterial*>(other)->constData();
554+ return memcmp(&m_data, otherData, sizeof(m_data))
555+ | (m_data.flags & ShapeMaterial::Data::Repeated);
556+}
557+
558+// --- Scene graph node ---
559+
560+ShapeNode::ShapeNode()
561+ : QSGGeometryNode()
562+ , m_material()
563+ , m_geometry(attributeSet(), vertexCount, indexCount, indexType)
564+{
565+ memcpy(m_geometry.indexData(), indices(), indexCount * indexTypeSize);
566+ m_geometry.setDrawingMode(drawingMode);
567+ m_geometry.setIndexDataPattern(indexDataPattern);
568+ m_geometry.setVertexDataPattern(vertexDataPattern);
569+ setMaterial(&m_material);
570+ setGeometry(&m_geometry);
571+}
572+
573+// static
574+const unsigned short* ShapeNode::indices()
575+{
576+ // Don't forget to update indexCount if changed.
577+ static const unsigned short indices[] = {
578+ 0, 4, 1, 5, 2, 6, 3, 7, // Triangles 1 to 6.
579+ 7, 4, // Degenerate triangles.
580+ 4, 8, 5, 9, 6, 10, 7, 11, // Triangles 7 to 12.
581+ 11, 8, // Degenerate triangles.
582+ 8, 12, 9, 13, 10, 14, 11, 15 // Triangles 13 to 18.
583+ };
584+ return indices;
585+}
586+
587+// static
588+const QSGGeometry::AttributeSet& ShapeNode::attributeSet()
589+{
590+ static const QSGGeometry::Attribute attributes[] = {
591+ QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
592+ QSGGeometry::Attribute::create(1, 2, GL_FLOAT),
593+ QSGGeometry::Attribute::create(2, 4, GL_FLOAT),
594+ QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE)
595+ };
596+ static const QSGGeometry::AttributeSet attributeSet = {
597+ 4, sizeof(Vertex), attributes
598+ };
599+ return attributeSet;
600+}
601+
602+// --- QtQuick item ---
603+
604+struct ShapeTextures
605+{
606+ ShapeTextures() : high(0), low(0) {}
607+ QSGTexture* high;
608+ QSGTexture* low;
609+};
610+
611+static QHash<QOpenGLContext*, ShapeTextures> shapeTexturesHash;
612+
613+const float implicitGridUnitWidth = 8.0f;
614+const float implicitGridUnitHeight = 8.0f;
615+
616+// Threshold in grid unit defining the texture quality to be used.
617+const float lowHighTextureThreshold = 11.0f;
618+
619+/*! \qmltype UbuntuShape
620+ \instantiates UCUbuntuShape
621+ \inqmlmodule Ubuntu.Components 1.2
622 \ingroup ubuntu
623- \brief The UbuntuShape item provides a standard Ubuntu shaped rounded rectangle.
624-
625- The UbuntuShape is used where a rounded rectangle is needed either filled
626- with a color or an image that it crops.
627-
628- When given with a \l color it is applied with an overlay blending as a
629- vertical gradient going from \l color to \l gradientColor.
630- Two corner \l radius are available, "small" (default) and "medium", that
631- determine the size of the corners.
632- Optionally, an Image can be passed that will be displayed inside the
633- UbuntuShape and cropped to fit it.
634+ \brief Rounded rectangle containing a source image blended over a background color.
635+
636+ The UbuntuShape is a rounded rectangle (based on a \l
637+ {https://en.wikipedia.org/wiki/Squircle}{squircle}) containing an optional source image blended
638+ over a background color (solid or linear gradient). Different properties allow to change the
639+ look of the shape.
640
641 Examples:
642- \qml
643- import Ubuntu.Components 1.1
644-
645- UbuntuShape {
646- color: "lightblue"
647- radius: "medium"
648- }
649- \endqml
650-
651- \qml
652- import Ubuntu.Components 1.1
653-
654- UbuntuShape {
655- image: Image {
656- source: "icon.png"
657- }
658- }
659- \endqml
660-*/
661-
662-/*!
663- \qmlproperty string UbuntuShape::radius
664-
665- The size of the corners among: "small" (default) and "medium".
666-*/
667-
668-/*!
669- \qmlproperty color UbuntuShape::color
670-
671- The top color of the gradient used to fill the shape. Setting only this
672- one is enough to set the overall color the shape.
673-*/
674-
675-/*!
676- \qmlproperty color UbuntuShape::gradientColor
677-
678- The bottom color of the gradient used for the overlay blending of the
679- color that fills the shape. It is optional to set this one as setting
680- \l color is enough to set the overall color of the shape.
681-*/
682-
683-/*!
684- \qmlproperty string UbuntuShape::borderSource
685-
686- This property defines the look of the shape borders. The supported strings
687- are \c "radius_idle.sci" providing an idle button style and
688- "radius_pressed.sci" providing a pressed button style. Any other strings
689- (like the empty one "") disables styling. Default value is \c
690- "radius_idle.sci".
691-
692- \note We plan to expose that feature through styling properties.
693-*/
694-
695-/*!
696- \qmlproperty Image UbuntuShape::image
697-
698- The image used to fill the shape.
699-*/
700-
701-// Retrieves the size of an array at compile time.
702-#define ARRAY_SIZE(a) \
703- ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
704-
705-// Threshold in grid unit defining the texture quality to be used.
706-const float lowHighTextureThreshold = 11.0f;
707-
708-// Map of windows and associated textures.
709-QHash<QOpenGLContext*, ShapeItem::TextureHandles> ShapeItem::textures_;
710-
711-static const char* const shapeVertexShader =
712- "uniform lowp mat4 matrix; \n"
713- "attribute lowp vec4 positionAttrib; \n"
714- "attribute lowp vec2 shapeCoordAttrib; \n"
715- "attribute lowp vec2 imageCoordAttrib; \n"
716- "varying lowp vec2 shapeCoord; \n"
717- "varying lowp vec2 imageCoord; \n"
718- "void main() \n"
719- "{ \n"
720- " shapeCoord = shapeCoordAttrib; \n"
721- " imageCoord = imageCoordAttrib; \n"
722- " gl_Position = matrix * positionAttrib; \n"
723- "}";
724-
725-static const char* const shapeTexturedFragmentShader =
726- "uniform lowp float opacity; \n"
727- "uniform sampler2D shapeTexture; \n"
728- "uniform sampler2D imageTexture; \n"
729- "varying lowp vec2 shapeCoord; \n"
730- "varying lowp vec2 imageCoord; \n"
731- "void main() \n"
732- "{ \n"
733- " lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord); \n"
734- " lowp vec4 color = texture2D(imageTexture, imageCoord) * vec4(shapeData.b); \n"
735- " lowp vec4 blend = shapeData.gggr + vec4(1.0 - shapeData.r) * color; \n"
736- " gl_FragColor = blend * vec4(opacity); \n"
737- "}";
738-
739-static const char* const shapeColoredFragmentShader =
740- "uniform lowp float opacity; \n"
741- "uniform sampler2D shapeTexture; \n"
742- "uniform lowp vec4 color; \n"
743- "uniform lowp vec4 gradientColor; \n"
744- "varying lowp vec2 shapeCoord; \n"
745- "varying lowp vec2 imageCoord; \n"
746- "void main(void) \n"
747- "{ \n"
748- " lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord); \n"
749- " lowp vec4 result = mix(color, gradientColor, imageCoord.t) * vec4(shapeData.b); \n"
750- " lowp vec4 blend = shapeData.gggr + vec4(1.0 - shapeData.r) * result; \n"
751- " gl_FragColor = blend * vec4(opacity); \n"
752- "}";
753-
754-static const unsigned short shapeMeshIndices[] __attribute__((aligned(16))) = {
755- 0, 4, 1, 5, 2, 6, 3, 7, // Triangles 1 to 6.
756- 7, 4, // Degenerate triangles.
757- 4, 8, 5, 9, 6, 10, 7, 11, // Triangles 7 to 12.
758- 11, 8, // Degenerate triangles.
759- 8, 12, 9, 13, 10, 14, 11, 15 // Triangles 13 to 18
760-};
761-
762-static const struct {
763- const unsigned short* const indices;
764- int indexCount; // Number of indices.
765- int vertexCount; // Number of vertices.
766- int attributeCount; // Number of attributes.
767- int stride; // Offset in bytes from one vertex to the other.
768- int positionCount; // Number of components per position.
769- int positionType; // OpenGL type of the position components.
770- int shapeCoordCount; // Number of components per shape texture coordinate.
771- int shapeCoordType; // OpenGL type of the shape texture coordinate components.
772- int imageCoordCount; // Number of components per image texture coordinate.
773- int imageCoordType; // OpenGL type of the image texture coordinate components.
774- int indexType; // OpenGL type of the indices.
775-} shapeMesh = {
776- shapeMeshIndices, ARRAY_SIZE(shapeMeshIndices),
777- 16, 3, sizeof(ShapeNode::Vertex), 2, GL_FLOAT, 2, GL_FLOAT, 2, GL_FLOAT, GL_UNSIGNED_SHORT
778-};
779-
780-static const QSGGeometry::AttributeSet& getAttributes()
781-{
782- static QSGGeometry::Attribute data[] = {
783- QSGGeometry::Attribute::create(0, shapeMesh.positionCount, shapeMesh.positionType, true),
784- QSGGeometry::Attribute::create(1, shapeMesh.shapeCoordCount, shapeMesh.shapeCoordType),
785- QSGGeometry::Attribute::create(2, shapeMesh.imageCoordCount, shapeMesh.imageCoordType)
786- };
787- static QSGGeometry::AttributeSet attributes = {
788- shapeMesh.attributeCount, shapeMesh.stride, data
789- };
790- return attributes;
791-}
792-
793-// Gets the size in bytes of an OpenGL type in the range [GL_BYTE, GL_DOUBLE].
794-static int sizeOfType(GLenum type)
795-{
796- static int sizes[] = {
797- sizeof(char), sizeof(unsigned char), sizeof(short), sizeof(unsigned short), sizeof(int),
798- sizeof(unsigned int), sizeof(float), 2, 3, 4, sizeof(double)
799- };
800- Q_ASSERT(type >= 0x1400 && type <= 0x140a);
801- return sizes[type - 0x1400];
802-}
803-
804-// --- QtQuick item ---
805-
806-ShapeItem::ShapeItem(QQuickItem* parent)
807+
808+ \qml
809+ import Ubuntu.Components 1.2
810+
811+ UbuntuShape {
812+ backgroundColor: "green"
813+ }
814+ \endqml
815+
816+ \qml
817+ import Ubuntu.Components 1.2
818+
819+ UbuntuShape {
820+ source: Image {
821+ source: "ubuntu.png"
822+ }
823+ }
824+ \endqml
825+*/
826+UCUbuntuShape::UCUbuntuShape(QQuickItem* parent)
827 : QQuickItem(parent)
828- , provider_(NULL)
829- , color_(0.0, 0.0, 0.0, 0.0)
830- , gradientColor_(0.0, 0.0, 0.0, 0.0)
831- , gradientColorSet_(false)
832- , radiusString_("small")
833- , radius_(ShapeItem::SmallRadius)
834- , border_(ShapeItem::IdleBorder)
835- , image_(NULL)
836- , stretched_(true)
837- , hAlignment_(ShapeItem::AlignHCenter)
838- , vAlignment_(ShapeItem::AlignVCenter)
839- , gridUnit_(UCUnits::instance().gridUnit())
840- , geometry_()
841+ , m_source(NULL)
842+ , m_sourceTextureProvider(NULL)
843+ , m_backgroundColor(qRgba(0, 0, 0, 0))
844+ , m_secondaryBackgroundColor(qRgba(0, 0, 0, 0))
845+ , m_sourceScale(1.0f, 1.0f)
846+ , m_sourceTranslation(0.0f, 0.0f)
847+ , m_sourceTransform(1.0f, 1.0f, 0.0f, 0.0f)
848+ , m_radius(SmallRadius)
849+ , m_border(IdleBorder)
850+ , m_imageHorizontalAlignment(AlignHCenter)
851+ , m_imageVerticalAlignment(AlignVCenter)
852+ , m_backgroundMode(SolidColor)
853+ , m_sourceHorizontalAlignment(AlignHCenter)
854+ , m_sourceVerticalAlignment(AlignVCenter)
855+ , m_sourceFillMode(Stretch)
856+ , m_sourceHorizontalWrapMode(Transparent)
857+ , m_sourceVerticalWrapMode(Transparent)
858+ , m_sourceOpacity(255)
859+ , m_flags(Stretched)
860 {
861 setFlag(ItemHasContents);
862 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,
863- SLOT(gridUnitChanged()));
864- setImplicitWidth(8 * gridUnit_);
865- setImplicitHeight(8 * gridUnit_);
866+ SLOT(_q_gridUnitChanged()));
867+ const float gridUnit = UCUnits::instance().gridUnit();
868+ setImplicitWidth(implicitGridUnitWidth * gridUnit);
869+ setImplicitHeight(implicitGridUnitHeight * gridUnit);
870 update();
871 }
872
873-void ShapeItem::setColor(const QColor& color)
874-{
875- if (color_ != color) {
876- color_ = color;
877- // gradientColor has the same value as color unless it was manually set
878- if (!gradientColorSet_) {
879- gradientColor_ = color;
880- Q_EMIT gradientColorChanged();
881- }
882- update();
883- Q_EMIT colorChanged();
884- }
885-}
886-
887-void ShapeItem::setGradientColor(const QColor& gradientColor)
888-{
889- gradientColorSet_ = true;
890- if (gradientColor_ != gradientColor) {
891- gradientColor_ = gradientColor;
892- update();
893- Q_EMIT gradientColorChanged();
894- }
895-}
896-
897-void ShapeItem::setRadius(const QString& radius)
898-{
899- if (radiusString_ != radius) {
900- radiusString_ = radius;
901- radius_ = (radius == "medium") ? ShapeItem::MediumRadius : ShapeItem::SmallRadius;
902+/*! \qmlproperty string UbuntuShape::radius
903+
904+ This property defines the corner radius. Two fixed values are supported: \c "small" and \c
905+ "medium". The default value is \c "small".
906+*/
907+void UCUbuntuShape::setRadius(const QString& radius)
908+{
909+ const Radius newRadius = (radius == "medium") ? MediumRadius : SmallRadius;
910+ if (m_radius != newRadius) {
911+ m_radius = newRadius;
912 update();
913 Q_EMIT radiusChanged();
914 }
915 }
916
917-void ShapeItem::setBorderSource(const QString& borderSource)
918+/*! \qmlproperty string UbuntuShape::borderSource
919+
920+ This property defines the look of the shape borders. The supported strings are \c
921+ "radius_idle.sci" providing an idle button style and \c "radius_pressed.sci" providing a pressed
922+ button style. Any other strings (like the empty one \c "") disables styling. The default value
923+ is \c "radius_idle.sci".
924+*/
925+void UCUbuntuShape::setBorderSource(const QString& borderSource)
926 {
927- if (borderSource_ != borderSource) {
928- if (borderSource.endsWith(QString("radius_idle.sci")))
929- border_ = ShapeItem::IdleBorder;
930- else if (borderSource.endsWith(QString("radius_pressed.sci")))
931- border_ = ShapeItem::PressedBorder;
932- else
933- border_ = ShapeItem::RawBorder;
934- borderSource_ = borderSource;
935+ Border border;
936+ if (borderSource.endsWith(QString("radius_idle.sci"))) {
937+ border = IdleBorder;
938+ } else if (borderSource.endsWith(QString("radius_pressed.sci"))) {
939+ border = PressedBorder;
940+ } else {
941+ border = RawBorder;
942+ }
943+ if (m_border != border) {
944+ m_border = border;
945 update();
946 Q_EMIT borderSourceChanged();
947 }
948 }
949
950-void ShapeItem::setImage(const QVariant& image)
951-{
952- QQuickItem* newImage = qobject_cast<QQuickItem*>(qvariant_cast<QObject*>(image));
953- if (image_ != newImage) {
954- image_ = newImage;
955-
956- // update values of properties that depend on properties of the image
957- QObject::disconnect(image_);
958- if (newImage != NULL) {
959- updateFromImageProperties(newImage);
960- connectToImageProperties(newImage);
961- }
962-
963- if (image_ && !image_->parentItem()) {
964- // Inlined images need a parent and must not be visible.
965- image_->setParentItem(this);
966- image_->setVisible(false);
967- }
968- update();
969- Q_EMIT imageChanged();
970- }
971-}
972-
973-void ShapeItem::updateFromImageProperties(QQuickItem* image)
974+// Deprecation layer.
975+void UCUbuntuShape::dropImageSupport()
976+{
977+ if (!(m_flags & SourceApiSet)) {
978+ m_flags |= SourceApiSet;
979+ if (m_source) {
980+ QObject::disconnect(m_source);
981+ m_source = NULL;
982+ update();
983+ Q_EMIT imageChanged();
984+ }
985+ }
986+}
987+
988+/*! \qmlproperty variant UbuntuShape::source
989+ \since Ubuntu.Components 1.2
990+
991+ This property sets the source provider of a texture rendered in the UbuntuShape. Supported types
992+ are \c Image, \c AnimatedImage (to render a GIF image for instance) and \c ShaderEffectSource
993+ (to embed a UI previously rendered with QML). It is blended over the background color. The
994+ default value is \c null.
995+
996+ It can be set either with an inlined \c Image:
997+
998+ \qml
999+ Item {
1000+ UbuntuShape {
1001+ source: Image { source: "ubuntu.png" }
1002+ }
1003+ }
1004+ \endqml
1005+
1006+ or with an \c Image \c id:
1007+
1008+ \qml
1009+ Item {
1010+ Image {
1011+ id: img
1012+ visible: false
1013+ source: "ubuntu.png"
1014+ }
1015+ UbuntuShape {
1016+ source: img
1017+ }
1018+ }
1019+ \endqml
1020+
1021+ Note that in this case, the \c Image is stored in the scene tree as any other items. So setting
1022+ it as not visible might be needed.
1023+
1024+ The \l{https://en.wikipedia.org/wiki/Texture_filtering}{sampling filter} is set through the
1025+ given Item's \c smooth property. Set it to \c false for nearest-neighbor filtering or to \c true
1026+ for bilinear filtering.
1027+
1028+ The fill modes and alignments set on the \c Image and \c AnimatedImage are not monitored, use
1029+ the appropriate UbuntuShape properties instead (\l sourceFillMode, \l sourceHorizontalAlignment
1030+ and \l sourceVerticalAlignment).
1031+
1032+ \note Setting this disables support for the deprecated \l image property.
1033+*/
1034+void UCUbuntuShape::setSource(const QVariant& source)
1035+{
1036+ dropImageSupport();
1037+
1038+ QQuickItem* newSource = qobject_cast<QQuickItem*>(qvariant_cast<QObject*>(source));
1039+ if (m_source != newSource) {
1040+ if (newSource) {
1041+ if (!newSource->parentItem()) {
1042+ // Inlined images need a parent and must not be visible.
1043+ newSource->setParentItem(this);
1044+ newSource->setVisible(false);
1045+ }
1046+ m_flags |= DirtySourceTransform;
1047+ }
1048+ m_source = newSource;
1049+ update();
1050+ Q_EMIT sourceChanged();
1051+ }
1052+}
1053+
1054+/*! \qmlproperty real UbuntuShape::sourceOpacity
1055+ \since Ubuntu.Components 1.2
1056+
1057+ This property holds the opacity of the \l source texture. Opacity is specified as a number
1058+ between 0.0 (fully transparent) and 1.0 (fully opaque). The default value is 1.0.
1059+
1060+ \note Setting this disables support for the deprecated \l image property.
1061+*/
1062+void UCUbuntuShape::setSourceOpacity(float sourceOpacity)
1063+{
1064+ dropImageSupport();
1065+
1066+ const quint8 sourceOpacityPacked =
1067+ qMax(0.0f, qMin(1.0f, sourceOpacity)) * static_cast<float>(0xff);
1068+ if (m_sourceOpacity != sourceOpacityPacked) {
1069+ m_sourceOpacity = sourceOpacityPacked;
1070+ update();
1071+ Q_EMIT sourceOpacityChanged();
1072+ }
1073+}
1074+
1075+/*! \qmlproperty enumeration UbuntuShape::sourceFillMode
1076+ \since Ubuntu.Components 1.2
1077+
1078+ This properties defines how the \l source texture fills the UbuntuShape. The modes are the same
1079+ as the ones used by \c Image, minus the tiling which is exposed through wrapping properties (\l
1080+ sourceHorizontalWrapMode and \l sourceVerticalWrapMode). The default value is \c
1081+ UbuntuShape.Stretch.
1082+
1083+ \note Setting this disables support for the deprecated \l image property.
1084+
1085+ \list
1086+ \li \b UbuntuShape.Stretch - the source is scaled non-uniformly to fit
1087+ \li \b UbuntuShape.PreserveAspectFit - the source is scaled uniformly to fit without cropping
1088+ \li \b UbuntuShape.PreserveAspectCrop - the source is scaled uniformly to fit with cropping
1089+ \li \b UbuntuShape.Pad - the source is not scaled
1090+ \endlist
1091+*/
1092+void UCUbuntuShape::setSourceFillMode(UCUbuntuShape::FillMode sourceFillMode)
1093+{
1094+ dropImageSupport();
1095+
1096+ if (m_sourceFillMode != sourceFillMode) {
1097+ m_sourceFillMode = sourceFillMode;
1098+ m_flags |= DirtySourceTransform;
1099+ update();
1100+ Q_EMIT sourceFillModeChanged();
1101+ }
1102+}
1103+
1104+/*! \qmlproperty enumeration UbuntuShape::sourceHorizontalWrapMode
1105+ \qmlproperty enumeration UbuntuShape::sourceVerticalWrapMode
1106+ \since Ubuntu.Components 1.2
1107+
1108+ When the \l sourceFillMode is set to \c UbuntuShape.Pad or \c UbuntuShape.PreserveAspectFit or
1109+ when the \l sourceScale and/or \l sourceTranslation properties are changed, the \l source
1110+ texture might not cover the entire UbuntuShape area. This property defines how the source
1111+ texture wraps outside of its content area. The default value is \c UbuntuShape.Transparent.
1112+
1113+ Ensure \c UbuntuShape.Repeat is used only when necessary (in case of an \c Image or \c
1114+ AnimatedImage source) as it requires the underlying texture to be extracted from its atlas. That
1115+ slows down the rendering speed since it prevents the QtQuick renderer to batch the UbuntuShape
1116+ with others.
1117+
1118+ \note Some OpenGL ES 2 implementations do not support \c UbuntuShape.Repeat with
1119+ non-power-of-two sized source textures.
1120+ \note Setting this disables support for the deprecated \l image property.
1121+
1122+ \list
1123+ \li \b UbuntuShape.Transparent - the source is clamped to transparent
1124+ \li \b UbuntuShape.Repeat - the source is repeated indefinitely (not supported yet)
1125+ \endlist
1126+*/
1127+void UCUbuntuShape::setSourceHorizontalWrapMode(UCUbuntuShape::WrapMode sourceHorizontalWrapMode)
1128+{
1129+ dropImageSupport();
1130+
1131+ if (m_sourceHorizontalWrapMode != sourceHorizontalWrapMode) {
1132+ m_sourceHorizontalWrapMode = sourceHorizontalWrapMode;
1133+ update();
1134+ Q_EMIT sourceHorizontalWrapModeChanged();
1135+ }
1136+}
1137+
1138+void UCUbuntuShape::setSourceVerticalWrapMode(UCUbuntuShape::WrapMode sourceVerticalWrapMode)
1139+{
1140+ dropImageSupport();
1141+
1142+ if (m_sourceVerticalWrapMode != sourceVerticalWrapMode) {
1143+ m_sourceVerticalWrapMode = sourceVerticalWrapMode;
1144+ update();
1145+ Q_EMIT sourceVerticalWrapModeChanged();
1146+ }
1147+}
1148+
1149+/*! \qmlproperty enumeration UbuntuShape::sourceHorizontalAlignment
1150+ \since Ubuntu.Components 1.2
1151+
1152+ This property defines how the \l source texture is horizontally aligned inside the UbuntuShape
1153+ area. The default value is \c UbuntuShape.AlignLeft.
1154+
1155+ \note Setting this disables support for the deprecated \l image property.
1156+
1157+ \list
1158+ \li \b UbuntuShape.AlignLeft - the source is aligned to the left
1159+ \li \b UbuntuShape.AlignHCenter - the source is aligned to the horizontal center
1160+ \li \b UbuntuShape.AlignRight - the source is aligned to the right
1161+ \endlist
1162+*/
1163+void UCUbuntuShape::setSourceHorizontalAlignment(
1164+ UCUbuntuShape::HAlignment sourceHorizontalAlignment)
1165+{
1166+ dropImageSupport();
1167+
1168+ if (m_sourceHorizontalAlignment != sourceHorizontalAlignment) {
1169+ m_sourceHorizontalAlignment = sourceHorizontalAlignment;
1170+ m_flags |= DirtySourceTransform;
1171+ update();
1172+ Q_EMIT sourceHorizontalAlignmentChanged();
1173+ }
1174+}
1175+
1176+/*! \qmlproperty enumeration UbuntuShape::sourceVerticalAlignment
1177+ \since Ubuntu.Components 1.2
1178+
1179+ This property defines how the \l source texture is vertically aligned inside the UbuntuShape
1180+ area. The default value is \c UbuntuShape.AlignTop.
1181+
1182+ \note Setting this disables support for the deprecated \l image property.
1183+
1184+ \list
1185+ \li \b UbuntuShape.AlignTop - the source is aligned to the top
1186+ \li \b UbuntuShape.AlignVCenter - the source is aligned to the vertical center
1187+ \li \b UbuntuShape.AlignBottom - the source is aligned to the bottom
1188+ \endlist
1189+*/
1190+void UCUbuntuShape::setSourceVerticalAlignment(UCUbuntuShape::VAlignment sourceVerticalAlignment)
1191+{
1192+ dropImageSupport();
1193+
1194+ if (m_sourceVerticalAlignment != sourceVerticalAlignment) {
1195+ m_sourceVerticalAlignment = sourceVerticalAlignment;
1196+ m_flags |= DirtySourceTransform;
1197+ update();
1198+ Q_EMIT sourceVerticalAlignmentChanged();
1199+ }
1200+}
1201+
1202+/*! \qmlproperty vector2d UbuntuShape::sourceTranslation
1203+ \since Ubuntu.Components 1.2
1204+
1205+ This property defines the two-component vector in normalized item coordinates used to translate
1206+ the \l source texture. The default value is \c {Qt.vector2d(0.0,0.0)}.
1207+
1208+ That can be used to put the \l source texture at a precise position, to create infinite
1209+ scrolling animations (using the \c UbuntuShape.Repeat wrap mode), etc.
1210+
1211+ \note Setting this disables support for the deprecated \l image property.
1212+*/
1213+void UCUbuntuShape::setSourceTranslation(const QVector2D& sourceTranslation)
1214+{
1215+ dropImageSupport();
1216+
1217+ if (m_sourceTranslation != sourceTranslation) {
1218+ m_sourceTranslation = sourceTranslation;
1219+ m_flags |= DirtySourceTransform;
1220+ update();
1221+ Q_EMIT sourceTranslationChanged();
1222+ }
1223+}
1224+
1225+/*! \qmlproperty vector2d UbuntuShape::sourceScale
1226+ \since Ubuntu.Components 1.2
1227+
1228+ This property defines the two-component vector used to scale the \l source texture. The texture
1229+ is scaled at the alignment point defined by \l sourceHorizontalAlignment and \l
1230+ sourceVerticalAlignment. The default value is \c {Qt.vector2d(1.0,1.0)}.
1231+
1232+ That can be used to change the size of the \l source texture, to flip it horizontally and/or
1233+ vertically, to achieve pulsing animations, etc.
1234+
1235+ Here is a code sample showing how to apply an horizontal flip:
1236+
1237+ \qml
1238+ UbuntuShape {
1239+ source: Image { source: "ubuntu.png" }
1240+ sourceScale: Qt.vector2d(-1.0, 1.0)
1241+ }
1242+ \endqml
1243+
1244+ \note Setting this disables support for the deprecated \l image property.
1245+*/
1246+void UCUbuntuShape::setSourceScale(const QVector2D& sourceScale)
1247+{
1248+ dropImageSupport();
1249+
1250+ if (m_sourceScale != sourceScale) {
1251+ m_sourceScale = sourceScale;
1252+ m_flags |= DirtySourceTransform;
1253+ update();
1254+ Q_EMIT sourceScaleChanged();
1255+ }
1256+}
1257+
1258+// Deprecation layer.
1259+void UCUbuntuShape::dropColorSupport()
1260+{
1261+ if (!(m_flags & BackgroundApiSet)) {
1262+ m_flags |= BackgroundApiSet;
1263+ if (m_backgroundColor) {
1264+ m_backgroundColor = qRgba(0, 0, 0, 0);
1265+ Q_EMIT colorChanged();
1266+ }
1267+ if (m_secondaryBackgroundColor) {
1268+ m_secondaryBackgroundColor = qRgba(0, 0, 0, 0);
1269+ Q_EMIT gradientColorChanged();
1270+ }
1271+ }
1272+}
1273+
1274+/*! \qmlproperty color UbuntuShape::backgroundColor
1275+ \since Ubuntu.Components 1.2
1276+
1277+ This property defines the background color. The default value is transparent black.
1278+
1279+ \note Setting this disables support for the deprecated \l color and \l gradientColor properties.
1280+*/
1281+void UCUbuntuShape::setBackgroundColor(const QColor& backgroundColor)
1282+{
1283+ dropColorSupport();
1284+
1285+ const QRgb backgroundColorRgb = qRgba(
1286+ backgroundColor.red(), backgroundColor.green(), backgroundColor.blue(),
1287+ backgroundColor.alpha());
1288+ if (m_backgroundColor != backgroundColorRgb) {
1289+ m_backgroundColor = backgroundColorRgb;
1290+ update();
1291+ Q_EMIT backgroundColorChanged();
1292+ }
1293+}
1294+
1295+/*! \qmlproperty color UbuntuShape::secondaryBackgroundColor
1296+ \since Ubuntu.Components 1.2
1297+
1298+ This property defines the secondary background color. It is used when \l backgroundMode is set
1299+ to \c UbuntuShape.VerticalGradient. The default value is transparent black.
1300+
1301+ \note Setting this disables support for the deprecated \l color and \l gradientColor properties.
1302+*/
1303+void UCUbuntuShape::setSecondaryBackgroundColor(const QColor& secondaryBackgroundColor)
1304+{
1305+ dropColorSupport();
1306+
1307+ const QRgb secondaryBackgroundColorRgb = qRgba(
1308+ secondaryBackgroundColor.red(), secondaryBackgroundColor.green(),
1309+ secondaryBackgroundColor.blue(), secondaryBackgroundColor.alpha());
1310+ if (m_secondaryBackgroundColor != secondaryBackgroundColorRgb) {
1311+ m_secondaryBackgroundColor = secondaryBackgroundColorRgb;
1312+ update();
1313+ Q_EMIT secondaryBackgroundColorChanged();
1314+ }
1315+}
1316+
1317+/*! \qmlproperty enumeration UbuntuShape::backgroundMode
1318+ \since Ubuntu.Components 1.2
1319+
1320+ This property defines the background rendering mode. The default value is \c
1321+ UbuntuShape.SolidColor.
1322+
1323+ \note Setting this disables support for the deprecated \l color and \l gradientColor properties.
1324+
1325+ \list
1326+ \li \b UbuntuShape.SolidColor - the color is \l backgroundColor
1327+ \li \b UbuntuShape.VerticalGradient - the color is a vertical gradient from \l backgroundColor
1328+ to \l secondaryBackgroundColor.
1329+ \endlist
1330+*/
1331+void UCUbuntuShape::setBackgroundMode(BackgroundMode backgroundMode)
1332+{
1333+ dropColorSupport();
1334+
1335+ if (m_backgroundMode != backgroundMode) {
1336+ m_backgroundMode = backgroundMode;
1337+ update();
1338+ Q_EMIT backgroundModeChanged();
1339+ }
1340+}
1341+
1342+/*! \qmlproperty color UbuntuShape::color
1343+ \deprecated
1344+
1345+ This property defines the color used to fill the UbuntuShape when there is no \l image set. If
1346+ \l gradientColor is set, this property defines the top color of the gradient. The default value
1347+ is transparent black.
1348+
1349+ \note Use \l backgroundColor, \l secondaryBackgroundColor and \l backgroundMode instead.
1350+*/
1351+void UCUbuntuShape::setColor(const QColor& color)
1352+{
1353+ if (!(m_flags & BackgroundApiSet)) {
1354+ const QRgb colorRgb = qRgba(color.red(), color.green(), color.blue(), color.alpha());
1355+ if (m_backgroundColor != colorRgb) {
1356+ m_backgroundColor = colorRgb;
1357+ // gradientColor has the same value as color unless it was explicitly set.
1358+ if (!(m_flags & GradientColorSet)) {
1359+ m_secondaryBackgroundColor = colorRgb;
1360+ Q_EMIT gradientColorChanged();
1361+ }
1362+ update();
1363+ Q_EMIT colorChanged();
1364+ }
1365+ }
1366+}
1367+
1368+/*! \qmlproperty color UbuntuShape::gradientColor
1369+ \deprecated
1370+
1371+ This property defines the bottom color used for the vertical gradient filling the UbuntuShape
1372+ when there is no \l image set. As long as this property is not set, a single color (defined
1373+ by \l color) is used to fill the UbuntuShape.
1374+
1375+ \note Use \l backgroundColor, \l secondaryBackgroundColor and \l backgroundMode instead.
1376+*/
1377+void UCUbuntuShape::setGradientColor(const QColor& gradientColor)
1378+{
1379+ if (!(m_flags & BackgroundApiSet)) {
1380+ m_flags |= GradientColorSet;
1381+ const QRgb gradientColorRgb = qRgba(
1382+ gradientColor.red(), gradientColor.green(), gradientColor.blue(),
1383+ gradientColor.alpha());
1384+ if (m_secondaryBackgroundColor != gradientColorRgb) {
1385+ m_secondaryBackgroundColor = gradientColorRgb;
1386+ update();
1387+ Q_EMIT gradientColorChanged();
1388+ }
1389+ }
1390+}
1391+
1392+/*! \qmlproperty Image UbuntuShape::image
1393+ \deprecated
1394+
1395+ This property holds the \c Image or \c ShaderEffectSource rendered in the UbuntuShape. In case
1396+ of an \c Image, it watches for fillMode (\c Image.Stretch and\c Image.PreserveAspectCrop), \c
1397+ horizontalAlignment and \c verticalAlignment property changes. The default value is \c null.
1398+
1399+ \note Use \l source instead.
1400+*/
1401+void UCUbuntuShape::setImage(const QVariant& image)
1402+{
1403+ if (!(m_flags & SourceApiSet)) {
1404+ QQuickItem* newImage = qobject_cast<QQuickItem*>(qvariant_cast<QObject*>(image));
1405+ if (m_source != newImage) {
1406+ if (newImage) {
1407+ // Watch for property changes.
1408+ updateFromImageProperties(newImage);
1409+ connectToImageProperties(newImage);
1410+ if (!newImage->parentItem()) {
1411+ // Inlined images need a parent and must not be visible.
1412+ newImage->setParentItem(this);
1413+ newImage->setVisible(false);
1414+ }
1415+ m_flags |= DirtySourceTransform;
1416+ }
1417+ QObject::disconnect(m_source);
1418+ update();
1419+ m_source = newImage;
1420+ Q_EMIT imageChanged();
1421+ }
1422+ }
1423+}
1424+
1425+// Deprecation layer. Even though "stretched" is exposed as a QML property, it's only been used when
1426+// there was a QML UbuntuShape proxy. This is why we don't provide doc for it. We'll still have to
1427+// maintain it for a while for compatibility reasons.
1428+void UCUbuntuShape::setStretched(bool stretched)
1429+{
1430+ if (!(m_flags & SourceApiSet)) {
1431+ if (!!(m_flags & Stretched) != stretched) {
1432+ if (stretched) {
1433+ m_flags |= Stretched;
1434+ } else {
1435+ m_flags &= ~Stretched;
1436+ }
1437+ m_flags |= DirtySourceTransform;
1438+ update();
1439+ Q_EMIT stretchedChanged();
1440+ }
1441+ }
1442+}
1443+
1444+// Deprecation layer. Same comment as setStretched().
1445+void UCUbuntuShape::setHorizontalAlignment(HAlignment horizontalAlignment)
1446+{
1447+ if (!(m_flags & SourceApiSet)) {
1448+ if (m_imageHorizontalAlignment != horizontalAlignment) {
1449+ m_imageHorizontalAlignment = horizontalAlignment;
1450+ m_flags |= DirtySourceTransform;
1451+ update();
1452+ Q_EMIT horizontalAlignmentChanged();
1453+ }
1454+ }
1455+}
1456+
1457+// Deprecation layer. Same comment as setStretched().
1458+void UCUbuntuShape::setVerticalAlignment(VAlignment verticalAlignment)
1459+{
1460+ if (!(m_flags & SourceApiSet)) {
1461+ if (m_imageVerticalAlignment != verticalAlignment) {
1462+ m_imageVerticalAlignment = verticalAlignment;
1463+ m_flags |= DirtySourceTransform;
1464+ update();
1465+ Q_EMIT verticalAlignmentChanged();
1466+ }
1467+ }
1468+}
1469+
1470+// Deprecation layer.
1471+void UCUbuntuShape::updateFromImageProperties(QQuickItem* image)
1472 {
1473 int alignment;
1474
1475- // ShapeItem::stretched depends on image::fillMode
1476+ // UbuntuShape::stretched depends on Image::fillMode.
1477 QQuickImage::FillMode fillMode = (QQuickImage::FillMode)image->property("fillMode").toInt();
1478 if (fillMode == QQuickImage::PreserveAspectCrop) {
1479 setStretched(false);
1480@@ -314,640 +820,516 @@
1481 setStretched(true);
1482 }
1483
1484- // ShapeItem::horizontalAlignment depends on image::horizontalAlignment
1485+ // UbuntuShape::horizontalAlignment depends on Image::horizontalAlignment.
1486 int imageHorizontalAlignment = image->property("horizontalAlignment").toInt();
1487 if (imageHorizontalAlignment == Qt::AlignLeft) {
1488- alignment = ShapeItem::AlignLeft;
1489+ alignment = AlignLeft;
1490 } else if (imageHorizontalAlignment == Qt::AlignRight) {
1491- alignment = ShapeItem::AlignRight;
1492+ alignment = AlignRight;
1493 } else {
1494- alignment = ShapeItem::AlignHCenter;
1495+ alignment = AlignHCenter;
1496 }
1497- setHorizontalAlignment(static_cast<ShapeItem::HAlignment>(alignment));
1498+ setHorizontalAlignment(static_cast<HAlignment>(alignment));
1499
1500- // ShapeItem::verticalAlignment depends on image::verticalAlignment
1501+ // UbuntuShape::verticalAlignment depends on Image::verticalAlignment.
1502 int imageVerticalAlignment = image->property("verticalAlignment").toInt();
1503 if (imageVerticalAlignment == Qt::AlignTop) {
1504- alignment = ShapeItem::AlignTop;
1505+ alignment = AlignTop;
1506 } else if (imageVerticalAlignment == Qt::AlignBottom) {
1507- alignment = ShapeItem::AlignBottom;
1508+ alignment = AlignBottom;
1509 } else {
1510- alignment = ShapeItem::AlignVCenter;
1511+ alignment = AlignVCenter;
1512 }
1513- setVerticalAlignment(static_cast<ShapeItem::VAlignment>(alignment));
1514+ setVerticalAlignment(static_cast<UCUbuntuShape::VAlignment>(alignment));
1515 }
1516
1517-void ShapeItem::connectToPropertyChange(QObject* sender, const char* property,
1518- QObject* receiver, const char* slot)
1519+// Deprecation layer.
1520+void UCUbuntuShape::connectToPropertyChange(
1521+ QObject* sender, const char* property, QObject* receiver, const char* slot)
1522 {
1523 int propertyIndex = sender->metaObject()->indexOfProperty(property);
1524 if (propertyIndex != -1) {
1525 QMetaMethod changeSignal = sender->metaObject()->property(propertyIndex).notifySignal();
1526-
1527 int slotIndex = receiver->metaObject()->indexOfSlot(slot);
1528 QMetaMethod updateSlot = receiver->metaObject()->method(slotIndex);
1529-
1530 QObject::connect(sender, changeSignal, receiver, updateSlot);
1531 }
1532 }
1533
1534-void ShapeItem::connectToImageProperties(QQuickItem* image)
1535+// Deprecation layer.
1536+void UCUbuntuShape::connectToImageProperties(QQuickItem* image)
1537 {
1538- connectToPropertyChange(image, "fillMode", this, "onImagePropertiesChanged()");
1539- connectToPropertyChange(image, "horizontalAlignment", this, "onImagePropertiesChanged()");
1540- connectToPropertyChange(image, "verticalAlignment", this, "onImagePropertiesChanged()");
1541+ connectToPropertyChange(image, "fillMode", this, "_q_imagePropertiesChanged()");
1542+ connectToPropertyChange(image, "horizontalAlignment", this, "_q_imagePropertiesChanged()");
1543+ connectToPropertyChange(image, "verticalAlignment", this, "_q_imagePropertiesChanged()");
1544 }
1545
1546-void ShapeItem::onImagePropertiesChanged()
1547+// Deprecation layer.
1548+void UCUbuntuShape::_q_imagePropertiesChanged()
1549 {
1550 QQuickItem* image = qobject_cast<QQuickItem*>(sender());
1551 updateFromImageProperties(image);
1552 }
1553
1554-void ShapeItem::setStretched(bool stretched)
1555-{
1556- if (stretched_ != stretched) {
1557- stretched_ = stretched;
1558- update();
1559- Q_EMIT stretchedChanged();
1560- }
1561-}
1562-
1563-void ShapeItem::setHorizontalAlignment(HAlignment hAlignment)
1564-{
1565- if (hAlignment_ != hAlignment) {
1566- hAlignment_ = hAlignment;
1567- update();
1568- Q_EMIT horizontalAlignmentChanged();
1569- }
1570-}
1571-
1572-void ShapeItem::setVerticalAlignment(VAlignment vAlignment)
1573-{
1574- if (vAlignment_ != vAlignment) {
1575- vAlignment_ = vAlignment;
1576- update();
1577- Q_EMIT verticalAlignmentChanged();
1578- }
1579-}
1580-
1581-void ShapeItem::gridUnitChanged()
1582-{
1583- gridUnit_ = UCUnits::instance().gridUnit();
1584- setImplicitWidth(8 * gridUnit_);
1585- setImplicitHeight(8 * gridUnit_);
1586- update();
1587-}
1588-
1589-void ShapeItem::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
1590-{
1591- geometry_ = newGeometry;
1592- QQuickItem::geometryChanged(newGeometry, oldGeometry);
1593- update();
1594-}
1595-
1596-void ShapeItem::onOpenglContextDestroyed()
1597+void UCUbuntuShape::_q_openglContextDestroyed()
1598 {
1599 QOpenGLContext* context = qobject_cast<QOpenGLContext*>(sender());
1600- if (Q_UNLIKELY(!context)) return;
1601-
1602- QHash<QOpenGLContext*, TextureHandles>::iterator it =
1603- textures_.find(context);
1604- if (it != textures_.end()) {
1605- TextureHandles &textureHandles = it.value();
1606- delete textureHandles.high;
1607- delete textureHandles.low;
1608- textures_.erase(it);
1609+ if (context) {
1610+ QHash<QOpenGLContext*, ShapeTextures>::iterator it = shapeTexturesHash.find(context);
1611+ if (it != shapeTexturesHash.end()) {
1612+ ShapeTextures &shapeTextures = it.value();
1613+ delete shapeTextures.high;
1614+ delete shapeTextures.low;
1615+ shapeTexturesHash.erase(it);
1616+ }
1617 }
1618 }
1619
1620-void ShapeItem::providerDestroyed(QObject* object)
1621+void UCUbuntuShape::_q_gridUnitChanged()
1622+{
1623+ const float gridUnit = UCUnits::instance().gridUnit();
1624+ setImplicitWidth(implicitGridUnitWidth * gridUnit);
1625+ setImplicitHeight(implicitGridUnitHeight * gridUnit);
1626+ update();
1627+}
1628+
1629+void UCUbuntuShape::_q_providerDestroyed(QObject* object)
1630 {
1631 Q_UNUSED(object);
1632- provider_ = NULL;
1633-}
1634-
1635-QSGNode* ShapeItem::updatePaintNode(QSGNode* old_node, UpdatePaintNodeData* data)
1636+ m_sourceTextureProvider = NULL;
1637+}
1638+
1639+void UCUbuntuShape::_q_textureChanged()
1640+{
1641+ m_flags |= DirtySourceTransform;
1642+ update();
1643+}
1644+
1645+void UCUbuntuShape::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
1646+{
1647+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
1648+ m_flags |= DirtySourceTransform;
1649+}
1650+
1651+// Gets the nearest boundary to coord in the texel grid of the given size.
1652+static Q_DECL_CONSTEXPR float roundTextureCoord(float coord, float size)
1653+{
1654+ return roundf(coord * size) / size;
1655+}
1656+
1657+void UCUbuntuShape::updateSourceTransform(
1658+ float itemWidth, float itemHeight, FillMode fillMode, HAlignment horizontalAlignment,
1659+ VAlignment verticalAlignment, const QSize& textureSize)
1660+{
1661+ float fillSx, fillSy;
1662+ if (fillMode == PreserveAspectFit) {
1663+ const float textureRatio = static_cast<float>(textureSize.width()) / textureSize.height();
1664+ const float itemRatio = itemWidth / itemHeight;
1665+ fillSx = (textureRatio < itemRatio) ? (itemRatio / textureRatio) : 1.0f;
1666+ fillSy = (textureRatio < itemRatio) ? 1.0f : (textureRatio / itemRatio);
1667+ } else if (fillMode == PreserveAspectCrop) {
1668+ const float textureRatio = static_cast<float>(textureSize.width()) / textureSize.height();
1669+ const float itemRatio = itemWidth / itemHeight;
1670+ fillSx = (textureRatio < itemRatio) ? 1.0f : (itemRatio / textureRatio);
1671+ fillSy = (textureRatio < itemRatio) ? (textureRatio / itemRatio) : 1.0f;
1672+ } else if (fillMode == Pad) {
1673+ fillSx = itemWidth / textureSize.width();
1674+ fillSy = itemHeight / textureSize.height();
1675+ } else {
1676+ fillSx = 1.0f;
1677+ fillSy = 1.0f;
1678+ }
1679+
1680+ const float sourceSxInv = 1.0f / m_sourceScale.x();
1681+ const float sourceSyInv = 1.0f / m_sourceScale.y();
1682+ // Multiplied by fillS* so that the translation unit is in normalized item coordinates.
1683+ const float sourceTx = (m_sourceTranslation.x() * sourceSxInv) * fillSx;
1684+ const float sourceTy = (m_sourceTranslation.y() * sourceSyInv) * fillSy;
1685+ const float sx = fillSx * sourceSxInv;
1686+ const float sy = fillSy * sourceSyInv;
1687+ const float factorTable[3] = { 0.0f, 0.5f, 1.0f };
1688+ const float hFactor = factorTable[static_cast<int>(horizontalAlignment)];
1689+ const float vFactor = factorTable[static_cast<int>(verticalAlignment)];
1690+ const float tx = hFactor * (1.0f - sx) - sourceTx;
1691+ const float ty = vFactor * (1.0f - sy) - sourceTy;
1692+
1693+ // Rounding is important to get padded texture perfectly mapped to the pixel grid. It shouldn't
1694+ // be necessary when there's a scaling but we make it consistent by applying the scale factors
1695+ // to the texture size, so that there's no ugly position jumps with big scaling values.
1696+ m_sourceTransform = QVector4D(
1697+ sx, sy, roundTextureCoord(tx, textureSize.width() * m_sourceScale.x()),
1698+ roundTextureCoord(ty, textureSize.height() * m_sourceScale.y()));
1699+}
1700+
1701+// Pack a premultiplied 32-bit ABGR integer.
1702+static quint32 packColor(quint32 a, quint32 b, quint32 g, quint32 r)
1703+{
1704+ const quint32 pb = ((b * a) + 0xff) >> 8;
1705+ const quint32 pg = ((g * a) + 0xff) >> 8;
1706+ const quint32 pr = ((r * a) + 0xff) >> 8;
1707+ return (a << 24) | ((pb & 0xff) << 16) | ((pg & 0xff) << 8) | (pr & 0xff);
1708+}
1709+
1710+// Lerp c1 and c2 with t in the range [0, 255]. Return value is a premultiplied 32-bit ABGR integer.
1711+static quint32 lerpColor(quint32 t, QRgb c1, QRgb c2)
1712+{
1713+ const quint32 a = qAlpha(c1) + ((t * (qAlpha(c2) - qAlpha(c1)) + 0xff) >> 8);
1714+ const quint32 b = qBlue(c1) + ((t * (qBlue(c2) - qBlue(c1)) + 0xff) >> 8);
1715+ const quint32 g = qGreen(c1) + ((t * (qGreen(c2) - qGreen(c1)) + 0xff) >> 8);
1716+ const quint32 r = qRed(c1) + ((t * (qRed(c2) - qRed(c1)) + 0xff) >> 8);
1717+ return packColor(a, b, g, r);
1718+}
1719+
1720+QSGNode* UCUbuntuShape::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data)
1721 {
1722 Q_UNUSED(data);
1723
1724- // FIXME(loicm) Shape textures are stored in the read-only data section of the plugin as it
1725- // avoids having to deal with paths for now. It should preferably be loaded from a file.
1726-
1727- // OpenGL allocates textures per context, so we store textures reused by
1728- // all shape instances per context as well
1729+ const QSizeF itemSize(width(), height());
1730+ if (itemSize.isEmpty()) {
1731+ delete oldNode;
1732+ return NULL;
1733+ }
1734+
1735+ QSGNode* node = oldNode ? oldNode : createSceneGraphNode();
1736+ Q_ASSERT(node);
1737+
1738+ // OpenGL allocates textures per context, so we store textures reused by all shape instances
1739+ // per context as well.
1740 QOpenGLContext* openglContext = window() ? window()->openglContext() : NULL;
1741- if (Q_UNLIKELY(!openglContext)) {
1742- qCritical() << "Window has no GL context!";
1743- delete old_node;
1744- return NULL;
1745- }
1746-
1747- TextureHandles &textureHandles = textures_[openglContext];
1748- // If the hash table didn't contain an entry for the current context, the
1749- // line above has just caused the creation of a default-constructed value.
1750- if (!textureHandles.high) {
1751- textureHandles.high = window()->createTextureFromImage(
1752+ Q_ASSERT(openglContext);
1753+ ShapeTextures &shapeTextures = shapeTexturesHash[openglContext];
1754+ if (!shapeTextures.high) {
1755+ shapeTextures.high = window()->createTextureFromImage(
1756 QImage(shapeTextureHigh.data, shapeTextureHigh.width, shapeTextureHigh.height,
1757 QImage::Format_ARGB32_Premultiplied));
1758- textureHandles.low = window()->createTextureFromImage(
1759+ shapeTextures.low = window()->createTextureFromImage(
1760 QImage(shapeTextureLow.data, shapeTextureLow.width, shapeTextureLow.height,
1761 QImage::Format_ARGB32_Premultiplied));
1762 QObject::connect(openglContext, SIGNAL(aboutToBeDestroyed()),
1763- this, SLOT(onOpenglContextDestroyed()),
1764- Qt::DirectConnection);
1765- }
1766-
1767- // Update the node whenever the source item's texture changes.
1768- QSGTextureProvider* provider = image_ ? image_->textureProvider() : NULL;
1769- if (provider != provider_) {
1770- if (provider_) {
1771- QObject::disconnect(provider_, SIGNAL(textureChanged()), this, SLOT(update()));
1772- QObject::disconnect(provider_, SIGNAL(destroyed()), this, SLOT(providerDestroyed()));
1773+ this, SLOT(_q_openglContextDestroyed()), Qt::DirectConnection);
1774+ }
1775+
1776+ // Get the texture info and update the source transform if needed.
1777+ QSGTextureProvider* provider = m_source ? m_source->textureProvider() : NULL;
1778+ QSGTexture* sourceTexture = provider ? provider->texture() : NULL;
1779+ QRectF sourceTextureRect(0.0f, 0.0f, 1.0f, 1.0f);
1780+ if (sourceTexture) {
1781+ if (m_sourceHorizontalWrapMode == Transparent && m_sourceVerticalWrapMode == Transparent) {
1782+ sourceTextureRect = sourceTexture->normalizedTextureSubRect();
1783+ }
1784+ if (m_flags & DirtySourceTransform) {
1785+ if (m_flags & SourceApiSet) {
1786+ updateSourceTransform(itemSize.width(), itemSize.height(), m_sourceFillMode,
1787+ m_sourceHorizontalAlignment, m_sourceVerticalAlignment,
1788+ sourceTexture->textureSize());
1789+ } else {
1790+ FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;
1791+ updateSourceTransform(itemSize.width(), itemSize.height(), imageFillMode,
1792+ m_imageHorizontalAlignment, m_imageVerticalAlignment,
1793+ sourceTexture->textureSize());
1794+ }
1795+ m_flags &= ~DirtySourceTransform;
1796+ }
1797+ }
1798+
1799+ // Update the shape item whenever the source item's texture changes.
1800+ if (provider != m_sourceTextureProvider) {
1801+ if (m_sourceTextureProvider) {
1802+ QObject::disconnect(m_sourceTextureProvider, SIGNAL(textureChanged()),
1803+ this, SLOT(_q_textureChanged()));
1804+ QObject::disconnect(m_sourceTextureProvider, SIGNAL(destroyed()),
1805+ this, SLOT(_q_providerDestroyed()));
1806 }
1807 if (provider) {
1808- QObject::connect(provider, SIGNAL(textureChanged()), this, SLOT(update()));
1809- QObject::connect(provider, SIGNAL(destroyed()), this, SLOT(providerDestroyed()));
1810+ QObject::connect(provider, SIGNAL(textureChanged()), this, SLOT(_q_textureChanged()));
1811+ QObject::connect(provider, SIGNAL(destroyed()), this, SLOT(_q_providerDestroyed()));
1812 }
1813- provider_ = provider;
1814- }
1815-
1816- ShapeNode* node = static_cast<ShapeNode*>(old_node);
1817- if (!node) {
1818- node = new ShapeNode(this);
1819- }
1820-
1821- ShapeTexturedMaterial* texturedMaterial = node->texturedMaterial();
1822- ShapeColoredMaterial* coloredMaterial = node->coloredMaterial();
1823- TextureData* textureData;
1824- QSGTexture* textureHandle;
1825- if (gridUnit_ > lowHighTextureThreshold) {
1826- textureData = &shapeTextureHigh;
1827- textureHandle = textureHandles.high;
1828+ m_sourceTextureProvider = provider;
1829+ }
1830+
1831+ const float gridUnit = UCUnits::instance().gridUnit();
1832+ ShapeTextureData* shapeTextureData;
1833+ QSGTexture* shapeTexture;
1834+ if (gridUnit > lowHighTextureThreshold) {
1835+ shapeTextureData = &shapeTextureHigh;
1836+ shapeTexture = shapeTextures.high;
1837 } else {
1838- textureData = &shapeTextureLow;
1839- textureHandle = textureHandles.low;
1840+ shapeTextureData = &shapeTextureLow;
1841+ shapeTexture = shapeTextures.low;
1842 }
1843
1844 // Set the shape texture to be used by the materials depending on current grid unit. The radius
1845 // is set considering the current grid unit and the texture raster grid unit. When the item size
1846- // is less than 2 radii, the radius is scaled down anyhow.
1847- float radius = (radius_ == ShapeItem::SmallRadius) ?
1848- textureData->smallRadius : textureData->mediumRadius;
1849- const float scaleFactor = gridUnit_ / textureData->gridUnit;
1850- radius *= scaleFactor;
1851- int scaledDown = 0;
1852+ // is less than 2 radii, the radius is scaled down.
1853+ QSGTexture::Filtering shapeTextureFiltering;
1854+ float radius = (m_radius == SmallRadius) ?
1855+ shapeTextureData->smallRadius : shapeTextureData->mediumRadius;
1856+ const float scaleFactor = gridUnit / shapeTextureData->gridUnit;
1857+ shapeTextureFiltering = QSGTexture::Nearest;
1858 if (scaleFactor != 1.0f) {
1859- scaledDown |= 1;
1860+ radius *= scaleFactor;
1861+ shapeTextureFiltering = QSGTexture::Linear;
1862 }
1863- const float halfMinWidthHeight = qMin(geometry_.width(), geometry_.height()) * 0.5f;
1864+ const float halfMinWidthHeight = qMin(itemSize.width(), itemSize.height()) * 0.5f;
1865 if (radius > halfMinWidthHeight) {
1866 radius = halfMinWidthHeight;
1867- scaledDown |= 1;
1868+ shapeTextureFiltering = QSGTexture::Linear;
1869 }
1870- coloredMaterial->setShapeTexture(textureHandle, !!scaledDown);
1871- texturedMaterial->setShapeTexture(textureHandle, !!scaledDown);
1872-
1873- // Update the other material properties.
1874- coloredMaterial->setColor(color_);
1875- coloredMaterial->setGradientColor(gradientColor_);
1876- texturedMaterial->setImage(image_);
1877-
1878- // Update node vertices and type.
1879- int index = (border_ == ShapeItem::RawBorder) ?
1880- 0 : (border_ == ShapeItem::IdleBorder) ? 1 : 2;
1881- if (radius_ == ShapeItem::SmallRadius)
1882+
1883+ updateMaterial(node, shapeTexture, shapeTextureFiltering, sourceTexture);
1884+
1885+ // Select the right shape texture coordinates.
1886+ int index = (m_border == RawBorder) ? 0 : (m_border == IdleBorder) ? 1 : 2;
1887+ if (m_radius == SmallRadius) {
1888 index += 3;
1889- node->setVertices(geometry_, radius, image_, stretched_, hAlignment_, vAlignment_,
1890- textureData->coordinate[index]);
1891- const QSGTexture* texture = provider ? provider->texture() : NULL;
1892- node->setMaterialType(texture ? ShapeNode::TexturedMaterial : ShapeNode::ColoredMaterial);
1893+ }
1894+
1895+ // Get the affine transformation for the source texture coordinates.
1896+ const QVector4D sourceCoordTransform(
1897+ m_sourceTransform.x() * sourceTextureRect.width(),
1898+ m_sourceTransform.y() * sourceTextureRect.height(),
1899+ m_sourceTransform.z() * sourceTextureRect.width() + sourceTextureRect.x(),
1900+ m_sourceTransform.w() * sourceTextureRect.height() + sourceTextureRect.y());
1901+
1902+ // Get the affine transformation for the source mask coordinates, pixels lying inside the mask
1903+ // (values in the range [-1, 1]) will be textured in the fragment shader. In case of a repeat
1904+ // wrap mode, the transformation is made so that the mask takes the whole area.
1905+ const QVector4D sourceMaskTransform(
1906+ m_sourceHorizontalWrapMode == Transparent ? m_sourceTransform.x() * 2.0f : 2.0f,
1907+ m_sourceVerticalWrapMode == Transparent ? m_sourceTransform.y() * 2.0f : 2.0f,
1908+ m_sourceHorizontalWrapMode == Transparent ? m_sourceTransform.z() * 2.0f - 1.0f : -1.0f,
1909+ m_sourceVerticalWrapMode == Transparent ? m_sourceTransform.w() * 2.0f - 1.0f : -1.0f);
1910+
1911+ // Select and pack the lerp'd and premultiplied background colors.
1912+ QRgb color[2];
1913+ if (m_flags & BackgroundApiSet) {
1914+ color[0] = m_backgroundColor;
1915+ color[1] = (m_backgroundMode == SolidColor) ?
1916+ m_backgroundColor : m_secondaryBackgroundColor;
1917+ } else {
1918+ if (!sourceTexture) {
1919+ color[0] = m_backgroundColor;
1920+ // For API compatibility reasons, m_secondaryBackgroundColor is set to m_backgroundColor
1921+ // as long as setGradientColor() isn't called, so we can safely use it here.
1922+ color[1] = m_secondaryBackgroundColor;
1923+ } else {
1924+ // The deprecated image API was created such that whenever an image is set, the
1925+ // background color is transparent.
1926+ color[0] = qRgba(0, 0, 0, 0);
1927+ color[1] = qRgba(0, 0, 0, 0);
1928+ }
1929+ }
1930+ const quint32 radiusHeight = static_cast<quint32>((radius / itemSize.height()) * 255.0f);
1931+ const quint32 backgroundColor[4] = {
1932+ packColor(qAlpha(color[0]), qBlue(color[0]), qGreen(color[0]), qRed(color[0])),
1933+ lerpColor(radiusHeight, color[0], color[1]),
1934+ lerpColor(255 - radiusHeight, color[0], color[1]),
1935+ packColor(qAlpha(color[1]), qBlue(color[1]), qGreen(color[1]), qRed(color[1]))
1936+ };
1937+
1938+ updateGeometry(
1939+ node, itemSize.width(), itemSize.height(), radius, shapeTextureData->coordinate[index],
1940+ sourceCoordTransform, sourceMaskTransform, backgroundColor);
1941
1942 return node;
1943 }
1944
1945-// --- Scene graph geometry node ---
1946-
1947-ShapeNode::ShapeNode(ShapeItem* item)
1948- : QSGGeometryNode()
1949- , item_(item)
1950- , geometry_(getAttributes(), shapeMesh.vertexCount, shapeMesh.indexCount, shapeMesh.indexType)
1951- , texturedMaterial_()
1952- , coloredMaterial_()
1953- , currentMaterial_(ShapeNode::ColoredMaterial)
1954+QSGNode* UCUbuntuShape::createSceneGraphNode() const
1955 {
1956- memcpy(geometry_.indexData(), shapeMesh.indices,
1957- shapeMesh.indexCount * sizeOfType(shapeMesh.indexType));
1958- geometry_.setDrawingMode(GL_TRIANGLE_STRIP);
1959- geometry_.setIndexDataPattern(QSGGeometry::StaticPattern);
1960- geometry_.setVertexDataPattern(QSGGeometry::AlwaysUploadPattern);
1961- setGeometry(&geometry_);
1962- setMaterial(&coloredMaterial_);
1963- setFlag(UsePreprocess, false);
1964+ return new ShapeNode;
1965 }
1966
1967-void ShapeNode::setVertices(const QRectF& geometry, float radius, QQuickItem* image, bool stretched,
1968- ShapeItem::HAlignment hAlignment, ShapeItem::VAlignment vAlignment,
1969- float shapeCoordinate[][2])
1970+void UCUbuntuShape::updateMaterial(
1971+ QSGNode* node, QSGTexture* shapeTexture, QSGTexture::Filtering shapeTextureFiltering,
1972+ QSGTexture* sourceTexture)
1973 {
1974- ShapeNode::Vertex* vertices = reinterpret_cast<ShapeNode::Vertex*>(geometry_.vertexData());
1975- const QSGTextureProvider* provider = image ? image->textureProvider() : NULL;
1976- const QSGTexture* texture = provider ? provider->texture() : NULL;
1977- const float width = geometry.width();
1978- const float height = geometry.height();
1979- float topCoordinate;
1980- float bottomCoordinate;
1981- float leftCoordinate;
1982- float rightCoordinate;
1983- float radiusCoordinateWidth;
1984- float radiusCoordinateHeight;
1985+ ShapeNode* shapeNode = static_cast<ShapeNode*>(node);
1986+ ShapeMaterial::Data* materialData = shapeNode->material()->data();
1987+ quint8 flags = 0;
1988
1989- // FIXME(loicm) With a NxM image, a preserve aspect crop fill mode and a width
1990- // component size of N (or a height component size of M), changing the the
1991- // height (or width) breaks the 1:1 texel/pixel mapping for odd values.
1992- if (!stretched && texture) {
1993- // Preserve source image aspect ratio cropping areas exceeding destination rectangle.
1994- const float factors[3] = { 0.0f, 0.5f, 1.0f };
1995- const QSize srcSize = texture->textureSize();
1996- const float srcRatio = static_cast<float>(srcSize.width()) / srcSize.height();
1997- const float dstRatio = static_cast<float>(width) / height;
1998- if (dstRatio <= srcRatio) {
1999- const float inCoordinateSize = dstRatio / srcRatio;
2000- const float outCoordinateSize = 1.0f - inCoordinateSize;
2001- topCoordinate = 0.0f;
2002- bottomCoordinate = 1.0f;
2003- leftCoordinate = outCoordinateSize * factors[hAlignment];
2004- rightCoordinate = 1.0f - (outCoordinateSize * (1.0f - factors[hAlignment]));
2005- radiusCoordinateHeight = radius / height;
2006- radiusCoordinateWidth = (radius / width) * inCoordinateSize;
2007- } else {
2008- const float inCoordinateSize = srcRatio / dstRatio;
2009- const float outCoordinateSize = 1.0f - inCoordinateSize;
2010- topCoordinate = outCoordinateSize * factors[vAlignment];
2011- bottomCoordinate = 1.0f - (outCoordinateSize * (1.0f - factors[vAlignment]));
2012- leftCoordinate = 0.0f;
2013- rightCoordinate = 1.0f;
2014- radiusCoordinateHeight = (radius / height) * inCoordinateSize;
2015- radiusCoordinateWidth = radius / width;
2016- }
2017+ materialData->shapeTexture = shapeTexture;
2018+ if (sourceTexture && m_sourceOpacity) {
2019+ materialData->sourceTextureProvider = m_sourceTextureProvider;
2020+ materialData->sourceOpacity = m_sourceOpacity;
2021+ if (m_sourceHorizontalWrapMode == Repeat) {
2022+ flags |= ShapeMaterial::Data::HorizontallyRepeated;
2023+ }
2024+ if (m_sourceVerticalWrapMode == Repeat) {
2025+ flags |= ShapeMaterial::Data::VerticallyRepeated;
2026+ }
2027+ flags |= ShapeMaterial::Data::Textured;
2028 } else {
2029- // Don't preserve source image aspect ratio stretching it in destination rectangle.
2030- topCoordinate = 0.0f;
2031- bottomCoordinate = 1.0f;
2032- leftCoordinate = 0.0f;
2033- rightCoordinate = 1.0f;
2034- radiusCoordinateHeight = radius / height;
2035- radiusCoordinateWidth = radius / width;
2036- }
2037-
2038- // Scale and translate coordinates of textures packed in an atlas.
2039- if (texture && texture->isAtlasTexture()) {
2040- const QRectF srcSubRect = texture->normalizedTextureSubRect();
2041- topCoordinate = topCoordinate * srcSubRect.height() + srcSubRect.y();
2042- bottomCoordinate = bottomCoordinate * srcSubRect.height() + srcSubRect.y();
2043- leftCoordinate = leftCoordinate * srcSubRect.width() + srcSubRect.x();
2044- rightCoordinate = rightCoordinate * srcSubRect.width() + srcSubRect.x();
2045- radiusCoordinateHeight = radiusCoordinateHeight * srcSubRect.height();
2046- radiusCoordinateWidth = radiusCoordinateWidth * srcSubRect.width();
2047- }
2048+ materialData->sourceTextureProvider = NULL;
2049+ materialData->sourceOpacity = 0;
2050+ }
2051+ materialData->shapeTextureFiltering = shapeTextureFiltering;
2052+ materialData->flags = flags;
2053+}
2054+
2055+void UCUbuntuShape::updateGeometry(
2056+ QSGNode* node, float width, float height, float radius, const float shapeCoordinate[][2],
2057+ const QVector4D& sourceCoordTransform, const QVector4D& sourceMaskTransform,
2058+ const quint32 backgroundColor[4])
2059+{
2060+ ShapeNode* shapeNode = static_cast<ShapeNode*>(node);
2061+ ShapeNode::Vertex* v = reinterpret_cast<ShapeNode::Vertex*>(
2062+ shapeNode->geometry()->vertexData());
2063+
2064+ // Convert radius to normalized coordinates.
2065+ const float rw = radius / width;
2066+ const float rh = radius / height;
2067
2068 // Set top row of 4 vertices.
2069- vertices[0].position[0] = 0.0f;
2070- vertices[0].position[1] = 0.0f;
2071- vertices[0].shapeCoordinate[0] = shapeCoordinate[0][0];
2072- vertices[0].shapeCoordinate[1] = shapeCoordinate[0][1];
2073- vertices[0].imageCoordinate[0] = leftCoordinate;
2074- vertices[0].imageCoordinate[1] = topCoordinate;
2075- vertices[1].position[0] = radius;
2076- vertices[1].position[1] = 0.0f;
2077- vertices[1].shapeCoordinate[0] = shapeCoordinate[1][0];
2078- vertices[1].shapeCoordinate[1] = shapeCoordinate[1][1];
2079- vertices[1].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;
2080- vertices[1].imageCoordinate[1] = topCoordinate;
2081- vertices[2].position[0] = width - radius;
2082- vertices[2].position[1] = 0.0f;
2083- vertices[2].shapeCoordinate[0] = shapeCoordinate[2][0];
2084- vertices[2].shapeCoordinate[1] = shapeCoordinate[2][1];
2085- vertices[2].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;
2086- vertices[2].imageCoordinate[1] = topCoordinate;
2087- vertices[3].position[0] = width;
2088- vertices[3].position[1] = 0.0f;
2089- vertices[3].shapeCoordinate[0] = shapeCoordinate[3][0];
2090- vertices[3].shapeCoordinate[1] = shapeCoordinate[3][1];
2091- vertices[3].imageCoordinate[0] = rightCoordinate;
2092- vertices[3].imageCoordinate[1] = topCoordinate;
2093+ v[0].position[0] = 0.0f;
2094+ v[0].position[1] = 0.0f;
2095+ v[0].shapeCoordinate[0] = shapeCoordinate[0][0];
2096+ v[0].shapeCoordinate[1] = shapeCoordinate[0][1];
2097+ v[0].sourceCoordinate[0] = sourceCoordTransform.z();
2098+ v[0].sourceCoordinate[1] = sourceCoordTransform.w();
2099+ v[0].sourceCoordinate[2] = sourceMaskTransform.z();
2100+ v[0].sourceCoordinate[3] = sourceMaskTransform.w();
2101+ v[0].backgroundColor = backgroundColor[0];
2102+ v[1].position[0] = radius;
2103+ v[1].position[1] = 0.0f;
2104+ v[1].shapeCoordinate[0] = shapeCoordinate[1][0];
2105+ v[1].shapeCoordinate[1] = shapeCoordinate[1][1];
2106+ v[1].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
2107+ v[1].sourceCoordinate[1] = sourceCoordTransform.w();
2108+ v[1].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
2109+ v[1].sourceCoordinate[3] = sourceMaskTransform.w();
2110+ v[1].backgroundColor = backgroundColor[0];
2111+ v[2].position[0] = width - radius;
2112+ v[2].position[1] = 0.0f;
2113+ v[2].shapeCoordinate[0] = shapeCoordinate[2][0];
2114+ v[2].shapeCoordinate[1] = shapeCoordinate[2][1];
2115+ v[2].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
2116+ v[2].sourceCoordinate[1] = sourceCoordTransform.w();
2117+ v[2].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
2118+ v[2].sourceCoordinate[3] = sourceMaskTransform.w();
2119+ v[2].backgroundColor = backgroundColor[0];
2120+ v[3].position[0] = width;
2121+ v[3].position[1] = 0.0f;
2122+ v[3].shapeCoordinate[0] = shapeCoordinate[3][0];
2123+ v[3].shapeCoordinate[1] = shapeCoordinate[3][1];
2124+ v[3].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
2125+ v[3].sourceCoordinate[1] = sourceCoordTransform.w();
2126+ v[3].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
2127+ v[3].sourceCoordinate[3] = sourceMaskTransform.w();
2128+ v[3].backgroundColor = backgroundColor[0];
2129
2130 // Set middle-top row of 4 vertices.
2131- vertices[4].position[0] = 0.0f;
2132- vertices[4].position[1] = radius;
2133- vertices[4].shapeCoordinate[0] = shapeCoordinate[4][0];
2134- vertices[4].shapeCoordinate[1] = shapeCoordinate[4][1];
2135- vertices[4].imageCoordinate[0] = leftCoordinate;
2136- vertices[4].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;
2137- vertices[5].position[0] = radius;
2138- vertices[5].position[1] = radius;
2139- vertices[5].shapeCoordinate[0] = shapeCoordinate[5][0];
2140- vertices[5].shapeCoordinate[1] = shapeCoordinate[5][1];
2141- vertices[5].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;
2142- vertices[5].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;
2143- vertices[6].position[0] = width - radius;
2144- vertices[6].position[1] = radius;
2145- vertices[6].shapeCoordinate[0] = shapeCoordinate[6][0];
2146- vertices[6].shapeCoordinate[1] = shapeCoordinate[6][1];
2147- vertices[6].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;
2148- vertices[6].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;
2149- vertices[7].position[0] = width;
2150- vertices[7].position[1] = radius;
2151- vertices[7].shapeCoordinate[0] = shapeCoordinate[7][0];
2152- vertices[7].shapeCoordinate[1] = shapeCoordinate[7][1];
2153- vertices[7].imageCoordinate[0] = rightCoordinate;
2154- vertices[7].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;
2155+ v[4].position[0] = 0.0f;
2156+ v[4].position[1] = radius;
2157+ v[4].shapeCoordinate[0] = shapeCoordinate[4][0];
2158+ v[4].shapeCoordinate[1] = shapeCoordinate[4][1];
2159+ v[4].sourceCoordinate[0] = sourceCoordTransform.z();
2160+ v[4].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
2161+ v[4].sourceCoordinate[2] = sourceMaskTransform.z();
2162+ v[4].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
2163+ v[4].backgroundColor = backgroundColor[1];
2164+ v[5].position[0] = radius;
2165+ v[5].position[1] = radius;
2166+ v[5].shapeCoordinate[0] = shapeCoordinate[5][0];
2167+ v[5].shapeCoordinate[1] = shapeCoordinate[5][1];
2168+ v[5].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
2169+ v[5].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
2170+ v[5].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
2171+ v[5].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
2172+ v[5].backgroundColor = backgroundColor[1];
2173+ v[6].position[0] = width - radius;
2174+ v[6].position[1] = radius;
2175+ v[6].shapeCoordinate[0] = shapeCoordinate[6][0];
2176+ v[6].shapeCoordinate[1] = shapeCoordinate[6][1];
2177+ v[6].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
2178+ v[6].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
2179+ v[6].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
2180+ v[6].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
2181+ v[6].backgroundColor = backgroundColor[1];
2182+ v[7].position[0] = width;
2183+ v[7].position[1] = radius;
2184+ v[7].shapeCoordinate[0] = shapeCoordinate[7][0];
2185+ v[7].shapeCoordinate[1] = shapeCoordinate[7][1];
2186+ v[7].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
2187+ v[7].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
2188+ v[7].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
2189+ v[7].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
2190+ v[7].backgroundColor = backgroundColor[1];
2191
2192 // Set middle-bottom row of 4 vertices.
2193- vertices[8].position[0] = 0.0f;
2194- vertices[8].position[1] = height - radius;
2195- vertices[8].shapeCoordinate[0] = shapeCoordinate[8][0];
2196- vertices[8].shapeCoordinate[1] = shapeCoordinate[8][1];
2197- vertices[8].imageCoordinate[0] = leftCoordinate;
2198- vertices[8].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;
2199- vertices[9].position[0] = radius;
2200- vertices[9].position[1] = height - radius;
2201- vertices[9].shapeCoordinate[0] = shapeCoordinate[9][0];
2202- vertices[9].shapeCoordinate[1] = shapeCoordinate[9][1];
2203- vertices[9].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;
2204- vertices[9].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;
2205- vertices[10].position[0] = width - radius;
2206- vertices[10].position[1] = height - radius;
2207- vertices[10].shapeCoordinate[0] = shapeCoordinate[10][0];
2208- vertices[10].shapeCoordinate[1] = shapeCoordinate[10][1];
2209- vertices[10].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;
2210- vertices[10].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;
2211- vertices[11].position[0] = width;
2212- vertices[11].position[1] = height - radius;
2213- vertices[11].shapeCoordinate[0] = shapeCoordinate[11][0];
2214- vertices[11].shapeCoordinate[1] = shapeCoordinate[11][1];
2215- vertices[11].imageCoordinate[0] = rightCoordinate;
2216- vertices[11].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;
2217+ v[8].position[0] = 0.0f;
2218+ v[8].position[1] = height - radius;
2219+ v[8].shapeCoordinate[0] = shapeCoordinate[8][0];
2220+ v[8].shapeCoordinate[1] = shapeCoordinate[8][1];
2221+ v[8].sourceCoordinate[0] = sourceCoordTransform.z();
2222+ v[8].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
2223+ v[8].sourceCoordinate[2] = sourceMaskTransform.z();
2224+ v[8].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
2225+ v[8].backgroundColor = backgroundColor[2];
2226+ v[9].position[0] = radius;
2227+ v[9].position[1] = height - radius;
2228+ v[9].shapeCoordinate[0] = shapeCoordinate[9][0];
2229+ v[9].shapeCoordinate[1] = shapeCoordinate[9][1];
2230+ v[9].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
2231+ v[9].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
2232+ v[9].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
2233+ v[9].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
2234+ v[9].backgroundColor = backgroundColor[2];
2235+ v[10].position[0] = width - radius;
2236+ v[10].position[1] = height - radius;
2237+ v[10].shapeCoordinate[0] = shapeCoordinate[10][0];
2238+ v[10].shapeCoordinate[1] = shapeCoordinate[10][1];
2239+ v[10].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
2240+ v[10].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
2241+ v[10].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
2242+ v[10].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
2243+ v[10].backgroundColor = backgroundColor[2];
2244+ v[11].position[0] = width;
2245+ v[11].position[1] = height - radius;
2246+ v[11].shapeCoordinate[0] = shapeCoordinate[11][0];
2247+ v[11].shapeCoordinate[1] = shapeCoordinate[11][1];
2248+ v[11].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
2249+ v[11].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
2250+ v[11].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
2251+ v[11].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
2252+ v[11].backgroundColor = backgroundColor[2];
2253
2254 // Set bottom row of 4 vertices.
2255- vertices[12].position[0] = 0.0f;
2256- vertices[12].position[1] = height;
2257- vertices[12].shapeCoordinate[0] = shapeCoordinate[12][0];
2258- vertices[12].shapeCoordinate[1] = shapeCoordinate[12][1];
2259- vertices[12].imageCoordinate[0] = leftCoordinate;
2260- vertices[12].imageCoordinate[1] = bottomCoordinate;
2261- vertices[13].position[0] = radius;
2262- vertices[13].position[1] = height;
2263- vertices[13].shapeCoordinate[0] = shapeCoordinate[13][0];
2264- vertices[13].shapeCoordinate[1] = shapeCoordinate[13][1];
2265- vertices[13].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;
2266- vertices[13].imageCoordinate[1] = bottomCoordinate;
2267- vertices[14].position[0] = width - radius;
2268- vertices[14].position[1] = height;
2269- vertices[14].shapeCoordinate[0] = shapeCoordinate[14][0];
2270- vertices[14].shapeCoordinate[1] = shapeCoordinate[14][1];
2271- vertices[14].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;
2272- vertices[14].imageCoordinate[1] = bottomCoordinate;
2273- vertices[15].position[0] = width;
2274- vertices[15].position[1] = height;
2275- vertices[15].shapeCoordinate[0] = shapeCoordinate[15][0];
2276- vertices[15].shapeCoordinate[1] = shapeCoordinate[15][1];
2277- vertices[15].imageCoordinate[0] = rightCoordinate;
2278- vertices[15].imageCoordinate[1] = bottomCoordinate;
2279-
2280- markDirty(DirtyGeometry);
2281-}
2282-
2283-void ShapeNode::setMaterialType(ShapeNode::MaterialType material)
2284-{
2285- if (currentMaterial_ != material) {
2286- if (material == ShapeNode::ColoredMaterial)
2287- setMaterial(&coloredMaterial_);
2288- else
2289- setMaterial(&texturedMaterial_);
2290- currentMaterial_ = material;
2291- markDirty(DirtyMaterial);
2292- }
2293-}
2294-
2295-// --- Scene graph textured material ---
2296-
2297-ShapeTexturedMaterial::ShapeTexturedMaterial()
2298- : imageTextureProvider_(NULL)
2299- , shapeTexture_(NULL)
2300- , filtering_(QSGTexture::Nearest)
2301-{
2302- setFlag(Blending);
2303-}
2304-
2305-QSGMaterialType* ShapeTexturedMaterial::type() const
2306-{
2307- static QSGMaterialType type;
2308- return &type;
2309-}
2310-
2311-QSGMaterialShader* ShapeTexturedMaterial::createShader() const
2312-{
2313- return new ShapeTexturedShader;
2314-}
2315-
2316-int ShapeTexturedMaterial::compare(const QSGMaterial* other) const
2317-{
2318- const ShapeTexturedMaterial* otherMaterial = static_cast<const ShapeTexturedMaterial*>(other);
2319- const QSGTextureProvider* otherTextureProvider = otherMaterial->imageTextureProvider();
2320- const QSGTexture* otherTexture = otherTextureProvider ? otherTextureProvider->texture() : NULL;
2321- const int otherTextureId = otherTexture ? otherTexture->textureId() : 0;
2322- const QSGTexture* texture = imageTextureProvider_ ? imageTextureProvider_->texture() : NULL;
2323- const int textureId = texture ? texture->textureId() : 0;
2324- return textureId - otherTextureId;
2325-}
2326-
2327-void ShapeTexturedMaterial::setImage(QQuickItem* image)
2328-{
2329- imageTextureProvider_ = image ? image->textureProvider() : NULL;
2330-}
2331-
2332-QSGTextureProvider* ShapeTexturedMaterial::imageTextureProvider() const
2333-{
2334- return imageTextureProvider_;
2335-}
2336-
2337-void ShapeTexturedMaterial::setShapeTexture(QSGTexture* texture, bool scaledDown)
2338-{
2339- shapeTexture_ = texture;
2340- filtering_ = scaledDown ? QSGTexture::Linear : QSGTexture::Nearest;
2341-}
2342-
2343-// -- Scene graph textured material shader ---
2344-
2345-const char *ShapeTexturedShader::vertexShader() const
2346-{
2347- return shapeVertexShader;
2348-}
2349-
2350-const char* ShapeTexturedShader::fragmentShader() const
2351-{
2352- return shapeTexturedFragmentShader;
2353-}
2354-
2355-char const* const* ShapeTexturedShader::attributeNames() const
2356-{
2357- static char const* const attributes[] = {
2358- "positionAttrib", "shapeCoordAttrib", "imageCoordAttrib", 0
2359- };
2360- return attributes;
2361-}
2362-
2363-void ShapeTexturedShader::initialize()
2364-{
2365- QSGMaterialShader::initialize();
2366- program()->bind();
2367- program()->setUniformValue("shapeTexture", 0);
2368- program()->setUniformValue("imageTexture", 1);
2369- matrixId_ = program()->uniformLocation("matrix");
2370- opacityId_ = program()->uniformLocation("opacity");
2371- glFuncs_ = QOpenGLContext::currentContext()->functions();
2372-}
2373-
2374-void ShapeTexturedShader::updateState(const RenderState& state, QSGMaterial* newEffect,
2375- QSGMaterial* oldEffect)
2376-{
2377- Q_UNUSED(oldEffect);
2378- ShapeTexturedMaterial* material = static_cast<ShapeTexturedMaterial*>(newEffect);
2379-
2380- // Bind textures.
2381- glFuncs_->glActiveTexture(GL_TEXTURE1);
2382- QSGTextureProvider* provider = material->imageTextureProvider();
2383- QSGTexture* texture = provider ? provider->texture() : NULL;
2384- if (texture)
2385- texture->bind();
2386- else
2387- glBindTexture(GL_TEXTURE_2D, 0);
2388- glFuncs_->glActiveTexture(GL_TEXTURE0);
2389- QSGTexture* shapeTexture = material->shapeTexture();
2390- if (shapeTexture) {
2391- shapeTexture->setFiltering(material->filtering());
2392- shapeTexture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
2393- shapeTexture->setVerticalWrapMode(QSGTexture::ClampToEdge);
2394- shapeTexture->bind();
2395- } else {
2396- glBindTexture(GL_TEXTURE_2D, 0);
2397- }
2398-
2399- // Bind uniforms.
2400- if (state.isMatrixDirty())
2401- program()->setUniformValue(matrixId_, state.combinedMatrix());
2402- if (state.isOpacityDirty())
2403- program()->setUniformValue(opacityId_, state.opacity());
2404-}
2405-
2406-// --- Scene graph colored material ---
2407-
2408-ShapeColoredMaterial::ShapeColoredMaterial()
2409- : color_(0.0, 0.0, 0.0, 0.0)
2410- , gradientColor_(0.0, 0.0, 0.0, 0.0)
2411- , shapeTexture_(NULL)
2412- , filtering_(QSGTexture::Nearest)
2413-{
2414- setFlag(Blending);
2415-}
2416-
2417-QSGMaterialType* ShapeColoredMaterial::type() const
2418-{
2419- static QSGMaterialType type;
2420- return &type;
2421-}
2422-
2423-QSGMaterialShader* ShapeColoredMaterial::createShader() const
2424-{
2425- return new ShapeColoredShader;
2426-}
2427-
2428-int ShapeColoredMaterial::compare(const QSGMaterial* other) const
2429-{
2430- const ShapeColoredMaterial* otherMaterial = static_cast<const ShapeColoredMaterial*>(other);
2431- if ((color_ != otherMaterial->color()) || (gradientColor_ != otherMaterial->gradientColor())) {
2432- return -1;
2433- } else {
2434- return 0;
2435- }
2436-}
2437-
2438-void ShapeColoredMaterial::setColor(const QColor& color)
2439-{
2440- // Premultiply color components by alpha.
2441- const float alpha = color.alphaF();
2442- color_ = QVector4D(color.redF() * alpha, color.greenF() * alpha,
2443- color.blueF() * alpha, alpha);
2444-}
2445-
2446-void ShapeColoredMaterial::setGradientColor(const QColor& gradientColor)
2447-{
2448- // Premultiply color components by alpha.
2449- const float alpha = gradientColor.alphaF();
2450- gradientColor_ = QVector4D(gradientColor.redF() * alpha, gradientColor.greenF() * alpha,
2451- gradientColor.blueF() * alpha, alpha);
2452-}
2453-
2454-void ShapeColoredMaterial::setShapeTexture(QSGTexture* texture, bool scaledDown)
2455-{
2456- shapeTexture_ = texture;
2457- filtering_ = scaledDown ? QSGTexture::Linear : QSGTexture::Nearest;
2458-}
2459-
2460-// -- Scene graph colored material shader ---
2461-
2462-const char *ShapeColoredShader::vertexShader() const
2463-{
2464- return shapeVertexShader;
2465-}
2466-
2467-const char* ShapeColoredShader::fragmentShader() const
2468-{
2469- return shapeColoredFragmentShader;
2470-}
2471-
2472-char const* const* ShapeColoredShader::attributeNames() const
2473-{
2474- static char const* const attributes[] = {
2475- "positionAttrib", "shapeCoordAttrib", "imageCoordAttrib", 0
2476- };
2477- return attributes;
2478-}
2479-
2480-void ShapeColoredShader::initialize()
2481-{
2482- QSGMaterialShader::initialize();
2483- program()->bind();
2484- program()->setUniformValue("shapeTexture", 0);
2485- matrixId_ = program()->uniformLocation("matrix");
2486- opacityId_ = program()->uniformLocation("opacity");
2487- colorId_ = program()->uniformLocation("color");
2488- gradientColorId_ = program()->uniformLocation("gradientColor");
2489-}
2490-
2491-void ShapeColoredShader::updateState(const RenderState& state, QSGMaterial* newEffect,
2492- QSGMaterial* oldEffect)
2493-{
2494- Q_UNUSED(oldEffect);
2495- ShapeColoredMaterial* material = static_cast<ShapeColoredMaterial*>(newEffect);
2496-
2497- // Bind texture.
2498- QSGTexture* shapeTexture = material->shapeTexture();
2499- if (shapeTexture) {
2500- shapeTexture->setFiltering(material->filtering());
2501- shapeTexture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
2502- shapeTexture->setVerticalWrapMode(QSGTexture::ClampToEdge);
2503- shapeTexture->bind();
2504- } else {
2505- glBindTexture(GL_TEXTURE_2D, 0);
2506- }
2507-
2508- // Bind uniforms.
2509- if (state.isMatrixDirty())
2510- program()->setUniformValue(matrixId_, state.combinedMatrix());
2511- if (state.isOpacityDirty())
2512- program()->setUniformValue(opacityId_, state.opacity());
2513- program()->setUniformValue(colorId_, material->color());
2514- program()->setUniformValue(gradientColorId_, material->gradientColor());
2515+ v[12].position[0] = 0.0f;
2516+ v[12].position[1] = height;
2517+ v[12].shapeCoordinate[0] = shapeCoordinate[12][0];
2518+ v[12].shapeCoordinate[1] = shapeCoordinate[12][1];
2519+ v[12].sourceCoordinate[0] = sourceCoordTransform.z();
2520+ v[12].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
2521+ v[12].sourceCoordinate[2] = sourceMaskTransform.z();
2522+ v[12].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
2523+ v[12].backgroundColor = backgroundColor[3];
2524+ v[13].position[0] = radius;
2525+ v[13].position[1] = height;
2526+ v[13].shapeCoordinate[0] = shapeCoordinate[13][0];
2527+ v[13].shapeCoordinate[1] = shapeCoordinate[13][1];
2528+ v[13].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
2529+ v[13].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
2530+ v[13].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
2531+ v[13].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
2532+ v[13].backgroundColor = backgroundColor[3];
2533+ v[14].position[0] = width - radius;
2534+ v[14].position[1] = height;
2535+ v[14].shapeCoordinate[0] = shapeCoordinate[14][0];
2536+ v[14].shapeCoordinate[1] = shapeCoordinate[14][1];
2537+ v[14].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
2538+ v[14].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
2539+ v[14].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
2540+ v[14].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
2541+ v[14].backgroundColor = backgroundColor[3];
2542+ v[15].position[0] = width;
2543+ v[15].position[1] = height;
2544+ v[15].shapeCoordinate[0] = shapeCoordinate[15][0];
2545+ v[15].shapeCoordinate[1] = shapeCoordinate[15][1];
2546+ v[15].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
2547+ v[15].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
2548+ v[15].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
2549+ v[15].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
2550+ v[15].backgroundColor = backgroundColor[3];
2551+
2552+ node->markDirty(QSGNode::DirtyGeometry);
2553 }
2554
2555=== renamed file 'modules/Ubuntu/Components/plugin/shapeitem.h' => 'modules/Ubuntu/Components/plugin/ucubuntushape.h'
2556--- modules/Ubuntu/Components/plugin/shapeitem.h 2014-09-10 18:04:50 +0000
2557+++ modules/Ubuntu/Components/plugin/ucubuntushape.h 2015-03-02 15:41:23 +0000
2558@@ -1,5 +1,5 @@
2559 /*
2560- * Copyright 2013 Canonical Ltd.
2561+ * Copyright 2013-2015 Canonical Ltd.
2562 *
2563 * This program is free software; you can redistribute it and/or modify
2564 * it under the terms of the GNU Lesser General Public License as published by
2565@@ -16,227 +16,314 @@
2566 * Author: Loïc Molinari <loic.molinari@canonical.com>
2567 */
2568
2569-#ifndef UBUNTU_COMPONENTS_SHAPE_H
2570-#define UBUNTU_COMPONENTS_SHAPE_H
2571+#ifndef UCUBUNTUSHAPE_H
2572+#define UCUBUNTUSHAPE_H
2573
2574 #include <QtQuick/QQuickItem>
2575 #include <QtQuick/QSGNode>
2576-#include <QtQuick/qsgflatcolormaterial.h>
2577 #include <QtQuick/qsgtexture.h>
2578+#include <QtQuick/qsgmaterial.h>
2579 #include <QtGui/QOpenGLFunctions>
2580
2581-// QtQuick item.
2582-
2583-class ShapeItem : public QQuickItem
2584+class UCUbuntuShape;
2585+
2586+// --- Scene graph shader ---
2587+
2588+class ShapeShader : public QSGMaterialShader
2589+{
2590+public:
2591+ ShapeShader();
2592+ virtual char const* const* attributeNames() const;
2593+ virtual void initialize();
2594+ virtual void updateState(
2595+ const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect);
2596+
2597+private:
2598+ QOpenGLFunctions* m_functions;
2599+ int m_matrixId;
2600+ int m_opacityId;
2601+ int m_sourceOpacityId;
2602+ int m_texturedId;
2603+};
2604+
2605+// --- Scene graph material ---
2606+
2607+class ShapeMaterial : public QSGMaterial
2608+{
2609+public:
2610+ struct Data {
2611+ enum {
2612+ Textured = (1 << 0),
2613+ HorizontallyRepeated = (1 << 1),
2614+ VerticallyRepeated = (1 << 2),
2615+ Repeated = (HorizontallyRepeated | VerticallyRepeated)
2616+ };
2617+ QSGTexture* shapeTexture;
2618+ QSGTextureProvider* sourceTextureProvider;
2619+ quint8 sourceOpacity;
2620+ quint8 shapeTextureFiltering;
2621+ quint8 flags;
2622+ };
2623+
2624+ ShapeMaterial();
2625+ virtual QSGMaterialType* type() const;
2626+ virtual QSGMaterialShader* createShader() const;
2627+ virtual int compare(const QSGMaterial* other) const;
2628+ const Data* constData() const { return &m_data; }
2629+ Data* data() { return &m_data; }
2630+
2631+private:
2632+ Data m_data;
2633+};
2634+
2635+// --- Scene graph node ---
2636+
2637+class ShapeNode : public QSGGeometryNode
2638+{
2639+public:
2640+ struct Vertex {
2641+ float position[2];
2642+ float shapeCoordinate[2];
2643+ float sourceCoordinate[4];
2644+ quint32 backgroundColor;
2645+ };
2646+
2647+ static const int indexCount = 28;
2648+ static const int indexType = GL_UNSIGNED_SHORT;
2649+ static const int indexTypeSize = sizeof(unsigned short);
2650+ static const int vertexCount = 16;
2651+ static const QSGGeometry::DataPattern indexDataPattern = QSGGeometry::StaticPattern;
2652+ static const QSGGeometry::DataPattern vertexDataPattern = QSGGeometry::AlwaysUploadPattern;
2653+ static const GLenum drawingMode = GL_TRIANGLE_STRIP;
2654+ static const unsigned short* indices();
2655+ static const QSGGeometry::AttributeSet& attributeSet();
2656+
2657+ ShapeNode();
2658+ ShapeMaterial* material() { return &m_material; }
2659+ QSGGeometry* geometry() { return &m_geometry; }
2660+
2661+private:
2662+ ShapeMaterial m_material;
2663+ QSGGeometry m_geometry;
2664+};
2665+
2666+// --- QtQuick item ---
2667+
2668+class UCUbuntuShape : public QQuickItem
2669 {
2670 Q_OBJECT
2671+
2672+ // Shape properties.
2673+ Q_PROPERTY(QString radius READ radius WRITE setRadius NOTIFY radiusChanged)
2674+ Q_PROPERTY(QString borderSource READ borderSource WRITE setBorderSource
2675+ NOTIFY borderSourceChanged)
2676+
2677+ // Source properties.
2678+ Q_ENUMS(FillMode)
2679+ Q_ENUMS(WrapMode)
2680 Q_ENUMS(HAlignment)
2681 Q_ENUMS(VAlignment)
2682+ Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged REVISION 1)
2683+ Q_PROPERTY(float sourceOpacity READ sourceOpacity WRITE setSourceOpacity
2684+ NOTIFY sourceOpacityChanged REVISION 1)
2685+ Q_PROPERTY(FillMode sourceFillMode READ sourceFillMode WRITE setSourceFillMode
2686+ NOTIFY sourceFillModeChanged REVISION 1)
2687+ Q_PROPERTY(WrapMode sourceHorizontalWrapMode READ sourceHorizontalWrapMode
2688+ WRITE setSourceHorizontalWrapMode NOTIFY sourceHorizontalWrapModeChanged REVISION 1)
2689+ Q_PROPERTY(WrapMode sourceVerticalWrapMode READ sourceVerticalWrapMode
2690+ WRITE setSourceVerticalWrapMode NOTIFY sourceVerticalWrapModeChanged REVISION 1)
2691+ Q_PROPERTY(HAlignment sourceHorizontalAlignment READ sourceHorizontalAlignment
2692+ WRITE setSourceHorizontalAlignment NOTIFY sourceHorizontalAlignmentChanged
2693+ REVISION 1)
2694+ Q_PROPERTY(VAlignment sourceVerticalAlignment READ sourceVerticalAlignment
2695+ WRITE setSourceVerticalAlignment NOTIFY sourceVerticalAlignmentChanged REVISION 1)
2696+ Q_PROPERTY(QVector2D sourceTranslation READ sourceTranslation WRITE setSourceTranslation
2697+ NOTIFY sourceTranslationChanged REVISION 1)
2698+ Q_PROPERTY(QVector2D sourceScale READ sourceScale WRITE setSourceScale
2699+ NOTIFY sourceScaleChanged REVISION 1)
2700+
2701+ // Background properties.
2702+ Q_ENUMS(BackgroundMode)
2703+ Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor
2704+ NOTIFY backgroundColorChanged REVISION 1)
2705+ Q_PROPERTY(QColor secondaryBackgroundColor READ secondaryBackgroundColor
2706+ WRITE setSecondaryBackgroundColor NOTIFY secondaryBackgroundColorChanged REVISION 1)
2707+ Q_PROPERTY(BackgroundMode backgroundMode READ backgroundMode WRITE setBackgroundMode
2708+ NOTIFY backgroundModeChanged REVISION 1)
2709+
2710+ // Deprecated properties.
2711 Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
2712 Q_PROPERTY(QColor gradientColor READ gradientColor WRITE setGradientColor
2713 NOTIFY gradientColorChanged)
2714- Q_PROPERTY(QString radius READ radius WRITE setRadius NOTIFY radiusChanged)
2715 Q_PROPERTY(QVariant image READ image WRITE setImage NOTIFY imageChanged)
2716 Q_PROPERTY(bool stretched READ stretched WRITE setStretched NOTIFY stretchedChanged)
2717- Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)
2718- Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)
2719- Q_PROPERTY(QString borderSource READ borderSource WRITE setBorderSource NOTIFY borderSourceChanged)
2720+ Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment
2721+ NOTIFY horizontalAlignmentChanged)
2722+ Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment
2723+ NOTIFY verticalAlignmentChanged)
2724
2725 public:
2726- ShapeItem(QQuickItem* parent=0);
2727+ UCUbuntuShape(QQuickItem* parent=0);
2728
2729- enum Radius { SmallRadius, MediumRadius };
2730- enum Border { RawBorder, IdleBorder, PressedBorder };
2731+ enum BackgroundMode { SolidColor = 0, VerticalGradient = 1 };
2732 enum HAlignment { AlignLeft = 0, AlignHCenter = 1, AlignRight = 2 };
2733 enum VAlignment { AlignTop = 0, AlignVCenter = 1, AlignBottom = 2 };
2734+ enum FillMode { Stretch = 0, PreserveAspectFit = 1, PreserveAspectCrop = 2, Pad = 3 };
2735+ enum WrapMode { Transparent = 0, Repeat = 1 };
2736
2737- QColor color() const { return color_; }
2738- void setColor(const QColor& color);
2739- QColor gradientColor() const { return gradientColor_; }
2740- void setGradientColor(const QColor& gradientColor);
2741- QString radius() const { return radiusString_; }
2742+ QString radius() const { return (m_radius == SmallRadius) ? "small" : "medium"; }
2743 void setRadius(const QString& radius);
2744- QString borderSource() const { return borderSource_; }
2745+ QString borderSource() const {
2746+ return (m_border == IdleBorder) ? "radius_idle.sci" :
2747+ ((m_border == PressedBorder) ? "radius_pressed.sci" : ""); }
2748 void setBorderSource(const QString& borderSource);
2749- QVariant image() const { return QVariant::fromValue(image_); }
2750+
2751+ QVariant source() const {
2752+ return QVariant::fromValue((m_flags & SourceApiSet) ? m_source : NULL); }
2753+ void setSource(const QVariant& source);
2754+ float sourceOpacity() const { return m_sourceOpacity / static_cast<float>(0xff); }
2755+ void setSourceOpacity(float sourceOpacity);
2756+ FillMode sourceFillMode() const { return m_sourceFillMode; }
2757+ void setSourceFillMode(FillMode sourceFillMode);
2758+ WrapMode sourceHorizontalWrapMode() const { return m_sourceHorizontalWrapMode; }
2759+ void setSourceHorizontalWrapMode(WrapMode sourceHorizontalWrapMode);
2760+ WrapMode sourceVerticalWrapMode() const { return m_sourceVerticalWrapMode; }
2761+ void setSourceVerticalWrapMode(WrapMode sourceVerticalWrapMode);
2762+ HAlignment sourceHorizontalAlignment() const { return m_sourceHorizontalAlignment; }
2763+ void setSourceHorizontalAlignment(HAlignment sourceHorizontalAlignment);
2764+ VAlignment sourceVerticalAlignment() const { return m_sourceVerticalAlignment; }
2765+ void setSourceVerticalAlignment(VAlignment sourceVerticalAlignment);
2766+ QVector2D sourceTranslation() const { return m_sourceTranslation; }
2767+ void setSourceTranslation(const QVector2D& sourceTranslation);
2768+ QVector2D sourceScale() const { return m_sourceScale; }
2769+ void setSourceScale(const QVector2D& sourceScale);
2770+ QColor backgroundColor() const {
2771+ return (m_flags & BackgroundApiSet) ?
2772+ QColor(qRed(m_backgroundColor), qGreen(m_backgroundColor), qBlue(m_backgroundColor),
2773+ qAlpha(m_backgroundColor)) :
2774+ QColor(0, 0, 0, 0); }
2775+ void setBackgroundColor(const QColor& backgroundColor);
2776+ QColor secondaryBackgroundColor() const {
2777+ return (m_flags & BackgroundApiSet) ?
2778+ QColor(qRed(m_secondaryBackgroundColor), qGreen(m_secondaryBackgroundColor),
2779+ qBlue(m_secondaryBackgroundColor), qAlpha(m_secondaryBackgroundColor)) :
2780+ QColor(0, 0, 0, 0); }
2781+ void setSecondaryBackgroundColor(const QColor& secondaryBackgroundColor);
2782+ BackgroundMode backgroundMode() const { return m_backgroundMode; }
2783+ void setBackgroundMode(BackgroundMode backgroundMode);
2784+
2785+ QColor color() const {
2786+ return (m_flags & BackgroundApiSet) ?
2787+ QColor(0, 0, 0, 0) :
2788+ QColor(qRed(m_backgroundColor), qGreen(m_backgroundColor), qBlue(m_backgroundColor),
2789+ qAlpha(m_backgroundColor)); }
2790+ void setColor(const QColor& color);
2791+ QColor gradientColor() const {
2792+ return (m_flags & BackgroundApiSet) ?
2793+ QColor(0, 0, 0, 0) :
2794+ QColor(qRed(m_secondaryBackgroundColor), qGreen(m_secondaryBackgroundColor),
2795+ qBlue(m_secondaryBackgroundColor), qAlpha(m_secondaryBackgroundColor)); }
2796+ void setGradientColor(const QColor& gradientColor);
2797+ QVariant image() const {
2798+ return QVariant::fromValue((m_flags & SourceApiSet) ? NULL : m_source); }
2799 void setImage(const QVariant& image);
2800- bool stretched() const { return stretched_; }
2801+ bool stretched() const { return !!(m_flags & Stretched); }
2802 void setStretched(bool stretched);
2803- HAlignment horizontalAlignment() const { return hAlignment_; }
2804+ HAlignment horizontalAlignment() const { return m_imageHorizontalAlignment; }
2805 void setHorizontalAlignment(HAlignment horizontalAlignment);
2806- VAlignment verticalAlignment() const { return vAlignment_; }
2807+ VAlignment verticalAlignment() const { return m_imageVerticalAlignment; }
2808 void setVerticalAlignment(VAlignment verticalAlignment);
2809- Q_SLOT void gridUnitChanged();
2810
2811 Q_SIGNALS:
2812+ void radiusChanged();
2813+ void borderSourceChanged();
2814+
2815+ Q_REVISION(1) void sourceChanged();
2816+ Q_REVISION(1) void sourceOpacityChanged();
2817+ Q_REVISION(1) void sourceFillModeChanged();
2818+ Q_REVISION(1) void sourceHorizontalWrapModeChanged();
2819+ Q_REVISION(1) void sourceVerticalWrapModeChanged();
2820+ Q_REVISION(1) void sourceHorizontalAlignmentChanged();
2821+ Q_REVISION(1) void sourceVerticalAlignmentChanged();
2822+ Q_REVISION(1) void sourceTranslationChanged();
2823+ Q_REVISION(1) void sourceScaleChanged();
2824+
2825+ Q_REVISION(1) void backgroundColorChanged();
2826+ Q_REVISION(1) void secondaryBackgroundColorChanged();
2827+ Q_REVISION(1) void backgroundModeChanged();
2828+
2829 void colorChanged();
2830 void gradientColorChanged();
2831- void radiusChanged();
2832- void borderChanged();
2833 void imageChanged();
2834 void stretchedChanged();
2835 void horizontalAlignmentChanged();
2836 void verticalAlignmentChanged();
2837- void borderSourceChanged();
2838
2839 protected:
2840+ virtual QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data);
2841 virtual void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry);
2842- virtual QSGNode* updatePaintNode(QSGNode*, UpdatePaintNodeData*);
2843+
2844+ // Virtual functions for extended shapes.
2845+ virtual QSGNode* createSceneGraphNode() const;
2846+ virtual void updateMaterial(
2847+ QSGNode* node, QSGTexture* shapeTexture, QSGTexture::Filtering shapeTextureFiltering,
2848+ QSGTexture* sourceTexture);
2849+ virtual void updateGeometry(
2850+ QSGNode* node, float width, float height, float radius, const float shapeCoordinate[][2],
2851+ const QVector4D& sourceCoordTransform, const QVector4D& sourceMaskTransform,
2852+ const quint32 backgroundColor[4]);
2853+
2854+private Q_SLOTS:
2855+ void _q_imagePropertiesChanged();
2856+ void _q_openglContextDestroyed();
2857+ void _q_gridUnitChanged();
2858+ void _q_providerDestroyed(QObject* object=0);
2859+ void _q_textureChanged();
2860
2861 private:
2862 void updateFromImageProperties(QQuickItem* image);
2863- void connectToPropertyChange(QObject* sender, const char* property,
2864- QObject* receiver, const char* slot);
2865+ void connectToPropertyChange(
2866+ QObject* sender, const char* property, QObject* receiver, const char* slot);
2867 void connectToImageProperties(QQuickItem* image);
2868-
2869-private Q_SLOTS:
2870- void onImagePropertiesChanged();
2871- void onOpenglContextDestroyed();
2872- void providerDestroyed(QObject* object=0);
2873-
2874-private:
2875- struct TextureHandles {
2876- TextureHandles(): high(0), low(0) {}
2877- QSGTexture* high;
2878- QSGTexture* low;
2879- };
2880-
2881- QSGTextureProvider* provider_;
2882- QColor color_;
2883- QColor gradientColor_;
2884- bool gradientColorSet_;
2885- QString radiusString_;
2886- Radius radius_;
2887- QString borderSource_;
2888- Border border_;
2889- QQuickItem* image_;
2890- bool stretched_;
2891- HAlignment hAlignment_;
2892- VAlignment vAlignment_;
2893- float gridUnit_;
2894- QRectF geometry_;
2895- static QHash<QOpenGLContext*, TextureHandles> textures_;
2896-
2897- Q_DISABLE_COPY(ShapeItem)
2898-};
2899-
2900-// Scene graph textured material.
2901-
2902-class ShapeTexturedMaterial : public QSGMaterial
2903-{
2904-public:
2905- ShapeTexturedMaterial();
2906- virtual QSGMaterialType* type() const;
2907- virtual QSGMaterialShader* createShader() const;
2908- virtual int compare(const QSGMaterial* other) const;
2909- QSGTextureProvider* imageTextureProvider() const;
2910- void setImage(QQuickItem* image);
2911- QSGTexture* shapeTexture() const { return shapeTexture_; }
2912- QSGTexture::Filtering filtering() const { return filtering_; }
2913- void setShapeTexture(QSGTexture* shapeTexture, bool scaledDown);
2914-
2915-private:
2916- QSGTextureProvider* imageTextureProvider_;
2917- QSGTexture* shapeTexture_;
2918- QSGTexture::Filtering filtering_;
2919-};
2920-
2921-// Scene graph textured material shader.
2922-
2923-class ShapeTexturedShader : public QSGMaterialShader
2924-{
2925-public:
2926- virtual char const* const* attributeNames() const;
2927- virtual void initialize();
2928- virtual void updateState(
2929- const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect);
2930-
2931-private:
2932- virtual const char* vertexShader() const;
2933- virtual const char* fragmentShader() const;
2934-
2935- int matrixId_;
2936- int opacityId_;
2937- QOpenGLFunctions* glFuncs_;
2938-};
2939-
2940-// Scene graph colored material.
2941-
2942-class ShapeColoredMaterial : public QSGMaterial
2943-{
2944-public:
2945- ShapeColoredMaterial();
2946- virtual QSGMaterialType* type() const;
2947- virtual QSGMaterialShader* createShader() const;
2948- virtual int compare(const QSGMaterial* other) const;
2949- const QVector4D& color() const { return color_; }
2950- void setColor(const QColor& color);
2951- const QVector4D& gradientColor() const { return gradientColor_; }
2952- void setGradientColor(const QColor& gradientColor);
2953- QSGTexture* shapeTexture() const { return shapeTexture_; }
2954- QSGTexture::Filtering filtering() const { return filtering_; }
2955- void setShapeTexture(QSGTexture* shapeTexture, bool scaledDown);
2956-
2957-private:
2958- QVector4D color_;
2959- QVector4D gradientColor_;
2960- QSGTexture* shapeTexture_;
2961- QSGTexture::Filtering filtering_;
2962-};
2963-
2964-// Scene graph colored material shader.
2965-
2966-class ShapeColoredShader : public QSGMaterialShader
2967-{
2968-public:
2969- virtual char const* const* attributeNames() const;
2970- virtual void initialize();
2971- virtual void updateState(
2972- const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect);
2973-
2974-private:
2975- virtual const char* vertexShader() const;
2976- virtual const char* fragmentShader() const;
2977-
2978- int matrixId_;
2979- int opacityId_;
2980- int colorId_;
2981- int gradientColorId_;
2982-};
2983-
2984-// Scene graph node.
2985-
2986-struct TextureData;
2987-
2988-class ShapeNode : public QObject, public QSGGeometryNode
2989-{
2990- Q_OBJECT
2991-
2992-public:
2993- struct Vertex {
2994- float position[2];
2995- float shapeCoordinate[2];
2996- float imageCoordinate[2];
2997- float padding[2]; // Ensure a 32 bytes stride.
2998- };
2999- enum MaterialType { TexturedMaterial, ColoredMaterial };
3000-
3001- ShapeNode(ShapeItem* item);
3002- ShapeTexturedMaterial* texturedMaterial() { return &texturedMaterial_; }
3003- ShapeColoredMaterial* coloredMaterial() { return &coloredMaterial_; }
3004- void setVertices(const QRectF& geometry, float radius, QQuickItem* image, bool stretched,
3005- ShapeItem::HAlignment hAlignment, ShapeItem::VAlignment vAlignment,
3006- float shapeCoordinate[][2]);
3007- void setMaterialType(MaterialType material);
3008-
3009-private:
3010- ShapeItem* item_;
3011- QSGGeometry geometry_;
3012- ShapeTexturedMaterial texturedMaterial_;
3013- ShapeColoredMaterial coloredMaterial_;
3014- MaterialType currentMaterial_;
3015-};
3016-
3017-QML_DECLARE_TYPE(ShapeItem)
3018-
3019-#endif // UBUNTU_COMPONENTS_SHAPE_H
3020+ void dropColorSupport();
3021+ void dropImageSupport();
3022+ void updateSourceTransform(
3023+ float itemWidth, float itemHeight, FillMode fillMode, HAlignment horizontalAlignment,
3024+ VAlignment verticalAlignment, const QSize& textureSize);
3025+
3026+ enum Radius { SmallRadius, MediumRadius };
3027+ enum Border { RawBorder, IdleBorder, PressedBorder };
3028+ enum {
3029+ GradientColorSet = (1 << 0),
3030+ Stretched = (1 << 1),
3031+ BackgroundApiSet = (1 << 2),
3032+ SourceApiSet = (1 << 3),
3033+ DirtySourceTransform = (1 << 4)
3034+ };
3035+
3036+ QQuickItem* m_source;
3037+ QSGTextureProvider* m_sourceTextureProvider;
3038+ QRgb m_backgroundColor;
3039+ QRgb m_secondaryBackgroundColor;
3040+ QVector2D m_sourceScale;
3041+ QVector2D m_sourceTranslation;
3042+ QVector4D m_sourceTransform;
3043+ Radius m_radius : 1;
3044+ Border m_border : 2;
3045+ HAlignment m_imageHorizontalAlignment : 2;
3046+ VAlignment m_imageVerticalAlignment : 2;
3047+ BackgroundMode m_backgroundMode : 1;
3048+ HAlignment m_sourceHorizontalAlignment : 2;
3049+ VAlignment m_sourceVerticalAlignment : 2;
3050+ FillMode m_sourceFillMode : 2;
3051+ WrapMode m_sourceHorizontalWrapMode : 1;
3052+ WrapMode m_sourceVerticalWrapMode : 1;
3053+ quint8 m_sourceOpacity;
3054+ quint8 m_flags;
3055+
3056+ Q_DISABLE_COPY(UCUbuntuShape)
3057+};
3058+
3059+QML_DECLARE_TYPE(UCUbuntuShape)
3060+
3061+#endif // UCUBUNTUSHAPE_H
3062
3063=== renamed file 'modules/Ubuntu/Components/plugin/shapeitemtexture.h' => 'modules/Ubuntu/Components/plugin/ucubuntushapetexture.h'
3064--- modules/Ubuntu/Components/plugin/shapeitemtexture.h 2014-03-24 15:24:31 +0000
3065+++ modules/Ubuntu/Components/plugin/ucubuntushapetexture.h 2015-03-02 15:41:23 +0000
3066@@ -1,5 +1,5 @@
3067 /*
3068- * Copyright 2013 Canonical Ltd.
3069+ * Copyright 2013-2014 Canonical Ltd.
3070 *
3071 * This program is free software; you can redistribute it and/or modify
3072 * it under the terms of the GNU Lesser General Public License as published by
3073@@ -18,7 +18,7 @@
3074
3075 class QSGTexture;
3076
3077-struct TextureData {
3078+struct ShapeTextureData {
3079 const unsigned char* const data;
3080 int width;
3081 int height;
3082@@ -5158,7 +5158,7 @@
3083 const float hh = 1.0f / 512.0f;
3084
3085 // High resolution shape texture.
3086-TextureData shapeTextureHigh __attribute__((aligned(16))) = {
3087+ShapeTextureData shapeTextureHigh __attribute__((aligned(16))) = {
3088 shapeTextureHighData, 256, 128, 4, 32.0f, 64.0f, 18.0f,
3089 {
3090 { // Medium raw coords.
3091@@ -6482,7 +6482,7 @@
3092 const float hl = 1.0f / 256.0f;
3093
3094 // Low resolution shape texture.
3095-TextureData shapeTextureLow __attribute__((aligned(16))) = {
3096+ShapeTextureData shapeTextureLow __attribute__((aligned(16))) = {
3097 shapeTextureLowData, 128, 64, 4, 16.0f, 32.0f, 9.0f,
3098 {
3099 { // Medium raw coords.
3100
3101=== added directory 'tests/resources/ubuntushape'
3102=== added file 'tests/resources/ubuntushape/UbuntuShapeTest.qml'
3103--- tests/resources/ubuntushape/UbuntuShapeTest.qml 1970-01-01 00:00:00 +0000
3104+++ tests/resources/ubuntushape/UbuntuShapeTest.qml 2015-03-02 15:41:23 +0000
3105@@ -0,0 +1,299 @@
3106+/*
3107+ * Copyright 2015 Canonical Ltd.
3108+ *
3109+ * This program is free software; you can redistribute it and/or modify
3110+ * it under the terms of the GNU Lesser General Public License as published by
3111+ * the Free Software Foundation; version 3.
3112+ *
3113+ * This program is distributed in the hope that it will be useful,
3114+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
3115+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3116+ * GNU Lesser General Public License for more details.
3117+ *
3118+ * You should have received a copy of the GNU Lesser General Public License
3119+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
3120+ */
3121+
3122+import QtQuick 2.0
3123+import Ubuntu.Components 1.2
3124+
3125+Item {
3126+ id: root
3127+ width: 1000
3128+ height: 600
3129+ focus: true
3130+
3131+ // Enum to string tables.
3132+ property variant backgroundModeTable: [
3133+ "SolidColor", "VerticalGradient"
3134+ ]
3135+ property variant sourceHAlignmentTable: [
3136+ "AlignLeft", "AlignHCenter", "AlignRight"
3137+ ]
3138+ property variant sourceVAlignmentTable: [
3139+ "AlignTop", "AlignVCenter", "AlignBottom"
3140+ ]
3141+ property variant sourceFillModeTable: [
3142+ "Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Pad"
3143+ ]
3144+ property variant wrapModeTable: [
3145+ "Transparent", "Repeat"
3146+ ]
3147+ property variant imageFillModeTable: [
3148+ "Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically",
3149+ "TileHorizontally", "Pad"
3150+ ]
3151+
3152+ // Zoom properties.
3153+ property variant translation: Qt.point(0.0, 0.0)
3154+ property real scaleBase: 1.1
3155+ property real scaleExponent: 0.0
3156+ property real minScaleExponent: 0.0
3157+ property real maxScaleExponent: 48.317715856 // Logarithm of 100 to base 1.1 (scaleBase).
3158+ property real scaleFactor: 1.0
3159+ property real scale: 1.0
3160+
3161+ // Overlay text properties. French keymapping... :)
3162+ property string textOverlayString:
3163+ "Zoom (scroll): x " + root.scaleFactor.toFixed(1) + "\n\n" +
3164+ "Background colors (a/z): " + shape.backgroundColor + ", " + shape.secondaryBackgroundColor + "\n" +
3165+ "Background mode (e): " + root.backgroundModeTable[shape.backgroundMode] + "\n\n" +
3166+ "Source (o): " + shape.source + "\n" +
3167+ "Source opacity (p): " + shape.sourceOpacity.toFixed(2) + "\n" +
3168+ "Source fill (q): " + root.sourceFillModeTable[shape.sourceFillMode] + "\n" +
3169+ "Source hwrap (s): " + root.wrapModeTable[shape.sourceHorizontalWrapMode] + "\n" +
3170+ "Source vwrap (d): " + root.wrapModeTable[shape.sourceVerticalWrapMode] + "\n" +
3171+ "Source halign (f): " + root.sourceHAlignmentTable[shape.sourceHorizontalAlignment] + "\n" +
3172+ "Source valign (g): " + root.sourceVAlignmentTable[shape.sourceVerticalAlignment] + "\n" +
3173+ "Source translation (h/j): " + shape.sourceTranslation.x.toFixed(2) + ", " + shape.sourceTranslation.y.toFixed(2) + "\n" +
3174+ "Source scale (k/l): " + shape.sourceScale.x.toFixed(2) + ", " + shape.sourceScale.y.toFixed(2) + "\n\n" +
3175+ "Image (deprecated) (m): " + shape.image + "\n" +
3176+ "Image fill (w): " + root.imageFillModeTable[img1.fillMode] + "\n" +
3177+ "Image halign (x): " + img1.horizontalAlignment + "\n" +
3178+ "Image valign (c): " + img1.verticalAlignment + "\n\n" +
3179+ "Radius (v): " + "\"" + shape.radius + "\"\n" +
3180+ "Border (b): " + "\"" + shape.borderSource + "\"\n\n" +
3181+ "Colors (deprecated) (n/,): " + shape.color + ", " + shape.gradientColor
3182+
3183+ // Main scene.
3184+ Item {
3185+ id: scene
3186+ anchors.fill: parent
3187+
3188+ Image {
3189+ id: background
3190+ anchors.fill: parent
3191+ source: "background.jpg"
3192+ fillMode: Image.Tile
3193+ }
3194+
3195+ // Put the UbuntuShape source image in the middle of a texture atlas. We use img1.
3196+ Image { id: img1; visible: false; source: "img1.png"; }
3197+ Image { id: img2; visible: false; source: "img2.png"; }
3198+ Image { id: img3; visible: false; source: "img3.png"; }
3199+ Image { id: img4; visible: false; source: "img4.png"; }
3200+
3201+ UbuntuShape {
3202+ id: shape
3203+ anchors.fill: parent
3204+ anchors.leftMargin: 400
3205+ anchors.rightMargin: 100
3206+ anchors.topMargin: 100
3207+ anchors.bottomMargin: 100
3208+ }
3209+ }
3210+
3211+ // Zoom support.
3212+ ShaderEffectSource {
3213+ id: shaderEffectSource
3214+ anchors.fill: scene
3215+ sourceItem: scene
3216+ hideSource: true
3217+ visible: false
3218+ smooth: false
3219+ }
3220+ ShaderEffect {
3221+ anchors.fill: scene
3222+ property variant tex: shaderEffectSource
3223+ property variant translation: root.translation
3224+ property real scaleFactor: root.scale
3225+ vertexShader: "
3226+ uniform mat4 qt_Matrix;
3227+ uniform float scaleFactor;
3228+ uniform vec2 translation;
3229+ attribute vec4 qt_Vertex;
3230+ attribute vec2 qt_MultiTexCoord0;
3231+ varying vec2 texCoord;
3232+ void main() {
3233+ texCoord = vec2(scaleFactor) * qt_MultiTexCoord0 + translation;
3234+ gl_Position = qt_Matrix * qt_Vertex;
3235+ }"
3236+ fragmentShader: "
3237+ uniform sampler2D tex;
3238+ uniform float qt_Opacity;
3239+ varying vec2 texCoord;
3240+ void main() {
3241+ gl_FragColor = texture2D(tex, texCoord) * qt_Opacity;
3242+ }"
3243+ }
3244+
3245+ // Text overlay.
3246+ Text {
3247+ id: textOverlay
3248+ width:200
3249+ anchors.top: parent.top
3250+ anchors.topMargin: 10
3251+ anchors.left: parent.left
3252+ anchors.leftMargin: 10
3253+ font.family: "Ubuntu Mono"
3254+ font.pixelSize: 14
3255+ font.weight: Font.Bold
3256+ color: "black"
3257+ text: textOverlayString
3258+ }
3259+
3260+ // Mouse handling.
3261+ MouseArea {
3262+ id: mouseArea
3263+ anchors.fill: parent
3264+ acceptedButtons: Qt.LeftButton
3265+ hoverEnabled: true
3266+
3267+ property real lastX: 0.0
3268+ property real lastY: 0.0
3269+
3270+ onPressed: {
3271+ if (pressedButtons & Qt.LeftButton) {
3272+ lastX = mouseX;
3273+ lastY = mouseY;
3274+ }
3275+ }
3276+ onPositionChanged: {
3277+ if (pressedButtons & Qt.LeftButton) {
3278+ var tx = root.translation.x;
3279+ var ty = root.translation.y;
3280+ var sx = root.scale / root.width;
3281+ var sy = root.scale / root.height;
3282+ var x = mouseX - lastX;
3283+ var y = mouseY - lastY;
3284+ root.translation = Qt.point(Math.max(0.0, Math.min(1.0 - root.scale, tx - sx * x)),
3285+ Math.max(0.0, Math.min(1.0 - root.scale, ty - sy * y)));
3286+ lastX = mouseX;
3287+ lastY = mouseY;
3288+ }
3289+ }
3290+ onWheel: {
3291+ root.scaleExponent = Math.max(minScaleExponent, Math.min(maxScaleExponent,
3292+ root.scaleExponent + (wheel.angleDelta.y < 0.0 ? -1.0 : 1.0)));
3293+ root.scaleFactor = Math.pow(root.scaleBase, root.scaleExponent);
3294+ var oldScale = root.scale;
3295+ root.scale = 1.0 / root.scaleFactor;
3296+ var s = oldScale - root.scale;
3297+ var tx = root.translation.x;
3298+ var ty = root.translation.y;
3299+ var x = mouseX / root.width;
3300+ var y = mouseY / root.height;
3301+ root.translation = Qt.point(Math.max(0.0, Math.min(1.0 - root.scale, tx + s * x)),
3302+ Math.max(0.0, Math.min(1.0 - root.scale, ty + s * y)));
3303+ }
3304+ }
3305+
3306+ // Keyboard handling.
3307+ Keys.onPressed: {
3308+ var shift = Qt.ShiftModifier;
3309+
3310+ // Background.
3311+ if (event.key == Qt.Key_A) {
3312+ shape.backgroundColor = Qt.rgba(
3313+ Math.random(), Math.random(), Math.random(), Math.random());
3314+ } else if (event.key == Qt.Key_Z) {
3315+ shape.secondaryBackgroundColor = Qt.rgba(
3316+ Math.random(), Math.random(), Math.random(), Math.random());
3317+ } else if (event.key == Qt.Key_E) {
3318+ shape.backgroundMode = (shape.backgroundMode + 1) % 3;
3319+
3320+ // Source.
3321+ } else if (event.key == Qt.Key_O) {
3322+ if (shape.source == null) {
3323+ shape.source = img1;
3324+ } else {
3325+ shape.source = null;
3326+ }
3327+ } else if (event.key == Qt.Key_P) {
3328+ shape.sourceOpacity = Math.max(0.0, Math.min(
3329+ 1.0, shape.sourceOpacity + ((event.modifiers & shift) ? 0.01 : -0.01)));
3330+ } else if (event.key == Qt.Key_Q) {
3331+ shape.sourceFillMode = (shape.sourceFillMode + 1) % 4;
3332+ } else if (event.key == Qt.Key_S) {
3333+ shape.sourceHorizontalWrapMode = (shape.sourceHorizontalWrapMode + 1) % 3;
3334+ } else if (event.key == Qt.Key_D) {
3335+ shape.sourceVerticalWrapMode = (shape.sourceVerticalWrapMode + 1) % 3;
3336+ } else if (event.key == Qt.Key_F) {
3337+ shape.sourceHorizontalAlignment = (shape.sourceHorizontalAlignment + 1) % 3;
3338+ } else if (event.key == Qt.Key_G) {
3339+ shape.sourceVerticalAlignment = (shape.sourceVerticalAlignment + 1) % 3;
3340+ } else if (event.key == Qt.Key_H) {
3341+ shape.sourceTranslation = Qt.vector2d(
3342+ shape.sourceTranslation.x + ((event.modifiers & shift) ? 0.01 : -0.01),
3343+ shape.sourceTranslation.y);
3344+ } else if (event.key == Qt.Key_J) {
3345+ shape.sourceTranslation = Qt.vector2d(
3346+ shape.sourceTranslation.x,
3347+ shape.sourceTranslation.y + ((event.modifiers & shift) ? 0.01 : -0.01));
3348+ } else if (event.key == Qt.Key_K) {
3349+ shape.sourceScale = Qt.vector2d(
3350+ shape.sourceScale.x + ((event.modifiers & shift) ? 0.02 : -0.02),
3351+ shape.sourceScale.y);
3352+ } else if (event.key == Qt.Key_L) {
3353+ shape.sourceScale = Qt.vector2d(
3354+ shape.sourceScale.x,
3355+ shape.sourceScale.y + ((event.modifiers & shift) ? 0.02 : -0.02));
3356+
3357+ // Image.
3358+ } else if (event.key == Qt.Key_M) {
3359+ if (shape.image == null) {
3360+ shape.image = img1;
3361+ } else {
3362+ shape.image = null;
3363+ }
3364+ } else if (event.key == Qt.Key_W) {
3365+ img1.fillMode = (img1.fillMode + 1) % 7;
3366+ } else if (event.key == Qt.Key_X) {
3367+ if (img1.horizontalAlignment == Image.AlignLeft) {
3368+ img1.horizontalAlignment = Image.AlignHCenter;
3369+ } else if (img1.horizontalAlignment == Image.AlignHCenter) {
3370+ img1.horizontalAlignment = Image.AlignRight;
3371+ } else {
3372+ img1.horizontalAlignment = Image.AlignLeft;
3373+ }
3374+ } else if (event.key == Qt.Key_C) {
3375+ if (img1.verticalAlignment == Image.AlignTop) {
3376+ img1.verticalAlignment = Image.AlignVCenter;
3377+ } else if (img1.verticalAlignment == Image.AlignVCenter) {
3378+ img1.verticalAlignment = Image.AlignBottom;
3379+ } else {
3380+ img1.verticalAlignment = Image.AlignTop;
3381+ }
3382+
3383+ // Styling.
3384+ } else if (event.key == Qt.Key_V) {
3385+ shape.radius = (shape.radius == "medium") ? "small" : "medium";
3386+ } else if (event.key == Qt.Key_B) {
3387+ if (shape.borderSource == "radius_idle.sci") {
3388+ shape.borderSource = "radius_pressed.sci";
3389+ } else if (shape.borderSource == "radius_pressed.sci") {
3390+ shape.borderSource = "";
3391+ } else {
3392+ shape.borderSource = "radius_idle.sci";
3393+ }
3394+
3395+ // Colors.
3396+ } else if (event.key == Qt.Key_N) {
3397+ shape.color = Qt.rgba(
3398+ Math.random(), Math.random(), Math.random(), Math.random());
3399+ } else if (event.key == Qt.Key_Comma) {
3400+ shape.gradientColor = Qt.rgba(
3401+ Math.random(), Math.random(), Math.random(), Math.random());
3402+ }
3403+ }
3404+}
3405
3406=== added file 'tests/resources/ubuntushape/background.jpg'
3407Binary files tests/resources/ubuntushape/background.jpg 1970-01-01 00:00:00 +0000 and tests/resources/ubuntushape/background.jpg 2015-03-02 15:41:23 +0000 differ
3408=== added file 'tests/resources/ubuntushape/img1.png'
3409Binary files tests/resources/ubuntushape/img1.png 1970-01-01 00:00:00 +0000 and tests/resources/ubuntushape/img1.png 2015-03-02 15:41:23 +0000 differ
3410=== added file 'tests/resources/ubuntushape/img2.png'
3411Binary files tests/resources/ubuntushape/img2.png 1970-01-01 00:00:00 +0000 and tests/resources/ubuntushape/img2.png 2015-03-02 15:41:23 +0000 differ
3412=== added file 'tests/resources/ubuntushape/img3.png'
3413Binary files tests/resources/ubuntushape/img3.png 1970-01-01 00:00:00 +0000 and tests/resources/ubuntushape/img3.png 2015-03-02 15:41:23 +0000 differ
3414=== added file 'tests/resources/ubuntushape/img4.png'
3415Binary files tests/resources/ubuntushape/img4.png 1970-01-01 00:00:00 +0000 and tests/resources/ubuntushape/img4.png 2015-03-02 15:41:23 +0000 differ

Subscribers

People subscribed via source and target branches