Merge branch 'main' into open-panel-overlay-layer

This commit is contained in:
Damian D'Souza
2025-10-20 22:14:18 +02:00
committed by GitHub
43 changed files with 1567 additions and 412 deletions
+51 -3
View File
@@ -35,7 +35,10 @@ Item {
readonly property bool showIcon: (widgetSettings.showIcon !== undefined) ? widgetSettings.showIcon : widgetMetadata.showIcon
readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : widgetMetadata.hideMode
readonly property string scrollingMode: (widgetSettings.scrollingMode !== undefined) ? widgetSettings.scrollingMode : (widgetMetadata.scrollingMode !== undefined ? widgetMetadata.scrollingMode : "hover")
readonly property int widgetWidth: (widgetSettings.width !== undefined) ? widgetSettings.width : Math.max(widgetMetadata.width, screen.width * 0.06)
// Maximum widget width with user settings support
readonly property real maxWidth: (widgetSettings.maxWidth !== undefined) ? widgetSettings.maxWidth : Math.max(widgetMetadata.maxWidth, screen ? screen.width * 0.06 : 0)
readonly property bool useFixedWidth: (widgetSettings.useFixedWidth !== undefined) ? widgetSettings.useFixedWidth : widgetMetadata.useFixedWidth
readonly property bool isVerticalBar: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right")
readonly property bool hasFocusedWindow: CompositorService.getFocusedWindow() !== null
@@ -43,7 +46,7 @@ Item {
readonly property string fallbackIcon: "user-desktop"
implicitHeight: visible ? (isVerticalBar ? calculatedVerticalDimension() : Style.barHeight) : 0
implicitWidth: visible ? (isVerticalBar ? calculatedVerticalDimension() : widgetWidth) : 0
implicitWidth: visible ? (isVerticalBar ? calculatedVerticalDimension() : dynamicWidth) : 0
// "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty
visible: hideMode !== "hidden" || hasFocusedWindow
@@ -59,6 +62,43 @@ Item {
return Math.round((Style.baseWidgetSize - 5) * scaling)
}
function calculateContentWidth() {
// Calculate the actual content width based on visible elements
var contentWidth = 0
var margins = Style.marginS * scaling * 2 // Left and right margins
// Icon width (if visible)
if (showIcon) {
contentWidth += 18 * scaling
contentWidth += Style.marginS * scaling // Spacing after icon
}
// Text width (use the measured width)
contentWidth += fullTitleMetrics.contentWidth
// Additional small margin for text
contentWidth += Style.marginXXS * 2
// Add container margins
contentWidth += margins
return Math.ceil(contentWidth)
}
// Dynamic width: adapt to content but respect maximum width setting
readonly property real dynamicWidth: {
// If using fixed width mode, always use maxWidth
if (useFixedWidth) {
return maxWidth
}
// Otherwise, adapt to content
if (!hasFocusedWindow) {
return maxWidth
}
// Use content width but don't exceed user-set maximum width
return Math.min(calculateContentWidth(), maxWidth)
}
function getAppIcon() {
try {
// Try CompositorService first
@@ -117,11 +157,19 @@ Item {
visible: root.visible
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: isVerticalBar ? root.width : widgetWidth
width: isVerticalBar ? root.width : dynamicWidth
height: isVerticalBar ? width : Style.capsuleHeight
radius: isVerticalBar ? width / 2 : Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
// Smooth width transition
Behavior on width {
NumberAnimation {
duration: Style.animationNormal
easing.type: Easing.InOutCubic
}
}
Item {
id: mainContainer
anchors.fill: parent
+56 -4
View File
@@ -38,8 +38,9 @@ Item {
readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType !== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType
readonly property string scrollingMode: (widgetSettings.scrollingMode !== undefined) ? widgetSettings.scrollingMode : widgetMetadata.scrollingMode
// Fixed width - no expansion
readonly property real widgetWidth: Math.max(145, screen.width * 0.06)
// Maximum widget width with user settings support
readonly property real maxWidth: (widgetSettings.maxWidth !== undefined) ? widgetSettings.maxWidth : Math.max(widgetMetadata.maxWidth, screen ? screen.width * 0.06 : 0)
readonly property bool useFixedWidth: (widgetSettings.useFixedWidth !== undefined) ? widgetSettings.useFixedWidth : widgetMetadata.useFixedWidth
readonly property bool hasActivePlayer: MediaService.currentPlayer !== null
readonly property string placeholderText: I18n.tr("bar.widget-settings.media-mini.no-active-player")
@@ -60,7 +61,7 @@ Item {
}
implicitHeight: visible ? (isVerticalBar ? calculatedVerticalDimension() : Style.barHeight) : 0
implicitWidth: visible ? (isVerticalBar ? calculatedVerticalDimension() : widgetWidth) : 0
implicitWidth: visible ? (isVerticalBar ? calculatedVerticalDimension() : dynamicWidth) : 0
// "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty
visible: hideMode !== "hidden" || hasActivePlayer
@@ -80,6 +81,49 @@ Item {
return Math.round((Style.baseWidgetSize - 5) * scaling)
}
function calculateContentWidth() {
// Calculate the actual content width based on visible elements
var contentWidth = 0
var margins = Style.marginS * scaling * 2 // Left and right margins
// Icon or album art width
if (!hasActivePlayer || !showAlbumArt) {
// Icon width
contentWidth += Style.fontSizeL * scaling
} else if (showAlbumArt && hasActivePlayer) {
// Album art width
contentWidth += 21 * scaling
}
// Spacing between icon/art and text
contentWidth += Style.marginS * scaling
// Text width (use the measured width)
contentWidth += fullTitleMetrics.contentWidth
// Additional small margin for text
contentWidth += Style.marginXXS * 2
// Add container margins
contentWidth += margins
return Math.ceil(contentWidth)
}
// Dynamic width: adapt to content but respect maximum width setting
readonly property real dynamicWidth: {
// If using fixed width mode, always use maxWidth
if (useFixedWidth) {
return maxWidth
}
// Otherwise, adapt to content
if (!hasActivePlayer) {
return maxWidth
}
// Use content width but don't exceed user-set maximum width
return Math.min(calculateContentWidth(), maxWidth)
}
// A hidden text element to safely measure the full title width
NText {
id: fullTitleMetrics
@@ -95,11 +139,19 @@ Item {
visible: root.visible
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
width: isVerticalBar ? root.width : (widgetWidth)
width: isVerticalBar ? root.width : dynamicWidth
height: isVerticalBar ? width : Style.capsuleHeight
radius: isVerticalBar ? width / 2 : Style.radiusM
color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent
// Smooth width transition
Behavior on width {
NumberAnimation {
duration: Style.animationNormal
easing.type: Easing.InOutCubic
}
}
Item {
id: mainContainer
anchors.fill: parent
+2 -14
View File
@@ -63,7 +63,7 @@ Variants {
readonly property int hideAnimationDuration: Style.animationFast
readonly property int showAnimationDuration: Style.animationFast
readonly property int peekHeight: 1
readonly property int iconSize: 36
readonly property int iconSize: Math.round(12 + 24 * (Settings.data.dock.size ?? 1))
readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL
// Bar detection and positioning properties
@@ -199,15 +199,9 @@ Variants {
color: Color.transparent
WlrLayershell.namespace: "noctalia-dock-peek"
WlrLayershell.exclusionMode: ExclusionMode.Auto // Always exclusive
WlrLayershell.exclusionMode: ExclusionMode.Ignore
implicitHeight: peekHeight
Rectangle {
anchors.fill: parent
color: barAtBottom ? Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity) : Color.transparent
}
MouseArea {
id: peekArea
anchors.fill: parent
@@ -261,12 +255,6 @@ Variants {
}
}
// Rectangle {
// anchors.fill: parent
// color: "#000FF0"
// z: -1
// }
// Wrapper item for scale/opacity animations
Item {
id: dockContainerWrapper
+68 -67
View File
@@ -13,8 +13,8 @@ import qs.Widgets
NPanel {
id: root
preferredWidth: 320 * Style.uiScaleRatio
preferredHeight: 360 * Style.uiScaleRatio
preferredWidth: 400 * Style.uiScaleRatio
preferredHeight: 340 * Style.uiScaleRatio
panelAnchorHorizontalCenter: true
panelAnchorVerticalCenter: true
panelKeyboardFocus: true
@@ -31,10 +31,6 @@ NPanel {
"action": "lock",
"icon": "lock",
"title": I18n.tr("session-menu.lock")
}, {
"action": "lockAndSuspend",
"icon": "lock-pause",
"title": I18n.tr("session-menu.lock-and-suspend")
}, {
"action": "suspend",
"icon": "suspend",
@@ -96,11 +92,13 @@ NPanel {
lockScreen.active = true
}
break
case "lockAndSuspend":
CompositorService.lockAndSuspend()
break
case "suspend":
CompositorService.suspend()
// Check if we should lock before suspending
if (Settings.data.general.lockOnSuspend) {
CompositorService.lockAndSuspend()
} else {
CompositorService.suspend()
}
break
case "reboot":
CompositorService.reboot()
@@ -263,74 +261,77 @@ NPanel {
root.activate()
}
ColumnLayout {
NBox {
anchors.fill: parent
anchors.topMargin: Style.marginM
anchors.leftMargin: Style.marginM
anchors.rightMargin: Style.marginM
anchors.bottomMargin: Style.marginS
spacing: Style.marginXS
anchors.margins: Style.marginL
// Header with title and close button
RowLayout {
Layout.fillWidth: true
Layout.preferredHeight: Style.baseWidgetSize * 0.6
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginL
spacing: Style.marginL
NText {
text: timerActive ? I18n.tr("session-menu.action-in-seconds", {
"action": pendingAction.charAt(0).toUpperCase() + pendingAction.slice(1),
"seconds": Math.ceil(timeRemaining / 1000)
}) : I18n.tr("session-menu.title")
font.weight: Style.fontWeightBold
pointSize: Style.fontSizeM
color: timerActive ? Color.mPrimary : Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
verticalAlignment: Text.AlignVCenter
}
Item {
// Header with title and close button
RowLayout {
Layout.fillWidth: true
}
Layout.preferredHeight: Style.baseWidgetSize * 0.6
NIconButton {
icon: timerActive ? "stop" : "close"
tooltipText: timerActive ? I18n.tr("tooltips.cancel-timer") : I18n.tr("tooltips.close")
Layout.alignment: Qt.AlignVCenter
colorBg: timerActive ? Qt.alpha(Color.mError, 0.08) : Color.transparent
colorFg: timerActive ? Color.mError : Color.mOnSurface
onClicked: {
if (timerActive) {
cancelTimer()
} else {
cancelTimer()
root.close()
NText {
text: timerActive ? I18n.tr("session-menu.action-in-seconds", {
"action": pendingAction.charAt(0).toUpperCase() + pendingAction.slice(1),
"seconds": Math.ceil(timeRemaining / 1000)
}) : I18n.tr("session-menu.title")
font.weight: Style.fontWeightBold
pointSize: Style.fontSizeM
color: timerActive ? Color.mPrimary : Color.mOnSurface
Layout.alignment: Qt.AlignVCenter
verticalAlignment: Text.AlignVCenter
}
Item {
Layout.fillWidth: true
}
NIconButton {
icon: timerActive ? "stop" : "close"
tooltipText: timerActive ? I18n.tr("tooltips.cancel-timer") : I18n.tr("tooltips.close")
Layout.alignment: Qt.AlignVCenter
baseSize: Style.baseWidgetSize * 0.7
colorBg: timerActive ? Qt.alpha(Color.mError, 0.08) : Color.transparent
colorFg: timerActive ? Color.mError : Color.mOnSurface
onClicked: {
if (timerActive) {
cancelTimer()
} else {
cancelTimer()
root.close()
}
}
}
}
}
NDivider {
Layout.fillWidth: true
}
NDivider {
Layout.fillWidth: true
}
// Power options
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginS
// Power options
ColumnLayout {
Layout.fillWidth: true
spacing: Style.marginS
Repeater {
model: powerOptions
delegate: PowerButton {
Layout.fillWidth: true
icon: modelData.icon
title: modelData.title
isShutdown: modelData.isShutdown || false
isSelected: index === selectedIndex
onClicked: {
selectedIndex = index
startTimer(modelData.action)
Repeater {
model: powerOptions
delegate: PowerButton {
Layout.fillWidth: true
icon: modelData.icon
title: modelData.title
isShutdown: modelData.isShutdown || false
isSelected: index === selectedIndex
onClicked: {
selectedIndex = index
startTimer(modelData.action)
}
pending: timerActive && pendingAction === modelData.action
}
pending: timerActive && pendingAction === modelData.action
}
}
}
@@ -349,7 +350,7 @@ NPanel {
signal clicked
height: Style.baseWidgetSize * 1.2 * Style.uiScaleRatio
height: Style.baseWidgetSize * 1.3 * Style.uiScaleRatio
radius: Style.radiusS
color: {
if (pending) {
@@ -17,7 +17,8 @@ ColumnLayout {
property bool valueShowIcon: widgetData.showIcon !== undefined ? widgetData.showIcon : widgetMetadata.showIcon
property string valueHideMode: "hidden" // Default to 'Hide When Empty'
property string valueScrollingMode: widgetData.scrollingMode || widgetMetadata.scrollingMode
property int valueWidth: widgetData.width !== undefined ? widgetData.width : widgetMetadata.width
property int valueMaxWidth: widgetData.maxWidth !== undefined ? widgetData.maxWidth : widgetMetadata.maxWidth
property bool valueUseFixedWidth: widgetData.useFixedWidth !== undefined ? widgetData.useFixedWidth : widgetMetadata.useFixedWidth
property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons
Component.onCompleted: {
@@ -31,7 +32,8 @@ ColumnLayout {
settings.hideMode = valueHideMode
settings.showIcon = valueShowIcon
settings.scrollingMode = valueScrollingMode
settings.width = parseInt(widthInput.text) || widgetMetadata.width
settings.maxWidth = parseInt(widthInput.text) || widgetMetadata.maxWidth
settings.useFixedWidth = valueUseFixedWidth
settings.colorizeIcons = valueColorizeIcons
return settings
}
@@ -73,10 +75,18 @@ ColumnLayout {
NTextInput {
id: widthInput
Layout.fillWidth: true
label: I18n.tr("bar.widget-settings.active-window.width.label")
description: I18n.tr("bar.widget-settings.active-window.width.description")
placeholderText: widgetMetadata.width
text: valueWidth
label: I18n.tr("bar.widget-settings.active-window.max-width.label")
description: I18n.tr("bar.widget-settings.active-window.max-width.description")
placeholderText: widgetMetadata.maxWidth
text: valueMaxWidth
}
NToggle {
Layout.fillWidth: true
label: I18n.tr("bar.widget-settings.active-window.use-fixed-width.label")
description: I18n.tr("bar.widget-settings.active-window.use-fixed-width.description")
checked: valueUseFixedWidth
onToggled: checked => valueUseFixedWidth = checked
}
NComboBox {
@@ -19,6 +19,8 @@ ColumnLayout {
property bool valueShowVisualizer: widgetData.showVisualizer !== undefined ? widgetData.showVisualizer : widgetMetadata.showVisualizer
property string valueVisualizerType: widgetData.visualizerType || widgetMetadata.visualizerType
property string valueScrollingMode: widgetData.scrollingMode || widgetMetadata.scrollingMode
property int valueMaxWidth: widgetData.maxWidth !== undefined ? widgetData.maxWidth : widgetMetadata.maxWidth
property bool valueUseFixedWidth: widgetData.useFixedWidth !== undefined ? widgetData.useFixedWidth : widgetMetadata.useFixedWidth
Component.onCompleted: {
if (widgetData && widgetData.hideMode !== undefined) {
@@ -33,6 +35,8 @@ ColumnLayout {
settings.showVisualizer = valueShowVisualizer
settings.visualizerType = valueVisualizerType
settings.scrollingMode = valueScrollingMode
settings.maxWidth = parseInt(widthInput.text) || widgetMetadata.maxWidth
settings.useFixedWidth = valueUseFixedWidth
return settings
}
@@ -87,6 +91,22 @@ ColumnLayout {
minimumWidth: 200
}
NTextInput {
id: widthInput
Layout.fillWidth: true
label: I18n.tr("bar.widget-settings.media-mini.max-width.label")
description: I18n.tr("bar.widget-settings.media-mini.max-width.description")
placeholderText: widgetMetadata.maxWidth
text: valueMaxWidth
}
NToggle {
label: I18n.tr("bar.widget-settings.media-mini.use-fixed-width.label")
description: I18n.tr("bar.widget-settings.media-mini.use-fixed-width.description")
checked: valueUseFixedWidth
onToggled: checked => valueUseFixedWidth = checked
}
NComboBox {
label: I18n.tr("bar.widget-settings.media-mini.scrolling-mode.label")
description: I18n.tr("bar.widget-settings.media-mini.scrolling-mode.description")
+11
View File
@@ -26,6 +26,7 @@ NPanel {
Audio,
Bar,
ColorScheme,
LockScreen,
ControlCenter,
OSD,
Display,
@@ -118,6 +119,11 @@ NPanel {
id: userInterfaceTab
UserInterfaceTab {}
}
Component {
id: lockScreenTab
LockScreenTab {}
}
// Order *DOES* matter
function updateTabsModel() {
let newTabs = [{
@@ -150,6 +156,11 @@ NPanel {
"label": "settings.launcher.title",
"icon": "settings-launcher",
"source": launcherTab
}, {
"id": SettingsPanel.Tab.LockScreen,
"label": "settings.lock-screen.title",
"icon": "settings-lock-screen",
"source": lockScreenTab
}, {
"id": SettingsPanel.Tab.Audio,
"label": "settings.audio.title",
+112 -3
View File
@@ -13,6 +13,24 @@ ColumnLayout {
property var schemeColorsCache: ({})
property int cacheVersion: 0 // Increment to trigger UI updates
// Time dropdown options (00:00 .. 23:30)
ListModel {
id: timeOptions
}
Component.onCompleted: {
for (var h = 0; h < 24; h++) {
for (var m = 0; m < 60; m += 30) {
var hh = ("0" + h).slice(-2)
var mm = ("0" + m).slice(-2)
var key = hh + ":" + mm
timeOptions.append({
"key": key,
"name": key
})
}
}
}
spacing: Style.marginL
// Helper function to extract scheme name from path
@@ -138,20 +156,91 @@ ColumnLayout {
// Dark Mode Toggle
NToggle {
label: I18n.tr("settings.color-scheme.color-source.dark-mode.label")
description: I18n.tr("settings.color-scheme.color-source.dark-mode.description")
label: I18n.tr("settings.color-scheme.dark-mode.switch.label")
description: I18n.tr("settings.color-scheme.dark-mode.switch.description")
checked: Settings.data.colorSchemes.darkMode
enabled: true
onToggled: checked => {
Settings.data.colorSchemes.darkMode = checked
root.cacheVersion++ // Force UI update for dark/light variants
}
}
NComboBox {
label: I18n.tr("settings.color-scheme.dark-mode.mode.label")
description: I18n.tr("settings.color-scheme.dark-mode.mode.description")
model: [{
"name": I18n.tr("settings.color-scheme.dark-mode.mode.off"),
"key": "off"
}, {
"name": I18n.tr("settings.color-scheme.dark-mode.mode.manual"),
"key": "manual"
}, {
"name": I18n.tr("settings.color-scheme.dark-mode.mode.location"),
"key": "location"
}]
currentKey: Settings.data.colorSchemes.schedulingMode
onSelected: key => {
Settings.data.colorSchemes.schedulingMode = key
AppThemeService.generate()
}
}
// Manual scheduling
ColumnLayout {
spacing: Style.marginS
visible: Settings.data.colorSchemes.schedulingMode === "manual"
NLabel {
label: I18n.tr("settings.display.night-light.manual-schedule.label")
description: I18n.tr("settings.display.night-light.manual-schedule.description")
}
RowLayout {
Layout.fillWidth: false
spacing: Style.marginS
NText {
text: I18n.tr("settings.display.night-light.manual-schedule.sunrise")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
}
NComboBox {
model: timeOptions
currentKey: Settings.data.colorSchemes.manualSunrise
placeholder: I18n.tr("settings.display.night-light.manual-schedule.select-start")
onSelected: key => Settings.data.colorSchemes.manualSunrise = key
minimumWidth: 120
}
Item {
Layout.preferredWidth: 20
}
NText {
text: I18n.tr("settings.display.night-light.manual-schedule.sunset")
pointSize: Style.fontSizeM
color: Color.mOnSurfaceVariant
}
NComboBox {
model: timeOptions
currentKey: Settings.data.colorSchemes.manualSunset
placeholder: I18n.tr("settings.display.night-light.manual-schedule.select-stop")
onSelected: key => Settings.data.colorSchemes.manualSunset = key
minimumWidth: 120
}
}
}
// Use Wallpaper Colors
NToggle {
label: I18n.tr("settings.color-scheme.color-source.use-wallpaper-colors.label")
description: I18n.tr("settings.color-scheme.color-source.use-wallpaper-colors.description")
enabled: ProgramCheckerService.matugenAvailable
checked: Settings.data.colorSchemes.useWallpaperColors
onToggled: checked => {
if (checked) {
@@ -575,6 +664,23 @@ ColumnLayout {
}
}
}
NCheckbox {
label: "Vicinae"
description: ProgramCheckerService.vicinaeAvailable ? I18n.tr("settings.color-scheme.templates.programs.vicinae.description", {
"filepath": "~/.local/share/vicinae/themes/matugen.toml"
}) : I18n.tr("settings.color-scheme.templates.programs.vicinae.description-missing", {
"app": "vicinae"
})
checked: Settings.data.templates.vicinae
enabled: ProgramCheckerService.vicinaeAvailable
opacity: ProgramCheckerService.vicinaeAvailable ? 1.0 : 0.6
onToggled: checked => {
if (ProgramCheckerService.vicinaeAvailable) {
Settings.data.templates.vicinae = checked
AppThemeService.generate()
}
}
}
}
// Miscellaneous
@@ -590,6 +696,9 @@ ColumnLayout {
checked: Settings.data.templates.enableUserTemplates
onToggled: checked => {
Settings.data.templates.enableUserTemplates = checked
if (checked) {
MatugenTemplates.writeUserTemplatesToml()
}
AppThemeService.generate()
}
}
+18
View File
@@ -87,6 +87,24 @@ ColumnLayout {
}
}
ColumnLayout {
spacing: Style.marginXXS
Layout.fillWidth: true
NLabel {
label: I18n.tr("settings.dock.appearance.icon-size.label")
description: I18n.tr("settings.dock.appearance.icon-size.description")
}
NValueSlider {
Layout.fillWidth: true
from: 0
to: 2
stepSize: 0.01
value: Settings.data.dock.size
onMoved: value => Settings.data.dock.size = value
text: Math.floor(Settings.data.dock.size * 100) + "%"
}
}
NToggle {
label: I18n.tr("settings.dock.monitors.only-same-output.label")
description: I18n.tr("settings.dock.monitors.only-same-output.description")
+50
View File
@@ -189,4 +189,54 @@ ColumnLayout {
Layout.topMargin: Style.marginXL
Layout.bottomMargin: Style.marginXL
}
// Language selection
ColumnLayout {
spacing: Style.marginL
Layout.fillWidth: true
NHeader {
label: I18n.tr("settings.general.language.section.label")
description: I18n.tr("settings.general.language.section.description")
}
NComboBox {
Layout.fillWidth: true
label: I18n.tr("settings.general.language.select.label")
description: I18n.tr("settings.general.language.select.description")
model: [{
"key": "",
"name": I18n.tr("settings.general.language.select.auto-detect") + " (" + I18n.systemDetectedLangCode + ")"
}].concat(I18n.availableLanguages.map(function (langCode) {
return {
"key": langCode,
"name": langCode
}
}))
currentKey: Settings.data.general.language
onSelected: key => {
Settings.data.general.language = key
if (key === "") {
I18n.detectLanguage() // Re-detect system language if "Automatic" is selected
} else {
I18n.setLanguage(key) // Set specific language
}
}
}
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL
Layout.bottomMargin: Style.marginXL
}
NButton {
visible: !DistroService.isNixOS
text: I18n.tr("settings.general.launch-setup-wizard")
onClicked: {
setupWizardLoader.active = false
setupWizardLoader.active = true
}
}
}
+31
View File
@@ -0,0 +1,31 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
ColumnLayout {
id: root
NToggle {
label: I18n.tr("settings.lock-screen.lock-on-suspend.label")
description: I18n.tr("settings.lock-screen.lock-on-suspend.description")
checked: Settings.data.general.lockOnSuspend
onToggled: Settings.data.general.lockOnSuspend = checked
}
NToggle {
label: I18n.tr("settings.lock-screen.compact-lockscreen.label")
description: I18n.tr("settings.lock-screen.compact-lockscreen.description")
checked: Settings.data.general.compactLockScreen
onToggled: checked => Settings.data.general.compactLockScreen = checked
}
NDivider {
Layout.fillWidth: true
Layout.topMargin: Style.marginXL
Layout.bottomMargin: Style.marginXL
}
}
@@ -33,13 +33,6 @@ ColumnLayout {
onToggled: checked => Settings.data.ui.tooltipsEnabled = checked
}
NToggle {
label: I18n.tr("settings.user-interface.compact-lockscreen.label")
description: I18n.tr("settings.user-interface.compact-lockscreen.description")
checked: Settings.data.general.compactLockScreen
onToggled: checked => Settings.data.general.compactLockScreen = checked
}
NToggle {
label: I18n.tr("settings.user-interface.panels-overlay.label")
description: I18n.tr("settings.user-interface.panels-overlay.description")
+3 -32
View File
@@ -124,14 +124,14 @@ ColumnLayout {
spacing: 2
NText {
text: I18n.tr("settings.color-scheme.color-source.dark-mode.label")
text: I18n.tr("settings.color-scheme.dark-mode.switch.label")
pointSize: Style.fontSizeL
font.weight: Style.fontWeightBold
color: Color.mOnSurface
}
NText {
text: I18n.tr("settings.color-scheme.color-source.dark-mode.description")
text: I18n.tr("settings.color-scheme.dark-mode.switch.description")
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
@@ -167,7 +167,7 @@ ColumnLayout {
color: Color.mSurface
NIcon {
icon: "color-picker"
icon: ProgramCheckerService.matugenAvailable ? "color-picker" : "alert-triangle"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
@@ -196,7 +196,6 @@ ColumnLayout {
NToggle {
enabled: ProgramCheckerService.matugenAvailable
opacity: ProgramCheckerService.matugenAvailable ? 1.0 : 0.6
checked: Settings.data.colorSchemes.useWallpaperColors && ProgramCheckerService.matugenAvailable
onToggled: checked => {
if (!ProgramCheckerService.matugenAvailable)
@@ -214,34 +213,6 @@ ColumnLayout {
}
}
// Matugen not available notice
RowLayout {
Layout.fillWidth: true
spacing: Style.marginS
visible: !ProgramCheckerService.matugenAvailable
Rectangle {
width: 28
height: 28
radius: Style.radiusM
color: Color.mSurface
NIcon {
icon: "alert-triangle"
pointSize: Style.fontSizeL
color: Color.mPrimary
anchors.centerIn: parent
}
}
NText {
text: I18n.tr("settings.color-scheme.color-source.use-wallpaper-colors.description")
// Reuse description; availability is visually indicated
pointSize: Style.fontSizeS
color: Color.mOnSurfaceVariant
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
}
// Matugen scheme type (visible when wallpaper colors enabled and matugen available)
ColumnLayout {
Layout.fillWidth: true
+27 -2
View File
@@ -321,11 +321,36 @@ PopupWindow {
completeHide()
}
// Update text function for binding support
// Update text function
function updateText(newText) {
if (visible && targetItem) {
text = newText
positionAndShow()
// Recalculate dimensions
const tipWidth = Math.min(tooltipText.implicitWidth + (padding * 2), maxWidth)
root.implicitWidth = tipWidth
const tipHeight = tooltipText.implicitHeight + (padding * 2)
root.implicitHeight = tipHeight
// Reposition if necessary
var targetGlobal = targetItem.mapToItem(null, 0, 0)
const targetWidth = targetItem.width
// Adjust horizontal position to keep tooltip on screen if needed
const globalX = targetGlobal.x + anchorX
if (globalX < 0) {
anchorX = -targetGlobal.x + margin
} else if (globalX + tipWidth > screenWidth) {
anchorX = screenWidth - targetGlobal.x - tipWidth - margin
}
// Force anchor update
Qt.callLater(() => {
if (root.anchor && root.visible) {
root.anchor.updateAnchor()
}
})
}
}