QmlDesigner: Fix ColorEditor

* Change the look of the picker cross
* Cleanup custom RGB, HSL, HSV and Alpha value storage and handling
* Fix issue of alpha not updating when selecting gradient stops
* Fix initial color not shown correctly
* Fix ComboBox warning about parameter injection
* Add checkerboard image to GradientLine
* Remove GradientPopupIndicator
* Add signals to RealSpinBox in order to react to user interaction
* Cleanup code
* Change how porperty editor value emits value if old and new color are
  equal

Task-number: QDS-4755
Change-Id: I1a8095664fc8ed53c52659ac20557c03b89704c9
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
This commit is contained in:
Henning Gruendl
2021-08-20 17:37:17 +02:00
committed by Henning Gründl
parent 74bfae6a4a
commit 04c36419f7
12 changed files with 366 additions and 288 deletions

View File

@@ -189,8 +189,20 @@ SecondColumnLayout {
colorEditor.originalColor = colorEditor.color colorEditor.originalColor = colorEditor.color
} }
onValueChanged: colorEditor.color = colorEditor.value Connections {
onBackendValueChanged: colorEditor.color = colorEditor.value id: backendConnection
target: colorEditor
function onValueChanged() {
if (isNotInGradientMode())
colorEditor.color = colorEditor.value
}
function onBackendValueChanged() {
if (isNotInGradientMode())
colorEditor.color = colorEditor.value
}
}
Timer { Timer {
id: colorEditorTimer id: colorEditorTimer
@@ -198,15 +210,18 @@ SecondColumnLayout {
interval: 100 interval: 100
running: false running: false
onTriggered: { onTriggered: {
backendConnection.enabled = false
if (colorEditor.backendValue !== undefined) { if (colorEditor.backendValue !== undefined) {
if (isVector3D) { if (colorEditor.isVector3D)
colorEditor.backendValue.value = Qt.vector3d(colorEditor.color.r, colorEditor.backendValue.value = Qt.vector3d(colorEditor.color.r,
colorEditor.color.g, colorEditor.color.g,
colorEditor.color.b) colorEditor.color.b)
} else { else
colorEditor.backendValue.value = colorEditor.color colorEditor.backendValue.value = colorEditor.color
}
} }
backendConnection.enabled = true
} }
} }
@@ -223,8 +238,6 @@ SecondColumnLayout {
if (isNotInGradientMode()) if (isNotInGradientMode())
colorEditorTimer.restart() // Delay setting the color to keep ui responsive colorEditorTimer.restart() // Delay setting the color to keep ui responsive
colorPalette.selectedColor = colorEditor.color
} }
Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth } Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth }
@@ -419,6 +432,7 @@ SecondColumnLayout {
tooltip: qsTr("Transparent") tooltip: qsTr("Transparent")
onClicked: { onClicked: {
colorPicker.alpha = 0 colorPicker.alpha = 0
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
@@ -503,8 +517,10 @@ SecondColumnLayout {
visible: !isNotInGradientMode() visible: !isNotInGradientMode()
onCurrentColorChanged: { onCurrentColorChanged: {
if (colorEditor.supportGradient && gradientLine.hasGradient) if (colorEditor.supportGradient && gradientLine.hasGradient) {
colorEditor.color = gradientLine.currentColor colorEditor.color = gradientLine.currentColor
colorPicker.color = colorEditor.color
}
} }
onHasGradientChanged: { onHasGradientChanged: {
@@ -515,9 +531,8 @@ SecondColumnLayout {
} }
onSelectedNodeChanged: { onSelectedNodeChanged: {
if (colorEditor.supportGradient && gradientLine.hasGradient) { if (colorEditor.supportGradient && gradientLine.hasGradient)
colorEditor.originalColor = gradientLine.currentColor colorEditor.originalColor = gradientLine.currentColor
}
} }
onInvalidated: colorEditor.updateThumbnail() onInvalidated: colorEditor.updateThumbnail()
@@ -546,13 +561,15 @@ SecondColumnLayout {
function onSelectionChanged() { function onSelectionChanged() {
if (colorEditor.supportGradient && gradientLine.hasGradient) { if (colorEditor.supportGradient && gradientLine.hasGradient) {
colorEditor.color = gradientLine.currentColor colorEditor.color = gradientLine.currentColor
gradientLine.currentColor = color gradientLine.currentColor = colorEditor.color
hexTextField.text = colorEditor.color hexTextField.text = colorEditor.color
popupHexTextField.text = colorEditor.color popupHexTextField.text = colorEditor.color
} }
gradientLine.isInValidState = true gradientLine.isInValidState = true
colorEditor.originalColor = colorEditor.color colorEditor.originalColor = colorEditor.color
colorPalette.selectedColor = colorEditor.color colorPalette.selectedColor = colorEditor.color
colorPicker.color = colorEditor.color
colorEditor.createModel() colorEditor.createModel()
colorEditor.determineActiveColorMode() colorEditor.determineActiveColorMode()
@@ -563,44 +580,32 @@ SecondColumnLayout {
ColorPicker { ColorPicker {
id: colorPicker id: colorPicker
property color boundColor: colorEditor.color
width: parent.width width: parent.width
sliderMargins: 4 sliderMargins: 4
// Prevent the binding to be deleted by assignment
onBoundColorChanged: colorPicker.color = colorPicker.boundColor
onUpdateColor: { onUpdateColor: {
colorEditor.color = colorPicker.color colorEditor.color = colorPicker.color
if (contextMenu.opened) if (contextMenu.opened)
contextMenu.close() contextMenu.close()
} }
onRightMouseButtonClicked: contextMenu.popup(colorPicker) onRightMouseButtonClicked: contextMenu.popup(colorPicker)
onColorInvalidated: { onColorInvalidated: {
switch (colorPicker.mode) { hslHueSpinBox.value = colorPicker.hue
case ColorPicker.Mode.HSLA: hslSaturationSpinBox.value = colorPicker.saturationHSL
hslHueSpinBox.value = colorPicker.hue hslLightnessSpinBox.value = colorPicker.lightness
hslSaturationSpinBox.value = colorPicker.saturationHSL hslAlphaSpinBox.value = colorPicker.alpha
hslLightnessSpinBox.value = colorPicker.lightness
hslAlphaSpinBox.value = colorPicker.alpha
break
case ColorPicker.Mode.RGBA: redSpinBox.value = (colorPicker.red * 255)
redSpinBox.value = (colorPicker.color.r * 255) greenSpinBox.value = (colorPicker.green * 255)
greenSpinBox.value = (colorPicker.color.g * 255) blueSpinBox.value = (colorPicker.blue * 255)
blueSpinBox.value = (colorPicker.color.b * 255) rgbAlphaSpinBox.value = (colorPicker.alpha * 255)
rgbAlphaSpinBox.value = (colorPicker.alpha * 255)
break
case ColorPicker.Mode.HSVA: hsvHueSpinBox.value = colorPicker.hue
default: hsvSaturationSpinBox.value = colorPicker.saturationHSV
hsvHueSpinBox.value = colorPicker.hue hsvValueSpinBox.value = colorPicker.value
hsvSaturationSpinBox.value = colorPicker.saturationHSV hsvAlphaSpinBox.value = colorPicker.alpha
hsvValueSpinBox.value = colorPicker.value
hsvAlphaSpinBox.value = colorPicker.alpha
break
}
} }
} }
@@ -790,7 +795,6 @@ SecondColumnLayout {
RowLayout { RowLayout {
id: rgbaRow id: rgbaRow
visible: colorPicker.mode === ColorPicker.Mode.RGBA visible: colorPicker.mode === ColorPicker.Mode.RGBA
Layout.fillWidth: true Layout.fillWidth: true
spacing: StudioTheme.Values.controlGap spacing: StudioTheme.Values.controlGap
@@ -798,7 +802,6 @@ SecondColumnLayout {
DoubleSpinBox { DoubleSpinBox {
id: redSpinBox id: redSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
stepSize: 1 stepSize: 1
minimumValue: 0 minimumValue: 0
maximumValue: 255 maximumValue: 255
@@ -806,17 +809,19 @@ SecondColumnLayout {
onValueModified: { onValueModified: {
var tmp = redSpinBox.value / 255.0 var tmp = redSpinBox.value / 255.0
if (colorPicker.color.r !== tmp && !colorPicker.block) { if (colorPicker.red !== tmp && !colorPicker.block) {
colorPicker.color.r = tmp colorPicker.red = tmp
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
id: greenSpinBox id: greenSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
stepSize: 1 stepSize: 1
minimumValue: 0 minimumValue: 0
maximumValue: 255 maximumValue: 255
@@ -824,17 +829,19 @@ SecondColumnLayout {
onValueModified: { onValueModified: {
var tmp = greenSpinBox.value / 255.0 var tmp = greenSpinBox.value / 255.0
if (colorPicker.color.g !== tmp && !colorPicker.block) { if (colorPicker.green !== tmp && !colorPicker.block) {
colorPicker.color.g = tmp colorPicker.green = tmp
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
id: blueSpinBox id: blueSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
stepSize: 1 stepSize: 1
minimumValue: 0 minimumValue: 0
maximumValue: 255 maximumValue: 255
@@ -842,17 +849,19 @@ SecondColumnLayout {
onValueModified: { onValueModified: {
var tmp = blueSpinBox.value / 255.0 var tmp = blueSpinBox.value / 255.0
if (colorPicker.color.b !== tmp && !colorPicker.block) { if (colorPicker.blue !== tmp && !colorPicker.block) {
colorPicker.color.b = tmp colorPicker.blue = tmp
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
id: rgbAlphaSpinBox id: rgbAlphaSpinBox
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
stepSize: 1 stepSize: 1
minimumValue: 0 minimumValue: 0
maximumValue: 255 maximumValue: 255
@@ -862,15 +871,17 @@ SecondColumnLayout {
var tmp = rgbAlphaSpinBox.value / 255.0 var tmp = rgbAlphaSpinBox.value / 255.0
if (colorPicker.alpha !== tmp && !colorPicker.block) { if (colorPicker.alpha !== tmp && !colorPicker.block) {
colorPicker.alpha = tmp colorPicker.alpha = tmp
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
} }
RowLayout { RowLayout {
id: hslaRow id: hslaRow
visible: colorPicker.mode === ColorPicker.Mode.HSLA visible: colorPicker.mode === ColorPicker.Mode.HSLA
Layout.fillWidth: true Layout.fillWidth: true
spacing: StudioTheme.Values.controlGap spacing: StudioTheme.Values.controlGap
@@ -882,9 +893,12 @@ SecondColumnLayout {
if (colorPicker.hue !== hslHueSpinBox.value if (colorPicker.hue !== hslHueSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.hue = hslHueSpinBox.value colorPicker.hue = hslHueSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
@@ -894,9 +908,12 @@ SecondColumnLayout {
if (colorPicker.saturationHSL !== hslSaturationSpinBox.value if (colorPicker.saturationHSL !== hslSaturationSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.saturationHSL = hslSaturationSpinBox.value colorPicker.saturationHSL = hslSaturationSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
@@ -906,6 +923,7 @@ SecondColumnLayout {
if (colorPicker.lightness !== hslLightnessSpinBox.value if (colorPicker.lightness !== hslLightnessSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.lightness = hslLightnessSpinBox.value colorPicker.lightness = hslLightnessSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
@@ -918,15 +936,17 @@ SecondColumnLayout {
if (colorPicker.alpha !== hslAlphaSpinBox.value if (colorPicker.alpha !== hslAlphaSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.alpha = hslAlphaSpinBox.value colorPicker.alpha = hslAlphaSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
} }
RowLayout { RowLayout {
id: hsvaRow id: hsvaRow
visible: colorPicker.mode === ColorPicker.Mode.HSVA visible: colorPicker.mode === ColorPicker.Mode.HSVA
Layout.fillWidth: true Layout.fillWidth: true
spacing: StudioTheme.Values.controlGap spacing: StudioTheme.Values.controlGap
@@ -938,9 +958,12 @@ SecondColumnLayout {
if (colorPicker.hue !== hsvHueSpinBox.value if (colorPicker.hue !== hsvHueSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.hue = hsvHueSpinBox.value colorPicker.hue = hsvHueSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
@@ -950,9 +973,12 @@ SecondColumnLayout {
if (colorPicker.saturationHSV !== hsvSaturationSpinBox.value if (colorPicker.saturationHSV !== hsvSaturationSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.saturationHSV = hsvSaturationSpinBox.value colorPicker.saturationHSV = hsvSaturationSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
@@ -962,9 +988,12 @@ SecondColumnLayout {
if (colorPicker.value !== hsvValueSpinBox.value if (colorPicker.value !== hsvValueSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.value = hsvValueSpinBox.value colorPicker.value = hsvValueSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
DoubleSpinBox { DoubleSpinBox {
@@ -974,9 +1003,12 @@ SecondColumnLayout {
if (colorPicker.alpha !== hsvAlphaSpinBox.value if (colorPicker.alpha !== hsvAlphaSpinBox.value
&& !colorPicker.block) { && !colorPicker.block) {
colorPicker.alpha = hsvAlphaSpinBox.value colorPicker.alpha = hsvAlphaSpinBox.value
colorPicker.invalidateColor()
colorPicker.updateColor() colorPicker.updateColor()
} }
} }
onDragStarted: colorEditorTimer.stop()
onIndicatorPressed: colorEditorTimer.stop()
} }
} }
} }
@@ -986,7 +1018,6 @@ SecondColumnLayout {
caption: qsTr("Palette") caption: qsTr("Palette")
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
leftPadding: 10 leftPadding: 10
rightPadding: 10 rightPadding: 10
bottomPadding: 5 bottomPadding: 5
@@ -994,8 +1025,14 @@ SecondColumnLayout {
ColorPalette { ColorPalette {
id: colorPalette id: colorPalette
enableSingletonConnection: cePopup.opened enableSingletonConnection: cePopup.opened
onSelectedColorChanged: colorEditor.color = colorPalette.selectedColor onSelectedColorChanged: {
onDialogColorChanged: colorEditor.color = colorPalette.selectedColor colorPicker.color = colorPalette.selectedColor
colorEditor.color = colorPalette.selectedColor
}
onDialogColorChanged: {
colorPicker.color = colorPalette.selectedColor
colorEditor.color = colorPalette.selectedColor
}
} }
} }
@@ -1005,7 +1042,6 @@ SecondColumnLayout {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
visible: !colorEditor.isNotInGradientMode() visible: !colorEditor.isNotInGradientMode()
leftPadding: 10 leftPadding: 10
rightPadding: 10 rightPadding: 10
@@ -1039,12 +1075,10 @@ SecondColumnLayout {
Column { Column {
id: defaultGradientControls id: defaultGradientControls
spacing: 10 spacing: 10
visible: colorEditor.hasLinearGradient() && !colorEditor.shapeGradients visible: colorEditor.hasLinearGradient() && !colorEditor.shapeGradients
RowLayout { RowLayout {
id: defaultGradientOrientation id: defaultGradientOrientation
Layout.fillWidth: true Layout.fillWidth: true
spacing: 0 spacing: 0
@@ -1055,9 +1089,9 @@ SecondColumnLayout {
width: implicitWidth width: implicitWidth
model: [{ value: Gradient.Vertical, text: qsTr("Vertical") }, model: [{ value: Gradient.Vertical, text: qsTr("Vertical") },
{ value: Gradient.Horizontal, text: qsTr("Horizontal") }] { value: Gradient.Horizontal, text: qsTr("Horizontal") }]
textRole: "text" textRole: "text"
valueRole: "value" valueRole: "value"
onActivated: { onActivated: {
gradientLine.model.setGradientOrientation(gradientOrientation.currentValue) gradientLine.model.setGradientOrientation(gradientOrientation.currentValue)
colorEditor.updateThumbnail() colorEditor.updateThumbnail()
@@ -1090,7 +1124,6 @@ SecondColumnLayout {
Column { Column {
id: linearGradientControls id: linearGradientControls
spacing: 10 spacing: 10
visible: colorEditor.hasLinearGradient() && colorEditor.shapeGradients visible: colorEditor.hasLinearGradient() && colorEditor.shapeGradients
ControlsRow { ControlsRow {
@@ -1126,7 +1159,6 @@ SecondColumnLayout {
Column { Column {
id: radialGradientControls id: radialGradientControls
spacing: 10 spacing: 10
visible: colorEditor.hasRadialGradient() visible: colorEditor.hasRadialGradient()
ControlsRow { ControlsRow {
@@ -1170,7 +1202,6 @@ SecondColumnLayout {
Column { Column {
id: concialGradientControls id: concialGradientControls
spacing: 10 spacing: 10
visible: colorEditor.hasConicalGradient() visible: colorEditor.hasConicalGradient()
ControlsRow { ControlsRow {

View File

@@ -36,18 +36,20 @@ Column {
} }
property int mode: ColorPicker.Mode.HSVA property int mode: ColorPicker.Mode.HSVA
property color color property color color: "#303091"
property real red: 0
property real green: 0
property real blue: 0
property real hue: 0 property real hue: 0
property real saturationHSL: 0 property real saturationHSL: 0.5
property real saturationHSV: 0 property real saturationHSV: 0.5
property real lightness: 0 property real lightness: 0.5
property real value: 0 property real value: 0.5
property real alpha: 1 property real alpha: 1
property bool achromatic: false
property int sliderMargins: 6 property int sliderMargins: 6
property bool block: false property bool block: false
@@ -57,81 +59,90 @@ Column {
spacing: 10 spacing: 10
onModeChanged: { onColorChanged: {
if (root.block)
return
switch (root.mode) { switch (root.mode) {
case ColorPicker.Mode.RGBA: case ColorPicker.Mode.RGBA:
root.color = Qt.rgba(root.color.r, root.color.g, root.color.b, root.alpha) root.red = root.color.r
root.green = root.color.g
root.blue = root.color.b
root.alpha = root.color.a
break break
case ColorPicker.Mode.HSLA: case ColorPicker.Mode.HSLA:
root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha) if (root.color.hslHue !== -1)
root.hue = root.color.hslHue
root.saturationHSL = root.color.hslSaturation
root.lightness = root.color.hslLightness
root.alpha = root.color.a
break break
case ColorPicker.Mode.HSVA: case ColorPicker.Mode.HSVA:
default: default:
root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha) if (root.color.hsvHue !== -1)
root.hue = root.color.hsvHue
root.saturationHSV = root.color.hsvSaturation
root.value = root.color.hsvValue
root.alpha = root.color.a
break break
} }
gradientOverlay.requestPaint() root.invalidateColor()
} }
onHueChanged: {
if (root.mode === ColorPicker.Mode.HSLA)
root.color.hslHue = root.hue
else
root.color.hsvHue = root.hue
}
onSaturationHSLChanged: {
root.color.hslSaturation = root.saturationHSL
invalidateColor()
}
onSaturationHSVChanged: {
root.color.hsvSaturation = root.saturationHSV
}
onLightnessChanged: {
root.color.hslLightness = root.lightness
}
onValueChanged: {
root.color.hsvValue = root.value
}
onAlphaChanged: invalidateColor()
onColorChanged: invalidateColor()
function invalidateColor() { function invalidateColor() {
if (root.block) if (root.block)
return return
root.block = true root.block = true
if (root.color.hsvSaturation > 0.0 switch (root.mode) {
&& root.color.hsvValue > 0.0 case ColorPicker.Mode.RGBA:
&& root.color.hsvHue !== -1.0) root.color = Qt.rgba(root.red, root.green, root.blue, root.alpha)
root.hue = root.color.hsvHue // Set HSVA and HSLA
if (root.color.hsvHue !== -1)
root.hue = root.color.hsvHue // doesn't matter if hsvHue or hslHue
if (root.color.hslSaturation > 0.0 if (root.color.hslLightness !== 0.0 && root.color.hslLightness !== 1.0)
&& root.color.hslLightness > 0.0 root.saturationHSL = root.color.hslSaturation
&& root.color.hslHue !== -1.0)
root.hue = root.color.hslHue
if (root.color.hslLightness !== 0.0 && root.color.hslLightness !== 1.0 && !root.achromatic) if (root.color.hsvValue !== 0.0)
root.saturationHSL = root.color.hslSaturation root.saturationHSV = root.color.hsvSaturation
if (root.color.hsvValue !== 0.0 && root.color.hsvValue !== 1.0 && !root.achromatic) root.lightness = root.color.hslLightness
root.saturationHSV = root.color.hsvSaturation root.value = root.color.hsvValue
break
root.lightness = root.color.hslLightness case ColorPicker.Mode.HSLA:
root.value = root.color.hsvValue
if (root.color.hslLightness === 0.0 || root.color.hslLightness === 1.0
|| root.color.hsvValue === 0.0 || root.color.hsvValue === 1.0
|| root.color.hsvHue === -1.0 || root.color.hslHue === -1.0)
root.achromatic = true
else
root.achromatic = false
if (root.mode === ColorPicker.Mode.HSLA)
root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha) root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha)
else // Set RGBA and HSVA
root.red = root.color.r
root.green = root.color.g
root.blue = root.color.b
if (root.color.hsvValue !== 0.0)
root.saturationHSV = root.color.hsvSaturation
root.value = root.color.hsvValue
break
case ColorPicker.Mode.HSVA:
default:
root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha) root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha)
// Set RGBA and HSLA
root.red = root.color.r
root.green = root.color.g
root.blue = root.color.b
if (root.color.hslLightness !== 0.0 && root.color.hslLightness !== 1.0)
root.saturationHSL = root.color.hslSaturation
root.lightness = root.color.hslLightness
break
}
luminanceSlider.value = (1.0 - root.value) luminanceSlider.value = (1.0 - root.value)
hueSlider.value = root.hue hueSlider.value = root.hue
@@ -142,21 +153,21 @@ Column {
root.block = false root.block = false
} }
function drawHSVA(ctx) { function drawHSVA(ctx, width, height, hue) {
for (var row = 0; row < gradientOverlay.height; row++) { for (var row = 0; row < height; row++) {
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0) var gradient = ctx.createLinearGradient(0, 0, width, 0)
var v = Math.abs(row - gradientOverlay.height) / gradientOverlay.height var v = Math.abs(row - height) / height
gradient.addColorStop(0, Qt.hsva(root.hue, 0, v, 1)) gradient.addColorStop(0, Qt.hsva(hue, 0, v, 1))
gradient.addColorStop(1, Qt.hsva(root.hue, 1, v, 1)) gradient.addColorStop(1, Qt.hsva(hue, 1, v, 1))
ctx.fillStyle = gradient ctx.fillStyle = gradient
ctx.fillRect(0, row, gradientOverlay.width, 1) ctx.fillRect(0, row, width, 1)
} }
} }
function drawRGBA(ctx) { function drawRGBA(ctx, width, height) {
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0) var gradient = ctx.createLinearGradient(0, 0, width, 0)
gradient.addColorStop(0.000, Qt.rgba(1, 0, 0, 1)) gradient.addColorStop(0.000, Qt.rgba(1, 0, 0, 1))
gradient.addColorStop(0.167, Qt.rgba(1, 1, 0, 1)) gradient.addColorStop(0.167, Qt.rgba(1, 1, 0, 1))
gradient.addColorStop(0.333, Qt.rgba(0, 1, 0, 1)) gradient.addColorStop(0.333, Qt.rgba(0, 1, 0, 1))
@@ -166,26 +177,26 @@ Column {
gradient.addColorStop(1.000, Qt.rgba(1, 0, 0, 1)) gradient.addColorStop(1.000, Qt.rgba(1, 0, 0, 1))
ctx.fillStyle = gradient ctx.fillStyle = gradient
ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height) ctx.fillRect(0, 0, width, height)
gradient = ctx.createLinearGradient(0, 0, 0, gradientOverlay.height) gradient = ctx.createLinearGradient(0, 0, 0, height)
gradient.addColorStop(0.000, Qt.rgba(0, 0, 0, 0)) gradient.addColorStop(0.000, Qt.rgba(0, 0, 0, 0))
gradient.addColorStop(1.000, Qt.rgba(1, 1, 1, 1)) gradient.addColorStop(1.000, Qt.rgba(1, 1, 1, 1))
ctx.fillStyle = gradient ctx.fillStyle = gradient
ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height) ctx.fillRect(0, 0, width, height)
} }
function drawHSLA(ctx) { function drawHSLA(ctx, width, height, hue) {
for (var row = 0; row < gradientOverlay.height; row++) { for (var row = 0; row < height; row++) {
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0) var gradient = ctx.createLinearGradient(0, 0, width, 0)
var l = Math.abs(row - gradientOverlay.height) / gradientOverlay.height var l = Math.abs(row - height) / height
gradient.addColorStop(0, Qt.hsla(root.hue, 0, l, 1)) gradient.addColorStop(0, Qt.hsla(hue, 0, l, 1))
gradient.addColorStop(1, Qt.hsla(root.hue, 1, l, 1)) gradient.addColorStop(1, Qt.hsla(hue, 1, l, 1))
ctx.fillStyle = gradient ctx.fillStyle = gradient
ctx.fillRect(0, row, gradientOverlay.width, 1) ctx.fillRect(0, row, width, 1)
} }
} }
@@ -211,11 +222,12 @@ Column {
id: gradientOverlay id: gradientOverlay
anchors.fill: parent anchors.fill: parent
opacity: root.color.a opacity: root.alpha
Connections { Connections {
target: root target: root
function onHueChanged() { gradientOverlay.requestPaint() } function onHueChanged() { gradientOverlay.requestPaint() }
function onModeChanged() { gradientOverlay.requestPaint() }
} }
onPaint: { onPaint: {
@@ -225,14 +237,14 @@ Column {
switch (root.mode) { switch (root.mode) {
case ColorPicker.Mode.RGBA: case ColorPicker.Mode.RGBA:
root.drawRGBA(ctx) root.drawRGBA(ctx, gradientOverlay.width, gradientOverlay.height)
break break
case ColorPicker.Mode.HSLA: case ColorPicker.Mode.HSLA:
root.drawHSLA(ctx) root.drawHSLA(ctx, gradientOverlay.width, gradientOverlay.height, root.hue)
break break
case ColorPicker.Mode.HSVA: case ColorPicker.Mode.HSVA:
default: default:
root.drawHSVA(ctx) root.drawHSVA(ctx, gradientOverlay.width, gradientOverlay.height, root.hue)
break break
} }
@@ -244,9 +256,14 @@ Column {
id: pickerCross id: pickerCross
property color strokeStyle: "lightGray" property color strokeStyle: "lightGray"
property string loadImageUrl: "images/checkers.png"
property int radius: 10
Component.onCompleted: pickerCross.loadImage(pickerCross.loadImageUrl)
onImageLoaded: pickerCross.requestPaint()
opacity: 0.8
anchors.fill: parent anchors.fill: parent
anchors.margins: -pickerCross.radius
antialiasing: true antialiasing: true
Connections { Connections {
@@ -261,35 +278,63 @@ Column {
ctx.save() ctx.save()
ctx.clearRect(0, 0, pickerCross.width, pickerCross.height) ctx.clearRect(0, 0, pickerCross.width, pickerCross.height)
var yy, xx = 0 var normX, normY = 0
switch (root.mode) { switch (root.mode) {
case ColorPicker.Mode.RGBA: case ColorPicker.Mode.RGBA:
yy = pickerCross.height - root.saturationHSV * pickerCross.height normX = root.hue
xx = root.hue * pickerCross.width normY = 1.0 - root.saturationHSV
break break
case ColorPicker.Mode.HSLA: case ColorPicker.Mode.HSLA:
yy = pickerCross.height - root.lightness * pickerCross.height normX = root.saturationHSL
xx = root.saturationHSL * pickerCross.width normY = 1.0 - root.lightness
break break
case ColorPicker.Mode.HSVA: case ColorPicker.Mode.HSVA:
default: default:
yy = pickerCross.height - root.value * pickerCross.height normX = root.saturationHSV
xx = root.saturationHSV * pickerCross.width normY = 1.0 - root.value
break break
} }
ctx.strokeStyle = pickerCross.strokeStyle var width = pickerCross.width - pickerCross.radius * 2
ctx.lineWidth = 1 var height = pickerCross.height - pickerCross.radius * 2
var x = normX * width
var y = normY * height
var centerX = pickerCross.radius + x
var centerY = pickerCross.radius + y
// Draw checkerboard
if (isImageLoaded(pickerCross.loadImageUrl)) {
ctx.beginPath()
ctx.arc(centerX, centerY, pickerCross.radius, 0, 2 * Math.PI)
ctx.clip()
var pattern = context.createPattern(pickerCross.loadImageUrl, 'repeat')
context.fillStyle = pattern
ctx.fillRect(x, y, pickerCross.radius * 2, pickerCross.radius * 2)
}
// Draw current color
if (root.mode === ColorPicker.Mode.RGBA)
ctx.fillStyle = Qt.hsva(root.hue, root.saturationHSV, 1, root.alpha)
else
ctx.fillStyle = root.color
ctx.fillRect(x, y, pickerCross.radius * 2, pickerCross.radius * 2)
// Draw black and white circle
ctx.lineWidth = 2
ctx.strokeStyle = "black"
ctx.beginPath() ctx.beginPath()
ctx.moveTo(0, yy) ctx.arc(centerX, centerY, pickerCross.radius, 0, 2 * Math.PI)
ctx.lineTo(pickerCross.width, yy)
ctx.stroke() ctx.stroke()
ctx.strokeStyle = "white"
ctx.beginPath() ctx.beginPath()
ctx.moveTo(xx, 0) ctx.arc(centerX, centerY, pickerCross.radius - 2, 0, 2 * Math.PI)
ctx.lineTo(xx, pickerCross.height)
ctx.stroke() ctx.stroke()
ctx.restore() ctx.restore()
@@ -298,31 +343,48 @@ Column {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
anchors.margins: -pickerCross.radius
preventStealing: true preventStealing: true
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onPositionChanged: function(mouse) { onPositionChanged: function(mouse) {
if (mouseArea.pressed && mouse.buttons === Qt.LeftButton) { if (mouseArea.pressed && mouse.buttons === Qt.LeftButton) {
var xx = Math.max(0, Math.min(mouse.x, parent.width)) // Generate color values from mouse position
var yy = Math.max(0, Math.min(mouse.y, parent.height))
// Clip/limit to margin
var x = Math.max(0, Math.min(mouse.x - pickerCross.radius, parent.width))
var y = Math.max(0, Math.min(mouse.y - pickerCross.radius, parent.height))
var normX = x / parent.width
var normY = y / parent.height
switch (root.mode) { switch (root.mode) {
case ColorPicker.Mode.RGBA: case ColorPicker.Mode.RGBA:
root.saturationHSV = 1.0 - yy / parent.height var tmpColor = Qt.hsva(normX, // hue
root.hue = xx / parent.width 1.0 - normY, // saturation
root.value,
root.alpha)
root.hue = normX
root.saturationHSV = 1.0 - normY
root.red = tmpColor.r
root.green = tmpColor.g
root.blue = tmpColor.b
break break
case ColorPicker.Mode.HSLA: case ColorPicker.Mode.HSLA:
root.saturationHSL = xx / parent.width root.saturationHSL = normX
root.lightness = 1.0 - yy / parent.height root.lightness = 1.0 - normY
break break
case ColorPicker.Mode.HSVA: case ColorPicker.Mode.HSVA:
default: default:
root.saturationHSV = xx / parent.width root.saturationHSV = normX
root.value = 1.0 - yy / parent.height root.value = 1.0 - normY
break break
} }
root.invalidateColor()
} }
} }
onPressed: function(mouse) { onPressed: function(mouse) {
@@ -345,9 +407,11 @@ Column {
id: hueSlider id: hueSlider
visible: root.mode !== ColorPicker.Mode.RGBA visible: root.mode !== ColorPicker.Mode.RGBA
width: parent.width width: parent.width
onValueChanged: { onMoved: {
if (root.hue !== hueSlider.value) if (root.hue !== hueSlider.value)
root.hue = hueSlider.value root.hue = hueSlider.value
root.invalidateColor()
} }
onClicked: root.updateColor() onClicked: root.updateColor()
} }
@@ -356,10 +420,21 @@ Column {
id: luminanceSlider id: luminanceSlider
visible: root.mode === ColorPicker.Mode.RGBA visible: root.mode === ColorPicker.Mode.RGBA
width: parent.width width: parent.width
color: Qt.hsva(root.hue, root.color.hsvSaturation, 1, 1) color: Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha)
onValueChanged: { onMoved: {
if (root.value !== luminanceSlider.value) if (root.value !== (1.0 - luminanceSlider.value))
root.value = (1.0 - luminanceSlider.value) root.value = (1.0 - luminanceSlider.value)
var tmpColor = Qt.hsva(root.hue,
root.saturationHSV,
root.value,
root.alpha)
root.red = tmpColor.r
root.green = tmpColor.g
root.blue = tmpColor.b
root.invalidateColor()
} }
onClicked: root.updateColor() onClicked: root.updateColor()
} }
@@ -367,10 +442,12 @@ Column {
OpacitySlider { OpacitySlider {
id: opacitySlider id: opacitySlider
width: parent.width width: parent.width
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1) color: root.color
onValueChanged: { onMoved: {
if (root.alpha !== opacitySlider.value) if (root.alpha !== (1.0 - opacitySlider.value))
root.alpha = (1.0 - opacitySlider.value) root.alpha = (1.0 - opacitySlider.value)
root.invalidateColor()
} }
onClicked: root.updateColor() onClicked: root.updateColor()
} }

View File

@@ -39,6 +39,8 @@ Item {
property alias hover: spinBox.hover property alias hover: spinBox.hover
signal valueModified signal valueModified
signal dragStarted
signal indicatorPressed
width: 90 width: 90
implicitHeight: spinBox.height implicitHeight: spinBox.height
@@ -48,9 +50,13 @@ Item {
StudioControls.RealSpinBox { StudioControls.RealSpinBox {
id: spinBox id: spinBox
onDragStarted: hideCursor() onDragStarted: {
hideCursor()
wrapper.dragStarted()
}
onDragEnded: restoreCursor() onDragEnded: restoreCursor()
onDragging: holdCursorInPlace() onDragging: holdCursorInPlace()
onIndicatorPressed: wrapper.indicatorPressed()
property bool hasSlider: spinBox.sliderIndicatorVisible property bool hasSlider: spinBox.sliderIndicatorVisible

View File

@@ -96,13 +96,12 @@ Item {
height: 80 height: 80
width: parent.width width: parent.width
property int effectiveWidth: width - 10 property int effectiveWidth: colorLine.width - 10
property int selectedIndex: 0 property int selectedIndex: 0
function select(index) { function select(index) {
for (var i = 0; i < repeater.model.count; i++) { for (var i = 0; i < repeater.model.count; i++)
repeater.itemAt(i).item.highlighted = false repeater.itemAt(i).item.highlighted = false
}
if (repeater.model.count < index + 1) if (repeater.model.count < index + 1)
return return
@@ -113,11 +112,12 @@ Item {
gradientModel.lock() gradientModel.lock()
root.currentColor = repeater.itemAt(index).item.color root.currentColor = repeater.itemAt(index).item.color
gradientModel.unlock() gradientModel.unlock()
root.selectedNodeChanged() root.selectedNodeChanged()
} }
function invalidate() { function invalidate() {
var gradientString = "import QtQuick 2.15; Gradient {" var gradientString = "import QtQuick 2.15; Gradient { orientation: Gradient.Horizontal;"
for (var i = 0; i < gradientModel.count; i++) { for (var i = 0; i < gradientModel.count; i++) {
gradientString += "GradientStop {}" gradientString += "GradientStop {}"
@@ -209,21 +209,21 @@ Item {
anchors.left: parent.left anchors.left: parent.left
anchors.right: parent.right anchors.right: parent.right
Image {
id: checkerboard
anchors.fill: parent
source: "images/checkers.png"
fillMode: Image.Tile
}
Rectangle { Rectangle {
id: gradientRectangle id: gradientRectangle
smooth: true anchors.fill: parent
x: 0 border.color: StudioTheme.Values.themeControlOutline
y: 16 border.width: StudioTheme.Values.border
radius: 1
border.color: "#555555"
border.width: 1
width: parent.height
height: parent.width
gradient: Gradient { gradient: Gradient {
id: gradient id: gradient
} }
transformOrigin: Item.TopLeft
rotation: 270
} }
} }
} }
@@ -270,6 +270,13 @@ Item {
onXChanged: gradientStopHandle.refreshToolTip(gradientStopHandle.toolTipVisible) onXChanged: gradientStopHandle.refreshToolTip(gradientStopHandle.toolTipVisible)
Image {
width: 10
height: 10
source: "images/checkers.png"
fillMode: Image.Tile
}
Rectangle { Rectangle {
id: rectangle id: rectangle
width: 10 width: 10
@@ -277,7 +284,6 @@ Item {
color: "red" color: "red"
border.color: "gray" border.color: "gray"
border.width: 1 border.width: 1
radius: 1
} }
Canvas { Canvas {

View File

@@ -1,50 +0,0 @@
/****************************************************************************
**
** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
import QtQuick 2.15
import QtQuick.Layouts 1.15
Image {
id: root
signal clicked
visible: colorEditor.shapeGradients && parent.checked
width: 8
height: 4
source: "image://icons/down-arrow"
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.bottom
anchors.topMargin: 2
opacity: popupRegion.containsMouse ? 1 : 0.8
ToolTipArea {
id: popupRegion
onClicked: root.clicked()
hoverEnabled: true
anchors.fill: parent
anchors.margins: -2
tooltip: qsTr("Edit Gradient Properties")
}
}

View File

@@ -36,13 +36,14 @@ Item {
property bool integer: false property bool integer: false
signal clicked signal clicked
signal moved
height: StudioTheme.Values.hueSliderHeight height: StudioTheme.Values.hueSliderHeight
function updatePos() { function updatePos() {
if (root.maximum > root.minimum) { if (root.maximum > root.minimum) {
var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum) var pos = track.width * (root.value - root.minimum) / (root.maximum - root.minimum)
return Math.min(Math.max(pos, 0), track.width - handle.width) return Math.min(Math.max(pos, 0), track.width)
} else { } else {
return 0 return 0
} }
@@ -50,7 +51,6 @@ Item {
Item { Item {
id: track id: track
width: parent.width width: parent.width
height: parent.height height: parent.height
@@ -74,21 +74,20 @@ Item {
Rectangle { Rectangle {
id: handle id: handle
width: StudioTheme.Values.hueSliderHandleWidth width: StudioTheme.Values.hueSliderHandleWidth
height: track.height - 4 height: track.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
smooth: true
color: "transparent" color: "transparent"
radius: 2 radius: 2
border.color: "black" border.color: "black"
border.width: 1 border.width: 1
x: root.updatePos() x: root.updatePos() - handle.width * 0.5
y: 2 y: 2
z: 1 z: 1
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: 1 anchors.margins: 1
color: "transparent" color: Qt.hsva(value, 1, 1, 1)
radius: 1 radius: 1
border.color: "white" border.color: "white"
border.width: 1 border.width: 1
@@ -98,21 +97,23 @@ Item {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
anchors.margins: -StudioTheme.Values.hueSliderHandleWidth * 0.5
preventStealing: true preventStealing: true
function calculateValue() { function calculateValue() {
var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width)) var halfHandle = StudioTheme.Values.hueSliderHandleWidth * 0.5
var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum var handleX = Math.max(0, Math.min(mouseArea.mouseX - halfHandle, parent.width))
var realValue = (root.maximum - root.minimum) * handleX / parent.width + root.minimum
root.value = root.integer ? Math.round(realValue) : realValue root.value = root.integer ? Math.round(realValue) : realValue
root.moved()
} }
onPressed: calculateValue() onPressed: mouseArea.calculateValue()
onReleased: root.clicked() onReleased: root.clicked()
onPositionChanged: { onPositionChanged: {
if (pressed) if (mouseArea.pressed)
calculateValue() mouseArea.calculateValue()
} }
} }
} }
} }

View File

@@ -37,13 +37,14 @@ Item {
property color color property color color
signal clicked signal clicked
signal moved
height: StudioTheme.Values.hueSliderHeight height: StudioTheme.Values.hueSliderHeight
function updatePos() { function updatePos() {
if (root.maximum > root.minimum) { if (root.maximum > root.minimum) {
var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum) var pos = track.width * (root.value - root.minimum) / (root.maximum - root.minimum)
return Math.min(Math.max(pos, 0), track.width - handle.width) return Math.min(Math.max(pos, 0), track.width)
} else { } else {
return 0 return 0
} }
@@ -51,17 +52,9 @@ Item {
Item { Item {
id: track id: track
width: parent.width width: parent.width
height: parent.height height: parent.height
Image {
id: checkerboard
anchors.fill: parent
source: "images/checkers.png"
fillMode: Image.Tile
}
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
border.color: StudioTheme.Values.themeControlOutline border.color: StudioTheme.Values.themeControlOutline
@@ -69,7 +62,7 @@ Item {
gradient: Gradient { gradient: Gradient {
orientation: Gradient.Horizontal orientation: Gradient.Horizontal
GradientStop { position: 0.000; color: root.color } GradientStop { position: 0.000; color: Qt.hsva(root.color.hsvHue, root.color.hsvSaturation, 1, 1) }
GradientStop { position: 1.000; color: "black" } GradientStop { position: 1.000; color: "black" }
} }
} }
@@ -77,21 +70,20 @@ Item {
Rectangle { Rectangle {
id: handle id: handle
width: StudioTheme.Values.hueSliderHandleWidth width: StudioTheme.Values.hueSliderHandleWidth
height: track.height - 4 height: track.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
smooth: true
color: "transparent" color: "transparent"
radius: 2 radius: 2
border.color: "black" border.color: "black"
border.width: 1 border.width: 1
x: root.updatePos() x: root.updatePos() - handle.width * 0.5
y: 2 y: 2
z: 1 z: 1
Rectangle { Rectangle {
anchors.fill: parent anchors.fill: parent
anchors.margins: 1 anchors.margins: 1
color: "transparent" color: Qt.hsva(root.color.hsvHue, root.color.hsvSaturation, root.color.hsvValue, 1)
radius: 1 radius: 1
border.color: "white" border.color: "white"
border.width: 1 border.width: 1
@@ -101,19 +93,22 @@ Item {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
anchors.margins: -StudioTheme.Values.hueSliderHandleWidth * 0.5
preventStealing: true preventStealing: true
function calculateValue() { function calculateValue() {
var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width)) var halfHandle = StudioTheme.Values.hueSliderHandleWidth * 0.5
var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum var handleX = Math.max(0, Math.min(mouseArea.mouseX - halfHandle, parent.width))
var realValue = (root.maximum - root.minimum) * handleX / parent.width + root.minimum
root.value = root.integer ? Math.round(realValue) : realValue root.value = root.integer ? Math.round(realValue) : realValue
root.moved()
} }
onPressed: calculateValue() onPressed: mouseArea.calculateValue()
onReleased: root.clicked() onReleased: root.clicked()
onPositionChanged: { onPositionChanged: {
if (pressed) if (mouseArea.pressed)
calculateValue() mouseArea.calculateValue()
} }
} }

View File

@@ -37,13 +37,14 @@ Item {
property color color property color color
signal clicked signal clicked
signal moved
height: StudioTheme.Values.hueSliderHeight height: StudioTheme.Values.hueSliderHeight
function updatePos() { function updatePos() {
if (root.maximum > root.minimum) { if (root.maximum > root.minimum) {
var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum) var pos = track.width * (root.value - root.minimum) / (root.maximum - root.minimum)
return Math.min(Math.max(pos, 0), track.width - handle.width) return Math.min(Math.max(pos, 0), track.width)
} else { } else {
return 0 return 0
} }
@@ -51,12 +52,10 @@ Item {
Item { Item {
id: track id: track
width: parent.width width: parent.width
height: parent.height height: parent.height
Image { Image {
id: checkerboard
anchors.fill: parent anchors.fill: parent
source: "images/checkers.png" source: "images/checkers.png"
fillMode: Image.Tile fillMode: Image.Tile
@@ -69,7 +68,7 @@ Item {
gradient: Gradient { gradient: Gradient {
orientation: Gradient.Horizontal orientation: Gradient.Horizontal
GradientStop { position: 0.000; color: root.color } GradientStop { position: 0.000; color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1) }
GradientStop { position: 1.000; color: "transparent" } GradientStop { position: 1.000; color: "transparent" }
} }
} }
@@ -77,21 +76,27 @@ Item {
Rectangle { Rectangle {
id: handle id: handle
width: StudioTheme.Values.hueSliderHandleWidth width: StudioTheme.Values.hueSliderHandleWidth
height: track.height - 4 height: track.height + 4
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
smooth: true
color: "transparent" color: "transparent"
radius: 2 radius: 2
border.color: "black" border.color: "black"
border.width: 1 border.width: 1
x: root.updatePos() x: root.updatePos() - handle.width * 0.5
y: 2 y: 2
z: 1 z: 1
Image {
anchors.fill: handleInside
source: "images/checkers.png"
fillMode: Image.Tile
}
Rectangle { Rectangle {
id: handleInside
anchors.fill: parent anchors.fill: parent
anchors.margins: 1 anchors.margins: 1
color: "transparent" color: root.color
radius: 1 radius: 1
border.color: "white" border.color: "white"
border.width: 1 border.width: 1
@@ -101,19 +106,22 @@ Item {
MouseArea { MouseArea {
id: mouseArea id: mouseArea
anchors.fill: parent anchors.fill: parent
anchors.margins: -StudioTheme.Values.hueSliderHandleWidth * 0.5
preventStealing: true preventStealing: true
function calculateValue() { function calculateValue() {
var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width)) var halfHandle = StudioTheme.Values.hueSliderHandleWidth * 0.5
var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum var handleX = Math.max(0, Math.min(mouseArea.mouseX - halfHandle, parent.width))
var realValue = (root.maximum - root.minimum) * handleX / parent.width + root.minimum
root.value = root.integer ? Math.round(realValue) : realValue root.value = root.integer ? Math.round(realValue) : realValue
root.moved()
} }
onPressed: calculateValue() onPressed: mouseArea.calculateValue()
onReleased: root.clicked() onReleased: root.clicked()
onPositionChanged: { onPositionChanged: {
if (pressed) if (mouseArea.pressed)
calculateValue() mouseArea.calculateValue()
} }
} }

View File

@@ -31,7 +31,6 @@ FontExtrasSection 2.0 FontExtrasSection.qml
FontSection 2.0 FontSection.qml FontSection 2.0 FontSection.qml
FontStyleButtons 2.0 FontStyleButtons.qml FontStyleButtons 2.0 FontStyleButtons.qml
GradientLine 2.0 GradientLine.qml GradientLine 2.0 GradientLine.qml
GradientPopupIndicator 2.0 GradientPopupIndicator.qml
GradientPresetList 2.0 GradientPresetList.qml GradientPresetList 2.0 GradientPresetList.qml
GradientPresetTabContent 2.0 GradientPresetTabContent.qml GradientPresetTabContent 2.0 GradientPresetTabContent.qml
GradientPropertySpinBox 2.0 GradientPropertySpinBox.qml GradientPropertySpinBox 2.0 GradientPropertySpinBox.qml

View File

@@ -121,7 +121,7 @@ T.ComboBox {
ComboBox.ActivatedReason.Other) ComboBox.ActivatedReason.Other)
} }
onActivated: { onActivated: function(index) {
myTimer.activatedIndex = index myTimer.activatedIndex = index
myTimer.restart() myTimer.restart()
} }

View File

@@ -81,6 +81,7 @@ T.SpinBox {
signal dragStarted signal dragStarted
signal dragEnded signal dragEnded
signal dragging signal dragging
signal indicatorPressed
// Use custom wheel handling due to bugs // Use custom wheel handling due to bugs
property bool __wheelEnabled: false property bool __wheelEnabled: false
@@ -124,6 +125,7 @@ T.SpinBox {
myControl: mySpinBox myControl: mySpinBox
iconFlip: -1 iconFlip: -1
visible: mySpinBox.spinBoxIndicatorVisible visible: mySpinBox.spinBoxIndicatorVisible
onRealPressed: mySpinBox.indicatorPressed()
onRealReleased: mySpinBox.realIncrease() onRealReleased: mySpinBox.realIncrease()
onRealPressAndHold: mySpinBox.realIncrease() onRealPressAndHold: mySpinBox.realIncrease()
x: actionIndicator.width + StudioTheme.Values.border x: actionIndicator.width + StudioTheme.Values.border
@@ -139,6 +141,7 @@ T.SpinBox {
id: spinBoxIndicatorDown id: spinBoxIndicatorDown
myControl: mySpinBox myControl: mySpinBox
visible: mySpinBox.spinBoxIndicatorVisible visible: mySpinBox.spinBoxIndicatorVisible
onRealPressed: mySpinBox.indicatorPressed()
onRealReleased: mySpinBox.realDecrease() onRealReleased: mySpinBox.realDecrease()
onRealPressAndHold: mySpinBox.realDecrease() onRealPressAndHold: mySpinBox.realDecrease()
x: actionIndicator.width + StudioTheme.Values.border x: actionIndicator.width + StudioTheme.Values.border

View File

@@ -155,15 +155,17 @@ void PropertyEditorValue::setValueWithEmit(const QVariant &value)
void PropertyEditorValue::setValue(const QVariant &value) void PropertyEditorValue::setValue(const QVariant &value)
{ {
const bool colorsEqual = cleverColorCompare(value, m_value);
if (!compareVariants(m_value, value) && if (!compareVariants(m_value, value) &&
!cleverDoubleCompare(value, m_value) && !cleverDoubleCompare(value, m_value) &&
!cleverColorCompare(value, m_value)) !colorsEqual)
m_value = value; m_value = value;
fixAmbigousColorNames(modelNode(), name(), &m_value); fixAmbigousColorNames(modelNode(), name(), &m_value);
fixUrl(modelNode(), name(), &m_value); fixUrl(modelNode(), name(), &m_value);
if (m_value.isValid()) if (m_value.isValid() && !colorsEqual)
emit valueChangedQml(); emit valueChangedQml();
emit isExplicitChanged(); emit isExplicitChanged();