From cafcdd73b73947fa6e64689a346966eab1128b44 Mon Sep 17 00:00:00 2001 From: J-P Nurmi Date: Sat, 15 Nov 2014 00:35:05 +0100 Subject: WIP: Android 5.0: add missing vector drawable support Task-number: QTBUG-42520 Change-Id: I730c8ba89c957a2090b49a873f0dbabbf9581feb --- src/controls/Styles/Android/Android.pro | 5 +- .../Styles/Android/drawables/DrawableLoader.qml | 3 +- .../Styles/Android/drawables/VectorDrawable.qml | 86 +++++++++ .../Android/drawables/VectorGroupDrawable.qml | 81 +++++++++ .../Android/drawables/VectorPathDrawable.qml | 192 +++++++++++++++++++++ 5 files changed, 365 insertions(+), 2 deletions(-) create mode 100644 src/controls/Styles/Android/drawables/VectorDrawable.qml create mode 100644 src/controls/Styles/Android/drawables/VectorGroupDrawable.qml create mode 100644 src/controls/Styles/Android/drawables/VectorPathDrawable.qml diff --git a/src/controls/Styles/Android/Android.pro b/src/controls/Styles/Android/Android.pro index 64b76a65a..f7a23d182 100644 --- a/src/controls/Styles/Android/Android.pro +++ b/src/controls/Styles/Android/Android.pro @@ -41,7 +41,10 @@ QML_FILES += \ $$PWD/drawables/LayerDrawable.qml \ $$PWD/drawables/NinePatchDrawable.qml \ $$PWD/drawables/RotateDrawable.qml \ - $$PWD/drawables/StateDrawable.qml + $$PWD/drawables/StateDrawable.qml \ + $$PWD/drawables/VectorDrawable.qml \ + $$PWD/drawables/VectorGroupDrawable.qml \ + $$PWD/drawables/VectorPathDrawable.qml HEADERS += \ $$PWD/qquickandroid9patch_p.h \ diff --git a/src/controls/Styles/Android/drawables/DrawableLoader.qml b/src/controls/Styles/Android/drawables/DrawableLoader.qml index 4dd82c03e..878ad914a 100644 --- a/src/controls/Styles/Android/drawables/DrawableLoader.qml +++ b/src/controls/Styles/Android/drawables/DrawableLoader.qml @@ -84,7 +84,8 @@ Loader { type === "layer" ? Qt.createComponent("LayerDrawable.qml") : type === "9patch" ? Qt.createComponent("NinePatchDrawable.qml") : type === "rotate" ? Qt.createComponent("RotateDrawable.qml") : - type === "stateslist" ? Qt.createComponent("StateDrawable.qml") : null + type === "stateslist" ? Qt.createComponent("StateDrawable.qml") : + type === "vector" ? Qt.createComponent("VectorDrawable.qml") : null Binding { target: loader.item; property: "styleDef"; value: loader.styleDef } Binding { target: loader.item; property: "focused"; value: loader.focused } diff --git a/src/controls/Styles/Android/drawables/VectorDrawable.qml b/src/controls/Styles/Android/drawables/VectorDrawable.qml new file mode 100644 index 000000000..c2181c33c --- /dev/null +++ b/src/controls/Styles/Android/drawables/VectorDrawable.qml @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Controls.Styles.Android 1.0 + +Drawable { + id: root + + implicitWidth: styleDef.baseWidth || styleDef.width || 0 + implicitHeight: styleDef.baseHeight || styleDef.height || 0 + + VectorGroupDrawable { + id: group + anchors.fill: parent + styleDef: root.styleDef.rootGroup + // opacity: root.styleDef.rootAlpha / 255.0 + viewportWidth: root.styleDef.viewportWidth + viewportHeight: root.styleDef.viewportHeight + } + + layer.enabled: !!styleDef && !!styleDef.tintList + layer.effect: ShaderEffect { + property variant source: image + property color color: AndroidStyle.colorValue(styleDef.tintList[state]) + state: { + var states = [] + if (pressed) states.push("PRESSED") + if (enabled) states.push("ENABLED") + if (focused) states.push("FOCUSED") + if (selected) states.push("SELECTED") + if (window_focused) states.push("WINDOW_FOCUSED") + if (!states.length) + states.push("EMPTY") + return states.join("_") + "_STATE_SET" + } + // QtGraphicalEffects/ColorOverlay: + fragmentShader: " + varying mediump vec2 qt_TexCoord0; + uniform highp float qt_Opacity; + uniform lowp sampler2D source; + uniform highp vec4 color; + void main() { + highp vec4 pixelColor = texture2D(source, qt_TexCoord0); + gl_FragColor = vec4(mix(pixelColor.rgb/max(pixelColor.a, 0.00390625), color.rgb/max(color.a, 0.00390625), color.a) * pixelColor.a, pixelColor.a) * qt_Opacity; + } + " + } +} diff --git a/src/controls/Styles/Android/drawables/VectorGroupDrawable.qml b/src/controls/Styles/Android/drawables/VectorGroupDrawable.qml new file mode 100644 index 000000000..b75f6f278 --- /dev/null +++ b/src/controls/Styles/Android/drawables/VectorGroupDrawable.qml @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 + +Item { + id: root + + property var styleDef + property real viewportWidth + property real viewportHeight + +// transform: [ +// Rotation { +// angle: styleDef.rotate +// origin.x: styleDef.pivotX +// origin.y: styleDef.pivotY +// }, +// Scale { +// xScale: styleDef.scaleX +// yScale: styleDef.scaleY +// origin.x: styleDef.pivotX +// origin.y: styleDef.pivotY +// }, +// Translate { +// x: styleDef.translateX +// y: styleDef.translateY +// } +// ] + + Repeater { + anchors.fill: parent + model: styleDef.children + Loader { + anchors.fill: parent + sourceComponent: styleDef.type === "group" ? Qt.createComponent("VectorGroupDrawable.qml") : + styleDef.type === "path" ? Qt.createComponent("VectorPathDrawable.qml") : "" + + Binding { target: item; property: "styleDef"; value: modelData } + Binding { target: item; property: "viewportWidth"; value: root.viewportWidth } + Binding { target: item; property: "viewportHeight"; value: root.viewportHeight } + } + } +} diff --git a/src/controls/Styles/Android/drawables/VectorPathDrawable.qml b/src/controls/Styles/Android/drawables/VectorPathDrawable.qml new file mode 100644 index 000000000..dfd4bf8e7 --- /dev/null +++ b/src/controls/Styles/Android/drawables/VectorPathDrawable.qml @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Quick Controls module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** You may use this file under the terms of the BSD license as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names +** of its contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.2 +import QtQuick.Controls.Styles.Android 1.0 + +Canvas { + id: root + + property var styleDef + property real viewportWidth + property real viewportHeight + + clip: styleDef.isClip + canvasSize: Qt.size(viewportWidth, viewportHeight) + + readonly property color fillColor: AndroidStyle.colorValue(styleDef.fillColor) + readonly property color strokeColor: AndroidStyle.colorValue(styleDef.strokeColor) + + fillStyle: Qt.rgba(fillColor.r, fillColor.g, fillColor.b, styleDef.fillAlpha) + strokeStyle: Qt.rgba(strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.strokeAlpha) + + lineCap: styleDef.strokeLineCap.toLowerCase() + lineJoin: styleDef.strokeLineJoin.toLowerCase() + lineWidth: styleDef.strokeWidth + miterLimit: styleDef.strokeMiterlimit + + // TODO: + // - styleDef.fillRule (VectorPathDrawable.VFullPath.mFillRule is unused) + // - styleDef.trimPathStart + // - styleDef.trimPathEnd + // - styleDef.trimPathOffset + + onPaint:{ + var ctx = canvas.getContext('2d') + for (var i = 0; i < styleDef.nodes.length; ++i) { + var currentX = 0 + var currentY = 0 + var ctrlPointX = 0 + var ctrlPointY = 0 + var reflectiveCtrlPointX = 0 + var reflectiveCtrlPointY = 0 + var cmd = styleDef.nodes[i].type + var params = styleDef.nodes[i].params + var previousCmd = '' + switch (cmd) { + case 'm': // moveto - Start a new sub-path (relative) + currentX += params[0] + currentY += params[1] + ctx.moveTo(currentX, currentY) + break; + case 'M': // moveto - Start a new sub-path + currentX = params[0] + currentY = params[1] + ctx.moveTo(currentX, currentY) + break; + case 'l': // lineto - Draw a line from the current point (relative) + currentX += params[0] + currentY += params[1] + ctx.lineTo(currentX, currentY) + break; + case 'L': // lineto - Draw a line from the current point + currentX = params[0] + currentY = params[1] + ctx.lineTo(currentX, currentY) + break; + case 'z': // closepath - Close the current subpath + case 'Z': // closepath - Close the current subpath + ctx.closePath() + break; + case 'h': // horizontal lineto - Draws a horizontal line (relative) + currentX += params[0] + ctx.lineTo(currentX, currentY) + break; + case 'H': // horizontal lineto - Draws a horizontal line + currentX = params[0] + ctx.lineTo(currentX, currentY) + break; + case 'v': // vertical lineto - Draws a vertical line from the current point (relative) + currentY += params[0] + ctx.lineTo(currentX, currentY) + break; + case 'V': // vertical lineto - Draws a vertical line from the current point + currentY = params[0] + ctx.lineTo(currentX, currentY) + break; + case 'c': // curveto - Draws a cubic Bézier curve (relative) + ctrlPointX = currentX + params[2] + ctrlPointY = currentY + params[3] + currentX += params[4] + currentY += params[5] + ctx.bezierCurveTo(params[0], params[1], ctrlPointX, ctrlPointY, currentX, currentY) + break; + case 'C': // curveto - Draws a cubic Bézier curve + ctrlPointX = params[2] + ctrlPointY = params[3] + currentX = params[4] + currentY = params[5] + ctx.bezierCurveTo(params[0], params[1], ctrlPointX, ctrlPointY, currentX, currentY) + break; + case 's': // smooth curveto - Draws a cubic Bézier curve (reflective control point) + break; + case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve (reflective control point) + break; + case 'q': // Draws a quadratic Bézier (relative) + ctrlPointX = currentX + params[0] + ctrlPointY = currentY + params[1] + currentX += params[2] + currentY += params[3] + ctx.quadraticCurveTo(ctrlPointX, ctrlPointY, currentX, currentY) + break; + case 'Q': // Draws a quadratic Bézier + ctrlPointX = params[0] + ctrlPointY = params[1] + currentX = params[2] + currentY = params[3] + ctx.quadraticCurveTo(ctrlPointX, ctrlPointY, currentX, currentY) + break; + case 't': // Draws a quadratic Bézier curve (reflective control point) (relative) + reflectiveCtrlPointX = 0 + reflectiveCtrlPointY = 0 + if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' || previousCmd == 'T') { + reflectiveCtrlPointX = currentX - ctrlPointX + reflectiveCtrlPointY = currentY - ctrlPointY + } + ctrlPointX = currentX + reflectiveCtrlPointX + ctrlPointY = currentY + reflectiveCtrlPointY + currentX += params[0] + currentY += params[1] + ctx.quadraticCurveTo(reflectiveCtrlPointX, reflectiveCtrlPointY, currentX, currentY) + break; + case 'T': // Draws a quadratic Bézier curve (reflective control point) + reflectiveCtrlPointX = currentX + reflectiveCtrlPointY = currentY + if (previousCmd == 'q' || previousCmd == 't' || previousCmd == 'Q' || previousCmd == 'T') { + reflectiveCtrlPointX = 2 * currentX - ctrlPointX + reflectiveCtrlPointY = 2 * currentY - ctrlPointY + } + ctrlPointX = reflectiveCtrlPointX + ctrlPointY = reflectiveCtrlPointY + currentX = params[0] + currentY = params[1] + ctx.quadraticCurveTo(reflectiveCtrlPointX, reflectiveCtrlPointY, currentX, currentY) + break; + case 'a': // Draws an elliptical arc + // ### TODO + break; + case 'A': // Draws an elliptical arc + // ### TODO + break; + } + previousCmd = node.type + } + } +} -- cgit v1.2.3