0

I have the following problem:

I have a ListView with movies like this: enter image description here

I would like at the moment when I will click into a movie to get a bit bigger on with and high independently the rest of them, but for some reason, I'm getting this.

enter image description here

I've increased the width size by a lot just to show my problem, in reality, it doesn't need to be that big.

Could you explain to me why it's keeping the shape of that button even those the scaling is right except for the actual shape?


Here is how I'm using my custom widget (it's a delegate for a ListView):

SideButtons {
    id: imageButton
    property int recDynamicHeight: listViewID.height/10 * 5
    property int recOriginalHeight: listViewID.height/10 * 5
    property int recDynamiclWidth: listViewID.width/10 * 1.2
    property int recOriginalWidth: listViewID.width/10 * 1.2
    roundedCorners: ['TL','TR']
    clickable: false
    radius: 20
    width: recDynamiclWidth
    height: recDynamicHeight
    backgroundImage: model.imgUrl
    Text {
        property bool isVisible: false
        color: "#ffffff"
        anchors.fill: parent
        visible: textid.isVisible
        id: textid
        text: model.title
        font.bold: true
        horizontalAlignment: Text.AlignLeft
        font.pixelSize: listViewID.width/8/9
        topPadding: listViewID.width/8/9
        leftPadding: listViewID.width/8/9
    }
    Text {
        anchors.topMargin: listViewID.width/8/9
        color: "#ffffff"
        anchors.fill: parent
        visible: textid.isVisible
        id: yearId
        text: model.year
        horizontalAlignment: Text.AlignLeft
        font.pixelSize: listViewID.width/8/9
        topPadding: listViewID.width/8/9*2
        leftPadding: listViewID.width/8/9
    }
    onRelease: {
        console.log("release")
        imageButton.recDynamicHeight = imageButton.recOriginalHeight;
        imageButton.recDynamiclWidth = imageButton.recOriginalWidth;
        textid.isVisible = false;
        textid.visible = textid.isVisible;
    }
    onPressed: {
        console.log("pressed")
        imageButton.recDynamicHeight = imageButton.recOriginalHeight;
        imageButton.recDynamicHeight += imageButton.recDynamicHeight * 10/100;
        imageButton.recDynamiclWidth += 400;
        textid.isVisible = true;
        textid.visible = textid.isVisible;
    }
    onClicked: {
        load_page(PageType.movie_detailed_view, model.title, model.description, model.imgUrl, model.type, model.year)
    }
}

And here it's the actuall code from SideButton:

