RibbonRectangle: Use Canvas to replace Shape due to Qt 5.15's bug.

This commit is contained in:
Mentalflow 2025-05-15 11:13:04 +08:00
parent 51e210ab7b
commit 227f3e5dbe
Signed by: Mentalflow
GPG Key ID: 5AE68D4401A2EE71
2 changed files with 60 additions and 37 deletions

View File

@ -5,7 +5,7 @@ import QtGraphicalEffects 1.15
Item { Item {
id: control id: control
property string color property color color
property int radius: 0 property int radius: 0
property int topLeftRadius: radius property int topLeftRadius: radius
property int topRightRadius: radius property int topRightRadius: radius
@ -19,51 +19,73 @@ Item {
property string borderColor: "transparent" property string borderColor: "transparent"
default property alias contentItem: container.data default property alias contentItem: container.data
Shape { onColorChanged: shape.requestPaint()
onBorderColorChanged: border.requestPaint()
Canvas {
id: shape id: shape
anchors.fill: parent anchors.fill: parent
layer.enabled: true layer.enabled: true
layer.samples: 4 // Workaround for Qt 6.5 and below, for Qt 6.6, just set "preferredRendererType" to "Shape.CurveRenderer" layer.samples: 4
ShapePath {
capStyle: ShapePath.RoundCap onPaint: {
strokeWidth: 0 var ctx = getContext("2d");
strokeColor: "transparent" ctx.clearRect(0, 0, width, height);
fillColor: control.color
joinStyle: ShapePath.RoundJoin var tl = control.topLeftRadius;
startX: control.topLeftRadius; startY: 0 var tr = control.topRightRadius;
PathLine { x: shape.width - control.topRightRadius; y: 0 } var br = control.bottomRightRadius;
PathArc { x: shape.width; y: control.topRightRadius; radiusX: control.topRightRadius; radiusY: radiusX } var bl = control.bottomLeftRadius;
PathLine { x: shape.width; y: shape.height - control.bottomRightRadius }
PathArc { x: shape.width - control.bottomRightRadius; y: shape.height; radiusX: control.bottomRightRadius; radiusY: radiusX } ctx.beginPath();
PathLine { x: control.bottomLeftRadius; y: shape.height } ctx.moveTo(tl, 0);
PathArc { x: 0; y: shape.height - control.bottomLeftRadius; radiusX: control.bottomLeftRadius; radiusY: radiusX } ctx.lineTo(width - tr, 0);
PathLine { x: 0; y: control.topLeftRadius } ctx.arc(width - tr, tr, tr, -Math.PI / 2, 0, false); // top-right
PathArc { x: control.topLeftRadius; y: 0; radiusX: control.topLeftRadius; radiusY: radiusX } ctx.lineTo(width, height - br);
ctx.arc(width - br, height - br, br, 0, Math.PI / 2, false); // bottom-right
ctx.lineTo(bl, height);
ctx.arc(bl, height - bl, bl, Math.PI / 2, Math.PI, false); // bottom-left
ctx.lineTo(0, tl);
ctx.arc(tl, tl, tl, Math.PI, Math.PI * 3 / 2, false); // top-left
ctx.closePath();
ctx.fillStyle = control.color;
ctx.fill();
} }
} }
Shape { Canvas {
id: border id: border
width: shape.width width: shape.width
height: shape.height height: shape.height
anchors.centerIn: parent anchors.centerIn: parent
layer.enabled: true layer.enabled: true
layer.samples: 4 layer.samples: 4
ShapePath {
capStyle: ShapePath.RoundCap onPaint: {
strokeWidth: control.borderWidth * 2 var ctx = getContext("2d");
strokeColor: control.borderColor ctx.clearRect(0, 0, width, height);
fillColor: "transparent"
joinStyle: ShapePath.RoundJoin var tl = control.topLeftRadius;
startX: control.topLeftRadius; startY: 0 var tr = control.topRightRadius;
PathLine { x: border.width - control.topRightRadius; y: 0 } var br = control.bottomRightRadius;
PathArc { x: border.width; y: control.topRightRadius; radiusX: control.topRightRadius; radiusY: radiusX } var bl = control.bottomLeftRadius;
PathLine { x: border.width; y: border.height - control.bottomRightRadius }
PathArc { x: border.width - control.bottomRightRadius; y: border.height; radiusX: control.bottomRightRadius; radiusY: radiusX } ctx.beginPath();
PathLine { x: control.bottomLeftRadius; y: border.height } ctx.moveTo(tl, 0);
PathArc { x: 0; y: border.height - control.bottomLeftRadius; radiusX: control.bottomLeftRadius; radiusY: radiusX } ctx.lineTo(width - tr, 0);
PathLine { x: 0; y: control.topLeftRadius } ctx.arc(width - tr, tr, tr, -Math.PI / 2, 0, false); // top-right
PathArc { x: control.topLeftRadius; y: 0; radiusX: control.topLeftRadius; radiusY: radiusX } ctx.lineTo(width, height - br);
ctx.arc(width - br, height - br, br, 0, Math.PI / 2, false); // bottom-right
ctx.lineTo(bl, height);
ctx.arc(bl, height - bl, bl, Math.PI / 2, Math.PI, false); // bottom-left
ctx.lineTo(0, tl);
ctx.arc(tl, tl, tl, Math.PI, Math.PI * 3 / 2, false); // top-left
ctx.closePath();
ctx.strokeStyle = control.borderColor;
ctx.lineWidth = control.borderWidth * 2;
ctx.stroke();
} }
} }
@ -79,10 +101,11 @@ Item {
clip: true clip: true
layer.enabled: true layer.enabled: true
layer.effect: OpacityMask { layer.effect: OpacityMask {
visible: false
implicitHeight: container.height implicitHeight: container.height
implicitWidth: container.width implicitWidth: container.width
maskSource: shape maskSource: shape
invert: control.color === "transparent" || control.color === "#00000000" invert: control.color.a === 0
} }
} }
} }

View File

@ -5,7 +5,7 @@ import Qt5Compat.GraphicalEffects
Item { Item {
id: control id: control
property string color property color color
property int radius: 0 property int radius: 0
property int topLeftRadius: radius property int topLeftRadius: radius
property int topRightRadius: radius property int topRightRadius: radius
@ -82,7 +82,7 @@ Item {
implicitHeight: container.height implicitHeight: container.height
implicitWidth: container.width implicitWidth: container.width
maskSource: shape maskSource: shape
invert: control.color === "transparent" || control.color === "#00000000" invert: control.color.a === 0
} }
} }
} }