14 changed files with 372 additions and 11 deletions
			
			
		| @ -0,0 +1,321 @@ | |||
| import QtQuick 2.10 | |||
| import QtQuick.Controls 2.3 | |||
| import QtQuick.Controls.Material 2.3 | |||
| import QtQuick.Layouts 1.3 | |||
| import QtGraphicalEffects 1.0 | |||
| import de.skycoder42.QtMvvm.Quick 1.1 | |||
| 
 | |||
| GridLayout { | |||
| 	id: _colorPicker | |||
| 	columns: 2 | |||
| 	rowSpacing: 16 | |||
| 
 | |||
| 	ColorHelper { | |||
| 		id: helper | |||
| 	} | |||
| 
 | |||
| 	property bool alpha: false | |||
| 	property color color | |||
| 	onColorChanged: { | |||
| 		if(!_p.changing){ | |||
| 			var hsvColor = _p.rgbToHsv(color); | |||
| 			_p.changing = true; | |||
| 			hueSlider.value = hsvColor.h; | |||
| 			saturationSlider.value = 1 - hsvColor.s; | |||
| 			valueSlider.value = hsvColor.v; | |||
| 			_colorEdit.setColor(color); | |||
| 			_p.changing = false; | |||
| 		} | |||
| 	} | |||
| 
 | |||
| 	QtObject { | |||
| 		id: _p | |||
| 
 | |||
| 		property bool changing: false | |||
| 		readonly property color color: Qt.hsva(hueSlider.position, 1 - saturationSlider.position, valueSlider.position) | |||
| 		readonly property color hueColor: Qt.hsva(hueSlider.position, 1, 1); | |||
| 
 | |||
| 		onColorChanged: { | |||
| 			if(!_p.changing) { | |||
| 				_p.changing = true; | |||
| 				_colorPicker.color = _p.color | |||
| 				_colorEdit.setColor(color); | |||
| 				_p.changing = false; | |||
| 			} | |||
| 		} | |||
| 
 | |||
| 		function rgbToHsv(rgbColor) { | |||
| 			var rr, gg, bb, | |||
| 				r = rgbColor.r, | |||
| 				g = rgbColor.g, | |||
| 				b = rgbColor.b, | |||
| 				h, s, | |||
| 				v = Math.max(r, g, b), | |||
| 				diff = v - Math.min(r, g, b), | |||
| 				diffc = function(c){ | |||
| 					return (v - c) / 6 / diff + 1 / 2; | |||
| 				}; | |||
| 
 | |||
| 			if (diff == 0) { | |||
| 				h = s = 0; | |||
| 			} else { | |||
| 				s = diff / v; | |||
| 				rr = diffc(r); | |||
| 				gg = diffc(g); | |||
| 				bb = diffc(b); | |||
| 
 | |||
| 				if (r === v) { | |||
| 					h = bb - gg; | |||
| 				} else if (g === v) { | |||
| 					h = (1 / 3) + rr - bb; | |||
| 				} else if (b === v) { | |||
| 					h = (2 / 3) + gg - rr; | |||
| 				} | |||
| 
 | |||
| 				if (h < 0) { | |||
| 					h += 1; | |||
| 				} else if (h > 1) { | |||
| 					h -= 1; | |||
| 				} | |||
| 			} | |||
| 
 | |||
| 			return { | |||
| 				h: h, | |||
| 				s: s, | |||
| 				v: v | |||
| 			}; | |||
| 		} | |||
| 	} | |||
| 
 | |||
| 	Rectangle { | |||
| 		id: colorPreview | |||
| 		color: _colorPicker.color | |||
| 		Layout.rowSpan: 3 | |||
| 		Layout.preferredWidth: hueSlider.height + saturationSlider.height + valueSlider.height + 2 * _colorPicker.rowSpacing | |||
| 		Layout.maximumWidth: _colorPicker.width/3 | |||
| 		Layout.fillHeight: true | |||
| 
 | |||
| 		border.color: helper.text | |||
| 		border.width: 1 | |||
| 	} | |||
| 
 | |||
| 	Slider { | |||
| 		id: hueSlider | |||
| 		Layout.fillWidth: true | |||
| 		Material.accent: "#FF0000" | |||
| 		from: 0 | |||
| 		to: 1 | |||
| 
 | |||
| 		readonly property real handleWidth: 25 | |||
| 		readonly property real handleHeight: ((handleWidth-1)/2)*3 + 1 | |||
| 		leftPadding: (handleWidth-1)/2 + 1 | |||
| 		rightPadding: (handleWidth-1)/2 + 1 | |||
| 
 | |||
| 		background: LinearGradient { | |||
| 			x: hueSlider.leftPadding | |||
| 			y: 0 | |||
| 			implicitWidth: 200 | |||
| 			implicitHeight: hueSlider.handleHeight | |||
| 			width: hueSlider.availableWidth | |||
| 			height: implicitHeight | |||
| 			start: Qt.point(0, 0) | |||
| 			end: Qt.point(width, 0) | |||
| 
 | |||
| 			Rectangle { | |||
| 				anchors.fill: parent | |||
| 				color: "transparent" | |||
| 				border.color: helper.text | |||
| 			} | |||
| 
 | |||
| 			gradient: Gradient { | |||
| 				GradientStop { | |||
| 					position: 0.000 | |||
| 					color: Qt.rgba(1, 0, 0, 1) | |||
| 				} | |||
| 				GradientStop { | |||
| 					position: 0.167 | |||
| 					color: Qt.rgba(1, 1, 0, 1) | |||
| 				} | |||
| 				GradientStop { | |||
| 					position: 0.333 | |||
| 					color: Qt.rgba(0, 1, 0, 1) | |||
| 				} | |||
| 				GradientStop { | |||
| 					position: 0.500 | |||
| 					color: Qt.rgba(0, 1, 1, 1) | |||
| 				} | |||
| 				GradientStop { | |||
| 					position: 0.667 | |||
| 					color: Qt.rgba(0, 0, 1, 1) | |||
| 				} | |||
| 				GradientStop { | |||
| 					position: 0.833 | |||
| 					color: Qt.rgba(1, 0, 1, 1) | |||
| 				} | |||
| 				GradientStop { | |||
| 					position: 1.000 | |||
| 					color: Qt.rgba(1, 0, 0, 1) | |||
| 				} | |||
| 			} | |||
| 		} | |||
| 
 | |||
| 		handle: Item { | |||
| 			x: 1 + hueSlider.visualPosition * (hueSlider.availableWidth - 1) | |||
| 			width: hueSlider.handleWidth | |||
| 			height: hueSlider.handleHeight | |||
| 
 | |||
| 			Rectangle { | |||
| 				anchors.horizontalCenter: parent.horizontalCenter | |||
| 				anchors.top: parent.top | |||
| 				anchors.bottom: circle.top | |||
| 				width: 1 | |||
| 				color: helper.text | |||
| 			} | |||
| 
 | |||
| 			Rectangle { | |||
| 				id: circle | |||
| 				anchors.centerIn: parent | |||
| 				implicitWidth: parent.width | |||
| 				implicitHeight: parent.width | |||
| 				radius: parent.width / 2 | |||
| 				color: Qt.hsva(hueSlider.position, 1, 1) | |||
| 				border.color: helper.text | |||
| 			} | |||
| 
 | |||
| 			Rectangle { | |||
| 				anchors.horizontalCenter: parent.horizontalCenter | |||
| 				anchors.top: circle.bottom | |||
| 				anchors.bottom: parent.bottom | |||
| 				width: 1 | |||
| 				color: helper.text | |||
| 			} | |||
| 		} | |||
| 	} | |||
| 
 | |||
| 	Slider { | |||
| 		id: saturationSlider | |||
| 		Layout.fillWidth: true | |||
| 		from: 0 | |||
| 		to: 1 | |||
| 
 | |||
| 		readonly property real handleSize: 24 | |||
| 		leftPadding: handleSize/2 + 1 | |||
| 		rightPadding: handleSize/2 + 1 | |||
| 
 | |||
| 		background: Item { | |||
| 			x: saturationSlider.leftPadding | |||
| 			y: saturationSlider.topPadding + (saturationSlider.availableHeight - height) / 2 | |||
| 			implicitWidth: 200 | |||
| 			implicitHeight: 6 | |||
| 			width: saturationSlider.availableWidth | |||
| 			height: implicitHeight | |||
| 
 | |||
| 			Rectangle { | |||
| 				rotation: -90 | |||
| 				anchors.centerIn: parent | |||
| 				width: parent.height | |||
| 				height: parent.width | |||
| 				radius: 3 | |||
| 				border.color: helper.text | |||
| 
 | |||
| 				gradient: Gradient { | |||
| 					GradientStop { | |||
| 						position: 0.000 | |||
| 						color: Qt.hsva(hueSlider.position, 1, 1) | |||
| 					} | |||
| 					GradientStop { | |||
| 						position: 1.000 | |||
| 						color: Qt.hsva(hueSlider.position, 0, 1) | |||
| 					} | |||
| 				} | |||
| 			} | |||
| 		} | |||
| 
 | |||
| 		handle: Rectangle { | |||
| 			x: 1 + saturationSlider.visualPosition * saturationSlider.availableWidth | |||
| 			y: saturationSlider.topPadding + (saturationSlider.availableHeight - height)/2 | |||
| 			width: saturationSlider.handleSize | |||
| 			height: saturationSlider.handleSize | |||
| 			radius: saturationSlider.handleSize/2 | |||
| 			color: Qt.hsva(hueSlider.position, 1 - saturationSlider.position, 1) | |||
| 			border.color: helper.text | |||
| 		} | |||
| 	} | |||
| 
 | |||
| 	Slider { | |||
| 		id: valueSlider | |||
| 		Layout.fillWidth: true | |||
| 		from: 0 | |||
| 		to: 1 | |||
| 
 | |||
| 		readonly property real handleSize: 24 | |||
| 		leftPadding: handleSize/2 + 1 | |||
| 		rightPadding: handleSize/2 + 1 | |||
| 
 | |||
| 		background: Item { | |||
| 			x: valueSlider.leftPadding | |||
| 			y: valueSlider.topPadding + (valueSlider.availableHeight - height) / 2 | |||
| 			implicitWidth: 200 | |||
| 			implicitHeight: 6 | |||
| 			width: valueSlider.availableWidth | |||
| 			height: implicitHeight | |||
| 
 | |||
| 			Rectangle { | |||
| 				rotation: -90 | |||
| 				anchors.centerIn: parent | |||
| 				width: parent.height | |||
| 				height: parent.width | |||
| 				radius: 3 | |||
| 				border.color: helper.text | |||
| 
 | |||
| 				gradient: Gradient { | |||
| 					GradientStop { | |||
| 						position: 0.000 | |||
| 						color: Qt.hsva(hueSlider.position, 1, 0) | |||
| 					} | |||
| 					GradientStop { | |||
| 						position: 1.000 | |||
| 						color: Qt.hsva(hueSlider.position, 1, 1) | |||
| 					} | |||
| 				} | |||
| 			} | |||
| 		} | |||
| 
 | |||
| 		handle: Rectangle { | |||
| 			x: 1 + valueSlider.visualPosition * valueSlider.availableWidth | |||
| 			y: valueSlider.topPadding + (valueSlider.availableHeight - height)/2 | |||
| 			width: valueSlider.handleSize | |||
| 			height: valueSlider.handleSize | |||
| 			radius: valueSlider.handleSize/2 | |||
| 			color: Qt.hsva(hueSlider.position, 1, valueSlider.position) | |||
| 			border.color: helper.text | |||
| 		} | |||
| 	} | |||
| 
 | |||
| 	TextField { | |||
| 		id: _colorEdit | |||
| 		Layout.columnSpan: 2 | |||
| 		Layout.fillWidth: true | |||
| 		selectByMouse: true | |||
| 
 | |||
| 		validator: RegExpValidator { | |||
| 			regExp: _colorPicker.alpha ? /^#(?:[0-9a-f]{4}){1,2}$/ : /^#(?:[0-9a-f]{3}){1,2}$/ | |||
| 		} | |||
| 
 | |||
| 		property bool _skipSet: false | |||
| 		function setColor(color) { | |||
| 			if(_skipSet) | |||
| 				_skipSet = false; | |||
| 			else | |||
| 				text = color; | |||
| 		} | |||
| 
 | |||
| 		text: _colorPicker.color | |||
| 		onTextEdited: { | |||
| 			if(_colorEdit.acceptableInput) { | |||
| 				_skipSet = true; | |||
| 				_colorPicker.color = text; | |||
| 			} | |||
| 		} | |||
| 	} | |||
| } | |||
| @ -0,0 +1,15 @@ | |||
| import QtQuick 2.10 | |||
| import de.skycoder42.QtMvvm.Quick 1.1 as QtMvvm | |||
| 
 | |||
| QtMvvm.MsgDelegate { | |||
| 	id: _colorDelegate | |||
| 
 | |||
| 	editDialogType: "QColor" | |||
| 	indicatorComponent: Rectangle { | |||
| 		id: colorCircle | |||
| 		width: 24 | |||
| 		height: 24 | |||
| 		radius: height / 2 | |||
| 		color: inputValue | |||
| 	} | |||
| } | |||
| @ -0,0 +1,6 @@ | |||
| import de.skycoder42.QtMvvm.Quick 1.1 as QtMvvm | |||
| 
 | |||
| QtMvvm.ColorEdit { | |||
| 	id: _edit | |||
| 	property alias inputValue: _edit.color | |||
| } | |||
					Loading…
					
					
				
		Reference in new issue