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
=== modified file '.bzrignore'
--- .bzrignore 2015-02-02 14:40:18 +0000
+++ .bzrignore 2015-03-02 15:41:23 +0000
@@ -2,6 +2,7 @@
2modules/Makefile.ubuntu-ui-toolkit2modules/Makefile.ubuntu-ui-toolkit
3modules/Ubuntu/Components/Makefile.ubuntu-ui-toolkit3modules/Ubuntu/Components/Makefile.ubuntu-ui-toolkit
4modules/Ubuntu/Components/plugin/Makefile.ubuntu-ui-toolkit4modules/Ubuntu/Components/plugin/Makefile.ubuntu-ui-toolkit
5modules/Ubuntu/Components/plugin/qrc_plugin.cpp
5documentation/html/*6documentation/html/*
6*.moc7*.moc
7moc_*.cpp8moc_*.cpp
89
=== modified file 'components.api'
--- components.api 2015-02-24 14:54:58 +0000
+++ components.api 2015-03-02 15:41:23 +0000
@@ -794,21 +794,6 @@
794 name: "get"794 name: "get"
795 Parameter { name: "row"; type: "int" }795 Parameter { name: "row"; type: "int" }
796 Method { name: "count"; type: "int" }796 Method { name: "count"; type: "int" }
797 name: "ShapeItem"
798 prototype: "QQuickItem"
799 exports: [
800 name: "HAlignment"
801 name: "VAlignment"
802 Property { name: "color"; type: "QColor" }
803 Property { name: "gradientColor"; type: "QColor" }
804 Property { name: "radius"; type: "string" }
805 Property { name: "image"; type: "QVariant" }
806 Property { name: "stretched"; type: "bool" }
807 Property { name: "horizontalAlignment"; type: "HAlignment" }
808 Property { name: "verticalAlignment"; type: "VAlignment" }
809 Property { name: "borderSource"; type: "string" }
810 Signal { name: "borderChanged" }
811 Method { name: "gridUnitChanged" }
812 name: "SortBehavior"797 name: "SortBehavior"
813 prototype: "QObject"798 prototype: "QObject"
814 exports: ["SortBehavior 1.1"]799 exports: ["SortBehavior 1.1"]
@@ -1073,6 +1058,46 @@
1073 Property { name: "SleepyDuration"; type: "int"; isReadonly: true }1058 Property { name: "SleepyDuration"; type: "int"; isReadonly: true }
1074 Property { name: "StandardEasing"; type: "QEasingCurve"; isReadonly: true }1059 Property { name: "StandardEasing"; type: "QEasingCurve"; isReadonly: true }
1075 Property { name: "StandardEasingReverse"; type: "QEasingCurve"; isReadonly: true }1060 Property { name: "StandardEasingReverse"; type: "QEasingCurve"; isReadonly: true }
1061 name: "UCUbuntuShape"
1062 prototype: "QQuickItem"
1063 exports: [
1064 name: "BackgroundMode"
1065 name: "HAlignment"
1066 name: "VAlignment"
1067 name: "FillMode"
1068 name: "WrapMode"
1069 Property { name: "radius"; type: "string" }
1070 Property { name: "borderSource"; type: "string" }
1071 Property { name: "source"; revision: 1; type: "QVariant" }
1072 Property { name: "sourceOpacity"; revision: 1; type: "float" }
1073 Property { name: "sourceFillMode"; revision: 1; type: "FillMode" }
1074 Property { name: "sourceHorizontalWrapMode"; revision: 1; type: "WrapMode" }
1075 Property { name: "sourceVerticalWrapMode"; revision: 1; type: "WrapMode" }
1076 Property { name: "sourceHorizontalAlignment"; revision: 1; type: "HAlignment" }
1077 Property { name: "sourceVerticalAlignment"; revision: 1; type: "VAlignment" }
1078 Property { name: "sourceTranslation"; revision: 1; type: "QVector2D" }
1079 Property { name: "sourceScale"; revision: 1; type: "QVector2D" }
1080 Property { name: "backgroundColor"; revision: 1; type: "QColor" }
1081 Property { name: "secondaryBackgroundColor"; revision: 1; type: "QColor" }
1082 Property { name: "backgroundMode"; revision: 1; type: "BackgroundMode" }
1083 Property { name: "color"; type: "QColor" }
1084 Property { name: "gradientColor"; type: "QColor" }
1085 Property { name: "image"; type: "QVariant" }
1086 Property { name: "stretched"; type: "bool" }
1087 Property { name: "horizontalAlignment"; type: "HAlignment" }
1088 Property { name: "verticalAlignment"; type: "VAlignment" }
1089 Signal { name: "sourceChanged"; revision: 1 }
1090 Signal { name: "sourceOpacityChanged"; revision: 1 }
1091 Signal { name: "sourceFillModeChanged"; revision: 1 }
1092 Signal { name: "sourceHorizontalWrapModeChanged"; revision: 1 }
1093 Signal { name: "sourceVerticalWrapModeChanged"; revision: 1 }
1094 Signal { name: "sourceHorizontalAlignmentChanged"; revision: 1 }
1095 Signal { name: "sourceVerticalAlignmentChanged"; revision: 1 }
1096 Signal { name: "sourceTranslationChanged"; revision: 1 }
1097 Signal { name: "sourceScaleChanged"; revision: 1 }
1098 Signal { name: "backgroundColorChanged"; revision: 1 }
1099 Signal { name: "secondaryBackgroundColorChanged"; revision: 1 }
1100 Signal { name: "backgroundModeChanged"; revision: 1 }
1076 name: "UCUnits"1101 name: "UCUnits"
1077 prototype: "QObject"1102 prototype: "QObject"
1078 exports: ["UCUnits 0.1", "UCUnits 1.0"]1103 exports: ["UCUnits 0.1", "UCUnits 1.0"]
10791104
=== modified file 'examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml'
--- examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml 2014-11-19 11:10:00 +0000
+++ examples/ubuntu-ui-toolkit-gallery/UbuntuShape.qml 2015-03-02 15:41:23 +0000
@@ -14,8 +14,8 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */15 */
1616
17import QtQuick 2.017import QtQuick 2.2
18import Ubuntu.Components 0.118import Ubuntu.Components 1.2
1919
20Template {20Template {
21 objectName: "ubuntuShapesTemplate"21 objectName: "ubuntuShapesTemplate"
@@ -30,18 +30,17 @@
30 height: units.gu(8)30 height: units.gu(8)
3131
32 UbuntuShape {32 UbuntuShape {
33 objectName: "ubuntushape_color_hex"33 objectName: "ubuntushape_backgroundcolor_orange"
34 color: UbuntuColors.orange34 backgroundColor: UbuntuColors.orange
35 }35 }
3636
37 UbuntuShape {37 UbuntuShape {
38 objectName: "ubuntushape_color_lightaubergine"38 objectName: "ubuntushape_verticalgradient"
39 color: UbuntuColors.lightAubergine39 backgroundColor: UbuntuColors.lightAubergine
40 }40 secondaryBackgroundColor: Qt.rgba(
4141 UbuntuColors.lightAubergine.r, UbuntuColors.lightAubergine.g,
42 UbuntuShape {42 UbuntuColors.lightAubergine.b, 0.25)
43 objectName: "ubuntushape_color_darkgray"43 backgroundMode: UbuntuShape.VerticalGradient
44 color: UbuntuColors.warmGrey
45 }44 }
46 }45 }
4746
@@ -51,12 +50,16 @@
51 height: units.gu(8)50 height: units.gu(8)
5251
53 UbuntuShape {52 UbuntuShape {
54 objectName: "ubuntushape_image"53 objectName: "ubuntushape_preserveaspectcrop"
54 source: Image { source: "map_icon.png" }
55 sourceFillMode: UbuntuShape.PreserveAspectCrop
56 }
5557
56 image: Image {58 UbuntuShape {
57 source: "map_icon.png"59 objectName: "ubuntushape_pad"
58 fillMode: Image.PreserveAspectCrop60 backgroundColor: UbuntuColors.warmGrey
59 }61 source: Image { source: "images.png" }
62 sourceFillMode: UbuntuShape.Pad
60 }63 }
61 }64 }
6265
@@ -68,7 +71,7 @@
68 UbuntuShape {71 UbuntuShape {
69 objectName: "ubuntushape_radius_small"72 objectName: "ubuntushape_radius_small"
7073
71 color: Theme.palette.normal.foreground74 backgroundColor: Theme.palette.normal.foreground
72 radius: "small"75 radius: "small"
7376
74 Label {77 Label {
@@ -81,7 +84,7 @@
8184
82 UbuntuShape {85 UbuntuShape {
83 objectName: "ubuntushape_radius_medium"86 objectName: "ubuntushape_radius_medium"
84 color: Theme.palette.normal.foreground87 backgroundColor: Theme.palette.normal.foreground
85 radius: "medium"88 radius: "medium"
8689
87 Label {90 Label {
@@ -100,7 +103,7 @@
100103
101 UbuntuShape {104 UbuntuShape {
102 objectName: "ubuntushape_sizes_15_6"105 objectName: "ubuntushape_sizes_15_6"
103 color: Theme.palette.normal.foreground106 backgroundColor: Theme.palette.normal.foreground
104 width: units.gu(15)107 width: units.gu(15)
105 height: units.gu(6)108 height: units.gu(6)
106 anchors.verticalCenter: parent.verticalCenter109 anchors.verticalCenter: parent.verticalCenter
@@ -108,7 +111,7 @@
108111
109 UbuntuShape {112 UbuntuShape {
110 objectName: "ubuntushape_sizes_10_14"113 objectName: "ubuntushape_sizes_10_14"
111 color: Theme.palette.normal.foreground114 backgroundColor: Theme.palette.normal.foreground
112 width: units.gu(10)115 width: units.gu(10)
113 height: units.gu(14)116 height: units.gu(14)
114 }117 }
115118
=== modified file 'modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml'
--- modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml 2015-02-10 16:47:59 +0000
+++ modules/Ubuntu/Components/Themes/Ambiance/ProgressBarStyle.qml 2015-03-02 15:41:23 +0000
@@ -36,7 +36,7 @@
36 /* The color must be white for PartialColorizeUbuntuShape to accurately36 /* The color must be white for PartialColorizeUbuntuShape to accurately
37 replace the white with leftColor and rightColor37 replace the white with leftColor and rightColor
38 */38 */
39 color: progressBar.indeterminate ? backgroundColor : "#FFFFFF"39 color: progressBar.indeterminate ? progressBarStyle.backgroundColor : "#FFFFFF"
40 }40 }
4141
42 property real progress: progressBar.indeterminate ? 0.042 property real progress: progressBar.indeterminate ? 0.0
4343
=== modified file 'modules/Ubuntu/Components/plugin/plugin.cpp'
--- modules/Ubuntu/Components/plugin/plugin.cpp 2015-02-13 13:27:51 +0000
+++ modules/Ubuntu/Components/plugin/plugin.cpp 2015-03-02 15:41:23 +0000
@@ -31,7 +31,7 @@
31#include "ucscalingimageprovider.h"31#include "ucscalingimageprovider.h"
32#include "ucqquickimageextension.h"32#include "ucqquickimageextension.h"
33#include "quickutils.h"33#include "quickutils.h"
34#include "shapeitem.h"34#include "ucubuntushape.h"
35#include "inversemouseareatype.h"35#include "inversemouseareatype.h"
36#include "qquickclipboard.h"36#include "qquickclipboard.h"
37#include "qquickmimedata.h"37#include "qquickmimedata.h"
@@ -129,9 +129,9 @@
129 qmlRegisterUncreatableType<UbuntuI18n>(uri, major, minor, "i18n", "Singleton object");129 qmlRegisterUncreatableType<UbuntuI18n>(uri, major, minor, "i18n", "Singleton object");
130 qmlRegisterExtendedType<QQuickImageBase, UCQQuickImageExtension>(uri, major, minor, "QQuickImageBase");130 qmlRegisterExtendedType<QQuickImageBase, UCQQuickImageExtension>(uri, major, minor, "QQuickImageBase");
131 qmlRegisterUncreatableType<UCUnits>(uri, major, minor, "UCUnits", "Not instantiable");131 qmlRegisterUncreatableType<UCUnits>(uri, major, minor, "UCUnits", "Not instantiable");
132 qmlRegisterType<ShapeItem>(uri, major, minor, "UbuntuShape");132 qmlRegisterType<UCUbuntuShape>(uri, major, minor, "UbuntuShape");
133 // FIXME/DEPRECATED: Shape is exported for backwards compatibity only133 // FIXME/DEPRECATED: Shape is exported for backwards compatibility only
134 qmlRegisterType<ShapeItem>(uri, major, minor, "Shape");134 qmlRegisterType<UCUbuntuShape>(uri, major, minor, "Shape");
135 qmlRegisterType<InverseMouseAreaType>(uri, major, minor, "InverseMouseArea");135 qmlRegisterType<InverseMouseAreaType>(uri, major, minor, "InverseMouseArea");
136 qmlRegisterType<QQuickMimeData>(uri, major, minor, "MimeData");136 qmlRegisterType<QQuickMimeData>(uri, major, minor, "MimeData");
137 qmlRegisterSingletonType<QQuickClipboard>(uri, major, minor, "Clipboard", registerClipboard);137 qmlRegisterSingletonType<QQuickClipboard>(uri, major, minor, "Clipboard", registerClipboard);
@@ -169,13 +169,14 @@
169 qmlRegisterUncreatableType<SortBehavior>(uri, 1, 1, "SortBehavior", "Not instantiable");169 qmlRegisterUncreatableType<SortBehavior>(uri, 1, 1, "SortBehavior", "Not instantiable");
170 qmlRegisterType<UCServiceProperties, 1>(uri, 1, 1, "ServiceProperties");170 qmlRegisterType<UCServiceProperties, 1>(uri, 1, 1, "ServiceProperties");
171171
172 // ListItem and related types, released to 1.2172 // register 1.2 only API
173 qmlRegisterType<UCListItem>(uri, 1, 2, "ListItem");173 qmlRegisterType<UCListItem>(uri, 1, 2, "ListItem");
174 qmlRegisterType<UCListItemDivider>();174 qmlRegisterType<UCListItemDivider>();
175 qmlRegisterUncreatableType<UCSwipeEvent>(uri, 1, 2, "SwipeEvent", "This is an event object.");175 qmlRegisterUncreatableType<UCSwipeEvent>(uri, 1, 2, "SwipeEvent", "This is an event object.");
176 qmlRegisterUncreatableType<UCDragEvent>(uri, 1, 2, "ListItemDrag", "This is an event object");176 qmlRegisterUncreatableType<UCDragEvent>(uri, 1, 2, "ListItemDrag", "This is an event object");
177 qmlRegisterType<UCListItemActions>(uri, 1, 2, "ListItemActions");177 qmlRegisterType<UCListItemActions>(uri, 1, 2, "ListItemActions");
178 qmlRegisterUncreatableType<UCViewItemsAttached>(uri, 1, 2, "ViewItems", "Not instantiable");178 qmlRegisterUncreatableType<UCViewItemsAttached>(uri, 1, 2, "ViewItems", "Not instantiable");
179 qmlRegisterType<UCUbuntuShape, 1>(uri, 1, 2, "UbuntuShape");
179}180}
180181
181void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)182void UbuntuComponentsPlugin::initializeEngine(QQmlEngine *engine, const char *uri)
182183
=== modified file 'modules/Ubuntu/Components/plugin/plugin.pro'
--- modules/Ubuntu/Components/plugin/plugin.pro 2015-02-17 12:21:52 +0000
+++ modules/Ubuntu/Components/plugin/plugin.pro 2015-03-02 15:41:23 +0000
@@ -33,8 +33,8 @@
33 ucunits.h \33 ucunits.h \
34 ucqquickimageextension.h \34 ucqquickimageextension.h \
35 quickutils.h \35 quickutils.h \
36 shapeitemtexture.h \36 ucubuntushapetexture.h \
37 shapeitem.h \37 ucubuntushape.h \
38 inversemouseareatype.h \38 inversemouseareatype.h \
39 qquickclipboard.h \39 qquickclipboard.h \
40 qquickmimedata.h \40 qquickmimedata.h \
@@ -88,7 +88,7 @@
88 ucunits.cpp \88 ucunits.cpp \
89 ucqquickimageextension.cpp \89 ucqquickimageextension.cpp \
90 quickutils.cpp \90 quickutils.cpp \
91 shapeitem.cpp \91 ucubuntushape.cpp \
92 inversemouseareatype.cpp \92 inversemouseareatype.cpp \
93 qquickclipboard.cpp \93 qquickclipboard.cpp \
94 qquickmimedata.cpp \94 qquickmimedata.cpp \
@@ -127,6 +127,13 @@
127# adapters127# adapters
128SOURCES += adapters/alarmsadapter_organizer.cpp128SOURCES += adapters/alarmsadapter_organizer.cpp
129129
130RESOURCES += \
131 plugin.qrc
132
133OTHER_FILES += \
134 shaders/shape.vert \
135 shaders/shape.frag
136
130# deployment rules for the plugin137# deployment rules for the plugin
131installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)138installPath = $$[QT_INSTALL_QML]/$$replace(uri, \\., /)
132target.path = $$installPath139target.path = $$installPath
133140
=== added file 'modules/Ubuntu/Components/plugin/plugin.qrc'
--- modules/Ubuntu/Components/plugin/plugin.qrc 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/plugin/plugin.qrc 2015-03-02 15:41:23 +0000
@@ -0,0 +1,6 @@
1<RCC>
2 <qresource prefix="/uc">
3 <file>shaders/shape.frag</file>
4 <file>shaders/shape.vert</file>
5 </qresource>
6</RCC>
07
=== added directory 'modules/Ubuntu/Components/plugin/shaders'
=== added file 'modules/Ubuntu/Components/plugin/shaders/shape.frag'
--- modules/Ubuntu/Components/plugin/shaders/shape.frag 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/plugin/shaders/shape.frag 2015-03-02 15:41:23 +0000
@@ -0,0 +1,57 @@
1// Copyright © 2015 Canonical Ltd.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published by
5// the Free Software Foundation; version 3.
6//
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU Lesser General Public License for more details.
11//
12// You should have received a copy of the GNU Lesser General Public License
13// along with this program. If not, see <http://www.gnu.org/licenses/>.
14//
15// Author: Loïc Molinari <loic.molinari@canonical.com>
16
17// Static flow control (branching on a uniform value) is fast on most GPUs (including ultra-low
18// power ones) because it allows to use the same shader execution path for an entire draw call. We
19// rely on that technique here (also known as "uber-shader" solution) to avoid the complexity of
20// dealing with a multiple shaders solution.
21// FIXME(loicm) Validate GPU behavior with regards to static flow control.
22
23uniform sampler2D shapeTexture;
24uniform sampler2D sourceTexture;
25uniform lowp float sourceOpacity;
26uniform lowp float opacity;
27uniform bool textured;
28
29varying mediump vec2 shapeCoord;
30varying mediump vec4 sourceCoord;
31varying lowp vec4 backgroundColor;
32
33void main(void)
34{
35 // Early texture fetch to cover latency as best as possible.
36 lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord);
37
38 lowp vec4 color = backgroundColor;
39
40 // FIXME(loicm) Would be better to use a bitfield but bitwise ops have only been integrated in
41 // GLSL 1.3 (OpenGL 3) and GLSL ES 3 (OpenGL ES 3).
42 if (textured) {
43 // Blend the source over the current color (static flow control prevents the texture fetch).
44 lowp vec2 axisMask = -sign((sourceCoord.zw * sourceCoord.zw) - vec2(1.0));
45 lowp float mask = clamp(axisMask.x + axisMask.y, 0.0, 1.0);
46 lowp vec4 source = texture2D(sourceTexture, sourceCoord.st) * vec4(sourceOpacity * mask);
47 color = vec4(1.0 - source.a) * color + source;
48 }
49
50 // Shape the current color with the mask.
51 color *= vec4(shapeData.b);
52
53 // Blend the border over the current color.
54 color = vec4(1.0 - shapeData.r) * color + shapeData.gggr;
55
56 gl_FragColor = color * vec4(opacity);
57}
058
=== added file 'modules/Ubuntu/Components/plugin/shaders/shape.vert'
--- modules/Ubuntu/Components/plugin/shaders/shape.vert 1970-01-01 00:00:00 +0000
+++ modules/Ubuntu/Components/plugin/shaders/shape.vert 2015-03-02 15:41:23 +0000
@@ -0,0 +1,43 @@
1// Copyright © 2015 Canonical Ltd.
2//
3// This program is free software; you can redistribute it and/or modify
4// it under the terms of the GNU Lesser General Public License as published by
5// the Free Software Foundation; version 3.
6//
7// This program is distributed in the hope that it will be useful,
8// but WITHOUT ANY WARRANTY; without even the implied warranty of
9// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10// GNU Lesser General Public License for more details.
11//
12// You should have received a copy of the GNU Lesser General Public License
13// along with this program. If not, see <http://www.gnu.org/licenses/>.
14//
15// Author: Loïc Molinari <loic.molinari@canonical.com>
16
17uniform mediump mat4 matrix;
18uniform bool textured;
19
20attribute mediump vec4 positionAttrib;
21attribute mediump vec2 shapeCoordAttrib;
22attribute mediump vec4 sourceCoordAttrib;
23attribute lowp vec4 backgroundColorAttrib;
24
25// FIXME(loicm) Optimize by reducing/packing varyings.
26varying mediump vec2 shapeCoord;
27varying mediump vec4 sourceCoord;
28varying lowp vec4 backgroundColor;
29
30void main()
31{
32 shapeCoord = shapeCoordAttrib;
33
34 // FIXME(loicm) Would be better to use a bitfield but bitwise ops have only been integrated in
35 // GLSL 1.3 (OpenGL 3) and GLSL ES 3 (OpenGL ES 3).
36 if (textured) {
37 sourceCoord = sourceCoordAttrib;
38 }
39
40 backgroundColor = backgroundColorAttrib;
41
42 gl_Position = matrix * positionAttrib;
43}
044
=== renamed file 'modules/Ubuntu/Components/plugin/shapeitem.cpp' => 'modules/Ubuntu/Components/plugin/ucubuntushape.cpp'
--- modules/Ubuntu/Components/plugin/shapeitem.cpp 2014-11-19 12:23:05 +0000
+++ modules/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-03-02 15:41:23 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2013-2015 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by5 * it under the terms of the GNU Lesser General Public License as published by
@@ -16,297 +16,803 @@
16 * Author: Loïc Molinari <loic.molinari@canonical.com>16 * Author: Loïc Molinari <loic.molinari@canonical.com>
17 */17 */
1818
19#include "shapeitem.h"19// FIXME(loicm) Storing lower precision data types in the vertex buffer could be more efficent. On
20#include "shapeitemtexture.h"20// PowerVR, for instance, that requires a conversion so the trade-off between shader cycles and
21// bandwidth requirements must be benchmarked.
22
23#include "ucubuntushape.h"
24#include "ucubuntushapetexture.h"
21#include "ucunits.h"25#include "ucunits.h"
22#include <QtCore/QPointer>26#include <QtCore/QPointer>
23#include <QtQuick/QQuickWindow>27#include <QtQuick/QQuickWindow>
24#include <QtQuick/QSGTextureProvider>28#include <QtQuick/QSGTextureProvider>
25#include <QtQuick/private/qquickimage_p.h>29#include <QtQuick/private/qquickimage_p.h>
2630#include <math.h>
27/*!31
28 \qmltype UbuntuShape32// --- Scene graph shader ---
29 \instantiates ShapeItem33
30 \inqmlmodule Ubuntu.Components 1.134ShapeShader::ShapeShader()
35{
36 setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/uc/shaders/shape.vert"));
37 setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shape.frag"));
38}
39
40char const* const* ShapeShader::attributeNames() const
41{
42 static char const* const attributes[] = {
43 "positionAttrib", "shapeCoordAttrib", "sourceCoordAttrib", "backgroundColorAttrib", 0
44 };
45 return attributes;
46}
47
48void ShapeShader::initialize()
49{
50 QSGMaterialShader::initialize();
51
52 program()->bind();
53 program()->setUniformValue("shapeTexture", 0);
54 program()->setUniformValue("sourceTexture", 1);
55
56 m_functions = QOpenGLContext::currentContext()->functions();
57 m_matrixId = program()->uniformLocation("matrix");
58 m_opacityId = program()->uniformLocation("opacity");
59 m_sourceOpacityId = program()->uniformLocation("sourceOpacity");
60 m_texturedId = program()->uniformLocation("textured");
61}
62
63void ShapeShader::updateState(
64 const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect)
65{
66 Q_UNUSED(oldEffect);
67
68 const ShapeMaterial::Data* data = static_cast<ShapeMaterial*>(newEffect)->constData();
69
70 // Bind shape texture.
71 QSGTexture* shapeTexture = data->shapeTexture;
72 if (shapeTexture) {
73 shapeTexture->setFiltering(static_cast<QSGTexture::Filtering>(data->shapeTextureFiltering));
74 shapeTexture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
75 shapeTexture->setVerticalWrapMode(QSGTexture::ClampToEdge);
76 shapeTexture->bind();
77 } else {
78 glBindTexture(GL_TEXTURE_2D, 0);
79 }
80
81 if (data->flags & ShapeMaterial::Data::Textured) {
82 // Bind image texture.
83 m_functions->glActiveTexture(GL_TEXTURE1);
84 QSGTextureProvider* provider = data->sourceTextureProvider;
85 QSGTexture* texture = provider ? provider->texture() : NULL;
86 if (texture) {
87 if (data->flags & ShapeMaterial::Data::Repeated) {
88 if (texture->isAtlasTexture()) {
89 // A texture in an atlas can't be repeated with builtin GPU facility (exposed by
90 // GL_REPEAT with OpenGL), so we extract it and create a new dedicated one.
91 texture = texture->removedFromAtlas();
92 }
93 texture->setHorizontalWrapMode(
94 data->flags & ShapeMaterial::Data::HorizontallyRepeated ?
95 QSGTexture::Repeat : QSGTexture::ClampToEdge);
96 texture->setVerticalWrapMode(
97 data->flags & ShapeMaterial::Data::VerticallyRepeated ?
98 QSGTexture::Repeat : QSGTexture::ClampToEdge);
99 }
100 texture->bind();
101 } else {
102 glBindTexture(GL_TEXTURE_2D, 0);
103 }
104 m_functions->glActiveTexture(GL_TEXTURE0);
105 // Update image uniform.
106 const float u8toF32 = 1.0f / 255.0f;
107 program()->setUniformValue(m_sourceOpacityId, data->sourceOpacity * u8toF32);
108 }
109
110 program()->setUniformValue(m_texturedId, !!(data->flags & ShapeMaterial::Data::Textured));
111
112 // Update QtQuick engine uniforms.
113 if (state.isMatrixDirty()) {
114 program()->setUniformValue(m_matrixId, state.combinedMatrix());
115 }
116 if (state.isOpacityDirty()) {
117 program()->setUniformValue(m_opacityId, state.opacity());
118 }
119}
120
121// --- Scene graph material ---
122
123ShapeMaterial::ShapeMaterial()
124{
125 // The whole struct (with the padding bytes) must be initialized for memcmp() to work as
126 // expected in ShapeMaterial::compare().
127 memset(&m_data, 0x00, sizeof(Data));
128 setFlag(Blending);
129}
130
131QSGMaterialType* ShapeMaterial::type() const
132{
133 static QSGMaterialType type;
134 return &type;
135}
136
137QSGMaterialShader* ShapeMaterial::createShader() const
138{
139 return new ShapeShader;
140}
141
142int ShapeMaterial::compare(const QSGMaterial* other) const
143{
144 // Repeat wrap modes require textures to be extracted from their atlases. Since we just store
145 // the texture provider in the material data (not the texture as we want to do the extraction at
146 // QSGShader::updateState() time), we make the comparison fail when repeat wrapping is set.
147 const ShapeMaterial::Data* otherData = static_cast<const ShapeMaterial*>(other)->constData();
148 return memcmp(&m_data, otherData, sizeof(m_data))
149 | (m_data.flags & ShapeMaterial::Data::Repeated);
150}
151
152// --- Scene graph node ---
153
154ShapeNode::ShapeNode()
155 : QSGGeometryNode()
156 , m_material()
157 , m_geometry(attributeSet(), vertexCount, indexCount, indexType)
158{
159 memcpy(m_geometry.indexData(), indices(), indexCount * indexTypeSize);
160 m_geometry.setDrawingMode(drawingMode);
161 m_geometry.setIndexDataPattern(indexDataPattern);
162 m_geometry.setVertexDataPattern(vertexDataPattern);
163 setMaterial(&m_material);
164 setGeometry(&m_geometry);
165}
166
167// static
168const unsigned short* ShapeNode::indices()
169{
170 // Don't forget to update indexCount if changed.
171 static const unsigned short indices[] = {
172 0, 4, 1, 5, 2, 6, 3, 7, // Triangles 1 to 6.
173 7, 4, // Degenerate triangles.
174 4, 8, 5, 9, 6, 10, 7, 11, // Triangles 7 to 12.
175 11, 8, // Degenerate triangles.
176 8, 12, 9, 13, 10, 14, 11, 15 // Triangles 13 to 18.
177 };
178 return indices;
179}
180
181// static
182const QSGGeometry::AttributeSet& ShapeNode::attributeSet()
183{
184 static const QSGGeometry::Attribute attributes[] = {
185 QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true),
186 QSGGeometry::Attribute::create(1, 2, GL_FLOAT),
187 QSGGeometry::Attribute::create(2, 4, GL_FLOAT),
188 QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE)
189 };
190 static const QSGGeometry::AttributeSet attributeSet = {
191 4, sizeof(Vertex), attributes
192 };
193 return attributeSet;
194}
195
196// --- QtQuick item ---
197
198struct ShapeTextures
199{
200 ShapeTextures() : high(0), low(0) {}
201 QSGTexture* high;
202 QSGTexture* low;
203};
204
205static QHash<QOpenGLContext*, ShapeTextures> shapeTexturesHash;
206
207const float implicitGridUnitWidth = 8.0f;
208const float implicitGridUnitHeight = 8.0f;
209
210// Threshold in grid unit defining the texture quality to be used.
211const float lowHighTextureThreshold = 11.0f;
212
213/*! \qmltype UbuntuShape
214 \instantiates UCUbuntuShape
215 \inqmlmodule Ubuntu.Components 1.2
31 \ingroup ubuntu216 \ingroup ubuntu
32 \brief The UbuntuShape item provides a standard Ubuntu shaped rounded rectangle.217 \brief Rounded rectangle containing a source image blended over a background color.
33218
34 The UbuntuShape is used where a rounded rectangle is needed either filled219 The UbuntuShape is a rounded rectangle (based on a \l
35 with a color or an image that it crops.220 {https://en.wikipedia.org/wiki/Squircle}{squircle}) containing an optional source image blended
36221 over a background color (solid or linear gradient). Different properties allow to change the
37 When given with a \l color it is applied with an overlay blending as a222 look of the shape.
38 vertical gradient going from \l color to \l gradientColor.
39 Two corner \l radius are available, "small" (default) and "medium", that
40 determine the size of the corners.
41 Optionally, an Image can be passed that will be displayed inside the
42 UbuntuShape and cropped to fit it.
43223
44 Examples:224 Examples:
45 \qml225
46 import Ubuntu.Components 1.1226 \qml
47227 import Ubuntu.Components 1.2
48 UbuntuShape {228
49 color: "lightblue"229 UbuntuShape {
50 radius: "medium"230 backgroundColor: "green"
51 }231 }
52 \endqml232 \endqml
53233
54 \qml234 \qml
55 import Ubuntu.Components 1.1235 import Ubuntu.Components 1.2
56236
57 UbuntuShape {237 UbuntuShape {
58 image: Image {238 source: Image {
59 source: "icon.png"239 source: "ubuntu.png"
60 }240 }
61 }241 }
62 \endqml242 \endqml
63*/243*/
64244UCUbuntuShape::UCUbuntuShape(QQuickItem* parent)
65/*!
66 \qmlproperty string UbuntuShape::radius
67
68 The size of the corners among: "small" (default) and "medium".
69*/
70
71/*!
72 \qmlproperty color UbuntuShape::color
73
74 The top color of the gradient used to fill the shape. Setting only this
75 one is enough to set the overall color the shape.
76*/
77
78/*!
79 \qmlproperty color UbuntuShape::gradientColor
80
81 The bottom color of the gradient used for the overlay blending of the
82 color that fills the shape. It is optional to set this one as setting
83 \l color is enough to set the overall color of the shape.
84*/
85
86/*!
87 \qmlproperty string UbuntuShape::borderSource
88
89 This property defines the look of the shape borders. The supported strings
90 are \c "radius_idle.sci" providing an idle button style and
91 "radius_pressed.sci" providing a pressed button style. Any other strings
92 (like the empty one "") disables styling. Default value is \c
93 "radius_idle.sci".
94
95 \note We plan to expose that feature through styling properties.
96*/
97
98/*!
99 \qmlproperty Image UbuntuShape::image
100
101 The image used to fill the shape.
102*/
103
104// Retrieves the size of an array at compile time.
105#define ARRAY_SIZE(a) \
106 ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
107
108// Threshold in grid unit defining the texture quality to be used.
109const float lowHighTextureThreshold = 11.0f;
110
111// Map of windows and associated textures.
112QHash<QOpenGLContext*, ShapeItem::TextureHandles> ShapeItem::textures_;
113
114static const char* const shapeVertexShader =
115 "uniform lowp mat4 matrix; \n"
116 "attribute lowp vec4 positionAttrib; \n"
117 "attribute lowp vec2 shapeCoordAttrib; \n"
118 "attribute lowp vec2 imageCoordAttrib; \n"
119 "varying lowp vec2 shapeCoord; \n"
120 "varying lowp vec2 imageCoord; \n"
121 "void main() \n"
122 "{ \n"
123 " shapeCoord = shapeCoordAttrib; \n"
124 " imageCoord = imageCoordAttrib; \n"
125 " gl_Position = matrix * positionAttrib; \n"
126 "}";
127
128static const char* const shapeTexturedFragmentShader =
129 "uniform lowp float opacity; \n"
130 "uniform sampler2D shapeTexture; \n"
131 "uniform sampler2D imageTexture; \n"
132 "varying lowp vec2 shapeCoord; \n"
133 "varying lowp vec2 imageCoord; \n"
134 "void main() \n"
135 "{ \n"
136 " lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord); \n"
137 " lowp vec4 color = texture2D(imageTexture, imageCoord) * vec4(shapeData.b); \n"
138 " lowp vec4 blend = shapeData.gggr + vec4(1.0 - shapeData.r) * color; \n"
139 " gl_FragColor = blend * vec4(opacity); \n"
140 "}";
141
142static const char* const shapeColoredFragmentShader =
143 "uniform lowp float opacity; \n"
144 "uniform sampler2D shapeTexture; \n"
145 "uniform lowp vec4 color; \n"
146 "uniform lowp vec4 gradientColor; \n"
147 "varying lowp vec2 shapeCoord; \n"
148 "varying lowp vec2 imageCoord; \n"
149 "void main(void) \n"
150 "{ \n"
151 " lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord); \n"
152 " lowp vec4 result = mix(color, gradientColor, imageCoord.t) * vec4(shapeData.b); \n"
153 " lowp vec4 blend = shapeData.gggr + vec4(1.0 - shapeData.r) * result; \n"
154 " gl_FragColor = blend * vec4(opacity); \n"
155 "}";
156
157static const unsigned short shapeMeshIndices[] __attribute__((aligned(16))) = {
158 0, 4, 1, 5, 2, 6, 3, 7, // Triangles 1 to 6.
159 7, 4, // Degenerate triangles.
160 4, 8, 5, 9, 6, 10, 7, 11, // Triangles 7 to 12.
161 11, 8, // Degenerate triangles.
162 8, 12, 9, 13, 10, 14, 11, 15 // Triangles 13 to 18
163};
164
165static const struct {
166 const unsigned short* const indices;
167 int indexCount; // Number of indices.
168 int vertexCount; // Number of vertices.
169 int attributeCount; // Number of attributes.
170 int stride; // Offset in bytes from one vertex to the other.
171 int positionCount; // Number of components per position.
172 int positionType; // OpenGL type of the position components.
173 int shapeCoordCount; // Number of components per shape texture coordinate.
174 int shapeCoordType; // OpenGL type of the shape texture coordinate components.
175 int imageCoordCount; // Number of components per image texture coordinate.
176 int imageCoordType; // OpenGL type of the image texture coordinate components.
177 int indexType; // OpenGL type of the indices.
178} shapeMesh = {
179 shapeMeshIndices, ARRAY_SIZE(shapeMeshIndices),
180 16, 3, sizeof(ShapeNode::Vertex), 2, GL_FLOAT, 2, GL_FLOAT, 2, GL_FLOAT, GL_UNSIGNED_SHORT
181};
182
183static const QSGGeometry::AttributeSet& getAttributes()
184{
185 static QSGGeometry::Attribute data[] = {
186 QSGGeometry::Attribute::create(0, shapeMesh.positionCount, shapeMesh.positionType, true),
187 QSGGeometry::Attribute::create(1, shapeMesh.shapeCoordCount, shapeMesh.shapeCoordType),
188 QSGGeometry::Attribute::create(2, shapeMesh.imageCoordCount, shapeMesh.imageCoordType)
189 };
190 static QSGGeometry::AttributeSet attributes = {
191 shapeMesh.attributeCount, shapeMesh.stride, data
192 };
193 return attributes;
194}
195
196// Gets the size in bytes of an OpenGL type in the range [GL_BYTE, GL_DOUBLE].
197static int sizeOfType(GLenum type)
198{
199 static int sizes[] = {
200 sizeof(char), sizeof(unsigned char), sizeof(short), sizeof(unsigned short), sizeof(int),
201 sizeof(unsigned int), sizeof(float), 2, 3, 4, sizeof(double)
202 };
203 Q_ASSERT(type >= 0x1400 && type <= 0x140a);
204 return sizes[type - 0x1400];
205}
206
207// --- QtQuick item ---
208
209ShapeItem::ShapeItem(QQuickItem* parent)
210 : QQuickItem(parent)245 : QQuickItem(parent)
211 , provider_(NULL)246 , m_source(NULL)
212 , color_(0.0, 0.0, 0.0, 0.0)247 , m_sourceTextureProvider(NULL)
213 , gradientColor_(0.0, 0.0, 0.0, 0.0)248 , m_backgroundColor(qRgba(0, 0, 0, 0))
214 , gradientColorSet_(false)249 , m_secondaryBackgroundColor(qRgba(0, 0, 0, 0))
215 , radiusString_("small")250 , m_sourceScale(1.0f, 1.0f)
216 , radius_(ShapeItem::SmallRadius)251 , m_sourceTranslation(0.0f, 0.0f)
217 , border_(ShapeItem::IdleBorder)252 , m_sourceTransform(1.0f, 1.0f, 0.0f, 0.0f)
218 , image_(NULL)253 , m_radius(SmallRadius)
219 , stretched_(true)254 , m_border(IdleBorder)
220 , hAlignment_(ShapeItem::AlignHCenter)255 , m_imageHorizontalAlignment(AlignHCenter)
221 , vAlignment_(ShapeItem::AlignVCenter)256 , m_imageVerticalAlignment(AlignVCenter)
222 , gridUnit_(UCUnits::instance().gridUnit())257 , m_backgroundMode(SolidColor)
223 , geometry_()258 , m_sourceHorizontalAlignment(AlignHCenter)
259 , m_sourceVerticalAlignment(AlignVCenter)
260 , m_sourceFillMode(Stretch)
261 , m_sourceHorizontalWrapMode(Transparent)
262 , m_sourceVerticalWrapMode(Transparent)
263 , m_sourceOpacity(255)
264 , m_flags(Stretched)
224{265{
225 setFlag(ItemHasContents);266 setFlag(ItemHasContents);
226 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,267 QObject::connect(&UCUnits::instance(), SIGNAL(gridUnitChanged()), this,
227 SLOT(gridUnitChanged()));268 SLOT(_q_gridUnitChanged()));
228 setImplicitWidth(8 * gridUnit_);269 const float gridUnit = UCUnits::instance().gridUnit();
229 setImplicitHeight(8 * gridUnit_);270 setImplicitWidth(implicitGridUnitWidth * gridUnit);
271 setImplicitHeight(implicitGridUnitHeight * gridUnit);
230 update();272 update();
231}273}
232274
233void ShapeItem::setColor(const QColor& color)275/*! \qmlproperty string UbuntuShape::radius
234{276
235 if (color_ != color) {277 This property defines the corner radius. Two fixed values are supported: \c "small" and \c
236 color_ = color;278 "medium". The default value is \c "small".
237 // gradientColor has the same value as color unless it was manually set279*/
238 if (!gradientColorSet_) {280void UCUbuntuShape::setRadius(const QString& radius)
239 gradientColor_ = color;281{
240 Q_EMIT gradientColorChanged();282 const Radius newRadius = (radius == "medium") ? MediumRadius : SmallRadius;
241 }283 if (m_radius != newRadius) {
242 update();284 m_radius = newRadius;
243 Q_EMIT colorChanged();
244 }
245}
246
247void ShapeItem::setGradientColor(const QColor& gradientColor)
248{
249 gradientColorSet_ = true;
250 if (gradientColor_ != gradientColor) {
251 gradientColor_ = gradientColor;
252 update();
253 Q_EMIT gradientColorChanged();
254 }
255}
256
257void ShapeItem::setRadius(const QString& radius)
258{
259 if (radiusString_ != radius) {
260 radiusString_ = radius;
261 radius_ = (radius == "medium") ? ShapeItem::MediumRadius : ShapeItem::SmallRadius;
262 update();285 update();
263 Q_EMIT radiusChanged();286 Q_EMIT radiusChanged();
264 }287 }
265}288}
266289
267void ShapeItem::setBorderSource(const QString& borderSource)290/*! \qmlproperty string UbuntuShape::borderSource
291
292 This property defines the look of the shape borders. The supported strings are \c
293 "radius_idle.sci" providing an idle button style and \c "radius_pressed.sci" providing a pressed
294 button style. Any other strings (like the empty one \c "") disables styling. The default value
295 is \c "radius_idle.sci".
296*/
297void UCUbuntuShape::setBorderSource(const QString& borderSource)
268{298{
269 if (borderSource_ != borderSource) {299 Border border;
270 if (borderSource.endsWith(QString("radius_idle.sci")))300 if (borderSource.endsWith(QString("radius_idle.sci"))) {
271 border_ = ShapeItem::IdleBorder;301 border = IdleBorder;
272 else if (borderSource.endsWith(QString("radius_pressed.sci")))302 } else if (borderSource.endsWith(QString("radius_pressed.sci"))) {
273 border_ = ShapeItem::PressedBorder;303 border = PressedBorder;
274 else304 } else {
275 border_ = ShapeItem::RawBorder;305 border = RawBorder;
276 borderSource_ = borderSource;306 }
307 if (m_border != border) {
308 m_border = border;
277 update();309 update();
278 Q_EMIT borderSourceChanged();310 Q_EMIT borderSourceChanged();
279 }311 }
280}312}
281313
282void ShapeItem::setImage(const QVariant& image)314// Deprecation layer.
283{315void UCUbuntuShape::dropImageSupport()
284 QQuickItem* newImage = qobject_cast<QQuickItem*>(qvariant_cast<QObject*>(image));316{
285 if (image_ != newImage) {317 if (!(m_flags & SourceApiSet)) {
286 image_ = newImage;318 m_flags |= SourceApiSet;
287319 if (m_source) {
288 // update values of properties that depend on properties of the image320 QObject::disconnect(m_source);
289 QObject::disconnect(image_);321 m_source = NULL;
290 if (newImage != NULL) {322 update();
291 updateFromImageProperties(newImage);323 Q_EMIT imageChanged();
292 connectToImageProperties(newImage);324 }
293 }325 }
294326}
295 if (image_ && !image_->parentItem()) {327
296 // Inlined images need a parent and must not be visible.328/*! \qmlproperty variant UbuntuShape::source
297 image_->setParentItem(this);329 \since Ubuntu.Components 1.2
298 image_->setVisible(false);330
299 }331 This property sets the source provider of a texture rendered in the UbuntuShape. Supported types
300 update();332 are \c Image, \c AnimatedImage (to render a GIF image for instance) and \c ShaderEffectSource
301 Q_EMIT imageChanged();333 (to embed a UI previously rendered with QML). It is blended over the background color. The
302 }334 default value is \c null.
303}335
304336 It can be set either with an inlined \c Image:
305void ShapeItem::updateFromImageProperties(QQuickItem* image)337
338 \qml
339 Item {
340 UbuntuShape {
341 source: Image { source: "ubuntu.png" }
342 }
343 }
344 \endqml
345
346 or with an \c Image \c id:
347
348 \qml
349 Item {
350 Image {
351 id: img
352 visible: false
353 source: "ubuntu.png"
354 }
355 UbuntuShape {
356 source: img
357 }
358 }
359 \endqml
360
361 Note that in this case, the \c Image is stored in the scene tree as any other items. So setting
362 it as not visible might be needed.
363
364 The \l{https://en.wikipedia.org/wiki/Texture_filtering}{sampling filter} is set through the
365 given Item's \c smooth property. Set it to \c false for nearest-neighbor filtering or to \c true
366 for bilinear filtering.
367
368 The fill modes and alignments set on the \c Image and \c AnimatedImage are not monitored, use
369 the appropriate UbuntuShape properties instead (\l sourceFillMode, \l sourceHorizontalAlignment
370 and \l sourceVerticalAlignment).
371
372 \note Setting this disables support for the deprecated \l image property.
373*/
374void UCUbuntuShape::setSource(const QVariant& source)
375{
376 dropImageSupport();
377
378 QQuickItem* newSource = qobject_cast<QQuickItem*>(qvariant_cast<QObject*>(source));
379 if (m_source != newSource) {
380 if (newSource) {
381 if (!newSource->parentItem()) {
382 // Inlined images need a parent and must not be visible.
383 newSource->setParentItem(this);
384 newSource->setVisible(false);
385 }
386 m_flags |= DirtySourceTransform;
387 }
388 m_source = newSource;
389 update();
390 Q_EMIT sourceChanged();
391 }
392}
393
394/*! \qmlproperty real UbuntuShape::sourceOpacity
395 \since Ubuntu.Components 1.2
396
397 This property holds the opacity of the \l source texture. Opacity is specified as a number
398 between 0.0 (fully transparent) and 1.0 (fully opaque). The default value is 1.0.
399
400 \note Setting this disables support for the deprecated \l image property.
401*/
402void UCUbuntuShape::setSourceOpacity(float sourceOpacity)
403{
404 dropImageSupport();
405
406 const quint8 sourceOpacityPacked =
407 qMax(0.0f, qMin(1.0f, sourceOpacity)) * static_cast<float>(0xff);
408 if (m_sourceOpacity != sourceOpacityPacked) {
409 m_sourceOpacity = sourceOpacityPacked;
410 update();
411 Q_EMIT sourceOpacityChanged();
412 }
413}
414
415/*! \qmlproperty enumeration UbuntuShape::sourceFillMode
416 \since Ubuntu.Components 1.2
417
418 This properties defines how the \l source texture fills the UbuntuShape. The modes are the same
419 as the ones used by \c Image, minus the tiling which is exposed through wrapping properties (\l
420 sourceHorizontalWrapMode and \l sourceVerticalWrapMode). The default value is \c
421 UbuntuShape.Stretch.
422
423 \note Setting this disables support for the deprecated \l image property.
424
425 \list
426 \li \b UbuntuShape.Stretch - the source is scaled non-uniformly to fit
427 \li \b UbuntuShape.PreserveAspectFit - the source is scaled uniformly to fit without cropping
428 \li \b UbuntuShape.PreserveAspectCrop - the source is scaled uniformly to fit with cropping
429 \li \b UbuntuShape.Pad - the source is not scaled
430 \endlist
431*/
432void UCUbuntuShape::setSourceFillMode(UCUbuntuShape::FillMode sourceFillMode)
433{
434 dropImageSupport();
435
436 if (m_sourceFillMode != sourceFillMode) {
437 m_sourceFillMode = sourceFillMode;
438 m_flags |= DirtySourceTransform;
439 update();
440 Q_EMIT sourceFillModeChanged();
441 }
442}
443
444/*! \qmlproperty enumeration UbuntuShape::sourceHorizontalWrapMode
445 \qmlproperty enumeration UbuntuShape::sourceVerticalWrapMode
446 \since Ubuntu.Components 1.2
447
448 When the \l sourceFillMode is set to \c UbuntuShape.Pad or \c UbuntuShape.PreserveAspectFit or
449 when the \l sourceScale and/or \l sourceTranslation properties are changed, the \l source
450 texture might not cover the entire UbuntuShape area. This property defines how the source
451 texture wraps outside of its content area. The default value is \c UbuntuShape.Transparent.
452
453 Ensure \c UbuntuShape.Repeat is used only when necessary (in case of an \c Image or \c
454 AnimatedImage source) as it requires the underlying texture to be extracted from its atlas. That
455 slows down the rendering speed since it prevents the QtQuick renderer to batch the UbuntuShape
456 with others.
457
458 \note Some OpenGL ES 2 implementations do not support \c UbuntuShape.Repeat with
459 non-power-of-two sized source textures.
460 \note Setting this disables support for the deprecated \l image property.
461
462 \list
463 \li \b UbuntuShape.Transparent - the source is clamped to transparent
464 \li \b UbuntuShape.Repeat - the source is repeated indefinitely (not supported yet)
465 \endlist
466*/
467void UCUbuntuShape::setSourceHorizontalWrapMode(UCUbuntuShape::WrapMode sourceHorizontalWrapMode)
468{
469 dropImageSupport();
470
471 if (m_sourceHorizontalWrapMode != sourceHorizontalWrapMode) {
472 m_sourceHorizontalWrapMode = sourceHorizontalWrapMode;
473 update();
474 Q_EMIT sourceHorizontalWrapModeChanged();
475 }
476}
477
478void UCUbuntuShape::setSourceVerticalWrapMode(UCUbuntuShape::WrapMode sourceVerticalWrapMode)
479{
480 dropImageSupport();
481
482 if (m_sourceVerticalWrapMode != sourceVerticalWrapMode) {
483 m_sourceVerticalWrapMode = sourceVerticalWrapMode;
484 update();
485 Q_EMIT sourceVerticalWrapModeChanged();
486 }
487}
488
489/*! \qmlproperty enumeration UbuntuShape::sourceHorizontalAlignment
490 \since Ubuntu.Components 1.2
491
492 This property defines how the \l source texture is horizontally aligned inside the UbuntuShape
493 area. The default value is \c UbuntuShape.AlignLeft.
494
495 \note Setting this disables support for the deprecated \l image property.
496
497 \list
498 \li \b UbuntuShape.AlignLeft - the source is aligned to the left
499 \li \b UbuntuShape.AlignHCenter - the source is aligned to the horizontal center
500 \li \b UbuntuShape.AlignRight - the source is aligned to the right
501 \endlist
502*/
503void UCUbuntuShape::setSourceHorizontalAlignment(
504 UCUbuntuShape::HAlignment sourceHorizontalAlignment)
505{
506 dropImageSupport();
507
508 if (m_sourceHorizontalAlignment != sourceHorizontalAlignment) {
509 m_sourceHorizontalAlignment = sourceHorizontalAlignment;
510 m_flags |= DirtySourceTransform;
511 update();
512 Q_EMIT sourceHorizontalAlignmentChanged();
513 }
514}
515
516/*! \qmlproperty enumeration UbuntuShape::sourceVerticalAlignment
517 \since Ubuntu.Components 1.2
518
519 This property defines how the \l source texture is vertically aligned inside the UbuntuShape
520 area. The default value is \c UbuntuShape.AlignTop.
521
522 \note Setting this disables support for the deprecated \l image property.
523
524 \list
525 \li \b UbuntuShape.AlignTop - the source is aligned to the top
526 \li \b UbuntuShape.AlignVCenter - the source is aligned to the vertical center
527 \li \b UbuntuShape.AlignBottom - the source is aligned to the bottom
528 \endlist
529*/
530void UCUbuntuShape::setSourceVerticalAlignment(UCUbuntuShape::VAlignment sourceVerticalAlignment)
531{
532 dropImageSupport();
533
534 if (m_sourceVerticalAlignment != sourceVerticalAlignment) {
535 m_sourceVerticalAlignment = sourceVerticalAlignment;
536 m_flags |= DirtySourceTransform;
537 update();
538 Q_EMIT sourceVerticalAlignmentChanged();
539 }
540}
541
542/*! \qmlproperty vector2d UbuntuShape::sourceTranslation
543 \since Ubuntu.Components 1.2
544
545 This property defines the two-component vector in normalized item coordinates used to translate
546 the \l source texture. The default value is \c {Qt.vector2d(0.0,0.0)}.
547
548 That can be used to put the \l source texture at a precise position, to create infinite
549 scrolling animations (using the \c UbuntuShape.Repeat wrap mode), etc.
550
551 \note Setting this disables support for the deprecated \l image property.
552*/
553void UCUbuntuShape::setSourceTranslation(const QVector2D& sourceTranslation)
554{
555 dropImageSupport();
556
557 if (m_sourceTranslation != sourceTranslation) {
558 m_sourceTranslation = sourceTranslation;
559 m_flags |= DirtySourceTransform;
560 update();
561 Q_EMIT sourceTranslationChanged();
562 }
563}
564
565/*! \qmlproperty vector2d UbuntuShape::sourceScale
566 \since Ubuntu.Components 1.2
567
568 This property defines the two-component vector used to scale the \l source texture. The texture
569 is scaled at the alignment point defined by \l sourceHorizontalAlignment and \l
570 sourceVerticalAlignment. The default value is \c {Qt.vector2d(1.0,1.0)}.
571
572 That can be used to change the size of the \l source texture, to flip it horizontally and/or
573 vertically, to achieve pulsing animations, etc.
574
575 Here is a code sample showing how to apply an horizontal flip:
576
577 \qml
578 UbuntuShape {
579 source: Image { source: "ubuntu.png" }
580 sourceScale: Qt.vector2d(-1.0, 1.0)
581 }
582 \endqml
583
584 \note Setting this disables support for the deprecated \l image property.
585*/
586void UCUbuntuShape::setSourceScale(const QVector2D& sourceScale)
587{
588 dropImageSupport();
589
590 if (m_sourceScale != sourceScale) {
591 m_sourceScale = sourceScale;
592 m_flags |= DirtySourceTransform;
593 update();
594 Q_EMIT sourceScaleChanged();
595 }
596}
597
598// Deprecation layer.
599void UCUbuntuShape::dropColorSupport()
600{
601 if (!(m_flags & BackgroundApiSet)) {
602 m_flags |= BackgroundApiSet;
603 if (m_backgroundColor) {
604 m_backgroundColor = qRgba(0, 0, 0, 0);
605 Q_EMIT colorChanged();
606 }
607 if (m_secondaryBackgroundColor) {
608 m_secondaryBackgroundColor = qRgba(0, 0, 0, 0);
609 Q_EMIT gradientColorChanged();
610 }
611 }
612}
613
614/*! \qmlproperty color UbuntuShape::backgroundColor
615 \since Ubuntu.Components 1.2
616
617 This property defines the background color. The default value is transparent black.
618
619 \note Setting this disables support for the deprecated \l color and \l gradientColor properties.
620*/
621void UCUbuntuShape::setBackgroundColor(const QColor& backgroundColor)
622{
623 dropColorSupport();
624
625 const QRgb backgroundColorRgb = qRgba(
626 backgroundColor.red(), backgroundColor.green(), backgroundColor.blue(),
627 backgroundColor.alpha());
628 if (m_backgroundColor != backgroundColorRgb) {
629 m_backgroundColor = backgroundColorRgb;
630 update();
631 Q_EMIT backgroundColorChanged();
632 }
633}
634
635/*! \qmlproperty color UbuntuShape::secondaryBackgroundColor
636 \since Ubuntu.Components 1.2
637
638 This property defines the secondary background color. It is used when \l backgroundMode is set
639 to \c UbuntuShape.VerticalGradient. The default value is transparent black.
640
641 \note Setting this disables support for the deprecated \l color and \l gradientColor properties.
642*/
643void UCUbuntuShape::setSecondaryBackgroundColor(const QColor& secondaryBackgroundColor)
644{
645 dropColorSupport();
646
647 const QRgb secondaryBackgroundColorRgb = qRgba(
648 secondaryBackgroundColor.red(), secondaryBackgroundColor.green(),
649 secondaryBackgroundColor.blue(), secondaryBackgroundColor.alpha());
650 if (m_secondaryBackgroundColor != secondaryBackgroundColorRgb) {
651 m_secondaryBackgroundColor = secondaryBackgroundColorRgb;
652 update();
653 Q_EMIT secondaryBackgroundColorChanged();
654 }
655}
656
657/*! \qmlproperty enumeration UbuntuShape::backgroundMode
658 \since Ubuntu.Components 1.2
659
660 This property defines the background rendering mode. The default value is \c
661 UbuntuShape.SolidColor.
662
663 \note Setting this disables support for the deprecated \l color and \l gradientColor properties.
664
665 \list
666 \li \b UbuntuShape.SolidColor - the color is \l backgroundColor
667 \li \b UbuntuShape.VerticalGradient - the color is a vertical gradient from \l backgroundColor
668 to \l secondaryBackgroundColor.
669 \endlist
670*/
671void UCUbuntuShape::setBackgroundMode(BackgroundMode backgroundMode)
672{
673 dropColorSupport();
674
675 if (m_backgroundMode != backgroundMode) {
676 m_backgroundMode = backgroundMode;
677 update();
678 Q_EMIT backgroundModeChanged();
679 }
680}
681
682/*! \qmlproperty color UbuntuShape::color
683 \deprecated
684
685 This property defines the color used to fill the UbuntuShape when there is no \l image set. If
686 \l gradientColor is set, this property defines the top color of the gradient. The default value
687 is transparent black.
688
689 \note Use \l backgroundColor, \l secondaryBackgroundColor and \l backgroundMode instead.
690*/
691void UCUbuntuShape::setColor(const QColor& color)
692{
693 if (!(m_flags & BackgroundApiSet)) {
694 const QRgb colorRgb = qRgba(color.red(), color.green(), color.blue(), color.alpha());
695 if (m_backgroundColor != colorRgb) {
696 m_backgroundColor = colorRgb;
697 // gradientColor has the same value as color unless it was explicitly set.
698 if (!(m_flags & GradientColorSet)) {
699 m_secondaryBackgroundColor = colorRgb;
700 Q_EMIT gradientColorChanged();
701 }
702 update();
703 Q_EMIT colorChanged();
704 }
705 }
706}
707
708/*! \qmlproperty color UbuntuShape::gradientColor
709 \deprecated
710
711 This property defines the bottom color used for the vertical gradient filling the UbuntuShape
712 when there is no \l image set. As long as this property is not set, a single color (defined
713 by \l color) is used to fill the UbuntuShape.
714
715 \note Use \l backgroundColor, \l secondaryBackgroundColor and \l backgroundMode instead.
716*/
717void UCUbuntuShape::setGradientColor(const QColor& gradientColor)
718{
719 if (!(m_flags & BackgroundApiSet)) {
720 m_flags |= GradientColorSet;
721 const QRgb gradientColorRgb = qRgba(
722 gradientColor.red(), gradientColor.green(), gradientColor.blue(),
723 gradientColor.alpha());
724 if (m_secondaryBackgroundColor != gradientColorRgb) {
725 m_secondaryBackgroundColor = gradientColorRgb;
726 update();
727 Q_EMIT gradientColorChanged();
728 }
729 }
730}
731
732/*! \qmlproperty Image UbuntuShape::image
733 \deprecated
734
735 This property holds the \c Image or \c ShaderEffectSource rendered in the UbuntuShape. In case
736 of an \c Image, it watches for fillMode (\c Image.Stretch and\c Image.PreserveAspectCrop), \c
737 horizontalAlignment and \c verticalAlignment property changes. The default value is \c null.
738
739 \note Use \l source instead.
740*/
741void UCUbuntuShape::setImage(const QVariant& image)
742{
743 if (!(m_flags & SourceApiSet)) {
744 QQuickItem* newImage = qobject_cast<QQuickItem*>(qvariant_cast<QObject*>(image));
745 if (m_source != newImage) {
746 if (newImage) {
747 // Watch for property changes.
748 updateFromImageProperties(newImage);
749 connectToImageProperties(newImage);
750 if (!newImage->parentItem()) {
751 // Inlined images need a parent and must not be visible.
752 newImage->setParentItem(this);
753 newImage->setVisible(false);
754 }
755 m_flags |= DirtySourceTransform;
756 }
757 QObject::disconnect(m_source);
758 update();
759 m_source = newImage;
760 Q_EMIT imageChanged();
761 }
762 }
763}
764
765// Deprecation layer. Even though "stretched" is exposed as a QML property, it's only been used when
766// there was a QML UbuntuShape proxy. This is why we don't provide doc for it. We'll still have to
767// maintain it for a while for compatibility reasons.
768void UCUbuntuShape::setStretched(bool stretched)
769{
770 if (!(m_flags & SourceApiSet)) {
771 if (!!(m_flags & Stretched) != stretched) {
772 if (stretched) {
773 m_flags |= Stretched;
774 } else {
775 m_flags &= ~Stretched;
776 }
777 m_flags |= DirtySourceTransform;
778 update();
779 Q_EMIT stretchedChanged();
780 }
781 }
782}
783
784// Deprecation layer. Same comment as setStretched().
785void UCUbuntuShape::setHorizontalAlignment(HAlignment horizontalAlignment)
786{
787 if (!(m_flags & SourceApiSet)) {
788 if (m_imageHorizontalAlignment != horizontalAlignment) {
789 m_imageHorizontalAlignment = horizontalAlignment;
790 m_flags |= DirtySourceTransform;
791 update();
792 Q_EMIT horizontalAlignmentChanged();
793 }
794 }
795}
796
797// Deprecation layer. Same comment as setStretched().
798void UCUbuntuShape::setVerticalAlignment(VAlignment verticalAlignment)
799{
800 if (!(m_flags & SourceApiSet)) {
801 if (m_imageVerticalAlignment != verticalAlignment) {
802 m_imageVerticalAlignment = verticalAlignment;
803 m_flags |= DirtySourceTransform;
804 update();
805 Q_EMIT verticalAlignmentChanged();
806 }
807 }
808}
809
810// Deprecation layer.
811void UCUbuntuShape::updateFromImageProperties(QQuickItem* image)
306{812{
307 int alignment;813 int alignment;
308814
309 // ShapeItem::stretched depends on image::fillMode815 // UbuntuShape::stretched depends on Image::fillMode.
310 QQuickImage::FillMode fillMode = (QQuickImage::FillMode)image->property("fillMode").toInt();816 QQuickImage::FillMode fillMode = (QQuickImage::FillMode)image->property("fillMode").toInt();
311 if (fillMode == QQuickImage::PreserveAspectCrop) {817 if (fillMode == QQuickImage::PreserveAspectCrop) {
312 setStretched(false);818 setStretched(false);
@@ -314,640 +820,516 @@
314 setStretched(true);820 setStretched(true);
315 }821 }
316822
317 // ShapeItem::horizontalAlignment depends on image::horizontalAlignment823 // UbuntuShape::horizontalAlignment depends on Image::horizontalAlignment.
318 int imageHorizontalAlignment = image->property("horizontalAlignment").toInt();824 int imageHorizontalAlignment = image->property("horizontalAlignment").toInt();
319 if (imageHorizontalAlignment == Qt::AlignLeft) {825 if (imageHorizontalAlignment == Qt::AlignLeft) {
320 alignment = ShapeItem::AlignLeft;826 alignment = AlignLeft;
321 } else if (imageHorizontalAlignment == Qt::AlignRight) {827 } else if (imageHorizontalAlignment == Qt::AlignRight) {
322 alignment = ShapeItem::AlignRight;828 alignment = AlignRight;
323 } else {829 } else {
324 alignment = ShapeItem::AlignHCenter;830 alignment = AlignHCenter;
325 }831 }
326 setHorizontalAlignment(static_cast<ShapeItem::HAlignment>(alignment));832 setHorizontalAlignment(static_cast<HAlignment>(alignment));
327833
328 // ShapeItem::verticalAlignment depends on image::verticalAlignment834 // UbuntuShape::verticalAlignment depends on Image::verticalAlignment.
329 int imageVerticalAlignment = image->property("verticalAlignment").toInt();835 int imageVerticalAlignment = image->property("verticalAlignment").toInt();
330 if (imageVerticalAlignment == Qt::AlignTop) {836 if (imageVerticalAlignment == Qt::AlignTop) {
331 alignment = ShapeItem::AlignTop;837 alignment = AlignTop;
332 } else if (imageVerticalAlignment == Qt::AlignBottom) {838 } else if (imageVerticalAlignment == Qt::AlignBottom) {
333 alignment = ShapeItem::AlignBottom;839 alignment = AlignBottom;
334 } else {840 } else {
335 alignment = ShapeItem::AlignVCenter;841 alignment = AlignVCenter;
336 }842 }
337 setVerticalAlignment(static_cast<ShapeItem::VAlignment>(alignment));843 setVerticalAlignment(static_cast<UCUbuntuShape::VAlignment>(alignment));
338}844}
339845
340void ShapeItem::connectToPropertyChange(QObject* sender, const char* property,846// Deprecation layer.
341 QObject* receiver, const char* slot)847void UCUbuntuShape::connectToPropertyChange(
848 QObject* sender, const char* property, QObject* receiver, const char* slot)
342{849{
343 int propertyIndex = sender->metaObject()->indexOfProperty(property);850 int propertyIndex = sender->metaObject()->indexOfProperty(property);
344 if (propertyIndex != -1) {851 if (propertyIndex != -1) {
345 QMetaMethod changeSignal = sender->metaObject()->property(propertyIndex).notifySignal();852 QMetaMethod changeSignal = sender->metaObject()->property(propertyIndex).notifySignal();
346
347 int slotIndex = receiver->metaObject()->indexOfSlot(slot);853 int slotIndex = receiver->metaObject()->indexOfSlot(slot);
348 QMetaMethod updateSlot = receiver->metaObject()->method(slotIndex);854 QMetaMethod updateSlot = receiver->metaObject()->method(slotIndex);
349
350 QObject::connect(sender, changeSignal, receiver, updateSlot);855 QObject::connect(sender, changeSignal, receiver, updateSlot);
351 }856 }
352}857}
353858
354void ShapeItem::connectToImageProperties(QQuickItem* image)859// Deprecation layer.
860void UCUbuntuShape::connectToImageProperties(QQuickItem* image)
355{861{
356 connectToPropertyChange(image, "fillMode", this, "onImagePropertiesChanged()");862 connectToPropertyChange(image, "fillMode", this, "_q_imagePropertiesChanged()");
357 connectToPropertyChange(image, "horizontalAlignment", this, "onImagePropertiesChanged()");863 connectToPropertyChange(image, "horizontalAlignment", this, "_q_imagePropertiesChanged()");
358 connectToPropertyChange(image, "verticalAlignment", this, "onImagePropertiesChanged()");864 connectToPropertyChange(image, "verticalAlignment", this, "_q_imagePropertiesChanged()");
359}865}
360866
361void ShapeItem::onImagePropertiesChanged()867// Deprecation layer.
868void UCUbuntuShape::_q_imagePropertiesChanged()
362{869{
363 QQuickItem* image = qobject_cast<QQuickItem*>(sender());870 QQuickItem* image = qobject_cast<QQuickItem*>(sender());
364 updateFromImageProperties(image);871 updateFromImageProperties(image);
365}872}
366873
367void ShapeItem::setStretched(bool stretched)874void UCUbuntuShape::_q_openglContextDestroyed()
368{
369 if (stretched_ != stretched) {
370 stretched_ = stretched;
371 update();
372 Q_EMIT stretchedChanged();
373 }
374}
375
376void ShapeItem::setHorizontalAlignment(HAlignment hAlignment)
377{
378 if (hAlignment_ != hAlignment) {
379 hAlignment_ = hAlignment;
380 update();
381 Q_EMIT horizontalAlignmentChanged();
382 }
383}
384
385void ShapeItem::setVerticalAlignment(VAlignment vAlignment)
386{
387 if (vAlignment_ != vAlignment) {
388 vAlignment_ = vAlignment;
389 update();
390 Q_EMIT verticalAlignmentChanged();
391 }
392}
393
394void ShapeItem::gridUnitChanged()
395{
396 gridUnit_ = UCUnits::instance().gridUnit();
397 setImplicitWidth(8 * gridUnit_);
398 setImplicitHeight(8 * gridUnit_);
399 update();
400}
401
402void ShapeItem::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
403{
404 geometry_ = newGeometry;
405 QQuickItem::geometryChanged(newGeometry, oldGeometry);
406 update();
407}
408
409void ShapeItem::onOpenglContextDestroyed()
410{875{
411 QOpenGLContext* context = qobject_cast<QOpenGLContext*>(sender());876 QOpenGLContext* context = qobject_cast<QOpenGLContext*>(sender());
412 if (Q_UNLIKELY(!context)) return;877 if (context) {
413878 QHash<QOpenGLContext*, ShapeTextures>::iterator it = shapeTexturesHash.find(context);
414 QHash<QOpenGLContext*, TextureHandles>::iterator it =879 if (it != shapeTexturesHash.end()) {
415 textures_.find(context);880 ShapeTextures &shapeTextures = it.value();
416 if (it != textures_.end()) {881 delete shapeTextures.high;
417 TextureHandles &textureHandles = it.value();882 delete shapeTextures.low;
418 delete textureHandles.high;883 shapeTexturesHash.erase(it);
419 delete textureHandles.low;884 }
420 textures_.erase(it);
421 }885 }
422}886}
423887
424void ShapeItem::providerDestroyed(QObject* object)888void UCUbuntuShape::_q_gridUnitChanged()
889{
890 const float gridUnit = UCUnits::instance().gridUnit();
891 setImplicitWidth(implicitGridUnitWidth * gridUnit);
892 setImplicitHeight(implicitGridUnitHeight * gridUnit);
893 update();
894}
895
896void UCUbuntuShape::_q_providerDestroyed(QObject* object)
425{897{
426 Q_UNUSED(object);898 Q_UNUSED(object);
427 provider_ = NULL;899 m_sourceTextureProvider = NULL;
428}900}
429901
430QSGNode* ShapeItem::updatePaintNode(QSGNode* old_node, UpdatePaintNodeData* data)902void UCUbuntuShape::_q_textureChanged()
903{
904 m_flags |= DirtySourceTransform;
905 update();
906}
907
908void UCUbuntuShape::geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry)
909{
910 QQuickItem::geometryChanged(newGeometry, oldGeometry);
911 m_flags |= DirtySourceTransform;
912}
913
914// Gets the nearest boundary to coord in the texel grid of the given size.
915static Q_DECL_CONSTEXPR float roundTextureCoord(float coord, float size)
916{
917 return roundf(coord * size) / size;
918}
919
920void UCUbuntuShape::updateSourceTransform(
921 float itemWidth, float itemHeight, FillMode fillMode, HAlignment horizontalAlignment,
922 VAlignment verticalAlignment, const QSize& textureSize)
923{
924 float fillSx, fillSy;
925 if (fillMode == PreserveAspectFit) {
926 const float textureRatio = static_cast<float>(textureSize.width()) / textureSize.height();
927 const float itemRatio = itemWidth / itemHeight;
928 fillSx = (textureRatio < itemRatio) ? (itemRatio / textureRatio) : 1.0f;
929 fillSy = (textureRatio < itemRatio) ? 1.0f : (textureRatio / itemRatio);
930 } else if (fillMode == PreserveAspectCrop) {
931 const float textureRatio = static_cast<float>(textureSize.width()) / textureSize.height();
932 const float itemRatio = itemWidth / itemHeight;
933 fillSx = (textureRatio < itemRatio) ? 1.0f : (itemRatio / textureRatio);
934 fillSy = (textureRatio < itemRatio) ? (textureRatio / itemRatio) : 1.0f;
935 } else if (fillMode == Pad) {
936 fillSx = itemWidth / textureSize.width();
937 fillSy = itemHeight / textureSize.height();
938 } else {
939 fillSx = 1.0f;
940 fillSy = 1.0f;
941 }
942
943 const float sourceSxInv = 1.0f / m_sourceScale.x();
944 const float sourceSyInv = 1.0f / m_sourceScale.y();
945 // Multiplied by fillS* so that the translation unit is in normalized item coordinates.
946 const float sourceTx = (m_sourceTranslation.x() * sourceSxInv) * fillSx;
947 const float sourceTy = (m_sourceTranslation.y() * sourceSyInv) * fillSy;
948 const float sx = fillSx * sourceSxInv;
949 const float sy = fillSy * sourceSyInv;
950 const float factorTable[3] = { 0.0f, 0.5f, 1.0f };
951 const float hFactor = factorTable[static_cast<int>(horizontalAlignment)];
952 const float vFactor = factorTable[static_cast<int>(verticalAlignment)];
953 const float tx = hFactor * (1.0f - sx) - sourceTx;
954 const float ty = vFactor * (1.0f - sy) - sourceTy;
955
956 // Rounding is important to get padded texture perfectly mapped to the pixel grid. It shouldn't
957 // be necessary when there's a scaling but we make it consistent by applying the scale factors
958 // to the texture size, so that there's no ugly position jumps with big scaling values.
959 m_sourceTransform = QVector4D(
960 sx, sy, roundTextureCoord(tx, textureSize.width() * m_sourceScale.x()),
961 roundTextureCoord(ty, textureSize.height() * m_sourceScale.y()));
962}
963
964// Pack a premultiplied 32-bit ABGR integer.
965static quint32 packColor(quint32 a, quint32 b, quint32 g, quint32 r)
966{
967 const quint32 pb = ((b * a) + 0xff) >> 8;
968 const quint32 pg = ((g * a) + 0xff) >> 8;
969 const quint32 pr = ((r * a) + 0xff) >> 8;
970 return (a << 24) | ((pb & 0xff) << 16) | ((pg & 0xff) << 8) | (pr & 0xff);
971}
972
973// Lerp c1 and c2 with t in the range [0, 255]. Return value is a premultiplied 32-bit ABGR integer.
974static quint32 lerpColor(quint32 t, QRgb c1, QRgb c2)
975{
976 const quint32 a = qAlpha(c1) + ((t * (qAlpha(c2) - qAlpha(c1)) + 0xff) >> 8);
977 const quint32 b = qBlue(c1) + ((t * (qBlue(c2) - qBlue(c1)) + 0xff) >> 8);
978 const quint32 g = qGreen(c1) + ((t * (qGreen(c2) - qGreen(c1)) + 0xff) >> 8);
979 const quint32 r = qRed(c1) + ((t * (qRed(c2) - qRed(c1)) + 0xff) >> 8);
980 return packColor(a, b, g, r);
981}
982
983QSGNode* UCUbuntuShape::updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data)
431{984{
432 Q_UNUSED(data);985 Q_UNUSED(data);
433986
434 // FIXME(loicm) Shape textures are stored in the read-only data section of the plugin as it987 const QSizeF itemSize(width(), height());
435 // avoids having to deal with paths for now. It should preferably be loaded from a file.988 if (itemSize.isEmpty()) {
436989 delete oldNode;
437 // OpenGL allocates textures per context, so we store textures reused by990 return NULL;
438 // all shape instances per context as well991 }
992
993 QSGNode* node = oldNode ? oldNode : createSceneGraphNode();
994 Q_ASSERT(node);
995
996 // OpenGL allocates textures per context, so we store textures reused by all shape instances
997 // per context as well.
439 QOpenGLContext* openglContext = window() ? window()->openglContext() : NULL;998 QOpenGLContext* openglContext = window() ? window()->openglContext() : NULL;
440 if (Q_UNLIKELY(!openglContext)) {999 Q_ASSERT(openglContext);
441 qCritical() << "Window has no GL context!";1000 ShapeTextures &shapeTextures = shapeTexturesHash[openglContext];
442 delete old_node;1001 if (!shapeTextures.high) {
443 return NULL;1002 shapeTextures.high = window()->createTextureFromImage(
444 }
445
446 TextureHandles &textureHandles = textures_[openglContext];
447 // If the hash table didn't contain an entry for the current context, the
448 // line above has just caused the creation of a default-constructed value.
449 if (!textureHandles.high) {
450 textureHandles.high = window()->createTextureFromImage(
451 QImage(shapeTextureHigh.data, shapeTextureHigh.width, shapeTextureHigh.height,1003 QImage(shapeTextureHigh.data, shapeTextureHigh.width, shapeTextureHigh.height,
452 QImage::Format_ARGB32_Premultiplied));1004 QImage::Format_ARGB32_Premultiplied));
453 textureHandles.low = window()->createTextureFromImage(1005 shapeTextures.low = window()->createTextureFromImage(
454 QImage(shapeTextureLow.data, shapeTextureLow.width, shapeTextureLow.height,1006 QImage(shapeTextureLow.data, shapeTextureLow.width, shapeTextureLow.height,
455 QImage::Format_ARGB32_Premultiplied));1007 QImage::Format_ARGB32_Premultiplied));
456 QObject::connect(openglContext, SIGNAL(aboutToBeDestroyed()),1008 QObject::connect(openglContext, SIGNAL(aboutToBeDestroyed()),
457 this, SLOT(onOpenglContextDestroyed()),1009 this, SLOT(_q_openglContextDestroyed()), Qt::DirectConnection);
458 Qt::DirectConnection);1010 }
459 }1011
4601012 // Get the texture info and update the source transform if needed.
461 // Update the node whenever the source item's texture changes.1013 QSGTextureProvider* provider = m_source ? m_source->textureProvider() : NULL;
462 QSGTextureProvider* provider = image_ ? image_->textureProvider() : NULL;1014 QSGTexture* sourceTexture = provider ? provider->texture() : NULL;
463 if (provider != provider_) {1015 QRectF sourceTextureRect(0.0f, 0.0f, 1.0f, 1.0f);
464 if (provider_) {1016 if (sourceTexture) {
465 QObject::disconnect(provider_, SIGNAL(textureChanged()), this, SLOT(update()));1017 if (m_sourceHorizontalWrapMode == Transparent && m_sourceVerticalWrapMode == Transparent) {
466 QObject::disconnect(provider_, SIGNAL(destroyed()), this, SLOT(providerDestroyed()));1018 sourceTextureRect = sourceTexture->normalizedTextureSubRect();
1019 }
1020 if (m_flags & DirtySourceTransform) {
1021 if (m_flags & SourceApiSet) {
1022 updateSourceTransform(itemSize.width(), itemSize.height(), m_sourceFillMode,
1023 m_sourceHorizontalAlignment, m_sourceVerticalAlignment,
1024 sourceTexture->textureSize());
1025 } else {
1026 FillMode imageFillMode = (m_flags & Stretched) ? Stretch : PreserveAspectCrop;
1027 updateSourceTransform(itemSize.width(), itemSize.height(), imageFillMode,
1028 m_imageHorizontalAlignment, m_imageVerticalAlignment,
1029 sourceTexture->textureSize());
1030 }
1031 m_flags &= ~DirtySourceTransform;
1032 }
1033 }
1034
1035 // Update the shape item whenever the source item's texture changes.
1036 if (provider != m_sourceTextureProvider) {
1037 if (m_sourceTextureProvider) {
1038 QObject::disconnect(m_sourceTextureProvider, SIGNAL(textureChanged()),
1039 this, SLOT(_q_textureChanged()));
1040 QObject::disconnect(m_sourceTextureProvider, SIGNAL(destroyed()),
1041 this, SLOT(_q_providerDestroyed()));
467 }1042 }
468 if (provider) {1043 if (provider) {
469 QObject::connect(provider, SIGNAL(textureChanged()), this, SLOT(update()));1044 QObject::connect(provider, SIGNAL(textureChanged()), this, SLOT(_q_textureChanged()));
470 QObject::connect(provider, SIGNAL(destroyed()), this, SLOT(providerDestroyed()));1045 QObject::connect(provider, SIGNAL(destroyed()), this, SLOT(_q_providerDestroyed()));
471 }1046 }
472 provider_ = provider;1047 m_sourceTextureProvider = provider;
473 }1048 }
4741049
475 ShapeNode* node = static_cast<ShapeNode*>(old_node);1050 const float gridUnit = UCUnits::instance().gridUnit();
476 if (!node) {1051 ShapeTextureData* shapeTextureData;
477 node = new ShapeNode(this);1052 QSGTexture* shapeTexture;
478 }1053 if (gridUnit > lowHighTextureThreshold) {
4791054 shapeTextureData = &shapeTextureHigh;
480 ShapeTexturedMaterial* texturedMaterial = node->texturedMaterial();1055 shapeTexture = shapeTextures.high;
481 ShapeColoredMaterial* coloredMaterial = node->coloredMaterial();
482 TextureData* textureData;
483 QSGTexture* textureHandle;
484 if (gridUnit_ > lowHighTextureThreshold) {
485 textureData = &shapeTextureHigh;
486 textureHandle = textureHandles.high;
487 } else {1056 } else {
488 textureData = &shapeTextureLow;1057 shapeTextureData = &shapeTextureLow;
489 textureHandle = textureHandles.low;1058 shapeTexture = shapeTextures.low;
490 }1059 }
4911060
492 // Set the shape texture to be used by the materials depending on current grid unit. The radius1061 // Set the shape texture to be used by the materials depending on current grid unit. The radius
493 // is set considering the current grid unit and the texture raster grid unit. When the item size1062 // is set considering the current grid unit and the texture raster grid unit. When the item size
494 // is less than 2 radii, the radius is scaled down anyhow.1063 // is less than 2 radii, the radius is scaled down.
495 float radius = (radius_ == ShapeItem::SmallRadius) ?1064 QSGTexture::Filtering shapeTextureFiltering;
496 textureData->smallRadius : textureData->mediumRadius;1065 float radius = (m_radius == SmallRadius) ?
497 const float scaleFactor = gridUnit_ / textureData->gridUnit;1066 shapeTextureData->smallRadius : shapeTextureData->mediumRadius;
498 radius *= scaleFactor;1067 const float scaleFactor = gridUnit / shapeTextureData->gridUnit;
499 int scaledDown = 0;1068 shapeTextureFiltering = QSGTexture::Nearest;
500 if (scaleFactor != 1.0f) {1069 if (scaleFactor != 1.0f) {
501 scaledDown |= 1;1070 radius *= scaleFactor;
1071 shapeTextureFiltering = QSGTexture::Linear;
502 }1072 }
503 const float halfMinWidthHeight = qMin(geometry_.width(), geometry_.height()) * 0.5f;1073 const float halfMinWidthHeight = qMin(itemSize.width(), itemSize.height()) * 0.5f;
504 if (radius > halfMinWidthHeight) {1074 if (radius > halfMinWidthHeight) {
505 radius = halfMinWidthHeight;1075 radius = halfMinWidthHeight;
506 scaledDown |= 1;1076 shapeTextureFiltering = QSGTexture::Linear;
507 }1077 }
508 coloredMaterial->setShapeTexture(textureHandle, !!scaledDown);1078
509 texturedMaterial->setShapeTexture(textureHandle, !!scaledDown);1079 updateMaterial(node, shapeTexture, shapeTextureFiltering, sourceTexture);
5101080
511 // Update the other material properties.1081 // Select the right shape texture coordinates.
512 coloredMaterial->setColor(color_);1082 int index = (m_border == RawBorder) ? 0 : (m_border == IdleBorder) ? 1 : 2;
513 coloredMaterial->setGradientColor(gradientColor_);1083 if (m_radius == SmallRadius) {
514 texturedMaterial->setImage(image_);
515
516 // Update node vertices and type.
517 int index = (border_ == ShapeItem::RawBorder) ?
518 0 : (border_ == ShapeItem::IdleBorder) ? 1 : 2;
519 if (radius_ == ShapeItem::SmallRadius)
520 index += 3;1084 index += 3;
521 node->setVertices(geometry_, radius, image_, stretched_, hAlignment_, vAlignment_,1085 }
522 textureData->coordinate[index]);1086
523 const QSGTexture* texture = provider ? provider->texture() : NULL;1087 // Get the affine transformation for the source texture coordinates.
524 node->setMaterialType(texture ? ShapeNode::TexturedMaterial : ShapeNode::ColoredMaterial);1088 const QVector4D sourceCoordTransform(
1089 m_sourceTransform.x() * sourceTextureRect.width(),
1090 m_sourceTransform.y() * sourceTextureRect.height(),
1091 m_sourceTransform.z() * sourceTextureRect.width() + sourceTextureRect.x(),
1092 m_sourceTransform.w() * sourceTextureRect.height() + sourceTextureRect.y());
1093
1094 // Get the affine transformation for the source mask coordinates, pixels lying inside the mask
1095 // (values in the range [-1, 1]) will be textured in the fragment shader. In case of a repeat
1096 // wrap mode, the transformation is made so that the mask takes the whole area.
1097 const QVector4D sourceMaskTransform(
1098 m_sourceHorizontalWrapMode == Transparent ? m_sourceTransform.x() * 2.0f : 2.0f,
1099 m_sourceVerticalWrapMode == Transparent ? m_sourceTransform.y() * 2.0f : 2.0f,
1100 m_sourceHorizontalWrapMode == Transparent ? m_sourceTransform.z() * 2.0f - 1.0f : -1.0f,
1101 m_sourceVerticalWrapMode == Transparent ? m_sourceTransform.w() * 2.0f - 1.0f : -1.0f);
1102
1103 // Select and pack the lerp'd and premultiplied background colors.
1104 QRgb color[2];
1105 if (m_flags & BackgroundApiSet) {
1106 color[0] = m_backgroundColor;
1107 color[1] = (m_backgroundMode == SolidColor) ?
1108 m_backgroundColor : m_secondaryBackgroundColor;
1109 } else {
1110 if (!sourceTexture) {
1111 color[0] = m_backgroundColor;
1112 // For API compatibility reasons, m_secondaryBackgroundColor is set to m_backgroundColor
1113 // as long as setGradientColor() isn't called, so we can safely use it here.
1114 color[1] = m_secondaryBackgroundColor;
1115 } else {
1116 // The deprecated image API was created such that whenever an image is set, the
1117 // background color is transparent.
1118 color[0] = qRgba(0, 0, 0, 0);
1119 color[1] = qRgba(0, 0, 0, 0);
1120 }
1121 }
1122 const quint32 radiusHeight = static_cast<quint32>((radius / itemSize.height()) * 255.0f);
1123 const quint32 backgroundColor[4] = {
1124 packColor(qAlpha(color[0]), qBlue(color[0]), qGreen(color[0]), qRed(color[0])),
1125 lerpColor(radiusHeight, color[0], color[1]),
1126 lerpColor(255 - radiusHeight, color[0], color[1]),
1127 packColor(qAlpha(color[1]), qBlue(color[1]), qGreen(color[1]), qRed(color[1]))
1128 };
1129
1130 updateGeometry(
1131 node, itemSize.width(), itemSize.height(), radius, shapeTextureData->coordinate[index],
1132 sourceCoordTransform, sourceMaskTransform, backgroundColor);
5251133
526 return node;1134 return node;
527}1135}
5281136
529// --- Scene graph geometry node ---1137QSGNode* UCUbuntuShape::createSceneGraphNode() const
530
531ShapeNode::ShapeNode(ShapeItem* item)
532 : QSGGeometryNode()
533 , item_(item)
534 , geometry_(getAttributes(), shapeMesh.vertexCount, shapeMesh.indexCount, shapeMesh.indexType)
535 , texturedMaterial_()
536 , coloredMaterial_()
537 , currentMaterial_(ShapeNode::ColoredMaterial)
538{1138{
539 memcpy(geometry_.indexData(), shapeMesh.indices,1139 return new ShapeNode;
540 shapeMesh.indexCount * sizeOfType(shapeMesh.indexType));
541 geometry_.setDrawingMode(GL_TRIANGLE_STRIP);
542 geometry_.setIndexDataPattern(QSGGeometry::StaticPattern);
543 geometry_.setVertexDataPattern(QSGGeometry::AlwaysUploadPattern);
544 setGeometry(&geometry_);
545 setMaterial(&coloredMaterial_);
546 setFlag(UsePreprocess, false);
547}1140}
5481141
549void ShapeNode::setVertices(const QRectF& geometry, float radius, QQuickItem* image, bool stretched,1142void UCUbuntuShape::updateMaterial(
550 ShapeItem::HAlignment hAlignment, ShapeItem::VAlignment vAlignment,1143 QSGNode* node, QSGTexture* shapeTexture, QSGTexture::Filtering shapeTextureFiltering,
551 float shapeCoordinate[][2])1144 QSGTexture* sourceTexture)
552{1145{
553 ShapeNode::Vertex* vertices = reinterpret_cast<ShapeNode::Vertex*>(geometry_.vertexData());1146 ShapeNode* shapeNode = static_cast<ShapeNode*>(node);
554 const QSGTextureProvider* provider = image ? image->textureProvider() : NULL;1147 ShapeMaterial::Data* materialData = shapeNode->material()->data();
555 const QSGTexture* texture = provider ? provider->texture() : NULL;1148 quint8 flags = 0;
556 const float width = geometry.width();
557 const float height = geometry.height();
558 float topCoordinate;
559 float bottomCoordinate;
560 float leftCoordinate;
561 float rightCoordinate;
562 float radiusCoordinateWidth;
563 float radiusCoordinateHeight;
5641149
565 // FIXME(loicm) With a NxM image, a preserve aspect crop fill mode and a width1150 materialData->shapeTexture = shapeTexture;
566 // component size of N (or a height component size of M), changing the the1151 if (sourceTexture && m_sourceOpacity) {
567 // height (or width) breaks the 1:1 texel/pixel mapping for odd values.1152 materialData->sourceTextureProvider = m_sourceTextureProvider;
568 if (!stretched && texture) {1153 materialData->sourceOpacity = m_sourceOpacity;
569 // Preserve source image aspect ratio cropping areas exceeding destination rectangle.1154 if (m_sourceHorizontalWrapMode == Repeat) {
570 const float factors[3] = { 0.0f, 0.5f, 1.0f };1155 flags |= ShapeMaterial::Data::HorizontallyRepeated;
571 const QSize srcSize = texture->textureSize();1156 }
572 const float srcRatio = static_cast<float>(srcSize.width()) / srcSize.height();1157 if (m_sourceVerticalWrapMode == Repeat) {
573 const float dstRatio = static_cast<float>(width) / height;1158 flags |= ShapeMaterial::Data::VerticallyRepeated;
574 if (dstRatio <= srcRatio) {1159 }
575 const float inCoordinateSize = dstRatio / srcRatio;1160 flags |= ShapeMaterial::Data::Textured;
576 const float outCoordinateSize = 1.0f - inCoordinateSize;
577 topCoordinate = 0.0f;
578 bottomCoordinate = 1.0f;
579 leftCoordinate = outCoordinateSize * factors[hAlignment];
580 rightCoordinate = 1.0f - (outCoordinateSize * (1.0f - factors[hAlignment]));
581 radiusCoordinateHeight = radius / height;
582 radiusCoordinateWidth = (radius / width) * inCoordinateSize;
583 } else {
584 const float inCoordinateSize = srcRatio / dstRatio;
585 const float outCoordinateSize = 1.0f - inCoordinateSize;
586 topCoordinate = outCoordinateSize * factors[vAlignment];
587 bottomCoordinate = 1.0f - (outCoordinateSize * (1.0f - factors[vAlignment]));
588 leftCoordinate = 0.0f;
589 rightCoordinate = 1.0f;
590 radiusCoordinateHeight = (radius / height) * inCoordinateSize;
591 radiusCoordinateWidth = radius / width;
592 }
593 } else {1161 } else {
594 // Don't preserve source image aspect ratio stretching it in destination rectangle.1162 materialData->sourceTextureProvider = NULL;
595 topCoordinate = 0.0f;1163 materialData->sourceOpacity = 0;
596 bottomCoordinate = 1.0f;1164 }
597 leftCoordinate = 0.0f;1165 materialData->shapeTextureFiltering = shapeTextureFiltering;
598 rightCoordinate = 1.0f;1166 materialData->flags = flags;
599 radiusCoordinateHeight = radius / height;1167}
600 radiusCoordinateWidth = radius / width;1168
601 }1169void UCUbuntuShape::updateGeometry(
6021170 QSGNode* node, float width, float height, float radius, const float shapeCoordinate[][2],
603 // Scale and translate coordinates of textures packed in an atlas.1171 const QVector4D& sourceCoordTransform, const QVector4D& sourceMaskTransform,
604 if (texture && texture->isAtlasTexture()) {1172 const quint32 backgroundColor[4])
605 const QRectF srcSubRect = texture->normalizedTextureSubRect();1173{
606 topCoordinate = topCoordinate * srcSubRect.height() + srcSubRect.y();1174 ShapeNode* shapeNode = static_cast<ShapeNode*>(node);
607 bottomCoordinate = bottomCoordinate * srcSubRect.height() + srcSubRect.y();1175 ShapeNode::Vertex* v = reinterpret_cast<ShapeNode::Vertex*>(
608 leftCoordinate = leftCoordinate * srcSubRect.width() + srcSubRect.x();1176 shapeNode->geometry()->vertexData());
609 rightCoordinate = rightCoordinate * srcSubRect.width() + srcSubRect.x();1177
610 radiusCoordinateHeight = radiusCoordinateHeight * srcSubRect.height();1178 // Convert radius to normalized coordinates.
611 radiusCoordinateWidth = radiusCoordinateWidth * srcSubRect.width();1179 const float rw = radius / width;
612 }1180 const float rh = radius / height;
6131181
614 // Set top row of 4 vertices.1182 // Set top row of 4 vertices.
615 vertices[0].position[0] = 0.0f;1183 v[0].position[0] = 0.0f;
616 vertices[0].position[1] = 0.0f;1184 v[0].position[1] = 0.0f;
617 vertices[0].shapeCoordinate[0] = shapeCoordinate[0][0];1185 v[0].shapeCoordinate[0] = shapeCoordinate[0][0];
618 vertices[0].shapeCoordinate[1] = shapeCoordinate[0][1];1186 v[0].shapeCoordinate[1] = shapeCoordinate[0][1];
619 vertices[0].imageCoordinate[0] = leftCoordinate;1187 v[0].sourceCoordinate[0] = sourceCoordTransform.z();
620 vertices[0].imageCoordinate[1] = topCoordinate;1188 v[0].sourceCoordinate[1] = sourceCoordTransform.w();
621 vertices[1].position[0] = radius;1189 v[0].sourceCoordinate[2] = sourceMaskTransform.z();
622 vertices[1].position[1] = 0.0f;1190 v[0].sourceCoordinate[3] = sourceMaskTransform.w();
623 vertices[1].shapeCoordinate[0] = shapeCoordinate[1][0];1191 v[0].backgroundColor = backgroundColor[0];
624 vertices[1].shapeCoordinate[1] = shapeCoordinate[1][1];1192 v[1].position[0] = radius;
625 vertices[1].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;1193 v[1].position[1] = 0.0f;
626 vertices[1].imageCoordinate[1] = topCoordinate;1194 v[1].shapeCoordinate[0] = shapeCoordinate[1][0];
627 vertices[2].position[0] = width - radius;1195 v[1].shapeCoordinate[1] = shapeCoordinate[1][1];
628 vertices[2].position[1] = 0.0f;1196 v[1].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
629 vertices[2].shapeCoordinate[0] = shapeCoordinate[2][0];1197 v[1].sourceCoordinate[1] = sourceCoordTransform.w();
630 vertices[2].shapeCoordinate[1] = shapeCoordinate[2][1];1198 v[1].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
631 vertices[2].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;1199 v[1].sourceCoordinate[3] = sourceMaskTransform.w();
632 vertices[2].imageCoordinate[1] = topCoordinate;1200 v[1].backgroundColor = backgroundColor[0];
633 vertices[3].position[0] = width;1201 v[2].position[0] = width - radius;
634 vertices[3].position[1] = 0.0f;1202 v[2].position[1] = 0.0f;
635 vertices[3].shapeCoordinate[0] = shapeCoordinate[3][0];1203 v[2].shapeCoordinate[0] = shapeCoordinate[2][0];
636 vertices[3].shapeCoordinate[1] = shapeCoordinate[3][1];1204 v[2].shapeCoordinate[1] = shapeCoordinate[2][1];
637 vertices[3].imageCoordinate[0] = rightCoordinate;1205 v[2].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
638 vertices[3].imageCoordinate[1] = topCoordinate;1206 v[2].sourceCoordinate[1] = sourceCoordTransform.w();
1207 v[2].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
1208 v[2].sourceCoordinate[3] = sourceMaskTransform.w();
1209 v[2].backgroundColor = backgroundColor[0];
1210 v[3].position[0] = width;
1211 v[3].position[1] = 0.0f;
1212 v[3].shapeCoordinate[0] = shapeCoordinate[3][0];
1213 v[3].shapeCoordinate[1] = shapeCoordinate[3][1];
1214 v[3].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
1215 v[3].sourceCoordinate[1] = sourceCoordTransform.w();
1216 v[3].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
1217 v[3].sourceCoordinate[3] = sourceMaskTransform.w();
1218 v[3].backgroundColor = backgroundColor[0];
6391219
640 // Set middle-top row of 4 vertices.1220 // Set middle-top row of 4 vertices.
641 vertices[4].position[0] = 0.0f;1221 v[4].position[0] = 0.0f;
642 vertices[4].position[1] = radius;1222 v[4].position[1] = radius;
643 vertices[4].shapeCoordinate[0] = shapeCoordinate[4][0];1223 v[4].shapeCoordinate[0] = shapeCoordinate[4][0];
644 vertices[4].shapeCoordinate[1] = shapeCoordinate[4][1];1224 v[4].shapeCoordinate[1] = shapeCoordinate[4][1];
645 vertices[4].imageCoordinate[0] = leftCoordinate;1225 v[4].sourceCoordinate[0] = sourceCoordTransform.z();
646 vertices[4].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;1226 v[4].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
647 vertices[5].position[0] = radius;1227 v[4].sourceCoordinate[2] = sourceMaskTransform.z();
648 vertices[5].position[1] = radius;1228 v[4].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
649 vertices[5].shapeCoordinate[0] = shapeCoordinate[5][0];1229 v[4].backgroundColor = backgroundColor[1];
650 vertices[5].shapeCoordinate[1] = shapeCoordinate[5][1];1230 v[5].position[0] = radius;
651 vertices[5].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;1231 v[5].position[1] = radius;
652 vertices[5].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;1232 v[5].shapeCoordinate[0] = shapeCoordinate[5][0];
653 vertices[6].position[0] = width - radius;1233 v[5].shapeCoordinate[1] = shapeCoordinate[5][1];
654 vertices[6].position[1] = radius;1234 v[5].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
655 vertices[6].shapeCoordinate[0] = shapeCoordinate[6][0];1235 v[5].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
656 vertices[6].shapeCoordinate[1] = shapeCoordinate[6][1];1236 v[5].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
657 vertices[6].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;1237 v[5].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
658 vertices[6].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;1238 v[5].backgroundColor = backgroundColor[1];
659 vertices[7].position[0] = width;1239 v[6].position[0] = width - radius;
660 vertices[7].position[1] = radius;1240 v[6].position[1] = radius;
661 vertices[7].shapeCoordinate[0] = shapeCoordinate[7][0];1241 v[6].shapeCoordinate[0] = shapeCoordinate[6][0];
662 vertices[7].shapeCoordinate[1] = shapeCoordinate[7][1];1242 v[6].shapeCoordinate[1] = shapeCoordinate[6][1];
663 vertices[7].imageCoordinate[0] = rightCoordinate;1243 v[6].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
664 vertices[7].imageCoordinate[1] = topCoordinate + radiusCoordinateHeight;1244 v[6].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
1245 v[6].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
1246 v[6].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
1247 v[6].backgroundColor = backgroundColor[1];
1248 v[7].position[0] = width;
1249 v[7].position[1] = radius;
1250 v[7].shapeCoordinate[0] = shapeCoordinate[7][0];
1251 v[7].shapeCoordinate[1] = shapeCoordinate[7][1];
1252 v[7].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
1253 v[7].sourceCoordinate[1] = rh * sourceCoordTransform.y() + sourceCoordTransform.w();
1254 v[7].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
1255 v[7].sourceCoordinate[3] = rh * sourceMaskTransform.y() + sourceMaskTransform.w();
1256 v[7].backgroundColor = backgroundColor[1];
6651257
666 // Set middle-bottom row of 4 vertices.1258 // Set middle-bottom row of 4 vertices.
667 vertices[8].position[0] = 0.0f;1259 v[8].position[0] = 0.0f;
668 vertices[8].position[1] = height - radius;1260 v[8].position[1] = height - radius;
669 vertices[8].shapeCoordinate[0] = shapeCoordinate[8][0];1261 v[8].shapeCoordinate[0] = shapeCoordinate[8][0];
670 vertices[8].shapeCoordinate[1] = shapeCoordinate[8][1];1262 v[8].shapeCoordinate[1] = shapeCoordinate[8][1];
671 vertices[8].imageCoordinate[0] = leftCoordinate;1263 v[8].sourceCoordinate[0] = sourceCoordTransform.z();
672 vertices[8].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;1264 v[8].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
673 vertices[9].position[0] = radius;1265 v[8].sourceCoordinate[2] = sourceMaskTransform.z();
674 vertices[9].position[1] = height - radius;1266 v[8].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
675 vertices[9].shapeCoordinate[0] = shapeCoordinate[9][0];1267 v[8].backgroundColor = backgroundColor[2];
676 vertices[9].shapeCoordinate[1] = shapeCoordinate[9][1];1268 v[9].position[0] = radius;
677 vertices[9].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;1269 v[9].position[1] = height - radius;
678 vertices[9].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;1270 v[9].shapeCoordinate[0] = shapeCoordinate[9][0];
679 vertices[10].position[0] = width - radius;1271 v[9].shapeCoordinate[1] = shapeCoordinate[9][1];
680 vertices[10].position[1] = height - radius;1272 v[9].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
681 vertices[10].shapeCoordinate[0] = shapeCoordinate[10][0];1273 v[9].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
682 vertices[10].shapeCoordinate[1] = shapeCoordinate[10][1];1274 v[9].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
683 vertices[10].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;1275 v[9].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
684 vertices[10].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;1276 v[9].backgroundColor = backgroundColor[2];
685 vertices[11].position[0] = width;1277 v[10].position[0] = width - radius;
686 vertices[11].position[1] = height - radius;1278 v[10].position[1] = height - radius;
687 vertices[11].shapeCoordinate[0] = shapeCoordinate[11][0];1279 v[10].shapeCoordinate[0] = shapeCoordinate[10][0];
688 vertices[11].shapeCoordinate[1] = shapeCoordinate[11][1];1280 v[10].shapeCoordinate[1] = shapeCoordinate[10][1];
689 vertices[11].imageCoordinate[0] = rightCoordinate;1281 v[10].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
690 vertices[11].imageCoordinate[1] = bottomCoordinate - radiusCoordinateHeight;1282 v[10].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
1283 v[10].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
1284 v[10].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
1285 v[10].backgroundColor = backgroundColor[2];
1286 v[11].position[0] = width;
1287 v[11].position[1] = height - radius;
1288 v[11].shapeCoordinate[0] = shapeCoordinate[11][0];
1289 v[11].shapeCoordinate[1] = shapeCoordinate[11][1];
1290 v[11].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
1291 v[11].sourceCoordinate[1] = (1.0f - rh) * sourceCoordTransform.y() + sourceCoordTransform.w();
1292 v[11].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
1293 v[11].sourceCoordinate[3] = (1.0f - rh) * sourceMaskTransform.y() + sourceMaskTransform.w();
1294 v[11].backgroundColor = backgroundColor[2];
6911295
692 // Set bottom row of 4 vertices.1296 // Set bottom row of 4 vertices.
693 vertices[12].position[0] = 0.0f;1297 v[12].position[0] = 0.0f;
694 vertices[12].position[1] = height;1298 v[12].position[1] = height;
695 vertices[12].shapeCoordinate[0] = shapeCoordinate[12][0];1299 v[12].shapeCoordinate[0] = shapeCoordinate[12][0];
696 vertices[12].shapeCoordinate[1] = shapeCoordinate[12][1];1300 v[12].shapeCoordinate[1] = shapeCoordinate[12][1];
697 vertices[12].imageCoordinate[0] = leftCoordinate;1301 v[12].sourceCoordinate[0] = sourceCoordTransform.z();
698 vertices[12].imageCoordinate[1] = bottomCoordinate;1302 v[12].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
699 vertices[13].position[0] = radius;1303 v[12].sourceCoordinate[2] = sourceMaskTransform.z();
700 vertices[13].position[1] = height;1304 v[12].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
701 vertices[13].shapeCoordinate[0] = shapeCoordinate[13][0];1305 v[12].backgroundColor = backgroundColor[3];
702 vertices[13].shapeCoordinate[1] = shapeCoordinate[13][1];1306 v[13].position[0] = radius;
703 vertices[13].imageCoordinate[0] = leftCoordinate + radiusCoordinateWidth;1307 v[13].position[1] = height;
704 vertices[13].imageCoordinate[1] = bottomCoordinate;1308 v[13].shapeCoordinate[0] = shapeCoordinate[13][0];
705 vertices[14].position[0] = width - radius;1309 v[13].shapeCoordinate[1] = shapeCoordinate[13][1];
706 vertices[14].position[1] = height;1310 v[13].sourceCoordinate[0] = rw * sourceCoordTransform.x() + sourceCoordTransform.z();
707 vertices[14].shapeCoordinate[0] = shapeCoordinate[14][0];1311 v[13].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
708 vertices[14].shapeCoordinate[1] = shapeCoordinate[14][1];1312 v[13].sourceCoordinate[2] = rw * sourceMaskTransform.x() + sourceMaskTransform.z();
709 vertices[14].imageCoordinate[0] = rightCoordinate - radiusCoordinateWidth;1313 v[13].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
710 vertices[14].imageCoordinate[1] = bottomCoordinate;1314 v[13].backgroundColor = backgroundColor[3];
711 vertices[15].position[0] = width;1315 v[14].position[0] = width - radius;
712 vertices[15].position[1] = height;1316 v[14].position[1] = height;
713 vertices[15].shapeCoordinate[0] = shapeCoordinate[15][0];1317 v[14].shapeCoordinate[0] = shapeCoordinate[14][0];
714 vertices[15].shapeCoordinate[1] = shapeCoordinate[15][1];1318 v[14].shapeCoordinate[1] = shapeCoordinate[14][1];
715 vertices[15].imageCoordinate[0] = rightCoordinate;1319 v[14].sourceCoordinate[0] = (1.0f - rw) * sourceCoordTransform.x() + sourceCoordTransform.z();
716 vertices[15].imageCoordinate[1] = bottomCoordinate;1320 v[14].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
7171321 v[14].sourceCoordinate[2] = (1.0f - rw) * sourceMaskTransform.x() + sourceMaskTransform.z();
718 markDirty(DirtyGeometry);1322 v[14].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
719}1323 v[14].backgroundColor = backgroundColor[3];
7201324 v[15].position[0] = width;
721void ShapeNode::setMaterialType(ShapeNode::MaterialType material)1325 v[15].position[1] = height;
722{1326 v[15].shapeCoordinate[0] = shapeCoordinate[15][0];
723 if (currentMaterial_ != material) {1327 v[15].shapeCoordinate[1] = shapeCoordinate[15][1];
724 if (material == ShapeNode::ColoredMaterial)1328 v[15].sourceCoordinate[0] = sourceCoordTransform.x() + sourceCoordTransform.z();
725 setMaterial(&coloredMaterial_);1329 v[15].sourceCoordinate[1] = sourceCoordTransform.y() + sourceCoordTransform.w();
726 else1330 v[15].sourceCoordinate[2] = sourceMaskTransform.x() + sourceMaskTransform.z();
727 setMaterial(&texturedMaterial_);1331 v[15].sourceCoordinate[3] = sourceMaskTransform.y() + sourceMaskTransform.w();
728 currentMaterial_ = material;1332 v[15].backgroundColor = backgroundColor[3];
729 markDirty(DirtyMaterial);1333
730 }1334 node->markDirty(QSGNode::DirtyGeometry);
731}
732
733// --- Scene graph textured material ---
734
735ShapeTexturedMaterial::ShapeTexturedMaterial()
736 : imageTextureProvider_(NULL)
737 , shapeTexture_(NULL)
738 , filtering_(QSGTexture::Nearest)
739{
740 setFlag(Blending);
741}
742
743QSGMaterialType* ShapeTexturedMaterial::type() const
744{
745 static QSGMaterialType type;
746 return &type;
747}
748
749QSGMaterialShader* ShapeTexturedMaterial::createShader() const
750{
751 return new ShapeTexturedShader;
752}
753
754int ShapeTexturedMaterial::compare(const QSGMaterial* other) const
755{
756 const ShapeTexturedMaterial* otherMaterial = static_cast<const ShapeTexturedMaterial*>(other);
757 const QSGTextureProvider* otherTextureProvider = otherMaterial->imageTextureProvider();
758 const QSGTexture* otherTexture = otherTextureProvider ? otherTextureProvider->texture() : NULL;
759 const int otherTextureId = otherTexture ? otherTexture->textureId() : 0;
760 const QSGTexture* texture = imageTextureProvider_ ? imageTextureProvider_->texture() : NULL;
761 const int textureId = texture ? texture->textureId() : 0;
762 return textureId - otherTextureId;
763}
764
765void ShapeTexturedMaterial::setImage(QQuickItem* image)
766{
767 imageTextureProvider_ = image ? image->textureProvider() : NULL;
768}
769
770QSGTextureProvider* ShapeTexturedMaterial::imageTextureProvider() const
771{
772 return imageTextureProvider_;
773}
774
775void ShapeTexturedMaterial::setShapeTexture(QSGTexture* texture, bool scaledDown)
776{
777 shapeTexture_ = texture;
778 filtering_ = scaledDown ? QSGTexture::Linear : QSGTexture::Nearest;
779}
780
781// -- Scene graph textured material shader ---
782
783const char *ShapeTexturedShader::vertexShader() const
784{
785 return shapeVertexShader;
786}
787
788const char* ShapeTexturedShader::fragmentShader() const
789{
790 return shapeTexturedFragmentShader;
791}
792
793char const* const* ShapeTexturedShader::attributeNames() const
794{
795 static char const* const attributes[] = {
796 "positionAttrib", "shapeCoordAttrib", "imageCoordAttrib", 0
797 };
798 return attributes;
799}
800
801void ShapeTexturedShader::initialize()
802{
803 QSGMaterialShader::initialize();
804 program()->bind();
805 program()->setUniformValue("shapeTexture", 0);
806 program()->setUniformValue("imageTexture", 1);
807 matrixId_ = program()->uniformLocation("matrix");
808 opacityId_ = program()->uniformLocation("opacity");
809 glFuncs_ = QOpenGLContext::currentContext()->functions();
810}
811
812void ShapeTexturedShader::updateState(const RenderState& state, QSGMaterial* newEffect,
813 QSGMaterial* oldEffect)
814{
815 Q_UNUSED(oldEffect);
816 ShapeTexturedMaterial* material = static_cast<ShapeTexturedMaterial*>(newEffect);
817
818 // Bind textures.
819 glFuncs_->glActiveTexture(GL_TEXTURE1);
820 QSGTextureProvider* provider = material->imageTextureProvider();
821 QSGTexture* texture = provider ? provider->texture() : NULL;
822 if (texture)
823 texture->bind();
824 else
825 glBindTexture(GL_TEXTURE_2D, 0);
826 glFuncs_->glActiveTexture(GL_TEXTURE0);
827 QSGTexture* shapeTexture = material->shapeTexture();
828 if (shapeTexture) {
829 shapeTexture->setFiltering(material->filtering());
830 shapeTexture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
831 shapeTexture->setVerticalWrapMode(QSGTexture::ClampToEdge);
832 shapeTexture->bind();
833 } else {
834 glBindTexture(GL_TEXTURE_2D, 0);
835 }
836
837 // Bind uniforms.
838 if (state.isMatrixDirty())
839 program()->setUniformValue(matrixId_, state.combinedMatrix());
840 if (state.isOpacityDirty())
841 program()->setUniformValue(opacityId_, state.opacity());
842}
843
844// --- Scene graph colored material ---
845
846ShapeColoredMaterial::ShapeColoredMaterial()
847 : color_(0.0, 0.0, 0.0, 0.0)
848 , gradientColor_(0.0, 0.0, 0.0, 0.0)
849 , shapeTexture_(NULL)
850 , filtering_(QSGTexture::Nearest)
851{
852 setFlag(Blending);
853}
854
855QSGMaterialType* ShapeColoredMaterial::type() const
856{
857 static QSGMaterialType type;
858 return &type;
859}
860
861QSGMaterialShader* ShapeColoredMaterial::createShader() const
862{
863 return new ShapeColoredShader;
864}
865
866int ShapeColoredMaterial::compare(const QSGMaterial* other) const
867{
868 const ShapeColoredMaterial* otherMaterial = static_cast<const ShapeColoredMaterial*>(other);
869 if ((color_ != otherMaterial->color()) || (gradientColor_ != otherMaterial->gradientColor())) {
870 return -1;
871 } else {
872 return 0;
873 }
874}
875
876void ShapeColoredMaterial::setColor(const QColor& color)
877{
878 // Premultiply color components by alpha.
879 const float alpha = color.alphaF();
880 color_ = QVector4D(color.redF() * alpha, color.greenF() * alpha,
881 color.blueF() * alpha, alpha);
882}
883
884void ShapeColoredMaterial::setGradientColor(const QColor& gradientColor)
885{
886 // Premultiply color components by alpha.
887 const float alpha = gradientColor.alphaF();
888 gradientColor_ = QVector4D(gradientColor.redF() * alpha, gradientColor.greenF() * alpha,
889 gradientColor.blueF() * alpha, alpha);
890}
891
892void ShapeColoredMaterial::setShapeTexture(QSGTexture* texture, bool scaledDown)
893{
894 shapeTexture_ = texture;
895 filtering_ = scaledDown ? QSGTexture::Linear : QSGTexture::Nearest;
896}
897
898// -- Scene graph colored material shader ---
899
900const char *ShapeColoredShader::vertexShader() const
901{
902 return shapeVertexShader;
903}
904
905const char* ShapeColoredShader::fragmentShader() const
906{
907 return shapeColoredFragmentShader;
908}
909
910char const* const* ShapeColoredShader::attributeNames() const
911{
912 static char const* const attributes[] = {
913 "positionAttrib", "shapeCoordAttrib", "imageCoordAttrib", 0
914 };
915 return attributes;
916}
917
918void ShapeColoredShader::initialize()
919{
920 QSGMaterialShader::initialize();
921 program()->bind();
922 program()->setUniformValue("shapeTexture", 0);
923 matrixId_ = program()->uniformLocation("matrix");
924 opacityId_ = program()->uniformLocation("opacity");
925 colorId_ = program()->uniformLocation("color");
926 gradientColorId_ = program()->uniformLocation("gradientColor");
927}
928
929void ShapeColoredShader::updateState(const RenderState& state, QSGMaterial* newEffect,
930 QSGMaterial* oldEffect)
931{
932 Q_UNUSED(oldEffect);
933 ShapeColoredMaterial* material = static_cast<ShapeColoredMaterial*>(newEffect);
934
935 // Bind texture.
936 QSGTexture* shapeTexture = material->shapeTexture();
937 if (shapeTexture) {
938 shapeTexture->setFiltering(material->filtering());
939 shapeTexture->setHorizontalWrapMode(QSGTexture::ClampToEdge);
940 shapeTexture->setVerticalWrapMode(QSGTexture::ClampToEdge);
941 shapeTexture->bind();
942 } else {
943 glBindTexture(GL_TEXTURE_2D, 0);
944 }
945
946 // Bind uniforms.
947 if (state.isMatrixDirty())
948 program()->setUniformValue(matrixId_, state.combinedMatrix());
949 if (state.isOpacityDirty())
950 program()->setUniformValue(opacityId_, state.opacity());
951 program()->setUniformValue(colorId_, material->color());
952 program()->setUniformValue(gradientColorId_, material->gradientColor());
953}1335}
9541336
=== renamed file 'modules/Ubuntu/Components/plugin/shapeitem.h' => 'modules/Ubuntu/Components/plugin/ucubuntushape.h'
--- modules/Ubuntu/Components/plugin/shapeitem.h 2014-09-10 18:04:50 +0000
+++ modules/Ubuntu/Components/plugin/ucubuntushape.h 2015-03-02 15:41:23 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2013-2015 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by5 * it under the terms of the GNU Lesser General Public License as published by
@@ -16,227 +16,314 @@
16 * Author: Loïc Molinari <loic.molinari@canonical.com>16 * Author: Loïc Molinari <loic.molinari@canonical.com>
17 */17 */
1818
19#ifndef UBUNTU_COMPONENTS_SHAPE_H19#ifndef UCUBUNTUSHAPE_H
20#define UBUNTU_COMPONENTS_SHAPE_H20#define UCUBUNTUSHAPE_H
2121
22#include <QtQuick/QQuickItem>22#include <QtQuick/QQuickItem>
23#include <QtQuick/QSGNode>23#include <QtQuick/QSGNode>
24#include <QtQuick/qsgflatcolormaterial.h>
25#include <QtQuick/qsgtexture.h>24#include <QtQuick/qsgtexture.h>
25#include <QtQuick/qsgmaterial.h>
26#include <QtGui/QOpenGLFunctions>26#include <QtGui/QOpenGLFunctions>
2727
28// QtQuick item.28class UCUbuntuShape;
2929
30class ShapeItem : public QQuickItem30// --- Scene graph shader ---
31
32class ShapeShader : public QSGMaterialShader
33{
34public:
35 ShapeShader();
36 virtual char const* const* attributeNames() const;
37 virtual void initialize();
38 virtual void updateState(
39 const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect);
40
41private:
42 QOpenGLFunctions* m_functions;
43 int m_matrixId;
44 int m_opacityId;
45 int m_sourceOpacityId;
46 int m_texturedId;
47};
48
49// --- Scene graph material ---
50
51class ShapeMaterial : public QSGMaterial
52{
53public:
54 struct Data {
55 enum {
56 Textured = (1 << 0),
57 HorizontallyRepeated = (1 << 1),
58 VerticallyRepeated = (1 << 2),
59 Repeated = (HorizontallyRepeated | VerticallyRepeated)
60 };
61 QSGTexture* shapeTexture;
62 QSGTextureProvider* sourceTextureProvider;
63 quint8 sourceOpacity;
64 quint8 shapeTextureFiltering;
65 quint8 flags;
66 };
67
68 ShapeMaterial();
69 virtual QSGMaterialType* type() const;
70 virtual QSGMaterialShader* createShader() const;
71 virtual int compare(const QSGMaterial* other) const;
72 const Data* constData() const { return &m_data; }
73 Data* data() { return &m_data; }
74
75private:
76 Data m_data;
77};
78
79// --- Scene graph node ---
80
81class ShapeNode : public QSGGeometryNode
82{
83public:
84 struct Vertex {
85 float position[2];
86 float shapeCoordinate[2];
87 float sourceCoordinate[4];
88 quint32 backgroundColor;
89 };
90
91 static const int indexCount = 28;
92 static const int indexType = GL_UNSIGNED_SHORT;
93 static const int indexTypeSize = sizeof(unsigned short);
94 static const int vertexCount = 16;
95 static const QSGGeometry::DataPattern indexDataPattern = QSGGeometry::StaticPattern;
96 static const QSGGeometry::DataPattern vertexDataPattern = QSGGeometry::AlwaysUploadPattern;
97 static const GLenum drawingMode = GL_TRIANGLE_STRIP;
98 static const unsigned short* indices();
99 static const QSGGeometry::AttributeSet& attributeSet();
100
101 ShapeNode();
102 ShapeMaterial* material() { return &m_material; }
103 QSGGeometry* geometry() { return &m_geometry; }
104
105private:
106 ShapeMaterial m_material;
107 QSGGeometry m_geometry;
108};
109
110// --- QtQuick item ---
111
112class UCUbuntuShape : public QQuickItem
31{113{
32 Q_OBJECT114 Q_OBJECT
115
116 // Shape properties.
117 Q_PROPERTY(QString radius READ radius WRITE setRadius NOTIFY radiusChanged)
118 Q_PROPERTY(QString borderSource READ borderSource WRITE setBorderSource
119 NOTIFY borderSourceChanged)
120
121 // Source properties.
122 Q_ENUMS(FillMode)
123 Q_ENUMS(WrapMode)
33 Q_ENUMS(HAlignment)124 Q_ENUMS(HAlignment)
34 Q_ENUMS(VAlignment)125 Q_ENUMS(VAlignment)
126 Q_PROPERTY(QVariant source READ source WRITE setSource NOTIFY sourceChanged REVISION 1)
127 Q_PROPERTY(float sourceOpacity READ sourceOpacity WRITE setSourceOpacity
128 NOTIFY sourceOpacityChanged REVISION 1)
129 Q_PROPERTY(FillMode sourceFillMode READ sourceFillMode WRITE setSourceFillMode
130 NOTIFY sourceFillModeChanged REVISION 1)
131 Q_PROPERTY(WrapMode sourceHorizontalWrapMode READ sourceHorizontalWrapMode
132 WRITE setSourceHorizontalWrapMode NOTIFY sourceHorizontalWrapModeChanged REVISION 1)
133 Q_PROPERTY(WrapMode sourceVerticalWrapMode READ sourceVerticalWrapMode
134 WRITE setSourceVerticalWrapMode NOTIFY sourceVerticalWrapModeChanged REVISION 1)
135 Q_PROPERTY(HAlignment sourceHorizontalAlignment READ sourceHorizontalAlignment
136 WRITE setSourceHorizontalAlignment NOTIFY sourceHorizontalAlignmentChanged
137 REVISION 1)
138 Q_PROPERTY(VAlignment sourceVerticalAlignment READ sourceVerticalAlignment
139 WRITE setSourceVerticalAlignment NOTIFY sourceVerticalAlignmentChanged REVISION 1)
140 Q_PROPERTY(QVector2D sourceTranslation READ sourceTranslation WRITE setSourceTranslation
141 NOTIFY sourceTranslationChanged REVISION 1)
142 Q_PROPERTY(QVector2D sourceScale READ sourceScale WRITE setSourceScale
143 NOTIFY sourceScaleChanged REVISION 1)
144
145 // Background properties.
146 Q_ENUMS(BackgroundMode)
147 Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor
148 NOTIFY backgroundColorChanged REVISION 1)
149 Q_PROPERTY(QColor secondaryBackgroundColor READ secondaryBackgroundColor
150 WRITE setSecondaryBackgroundColor NOTIFY secondaryBackgroundColorChanged REVISION 1)
151 Q_PROPERTY(BackgroundMode backgroundMode READ backgroundMode WRITE setBackgroundMode
152 NOTIFY backgroundModeChanged REVISION 1)
153
154 // Deprecated properties.
35 Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)155 Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
36 Q_PROPERTY(QColor gradientColor READ gradientColor WRITE setGradientColor156 Q_PROPERTY(QColor gradientColor READ gradientColor WRITE setGradientColor
37 NOTIFY gradientColorChanged)157 NOTIFY gradientColorChanged)
38 Q_PROPERTY(QString radius READ radius WRITE setRadius NOTIFY radiusChanged)
39 Q_PROPERTY(QVariant image READ image WRITE setImage NOTIFY imageChanged)158 Q_PROPERTY(QVariant image READ image WRITE setImage NOTIFY imageChanged)
40 Q_PROPERTY(bool stretched READ stretched WRITE setStretched NOTIFY stretchedChanged)159 Q_PROPERTY(bool stretched READ stretched WRITE setStretched NOTIFY stretchedChanged)
41 Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment NOTIFY horizontalAlignmentChanged)160 Q_PROPERTY(HAlignment horizontalAlignment READ horizontalAlignment WRITE setHorizontalAlignment
42 Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment NOTIFY verticalAlignmentChanged)161 NOTIFY horizontalAlignmentChanged)
43 Q_PROPERTY(QString borderSource READ borderSource WRITE setBorderSource NOTIFY borderSourceChanged)162 Q_PROPERTY(VAlignment verticalAlignment READ verticalAlignment WRITE setVerticalAlignment
163 NOTIFY verticalAlignmentChanged)
44164
45public:165public:
46 ShapeItem(QQuickItem* parent=0);166 UCUbuntuShape(QQuickItem* parent=0);
47167
48 enum Radius { SmallRadius, MediumRadius };168 enum BackgroundMode { SolidColor = 0, VerticalGradient = 1 };
49 enum Border { RawBorder, IdleBorder, PressedBorder };
50 enum HAlignment { AlignLeft = 0, AlignHCenter = 1, AlignRight = 2 };169 enum HAlignment { AlignLeft = 0, AlignHCenter = 1, AlignRight = 2 };
51 enum VAlignment { AlignTop = 0, AlignVCenter = 1, AlignBottom = 2 };170 enum VAlignment { AlignTop = 0, AlignVCenter = 1, AlignBottom = 2 };
171 enum FillMode { Stretch = 0, PreserveAspectFit = 1, PreserveAspectCrop = 2, Pad = 3 };
172 enum WrapMode { Transparent = 0, Repeat = 1 };
52173
53 QColor color() const { return color_; }174 QString radius() const { return (m_radius == SmallRadius) ? "small" : "medium"; }
54 void setColor(const QColor& color);
55 QColor gradientColor() const { return gradientColor_; }
56 void setGradientColor(const QColor& gradientColor);
57 QString radius() const { return radiusString_; }
58 void setRadius(const QString& radius);175 void setRadius(const QString& radius);
59 QString borderSource() const { return borderSource_; }176 QString borderSource() const {
177 return (m_border == IdleBorder) ? "radius_idle.sci" :
178 ((m_border == PressedBorder) ? "radius_pressed.sci" : ""); }
60 void setBorderSource(const QString& borderSource);179 void setBorderSource(const QString& borderSource);
61 QVariant image() const { return QVariant::fromValue(image_); }180
181 QVariant source() const {
182 return QVariant::fromValue((m_flags & SourceApiSet) ? m_source : NULL); }
183 void setSource(const QVariant& source);
184 float sourceOpacity() const { return m_sourceOpacity / static_cast<float>(0xff); }
185 void setSourceOpacity(float sourceOpacity);
186 FillMode sourceFillMode() const { return m_sourceFillMode; }
187 void setSourceFillMode(FillMode sourceFillMode);
188 WrapMode sourceHorizontalWrapMode() const { return m_sourceHorizontalWrapMode; }
189 void setSourceHorizontalWrapMode(WrapMode sourceHorizontalWrapMode);
190 WrapMode sourceVerticalWrapMode() const { return m_sourceVerticalWrapMode; }
191 void setSourceVerticalWrapMode(WrapMode sourceVerticalWrapMode);
192 HAlignment sourceHorizontalAlignment() const { return m_sourceHorizontalAlignment; }
193 void setSourceHorizontalAlignment(HAlignment sourceHorizontalAlignment);
194 VAlignment sourceVerticalAlignment() const { return m_sourceVerticalAlignment; }
195 void setSourceVerticalAlignment(VAlignment sourceVerticalAlignment);
196 QVector2D sourceTranslation() const { return m_sourceTranslation; }
197 void setSourceTranslation(const QVector2D& sourceTranslation);
198 QVector2D sourceScale() const { return m_sourceScale; }
199 void setSourceScale(const QVector2D& sourceScale);
200 QColor backgroundColor() const {
201 return (m_flags & BackgroundApiSet) ?
202 QColor(qRed(m_backgroundColor), qGreen(m_backgroundColor), qBlue(m_backgroundColor),
203 qAlpha(m_backgroundColor)) :
204 QColor(0, 0, 0, 0); }
205 void setBackgroundColor(const QColor& backgroundColor);
206 QColor secondaryBackgroundColor() const {
207 return (m_flags & BackgroundApiSet) ?
208 QColor(qRed(m_secondaryBackgroundColor), qGreen(m_secondaryBackgroundColor),
209 qBlue(m_secondaryBackgroundColor), qAlpha(m_secondaryBackgroundColor)) :
210 QColor(0, 0, 0, 0); }
211 void setSecondaryBackgroundColor(const QColor& secondaryBackgroundColor);
212 BackgroundMode backgroundMode() const { return m_backgroundMode; }
213 void setBackgroundMode(BackgroundMode backgroundMode);
214
215 QColor color() const {
216 return (m_flags & BackgroundApiSet) ?
217 QColor(0, 0, 0, 0) :
218 QColor(qRed(m_backgroundColor), qGreen(m_backgroundColor), qBlue(m_backgroundColor),
219 qAlpha(m_backgroundColor)); }
220 void setColor(const QColor& color);
221 QColor gradientColor() const {
222 return (m_flags & BackgroundApiSet) ?
223 QColor(0, 0, 0, 0) :
224 QColor(qRed(m_secondaryBackgroundColor), qGreen(m_secondaryBackgroundColor),
225 qBlue(m_secondaryBackgroundColor), qAlpha(m_secondaryBackgroundColor)); }
226 void setGradientColor(const QColor& gradientColor);
227 QVariant image() const {
228 return QVariant::fromValue((m_flags & SourceApiSet) ? NULL : m_source); }
62 void setImage(const QVariant& image);229 void setImage(const QVariant& image);
63 bool stretched() const { return stretched_; }230 bool stretched() const { return !!(m_flags & Stretched); }
64 void setStretched(bool stretched);231 void setStretched(bool stretched);
65 HAlignment horizontalAlignment() const { return hAlignment_; }232 HAlignment horizontalAlignment() const { return m_imageHorizontalAlignment; }
66 void setHorizontalAlignment(HAlignment horizontalAlignment);233 void setHorizontalAlignment(HAlignment horizontalAlignment);
67 VAlignment verticalAlignment() const { return vAlignment_; }234 VAlignment verticalAlignment() const { return m_imageVerticalAlignment; }
68 void setVerticalAlignment(VAlignment verticalAlignment);235 void setVerticalAlignment(VAlignment verticalAlignment);
69 Q_SLOT void gridUnitChanged();
70236
71Q_SIGNALS:237Q_SIGNALS:
238 void radiusChanged();
239 void borderSourceChanged();
240
241 Q_REVISION(1) void sourceChanged();
242 Q_REVISION(1) void sourceOpacityChanged();
243 Q_REVISION(1) void sourceFillModeChanged();
244 Q_REVISION(1) void sourceHorizontalWrapModeChanged();
245 Q_REVISION(1) void sourceVerticalWrapModeChanged();
246 Q_REVISION(1) void sourceHorizontalAlignmentChanged();
247 Q_REVISION(1) void sourceVerticalAlignmentChanged();
248 Q_REVISION(1) void sourceTranslationChanged();
249 Q_REVISION(1) void sourceScaleChanged();
250
251 Q_REVISION(1) void backgroundColorChanged();
252 Q_REVISION(1) void secondaryBackgroundColorChanged();
253 Q_REVISION(1) void backgroundModeChanged();
254
72 void colorChanged();255 void colorChanged();
73 void gradientColorChanged();256 void gradientColorChanged();
74 void radiusChanged();
75 void borderChanged();
76 void imageChanged();257 void imageChanged();
77 void stretchedChanged();258 void stretchedChanged();
78 void horizontalAlignmentChanged();259 void horizontalAlignmentChanged();
79 void verticalAlignmentChanged();260 void verticalAlignmentChanged();
80 void borderSourceChanged();
81261
82protected:262protected:
263 virtual QSGNode* updatePaintNode(QSGNode* oldNode, UpdatePaintNodeData* data);
83 virtual void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry);264 virtual void geometryChanged(const QRectF& newGeometry, const QRectF& oldGeometry);
84 virtual QSGNode* updatePaintNode(QSGNode*, UpdatePaintNodeData*);265
266 // Virtual functions for extended shapes.
267 virtual QSGNode* createSceneGraphNode() const;
268 virtual void updateMaterial(
269 QSGNode* node, QSGTexture* shapeTexture, QSGTexture::Filtering shapeTextureFiltering,
270 QSGTexture* sourceTexture);
271 virtual void updateGeometry(
272 QSGNode* node, float width, float height, float radius, const float shapeCoordinate[][2],
273 const QVector4D& sourceCoordTransform, const QVector4D& sourceMaskTransform,
274 const quint32 backgroundColor[4]);
275
276private Q_SLOTS:
277 void _q_imagePropertiesChanged();
278 void _q_openglContextDestroyed();
279 void _q_gridUnitChanged();
280 void _q_providerDestroyed(QObject* object=0);
281 void _q_textureChanged();
85282
86private:283private:
87 void updateFromImageProperties(QQuickItem* image);284 void updateFromImageProperties(QQuickItem* image);
88 void connectToPropertyChange(QObject* sender, const char* property,285 void connectToPropertyChange(
89 QObject* receiver, const char* slot);286 QObject* sender, const char* property, QObject* receiver, const char* slot);
90 void connectToImageProperties(QQuickItem* image);287 void connectToImageProperties(QQuickItem* image);
91288 void dropColorSupport();
92private Q_SLOTS:289 void dropImageSupport();
93 void onImagePropertiesChanged();290 void updateSourceTransform(
94 void onOpenglContextDestroyed();291 float itemWidth, float itemHeight, FillMode fillMode, HAlignment horizontalAlignment,
95 void providerDestroyed(QObject* object=0);292 VAlignment verticalAlignment, const QSize& textureSize);
96293
97private:294 enum Radius { SmallRadius, MediumRadius };
98 struct TextureHandles {295 enum Border { RawBorder, IdleBorder, PressedBorder };
99 TextureHandles(): high(0), low(0) {}296 enum {
100 QSGTexture* high;297 GradientColorSet = (1 << 0),
101 QSGTexture* low;298 Stretched = (1 << 1),
102 };299 BackgroundApiSet = (1 << 2),
103300 SourceApiSet = (1 << 3),
104 QSGTextureProvider* provider_;301 DirtySourceTransform = (1 << 4)
105 QColor color_;302 };
106 QColor gradientColor_;303
107 bool gradientColorSet_;304 QQuickItem* m_source;
108 QString radiusString_;305 QSGTextureProvider* m_sourceTextureProvider;
109 Radius radius_;306 QRgb m_backgroundColor;
110 QString borderSource_;307 QRgb m_secondaryBackgroundColor;
111 Border border_;308 QVector2D m_sourceScale;
112 QQuickItem* image_;309 QVector2D m_sourceTranslation;
113 bool stretched_;310 QVector4D m_sourceTransform;
114 HAlignment hAlignment_;311 Radius m_radius : 1;
115 VAlignment vAlignment_;312 Border m_border : 2;
116 float gridUnit_;313 HAlignment m_imageHorizontalAlignment : 2;
117 QRectF geometry_;314 VAlignment m_imageVerticalAlignment : 2;
118 static QHash<QOpenGLContext*, TextureHandles> textures_;315 BackgroundMode m_backgroundMode : 1;
119316 HAlignment m_sourceHorizontalAlignment : 2;
120 Q_DISABLE_COPY(ShapeItem)317 VAlignment m_sourceVerticalAlignment : 2;
121};318 FillMode m_sourceFillMode : 2;
122319 WrapMode m_sourceHorizontalWrapMode : 1;
123// Scene graph textured material.320 WrapMode m_sourceVerticalWrapMode : 1;
124321 quint8 m_sourceOpacity;
125class ShapeTexturedMaterial : public QSGMaterial322 quint8 m_flags;
126{323
127public:324 Q_DISABLE_COPY(UCUbuntuShape)
128 ShapeTexturedMaterial();325};
129 virtual QSGMaterialType* type() const;326
130 virtual QSGMaterialShader* createShader() const;327QML_DECLARE_TYPE(UCUbuntuShape)
131 virtual int compare(const QSGMaterial* other) const;328
132 QSGTextureProvider* imageTextureProvider() const;329#endif // UCUBUNTUSHAPE_H
133 void setImage(QQuickItem* image);
134 QSGTexture* shapeTexture() const { return shapeTexture_; }
135 QSGTexture::Filtering filtering() const { return filtering_; }
136 void setShapeTexture(QSGTexture* shapeTexture, bool scaledDown);
137
138private:
139 QSGTextureProvider* imageTextureProvider_;
140 QSGTexture* shapeTexture_;
141 QSGTexture::Filtering filtering_;
142};
143
144// Scene graph textured material shader.
145
146class ShapeTexturedShader : public QSGMaterialShader
147{
148public:
149 virtual char const* const* attributeNames() const;
150 virtual void initialize();
151 virtual void updateState(
152 const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect);
153
154private:
155 virtual const char* vertexShader() const;
156 virtual const char* fragmentShader() const;
157
158 int matrixId_;
159 int opacityId_;
160 QOpenGLFunctions* glFuncs_;
161};
162
163// Scene graph colored material.
164
165class ShapeColoredMaterial : public QSGMaterial
166{
167public:
168 ShapeColoredMaterial();
169 virtual QSGMaterialType* type() const;
170 virtual QSGMaterialShader* createShader() const;
171 virtual int compare(const QSGMaterial* other) const;
172 const QVector4D& color() const { return color_; }
173 void setColor(const QColor& color);
174 const QVector4D& gradientColor() const { return gradientColor_; }
175 void setGradientColor(const QColor& gradientColor);
176 QSGTexture* shapeTexture() const { return shapeTexture_; }
177 QSGTexture::Filtering filtering() const { return filtering_; }
178 void setShapeTexture(QSGTexture* shapeTexture, bool scaledDown);
179
180private:
181 QVector4D color_;
182 QVector4D gradientColor_;
183 QSGTexture* shapeTexture_;
184 QSGTexture::Filtering filtering_;
185};
186
187// Scene graph colored material shader.
188
189class ShapeColoredShader : public QSGMaterialShader
190{
191public:
192 virtual char const* const* attributeNames() const;
193 virtual void initialize();
194 virtual void updateState(
195 const RenderState& state, QSGMaterial* newEffect, QSGMaterial* oldEffect);
196
197private:
198 virtual const char* vertexShader() const;
199 virtual const char* fragmentShader() const;
200
201 int matrixId_;
202 int opacityId_;
203 int colorId_;
204 int gradientColorId_;
205};
206
207// Scene graph node.
208
209struct TextureData;
210
211class ShapeNode : public QObject, public QSGGeometryNode
212{
213 Q_OBJECT
214
215public:
216 struct Vertex {
217 float position[2];
218 float shapeCoordinate[2];
219 float imageCoordinate[2];
220 float padding[2]; // Ensure a 32 bytes stride.
221 };
222 enum MaterialType { TexturedMaterial, ColoredMaterial };
223
224 ShapeNode(ShapeItem* item);
225 ShapeTexturedMaterial* texturedMaterial() { return &texturedMaterial_; }
226 ShapeColoredMaterial* coloredMaterial() { return &coloredMaterial_; }
227 void setVertices(const QRectF& geometry, float radius, QQuickItem* image, bool stretched,
228 ShapeItem::HAlignment hAlignment, ShapeItem::VAlignment vAlignment,
229 float shapeCoordinate[][2]);
230 void setMaterialType(MaterialType material);
231
232private:
233 ShapeItem* item_;
234 QSGGeometry geometry_;
235 ShapeTexturedMaterial texturedMaterial_;
236 ShapeColoredMaterial coloredMaterial_;
237 MaterialType currentMaterial_;
238};
239
240QML_DECLARE_TYPE(ShapeItem)
241
242#endif // UBUNTU_COMPONENTS_SHAPE_H
243330
=== renamed file 'modules/Ubuntu/Components/plugin/shapeitemtexture.h' => 'modules/Ubuntu/Components/plugin/ucubuntushapetexture.h'
--- modules/Ubuntu/Components/plugin/shapeitemtexture.h 2014-03-24 15:24:31 +0000
+++ modules/Ubuntu/Components/plugin/ucubuntushapetexture.h 2015-03-02 15:41:23 +0000
@@ -1,5 +1,5 @@
1/*1/*
2 * Copyright 2013 Canonical Ltd.2 * Copyright 2013-2014 Canonical Ltd.
3 *3 *
4 * This program is free software; you can redistribute it and/or modify4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by5 * it under the terms of the GNU Lesser General Public License as published by
@@ -18,7 +18,7 @@
1818
19class QSGTexture;19class QSGTexture;
2020
21struct TextureData {21struct ShapeTextureData {
22 const unsigned char* const data;22 const unsigned char* const data;
23 int width;23 int width;
24 int height;24 int height;
@@ -5158,7 +5158,7 @@
5158const float hh = 1.0f / 512.0f;5158const float hh = 1.0f / 512.0f;
51595159
5160// High resolution shape texture.5160// High resolution shape texture.
5161TextureData shapeTextureHigh __attribute__((aligned(16))) = {5161ShapeTextureData shapeTextureHigh __attribute__((aligned(16))) = {
5162 shapeTextureHighData, 256, 128, 4, 32.0f, 64.0f, 18.0f,5162 shapeTextureHighData, 256, 128, 4, 32.0f, 64.0f, 18.0f,
5163 {5163 {
5164 { // Medium raw coords.5164 { // Medium raw coords.
@@ -6482,7 +6482,7 @@
6482const float hl = 1.0f / 256.0f;6482const float hl = 1.0f / 256.0f;
64836483
6484// Low resolution shape texture.6484// Low resolution shape texture.
6485TextureData shapeTextureLow __attribute__((aligned(16))) = {6485ShapeTextureData shapeTextureLow __attribute__((aligned(16))) = {
6486 shapeTextureLowData, 128, 64, 4, 16.0f, 32.0f, 9.0f,6486 shapeTextureLowData, 128, 64, 4, 16.0f, 32.0f, 9.0f,
6487 {6487 {
6488 { // Medium raw coords.6488 { // Medium raw coords.
64896489
=== added directory 'tests/resources/ubuntushape'
=== added file 'tests/resources/ubuntushape/UbuntuShapeTest.qml'
--- tests/resources/ubuntushape/UbuntuShapeTest.qml 1970-01-01 00:00:00 +0000
+++ tests/resources/ubuntushape/UbuntuShapeTest.qml 2015-03-02 15:41:23 +0000
@@ -0,0 +1,299 @@
1/*
2 * Copyright 2015 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17import QtQuick 2.0
18import Ubuntu.Components 1.2
19
20Item {
21 id: root
22 width: 1000
23 height: 600
24 focus: true
25
26 // Enum to string tables.
27 property variant backgroundModeTable: [
28 "SolidColor", "VerticalGradient"
29 ]
30 property variant sourceHAlignmentTable: [
31 "AlignLeft", "AlignHCenter", "AlignRight"
32 ]
33 property variant sourceVAlignmentTable: [
34 "AlignTop", "AlignVCenter", "AlignBottom"
35 ]
36 property variant sourceFillModeTable: [
37 "Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Pad"
38 ]
39 property variant wrapModeTable: [
40 "Transparent", "Repeat"
41 ]
42 property variant imageFillModeTable: [
43 "Stretch", "PreserveAspectFit", "PreserveAspectCrop", "Tile", "TileVertically",
44 "TileHorizontally", "Pad"
45 ]
46
47 // Zoom properties.
48 property variant translation: Qt.point(0.0, 0.0)
49 property real scaleBase: 1.1
50 property real scaleExponent: 0.0
51 property real minScaleExponent: 0.0
52 property real maxScaleExponent: 48.317715856 // Logarithm of 100 to base 1.1 (scaleBase).
53 property real scaleFactor: 1.0
54 property real scale: 1.0
55
56 // Overlay text properties. French keymapping... :)
57 property string textOverlayString:
58 "Zoom (scroll): x " + root.scaleFactor.toFixed(1) + "\n\n" +
59 "Background colors (a/z): " + shape.backgroundColor + ", " + shape.secondaryBackgroundColor + "\n" +
60 "Background mode (e): " + root.backgroundModeTable[shape.backgroundMode] + "\n\n" +
61 "Source (o): " + shape.source + "\n" +
62 "Source opacity (p): " + shape.sourceOpacity.toFixed(2) + "\n" +
63 "Source fill (q): " + root.sourceFillModeTable[shape.sourceFillMode] + "\n" +
64 "Source hwrap (s): " + root.wrapModeTable[shape.sourceHorizontalWrapMode] + "\n" +
65 "Source vwrap (d): " + root.wrapModeTable[shape.sourceVerticalWrapMode] + "\n" +
66 "Source halign (f): " + root.sourceHAlignmentTable[shape.sourceHorizontalAlignment] + "\n" +
67 "Source valign (g): " + root.sourceVAlignmentTable[shape.sourceVerticalAlignment] + "\n" +
68 "Source translation (h/j): " + shape.sourceTranslation.x.toFixed(2) + ", " + shape.sourceTranslation.y.toFixed(2) + "\n" +
69 "Source scale (k/l): " + shape.sourceScale.x.toFixed(2) + ", " + shape.sourceScale.y.toFixed(2) + "\n\n" +
70 "Image (deprecated) (m): " + shape.image + "\n" +
71 "Image fill (w): " + root.imageFillModeTable[img1.fillMode] + "\n" +
72 "Image halign (x): " + img1.horizontalAlignment + "\n" +
73 "Image valign (c): " + img1.verticalAlignment + "\n\n" +
74 "Radius (v): " + "\"" + shape.radius + "\"\n" +
75 "Border (b): " + "\"" + shape.borderSource + "\"\n\n" +
76 "Colors (deprecated) (n/,): " + shape.color + ", " + shape.gradientColor
77
78 // Main scene.
79 Item {
80 id: scene
81 anchors.fill: parent
82
83 Image {
84 id: background
85 anchors.fill: parent
86 source: "background.jpg"
87 fillMode: Image.Tile
88 }
89
90 // Put the UbuntuShape source image in the middle of a texture atlas. We use img1.
91 Image { id: img1; visible: false; source: "img1.png"; }
92 Image { id: img2; visible: false; source: "img2.png"; }
93 Image { id: img3; visible: false; source: "img3.png"; }
94 Image { id: img4; visible: false; source: "img4.png"; }
95
96 UbuntuShape {
97 id: shape
98 anchors.fill: parent
99 anchors.leftMargin: 400
100 anchors.rightMargin: 100
101 anchors.topMargin: 100
102 anchors.bottomMargin: 100
103 }
104 }
105
106 // Zoom support.
107 ShaderEffectSource {
108 id: shaderEffectSource
109 anchors.fill: scene
110 sourceItem: scene
111 hideSource: true
112 visible: false
113 smooth: false
114 }
115 ShaderEffect {
116 anchors.fill: scene
117 property variant tex: shaderEffectSource
118 property variant translation: root.translation
119 property real scaleFactor: root.scale
120 vertexShader: "
121 uniform mat4 qt_Matrix;
122 uniform float scaleFactor;
123 uniform vec2 translation;
124 attribute vec4 qt_Vertex;
125 attribute vec2 qt_MultiTexCoord0;
126 varying vec2 texCoord;
127 void main() {
128 texCoord = vec2(scaleFactor) * qt_MultiTexCoord0 + translation;
129 gl_Position = qt_Matrix * qt_Vertex;
130 }"
131 fragmentShader: "
132 uniform sampler2D tex;
133 uniform float qt_Opacity;
134 varying vec2 texCoord;
135 void main() {
136 gl_FragColor = texture2D(tex, texCoord) * qt_Opacity;
137 }"
138 }
139
140 // Text overlay.
141 Text {
142 id: textOverlay
143 width:200
144 anchors.top: parent.top
145 anchors.topMargin: 10
146 anchors.left: parent.left
147 anchors.leftMargin: 10
148 font.family: "Ubuntu Mono"
149 font.pixelSize: 14
150 font.weight: Font.Bold
151 color: "black"
152 text: textOverlayString
153 }
154
155 // Mouse handling.
156 MouseArea {
157 id: mouseArea
158 anchors.fill: parent
159 acceptedButtons: Qt.LeftButton
160 hoverEnabled: true
161
162 property real lastX: 0.0
163 property real lastY: 0.0
164
165 onPressed: {
166 if (pressedButtons & Qt.LeftButton) {
167 lastX = mouseX;
168 lastY = mouseY;
169 }
170 }
171 onPositionChanged: {
172 if (pressedButtons & Qt.LeftButton) {
173 var tx = root.translation.x;
174 var ty = root.translation.y;
175 var sx = root.scale / root.width;
176 var sy = root.scale / root.height;
177 var x = mouseX - lastX;
178 var y = mouseY - lastY;
179 root.translation = Qt.point(Math.max(0.0, Math.min(1.0 - root.scale, tx - sx * x)),
180 Math.max(0.0, Math.min(1.0 - root.scale, ty - sy * y)));
181 lastX = mouseX;
182 lastY = mouseY;
183 }
184 }
185 onWheel: {
186 root.scaleExponent = Math.max(minScaleExponent, Math.min(maxScaleExponent,
187 root.scaleExponent + (wheel.angleDelta.y < 0.0 ? -1.0 : 1.0)));
188 root.scaleFactor = Math.pow(root.scaleBase, root.scaleExponent);
189 var oldScale = root.scale;
190 root.scale = 1.0 / root.scaleFactor;
191 var s = oldScale - root.scale;
192 var tx = root.translation.x;
193 var ty = root.translation.y;
194 var x = mouseX / root.width;
195 var y = mouseY / root.height;
196 root.translation = Qt.point(Math.max(0.0, Math.min(1.0 - root.scale, tx + s * x)),
197 Math.max(0.0, Math.min(1.0 - root.scale, ty + s * y)));
198 }
199 }
200
201 // Keyboard handling.
202 Keys.onPressed: {
203 var shift = Qt.ShiftModifier;
204
205 // Background.
206 if (event.key == Qt.Key_A) {
207 shape.backgroundColor = Qt.rgba(
208 Math.random(), Math.random(), Math.random(), Math.random());
209 } else if (event.key == Qt.Key_Z) {
210 shape.secondaryBackgroundColor = Qt.rgba(
211 Math.random(), Math.random(), Math.random(), Math.random());
212 } else if (event.key == Qt.Key_E) {
213 shape.backgroundMode = (shape.backgroundMode + 1) % 3;
214
215 // Source.
216 } else if (event.key == Qt.Key_O) {
217 if (shape.source == null) {
218 shape.source = img1;
219 } else {
220 shape.source = null;
221 }
222 } else if (event.key == Qt.Key_P) {
223 shape.sourceOpacity = Math.max(0.0, Math.min(
224 1.0, shape.sourceOpacity + ((event.modifiers & shift) ? 0.01 : -0.01)));
225 } else if (event.key == Qt.Key_Q) {
226 shape.sourceFillMode = (shape.sourceFillMode + 1) % 4;
227 } else if (event.key == Qt.Key_S) {
228 shape.sourceHorizontalWrapMode = (shape.sourceHorizontalWrapMode + 1) % 3;
229 } else if (event.key == Qt.Key_D) {
230 shape.sourceVerticalWrapMode = (shape.sourceVerticalWrapMode + 1) % 3;
231 } else if (event.key == Qt.Key_F) {
232 shape.sourceHorizontalAlignment = (shape.sourceHorizontalAlignment + 1) % 3;
233 } else if (event.key == Qt.Key_G) {
234 shape.sourceVerticalAlignment = (shape.sourceVerticalAlignment + 1) % 3;
235 } else if (event.key == Qt.Key_H) {
236 shape.sourceTranslation = Qt.vector2d(
237 shape.sourceTranslation.x + ((event.modifiers & shift) ? 0.01 : -0.01),
238 shape.sourceTranslation.y);
239 } else if (event.key == Qt.Key_J) {
240 shape.sourceTranslation = Qt.vector2d(
241 shape.sourceTranslation.x,
242 shape.sourceTranslation.y + ((event.modifiers & shift) ? 0.01 : -0.01));
243 } else if (event.key == Qt.Key_K) {
244 shape.sourceScale = Qt.vector2d(
245 shape.sourceScale.x + ((event.modifiers & shift) ? 0.02 : -0.02),
246 shape.sourceScale.y);
247 } else if (event.key == Qt.Key_L) {
248 shape.sourceScale = Qt.vector2d(
249 shape.sourceScale.x,
250 shape.sourceScale.y + ((event.modifiers & shift) ? 0.02 : -0.02));
251
252 // Image.
253 } else if (event.key == Qt.Key_M) {
254 if (shape.image == null) {
255 shape.image = img1;
256 } else {
257 shape.image = null;
258 }
259 } else if (event.key == Qt.Key_W) {
260 img1.fillMode = (img1.fillMode + 1) % 7;
261 } else if (event.key == Qt.Key_X) {
262 if (img1.horizontalAlignment == Image.AlignLeft) {
263 img1.horizontalAlignment = Image.AlignHCenter;
264 } else if (img1.horizontalAlignment == Image.AlignHCenter) {
265 img1.horizontalAlignment = Image.AlignRight;
266 } else {
267 img1.horizontalAlignment = Image.AlignLeft;
268 }
269 } else if (event.key == Qt.Key_C) {
270 if (img1.verticalAlignment == Image.AlignTop) {
271 img1.verticalAlignment = Image.AlignVCenter;
272 } else if (img1.verticalAlignment == Image.AlignVCenter) {
273 img1.verticalAlignment = Image.AlignBottom;
274 } else {
275 img1.verticalAlignment = Image.AlignTop;
276 }
277
278 // Styling.
279 } else if (event.key == Qt.Key_V) {
280 shape.radius = (shape.radius == "medium") ? "small" : "medium";
281 } else if (event.key == Qt.Key_B) {
282 if (shape.borderSource == "radius_idle.sci") {
283 shape.borderSource = "radius_pressed.sci";
284 } else if (shape.borderSource == "radius_pressed.sci") {
285 shape.borderSource = "";
286 } else {
287 shape.borderSource = "radius_idle.sci";
288 }
289
290 // Colors.
291 } else if (event.key == Qt.Key_N) {
292 shape.color = Qt.rgba(
293 Math.random(), Math.random(), Math.random(), Math.random());
294 } else if (event.key == Qt.Key_Comma) {
295 shape.gradientColor = Qt.rgba(
296 Math.random(), Math.random(), Math.random(), Math.random());
297 }
298 }
299}
0300
=== added file 'tests/resources/ubuntushape/background.jpg'
1Binary 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 differ301Binary 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
=== added file 'tests/resources/ubuntushape/img1.png'
2Binary 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 differ302Binary 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
=== added file 'tests/resources/ubuntushape/img2.png'
3Binary 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 differ303Binary 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
=== added file 'tests/resources/ubuntushape/img3.png'
4Binary 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 differ304Binary 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
=== added file 'tests/resources/ubuntushape/img4.png'
5Binary 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 differ305Binary 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