Files
noctalia-shell/Modules/SettingsPanel/Bar/WidgetSettings/ClockSettings.qml
T
2025-09-20 01:23:59 -04:00

335 lines
10 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
import qs.Services
ColumnLayout {
id: root
spacing: Style.marginM * scaling
width: 700 * scaling
// Properties to receive data from parent
property var widgetData: null
property var widgetMetadata: null
// Local state
property bool valueUsePrimaryColor: widgetData.usePrimaryColor !== undefined ? widgetData.usePrimaryColor : widgetMetadata.usePrimaryColor
property bool valueUseMonospacedFont: widgetData.useMonospacedFont !== undefined ? widgetData.useMonospacedFont : widgetMetadata.useMonospacedFont
property string valueLine1: widgetData.line1 !== undefined ? widgetData.line1 : widgetMetadata.line1
property string valueLine2: widgetData.line2 !== undefined ? widgetData.line2 : widgetMetadata.line2
property string valueLine3: widgetData.line3 !== undefined ? widgetData.line3 : widgetMetadata.line3
property string valueLine4: widgetData.line4 !== undefined ? widgetData.line4 : widgetMetadata.line4
// Track the currently focused input field
property var focusedInput: null
property int focusedLineIndex: -1
readonly property var now: Time.date
function saveSettings() {
var settings = Object.assign({}, widgetData || {})
settings.usePrimaryColor = valueUsePrimaryColor
settings.useMonospacedFont = valueUseMonospacedFont
settings.line1 = valueLine1.trim()
settings.line2 = valueLine2.trim()
settings.line3 = valueLine3.trim()
settings.line4 = valueLine4.trim()
return settings
}
// Function to insert token at cursor position in the focused input
function insertToken(token) {
if (!focusedInput || !focusedInput.inputItem) {
// If no input is focused, default to line 1
if (inputLine1.inputItem) {
inputLine1.inputItem.focus = true
focusedInput = inputLine1
focusedLineIndex = 1
}
}
if (focusedInput && focusedInput.inputItem) {
var input = focusedInput.inputItem
var cursorPos = input.cursorPosition
var currentText = input.text
// Insert token at cursor position
var newText = currentText.substring(0, cursorPos) + token + currentText.substring(cursorPos)
input.text = newText + " "
// Move cursor after the inserted token
input.cursorPosition = cursorPos + token.length + 1
// Ensure the input keeps focus
input.focus = true
}
}
// Function to update the value property based on which line was edited
function updateLineValue(lineIndex, text) {
switch (lineIndex) {
case 1:
valueLine1 = text
break
case 2:
valueLine2 = text
break
case 3:
valueLine3 = text
break
case 4:
valueLine4 = text
break
}
}
NToggle {
Layout.fillWidth: true
label: "Use primary color"
description: "When enabled, this applies the primary color for emphasis."
checked: valueUsePrimaryColor
onToggled: checked => valueUsePrimaryColor = checked
}
NToggle {
Layout.fillWidth: true
label: "Use monospaced font"
description: "When enabled, the clock will use the monospaced font."
checked: valueUseMonospacedFont
onToggled: checked => valueUseMonospacedFont = checked
}
NDivider {
Layout.fillWidth: true
}
NHeader {
label: "Clock format"
description: "Build your clock display using the tokens below. Additional lines (3 & 4) are only shown in the vertical bar layout.\nClick on any token to insert it into the selected input field."
}
RowLayout {
id: main
Layout.fillWidth: true
spacing: Style.marginL * scaling
ColumnLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1 // Equal sizing hint
spacing: Style.marginM * scaling
NTextInput {
id: inputLine1
Layout.fillWidth: true
label: "1st line"
placeholderText: "HH:mm"
text: valueLine1
onTextChanged: updateLineValue(1, text)
// Track focus state
Component.onCompleted: {
if (inputItem) {
inputItem.onActiveFocusChanged.connect(function () {
if (inputItem.activeFocus) {
root.focusedInput = inputLine1
root.focusedLineIndex = 1
}
})
}
}
}
NTextInput {
id: inputLine2
Layout.fillWidth: true
label: "2nd line"
placeholderText: "ddd MMM d"
text: valueLine2
onTextChanged: updateLineValue(2, text)
// Track focus state
Component.onCompleted: {
if (inputItem) {
inputItem.onActiveFocusChanged.connect(function () {
if (inputItem.activeFocus) {
root.focusedInput = inputLine2
root.focusedLineIndex = 2
}
})
}
}
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.preferredWidth: 1 // Equal sizing hint
spacing: Style.marginM * scaling
NTextInput {
id: inputLine3
Layout.fillWidth: true
label: "3rd line"
placeholderText: ""
text: valueLine3
onTextChanged: updateLineValue(3, text)
// Track focus state
Component.onCompleted: {
if (inputItem) {
inputItem.onActiveFocusChanged.connect(function () {
if (inputItem.activeFocus) {
root.focusedInput = inputLine3
root.focusedLineIndex = 3
}
})
}
}
}
NTextInput {
id: inputLine4
Layout.fillWidth: true
label: "4th line"
placeholderText: ""
text: valueLine4
onTextChanged: updateLineValue(4, text)
// Track focus state
Component.onCompleted: {
if (inputItem) {
inputItem.onActiveFocusChanged.connect(function () {
if (inputItem.activeFocus) {
root.focusedInput = inputLine4
root.focusedLineIndex = 4
}
})
}
}
}
}
// --------------
// Preview
ColumnLayout {
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
Layout.fillWidth: false // Don't stretch this column
NLabel {
label: "Preview"
Layout.alignment: Qt.AlignHCenter | Qt.AlignTop
}
Rectangle {
Layout.preferredWidth: 240 * scaling
Layout.preferredHeight: 120 * scaling // Fixed height instead of fillHeight
color: Color.mSurfaceVariant
radius: Style.radiusM * scaling
border.color: focusedLineIndex > 0 ? Color.mSecondary : Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
Behavior on border.color {
ColorAnimation {
duration: Style.animationFast
}
}
ColumnLayout {
spacing: -2 * scaling
anchors.centerIn: parent
NText {
visible: text !== ""
text: Qt.formatDateTime(now, valueLine1.trim())
font.family: valueUseMonospacedFont ? Settings.data.ui.fontFixed : Settings.data.ui.fontDefault
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: valueUsePrimaryColor ? Color.mPrimary : Color.mOnSurface
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
}
NText {
visible: text !== ""
text: Qt.formatDateTime(now, valueLine2.trim())
font.family: valueUseMonospacedFont ? Settings.data.ui.fontFixed : Settings.data.ui.fontDefault
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: valueUsePrimaryColor ? Color.mPrimary : Color.mOnSurface
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
}
NText {
visible: text !== ""
text: Qt.formatDateTime(now, valueLine3.trim())
font.family: valueUseMonospacedFont ? Settings.data.ui.fontFixed : Settings.data.ui.fontDefault
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: valueUsePrimaryColor ? Color.mPrimary : Color.mOnSurface
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.topMargin: visible ? Style.marginXS * scaling : 0
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
}
NText {
visible: text !== ""
text: Qt.formatDateTime(now, valueLine4.trim())
font.family: valueUseMonospacedFont ? Settings.data.ui.fontFixed : Settings.data.ui.fontDefault
font.pointSize: Style.fontSizeM * scaling
font.weight: Style.fontWeightBold
color: valueUsePrimaryColor ? Color.mPrimary : Color.mOnSurface
wrapMode: Text.WordWrap
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Behavior on color {
ColorAnimation {
duration: Style.animationFast
}
}
}
}
}
}
}
NDivider {
Layout.topMargin: Style.marginL * scaling
Layout.bottomMargin: Style.marginL * scaling
}
// NHeader {
// label: "Tokens"
// description: focusedLineIndex > 0 ? "Click any token to add it to line " + focusedLineIndex : "Select an input field above, then click a token to insert it."
// }
NDateTimeTokens {
Layout.fillWidth: true
height: 200 * scaling
// Connect to token clicked signal if NDateTimeTokens provides it
onTokenClicked: token => root.insertToken(token)
}
}