Item {
    id: sideButtonID

    property var coordinates: generateButtonShapeCoordinates(width, height)

    property bool hasRoundedCorners: true
    property var roundedCorners: ['TL','TR','BR','BL']
    property var backgroundImage: ""
    property var clickable: true

    property int radius: 10

    property alias mouseX: mouseArea.mouseX
    property alias mouseY: mouseArea.mouseY
    readonly property bool pressedOnArea: containsMouse && mouseArea.pressed
    onPressedOnAreaChanged: canvasID.requestPaint()

    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 icon: ""

    property var colorPressed: "green"
    property var colorSelected: "#434343"
    property var colorUnselected: "#434343"

    signal clicked
    signal release
    signal pressed

    function noRoundedCornersShapeCoordinates(width, height){
        var topLeft = Qt.point(topLeftOffset.x, topLeftOffset.y)
        var topRight = Qt.point(width - topRightOffset.x, topRightOffset.y)
        var bottomRight = Qt.point(width - bottomRightOffset.x, height - bottomRightOffset.y)
        var bottomLeft = Qt.point(bottomLeftOffset.x, height - bottomLeftOffset.y)

        return {
            topLeft : topLeft,
            topRight : topRight,
            bottomRight : bottomRight,
            bottomLeft : bottomLeft
        };
    }
    function roundedCornersShapeCoordinates(width, height){
        var offset = radius
        var topLeftOr = Qt.point(topLeftOffset.x, topLeftOffset.y)
        var topLeftDown = Qt.point(topLeftOffset.x, topLeftOffset.y +offset)
        var topLeftRight = Qt.point(topLeftOffset.x + offset, topLeftOffset.y)

        var topRightOr = Qt.point(width - topRightOffset.x, topRightOffset.y)
        var topRightLeft = Qt.point(width - topRightOffset.x - offset, topRightOffset.y)
        var topRightDown = Qt.point(width - topRightOffset.x, topRightOffset.y + offset)

        var bottomRightOr = Qt.point(width - bottomRightOffset.x, height - bottomRightOffset.y)
        var bottomRightTop = Qt.point(width - bottomRightOffset.x, height - bottomRightOffset.y -offset)
        var bottomRightLeft = Qt.point(width - bottomRightOffset.x - offset, height - bottomRightOffset.y)

        var bottomLeftOr = Qt.point(bottomLeftOffset.x, height - bottomLeftOffset.y)
        var bottomLeftDown = Qt.point(bottomLeftOffset.x + offset, height - bottomLeftOffset.y)
        var bottomLeftLeft = Qt.point(bottomLeftOffset.x, height - bottomLeftOffset.y -offset)

        return {
            topLeftDown : topLeftDown,
            topLeftOr : topLeftOr,
            topLeftRight : topLeftRight,

            topRightLeft : topRightLeft,
            topRightOr : topRightOr,
            topRightDown : topRightDown,

            bottomRightTop : bottomRightTop,
            bottomRightOr : bottomRightOr,
            bottomRightLeft : bottomRightLeft,

            bottomLeftDown : bottomLeftDown,
            bottomLeftOr : bottomLeftOr,
            bottomLeftLeft : bottomLeftLeft,
        };
    }

    function generateButtonShapeCoordinates(width, height){
        if(hasRoundedCorners){
            return roundedCornersShapeCoordinates(width, height)
        }
        else{
            return noRoundedCornersShapeCoordinates(width, height)
        }
    }

    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 corners = coordinates

        var polygon =[[]]

        for (const [key, value] of Object.entries(corners)) {
            polygon.push([corners[key].x,corners[key].y])
        }

        var point = [mouseX, mouseY]
        return inside(point, polygon)
    }

    MouseArea {
        id: mouseArea
        propagateComposedEvents: true
        anchors.fill: parent
        hoverEnabled: true
        acceptedButtons: Qt.LeftButton | Qt.RightButton
        onClicked: {
            if (sideButtonID.containsMouse){
                sideButtonID.clicked();
            }
            else{
                mouse.accepted = false;
                return;
            }
        }
        onReleased : sideButtonID.release();
        onPressed: {
            if (sideButtonID.containsMouse){
                sideButtonID.pressed();
            }
            else{
                mouse.accepted = false;
                return;
            }
        }
    }
    Shape {
        id: shapeRootID
        antialiasing: true
        vendorExtensionsEnabled: true
        asynchronous: true
        anchors.fill: parent

        Canvas {
            id: canvasID
            anchors.fill: parent
            onImageLoaded: requestPaint()
            onPaint: {
                var ctx = getContext("2d");

                if(clickable)
                    ctx.fillStyle = pressedOnArea ? colorPressed : (containsMouse ? colorSelected : colorUnselected)

                ctx.lineWidth = 2;
                ctx.beginPath();

                var corners = coordinates
                var firstTime = true

                if(!hasRoundedCorners){
                    ctx.moveTo(corners['topLeft'].x,corners['topLeft'].y)
                    ctx.lineTo(corners['topRight'].x,corners['topRight'].y)
                    ctx.lineTo(corners['bottomRight'].x,corners['bottomRight'].y)
                    ctx.lineTo(corners['bottomLeft'].x,corners['bottomLeft'].y)
                }
                else{
                    //https://www.w3schools.com/tags/canvas_arcto.asp

                    var radius = sideButtonID.radius

                    if(roundedCorners.includes('TL')){
                        ctx.moveTo(corners['topLeftDown'].x,corners['topLeftDown'].y);
                        ctx.arcTo(corners['topLeftOr'].x,corners['topLeftOr'].y,
                                  corners['topLeftRight'].x+radius, corners['topLeftRight'].y,
                                  radius)
                    }
                    else{
                        ctx.moveTo(corners['topLeftOr'].x,corners['topLeftOr'].y);
                    }

                    if(roundedCorners.includes('TR')){
                        ctx.lineTo(corners['topRightLeft'].x, corners['topRightLeft'].y);
                        ctx.arcTo(corners['topRightOr'].x,corners['topRightOr'].y,
                                  corners['topRightDown'].x, corners['topRightDown'].y+radius,
                                  radius)
                    }
                    else{
                        ctx.lineTo(corners['topRightOr'].x, corners['topRightOr'].y);
                    }


                    if(roundedCorners.includes('BR')){
                        ctx.lineTo(corners['bottomRightTop'].x, corners['bottomRightTop'].y);
                        ctx.arcTo(corners['bottomRightOr'].x,corners['bottomRightOr'].y,
                                  corners['bottomRightLeft'].x - radius, corners['bottomRightLeft'].y,
                                  radius)
                    }
                    else{
                        ctx.lineTo(corners['bottomRightOr'].x, corners['bottomRightOr'].y)
                    }

                    if(roundedCorners.includes('BL')){
                        ctx.lineTo(corners['bottomLeftDown'].x, corners['bottomLeftDown'].y);
                        ctx.arcTo(corners['bottomLeftOr'].x,corners['bottomLeftOr'].y,
                                  corners['bottomLeftLeft'].x, corners['bottomLeftLeft'].y - radius,
                                  radius)
                    }
                    else{
                        ctx.lineTo(corners['bottomLeftOr'].x, corners['bottomLeftOr'].y)
                    }
                }
                ctx.fill()

                if(backgroundImage != ""){
                    ctx.clip()
                    ctx.drawImage(backgroundImage,0,0, parent.width, parent.height);
                }
            }
        }
    }

    Image {
        x: 0
        y: 0
        anchors.right: parent.right
        anchors.rightMargin: 3
        anchors.left: parent.left
        anchors.leftMargin: 6
        clip: true
        anchors.verticalCenterOffset: 0
        anchors.verticalCenter: mouseArea.verticalCenter
        fillMode: Image.PreserveAspectFit
        source: sideButtonID.icon
    }
}

Does any of you what I'm doing wrong and if so how can I fix it? I've spent so many hours and I didn't get the problem because so far as I know all the resolutions are been set right inside of that button.

Mircea
  • 1,671
  • 7
  • 25
  • 41
  • You've got quite a bit of potentially unnecessary complexity going on here. For instance, to do a rounded rectangle, just use Rectangle with a border radius. If you want some corners not rounded, just put a Rectangle as a child in that corner to hide the radius of the parent. Regardless, I find the best success with QML by starting with the simplest structure and layout and then slowly grow it in complexity from there. So, comment out as much as possible and grow it from there. – David K. Hess Apr 15 '20 at 19:09
  • I also recommend breaking this into more components using .ui and .qml files together (i.e. "code behind" approach). That will help you debug components separately before trying to combine them together. – David K. Hess Apr 15 '20 at 19:12
  • Hey, thanks for the feedback but regarding the 2 rectangles, I can't do that. I mean I could use this for this case, but the main purpose of this code is to create polygonal buttons. Which this can't be done with rectangles, so I've thought there is something wrong which I'm doing there. Otherwise, I will do this with 2 rectangles just for this case. – Mircea Apr 15 '20 at 19:51

0 Answers0