/**************************************************************************** ** ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the Qt scene graph research project. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the Technology Preview License Agreement accompanying ** this package. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights. These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** ** ** ** ** ** ** ** ** $QT_END_LICENSE$ ** ****************************************************************************/ import QtQuick 2.0 Rectangle { id: topLevel width: 360 height: 540 color: "#000040" Component { id: whiteBorder Rectangle { anchors.fill: parent color: "transparent" border.width: 2 border.color: "white" radius: 10 } } MouseArea { id: mouseArea1 x: 0 y: 0 width: parent.width / 3 height: parent.height / 6 drag.target: item1 drag.axis: Drag.XandYAxis drag.maximumX: topLevel.width - drag.target.width drag.maximumY: topLevel.height - drag.target.height function itemContains(item, point) { var p = mapToItem(item, point.x, point.y) return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height } onPressed: { drag.target.z = 1 } onReleased: { var effect = null if (itemContains(effect1, mouse)) effect = effect1 if (itemContains(effect2, mouse)) effect = effect2 if (itemContains(effect3, mouse)) effect = effect3 if (effect != null) { effect.source = effectSource1 effect.active = true } drag.target.x = x drag.target.y = y drag.target.z = 0 } } Item { id: item1 x: mouseArea1.x y: mouseArea1.y width: mouseArea1.width height: mouseArea1.height Loader { anchors.fill: parent; sourceComponent: whiteBorder } Item { id: sourceItem1 anchors.fill: parent Rectangle { anchors.fill: parent anchors.margins: 10 gradient: Gradient { GradientStop { position: 0; color: "blue" } GradientStop { position: 1; color: "white" } } border.width: 4 border.color: "navy" radius: 6 } } ShaderEffectSource { id: effectSource1 sourceItem: sourceItem1 filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { anchors.left: parent.left anchors.top: parent.top anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource1.hideOriginal ? "Hidden" : "Shown" MouseArea { anchors.fill: parent; onClicked: { effectSource1.hideOriginal = !effectSource1.hideOriginal } } } } MouseArea { id: mouseArea2 x: parent.width / 3 y: 0 width: parent.width / 3 height: parent.height / 6 drag.target: item2 drag.axis: Drag.XandYAxis drag.maximumX: topLevel.width - drag.target.width drag.maximumY: topLevel.height - drag.target.height function itemContains(item, point) { var p = mapToItem(item, point.x, point.y) return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height } onPressed: { drag.target.z = 1 } onReleased: { var effect = null if (itemContains(effect1, mouse)) effect = effect1 if (itemContains(effect2, mouse)) effect = effect2 if (itemContains(effect3, mouse)) effect = effect3 if (effect != null) { effect.source = effectSource2 effect.active = true } drag.target.x = x drag.target.y = y drag.target.z = 0 } onClicked: { effectSource2.grab(); grabbedAnim2.restart() } } Item { id: item2 x: mouseArea2.x y: mouseArea2.y width: mouseArea2.width height: mouseArea2.height Loader { anchors.fill: parent; sourceComponent: whiteBorder } Item { id: sourceItem2 anchors.fill: parent Rectangle { anchors.centerIn: parent radius: Math.min(parent.width, parent.height) * 0.4 width: 2 * radius height: 2 * radius color: "transparent" border.width: 4 border.color: "white" Repeater { model: 4 Rectangle { anchors.centerIn: parent width: 4 height: parent.height - 4 color: "white" rotation: index * 45 } } NumberAnimation on rotation { loops: Animation.Infinite from: 0 to: 360 duration: 5000 } } } ShaderEffectSource { id: effectSource2 sourceItem: sourceItem2 filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource2.static ? "Static" : "Dynamic" MouseArea { anchors.fill: parent; onClicked: { effectSource2.static = !effectSource2.static } } } Text { anchors.left: parent.left anchors.top: parent.top anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource2.hideOriginal ? "Hidden" : "Shown" MouseArea { anchors.fill: parent; onClicked: { effectSource2.hideOriginal = !effectSource2.hideOriginal } } } Text { anchors.centerIn: parent color: "red" font.pixelSize: 12 text: "Grabbed" opacity: 0 SequentialAnimation on opacity { id: grabbedAnim2 running: false PropertyAction { value: 1 } PauseAnimation { duration: 1000 } NumberAnimation { to: 0; duration: 1000 } } } } MouseArea { id: mouseArea3 x: parent.width * 2 / 3 y: 0 width: parent.width / 3 height: parent.height / 6 drag.target: item3 drag.axis: Drag.XandYAxis drag.maximumX: topLevel.width - drag.target.width drag.maximumY: topLevel.height - drag.target.height function itemContains(item, point) { var p = mapToItem(item, point.x, point.y) return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height } onPressed: { drag.target.z = 1 } onReleased: { var effect = null if (itemContains(effect1, mouse)) effect = effect1 if (itemContains(effect2, mouse)) effect = effect2 if (itemContains(effect3, mouse)) effect = effect3 if (effect != null) { effect.source = effectSource3 effect.active = true } drag.target.x = x drag.target.y = y drag.target.z = 0 } onClicked: { effectSource3.grab(); grabbedAnim3.restart() } } Item { id: item3 x: mouseArea3.x y: mouseArea3.y width: mouseArea3.width height: mouseArea3.height Loader { anchors.fill: parent; sourceComponent: whiteBorder } Item { id: sourceItem3 anchors.fill: parent Item { anchors.fill: parent anchors.margins: 6 Repeater { model: 16 Rectangle { x: (index % 4) * parent.width / 4 y: Math.floor(index / 4) * parent.height / 4 width: parent.width / 4 height: parent.height / 4 radius: Math.min(width, height) * 0.25 color: Qt.rgba(Math.random(), Math.random(), Math.random(), 1) property int delay: (index % 4) + Math.floor(index / 4) SequentialAnimation on scale { loops: Animation.Infinite PauseAnimation { duration: delay * 100 } NumberAnimation { to: 0.5; duration: 500 } PauseAnimation { duration: 8 * 100 } NumberAnimation { to: 1; duration: 500 } PauseAnimation { duration: (8 - delay) * 100 } } } } } } ShaderEffectSource { id: effectSource3 sourceItem: sourceItem3 filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource3.static ? "Static" : "Dynamic" MouseArea { anchors.fill: parent; onClicked: { effectSource3.static = !effectSource3.static } } } Text { anchors.left: parent.left anchors.top: parent.top anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource3.hideOriginal ? "Hidden" : "Shown" MouseArea { anchors.fill: parent; onClicked: { effectSource3.hideOriginal = !effectSource3.hideOriginal } } } Text { anchors.centerIn: parent color: "red" font.pixelSize: 12 text: "Grabbed" opacity: 0 SequentialAnimation on opacity { id: grabbedAnim3 running: false PropertyAction { value: 1 } PauseAnimation { duration: 1000 } NumberAnimation { to: 0; duration: 1000 } } } } MouseArea { id: mouseArea4 x: 0 y: parent.height / 6 width: parent.width / 3 height: parent.height / 6 drag.target: item4 drag.axis: Drag.XandYAxis drag.maximumX: topLevel.width - drag.target.width drag.maximumY: topLevel.height - drag.target.height function itemContains(item, point) { var p = mapToItem(item, point.x, point.y) return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height } onPressed: { drag.target.z = 1 } onReleased: { var effect = null if (itemContains(effect1, mouse)) effect = effect1 if (itemContains(effect2, mouse)) effect = effect2 if (itemContains(effect3, mouse)) effect = effect3 if (effect != null) { effect.source = effectSource4 effect.active = true } drag.target.x = x drag.target.y = y drag.target.z = 0 } } Item { id: item4 x: mouseArea4.x y: mouseArea4.y width: mouseArea4.width height: mouseArea4.height Loader { anchors.fill: parent; sourceComponent: whiteBorder } Image { id: sourceItem4 anchors.fill: parent source: "qt-logo.png" smooth: true } ShaderEffectSource { id: effectSource4 sourceImage: sourceItem4.source filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } } MouseArea { id: mouseArea5 x: parent.width / 3 y: parent.height / 6 width: parent.width / 3 height: parent.height / 6 drag.target: item5 drag.axis: Drag.XandYAxis drag.maximumX: topLevel.width - drag.target.width drag.maximumY: topLevel.height - drag.target.height function itemContains(item, point) { var p = mapToItem(item, point.x, point.y) return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height } onPressed: { drag.target.z = 1 } onReleased: { var effect = null if (itemContains(effect1, mouse)) effect = effect1 if (itemContains(effect2, mouse)) effect = effect2 if (itemContains(effect3, mouse)) effect = effect3 if (effect != null) { effect.source = effectSource5 effect.active = true } drag.target.x = x drag.target.y = y drag.target.z = 0 } onClicked: { effectSource5.grab(); grabbedAnim5.restart() } } Item { id: item5 x: mouseArea5.x y: mouseArea5.y width: mouseArea5.width height: mouseArea5.height Loader { anchors.fill: parent; sourceComponent: whiteBorder } Item { id: sourceItem5 anchors.fill: parent Image { anchors.fill: parent source: "qt-logo.png" smooth: true transformOrigin: Item.Top scale: 0 SequentialAnimation on scale { loops: Animation.Infinite NumberAnimation { to: 1; duration: 1500; easing.type: Easing.OutBounce } NumberAnimation { to: 0; duration: 1500; easing.type: Easing.OutBounce } } } Image { anchors.fill: parent source: "face-smile.png" smooth: true transformOrigin: Item.Bottom SequentialAnimation on scale { loops: Animation.Infinite NumberAnimation { to: 0; duration: 1500; easing.type: Easing.OutBounce } NumberAnimation { to: 1; duration: 1500; easing.type: Easing.OutBounce } } } } ShaderEffectSource { id: effectSource5 sourceItem: sourceItem5 filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } Text { anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource5.static ? "Static" : "Dynamic" MouseArea { anchors.fill: parent; onClicked: { effectSource5.static = !effectSource5.static } } } Text { anchors.left: parent.left anchors.top: parent.top anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource5.hideOriginal ? "Hidden" : "Shown" MouseArea { anchors.fill: parent; onClicked: { effectSource5.hideOriginal = !effectSource5.hideOriginal } } } Text { anchors.centerIn: parent color: "red" font.pixelSize: 12 text: "Grabbed" opacity: 0 SequentialAnimation on opacity { id: grabbedAnim5 running: false PropertyAction { value: 1 } PauseAnimation { duration: 1000 } NumberAnimation { to: 0; duration: 1000 } } } } MouseArea { id: mouseArea6 x: parent.width * 2 / 3 y: parent.height / 6 width: parent.width / 3 height: parent.height / 6 drag.target: item6 drag.axis: Drag.XandYAxis drag.maximumX: topLevel.width - drag.target.width drag.maximumY: topLevel.height - drag.target.height function itemContains(item, point) { var p = mapToItem(item, point.x, point.y) return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height } onPressed: { drag.target.z = 1 } onReleased: { var effect = null if (itemContains(effect1, mouse)) effect = effect1 if (itemContains(effect2, mouse)) effect = effect2 if (itemContains(effect3, mouse)) effect = effect3 if (effect != null) { effect.source = effectSource6 effect.active = true } drag.target.x = x drag.target.y = y drag.target.z = 0 } } Item { id: item6 x: mouseArea6.x y: mouseArea6.y width: mouseArea6.width height: mouseArea6.height Loader { anchors.fill: parent; sourceComponent: whiteBorder } Image { id: sourceItem6 anchors.fill: parent source: "face-smile.png" smooth: true } ShaderEffectSource { id: effectSource6 sourceImage: sourceItem6.source filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } } Rectangle { id: colorSample width: 32 height: 32 border.width: 2 border.color: "white" radius: width / 2 visible: false z: 1 } Item { id: gradient x: 0 y: parent.height / 3 width: parent.width height: parent.height / 6 ShaderEffectItem { anchors.fill: parent fragmentShader: "uniform highp float qt_Opacity; \n" + "varying highp vec2 qt_TexCoord0; \n" + "void main() { \n" + " highp float x = 6. * qt_TexCoord0.x; \n" + " highp float r = max(2. - x, x - 4.); \n" + " highp float g = min(x, 4. - x); \n" + " highp float b = min(x - 2., 6. - x); \n" + " gl_FragColor = qt_Opacity * vec4(r, g, b, 1.); \n" + "}" } } MouseArea { function clamp(x, lo, hi) { return Math.max(lo, Math.min(hi, x)); } function hueToRgb(x) { var t = 6 * x; var r = clamp(Math.max(2 - t, t - 4), 0, 1); var g = clamp(Math.min(t, 4 - t), 0, 1); var b = clamp(Math.min(t - 2, 6 - t), 0, 1); return Qt.rgba(r, g, b, 1); } function itemContains(item, point) { var p = mapToItem(item, point.x, point.y); return p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height; } anchors.fill: gradient drag.target: colorSample drag.axis: Drag.XandYAxis drag.minimumX: 0 drag.maximumX: topLevel.width - colorSample.width drag.minimumY: 0 drag.maximumY: topLevel.height - colorSample.height onPressed: { colorSample.visible = true colorSample.x = mapToItem(colorSample.parent, mouse.x, mouse.y).x - colorSample.width / 2 colorSample.y = mapToItem(colorSample.parent, mouse.x, mouse.y).y - colorSample.height / 2 colorSample.color = hueToRgb(mouse.x / width) } onReleased: { colorSample.visible = false if (itemContains(effect1, mouse)) effect1.color = colorSample.color if (itemContains(effect2, mouse)) effect2.color = colorSample.color if (itemContains(effect3, mouse)) effect3.color = colorSample.color } } ShaderEffectSource { id: defaultSource sourceItem: Item { width: topLevel.width / 2 height: topLevel.height / 4 Text { anchors.centerIn: parent color: "white" text: "Drag item and\ncolor here" horizontalAlignment: Text.AlignHCenter font.pixelSize: 20 } } filtering: ShaderEffectSource.Linear mipmap: controls.mipmap ? ShaderEffectSource.Linear : ShaderEffectSource.None textureSize: Qt.size(effect1.width, effect1.height) } ShaderEffectItem { id: effect1 x: 0 y: parent.height / 2 width: parent.width / 2 height: parent.height / 4 scale: controls.value property color color: "red" property variant source: defaultSource property real intensity fragmentShader: "varying highp vec2 qt_TexCoord0; \n" + "uniform lowp sampler2D source; \n" + "uniform lowp vec4 color; \n" + "uniform lowp float intensity; \n" + "uniform lowp float qt_Opacity; \n" + "void main() { \n" + " lowp vec4 pix = texture2D(source, qt_TexCoord0); \n" + " lowp float gray = dot(pix.xyz, vec3(0.5, 0.5, 0.5)); \n" + " gl_FragColor = qt_Opacity * mix(pix, vec4(color.xyz * gray, pix.w), intensity); \n" + "}" SequentialAnimation on intensity { loops: Animation.Infinite NumberAnimation { to: 1; duration: 2000 } NumberAnimation { to: 0; duration: 2000 } } MouseArea { anchors.fill: parent onClicked: { parent.active = !parent.active } } Text { anchors.centerIn: parent color: "white" font.pixelSize: 20 text: "Inactive\nClick to activate" horizontalAlignment: Text.AlignHCenter visible: !parent.active } } Text { anchors.left: effect1.left anchors.top: effect1.top anchors.margins: 3 color: "red" font.pixelSize: 12 text: effectSource2.mipmap ? "Mipmap on" : "Mipmap off" opacity: 0 SequentialAnimation on opacity { id: mipmapStateAnim running: false PropertyAction { value: 1 } PauseAnimation { duration: 1000 } NumberAnimation { to: 0; duration: 1000 } } } ShaderEffectItem { id: effect2 x: parent.width / 2 y: parent.height / 2 width: parent.width / 2 height: parent.height / 4 scale: controls.value property color color: "green" property alias source: innerInnerEffect2._source property real radius: 8 property variant direction: Qt.point(0, 1 / _source.height) property real intensity: 1 property variant _w: [ 0.5, // sampled twice, so each sample should weigh half the original weight. Math.exp(-1 / (radius * radius)), Math.exp(-4 / (radius * radius)), Math.exp(-9 / (radius * radius)), Math.exp(-16 / (radius * radius)), Math.exp(-25 / (radius * radius)), Math.exp(-36 / (radius * radius)), Math.exp(-49 / (radius * radius)) ] property variant _w2: [_w[0] + _w[1], _w[2] + _w[3], _w[4] + _w[5], _w[6] + _w[7]] property variant offsets: Qt.rect(_w[1] / _w2[0], 2 + _w[3] / _w2[1], 4 + _w[5] / _w2[2], 6 + _w[7] / _w2[3]) property real _s: .5 / (_w2[0] + _w2[1] + _w2[2] + _w2[3]) property variant weights: Qt.rect(_w2[0] * _s, _w2[1] * _s, _w2[2] * _s, _w2[3] * _s) property variant _source: ShaderEffectSource { sourceItem: innerEffect2 filtering: ShaderEffectSource.Linear } SequentialAnimation on intensity { loops: Animation.Infinite NumberAnimation { to: 1; duration: 2000 } NumberAnimation { to: 0; duration: 2000 } } property string blurShader: "varying highp vec2 qt_TexCoord0; \n" + "uniform lowp sampler2D _source; \n" + "uniform highp vec4 offsets; \n" + "uniform highp vec4 weights; \n" + "uniform highp vec2 direction; \n" + "uniform lowp float qt_Opacity; \n" + "void main() { \n" + " highp vec4 sum = vec4(0.); \n" + " sum += texture2D(_source, qt_TexCoord0 - direction * offsets.x) * weights.x; \n" + " sum += texture2D(_source, qt_TexCoord0 - direction * offsets.y) * weights.y; \n" + " sum += texture2D(_source, qt_TexCoord0 - direction * offsets.z) * weights.z; \n" + " sum += texture2D(_source, qt_TexCoord0 - direction * offsets.w) * weights.w; \n" + " sum += texture2D(_source, qt_TexCoord0 + direction * offsets.x) * weights.x; \n" + " sum += texture2D(_source, qt_TexCoord0 + direction * offsets.y) * weights.y; \n" + " sum += texture2D(_source, qt_TexCoord0 + direction * offsets.z) * weights.z; \n" + " sum += texture2D(_source, qt_TexCoord0 + direction * offsets.w) * weights.w; \n" + " gl_FragColor = qt_Opacity * sum; \n" + "}" fragmentShader: "varying highp vec2 qt_TexCoord0; \n" + "uniform lowp sampler2D _source; \n" + "uniform lowp sampler2D source; \n" + "uniform lowp vec4 color; \n" + "uniform lowp float intensity; \n" + "uniform lowp float qt_Opacity; \n" + "void main() { \n" + " lowp vec4 pix = texture2D(source, qt_TexCoord0); \n" + " lowp vec4 glow = texture2D(_source, qt_TexCoord0); \n" + " lowp float gray = dot(glow.xyz, vec3(intensity)); \n" + " gl_FragColor = qt_Opacity * vec4(pix.xyz + color.xyz * gray, pix.w); \n" + "}" ShaderEffectItem { id: innerEffect2 anchors.fill: parent fragmentShader: parent.blurShader property variant direction: Qt.point(1 / _source.width, 0) property alias offsets: effect2.offsets property alias weights: effect2.weights property variant _source: ShaderEffectSource { sourceItem: innerInnerEffect2 filtering: ShaderEffectSource.Linear } active: parent.active } ShaderEffectItem { id: innerInnerEffect2 anchors.fill: parent fragmentShader: parent.blurShader property variant direction: Qt.point(0, 1 / _source.height) property variant _source: defaultSource property alias offsets: effect2.offsets property alias weights: effect2.weights active: parent.active } MouseArea { anchors.fill: parent onClicked: { parent.active = !parent.active } } Text { anchors.centerIn: parent color: "white" font.pixelSize: 20 text: "Inactive\nClick to activate" horizontalAlignment: Text.AlignHCenter visible: !parent.active } } ShaderEffectItem { id: effect3 x: parent.width / 4 y: parent.height * 3 / 4 width: parent.width / 2 height: parent.height / 4 scale: controls.value property color color: "blue" property variant source: defaultSource property real intensity fragmentShader: "varying highp vec2 qt_TexCoord0; \n" + "uniform lowp sampler2D source; \n" + "uniform lowp vec4 color; \n" + "uniform lowp float intensity; \n" + "uniform lowp float qt_Opacity; \n" + "highp float minc(lowp vec3 v) { return min(v.x, min(v.y, v.z)); } \n" + "highp float maxc(lowp vec3 v) { return max(v.x, max(v.y, v.z)); } \n" + "void main() { \n" + " lowp vec4 pix = texture2D(source, qt_TexCoord0); \n" + " highp float lo = minc(pix.xyz); \n" + " highp float hi = maxc(pix.xyz); \n" + " gl_FragColor = qt_Opacity * vec4(mix(pix.xyz, color.xyz * (hi - lo) + lo, intensity), pix.w); \n" + "}" SequentialAnimation on intensity { loops: Animation.Infinite NumberAnimation { to: 1; duration: 2000 } NumberAnimation { to: 0; duration: 2000 } } MouseArea { anchors.fill: parent onClicked: { parent.active = !parent.active } } Text { anchors.centerIn: parent color: "white" font.pixelSize: 20 text: "Inactive\nClick to activate" horizontalAlignment: Text.AlignHCenter visible: !parent.active } } Item { id: controls anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom height: parent.height / 4 property real value: 1 property real min: 0.1 property real max: 1 property bool mipmap: false Behavior on value { animation: NumberAnimation { duration: 200 } } MouseArea { anchors.left: parent.left anchors.bottom: parent.bottom height: parent.height / 2 width: height scale: parent.value <= parent.min + 0.0001 ? 0.5 : 1 Behavior on scale { animation: NumberAnimation { duration: 200 } } Rectangle { anchors.fill: parent anchors.margins: parent.width / 8 color: "transparent" border.width: 4 border.color: "white" radius: width / 2 Rectangle { color: "white" anchors.centerIn: parent width: parent.width / 2 height: 4 } } onClicked: { parent.value = Math.max(0.8 * parent.value, parent.min) } } MouseArea { anchors.right: parent.right anchors.bottom: parent.bottom height: parent.height / 2 width: height scale: parent.value >= parent.max - 0.0001 ? 0.5 : 1 Behavior on scale { animation: NumberAnimation { duration: 200 } } Rectangle { anchors.fill: parent anchors.margins: parent.width / 8 color: "transparent" border.width: 4 border.color: "white" radius: width / 2 Rectangle { color: "white" anchors.centerIn: parent width: parent.width / 2 height: 4 } Rectangle { color: "white" anchors.centerIn: parent width: 4 height: parent.height / 2 } } onClicked: { parent.value = Math.min(1.25 * parent.value, parent.max) } } MouseArea { id: mipmapButton anchors.left: parent.left anchors.top: parent.top height: parent.height / 2 width: height Rectangle { anchors.fill: parent anchors.margins: parent.width / 8 color: "transparent" border.width: 4 border.color: "white" radius: width / 2 Text { anchors.centerIn: parent color: "white" font.pixelSize: parent.height * 0.3 horizontalAlignment: Text.AlignHCenter text: "MIP\nMAP" } Rectangle { anchors.centerIn: parent width: parent.width height: 4 rotation: -45 visible: controls.mipmap } } onClicked: { parent.mipmap = !parent.mipmap mipmapStateAnim.restart() } } } }