Draw transparent hole or something like that
-
Hi. I've try out to make a user tutorial like in popular Android-based library https://github.com/amlcurran/ShowcaseView. But how can draw a transparent hole? I need it to accent user for a view.
P.S.: I've stop on using FocusScope, but I can't make a hole with OpacityMask.
-
@alejandro_pnz said in Draw transparent hole or something like that:
P.S.: I've stop on using FocusScope, but I can't make a hole with OpacityMask.
show some code pls.
There are multiple ways to achieve that. For example using ShaderEffect or layering with OpacityMask. -
I'd just use an
OpacityMask
with your overlay as thesource
, a circle as themaskSource
, and setinvert
totrue
.
It will effectively make a circle hole in your overlay.EDIT : I did a quick proof of concept but then I had some fun overcomplicating it a bit with silly animations (preview here : http://www.gfycat.com/DevotedTangibleBobwhite) :
import QtQuick 2.7 import QtQuick.Controls 2.0 import QtGraphicalEffects 1.0 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") Label { text: "Dimmed text in background" anchors.horizontalCenter: parent.horizontalCenter font.pixelSize: 18 } Button { id: button text: "Showcase me" property real circleRadius: Math.min(parent.width/3, parent.height/3) x: parent.width/2 - width/2 + circleRadius * Math.cos(angleInRadians) y: parent.height/2 - height/2 + circleRadius * Math.sin(angleInRadians) property real angle: 0 property real angleInRadians: angle * Math.PI / 180 property bool showcase: false RotationAnimation on angle{ id: rotationAnimation running: button.showcase from: 0 to: 360 loops: Animation.Infinite duration: 4000 } onClicked: showcase = !showcase } Item { id: mask visible: false anchors.fill: parent Item { id: buttonGeometry x: button.x y: button.y width: button.width height: button.height } Repeater { id: repeater property real startDiameter: Math.max(button.width, button.height) + 50 property real diameterStep: 50 property real opacityStep: 0.2 model: 2 Rectangle { anchors.centerIn: buttonGeometry property real diameter: repeater.startDiameter + repeater.diameterStep * index width: diameter height: diameter radius: diameter/2 opacity: 1 - repeater.opacityStep * index } } } Rectangle { id: overlayRectangle visible: false anchors.fill: parent color: "#888" } OpacityMask { visible: opacity enabled: visible anchors.fill: parent maskSource: mask source: overlayRectangle invert: true opacity: button.showcase ? 0.8 : 0 Behavior on opacity { NumberAnimation { easing.type: Easing.InOutCubic } } Label { anchors.centerIn: parent text: "Showcase Sample" font.pixelSize: 30 color: "blue" } Button { anchors { bottom: parent.bottom left: parent.left margins: 16 } text: "Close" onClicked: button.showcase = false } } }
-
@GrecKo Thanks, this one is pretty good. But what about backward compatibility? I mean that "invert" property for OpacityMask available only from Qt 5.7. Any suggestions?
P.S.: OpacityMask in docs
P.P.S.: thanks all! I've search answer for the question described above here -
For someone which interest on same problem:
import QtQuick 2.6 Item { anchors.fill: parent Image { anchors.fill: parent source: "http://i.imgur.com/R3yMj0y.jpg" fillMode: Image.PreserveAspectCrop focus: true Keys.onRightPressed: _mask.maskX += 100 Keys.onLeftPressed: _mask.maskX -= 100 Keys.onUpPressed: _mask.maskY -= 100 Keys.onDownPressed: _mask.maskY += 100 MouseArea { anchors.fill: parent hoverEnabled: true onPositionChanged: { _mask.maskX = mouseX; _mask.maskY = mouseY; } } } Rectangle { id: _bk anchors.fill: parent color: "#33000000" visible: false layer.enabled: true layer.smooth: true } Rectangle { id: _mask anchors.fill: parent color: "transparent" visible: true property int maskX: 0 property int maskY: 0 Rectangle { id: circle width: 100; height: 100 x: _mask.maskX-50; y: _mask.maskY-50 radius: 50 color: "#000" Behavior on x { NumberAnimation { duration: 400; easing.type: Easing.OutBack; easing.overshoot: 1.4 } } Behavior on y { NumberAnimation { duration: 400; easing.type: Easing.OutBack; easing.overshoot: 1.4 } } } layer.enabled: true layer.samplerName: "maskSource" layer.effect: ShaderEffect { property variant source: _bk fragmentShader: " varying highp vec2 qt_TexCoord0; uniform highp float qt_Opacity; uniform lowp sampler2D source; uniform lowp sampler2D maskSource; void main(void) { gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity; } " } } Rectangle { id: _mask2 anchors.fill: parent color: "transparent" visible: true Rectangle { id: circle2 width: 150; height: 150 x: _mask.maskX-75; y: _mask.maskY-75 radius: 75 color: "#000" Behavior on x { NumberAnimation { duration: 550; easing.type: Easing.OutBack; easing.overshoot: 2.4 } } Behavior on y { NumberAnimation { duration: 550; easing.type: Easing.OutBack; easing.overshoot: 2.4 } } } layer.enabled: true layer.samplerName: "maskSource" layer.effect: ShaderEffect { property variant source: _bk fragmentShader: " varying highp vec2 qt_TexCoord0; uniform highp float qt_Opacity; uniform lowp sampler2D source; uniform lowp sampler2D maskSource; void main(void) { gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity; } " } } Rectangle { id: _mask3 anchors.fill: parent color: "transparent" visible: true Rectangle { id: circle3 width: 220; height: 220 x: _mask.maskX-110; y: _mask.maskY-110 radius: 110 color: "#000" Behavior on x { NumberAnimation { duration: 650; easing.type: Easing.OutBack; easing.overshoot: 3.0 } } Behavior on y { NumberAnimation { duration: 650; easing.type: Easing.OutBack; easing.overshoot: 3.0 } } } layer.enabled: true layer.samplerName: "maskSource" layer.effect: ShaderEffect { property variant source: _bk fragmentShader: " varying highp vec2 qt_TexCoord0; uniform highp float qt_Opacity; uniform lowp sampler2D source; uniform lowp sampler2D maskSource; void main(void) { gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0-texture2D(maskSource, qt_TexCoord0.st).a) * qt_Opacity; } " } } }
and result:
I make it a little nice and interactive but the key is
(1.0-texture2D(maskSource, qt_TexCoord0.st).a)
which makes opacity mask reversed.