Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QML ListView Resize Custom Widget delegate



  • 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 actual 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.


Log in to reply