PDA

View Full Version : Qt QML click under the bounding box



Vildnex
29th March 2020, 20:43
What I'm trying to do is present in the following image: https://i.imgur.com/xW0kU3g.png?1


So far the only solution I found is to create my button from C++ and to use setMask. Is there any other way in order to achieve the same results but just using QML?

**My shape button:**


import QtQuick 2.0
import QtQuick.Shapes 1.14



Item {
id: sideButtonID
property alias mouseX: mouseArea.mouseX
property alias mouseY: mouseArea.mouseY
readonly property bool pressed: containsMouse && mouseArea.pressed

property point topLeftOffset: Qt.point(0, 0)
property point topRightOffset: Qt.point(0, 0)
property point bottomRightOffset: Qt.point(0, 0)
property point bottomLeftOffset: Qt.point(0, 0)

property var colorPressed: "green"
property var colorSelected: "red"
property var colorUnselected: "darkorange"

signal clicked

property var coordinate: generateButtonShapeCoordinates(x,y,width,height)
property point topLeft: coordinate.topLeft
property point topRight: coordinate.topRight
property point bottomRight: coordinate.bottomRight
property point bottomLeft: coordinate.bottomLeft


function generateButtonShapeCoordinates(x, y, width, height){

var topLeft = Qt.point(x-width/2 - topLeftOffset.x, y-height-topLeftOffset.y)
var topRight = Qt.point(x+width/2-topRightOffset.x, y-height-topRightOffset.y)
var bottomRight = Qt.point(x+width/2-bottomRightOffset.x, y-bottomRightOffset.y)
var bottomLeft = Qt.point(x - width/2-bottomLeftOffset.x, y-bottomLeftOffset.y)

return {
topLeft : topLeft,
topRight : topRight,
bottomRight : bottomRight,
bottomLeft : bottomLeft
};
}

function inside(point, polygon) {
// ray-casting algorithm based on
// http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
var x = point[0], y = point[1];

var inside = false;
for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
var xi = polygon[i][0], yi = polygon[i][1];
var xj = polygon[j][0], yj = polygon[j][1];

var intersect = ((yi > y) != (yj > y))
&& (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) inside = !inside;
}

return inside;
}

property bool containsMouse: {
var topLeft = Qt.point(0-topLeftOffset.x, 0-topLeftOffset.y)
var topRigh = Qt.point(width-topRightOffset.x, 0-topRightOffset.y)
var bottomRight = Qt.point(width-bottomRightOffset.x, height-bottomRightOffset.y)
var bottomLeft = Qt.point(0-bottomLeftOffset.x, height-bottomLeftOffset.y)

var polygon = [[topLeft.x,topLeft.y],[topRigh.x,topRigh.y],[bottomRight.x,bottomRight.y],[bottomLeft.x,bottomLeft.y]]
var point = [mouseX, mouseY]

return inside(point, polygon)
}

MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: if (sideButtonID.containsMouse) sideButtonID.clicked()
}
Shape {
antialiasing: true
vendorExtensionsEnabled: true
asynchronous: true
anchors.centerIn: parent


ShapePath {
id: shapepathId

strokeWidth: -1
fillColor: sideButtonID.pressed ? sideButtonID.colorPressed : (sideButtonID.containsMouse ? sideButtonID.colorSelected : sideButtonID.colorUnselected)
startX: sideButtonID.topLeft.x; startY: sideButtonID.topLeft.y
PathLine { x: sideButtonID.topRight.x; y: sideButtonID.topRight.y }
PathLine { x: sideButtonID.bottomRight.x; y: sideButtonID.bottomRight.y }
PathLine { x: sideButtonID.bottomLeft.x; y: sideButtonID.bottomLeft.y }
}
Component.onCompleted: {
console.log("TopLeft: "+sideButtonID.topLeft)
console.log("TopRight: "+sideButtonID.topRight)
console.log("BottomLeft: "+sideButtonID.bottomLeft)
console.log("BottomRight: "+sideButtonID.bottomRight)
}
}
}

**The usage of my button:**


SideButtons {
z: 100
id: sideButtonID
width: 130
height: 248
anchors.verticalCenterOffset: 9
anchors.horizontalCenterOffset: -255
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
bottomRightOffset: Qt.point(100,0)
onClicked: {
print("X: "+mouseX)
print("Y: "+mouseY)
print("clicked")
}
}

Some of the options that I've heard so far but there are not good in my case.

1. using an image with a transparent background (sure but I'm going to have the same problem)
2. creating a C++ class which will inherit **QAbstractButton** (I would prefer to avoid as much as I can usage of C++ in the Ui side)
3. usage of a **Shape** in combination with **MouseArea** (I'm doing this already but I am encountering the bounding box problem.

Is there any other way which I don't know yet about?