forked from qt-creator/qt-creator
QmlDesigner: Add RGB und HSV picker
* Add modes to color picker * Add color picker for RGBA mode * Add color picker for HSVA mode * Add luminance slider for RGBA mode Change-Id: I0bb1dbb67b7c18d156eee0d4e07cfa942162f832 Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
committed by
Henning Gründl
parent
4895eb346a
commit
6fef74a8cb
@@ -413,7 +413,7 @@ SecondColumnLayout {
|
|||||||
id: transparentIndicator
|
id: transparentIndicator
|
||||||
icon: StudioTheme.Constants.transparent
|
icon: StudioTheme.Constants.transparent
|
||||||
pixelSize: StudioTheme.Values.myIconFontSize * 1.4
|
pixelSize: StudioTheme.Values.myIconFontSize * 1.4
|
||||||
tooltip: qsTr("Transparent TODO")
|
tooltip: qsTr("Transparent")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
colorPicker.alpha = 0
|
colorPicker.alpha = 0
|
||||||
colorPicker.updateColor()
|
colorPicker.updateColor()
|
||||||
@@ -575,22 +575,29 @@ SecondColumnLayout {
|
|||||||
onRightMouseButtonClicked: contextMenu.popup(colorPicker)
|
onRightMouseButtonClicked: contextMenu.popup(colorPicker)
|
||||||
|
|
||||||
onColorInvalidated: {
|
onColorInvalidated: {
|
||||||
if (colorPicker.saturation > 0.0 && colorPicker.lightness > 0.0) {
|
switch (colorPicker.mode) {
|
||||||
hueSpinBox.value = colorPicker.hue
|
case ColorPicker.Mode.HSLA:
|
||||||
|
hslHueSpinBox.value = colorPicker.hue
|
||||||
|
hslSaturationSpinBox.value = colorPicker.saturationHSL
|
||||||
|
hslLightnessSpinBox.value = colorPicker.lightness
|
||||||
|
hslAlphaSpinBox.value = colorPicker.alpha
|
||||||
|
break
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
case ColorPicker.Mode.HSVA:
|
||||||
|
default:
|
||||||
|
hsvHueSpinBox.value = colorPicker.hue
|
||||||
|
hsvSaturationSpinBox.value = colorPicker.saturationHSV
|
||||||
|
hsvValueSpinBox.value = colorPicker.value
|
||||||
|
hsvAlphaSpinBox.value = colorPicker.alpha
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (colorPicker.lightness > 0.0)
|
|
||||||
saturationSpinBox.value = colorPicker.saturation
|
|
||||||
else
|
|
||||||
colorPicker.saturation = saturationSpinBox.value
|
|
||||||
|
|
||||||
lightnessSpinBox.value = colorPicker.lightness
|
|
||||||
hslaAlphaSpinBox.value = colorPicker.alpha
|
|
||||||
|
|
||||||
redSpinBox.value = (colorPicker.color.r * 255)
|
|
||||||
greenSpinBox.value = (colorPicker.color.g * 255)
|
|
||||||
blueSpinBox.value = (colorPicker.color.b * 255)
|
|
||||||
rgbaAlphaSpinBox.value = (colorPicker.alpha * 255)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -766,29 +773,22 @@ SecondColumnLayout {
|
|||||||
+ 4 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
+ 4 * StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
width: implicitWidth
|
width: implicitWidth
|
||||||
actionIndicatorVisible: false
|
actionIndicatorVisible: false
|
||||||
model: ["RGBA", "HSLA"]
|
textRole: "text"
|
||||||
onActivated: {
|
valueRole: "value"
|
||||||
switch (colorMode.currentText) {
|
model: [
|
||||||
case "RGBA":
|
{ value: ColorPicker.Mode.HSVA, text: "HSVA" },
|
||||||
rgbaRow.visible = true
|
{ value: ColorPicker.Mode.RGBA, text: "RGBA" },
|
||||||
hslaRow.visible = false
|
{ value: ColorPicker.Mode.HSLA, text: "HSLA" }
|
||||||
break
|
]
|
||||||
case "HSLA":
|
|
||||||
rgbaRow.visible = false
|
onActivated: colorPicker.mode = colorMode.currentValue
|
||||||
hslaRow.visible = true
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
console.log("Unknown color mode selected.")
|
|
||||||
rgbaRow.visible = true
|
|
||||||
hslaRow.visible = false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
id: rgbaRow
|
id: rgbaRow
|
||||||
|
|
||||||
|
visible: colorPicker.mode === ColorPicker.Mode.RGBA
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: StudioTheme.Values.controlGap
|
spacing: StudioTheme.Values.controlGap
|
||||||
|
|
||||||
@@ -847,7 +847,7 @@ SecondColumnLayout {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DoubleSpinBox {
|
DoubleSpinBox {
|
||||||
id: rgbaAlphaSpinBox
|
id: rgbAlphaSpinBox
|
||||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
|
|
||||||
stepSize: 1
|
stepSize: 1
|
||||||
@@ -856,7 +856,7 @@ SecondColumnLayout {
|
|||||||
decimals: 0
|
decimals: 0
|
||||||
|
|
||||||
onValueModified: {
|
onValueModified: {
|
||||||
var tmp = rgbaAlphaSpinBox.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.updateColor()
|
colorPicker.updateColor()
|
||||||
@@ -868,49 +868,109 @@ SecondColumnLayout {
|
|||||||
RowLayout {
|
RowLayout {
|
||||||
id: hslaRow
|
id: hslaRow
|
||||||
|
|
||||||
visible: false
|
visible: colorPicker.mode === ColorPicker.Mode.HSLA
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
spacing: StudioTheme.Values.controlGap
|
spacing: StudioTheme.Values.controlGap
|
||||||
|
|
||||||
DoubleSpinBox {
|
DoubleSpinBox {
|
||||||
id: hueSpinBox
|
id: hslHueSpinBox
|
||||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
onValueModified: {
|
onValueModified: {
|
||||||
if (colorPicker.hue !== hueSpinBox.value && !colorPicker.block) {
|
if (colorPicker.hue !== hslHueSpinBox.value
|
||||||
colorPicker.hue = hueSpinBox.value
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.hue = hslHueSpinBox.value
|
||||||
colorPicker.updateColor()
|
colorPicker.updateColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DoubleSpinBox {
|
DoubleSpinBox {
|
||||||
id: saturationSpinBox
|
id: hslSaturationSpinBox
|
||||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
onValueModified: {
|
onValueModified: {
|
||||||
if (colorPicker.saturation !== saturationSpinBox.value && !colorPicker.block) {
|
if (colorPicker.saturationHSL !== hslSaturationSpinBox.value
|
||||||
colorPicker.saturation = saturationSpinBox.value
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.saturationHSL = hslSaturationSpinBox.value
|
||||||
colorPicker.updateColor()
|
colorPicker.updateColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DoubleSpinBox {
|
DoubleSpinBox {
|
||||||
id: lightnessSpinBox
|
id: hslLightnessSpinBox
|
||||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
onValueModified: {
|
onValueModified: {
|
||||||
if (colorPicker.lightness !== lightnessSpinBox.value && !colorPicker.block) {
|
if (colorPicker.lightness !== hslLightnessSpinBox.value
|
||||||
colorPicker.lightness = lightnessSpinBox.value
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.lightness = hslLightnessSpinBox.value
|
||||||
colorPicker.updateColor()
|
colorPicker.updateColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DoubleSpinBox {
|
DoubleSpinBox {
|
||||||
id: hslaAlphaSpinBox
|
id: hslAlphaSpinBox
|
||||||
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
onValueModified: {
|
onValueModified: {
|
||||||
if (colorPicker.alpha !== hslaAlphaSpinBox.value && !colorPicker.block) {
|
if (colorPicker.alpha !== hslAlphaSpinBox.value
|
||||||
colorPicker.alpha = hslaAlphaSpinBox.value
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.alpha = hslAlphaSpinBox.value
|
||||||
|
colorPicker.updateColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
id: hsvaRow
|
||||||
|
|
||||||
|
visible: colorPicker.mode === ColorPicker.Mode.HSVA
|
||||||
|
Layout.fillWidth: true
|
||||||
|
spacing: StudioTheme.Values.controlGap
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: hsvHueSpinBox
|
||||||
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
|
onValueModified: {
|
||||||
|
if (colorPicker.hue !== hsvHueSpinBox.value
|
||||||
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.hue = hsvHueSpinBox.value
|
||||||
|
colorPicker.updateColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: hsvSaturationSpinBox
|
||||||
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
|
onValueModified: {
|
||||||
|
if (colorPicker.saturationHSV !== hsvSaturationSpinBox.value
|
||||||
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.saturationHSV = hsvSaturationSpinBox.value
|
||||||
|
colorPicker.updateColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: hsvValueSpinBox
|
||||||
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
|
onValueModified: {
|
||||||
|
if (colorPicker.value !== hsvValueSpinBox.value
|
||||||
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.value = hsvValueSpinBox.value
|
||||||
|
colorPicker.updateColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DoubleSpinBox {
|
||||||
|
id: hsvAlphaSpinBox
|
||||||
|
width: StudioTheme.Values.colorEditorPopupSpinBoxWidth
|
||||||
|
onValueModified: {
|
||||||
|
if (colorPicker.alpha !== hsvAlphaSpinBox.value
|
||||||
|
&& !colorPicker.block) {
|
||||||
|
colorPicker.alpha = hsvAlphaSpinBox.value
|
||||||
colorPicker.updateColor()
|
colorPicker.updateColor()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -29,15 +29,26 @@ import StudioTheme 1.0 as StudioTheme
|
|||||||
Column {
|
Column {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
enum Mode {
|
||||||
|
HSVA,
|
||||||
|
RGBA,
|
||||||
|
HSLA
|
||||||
|
}
|
||||||
|
|
||||||
|
property int mode: ColorPicker.Mode.HSVA
|
||||||
property color color
|
property color color
|
||||||
property real alpha: 1
|
|
||||||
|
|
||||||
property real hue: 0
|
property real hue: 0
|
||||||
property real saturation: 0
|
property real saturationHSL: 0
|
||||||
|
property real saturationHSV: 0
|
||||||
property real lightness: 0
|
property real lightness: 0
|
||||||
|
property real value: 0
|
||||||
|
|
||||||
|
property real alpha: 1
|
||||||
|
|
||||||
|
property bool achromatic: false
|
||||||
|
|
||||||
property int sliderMargins: 6
|
property int sliderMargins: 6
|
||||||
|
|
||||||
property bool block: false
|
property bool block: false
|
||||||
|
|
||||||
signal updateColor
|
signal updateColor
|
||||||
@@ -46,30 +57,84 @@ Column {
|
|||||||
|
|
||||||
spacing: 10
|
spacing: 10
|
||||||
|
|
||||||
onAlphaChanged: invalidateColor()
|
onModeChanged: {
|
||||||
onSaturationChanged: invalidateColor()
|
switch (root.mode) {
|
||||||
onLightnessChanged: invalidateColor()
|
case ColorPicker.Mode.RGBA:
|
||||||
onHueChanged: invalidateColor()
|
root.color = Qt.rgba(root.color.r, root.color.g, root.color.b, root.alpha)
|
||||||
onColorChanged: {
|
break
|
||||||
var myAlpha = root.color.a
|
case ColorPicker.Mode.HSLA:
|
||||||
rgbToHsl(root.color)
|
root.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha)
|
||||||
root.alpha = myAlpha
|
break
|
||||||
|
case ColorPicker.Mode.HSVA:
|
||||||
|
default:
|
||||||
|
root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
gradientOverlay.requestPaint()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
root.color = Qt.hsla(root.hue,
|
if (root.color.hsvSaturation > 0.0
|
||||||
root.saturation,
|
&& root.color.hsvValue > 0.0
|
||||||
root.lightness,
|
&& root.color.hsvHue !== -1.0)
|
||||||
root.alpha)
|
root.hue = root.color.hsvHue
|
||||||
|
|
||||||
if (root.saturation > 0.0 && root.lightness > 0.0)
|
if (root.color.hslSaturation > 0.0
|
||||||
hueSlider.value = root.hue
|
&& 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.achromatic)
|
||||||
|
root.saturationHSL = root.color.hslSaturation
|
||||||
|
|
||||||
|
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.color = Qt.hsla(root.hue, root.saturationHSL, root.lightness, root.alpha)
|
||||||
|
else
|
||||||
|
root.color = Qt.hsva(root.hue, root.saturationHSV, root.value, root.alpha)
|
||||||
|
|
||||||
|
luminanceSlider.value = (1.0 - root.value)
|
||||||
|
hueSlider.value = root.hue
|
||||||
opacitySlider.value = (1.0 - root.alpha)
|
opacitySlider.value = (1.0 - root.alpha)
|
||||||
|
|
||||||
root.colorInvalidated()
|
root.colorInvalidated()
|
||||||
@@ -77,39 +142,51 @@ Column {
|
|||||||
root.block = false
|
root.block = false
|
||||||
}
|
}
|
||||||
|
|
||||||
function rgbToHsl(color) {
|
function drawHSVA(ctx) {
|
||||||
var r = color.r
|
for (var row = 0; row < gradientOverlay.height; row++) {
|
||||||
var g = color.g
|
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width, 0)
|
||||||
var b = color.b
|
var v = Math.abs(row - gradientOverlay.height) / gradientOverlay.height
|
||||||
|
|
||||||
var max = Math.max(r, g, b), min = Math.min(r, g, b)
|
gradient.addColorStop(0, Qt.hsva(root.hue, 0, v, 1))
|
||||||
var h, s, l = (max + min) / 2
|
gradient.addColorStop(1, Qt.hsva(root.hue, 1, v, 1))
|
||||||
|
|
||||||
if (max === min) {
|
ctx.fillStyle = gradient
|
||||||
h = 0
|
ctx.fillRect(0, row, gradientOverlay.width, 1)
|
||||||
s = 0
|
|
||||||
} else {
|
|
||||||
var d = max - min
|
|
||||||
s = l > 0.5 ? d / (2 - max - min) : d / (max + min)
|
|
||||||
switch (max) {
|
|
||||||
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
|
|
||||||
case g: h = (b - r) / d + 2; break;
|
|
||||||
case b: h = (r - g) / d + 4; break;
|
|
||||||
}
|
|
||||||
|
|
||||||
h /= 6
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
root.block = true
|
function drawRGBA(ctx) {
|
||||||
|
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.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))
|
||||||
|
gradient.addColorStop(0.500, Qt.rgba(0, 1, 1, 1))
|
||||||
|
gradient.addColorStop(0.667, Qt.rgba(0, 0, 1, 1))
|
||||||
|
gradient.addColorStop(0.833, Qt.rgba(1, 0, 1, 1))
|
||||||
|
gradient.addColorStop(1.000, Qt.rgba(1, 0, 0, 1))
|
||||||
|
|
||||||
if (s > 0)
|
ctx.fillStyle = gradient
|
||||||
root.hue = h
|
ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.height)
|
||||||
|
|
||||||
root.saturation = s
|
gradient = ctx.createLinearGradient(0, 0, 0, gradientOverlay.height)
|
||||||
root.lightness = l
|
gradient.addColorStop(0.000, Qt.rgba(0, 0, 0, 0))
|
||||||
|
gradient.addColorStop(1.000, Qt.rgba(1, 1, 1, 1))
|
||||||
|
|
||||||
root.block = false
|
ctx.fillStyle = gradient
|
||||||
invalidateColor()
|
ctx.fillRect(0, 0, gradientOverlay.width, gradientOverlay.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
|
||||||
|
|
||||||
|
gradient.addColorStop(0, Qt.hsla(root.hue, 0, l, 1))
|
||||||
|
gradient.addColorStop(1, Qt.hsla(root.hue, 1, l, 1))
|
||||||
|
|
||||||
|
ctx.fillStyle = gradient
|
||||||
|
ctx.fillRect(0, row, gradientOverlay.width, 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -133,26 +210,30 @@ Column {
|
|||||||
Canvas {
|
Canvas {
|
||||||
id: gradientOverlay
|
id: gradientOverlay
|
||||||
|
|
||||||
property real hue: root.hue
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
opacity: root.alpha
|
opacity: root.color.a
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: root
|
||||||
|
function onHueChanged() { gradientOverlay.requestPaint() }
|
||||||
|
}
|
||||||
|
|
||||||
onHueChanged: requestPaint()
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
var ctx = gradientOverlay.getContext('2d')
|
var ctx = gradientOverlay.getContext('2d')
|
||||||
ctx.save()
|
ctx.save()
|
||||||
ctx.clearRect(0, 0, gradientOverlay.width, gradientOverlay.height)
|
ctx.clearRect(0, 0, gradientOverlay.width, gradientOverlay.height)
|
||||||
|
|
||||||
for (var row = 0; row < gradientOverlay.height; row++) {
|
switch (root.mode) {
|
||||||
var gradient = ctx.createLinearGradient(0, 0, gradientOverlay.width,0)
|
case ColorPicker.Mode.RGBA:
|
||||||
var l = Math.abs(row - gradientOverlay.height) / gradientOverlay.height
|
root.drawRGBA(ctx)
|
||||||
|
break
|
||||||
gradient.addColorStop(0, Qt.hsla(gradientOverlay.hue, 0, l, 1))
|
case ColorPicker.Mode.HSLA:
|
||||||
gradient.addColorStop(1, Qt.hsla(gradientOverlay.hue, 1, l, 1))
|
root.drawHSLA(ctx)
|
||||||
|
break
|
||||||
ctx.fillStyle = gradient
|
case ColorPicker.Mode.HSVA:
|
||||||
ctx.fillRect(0, row, gradientOverlay.width, 1)
|
default:
|
||||||
|
root.drawHSVA(ctx)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.restore()
|
ctx.restore()
|
||||||
@@ -162,25 +243,41 @@ Column {
|
|||||||
Canvas {
|
Canvas {
|
||||||
id: pickerCross
|
id: pickerCross
|
||||||
|
|
||||||
property real cavnasSaturation: root.saturation
|
|
||||||
property real canvasLightness: root.lightness
|
|
||||||
property color strokeStyle: "lightGray"
|
property color strokeStyle: "lightGray"
|
||||||
|
|
||||||
opacity: 0.8
|
opacity: 0.8
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
|
|
||||||
onCavnasSaturationChanged: requestPaint();
|
Connections {
|
||||||
onCanvasLightnessChanged: requestPaint();
|
target: root
|
||||||
|
function onColorInvalidated() { pickerCross.requestPaint() }
|
||||||
|
function onColorChanged() { pickerCross.requestPaint() }
|
||||||
|
function onModeChanged() { pickerCross.requestPaint() }
|
||||||
|
}
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
var ctx = pickerCross.getContext('2d')
|
var ctx = pickerCross.getContext('2d')
|
||||||
|
|
||||||
ctx.save()
|
ctx.save()
|
||||||
|
|
||||||
ctx.clearRect(0, 0, pickerCross.width, pickerCross.height)
|
ctx.clearRect(0, 0, pickerCross.width, pickerCross.height)
|
||||||
|
|
||||||
var yy = pickerCross.height -root.lightness * pickerCross.height
|
var yy, xx = 0
|
||||||
var xx = root.saturation * pickerCross.width
|
|
||||||
|
switch (root.mode) {
|
||||||
|
case ColorPicker.Mode.RGBA:
|
||||||
|
yy = pickerCross.height - root.saturationHSV * pickerCross.height
|
||||||
|
xx = root.hue * pickerCross.width
|
||||||
|
break
|
||||||
|
case ColorPicker.Mode.HSLA:
|
||||||
|
yy = pickerCross.height - root.lightness * pickerCross.height
|
||||||
|
xx = root.saturationHSL * pickerCross.width
|
||||||
|
break
|
||||||
|
case ColorPicker.Mode.HSVA:
|
||||||
|
default:
|
||||||
|
yy = pickerCross.height - root.value * pickerCross.height
|
||||||
|
xx = root.saturationHSV * pickerCross.width
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
ctx.strokeStyle = pickerCross.strokeStyle
|
ctx.strokeStyle = pickerCross.strokeStyle
|
||||||
ctx.lineWidth = 1
|
ctx.lineWidth = 1
|
||||||
@@ -200,24 +297,37 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
id: mapMouseArea
|
id: mouseArea
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
preventStealing: true
|
preventStealing: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
|
||||||
onPositionChanged: function(mouse) {
|
onPositionChanged: function(mouse) {
|
||||||
if (pressed && mouse.buttons === Qt.LeftButton) {
|
if (mouseArea.pressed && mouse.buttons === Qt.LeftButton) {
|
||||||
var xx = Math.max(0, Math.min(mouse.x, parent.width))
|
var xx = Math.max(0, Math.min(mouse.x, parent.width))
|
||||||
var yy = Math.max(0, Math.min(mouse.y, parent.height))
|
var yy = Math.max(0, Math.min(mouse.y, parent.height))
|
||||||
|
|
||||||
root.lightness = 1.0 - yy / parent.height
|
switch (root.mode) {
|
||||||
root.saturation = xx / parent.width
|
case ColorPicker.Mode.RGBA:
|
||||||
|
root.saturationHSV = 1.0 - yy / parent.height
|
||||||
|
root.hue = xx / parent.width
|
||||||
|
break
|
||||||
|
case ColorPicker.Mode.HSLA:
|
||||||
|
root.saturationHSL = xx / parent.width
|
||||||
|
root.lightness = 1.0 - yy / parent.height
|
||||||
|
break
|
||||||
|
case ColorPicker.Mode.HSVA:
|
||||||
|
default:
|
||||||
|
root.saturationHSV = xx / parent.width
|
||||||
|
root.value = 1.0 - yy / parent.height
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onPressed: function(mouse) {
|
onPressed: function(mouse) {
|
||||||
if (mouse.button === Qt.LeftButton)
|
if (mouse.button === Qt.LeftButton)
|
||||||
positionChanged(mouse)
|
mouseArea.positionChanged(mouse)
|
||||||
}
|
}
|
||||||
onReleased: function(mouse) {
|
onReleased: function(mouse) {
|
||||||
if (mouse.button === Qt.LeftButton)
|
if (mouse.button === Qt.LeftButton)
|
||||||
@@ -233,10 +343,23 @@ Column {
|
|||||||
|
|
||||||
HueSlider {
|
HueSlider {
|
||||||
id: hueSlider
|
id: hueSlider
|
||||||
|
visible: root.mode !== ColorPicker.Mode.RGBA
|
||||||
width: parent.width
|
width: parent.width
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
if (root.hue !== value)
|
if (root.hue !== hueSlider.value)
|
||||||
root.hue = value
|
root.hue = hueSlider.value
|
||||||
|
}
|
||||||
|
onClicked: root.updateColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
LuminanceSlider {
|
||||||
|
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)
|
||||||
|
root.value = (1.0 - luminanceSlider.value)
|
||||||
}
|
}
|
||||||
onClicked: root.updateColor()
|
onClicked: root.updateColor()
|
||||||
}
|
}
|
||||||
@@ -246,8 +369,8 @@ Column {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1)
|
color: Qt.rgba(root.color.r, root.color.g, root.color.b, 1)
|
||||||
onValueChanged: {
|
onValueChanged: {
|
||||||
if (root.alpha !== value)
|
if (root.alpha !== opacitySlider.value)
|
||||||
root.alpha = (1.0 - value)
|
root.alpha = (1.0 - opacitySlider.value)
|
||||||
}
|
}
|
||||||
onClicked: root.updateColor()
|
onClicked: root.updateColor()
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,121 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 StudioTheme 1.0 as StudioTheme
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property real value: 1
|
||||||
|
property real minimum: 0
|
||||||
|
property real maximum: 1
|
||||||
|
property bool pressed: mouseArea.pressed
|
||||||
|
property bool integer: false
|
||||||
|
property color color
|
||||||
|
|
||||||
|
signal clicked
|
||||||
|
|
||||||
|
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)
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
border.width: StudioTheme.Values.border
|
||||||
|
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Horizontal
|
||||||
|
GradientStop { position: 0.000; color: root.color }
|
||||||
|
GradientStop { position: 1.000; color: "black" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: handle
|
||||||
|
width: StudioTheme.Values.hueSliderHandleWidth
|
||||||
|
height: track.height - 4
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
smooth: true
|
||||||
|
color: "transparent"
|
||||||
|
radius: 2
|
||||||
|
border.color: "black"
|
||||||
|
border.width: 1
|
||||||
|
x: root.updatePos()
|
||||||
|
y: 2
|
||||||
|
z: 1
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: 1
|
||||||
|
color: "transparent"
|
||||||
|
radius: 1
|
||||||
|
border.color: "white"
|
||||||
|
border.width: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
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
|
||||||
|
root.value = root.integer ? Math.round(realValue) : realValue
|
||||||
|
}
|
||||||
|
|
||||||
|
onPressed: calculateValue()
|
||||||
|
onReleased: root.clicked()
|
||||||
|
onPositionChanged: {
|
||||||
|
if (pressed)
|
||||||
|
calculateValue()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@@ -45,6 +45,7 @@ Label 2.0 Label.qml
|
|||||||
LineEdit 2.0 LineEdit.qml
|
LineEdit 2.0 LineEdit.qml
|
||||||
LinkIndicator2D 2.0 LinkIndicator2D.qml
|
LinkIndicator2D 2.0 LinkIndicator2D.qml
|
||||||
ListViewComboBox 2.0 ListViewComboBox.qml
|
ListViewComboBox 2.0 ListViewComboBox.qml
|
||||||
|
LuminanceSlider 2.0 LuminanceSlider.qml
|
||||||
MarginSection 2.0 MarginSection.qml
|
MarginSection 2.0 MarginSection.qml
|
||||||
MultiIconLabel 2.0 MultiIconLabel.qml
|
MultiIconLabel 2.0 MultiIconLabel.qml
|
||||||
OpacitySlider 2.0 OpacitySlider.qml
|
OpacitySlider 2.0 OpacitySlider.qml
|
||||||
|
Reference in New Issue
Block a user