NTextInput: improved layout and adapted calling code all over the shell.
This commit is contained in:
parent
e86e7344f3
commit
3f4cec1719
8 changed files with 106 additions and 105 deletions
|
|
@ -301,6 +301,7 @@ NPanel {
|
||||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||||
padding: Style.marginL * scaling
|
padding: Style.marginL * scaling
|
||||||
|
clip: true
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
active: true
|
active: true
|
||||||
|
|
|
||||||
|
|
@ -216,8 +216,6 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
// Preferred player (persistent)
|
// Preferred player (persistent)
|
||||||
NTextInput {
|
NTextInput {
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
label: "Preferred Player"
|
label: "Preferred Player"
|
||||||
description: "Substring to match MPRIS player (identity/bus/desktop)."
|
description: "Substring to match MPRIS player (identity/bus/desktop)."
|
||||||
placeholderText: "e.g. spotify, vlc, mpv"
|
placeholderText: "e.g. spotify, vlc, mpv"
|
||||||
|
|
@ -239,8 +237,6 @@ ColumnLayout {
|
||||||
|
|
||||||
NTextInput {
|
NTextInput {
|
||||||
id: blacklistInput
|
id: blacklistInput
|
||||||
Layout.fillWidth: true
|
|
||||||
Layout.alignment: Qt.AlignTop
|
|
||||||
label: "Blacklist player"
|
label: "Blacklist player"
|
||||||
description: "Substring, e.g. plex, shim, mpv."
|
description: "Substring, e.g. plex, shim, mpv."
|
||||||
placeholderText: "type substring and press +"
|
placeholderText: "type substring and press +"
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,6 @@ ColumnLayout {
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
@ -253,7 +252,6 @@ ColumnLayout {
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredWidth: parent.width - (Style.marginL * 2 * scaling)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -278,7 +276,7 @@ ColumnLayout {
|
||||||
visible: Settings.data.nightLight.enabled
|
visible: Settings.data.nightLight.enabled
|
||||||
NLabel {
|
NLabel {
|
||||||
label: "Intensity"
|
label: "Intensity"
|
||||||
description: "Higher values create warmer light."
|
description: "Higher values create warmer tones."
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
spacing: Style.marginS * scaling
|
spacing: Style.marginS * scaling
|
||||||
|
|
@ -305,46 +303,61 @@ ColumnLayout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Temperature settings (inline like schedule)
|
// Temperature
|
||||||
RowLayout {
|
ColumnLayout {
|
||||||
visible: Settings.data.nightLight.enabled
|
spacing: Style.marginXS * scaling
|
||||||
Layout.fillWidth: false
|
Layout.alignment: Qt.AlignVCenter
|
||||||
spacing: Style.marginM * scaling
|
|
||||||
|
NLabel {
|
||||||
NText {
|
label: "Color temperature"
|
||||||
text: "Low"
|
description: "Select two temperatures in Kelvin"
|
||||||
font.pointSize: Style.fontSizeM * scaling
|
|
||||||
color: Color.mOnSurfaceVariant
|
|
||||||
}
|
}
|
||||||
NTextInput {
|
|
||||||
text: Settings.data.nightLight.lowTemp.toString()
|
RowLayout {
|
||||||
inputMethodHints: Qt.ImhDigitsOnly
|
visible: Settings.data.nightLight.enabled
|
||||||
Layout.preferredWidth: 100 * scaling
|
spacing: Style.marginM * scaling
|
||||||
onEditingFinished: {
|
Layout.fillWidth: false
|
||||||
var v = parseInt(text)
|
Layout.fillHeight: true
|
||||||
if (!isNaN(v)) {
|
Layout.alignment: Qt.AlignVCenter
|
||||||
Settings.data.nightLight.lowTemp = Math.max(1000, Math.min(6500, v))
|
|
||||||
NightLightService.apply()
|
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 {
|
NText {
|
||||||
text: "High"
|
text: "High"
|
||||||
font.pointSize: Style.fontSizeM * scaling
|
font.pointSize: Style.fontSizeM * scaling
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
}
|
Layout.alignment: Qt.AlignVCenter
|
||||||
NTextInput {
|
}
|
||||||
text: Settings.data.nightLight.highTemp.toString()
|
NTextInput {
|
||||||
inputMethodHints: Qt.ImhDigitsOnly
|
text: Settings.data.nightLight.highTemp.toString()
|
||||||
Layout.preferredWidth: 100 * scaling
|
inputMethodHints: Qt.ImhDigitsOnly
|
||||||
onEditingFinished: {
|
Layout.alignment: Qt.AlignVCenter
|
||||||
var v = parseInt(text)
|
onEditingFinished: {
|
||||||
if (!isNaN(v)) {
|
var v = parseInt(text)
|
||||||
Settings.data.nightLight.highTemp = Math.max(1000, Math.min(10000, v))
|
if (!isNaN(v)) {
|
||||||
NightLightService.apply()
|
Settings.data.nightLight.highTemp = Math.max(1000, Math.min(10000, v))
|
||||||
|
NightLightService.apply()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,9 @@ ColumnLayout {
|
||||||
|
|
||||||
NTextInput {
|
NTextInput {
|
||||||
label: "Profile Picture"
|
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
|
text: Settings.data.general.avatarImage
|
||||||
placeholderText: "/home/user/.face"
|
placeholderText: "/home/user/.face"
|
||||||
Layout.fillWidth: true
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
Settings.data.general.avatarImage = text
|
Settings.data.general.avatarImage = text
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,8 @@ ColumnLayout {
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
Settings.data.screenRecorder.directory = text
|
Settings.data.screenRecorder.directory = text
|
||||||
}
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
|
Layout.maximumWidth: 420 * scaling
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ ColumnLayout {
|
||||||
|
|
||||||
// Location section
|
// Location section
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
spacing: Style.marginL * scaling
|
spacing: Style.marginL * scaling
|
||||||
|
|
||||||
NTextInput {
|
NTextInput {
|
||||||
|
|
@ -25,6 +26,7 @@ ColumnLayout {
|
||||||
LocationService.resetWeather()
|
LocationService.resetWeather()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Layout.maximumWidth: 420 * scaling
|
||||||
}
|
}
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,10 @@ ColumnLayout {
|
||||||
label: "Wallpaper Directory"
|
label: "Wallpaper Directory"
|
||||||
description: "Path to your wallpaper directory."
|
description: "Path to your wallpaper directory."
|
||||||
text: Settings.data.wallpaper.directory
|
text: Settings.data.wallpaper.directory
|
||||||
Layout.fillWidth: true
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
Settings.data.wallpaper.directory = text
|
Settings.data.wallpaper.directory = text
|
||||||
}
|
}
|
||||||
|
Layout.maximumWidth: 420 * scaling
|
||||||
}
|
}
|
||||||
|
|
||||||
NDivider {
|
NDivider {
|
||||||
|
|
@ -79,12 +79,7 @@ ColumnLayout {
|
||||||
|
|
||||||
NText {
|
NText {
|
||||||
// Show friendly H:MM format from current settings
|
// Show friendly H:MM format from current settings
|
||||||
text: {
|
text: Time.formatVagueHumanReadableDuration(Settings.data.wallpaper.randomInterval)
|
||||||
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" : ""))
|
|
||||||
}
|
|
||||||
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
|
Layout.alignment: Qt.AlignBottom | Qt.AlignRight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -284,14 +279,15 @@ ColumnLayout {
|
||||||
|
|
||||||
NTextInput {
|
NTextInput {
|
||||||
label: "Custom Interval"
|
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: {
|
text: {
|
||||||
const s = Settings.data.wallpaper.randomInterval
|
const s = Settings.data.wallpaper.randomInterval
|
||||||
const h = Math.floor(s / 3600)
|
const h = Math.floor(s / 3600)
|
||||||
const m = Math.floor((s % 3600) / 60)
|
const m = Math.floor((s % 3600) / 60)
|
||||||
return h + ":" + (m < 10 ? ("0" + m) : m)
|
return h + ":" + (m < 10 ? ("0" + m) : m)
|
||||||
}
|
}
|
||||||
Layout.fillWidth: true
|
|
||||||
onEditingFinished: {
|
onEditingFinished: {
|
||||||
const m = text.trim().match(/^(\d{1,2}):(\d{2})$/)
|
const m = text.trim().match(/^(\d{1,2}):(\d{2})$/)
|
||||||
if (m) {
|
if (m) {
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,14 @@ import QtQuick.Layouts
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
Item {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property string label: ""
|
property string label: ""
|
||||||
property string description: ""
|
property string description: ""
|
||||||
property bool readOnly: false
|
property bool readOnly: false
|
||||||
property bool enabled: true
|
property bool enabled: true
|
||||||
|
property int inputMaxWidth: 420 * scaling
|
||||||
|
|
||||||
property alias text: input.text
|
property alias text: input.text
|
||||||
property alias placeholderText: input.placeholderText
|
property alias placeholderText: input.placeholderText
|
||||||
|
|
@ -18,61 +19,53 @@ Item {
|
||||||
|
|
||||||
signal editingFinished
|
signal editingFinished
|
||||||
|
|
||||||
// Sizing
|
spacing: Style.marginS * scaling
|
||||||
implicitWidth: Style.sliderWidth * 1.6 * scaling
|
implicitHeight: frame.height
|
||||||
implicitHeight: Style.baseWidgetSize * 2.75 * scaling
|
|
||||||
|
|
||||||
ColumnLayout {
|
NLabel {
|
||||||
spacing: Style.marginXXS * scaling
|
label: root.label
|
||||||
Layout.fillWidth: true
|
description: root.description
|
||||||
|
visible: root.label !== "" || root.description !== ""
|
||||||
|
}
|
||||||
|
|
||||||
NLabel {
|
// Container
|
||||||
label: root.label
|
Rectangle {
|
||||||
description: root.description
|
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
|
RowLayout {
|
||||||
Rectangle {
|
anchors.fill: parent
|
||||||
id: frame
|
anchors.leftMargin: Style.marginM * scaling
|
||||||
Layout.topMargin: Style.marginXS * scaling
|
anchors.rightMargin: Style.marginM * scaling
|
||||||
implicitWidth: root.width
|
spacing: Style.marginS * scaling
|
||||||
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)
|
|
||||||
|
|
||||||
// Focus ring
|
TextField {
|
||||||
Rectangle {
|
id: input
|
||||||
anchors.fill: parent
|
Layout.fillWidth: true
|
||||||
radius: frame.radius
|
echoMode: TextInput.Normal
|
||||||
color: Color.transparent
|
readOnly: root.readOnly
|
||||||
border.color: input.activeFocus ? Color.mSecondary : Color.transparent
|
enabled: root.enabled
|
||||||
border.width: input.activeFocus ? Math.max(1, Style.borderS * scaling) : 0
|
color: Color.mOnSurface
|
||||||
}
|
placeholderTextColor: Color.mOnSurfaceVariant
|
||||||
|
background: null
|
||||||
RowLayout {
|
font.pointSize: Style.fontSizeS * scaling
|
||||||
anchors.fill: parent
|
onEditingFinished: root.editingFinished()
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue