Remove "%" from NVerticalPill add force close option to it too

NVerticalPill: add force close option
Any vertical bar widget: remove "%" display to have nice horizontal text
BarTab: add "always hide percentage" option so the pills will never
expand (opposite of always show percentage)
This commit is contained in:
Ly-sec 2025-09-14 23:13:11 +02:00
parent 852e2fa4d1
commit aed81e82b0
14 changed files with 158 additions and 66 deletions

View file

@ -30,12 +30,12 @@ Item {
} }
// Resolve settings: try user settings or defaults from BarWidgetRegistry // Resolve settings: try user settings or defaults from BarWidgetRegistry
readonly property bool alwaysShowPercentage: widgetSettings.alwaysShowPercentage !== undefined ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage readonly property string displayMode: widgetSettings.displayMode !== undefined ? widgetSettings.displayMode : widgetMetadata.displayMode
readonly property real warningThreshold: widgetSettings.warningThreshold !== undefined ? widgetSettings.warningThreshold : widgetMetadata.warningThreshold readonly property real warningThreshold: widgetSettings.warningThreshold !== undefined ? widgetSettings.warningThreshold : widgetMetadata.warningThreshold
// Test mode // Test mode
readonly property bool testMode: false readonly property bool testMode: true
readonly property int testPercent: 90 readonly property int testPercent: 100
readonly property bool testCharging: false readonly property bool testCharging: false
// Main properties // Main properties
@ -86,9 +86,10 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root) rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady) icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady)
text: (isReady || testMode) ? Math.round(percent) + "%" : "-" text: (isReady || testMode) ? Math.round(percent) : "-"
autoHide: false autoHide: false
forceOpen: isReady && (testMode || battery.isLaptopBattery) && alwaysShowPercentage forceOpen: isReady && (testMode || battery.isLaptopBattery) && displayMode === "alwaysShow"
forceClosed: displayMode === "alwaysHide"
disableOpen: (!isReady || (!testMode && !battery.isLaptopBattery)) disableOpen: (!isReady || (!testMode && !battery.isLaptopBattery))
tooltipText: { tooltipText: {
let lines = [] let lines = []

View file

@ -28,7 +28,7 @@ Item {
return {} return {}
} }
readonly property bool userAlwaysShowPercentage: (widgetSettings.alwaysShowPercentage !== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
// Used to avoid opening the pill on Quickshell startup // Used to avoid opening the pill on Quickshell startup
property bool firstBrightnessReceived: false property bool firstBrightnessReceived: false
@ -80,9 +80,10 @@ Item {
autoHide: false // Important to be false so we can hover as long as we want autoHide: false // Important to be false so we can hover as long as we want
text: { text: {
var monitor = getMonitor() var monitor = getMonitor()
return monitor ? (Math.round(monitor.brightness * 100) + "%") : "" return monitor ? Math.round(monitor.brightness * 100) : ""
} }
forceOpen: userAlwaysShowPercentage forceOpen: displayMode === "alwaysShow"
forceClosed: displayMode === "alwaysHide"
tooltipText: { tooltipText: {
var monitor = getMonitor() var monitor = getMonitor()
if (!monitor) if (!monitor)

View file

@ -30,7 +30,7 @@ Item {
return {} return {}
} }
readonly property bool forceOpen: (widgetSettings.forceOpen !== undefined) ? widgetSettings.forceOpen : widgetMetadata.forceOpen readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
// Use the shared service for keyboard layout // Use the shared service for keyboard layout
property string currentLayout: KeyboardLayoutService.currentLayout property string currentLayout: KeyboardLayoutService.currentLayout
@ -47,7 +47,8 @@ Item {
autoHide: false // Important to be false so we can hover as long as we want autoHide: false // Important to be false so we can hover as long as we want
text: currentLayout.toUpperCase() text: currentLayout.toUpperCase()
tooltipText: "Keyboard layout: " + currentLayout.toUpperCase() tooltipText: "Keyboard layout: " + currentLayout.toUpperCase()
forceOpen: root.forceOpen forceOpen: root.displayMode === "forceOpen"
forceClosed: root.displayMode === "alwaysHide"
fontSize: Style.fontSizeS // Use larger font size fontSize: Style.fontSizeS // Use larger font size
onClicked: { onClicked: {

View file

@ -30,7 +30,7 @@ Item {
return {} return {}
} }
readonly property bool alwaysShowPercentage: (widgetSettings.alwaysShowPercentage !== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
// Used to avoid opening the pill on Quickshell startup // Used to avoid opening the pill on Quickshell startup
property bool firstInputVolumeReceived: false property bool firstInputVolumeReceived: false
@ -91,8 +91,9 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root) rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: getIcon() icon: getIcon()
autoHide: false // Important to be false so we can hover as long as we want autoHide: false // Important to be false so we can hover as long as we want
text: Math.floor(AudioService.inputVolume * 100) + "%" text: Math.floor(AudioService.inputVolume * 100)
forceOpen: alwaysShowPercentage forceOpen: displayMode === "alwaysShow"
forceClosed: displayMode === "alwaysHide"
tooltipText: "Microphone: " + Math.round(AudioService.inputVolume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute." tooltipText: "Microphone: " + Math.round(AudioService.inputVolume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute."
onWheel: function (delta) { onWheel: function (delta) {

View file

@ -30,7 +30,7 @@ Item {
return {} return {}
} }
readonly property bool alwaysShowPercentage: (widgetSettings.alwaysShowPercentage !== undefined) ? widgetSettings.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
// Used to avoid opening the pill on Quickshell startup // Used to avoid opening the pill on Quickshell startup
property bool firstVolumeReceived: false property bool firstVolumeReceived: false
@ -76,8 +76,9 @@ Item {
rightOpen: BarWidgetRegistry.getNPillDirection(root) rightOpen: BarWidgetRegistry.getNPillDirection(root)
icon: getIcon() icon: getIcon()
autoHide: false // Important to be false so we can hover as long as we want autoHide: false // Important to be false so we can hover as long as we want
text: Math.floor(AudioService.volume * 100) + "%" text: Math.floor(AudioService.volume * 100)
forceOpen: alwaysShowPercentage forceOpen: displayMode === "alwaysShow"
forceClosed: displayMode === "alwaysHide"
tooltipText: "Volume: " + Math.round(AudioService.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute." tooltipText: "Volume: " + Math.round(AudioService.volume * 100) + "%\nLeft click for advanced settings.\nScroll up/down to change volume.\nRight click to toggle mute."
onWheel: function (delta) { onWheel: function (delta) {

View file

@ -14,20 +14,36 @@ ColumnLayout {
property var widgetMetadata: null property var widgetMetadata: null
// Local state // Local state
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
property int valueWarningThreshold: widgetData.warningThreshold !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold property int valueWarningThreshold: widgetData.warningThreshold !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
function saveSettings() { function saveSettings() {
var settings = Object.assign({}, widgetData || {}) var settings = Object.assign({}, widgetData || {})
settings.alwaysShowPercentage = valueAlwaysShowPercentage settings.displayMode = valueDisplayMode
settings.warningThreshold = valueWarningThreshold settings.warningThreshold = valueWarningThreshold
return settings return settings
} }
NToggle { NComboBox {
label: "Always show percentage" label: "Display mode"
checked: root.valueAlwaysShowPercentage description: "Choose how the percentage is displayed."
onToggled: checked => root.valueAlwaysShowPercentage = checked minimumWidth: 134 * scaling
model: ListModel {
ListElement {
key: "normal"
name: "Normal"
}
ListElement {
key: "alwaysShow"
name: "Always Show"
}
ListElement {
key: "alwaysHide"
name: "Always Hide"
}
}
currentKey: root.valueDisplayMode
onSelected: key => root.valueDisplayMode = key
} }
NSpinBox { NSpinBox {

View file

@ -14,17 +14,33 @@ ColumnLayout {
property var widgetMetadata: null property var widgetMetadata: null
// Local state // Local state
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
function saveSettings() { function saveSettings() {
var settings = Object.assign({}, widgetData || {}) var settings = Object.assign({}, widgetData || {})
settings.alwaysShowPercentage = valueAlwaysShowPercentage settings.displayMode = valueDisplayMode
return settings return settings
} }
NToggle { NComboBox {
label: "Always show percentage" label: "Display mode"
checked: valueAlwaysShowPercentage description: "Choose how the percentage is displayed."
onToggled: checked => valueAlwaysShowPercentage = checked minimumWidth: 134 * scaling
model: ListModel {
ListElement {
key: "normal"
name: "Normal"
}
ListElement {
key: "alwaysShow"
name: "Always Show"
}
ListElement {
key: "alwaysHide"
name: "Always Hide"
}
}
currentKey: valueDisplayMode
onSelected: key => valueDisplayMode = key
} }
} }

View file

@ -14,18 +14,33 @@ ColumnLayout {
property var widgetMetadata: null property var widgetMetadata: null
// Local state // Local state
property bool valueForceOpen: widgetData.forceOpen !== undefined ? widgetData.forceOpen : widgetMetadata.forceOpen property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
function saveSettings() { function saveSettings() {
var settings = Object.assign({}, widgetData || {}) var settings = Object.assign({}, widgetData || {})
settings.forceOpen = valueForceOpen settings.displayMode = valueDisplayMode
return settings return settings
} }
NToggle { NComboBox {
label: "Force open" label: "Display mode"
description: "Keep the keyboard layout widget always expanded." description: "Choose how the keyboard layout is displayed."
checked: valueForceOpen minimumWidth: 134 * scaling
onToggled: checked => valueForceOpen = checked model: ListModel {
ListElement {
key: "normal"
name: "Normal"
}
ListElement {
key: "forceOpen"
name: "Force Open"
}
ListElement {
key: "alwaysHide"
name: "Always Hide"
}
}
currentKey: valueDisplayMode
onSelected: key => valueDisplayMode = key
} }
} }

View file

@ -14,17 +14,33 @@ ColumnLayout {
property var widgetMetadata: null property var widgetMetadata: null
// Local state // Local state
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
function saveSettings() { function saveSettings() {
var settings = Object.assign({}, widgetData || {}) var settings = Object.assign({}, widgetData || {})
settings.alwaysShowPercentage = valueAlwaysShowPercentage settings.displayMode = valueDisplayMode
return settings return settings
} }
NToggle { NComboBox {
label: "Always show percentage" label: "Display mode"
checked: valueAlwaysShowPercentage description: "Choose how the percentage is displayed."
onToggled: checked => valueAlwaysShowPercentage = checked minimumWidth: 134 * scaling
model: ListModel {
ListElement {
key: "normal"
name: "Normal"
}
ListElement {
key: "alwaysShow"
name: "Always Show"
}
ListElement {
key: "alwaysHide"
name: "Always Hide"
}
}
currentKey: valueDisplayMode
onSelected: key => valueDisplayMode = key
} }
} }

View file

@ -14,17 +14,33 @@ ColumnLayout {
property var widgetMetadata: null property var widgetMetadata: null
// Local state // Local state
property bool valueAlwaysShowPercentage: widgetData.alwaysShowPercentage !== undefined ? widgetData.alwaysShowPercentage : widgetMetadata.alwaysShowPercentage property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
function saveSettings() { function saveSettings() {
var settings = Object.assign({}, widgetData || {}) var settings = Object.assign({}, widgetData || {})
settings.alwaysShowPercentage = valueAlwaysShowPercentage settings.displayMode = valueDisplayMode
return settings return settings
} }
NToggle { NComboBox {
label: "Always show percentage" label: "Display mode"
checked: valueAlwaysShowPercentage description: "Choose how the percentage is displayed."
onToggled: checked => valueAlwaysShowPercentage = checked minimumWidth: 134 * scaling
model: ListModel {
ListElement {
key: "normal"
name: "Normal"
}
ListElement {
key: "alwaysShow"
name: "Always Show"
}
ListElement {
key: "alwaysHide"
name: "Always Hide"
}
}
currentKey: valueDisplayMode
onSelected: key => valueDisplayMode = key
} }
} }

View file

@ -43,12 +43,12 @@ Singleton {
}, },
"Battery": { "Battery": {
"allowUserSettings": true, "allowUserSettings": true,
"alwaysShowPercentage": false, "displayMode": "normal",
"warningThreshold": 30 "warningThreshold": 30
}, },
"Brightness": { "Brightness": {
"allowUserSettings": true, "allowUserSettings": true,
"alwaysShowPercentage": false "displayMode": "normal"
}, },
"Clock": { "Clock": {
"allowUserSettings": true, "allowUserSettings": true,
@ -65,7 +65,7 @@ Singleton {
}, },
"Microphone": { "Microphone": {
"allowUserSettings": true, "allowUserSettings": true,
"alwaysShowPercentage": false "displayMode": "normal"
}, },
"NotificationHistory": { "NotificationHistory": {
"allowUserSettings": true, "allowUserSettings": true,
@ -102,11 +102,11 @@ Singleton {
}, },
"Volume": { "Volume": {
"allowUserSettings": true, "allowUserSettings": true,
"alwaysShowPercentage": false "displayMode": "normal"
}, },
"KeyboardLayout": { "KeyboardLayout": {
"allowUserSettings": true, "allowUserSettings": true,
"forceOpen": false "displayMode": "normal"
} }
}) })

View file

@ -12,6 +12,7 @@ Item {
property real sizeRatio: 0.8 property real sizeRatio: 0.8
property bool autoHide: false property bool autoHide: false
property bool forceOpen: false property bool forceOpen: false
property bool forceClosed: false
property bool disableOpen: false property bool disableOpen: false
property bool rightOpen: false property bool rightOpen: false
property bool hovered: false property bool hovered: false
@ -47,6 +48,7 @@ Item {
sizeRatio: root.sizeRatio sizeRatio: root.sizeRatio
autoHide: root.autoHide autoHide: root.autoHide
forceOpen: root.forceOpen forceOpen: root.forceOpen
forceClosed: root.forceClosed
disableOpen: root.disableOpen disableOpen: root.disableOpen
rightOpen: root.rightOpen rightOpen: root.rightOpen
hovered: root.hovered hovered: root.hovered
@ -72,6 +74,7 @@ Item {
sizeRatio: root.sizeRatio sizeRatio: root.sizeRatio
autoHide: root.autoHide autoHide: root.autoHide
forceOpen: root.forceOpen forceOpen: root.forceOpen
forceClosed: root.forceClosed
disableOpen: root.disableOpen disableOpen: root.disableOpen
rightOpen: root.rightOpen rightOpen: root.rightOpen
hovered: root.hovered hovered: root.hovered

View file

@ -12,6 +12,7 @@ Item {
property real sizeRatio: 0.8 property real sizeRatio: 0.8
property bool autoHide: false property bool autoHide: false
property bool forceOpen: false property bool forceOpen: false
property bool forceClosed: false
property bool disableOpen: false property bool disableOpen: false
property bool rightOpen: false property bool rightOpen: false
property bool hovered: false property bool hovered: false
@ -25,8 +26,8 @@ Item {
readonly property bool openRightward: rightOpen readonly property bool openRightward: rightOpen
readonly property bool openLeftward: !rightOpen readonly property bool openLeftward: !rightOpen
// Effective shown state (true if animated open or forced) // Effective shown state (true if animated open or forced, but not if force closed)
readonly property bool revealed: forceOpen || showPill readonly property bool revealed: !forceClosed && (forceOpen || showPill)
signal shown signal shown
signal hidden signal hidden
@ -80,7 +81,7 @@ Item {
id: textItem id: textItem
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.horizontalCenterOffset: 0 // Center the text properly in the pill anchors.horizontalCenterOffset: -pillPaddingHorizontal * 0.5 // Position text slightly left in the pill
text: root.text text: root.text
font.family: Settings.data.ui.fontFixed font.family: Settings.data.ui.fontFixed
font.pointSize: Style.fontSizeXXS * scaling font.pointSize: Style.fontSizeXXS * scaling
@ -253,7 +254,7 @@ Item {
hovered = true hovered = true
root.entered() root.entered()
tooltip.show() tooltip.show()
if (disableOpen) { if (disableOpen || forceClosed) {
return return
} }
if (!forceOpen) { if (!forceOpen) {
@ -263,7 +264,7 @@ Item {
onExited: { onExited: {
hovered = false hovered = false
root.exited() root.exited()
if (!forceOpen) { if (!forceOpen && !forceClosed) {
hide() hide()
} }
tooltip.hide() tooltip.hide()

View file

@ -12,6 +12,7 @@ Item {
property real sizeRatio: 0.8 property real sizeRatio: 0.8
property bool autoHide: false property bool autoHide: false
property bool forceOpen: false property bool forceOpen: false
property bool forceClosed: false
property bool disableOpen: false property bool disableOpen: false
property bool rightOpen: false property bool rightOpen: false
property bool hovered: false property bool hovered: false
@ -25,8 +26,8 @@ Item {
readonly property bool openDownward: rightOpen readonly property bool openDownward: rightOpen
readonly property bool openUpward: !rightOpen readonly property bool openUpward: !rightOpen
// Effective shown state (true if animated open or forced) // Effective shown state (true if animated open or forced, but not if force closed)
readonly property bool revealed: forceOpen || showPill readonly property bool revealed: !forceClosed && (forceOpen || showPill)
signal shown signal shown
signal hidden signal hidden
@ -48,7 +49,7 @@ Item {
readonly property int pillPaddingVertical: Style.marginS * scaling readonly property int pillPaddingVertical: Style.marginS * scaling
readonly property int pillOverlap: iconSize * 0.5 readonly property int pillOverlap: iconSize * 0.5
readonly property int maxPillWidth: iconSize readonly property int maxPillWidth: iconSize
readonly property int maxPillHeight: Math.max(1, textItem.implicitHeight + pillPaddingVertical * 3) readonly property int maxPillHeight: Math.max(1, textItem.implicitHeight + pillPaddingVertical * 4)
// For vertical bars: width is just icon size, height includes pill space // For vertical bars: width is just icon size, height includes pill space
width: iconSize width: iconSize
@ -76,14 +77,17 @@ Item {
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
NTextVertical { NText {
id: textItem id: textItem
anchors.horizontalCenter: parent.horizontalCenter anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset: 0 // Center the text properly in the pill anchors.verticalCenterOffset: -pillPaddingVertical * 0.5 // Position text slightly higher in the pill
text: root.text text: root.text
fontSize: Style.fontSizeXXS * scaling font.family: Settings.data.ui.fontFixed
fontWeight: Style.fontWeightBold font.pointSize: Style.fontSizeXXS * scaling
font.weight: Style.fontWeightMedium
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
color: Color.mOnSurface color: Color.mOnSurface
visible: revealed visible: revealed
} }
@ -252,7 +256,7 @@ Item {
hovered = true hovered = true
root.entered() root.entered()
tooltip.show() tooltip.show()
if (disableOpen) { if (disableOpen || forceClosed) {
return return
} }
if (!forceOpen) { if (!forceOpen) {
@ -262,7 +266,7 @@ Item {
onExited: { onExited: {
hovered = false hovered = false
root.exited() root.exited()
if (!forceOpen) { if (!forceOpen && !forceClosed) {
hide() hide()
} }
tooltip.hide() tooltip.hide()