diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml index 2ed45ea3e12..cd956dd99e0 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorEditor.qml @@ -189,8 +189,20 @@ SecondColumnLayout { colorEditor.originalColor = colorEditor.color } - onValueChanged: colorEditor.color = colorEditor.value - onBackendValueChanged: colorEditor.color = colorEditor.value + Connections { + id: backendConnection + target: colorEditor + + function onValueChanged() { + if (isNotInGradientMode()) + colorEditor.color = colorEditor.value + } + + function onBackendValueChanged() { + if (isNotInGradientMode()) + colorEditor.color = colorEditor.value + } + } Timer { id: colorEditorTimer @@ -198,15 +210,18 @@ SecondColumnLayout { interval: 100 running: false onTriggered: { + backendConnection.enabled = false + if (colorEditor.backendValue !== undefined) { - if (isVector3D) { + if (colorEditor.isVector3D) colorEditor.backendValue.value = Qt.vector3d(colorEditor.color.r, colorEditor.color.g, colorEditor.color.b) - } else { + else colorEditor.backendValue.value = colorEditor.color - } } + + backendConnection.enabled = true } } @@ -223,8 +238,6 @@ SecondColumnLayout { if (isNotInGradientMode()) colorEditorTimer.restart() // Delay setting the color to keep ui responsive - - colorPalette.selectedColor = colorEditor.color } Spacer { implicitWidth: StudioTheme.Values.actionIndicatorWidth } @@ -419,6 +432,7 @@ SecondColumnLayout { tooltip: qsTr("Transparent") onClicked: { colorPicker.alpha = 0 + colorPicker.invalidateColor() colorPicker.updateColor() } } @@ -503,8 +517,10 @@ SecondColumnLayout { visible: !isNotInGradientMode() onCurrentColorChanged: { - if (colorEditor.supportGradient && gradientLine.hasGradient) + if (colorEditor.supportGradient && gradientLine.hasGradient) { colorEditor.color = gradientLine.currentColor + colorPicker.color = colorEditor.color + } } onHasGradientChanged: { @@ -515,9 +531,8 @@ SecondColumnLayout { } onSelectedNodeChanged: { - if (colorEditor.supportGradient && gradientLine.hasGradient) { + if (colorEditor.supportGradient && gradientLine.hasGradient) colorEditor.originalColor = gradientLine.currentColor - } } onInvalidated: colorEditor.updateThumbnail() @@ -546,13 +561,15 @@ SecondColumnLayout { function onSelectionChanged() { if (colorEditor.supportGradient && gradientLine.hasGradient) { colorEditor.color = gradientLine.currentColor - gradientLine.currentColor = color + gradientLine.currentColor = colorEditor.color hexTextField.text = colorEditor.color popupHexTextField.text = colorEditor.color } + gradientLine.isInValidState = true colorEditor.originalColor = colorEditor.color colorPalette.selectedColor = colorEditor.color + colorPicker.color = colorEditor.color colorEditor.createModel() colorEditor.determineActiveColorMode() @@ -563,44 +580,32 @@ SecondColumnLayout { ColorPicker { id: colorPicker - property color boundColor: colorEditor.color - width: parent.width sliderMargins: 4 - // Prevent the binding to be deleted by assignment - onBoundColorChanged: colorPicker.color = colorPicker.boundColor onUpdateColor: { colorEditor.color = colorPicker.color + if (contextMenu.opened) contextMenu.close() } onRightMouseButtonClicked: contextMenu.popup(colorPicker) onColorInvalidated: { - switch (colorPicker.mode) { - case ColorPicker.Mode.HSLA: - hslHueSpinBox.value = colorPicker.hue - hslSaturationSpinBox.value = colorPicker.saturationHSL - hslLightnessSpinBox.value = colorPicker.lightness - hslAlphaSpinBox.value = colorPicker.alpha - break + hslHueSpinBox.value = colorPicker.hue + hslSaturationSpinBox.value = colorPicker.saturationHSL + hslLightnessSpinBox.value = colorPicker.lightness + hslAlphaSpinBox.value = colorPicker.alpha - case ColorPicker.Mode.RGBA: - redSpinBox.value = (colorPicker.color.r * 255) - greenSpinBox.value = (colorPicker.color.g * 255) - blueSpinBox.value = (colorPicker.color.b * 255) - rgbAlphaSpinBox.value = (colorPicker.alpha * 255) - break + redSpinBox.value = (colorPicker.red * 255) + greenSpinBox.value = (colorPicker.green * 255) + blueSpinBox.value = (colorPicker.blue * 255) + rgbAlphaSpinBox.value = (colorPicker.alpha * 255) - case ColorPicker.Mode.HSVA: - default: - hsvHueSpinBox.value = colorPicker.hue - hsvSaturationSpinBox.value = colorPicker.saturationHSV - hsvValueSpinBox.value = colorPicker.value - hsvAlphaSpinBox.value = colorPicker.alpha - break - } + hsvHueSpinBox.value = colorPicker.hue + hsvSaturationSpinBox.value = colorPicker.saturationHSV + hsvValueSpinBox.value = colorPicker.value + hsvAlphaSpinBox.value = colorPicker.alpha } } @@ -790,7 +795,6 @@ SecondColumnLayout { RowLayout { id: rgbaRow - visible: colorPicker.mode === ColorPicker.Mode.RGBA Layout.fillWidth: true spacing: StudioTheme.Values.controlGap @@ -798,7 +802,6 @@ SecondColumnLayout { DoubleSpinBox { id: redSpinBox width: StudioTheme.Values.colorEditorPopupSpinBoxWidth - stepSize: 1 minimumValue: 0 maximumValue: 255 @@ -806,17 +809,19 @@ SecondColumnLayout { onValueModified: { var tmp = redSpinBox.value / 255.0 - if (colorPicker.color.r !== tmp && !colorPicker.block) { - colorPicker.color.r = tmp + if (colorPicker.red !== tmp && !colorPicker.block) { + colorPicker.red = tmp + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { id: greenSpinBox width: StudioTheme.Values.colorEditorPopupSpinBoxWidth - stepSize: 1 minimumValue: 0 maximumValue: 255 @@ -824,17 +829,19 @@ SecondColumnLayout { onValueModified: { var tmp = greenSpinBox.value / 255.0 - if (colorPicker.color.g !== tmp && !colorPicker.block) { - colorPicker.color.g = tmp + if (colorPicker.green !== tmp && !colorPicker.block) { + colorPicker.green = tmp + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { id: blueSpinBox width: StudioTheme.Values.colorEditorPopupSpinBoxWidth - stepSize: 1 minimumValue: 0 maximumValue: 255 @@ -842,17 +849,19 @@ SecondColumnLayout { onValueModified: { var tmp = blueSpinBox.value / 255.0 - if (colorPicker.color.b !== tmp && !colorPicker.block) { - colorPicker.color.b = tmp + if (colorPicker.blue !== tmp && !colorPicker.block) { + colorPicker.blue = tmp + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { id: rgbAlphaSpinBox width: StudioTheme.Values.colorEditorPopupSpinBoxWidth - stepSize: 1 minimumValue: 0 maximumValue: 255 @@ -862,15 +871,17 @@ SecondColumnLayout { var tmp = rgbAlphaSpinBox.value / 255.0 if (colorPicker.alpha !== tmp && !colorPicker.block) { colorPicker.alpha = tmp + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } } RowLayout { id: hslaRow - visible: colorPicker.mode === ColorPicker.Mode.HSLA Layout.fillWidth: true spacing: StudioTheme.Values.controlGap @@ -882,9 +893,12 @@ SecondColumnLayout { if (colorPicker.hue !== hslHueSpinBox.value && !colorPicker.block) { colorPicker.hue = hslHueSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { @@ -894,9 +908,12 @@ SecondColumnLayout { if (colorPicker.saturationHSL !== hslSaturationSpinBox.value && !colorPicker.block) { colorPicker.saturationHSL = hslSaturationSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { @@ -906,6 +923,7 @@ SecondColumnLayout { if (colorPicker.lightness !== hslLightnessSpinBox.value && !colorPicker.block) { colorPicker.lightness = hslLightnessSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } @@ -918,15 +936,17 @@ SecondColumnLayout { if (colorPicker.alpha !== hslAlphaSpinBox.value && !colorPicker.block) { colorPicker.alpha = hslAlphaSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } } RowLayout { id: hsvaRow - visible: colorPicker.mode === ColorPicker.Mode.HSVA Layout.fillWidth: true spacing: StudioTheme.Values.controlGap @@ -938,9 +958,12 @@ SecondColumnLayout { if (colorPicker.hue !== hsvHueSpinBox.value && !colorPicker.block) { colorPicker.hue = hsvHueSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { @@ -950,9 +973,12 @@ SecondColumnLayout { if (colorPicker.saturationHSV !== hsvSaturationSpinBox.value && !colorPicker.block) { colorPicker.saturationHSV = hsvSaturationSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { @@ -962,9 +988,12 @@ SecondColumnLayout { if (colorPicker.value !== hsvValueSpinBox.value && !colorPicker.block) { colorPicker.value = hsvValueSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } DoubleSpinBox { @@ -974,9 +1003,12 @@ SecondColumnLayout { if (colorPicker.alpha !== hsvAlphaSpinBox.value && !colorPicker.block) { colorPicker.alpha = hsvAlphaSpinBox.value + colorPicker.invalidateColor() colorPicker.updateColor() } } + onDragStarted: colorEditorTimer.stop() + onIndicatorPressed: colorEditorTimer.stop() } } } @@ -986,7 +1018,6 @@ SecondColumnLayout { caption: qsTr("Palette") anchors.left: parent.left anchors.right: parent.right - leftPadding: 10 rightPadding: 10 bottomPadding: 5 @@ -994,8 +1025,14 @@ SecondColumnLayout { ColorPalette { id: colorPalette enableSingletonConnection: cePopup.opened - onSelectedColorChanged: colorEditor.color = colorPalette.selectedColor - onDialogColorChanged: colorEditor.color = colorPalette.selectedColor + onSelectedColorChanged: { + 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.right: parent.right visible: !colorEditor.isNotInGradientMode() - leftPadding: 10 rightPadding: 10 @@ -1039,12 +1075,10 @@ SecondColumnLayout { Column { id: defaultGradientControls spacing: 10 - visible: colorEditor.hasLinearGradient() && !colorEditor.shapeGradients RowLayout { id: defaultGradientOrientation - Layout.fillWidth: true spacing: 0 @@ -1055,9 +1089,9 @@ SecondColumnLayout { width: implicitWidth model: [{ value: Gradient.Vertical, text: qsTr("Vertical") }, { value: Gradient.Horizontal, text: qsTr("Horizontal") }] - textRole: "text" valueRole: "value" + onActivated: { gradientLine.model.setGradientOrientation(gradientOrientation.currentValue) colorEditor.updateThumbnail() @@ -1090,7 +1124,6 @@ SecondColumnLayout { Column { id: linearGradientControls spacing: 10 - visible: colorEditor.hasLinearGradient() && colorEditor.shapeGradients ControlsRow { @@ -1126,7 +1159,6 @@ SecondColumnLayout { Column { id: radialGradientControls spacing: 10 - visible: colorEditor.hasRadialGradient() ControlsRow { @@ -1170,7 +1202,6 @@ SecondColumnLayout { Column { id: concialGradientControls spacing: 10 - visible: colorEditor.hasConicalGradient() ControlsRow { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorPicker.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorPicker.qml index 13f43f79955..640ba3a0c25 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorPicker.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/ColorPicker.qml @@ -36,18 +36,20 @@ Column { } 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 saturationHSL: 0 - property real saturationHSV: 0 - property real lightness: 0 - property real value: 0 + property real saturationHSL: 0.5 + property real saturationHSV: 0.5 + property real lightness: 0.5 + property real value: 0.5 property real alpha: 1 - property bool achromatic: false - property int sliderMargins: 6 property bool block: false @@ -57,81 +59,90 @@ Column { spacing: 10 - onModeChanged: { + onColorChanged: { + if (root.block) + return + switch (root.mode) { 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 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 case ColorPicker.Mode.HSVA: 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 } - 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() { if (root.block) return root.block = true - if (root.color.hsvSaturation > 0.0 - && root.color.hsvValue > 0.0 - && root.color.hsvHue !== -1.0) - root.hue = root.color.hsvHue + switch (root.mode) { + case ColorPicker.Mode.RGBA: + root.color = Qt.rgba(root.red, root.green, root.blue, root.alpha) + // 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 - && root.color.hslLightness > 0.0 - && root.color.hslHue !== -1.0) - root.hue = root.color.hslHue + if (root.color.hslLightness !== 0.0 && root.color.hslLightness !== 1.0) + root.saturationHSL = root.color.hslSaturation - if (root.color.hslLightness !== 0.0 && root.color.hslLightness !== 1.0 && !root.achromatic) - root.saturationHSL = root.color.hslSaturation + if (root.color.hsvValue !== 0.0) + root.saturationHSV = root.color.hsvSaturation - if (root.color.hsvValue !== 0.0 && root.color.hsvValue !== 1.0 && !root.achromatic) - root.saturationHSV = root.color.hsvSaturation - - root.lightness = root.color.hslLightness - 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.lightness = root.color.hslLightness + root.value = root.color.hsvValue + break + case ColorPicker.Mode.HSLA: 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) + // 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) hueSlider.value = root.hue @@ -142,21 +153,21 @@ Column { root.block = false } - function drawHSVA(ctx) { - for (var row = 0; row < gradientOverlay.height; row++) { - var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0) - var v = Math.abs(row - gradientOverlay.height) / gradientOverlay.height + function drawHSVA(ctx, width, height, hue) { + for (var row = 0; row < height; row++) { + var gradient = ctx.createLinearGradient(0, 0, width, 0) + var v = Math.abs(row - height) / height - gradient.addColorStop(0, Qt.hsva(root.hue, 0, v, 1)) - gradient.addColorStop(1, Qt.hsva(root.hue, 1, v, 1)) + gradient.addColorStop(0, Qt.hsva(hue, 0, v, 1)) + gradient.addColorStop(1, Qt.hsva(hue, 1, v, 1)) ctx.fillStyle = gradient - ctx.fillRect(0, row, gradientOverlay.width, 1) + ctx.fillRect(0, row, width, 1) } } - function drawRGBA(ctx) { - var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0) + function drawRGBA(ctx, width, height) { + var gradient = ctx.createLinearGradient(0, 0, width, 0) gradient.addColorStop(0.000, Qt.rgba(1, 0, 0, 1)) gradient.addColorStop(0.167, Qt.rgba(1, 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)) 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(1.000, Qt.rgba(1, 1, 1, 1)) ctx.fillStyle = gradient - ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height) + ctx.fillRect(0, 0, width, height) } - function drawHSLA(ctx) { - for (var row = 0; row < gradientOverlay.height; row++) { - var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0) - var l = Math.abs(row - gradientOverlay.height) / gradientOverlay.height + function drawHSLA(ctx, width, height, hue) { + for (var row = 0; row < height; row++) { + var gradient = ctx.createLinearGradient(0, 0, width, 0) + var l = Math.abs(row - height) / height - gradient.addColorStop(0, Qt.hsla(root.hue, 0, l, 1)) - gradient.addColorStop(1, Qt.hsla(root.hue, 1, l, 1)) + gradient.addColorStop(0, Qt.hsla(hue, 0, l, 1)) + gradient.addColorStop(1, Qt.hsla(hue, 1, l, 1)) ctx.fillStyle = gradient - ctx.fillRect(0, row, gradientOverlay.width, 1) + ctx.fillRect(0, row, width, 1) } } @@ -211,11 +222,12 @@ Column { id: gradientOverlay anchors.fill: parent - opacity: root.color.a + opacity: root.alpha Connections { target: root function onHueChanged() { gradientOverlay.requestPaint() } + function onModeChanged() { gradientOverlay.requestPaint() } } onPaint: { @@ -225,14 +237,14 @@ Column { switch (root.mode) { case ColorPicker.Mode.RGBA: - root.drawRGBA(ctx) + root.drawRGBA(ctx, gradientOverlay.width, gradientOverlay.height) break case ColorPicker.Mode.HSLA: - root.drawHSLA(ctx) + root.drawHSLA(ctx, gradientOverlay.width, gradientOverlay.height, root.hue) break case ColorPicker.Mode.HSVA: default: - root.drawHSVA(ctx) + root.drawHSVA(ctx, gradientOverlay.width, gradientOverlay.height, root.hue) break } @@ -244,9 +256,14 @@ Column { id: pickerCross 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.margins: -pickerCross.radius antialiasing: true Connections { @@ -261,35 +278,63 @@ Column { ctx.save() ctx.clearRect(0, 0, pickerCross.width, pickerCross.height) - var yy, xx = 0 + var normX, normY = 0 switch (root.mode) { case ColorPicker.Mode.RGBA: - yy = pickerCross.height - root.saturationHSV * pickerCross.height - xx = root.hue * pickerCross.width + normX = root.hue + normY = 1.0 - root.saturationHSV break case ColorPicker.Mode.HSLA: - yy = pickerCross.height - root.lightness * pickerCross.height - xx = root.saturationHSL * pickerCross.width + normX = root.saturationHSL + normY = 1.0 - root.lightness break case ColorPicker.Mode.HSVA: default: - yy = pickerCross.height - root.value * pickerCross.height - xx = root.saturationHSV * pickerCross.width + normX = root.saturationHSV + normY = 1.0 - root.value break } - ctx.strokeStyle = pickerCross.strokeStyle - ctx.lineWidth = 1 + var width = pickerCross.width - pickerCross.radius * 2 + 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.moveTo(0, yy) - ctx.lineTo(pickerCross.width, yy) + ctx.arc(centerX, centerY, pickerCross.radius, 0, 2 * Math.PI) ctx.stroke() + ctx.strokeStyle = "white" ctx.beginPath() - ctx.moveTo(xx, 0) - ctx.lineTo(xx, pickerCross.height) + ctx.arc(centerX, centerY, pickerCross.radius - 2, 0, 2 * Math.PI) ctx.stroke() ctx.restore() @@ -298,31 +343,48 @@ Column { MouseArea { id: mouseArea - anchors.fill: parent + anchors.margins: -pickerCross.radius preventStealing: true acceptedButtons: Qt.LeftButton | Qt.RightButton onPositionChanged: function(mouse) { if (mouseArea.pressed && mouse.buttons === Qt.LeftButton) { - var xx = Math.max(0, Math.min(mouse.x, parent.width)) - var yy = Math.max(0, Math.min(mouse.y, parent.height)) + // Generate color values from mouse position + + // 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) { case ColorPicker.Mode.RGBA: - root.saturationHSV = 1.0 - yy / parent.height - root.hue = xx / parent.width + var tmpColor = Qt.hsva(normX, // hue + 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 case ColorPicker.Mode.HSLA: - root.saturationHSL = xx / parent.width - root.lightness = 1.0 - yy / parent.height + root.saturationHSL = normX + root.lightness = 1.0 - normY break case ColorPicker.Mode.HSVA: default: - root.saturationHSV = xx / parent.width - root.value = 1.0 - yy / parent.height + root.saturationHSV = normX + root.value = 1.0 - normY break } + + root.invalidateColor() } } onPressed: function(mouse) { @@ -345,9 +407,11 @@ Column { id: hueSlider visible: root.mode !== ColorPicker.Mode.RGBA width: parent.width - onValueChanged: { + onMoved: { if (root.hue !== hueSlider.value) root.hue = hueSlider.value + + root.invalidateColor() } onClicked: root.updateColor() } @@ -356,10 +420,21 @@ Column { id: luminanceSlider visible: root.mode === ColorPicker.Mode.RGBA width: parent.width - color: Qt.hsva(root.hue, root.color.hsvSaturation, 1, 1) - onValueChanged: { - if (root.value !== luminanceSlider.value) + color: Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha) + onMoved: { + if (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() } @@ -367,10 +442,12 @@ Column { OpacitySlider { id: opacitySlider width: parent.width - color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1) - onValueChanged: { - if (root.alpha !== opacitySlider.value) + color: root.color + onMoved: { + if (root.alpha !== (1.0 - opacitySlider.value)) root.alpha = (1.0 - opacitySlider.value) + + root.invalidateColor() } onClicked: root.updateColor() } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DoubleSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DoubleSpinBox.qml index de0b0de64c1..10e21ec3f16 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DoubleSpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/DoubleSpinBox.qml @@ -39,6 +39,8 @@ Item { property alias hover: spinBox.hover signal valueModified + signal dragStarted + signal indicatorPressed width: 90 implicitHeight: spinBox.height @@ -48,9 +50,13 @@ Item { StudioControls.RealSpinBox { id: spinBox - onDragStarted: hideCursor() + onDragStarted: { + hideCursor() + wrapper.dragStarted() + } onDragEnded: restoreCursor() onDragging: holdCursorInPlace() + onIndicatorPressed: wrapper.indicatorPressed() property bool hasSlider: spinBox.sliderIndicatorVisible diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientLine.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientLine.qml index 8e32e3bce0e..c29d8d0689c 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientLine.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientLine.qml @@ -96,13 +96,12 @@ Item { height: 80 width: parent.width - property int effectiveWidth: width - 10 + property int effectiveWidth: colorLine.width - 10 property int selectedIndex: 0 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 - } if (repeater.model.count < index + 1) return @@ -113,11 +112,12 @@ Item { gradientModel.lock() root.currentColor = repeater.itemAt(index).item.color gradientModel.unlock() + root.selectedNodeChanged() } 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++) { gradientString += "GradientStop {}" @@ -209,21 +209,21 @@ Item { anchors.left: parent.left anchors.right: parent.right + Image { + id: checkerboard + anchors.fill: parent + source: "images/checkers.png" + fillMode: Image.Tile + } + Rectangle { id: gradientRectangle - smooth: true - x: 0 - y: 16 - radius: 1 - border.color: "#555555" - border.width: 1 - width: parent.height - height: parent.width + anchors.fill: parent + border.color: StudioTheme.Values.themeControlOutline + border.width: StudioTheme.Values.border gradient: Gradient { id: gradient } - transformOrigin: Item.TopLeft - rotation: 270 } } } @@ -270,6 +270,13 @@ Item { onXChanged: gradientStopHandle.refreshToolTip(gradientStopHandle.toolTipVisible) + Image { + width: 10 + height: 10 + source: "images/checkers.png" + fillMode: Image.Tile + } + Rectangle { id: rectangle width: 10 @@ -277,7 +284,6 @@ Item { color: "red" border.color: "gray" border.width: 1 - radius: 1 } Canvas { diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPopupIndicator.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPopupIndicator.qml deleted file mode 100644 index 4212bfa2483..00000000000 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/GradientPopupIndicator.qml +++ /dev/null @@ -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") - } -} diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HueSlider.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HueSlider.qml index a09fc23d7f3..d3108c70fa2 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HueSlider.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/HueSlider.qml @@ -36,13 +36,14 @@ Item { property bool integer: false signal clicked + signal moved height: StudioTheme.Values.hueSliderHeight function updatePos() { if (root.maximum > root.minimum) { - var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum) - return Math.min(Math.max(pos, 0), track.width - handle.width) + var pos = track.width * (root.value - root.minimum) / (root.maximum - root.minimum) + return Math.min(Math.max(pos, 0), track.width) } else { return 0 } @@ -50,7 +51,6 @@ Item { Item { id: track - width: parent.width height: parent.height @@ -74,21 +74,20 @@ Item { Rectangle { id: handle width: StudioTheme.Values.hueSliderHandleWidth - height: track.height - 4 + height: track.height + 4 anchors.verticalCenter: parent.verticalCenter - smooth: true color: "transparent" radius: 2 border.color: "black" border.width: 1 - x: root.updatePos() + x: root.updatePos() - handle.width * 0.5 y: 2 z: 1 Rectangle { anchors.fill: parent anchors.margins: 1 - color: "transparent" + color: Qt.hsva(value, 1, 1, 1) radius: 1 border.color: "white" border.width: 1 @@ -98,21 +97,23 @@ Item { MouseArea { id: mouseArea anchors.fill: parent + anchors.margins: -StudioTheme.Values.hueSliderHandleWidth * 0.5 preventStealing: true function calculateValue() { - var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width)) - var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum + var halfHandle = StudioTheme.Values.hueSliderHandleWidth * 0.5 + 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.moved() } - onPressed: calculateValue() + onPressed: mouseArea.calculateValue() onReleased: root.clicked() onPositionChanged: { - if (pressed) - calculateValue() + if (mouseArea.pressed) + mouseArea.calculateValue() } } - } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LuminanceSlider.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LuminanceSlider.qml index a1fe726a9cd..c7397df6c2d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LuminanceSlider.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/LuminanceSlider.qml @@ -37,13 +37,14 @@ Item { property color color signal clicked + signal moved height: StudioTheme.Values.hueSliderHeight function updatePos() { if (root.maximum > root.minimum) { - var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum) - return Math.min(Math.max(pos, 0), track.width - handle.width) + var pos = track.width * (root.value - root.minimum) / (root.maximum - root.minimum) + return Math.min(Math.max(pos, 0), track.width) } else { return 0 } @@ -51,17 +52,9 @@ Item { Item { id: track - width: parent.width height: parent.height - Image { - id: checkerboard - anchors.fill: parent - source: "images/checkers.png" - fillMode: Image.Tile - } - Rectangle { anchors.fill: parent border.color: StudioTheme.Values.themeControlOutline @@ -69,7 +62,7 @@ Item { gradient: Gradient { 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" } } } @@ -77,21 +70,20 @@ Item { Rectangle { id: handle width: StudioTheme.Values.hueSliderHandleWidth - height: track.height - 4 + height: track.height + 4 anchors.verticalCenter: parent.verticalCenter - smooth: true color: "transparent" radius: 2 border.color: "black" border.width: 1 - x: root.updatePos() + x: root.updatePos() - handle.width * 0.5 y: 2 z: 1 Rectangle { anchors.fill: parent anchors.margins: 1 - color: "transparent" + color: Qt.hsva(root.color.hsvHue, root.color.hsvSaturation, root.color.hsvValue, 1) radius: 1 border.color: "white" border.width: 1 @@ -101,19 +93,22 @@ Item { MouseArea { id: mouseArea anchors.fill: parent + anchors.margins: -StudioTheme.Values.hueSliderHandleWidth * 0.5 preventStealing: true function calculateValue() { - var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width)) - var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum + var halfHandle = StudioTheme.Values.hueSliderHandleWidth * 0.5 + 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.moved() } - onPressed: calculateValue() + onPressed: mouseArea.calculateValue() onReleased: root.clicked() onPositionChanged: { - if (pressed) - calculateValue() + if (mouseArea.pressed) + mouseArea.calculateValue() } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OpacitySlider.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OpacitySlider.qml index 176b493a19b..85fbbe6434b 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OpacitySlider.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/OpacitySlider.qml @@ -37,13 +37,14 @@ Item { property color color signal clicked + signal moved height: StudioTheme.Values.hueSliderHeight function updatePos() { if (root.maximum > root.minimum) { - var pos = (track.width - handle.width) * (root.value - root.minimum) / (root.maximum - root.minimum) - return Math.min(Math.max(pos, 0), track.width - handle.width) + var pos = track.width * (root.value - root.minimum) / (root.maximum - root.minimum) + return Math.min(Math.max(pos, 0), track.width) } else { return 0 } @@ -51,12 +52,10 @@ Item { Item { id: track - width: parent.width height: parent.height Image { - id: checkerboard anchors.fill: parent source: "images/checkers.png" fillMode: Image.Tile @@ -69,7 +68,7 @@ Item { gradient: Gradient { 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" } } } @@ -77,21 +76,27 @@ Item { Rectangle { id: handle width: StudioTheme.Values.hueSliderHandleWidth - height: track.height - 4 + height: track.height + 4 anchors.verticalCenter: parent.verticalCenter - smooth: true color: "transparent" radius: 2 border.color: "black" border.width: 1 - x: root.updatePos() + x: root.updatePos() - handle.width * 0.5 y: 2 z: 1 + Image { + anchors.fill: handleInside + source: "images/checkers.png" + fillMode: Image.Tile + } + Rectangle { + id: handleInside anchors.fill: parent anchors.margins: 1 - color: "transparent" + color: root.color radius: 1 border.color: "white" border.width: 1 @@ -101,19 +106,22 @@ Item { MouseArea { id: mouseArea anchors.fill: parent + anchors.margins: -StudioTheme.Values.hueSliderHandleWidth * 0.5 preventStealing: true function calculateValue() { - var handleX = Math.max(0, Math.min(mouseArea.mouseX, mouseArea.width)) - var realValue = (root.maximum - root.minimum) * handleX / mouseArea.width + root.minimum + var halfHandle = StudioTheme.Values.hueSliderHandleWidth * 0.5 + 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.moved() } - onPressed: calculateValue() + onPressed: mouseArea.calculateValue() onReleased: root.clicked() onPositionChanged: { - if (pressed) - calculateValue() + if (mouseArea.pressed) + mouseArea.calculateValue() } } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir index 19a4c8c2ae1..8b87f1ca79f 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/HelperWidgets/qmldir @@ -31,7 +31,6 @@ FontExtrasSection 2.0 FontExtrasSection.qml FontSection 2.0 FontSection.qml FontStyleButtons 2.0 FontStyleButtons.qml GradientLine 2.0 GradientLine.qml -GradientPopupIndicator 2.0 GradientPopupIndicator.qml GradientPresetList 2.0 GradientPresetList.qml GradientPresetTabContent 2.0 GradientPresetTabContent.qml GradientPropertySpinBox 2.0 GradientPropertySpinBox.qml diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml index c5919d2ef27..98fdccddb0d 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/ComboBox.qml @@ -121,7 +121,7 @@ T.ComboBox { ComboBox.ActivatedReason.Other) } - onActivated: { + onActivated: function(index) { myTimer.activatedIndex = index myTimer.restart() } diff --git a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml index cc8487ddb9d..dd2fe2357f1 100644 --- a/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml +++ b/share/qtcreator/qmldesigner/propertyEditorQmlSources/imports/StudioControls/RealSpinBox.qml @@ -81,6 +81,7 @@ T.SpinBox { signal dragStarted signal dragEnded signal dragging + signal indicatorPressed // Use custom wheel handling due to bugs property bool __wheelEnabled: false @@ -124,6 +125,7 @@ T.SpinBox { myControl: mySpinBox iconFlip: -1 visible: mySpinBox.spinBoxIndicatorVisible + onRealPressed: mySpinBox.indicatorPressed() onRealReleased: mySpinBox.realIncrease() onRealPressAndHold: mySpinBox.realIncrease() x: actionIndicator.width + StudioTheme.Values.border @@ -139,6 +141,7 @@ T.SpinBox { id: spinBoxIndicatorDown myControl: mySpinBox visible: mySpinBox.spinBoxIndicatorVisible + onRealPressed: mySpinBox.indicatorPressed() onRealReleased: mySpinBox.realDecrease() onRealPressAndHold: mySpinBox.realDecrease() x: actionIndicator.width + StudioTheme.Values.border diff --git a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp index 684a1746e03..99686cae30b 100644 --- a/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp +++ b/src/plugins/qmldesigner/components/propertyeditor/propertyeditorvalue.cpp @@ -155,15 +155,17 @@ void PropertyEditorValue::setValueWithEmit(const QVariant &value) void PropertyEditorValue::setValue(const QVariant &value) { + const bool colorsEqual = cleverColorCompare(value, m_value); + if (!compareVariants(m_value, value) && !cleverDoubleCompare(value, m_value) && - !cleverColorCompare(value, m_value)) + !colorsEqual) m_value = value; fixAmbigousColorNames(modelNode(), name(), &m_value); fixUrl(modelNode(), name(), &m_value); - if (m_value.isValid()) + if (m_value.isValid() && !colorsEqual) emit valueChangedQml(); emit isExplicitChanged();