drawing sliders
This commit is contained in:
@@ -0,0 +1,165 @@
|
||||
import QtQuick
|
||||
import QtQuick.Templates
|
||||
import qs.Config
|
||||
|
||||
Slider {
|
||||
id: root
|
||||
|
||||
property color color: DynamicColors.palette.m3secondary
|
||||
required property string icon
|
||||
property bool initialized: false
|
||||
readonly property bool isHorizontal: orientation === Qt.Horizontal
|
||||
readonly property bool isVertical: orientation === Qt.Vertical
|
||||
property real multiplier: 100
|
||||
property real oldValue
|
||||
|
||||
// Wrapper components can inject their own track visuals here.
|
||||
property Component trackContent
|
||||
|
||||
// Keep current behavior for existing usages.
|
||||
orientation: Qt.Vertical
|
||||
|
||||
background: CustomRect {
|
||||
id: groove
|
||||
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
|
||||
height: root.availableHeight
|
||||
radius: Appearance.rounding.full
|
||||
width: root.availableWidth
|
||||
x: root.leftPadding
|
||||
y: root.topPadding
|
||||
|
||||
Loader {
|
||||
id: trackLoader
|
||||
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.trackContent
|
||||
|
||||
onLoaded: {
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
item.rootSlider = root;
|
||||
item.groove = groove;
|
||||
item.handleItem = handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
handle: Item {
|
||||
id: handle
|
||||
|
||||
property alias moving: icon.moving
|
||||
|
||||
implicitHeight: Math.min(root.width, root.height)
|
||||
implicitWidth: Math.min(root.width, root.height)
|
||||
x: root.isHorizontal ? root.leftPadding + root.visualPosition * (root.availableWidth - width) : root.leftPadding + (root.availableWidth - width) / 2
|
||||
y: root.isVertical ? root.topPadding + root.visualPosition * (root.availableHeight - height) : root.topPadding + (root.availableHeight - height) / 2
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
level: handleInteraction.containsMouse ? 2 : 1
|
||||
radius: rect.radius
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: rect
|
||||
|
||||
anchors.fill: parent
|
||||
color: DynamicColors.palette.m3inverseSurface
|
||||
radius: Appearance.rounding.full
|
||||
|
||||
MouseArea {
|
||||
id: handleInteraction
|
||||
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
property bool moving
|
||||
|
||||
function update(): void {
|
||||
animate = !moving;
|
||||
binding.when = moving;
|
||||
font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger;
|
||||
font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material;
|
||||
}
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: DynamicColors.palette.m3inverseOnSurface
|
||||
text: root.icon
|
||||
|
||||
onMovingChanged: anim.restart()
|
||||
|
||||
Binding {
|
||||
id: binding
|
||||
|
||||
property: "text"
|
||||
target: icon
|
||||
value: Math.round(root.value * root.multiplier)
|
||||
when: false
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: anim
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.normal / 2
|
||||
easing.bezierCurve: Appearance.anim.curves.standardAccel
|
||||
property: "scale"
|
||||
target: icon
|
||||
to: 0
|
||||
}
|
||||
|
||||
ScriptAction {
|
||||
script: icon.update()
|
||||
}
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.normal / 2
|
||||
easing.bezierCurve: Appearance.anim.curves.standardDecel
|
||||
property: "scale"
|
||||
target: icon
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Behavior on value {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.large
|
||||
}
|
||||
}
|
||||
|
||||
onPressedChanged: handle.moving = pressed
|
||||
onValueChanged: {
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
oldValue = value;
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(value - oldValue) < 0.01)
|
||||
return;
|
||||
|
||||
oldValue = value;
|
||||
handle.moving = true;
|
||||
stateChangeDelay.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: stateChangeDelay
|
||||
|
||||
interval: 500
|
||||
|
||||
onTriggered: {
|
||||
if (!root.pressed)
|
||||
handle.moving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import qs.Config
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -8,11 +9,18 @@ Item {
|
||||
readonly property real arcStartAngle: 0.75 * Math.PI
|
||||
readonly property real arcSweep: 1.5 * Math.PI
|
||||
property real currentHue: 0
|
||||
property bool dragActive: false
|
||||
required property var drawing
|
||||
property real handleSize: 30
|
||||
readonly property real handleAngle: hueToAngle(currentHue)
|
||||
readonly property real handleCenterX: width / 2 + radius * Math.cos(handleAngle)
|
||||
readonly property real handleCenterY: height / 2 + radius * Math.sin(handleAngle)
|
||||
property real handleSize: 32
|
||||
property real lastChromaticHue: 0
|
||||
property real ringThickness: 12
|
||||
readonly property int segmentCount: 180
|
||||
readonly property real radius: (Math.min(width, height) - handleSize) / 2
|
||||
readonly property int segmentCount: 240
|
||||
readonly property color thumbColor: DynamicColors.palette.m3inverseSurface
|
||||
readonly property color thumbContentColor: DynamicColors.palette.m3inverseOnSurface
|
||||
readonly property color trackColor: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
|
||||
|
||||
function hueToAngle(hue) {
|
||||
return arcStartAngle + arcSweep * hue;
|
||||
@@ -26,18 +34,25 @@ Item {
|
||||
return a;
|
||||
}
|
||||
|
||||
function pointIsOnTrack(x, y) {
|
||||
const cx = width / 2;
|
||||
const cy = height / 2;
|
||||
const dx = x - cx;
|
||||
const dy = y - cy;
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
return distance >= radius - handleSize / 2 && distance <= radius + handleSize / 2;
|
||||
}
|
||||
|
||||
function syncFromPenColor() {
|
||||
if (!drawing)
|
||||
return;
|
||||
|
||||
const c = drawing.penColor;
|
||||
|
||||
// QML color exposes HSL channels directly.
|
||||
// If the current color is chromatic, move the handle to that hue.
|
||||
// If it is achromatic (black/white/gray), keep the last useful hue.
|
||||
if (c.hslSaturation > 0) {
|
||||
currentHue = c.hslHue;
|
||||
lastChromaticHue = c.hslHue;
|
||||
if (c.hsvSaturation > 0) {
|
||||
currentHue = c.hsvHue;
|
||||
lastChromaticHue = c.hsvHue;
|
||||
} else {
|
||||
currentHue = lastChromaticHue;
|
||||
}
|
||||
@@ -45,16 +60,15 @@ Item {
|
||||
canvas.requestPaint();
|
||||
}
|
||||
|
||||
function updateHueFromPoint(x, y) {
|
||||
const cx = canvas.width / 2;
|
||||
const cy = canvas.height / 2;
|
||||
function updateHueFromPoint(x, y, force = false) {
|
||||
const cx = width / 2;
|
||||
const cy = height / 2;
|
||||
const dx = x - cx;
|
||||
const dy = y - cy;
|
||||
|
||||
const distance = Math.sqrt(dx * dx + dy * dy);
|
||||
const radius = (Math.min(canvas.width, canvas.height) - handleSize - 8) / 2;
|
||||
|
||||
if (distance < radius - 24 || distance > radius + 24)
|
||||
if (!force && (distance < radius - handleSize / 2 || distance > radius + handleSize / 2))
|
||||
return;
|
||||
|
||||
const angle = normalizeAngle(Math.atan2(dy, dx));
|
||||
@@ -71,7 +85,7 @@ Item {
|
||||
|
||||
currentHue = relative / arcSweep;
|
||||
lastChromaticHue = currentHue;
|
||||
drawing.penColor = Qt.hsla(currentHue, 1.0, 0.5, 1.0);
|
||||
drawing.penColor = Qt.hsva(currentHue, drawing.penColor.hsvSaturation, drawing.penColor.hsvValue, drawing.penColor.a);
|
||||
}
|
||||
|
||||
implicitHeight: 180
|
||||
@@ -80,6 +94,9 @@ Item {
|
||||
Component.onCompleted: syncFromPenColor()
|
||||
onCurrentHueChanged: canvas.requestPaint()
|
||||
onDrawingChanged: syncFromPenColor()
|
||||
onHandleSizeChanged: canvas.requestPaint()
|
||||
onHeightChanged: canvas.requestPaint()
|
||||
onWidthChanged: canvas.requestPaint()
|
||||
|
||||
Connections {
|
||||
function onPenColorChanged() {
|
||||
@@ -97,7 +114,6 @@ Item {
|
||||
renderTarget: Canvas.Image
|
||||
|
||||
Component.onCompleted: requestPaint()
|
||||
onHeightChanged: requestPaint()
|
||||
onPaint: {
|
||||
const ctx = getContext("2d");
|
||||
ctx.reset();
|
||||
@@ -105,15 +121,10 @@ Item {
|
||||
|
||||
const cx = width / 2;
|
||||
const cy = height / 2;
|
||||
const radius = (Math.min(width, height) - root.handleSize - 8) / 2;
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, radius, root.arcStartAngle, root.arcStartAngle + root.arcSweep);
|
||||
ctx.lineWidth = root.ringThickness + 4;
|
||||
ctx.lineCap = "round";
|
||||
ctx.strokeStyle = Qt.rgba(1, 1, 1, 0.12);
|
||||
ctx.stroke();
|
||||
const radius = root.radius;
|
||||
const trackWidth = root.handleSize;
|
||||
|
||||
// Background track: always show the full hue spectrum
|
||||
for (let i = 0; i < root.segmentCount; ++i) {
|
||||
const t1 = i / root.segmentCount;
|
||||
const t2 = (i + 1) / root.segmentCount;
|
||||
@@ -122,49 +133,76 @@ Item {
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(cx, cy, radius, a1, a2);
|
||||
ctx.lineWidth = root.ringThickness;
|
||||
ctx.lineWidth = trackWidth;
|
||||
ctx.lineCap = "round";
|
||||
ctx.strokeStyle = Qt.hsla(t1, 1.0, 0.5, 1.0);
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
const handleAngle = root.hueToAngle(root.currentHue);
|
||||
const hx = cx + radius * Math.cos(handleAngle);
|
||||
const hy = cy + radius * Math.sin(handleAngle);
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(hx, hy, root.handleSize / 2, 0, Math.PI * 2);
|
||||
ctx.fillStyle = Qt.rgba(1, 1, 1, 0.95);
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(hx, hy, root.handleSize / 2, 0, Math.PI * 2);
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.strokeStyle = Qt.rgba(0, 0, 0, 0.18);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(hx, hy, root.handleSize / 2 - 6, 0, Math.PI * 2);
|
||||
ctx.fillStyle = root.drawing.penColor;
|
||||
ctx.fill();
|
||||
|
||||
ctx.beginPath();
|
||||
ctx.arc(hx, hy, root.handleSize / 2 - 6, 0, Math.PI * 2);
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeStyle = Qt.rgba(0, 0, 0, 0.20);
|
||||
ctx.stroke();
|
||||
}
|
||||
onWidthChanged: requestPaint()
|
||||
}
|
||||
|
||||
Item {
|
||||
id: handle
|
||||
|
||||
height: root.handleSize
|
||||
width: root.handleSize
|
||||
x: root.handleCenterX - width / 2
|
||||
y: root.handleCenterY - height / 2
|
||||
z: 1
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
level: handleHover.containsMouse ? 2 : 1
|
||||
radius: rect.radius
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: rect
|
||||
|
||||
anchors.fill: parent
|
||||
color: root.thumbColor
|
||||
radius: width / 2
|
||||
|
||||
MouseArea {
|
||||
id: handleHover
|
||||
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
color: root.drawing ? root.drawing.penColor : Qt.hsla(root.currentHue, 1.0, 0.5, 1.0)
|
||||
height: width
|
||||
radius: width / 2
|
||||
width: parent.width - 12
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
|
||||
acceptedButtons: Qt.LeftButton
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
|
||||
onCanceled: {
|
||||
root.dragActive = false;
|
||||
}
|
||||
onPositionChanged: mouse => {
|
||||
if (mouse.buttons & Qt.LeftButton)
|
||||
if ((mouse.buttons & Qt.LeftButton) && root.dragActive)
|
||||
root.updateHueFromPoint(mouse.x, mouse.y, true);
|
||||
}
|
||||
onPressed: mouse => {
|
||||
root.dragActive = root.pointIsOnTrack(mouse.x, mouse.y);
|
||||
if (root.dragActive)
|
||||
root.updateHueFromPoint(mouse.x, mouse.y);
|
||||
}
|
||||
onPressed: mouse => root.updateHueFromPoint(mouse.x, mouse.y)
|
||||
onReleased: {
|
||||
root.dragActive = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+16
-128
@@ -1,141 +1,29 @@
|
||||
import QtQuick
|
||||
import QtQuick.Templates
|
||||
import qs.Config
|
||||
|
||||
Slider {
|
||||
BaseStyledSlider {
|
||||
id: root
|
||||
|
||||
property color color: DynamicColors.palette.m3secondary
|
||||
required property string icon
|
||||
property bool initialized
|
||||
property real oldValue
|
||||
trackContent: Component {
|
||||
Item {
|
||||
property var groove
|
||||
readonly property real handleHeight: handleItem ? handleItem.height : 0
|
||||
property var handleItem
|
||||
readonly property real handleWidth: handleItem ? handleItem.width : 0
|
||||
|
||||
orientation: Qt.Vertical
|
||||
|
||||
background: CustomRect {
|
||||
color: DynamicColors.layer(DynamicColors.palette.m3surfaceContainer, 2)
|
||||
radius: Appearance.rounding.full
|
||||
|
||||
CustomRect {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: root.color
|
||||
implicitHeight: parent.height - y
|
||||
radius: parent.radius
|
||||
y: root.handle.y
|
||||
}
|
||||
}
|
||||
handle: Item {
|
||||
id: handle
|
||||
|
||||
property alias moving: icon.moving
|
||||
|
||||
implicitHeight: root.width
|
||||
implicitWidth: root.width
|
||||
y: root.visualPosition * (root.availableHeight - height)
|
||||
|
||||
Elevation {
|
||||
anchors.fill: parent
|
||||
level: handleInteraction.containsMouse ? 2 : 1
|
||||
radius: rect.radius
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
id: rect
|
||||
// Set by BaseStyledSlider's Loader
|
||||
property var rootSlider
|
||||
|
||||
anchors.fill: parent
|
||||
color: DynamicColors.palette.m3inverseSurface
|
||||
radius: Appearance.rounding.full
|
||||
|
||||
MouseArea {
|
||||
id: handleInteraction
|
||||
|
||||
acceptedButtons: Qt.NoButton
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
CustomRect {
|
||||
color: rootSlider?.color
|
||||
height: rootSlider?.isVertical ? handleHeight + (1 - rootSlider?.visualPosition) * (groove?.height - handleHeight) : groove?.height
|
||||
radius: groove?.radius
|
||||
width: rootSlider?.isHorizontal ? handleWidth + rootSlider?.visualPosition * (groove?.width - handleWidth) : groove?.width
|
||||
x: rootSlider?.isHorizontal ? (rootSlider?.mirrored ? groove?.width - width : 0) : 0
|
||||
y: rootSlider?.isVertical ? groove?.height - height : 0
|
||||
}
|
||||
|
||||
MaterialIcon {
|
||||
id: icon
|
||||
|
||||
property bool moving
|
||||
|
||||
function update(): void {
|
||||
animate = !moving;
|
||||
binding.when = moving;
|
||||
font.pointSize = moving ? Appearance.font.size.small : Appearance.font.size.larger;
|
||||
font.family = moving ? Appearance.font.family.sans : Appearance.font.family.material;
|
||||
}
|
||||
|
||||
anchors.centerIn: parent
|
||||
color: DynamicColors.palette.m3inverseOnSurface
|
||||
text: root.icon
|
||||
|
||||
onMovingChanged: anim.restart()
|
||||
|
||||
Binding {
|
||||
id: binding
|
||||
|
||||
property: "text"
|
||||
target: icon
|
||||
value: Math.round(root.value * 100)
|
||||
when: false
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
id: anim
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.normal / 2
|
||||
easing.bezierCurve: Appearance.anim.curves.standardAccel
|
||||
property: "scale"
|
||||
target: icon
|
||||
to: 0
|
||||
}
|
||||
|
||||
ScriptAction {
|
||||
script: icon.update()
|
||||
}
|
||||
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.normal / 2
|
||||
easing.bezierCurve: Appearance.anim.curves.standardDecel
|
||||
property: "scale"
|
||||
target: icon
|
||||
to: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Behavior on value {
|
||||
Anim {
|
||||
duration: Appearance.anim.durations.large
|
||||
}
|
||||
}
|
||||
|
||||
onPressedChanged: handle.moving = pressed
|
||||
onValueChanged: {
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
return;
|
||||
}
|
||||
if (Math.abs(value - oldValue) < 0.01)
|
||||
return;
|
||||
oldValue = value;
|
||||
handle.moving = true;
|
||||
stateChangeDelay.restart();
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: stateChangeDelay
|
||||
|
||||
interval: 500
|
||||
|
||||
onTriggered: {
|
||||
if (!root.pressed)
|
||||
handle.moving = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import QtQuick
|
||||
import qs.Config
|
||||
|
||||
BaseStyledSlider {
|
||||
id: root
|
||||
|
||||
property real alpha: 1.0
|
||||
property real brightness: 1.0
|
||||
property string channel: "saturation"
|
||||
readonly property color currentColor: Qt.hsva(hue, channel === "saturation" ? value : saturation, channel === "brightness" ? value : brightness, alpha)
|
||||
property real hue: 0.0
|
||||
property real saturation: 1.0
|
||||
|
||||
from: 0
|
||||
to: 1
|
||||
|
||||
trackContent: Component {
|
||||
Item {
|
||||
property var groove
|
||||
property var handleItem
|
||||
property var rootSlider
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
color: "transparent"
|
||||
radius: groove?.radius ?? 0
|
||||
|
||||
gradient: Gradient {
|
||||
orientation: rootSlider?.isHorizontal ? Gradient.Horizontal : Gradient.Vertical
|
||||
|
||||
GradientStop {
|
||||
color: root.channel === "saturation" ? Qt.hsva(root.hue, 0.0, root.brightness, root.alpha) : Qt.hsva(root.hue, root.saturation, 0.0, root.alpha)
|
||||
position: 0.0
|
||||
}
|
||||
|
||||
GradientStop {
|
||||
color: root.channel === "saturation" ? Qt.hsva(root.hue, 1.0, root.brightness, root.alpha) : Qt.hsva(root.hue, root.saturation, 1.0, root.alpha)
|
||||
position: 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+91
-16
@@ -12,10 +12,40 @@ Item {
|
||||
required property Canvas drawing
|
||||
required property var visibilities
|
||||
|
||||
implicitHeight: huePicker.implicitHeight + 12 + palette.implicitHeight + Appearance.padding.normal * 2
|
||||
function syncFromPenColor() {
|
||||
if (!drawing)
|
||||
return;
|
||||
|
||||
if (!saturationSlider.pressed)
|
||||
saturationSlider.value = drawing.penColor.hsvSaturation;
|
||||
|
||||
if (!brightnessSlider.pressed)
|
||||
brightnessSlider.value = drawing.penColor.hsvValue;
|
||||
}
|
||||
|
||||
function updatePenColorFromHsv() {
|
||||
if (!drawing)
|
||||
return;
|
||||
|
||||
drawing.penColor = Qt.hsva(huePicker.currentHue, saturationSlider.value, brightnessSlider.value, drawing.penColor.a);
|
||||
}
|
||||
|
||||
implicitHeight: column.height + Appearance.padding.larger * 2
|
||||
implicitWidth: huePicker.implicitWidth + Appearance.padding.normal * 2
|
||||
|
||||
Component.onCompleted: syncFromPenColor()
|
||||
|
||||
Connections {
|
||||
function onPenColorChanged() {
|
||||
root.syncFromPenColor();
|
||||
}
|
||||
|
||||
target: root.drawing
|
||||
}
|
||||
|
||||
Column {
|
||||
id: column
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: 12
|
||||
|
||||
@@ -25,6 +55,38 @@ Item {
|
||||
drawing: root.drawing
|
||||
}
|
||||
|
||||
GradientSlider {
|
||||
id: saturationSlider
|
||||
|
||||
brightness: brightnessSlider.value
|
||||
channel: "saturation"
|
||||
from: 0
|
||||
hue: huePicker.currentHue
|
||||
icon: "\ue40a"
|
||||
implicitHeight: 30
|
||||
implicitWidth: palette.width
|
||||
orientation: Qt.Horizontal
|
||||
to: 1
|
||||
|
||||
onMoved: root.updatePenColorFromHsv()
|
||||
}
|
||||
|
||||
GradientSlider {
|
||||
id: brightnessSlider
|
||||
|
||||
channel: "brightness"
|
||||
from: 0
|
||||
hue: huePicker.currentHue
|
||||
icon: "\ue1ac"
|
||||
implicitHeight: 30
|
||||
implicitWidth: palette.width
|
||||
orientation: Qt.Horizontal
|
||||
saturation: saturationSlider.value
|
||||
to: 1
|
||||
|
||||
onMoved: root.updatePenColorFromHsv()
|
||||
}
|
||||
|
||||
GridLayout {
|
||||
id: palette
|
||||
|
||||
@@ -38,12 +100,24 @@ Item {
|
||||
model: root.colors
|
||||
|
||||
delegate: Item {
|
||||
id: colorCircle
|
||||
|
||||
required property color modelData
|
||||
readonly property bool selected: Qt.colorEqual(root.drawing.penColor, modelData)
|
||||
|
||||
Layout.fillWidth: true
|
||||
height: 28
|
||||
|
||||
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)
|
||||
@@ -52,25 +126,26 @@ Item {
|
||||
height: parent.height
|
||||
radius: width / 2
|
||||
width: parent.height
|
||||
}
|
||||
|
||||
CustomRect {
|
||||
anchors.centerIn: parent
|
||||
border.color: Qt.rgba(0, 0, 0, 0.25)
|
||||
border.width: Qt.colorEqual(modelData, "#ffffff") ? 1 : 0
|
||||
color: modelData
|
||||
height: 20
|
||||
radius: width / 2
|
||||
width: 20
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
|
||||
onClicked: root.drawing.penColor = parent.modelData
|
||||
StateLayer {
|
||||
onClicked: root.drawing.penColor = colorCircle.modelData
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FilledSlider {
|
||||
from: 1
|
||||
icon: "border_color"
|
||||
implicitHeight: 30
|
||||
implicitWidth: palette.width
|
||||
multiplier: 1
|
||||
orientation: Qt.Horizontal
|
||||
to: 45
|
||||
value: root.drawing.penWidth
|
||||
|
||||
onMoved: root.drawing.penWidth = value
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user