mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-03 20:32:07 -04:00
feat: Rebuilt DankColorPicker w/Color Sampling
- Fully custom built ColorDialog - Replaces previous Wallpaper background color tool - Requires hyprpicker for color sampling, thanks @Vaxry
This commit is contained in:
@@ -70,6 +70,7 @@ Singleton {
|
|||||||
property int batteryHibernateTimeout: 0 // Never
|
property int batteryHibernateTimeout: 0 // Never
|
||||||
|
|
||||||
property bool lockBeforeSuspend: false
|
property bool lockBeforeSuspend: false
|
||||||
|
property var recentColors: []
|
||||||
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
@@ -150,6 +151,7 @@ Singleton {
|
|||||||
batterySuspendTimeout = settings.batterySuspendTimeout !== undefined ? settings.batterySuspendTimeout : 0
|
batterySuspendTimeout = settings.batterySuspendTimeout !== undefined ? settings.batterySuspendTimeout : 0
|
||||||
batteryHibernateTimeout = settings.batteryHibernateTimeout !== undefined ? settings.batteryHibernateTimeout : 0
|
batteryHibernateTimeout = settings.batteryHibernateTimeout !== undefined ? settings.batteryHibernateTimeout : 0
|
||||||
lockBeforeSuspend = settings.lockBeforeSuspend !== undefined ? settings.lockBeforeSuspend : false
|
lockBeforeSuspend = settings.lockBeforeSuspend !== undefined ? settings.lockBeforeSuspend : false
|
||||||
|
recentColors = settings.recentColors !== undefined ? settings.recentColors : []
|
||||||
|
|
||||||
if (!isGreeterMode) {
|
if (!isGreeterMode) {
|
||||||
if (typeof Theme !== "undefined") {
|
if (typeof Theme !== "undefined") {
|
||||||
@@ -210,7 +212,8 @@ Singleton {
|
|||||||
"batteryLockTimeout": batteryLockTimeout,
|
"batteryLockTimeout": batteryLockTimeout,
|
||||||
"batterySuspendTimeout": batterySuspendTimeout,
|
"batterySuspendTimeout": batterySuspendTimeout,
|
||||||
"batteryHibernateTimeout": batteryHibernateTimeout,
|
"batteryHibernateTimeout": batteryHibernateTimeout,
|
||||||
"lockBeforeSuspend": lockBeforeSuspend
|
"lockBeforeSuspend": lockBeforeSuspend,
|
||||||
|
"recentColors": recentColors
|
||||||
}, null, 2))
|
}, null, 2))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,6 +362,16 @@ Singleton {
|
|||||||
saveSettings()
|
saveSettings()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addRecentColor(color) {
|
||||||
|
const colorStr = color.toString()
|
||||||
|
let recent = recentColors.slice()
|
||||||
|
recent = recent.filter(c => c !== colorStr)
|
||||||
|
recent.unshift(colorStr)
|
||||||
|
if (recent.length > 5) recent = recent.slice(0, 5)
|
||||||
|
recentColors = recent
|
||||||
|
saveSettings()
|
||||||
|
}
|
||||||
|
|
||||||
function addPinnedApp(appId) {
|
function addPinnedApp(appId) {
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -349,7 +349,7 @@ ShellRoot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColorPickerModal {
|
DankColorPickerModal {
|
||||||
id: colorPickerModal
|
id: colorPickerModal
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import Quickshell
|
|
||||||
import Quickshell.Io
|
|
||||||
import qs.Common
|
|
||||||
import qs.Services
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: colorPickerModal
|
|
||||||
|
|
||||||
property string availablePicker: "zenity"
|
|
||||||
|
|
||||||
signal colorSelected(color selectedColor)
|
|
||||||
|
|
||||||
function show() {
|
|
||||||
if (availablePicker === "kcolorchooser") {
|
|
||||||
kcolorchooserProcess.running = true
|
|
||||||
} else {
|
|
||||||
zenityProcess.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function hide() {
|
|
||||||
kcolorchooserProcess.running = false
|
|
||||||
zenityProcess.running = false
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyColorToClipboard(colorValue) {
|
|
||||||
Quickshell.execDetached(["sh", "-c", `echo "${colorValue}" | wl-copy`])
|
|
||||||
ToastService.showInfo(`Color ${colorValue} copied`)
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: kcolorDetector
|
|
||||||
running: false
|
|
||||||
command: ["which", "kcolorchooser"]
|
|
||||||
|
|
||||||
onExited: (code, status) => {
|
|
||||||
if (code === 0) {
|
|
||||||
availablePicker = "kcolorchooser"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: kcolorchooserProcess
|
|
||||||
running: false
|
|
||||||
command: ["kcolorchooser", "--print"]
|
|
||||||
|
|
||||||
stdout: SplitParser {
|
|
||||||
onRead: data => {
|
|
||||||
const colorValue = data.trim()
|
|
||||||
if (colorValue.length > 0) {
|
|
||||||
copyColorToClipboard(colorValue)
|
|
||||||
colorSelected(colorValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Process {
|
|
||||||
id: zenityProcess
|
|
||||||
running: false
|
|
||||||
command: ["zenity", "--color-selection", "--show-palette"]
|
|
||||||
|
|
||||||
stdout: SplitParser {
|
|
||||||
onRead: data => {
|
|
||||||
const colorValue = data.trim()
|
|
||||||
if (colorValue.length > 0) {
|
|
||||||
copyColorToClipboard(colorValue)
|
|
||||||
colorSelected(colorValue)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Component.onCompleted: {
|
|
||||||
kcolorDetector.running = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
571
Modals/DankColorPickerModal.qml
Normal file
571
Modals/DankColorPickerModal.qml
Normal file
@@ -0,0 +1,571 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import qs.Common
|
||||||
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
PanelWindow {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property string pickerTitle: "Choose Color"
|
||||||
|
property color selectedColor: Theme.primary
|
||||||
|
property bool shouldBeVisible: false
|
||||||
|
property var onColorSelectedCallback: null
|
||||||
|
|
||||||
|
signal colorSelected(color selectedColor)
|
||||||
|
|
||||||
|
property color currentColor: Theme.primary
|
||||||
|
property real hue: 0
|
||||||
|
property real saturation: 1
|
||||||
|
property real value: 1
|
||||||
|
property real alpha: 1
|
||||||
|
property real gradientX: 0
|
||||||
|
property real gradientY: 0
|
||||||
|
|
||||||
|
function open() {
|
||||||
|
currentColor = selectedColor
|
||||||
|
updateFromColor(currentColor)
|
||||||
|
shouldBeVisible = true
|
||||||
|
Qt.callLater(() => colorContent.forceActiveFocus())
|
||||||
|
}
|
||||||
|
|
||||||
|
function close() {
|
||||||
|
shouldBeVisible = false
|
||||||
|
onColorSelectedCallback = null
|
||||||
|
}
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
open()
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
onColorSelected: (color) => {
|
||||||
|
if (onColorSelectedCallback) {
|
||||||
|
onColorSelectedCallback(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyColorToClipboard(colorValue) {
|
||||||
|
Quickshell.execDetached(["sh", "-c", `echo "${colorValue}" | wl-copy`])
|
||||||
|
ToastService.showInfo(`Color ${colorValue} copied`)
|
||||||
|
SessionData.addRecentColor(currentColor)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateFromColor(color) {
|
||||||
|
hue = color.hsvHue
|
||||||
|
saturation = color.hsvSaturation
|
||||||
|
value = color.hsvValue
|
||||||
|
alpha = color.a
|
||||||
|
gradientX = saturation
|
||||||
|
gradientY = 1 - value
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateColor() {
|
||||||
|
currentColor = Qt.hsva(hue, saturation, value, alpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateColorFromGradient(x, y) {
|
||||||
|
saturation = Math.max(0, Math.min(1, x))
|
||||||
|
value = Math.max(0, Math.min(1, 1 - y))
|
||||||
|
updateColor()
|
||||||
|
}
|
||||||
|
|
||||||
|
function pickColorFromScreen() {
|
||||||
|
close()
|
||||||
|
hyprpickerProcess.running = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Process {
|
||||||
|
id: hyprpickerProcess
|
||||||
|
running: false
|
||||||
|
command: ["hyprpicker", "--format=hex"]
|
||||||
|
|
||||||
|
stdout: SplitParser {
|
||||||
|
onRead: data => {
|
||||||
|
const colorStr = data.trim()
|
||||||
|
if (colorStr.length >= 7 && colorStr.startsWith('#')) {
|
||||||
|
root.currentColor = colorStr
|
||||||
|
root.updateFromColor(root.currentColor)
|
||||||
|
copyColorToClipboard(colorStr)
|
||||||
|
root.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onExited: (exitCode, exitStatus) => {
|
||||||
|
if (exitCode !== 0) {
|
||||||
|
console.warn("hyprpicker exited with code:", exitCode)
|
||||||
|
}
|
||||||
|
root.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly property var standardColors: [
|
||||||
|
"#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4",
|
||||||
|
"#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722",
|
||||||
|
"#d32f2f", "#c2185b", "#7b1fa2", "#512da8", "#303f9f", "#1976d2", "#0288d1", "#0097a7",
|
||||||
|
"#00796b", "#388e3c", "#689f38", "#afb42b", "#fbc02d", "#ffa000", "#f57c00", "#e64a19",
|
||||||
|
"#c62828", "#ad1457", "#6a1b9a", "#4527a0", "#283593", "#1565c0", "#0277bd", "#00838f",
|
||||||
|
"#00695c", "#2e7d32", "#558b2f", "#9e9d24", "#f9a825", "#ff8f00", "#ef6c00", "#d84315",
|
||||||
|
"#ffffff", "#9e9e9e", "#212121"
|
||||||
|
]
|
||||||
|
|
||||||
|
visible: shouldBeVisible
|
||||||
|
|
||||||
|
WlrLayershell.namespace: "quickshell:color-picker"
|
||||||
|
WlrLayershell.layer: WlrLayer.Overlay
|
||||||
|
WlrLayershell.keyboardFocus: WlrKeyboardFocus.Exclusive
|
||||||
|
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
anchors {
|
||||||
|
top: true
|
||||||
|
left: true
|
||||||
|
right: true
|
||||||
|
bottom: true
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: root.close()
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
color: "#80000000"
|
||||||
|
anchors.fill: parent
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: 680
|
||||||
|
height: 680
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: Theme.surfaceContainer
|
||||||
|
border.color: Theme.outlineMedium
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
onClicked: {} // Prevent clicks from propagating to background
|
||||||
|
}
|
||||||
|
|
||||||
|
FocusScope {
|
||||||
|
id: colorContent
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
focus: root.shouldBeVisible
|
||||||
|
|
||||||
|
Keys.onEscapePressed: event => {
|
||||||
|
root.close()
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - 90
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: root.pickerTitle
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Select a color from the palette or use custom sliders"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceTextMedium
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
iconName: "colorize"
|
||||||
|
iconSize: Theme.iconSize - 4
|
||||||
|
iconColor: Theme.surfaceText
|
||||||
|
onClicked: () => {
|
||||||
|
pickColorFromScreen()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
iconName: "close"
|
||||||
|
iconSize: Theme.iconSize - 4
|
||||||
|
iconColor: Theme.surfaceText
|
||||||
|
onClicked: () => {
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: gradientPicker
|
||||||
|
width: parent.width - 70
|
||||||
|
height: 280
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.color: Theme.outlineStrong
|
||||||
|
border.width: 1
|
||||||
|
clip: true
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: Qt.hsva(root.hue, 1, 1, 1)
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Horizontal
|
||||||
|
GradientStop { position: 0.0; color: "#ffffff" }
|
||||||
|
GradientStop { position: 1.0; color: "transparent" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Vertical
|
||||||
|
GradientStop { position: 0.0; color: "transparent" }
|
||||||
|
GradientStop { position: 1.0; color: "#000000" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: pickerCircle
|
||||||
|
width: 16
|
||||||
|
height: 16
|
||||||
|
radius: 8
|
||||||
|
border.color: "white"
|
||||||
|
border.width: 2
|
||||||
|
color: "transparent"
|
||||||
|
x: root.gradientX * parent.width - width / 2
|
||||||
|
y: root.gradientY * parent.height - height / 2
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width - 4
|
||||||
|
height: parent.height - 4
|
||||||
|
radius: width / 2
|
||||||
|
border.color: "black"
|
||||||
|
border.width: 1
|
||||||
|
color: "transparent"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.CrossCursor
|
||||||
|
onPressed: mouse => {
|
||||||
|
const x = Math.max(0, Math.min(1, mouse.x / width))
|
||||||
|
const y = Math.max(0, Math.min(1, mouse.y / height))
|
||||||
|
root.gradientX = x
|
||||||
|
root.gradientY = y
|
||||||
|
root.updateColorFromGradient(x, y)
|
||||||
|
}
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (pressed) {
|
||||||
|
const x = Math.max(0, Math.min(1, mouse.x / width))
|
||||||
|
const y = Math.max(0, Math.min(1, mouse.y / height))
|
||||||
|
root.gradientX = x
|
||||||
|
root.gradientY = y
|
||||||
|
root.updateColorFromGradient(x, y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: hueSlider
|
||||||
|
width: 50
|
||||||
|
height: 280
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.color: Theme.outlineStrong
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
gradient: Gradient {
|
||||||
|
orientation: Gradient.Vertical
|
||||||
|
GradientStop { position: 0.00; color: "#ff0000" }
|
||||||
|
GradientStop { position: 0.17; color: "#ffff00" }
|
||||||
|
GradientStop { position: 0.33; color: "#00ff00" }
|
||||||
|
GradientStop { position: 0.50; color: "#00ffff" }
|
||||||
|
GradientStop { position: 0.67; color: "#0000ff" }
|
||||||
|
GradientStop { position: 0.83; color: "#ff00ff" }
|
||||||
|
GradientStop { position: 1.00; color: "#ff0000" }
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: hueIndicator
|
||||||
|
width: parent.width
|
||||||
|
height: 4
|
||||||
|
color: "white"
|
||||||
|
border.color: "black"
|
||||||
|
border.width: 1
|
||||||
|
y: root.hue * parent.height - height / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.SizeVerCursor
|
||||||
|
onPressed: mouse => {
|
||||||
|
const h = Math.max(0, Math.min(1, mouse.y / height))
|
||||||
|
root.hue = h
|
||||||
|
root.updateColor()
|
||||||
|
}
|
||||||
|
onPositionChanged: mouse => {
|
||||||
|
if (pressed) {
|
||||||
|
const h = Math.max(0, Math.min(1, mouse.y / height))
|
||||||
|
root.hue = h
|
||||||
|
root.updateColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Material Colors"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
width: parent.width
|
||||||
|
height: 140
|
||||||
|
cellWidth: 38
|
||||||
|
cellHeight: 38
|
||||||
|
clip: true
|
||||||
|
interactive: false
|
||||||
|
model: root.standardColors
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: 36
|
||||||
|
height: 36
|
||||||
|
color: modelData
|
||||||
|
radius: 4
|
||||||
|
border.color: Theme.outlineStrong
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: () => {
|
||||||
|
root.currentColor = modelData
|
||||||
|
root.updateFromColor(root.currentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: 210
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Recent Colors"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: 5
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 36
|
||||||
|
height: 36
|
||||||
|
radius: 4
|
||||||
|
border.color: Theme.outlineStrong
|
||||||
|
border.width: 1
|
||||||
|
|
||||||
|
color: {
|
||||||
|
if (index < SessionData.recentColors.length) {
|
||||||
|
return SessionData.recentColors[index]
|
||||||
|
}
|
||||||
|
return Theme.surfaceContainerHigh
|
||||||
|
}
|
||||||
|
|
||||||
|
opacity: index < SessionData.recentColors.length ? 1.0 : 0.3
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: index < SessionData.recentColors.length ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
enabled: index < SessionData.recentColors.length
|
||||||
|
onClicked: () => {
|
||||||
|
if (index < SessionData.recentColors.length) {
|
||||||
|
root.currentColor = SessionData.recentColors[index]
|
||||||
|
root.updateFromColor(root.currentColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
width: parent.width - 330
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Opacity"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
}
|
||||||
|
|
||||||
|
DankSlider {
|
||||||
|
width: parent.width
|
||||||
|
value: Math.round(root.alpha * 100)
|
||||||
|
minimum: 0
|
||||||
|
maximum: 100
|
||||||
|
showValue: false
|
||||||
|
onSliderValueChanged: (newValue) => {
|
||||||
|
root.alpha = newValue / 100
|
||||||
|
root.updateColor()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: 100
|
||||||
|
height: 50
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: root.currentColor
|
||||||
|
border.color: Theme.outlineStrong
|
||||||
|
border.width: 2
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
width: parent.width
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: "Hex:"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceTextMedium
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
DankTextField {
|
||||||
|
id: hexInput
|
||||||
|
width: 120
|
||||||
|
height: 38
|
||||||
|
text: root.currentColor.toString()
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
placeholderText: "#000000"
|
||||||
|
backgroundColor: Theme.surfaceHover
|
||||||
|
borderWidth: 1
|
||||||
|
focusedBorderWidth: 2
|
||||||
|
topPadding: Theme.spacingS
|
||||||
|
bottomPadding: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onAccepted: () => {
|
||||||
|
const color = Qt.color(text)
|
||||||
|
if (color) {
|
||||||
|
root.currentColor = color
|
||||||
|
root.updateFromColor(color)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
width: 80
|
||||||
|
buttonHeight: 36
|
||||||
|
text: "Apply"
|
||||||
|
backgroundColor: Theme.primary
|
||||||
|
textColor: Theme.background
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: {
|
||||||
|
const color = Qt.color(hexInput.text)
|
||||||
|
if (color) {
|
||||||
|
root.currentColor = color
|
||||||
|
root.updateFromColor(color)
|
||||||
|
root.selectedColor = root.currentColor
|
||||||
|
colorSelected(root.currentColor)
|
||||||
|
SessionData.addRecentColor(root.currentColor)
|
||||||
|
root.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: parent.width - 460
|
||||||
|
height: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
width: 70
|
||||||
|
buttonHeight: 36
|
||||||
|
text: "Cancel"
|
||||||
|
backgroundColor: "transparent"
|
||||||
|
textColor: Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: root.close()
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Theme.surfaceVariantAlpha
|
||||||
|
border.width: 1
|
||||||
|
z: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankButton {
|
||||||
|
width: 70
|
||||||
|
buttonHeight: 36
|
||||||
|
text: "Copy"
|
||||||
|
backgroundColor: Theme.primary
|
||||||
|
textColor: Theme.background
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
onClicked: {
|
||||||
|
const colorString = root.currentColor.toString()
|
||||||
|
copyColorToClipboard(colorString)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -252,7 +252,19 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
colorPicker.open()
|
if (PopoutService.colorPickerModal) {
|
||||||
|
var currentWallpaper = SessionData.perMonitorWallpaper ? SessionData.getMonitorWallpaper(selectedMonitorName) : SessionData.wallpaperPath
|
||||||
|
PopoutService.colorPickerModal.selectedColor = currentWallpaper.startsWith("#") ? currentWallpaper : Theme.primary
|
||||||
|
PopoutService.colorPickerModal.pickerTitle = "Choose Wallpaper Color"
|
||||||
|
PopoutService.colorPickerModal.onColorSelectedCallback = function(selectedColor) {
|
||||||
|
if (SessionData.perMonitorWallpaper) {
|
||||||
|
SessionData.setMonitorWallpaper(selectedMonitorName, selectedColor)
|
||||||
|
} else {
|
||||||
|
SessionData.setWallpaperColor(selectedColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PopoutService.colorPickerModal.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1853,18 +1865,4 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DankColorPicker {
|
|
||||||
id: colorPicker
|
|
||||||
|
|
||||||
pickerTitle: "Choose Wallpaper Color"
|
|
||||||
onColorSelected: selectedColor => {
|
|
||||||
if (SessionData.perMonitorWallpaper) {
|
|
||||||
SessionData.setMonitorWallpaper(selectedMonitorName, selectedColor)
|
|
||||||
} else {
|
|
||||||
SessionData.setWallpaperColor(selectedColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +0,0 @@
|
|||||||
import QtQuick
|
|
||||||
import qs.Common
|
|
||||||
import qs.Widgets
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: root
|
|
||||||
|
|
||||||
property string pickerTitle: "Choose Color"
|
|
||||||
property color selectedColor: Theme.primary
|
|
||||||
property bool isOpen: false
|
|
||||||
|
|
||||||
signal colorSelected(color selectedColor)
|
|
||||||
|
|
||||||
function open() {
|
|
||||||
customColorField.text = ""
|
|
||||||
isOpen = true
|
|
||||||
Qt.callLater(() => root.forceActiveFocus())
|
|
||||||
}
|
|
||||||
|
|
||||||
function close() {
|
|
||||||
isOpen = false
|
|
||||||
}
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: 320
|
|
||||||
height: 340
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: Theme.surfaceContainer
|
|
||||||
border.color: Theme.outlineMedium
|
|
||||||
border.width: 1
|
|
||||||
z: 1000
|
|
||||||
visible: isOpen
|
|
||||||
focus: isOpen
|
|
||||||
|
|
||||||
Keys.onPressed: function (event) {
|
|
||||||
if (event.key === Qt.Key_Escape) {
|
|
||||||
close()
|
|
||||||
event.accepted = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DankActionButton {
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
buttonSize: 28
|
|
||||||
iconName: "close"
|
|
||||||
iconSize: 16
|
|
||||||
iconColor: Theme.surfaceText
|
|
||||||
onClicked: root.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingL
|
|
||||||
spacing: Theme.spacingM
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: pickerTitle
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
font.weight: Font.Medium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
Grid {
|
|
||||||
columns: 8
|
|
||||||
spacing: 4
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
property var colors: ["#f44336", "#e91e63", "#9c27b0", "#673ab7", "#3f51b5", "#2196f3", "#03a9f4", "#00bcd4", "#009688", "#4caf50", "#8bc34a", "#cddc39", "#ffeb3b", "#ffc107", "#ff9800", "#ff5722", "#795548", "#9e9e9e", "#607d8b", "#000000", "#ffffff", "#ff1744", "#f50057", "#d500f9", "#651fff", "#3d5afe", "#2979ff", "#00b0ff", "#00e5ff", "#1de9b6", "#00e676", "#76ff03", "#c6ff00", "#ffff00", "#ffc400", "#ff9100", "#ff3d00", "#bf360c", "#424242", "#37474f"]
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: parent.colors
|
|
||||||
Rectangle {
|
|
||||||
width: 24
|
|
||||||
height: 24
|
|
||||||
color: modelData
|
|
||||||
radius: 4
|
|
||||||
border.color: Theme.outline
|
|
||||||
border.width: root.selectedColor == modelData ? 2 : 1
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
root.selectedColor = modelData
|
|
||||||
root.colorSelected(modelData)
|
|
||||||
root.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledText {
|
|
||||||
text: "Custom Color:"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceText
|
|
||||||
}
|
|
||||||
|
|
||||||
DankTextField {
|
|
||||||
id: customColorField
|
|
||||||
width: parent.width
|
|
||||||
height: 40
|
|
||||||
placeholderText: "#ff0000"
|
|
||||||
text: ""
|
|
||||||
onAccepted: {
|
|
||||||
var hexColor = text.startsWith("#") ? text : "#" + text
|
|
||||||
if (/^#[0-9A-Fa-f]{6}$/.test(hexColor)) {
|
|
||||||
root.selectedColor = hexColor
|
|
||||||
root.colorSelected(hexColor)
|
|
||||||
root.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user