Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Draw transparent hole or something like that
Forum Updated to NodeBB v4.3 + New Features

Draw transparent hole or something like that

Scheduled Pinned Locked Moved Solved QML and Qt Quick
5 Posts 4 Posters 2.8k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • alejandro_pnzA Offline
    alejandro_pnzA Offline
    alejandro_pnz
    wrote on last edited by alejandro_pnz
    #1

    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.
    Example tutorial

    raven-worxR 1 Reply Last reply
    0
    • alejandro_pnzA alejandro_pnz

      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.
      Example tutorial

      raven-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by
      #2

      @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.

      --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
      If you have a question please use the forum so others can benefit from the solution in the future

      1 Reply Last reply
      2
      • GrecKoG Online
        GrecKoG Online
        GrecKo
        Qt Champions 2018
        wrote on last edited by GrecKo
        #3

        I'd just use an OpacityMask with your overlay as the source, a circle as the maskSource, and set invert to true.
        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
                }
            }
        }
        
        
        alejandro_pnzA 1 Reply Last reply
        4
        • GrecKoG GrecKo

          I'd just use an OpacityMask with your overlay as the source, a circle as the maskSource, and set invert to true.
          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
                  }
              }
          }
          
          
          alejandro_pnzA Offline
          alejandro_pnzA Offline
          alejandro_pnz
          wrote on last edited by alejandro_pnz
          #4

          @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

          1 Reply Last reply
          0
          • S Offline
            S Offline
            seyed
            wrote on last edited by seyed
            #5

            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:
            Masked interactive guide

            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.

            1 Reply Last reply
            3

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved