preset color buttons rework + curve smoothing
Lint & Format (JS/TS) / lint-format (pull_request) Successful in 9s
Python / lint-format (pull_request) Successful in 17s
Python / test (pull_request) Successful in 30s
Lint & Format (Rust) / lint-format (pull_request) Successful in 1m6s

This commit is contained in:
2026-06-20 13:24:47 +02:00
parent ca1243f9c7
commit fc9be754fd
6 changed files with 103 additions and 49 deletions
+8
View File
@@ -91,6 +91,14 @@ Item {
implicitHeight: 180
implicitWidth: 220
Behavior on currentHue {
enabled: !root.dragActive
Anim {
type: Anim.StandardLarge
}
}
Component.onCompleted: syncFromPenColor()
onCurrentHueChanged: canvas.requestPaint()
onDrawingChanged: syncFromPenColor()
+6 -6
View File
@@ -123,7 +123,7 @@ Item {
property bool setInitialPoint: false
acceptedButtons: Qt.LeftButton | Qt.RightButton
enabled: root.visibilities.isDrawing
enabled: root.visibilities.isDrawing && !root.inLeftPanel(root.panels.drawing, hoverHandler.point.position.x, hoverHandler.point.position.y)
grabPermissions: PointerHandler.CanTakeOverFromAnything | PointerHandler.TakeOverForbidden
onActiveChanged: {
@@ -135,15 +135,15 @@ Item {
}
}
onPointChanged: {
if (point.pressedButtons & Qt.RightButton) {
root.drawing.clear();
return;
}
const x = point.position.x;
const y = point.position.y;
const origX = point.pressPosition.x;
const origY = point.pressPosition.y;
if (point.pressedButtons & Qt.RightButton) {
root.drawing.clear();
return;
}
if (x === 0 && y === 0 && origX === 0 && origY === 0)
return;
+27
View File
@@ -370,6 +370,33 @@ CustomWindow {
sourceComponent: Drawing {
id: drawing
layer.enabled: true
layer.effect: MultiEffect {
maskEnabled: true
maskInverted: true
maskSource: maskSource
}
}
}
Item {
id: maskSource
anchors.fill: parent
layer.enabled: true
visible: false
CustomRect {
readonly property int extraWidth: radius
color: "white"
implicitHeight: panels.drawing.height
implicitWidth: panels.drawing.width + extraWidth
radius: drawingBg.radius
x: -extraWidth + root.borderThickness + panels.drawing.x
y: panels.drawing.y + bar.implicitHeight
}
}
+40 -40
View File
@@ -2,13 +2,15 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Layouts
import ZShell.Components
import qs.Config
import qs.Components
Item {
id: root
readonly property var colors: ["#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#a855f7", "#ec4899", "#ffffff", "#000000"]
readonly property var colors1: ["#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4"]
readonly property var colors2: ["#3b82f6", "#a855f7", "#ec4899", "#ffffff", "#000000"]
required property var drawing
required property var visibilities
@@ -58,13 +60,14 @@ Item {
GradientSlider {
id: saturationSlider
anchors.left: parent.left
anchors.right: parent.right
brightness: brightnessSlider.value
channel: "saturation"
from: 0
hue: huePicker.currentHue
icon: "\ue40a"
implicitHeight: 30
implicitWidth: palette.width
orientation: Qt.Horizontal
to: 1
@@ -74,12 +77,13 @@ Item {
GradientSlider {
id: brightnessSlider
anchors.left: parent.left
anchors.right: parent.right
channel: "brightness"
from: 0
hue: huePicker.currentHue
icon: "\ue1ac"
implicitHeight: 30
implicitWidth: palette.width
orientation: Qt.Horizontal
saturation: saturationSlider.value
to: 1
@@ -87,59 +91,38 @@ Item {
onMoved: root.updatePenColorFromHsv()
}
GridLayout {
id: palette
ButtonRow {
anchors.left: parent.left
anchors.right: parent.right
columns: 5
rowSpacing: 8
rows: 2
spacing: Appearance.spacing.normal
Repeater {
model: root.colors
model: root.colors1
delegate: Item {
id: colorCircle
delegate: ColorButton {
}
}
}
required property color modelData
readonly property bool selected: Qt.colorEqual(root.drawing.penColor, modelData)
ButtonRow {
anchors.left: parent.left
anchors.right: parent.right
spacing: Appearance.spacing.normal
Layout.fillWidth: true
height: 28
Repeater {
model: root.colors2
CustomRect {
anchors.centerIn: parent
border.color: Qt.rgba(0, 0, 0, 0.25)
border.width: Qt.colorEqual(modelData, "#ffffff") ? 1 : 0
color: colorCircle.modelData
height: 20
radius: width / 2
width: 20
}
CustomRect {
anchors.centerIn: parent
border.color: selected ? "#ffffff" : Qt.rgba(1, 1, 1, 0.28)
border.width: selected ? 3 : 1
color: "transparent"
height: parent.height
radius: width / 2
width: parent.height
StateLayer {
onClicked: root.drawing.penColor = colorCircle.modelData
}
}
delegate: ColorButton {
}
}
}
FilledSlider {
anchors.left: parent.left
anchors.right: parent.right
from: 1
icon: "border_color"
implicitHeight: 30
implicitWidth: palette.width
multiplier: 1
orientation: Qt.Horizontal
to: 45
@@ -148,4 +131,21 @@ Item {
onMoved: root.drawing.penWidth = value
}
}
component ColorButton: IconButton {
id: colorButton
required property color modelData
fillWidth: false
icon: ""
inactiveColor: modelData
inactiveOnColor: DynamicColors.on(modelData)
isRound: true
padding: Appearance.padding.extraSmall
shapeMorph: true
shapeMorphExpansion: pressed ? 12 : 0
onClicked: root.drawing.penColor = modelData
}
}
+17 -1
View File
@@ -13,6 +13,20 @@ QCanvasPainterItemRenderer *StrokeCanvasItem::createItemRenderer() const {
return new StrokeCanvasRenderer;
}
static bool shouldAddPoint(
const QVector<QPointF> &points,
const QPointF &p,
qreal minDistance)
{
if (points.isEmpty())
return true;
const QPointF delta = p - points.last();
return QPointF::dotProduct(delta, delta)
>= minDistance * minDistance;
}
void StrokeCanvasItem::setPenColor(const QColor &color) {
if (m_penColor == color)
return;
@@ -44,7 +58,9 @@ void StrokeCanvasItem::beginStroke(qreal x, qreal y) {
}
void StrokeCanvasItem::appendPoint(qreal x, qreal y) {
m_currentStroke.points.append({x, y});
if (shouldAddPoint(m_currentStroke.points, {x, y}, 2.0))
m_currentStroke.points.append({x, y});
update();
}
@@ -28,8 +28,11 @@ static void drawStroke(
painter->beginPath();
painter->moveTo(points[0]);
for (qsizetype i = 1; i < points.size(); ++i)
painter->lineTo(points[i]);
for (int i = 1; i < points.size() - 1; ++i) {
QPointF mid = (points[i] + points [i + 1]) / 2;
painter->quadraticCurveTo(points[i], mid);
}
painter->lineTo(points.last());
painter->stroke();
}