From 3f4cec171947b046e1e9f3238aecc22a7bb288dd Mon Sep 17 00:00:00 2001 From: LemmyCook Date: Thu, 28 Aug 2025 12:22:42 -0400 Subject: [PATCH] NTextInput: improved layout and adapted calling code all over the shell. --- Modules/SettingsPanel/SettingsPanel.qml | 1 + Modules/SettingsPanel/Tabs/AudioTab.qml | 4 - Modules/SettingsPanel/Tabs/DisplayTab.qml | 89 +++++++++-------- Modules/SettingsPanel/Tabs/GeneralTab.qml | 3 +- .../SettingsPanel/Tabs/ScreenRecorderTab.qml | 3 +- Modules/SettingsPanel/Tabs/TimeWeatherTab.qml | 2 + Modules/SettingsPanel/Tabs/WallpaperTab.qml | 14 +-- Widgets/NTextInput.qml | 95 +++++++++---------- 8 files changed, 106 insertions(+), 105 deletions(-) diff --git a/Modules/SettingsPanel/SettingsPanel.qml b/Modules/SettingsPanel/SettingsPanel.qml index a1992f9..440daec 100644 --- a/Modules/SettingsPanel/SettingsPanel.qml +++ b/Modules/SettingsPanel/SettingsPanel.qml @@ -301,6 +301,7 @@ NPanel { ScrollBar.horizontal.policy: ScrollBar.AlwaysOff ScrollBar.vertical.policy: ScrollBar.AsNeeded padding: Style.marginL * scaling + clip: true Loader { active: true diff --git a/Modules/SettingsPanel/Tabs/AudioTab.qml b/Modules/SettingsPanel/Tabs/AudioTab.qml index 1a6f4b9..cce7a0b 100644 --- a/Modules/SettingsPanel/Tabs/AudioTab.qml +++ b/Modules/SettingsPanel/Tabs/AudioTab.qml @@ -216,8 +216,6 @@ ColumnLayout { } // Preferred player (persistent) NTextInput { - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop label: "Preferred Player" description: "Substring to match MPRIS player (identity/bus/desktop)." placeholderText: "e.g. spotify, vlc, mpv" @@ -239,8 +237,6 @@ ColumnLayout { NTextInput { id: blacklistInput - Layout.fillWidth: true - Layout.alignment: Qt.AlignTop label: "Blacklist player" description: "Substring, e.g. plex, shim, mpv." placeholderText: "type substring and press +" diff --git a/Modules/SettingsPanel/Tabs/DisplayTab.qml b/Modules/SettingsPanel/Tabs/DisplayTab.qml index f7ea808..eb9a766 100644 --- a/Modules/SettingsPanel/Tabs/DisplayTab.qml +++ b/Modules/SettingsPanel/Tabs/DisplayTab.qml @@ -74,7 +74,6 @@ ColumnLayout { color: Color.mOnSurfaceVariant wrapMode: Text.WordWrap Layout.fillWidth: true - Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling) } ColumnLayout { @@ -253,7 +252,6 @@ ColumnLayout { color: Color.mOnSurfaceVariant wrapMode: Text.WordWrap Layout.fillWidth: true - Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling) } } @@ -278,7 +276,7 @@ ColumnLayout { visible: Settings.data.nightLight.enabled NLabel { label: "Intensity" - description: "Higher values create warmer light." + description: "Higher values create warmer tones." } RowLayout { spacing: Style.marginS * scaling @@ -305,46 +303,61 @@ ColumnLayout { } } - // Temperature settings (inline like schedule) - RowLayout { - visible: Settings.data.nightLight.enabled - Layout.fillWidth: false - spacing: Style.marginM * scaling - - NText { - text: "Low" - font.pointSize: Style.fontSizeM * scaling - color: Color.mOnSurfaceVariant + // Temperature + ColumnLayout { + spacing: Style.marginXS * scaling + Layout.alignment: Qt.AlignVCenter + + NLabel { + label: "Color temperature" + description: "Select two temperatures in Kelvin" } - NTextInput { - text: Settings.data.nightLight.lowTemp.toString() - inputMethodHints: Qt.ImhDigitsOnly - Layout.preferredWidth: 100 * scaling - onEditingFinished: { - var v = parseInt(text) - if (!isNaN(v)) { - Settings.data.nightLight.lowTemp = Math.max(1000, Math.min(6500, v)) - NightLightService.apply() + + RowLayout { + visible: Settings.data.nightLight.enabled + spacing: Style.marginM * scaling + Layout.fillWidth: false + Layout.fillHeight: true + Layout.alignment: Qt.AlignVCenter + + NText { + text: "Low" + font.pointSize: Style.fontSizeM * scaling + color: Color.mOnSurfaceVariant + Layout.alignment: Qt.AlignVCenter + } + + NTextInput { + text: Settings.data.nightLight.lowTemp.toString() + inputMethodHints: Qt.ImhDigitsOnly + Layout.alignment: Qt.AlignVCenter + onEditingFinished: { + var v = parseInt(text) + if (!isNaN(v)) { + Settings.data.nightLight.lowTemp = Math.max(1000, Math.min(6500, v)) + NightLightService.apply() + } } } - } - Item {} + Item {} - NText { - text: "High" - font.pointSize: Style.fontSizeM * scaling - color: Color.mOnSurfaceVariant - } - NTextInput { - text: Settings.data.nightLight.highTemp.toString() - inputMethodHints: Qt.ImhDigitsOnly - Layout.preferredWidth: 100 * scaling - onEditingFinished: { - var v = parseInt(text) - if (!isNaN(v)) { - Settings.data.nightLight.highTemp = Math.max(1000, Math.min(10000, v)) - NightLightService.apply() + NText { + text: "High" + font.pointSize: Style.fontSizeM * scaling + color: Color.mOnSurfaceVariant + Layout.alignment: Qt.AlignVCenter + } + NTextInput { + text: Settings.data.nightLight.highTemp.toString() + inputMethodHints: Qt.ImhDigitsOnly + Layout.alignment: Qt.AlignVCenter + onEditingFinished: { + var v = parseInt(text) + if (!isNaN(v)) { + Settings.data.nightLight.highTemp = Math.max(1000, Math.min(10000, v)) + NightLightService.apply() + } } } } diff --git a/Modules/SettingsPanel/Tabs/GeneralTab.qml b/Modules/SettingsPanel/Tabs/GeneralTab.qml index 473a5ce..b80faa2 100644 --- a/Modules/SettingsPanel/Tabs/GeneralTab.qml +++ b/Modules/SettingsPanel/Tabs/GeneralTab.qml @@ -25,10 +25,9 @@ ColumnLayout { NTextInput { label: "Profile Picture" - description: "Your profile picture displayed in various places throughout the shell." + description: "Your profile picture that appears throughout the interface." text: Settings.data.general.avatarImage placeholderText: "/home/user/.face" - Layout.fillWidth: true onEditingFinished: { Settings.data.general.avatarImage = text } diff --git a/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml b/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml index 2a000c1..900b971 100644 --- a/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml +++ b/Modules/SettingsPanel/Tabs/ScreenRecorderTab.qml @@ -24,7 +24,8 @@ ColumnLayout { onEditingFinished: { Settings.data.screenRecorder.directory = text } - Layout.fillWidth: true + + Layout.maximumWidth: 420 * scaling } ColumnLayout { diff --git a/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml b/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml index 519177f..50ea298 100644 --- a/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml +++ b/Modules/SettingsPanel/Tabs/TimeWeatherTab.qml @@ -10,6 +10,7 @@ ColumnLayout { // Location section RowLayout { + Layout.fillWidth: true spacing: Style.marginL * scaling NTextInput { @@ -25,6 +26,7 @@ ColumnLayout { LocationService.resetWeather() } } + Layout.maximumWidth: 420 * scaling } NText { diff --git a/Modules/SettingsPanel/Tabs/WallpaperTab.qml b/Modules/SettingsPanel/Tabs/WallpaperTab.qml index 6f85cb0..e96b5ef 100644 --- a/Modules/SettingsPanel/Tabs/WallpaperTab.qml +++ b/Modules/SettingsPanel/Tabs/WallpaperTab.qml @@ -35,10 +35,10 @@ ColumnLayout { label: "Wallpaper Directory" description: "Path to your wallpaper directory." text: Settings.data.wallpaper.directory - Layout.fillWidth: true onEditingFinished: { Settings.data.wallpaper.directory = text } + Layout.maximumWidth: 420 * scaling } NDivider { @@ -79,12 +79,7 @@ ColumnLayout { NText { // Show friendly H:MM format from current settings - text: { - const s = Settings.data.wallpaper.randomInterval - const h = Math.floor(s / 3600) - const m = Math.floor((s % 3600) / 60) - return (h > 0 ? (h + "h ") : "") + (m > 0 ? (m + "m") : (h === 0 ? "0m" : "")) - } + text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomInterval) Layout.alignment: Qt.AlignBottom | Qt.AlignRight } } @@ -284,14 +279,15 @@ ColumnLayout { NTextInput { label: "Custom Interval" - description: "Enter time as HH:MM (e.g., 1:30)." + description: "Enter time as HH:MM (e.g., 01:30)." + inputMaxWidth: 100 * scaling text: { const s = Settings.data.wallpaper.randomInterval const h = Math.floor(s / 3600) const m = Math.floor((s % 3600) / 60) return h + ":" + (m < 10 ? ("0" + m) : m) } - Layout.fillWidth: true + onEditingFinished: { const m = text.trim().match(/^(\d{1,2}):(\d{2})$/) if (m) { diff --git a/Widgets/NTextInput.qml b/Widgets/NTextInput.qml index 6fd56a9..78fcd11 100644 --- a/Widgets/NTextInput.qml +++ b/Widgets/NTextInput.qml @@ -4,13 +4,14 @@ import QtQuick.Layouts import qs.Commons import qs.Services -Item { +ColumnLayout { id: root property string label: "" property string description: "" property bool readOnly: false property bool enabled: true + property int inputMaxWidth: 420 * scaling property alias text: input.text property alias placeholderText: input.placeholderText @@ -18,61 +19,53 @@ Item { signal editingFinished - // Sizing - implicitWidth: Style.sliderWidth * 1.6 * scaling - implicitHeight: Style.baseWidgetSize * 2.75 * scaling + spacing: Style.marginS * scaling + implicitHeight: frame.height - ColumnLayout { - spacing: Style.marginXXS * scaling - Layout.fillWidth: true + NLabel { + label: root.label + description: root.description + visible: root.label !== "" || root.description !== "" + } - NLabel { - label: root.label - description: root.description + // Container + Rectangle { + id: frame + implicitWidth: parent.width + implicitHeight: Style.baseWidgetSize * 1.1 * scaling + Layout.minimumWidth: 80 * scaling + Layout.maximumWidth: root.inputMaxWidth + radius: Style.radiusM * scaling + color: Color.mSurface + border.color: Color.mOutline + border.width: Math.max(1, Style.borderS * scaling) + + // Focus ring + Rectangle { + anchors.fill: parent + radius: frame.radius + color: Color.transparent + border.color: input.activeFocus ? Color.mSecondary : Color.transparent + border.width: input.activeFocus ? Math.max(1, Style.borderS * scaling) : 0 } - // Container - Rectangle { - id: frame - Layout.topMargin: Style.marginXS * scaling - implicitWidth: root.width - implicitHeight: Style.baseWidgetSize * 1.35 * scaling - radius: Style.radiusM * scaling - color: Color.mSurface - border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + RowLayout { + anchors.fill: parent + anchors.leftMargin: Style.marginM * scaling + anchors.rightMargin: Style.marginM * scaling + spacing: Style.marginS * scaling - // Focus ring - Rectangle { - anchors.fill: parent - radius: frame.radius - color: Color.transparent - border.color: input.activeFocus ? Color.mSecondary : Color.transparent - border.width: input.activeFocus ? Math.max(1, Style.borderS * scaling) : 0 - } - - RowLayout { - anchors.fill: parent - anchors.leftMargin: Style.marginM * scaling - anchors.rightMargin: Style.marginM * scaling - spacing: Style.marginS * scaling - - // Optional leading icon slot in the future - // Item { Layout.preferredWidth: 0 } - TextField { - id: input - Layout.fillWidth: true - echoMode: TextInput.Normal - readOnly: root.readOnly - enabled: root.enabled - color: Color.mOnSurface - placeholderTextColor: Color.mOnSurface - background: null - font.pointSize: Style.fontSizeXS * scaling - onEditingFinished: root.editingFinished() - // Text changes are observable via the aliased 'text' property (root.text) and its 'textChanged' signal. - // No additional callback is invoked here to avoid conflicts with QML's onTextChanged handler semantics. - } + TextField { + id: input + Layout.fillWidth: true + echoMode: TextInput.Normal + readOnly: root.readOnly + enabled: root.enabled + color: Color.mOnSurface + placeholderTextColor: Color.mOnSurfaceVariant + background: null + font.pointSize: Style.fontSizeS * scaling + onEditingFinished: root.editingFinished() } } }