plasmoides KDE Store/GitHub (gnome-pager, kMenu, kvitals, windowtitle, claude, launchpad)
This commit is contained in:
+251
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Plasma Gnome Pager — ConfigAppearance.qml (Appearance settings page)
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2026 Kenan Salar
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* The Appearance page, built on ConfigPageBase. Ratios use ConfigSlider; dotSize/pillSize are integer
|
||||
* sliders where 0 reads "Default"/"Match dots" (the 0 = auto sentinel). Colours use ColorButton, lazy-loaded
|
||||
* with the dialog so the import never affects the always-on widget. Each `cfg_<key>` MUST match main.xml.
|
||||
*/
|
||||
pragma ComponentBehavior: Bound // the occupancyStyle delegate references outer ids (occupancyStyle/root)
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
import org.kde.kquickcontrols as KQuickControls
|
||||
|
||||
ConfigPageBase {
|
||||
id: root
|
||||
|
||||
property alias cfg_dotStyle: dotStyle.currentIndex
|
||||
property alias cfg_singleLine: singleLine.checked
|
||||
property alias cfg_matchDesktopGrid: matchDesktopGrid.checked
|
||||
property alias cfg_dotSize: dotSize.value
|
||||
property alias cfg_pillSize: pillSize.value
|
||||
property alias cfg_spacingFactor: spacingFactor.value
|
||||
property alias cfg_pillWidthFactor: pillWidthFactor.value
|
||||
property alias cfg_inactiveOpacity: inactiveOpacity.value
|
||||
property alias cfg_hoverOpacity: hoverOpacity.value
|
||||
property alias cfg_showOccupancy: showOccupancy.checked
|
||||
property alias cfg_occupancyStyle: occupancyStyle.currentIndex
|
||||
property alias cfg_occupiedOpacity: occupiedOpacity.value
|
||||
property alias cfg_followThemeColors: followThemeColors.checked
|
||||
property alias cfg_activeColor: activeColor.color
|
||||
property alias cfg_inactiveColor: inactiveColor.color
|
||||
property alias cfg_occupiedColor: occupiedColor.color
|
||||
|
||||
// Injected by the config dialog from the main.xml defaults; read by the Defaults handler below.
|
||||
property int cfg_dotStyleDefault
|
||||
property bool cfg_singleLineDefault
|
||||
property bool cfg_matchDesktopGridDefault
|
||||
property int cfg_dotSizeDefault
|
||||
property int cfg_pillSizeDefault
|
||||
property real cfg_spacingFactorDefault
|
||||
property real cfg_pillWidthFactorDefault
|
||||
property real cfg_inactiveOpacityDefault
|
||||
property real cfg_hoverOpacityDefault
|
||||
property bool cfg_showOccupancyDefault
|
||||
property int cfg_occupancyStyleDefault
|
||||
property real cfg_occupiedOpacityDefault
|
||||
property bool cfg_followThemeColorsDefault
|
||||
property color cfg_activeColorDefault
|
||||
property color cfg_inactiveColorDefault
|
||||
property color cfg_occupiedColorDefault
|
||||
|
||||
// This page's keys + compare kind; ConfigPageBase binds isModified + the Defaults reset off it
|
||||
// (reals within epsilon, colours via Qt.colorEqual).
|
||||
configKeys: [
|
||||
{ n: "dotStyle", t: "int" },
|
||||
{ n: "singleLine", t: "bool" },
|
||||
{ n: "matchDesktopGrid", t: "bool" },
|
||||
{ n: "dotSize", t: "int" },
|
||||
{ n: "pillSize", t: "int" },
|
||||
{ n: "spacingFactor", t: "real" },
|
||||
{ n: "pillWidthFactor", t: "real" },
|
||||
{ n: "inactiveOpacity", t: "real" },
|
||||
{ n: "hoverOpacity", t: "real" },
|
||||
{ n: "showOccupancy", t: "bool" },
|
||||
{ n: "occupancyStyle", t: "int" },
|
||||
{ n: "occupiedOpacity", t: "real" },
|
||||
{ n: "followThemeColors", t: "bool" },
|
||||
{ n: "activeColor", t: "color" },
|
||||
{ n: "inactiveColor", t: "color" },
|
||||
{ n: "occupiedColor", t: "color" }
|
||||
]
|
||||
|
||||
// Which pager style is selected, by the dotStyle combo index (order matches Logic.DOT_STYLE / main.xml:
|
||||
// 0 = Sliding pill, 1 = Filled & ring). The pill knobs only apply to Sliding pill; Filled & ring disables
|
||||
// the redundant Hollow ring occupancy marker. Named once here so the index checks aren't repeated below.
|
||||
readonly property bool pillStyle: dotStyle.currentIndex === 0
|
||||
readonly property bool ringStyle: dotStyle.currentIndex === 1
|
||||
|
||||
Kirigami.FormLayout {
|
||||
QQC2.ComboBox {
|
||||
id: dotStyle
|
||||
Kirigami.FormData.label: i18n("Pager style:")
|
||||
// Order MUST match Logic.DOT_STYLE / main.xml dotStyle (currentIndex is stored as the index).
|
||||
model: [i18n("Sliding pill"), i18n("Filled & ring")]
|
||||
Layout.preferredWidth: root.fieldWidth // match the other field widths (ConfigPageBase.fieldWidth)
|
||||
// Filled & ring disables the Hollow ring occupancy marker (index 2) — the dot is already a ring —
|
||||
// so migrate a previously-chosen Hollow ring to Filled (0) when the user switches to it.
|
||||
onActivated: {
|
||||
if (root.ringStyle && occupancyStyle.currentIndex === 2)
|
||||
occupancyStyle.currentIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
QQC2.CheckBox {
|
||||
id: singleLine
|
||||
Kirigami.FormData.label: i18n("Multiple rows:")
|
||||
text: i18n("Show all desktops in a single line")
|
||||
}
|
||||
QQC2.Label {
|
||||
// Hint: ignore the KWin grid entirely and lay everything out as one strip following the panel.
|
||||
text: i18n("Ignore the grid rows from System Settings and lay every desktop out in one strip along the panel (a single vertical strip on a vertical panel).")
|
||||
wrapMode: Text.WordWrap
|
||||
opacity: 0.7
|
||||
font: Kirigami.Theme.smallFont
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: root.fieldWidth // wrap within the field column
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: matchDesktopGrid
|
||||
Kirigami.FormData.label: i18n("Vertical panels:")
|
||||
text: i18n("Match the virtual-desktop grid layout")
|
||||
// Orthogonal to "single line": this sets the direction (across vs. down), so it composes — single
|
||||
// line + match grid gives a single HORIZONTAL row. Hence no longer greyed while single line is on.
|
||||
}
|
||||
QQC2.Label {
|
||||
// Hint: this only matters on a vertical panel (a horizontal panel already mirrors the grid).
|
||||
text: i18n("Arrange the dots like the desktop grid in System Settings (rows top to bottom) instead of running them down the panel. No effect on horizontal panels.")
|
||||
wrapMode: Text.WordWrap
|
||||
opacity: 0.7
|
||||
font: Kirigami.Theme.smallFont
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: root.fieldWidth // wrap within the field column
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: dotSize
|
||||
label: i18n("Dot size:")
|
||||
from: 0
|
||||
to: 64
|
||||
stepSize: 1
|
||||
// 0 = auto: the widget falls back to the HiDPI-aware themed size.
|
||||
format: v => v === 0 ? i18n("Default") : i18np("%1 px", "%1 px", Math.round(v))
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: pillSize
|
||||
// "Thickness" (not "size") disambiguates from "Pill length:" below — the pill's two axes (also avoids an msgmerge fuzzy collision).
|
||||
label: i18n("Pill thickness:")
|
||||
enabled: root.pillStyle // the pill only exists in the Sliding pill style
|
||||
from: 0
|
||||
to: 64
|
||||
stepSize: 1
|
||||
// 0 = auto: the pill thickness matches the (effective) dot size, so the pill tracks the dots.
|
||||
format: v => v === 0 ? i18n("Match dots") : i18np("%1 px", "%1 px", Math.round(v))
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: spacingFactor
|
||||
label: i18n("Spacing:")
|
||||
from: 0.0
|
||||
to: 2.0
|
||||
stepSize: 0.05
|
||||
format: v => i18n("%1× dot", v.toFixed(2))
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: pillWidthFactor
|
||||
label: i18n("Pill length:")
|
||||
enabled: root.pillStyle // the pill only exists in the Sliding pill style
|
||||
from: 1.0
|
||||
to: 10.0
|
||||
stepSize: 0.1
|
||||
// Length as a multiple of the PILL thickness (its aspect ratio), not the dot size.
|
||||
format: v => i18n("%1× pill", v.toFixed(1))
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: inactiveOpacity
|
||||
label: i18n("Inactive opacity:")
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
stepSize: 0.01 // 1% increments for fine control (drag or arrow keys)
|
||||
format: v => Math.round(v * 100) + "%"
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: hoverOpacity
|
||||
label: i18n("Hover opacity:")
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
stepSize: 0.01 // 1% increments for fine control (drag or arrow keys)
|
||||
format: v => Math.round(v * 100) + "%"
|
||||
}
|
||||
|
||||
QQC2.CheckBox {
|
||||
id: showOccupancy
|
||||
Kirigami.FormData.label: i18n("Occupied desktops:")
|
||||
text: i18n("Highlight desktops with open windows")
|
||||
}
|
||||
QQC2.ComboBox {
|
||||
id: occupancyStyle
|
||||
Kirigami.FormData.label: i18n("Indicator style:")
|
||||
enabled: showOccupancy.checked
|
||||
// Order MUST match Logic.OCCUPANCY / main.xml occupancyStyle (currentIndex is stored as the index).
|
||||
model: [i18n("Filled"), i18n("Inner dot"), i18n("Hollow ring")]
|
||||
// "Hollow ring" (index 2) is redundant in the Filled & ring pager style — the dot is ALREADY a
|
||||
// hollow ring — so disable that item there (selection blocked; a stored value is suppressed at runtime).
|
||||
delegate: QQC2.ItemDelegate {
|
||||
id: occStyleItem
|
||||
required property int index
|
||||
required property string modelData
|
||||
width: occupancyStyle.width
|
||||
text: occStyleItem.modelData
|
||||
enabled: !(root.ringStyle && occStyleItem.index === 2)
|
||||
highlighted: occupancyStyle.highlightedIndex === occStyleItem.index
|
||||
}
|
||||
}
|
||||
ConfigSlider {
|
||||
id: occupiedOpacity
|
||||
label: i18n("Occupied opacity:")
|
||||
enabled: showOccupancy.checked // every indicator style uses the occupied-marker opacity
|
||||
from: 0.0
|
||||
to: 1.0
|
||||
stepSize: 0.01 // 1% increments for fine control (drag or arrow keys)
|
||||
format: v => Math.round(v * 100) + "%"
|
||||
}
|
||||
|
||||
Item {
|
||||
Kirigami.FormData.isSection: true // a little vertical breathing room before the colours
|
||||
}
|
||||
|
||||
QQC2.CheckBox {
|
||||
id: followThemeColors
|
||||
Kirigami.FormData.label: i18n("Colors:")
|
||||
text: i18n("Follow the color scheme")
|
||||
}
|
||||
KQuickControls.ColorButton {
|
||||
id: activeColor
|
||||
Kirigami.FormData.label: i18n("Active desktop:")
|
||||
enabled: !followThemeColors.checked // custom colours apply only when not following the theme
|
||||
showAlphaChannel: false
|
||||
}
|
||||
KQuickControls.ColorButton {
|
||||
id: inactiveColor
|
||||
Kirigami.FormData.label: i18n("Inactive desktop:")
|
||||
enabled: !followThemeColors.checked
|
||||
showAlphaChannel: false
|
||||
}
|
||||
KQuickControls.ColorButton {
|
||||
id: occupiedColor
|
||||
Kirigami.FormData.label: i18n("Occupied desktop:")
|
||||
enabled: !followThemeColors.checked // the occupied marker; theme accent is used while following the scheme
|
||||
showAlphaChannel: false
|
||||
}
|
||||
}
|
||||
}
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* Plasma Gnome Pager — ConfigGeneral.qml (Behavior settings page)
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2026 Kenan Salar
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* The Behavior page, built on ConfigPageBase. Each `cfg_<key>` alias MUST match a main.xml entry exactly
|
||||
* (the dialog wires load/save); `cfg_<key>Default` is injected from the schema.
|
||||
*/
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
ConfigPageBase {
|
||||
id: root
|
||||
|
||||
property alias cfg_enableScroll: enableScroll.checked
|
||||
property alias cfg_scrollWrap: scrollWrap.checked
|
||||
property alias cfg_invertScroll: invertScroll.checked
|
||||
property alias cfg_pillClickAction: pillClickAction.currentIndex
|
||||
property alias cfg_showTooltips: showTooltips.checked
|
||||
property alias cfg_showWindowList: showWindowList.checked
|
||||
property alias cfg_enableAddRemove: enableAddRemove.checked
|
||||
property alias cfg_enableRename: enableRename.checked
|
||||
property alias cfg_dynamicWorkspaces: dynamicWorkspaces.checked
|
||||
property alias cfg_dynamicNamePrefix: dynamicNamePrefix.text
|
||||
property alias cfg_animationDuration: animationDuration.value
|
||||
|
||||
// Injected by the config dialog from the main.xml defaults; read by the Defaults handler below.
|
||||
property bool cfg_enableScrollDefault
|
||||
property bool cfg_scrollWrapDefault
|
||||
property bool cfg_invertScrollDefault
|
||||
property int cfg_pillClickActionDefault
|
||||
property bool cfg_showTooltipsDefault
|
||||
property bool cfg_showWindowListDefault
|
||||
property bool cfg_enableAddRemoveDefault
|
||||
property bool cfg_enableRenameDefault
|
||||
property bool cfg_dynamicWorkspacesDefault
|
||||
property string cfg_dynamicNamePrefixDefault
|
||||
property int cfg_animationDurationDefault
|
||||
|
||||
// This page's keys + compare kind; ConfigPageBase binds isModified AND the Defaults reset off it.
|
||||
configKeys: [
|
||||
{ n: "enableScroll", t: "bool" },
|
||||
{ n: "scrollWrap", t: "bool" },
|
||||
{ n: "invertScroll", t: "bool" },
|
||||
{ n: "pillClickAction", t: "int" },
|
||||
{ n: "showTooltips", t: "bool" },
|
||||
{ n: "showWindowList", t: "bool" },
|
||||
{ n: "enableAddRemove", t: "bool" },
|
||||
{ n: "enableRename", t: "bool" },
|
||||
{ n: "dynamicWorkspaces", t: "bool" },
|
||||
{ n: "dynamicNamePrefix", t: "string" },
|
||||
{ n: "animationDuration", t: "int" }
|
||||
]
|
||||
|
||||
Kirigami.FormLayout {
|
||||
QQC2.CheckBox {
|
||||
id: enableScroll
|
||||
Kirigami.FormData.label: i18n("Mouse:")
|
||||
text: i18n("Scroll over the pager to switch desktops")
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: scrollWrap
|
||||
text: i18n("Wrap around at the first and last desktop")
|
||||
enabled: enableScroll.checked // wrap only matters when scrolling is on
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: invertScroll
|
||||
text: i18n("Invert the scroll direction")
|
||||
enabled: enableScroll.checked // inversion only matters when scrolling is on
|
||||
}
|
||||
QQC2.ComboBox {
|
||||
id: pillClickAction
|
||||
Kirigami.FormData.label: i18n("Click current desktop:")
|
||||
// Order MUST match Logic.PILL_CLICK_ACTION / main.xml pillClickAction (currentIndex is stored as the index).
|
||||
model: [i18n("Nothing"), i18n("Show Desktop"), i18n("Overview"), i18n("Grid")]
|
||||
Layout.preferredWidth: root.fieldWidth // match the other field widths (ConfigPageBase.fieldWidth)
|
||||
}
|
||||
QQC2.Label {
|
||||
// Clarify the action only fires on the highlighted (current) desktop; other dots just switch.
|
||||
text: i18n("Action when clicking the highlighted current desktop. Clicking any other desktop switches to it.")
|
||||
wrapMode: Text.WordWrap
|
||||
opacity: 0.7
|
||||
font: Kirigami.Theme.smallFont
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: root.fieldWidth // wrap within the field column
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: showTooltips
|
||||
Kirigami.FormData.label: i18n("Tooltips:")
|
||||
text: i18n("Show the desktop name on hover")
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: showWindowList
|
||||
text: i18n("List the open windows in the tooltip")
|
||||
enabled: showTooltips.checked // the window list only shows when tooltips are on
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: enableAddRemove
|
||||
Kirigami.FormData.label: i18n("Menu:")
|
||||
text: i18n("Add and remove desktops from the right-click menu")
|
||||
// Greyed while dynamic workspaces is on (mutually exclusive); value preserved, returns when off.
|
||||
enabled: !dynamicWorkspaces.checked
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: enableRename
|
||||
text: i18n("Rename the current desktop from the right-click menu")
|
||||
}
|
||||
QQC2.CheckBox {
|
||||
id: dynamicWorkspaces
|
||||
Kirigami.FormData.label: i18n("Dynamic desktops:")
|
||||
text: i18n("Automatically add and remove desktops (GNOME-style)")
|
||||
}
|
||||
QQC2.Label {
|
||||
// Hint explaining the exclusivity above, so a new user sees why Add/Remove greys out.
|
||||
text: i18n("While on, desktops are managed automatically — the menu Add/Remove options are disabled.")
|
||||
visible: dynamicWorkspaces.checked
|
||||
wrapMode: Text.WordWrap
|
||||
opacity: 0.7
|
||||
font: Kirigami.Theme.smallFont
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: root.fieldWidth // wrap within the field column
|
||||
}
|
||||
QQC2.TextField {
|
||||
id: dynamicNamePrefix
|
||||
Kirigami.FormData.label: i18n("New desktop name:")
|
||||
// Base name for auto-created desktops (number appended); empty → the placeholder default.
|
||||
enabled: dynamicWorkspaces.checked
|
||||
placeholderText: i18nc("@info default base name for auto-created virtual desktops", "Desktop")
|
||||
Layout.preferredWidth: root.fieldWidth // match the slider track width (ConfigPageBase.fieldWidth)
|
||||
}
|
||||
|
||||
ConfigSlider {
|
||||
id: animationDuration
|
||||
label: i18n("Animation duration:")
|
||||
from: 0
|
||||
to: 2000
|
||||
stepSize: 25 // clean 25 ms increments (SnapAlways is the ConfigSlider default)
|
||||
// 0 = follow the theme's default (and the global "reduce animations" setting).
|
||||
format: v => v === 0 ? i18n("Default") : i18np("%1 ms", "%1 ms", Math.round(v))
|
||||
}
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Plasma Gnome Pager — ConfigPageBase.qml (shared settings-page base)
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2026 Kenan Salar
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* Shared skeleton for every settings page: a Kirigami.ScrollablePage for the KDE header + scrolling, plus
|
||||
* the "Defaults" button the Plasma footer lacks (defined ONCE here). A derived page only declares its
|
||||
* `configKeys` { n, t } list; the modified-check and the Defaults reset are bound off it here, once.
|
||||
*/
|
||||
import QtQuick
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
Kirigami.ScrollablePage {
|
||||
id: root
|
||||
|
||||
// The derived page's keys + compare kind ({ n, t }); drives both isModified and the Defaults reset.
|
||||
property var configKeys: []
|
||||
|
||||
// True when any key differs from its default (gates the Defaults action). Bound off configKeys here
|
||||
// so a derived page need only declare the list; empty configKeys ⇒ false (unmodified).
|
||||
property bool isModified: configKeys.some(k => root.fieldChanged(root, k.n, k.t))
|
||||
|
||||
// Field-column width for non-slider fields; kept equal to ConfigSlider.trackWidth so every row lines up.
|
||||
readonly property int fieldWidth: Kirigami.Units.gridUnit * 18
|
||||
|
||||
// Tolerance for real-valued "differs from default": SnapAlways can land a value a ULP off the default.
|
||||
readonly property real epsilon: 1e-9
|
||||
|
||||
// Does cfg_<name> differ from cfg_<name>Default? Type-aware: reals within epsilon, colours via Qt.colorEqual, else exact.
|
||||
function fieldChanged(page, name, kind) {
|
||||
var a = page["cfg_" + name];
|
||||
var b = page["cfg_" + name + "Default"];
|
||||
if (kind === "real")
|
||||
return Math.abs(a - b) > root.epsilon;
|
||||
if (kind === "color")
|
||||
return !Qt.colorEqual(a, b);
|
||||
return a !== b;
|
||||
}
|
||||
|
||||
// Reset cfg_<name> to its injected schema default.
|
||||
function resetField(page, name) {
|
||||
page["cfg_" + name] = page["cfg_" + name + "Default"];
|
||||
}
|
||||
|
||||
// Raised by the Defaults action; resets every configKeys entry to its injected schema default.
|
||||
signal defaultsRequested()
|
||||
onDefaultsRequested: configKeys.forEach(k => root.resetField(root, k.n))
|
||||
|
||||
actions: [
|
||||
Kirigami.Action {
|
||||
text: i18n("Defaults")
|
||||
icon.name: "edit-undo-symbolic"
|
||||
enabled: root.isModified
|
||||
onTriggered: root.defaultsRequested()
|
||||
}
|
||||
]
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Plasma Gnome Pager — ConfigSlider.qml (reusable config-page control)
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2026 Kenan Salar
|
||||
* SPDX-License-Identifier: GPL-3.0-or-later
|
||||
*
|
||||
* A FormLayout row of a Slider + a right-hand value read-out. One `format` closure (value → string) drives
|
||||
* BOTH the read-out AND its reserved width (widest of from/to) so the label can't reflow mid-drag. The
|
||||
* track is a FIXED width (NOT fillWidth) so sliders match across both pages; the value label absorbs slack.
|
||||
*/
|
||||
import QtQuick
|
||||
import QtQuick.Controls as QQC2
|
||||
import QtQuick.Layouts
|
||||
import org.kde.kirigami as Kirigami
|
||||
|
||||
RowLayout {
|
||||
id: root
|
||||
|
||||
property alias value: slider.value
|
||||
property alias from: slider.from
|
||||
property alias to: slider.to
|
||||
property alias stepSize: slider.stepSize
|
||||
property alias snapMode: slider.snapMode
|
||||
property string label: "" // the row's Kirigami.FormData label
|
||||
property var format: (v) => String(v) // value → read-out string (drives text AND reserved width)
|
||||
|
||||
// Fixed track length, matched to ConfigPageBase.fieldWidth so every row's field column lines up.
|
||||
readonly property int trackWidth: Kirigami.Units.gridUnit * 18
|
||||
|
||||
Kirigami.FormData.label: root.label
|
||||
|
||||
QQC2.Slider {
|
||||
id: slider
|
||||
// Fixed track length (NOT fillWidth): a fillWidth track would stretch wider on the Behavior page's long labels. min == preferred so it can't shrink.
|
||||
Layout.preferredWidth: root.trackWidth
|
||||
Layout.minimumWidth: root.trackWidth
|
||||
snapMode: QQC2.Slider.SnapAlways // clean increments even when dragged (override via alias)
|
||||
}
|
||||
|
||||
QQC2.Label {
|
||||
id: valueLabel
|
||||
text: root.format(slider.value)
|
||||
horizontalAlignment: Text.AlignRight
|
||||
// fillWidth so extra column width is absorbed here — the right-aligned read-out pins to the column edge and the slider keeps its length.
|
||||
Layout.fillWidth: true
|
||||
// Reserve the widest the read-out can get (+ buffer) so the cell never resizes mid-drag.
|
||||
Layout.minimumWidth: Math.max(valueMetricsFrom.advanceWidth, valueMetricsTo.advanceWidth) + Kirigami.Units.smallSpacing
|
||||
Layout.preferredWidth: Layout.minimumWidth
|
||||
|
||||
TextMetrics {
|
||||
id: valueMetricsFrom
|
||||
font: valueLabel.font
|
||||
text: root.format(slider.from)
|
||||
}
|
||||
TextMetrics {
|
||||
id: valueMetricsTo
|
||||
font: valueLabel.font
|
||||
text: root.format(slider.to)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user