mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Merge branch 'main' into fix/NScrollText
This commit is contained in:
@@ -153,68 +153,46 @@ body {
|
||||
--purple-5: hsl(267deg, 83%, 70%);
|
||||
}
|
||||
|
||||
.divider__908e2:not(.isUnread__908e2) {
|
||||
border-color: var(--bg-2);
|
||||
/* Dividers (Channel list and messages) */
|
||||
[class*="divider"]:not([class*="isUnread"]) {
|
||||
border-color: var(--bg-2) !important;
|
||||
}
|
||||
|
||||
.bannerButton_de8008, .bannerColor_fb7f94 {
|
||||
color: var(--text-1);
|
||||
/* Profile Banners */
|
||||
[class*="bannerButton"],
|
||||
[class*="bannerColor"] {
|
||||
color: var(--text-1) !important;
|
||||
}
|
||||
|
||||
/* Prevent scaling animation on DMS icon */
|
||||
.wrapper__6e9f8[data-list-item-id='guildsnav___home']:hover > .childWrapper__6e9f8::before,
|
||||
.wrapper__6e9f8[data-list-item-id='guildsnav___home'].selected__6e9f8 > .childWrapper__6e9f8::before {
|
||||
/* Prevent scaling animation on Home/DMS icon */
|
||||
[class*="guildsnav"] [class*="wrapper"][data-list-item-id='guildsnav___home']:hover > [class*="childWrapper"]::before,
|
||||
[class*="guildsnav"] [class*="wrapper"][data-list-item-id='guildsnav___home'][class*="selected"] > [class*="childWrapper"]::before {
|
||||
transform: rotate(-360deg) scale(1) !important;
|
||||
}
|
||||
|
||||
/* Make timestamps use lighter text color */
|
||||
.timestamp_c19a55,
|
||||
.timestampInline_c19a55,
|
||||
.timestamp_c19a55 time,
|
||||
.timestampInline_c19a55 time {
|
||||
color: var(--text-4) !important;
|
||||
}
|
||||
|
||||
/* Make timestamps more readable by overriding inline styles */
|
||||
/* Timestamps */
|
||||
[class*="timestamp"],
|
||||
[class*="timestampInline"],
|
||||
[class*="timestamp"] time {
|
||||
color: var(--text-4) !important;
|
||||
}
|
||||
|
||||
.postTitleText_faa96b {
|
||||
/* Forum/Thread Titles */
|
||||
[class*="postTitleText"],
|
||||
[class*="postTitleText"] [class*="highlight"] {
|
||||
color: var(--text-2) !important;
|
||||
}
|
||||
|
||||
.postTitleText_faa96b .highlight {
|
||||
color: var(--text-2) !important;
|
||||
}
|
||||
|
||||
/* Make thread titles more readable by overriding inline styles */
|
||||
[class*="headerText"] [class*="postTitleText"],
|
||||
[class*="headerText"] h3[class*="postTitleText"] {
|
||||
color: var(--text-2) !important;
|
||||
}
|
||||
|
||||
.messageContent_c19a55,
|
||||
.messageContent_faa96b {
|
||||
color: var(--text-3) !important;
|
||||
}
|
||||
|
||||
.messageContent_c19a55 .highlight,
|
||||
.messageContent_faa96b .highlight {
|
||||
color: var(--text-2) !important;
|
||||
}
|
||||
|
||||
/* Make message content more readable by overriding inline styles */
|
||||
/* Message Content */
|
||||
[class*="messageContent"] {
|
||||
color: var(--text-3) !important;
|
||||
}
|
||||
|
||||
[class*="messageContent"] .highlight {
|
||||
[class*="messageContent"] [class*="highlight"] {
|
||||
color: var(--text-2) !important;
|
||||
}
|
||||
|
||||
/* Make slowmode/cooldown text more readable by overriding inline styles */
|
||||
/* Slowmode/Cooldown Text */
|
||||
[class*="cooldownText"] {
|
||||
color: var(--text-4) !important;
|
||||
}
|
||||
@@ -279,8 +257,8 @@ body {
|
||||
[class*="radioSelection"][data-selected="true"] [class*="innerDotRadio"],
|
||||
[class*="radioSelection"][aria-checked="true"] [class*="outerRadioFill"],
|
||||
[class*="radioSelection"][aria-checked="true"] [class*="innerDotRadio"],
|
||||
.parentSelected__6e9f8 [class*="outerRadioFill"],
|
||||
.parentSelected__6e9f8 [class*="innerDotRadio"] {
|
||||
[class*="parentSelected"] [class*="outerRadioFill"],
|
||||
[class*="parentSelected"] [class*="innerDotRadio"] {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
@@ -311,35 +289,36 @@ body {
|
||||
border-color: var(--accent-1) /* keep background consistent on hover */
|
||||
}
|
||||
|
||||
._714a9a7abaf0392a-checkboxOption[data-selected="true"]:hover ._714a9a7abaf0392a-checkStroke,
|
||||
._714a9a7abaf0392a-checkboxOption[data-selected="true"]:hover ._714a9a7abaf0392a-dot {
|
||||
color: var(--accent-1) !important; /* keep checkmark accent color on hover */
|
||||
}
|
||||
|
||||
/* Fix hover color for channel mentions */
|
||||
.channelMention:hover {
|
||||
color: var(--text-1) !important;
|
||||
}
|
||||
|
||||
[class*="unreadTop"],
|
||||
[class*="unreadBottom"],
|
||||
[class*="unreadMentionsIndicator"] {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
[class*="unreadBar"],
|
||||
[class*="unreadMentionsBar"] {
|
||||
background-color: var(--accent-1) !important;
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
|
||||
[class*="unreadBar"][class*="mention"],
|
||||
[class*="unreadMentionsBar"][class*="mention"] {
|
||||
background-color: var(--accent-1) !important;
|
||||
}
|
||||
|
||||
[class*="unreadBar"][class*="unread"],
|
||||
[class*="unreadMentionsBar"][class*="unread"] {
|
||||
background-color: var(--bg-1) !important;
|
||||
border-color: var(--accent-1) !important;
|
||||
}
|
||||
|
||||
[class*="unreadBar"] [class*="text"],
|
||||
[class*="unreadMentionsBar"] [class*="text"] {
|
||||
color: var(--text-0) !important;
|
||||
color: var(--text-1) !important;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
[class*="unreadMentionsIndicator"] [class*="bar"] {
|
||||
background-color: var(--accent-1) !important;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
;;; noctalia-theme.el --- Theme using Template SCSS variables
|
||||
;;; noctalia-theme.el --- Theme using Template SCSS variables -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2025
|
||||
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Benachrichtigungssymbol ausblenden, wenn keine ungelesenen Benachrichtigungen vorhanden sind.",
|
||||
"hide-widget-when-zero-unread-label": "Symbol bei keinen ungelesenen Benachrichtigungen ausblenden",
|
||||
"show-unread-badge-description": "Badge mit der Anzahl ungelesener Benachrichtigungen anzeigen.",
|
||||
"show-unread-badge-label": "Badge für ungelesene Nachrichten anzeigen"
|
||||
"show-unread-badge-label": "Badge für ungelesene Nachrichten anzeigen",
|
||||
"unread-badge-color-description": "Wähle die Farbe für das Abzeichen ungelesener Benachrichtigungen.",
|
||||
"unread-badge-color-label": "Farbe des ungelesenen Abzeichens"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Widget auswählen...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Anzahl der Zeichen, die von Arbeitsbereichsnamen angezeigt werden (1-10).",
|
||||
"character-count-label": "Zeichenanzahl",
|
||||
"empty-color-description": "Lege die Hintergrundfarbe für leere Workspaces fest.",
|
||||
"empty-color-label": "Farbe für leere Workspace",
|
||||
"enable-scrollwheel-description": "Zwischen Arbeitsbereichen mit dem Mausrad wechseln.",
|
||||
"enable-scrollwheel-label": "Zum Wechseln der Arbeitsbereiche scrollen",
|
||||
"focused-color-description": "Lege die Hintergrundfarbe für den fokussierten Workspace fest.",
|
||||
"focused-color-label": "Farbe des fokussierten Workspace",
|
||||
"follow-focused-screen-description": "Zeige Arbeitsbereiche vom aktuell fokussierten Bildschirm an, statt vom Bildschirm, auf dem sich die Leiste befindet.",
|
||||
"follow-focused-screen-label": "Fokussiertem Bildschirm folgen",
|
||||
"grouped-border-opacity-description": "Legen Sie die Deckkraft für Workspace-Container-Rahmen fest.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Unbesetzte ausblenden",
|
||||
"label-mode-description": "Wählen Sie, wie Arbeitsbereichs-Beschriftungen angezeigt werden.",
|
||||
"label-mode-label": "Beschriftungsmodus",
|
||||
"occupied-color-description": "Lege die Hintergrundfarbe für belegte Workspaces fest.",
|
||||
"occupied-color-label": "Farbe für belegte Arbeitsfläche",
|
||||
"reverse-scrolling-description": "Die Richtung des Arbeitsbereichswechsels beim Scrollen umkehren.",
|
||||
"reverse-scrolling-label": "Scrollen umkehren",
|
||||
"show-applications-description": "Anwendungssymbole in jedem Arbeitsbereich anzeigen.",
|
||||
"show-applications-label": "Anwendungen anzeigen",
|
||||
"show-badge-description": "Zeige die Arbeitsbereichsnummern-Plakette im gruppierten Modus an.",
|
||||
"show-badge-label": "Workspace-Badge anzeigen",
|
||||
"show-labels-only-when-occupied-description": "Arbeitsbereichsbezeichnungen nur anzeigen, wenn sie Fenster enthalten.",
|
||||
"show-labels-only-when-occupied-label": "Beschriftungen nur anzeigen, wenn belegt",
|
||||
"unfocused-icons-opacity-description": "Transparenzgrad für nicht fokussierte App-Symbole festlegen.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Nicht gefunden",
|
||||
"notifications": "Benachrichtigungen",
|
||||
"official": "Offiziell",
|
||||
"on-surface": "Auf Oberfläche",
|
||||
"output": "Ausgabe",
|
||||
"pair": "Koppeln",
|
||||
"paired": "Gekoppelt",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Abfrageintervall",
|
||||
"position": "Position",
|
||||
"previous": "Zurück",
|
||||
"primary": "Primär",
|
||||
"random": "Zufällig",
|
||||
"reboot": "Neu starten",
|
||||
"refresh": "Aktualisieren",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Scannen...",
|
||||
"screen-corners": "Bildschirmecken",
|
||||
"search": "Suche",
|
||||
"secondary": "Sekundär",
|
||||
"security": "Sicherheit",
|
||||
"select": "Auswählen",
|
||||
"shortcuts": "Kurzbefehle",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Stopp",
|
||||
"suspend": "Energie sparen",
|
||||
"templates": "Vorlagen",
|
||||
"tertiary": "Tertiär",
|
||||
"test": "Test",
|
||||
"thresholds": "Schwellenwerte",
|
||||
"title": "Titel",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Kompakt",
|
||||
"density-default": "Standard",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Geräumig"
|
||||
"density-spacious": "Geräumig",
|
||||
"type-floating": "Schwebend",
|
||||
"type-framed": "Gerahmt",
|
||||
"type-simple": "Einfach"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klassisch",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Erscheinungsbild und Position der Statusleiste anpassen.",
|
||||
"appearance-floating-description": "Statusleiste als schwebende 'Pille' anzeigen.",
|
||||
"appearance-floating-label": "Schwebende Statusleiste",
|
||||
"appearance-frame-radius": "Innenradius",
|
||||
"appearance-frame-settings-description": "Rahmenstärke und inneren Eckenradius anpassen",
|
||||
"appearance-frame-settings-label": "Rahmeneinstellungen",
|
||||
"appearance-frame-thickness": "Stärke",
|
||||
"appearance-hide-on-overview-description": "Die Leiste ausblenden und Panels schließen, wenn die Compositor-Übersicht aktiv ist.",
|
||||
"appearance-hide-on-overview-label": "Leiste in der Übersicht ausblenden",
|
||||
"appearance-margins-description": "Ränder um die schwebende Statusleiste anpassen.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Kapsel anzeigen",
|
||||
"appearance-show-outline-description": "Zeige eine sichtbare Umrandung um jedes Widget an.",
|
||||
"appearance-show-outline-label": "Widget-Umrisse anzeigen",
|
||||
"appearance-type-description": "Wähle den Stil der Leiste: Einfach, Schwebend oder Gerahmt",
|
||||
"appearance-type-label": "Leistentyp",
|
||||
"appearance-use-separate-opacity-description": "Ermöglicht die Verwendung eines separaten Deckkraftwerts für den Leistenhintergrund.",
|
||||
"appearance-use-separate-opacity-label": "Separate Leisten-Deckkraft",
|
||||
"monitor-configure-widgets": "Widgets konfigurieren",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Zwischenablage-Text umbrechen",
|
||||
"settings-clipboard-history-description": "Zugriff auf zuvor kopierte Elemente über den Launcher.",
|
||||
"settings-clipboard-history-label": "Zwischenablageverlauf aktivieren",
|
||||
"settings-clipboard-watch-image-description": "Vollständige Befehlszeichenfolge, die an wl-paste für Bildänderungen übergeben wird. (Neustart erforderlich)",
|
||||
"settings-clipboard-watch-image-label": "Bildüberwachungsbefehl",
|
||||
"settings-clipboard-watch-text-description": "Vollständiger Befehlsstring, der an wl-paste für Textänderungen übergeben wird. (Neustart erforderlich)",
|
||||
"settings-clipboard-watch-text-label": "Textüberwachungsbefehl",
|
||||
"settings-custom-launch-prefix-description": "Befehle mit einem benutzerdefinierten Launcher präfixieren (z.B. 'runapp' für systemd-Integration).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Verwenden Sie ein benutzerdefiniertes Präfix zum Starten von Anwendungen anstelle der Standardmethode.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Benutzerdefiniertes Start-Präfix aktivieren",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Wetter im Kalender anzeigen"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Wenn fprintd (Fingerabdruck-Authentifizierung) aktiv ist, können Sie mit dieser Option weiterhin Ihr Passwort anstelle eines Fingerabdrucks verwenden.",
|
||||
"allow-password-with-fprintd-label": "Passwort-Anmeldung mit fprintd erlauben",
|
||||
"auto-start-auth-description": "z. B. startet die Fingerabdruckauthentifizierung automatisch, ohne dass ein Tastendruck oder ein Klick erforderlich ist.",
|
||||
"auto-start-auth-label": "Automatische Authentifizierung beim Start",
|
||||
"compact-lockscreen-description": "Zeige nur die Login-Eingabe und Systemsteuerung, blende Wetter- und Medien-Widgets aus.",
|
||||
"compact-lockscreen-label": "Kompakter Sperrbildschirm",
|
||||
"lock-on-suspend-description": "Den Bildschirm beim Energiesparen automatisch sperren.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Hide the notification icon when there are no unread notifications.",
|
||||
"hide-widget-when-zero-unread-label": "Hide icon when no unread notifications",
|
||||
"show-unread-badge-description": "Display a badge showing the number of unread notifications.",
|
||||
"show-unread-badge-label": "Show unread badge"
|
||||
"show-unread-badge-label": "Show unread badge",
|
||||
"unread-badge-color-description": "Select the color for the unread notification badge.",
|
||||
"unread-badge-color-label": "Unread badge color"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Select a widget to add...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Number of characters to display from workspace names (1-10).",
|
||||
"character-count-label": "Character count",
|
||||
"empty-color-description": "Set the background color for empty workspaces.",
|
||||
"empty-color-label": "Empty workspace color",
|
||||
"enable-scrollwheel-description": "Switch between workspaces using the mouse scroll wheel.",
|
||||
"enable-scrollwheel-label": "Scroll to switch workspaces",
|
||||
"focused-color-description": "Set the background color for the focused workspace.",
|
||||
"focused-color-label": "Focused workspace color",
|
||||
"follow-focused-screen-description": "Display workspaces from the currently focused screen, rather than the screen where the bar is located.",
|
||||
"follow-focused-screen-label": "Follow focused screen",
|
||||
"grouped-border-opacity-description": "Set the opacity level for workspace container borders.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Hide unoccupied",
|
||||
"label-mode-description": "Choose how workspace labels are displayed.",
|
||||
"label-mode-label": "Label mode",
|
||||
"occupied-color-description": "Set the background color for occupied workspaces.",
|
||||
"occupied-color-label": "Occupied workspace color",
|
||||
"reverse-scrolling-description": "Reverse the direction of workspace switching when scrolling.",
|
||||
"reverse-scrolling-label": "Reverse scrolling",
|
||||
"show-applications-description": "Display application icons inside each workspace.",
|
||||
"show-applications-label": "Show applications",
|
||||
"show-badge-description": "Show the workspace number badge in grouped mode.",
|
||||
"show-badge-label": "Show workspace badge",
|
||||
"show-labels-only-when-occupied-description": "Only show workspace labels when they contain windows.",
|
||||
"show-labels-only-when-occupied-label": "Show labels only when occupied",
|
||||
"unfocused-icons-opacity-description": "Set the opacity level for unfocused app icons.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Not found",
|
||||
"notifications": "Notifications",
|
||||
"official": "Official",
|
||||
"on-surface": "On Surface",
|
||||
"output": "Output",
|
||||
"pair": "Pair",
|
||||
"paired": "Paired",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Polling",
|
||||
"position": "Position",
|
||||
"previous": "Previous",
|
||||
"primary": "Primary",
|
||||
"random": "Random",
|
||||
"reboot": "Reboot",
|
||||
"refresh": "Refresh",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Scanning...",
|
||||
"screen-corners": "Screen Corners",
|
||||
"search": "Search",
|
||||
"secondary": "Secondary",
|
||||
"security": "Security",
|
||||
"select": "Select",
|
||||
"shortcuts": "Shortcuts",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Stop",
|
||||
"suspend": "Suspend",
|
||||
"templates": "Templates",
|
||||
"tertiary": "Tertiary",
|
||||
"test": "Test",
|
||||
"thresholds": "Thresholds",
|
||||
"title": "Title",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Compact",
|
||||
"density-default": "Default",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Spacious"
|
||||
"density-spacious": "Spacious",
|
||||
"type-floating": "Floating",
|
||||
"type-framed": "Framed",
|
||||
"type-simple": "Simple"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Classic",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Customize the bar's appearance and position.",
|
||||
"appearance-floating-description": "Display the bar as a floating 'pill'.",
|
||||
"appearance-floating-label": "Floating bar",
|
||||
"appearance-frame-radius": "Inner Radius",
|
||||
"appearance-frame-settings-description": "Adjust frame thickness and inner corner radius",
|
||||
"appearance-frame-settings-label": "Frame Settings",
|
||||
"appearance-frame-thickness": "Thickness",
|
||||
"appearance-hide-on-overview-description": "Hide the bar and close panels when the compositor overview is active.",
|
||||
"appearance-hide-on-overview-label": "Hide bar on overview",
|
||||
"appearance-margins-description": "Adjust the margins around the floating bar.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Show capsule",
|
||||
"appearance-show-outline-description": "Displays a visible border around every widget.",
|
||||
"appearance-show-outline-label": "Show widget outlines",
|
||||
"appearance-type-description": "Choose the style of the bar: Simple, Floating or Framed",
|
||||
"appearance-type-label": "Bar Type",
|
||||
"appearance-use-separate-opacity-description": "Enable to use a separate opacity value for the bar background.",
|
||||
"appearance-use-separate-opacity-label": "Use separate bar opacity",
|
||||
"monitor-configure-widgets": "Configure widgets",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Wrap clipboard text",
|
||||
"settings-clipboard-history-description": "Access previously copied items from the launcher.",
|
||||
"settings-clipboard-history-label": "Enable clipboard history",
|
||||
"settings-clipboard-watch-image-description": "Full command string passed to wl-paste for image changes. (requires restart)",
|
||||
"settings-clipboard-watch-image-label": "Image watch command",
|
||||
"settings-clipboard-watch-text-description": "Full command string passed to wl-paste for text changes. (requires restart)",
|
||||
"settings-clipboard-watch-text-label": "Text watch command",
|
||||
"settings-custom-launch-prefix-description": "Prefix commands with a custom launcher (e.g., 'runapp' for systemd integration).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Use a custom prefix for launching applications instead of the default method.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Enable custom launch prefix",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Display weather in calendar"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "When fprintd (fingerprint authentication) is active, this option lets you still login using your password instead of a fingerprint",
|
||||
"allow-password-with-fprintd-label": "Allow password login with fprintd",
|
||||
"auto-start-auth-description": "e.g., automatically starts fingerprint authentication without requiring a key press or button click.",
|
||||
"auto-start-auth-label": "Auto-start authentication",
|
||||
"compact-lockscreen-description": "Show only the login input and system controls, hiding weather and media widgets.",
|
||||
"compact-lockscreen-label": "Compact lock screen",
|
||||
"lock-on-suspend-description": "Automatically lock the screen when suspending the system.",
|
||||
|
||||
+90
-57
@@ -26,8 +26,8 @@
|
||||
"widget-settings": "Configuración del widget"
|
||||
},
|
||||
"authentication": {
|
||||
"error": "Error de autenticación",
|
||||
"failed": "Autenticación fallida"
|
||||
"error": "Error de autentificación",
|
||||
"failed": "Autentificación fallida"
|
||||
},
|
||||
"bar": {
|
||||
"active-window": {
|
||||
@@ -60,7 +60,7 @@
|
||||
"show-power-profile-label": "Mostrar controles de perfil de energía"
|
||||
},
|
||||
"clock": {
|
||||
"clock-display-description": "Personaliza la visualización de tu reloj añadiendo tokens de la lista de abajo. Para usar el formato de 12 horas, debes incluir el token 'AP'.",
|
||||
"clock-display-description": "Personaliza la visualización del reloj añadiendo tokens de la lista de abajo. Para usar el formato de 12 horas, debes incluir el token 'AP'.",
|
||||
"clock-display-label": "Visualización del reloj",
|
||||
"custom-font-description": "Seleccionar una fuente personalizada para la visualización del reloj.",
|
||||
"custom-font-label": "Fuente personalizada",
|
||||
@@ -69,13 +69,13 @@
|
||||
"horizontal-bar-description": "Consejo: Usa \\n para crear un salto de línea.",
|
||||
"horizontal-bar-label": "Barra horizontal",
|
||||
"preview": "Vista previa",
|
||||
"tooltip-format-description": "Cadena de formato para la información sobre herramientas que se muestra al pasar el cursor sobre el reloj. Déjelo vacío para usar la información sobre herramientas predeterminada.",
|
||||
"tooltip-format-label": "Formato de información sobre herramientas",
|
||||
"use-custom-font-description": "Anular la selección de fuente predeterminada con una fuente personalizada para el reloj.",
|
||||
"tooltip-format-description": "Formato de la información mostrada al pasar el cursor sobre el reloj. Déjalo vacío para usar el formato por defecto.",
|
||||
"tooltip-format-label": "Formato del emergente",
|
||||
"use-custom-font-description": "Anular la fuente predeterminada del sistema con una fuente específica para el reloj.",
|
||||
"use-custom-font-label": "Usar fuente personalizada",
|
||||
"use-monospaced-font-description": "Cuando está activado, el reloj usará la fuente monoespaciada.",
|
||||
"use-monospaced-font-description": "Cuando está activada, el reloj usará la fuente monoespaciada.",
|
||||
"use-monospaced-font-label": "Usar fuente monoespaciada",
|
||||
"use-primary-color-description": "Cuando está activado, se aplica el color primario para dar énfasis.",
|
||||
"use-primary-color-description": "Cuando está activado, se aplicará el color primario para dar énfasis.",
|
||||
"use-primary-color-label": "Usar color primario",
|
||||
"vertical-bar-description": "Usa un espacio para separar cada parte en una nueva línea.",
|
||||
"vertical-bar-label": "Barra vertical"
|
||||
@@ -83,8 +83,8 @@
|
||||
"control-center": {
|
||||
"browse-file": "Explorar archivo",
|
||||
"browse-library": "Explorar biblioteca",
|
||||
"color-selection-description": "Aplica colores del tema a los íconos.",
|
||||
"enable-colorization-description": "Habilita la coloración para el ícono del centro de control, aplicando los colores del tema.",
|
||||
"color-selection-description": "Aplica colores del tema a los iconos.",
|
||||
"enable-colorization-description": "Habilita el coloreado del icono del centro de control, aplicando los colores del tema.",
|
||||
"icon-description": "Selecciona un icono de la biblioteca o un archivo personalizado.",
|
||||
"select-custom-icon": "Seleccionar un icono personalizado",
|
||||
"use-distro-logo-description": "Usar el logo de tu distribución en lugar de un icono personalizado.",
|
||||
@@ -95,19 +95,19 @@
|
||||
"collapse-condition-label": "Condición de colapso",
|
||||
"color-selection-description": "Aplicar colores del tema al icono y al texto.",
|
||||
"color-selection-label": "Seleccionar color",
|
||||
"display-command-output-description": "Ingresa un comando para ejecutar a intervalos regulares. La primera línea de su salida se mostrará como texto.",
|
||||
"display-command-output-label": "Mostrar salida de comando",
|
||||
"display-command-output-description": "Introduce un comando para ejecutar a intervalos regulares. La primera línea de su salida se mostrará como texto.",
|
||||
"display-command-output-label": "Mostrar salida del comando",
|
||||
"display-command-output-stream-description": "Introduce un comando para ejecutar continuamente.",
|
||||
"dynamic-text": "Texto dinámico",
|
||||
"enable-colorization-description": "Habilitar la coloración para el icono y el texto del botón personalizado, aplicando los colores del tema.",
|
||||
"enable-colorization-label": "Habilitar coloración",
|
||||
"enable-colorization-description": "Habilitar el coloreado para el icono y el texto del botón personalizado, aplicando los colores del tema.",
|
||||
"enable-colorization-label": "Habilitar coloreado",
|
||||
"hide-mode-always-expanded": "Siempre expandido",
|
||||
"hide-mode-description": "Controla la visibilidad del widget cuando el comando no tiene salida.",
|
||||
"hide-mode-expand-with-output": "Expandir cuando tiene salida",
|
||||
"hide-mode-label": "Modo de ocultar",
|
||||
"hide-mode-label": "Modo de ocultación",
|
||||
"hide-mode-max-transparent": "Máximo expandido pero transparente",
|
||||
"icon-description": "Selecciona un icono de la biblioteca.",
|
||||
"ipc-identifier-description": "Identificador único para comandos IPC. Utilice este identificador con 'qs -c noctalia-shell ipc call cb [acción] [identificador]' para controlar este botón a través de IPC.",
|
||||
"ipc-identifier-description": "Identificador único para comandos IPC. Utiliza este identificador con 'qs -c noctalia-shell ipc call cb [acción] [identificador]' para controlar este botón a través de IPC.",
|
||||
"ipc-identifier-label": "Identificador IPC",
|
||||
"left-click-description": "Comando a ejecutar cuando se hace clic izquierdo en el botón.",
|
||||
"left-click-label": "Clic izquierdo",
|
||||
@@ -116,11 +116,11 @@
|
||||
"max-text-length-horizontal-label": "Longitud máxima de texto (horizontal)",
|
||||
"max-text-length-vertical-description": "Número máximo de caracteres a mostrar en la barra vertical (0 para ocultar el texto).",
|
||||
"max-text-length-vertical-label": "Longitud máxima de texto (vertical)",
|
||||
"middle-click-description": "Comando a ejecutar cuando se hace clic medio en el botón.",
|
||||
"middle-click-label": "Clic medio",
|
||||
"middle-click-description": "Comando a ejecutar cuando se hace clic central en el botón.",
|
||||
"middle-click-label": "Clic central",
|
||||
"middle-click-update-text": "Actualizar el texto mostrado al hacer clic con el botón central",
|
||||
"parse-json-description": "Analizar la salida del comando como un objeto JSON para establecer dinámicamente el texto y el ícono.",
|
||||
"parse-json-label": "Analizar salida como JSON",
|
||||
"parse-json-label": "Interpretar salida como JSON",
|
||||
"refresh-interval-description": "Intervalo en milisegundos.",
|
||||
"refresh-interval-label": "Intervalo de actualización",
|
||||
"right-click-description": "Comando a ejecutar cuando se hace clic derecho en el botón.",
|
||||
@@ -129,7 +129,7 @@
|
||||
"show-icon-description": "Alterna la visibilidad del icono del widget.",
|
||||
"show-icon-label": "Mostrar icono",
|
||||
"text-stream-description": "Las líneas transmitidas desde el comando se mostrarán como texto en el botón.",
|
||||
"text-stream-label": "Transmisión",
|
||||
"text-stream-label": "Salida del comando",
|
||||
"wheel-description": "Comando a ejecutar cuando se usa la rueda de desplazamiento.<br>Usa $delta para el delta de la rueda de desplazamiento en el comando.",
|
||||
"wheel-down-description": "Comando a ejecutar cuando la rueda de desplazamiento se desplaza hacia abajo.",
|
||||
"wheel-down-label": "Comando de rueda hacia abajo",
|
||||
@@ -154,19 +154,19 @@
|
||||
"show-scroll-lock-label": "Bloq Despl"
|
||||
},
|
||||
"media-mini": {
|
||||
"compact-mode-description": "Habilitar un diseño que ahorre espacio para el panel del reproductor multimedia.",
|
||||
"compact-mode-description": "Habilitar un diseño compacto para el panel del reproductor multimedia.",
|
||||
"compact-mode-label": "Modo compacto",
|
||||
"hide-mode-description": "Controla el comportamiento del widget cuando no se está reproduciendo ningún medio.",
|
||||
"max-width-description": "Establece el tamaño horizontal máximo del widget. El widget se reducirá para adaptarse a contenido más corto.",
|
||||
"no-active-player": "Sin reproductor activo",
|
||||
"panel-section-description": "Configurar la apariencia y el comportamiento del panel del reproductor multimedia.",
|
||||
"panel-section-label": "Panel del reproductor multimedia",
|
||||
"scrolling-mode-description": "Controlar cuándo está habilitado el desplazamiento de texto para títulos de pista largos.",
|
||||
"scrolling-mode-description": "Controla cuándo está habilitado el desplazamiento de texto para títulos de pista largos.",
|
||||
"scrolling-mode-label": "Modo de desplazamiento",
|
||||
"show-album-art-description": "Mostrar la portada del álbum de la pista que se está reproduciendo actualmente.",
|
||||
"show-album-art-description": "Mostrar la portada del álbum de la pista que se está reproduciendo.",
|
||||
"show-album-art-label": "Mostrar arte del álbum",
|
||||
"show-artist-first-description": "Mostrar artista - título en lugar de título - artista.",
|
||||
"show-artist-first-label": "Mostrar primero al artista",
|
||||
"show-artist-first-description": "Mostrar 'artista - título' en lugar de 'título - artista'.",
|
||||
"show-artist-first-label": "Mostrar primero el artista",
|
||||
"show-progress-ring-description": "Mostrar un indicador de progreso circular que muestre el progreso de la pista.",
|
||||
"show-progress-ring-label": "Mostrar anillo de progreso",
|
||||
"show-visualizer-description": "Mostrar un visualizador de audio cuando se reproduce música.",
|
||||
@@ -179,10 +179,12 @@
|
||||
"notification-history": {
|
||||
"hide-widget-when-zero-description": "Ocultar el icono de notificaciones cuando no haya notificaciones.",
|
||||
"hide-widget-when-zero-label": "Ocultar icono sin notificaciones",
|
||||
"hide-widget-when-zero-unread-description": "Ocultar el icono de notificaciones cuando no haya notificaciones sin leer.",
|
||||
"hide-widget-when-zero-unread-label": "Ocultar icono sin notificaciones sin leer",
|
||||
"hide-widget-when-zero-unread-description": "Ocultar el icono de notificaciones cuando no haya notificaciones pendientes de leer.",
|
||||
"hide-widget-when-zero-unread-label": "Ocultar icono sin notificaciones pendientes",
|
||||
"show-unread-badge-description": "Mostrar una insignia con el número de notificaciones no leídas.",
|
||||
"show-unread-badge-label": "Mostrar insignia de no leídos"
|
||||
"show-unread-badge-label": "Mostrar insignia de no leídos",
|
||||
"unread-badge-color-description": "Selecciona el color para la insignia de notificación no leída.",
|
||||
"unread-badge-color-label": "Color de la insignia de no leídos"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Selecciona un widget para añadir...",
|
||||
@@ -254,9 +256,13 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Número de caracteres a mostrar de los nombres de espacios de trabajo (1-10).",
|
||||
"character-count-label": "Número de caracteres",
|
||||
"empty-color-description": "Establecer el color de fondo para los Workspaces vacíos.",
|
||||
"empty-color-label": "Color de espacio de trabajo vacío",
|
||||
"enable-scrollwheel-description": "Cambia entre espacios de trabajo usando la rueda de desplazamiento del ratón.",
|
||||
"enable-scrollwheel-label": "Desplázate para cambiar de espacio de trabajo",
|
||||
"follow-focused-screen-description": "Mostrar espacios de trabajo de la pantalla actualmente enfocada, en lugar de la pantalla donde se encuentra la barra.",
|
||||
"focused-color-description": "Establece el color de fondo para el Workspace enfocado.",
|
||||
"focused-color-label": "Color del espacio de trabajo enfocado",
|
||||
"follow-focused-screen-description": "Mostrar espacios de trabajo de la pantalla enfocada, en lugar de la pantalla donde se encuentra la barra.",
|
||||
"follow-focused-screen-label": "Seguir pantalla enfocada",
|
||||
"grouped-border-opacity-description": "Establecer el nivel de opacidad para los bordes del contenedor del espacio de trabajo.",
|
||||
"grouped-border-opacity-label": "Opacidad del borde",
|
||||
@@ -264,12 +270,18 @@
|
||||
"hide-unoccupied-label": "Ocultar desocupados",
|
||||
"label-mode-description": "Elegir cómo se muestran las etiquetas de los espacios de trabajo.",
|
||||
"label-mode-label": "Modo de etiqueta",
|
||||
"occupied-color-description": "Establecer el color de fondo para los Workspaces ocupados.",
|
||||
"occupied-color-label": "Color del espacio de trabajo ocupado",
|
||||
"reverse-scrolling-description": "Invertir la dirección del cambio de espacios de trabajo al desplazarse.",
|
||||
"reverse-scrolling-label": "Desplazamiento inverso",
|
||||
"show-applications-description": "Mostrar los iconos de las aplicaciones dentro de cada espacio de trabajo.",
|
||||
"show-applications-label": "Mostrar aplicaciones",
|
||||
"show-badge-description": "Mostrar la insignia del número de espacio de trabajo en modo agrupado.",
|
||||
"show-badge-label": "Mostrar insignia del espacio de trabajo",
|
||||
"show-labels-only-when-occupied-description": "Mostrar solo las etiquetas del espacio de trabajo cuando contengan ventanas.",
|
||||
"show-labels-only-when-occupied-label": "Mostrar etiquetas solo cuando esté ocupado",
|
||||
"show-labels-only-when-occupied-label": "Mostrar etiquetas solo cuando haya contenido",
|
||||
"unfocused-icons-opacity-description": "Establecer el nivel de opacidad para los iconos de aplicaciones no enfocadas.",
|
||||
"unfocused-icons-opacity-label": "Opacidad de iconos desenfocados"
|
||||
"unfocused-icons-opacity-label": "Opacidad de iconos de aplicaciones no enfocadas"
|
||||
}
|
||||
},
|
||||
"battery": {
|
||||
@@ -301,7 +313,7 @@
|
||||
"pairing-mode": "Asegúrate de que tu dispositivo esté en modo de emparejamiento.",
|
||||
"scanning": "Buscando dispositivos...",
|
||||
"signal-text-excellent": "Señal: Excelente",
|
||||
"signal-text-fair": "Señal: Regular",
|
||||
"signal-text-fair": "Señal: Razonable",
|
||||
"signal-text-good": "Señal: Buena",
|
||||
"signal-text-poor": "Señal: Débil",
|
||||
"signal-text-unknown": "Señal: Desconocida",
|
||||
@@ -316,11 +328,11 @@
|
||||
"panel": {
|
||||
"buttons-discord": "Únete a nuestro Discord",
|
||||
"buttons-dismiss": "OK",
|
||||
"buttons-feedback": "Dar retroalimentación",
|
||||
"buttons-feedback": "Dejar comentario",
|
||||
"empty": "Las notas de la versión aún no están disponibles.",
|
||||
"highlight-title": "Cambios destacados",
|
||||
"released": "Publicado el {date}",
|
||||
"subtitle-fresh": "Gracias por instalar Noctalia. Esto es lo que incluye esta compilación.",
|
||||
"subtitle-fresh": "¡Gracias por instalar Noctalia! Esto es lo que incluye esta compilación.",
|
||||
"subtitle-updated": "Actualizado desde {previousVersion}",
|
||||
"title": "Novedades en {version}",
|
||||
"version": "Versión {version}",
|
||||
@@ -329,7 +341,7 @@
|
||||
},
|
||||
"colors": {
|
||||
"error": "Error",
|
||||
"on-surface": "En la superficie",
|
||||
"on-surface": "Sobre la superficie",
|
||||
"primary": "Primario",
|
||||
"secondary": "Secundario",
|
||||
"tertiary": "Terciario"
|
||||
@@ -408,7 +420,7 @@
|
||||
"monitors": "Monitores",
|
||||
"network": "Red",
|
||||
"next": "Siguiente",
|
||||
"night-light": "Luz de noche",
|
||||
"night-light": "Luz nocturna",
|
||||
"no": "No",
|
||||
"no-results": "Sin resultados",
|
||||
"no-summary": "Sin resumen",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "No encontrado",
|
||||
"notifications": "Notificaciones",
|
||||
"official": "Oficial",
|
||||
"on-surface": "En superficie",
|
||||
"output": "Salida",
|
||||
"pair": "Emparejar",
|
||||
"paired": "Emparejado",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Sondeo",
|
||||
"position": "Posición",
|
||||
"previous": "Anterior",
|
||||
"primary": "Primario",
|
||||
"random": "Aleatorio",
|
||||
"reboot": "Reiniciar",
|
||||
"refresh": "Refrescar",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Escaneando...",
|
||||
"screen-corners": "Esquinas de la pantalla",
|
||||
"search": "Buscar",
|
||||
"secondary": "Secundario",
|
||||
"security": "Seguridad",
|
||||
"select": "Seleccionar",
|
||||
"shortcuts": "Atajos",
|
||||
@@ -448,13 +463,14 @@
|
||||
"sound": "Sonido",
|
||||
"sources": "Fuentes",
|
||||
"start": "Comienzo",
|
||||
"stop": "Pare",
|
||||
"stop": "Parar",
|
||||
"suspend": "Suspender",
|
||||
"templates": "Plantillas",
|
||||
"tertiary": "Terciario",
|
||||
"test": "Prueba",
|
||||
"thresholds": "Umbrales",
|
||||
"title": "Título",
|
||||
"toast": "Toast",
|
||||
"toast": "Emergente",
|
||||
"trusted": "De confianza",
|
||||
"uninstall": "Desinstalar",
|
||||
"unknown": "Desconocido",
|
||||
@@ -486,16 +502,16 @@
|
||||
}
|
||||
},
|
||||
"display-modes": {
|
||||
"always-hide": "Siempre esconderse",
|
||||
"always-show": "Siempre mostrar",
|
||||
"force-open": "Forzar la apertura",
|
||||
"on-hover": "Al pasar"
|
||||
"always-hide": "Ocultar siempre",
|
||||
"always-show": "Mostrar siempre",
|
||||
"force-open": "Forzar abierto",
|
||||
"on-hover": "Al pasar por encima"
|
||||
},
|
||||
"hide-modes": {
|
||||
"hidden": "Ocultar cuando esté vacío",
|
||||
"idle": "Ocultar cuando esté inactivo",
|
||||
"transparent": "Transparente cuando esté vacío",
|
||||
"visible": "Siempre visible"
|
||||
"visible": "Mostrar siempre"
|
||||
},
|
||||
"launcher": {
|
||||
"categories": {
|
||||
@@ -525,10 +541,10 @@
|
||||
"providers": {
|
||||
"applications": "Aplicaciones",
|
||||
"calculator": "Calculadora",
|
||||
"calculator-deprecated": "El comando >calc está obsoleto y será eliminado pronto. Por favor, escribe expresiones matemáticas directamente en la búsqueda en su lugar.",
|
||||
"calculator-deprecated": "El comando >calc está obsoleto y será eliminado pronto. Por favor, en su lugar escribe expresiones matemáticas directamente en la búsqueda.",
|
||||
"calculator-description": "Calculadora — evalúa expresiones matemáticas",
|
||||
"calculator-enter-expression": "Ingresa una expresión matemática",
|
||||
"calculator-press-enter-to-copy": "Presione Enter para copiar el resultado",
|
||||
"calculator-enter-expression": "Introduce una expresión matemática",
|
||||
"calculator-press-enter-to-copy": "Pulsa Enter para copiar el resultado",
|
||||
"clipboard": "Historial del portapapeles",
|
||||
"clipboard-clear-description": "Limpiar todo el historial del portapapeles",
|
||||
"clipboard-clear-description-full": "Eliminar todos los elementos del historial del portapapeles",
|
||||
@@ -542,12 +558,12 @@
|
||||
"emoji": "Selector de emojis",
|
||||
"emoji-loading": "Cargando emojis...",
|
||||
"emoji-loading-description": "Por favor espera",
|
||||
"emoji-no-recent": "Aún no hay emojis recientes",
|
||||
"emoji-no-recent": "No hay emojis recientes",
|
||||
"emoji-search-description": "Buscar y copiar emojis"
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
"authenticating": "Autenticando...",
|
||||
"authenticating": "Autentificando...",
|
||||
"password": "Ingresa tu contraseña...",
|
||||
"restart": "Reiniciar",
|
||||
"shut-down": "Apagar"
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Compacta",
|
||||
"density-default": "Predeterminada",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Espacioso/a"
|
||||
"density-spacious": "Espaciosa",
|
||||
"type-floating": "Flotante",
|
||||
"type-framed": "Con marco",
|
||||
"type-simple": "Simple"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Clásico",
|
||||
@@ -589,7 +608,7 @@
|
||||
"scrolling-modes": {
|
||||
"always": "Desplazar siempre",
|
||||
"hover": "Desplazar al pasar",
|
||||
"never": "Nunca desplazar"
|
||||
"never": "No desplazar nunca"
|
||||
},
|
||||
"session-menu-grid-layout": {
|
||||
"grid": "Cuadrícula",
|
||||
@@ -656,9 +675,9 @@
|
||||
},
|
||||
"audio": {
|
||||
"devices-desc": "Configura los dispositivos de entrada y salida de audio disponibles.",
|
||||
"devices-input-device-description": "Selecciona el dispositivo de entrada de audio deseado.",
|
||||
"devices-input-device-description": "Selecciona el dispositivo preferido de entrada de audio.",
|
||||
"devices-input-device-label": "Dispositivo de entrada",
|
||||
"devices-output-device-description": "Selecciona el dispositivo de salida de audio deseado.",
|
||||
"devices-output-device-description": "Selecciona el dispositivo preferido de salida de audio.",
|
||||
"devices-output-device-label": "Dispositivo de salida",
|
||||
"devices-title": "Dispositivos de audio",
|
||||
"external-mixer-description": "Ingrese el comando o la ruta de la aplicación para ejecutar al activar la función de mezclador de audio externo.",
|
||||
@@ -670,7 +689,7 @@
|
||||
"media-excluded-player-placeholder": "escribe una subcadena y presiona +",
|
||||
"media-frame-rate-description": "Tasas más altas son más fluidas pero usan más recursos.",
|
||||
"media-frame-rate-label": "Tasa de fotogramas",
|
||||
"media-primary-player-description": "Ingresa una palabra clave para identificar tu reproductor principal.",
|
||||
"media-primary-player-description": "Introduce una palabra clave para identificar tu reproductor principal.",
|
||||
"media-primary-player-label": "Reproductor principal",
|
||||
"media-primary-player-placeholder": "ej. spotify, vlc, mpv",
|
||||
"media-scrolling-speed-description": "Tiempo en segundos para que el título se desplace del inicio al final.",
|
||||
@@ -690,10 +709,10 @@
|
||||
"volumes-mute-output-description": "Silencia la salida de audio principal del sistema.",
|
||||
"volumes-mute-output-label": "Silenciar salida de audio",
|
||||
"volumes-output-volume-description": "Nivel de volumen de todo el sistema.",
|
||||
"volumes-step-size-description": "Ajusta el tamaño del paso para los cambios de volumen (rueda de desplazamiento, atajos de teclado).",
|
||||
"volumes-step-size-description": "Ajusta el tamaño del paso para los cambios de volumen (rueda del ratón, atajos de teclado).",
|
||||
"volumes-step-size-label": "Tamaño del paso de volumen",
|
||||
"volumes-volume-feedback-description": "Reproducir un sonido de retroalimentación al ajustar el volumen",
|
||||
"volumes-volume-feedback-label": "Reproducir sonido de retroalimentación de volumen",
|
||||
"volumes-volume-feedback-description": "Reproducir un sonido cuando se ajusta el volumen",
|
||||
"volumes-volume-feedback-label": "Reproducir sonido de cambio de volumen",
|
||||
"volumes-volume-overdrive-description": "Permite subir el volumen por encima del 100 %. Es posible que no sea compatible con todo el hardware.",
|
||||
"volumes-volume-overdrive-label": "Permitir sobreamplificación de volumen"
|
||||
},
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Personaliza la apariencia y posición de la barra.",
|
||||
"appearance-floating-description": "Muestra la barra como una 'píldora' flotante.",
|
||||
"appearance-floating-label": "Barra flotante",
|
||||
"appearance-frame-radius": "Radio interno",
|
||||
"appearance-frame-settings-description": "Ajustar el grosor del marco y el radio de la esquina interior",
|
||||
"appearance-frame-settings-label": "Ajustes del marco",
|
||||
"appearance-frame-thickness": "Grosor",
|
||||
"appearance-hide-on-overview-description": "Ocultar la barra y cerrar los paneles cuando la vista general del compositor esté activa.",
|
||||
"appearance-hide-on-overview-label": "Ocultar barra en la vista general",
|
||||
"appearance-margins-description": "Ajusta los márgenes alrededor de la barra flotante.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Mostrar cápsula",
|
||||
"appearance-show-outline-description": "Muestra un borde visible alrededor de cada widget.",
|
||||
"appearance-show-outline-label": "Mostrar contornos de widgets",
|
||||
"appearance-type-description": "Elige el estilo de la barra: Simple, Flotante o Con marco",
|
||||
"appearance-type-label": "Tipo de barra",
|
||||
"appearance-use-separate-opacity-description": "Permitir usar un valor de opacidad separado para el fondo de la barra.",
|
||||
"appearance-use-separate-opacity-label": "Usar opacidad de barra separada",
|
||||
"monitor-configure-widgets": "Configurar widgets",
|
||||
@@ -786,7 +811,7 @@
|
||||
"templates-filter-label": "Filtrar por categoría",
|
||||
"templates-misc-description": "Crea tus propias plantillas.",
|
||||
"templates-misc-label": "Avanzado",
|
||||
"templates-misc-user-templates-description": "Solo habilita si sabes lo que estás haciendo — consulta nuestra documentación en línea.",
|
||||
"templates-misc-user-templates-description": "Habilita sólamente si sabes lo que estás haciendo — consulta nuestra documentación en línea.",
|
||||
"templates-misc-user-templates-label": "Habilitar plantillas de usuario",
|
||||
"templates-none-detected": "Ninguno detectado",
|
||||
"templates-write-path": "Escribe: {filepath}",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Ajustar texto del portapapeles",
|
||||
"settings-clipboard-history-description": "Accede a los elementos copiados anteriormente desde el lanzador.",
|
||||
"settings-clipboard-history-label": "Activar historial del portapapeles",
|
||||
"settings-clipboard-watch-image-description": "Cadena de comando completa pasada a wl-paste para cambios de imagen. (requiere reinicio)",
|
||||
"settings-clipboard-watch-image-label": "Comando de Vigilancia de Imágenes",
|
||||
"settings-clipboard-watch-text-description": "Cadena de comando completa pasada a wl-paste para cambios de texto. (requiere reinicio)",
|
||||
"settings-clipboard-watch-text-label": "Comando de vigilancia de texto",
|
||||
"settings-custom-launch-prefix-description": "Prefijar comandos con un lanzador personalizado (ej. 'runapp' para integración con systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Usar un prefijo personalizado para lanzar aplicaciones en lugar del método predeterminado.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Habilitar prefijo de lanzamiento personalizado",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Mostrar el clima en el calendario"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Cuando fprintd (autenticación por huella dactilar) está activo, esta opción te permite iniciar sesión con tu contraseña en lugar de una huella dactilar.",
|
||||
"allow-password-with-fprintd-label": "Permitir inicio de sesión con contraseña usando fprintd",
|
||||
"auto-start-auth-description": "p. ej., inicia automáticamente la autenticación de huellas dactilares sin requerir una pulsación de tecla o un clic de botón.",
|
||||
"auto-start-auth-label": "Autentificación de inicio automática",
|
||||
"compact-lockscreen-description": "Mostrar solo el campo de inicio de sesión y los controles del sistema, ocultando los widgets del clima y multimedia.",
|
||||
"compact-lockscreen-label": "Pantalla de bloqueo compacta",
|
||||
"lock-on-suspend-description": "Bloquear la pantalla automáticamente al suspender el sistema.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Masquer l’icône de notification lorsqu’il n’y a aucune notification non lue.",
|
||||
"hide-widget-when-zero-unread-label": "Masquer l’icône sans notifications non lues",
|
||||
"show-unread-badge-description": "Afficher un badge montrant le nombre de notifications non lues.",
|
||||
"show-unread-badge-label": "Afficher le badge non lu"
|
||||
"show-unread-badge-label": "Afficher le badge non lu",
|
||||
"unread-badge-color-description": "Sélectionnez la couleur pour le badge de notification non lue.",
|
||||
"unread-badge-color-label": "Couleur du badge non lu"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Sélectionnez un widget à ajouter...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Nombre de caractères à afficher des noms d'espaces de travail (1-10).",
|
||||
"character-count-label": "Nombre de caractères",
|
||||
"empty-color-description": "Définir la couleur d'arrière-plan pour les Workspaces vides.",
|
||||
"empty-color-label": "Couleur d'espace de travail vide",
|
||||
"enable-scrollwheel-description": "Basculer entre les espaces de travail avec la molette de la souris.",
|
||||
"enable-scrollwheel-label": "Faites défiler pour changer d'espace de travail",
|
||||
"focused-color-description": "Définir la couleur d'arrière-plan pour l'espace de travail sélectionné.",
|
||||
"focused-color-label": "Couleur de l'espace de travail sélectionné",
|
||||
"follow-focused-screen-description": "Afficher les espaces de travail de l'écran actuellement ciblé, plutôt que de l'écran où se trouve la barre.",
|
||||
"follow-focused-screen-label": "Suivre l'écran ciblé",
|
||||
"grouped-border-opacity-description": "Définir le niveau d'opacité des bordures des conteneurs d'espace de travail.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Masquer les inoccupés",
|
||||
"label-mode-description": "Choisir comment les étiquettes d'espace de travail sont affichées.",
|
||||
"label-mode-label": "Mode d'étiquette",
|
||||
"occupied-color-description": "Définir la couleur d'arrière-plan pour les Workspaces occupés.",
|
||||
"occupied-color-label": "Couleur de l'espace de travail occupé",
|
||||
"reverse-scrolling-description": "Inverser la direction du changement d'espace de travail lors du défilement.",
|
||||
"reverse-scrolling-label": "Défilement inversé",
|
||||
"show-applications-description": "Afficher les icônes des applications dans chaque espace de travail.",
|
||||
"show-applications-label": "Afficher les applications",
|
||||
"show-badge-description": "Afficher le badge du numéro d'espace de travail en mode groupé.",
|
||||
"show-badge-label": "Afficher le badge de l'espace de travail",
|
||||
"show-labels-only-when-occupied-description": "Afficher uniquement les étiquettes d'espace de travail lorsqu'elles contiennent des fenêtres.",
|
||||
"show-labels-only-when-occupied-label": "Afficher les étiquettes uniquement lorsque le champ est occupé",
|
||||
"unfocused-icons-opacity-description": "Définir le niveau d'opacité des icônes d'applications non focalisées.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Non trouvé",
|
||||
"notifications": "Notifications",
|
||||
"official": "Officiel",
|
||||
"on-surface": "Sur la surface",
|
||||
"output": "Sortie",
|
||||
"pair": "Appairer",
|
||||
"paired": "Apparié",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Interrogation",
|
||||
"position": "Position",
|
||||
"previous": "Précédent",
|
||||
"primary": "Primaire",
|
||||
"random": "Aléatoire",
|
||||
"reboot": "Redémarrer",
|
||||
"refresh": "Actualiser",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Analyse en cours...",
|
||||
"screen-corners": "Coins d'écran",
|
||||
"search": "Rechercher",
|
||||
"secondary": "Secondaire",
|
||||
"security": "Sécurité",
|
||||
"select": "Sélectionner",
|
||||
"shortcuts": "Raccourcis",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Arrêtez",
|
||||
"suspend": "Mettre en veille",
|
||||
"templates": "Modèles",
|
||||
"tertiary": "Tertiaire",
|
||||
"test": "Test",
|
||||
"thresholds": "Seuils",
|
||||
"title": "Titre",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Compact",
|
||||
"density-default": "Défaut",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Spacieux"
|
||||
"density-spacious": "Spacieux",
|
||||
"type-floating": "Flottante",
|
||||
"type-framed": "Encadrée",
|
||||
"type-simple": "Simple"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Classique",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Personnalisez l'apparence et la position de la barre.",
|
||||
"appearance-floating-description": "Afficher la barre sous forme de 'pilule' flottante.",
|
||||
"appearance-floating-label": "Barre flottante",
|
||||
"appearance-frame-radius": "Rayon interne",
|
||||
"appearance-frame-settings-description": "Ajuster l'épaisseur du cadre et le rayon interne",
|
||||
"appearance-frame-settings-label": "Paramètres du cadre",
|
||||
"appearance-frame-thickness": "Épaisseur",
|
||||
"appearance-hide-on-overview-description": "Masquer la barre et fermer les panneaux lorsque l'aperçu du compositeur est actif.",
|
||||
"appearance-hide-on-overview-label": "Masquer la barre dans l'aperçu",
|
||||
"appearance-margins-description": "Ajustez les marges autour de la barre flottante.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Afficher la capsule",
|
||||
"appearance-show-outline-description": "Affiche une bordure visible autour de chaque widget.",
|
||||
"appearance-show-outline-label": "Afficher les contours des widgets",
|
||||
"appearance-type-description": "Choisissez le style de la barre : Simple, Flottante ou Encadrée",
|
||||
"appearance-type-label": "Type de barre",
|
||||
"appearance-use-separate-opacity-description": "Activer l'utilisation d'une valeur d'opacité distincte pour l'arrière-plan de la barre.",
|
||||
"appearance-use-separate-opacity-label": "Utiliser l'opacité des barres séparément",
|
||||
"monitor-configure-widgets": "Configurer les widgets",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Envelopper le texte du presse-papiers",
|
||||
"settings-clipboard-history-description": "Accédez aux éléments précédemment copiés depuis le lanceur.",
|
||||
"settings-clipboard-history-label": "Activer l'historique du presse-papiers",
|
||||
"settings-clipboard-watch-image-description": "Chaîne de commande complète passée à wl-paste pour les changements d'image. (redémarrage requis)",
|
||||
"settings-clipboard-watch-image-label": "Commande de Surveillance d'Images",
|
||||
"settings-clipboard-watch-text-description": "Chaîne de commande complète passée à wl-paste pour les changements de texte. (nécessite un redémarrage)",
|
||||
"settings-clipboard-watch-text-label": "Commande de surveillance de texte",
|
||||
"settings-custom-launch-prefix-description": "Préfixer les commandes avec un lanceur personnalisé (ex. 'runapp' pour l'intégration systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Utiliser un préfixe personnalisé pour lancer les applications au lieu de la méthode par défaut.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Activer le préfixe de lancement personnalisé",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Afficher la météo dans le calendrier"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Lorsque fprintd (authentification par empreinte digitale) est actif, cette option vous permet de vous connecter avec votre mot de passe au lieu d'une empreinte digitale.",
|
||||
"allow-password-with-fprintd-label": "Autoriser la connexion par mot de passe avec fprintd",
|
||||
"auto-start-auth-description": "par exemple, démarre automatiquement l'authentification par empreinte digitale sans nécessiter de pression sur une touche ou un clic de bouton.",
|
||||
"auto-start-auth-label": "Authentification au démarrage automatique",
|
||||
"compact-lockscreen-description": "Afficher uniquement le champ de saisie de connexion et les commandes système, en masquant les widgets météo et multimédia.",
|
||||
"compact-lockscreen-label": "Écran de verrouillage compact",
|
||||
"lock-on-suspend-description": "Verrouiller automatiquement l'écran lors de la mise en veille du système.",
|
||||
|
||||
@@ -1,4 +1,28 @@
|
||||
{
|
||||
"bar": {
|
||||
"workspace": {
|
||||
"empty-color-description": "खाली कार्यस्थानों के लिए पृष्ठभूमि रंग सेट करें।",
|
||||
"empty-color-label": "खाली कार्यस्थान रंग",
|
||||
"focused-color-description": "फोकस गरिएको कार्यक्षेत्रको लागि पृष्ठभूमि रङ सेट गर्नुहोस्।",
|
||||
"focused-color-label": "फोकस किए गए कार्यक्षेत्र का रंग",
|
||||
"occupied-color-description": "काम में लिए गए कार्यस्थानों के लिए पृष्ठभूमि रंग सेट करें।",
|
||||
"occupied-color-label": "अधिकृत कार्यक्षेत्र रंग",
|
||||
"show-badge-description": "समूहीकृत मोड में कार्यस्थान संख्या बैज दिखाएँ।",
|
||||
"show-badge-label": "कार्यस्थान बैज देखाउनुहोस्"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"on-surface": "सतह पर",
|
||||
"primary": "प्राइमरी",
|
||||
"secondary": "माध्यमिक",
|
||||
"tertiary": "तृतीयक"
|
||||
},
|
||||
"panels": {
|
||||
"lock-screen": {
|
||||
"auto-start-auth-description": "उदाहरण के लिए, बिना किसी कुंजी प्रेस या बटन क्लिक की आवश्यकता के स्वचालित रूप से फिंगरप्रिंट प्रमाणीकरण शुरू करता है।",
|
||||
"auto-start-auth-label": "स्वतः प्रमाणन शुरू करें"
|
||||
}
|
||||
},
|
||||
"toast": {
|
||||
"donation-opened": "दान पृष्ठ आपके ब्राउज़र में खुला"
|
||||
}
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Az értesítési ikon elrejtése, ha nincs olvasatlan értesítés.",
|
||||
"hide-widget-when-zero-unread-label": "Ikon elrejtése, amikor nincs olvasatlan értesítés",
|
||||
"show-unread-badge-description": "Jelenítsen meg egy jelvényt, amely mutatja az olvasatlan értesítések számát.",
|
||||
"show-unread-badge-label": "Olvasatlan jelvény megjelenítése"
|
||||
"show-unread-badge-label": "Olvasatlan jelvény megjelenítése",
|
||||
"unread-badge-color-description": "Válaszd ki az olvasatlan értesítési jelvény színét.",
|
||||
"unread-badge-color-label": "Olvasatlan jelvény színe"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Válasszon hozzáadandó widgetet...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "A munkaterületnevekből megjelenítendő karakterek száma (1-10).",
|
||||
"character-count-label": "Karakterek száma",
|
||||
"empty-color-description": "Üres Workspaces háttérszínének beállítása.",
|
||||
"empty-color-label": "Üres munkafelület színe",
|
||||
"enable-scrollwheel-description": "Váltás a munkaterületek között az egérgörgővel.",
|
||||
"enable-scrollwheel-label": "Görgetés a munkaterületek váltásához",
|
||||
"focused-color-description": "Állítsd be a fókuszált Workspace háttérszínét.",
|
||||
"focused-color-label": "Fókuszált munkaterület színe",
|
||||
"follow-focused-screen-description": "Munkaterületek megjelenítése az aktuálisan fókuszált képernyőről, nem arról a képernyőről, ahol a sáv található.",
|
||||
"follow-focused-screen-label": "Fókuszált képernyő követése",
|
||||
"grouped-border-opacity-description": "A munkaterület-konténerek szegélyeinek átlátszósági szintjének beállítása.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Foglalatlan elrejtése",
|
||||
"label-mode-description": "Válassza ki, hogyan jelenjenek meg a munkaterület címkéi.",
|
||||
"label-mode-label": "Címke mód",
|
||||
"occupied-color-description": "A foglalt Workspaces háttérszínének beállítása.",
|
||||
"occupied-color-label": "Foglalt munkaterület színe",
|
||||
"reverse-scrolling-description": "Görgetéskor fordított irányba váltson a munkaterületek között.",
|
||||
"reverse-scrolling-label": "Görgetés megfordítása",
|
||||
"show-applications-description": "Alkalmazásikonok megjelenítése minden munkaterületen belül.",
|
||||
"show-applications-label": "Alkalmazások megjelenítése",
|
||||
"show-badge-description": "Munkaterület számának jelzése csoportosított módban.",
|
||||
"show-badge-label": "Munkafelület jelvény megjelenítése",
|
||||
"show-labels-only-when-occupied-description": "Csak akkor jelenítse meg a munkaterület címkéket, ha azok tartalmaznak ablakokat.",
|
||||
"show-labels-only-when-occupied-label": "Címkék megjelenítése csak foglalt állapotban",
|
||||
"unfocused-icons-opacity-description": "Állítsa be a nem fókuszált alkalmazásikonok átlátszóságának szintjét.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Nem található",
|
||||
"notifications": "Értesítések",
|
||||
"official": "Hivatalos",
|
||||
"on-surface": "Felületen",
|
||||
"output": "Kimenet",
|
||||
"pair": "Párosítás",
|
||||
"paired": "Párosítva",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Lekérdezés",
|
||||
"position": "Pozíció",
|
||||
"previous": "Előző",
|
||||
"primary": "Elsődleges",
|
||||
"random": "Véletlen",
|
||||
"reboot": "Újraindítás",
|
||||
"refresh": "Frissítés",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Szkennelés...",
|
||||
"screen-corners": "Képernyő sarkok",
|
||||
"search": "Keresés",
|
||||
"secondary": "Másodlagos",
|
||||
"security": "Biztonság",
|
||||
"select": "Kiválasztás",
|
||||
"shortcuts": "Gyorsbillentyűk",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Állj",
|
||||
"suspend": "Felfüggesztés",
|
||||
"templates": "Sablonok",
|
||||
"tertiary": "Harmadlagos",
|
||||
"test": "Teszt",
|
||||
"thresholds": "Küszöbértékek",
|
||||
"title": "Cím",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Kompakt",
|
||||
"density-default": "Alapértelmezett",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Tágas"
|
||||
"density-spacious": "Tágas",
|
||||
"type-floating": "Lebegő",
|
||||
"type-framed": "Keretes",
|
||||
"type-simple": "Egyszerű"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klasszikus",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "A sáv megjelenésének és pozíciójának testreszabása.",
|
||||
"appearance-floating-description": "Megjeleníti a sávot lebegő „pirulaként”.",
|
||||
"appearance-floating-label": "Lebegő sáv",
|
||||
"appearance-frame-radius": "Belső sugár",
|
||||
"appearance-frame-settings-description": "Állítsa be a keret vastagságát és a belső sarok sugarát",
|
||||
"appearance-frame-settings-label": "Keret beállításai",
|
||||
"appearance-frame-thickness": "Vastagság",
|
||||
"appearance-hide-on-overview-description": "A sáv elrejtése és a panelek bezárása, amikor a kompozitor áttekintése aktív.",
|
||||
"appearance-hide-on-overview-label": "Sáv elrejtése az áttekintésben",
|
||||
"appearance-margins-description": "Beállítja a lebegő sáv körüli margókat.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Kapszula megjelenítése",
|
||||
"appearance-show-outline-description": "Látható szegély megjelenítése minden widget körül.",
|
||||
"appearance-show-outline-label": "Widget körvonalak megjelenítése",
|
||||
"appearance-type-description": "Válassza ki a sáv stílusát: Egyszerű, Lebegő vagy Keretes",
|
||||
"appearance-type-label": "Sáv típusa",
|
||||
"appearance-use-separate-opacity-description": "Lehetővé teszi egy külön átlátszatlansági érték használatát a sáv hátteréhez.",
|
||||
"appearance-use-separate-opacity-label": "Külön oszlop átlátszóság használata",
|
||||
"monitor-configure-widgets": "Widgetek konfigurálása",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Clipboard szöveg becsomagolása",
|
||||
"settings-clipboard-history-description": "Hozzáférés a korábban másolt elemekhez az indítóból.",
|
||||
"settings-clipboard-history-label": "Vágólapelőzmények engedélyezése",
|
||||
"settings-clipboard-watch-image-description": "Teljes parancssor, ami a wl-paste-nek kerül átadásra a képváltozásokhoz. (újraindítás szükséges)",
|
||||
"settings-clipboard-watch-image-label": "Képfigyelő Parancs",
|
||||
"settings-clipboard-watch-text-description": "A wl-paste-nek átadott teljes parancssor a szövegváltozásokhoz. (újraindítást igényel)",
|
||||
"settings-clipboard-watch-text-label": "Szövegfigyelő parancs",
|
||||
"settings-custom-launch-prefix-description": "Előtagolja a parancsokat egyéni indítóval (pl. 'runapp' a systemd integrációhoz).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Használjon egyéni előtagot az alkalmazások indításához az alapértelmezett módszer helyett.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Egyéni indítási előtag engedélyezése",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Időjárás megjelenítése a naptárban"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Ha az fprintd (ujjlenyomat-hitelesítés) aktív, ez az opció lehetővé teszi, hogy továbbra is jelszóval jelentkezzen be ujjlenyomat helyett.",
|
||||
"allow-password-with-fprintd-label": "Jelszavas bejelentkezés engedélyezése fprintd-vel",
|
||||
"auto-start-auth-description": "pl. automatikusan elindítja az ujjlenyomat-hitelesítést anélkül, hogy billentyűt kellene megnyomni vagy gombra kellene kattintani.",
|
||||
"auto-start-auth-label": "Automatikus hitelesítés indításkor",
|
||||
"compact-lockscreen-description": "Csak a bejelentkezési beviteli mező és a rendszervezérlők megjelenítése, elrejtve az időjárás és média widgeteket.",
|
||||
"compact-lockscreen-label": "Kompakt zárolási képernyő",
|
||||
"lock-on-suspend-description": "A képernyő automatikus zárolása a rendszer felfüggesztésekor.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "未読の通知がない場合に通知アイコンを非表示にします。",
|
||||
"hide-widget-when-zero-unread-label": "未読なしでアイコンを非表示",
|
||||
"show-unread-badge-description": "未読通知の数を表示するバッジを表示します。",
|
||||
"show-unread-badge-label": "未読バッジを表示"
|
||||
"show-unread-badge-label": "未読バッジを表示",
|
||||
"unread-badge-color-description": "未読の通知バッジの色を選択してください。",
|
||||
"unread-badge-color-label": "未読バッジの色"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "追加するウィジェットを選択...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "ワークスペース名から表示する文字数 (1-10)。",
|
||||
"character-count-label": "文字数",
|
||||
"empty-color-description": "空のWorkspaceの背景色を設定します。",
|
||||
"empty-color-label": "空のワークスペースの色",
|
||||
"enable-scrollwheel-description": "マウスホイールを使用してワークスペースを切り替えます。",
|
||||
"enable-scrollwheel-label": "スクロールでワークスペースを切り替え",
|
||||
"focused-color-description": "フォーカスされたWorkspaceの背景色を設定します。",
|
||||
"focused-color-label": "フォーカスされたワークスペースの色",
|
||||
"follow-focused-screen-description": "バーが配置されている画面ではなく、現在フォーカスされている画面のワークスペースを表示します。",
|
||||
"follow-focused-screen-label": "フォーカス中の画面に追従",
|
||||
"grouped-border-opacity-description": "ワークスペースコンテナのボーダーの不透明度を設定します。",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "空のワークスペースを隠す",
|
||||
"label-mode-description": "ワークスペースラベルの表示方法を選択します。",
|
||||
"label-mode-label": "ラベルモード",
|
||||
"occupied-color-description": "使用中のWorkspaceの背景色を設定します。",
|
||||
"occupied-color-label": "使用中のワークスペースの色",
|
||||
"reverse-scrolling-description": "スクロール時のワークスペース切り替え方向を反転する。",
|
||||
"reverse-scrolling-label": "スクロール方向を反転",
|
||||
"show-applications-description": "各ワークスペース内にアプリアイコンを表示します。",
|
||||
"show-applications-label": "アプリアイコンを表示",
|
||||
"show-badge-description": "グループ化モードでワークスペース番号バッジを表示します。",
|
||||
"show-badge-label": "ワークスペースバッジを表示",
|
||||
"show-labels-only-when-occupied-description": "ウィンドウが開いているワークスペースにのみラベルを表示します。",
|
||||
"show-labels-only-when-occupied-label": "ウィンドウがある時のみラベルを表示",
|
||||
"unfocused-icons-opacity-description": "フォーカスされていないアプリのアイコンの不透明度を設定します。",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "見つかりませんでした",
|
||||
"notifications": "通知",
|
||||
"official": "公式",
|
||||
"on-surface": "表面上",
|
||||
"output": "出力",
|
||||
"pair": "ペアリング",
|
||||
"paired": "ペアリング済み",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "ポーリング",
|
||||
"position": "位置",
|
||||
"previous": "前へ",
|
||||
"primary": "プライマリ",
|
||||
"random": "ランダム",
|
||||
"reboot": "再起動",
|
||||
"refresh": "更新",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "スキャン中...",
|
||||
"screen-corners": "画面の隅",
|
||||
"search": "検索",
|
||||
"secondary": "セカンダリー",
|
||||
"security": "セキュリティ",
|
||||
"select": "選択",
|
||||
"shortcuts": "ショートカット",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "停止",
|
||||
"suspend": "サスペンド",
|
||||
"templates": "テンプレート",
|
||||
"tertiary": "第三",
|
||||
"test": "テスト",
|
||||
"thresholds": "しきい値",
|
||||
"title": "タイトル",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "コンパクト",
|
||||
"density-default": "標準",
|
||||
"density-mini": "ミニ",
|
||||
"density-spacious": "広々とした"
|
||||
"density-spacious": "広々とした",
|
||||
"type-floating": "フローティング",
|
||||
"type-framed": "フレーム",
|
||||
"type-simple": "シンプル"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "クラシック",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "バーの外観や位置をカスタマイズします。",
|
||||
"appearance-floating-description": "バーを浮かせて、カプセル型で表示します。",
|
||||
"appearance-floating-label": "フローティングバー",
|
||||
"appearance-frame-radius": "内側の半径",
|
||||
"appearance-frame-settings-description": "フレームの太さと内側の半径を調整します",
|
||||
"appearance-frame-settings-label": "フレーム設定",
|
||||
"appearance-frame-thickness": "太さ",
|
||||
"appearance-hide-on-overview-description": "コンポジタの概要がアクティブなときは、バーを非表示にしてパネルを閉じます。",
|
||||
"appearance-hide-on-overview-label": "概要のバーを非表示にする",
|
||||
"appearance-margins-description": "フローティングバーの周囲の余白を調整します。",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "カプセルを表示",
|
||||
"appearance-show-outline-description": "すべてのウィジェットの周囲に枠線を表示します。",
|
||||
"appearance-show-outline-label": "ウィジェットの枠線を表示",
|
||||
"appearance-type-description": "バーのスタイルを選択:シンプル、フローティング、またはフレーム",
|
||||
"appearance-type-label": "バーの種類",
|
||||
"appearance-use-separate-opacity-description": "バーの背景に別の不透明度の値を使用できるようにする。",
|
||||
"appearance-use-separate-opacity-label": "バーの不透明度を個別に設定",
|
||||
"monitor-configure-widgets": "ウィジェットを設定",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "クリップボードのテキストを折り返す",
|
||||
"settings-clipboard-history-description": "以前コピーした項目にランチャーからアクセスできるようにします。",
|
||||
"settings-clipboard-history-label": "クリップボード履歴を有効化",
|
||||
"settings-clipboard-watch-image-description": "画像変更のためにwl-pasteに渡される完全なコマンド文字列。(再起動が必要)",
|
||||
"settings-clipboard-watch-image-label": "画像監視コマンド",
|
||||
"settings-clipboard-watch-text-description": "テキスト変更のために wl-paste に渡される完全なコマンド文字列。(再起動が必要)",
|
||||
"settings-clipboard-watch-text-label": "テキスト監視コマンド",
|
||||
"settings-custom-launch-prefix-description": "コマンドの先頭にカスタムランチャーを付与します(例: systemd 連携用の 'runapp')。",
|
||||
"settings-custom-launch-prefix-enabled-description": "デフォルトの方法の代わりに、カスタムプレフィックスを使用してアプリを起動します。",
|
||||
"settings-custom-launch-prefix-enabled-label": "カスタム起動プレフィックスを有効化",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "カレンダー"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "fprintd(指紋認証)が有効な場合、このオプションを使用すると、指紋の代わりにパスワードでログインできます。",
|
||||
"allow-password-with-fprintd-label": "fprintd でパスワードログインを許可する",
|
||||
"auto-start-auth-description": "たとえば、キーを押したりボタンをクリックしたりしなくても、指紋認証が自動的に開始されます。",
|
||||
"auto-start-auth-label": "自動認証を開始",
|
||||
"compact-lockscreen-description": "天気やメディアウィジェットを隠し、ログイン入力とシステムコントロールのみを表示します。",
|
||||
"compact-lockscreen-label": "コンパクトなロック画面",
|
||||
"lock-on-suspend-description": "システムのサスペンド時に、自動的に画面をロックします。",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Dema ku ti agahdarîya nexwendî tune be, îkona agahdarîyê veşêre.",
|
||||
"hide-widget-when-zero-unread-label": "Îkonê bê nexwendî veşêre",
|
||||
"show-unread-badge-description": "Nîşaneyekê nîşan bide ku hejmara agahiyên nehatine xwendin nîşan dide.",
|
||||
"show-unread-badge-label": "Nîşana ne xwendî nîşan bide"
|
||||
"show-unread-badge-label": "Nîşana ne xwendî nîşan bide",
|
||||
"unread-badge-color-description": "Rengê nîşana agahdariya nexwendî hilbijêre.",
|
||||
"unread-badge-color-label": "Rengê nîşana nexwendî"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Widgetekek hilbijêre ku lê zêde bike...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Hejmara tîpên ku ji navên qada xebatê bên nîşandan (1-10).",
|
||||
"character-count-label": "Hejmara tîpan",
|
||||
"empty-color-description": "Rengê paşxaneya ji bo Workspaceyên val destnîşan bike.",
|
||||
"empty-color-label": "Rengê cîhê kar ê vala",
|
||||
"enable-scrollwheel-description": "Bi tekerê mişkê di navbera cîhên xebatê de biguhere.",
|
||||
"enable-scrollwheel-label": "Bişkoka gerokê bizivirîne da ku cîhên kar biguherî",
|
||||
"focused-color-description": "Rengê paşperdeyê ji bo cîhê karê ku hatiye fokus kirin destnîşan bike.",
|
||||
"focused-color-label": "Rengê cîhê kar ê fokusdayî",
|
||||
"follow-focused-screen-description": "Dîmên xebatê ji dîmendera niha ya ku balê dikişîne, ne ji dîmendera ku bar lê ye, nîşan bide.",
|
||||
"follow-focused-screen-label": "Şopandina ekrana fokusê",
|
||||
"grouped-border-opacity-description": "Ayarê asta zelalbûna sînorên konteynerê cîhê kar.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Veşartî ne dagirkirî",
|
||||
"label-mode-description": "Çawa nîşaneyên cîhê kar têne nîşandan hilbijêre.",
|
||||
"label-mode-label": "Moda labelê",
|
||||
"occupied-color-description": "Rengê paşxaneyê ji bo Workspaceên dagirkirî destnîşan bike.",
|
||||
"occupied-color-label": "Rengê qada xebatê ya dagirkirî",
|
||||
"reverse-scrolling-description": "Dema ku hûn digerînin, rêgeha guhertina cîhê kar berevajî bike.",
|
||||
"reverse-scrolling-label": "گەڕاندنەوەی گەڕان",
|
||||
"show-applications-description": "Nîşaneyên sepanan di hundirê her cîhê xebatê de nîşan bide.",
|
||||
"show-applications-label": "Nîşan sepanan bide",
|
||||
"show-badge-description": "Di moda komkirî de nîşana jimareya cîhê kar nîşan bide.",
|
||||
"show-badge-label": "Nîşana qada xebatê nîşan bide",
|
||||
"show-labels-only-when-occupied-description": "Tenê etîketên cîhê xebatê nîşan bide dema ku ew pencereyan dihewînin.",
|
||||
"show-labels-only-when-occupied-label": "Tenê dema dagirkirî etîketan nîşan bide",
|
||||
"unfocused-icons-opacity-description": "Ayarê asta zelalbûna îkonên sepanên ne di fokusê de bike.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Nehat dîtin",
|
||||
"notifications": "Agahdarî",
|
||||
"official": "Fermî",
|
||||
"on-surface": "Li ser rûyê erdê",
|
||||
"output": "Derket",
|
||||
"pair": "Hevpar",
|
||||
"paired": "Hevpar bûyî",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Lêpirsîn",
|
||||
"position": "Helwest",
|
||||
"previous": "Berê",
|
||||
"primary": "Serekî",
|
||||
"random": "Bêserûber",
|
||||
"reboot": "Restart",
|
||||
"refresh": "Nûkirin",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Lêgerîn...",
|
||||
"screen-corners": "Kişekanên dîmenderê",
|
||||
"search": "Lêgerîn",
|
||||
"secondary": "Duyemîn",
|
||||
"security": "Ewlehî",
|
||||
"select": "Hilbijêre",
|
||||
"shortcuts": "Kurterê",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Raweste",
|
||||
"suspend": "Rawestîne",
|
||||
"templates": "Şablonan",
|
||||
"tertiary": "Sêyemîn",
|
||||
"test": "Test",
|
||||
"thresholds": "Asteyan",
|
||||
"title": "Sernav",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Kompakt",
|
||||
"density-default": "Berdest",
|
||||
"density-mini": "Piçûk",
|
||||
"density-spacious": "Berfireh"
|
||||
"density-spacious": "Berfireh",
|
||||
"type-floating": "Herikbar",
|
||||
"type-framed": "Çarçovekirî",
|
||||
"type-simple": "Sade"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klasîk",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Xuyakirina xuyabûn û pozîsyona bar.",
|
||||
"appearance-floating-description": "Bariş wekî 'heb'eke herikbar nîşan bide.",
|
||||
"appearance-floating-label": "Barê avjen",
|
||||
"appearance-frame-radius": "Nîvçapa Hundirîn",
|
||||
"appearance-frame-settings-description": "Stûrahiya çarçoveyê û nîvçapa goşeyê hundirîn sererast bike",
|
||||
"appearance-frame-settings-label": "Mîhengên Çarçoveyê",
|
||||
"appearance-frame-thickness": "Stûrahî",
|
||||
"appearance-hide-on-overview-description": "Dema ku pêşdîtina berhevker çalak be, bar veşêre û panelan bigire.",
|
||||
"appearance-hide-on-overview-label": "Li ser dîtinê bar veşêre",
|
||||
"appearance-margins-description": "Marginên dora bara herikbar eyar bike.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Pêşkêşkirina kapsulê",
|
||||
"appearance-show-outline-description": "Dîwarê xuya li dora her widgetê nîşan dide.",
|
||||
"appearance-show-outline-label": "Nîşandan xêzên widgetê",
|
||||
"appearance-type-description": "Stîla darikê hilbijêre: Sade, Herikbar an Çarçovekirî",
|
||||
"appearance-type-label": "Cureyê Darikê",
|
||||
"appearance-use-separate-opacity-description": "Destûrê bide ku ji bo paşxaneya bar nirxek opakbûna cuda were bikaranîn.",
|
||||
"appearance-use-separate-opacity-label": "Şefafiya bara cuda bikar bîne",
|
||||
"monitor-configure-widgets": "Widgetan saz bike",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Pêça nivîsa clipboardê",
|
||||
"settings-clipboard-history-description": "Gihîştina tiştên ku berê hatine kopîkirin ji destpêkerê.",
|
||||
"settings-clipboard-history-label": "Dîroka clipboardê çalak bike",
|
||||
"settings-clipboard-watch-image-description": "ڕستەی فەرمانی تەواو کە بۆ wl-paste تێدەپەڕێنرێت بۆ گۆڕانکارییەکانی وێنە. (پێویستی بە دووبارە دەستپێکردنەوە هەیە)",
|
||||
"settings-clipboard-watch-image-label": "فەرمانی چاودێریکردنی وێنە",
|
||||
"settings-clipboard-watch-text-description": "تەواوی زنجیرەی فەرمان کە بۆ wl-paste تێپەڕێنراوە بۆ گۆڕانکارییەکانی دەق. (پێویستی بە دووبارە دەستپێکردنەوە هەیە)",
|
||||
"settings-clipboard-watch-text-label": "فەرمانی چاودێری دەق",
|
||||
"settings-custom-launch-prefix-description": "Fermanên pêşgiran bi destpêkerek xwerû pêşda bikin (mînak, 'runapp' ji bo entegrasyona systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Bi awayekî xwerû destpêkê ji bo destpêkirina sepanan bikar bîne li şûna rêbaza standard.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Pêşgira destpêkirinê ya xwerû çalak bike",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Nîşandanîna hewayê di salnameyê de"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Dema ku fprintd (nasnameya tiliyan) çalak e, ev vebijêrk dihêle hûn bi şîfreya xwe têkevin, ne bi tiliya xwe.",
|
||||
"allow-password-with-fprintd-label": "Rêdan bi têketina şîfreyê bi fprintd",
|
||||
"auto-start-auth-description": "mînak, otomatîkî dest bi rastkirina tiliyê dike bêyî ku pêdivî bi pêlkeyek an klîkek hebe.",
|
||||
"auto-start-auth-label": "Destpêkirina otomatîkî ya rastkirinê",
|
||||
"compact-lockscreen-description": "Tenê inputa têketinê û kontrolên pergalê nîşan bide, widgetên hewayê û medyayê veşêre.",
|
||||
"compact-lockscreen-label": "Kilîta ekrana berhevkirî",
|
||||
"lock-on-suspend-description": "Dema ku pergal tê rawestandin, ekranê bixweber kilît bike.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Het meldingspictogram verbergen wanneer er geen ongelezen meldingen zijn.",
|
||||
"hide-widget-when-zero-unread-label": "Pictogram verbergen zonder ongelezen meldingen",
|
||||
"show-unread-badge-description": "Toon een badge met het aantal ongelezen meldingen.",
|
||||
"show-unread-badge-label": "Ongelezen-badge tonen"
|
||||
"show-unread-badge-label": "Ongelezen-badge tonen",
|
||||
"unread-badge-color-description": "Selecteer de kleur voor de badge van ongelezen meldingen.",
|
||||
"unread-badge-color-label": "Kleur van de ongelezen badge"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Selecteer een widget om toe te voegen...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Aantal tekens dat wordt weergegeven van werkruimtenamen (1-10).",
|
||||
"character-count-label": "Aantal tekens",
|
||||
"empty-color-description": "Stel de achtergrondkleur in voor lege Workspaces.",
|
||||
"empty-color-label": "Kleur van lege Workspace",
|
||||
"enable-scrollwheel-description": "Schakel tussen werkruimtes met het muiswiel.",
|
||||
"enable-scrollwheel-label": "Scroll om tussen werkruimtes te schakelen",
|
||||
"focused-color-description": "Stel de achtergrondkleur in voor de gefocuste Workspace.",
|
||||
"focused-color-label": "Kleur van de gefocuste Workspace",
|
||||
"follow-focused-screen-description": "Werkruimten weergeven van het momenteel gefocuste scherm, in plaats van het scherm waar de balk zich bevindt.",
|
||||
"follow-focused-screen-label": "Gefocust scherm volgen",
|
||||
"grouped-border-opacity-description": "Stel het dekkingsniveau in voor de randen van de werkruimtecontainer.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Ongebruikte verbergen",
|
||||
"label-mode-description": "Kies hoe labels van werkruimten worden weergegeven.",
|
||||
"label-mode-label": "Labelmodus",
|
||||
"occupied-color-description": "Stel de achtergrondkleur in voor bezette Workspaces.",
|
||||
"occupied-color-label": "Kleur van bezette workspace",
|
||||
"reverse-scrolling-description": "Keer de richting van het wisselen van werkruimtes om bij het scrollen.",
|
||||
"reverse-scrolling-label": "Omgekeerd scrollen",
|
||||
"show-applications-description": "Toon applicatiepictogrammen in elke werkruimte.",
|
||||
"show-applications-label": "Toon applicaties",
|
||||
"show-badge-description": "Toon de werkomgevingnummerbadge in gegroepeerde modus.",
|
||||
"show-badge-label": "Werkruimtebadge weergeven",
|
||||
"show-labels-only-when-occupied-description": "Toon alleen werkruimtelabels wanneer ze vensters bevatten.",
|
||||
"show-labels-only-when-occupied-label": "Toon labels alleen wanneer bezet",
|
||||
"unfocused-icons-opacity-description": "Stel het dekkingsniveau in voor app-pictogrammen die niet in focus zijn.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Niet gevonden",
|
||||
"notifications": "Meldingen",
|
||||
"official": "Officieel",
|
||||
"on-surface": "Op oppervlak",
|
||||
"output": "Uitvoer",
|
||||
"pair": "Koppelen",
|
||||
"paired": "Gekoppeld",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Polling",
|
||||
"position": "Positie",
|
||||
"previous": "Vorige",
|
||||
"primary": "Primair",
|
||||
"random": "Willekeurig",
|
||||
"reboot": "Herstarten",
|
||||
"refresh": "Vernieuwen",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Scannen...",
|
||||
"screen-corners": "Schermhoeken",
|
||||
"search": "Zoeken",
|
||||
"secondary": "Secundair",
|
||||
"security": "Beveiliging",
|
||||
"select": "Selecteer",
|
||||
"shortcuts": "Snelkoppelingen",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Stop",
|
||||
"suspend": "Onderbreken",
|
||||
"templates": "Sjablonen",
|
||||
"tertiary": "Tertiair",
|
||||
"test": "Test",
|
||||
"thresholds": "Drempels",
|
||||
"title": "Titel",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Compact",
|
||||
"density-default": "Standaard",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Ruim"
|
||||
"density-spacious": "Ruim",
|
||||
"type-floating": "Zwevend",
|
||||
"type-framed": "Omkaderd",
|
||||
"type-simple": "Eenvoudig"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klassiek",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Pas de uitstraling en positie van de balk aan.",
|
||||
"appearance-floating-description": "Toon de balk weer als een zwevende 'pil'.",
|
||||
"appearance-floating-label": "Zwevende balk",
|
||||
"appearance-frame-radius": "Binnenradius",
|
||||
"appearance-frame-settings-description": "Pas de kaderdikte en binnenste hoekradius aan",
|
||||
"appearance-frame-settings-label": "Kaderinstellingen",
|
||||
"appearance-frame-thickness": "Dikte",
|
||||
"appearance-hide-on-overview-description": "Verberg de balk en sluit panelen wanneer het compositoroverzicht actief is.",
|
||||
"appearance-hide-on-overview-label": "Balk verbergen in overzicht",
|
||||
"appearance-margins-description": "Pas de marges rond de zwevende balk aan.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Capsules tonen",
|
||||
"appearance-show-outline-description": "Toon een zichtbare rand rondom elke widget.",
|
||||
"appearance-show-outline-label": "Toon widget-omtrekken",
|
||||
"appearance-type-description": "Kies de stijl van de balk: Eenvoudig, Zwevend of Omkaderd",
|
||||
"appearance-type-label": "Balktype",
|
||||
"appearance-use-separate-opacity-description": "Maak het mogelijk om een aparte dekkingswaarde te gebruiken voor de achtergrond van de balk.",
|
||||
"appearance-use-separate-opacity-label": "Gebruik afzonderlijke balkdekking",
|
||||
"monitor-configure-widgets": "Widgets configureren",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Klembordtekst omwikkelen",
|
||||
"settings-clipboard-history-description": "Toegang tot eerder gekopieerde items vanuit de launcher.",
|
||||
"settings-clipboard-history-label": "Klembordgeschiedenis inschakelen",
|
||||
"settings-clipboard-watch-image-description": "Volledige commandoreeks die aan wl-paste wordt doorgegeven voor afbeeldingswijzigingen. (herstart vereist)",
|
||||
"settings-clipboard-watch-image-label": "Afbeelding Bewakingscommando",
|
||||
"settings-clipboard-watch-text-description": "Volledige commandoreeks die aan wl-paste wordt doorgegeven voor tekstwijzigingen. (vereist herstart)",
|
||||
"settings-clipboard-watch-text-label": "Tekst volgcommando",
|
||||
"settings-custom-launch-prefix-description": "Voorzie commando's van een aangepaste launcher-prefix (bijv. 'runapp' voor systemd-integratie).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Gebruik een aangepaste prefix om applicaties te starten in plaats van de standaardmethode.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Aangepaste startprefix inschakelen",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Weer in kalender weergeven"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Wanneer fprintd (vingerafdrukauthenticatie) actief is, kunt u met deze optie nog steeds inloggen met uw wachtwoord in plaats van een vingerafdruk.",
|
||||
"allow-password-with-fprintd-label": "Wachtwoordlogin toestaan met fprintd",
|
||||
"auto-start-auth-description": "start bijvoorbeeld automatisch de vingerafdrukauthenticatie zonder dat er een toetsaanslag of klik nodig is.",
|
||||
"auto-start-auth-label": "Automatische authenticatie bij opstarten",
|
||||
"compact-lockscreen-description": "Toon alleen de logininvoer en systeemknoppen, verberg weer- en mediawidgets.",
|
||||
"compact-lockscreen-label": "Compact vergrendelscherm",
|
||||
"lock-on-suspend-description": "Vergrendel het scherm automatisch wanneer het systeem wordt onderbroken.",
|
||||
|
||||
+639
-14
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"actions": {
|
||||
"clear-history": "Fjern historikk",
|
||||
"clear-history": "Tøm historikk",
|
||||
"close-app": "Steng {app}",
|
||||
"connect-vpn": "Kopla til {app}",
|
||||
"cycle-visualizer": "Skift visualiserar",
|
||||
@@ -31,10 +31,10 @@
|
||||
},
|
||||
"bar": {
|
||||
"active-window": {
|
||||
"colorize-icons-description": "Farga ikonet til det aktive vindauga med temafargane.",
|
||||
"colorize-icons-description": "Fargar ikonet til det aktive vindauga med temafargane.",
|
||||
"hide-mode-description": "Styrer kva miniprogrammet gjer når det ikkje er eit aktivt vindauga.",
|
||||
"scrolling-mode-description": "Styr når rullande tekst slår på for lange vindaugenamn.",
|
||||
"show-app-icon-description": "Vis programikonet attmed vindaugenamnet.",
|
||||
"scrolling-mode-description": "Styrer når rullande tekst slår på for lange vindaugenamn.",
|
||||
"show-app-icon-description": "Viser programikonet attmed vindaugenamnet.",
|
||||
"show-app-icon-label": "Vis programikon"
|
||||
},
|
||||
"audio-visualizer": {
|
||||
@@ -48,34 +48,36 @@
|
||||
"device-default": "Standard (Skjermeining)",
|
||||
"device-description": "Vel kva for batterieining å visa.",
|
||||
"device-label": "Batterieining",
|
||||
"hide-if-idle-description": "Gøym miniprogrammet når batteriet ikkje ladar opp eller ut.",
|
||||
"hide-if-idle-description": "Gøymer miniprogrammet når batteriet ikkje ladar opp eller ut.",
|
||||
"hide-if-idle-label": "Gøym når i dvale",
|
||||
"hide-if-not-detected-description": "Gøym miniprogrammet når inga batterieining er funnen.",
|
||||
"hide-if-not-detected-description": "Gøymer miniprogrammet når inga batterieining er funnen.",
|
||||
"hide-if-not-detected-label": "Gøym når ikkje funnen",
|
||||
"low-battery-threshold-description": "Vis åtvaring når batterinivået fell under dette prosenttalet.",
|
||||
"low-battery-threshold-description": "Viser åtvaring når batterinivået fell under dette prosenttalet.",
|
||||
"low-battery-threshold-label": "Varslingsterskel for lågt batterinivå",
|
||||
"show-noctalia-performance-description": "Vis ytingsmodusbrytaren for Noctalia i batterifanen.<br>Slår av skugger og animasjonar i Noctalia for å minka ressursbruk.",
|
||||
"show-noctalia-performance-description": "Viser ytingsmodusbrytaren for Noctalia i batterifanen.<br>Slår av skugger og animasjonar i Noctalia for å minka ressursbruk.",
|
||||
"show-noctalia-performance-label": "Vis ytingsmodusbrytaren for Noctalia",
|
||||
"show-power-profile-description": "Vis veljaren for energiprofil i batterifanen.",
|
||||
"show-power-profile-description": "Viser veljaren for energiprofil i batterifanen.",
|
||||
"show-power-profile-label": "Vis kontrollane for energiprofil"
|
||||
},
|
||||
"clock": {
|
||||
"clock-display-description": "Tilpass klokkevisninga ved å leggja til merke frå lista. For å bruka 12-timarsformat må du ha med 'AP'-merket.",
|
||||
"clock-display-description": "Måtar klokkevisninga ved å leggja til merke frå lista. For å bruka 12-timarsformat må du ha med 'AP'-merket.",
|
||||
"clock-display-label": "Klokkevisar",
|
||||
"custom-font-description": "Vel eigendefinert skrifttype til klokkevisaren.",
|
||||
"custom-font-label": "Eigendefinert skrifttype",
|
||||
"custom-font-placeholder": "Vel eigendefinert skrifttype...",
|
||||
"custom-font-search-placeholder": "Søk gjennom skrifttypar...",
|
||||
"horizontal-bar-description": "Tips: Skriv \\n for å byrja ei ny linje",
|
||||
"horizontal-bar-label": "Vassrett panel",
|
||||
"preview": "Førevisning",
|
||||
"tooltip-format-description": "Formater streng til hjelpeteksten som kjem opp når peikaren er over klokka. Haldt dette tomt for å bruka standardteksten.",
|
||||
"tooltip-format-label": "Hjelpetekstformat",
|
||||
"use-custom-font-description": "Overstyr standardskrifttypen med eigendefinert skrifttype til klokka.",
|
||||
"use-custom-font-description": "Overstyrer standardskrifttypen med eigendefinert skrifttype til klokka.",
|
||||
"use-custom-font-label": "Bruk eigendefinert skrifttype",
|
||||
"use-monospaced-font-description": "Når dette er på, brukar klokka fastbreiddeskrift.",
|
||||
"use-monospaced-font-label": "Bruk fastbreiddeskrift",
|
||||
"use-primary-color-description": "Når dette er på, vert primærfargen brukt for å hevja ut.",
|
||||
"use-primary-color-label": "Bruk primærfarge",
|
||||
"vertical-bar-description": "Bruk mellomrom for å skilja kvar del på ei ny linje.",
|
||||
"vertical-bar-description": "Brukar mellomrom for å skilja kvar del på ei ny linje.",
|
||||
"vertical-bar-label": "Loddrett panel"
|
||||
},
|
||||
"control-center": {
|
||||
@@ -85,7 +87,7 @@
|
||||
"enable-colorization-description": "Fargar kontrollsenterikonet med temafargane.",
|
||||
"icon-description": "Vel ikon frå biblioteket eller eigendefinert fil.",
|
||||
"select-custom-icon": "Vel eigendefinert ikon",
|
||||
"use-distro-logo-description": "Bruk kjennemerket til distribusjonen din heller enn eigendefinert ikon.",
|
||||
"use-distro-logo-description": "Brukar kjennemerket til distribusjonen din heller enn eigendefinert ikon.",
|
||||
"use-distro-logo-label": "Bruk distrokjennemerke heller enn ikon"
|
||||
},
|
||||
"custom-button": {
|
||||
@@ -111,10 +113,633 @@
|
||||
"left-click-label": "Venstreklikk",
|
||||
"left-click-update-text": "Oppdater tekst som viser seg med venstreklikk",
|
||||
"max-text-length-horizontal-description": "Øvre grense på kor mange teikn som kan visast i vassrett panel (0 for å skyla tekst).",
|
||||
"max-text-length-horizontal-label": "Øvre grense på tekstlengd (vassrett)"
|
||||
"max-text-length-horizontal-label": "Øvre grense på tekstlengd (vassrett)",
|
||||
"max-text-length-vertical-description": "Øvre grense på kor mange teikn som kan visast i loddrett panel (0 for å skyla tekst).",
|
||||
"max-text-length-vertical-label": "Øvre grense på tekstlengd (loddrett)",
|
||||
"middle-click-description": "Kommando som køyrer når knappen er midtklikka.",
|
||||
"middle-click-label": "Midtklikk",
|
||||
"middle-click-update-text": "Oppdater tekst som viser seg med midtklikk",
|
||||
"parse-json-description": "Tolkar kommandoutskrift som JSON-objekt for å setja tekst og ikon dynamisk.",
|
||||
"parse-json-label": "Tolk utskrift som JSON",
|
||||
"refresh-interval-description": "Tidsrom i millisekund",
|
||||
"refresh-interval-label": "Tidsrom mellom oppdateringar",
|
||||
"right-click-description": "Kommando som køyrer når knappen er høgreklikka.",
|
||||
"right-click-label": "Høgreklikk",
|
||||
"right-click-update-text": "Oppdater tekst som viser seg med høgreklikk",
|
||||
"show-icon-description": "Gjer miniprogramsikonet synleg eller ikkje.",
|
||||
"show-icon-label": "Vis ikon",
|
||||
"text-stream-description": "Strøymde linjer frå kommandoen viser seg som tekst på knappen.",
|
||||
"text-stream-label": "Strøym",
|
||||
"wheel-description": "Kommando som køyrer når ein brukar rullehjulet.<br>Bruk $delta for rullehjulsdeltaen i kommandoen.",
|
||||
"wheel-down-description": "Kommando som køyrer når ein rullar ned på rullehjulet.",
|
||||
"wheel-down-label": "Hjul ned-kommando",
|
||||
"wheel-label": "Rullehjul",
|
||||
"wheel-mode-separate-description": "Slår på åtskilde kommandoar for når ein rullar opp eller ned.",
|
||||
"wheel-mode-separate-label": "Skilde hjulekommandoar",
|
||||
"wheel-up-description": "Kommando som køyrer når ein rullar opp på rullehjulet.",
|
||||
"wheel-up-label": "Hjul opp-kommando",
|
||||
"wheel-update-text": "Oppdater vist tekst på rulling"
|
||||
},
|
||||
"keyboard-layout": {
|
||||
"show-icon-description": "Viser ikonet for tastaturoppsett."
|
||||
},
|
||||
"lock-keys": {
|
||||
"hide-when-off-description": "Skyler indikatoren når knappen ikkje er aktiv.",
|
||||
"hide-when-off-label": "Skyl når avslegen",
|
||||
"show-caps-lock-description": "Viser status på Caps Lock.",
|
||||
"show-caps-lock-label": "Caps Lock",
|
||||
"show-num-lock-description": "Viser status på Num Lock.",
|
||||
"show-num-lock-label": "Num Lock",
|
||||
"show-scroll-lock-description": "Viser status på Scroll Lock.",
|
||||
"show-scroll-lock-label": "Scroll Lock"
|
||||
},
|
||||
"media-mini": {
|
||||
"compact-mode-description": "Slår på eit oppsett som sparar rom i mediaavspelarpanelet.",
|
||||
"compact-mode-label": "Tettmodus",
|
||||
"hide-mode-description": "Styrer kva miniprogrammet gjer når ingenting spelar av.",
|
||||
"max-width-description": "Set ei øvre grense for kor breid miniprogrammet kan vera. Miniprogrammet minkar for å romma kortare innhald.",
|
||||
"no-active-player": "Ingen aktiv avspelar",
|
||||
"panel-section-description": "Styrer kva mediaavspelarpanelet gjer og kor det ser ut.",
|
||||
"panel-section-label": "Mediaavspelarpanel",
|
||||
"scrolling-mode-description": "Styrer når rullande tekst slår på med lange songtitlar.",
|
||||
"scrolling-mode-label": "Rullemodus",
|
||||
"show-album-art-description": "Viser albumkunst for songen som spelar av no.",
|
||||
"show-album-art-label": "Vis albumkunst",
|
||||
"show-artist-first-description": "Viser artist - tittel heller enn tittel - artist.",
|
||||
"show-artist-first-label": "Vis artist fyrst",
|
||||
"show-progress-ring-description": "Viser rund sporgangsvisar.",
|
||||
"show-progress-ring-label": "Vis rund sporgangsvisar",
|
||||
"show-visualizer-description": "Viser ljodvisualiserar når musikk spelar av.",
|
||||
"show-visualizer-label": "Vis visualiserar",
|
||||
"use-fixed-width-description": "Når dette er på, brukar miniprogrammet maksimum breidde heile tida, heller enn å måta seg til innhald dynamisk.",
|
||||
"use-fixed-width-label": "Bruk fast breidde",
|
||||
"visualizer-type-description": "Vel kva slags ljodvisualiserer du vil sjå.",
|
||||
"visualizer-type-label": "Visualiserartype"
|
||||
},
|
||||
"notification-history": {
|
||||
"hide-widget-when-zero-description": "Skyler varslingsikonet når det ikkje er varsel.",
|
||||
"hide-widget-when-zero-label": "Skyl ikon når inga varsel",
|
||||
"hide-widget-when-zero-unread-description": "Skyler varslingsikonet når det ikkje er ulesne varsel.",
|
||||
"hide-widget-when-zero-unread-label": "Skyl ikon når inga ulesne varsel.",
|
||||
"show-unread-badge-description": "Viser merke med kor mange ulesne varsel det er.",
|
||||
"show-unread-badge-label": "Vis \"ulesne\"-merke",
|
||||
"unread-badge-color-description": "Vel fargen for merket for uleste varslingar.",
|
||||
"unread-badge-color-label": "Farge på ulest merke"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Vel miniprogram å leggja til...",
|
||||
"search-placeholder": "Leita i miniprogram..."
|
||||
},
|
||||
"spacer": {
|
||||
"width-description": "Mellomrom i piksel."
|
||||
},
|
||||
"system-monitor": {
|
||||
"compact-mode-description": "Viser statistikk som små stolpediagram heller enn tekst. Stoggar oppsettet frå å skifta.",
|
||||
"compact-mode-label": "Tettmodus",
|
||||
"cpu-temperature-description": "Viser temperaturmålingar frå prosessoren om mogeleg.",
|
||||
"cpu-temperature-label": "Prosessortemperatur",
|
||||
"cpu-usage-description": "Viser prosessorbruk no i prosenttal.",
|
||||
"cpu-usage-label": "Prosessorbruk",
|
||||
"disk-path-description": "Vel kva for monteringspunkt for disk å overvaka.",
|
||||
"disk-path-label": "Filbane til disk",
|
||||
"gpu-temperature-description": "Viser temperaturmålingar frå skjermkortet om mogeleg.",
|
||||
"load-average-description": "Viser snittleg systemlast.",
|
||||
"load-average-label": "Snittleg last",
|
||||
"memory-percentage-description": "Viser minnebruk som prosenttal heller enn absolutte verdiar.",
|
||||
"memory-percentage-label": "Minne som prosent",
|
||||
"memory-usage-description": "Viser minnebruk no.",
|
||||
"memory-usage-label": "Minnebruk",
|
||||
"network-traffic-description": "Viser snøggleik på opplasting og nedlasting på nettverket.",
|
||||
"network-traffic-label": "Nettverkstraffik",
|
||||
"storage-usage-description": "Viser diskplassbruk.",
|
||||
"storage-usage-label": "Diskplassbruk",
|
||||
"swap-usage-description": "Viser swap-minnebruk.",
|
||||
"swap-usage-label": "Swap-minnebruk",
|
||||
"use-monospace-font-description": "Bruk skrift med fast breidde.",
|
||||
"use-monospace-font-label": "Fastbreiddeskrift"
|
||||
},
|
||||
"taskbar": {
|
||||
"colorize-icons-description": "Gjev ikon på oppgåvelina temafargane.",
|
||||
"hide-mode-description": "Styrer kva miniprogrammet gjer når det ikkje er samsvarande vindaugo.",
|
||||
"hide-mode-label": "Gøymemodus",
|
||||
"icon-scale-description": "Fastset skaleringsfaktor for ikon på oppgåvelina.",
|
||||
"icon-scale-label": "Ikonskalering",
|
||||
"max-width-description": "Øvre grensa på kor breid oppgåvelina kan vera i høve til skjermen, i prosent.",
|
||||
"max-width-label": "Øvre grense på breidde",
|
||||
"only-active-workspaces-description": "Viser berre appar frå aktive arbeidsrom.",
|
||||
"only-active-workspaces-label": "Berre frå aktive arbeidsrom",
|
||||
"only-same-monitor-description": "Viser berre appar frå skjermen med panelet på.",
|
||||
"only-same-monitor-label": "Berre frå same skjerm",
|
||||
"show-pinned-apps-description": "Viser feste appar frå festepunktet i oppgåvelina.",
|
||||
"show-pinned-apps-label": "Vis feste appar",
|
||||
"show-title-description": "Viser vindaugenamn i oppgåvelina.",
|
||||
"show-title-description-disabled": "Loddrett panel kan ikkje visa vindaugenamn.",
|
||||
"show-title-label": "Vis namn",
|
||||
"smart-width-description": "Måtar til breidde automatisk med talet på oppføringar.",
|
||||
"smart-width-label": "Smart breidde",
|
||||
"title-width-description": "Fastset breidde på vindaugenamn i oppgåvelina (i piksel).",
|
||||
"title-width-label": "Namnebreidde",
|
||||
"title-width-reset-tooltip": "Tilbakestill namnebreidde"
|
||||
},
|
||||
"tray": {
|
||||
"colorize-icons-description": "Gjev ikona i systempanelet temafargane.",
|
||||
"colorize-icons-label": "Farga ikon",
|
||||
"drawer-enabled-description": "Når dette er på, viser ufeste systempanelobjekt seg i eit skuffepanel.<br>Når dette er avslege, viser alle systempanelobjekt seg i rad.",
|
||||
"drawer-enabled-label": "Aktiver skuff",
|
||||
"hide-passive-description": "Når dette er på, gøymer systempanelobjekt med \"passiv\" status seg.",
|
||||
"hide-passive-label": "Gøym passive objekt"
|
||||
},
|
||||
"volume": {
|
||||
"display-mode-description": "Vel korleis dette skal visast.",
|
||||
"display-mode-label": "Visningsmodus"
|
||||
},
|
||||
"workspace": {
|
||||
"character-count-description": "Kor mange teikn som skal visast frå arbeidsromnamn (1 - 10).",
|
||||
"character-count-label": "Teikntal",
|
||||
"empty-color-description": "Set bakgrunnsfargen for tomme Workspaces.",
|
||||
"empty-color-label": "Farge for tomt arbeidsområde",
|
||||
"enable-scrollwheel-description": "Byter mellom arbeidsrom med rullehjulet på musa.",
|
||||
"enable-scrollwheel-label": "Rull for å byta arbeidsrom",
|
||||
"focused-color-description": "Set bakgrunnsfargen for det fokuserte Workspace.",
|
||||
"focused-color-label": "Fokusert arbeidsområde-farge",
|
||||
"follow-focused-screen-description": "Viser arbeidsrom frå den aktive skjermen, heller enn skjermen der panelet finn seg.",
|
||||
"follow-focused-screen-label": "Fylg aktiv skjerm",
|
||||
"grouped-border-opacity-description": "Fastset kor ugjennomsynlege grensene på arbeidsromrammene er.",
|
||||
"grouped-border-opacity-label": "Ugjennomsynlege grenser",
|
||||
"hide-unoccupied-description": "Viser ikkje arbeidsrom utan vindaugo.",
|
||||
"hide-unoccupied-label": "Gøym utan vindaugo",
|
||||
"label-mode-description": "Vel korleis etikettar for arbeidsrom skal visast.",
|
||||
"label-mode-label": "Etikettmodus",
|
||||
"occupied-color-description": "Set bakgrunnsfargen for opptekne Workspaces.",
|
||||
"occupied-color-label": "Farge for oppteke arbeidsområde",
|
||||
"reverse-scrolling-description": "Reverser retninga for arbeidsområdebytte når du skrollar.",
|
||||
"reverse-scrolling-label": "Omvendt rulling",
|
||||
"show-applications-description": "Viser applikasjonsikon innanfor kvart arbeidsrom.",
|
||||
"show-applications-label": "Vis applikasjonar",
|
||||
"show-badge-description": "Vis arbeidsområdenummer-merket i gruppert modus.",
|
||||
"show-badge-label": "Vis arbeidsområde-merke",
|
||||
"show-labels-only-when-occupied-description": "Viser etiketter for arbeidsrom berre når dei har vindaugo.",
|
||||
"show-labels-only-when-occupied-label": "Vis etikettar berre med vindaugo",
|
||||
"unfocused-icons-opacity-description": "Fastset kor ugjennomsynlege ufokuserte applikasjonsikon er.",
|
||||
"unfocused-icons-opacity-label": "Ugjennomsynlege ufokuserte ikon"
|
||||
}
|
||||
},
|
||||
"battery": {
|
||||
"battery-health": "Batterihelse",
|
||||
"battery-level": "Batterinivå",
|
||||
"capacity-level": "Kapasitet: {level}",
|
||||
"charging-rate": "Ladesnøggleik: {rate} W",
|
||||
"discharging-rate": "Utladingssnøggleik: {rate} W",
|
||||
"health": "Helse: {percent}%",
|
||||
"inhibit-idle-description": "Held systemet vake.",
|
||||
"no-battery-detected": "Inga batteri funnen",
|
||||
"plugged-in": "Tilkopla",
|
||||
"power-profile": "Energiprofil",
|
||||
"time-left": "Tid att: {tid}",
|
||||
"time-until-full": "Tid til full: {tid}"
|
||||
},
|
||||
"bluetooth": {
|
||||
"panel": {
|
||||
"available-devices": "Tilgjengelege einingar",
|
||||
"blocked": "Blokkert",
|
||||
"connected-devices": "Kopla einingar",
|
||||
"device-address": "Einingadresse",
|
||||
"disabled": "Bluetooth er fråkopla",
|
||||
"discoverable": "Finnande",
|
||||
"enable-message": "Slå på Bluetooth for å sjå tilgjengelege einingar.",
|
||||
"known-devices": "Kjende einingar",
|
||||
"no-devices": "Ingen einingar funne",
|
||||
"paired-devices": "Kopla einingar",
|
||||
"pairing-mode": "Sjå at eininga di er i koplingsmodus.",
|
||||
"scanning": "Leitar etter einingar...",
|
||||
"signal-text-excellent": "Tilkopling: Framifrå",
|
||||
"signal-text-fair": "Tilkopling: Grei",
|
||||
"signal-text-good": "Tilkopling: God",
|
||||
"signal-text-poor": "Tilkopling: Dåleg",
|
||||
"signal-text-unknown": "Tilkopling: Ukjend",
|
||||
"signal-text-very-poor": "Tilkopling: Svært dåleg"
|
||||
}
|
||||
},
|
||||
"changelog": {
|
||||
"error": {
|
||||
"fetch-failed": "Kan ikkje lasta inn historikk. Prøv att seinare.",
|
||||
"rate-limit": "Du har nått lastgrensa på GitHub. Prøv att om nokre minutt."
|
||||
},
|
||||
"panel": {
|
||||
"buttons-discord": "Vert med på Discorden vår",
|
||||
"buttons-dismiss": "Greitt",
|
||||
"buttons-feedback": "Gjev attermelding",
|
||||
"empty": "Versjonsnotatar er ikkje tilgjengelege enno.",
|
||||
"highlight-title": "Høgdepunkt",
|
||||
"released": "Gjeven ut på {date}",
|
||||
"subtitle-fresh": "Takk for at du installerte Noctalia! Her er det som er med i denne utgåva.",
|
||||
"subtitle-updated": "Oppdatert frå {previousVersion}",
|
||||
"title": "Nytt i {version}",
|
||||
"version": "Versjon {version}",
|
||||
"version-new-user": "Fersk installasjon"
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
"error": "Feil",
|
||||
"on-surface": "På Yta",
|
||||
"primary": "Primær",
|
||||
"secondary": "Sekundær",
|
||||
"tertiary": "Tertiær"
|
||||
},
|
||||
"common": {
|
||||
"actions": "Handlingar",
|
||||
"add": "Legg til",
|
||||
"appearance": "Utsjånad",
|
||||
"apply": "Bruk",
|
||||
"automation": "Automatisering",
|
||||
"available": "Tilgjengeleg",
|
||||
"back": "Attende",
|
||||
"battery": "Batteri",
|
||||
"bluetooth": "Bluetooth",
|
||||
"brightness": "Ljosstyrke",
|
||||
"browse": "Blad",
|
||||
"calendar": "Kalender",
|
||||
"calendar-panel": "Kalenderpanel",
|
||||
"cancel": "Bryt av",
|
||||
"cards": "Kort",
|
||||
"charging": "Ladar",
|
||||
"clear": "Tøm",
|
||||
"clipboard": "Utklippstavle",
|
||||
"close": "Steng",
|
||||
"color-muted": "Dempa",
|
||||
"colors": "Fargar",
|
||||
"command": "Kommando",
|
||||
"connect": "Kopla til",
|
||||
"connected": "Kopla til",
|
||||
"connecting": "Koplar til...",
|
||||
"continue": "Hald fram",
|
||||
"contributors": "Medverkarar",
|
||||
"copied-to-clipboard": "Kopiert til utklippstavla",
|
||||
"countdown": "Nedteljing",
|
||||
"date": "Dato",
|
||||
"default": "Standard",
|
||||
"delete": "Slett",
|
||||
"devices": "Einingar",
|
||||
"disabled": "Avslegen",
|
||||
"discharging": "Ladar ut",
|
||||
"disconnect": "Kopla frå",
|
||||
"disconnected": "Kopla frå",
|
||||
"disconnecting": "Koplar frå...",
|
||||
"download": "Last ned",
|
||||
"duration": "Varing",
|
||||
"edit": "Endra",
|
||||
"enabled": "Påslegen",
|
||||
"events": "Arrangement",
|
||||
"execute": "Utfør",
|
||||
"faithful": "Tru",
|
||||
"focus": "Fokus",
|
||||
"frequency": "Frekvens",
|
||||
"gateway": "Port",
|
||||
"general": "Generell",
|
||||
"height": "Høgd",
|
||||
"hibernate": "Set i full dvale",
|
||||
"history": "Historikk",
|
||||
"icon": "Ikon",
|
||||
"idle": "Inaktiv",
|
||||
"info": "Info",
|
||||
"input": "Inndata",
|
||||
"install": "Installer",
|
||||
"installed": "Installert",
|
||||
"interface": "Grensesnitt",
|
||||
"internet": "Internett",
|
||||
"language": "Mål",
|
||||
"loading": "Lastar inn...",
|
||||
"local": "Lokal",
|
||||
"location": "Stad",
|
||||
"lock": "Lås",
|
||||
"logout": "Skriv ut",
|
||||
"look": "Sjå",
|
||||
"media": "Media",
|
||||
"media-player": "Mediaavspelar",
|
||||
"memory": "Minne",
|
||||
"monitors": "Skjermar",
|
||||
"network": "Nettverk",
|
||||
"next": "Neste",
|
||||
"night-light": "Natteljos",
|
||||
"no": "Nei",
|
||||
"no-results": "Ikkje noko utfall",
|
||||
"no-summary": "Ikkje noko samandrag",
|
||||
"none": "Ingen",
|
||||
"not-found": "Ikkje funne",
|
||||
"notifications": "Varsel",
|
||||
"official": "Offisiell",
|
||||
"on-surface": "På overflata",
|
||||
"output": "Utdata",
|
||||
"pair": "Par",
|
||||
"paired": "Para",
|
||||
"pairing": "Parar...",
|
||||
"panels": "Panel",
|
||||
"password": "Passord",
|
||||
"pause": "Pause",
|
||||
"pin": "Fest",
|
||||
"play": "Spel",
|
||||
"polling": "Avlesing",
|
||||
"position": "Posisjon",
|
||||
"previous": "Førre",
|
||||
"primary": "Primær",
|
||||
"random": "Tilfelleleg",
|
||||
"reboot": "Start å nyo",
|
||||
"refresh": "Lasta inn å nyo",
|
||||
"required": "(krevst)",
|
||||
"reset": "Attendestill",
|
||||
"result-count": "{count} utfall",
|
||||
"result-count-plural": "{count} utfall",
|
||||
"resume": "Tak opp att",
|
||||
"save": "Lagra",
|
||||
"scanning": "Leitar...",
|
||||
"screen-corners": "Skjermhyrne",
|
||||
"search": "Søk",
|
||||
"secondary": "Sekundær",
|
||||
"security": "Trygging",
|
||||
"select": "Vel",
|
||||
"shortcuts": "Beinvegar",
|
||||
"shutdown": "Slå av",
|
||||
"signal": "Dekning",
|
||||
"sound": "Ljod",
|
||||
"sources": "Kjelder",
|
||||
"start": "Start",
|
||||
"stop": "Stogg",
|
||||
"suspend": "Set i lett dvale",
|
||||
"templates": "Malar",
|
||||
"tertiary": "Tertiær",
|
||||
"test": "Test",
|
||||
"thresholds": "Tersklar",
|
||||
"title": "Tittel",
|
||||
"toast": "Skjermvarsel",
|
||||
"trusted": "Lita på",
|
||||
"uninstall": "Desinstaller",
|
||||
"unknown": "Ukjend",
|
||||
"unpair": "Par frå",
|
||||
"unpin": "Fest av",
|
||||
"update": "Oppdater",
|
||||
"upload": "Lasta opp",
|
||||
"version": "Versjon",
|
||||
"vibrant": "Livleg",
|
||||
"visualizer": "Visualiserar",
|
||||
"volume": "Ljodstyrke",
|
||||
"volumes": "Ljodstyrke",
|
||||
"wallpaper": "Bakgrunnsbilete",
|
||||
"weather": "Vêr",
|
||||
"weather-loading": "Lastar inn vêr",
|
||||
"week": "Veke",
|
||||
"widgets": "Miniprogram",
|
||||
"width": "Breidde",
|
||||
"yes": "Ja"
|
||||
},
|
||||
"control-center": {
|
||||
"power-profile": {
|
||||
"tooltip-action": "Energiprofil",
|
||||
"tooltip-disabled": "Installer power-profiles-daemon for å bruka energiprofil"
|
||||
},
|
||||
"wifi": {
|
||||
"label-disconnected": "Kopla frå Wi-Fi",
|
||||
"label-ethernet": "Ethernet"
|
||||
}
|
||||
},
|
||||
"display-modes": {
|
||||
"always-hide": "Alltid gøym",
|
||||
"always-show": "Alltid vis",
|
||||
"force-open": "Tving open",
|
||||
"on-hover": "Ved sviv"
|
||||
},
|
||||
"hide-modes": {
|
||||
"hidden": "Gøym når tom",
|
||||
"idle": "Gøym når inaktiv",
|
||||
"transparent": "Gjennomsynleg når tom",
|
||||
"visible": "Alltid synleg"
|
||||
},
|
||||
"launcher": {
|
||||
"categories": {
|
||||
"all": "Alt",
|
||||
"audiovideo": "Ljod & video",
|
||||
"chat": "Samtale",
|
||||
"development": "Utvikling",
|
||||
"education": "Opplæring",
|
||||
"emoji-activity": "Aktivitetar",
|
||||
"emoji-animals": "Dyr",
|
||||
"emoji-flags": "Flagg",
|
||||
"emoji-food": "Mat og drikke",
|
||||
"emoji-nature": "Natur",
|
||||
"emoji-objects": "Ting",
|
||||
"emoji-people": "Folk & kropp",
|
||||
"emoji-recent": "Nyleg",
|
||||
"emoji-symbols": "Symbol",
|
||||
"emoji-travel": "Reiser & stader",
|
||||
"game": "Spel",
|
||||
"graphics": "Grafikk",
|
||||
"misc": "Ymis",
|
||||
"office": "Kontor",
|
||||
"pinned": "Feste",
|
||||
"system": "System",
|
||||
"webbrowser": "Nettlesar"
|
||||
},
|
||||
"providers": {
|
||||
"applications": "Applikasjonar",
|
||||
"calculator": "Kalkulator",
|
||||
"calculator-deprecated": "\">calc\"-kommandoen er deprekert og skal snart slettast. Skriv heller matteuttrykk beinveges i søk.",
|
||||
"calculator-description": "Kalkulator — reknar ut matematiske uttrykk",
|
||||
"calculator-enter-expression": "Skriv inn eit matematisk uttrykk",
|
||||
"calculator-press-enter-to-copy": "Trykk Enter for å kopiera utfallet",
|
||||
"clipboard": "Utklippsbok",
|
||||
"clipboard-clear-description": "Tøm heile utklippsboka",
|
||||
"clipboard-clear-description-full": "Slett alt frå utklippsboka",
|
||||
"clipboard-clear-history": "Tøm utklippsboka",
|
||||
"clipboard-delete": "Slett oppføring på utklippstavla",
|
||||
"clipboard-history-disabled": "Utklippsboka avslegen",
|
||||
"clipboard-history-disabled-description": "Slå på utklippsboka i innstillingane eller installer cliphist",
|
||||
"clipboard-loading": "Lastar inn utklippsbok...",
|
||||
"clipboard-search-description": "Leita i utklippsboka",
|
||||
"command-description": "Køyr skalkommandoar",
|
||||
"emoji": "Emojiveljar",
|
||||
"emoji-loading": "Lastar inn emojiar...",
|
||||
"emoji-loading-description": "Vent litt",
|
||||
"emoji-no-recent": "Ingen nylege emojiar enno",
|
||||
"emoji-search-description": "Leita i og kopiera emojiar"
|
||||
}
|
||||
},
|
||||
"lock-screen": {
|
||||
"authenticating": "Autentiserer...",
|
||||
"password": "Skriv passordet ditt...",
|
||||
"restart": "Start å nyo",
|
||||
"shut-down": "Slå av"
|
||||
},
|
||||
"notifications": {
|
||||
"panel": {
|
||||
"click-to-expand": "Klikk for å utvida",
|
||||
"description": "Varsla dine kjem opp her når dei kjem inn.",
|
||||
"no-notifications": "Ingen varsel"
|
||||
},
|
||||
"range": {
|
||||
"earlier": "Tidlegare",
|
||||
"today": "I dag",
|
||||
"yesterday": "I går"
|
||||
},
|
||||
"time": {
|
||||
"diff-d": "For 1 dag sidan",
|
||||
"diff-dd": "For {diff} dagar sidan",
|
||||
"diff-h": "For 1 time sidan",
|
||||
"diff-hh": "For {diff} timar sidan",
|
||||
"diff-m": "For 1 minutt sidan",
|
||||
"diff-mm": "For {diff} minutt sidan",
|
||||
"now": "no"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"bar": {
|
||||
"density-comfortable": "Høveleg",
|
||||
"density-compact": "Tett",
|
||||
"density-default": "Standard",
|
||||
"density-mini": "Ørliten",
|
||||
"density-spacious": "Romsleg"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klassisk",
|
||||
"quick-settings-style-modern": "Moderne"
|
||||
},
|
||||
"frame-rates-fps": "{fps} FPS",
|
||||
"scrolling-modes": {
|
||||
"always": "Alltid rull",
|
||||
"hover": "Rull ved sviv",
|
||||
"never": "Aldri rull"
|
||||
},
|
||||
"session-menu-grid-layout": {
|
||||
"grid": "Rutenett",
|
||||
"single-row": "Einskild rad"
|
||||
},
|
||||
"settings-panel-mode": {
|
||||
"attached": "Panel knytt til lina",
|
||||
"centered": "Panel i midten",
|
||||
"window": "Utskilt vindauga"
|
||||
},
|
||||
"visualizer-types": {
|
||||
"linear": "Lineær",
|
||||
"mirrored": "Spegla",
|
||||
"wave": "Bylgja"
|
||||
},
|
||||
"visualizer-visibility": {
|
||||
"with-background": "Einast med bakgrunn"
|
||||
},
|
||||
"workspace-labels": {
|
||||
"index": "Register",
|
||||
"index-and-name": "Register og namn",
|
||||
"name": "Namn"
|
||||
}
|
||||
},
|
||||
"panels": {
|
||||
"about": {
|
||||
"changelog": "Sjå endringar",
|
||||
"contributors-desc": "Takk og ære til den {count} <b>framifrå</b> medverkaren vår!",
|
||||
"contributors-description-plural": "Takk og ære til alle dei {count} <b>framifrå</b> medverkarane våre!",
|
||||
"copy-info": "Kopier info",
|
||||
"info-copied": "Info kopiert til utklippstavla",
|
||||
"noctalia-desc": "Eit lettfram og minimalistisk skrivebordsskal skapa med omhug for Wayland, bygt med Quickshell.",
|
||||
"noctalia-git-commit": "Git commit:",
|
||||
"noctalia-installed-version": "Installert versjon:",
|
||||
"noctalia-latest-version": "Nyaste versjon:",
|
||||
"noctalia-title": "Noctaliaskal",
|
||||
"privacy-policy": "Personvernfråsegn",
|
||||
"support": "Støtt oss",
|
||||
"system-cpu": "Prosessor:",
|
||||
"system-disk": "Disk:",
|
||||
"system-gpu": "Skjermkort:",
|
||||
"system-host": "Vert:",
|
||||
"system-install-hint": "Installer fastfetch for å sjå systemopplysningar",
|
||||
"system-kernel": "Kjerne:",
|
||||
"system-loading": "Lastar inn systemopplysningar...",
|
||||
"system-memory": "Minne:",
|
||||
"system-monitor": "Skjerm:",
|
||||
"system-not-installed": "fasfetch er ikkje installert",
|
||||
"system-os": "OS:",
|
||||
"system-packages": "Pakkar:",
|
||||
"system-product": "Vare:",
|
||||
"system-title": "Systemopplysningar",
|
||||
"system-uptime": "Driftstid:",
|
||||
"system-wm": "WM:",
|
||||
"telemetry-data-copied": "Telemetri kopiert til utklippstavla",
|
||||
"telemetry-desc": "Hjelp oss gjera Noctalia betre ved å dela anonyme systemopplysningar (skjermoppløysing, kompositor, Linux-utgåve). Sende ein gong med maskinoppstart, inga sporing, data sletta automatisk etter 30 dagar.",
|
||||
"telemetry-enabled": "Send anonyme systemopplysningar",
|
||||
"telemetry-show-data": "Sjå data",
|
||||
"telemetry-title": "Personvern",
|
||||
"title": "Om",
|
||||
"up-to-date": "Du er oppdatert!",
|
||||
"update-available": "Oppdatering tilgjengeleg",
|
||||
"view-commit": "Sjå commit på GitHub"
|
||||
},
|
||||
"audio": {
|
||||
"devices-desc": "Set opp tilgjengeleg ljodinn- og ljoduteiningar.",
|
||||
"devices-input-device-description": "Vel ljodinneininga du vil setja opp.",
|
||||
"devices-input-device-label": "Inneining",
|
||||
"devices-output-device-description": "Vel ljoduteininga du vil setja opp.",
|
||||
"devices-output-device-label": "Uteining",
|
||||
"devices-title": "Ljodeiningar",
|
||||
"external-mixer-description": "Skriv inn kommandoen eller applikasjonsbana som køyrer når du slår på funksjonen for den eksterne ljodmiksaren.",
|
||||
"external-mixer-label": "Kommando for ekstern ljodmiksar",
|
||||
"external-mixer-placeholder": "pwvucontrol || pavucontrol",
|
||||
"media-desc": "Set mediaapplikasjonane du likar best og dei du vil ignorera.",
|
||||
"media-excluded-player-description": "Skriv inn lykelord for avspelarar som systemet skal ignorera. Kvart lykel ord skal vera på ei ny line.",
|
||||
"media-excluded-player-label": "Borttekne avspelar",
|
||||
"media-excluded-player-placeholder": "skriv substring og klikk på +",
|
||||
"media-frame-rate-description": "Høgre frekvens er jamnare men krev fleire ressursar.",
|
||||
"media-frame-rate-label": "Biletfrekvens",
|
||||
"media-primary-player-description": "Skriv lykelord for å kjenna att avspelaren du brukar mest.",
|
||||
"media-primary-player-label": "Hovudspelar",
|
||||
"media-primary-player-placeholder": "t.d. spotify, vlc, mpv",
|
||||
"media-scrolling-speed-description": "Tida det tek for tittelen å blada frå start til ende, i sekund.",
|
||||
"media-scrolling-speed-label": "Bladefart",
|
||||
"media-scrolling-title-description": "Slå på varig blading for lange mediatitlar.",
|
||||
"media-scrolling-title-label": "Bladande tittel",
|
||||
"media-title": "Mediaavspelarar",
|
||||
"on-middle-clicked-description": "Kommando som køyr når knappen er midtklikka.",
|
||||
"panel-applications-empty": "Ingen applikasjonar spelar av ljod no",
|
||||
"title": "Ljod",
|
||||
"visualizer-type-description": "Vel visualiseringstypen når ein spelar av media.",
|
||||
"visualizer-type-label": "Visualiseringstype",
|
||||
"volumes-desc": "Endrar kontrollane for ljodstyrke og ljodnivå",
|
||||
"volumes-input-volume-description": "Mikrofon inn-nivå",
|
||||
"volumes-mute-input-description": "Demp standard ljodinneining (mikrofon).",
|
||||
"volumes-mute-input-label": "Demp ljodinndata",
|
||||
"volumes-mute-output-description": "Demp hovudljoduteininga på systemet",
|
||||
"volumes-mute-output-label": "Demp ljodutdata",
|
||||
"volumes-output-volume-description": "Ljodstyrke på heile systemet",
|
||||
"volumes-step-size-description": "Endra kor mykje ljodstyrke endrar seg for kvart steg (rullehjul, beinknappar).",
|
||||
"volumes-step-size-label": "Steg for ljodstyrke",
|
||||
"volumes-volume-feedback-description": "Spel av svarljod når ein endrar på ljodstyrke",
|
||||
"volumes-volume-feedback-label": "Spel av svarljod med ljodstyrke",
|
||||
"volumes-volume-overdrive-description": "Tillèt at ljodstyrke kan gå over 100%. Ikkje alltid støtta av maskinvare.",
|
||||
"volumes-volume-overdrive-label": "Tillat overdrift på ljodstyrke"
|
||||
},
|
||||
"launcher": {
|
||||
"clipboard-desc": "Sjå og styra utklippsboka di frå programveljaren.",
|
||||
"settings-clipboard-watch-image-description": "Heil kommandostreng sendt til wl-paste for bildeendringar. (krev omstart)",
|
||||
"settings-clipboard-watch-image-label": "Biletovervakingskommando",
|
||||
"settings-clipboard-watch-text-description": "Fullstendig kommandostreng sendt til wl-paste for tekstendringer. (krever omstart)",
|
||||
"settings-clipboard-watch-text-label": "Tekstovervakingskommando"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Når fprintd (fingeravtrykkautentisering) er aktiv, lar dette alternativet deg framleis logge inn med passordet ditt i staden for eit fingeravtrykk.",
|
||||
"allow-password-with-fprintd-label": "Tillat passordpålogging med fprintd",
|
||||
"auto-start-auth-description": "t.d. startar automatisk fingeravtrykksautentisering utan å krevje eit tastetrykk eller eit knappetrykk.",
|
||||
"auto-start-auth-label": "Autostart autentisering"
|
||||
}
|
||||
},
|
||||
"toast": {
|
||||
"donation-opened": "Donasjonsside opna i nettlesaren din"
|
||||
},
|
||||
"widgets": {
|
||||
"datetime-tokens": {
|
||||
"common-12hour-time-minutes": "Tid i 12-timar med minutt",
|
||||
"common-24hour-time-minutes": "Tid i 24-timar med minutt",
|
||||
"common-24hour-time-seconds": "Tid i 24-timar med sekund",
|
||||
"common-european-date": "Europeisk datoformat",
|
||||
"common-iso-date": "ISO datoformat",
|
||||
"common-us-date": "Amerikansk datoformat",
|
||||
"common-weekday-date": "Vekedag med dato",
|
||||
"common-weekday-month-day": "Vekedag, månad og dag"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Ukryj ikonę powiadomień, gdy nie ma nieprzeczytanych powiadomień.",
|
||||
"hide-widget-when-zero-unread-label": "Ukryj ikonę bez nieprzeczytanych",
|
||||
"show-unread-badge-description": "Wyświetl plakietkę z liczbą nieprzeczytanych powiadomień.",
|
||||
"show-unread-badge-label": "Pokaż plakietkę nieprzeczytanych"
|
||||
"show-unread-badge-label": "Pokaż plakietkę nieprzeczytanych",
|
||||
"unread-badge-color-description": "Wybierz kolor dla plakietki nieprzeczytanych powiadomień.",
|
||||
"unread-badge-color-label": "Kolor plakietki nieprzeczytanych"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Wybierz widżet do dodania...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Liczba znaków do wyświetlenia z nazw obszarów roboczych (1-10).",
|
||||
"character-count-label": "Liczba znaków",
|
||||
"empty-color-description": "Ustaw kolor tła dla pustych Workspaceów.",
|
||||
"empty-color-label": "Kolor pustego obszaru roboczego",
|
||||
"enable-scrollwheel-description": "Przełączaj między obszarami roboczymi za pomocą kółka myszy.",
|
||||
"enable-scrollwheel-label": "Przewiń, aby przełączyć obszary",
|
||||
"focused-color-description": "Ustaw kolor tła dla aktywnego Workspace.",
|
||||
"focused-color-label": "Kolor aktywnego obszaru roboczego",
|
||||
"follow-focused-screen-description": "Wyświetl obszary robocze z aktualnie aktywnego ekranu, zamiast ekranu, na którym znajduje się pasek.",
|
||||
"follow-focused-screen-label": "Podążaj za skupionym ekranem",
|
||||
"grouped-border-opacity-description": "Ustaw poziom krycia dla obramowań kontenerów obszaru roboczego.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Ukryj nieobsadzone",
|
||||
"label-mode-description": "Wybierz sposób wyświetlania etykiet obszarów roboczych.",
|
||||
"label-mode-label": "Tryb etykiet",
|
||||
"occupied-color-description": "Ustaw kolor tła dla zajętych Workspace'ów.",
|
||||
"occupied-color-label": "Kolor zajętego obszaru roboczego",
|
||||
"reverse-scrolling-description": "Odwróć kierunek przełączania obszarów roboczych podczas przewijania.",
|
||||
"reverse-scrolling-label": "Odwróć przewijanie",
|
||||
"show-applications-description": "Wyświetl ikony aplikacji wewnątrz każdego obszaru roboczego.",
|
||||
"show-applications-label": "Pokaż aplikacje",
|
||||
"show-badge-description": "Pokaż plakietkę z numerem obszaru roboczego w trybie grupowym.",
|
||||
"show-badge-label": "Pokaż odznakę obszaru roboczego",
|
||||
"show-labels-only-when-occupied-description": "Pokazuj etykiety obszarów roboczych tylko wtedy, gdy zawierają okna.",
|
||||
"show-labels-only-when-occupied-label": "Pokaż etykiety tylko gdy obsadzone",
|
||||
"unfocused-icons-opacity-description": "Ustaw poziom przezroczystości dla ikon nieaktywnych aplikacji.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Nie znaleziono",
|
||||
"notifications": "Powiadomienia",
|
||||
"official": "Oficjalne",
|
||||
"on-surface": "Na powierzchni",
|
||||
"output": "Wyjście",
|
||||
"pair": "Paruj",
|
||||
"paired": "Sparowane",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Odpytywanie",
|
||||
"position": "Pozycja",
|
||||
"previous": "Poprzedni",
|
||||
"primary": "Podstawowy",
|
||||
"random": "Losowy",
|
||||
"reboot": "Restart",
|
||||
"refresh": "Odśwież",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Skanowanie...",
|
||||
"screen-corners": "Narożniki ekranu",
|
||||
"search": "Szukaj",
|
||||
"secondary": "Dodatkowy",
|
||||
"security": "Bezpieczeństwo",
|
||||
"select": "Wybierz",
|
||||
"shortcuts": "Skróty",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Stop",
|
||||
"suspend": "Wstrzymaj",
|
||||
"templates": "Szablony",
|
||||
"tertiary": "Trzeciorzędowy",
|
||||
"test": "Test",
|
||||
"thresholds": "Progi",
|
||||
"title": "Tytuł",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Kompaktowy",
|
||||
"density-default": "Domyślny",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Przestronny"
|
||||
"density-spacious": "Przestronny",
|
||||
"type-floating": "Pływający",
|
||||
"type-framed": "Obramowany",
|
||||
"type-simple": "Prosty"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klasyczny",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Dostosuj wygląd i pozycję paska.",
|
||||
"appearance-floating-description": "Wyświetl pasek jako pływającą 'pigułkę'.",
|
||||
"appearance-floating-label": "Pływający pasek",
|
||||
"appearance-frame-radius": "Promień wewnętrzny",
|
||||
"appearance-frame-settings-description": "Dostosuj grubość ramki i wewnętrzny promień narożników",
|
||||
"appearance-frame-settings-label": "Ustawienia ramki",
|
||||
"appearance-frame-thickness": "Grubość",
|
||||
"appearance-hide-on-overview-description": "Ukryj pasek i zamknij panele, gdy aktywny jest przegląd kompozytora.",
|
||||
"appearance-hide-on-overview-label": "Ukryj pasek w przeglądzie",
|
||||
"appearance-margins-description": "Dostosuj marginesy wokół pływającego paska.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Pokaż kapsułę",
|
||||
"appearance-show-outline-description": "Wyświetla widoczne obramowanie wokół każdego widżetu.",
|
||||
"appearance-show-outline-label": "Pokaż obramowanie widżetów",
|
||||
"appearance-type-description": "Wybierz styl paska: Prosty, Pływający lub Obramowany",
|
||||
"appearance-type-label": "Typ paska",
|
||||
"appearance-use-separate-opacity-description": "Umożliwia użycie oddzielnej wartości krycia dla tła paska.",
|
||||
"appearance-use-separate-opacity-label": "Użyj osobnej przezroczystości słupków",
|
||||
"monitor-configure-widgets": "Skonfiguruj widżety",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Zawijaj tekst ze schowka",
|
||||
"settings-clipboard-history-description": "Dostęp do wcześniej skopiowanych elementów z poziomu launchera.",
|
||||
"settings-clipboard-history-label": "Włącz historię schowka",
|
||||
"settings-clipboard-watch-image-description": "Pełny ciąg poleceń przekazywany do wl-paste dla zmian obrazu. (wymaga ponownego uruchomienia)",
|
||||
"settings-clipboard-watch-image-label": "Polecenie Monitorowania Obrazów",
|
||||
"settings-clipboard-watch-text-description": "Pełny ciąg polecenia przekazany do wl-paste dla zmian tekstu. (wymaga ponownego uruchomienia)",
|
||||
"settings-clipboard-watch-text-label": "Polecenie monitorowania tekstu",
|
||||
"settings-custom-launch-prefix-description": "Poprzedzaj polecenia własnym prefiksem (np. 'runapp' dla integracji z systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Używaj własnego prefiksu do uruchamiania aplikacji zamiast metody domyślnej.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Włącz własny prefiks",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Wyświetlaj pogodę w kalendarzu"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Gdy fprintd (uwierzytelnianie odciskiem palca) jest aktywne, ta opcja pozwala nadal logować się za pomocą hasła zamiast odcisku palca.",
|
||||
"allow-password-with-fprintd-label": "Zezwól na logowanie hasłem za pomocą fprintd",
|
||||
"auto-start-auth-description": "np. automatycznie uruchamia uwierzytelnianie odciskiem palca bez konieczności naciskania klawisza lub klikania przycisku.",
|
||||
"auto-start-auth-label": "Automatyczne uruchamianie uwierzytelniania",
|
||||
"compact-lockscreen-description": "Pokaż tylko logowanie i kontrolki systemowe, ukrywając widżety pogody i mediów.",
|
||||
"compact-lockscreen-label": "Kompaktowy ekran blokady",
|
||||
"lock-on-suspend-description": "Automatycznie blokuj ekran podczas uśpienia systemu.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Ocultar o ícone de notificações quando não houver notificações não lidas.",
|
||||
"hide-widget-when-zero-unread-label": "Ocultar ícone sem notificações não lidas",
|
||||
"show-unread-badge-description": "Exibir um distintivo mostrando o número de notificações não lidas.",
|
||||
"show-unread-badge-label": "Mostrar distintivo de não lidos"
|
||||
"show-unread-badge-label": "Mostrar distintivo de não lidos",
|
||||
"unread-badge-color-description": "Selecione a cor para o emblema de notificação não lida.",
|
||||
"unread-badge-color-label": "Cor do distintivo de não lido"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Selecione um widget para adicionar...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Número de caracteres a exibir dos nomes de espaços de trabalho (1-10).",
|
||||
"character-count-label": "Número de caracteres",
|
||||
"empty-color-description": "Definir a cor de fundo para Workspaces vazios.",
|
||||
"empty-color-label": "Cor do espaço de trabalho vazio",
|
||||
"enable-scrollwheel-description": "Alternar entre áreas de trabalho usando a roda do mouse.",
|
||||
"enable-scrollwheel-label": "Role para alternar entre áreas de trabalho",
|
||||
"focused-color-description": "Definir a cor de fundo para o Workspace focado.",
|
||||
"focused-color-label": "Cor do workspace focado",
|
||||
"follow-focused-screen-description": "Exibir áreas de trabalho da tela atualmente em foco, em vez da tela onde a barra está localizada.",
|
||||
"follow-focused-screen-label": "Seguir tela em foco",
|
||||
"grouped-border-opacity-description": "Definir o nível de opacidade para as bordas do contêiner do espaço de trabalho.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Ocultar desocupados",
|
||||
"label-mode-description": "Escolher como os rótulos de espaço de trabalho são exibidos.",
|
||||
"label-mode-label": "Modo de rótulo",
|
||||
"occupied-color-description": "Definir a cor de fundo para Workspaces ocupados.",
|
||||
"occupied-color-label": "Cor do espaço de trabalho ocupado",
|
||||
"reverse-scrolling-description": "Inverter a direção da troca de áreas de trabalho ao rolar.",
|
||||
"reverse-scrolling-label": "Rolagem invertida",
|
||||
"show-applications-description": "Exibir ícones de aplicativos dentro de cada espaço de trabalho.",
|
||||
"show-applications-label": "Mostrar aplicativos",
|
||||
"show-badge-description": "Mostrar o selo do número da área de trabalho no modo agrupado.",
|
||||
"show-badge-label": "Mostrar selo da área de trabalho",
|
||||
"show-labels-only-when-occupied-description": "Mostrar rótulos de área de trabalho apenas quando contiverem janelas.",
|
||||
"show-labels-only-when-occupied-label": "Mostrar rótulos apenas quando ocupado",
|
||||
"unfocused-icons-opacity-description": "Definir o nível de opacidade para ícones de aplicativos não focados.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Não encontrado",
|
||||
"notifications": "Notificações",
|
||||
"official": "Oficial",
|
||||
"on-surface": "Na Superfície",
|
||||
"output": "Saída",
|
||||
"pair": "Emparelhar",
|
||||
"paired": "Emparelhado",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Sondagem",
|
||||
"position": "Posição",
|
||||
"previous": "Anterior",
|
||||
"primary": "Primário",
|
||||
"random": "Aleatório",
|
||||
"reboot": "Reiniciar",
|
||||
"refresh": "Atualizar",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "A digitalização está em andamento...",
|
||||
"screen-corners": "Cantos da tela",
|
||||
"search": "Pesquisar",
|
||||
"secondary": "Secundário",
|
||||
"security": "Segurança",
|
||||
"select": "Selecionar",
|
||||
"shortcuts": "Atalhos",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Pare",
|
||||
"suspend": "Suspender",
|
||||
"templates": "Modelos",
|
||||
"tertiary": "Terciário",
|
||||
"test": "Teste",
|
||||
"thresholds": "Limiares",
|
||||
"title": "Título",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Compacta",
|
||||
"density-default": "Padrão",
|
||||
"density-mini": "Mini",
|
||||
"density-spacious": "Espaçoso(a)"
|
||||
"density-spacious": "Espaçoso(a)",
|
||||
"type-floating": "Flutuante",
|
||||
"type-framed": "Emoldurada",
|
||||
"type-simple": "Simples"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Clássico",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Personalize a aparência e a posição da barra.",
|
||||
"appearance-floating-description": "Exibe a barra como uma 'pílula' flutuante.",
|
||||
"appearance-floating-label": "Barra flutuante",
|
||||
"appearance-frame-radius": "Raio Interno",
|
||||
"appearance-frame-settings-description": "Ajuste a espessura da moldura e o raio interno",
|
||||
"appearance-frame-settings-label": "Configurações da Moldura",
|
||||
"appearance-frame-thickness": "Espessura",
|
||||
"appearance-hide-on-overview-description": "Ocultar a barra e fechar os painéis quando a visão geral do compositor estiver ativa.",
|
||||
"appearance-hide-on-overview-label": "Ocultar barra na visão geral",
|
||||
"appearance-margins-description": "Ajuste as margens ao redor da barra flutuante.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Mostrar cápsula",
|
||||
"appearance-show-outline-description": "Exibe uma borda visível ao redor de cada widget.",
|
||||
"appearance-show-outline-label": "Mostrar contornos do widget",
|
||||
"appearance-type-description": "Escolha o estilo da barra: Simples, Flutuante ou Emoldurada",
|
||||
"appearance-type-label": "Tipo de Barra",
|
||||
"appearance-use-separate-opacity-description": "Permitir usar um valor de opacidade separado para o fundo da barra.",
|
||||
"appearance-use-separate-opacity-label": "Usar opacidade separada para as barras",
|
||||
"monitor-configure-widgets": "Configurar widgets",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Quebrar texto da área de transferência",
|
||||
"settings-clipboard-history-description": "Acesse itens copiados anteriormente a partir do lançador.",
|
||||
"settings-clipboard-history-label": "Ativar histórico da área de transferência",
|
||||
"settings-clipboard-watch-image-description": "String de comando completa passada para wl-paste para alterações de imagem. (requer reinício)",
|
||||
"settings-clipboard-watch-image-label": "Comando de Vigilância de Imagens",
|
||||
"settings-clipboard-watch-text-description": "Cadeia de comando completa passada para wl-paste para alterações de texto. (requer reinício)",
|
||||
"settings-clipboard-watch-text-label": "Comando de observação de texto",
|
||||
"settings-custom-launch-prefix-description": "Prefixar comandos com um inicializador personalizado (ex. 'runapp' para integração systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Usar um prefixo personalizado para inicializar aplicativos em vez do método padrão.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Habilitar prefixo de inicialização personalizado",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Exibir clima no calendário"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Quando o fprintd (autenticação por impressão digital) está ativo, esta opção permite-lhe iniciar sessão com a sua palavra-passe em vez de uma impressão digital.",
|
||||
"allow-password-with-fprintd-label": "Permitir login por senha com fprintd",
|
||||
"auto-start-auth-description": "p. ex., inicia automaticamente a autenticação de impressão digital sem exigir uma pressão de tecla ou um clique de botão.",
|
||||
"auto-start-auth-label": "Autenticação de início automático",
|
||||
"compact-lockscreen-description": "Mostrar apenas a entrada de login e os controles do sistema, ocultando os widgets de clima e mídia.",
|
||||
"compact-lockscreen-label": "Tela de bloqueio compacta",
|
||||
"lock-on-suspend-description": "Bloquear a tela automaticamente ao suspender o sistema.",
|
||||
|
||||
+46
-13
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Скрывать значок уведомлений, если нет непрочитанных.",
|
||||
"hide-widget-when-zero-unread-label": "Скрывать значок без непрочитанных",
|
||||
"show-unread-badge-description": "Отображать значок, показывающий количество непрочитанных уведомлений.",
|
||||
"show-unread-badge-label": "Показывать значок непрочитанных"
|
||||
"show-unread-badge-label": "Показывать значок непрочитанных",
|
||||
"unread-badge-color-description": "Выберите цвет для значка непрочитанных уведомлений.",
|
||||
"unread-badge-color-label": "Цвет значка непрочитанных"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Выберите виджет для добавления...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Количество символов для отображения из имён рабочих пространств (1-10).",
|
||||
"character-count-label": "Количество символов",
|
||||
"empty-color-description": "Установить цвет фона для пустых рабочих пространств.",
|
||||
"empty-color-label": "Цвет пустого рабочего пространства",
|
||||
"enable-scrollwheel-description": "Переключайтесь между рабочими пространствами с помощью колеса прокрутки мыши.",
|
||||
"enable-scrollwheel-label": "Прокрутите, чтобы переключить рабочие столы",
|
||||
"enable-scrollwheel-label": "Прокрутите, чтобы переключить рабочие пространства",
|
||||
"focused-color-description": "Установить цвет фона для активного рабочего пространства.",
|
||||
"focused-color-label": "Цвет активного рабочего пространства",
|
||||
"follow-focused-screen-description": "Отображать рабочие пространства с текущего активного экрана, а не с экрана, на котором расположена панель.",
|
||||
"follow-focused-screen-label": "Следовать за активным экраном",
|
||||
"grouped-border-opacity-description": "Установить уровень прозрачности для границ контейнера рабочей области.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Скрыть незанятые",
|
||||
"label-mode-description": "Выберите, как отображаются метки рабочих пространств.",
|
||||
"label-mode-label": "Режим метки",
|
||||
"occupied-color-description": "Установить цвет фона для занятых рабочих пространств.",
|
||||
"occupied-color-label": "Цвет занятого рабочего пространства",
|
||||
"reverse-scrolling-description": "Изменить направление переключения рабочих пространств при прокрутке.",
|
||||
"reverse-scrolling-label": "Обратная прокрутка",
|
||||
"show-applications-description": "Отображать значки приложений внутри каждого рабочего пространства.",
|
||||
"show-applications-label": "Показать приложения",
|
||||
"show-badge-description": "Показывать значок номера рабочего пространства в сгруппированном режиме.",
|
||||
"show-badge-label": "Показывать значок рабочего стола",
|
||||
"show-labels-only-when-occupied-description": "Показывать метки рабочих пространств только тогда, когда они содержат окна.",
|
||||
"show-labels-only-when-occupied-label": "Показывать метки только при наличии содержимого",
|
||||
"unfocused-icons-opacity-description": "Установить уровень прозрачности для неактивных значков приложений.",
|
||||
@@ -402,7 +414,7 @@
|
||||
"lock": "Заблокировать",
|
||||
"logout": "Выйти",
|
||||
"look": "Внешний вид",
|
||||
"media": "СМИ",
|
||||
"media": "Плеер",
|
||||
"media-player": "Медиаплеер",
|
||||
"memory": "Память",
|
||||
"monitors": "Мониторы",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Не найдено",
|
||||
"notifications": "Уведомления",
|
||||
"official": "Официальный",
|
||||
"on-surface": "На поверхности",
|
||||
"output": "Вывод",
|
||||
"pair": "Спарить",
|
||||
"paired": "Спарено",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Опрашивание",
|
||||
"position": "Позиция",
|
||||
"previous": "Предыдущий",
|
||||
"primary": "Основной",
|
||||
"random": "Случайный",
|
||||
"reboot": "Перезагрузить",
|
||||
"refresh": "Обновить",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Сканирование...",
|
||||
"screen-corners": "Углы экрана",
|
||||
"search": "Поиск",
|
||||
"secondary": "Вторичный",
|
||||
"security": "Безопасность",
|
||||
"select": "Выбрать",
|
||||
"shortcuts": "Ярлыки",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Стоп",
|
||||
"suspend": "Приостановить",
|
||||
"templates": "Шаблоны",
|
||||
"tertiary": "Третичный",
|
||||
"test": "Тест",
|
||||
"thresholds": "Пороги",
|
||||
"title": "Название",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Компактная",
|
||||
"density-default": "По умолчанию",
|
||||
"density-mini": "Мини",
|
||||
"density-spacious": "Просторный"
|
||||
"density-spacious": "Просторный",
|
||||
"type-floating": "Плавающий",
|
||||
"type-framed": "В рамке",
|
||||
"type-simple": "Простой"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Классический",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Настройка внешнего вида и положения панели.",
|
||||
"appearance-floating-description": "Отображает панель как плавающую 'таблетку'.",
|
||||
"appearance-floating-label": "Плавающая панель",
|
||||
"appearance-frame-radius": "Внутренний радиус",
|
||||
"appearance-frame-settings-description": "Настройте толщину рамки и внутренний радиус углов",
|
||||
"appearance-frame-settings-label": "Настройки рамки",
|
||||
"appearance-frame-thickness": "Толщина",
|
||||
"appearance-hide-on-overview-description": "Скрыть панель и закрыть панели, когда активен обзор компоновщика.",
|
||||
"appearance-hide-on-overview-label": "Скрыть панель в обзоре",
|
||||
"appearance-margins-description": "Настройка отступов вокруг плавающей панели.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Показывать капсулу",
|
||||
"appearance-show-outline-description": "Отображает видимую границу вокруг каждого виджета.",
|
||||
"appearance-show-outline-label": "Показать контуры виджетов",
|
||||
"appearance-type-description": "Выберите стиль панели: Простой, Плавающий или В рамке",
|
||||
"appearance-type-label": "Тип панели",
|
||||
"appearance-use-separate-opacity-description": "Включить использование отдельного значения прозрачности для фона полосы.",
|
||||
"appearance-use-separate-opacity-label": "Использовать раздельную прозрачность столбцов",
|
||||
"monitor-configure-widgets": "Настроить виджеты",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Обернуть текст из буфера обмена",
|
||||
"settings-clipboard-history-description": "Доступ к ранее скопированным элементам из запуска.",
|
||||
"settings-clipboard-history-label": "Включить историю буфера обмена",
|
||||
"settings-clipboard-watch-image-description": "Полная командная строка, передаваемая в wl-paste для изменения изображений. (требуется перезапуск)",
|
||||
"settings-clipboard-watch-image-label": "Команда Отслеживания Изображений",
|
||||
"settings-clipboard-watch-text-description": "Полная строка команды, переданная в wl-paste для изменений текста. (требуется перезапуск)",
|
||||
"settings-clipboard-watch-text-label": "Команда наблюдения за текстом",
|
||||
"settings-custom-launch-prefix-description": "Добавлять префикс к командам с помощью пользовательского запуска (например, 'runapp' для интеграции с systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Использовать пользовательский префикс для запуска приложений вместо метода по умолчанию.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Включить пользовательский префикс запуска",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Отображать погоду в календаре"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Когда fprintd (аутентификация по отпечатку пальца) активен, эта опция позволяет вам входить в систему с помощью пароля вместо отпечатка пальца.",
|
||||
"allow-password-with-fprintd-label": "Разрешить вход по паролю с помощью fprintd",
|
||||
"auto-start-auth-description": "например, автоматически запускает аутентификацию по отпечатку пальца без необходимости нажатия клавиши или щелчка кнопки.",
|
||||
"auto-start-auth-label": "Автоматический запуск аутентификации",
|
||||
"compact-lockscreen-description": "Показывать только поле для ввода логина и системные элементы управления, скрывая виджеты погоды и медиа.",
|
||||
"compact-lockscreen-label": "Компактный экран блокировки",
|
||||
"lock-on-suspend-description": "Автоматически блокировать экран при приостановке работы системы.",
|
||||
@@ -1180,24 +1213,24 @@
|
||||
"duration-desc": "Как долго OSD остаётся видимым перед автоматическим скрытием.",
|
||||
"duration-title": "Таймаут автоскрытия",
|
||||
"enabled-description": "Показывать изменения громкости и яркости в реальном времени.",
|
||||
"enabled-label": "Включить экранное отображение (OSD)",
|
||||
"events-desc": "Выберите, какие события запускают экранное меню.",
|
||||
"general-desc": "Настроить видимость и поведение экранного меню (OSD).",
|
||||
"location-description": "Где появляются экранные отображения.",
|
||||
"enabled-label": "Включить уведомления (OSD)",
|
||||
"events-desc": "Выберите, по каким событиям выводить уведомления (OSD).",
|
||||
"general-desc": "Настроить видимость и поведение уведомлений (OSD).",
|
||||
"location-description": "Расположение экранных уведолений.",
|
||||
"monitors-desc": "Показывать OSD на определённых мониторах. По умолчанию на всех, если ни один не выбран.",
|
||||
"title": "Экранное отображение (OSD)",
|
||||
"title": "Уведомления (OSD)",
|
||||
"types-brightness-description": "Показывать OSD при изменении яркости экрана.",
|
||||
"types-brightness-label": "Яркость",
|
||||
"types-custom-text-description": "Показывать OSD для пользовательских текстовых сообщений через IPC.",
|
||||
"types-custom-text-label": "Пользовательский текст",
|
||||
"types-desc": "Выберите события, которые должны запускать экранное меню (OSD).",
|
||||
"types-desc": "Выберите события, которые должны запускать уведомления (OSD).",
|
||||
"types-input-volume-description": "Показывать OSD при изменении громкости микрофона.",
|
||||
"types-input-volume-label": "Входная громкость",
|
||||
"types-lockkey-description": "Показывать OSD при переключении клавиш Caps Lock, Num Lock или Scroll Lock.",
|
||||
"types-lockkey-label": "Клавиши блокировки",
|
||||
"types-media-description": "Показывать OSD при изменении состояния воспроизведения медиа (воспроизведение, пауза, пропуск).",
|
||||
"types-media-label": "Воспроизведение медиа",
|
||||
"types-title": "События, запускающие экранное меню",
|
||||
"types-title": "События, запускающие уведомления (OSD)",
|
||||
"types-volume-description": "Показывать OSD при изменении громкости аудиовыхода.",
|
||||
"types-volume-label": "Выходная громкость"
|
||||
},
|
||||
@@ -1325,7 +1358,7 @@
|
||||
"box-border-radius-description": "Настраивает скругление углов основных разделов макета, таких как боковые панели, карточки и панели контента.",
|
||||
"box-border-radius-label": "Радиус контейнера",
|
||||
"box-border-radius-reset": "Сбросить радиус контейнера",
|
||||
"control-border-radius-description": "Управляет кривизной интерактивных элементов, включая кнопки, переключатели и текстовые поля.",
|
||||
"control-border-radius-description": "Управляет скруглением интерактивных элементов, включая кнопки, переключатели и текстовые поля.",
|
||||
"control-border-radius-label": "Ввести радиус",
|
||||
"control-border-radius-reset": "Сбросить радиус ввода",
|
||||
"desc": "Настройка внешнего вида, ощущений и поведения интерфейса.",
|
||||
@@ -1398,7 +1431,7 @@
|
||||
"settings-view-mode-label": "Режим просмотра",
|
||||
"view-mode-browse": "Просмотр каталогов",
|
||||
"view-mode-cycle-tooltip": "Режим просмотра: {mode} (нажмите, чтобы изменить)",
|
||||
"view-mode-recursive": "Сглаженные подкаталоги",
|
||||
"view-mode-recursive": "Объединить с подкаталогами",
|
||||
"view-mode-single": "Корневой каталог"
|
||||
}
|
||||
},
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Okunmamış bildirim yokken bildirim simgesini gizle.",
|
||||
"hide-widget-when-zero-unread-label": "Okunmamış yokken simgeyi gizle",
|
||||
"show-unread-badge-description": "Okunmamış bildirim sayısını gösteren bir rozet göster.",
|
||||
"show-unread-badge-label": "Okunmamış bildirimleri göster"
|
||||
"show-unread-badge-label": "Okunmamış bildirimleri göster",
|
||||
"unread-badge-color-description": "Okunmamış bildirim rozeti için rengi seçin.",
|
||||
"unread-badge-color-label": "Okunmamış rozet rengi"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Eklenecek bir araç takımı seçin...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Çalışma alanı adlarından gösterilecek karakter sayısı (1-10).",
|
||||
"character-count-label": "Karakter sayısı",
|
||||
"empty-color-description": "Boş Workspace'ler için arka plan rengini ayarla.",
|
||||
"empty-color-label": "Boş çalışma alanı rengi",
|
||||
"enable-scrollwheel-description": "Fare tekerleği ile çalışma alanları arasında geçiş yapın.",
|
||||
"enable-scrollwheel-label": "Çalışma alanları arasında geçiş yapmak için kaydırın",
|
||||
"focused-color-description": "Odaklanılan Workspace için arka plan rengini ayarla.",
|
||||
"focused-color-label": "Odaklanılan çalışma alanı rengi",
|
||||
"follow-focused-screen-description": "Çubuğun bulunduğu ekran yerine, şu anda odaklanmış ekrandaki çalışma alanlarını göster.",
|
||||
"follow-focused-screen-label": "Odaklanmış ekranı takip et",
|
||||
"grouped-border-opacity-description": "Çalışma alanı kapsayıcı kenarlıklarının opaklık düzeyini ayarlayın.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Dolu olmayanları gizle",
|
||||
"label-mode-description": "Çalışma alanı etiketlerinin nasıl gösterileceğini seçin.",
|
||||
"label-mode-label": "Etiket Modu",
|
||||
"occupied-color-description": "Dolu Workspaces için arka plan rengini ayarla.",
|
||||
"occupied-color-label": "Dolu çalışma alanı rengi",
|
||||
"reverse-scrolling-description": "Kaydırırken çalışma alanı geçiş yönünü tersine çevir.",
|
||||
"reverse-scrolling-label": "Ters kaydırma",
|
||||
"show-applications-description": "Her çalışma alanının içinde uygulama simgelerini görüntüle.",
|
||||
"show-applications-label": "Uygulamaları göster",
|
||||
"show-badge-description": "Gruplandırılmış modda çalışma alanı numarası işaretini göster.",
|
||||
"show-badge-label": "Çalışma alanı rozetini göster",
|
||||
"show-labels-only-when-occupied-description": "Yalnızca pencere içeren çalışma alanı etiketlerini göster.",
|
||||
"show-labels-only-when-occupied-label": "Yalnızca dolu olduğunda etiketleri göster",
|
||||
"unfocused-icons-opacity-description": "Odaklanılmamış uygulama simgelerinin opaklık düzeyini ayarlayın.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Bulunamadı",
|
||||
"notifications": "Bildirimler",
|
||||
"official": "Resmi",
|
||||
"on-surface": "Yüzeyde",
|
||||
"output": "Çıktı",
|
||||
"pair": "Eşleştir",
|
||||
"paired": "Eşleştirildi",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Yoklama",
|
||||
"position": "Pozisyon",
|
||||
"previous": "Önceki",
|
||||
"primary": "Birincil",
|
||||
"random": "Rastgele",
|
||||
"reboot": "Yeniden başlat",
|
||||
"refresh": "Yenile",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Taranıyor...",
|
||||
"screen-corners": "Ekran köşeleri",
|
||||
"search": "Arama",
|
||||
"secondary": "İkincil",
|
||||
"security": "Güvenlik",
|
||||
"select": "Seç",
|
||||
"shortcuts": "Kısayollar",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Dur",
|
||||
"suspend": "Askıya al",
|
||||
"templates": "Şablonlar",
|
||||
"tertiary": "Üçüncül",
|
||||
"test": "Test",
|
||||
"thresholds": "Eşikler",
|
||||
"title": "Başlık",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Sıkı",
|
||||
"density-default": "Varsayılan",
|
||||
"density-mini": "Ufak",
|
||||
"density-spacious": "Geniş"
|
||||
"density-spacious": "Geniş",
|
||||
"type-floating": "Yüzen",
|
||||
"type-framed": "Çerçeveli",
|
||||
"type-simple": "Basit"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Klasik",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Araç çubuğunun görünümünü ve konumunu özelleştirin.",
|
||||
"appearance-floating-description": "Araç çubuğunu yüzen bir 'kapsül' olarak görüntüler. Not: Bu, ekran köşelerini kenarlara taşıyacaktır.",
|
||||
"appearance-floating-label": "Yüzen araç çubuğu",
|
||||
"appearance-frame-radius": "İç Yarıçap",
|
||||
"appearance-frame-settings-description": "Çerçeve kalınlığını ve iç köşe yarıçapını ayarlayın",
|
||||
"appearance-frame-settings-label": "Çerçeve Ayarları",
|
||||
"appearance-frame-thickness": "Kalınlık",
|
||||
"appearance-hide-on-overview-description": "Kompozitör önizlemesi aktif olduğunda çubuğu gizle ve panelleri kapat.",
|
||||
"appearance-hide-on-overview-label": "Genel bakışta çubuğu gizle",
|
||||
"appearance-margins-description": "Yüzen araç çubuğunun etrafındaki kenar boşluklarını ayarlayın.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Kapsülü göster",
|
||||
"appearance-show-outline-description": "Her widget'ın etrafında görünür bir kenarlık görüntüler.",
|
||||
"appearance-show-outline-label": "Araç kutusu ana hatlarını göster",
|
||||
"appearance-type-description": "Çubuk stilini seçin: Basit, Yüzen veya Çerçeveli",
|
||||
"appearance-type-label": "Çubuk Türü",
|
||||
"appearance-use-separate-opacity-description": "Çubuk arka planı için ayrı bir opaklık değeri kullanmayı etkinleştir.",
|
||||
"appearance-use-separate-opacity-label": "Ayrı çubuk opaklığı kullan",
|
||||
"monitor-configure-widgets": "Araçları yapılandır",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Panoyu metni kaydır",
|
||||
"settings-clipboard-history-description": "Başlatıcıdan daha önce kopyalanan öğelere erişin.",
|
||||
"settings-clipboard-history-label": "Pano geçmişini etkinleştir",
|
||||
"settings-clipboard-watch-image-description": "Görüntü değişiklikleri için wl-paste'e iletilen tam komut dizesi. (yeniden başlatma gerektirir)",
|
||||
"settings-clipboard-watch-image-label": "Görüntü İzleme Komutu",
|
||||
"settings-clipboard-watch-text-description": "Metin değişiklikleri için wl-paste'e iletilen tam komut dizesi. (yeniden başlatma gerektirir)",
|
||||
"settings-clipboard-watch-text-label": "Metin izleme komutu",
|
||||
"settings-custom-launch-prefix-description": "Komutlara özel bir başlatıcı ile ön ek ekleyin (örn., systemd entegrasyonu için 'runapp').",
|
||||
"settings-custom-launch-prefix-enabled-description": "Uygulamaları başlatmak için varsayılan yöntem yerine özel bir ön ek kullanın.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Özel başlatma ön ekini etkinleştir",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Takvimde hava durumunu göster"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "fprintd (parmak izi kimlik doğrulaması) etkin olduğunda, bu seçenek parmak izi yerine parolanızı kullanarak oturum açmanızı sağlar.",
|
||||
"allow-password-with-fprintd-label": "fprintd ile parola girişine izin ver",
|
||||
"auto-start-auth-description": "örneğin, bir tuşa basmaya veya düğmeye tıklamaya gerek kalmadan parmak izi kimlik doğrulamasını otomatik olarak başlatır.",
|
||||
"auto-start-auth-label": "Otomatik kimlik doğrulama başlatma",
|
||||
"compact-lockscreen-description": "Sadece giriş girdisini ve sistem kontrollerini göster, hava durumu ve ortam araç takımlarını gizle.",
|
||||
"compact-lockscreen-label": "Kompakt ekran kilidi",
|
||||
"lock-on-suspend-description": "Sistemi askıya alırken otomatik olarak ekranı kilitler.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "Приховувати значок сповіщень, якщо немає непрочитаних.",
|
||||
"hide-widget-when-zero-unread-label": "Приховувати значок без непрочитаних",
|
||||
"show-unread-badge-description": "Відображати значок з кількістю непрочитаних сповіщень.",
|
||||
"show-unread-badge-label": "Показувати значок непрочитаних"
|
||||
"show-unread-badge-label": "Показувати значок непрочитаних",
|
||||
"unread-badge-color-description": "Виберіть колір для значка непрочитаних сповіщень.",
|
||||
"unread-badge-color-label": "Колір значка непрочитаних"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "Виберіть віджет для додавання...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "Кількість символів для відображення з назв робочих просторів (1-10).",
|
||||
"character-count-label": "Кількість символів",
|
||||
"empty-color-description": "Встановити колір фону для порожніх Workspace.",
|
||||
"empty-color-label": "Колір порожнього робочого столу",
|
||||
"enable-scrollwheel-description": "Перемикайтеся між робочими столами за допомогою коліщатка миші.",
|
||||
"enable-scrollwheel-label": "Прокрутіть, щоб перемикати робочі простори",
|
||||
"focused-color-description": "Встановити колір тла для сфокусованого Workspace.",
|
||||
"focused-color-label": "Колір сфокусованого робочого столу",
|
||||
"follow-focused-screen-description": "Відображати робочі простори з поточного активного екрана, а не з екрана, на якому розташована панель.",
|
||||
"follow-focused-screen-label": "Слідувати за активним eкраном",
|
||||
"grouped-border-opacity-description": "Встановити рівень непрозорості для меж контейнерів робочої області.",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "Приховати незайняті",
|
||||
"label-mode-description": "Виберіть, як відображаються мітки робочих просторів.",
|
||||
"label-mode-label": "Режим міток",
|
||||
"occupied-color-description": "Встановити колір фону для зайнятих Workspace.",
|
||||
"occupied-color-label": "Колір зайнятого робочого столу",
|
||||
"reverse-scrolling-description": "Змінити напрямок перемикання робочих просторів під час прокручування.",
|
||||
"reverse-scrolling-label": "Зворотне прокручування",
|
||||
"show-applications-description": "Відображати значки програм у кожному робочому просторі.",
|
||||
"show-applications-label": "Показати застосунки",
|
||||
"show-badge-description": "Показувати значок номера робочого столу в згрупованому режимі.",
|
||||
"show-badge-label": "Показати значок робочого столу",
|
||||
"show-labels-only-when-occupied-description": "Показувати мітки робочих просторів лише тоді, коли вони містять вікна.",
|
||||
"show-labels-only-when-occupied-label": "Показувати мітки лише коли поле заповнене",
|
||||
"unfocused-icons-opacity-description": "Встановити рівень непрозорості для неактивних іконок застосунків.",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "Не знайдено",
|
||||
"notifications": "Сповіщення",
|
||||
"official": "Офіційний",
|
||||
"on-surface": "На поверхні",
|
||||
"output": "Вихід",
|
||||
"pair": "Спарувати",
|
||||
"paired": "Спаровано",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "Опитування",
|
||||
"position": "Позиція",
|
||||
"previous": "Попередній",
|
||||
"primary": "Основний",
|
||||
"random": "Випадковий",
|
||||
"reboot": "Перезапустити",
|
||||
"refresh": "Оновити",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "Сканування...",
|
||||
"screen-corners": "Кути екрана",
|
||||
"search": "Пошук",
|
||||
"secondary": "Вторинний",
|
||||
"security": "Безпека",
|
||||
"select": "Вибрати",
|
||||
"shortcuts": "Ярлики",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "Зупиніться",
|
||||
"suspend": "Призупинити",
|
||||
"templates": "Шаблони",
|
||||
"tertiary": "Третинний",
|
||||
"test": "Тест",
|
||||
"thresholds": "Порогові значення",
|
||||
"title": "Назва",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "Компактний",
|
||||
"density-default": "Стандартний",
|
||||
"density-mini": "Міні",
|
||||
"density-spacious": "Просторий"
|
||||
"density-spacious": "Просторий",
|
||||
"type-floating": "Плаваючий",
|
||||
"type-framed": "У рамці",
|
||||
"type-simple": "Простий"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "Класичний",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "Налаштуйте зовнішній вигляд та положення панелі.",
|
||||
"appearance-floating-description": "Відображати панель як плаваючу 'капсулу'. Примітка: Це перемістить кути екрана до країв.",
|
||||
"appearance-floating-label": "Плаваюча панель (Острівець)",
|
||||
"appearance-frame-radius": "Внутрішній радіус",
|
||||
"appearance-frame-settings-description": "Налаштуйте товщину рамки та внутрішній радіус кутів",
|
||||
"appearance-frame-settings-label": "Налаштування рамки",
|
||||
"appearance-frame-thickness": "Товщина",
|
||||
"appearance-hide-on-overview-description": "Приховати панель і закрити панелі, коли активний огляд компонувальника.",
|
||||
"appearance-hide-on-overview-label": "Приховати панель на огляді",
|
||||
"appearance-margins-description": "Налаштуйте поля навколо плаваючої панелі.",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "Показувати капсулу",
|
||||
"appearance-show-outline-description": "Відображає видиму рамку навколо кожного віджета.",
|
||||
"appearance-show-outline-label": "Показувати контури віджетів",
|
||||
"appearance-type-description": "Виберіть стиль панелі: Простий, Плаваючий або У рамці",
|
||||
"appearance-type-label": "Тип панелі",
|
||||
"appearance-use-separate-opacity-description": "Увімкнути використання окремого значення прозорості для фону панелі.",
|
||||
"appearance-use-separate-opacity-label": "Використовувати окрему прозорість стовпців",
|
||||
"monitor-configure-widgets": "Налаштувати віджети",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "Загорнути текст з буфера обміну",
|
||||
"settings-clipboard-history-description": "Отримати доступ до раніше скопійованих елементів із лаунчера.",
|
||||
"settings-clipboard-history-label": "Увімкнути історію буфера обміну",
|
||||
"settings-clipboard-watch-image-description": "Повний рядок команди, переданий до wl-paste для зміни зображень. (потрібен перезапуск)",
|
||||
"settings-clipboard-watch-image-label": "Команда Спостереження за Зображеннями",
|
||||
"settings-clipboard-watch-text-description": "Повний рядок команди, переданий до wl-paste для змін тексту. (потребує перезапуску)",
|
||||
"settings-clipboard-watch-text-label": "Команда спостереження за текстом",
|
||||
"settings-custom-launch-prefix-description": "Додати префікс до команд запуску лаунчером (напр., 'runapp' для інтеграції з systemd).",
|
||||
"settings-custom-launch-prefix-enabled-description": "Використовувати власний префікс для запуску застосунків замість стандартного методу.",
|
||||
"settings-custom-launch-prefix-enabled-label": "Увімкнути користувацький префікс запуску",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "Відображати погоду в календарі"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "Коли fprintd (автентифікація за відбитком пальця) активний, ця опція дозволяє входити в систему за допомогою пароля замість відбитка пальця.",
|
||||
"allow-password-with-fprintd-label": "Дозволити вхід за паролем за допомогою fprintd",
|
||||
"auto-start-auth-description": "наприклад, автоматично запускає автентифікацію за відбитком пальця без необхідності натискання клавіші або клацання кнопки.",
|
||||
"auto-start-auth-label": "Автоматичний запуск автентифікації",
|
||||
"compact-lockscreen-description": "Показувати тільки поле входу та системні елементи керування, приховуючи віджети погоди та медіа.",
|
||||
"compact-lockscreen-label": "Компактний екран блокування",
|
||||
"lock-on-suspend-description": "Автоматично блокувати екран при призупиненні системи.",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "没有未读通知时隐藏通知图标。",
|
||||
"hide-widget-when-zero-unread-label": "无未读时隐藏图标",
|
||||
"show-unread-badge-description": "显示一个用于展示未读通知数量的徽章。",
|
||||
"show-unread-badge-label": "显示未读徽章"
|
||||
"show-unread-badge-label": "显示未读徽章",
|
||||
"unread-badge-color-description": "选择未读通知徽章的颜色。",
|
||||
"unread-badge-color-label": "未读徽章颜色"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "选择要添加的小部件...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "显示工作区名称的字符数量(1-10)。",
|
||||
"character-count-label": "字符数量",
|
||||
"empty-color-description": "设置空工作区的背景颜色。",
|
||||
"empty-color-label": "空白工作区颜色",
|
||||
"enable-scrollwheel-description": "使用鼠标滚轮切换工作区。",
|
||||
"enable-scrollwheel-label": "滚动切换工作区",
|
||||
"focused-color-description": "设置焦点 Workspace 的背景颜色。",
|
||||
"focused-color-label": "聚焦工作区颜色",
|
||||
"follow-focused-screen-description": "显示当前焦点屏幕的工作区,而不是任务栏所在屏幕的工作区。",
|
||||
"follow-focused-screen-label": "跟随焦点屏幕",
|
||||
"grouped-border-opacity-description": "设置工作区容器边框的不透明度级别。",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "隐藏未占用",
|
||||
"label-mode-description": "选择工作区标签的显示方式。",
|
||||
"label-mode-label": "标签模式",
|
||||
"occupied-color-description": "设置已占用Workspace的背景颜色。",
|
||||
"occupied-color-label": "已占用工作区颜色",
|
||||
"reverse-scrolling-description": "滚动时反转工作区切换方向。",
|
||||
"reverse-scrolling-label": "反转滚动",
|
||||
"show-applications-description": "在每个工作区内显示应用程序图标。",
|
||||
"show-applications-label": "显示应用程序",
|
||||
"show-badge-description": "在分组模式下显示工作区编号徽章。",
|
||||
"show-badge-label": "显示工作区徽章",
|
||||
"show-labels-only-when-occupied-description": "仅在工作区包含窗口时显示工作区标签。",
|
||||
"show-labels-only-when-occupied-label": "仅在被占用时显示标签",
|
||||
"unfocused-icons-opacity-description": "设置未聚焦应用图标的不透明度级别。",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "未找到",
|
||||
"notifications": "通知",
|
||||
"official": "官方",
|
||||
"on-surface": "在表面上",
|
||||
"output": "输出",
|
||||
"pair": "配对",
|
||||
"paired": "已配对",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "数据轮询",
|
||||
"position": "位置",
|
||||
"previous": "上一个",
|
||||
"primary": "主要的",
|
||||
"random": "随机",
|
||||
"reboot": "重启",
|
||||
"refresh": "刷新",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "扫描中...",
|
||||
"screen-corners": "屏幕边角",
|
||||
"search": "搜索",
|
||||
"secondary": "辅助",
|
||||
"security": "安全",
|
||||
"select": "选择",
|
||||
"shortcuts": "快捷方式",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "停止",
|
||||
"suspend": "挂起",
|
||||
"templates": "模板",
|
||||
"tertiary": "第三",
|
||||
"test": "测试",
|
||||
"thresholds": "阈值",
|
||||
"title": "标题",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "紧凑",
|
||||
"density-default": "默认",
|
||||
"density-mini": "迷你",
|
||||
"density-spacious": "宽敞"
|
||||
"density-spacious": "宽敞",
|
||||
"type-floating": "悬浮",
|
||||
"type-framed": "边框",
|
||||
"type-simple": "简约"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "经典",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "自定义状态栏的外观和位置。",
|
||||
"appearance-floating-description": "将状态栏显示为浮动的“药丸”形状。",
|
||||
"appearance-floating-label": "浮动状态栏",
|
||||
"appearance-frame-radius": "内圆角",
|
||||
"appearance-frame-settings-description": "调整边框粗细和内圆角半径",
|
||||
"appearance-frame-settings-label": "边框设置",
|
||||
"appearance-frame-thickness": "粗细",
|
||||
"appearance-hide-on-overview-description": "当合成器概览处于活动状态时,隐藏栏并关闭面板。",
|
||||
"appearance-hide-on-overview-label": "在概览中隐藏栏",
|
||||
"appearance-margins-description": "调整浮动状态栏周围的边距。",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "显示组件背景",
|
||||
"appearance-show-outline-description": "在每个小部件周围显示可见边框。",
|
||||
"appearance-show-outline-label": "显示小部件轮廓",
|
||||
"appearance-type-description": "选择栏的样式:简约、悬浮或边框",
|
||||
"appearance-type-label": "栏类型",
|
||||
"appearance-use-separate-opacity-description": "启用后为状态栏背景使用单独的不透明度值。",
|
||||
"appearance-use-separate-opacity-label": "使用单独的状态栏不透明度",
|
||||
"monitor-configure-widgets": "配置小部件",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "环绕剪贴板文本",
|
||||
"settings-clipboard-history-description": "从启动器访问之前复制的项目。",
|
||||
"settings-clipboard-history-label": "启用剪贴板历史记录",
|
||||
"settings-clipboard-watch-image-description": "传递给 wl-paste 以进行图像更改的完整命令字符串。(需要重启)",
|
||||
"settings-clipboard-watch-image-label": "图像监视命令",
|
||||
"settings-clipboard-watch-text-description": "传递给 wl-paste 以进行文本更改的完整命令字符串。(需要重启)",
|
||||
"settings-clipboard-watch-text-label": "文本监视命令",
|
||||
"settings-custom-launch-prefix-description": "使用自定义启动器前缀命令(例如,'runapp'用于systemd集成)。",
|
||||
"settings-custom-launch-prefix-enabled-description": "使用自定义前缀启动应用程序,而不是默认方法。",
|
||||
"settings-custom-launch-prefix-enabled-label": "启用自定义启动前缀",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "在日历中显示天气"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "当 fprintd(指纹认证)处于活动状态时,此选项允许您使用密码而非指纹登录。",
|
||||
"allow-password-with-fprintd-label": "允许使用 fprintd 进行密码登录",
|
||||
"auto-start-auth-description": "例如,自动启动指纹验证,无需按键或单击按钮。",
|
||||
"auto-start-auth-label": "自动启动身份验证",
|
||||
"compact-lockscreen-description": "仅显示登录输入和系统控制,隐藏天气和媒体小部件。",
|
||||
"compact-lockscreen-label": "紧凑型锁屏",
|
||||
"lock-on-suspend-description": "系统挂起时自动锁定屏幕。",
|
||||
|
||||
@@ -182,7 +182,9 @@
|
||||
"hide-widget-when-zero-unread-description": "沒有未讀通知時隱藏通知圖示。",
|
||||
"hide-widget-when-zero-unread-label": "沒有未讀通知時隱藏圖示",
|
||||
"show-unread-badge-description": "顯示帶有數量的未讀標記",
|
||||
"show-unread-badge-label": "顯示未讀標記"
|
||||
"show-unread-badge-label": "顯示未讀標記",
|
||||
"unread-badge-color-description": "選擇未讀通知徽章的顏色。",
|
||||
"unread-badge-color-label": "未讀徽章顏色"
|
||||
},
|
||||
"section-editor": {
|
||||
"placeholder": "選取一個小工具來新增...",
|
||||
@@ -254,8 +256,12 @@
|
||||
"workspace": {
|
||||
"character-count-description": "限制工作區所設定的名字要顯示幾個字元 (1-10)",
|
||||
"character-count-label": "字元上限",
|
||||
"empty-color-description": "設定空白 Workspace 的背景顏色。",
|
||||
"empty-color-label": "空白工作區顏色",
|
||||
"enable-scrollwheel-description": "利用滑鼠滾輪在工作區間切換",
|
||||
"enable-scrollwheel-label": "捲輪切換工作區",
|
||||
"focused-color-description": "設定焦點 Workspace 的背景顏色。",
|
||||
"focused-color-label": "聚焦的工作區顏色",
|
||||
"follow-focused-screen-description": "顯示正在聚焦的螢幕所擁有的工作區, 而不是工具列所在的螢幕擁有的工作區",
|
||||
"follow-focused-screen-label": "跟隨焦點所在的螢幕",
|
||||
"grouped-border-opacity-description": "設定工作區邊框的不透明度",
|
||||
@@ -264,8 +270,14 @@
|
||||
"hide-unoccupied-label": "沒有佔用時隱藏",
|
||||
"label-mode-description": "選擇工作區標籤該如何顯示",
|
||||
"label-mode-label": "標籤樣式",
|
||||
"occupied-color-description": "設定已佔用Workspace的背景顏色。",
|
||||
"occupied-color-label": "已佔用工作區顏色",
|
||||
"reverse-scrolling-description": "捲動時反轉工作區切換方向。",
|
||||
"reverse-scrolling-label": "反轉捲動",
|
||||
"show-applications-description": "顯示各個工作區的程式圖示",
|
||||
"show-applications-label": "顯示應用程式",
|
||||
"show-badge-description": "在群組模式下顯示工作區編號徽章。",
|
||||
"show-badge-label": "顯示工作區標記",
|
||||
"show-labels-only-when-occupied-description": "只在工作區有視窗時顯示工作區標籤",
|
||||
"show-labels-only-when-occupied-label": "佔用時顯示標籤",
|
||||
"unfocused-icons-opacity-description": "設定非焦點應用程式圖示的不透明度。",
|
||||
@@ -416,6 +428,7 @@
|
||||
"not-found": "找不到",
|
||||
"notifications": "通知",
|
||||
"official": "官方",
|
||||
"on-surface": "在表面上",
|
||||
"output": "輸出",
|
||||
"pair": "配對",
|
||||
"paired": "已配對",
|
||||
@@ -428,6 +441,7 @@
|
||||
"polling": "輪詢",
|
||||
"position": "位置",
|
||||
"previous": "上一首",
|
||||
"primary": "主要的",
|
||||
"random": "隨機",
|
||||
"reboot": "重新啟動",
|
||||
"refresh": "重新整理",
|
||||
@@ -440,6 +454,7 @@
|
||||
"scanning": "掃描中...",
|
||||
"screen-corners": "畫面邊角",
|
||||
"search": "搜尋",
|
||||
"secondary": "輔助",
|
||||
"security": "安全",
|
||||
"select": "選取",
|
||||
"shortcuts": "快捷鍵",
|
||||
@@ -451,6 +466,7 @@
|
||||
"stop": "停止",
|
||||
"suspend": "暫停",
|
||||
"templates": "模板",
|
||||
"tertiary": "第三",
|
||||
"test": "測試",
|
||||
"thresholds": "門檻",
|
||||
"title": "標題",
|
||||
@@ -579,7 +595,10 @@
|
||||
"density-compact": "緊湊",
|
||||
"density-default": "預設",
|
||||
"density-mini": "迷你",
|
||||
"density-spacious": "寬敞"
|
||||
"density-spacious": "寬敞",
|
||||
"type-floating": "懸浮",
|
||||
"type-framed": "邊框",
|
||||
"type-simple": "簡約"
|
||||
},
|
||||
"control-center": {
|
||||
"quick-settings-style-classic": "古典",
|
||||
@@ -707,6 +726,10 @@
|
||||
"appearance-desc": "自訂工具列的外觀及位置",
|
||||
"appearance-floating-description": "將工具列以懸浮的圓弧長條狀顯示",
|
||||
"appearance-floating-label": "懸浮工具列",
|
||||
"appearance-frame-radius": "內圓角",
|
||||
"appearance-frame-settings-description": "調整邊框粗細和內圓角半徑",
|
||||
"appearance-frame-settings-label": "邊框設定",
|
||||
"appearance-frame-thickness": "粗細",
|
||||
"appearance-hide-on-overview-description": "當在合成器概覽時, 隱藏工具列並關閉面板",
|
||||
"appearance-hide-on-overview-label": "概覽時隱藏工具列",
|
||||
"appearance-margins-description": "調整懸浮工具列的邊距",
|
||||
@@ -721,6 +744,8 @@
|
||||
"appearance-show-capsule-label": "顯示小容器",
|
||||
"appearance-show-outline-description": "讓每個小工具都顯示可視邊框",
|
||||
"appearance-show-outline-label": "顯示小工具外框",
|
||||
"appearance-type-description": "選擇欄的樣式:簡約、懸浮或邊框",
|
||||
"appearance-type-label": "欄類型",
|
||||
"appearance-use-separate-opacity-description": "啟用後可針對工具列背景使用分開的不透明度數值",
|
||||
"appearance-use-separate-opacity-label": "分開設定工具列不透明度",
|
||||
"monitor-configure-widgets": "設定小工具",
|
||||
@@ -1027,6 +1052,10 @@
|
||||
"settings-clip-wrap-text-label": "剪貼簿文字換行",
|
||||
"settings-clipboard-history-description": "在啟動器存取先前所複製的項目",
|
||||
"settings-clipboard-history-label": "啟用剪貼簿歷史",
|
||||
"settings-clipboard-watch-image-description": "傳遞給 wl-paste 以進行圖像更改的完整命令字串。(需要重新啟動)",
|
||||
"settings-clipboard-watch-image-label": "圖像監控命令",
|
||||
"settings-clipboard-watch-text-description": "傳遞給 wl-paste 以進行文字變更的完整命令字串。(需要重新啟動)",
|
||||
"settings-clipboard-watch-text-label": "文字監看指令",
|
||||
"settings-custom-launch-prefix-description": "在命令前加上自訂啟動器前綴(例如:用「runapp」來整合 systemd)。",
|
||||
"settings-custom-launch-prefix-enabled-description": "使用自訂前綴而不是預設的方式來啟動應用程式",
|
||||
"settings-custom-launch-prefix-enabled-label": "啟用自訂的程式啟動前綴",
|
||||
@@ -1090,6 +1119,10 @@
|
||||
"weather-show-in-calendar-label": "在行事曆中顯示天氣"
|
||||
},
|
||||
"lock-screen": {
|
||||
"allow-password-with-fprintd-description": "當 fprintd(指紋認證)處於活動狀態時,此選項允許您使用密碼而非指紋登入。",
|
||||
"allow-password-with-fprintd-label": "允許使用 fprintd 進行密碼登入",
|
||||
"auto-start-auth-description": "例如,自動啟動指紋驗證,無需按鍵或點擊按鈕。",
|
||||
"auto-start-auth-label": "自動啟動驗證",
|
||||
"compact-lockscreen-description": "只顯示登入欄位及電源控制, 隱藏天氣及媒體小工具",
|
||||
"compact-lockscreen-label": "精簡鎖定畫面",
|
||||
"lock-on-suspend-description": "在暫停系統時自動鎖定畫面",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
{
|
||||
"settingsVersion": 0,
|
||||
"bar": {
|
||||
"barType": "simple",
|
||||
"position": "top",
|
||||
"monitors": [],
|
||||
"density": "default",
|
||||
@@ -12,6 +13,8 @@
|
||||
"floating": false,
|
||||
"marginVertical": 4,
|
||||
"marginHorizontal": 4,
|
||||
"frameThickness": 8,
|
||||
"frameRadius": 12,
|
||||
"outerCorners": true,
|
||||
"exclusive": true,
|
||||
"hideOnOverview": false,
|
||||
@@ -86,7 +89,9 @@
|
||||
"showChangelogOnStartup": true,
|
||||
"telemetryEnabled": false,
|
||||
"enableLockScreenCountdown": true,
|
||||
"lockScreenCountdownDuration": 10000
|
||||
"lockScreenCountdownDuration": 10000,
|
||||
"autoStartAuth": false,
|
||||
"allowPasswordWithFprintd": false
|
||||
},
|
||||
"ui": {
|
||||
"fontDefault": "",
|
||||
@@ -171,11 +176,13 @@
|
||||
"autoPasteClipboard": false,
|
||||
"enableClipPreview": true,
|
||||
"clipboardWrapText": true,
|
||||
"clipboardWatchTextCommand": "wl-paste --type text --watch cliphist store",
|
||||
"clipboardWatchImageCommand": "wl-paste --type image --watch cliphist store",
|
||||
"position": "center",
|
||||
"pinnedApps": [],
|
||||
"useApp2Unit": false,
|
||||
"sortByMostUsed": true,
|
||||
"terminalCommand": "xterm -e",
|
||||
"terminalCommand": "alacritty -e",
|
||||
"customLaunchPrefixEnabled": false,
|
||||
"customLaunchPrefix": "",
|
||||
"viewMode": "list",
|
||||
|
||||
@@ -189,9 +189,9 @@
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-floating-label",
|
||||
"descriptionKey": "panels.bar.appearance-floating-description",
|
||||
"widget": "NToggle",
|
||||
"labelKey": "panels.bar.appearance-type-label",
|
||||
"descriptionKey": "panels.bar.appearance-type-description",
|
||||
"widget": "NComboBox",
|
||||
"tab": 4,
|
||||
"tabLabel": "panels.bar.title",
|
||||
"subTab": 0,
|
||||
@@ -206,6 +206,33 @@
|
||||
"subTab": 0,
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-frame-settings-label",
|
||||
"descriptionKey": "panels.bar.appearance-frame-settings-description",
|
||||
"widget": "NLabel",
|
||||
"tab": 4,
|
||||
"tabLabel": "panels.bar.title",
|
||||
"subTab": 0,
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-frame-thickness",
|
||||
"descriptionKey": null,
|
||||
"widget": "NValueSlider",
|
||||
"tab": 4,
|
||||
"tabLabel": "panels.bar.title",
|
||||
"subTab": 0,
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-frame-radius",
|
||||
"descriptionKey": null,
|
||||
"widget": "NValueSlider",
|
||||
"tab": 4,
|
||||
"tabLabel": "panels.bar.title",
|
||||
"subTab": 0,
|
||||
"subTabLabel": "common.appearance"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.bar.appearance-margins-label",
|
||||
"descriptionKey": "panels.bar.appearance-margins-description",
|
||||
@@ -686,6 +713,24 @@
|
||||
"subTab": 1,
|
||||
"subTabLabel": "common.clipboard"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.launcher.settings-clipboard-watch-text-label",
|
||||
"descriptionKey": "panels.launcher.settings-clipboard-watch-text-description",
|
||||
"widget": "NTextInput",
|
||||
"tab": 8,
|
||||
"tabLabel": "panels.launcher.title",
|
||||
"subTab": 1,
|
||||
"subTabLabel": "common.clipboard"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.launcher.settings-clipboard-watch-image-label",
|
||||
"descriptionKey": "panels.launcher.settings-clipboard-watch-image-description",
|
||||
"widget": "NTextInput",
|
||||
"tab": 8,
|
||||
"tabLabel": "panels.launcher.title",
|
||||
"subTab": 1,
|
||||
"subTabLabel": "common.clipboard"
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.launcher.settings-use-app2unit-label",
|
||||
"descriptionKey": "panels.launcher.settings-use-app2unit-description",
|
||||
@@ -810,6 +855,22 @@
|
||||
"tabLabel": "panels.lock-screen.title",
|
||||
"subTab": null
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.lock-screen.auto-start-auth-label",
|
||||
"descriptionKey": "panels.lock-screen.auto-start-auth-description",
|
||||
"widget": "NToggle",
|
||||
"tab": 11,
|
||||
"tabLabel": "panels.lock-screen.title",
|
||||
"subTab": null
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.lock-screen.allow-password-with-fprintd-label",
|
||||
"descriptionKey": "panels.lock-screen.allow-password-with-fprintd-description",
|
||||
"widget": "NToggle",
|
||||
"tab": 11,
|
||||
"tabLabel": "panels.lock-screen.title",
|
||||
"subTab": null
|
||||
},
|
||||
{
|
||||
"labelKey": "panels.lock-screen.show-session-buttons-label",
|
||||
"descriptionKey": "panels.lock-screen.show-session-buttons-description",
|
||||
|
||||
@@ -78,13 +78,14 @@ Singleton {
|
||||
"star": "star",
|
||||
"star-off": "star-off",
|
||||
"battery-exclamation": "battery-exclamation",
|
||||
"common.charging": "common.charging",
|
||||
"battery-charging": "battery-charging",
|
||||
"battery-charging-2": "battery-charging-2",
|
||||
"battery-4": "battery-4",
|
||||
"battery-3": "battery-3",
|
||||
"battery-2": "battery-2",
|
||||
"battery-1": "battery-1",
|
||||
"battery": "battery",
|
||||
"battery-off": "battery-off",
|
||||
"wifi-0": "wifi-0",
|
||||
"wifi-1": "wifi-1",
|
||||
"wifi-2": "wifi-2",
|
||||
@@ -177,7 +178,8 @@ Singleton {
|
||||
"filepicker-eye-off": "eye-off",
|
||||
"filepicker-folder-current": "checks",
|
||||
"plugin": "plug-connected",
|
||||
"info": "file-description"
|
||||
"info": "file-description",
|
||||
"official-plugin": "shield-filled"
|
||||
}
|
||||
|
||||
// Fonts Codepoints - do not change!
|
||||
@@ -747,7 +749,7 @@ Singleton {
|
||||
"battery-4-filled": "\u{f721}",
|
||||
"battery-automotive": "\u{ee07}",
|
||||
"battery-automotive-filled": "\u{10029}",
|
||||
"common.charging": "\u{ea33}",
|
||||
"battery-charging": "\u{ea33}",
|
||||
"battery-charging-2": "\u{ef3b}",
|
||||
"battery-eco": "\u{ef3c}",
|
||||
"battery-exclamation": "\u{ff1d}",
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
/**
|
||||
* Migration 45: Migrate 'floating' bar setting to 'barType'
|
||||
*/
|
||||
function migrate(adapter, logger, rawJson) {
|
||||
logger.i("Migration45", "Migrating bar settings...");
|
||||
|
||||
if (adapter.bar.floating) {
|
||||
adapter.bar.barType = "floating";
|
||||
} else {
|
||||
adapter.bar.barType = "simple";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
function migrate(adapter, logger, rawJson) {
|
||||
logger.i("Migration46", "Removing legacy PAM configuration file");
|
||||
|
||||
const shellName = "noctalia";
|
||||
const configDir = Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/";
|
||||
const pamConfigDir = configDir + "pam";
|
||||
// Remove the entire pam directory if it exists
|
||||
const script = `rm -rf '${pamConfigDir}'`;
|
||||
Quickshell.execDetached(["sh", "-c", script]);
|
||||
|
||||
logger.d("Migration46", "Cleaned up legacy PAM config");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ QtObject {
|
||||
40: migration40Component,
|
||||
42: migration42Component,
|
||||
43: migration43Component,
|
||||
44: migration44Component
|
||||
44: migration44Component,
|
||||
45: migration45Component,
|
||||
46: migration46Component
|
||||
})
|
||||
|
||||
// Migration components
|
||||
@@ -34,4 +36,6 @@ QtObject {
|
||||
property Component migration42Component: Migration42 {}
|
||||
property Component migration43Component: Migration43 {}
|
||||
property Component migration44Component: Migration44 {}
|
||||
property Component migration45Component: Migration45 {}
|
||||
property Component migration46Component: Migration46 {}
|
||||
}
|
||||
|
||||
+11
-57
@@ -25,7 +25,7 @@ Singleton {
|
||||
- Default cache directory: ~/.cache/noctalia
|
||||
*/
|
||||
readonly property alias data: adapter // Used to access via Settings.data.xxx.yyy
|
||||
readonly property int settingsVersion: 44
|
||||
readonly property int settingsVersion: 46
|
||||
readonly property bool isDebug: Quickshell.env("NOCTALIA_DEBUG") === "1"
|
||||
readonly property string shellName: "noctalia"
|
||||
readonly property string configDir: Quickshell.env("NOCTALIA_CONFIG_DIR") || (Quickshell.env("XDG_CONFIG_HOME") || Quickshell.env("HOME") + "/.config") + "/" + shellName + "/"
|
||||
@@ -48,11 +48,6 @@ Singleton {
|
||||
Quickshell.execDetached(["mkdir", "-p", configDir]);
|
||||
Quickshell.execDetached(["mkdir", "-p", cacheDir]);
|
||||
|
||||
// Ensure PAM config file exists in configDir (create once, never override)
|
||||
if (!Quickshell.env("NOCTALIA_PAM_CONFIG")) {
|
||||
ensurePamConfig();
|
||||
}
|
||||
|
||||
// Mark directories as created and trigger file loading
|
||||
directoriesCreated = true;
|
||||
|
||||
@@ -175,6 +170,7 @@ Singleton {
|
||||
|
||||
// bar
|
||||
property JsonObject bar: JsonObject {
|
||||
property string barType: "simple" // "simple", "floating", "framed"
|
||||
property string position: "top" // "top", "bottom", "left", or "right"
|
||||
property list<string> monitors: [] // holds bar visibility per monitor
|
||||
property string density: "default" // "compact", "default", "comfortable"
|
||||
@@ -191,6 +187,10 @@ Singleton {
|
||||
property int marginVertical: 4
|
||||
property int marginHorizontal: 4
|
||||
|
||||
// Framed bar settings
|
||||
property int frameThickness: 8
|
||||
property int frameRadius: 12
|
||||
|
||||
// Bar outer corners (inverted/concave corners at bar edges when not floating)
|
||||
property bool outerCorners: true
|
||||
|
||||
@@ -279,6 +279,8 @@ Singleton {
|
||||
property bool telemetryEnabled: false
|
||||
property bool enableLockScreenCountdown: true
|
||||
property int lockScreenCountdownDuration: 10000
|
||||
property bool autoStartAuth: false
|
||||
property bool allowPasswordWithFprintd: false
|
||||
}
|
||||
|
||||
// ui
|
||||
@@ -377,11 +379,13 @@ Singleton {
|
||||
property bool autoPasteClipboard: false
|
||||
property bool enableClipPreview: true
|
||||
property bool clipboardWrapText: true
|
||||
property string clipboardWatchTextCommand: "wl-paste --type text --watch cliphist store"
|
||||
property string clipboardWatchImageCommand: "wl-paste --type image --watch cliphist store"
|
||||
property string position: "center" // Position: center, top_left, top_right, bottom_left, bottom_right, bottom_center, top_center
|
||||
property list<string> pinnedApps: []
|
||||
property bool useApp2Unit: false
|
||||
property bool sortByMostUsed: true
|
||||
property string terminalCommand: "xterm -e"
|
||||
property string terminalCommand: "alacritty -e"
|
||||
property bool customLaunchPrefixEnabled: false
|
||||
property string customLaunchPrefix: ""
|
||||
// View mode: "list" or "grid"
|
||||
@@ -1096,56 +1100,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Ensure PAM password.conf exists in configDir (create once, never override)
|
||||
function ensurePamConfig() {
|
||||
var pamConfigDir = configDir + "pam";
|
||||
var pamConfigFile = pamConfigDir + "/password.conf";
|
||||
|
||||
// Check if file already exists
|
||||
fileCheckPamProcess.command = ["test", "-f", pamConfigFile];
|
||||
fileCheckPamProcess.running = true;
|
||||
}
|
||||
|
||||
function doCreatePamConfig() {
|
||||
var pamConfigDir = configDir + "pam";
|
||||
var pamConfigFile = pamConfigDir + "/password.conf";
|
||||
var pamConfigDirEsc = pamConfigDir.replace(/'/g, "'\\''");
|
||||
var pamConfigFileEsc = pamConfigFile.replace(/'/g, "'\\''");
|
||||
|
||||
// Ensure directory exists
|
||||
Quickshell.execDetached(["mkdir", "-p", pamConfigDir]);
|
||||
|
||||
// Generate the PAM config file content
|
||||
var configContent = "auth sufficient pam_fprintd.so timeout=-1\n";
|
||||
configContent += "auth sufficient /run/current-system/sw/lib/security/pam_fprintd.so timeout=-1 # for NixOS\n";
|
||||
configContent += "auth required pam_unix.so\n";
|
||||
|
||||
// Write the config file using heredoc to avoid escaping issues
|
||||
var script = `cat > '${pamConfigFileEsc}' << 'EOF'\n`;
|
||||
script += configContent;
|
||||
script += "EOF\n";
|
||||
Quickshell.execDetached(["sh", "-c", script]);
|
||||
|
||||
Logger.d("Settings", "PAM config file created at:", pamConfigFile);
|
||||
}
|
||||
|
||||
// Process for checking if PAM config file exists
|
||||
Process {
|
||||
id: fileCheckPamProcess
|
||||
running: false
|
||||
|
||||
onExited: function (exitCode) {
|
||||
if (exitCode === 0) {
|
||||
// File exists, skip creation
|
||||
Logger.d("Settings", "PAM config file already exists, skipping creation");
|
||||
} else {
|
||||
// File doesn't exist, create it
|
||||
doCreatePamConfig();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------
|
||||
// Function to clean up deprecated user/custom bar widgets settings
|
||||
function upgradeWidget(widget) {
|
||||
|
||||
+66
-2
@@ -27,6 +27,34 @@ Item {
|
||||
});
|
||||
}
|
||||
|
||||
// Hot corner: trigger click on first widget in a section
|
||||
function triggerFirstWidgetInSection(sectionName: string) {
|
||||
var widgets = BarService.getWidgetsBySection(sectionName, screen?.name);
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
var widget = widgets[i];
|
||||
if (widget && widget.visible && widget.widgetId !== "Spacer") {
|
||||
if (typeof widget.clicked === "function") {
|
||||
widget.clicked();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hot corner: trigger click on last widget in a section
|
||||
function triggerLastWidgetInSection(sectionName: string) {
|
||||
var widgets = BarService.getWidgetsBySection(sectionName, screen?.name);
|
||||
for (var i = widgets.length - 1; i >= 0; i--) {
|
||||
var widget = widgets[i];
|
||||
if (widget && widget.visible && widget.widgetId !== "Spacer") {
|
||||
if (typeof widget.clicked === "function") {
|
||||
widget.clicked();
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Expose bar region for click-through mask
|
||||
readonly property var barRegion: barContentLoader.item?.children[0] || null
|
||||
|
||||
@@ -220,11 +248,29 @@ Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
// Top edge hot corner - triggers first widget in left (top) section
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: Style.marginS
|
||||
x: 0
|
||||
y: 0
|
||||
onClicked: root.triggerFirstWidgetInSection("left")
|
||||
}
|
||||
|
||||
// Bottom edge hot corner - triggers last widget in right (bottom) section
|
||||
MouseArea {
|
||||
width: parent.width
|
||||
height: Style.marginS
|
||||
x: 0
|
||||
anchors.bottom: parent.bottom
|
||||
onClicked: root.triggerLastWidgetInSection("right")
|
||||
}
|
||||
|
||||
// Top section (left widgets)
|
||||
ColumnLayout {
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Style.marginM
|
||||
anchors.topMargin: Style.marginS
|
||||
spacing: Style.marginS
|
||||
|
||||
Repeater {
|
||||
@@ -275,7 +321,7 @@ Item {
|
||||
ColumnLayout {
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Style.marginM
|
||||
anchors.bottomMargin: Style.marginS
|
||||
spacing: Style.marginS
|
||||
|
||||
Repeater {
|
||||
@@ -306,6 +352,24 @@ Item {
|
||||
anchors.fill: parent
|
||||
clip: true
|
||||
|
||||
// Left edge hot corner - triggers first widget in left section
|
||||
MouseArea {
|
||||
width: Style.marginS
|
||||
height: parent.height
|
||||
x: 0
|
||||
y: 0
|
||||
onClicked: root.triggerFirstWidgetInSection("left")
|
||||
}
|
||||
|
||||
// Right edge hot corner - triggers last widget in right section
|
||||
MouseArea {
|
||||
width: Style.marginS
|
||||
height: parent.height
|
||||
anchors.right: parent.right
|
||||
y: 0
|
||||
onClicked: root.triggerLastWidgetInSection("right")
|
||||
}
|
||||
|
||||
// Left Section
|
||||
RowLayout {
|
||||
id: leftSection
|
||||
|
||||
@@ -34,13 +34,18 @@ Item {
|
||||
signal middleClicked
|
||||
signal wheel(int delta)
|
||||
|
||||
// Dynamic sizing based on loaded component
|
||||
width: pillLoader.item ? pillLoader.item.width : 0
|
||||
height: pillLoader.item ? pillLoader.item.height : 0
|
||||
// Size based on content for the content dimension, fill parent for the extended dimension
|
||||
// Horizontal bars: width = content, height = fill parent (for extended click area)
|
||||
// Vertical bars: width = fill parent, height = content
|
||||
width: isVerticalBar ? parent.width : (pillLoader.item ? pillLoader.item.implicitWidth : 0)
|
||||
height: isVerticalBar ? (pillLoader.item ? pillLoader.item.implicitHeight : 0) : parent.height
|
||||
implicitWidth: pillLoader.item ? pillLoader.item.implicitWidth : 0
|
||||
implicitHeight: pillLoader.item ? pillLoader.item.implicitHeight : 0
|
||||
|
||||
// Loader to switch between vertical and horizontal pill implementations
|
||||
// Loader fills BarPill so child components can extend to full bar dimension
|
||||
Loader {
|
||||
id: pillLoader
|
||||
anchors.fill: parent
|
||||
sourceComponent: isVerticalBar ? verticalPillComponent : horizontalPillComponent
|
||||
|
||||
Component {
|
||||
|
||||
@@ -53,7 +53,8 @@ Item {
|
||||
|
||||
readonly property real iconSize: Style.toOdd(pillHeight * 0.48)
|
||||
|
||||
width: {
|
||||
// Content width calculation (for implicit sizing)
|
||||
readonly property real contentWidth: {
|
||||
if (collapseToIcon) {
|
||||
return hasIcon ? pillHeight : 0;
|
||||
}
|
||||
@@ -61,7 +62,12 @@ Item {
|
||||
var baseWidth = hasIcon ? pillHeight : 0;
|
||||
return baseWidth + Math.max(0, pill.width - overlap);
|
||||
}
|
||||
height: pillHeight
|
||||
|
||||
// Fill parent to extend click area to full bar height
|
||||
// Visual content is centered vertically within
|
||||
anchors.fill: parent
|
||||
implicitWidth: contentWidth
|
||||
implicitHeight: pillHeight
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
|
||||
@@ -60,9 +60,8 @@ Item {
|
||||
|
||||
readonly property real iconSize: Style.toOdd(pillHeight * 0.48)
|
||||
|
||||
// For vertical bars: width is just icon size, height includes pill space
|
||||
width: buttonSize
|
||||
height: {
|
||||
// Content height calculation (for implicit sizing and visual layout)
|
||||
readonly property real contentHeight: {
|
||||
if (collapseToIcon) {
|
||||
return hasIcon ? buttonSize : 0;
|
||||
}
|
||||
@@ -75,6 +74,15 @@ Item {
|
||||
return buttonSize;
|
||||
}
|
||||
|
||||
// Fill parent width to extend horizontal click area
|
||||
// Keep content-based height for visual layout
|
||||
anchors.left: parent ? parent.left : undefined
|
||||
anchors.right: parent ? parent.right : undefined
|
||||
anchors.verticalCenter: parent ? parent.verticalCenter : undefined
|
||||
height: contentHeight
|
||||
implicitWidth: buttonSize
|
||||
implicitHeight: contentHeight
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onTooltipTextChanged() {
|
||||
@@ -88,7 +96,7 @@ Item {
|
||||
Rectangle {
|
||||
id: pillBackground
|
||||
width: buttonSize
|
||||
height: root.height
|
||||
height: root.contentHeight
|
||||
radius: Style.radiusM
|
||||
color: root.bgColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
@@ -183,7 +191,7 @@ Item {
|
||||
|
||||
// Icon positioning based on direction
|
||||
x: 0
|
||||
y: openUpward ? (parent.height - height) : 0
|
||||
y: openUpward ? (root.contentHeight - height) : 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
NIcon {
|
||||
|
||||
@@ -15,9 +15,16 @@ Item {
|
||||
readonly property string section: widgetProps ? (widgetProps.section || "") : ""
|
||||
readonly property int sectionIndex: widgetProps ? (widgetProps.sectionWidgetIndex || 0) : 0
|
||||
|
||||
// Don't reserve space unless the loaded widget is really visible
|
||||
implicitWidth: getImplicitSize(loader.item, "implicitWidth")
|
||||
implicitHeight: getImplicitSize(loader.item, "implicitHeight")
|
||||
// Bar orientation and height for extended click areas
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(widgetScreen?.name)
|
||||
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(widgetScreen?.name)
|
||||
|
||||
// Request full bar dimension from layout to extend click areas above/below widgets
|
||||
// For horizontal bars: full bar height, widget's content width
|
||||
// For vertical bars: full bar width, widget's content height
|
||||
implicitWidth: isVerticalBar ? barHeight : getImplicitSize(loader.item, "implicitWidth")
|
||||
implicitHeight: isVerticalBar ? getImplicitSize(loader.item, "implicitHeight") : barHeight
|
||||
|
||||
// Remove layout space left by hidden widgets
|
||||
visible: loader.item ? ((loader.item.opacity > 0.0) || (loader.item.hasOwnProperty("hideMode") && loader.item.hideMode === "transparent")) : false
|
||||
@@ -66,6 +73,19 @@ Item {
|
||||
|
||||
Logger.d("BarWidgetLoader", "Loading widget", widgetId, "on screen:", widgetScreen.name);
|
||||
|
||||
// Extend widget to fill full bar dimension for extended click areas
|
||||
// For horizontal bars: widget fills bar height (content width preserved)
|
||||
// For vertical bars: widget fills bar width (content height preserved)
|
||||
if (root.isVerticalBar) {
|
||||
item.width = Qt.binding(function () {
|
||||
return root.barHeight;
|
||||
});
|
||||
} else {
|
||||
item.height = Qt.binding(function () {
|
||||
return root.barHeight;
|
||||
});
|
||||
}
|
||||
|
||||
// Apply properties to loaded widget
|
||||
for (var prop in widgetProps) {
|
||||
if (item.hasOwnProperty(prop)) {
|
||||
|
||||
@@ -47,6 +47,16 @@ PopupWindow {
|
||||
|
||||
// Use the content height of the Flickable for implicit height
|
||||
implicitHeight: Math.min(screen?.height * 0.9, flickable.contentHeight + (Style.marginS * 2))
|
||||
|
||||
// When implicitHeight changes (menu content loads), force anchor recalculation
|
||||
onImplicitHeightChanged: {
|
||||
if (visible && anchorItem) {
|
||||
Qt.callLater(() => {
|
||||
anchor.updateAnchor();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
visible: false
|
||||
color: "transparent"
|
||||
anchor.item: anchorItem
|
||||
@@ -63,21 +73,25 @@ PopupWindow {
|
||||
menuScreenX = windowXOnScreen + posInPopup.x + baseX;
|
||||
} else {
|
||||
const anchorGlobalPos = anchorItem.mapToItem(null, 0, 0);
|
||||
menuScreenX = anchorGlobalPos.x + baseX;
|
||||
const anchorScreenX = anchorGlobalPos.x;
|
||||
menuScreenX = anchorScreenX + baseX;
|
||||
}
|
||||
|
||||
const menuRight = menuScreenX + implicitWidth;
|
||||
const screenRight = screen.width;
|
||||
const menuLeft = menuScreenX;
|
||||
|
||||
// Adjust if menu would clip on the right
|
||||
if (menuRight > screenRight) {
|
||||
// Only adjust if menu would clip off screen boundaries
|
||||
// Don't adjust if the positioning is intentional (e.g., negative offset for right bar)
|
||||
if (menuRight > screenRight && menuLeft < screenRight) {
|
||||
// Clipping on right edge - shift left
|
||||
const overflow = menuRight - screenRight;
|
||||
return baseX - overflow - Style.marginM;
|
||||
} else if (menuLeft < 0 && menuRight > 0) {
|
||||
// Clipping on left edge - shift right
|
||||
return baseX - menuLeft + Style.marginM;
|
||||
}
|
||||
// Adjust if menu would clip on the left
|
||||
if (menuScreenX < 0) {
|
||||
return baseX - menuScreenX + Style.marginM;
|
||||
}
|
||||
|
||||
return baseX;
|
||||
}
|
||||
return anchorX;
|
||||
@@ -86,52 +100,56 @@ PopupWindow {
|
||||
if (anchorItem && screen) {
|
||||
const barPosition = Settings.getBarPositionForScreen(root.screen?.name);
|
||||
|
||||
// Calculate base Y offset (relative to anchor item)
|
||||
let baseY = anchorY;
|
||||
if (!isSubMenu && barPosition === "bottom") {
|
||||
// For bottom bar, position menu above the anchor with margin (adjusted to match widget menu positioning)
|
||||
|
||||
// Only apply bottom bar special positioning if:
|
||||
// 1. Not a submenu
|
||||
// 2. Bar is at bottom
|
||||
// 3. anchorY is not already negative (if negative, it's pre-calculated from drawer)
|
||||
const shouldApplyBottomBarLogic = !isSubMenu && barPosition === "bottom" && anchorY >= 0;
|
||||
|
||||
if (shouldApplyBottomBarLogic) {
|
||||
// For bottom bar from the bar itself, position menu above the anchor with margin
|
||||
baseY = -(implicitHeight + Style.marginL + 2);
|
||||
}
|
||||
|
||||
// Calculate position relative to current screen (not global coordinates)
|
||||
let menuScreenY;
|
||||
if (isSubMenu && anchorItem.Window && anchorItem.Window.window) {
|
||||
// Submenu: anchor is inside parent PopupWindow
|
||||
const posInPopup = anchorItem.mapToItem(null, 0, 0);
|
||||
const parentWindow = anchorItem.Window.window;
|
||||
// Convert global window Y to screen-relative Y by subtracting screen offset
|
||||
const windowYOnScreen = parentWindow.y - screen.y;
|
||||
menuScreenY = windowYOnScreen + posInPopup.y + baseY;
|
||||
} else if (!isSubMenu && barPosition === "bottom") {
|
||||
// Bottom bar main menu: subtract baseY to position above anchor
|
||||
const anchorGlobalPos = anchorItem.mapToItem(null, 0, 0);
|
||||
menuScreenY = anchorGlobalPos.y - baseY;
|
||||
} else {
|
||||
// Main menu for other positions: add baseY
|
||||
const anchorGlobalPos = anchorItem.mapToItem(null, 0, 0);
|
||||
menuScreenY = anchorGlobalPos.y + baseY;
|
||||
// Use a robust way to get screen coordinates
|
||||
const posInWindow = anchorItem.mapToItem(null, 0, 0);
|
||||
const parentWindow = anchorItem.Window.window;
|
||||
|
||||
// Calculate screen-relative Y of the window
|
||||
let windowYOnScreen = (parentWindow && screen) ? (parentWindow.y - screen.y) : 0;
|
||||
|
||||
// If window reported 0 but bar is at bottom, assume it's at screen bottom
|
||||
if (windowYOnScreen === 0 && barPosition === "bottom" && screen) {
|
||||
windowYOnScreen = screen.height - (parentWindow ? parentWindow.height : Style.getBarHeightForScreen(screen.name));
|
||||
}
|
||||
|
||||
const menuBottom = menuScreenY + implicitHeight;
|
||||
const screenBottom = screen.height;
|
||||
// Calculate the screen Y of the menu top
|
||||
// Use a small guess for height if implicitHeight is 0 to avoid covering the bar on the first frame
|
||||
const effectiveHeight = implicitHeight > 0 ? implicitHeight : 200;
|
||||
const effectiveBaseY = shouldApplyBottomBarLogic ? -(effectiveHeight + Style.marginL + 2) : baseY;
|
||||
|
||||
// Adjust baseY if menu would clip
|
||||
if (menuBottom > screenBottom) {
|
||||
// Clip at bottom - shift up by the overflow amount
|
||||
const overflow = menuBottom - screenBottom;
|
||||
if (!isSubMenu && barPosition === "bottom") {
|
||||
return baseY + overflow + Style.marginM;
|
||||
}
|
||||
return baseY - overflow - Style.marginM;
|
||||
const menuScreenY = windowYOnScreen + posInWindow.y + effectiveBaseY;
|
||||
const menuBottom = menuScreenY + (implicitHeight > 0 ? implicitHeight : effectiveHeight);
|
||||
const screenHeight = screen ? screen.height : 1080;
|
||||
|
||||
// Adjust the final baseY (the actual value returned to anchor.rect.y)
|
||||
let finalBaseY = shouldApplyBottomBarLogic ? -(implicitHeight + Style.marginL + 2) : baseY;
|
||||
|
||||
// Adjust if menu would clip off the bottom
|
||||
if (menuBottom > screenHeight) {
|
||||
const overflow = menuBottom - screenHeight;
|
||||
finalBaseY -= (overflow + Style.marginM);
|
||||
}
|
||||
|
||||
// Adjust if menu would clip off the top
|
||||
// menuScreenY < 0 means it's above the screen edge
|
||||
if (menuScreenY < 0) {
|
||||
// Clip at top - shift down
|
||||
if (!isSubMenu && barPosition === "bottom") {
|
||||
return baseY + menuScreenY - Style.marginM;
|
||||
}
|
||||
return baseY - menuScreenY + Style.marginM;
|
||||
finalBaseY -= (menuScreenY - Style.marginM);
|
||||
}
|
||||
return baseY;
|
||||
|
||||
return finalBaseY;
|
||||
}
|
||||
|
||||
// Fallback if no anchor/screen
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
import QtQuick
|
||||
import qs.Commons
|
||||
import qs.Services.Compositor
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: pillContainer
|
||||
|
||||
required property var workspace
|
||||
required property bool isVertical
|
||||
|
||||
// These must be provided by the parent Workspace widget
|
||||
required property real baseDimensionRatio
|
||||
required property real capsuleHeight
|
||||
required property real barHeight
|
||||
required property string labelMode
|
||||
required property int characterCount
|
||||
required property real textRatio
|
||||
required property bool showLabelsOnlyWhenOccupied
|
||||
required property var colorMap
|
||||
required property string focusedColor
|
||||
required property string occupiedColor
|
||||
required property string emptyColor
|
||||
required property real masterProgress
|
||||
required property bool effectsActive
|
||||
required property color effectColor
|
||||
required property var getWorkspaceWidth
|
||||
required property var getWorkspaceHeight
|
||||
|
||||
// Fixed dimension (cross-axis) for visual pill
|
||||
readonly property real fixedDimension: Style.toOdd(capsuleHeight * baseDimensionRatio)
|
||||
|
||||
// Helper to safely get colors with proper reactivity
|
||||
// Accesses Color singleton directly to ensure fresh values
|
||||
function getColorPair(colorKey) {
|
||||
switch (colorKey) {
|
||||
case "primary":
|
||||
return [Color.mPrimary, Color.mOnPrimary];
|
||||
case "secondary":
|
||||
return [Color.mSecondary, Color.mOnSecondary];
|
||||
case "tertiary":
|
||||
return [Color.mTertiary, Color.mOnTertiary];
|
||||
case "onSurface":
|
||||
return [Color.mOnSurface, Color.mSurface];
|
||||
default:
|
||||
return [Color.mPrimary, Color.mOnPrimary];
|
||||
}
|
||||
}
|
||||
|
||||
// Animated pill dimensions (for visual pill, not container)
|
||||
property real pillWidth: isVertical ? fixedDimension : getWorkspaceWidth(workspace, false)
|
||||
property real pillHeight: isVertical ? getWorkspaceHeight(workspace, false) : fixedDimension
|
||||
|
||||
// Container uses full barHeight on cross-axis for larger click area
|
||||
width: isVertical ? barHeight : getWorkspaceWidth(workspace, false)
|
||||
height: isVertical ? getWorkspaceHeight(workspace, false) : barHeight
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "active"
|
||||
when: workspace.isActive
|
||||
PropertyChanges {
|
||||
target: pillContainer
|
||||
width: isVertical ? barHeight : getWorkspaceWidth(workspace, true)
|
||||
height: isVertical ? getWorkspaceHeight(workspace, true) : barHeight
|
||||
pillWidth: isVertical ? fixedDimension : getWorkspaceWidth(workspace, true)
|
||||
pillHeight: isVertical ? getWorkspaceHeight(workspace, true) : fixedDimension
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "inactive"
|
||||
to: "active"
|
||||
NumberAnimation {
|
||||
properties: isVertical ? "height,pillHeight" : "width,pillWidth"
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "active"
|
||||
to: "inactive"
|
||||
NumberAnimation {
|
||||
properties: isVertical ? "height,pillHeight" : "width,pillWidth"
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Rectangle {
|
||||
id: pill
|
||||
width: pillContainer.pillWidth
|
||||
height: pillContainer.pillHeight
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
radius: Style.radiusM
|
||||
z: 0
|
||||
|
||||
color: {
|
||||
if (pillMouseArea.containsMouse)
|
||||
return Color.mHover;
|
||||
if (workspace.isFocused)
|
||||
return getColorPair(focusedColor)[0];
|
||||
if (workspace.isUrgent)
|
||||
return Color.mError;
|
||||
if (workspace.isOccupied)
|
||||
return getColorPair(occupiedColor)[0];
|
||||
return Qt.alpha(getColorPair(emptyColor)[0], 0.3);
|
||||
}
|
||||
|
||||
Loader {
|
||||
active: (labelMode !== "none") && (!showLabelsOnlyWhenOccupied || workspace.isOccupied || workspace.isFocused)
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: Component {
|
||||
NText {
|
||||
text: {
|
||||
if (workspace.name && workspace.name.length > 0) {
|
||||
if (labelMode === "name") {
|
||||
return workspace.name.substring(0, characterCount);
|
||||
}
|
||||
if (labelMode === "index+name") {
|
||||
// Vertical mode: compact format (no space, first char only)
|
||||
// Horizontal mode: full format (space, more chars)
|
||||
if (isVertical) {
|
||||
return workspace.idx.toString() + workspace.name.substring(0, 1);
|
||||
}
|
||||
return workspace.idx.toString() + " " + workspace.name.substring(0, characterCount);
|
||||
}
|
||||
}
|
||||
return workspace.idx.toString();
|
||||
}
|
||||
family: Settings.data.ui.fontFixed
|
||||
// Size based on the fixed dimension (cross-axis) of the visual pill
|
||||
pointSize: (isVertical ? pillContainer.pillWidth : pillContainer.pillHeight) * textRatio
|
||||
applyUiScale: false
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.weight: Style.fontWeightBold
|
||||
wrapMode: Text.Wrap
|
||||
color: {
|
||||
if (pillMouseArea.containsMouse)
|
||||
return Color.mOnHover;
|
||||
if (workspace.isFocused)
|
||||
return getColorPair(focusedColor)[1];
|
||||
if (workspace.isUrgent)
|
||||
return Color.mOnError;
|
||||
if (workspace.isOccupied)
|
||||
return getColorPair(occupiedColor)[1];
|
||||
return getColorPair(emptyColor)[1];
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
enabled: !Color.isTransitioning
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Material 3-inspired smooth animations
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on color {
|
||||
enabled: !Color.isTransitioning
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on pillWidth {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on pillHeight {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
|
||||
// Full-height click area
|
||||
MouseArea {
|
||||
id: pillMouseArea
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
hoverEnabled: true
|
||||
onClicked: {
|
||||
CompositorService.switchToWorkspace(workspace);
|
||||
}
|
||||
}
|
||||
|
||||
// Burst effect overlay for focused pill
|
||||
Rectangle {
|
||||
id: pillBurst
|
||||
anchors.centerIn: pill
|
||||
width: pillContainer.pillWidth + 18 * masterProgress * scale
|
||||
height: pillContainer.pillHeight + 18 * masterProgress * scale
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
border.color: effectColor
|
||||
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - masterProgress))))
|
||||
opacity: effectsActive && workspace.isFocused ? (1.0 - masterProgress) * 0.7 : 0
|
||||
visible: effectsActive && workspace.isFocused
|
||||
z: 1
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,10 @@ import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
Layout.preferredHeight: isVerticalBar ? -1 : Style.getBarHeightForScreen(screenName)
|
||||
Layout.preferredWidth: isVerticalBar ? Style.getBarHeightForScreen(screenName) : -1
|
||||
Layout.fillHeight: false
|
||||
Layout.fillWidth: false
|
||||
|
||||
property ShellScreen screen
|
||||
|
||||
@@ -22,9 +26,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId] || {}
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length && widgets[sectionWidgetIndex]) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -41,10 +47,10 @@ Item {
|
||||
readonly property real maxWidth: (widgetSettings.maxWidth !== undefined) ? widgetSettings.maxWidth : Math.max(widgetMetadata.maxWidth || 0, screen ? screen.width * 0.06 : 0)
|
||||
readonly property bool useFixedWidth: (widgetSettings.useFixedWidth !== undefined) ? widgetSettings.useFixedWidth : (widgetMetadata.useFixedWidth || false)
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
|
||||
readonly property bool hasFocusedWindow: CompositorService.getFocusedWindow() !== null
|
||||
readonly property string windowTitle: CompositorService.getFocusedWindowTitle() || "No active window"
|
||||
readonly property string fallbackIcon: "user-desktop"
|
||||
@@ -173,10 +179,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "widget-settings") {
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
@@ -263,6 +267,7 @@ Item {
|
||||
return NScrollText.ScrollMode.Hover;
|
||||
return NScrollText.ScrollMode.Never;
|
||||
}
|
||||
forcedHover: mainMouseArea.containsMouse
|
||||
NText {
|
||||
text: windowTitle
|
||||
pointSize: barFontSize
|
||||
@@ -312,32 +317,37 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse area for hover detection
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onEntered: {
|
||||
if ((windowTitle !== "") && isVerticalBar || (scrollingMode === "never")) {
|
||||
TooltipService.show(root, windowTitle, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
TooltipService.hide();
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Mouse area moved to root
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse area for hover detection
|
||||
MouseArea {
|
||||
id: mainMouseArea
|
||||
anchors.fill: parent
|
||||
|
||||
// Extend click area to screen edge if widget is at the start/end
|
||||
anchors.leftMargin: (!isVerticalBar && section === "left" && sectionWidgetIndex === 0) ? -Style.marginS : 0
|
||||
anchors.rightMargin: (!isVerticalBar && section === "right" && sectionWidgetIndex === sectionWidgetsCount - 1) ? -Style.marginS : 0
|
||||
anchors.topMargin: (isVerticalBar && section === "left" && sectionWidgetIndex === 0) ? -Style.marginM : 0
|
||||
anchors.bottomMargin: (isVerticalBar && section === "right" && sectionWidgetIndex === sectionWidgetsCount - 1) ? -Style.marginM : 0
|
||||
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onEntered: {
|
||||
if ((windowTitle !== "") && isVerticalBar || (scrollingMode === "never")) {
|
||||
TooltipService.show(root, windowTitle, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
TooltipService.hide();
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -19,14 +19,16 @@ Item {
|
||||
property int sectionWidgetIndex: -1
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -74,8 +76,12 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
implicitWidth: !shouldShow ? 0 : isVerticalBar ? capsuleHeight : visualizerWidth
|
||||
implicitHeight: !shouldShow ? 0 : isVerticalBar ? visualizerWidth : capsuleHeight
|
||||
// Content dimensions for implicit sizing
|
||||
readonly property real contentWidth: !shouldShow ? 0 : isVerticalBar ? capsuleHeight : visualizerWidth
|
||||
readonly property real contentHeight: !shouldShow ? 0 : isVerticalBar ? visualizerWidth : capsuleHeight
|
||||
|
||||
implicitWidth: contentWidth
|
||||
implicitHeight: contentHeight
|
||||
visible: shouldShow
|
||||
opacity: shouldShow ? 1.0 : 0.0
|
||||
|
||||
@@ -92,37 +98,40 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Store visualizer type to force re-evaluation
|
||||
readonly property string currentVisualizerType: Settings.data.audio.visualizerType
|
||||
|
||||
// Visual capsule centered in parent
|
||||
Rectangle {
|
||||
id: background
|
||||
anchors.fill: parent
|
||||
width: root.contentWidth
|
||||
height: root.contentHeight
|
||||
anchors.centerIn: parent
|
||||
radius: Style.radiusS
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
}
|
||||
|
||||
// Store visualizer type to force re-evaluation
|
||||
readonly property string currentVisualizerType: Settings.data.audio.visualizerType
|
||||
// When visualizer type or playback changes, shouldShow updates automatically
|
||||
// The Loader dynamically loads the appropriate visualizer based on settings
|
||||
Loader {
|
||||
id: visualizerLoader
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginS
|
||||
active: shouldShow
|
||||
asynchronous: true
|
||||
|
||||
// When visualizer type or playback changes, shouldShow updates automatically
|
||||
// The Loader dynamically loads the appropriate visualizer based on settings
|
||||
Loader {
|
||||
id: visualizerLoader
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginS
|
||||
active: shouldShow
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: {
|
||||
switch (currentVisualizerType) {
|
||||
case "linear":
|
||||
return linearComponent;
|
||||
case "mirrored":
|
||||
return mirroredComponent;
|
||||
case "wave":
|
||||
return waveComponent;
|
||||
default:
|
||||
return null;
|
||||
sourceComponent: {
|
||||
switch (currentVisualizerType) {
|
||||
case "linear":
|
||||
return linearComponent;
|
||||
case "mirrored":
|
||||
return mirroredComponent;
|
||||
case "wave":
|
||||
return waveComponent;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,10 +153,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "cycle-visualizer") {
|
||||
const types = ["linear", "mirrored", "wave"];
|
||||
@@ -170,11 +177,7 @@ Item {
|
||||
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
} else {
|
||||
const types = ["linear", "mirrored", "wave"];
|
||||
const currentIndex = types.indexOf(currentVisualizerType);
|
||||
|
||||
+65
-119
@@ -22,9 +22,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -32,7 +34,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: widgetSettings.displayMode !== undefined ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
readonly property real warningThreshold: widgetSettings.warningThreshold !== undefined ? widgetSettings.warningThreshold : widgetMetadata.warningThreshold
|
||||
@@ -43,8 +45,6 @@ Item {
|
||||
|
||||
// Visibility: show if hideIfNotDetected is false, or if battery is ready (after initialization)
|
||||
readonly property bool shouldShow: !hideIfNotDetected || (isReady && (hideIfIdle ? (!isCharging && !isPluggedIn) : true))
|
||||
visible: shouldShow
|
||||
opacity: shouldShow ? 1.0 : 0.0
|
||||
|
||||
// Test mode
|
||||
readonly property bool testMode: false
|
||||
@@ -53,84 +53,31 @@ Item {
|
||||
readonly property bool testPluggedIn: false
|
||||
readonly property string deviceNativePath: widgetSettings.deviceNativePath || ""
|
||||
|
||||
function findBatteryDevice(nativePath) {
|
||||
if (!nativePath || !UPower.devices) {
|
||||
return UPower.displayDevice;
|
||||
}
|
||||
var devices = UPower.devices.values || [];
|
||||
for (var i = 0; i < devices.length; i++) {
|
||||
var device = devices[i];
|
||||
if (device && device.nativePath === nativePath && device.type !== UPowerDeviceType.LinePower && device.percentage !== undefined) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return UPower.displayDevice;
|
||||
readonly property var battery: BatteryService.findUPowerDevice(deviceNativePath)
|
||||
readonly property var bluetoothDevice: deviceNativePath ? BatteryService.findBluetoothDevice(deviceNativePath) : null
|
||||
readonly property var device: {
|
||||
if (deviceNativePath)
|
||||
return bluetoothDevice || battery;
|
||||
return BatteryService.primaryDevice;
|
||||
}
|
||||
readonly property bool hasBluetoothBattery: BatteryService.isBluetoothDevice(device)
|
||||
|
||||
function findBluetoothDevice(nativePath) {
|
||||
if (!nativePath || !BluetoothService.devices) {
|
||||
return null;
|
||||
}
|
||||
var macMatch = nativePath.match(/([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2})/);
|
||||
if (!macMatch) {
|
||||
return null;
|
||||
}
|
||||
var macAddress = macMatch[1].toUpperCase();
|
||||
var devices = BluetoothService.devices.values || [];
|
||||
for (var i = 0; i < devices.length; i++) {
|
||||
var device = devices[i];
|
||||
if (device && device.address && device.address.toUpperCase() === macAddress) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
readonly property bool isReady: testMode ? true : (BatteryService.ready && BatteryService.isDeviceReady(device))
|
||||
readonly property real percent: testMode ? testPercent : (isReady ? BatteryService.getPercentage(device) : 0)
|
||||
readonly property bool isCharging: testMode ? testCharging : (isReady ? BatteryService.isCharging(device) : false)
|
||||
readonly property bool isPluggedIn: testMode ? testPluggedIn : (isReady ? BatteryService.isPluggedIn(device) : false)
|
||||
|
||||
readonly property var battery: findBatteryDevice(deviceNativePath)
|
||||
readonly property var bluetoothDevice: deviceNativePath ? findBluetoothDevice(deviceNativePath) : null
|
||||
readonly property bool hasBluetoothBattery: bluetoothDevice && bluetoothDevice.batteryAvailable && bluetoothDevice.battery !== undefined
|
||||
readonly property bool isBluetoothConnected: bluetoothDevice && bluetoothDevice.connected === true
|
||||
property bool hasNotifiedLowBattery: false
|
||||
|
||||
property bool initializationComplete: false
|
||||
Timer {
|
||||
interval: 500
|
||||
running: true
|
||||
onTriggered: root.initializationComplete = true
|
||||
}
|
||||
visible: shouldShow
|
||||
opacity: shouldShow ? 1.0 : 0.0
|
||||
|
||||
readonly property bool isDevicePresent: {
|
||||
if (testMode)
|
||||
return true;
|
||||
if (deviceNativePath) {
|
||||
if (bluetoothDevice) {
|
||||
return isBluetoothConnected;
|
||||
}
|
||||
if (battery && battery.nativePath === deviceNativePath) {
|
||||
if (battery.type === UPowerDeviceType.Battery && battery.isPresent !== undefined) {
|
||||
return battery.isPresent;
|
||||
}
|
||||
return battery.ready && battery.percentage !== undefined && (battery.percentage > 0 || isCharging);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (battery) {
|
||||
// For default device, check isPresent if it's a Battery type, otherwise require percentage > 0
|
||||
if (battery.type === UPowerDeviceType.Battery && battery.isPresent !== undefined) {
|
||||
return battery.isPresent;
|
||||
}
|
||||
// For non-battery types or when isPresent is undefined, require actual percentage
|
||||
return battery.ready && battery.percentage !== undefined && battery.percentage > 0;
|
||||
}
|
||||
return false;
|
||||
return BatteryService.isDevicePresent(device);
|
||||
}
|
||||
|
||||
readonly property bool isReady: testMode ? true : (initializationComplete && battery && battery.ready && isDevicePresent && (battery.percentage !== undefined || hasBluetoothBattery))
|
||||
readonly property real percent: testMode ? testPercent : (isReady ? (hasBluetoothBattery ? (bluetoothDevice.battery * 100) : (battery.percentage * 100)) : 0)
|
||||
readonly property bool isCharging: testMode ? testCharging : (isReady ? battery.state === UPowerDeviceState.Charging : false)
|
||||
readonly property bool isPluggedIn: testMode ? testPluggedIn : (isReady ? battery.state === UPowerDeviceState.FullyCharged || battery.state === UPowerDeviceState.PendingCharge : false)
|
||||
|
||||
property bool hasNotifiedLowBattery: false
|
||||
|
||||
implicitWidth: pill.width
|
||||
implicitHeight: pill.height
|
||||
|
||||
@@ -139,25 +86,26 @@ Item {
|
||||
hasNotifiedLowBattery = true;
|
||||
ToastService.showWarning(I18n.tr("toast.battery.low"), I18n.tr("toast.battery.low-desc", {
|
||||
"percent": Math.round(currentPercent)
|
||||
}));
|
||||
}), "battery-exclamation", "warning", 4000, "", null);
|
||||
} else if (hasNotifiedLowBattery && (charging || pluggedIn || currentPercent > warningThreshold + 5)) {
|
||||
hasNotifiedLowBattery = false;
|
||||
}
|
||||
}
|
||||
|
||||
function getCurrentPercent() {
|
||||
return hasBluetoothBattery ? (bluetoothDevice.battery * 100) : (battery ? battery.percentage * 100 : 0);
|
||||
return BatteryService.getPercentage(device);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: battery
|
||||
target: device
|
||||
function onPercentageChanged() {
|
||||
if (battery) {
|
||||
if (device) {
|
||||
maybeNotify(getCurrentPercent(), isCharging, isPluggedIn, isReady);
|
||||
}
|
||||
}
|
||||
|
||||
function onStateChanged() {
|
||||
if (battery) {
|
||||
if (device) {
|
||||
if (isCharging || isPluggedIn) {
|
||||
hasNotifiedLowBattery = false;
|
||||
}
|
||||
@@ -167,12 +115,7 @@ Item {
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: bluetoothDevice
|
||||
function onBatteryChanged() {
|
||||
if (bluetoothDevice && hasBluetoothBattery) {
|
||||
maybeNotify(bluetoothDevice.battery * 100, battery ? isCharging : false, battery ? isPluggedIn : false, true);
|
||||
}
|
||||
}
|
||||
target: (device && BatteryService.isBluetoothDevice(device)) ? device : null
|
||||
}
|
||||
|
||||
NPopupContextMenu {
|
||||
@@ -187,10 +130,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "widget-settings") {
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
@@ -200,7 +141,6 @@ Item {
|
||||
|
||||
BarPill {
|
||||
id: pill
|
||||
|
||||
screen: root.screen
|
||||
oppositeDirection: BarService.getPillDirection(root)
|
||||
icon: testMode ? BatteryService.getIcon(testPercent, testCharging, testPluggedIn, true) : BatteryService.getIcon(percent, isCharging, isPluggedIn, isReady)
|
||||
@@ -208,52 +148,58 @@ Item {
|
||||
suffix: "%"
|
||||
autoHide: false
|
||||
forceOpen: isReady && displayMode === "alwaysShow"
|
||||
forceClose: displayMode === "alwaysHide" || (initializationComplete && !isReady)
|
||||
customBackgroundColor: !initializationComplete ? "transparent" : (isCharging ? Color.mPrimary : (isLowBattery ? Color.mError : "transparent"))
|
||||
customTextIconColor: !initializationComplete ? "transparent" : (isCharging ? Color.mOnPrimary : (isLowBattery ? Color.mOnError : "transparent"))
|
||||
forceClose: displayMode === "alwaysHide" || (BatteryService.ready && !isReady)
|
||||
customBackgroundColor: !BatteryService.ready ? "transparent" : (isCharging ? Color.mPrimary : (isLowBattery ? Color.mError : "transparent"))
|
||||
customTextIconColor: !BatteryService.ready ? "transparent" : (isCharging ? Color.mOnPrimary : (isLowBattery ? Color.mOnError : "transparent"))
|
||||
|
||||
tooltipText: {
|
||||
let lines = [];
|
||||
if (testMode) {
|
||||
lines.push(`Time left: ${Time.formatVagueHumanReadableDuration(12345)}.`);
|
||||
lines.push("Time left: " + Time.formatVagueHumanReadableDuration(12345) + ".");
|
||||
return lines.join("\n");
|
||||
}
|
||||
if (!isReady || !isDevicePresent) {
|
||||
return I18n.tr("battery.no-battery-detected");
|
||||
}
|
||||
if (!isPluggedIn && battery.timeToEmpty > 0) {
|
||||
lines.push(I18n.tr("battery.time-left", {
|
||||
"time": Time.formatVagueHumanReadableDuration(battery.timeToEmpty)
|
||||
}));
|
||||
const isInternal = device === BatteryService.primaryDevice && BatteryService.isLaptopBattery;
|
||||
|
||||
if (isInternal) {
|
||||
let timeText = BatteryService.getTimeRemainingText(device);
|
||||
if (timeText && timeText !== I18n.tr("common.idle") && timeText !== I18n.tr("battery.no-battery-detected") && timeText !== I18n.tr("battery.plugged-in")) {
|
||||
lines.push(timeText);
|
||||
}
|
||||
|
||||
let rateText = BatteryService.getRateText(device);
|
||||
if (rateText) {
|
||||
lines.push(rateText);
|
||||
}
|
||||
} else if (device) {
|
||||
// External / Peripheral Device (Phone, Keyboard, Mouse, Gamepad, Headphone etc.)
|
||||
let name = BatteryService.getDeviceName(device);
|
||||
let pct = Math.round(BatteryService.getPercentage(device));
|
||||
lines.push(name + ": " + pct + suffix);
|
||||
}
|
||||
if (!isPluggedIn && battery.timeToFull > 0) {
|
||||
lines.push(I18n.tr("battery.time-until-full", {
|
||||
"time": Time.formatVagueHumanReadableDuration(battery.timeToFull)
|
||||
}));
|
||||
}
|
||||
if (battery.changeRate !== undefined) {
|
||||
const rate = Math.abs(battery.changeRate);
|
||||
if (isPluggedIn) {
|
||||
lines.push(I18n.tr("battery.plugged-in"));
|
||||
} else if (isCharging) {
|
||||
lines.push(I18n.tr("battery.charging-rate", {
|
||||
"rate": rate.toFixed(2)
|
||||
}));
|
||||
} else {
|
||||
lines.push(I18n.tr("battery.discharging-rate", {
|
||||
"rate": rate.toFixed(2)
|
||||
}));
|
||||
|
||||
// If we are showing the main laptop battery, append external devices
|
||||
if (isInternal) {
|
||||
var external = BatteryService.externalBatteries;
|
||||
if (external.length > 0) {
|
||||
if (lines.length > 0)
|
||||
lines.push(""); // Separator
|
||||
for (var j = 0; j < external.length; j++) {
|
||||
var dev = external[j];
|
||||
var dName = BatteryService.getDeviceName(dev);
|
||||
var dPct = Math.round(BatteryService.getPercentage(dev));
|
||||
lines.push(dName + ": " + dPct + suffix);
|
||||
}
|
||||
}
|
||||
}
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
onClicked: PanelService.getPanel("batteryPanel", screen)?.toggle(this)
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,9 +19,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -29,7 +31,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: widgetSettings.displayMode !== undefined ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
|
||||
@@ -53,10 +55,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "toggle-bluetooth") {
|
||||
BluetoothService.setBluetoothEnabled(!BluetoothService.enabled);
|
||||
@@ -94,11 +94,7 @@ Item {
|
||||
p.toggle(this);
|
||||
}
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
tooltipText: {
|
||||
if (pill.text !== "") {
|
||||
|
||||
@@ -20,9 +20,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -30,7 +32,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
|
||||
@@ -114,10 +116,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "open-display-settings") {
|
||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||
@@ -169,11 +169,7 @@ Item {
|
||||
onClicked: PanelService.getPanel("brightnessPanel", screen)?.toggle(this)
|
||||
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import qs.Modules.Bar.Extras
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
@@ -19,9 +19,11 @@ Rectangle {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -29,10 +31,10 @@ Rectangle {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
|
||||
readonly property var now: Time.now
|
||||
|
||||
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
||||
@@ -43,76 +45,89 @@ Rectangle {
|
||||
readonly property string formatVertical: widgetSettings.formatVertical !== undefined ? widgetSettings.formatVertical : widgetMetadata.formatVertical
|
||||
readonly property string tooltipFormat: widgetSettings.tooltipFormat !== undefined ? widgetSettings.tooltipFormat : widgetMetadata.tooltipFormat
|
||||
|
||||
implicitWidth: isBarVertical ? capsuleHeight : Math.round((isBarVertical ? verticalLoader.implicitWidth : horizontalLoader.implicitWidth) + Style.marginXL)
|
||||
// Content dimensions for implicit sizing
|
||||
readonly property real contentWidth: isBarVertical ? capsuleHeight : Math.round((isBarVertical ? verticalLoader.implicitWidth : horizontalLoader.implicitWidth) + Style.marginXL)
|
||||
readonly property real contentHeight: isBarVertical ? Math.round(verticalLoader.implicitHeight + Style.marginS * 2) : capsuleHeight
|
||||
|
||||
implicitHeight: isBarVertical ? Math.round(verticalLoader.implicitHeight + Style.marginS * 2) : capsuleHeight
|
||||
// Size: use implicit width/height
|
||||
// BarWidgetLoader sets explicit width/height to extend click area
|
||||
implicitWidth: contentWidth
|
||||
implicitHeight: contentHeight
|
||||
|
||||
radius: Style.radiusS
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
Item {
|
||||
id: clockContainer
|
||||
// Visual clock capsule - stays at content size, centered in parent
|
||||
Rectangle {
|
||||
id: visualClock
|
||||
width: root.contentWidth
|
||||
height: root.contentHeight
|
||||
anchors.centerIn: parent
|
||||
|
||||
// Horizontal
|
||||
Loader {
|
||||
id: horizontalLoader
|
||||
active: !isBarVertical
|
||||
radius: Style.radiusL
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
Item {
|
||||
id: clockContainer
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: ColumnLayout {
|
||||
|
||||
// Horizontal
|
||||
Loader {
|
||||
id: horizontalLoader
|
||||
active: !isBarVertical
|
||||
anchors.centerIn: parent
|
||||
spacing: Settings.data.bar.showCapsule ? -5 : -3
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: I18n.locale.toString(now, formatHorizontal.trim()).split("\\n")
|
||||
NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault
|
||||
Binding on pointSize {
|
||||
value: {
|
||||
if (repeater.model.length == 1) {
|
||||
// Single line: Full size
|
||||
return barFontSize;
|
||||
} else if (repeater.model.length == 2) {
|
||||
// Two lines: First line is bigger than the second
|
||||
return (index == 0) ? Math.round(barFontSize * 0.9) : Math.round(barFontSize * 0.75);
|
||||
} else {
|
||||
// More than two lines: Make it small!
|
||||
return Math.round(barFontSize * 0.75);
|
||||
sourceComponent: ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: Settings.data.bar.showCapsule ? -5 : -3
|
||||
Repeater {
|
||||
id: repeater
|
||||
model: I18n.locale.toString(now, formatHorizontal.trim()).split("\\n")
|
||||
NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault
|
||||
Binding on pointSize {
|
||||
value: {
|
||||
if (repeater.model.length == 1) {
|
||||
// Single line: Full size
|
||||
return barFontSize;
|
||||
} else if (repeater.model.length == 2) {
|
||||
// Two lines: First line is bigger than the second
|
||||
return (index == 0) ? Math.round(barFontSize * 0.9) : Math.round(barFontSize * 0.75);
|
||||
} else {
|
||||
// More than two lines: Make it small!
|
||||
return Math.round(barFontSize * 0.75);
|
||||
}
|
||||
}
|
||||
}
|
||||
applyUiScale: false
|
||||
color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
}
|
||||
applyUiScale: false
|
||||
color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Vertical
|
||||
Loader {
|
||||
id: verticalLoader
|
||||
active: isBarVertical
|
||||
anchors.centerIn: parent // Now this works without layout conflicts
|
||||
sourceComponent: ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: -2
|
||||
Repeater {
|
||||
model: I18n.locale.toString(now, formatVertical.trim()).split(" ")
|
||||
delegate: NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault
|
||||
pointSize: barFontSize
|
||||
applyUiScale: false
|
||||
color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
// Vertical
|
||||
Loader {
|
||||
id: verticalLoader
|
||||
active: isBarVertical
|
||||
anchors.centerIn: parent // Now this works without layout conflicts
|
||||
sourceComponent: ColumnLayout {
|
||||
anchors.centerIn: parent
|
||||
spacing: -2
|
||||
Repeater {
|
||||
model: I18n.locale.toString(now, formatVertical.trim()).split(" ")
|
||||
delegate: NText {
|
||||
visible: text !== ""
|
||||
text: modelData
|
||||
family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault
|
||||
pointSize: barFontSize
|
||||
applyUiScale: false
|
||||
color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface
|
||||
wrapMode: Text.WordWrap
|
||||
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,10 +151,9 @@ Rectangle {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
// Close the context menu
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "open-calendar") {
|
||||
PanelService.getPanel("clockPanel", screen)?.toggle(root);
|
||||
@@ -177,11 +191,7 @@ Rectangle {
|
||||
onClicked: mouse => {
|
||||
TooltipService.hide();
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
} else {
|
||||
PanelService.getPanel("clockPanel", screen)?.toggle(this);
|
||||
}
|
||||
|
||||
@@ -22,9 +22,11 @@ NIconButton {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -118,10 +120,8 @@ NIconButton {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "open-launcher") {
|
||||
PanelService.getPanel("launcherPanel", screen)?.toggle();
|
||||
@@ -145,11 +145,7 @@ NIconButton {
|
||||
}
|
||||
}
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
onMiddleClicked: PanelService.getPanel("launcherPanel", screen)?.toggle()
|
||||
|
||||
|
||||
@@ -21,9 +21,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -31,7 +33,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
|
||||
|
||||
readonly property string customIcon: widgetSettings.icon || widgetMetadata.icon
|
||||
@@ -231,10 +233,10 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: root.onClicked()
|
||||
onRightClicked: root.onRightClicked()
|
||||
onMiddleClicked: root.onMiddleClicked()
|
||||
onWheel: delta => root.onWheel(delta)
|
||||
onClicked: root.clicked()
|
||||
onRightClicked: root.rightClicked()
|
||||
onMiddleClicked: root.middleClicked()
|
||||
onWheel: delta => root.wheeled(delta)
|
||||
}
|
||||
|
||||
// Internal state for dynamic text
|
||||
@@ -456,22 +458,20 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function onClicked() {
|
||||
function clicked() {
|
||||
if (leftClickExec) {
|
||||
Quickshell.execDetached(["sh", "-lc", leftClickExec]);
|
||||
Logger.i("CustomButton", `Executing command: ${leftClickExec}`);
|
||||
} else if (!leftClickUpdateText) {
|
||||
// No left click script was defined, open settings
|
||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||
settingsPanel.requestedTab = SettingsPanel.Tab.Bar;
|
||||
settingsPanel.open();
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
//SettingsPanelService.openToTab(SettingsPanel.Tab.Bar, 1, screen);
|
||||
}
|
||||
if (!textStream && leftClickUpdateText) {
|
||||
runTextCommand();
|
||||
}
|
||||
}
|
||||
|
||||
function onRightClicked() {
|
||||
function rightClicked() {
|
||||
if (rightClickExec) {
|
||||
Quickshell.execDetached(["sh", "-lc", rightClickExec]);
|
||||
Logger.i("CustomButton", `Executing command: ${rightClickExec}`);
|
||||
@@ -481,7 +481,7 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
function onMiddleClicked() {
|
||||
function middleClicked() {
|
||||
if (middleClickExec) {
|
||||
Quickshell.execDetached(["sh", "-lc", middleClickExec]);
|
||||
Logger.i("CustomButton", `Executing command: ${middleClickExec}`);
|
||||
@@ -516,7 +516,7 @@ Item {
|
||||
textProc.running = true;
|
||||
}
|
||||
|
||||
function onWheel(delta) {
|
||||
function wheeled(delta) {
|
||||
if (wheelMode === "unified" && wheelExec) {
|
||||
let normalizedDelta = delta > 0 ? 1 : -1;
|
||||
|
||||
|
||||
@@ -19,9 +19,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -29,7 +31,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
|
||||
implicitWidth: pill.width
|
||||
|
||||
@@ -23,9 +23,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -33,7 +35,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
|
||||
readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
@@ -57,10 +59,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "widget-settings") {
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
@@ -82,11 +82,7 @@ Item {
|
||||
forceClose: root.showIcon && root.displayMode === "alwaysHide"
|
||||
onClicked: CompositorService.cycleKeyboardLayout()
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ NIconButton {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -32,8 +34,8 @@ NIconButton {
|
||||
|
||||
icon: iconName
|
||||
tooltipText: I18n.tr("actions.open-launcher")
|
||||
tooltipDirection: BarService.getTooltipDirection(screen?.name)
|
||||
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
tooltipDirection: BarService.getTooltipDirection(screenName)
|
||||
baseSize: Style.getCapsuleHeightForScreen(screenName)
|
||||
applyUiScale: false
|
||||
customRadius: Style.radiusL
|
||||
colorBg: Style.capsuleColor
|
||||
@@ -60,10 +62,8 @@ NIconButton {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "launcher-settings") {
|
||||
var panel = PanelService.getPanel("settingsPanel", screen);
|
||||
@@ -78,10 +78,6 @@ NIconButton {
|
||||
onClicked: PanelService.getPanel("launcherPanel", screen)?.toggle()
|
||||
onMiddleClicked: PanelService.getPanel("launcherPanel", screen)?.toggle()
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import qs.Services.Keyboard
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
@@ -21,9 +21,11 @@ Rectangle {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -31,9 +33,9 @@ Rectangle {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
|
||||
readonly property bool showCaps: (widgetSettings.showCapsLock !== undefined) ? widgetSettings.showCapsLock : widgetMetadata.showCapsLock
|
||||
readonly property bool showNum: (widgetSettings.showNumLock !== undefined) ? widgetSettings.showNumLock : widgetMetadata.showNumLock
|
||||
@@ -45,15 +47,12 @@ Rectangle {
|
||||
|
||||
readonly property bool hideWhenOff: (widgetSettings.hideWhenOff !== undefined) ? widgetSettings.hideWhenOff : (widgetMetadata.hideWhenOff !== undefined ? widgetMetadata.hideWhenOff : false)
|
||||
|
||||
implicitWidth: isVertical ? capsuleHeight : Math.round(layout.implicitWidth + Style.marginXL)
|
||||
implicitHeight: isVertical ? Math.round(layout.implicitHeight + Style.marginXL) : capsuleHeight
|
||||
// Content dimensions for implicit sizing
|
||||
readonly property real contentWidth: isVertical ? capsuleHeight : Math.round(layout.implicitWidth + Style.marginXL)
|
||||
readonly property real contentHeight: isVertical ? Math.round(layout.implicitHeight + Style.marginXL) : capsuleHeight
|
||||
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
implicitWidth: contentWidth
|
||||
implicitHeight: contentHeight
|
||||
|
||||
NPopupContextMenu {
|
||||
id: contextMenu
|
||||
@@ -67,10 +66,8 @@ Rectangle {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "widget-settings") {
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
@@ -78,70 +75,79 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
// Visual capsule centered in parent
|
||||
Rectangle {
|
||||
id: visualCapsule
|
||||
width: root.contentWidth
|
||||
height: root.contentHeight
|
||||
anchors.centerIn: parent
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
Item {
|
||||
id: layout
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
implicitWidth: rowLayout.visible ? rowLayout.implicitWidth : colLayout.implicitWidth
|
||||
implicitHeight: rowLayout.visible ? rowLayout.implicitHeight : colLayout.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
visible: !root.isVertical
|
||||
spacing: 0
|
||||
|
||||
NIcon {
|
||||
visible: root.showCaps && (!root.hideWhenOff || LockKeysService.capsLockOn)
|
||||
icon: root.capsIcon
|
||||
color: LockKeysService.capsLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showNum && (!root.hideWhenOff || LockKeysService.numLockOn)
|
||||
icon: root.numIcon
|
||||
color: LockKeysService.numLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showScroll && (!root.hideWhenOff || LockKeysService.scrollLockOn)
|
||||
icon: root.scrollIcon
|
||||
color: LockKeysService.scrollLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: colLayout
|
||||
visible: root.isVertical
|
||||
spacing: 0
|
||||
|
||||
NIcon {
|
||||
visible: root.showCaps && (!root.hideWhenOff || LockKeysService.capsLockOn)
|
||||
icon: root.capsIcon
|
||||
color: LockKeysService.capsLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showNum && (!root.hideWhenOff || LockKeysService.numLockOn)
|
||||
icon: root.numIcon
|
||||
color: LockKeysService.numLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showScroll && (!root.hideWhenOff || LockKeysService.scrollLockOn)
|
||||
icon: root.scrollIcon
|
||||
color: LockKeysService.scrollLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MouseArea at root level for extended click area
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: layout
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
implicitWidth: rowLayout.visible ? rowLayout.implicitWidth : colLayout.implicitWidth
|
||||
implicitHeight: rowLayout.visible ? rowLayout.implicitHeight : colLayout.implicitHeight
|
||||
|
||||
RowLayout {
|
||||
id: rowLayout
|
||||
visible: !root.isVertical
|
||||
spacing: 0
|
||||
|
||||
NIcon {
|
||||
visible: root.showCaps && (!root.hideWhenOff || LockKeysService.capsLockOn)
|
||||
icon: root.capsIcon
|
||||
color: LockKeysService.capsLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showNum && (!root.hideWhenOff || LockKeysService.numLockOn)
|
||||
icon: root.numIcon
|
||||
color: LockKeysService.numLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showScroll && (!root.hideWhenOff || LockKeysService.scrollLockOn)
|
||||
icon: root.scrollIcon
|
||||
color: LockKeysService.scrollLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: colLayout
|
||||
visible: root.isVertical
|
||||
spacing: 0
|
||||
|
||||
NIcon {
|
||||
visible: root.showCaps && (!root.hideWhenOff || LockKeysService.capsLockOn)
|
||||
icon: root.capsIcon
|
||||
color: LockKeysService.capsLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showNum && (!root.hideWhenOff || LockKeysService.numLockOn)
|
||||
icon: root.numIcon
|
||||
color: LockKeysService.numLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
NIcon {
|
||||
visible: root.showScroll && (!root.hideWhenOff || LockKeysService.scrollLockOn)
|
||||
icon: root.scrollIcon
|
||||
color: LockKeysService.scrollLockOn ? Color.mTertiary : Qt.alpha(Color.mOnSurfaceVariant, 0.3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ import qs.Widgets.AudioSpectrum
|
||||
|
||||
Item {
|
||||
id: root
|
||||
Layout.preferredHeight: isVertical ? -1 : Style.getBarHeightForScreen(screenName)
|
||||
Layout.preferredWidth: isVertical ? Style.getBarHeightForScreen(screenName) : -1
|
||||
Layout.fillHeight: false
|
||||
Layout.fillWidth: false
|
||||
|
||||
property ShellScreen screen
|
||||
property string widgetId: ""
|
||||
@@ -20,9 +24,11 @@ Item {
|
||||
|
||||
// Settings
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -31,10 +37,10 @@ Item {
|
||||
}
|
||||
|
||||
// Bar orientation (per-screen)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
|
||||
|
||||
// Widget settings
|
||||
readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : "hidden"
|
||||
@@ -205,9 +211,8 @@ Item {
|
||||
}
|
||||
|
||||
onTriggered: action => {
|
||||
var popupWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupWindow)
|
||||
popupWindow.close();
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "play-pause")
|
||||
MediaService.playPause();
|
||||
@@ -226,11 +231,11 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Main container
|
||||
// Main container - stays at content size, pixel-perfect centered in parent
|
||||
Rectangle {
|
||||
id: container
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
width: isVertical ? (isHidden ? 0 : verticalSize) : (isHidden ? 0 : contentWidth)
|
||||
height: isVertical ? (isHidden ? 0 : verticalSize) : capsuleHeight
|
||||
radius: Style.radiusM
|
||||
@@ -329,6 +334,7 @@ Item {
|
||||
}
|
||||
cursorShape: hasPlayer ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
maxWidth: root.maxWidth - root.mainContentWidth
|
||||
forcedHover: mainMouseArea.containsMouse
|
||||
NText {
|
||||
// anchors.fill: parent
|
||||
color: hasPlayer ? Color.mOnSurface : Color.mOnSurfaceVariant
|
||||
@@ -365,37 +371,43 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
// Mouse interaction
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
// Mouse interaction moved to root
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
PanelService.getPanel("mediaPlayerPanel", screen)?.toggle(container);
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
TooltipService.hide();
|
||||
var popupWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupWindow) {
|
||||
popupWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(container, screen);
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton && hasPlayer) {
|
||||
MediaService.playPause();
|
||||
TooltipService.hide();
|
||||
}
|
||||
}
|
||||
// Mouse interaction
|
||||
MouseArea {
|
||||
id: mainMouseArea
|
||||
anchors.fill: parent
|
||||
|
||||
onEntered: {
|
||||
if (isVertical || scrollingMode === "never") {
|
||||
TooltipService.show(root, title, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
}
|
||||
onExited: TooltipService.hide()
|
||||
// Extend click area to screen edge if widget is at the start/end
|
||||
anchors.leftMargin: (!isVertical && section === "left" && sectionWidgetIndex === 0) ? -Style.marginS : 0
|
||||
anchors.rightMargin: (!isVertical && section === "right" && sectionWidgetIndex === sectionWidgetsCount - 1) ? -Style.marginS : 0
|
||||
anchors.topMargin: (isVertical && section === "left" && sectionWidgetIndex === 0) ? -Style.marginM : 0
|
||||
anchors.bottomMargin: (isVertical && section === "right" && sectionWidgetIndex === sectionWidgetsCount - 1) ? -Style.marginM : 0
|
||||
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
PanelService.getPanel("mediaPlayerPanel", screen)?.toggle(container);
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
TooltipService.hide();
|
||||
PanelService.showContextMenu(contextMenu, container, screen);
|
||||
} else if (mouse.button === Qt.MiddleButton && hasPlayer) {
|
||||
MediaService.playPause();
|
||||
TooltipService.hide();
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
if (isVertical || scrollingMode === "never") {
|
||||
TooltipService.show(root, title, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
}
|
||||
onExited: TooltipService.hide()
|
||||
}
|
||||
|
||||
// Components
|
||||
|
||||
@@ -22,9 +22,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -32,7 +34,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
readonly property string middleClickCommand: (widgetSettings.middleClickCommand !== undefined) ? widgetSettings.middleClickCommand : widgetMetadata.middleClickCommand
|
||||
@@ -109,10 +111,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "toggle-mute") {
|
||||
AudioService.setInputMuted(!AudioService.inputMuted);
|
||||
@@ -164,11 +164,7 @@ Item {
|
||||
PanelService.getPanel("audioPanel", screen)?.toggle(this);
|
||||
}
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
onMiddleClicked: {
|
||||
Quickshell.execDetached(["sh", "-lc", middleClickCommand]);
|
||||
|
||||
@@ -19,9 +19,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -29,7 +31,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: widgetSettings.displayMode !== undefined ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
|
||||
@@ -53,10 +55,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "toggle-wifi") {
|
||||
NetworkService.setWifiEnabled(!Settings.data.network.wifiEnabled);
|
||||
@@ -115,11 +115,7 @@ Item {
|
||||
panel?.toggle(this);
|
||||
}
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
tooltipText: {
|
||||
try {
|
||||
|
||||
@@ -21,9 +21,11 @@ NIconButton {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -33,6 +35,14 @@ NIconButton {
|
||||
readonly property bool showUnreadBadge: (widgetSettings.showUnreadBadge !== undefined) ? widgetSettings.showUnreadBadge : widgetMetadata.showUnreadBadge
|
||||
readonly property bool hideWhenZero: (widgetSettings.hideWhenZero !== undefined) ? widgetSettings.hideWhenZero : widgetMetadata.hideWhenZero
|
||||
readonly property bool hideWhenZeroUnread: (widgetSettings.hideWhenZeroUnread !== undefined) ? widgetSettings.hideWhenZeroUnread : widgetMetadata.hideWhenZeroUnread
|
||||
readonly property string unreadBadgeColor: (widgetSettings.unreadBadgeColor !== undefined) ? widgetSettings.unreadBadgeColor : (widgetMetadata.unreadBadgeColor || "primary")
|
||||
|
||||
readonly property var colorMap: {
|
||||
"primary": Color.mPrimary,
|
||||
"secondary": Color.mSecondary,
|
||||
"tertiary": Color.mTertiary,
|
||||
"onSurface": Color.mOnSurface
|
||||
}
|
||||
|
||||
function computeUnreadCount() {
|
||||
var since = NotificationService.lastSeenTs;
|
||||
@@ -86,10 +96,8 @@ NIconButton {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "toggle-dnd") {
|
||||
NotificationService.doNotDisturb = !NotificationService.doNotDisturb;
|
||||
@@ -107,26 +115,22 @@ NIconButton {
|
||||
}
|
||||
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 2
|
||||
anchors.topMargin: 1
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.horizontalCenterOffset: parent.baseSize / 4
|
||||
anchors.verticalCenterOffset: -parent.baseSize / 4
|
||||
z: 2
|
||||
active: showUnreadBadge
|
||||
sourceComponent: Rectangle {
|
||||
id: badge
|
||||
height: 8
|
||||
height: 7
|
||||
width: height
|
||||
radius: Style.radiusXS
|
||||
color: Color.mError
|
||||
color: root.colorMap[root.unreadBadgeColor] || Color.mError
|
||||
border.color: Color.mSurface
|
||||
border.width: Style.borderS
|
||||
visible: count > 0
|
||||
|
||||
@@ -19,9 +19,11 @@ NIconButton {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -47,12 +49,12 @@ NIconButton {
|
||||
}
|
||||
}
|
||||
|
||||
baseSize: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
baseSize: Style.getCapsuleHeightForScreen(screenName)
|
||||
applyUiScale: false
|
||||
customRadius: Style.radiusL
|
||||
icon: "power"
|
||||
tooltipText: I18n.tr("tooltips.session-menu")
|
||||
tooltipDirection: BarService.getTooltipDirection(screen?.name)
|
||||
tooltipDirection: BarService.getTooltipDirection(screenName)
|
||||
colorBg: Style.capsuleColor
|
||||
colorFg: root.iconColor
|
||||
colorBorder: "transparent"
|
||||
@@ -72,10 +74,8 @@ NIconButton {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "widget-settings") {
|
||||
BarService.openWidgetSettings(screen, section, sectionWidgetIndex, widgetId, widgetSettings);
|
||||
@@ -85,10 +85,6 @@ NIconButton {
|
||||
|
||||
onClicked: PanelService.getPanel("sessionMenuPanel", screen)?.toggle()
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -27,9 +29,9 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screen?.name)
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screenName)
|
||||
readonly property int spacerSize: widgetSettings.width !== undefined ? widgetSettings.width : widgetMetadata.width
|
||||
|
||||
implicitWidth: isBarVertical ? barHeight : spacerSize
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+293
-303
@@ -10,7 +10,7 @@ import qs.Services.System
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
@@ -21,16 +21,18 @@ Rectangle {
|
||||
property int sectionWidgetIndex: -1
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screen?.name)
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screenName)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -59,19 +61,21 @@ Rectangle {
|
||||
}
|
||||
|
||||
readonly property int titleWidth: {
|
||||
if (smartWidth && showTitle && !isVerticalBar && combinedModel.length > 0) {
|
||||
var entriesCount = combinedModel.length;
|
||||
var baseWidth = 140;
|
||||
var calculatedWidth = baseWidth / Math.sqrt(entriesCount);
|
||||
// First, use user-defined title width if set
|
||||
var calculatedWidth = (widgetSettings.titleWidth !== undefined) ? widgetSettings.titleWidth : widgetMetadata.titleWidth;
|
||||
|
||||
// Second, shrink title width if it exceeds maxTaskbarWidth when smartWidth is enabled
|
||||
if (smartWidth && combinedModel.length > 0) {
|
||||
if (maxTaskbarWidth > 0) {
|
||||
var entriesCount = combinedModel.length;
|
||||
var maxWidthPerEntry = (maxTaskbarWidth / entriesCount) - itemSize - Style.marginS - Style.marginXL;
|
||||
calculatedWidth = Math.min(calculatedWidth, maxWidthPerEntry);
|
||||
}
|
||||
|
||||
return Math.max(Math.round(calculatedWidth), 20);
|
||||
calculatedWidth = Math.max(Math.round(calculatedWidth), 20);
|
||||
}
|
||||
return (widgetSettings.titleWidth !== undefined) ? widgetSettings.titleWidth : widgetMetadata.titleWidth;
|
||||
|
||||
return calculatedWidth;
|
||||
}
|
||||
readonly property bool showPinnedApps: (widgetSettings.showPinnedApps !== undefined) ? widgetSettings.showPinnedApps : widgetMetadata.showPinnedApps
|
||||
|
||||
@@ -458,10 +462,8 @@ Rectangle {
|
||||
return items;
|
||||
}
|
||||
onTriggered: (action, item) => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(root.screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(root.screen);
|
||||
|
||||
// Look up the window fresh each time to avoid stale references
|
||||
const selectedWindow = root.getSelectedWindow();
|
||||
@@ -589,7 +591,8 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
implicitWidth: {
|
||||
// Content dimensions for implicit sizing
|
||||
readonly property real contentWidth: {
|
||||
if (!visible)
|
||||
return 0;
|
||||
if (isVerticalBar)
|
||||
@@ -604,311 +607,322 @@ Rectangle {
|
||||
|
||||
return Math.round(calculatedWidth);
|
||||
}
|
||||
implicitHeight: visible ? (isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginXL) : capsuleHeight) : 0
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
readonly property real contentHeight: visible ? (isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginXL) : capsuleHeight) : 0
|
||||
|
||||
GridLayout {
|
||||
id: taskbarLayout
|
||||
implicitWidth: contentWidth
|
||||
implicitHeight: contentHeight
|
||||
|
||||
// Pixel-perfect centering
|
||||
x: isVerticalBar ? Style.pixelAlignCenter(parent.width, width) : ((root.showTitle) ? Style.pixelAlignCenter(parent.width, width) : Style.marginM)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
// Visual capsule centered in parent
|
||||
Rectangle {
|
||||
id: visualCapsule
|
||||
width: root.contentWidth
|
||||
height: root.contentHeight
|
||||
anchors.centerIn: parent
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
// Configure GridLayout to behave like RowLayout or ColumnLayout
|
||||
rows: isVerticalBar ? -1 : 1 // -1 means unlimited
|
||||
columns: isVerticalBar ? 1 : -1 // -1 means unlimited
|
||||
GridLayout {
|
||||
id: taskbarLayout
|
||||
|
||||
rowSpacing: isVerticalBar ? Style.marginXXS : 0
|
||||
columnSpacing: isVerticalBar ? 0 : Style.marginXXS
|
||||
// Pixel-perfect centering
|
||||
x: isVerticalBar ? Style.pixelAlignCenter(parent.width, width) : ((root.showTitle) ? Style.pixelAlignCenter(parent.width, width) : Style.marginM)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
|
||||
Repeater {
|
||||
model: root.combinedModel
|
||||
delegate: Item {
|
||||
id: taskbarItem
|
||||
required property var modelData
|
||||
required property int index
|
||||
property ShellScreen screen: root.screen
|
||||
// Configure GridLayout to behave like RowLayout or ColumnLayout
|
||||
rows: isVerticalBar ? -1 : 1 // -1 means unlimited
|
||||
columns: isVerticalBar ? 1 : -1 // -1 means unlimited
|
||||
|
||||
readonly property bool isRunning: modelData.window !== null
|
||||
readonly property bool isPinned: modelData.type === "pinned" || modelData.type === "pinned-running"
|
||||
readonly property bool isFocused: isRunning && modelData.window && modelData.window.isFocused
|
||||
readonly property bool isPinnedRunning: isPinned && isRunning && !isFocused
|
||||
readonly property bool isHovered: root.hoveredWindowId === modelData.id
|
||||
rowSpacing: isVerticalBar ? Style.marginXXS : 0
|
||||
columnSpacing: isVerticalBar ? 0 : Style.marginXXS
|
||||
|
||||
readonly property bool shouldShowTitle: root.showTitle && modelData.type !== "pinned"
|
||||
readonly property real itemSpacing: Style.marginS
|
||||
readonly property real contentWidth: shouldShowTitle ? root.itemSize + itemSpacing + root.titleWidth : root.itemSize
|
||||
Repeater {
|
||||
model: root.combinedModel
|
||||
delegate: Item {
|
||||
id: taskbarItem
|
||||
required property var modelData
|
||||
required property int index
|
||||
property ShellScreen screen: root.screen
|
||||
|
||||
readonly property string title: modelData.title || modelData.appId || "Unknown application"
|
||||
readonly property color titleBgColor: (isHovered || isFocused) ? Color.mHover : Style.capsuleColor
|
||||
readonly property color titleFgColor: (isHovered || isFocused) ? Color.mOnHover : Color.mOnSurface
|
||||
readonly property bool isRunning: modelData.window !== null
|
||||
readonly property bool isPinned: modelData.type === "pinned" || modelData.type === "pinned-running"
|
||||
readonly property bool isFocused: isRunning && modelData.window && modelData.window.isFocused
|
||||
readonly property bool isPinnedRunning: isPinned && isRunning && !isFocused
|
||||
readonly property bool isHovered: root.hoveredWindowId === modelData.id
|
||||
|
||||
Layout.preferredWidth: root.showTitle ? Math.round(contentWidth + Style.marginXL) : Math.round(contentWidth) // Add margins for both pinned and running apps
|
||||
Layout.preferredHeight: root.itemSize
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
readonly property bool shouldShowTitle: root.showTitle && modelData.type !== "pinned"
|
||||
readonly property real itemSpacing: Style.marginS
|
||||
readonly property real contentWidth: shouldShowTitle ? root.itemSize + itemSpacing + root.titleWidth : root.itemSize
|
||||
|
||||
// Ensure dragged item is on top
|
||||
z: (root.dragSourceIndex === index) ? 1000 : 1
|
||||
readonly property string title: modelData.title || modelData.appId || "Unknown application"
|
||||
readonly property color titleBgColor: (isHovered || isFocused) ? Color.mHover : Style.capsuleColor
|
||||
readonly property color titleFgColor: (isHovered || isFocused) ? Color.mOnHover : Color.mOnSurface
|
||||
|
||||
property int modelIndex: index
|
||||
objectName: "taskbarAppItem"
|
||||
Layout.preferredWidth: root.showTitle ? Math.round(contentWidth + Style.marginXL) : Math.round(contentWidth) // Add margins for both pinned and running apps
|
||||
Layout.preferredHeight: root.itemSize
|
||||
Layout.alignment: Qt.AlignCenter
|
||||
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
keys: ["taskbar-app"]
|
||||
onEntered: function (drag) {
|
||||
if (drag.source && drag.source.objectName === "taskbarAppItem") {
|
||||
root.dragTargetIndex = taskbarItem.modelIndex;
|
||||
// Ensure dragged item is on top
|
||||
z: (root.dragSourceIndex === index) ? 1000 : 1
|
||||
|
||||
property int modelIndex: index
|
||||
objectName: "taskbarAppItem"
|
||||
|
||||
DropArea {
|
||||
anchors.fill: parent
|
||||
keys: ["taskbar-app"]
|
||||
onEntered: function (drag) {
|
||||
if (drag.source && drag.source.objectName === "taskbarAppItem") {
|
||||
root.dragTargetIndex = taskbarItem.modelIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: function () {
|
||||
if (root.dragTargetIndex === taskbarItem.modelIndex) {
|
||||
onExited: function () {
|
||||
if (root.dragTargetIndex === taskbarItem.modelIndex) {
|
||||
root.dragTargetIndex = -1;
|
||||
}
|
||||
}
|
||||
onDropped: function (drop) {
|
||||
root.dragSourceIndex = -1;
|
||||
root.dragTargetIndex = -1;
|
||||
}
|
||||
}
|
||||
onDropped: function (drop) {
|
||||
root.dragSourceIndex = -1;
|
||||
root.dragTargetIndex = -1;
|
||||
Logger.d("Taskbar", "Dropped! Source: " + (drop.source ? drop.source.objectName : "null") + " Index: " + (drop.source ? drop.source.modelIndex : "?") + " -> Target Index: " + taskbarItem.modelIndex);
|
||||
if (drop.source && drop.source.objectName === "taskbarAppItem" && drop.source !== taskbarItem) {
|
||||
root.reorderApps(drop.source.modelIndex, taskbarItem.modelIndex);
|
||||
} else {
|
||||
Logger.d("Taskbar", "Drop ignored. Source objectName: " + (drop.source ? drop.source.objectName : "null"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: draggableContent
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
anchors.centerIn: dragging ? undefined : parent
|
||||
|
||||
// Visual shifting logic
|
||||
readonly property bool isDragged: root.dragSourceIndex === index
|
||||
property real shiftOffset: 0
|
||||
|
||||
// Calculate shift based on drag state
|
||||
// If I am NOT the dragged item, but I am in the path of the drag
|
||||
Binding on shiftOffset {
|
||||
value: {
|
||||
if (root.dragSourceIndex !== -1 && root.dragTargetIndex !== -1 && !draggableContent.isDragged) {
|
||||
if (root.dragSourceIndex < root.dragTargetIndex) {
|
||||
// Dragging Right: Items between source and target shift Left
|
||||
if (index > root.dragSourceIndex && index <= root.dragTargetIndex) {
|
||||
return -1 * (root.isVerticalBar ? root.itemSize : draggableContent.width); // Simple approximation, could be refined
|
||||
}
|
||||
} else if (root.dragSourceIndex > root.dragTargetIndex) {
|
||||
// Dragging Left: Items between target and source shift Right
|
||||
if (index >= root.dragTargetIndex && index < root.dragSourceIndex) {
|
||||
return (root.isVerticalBar ? root.itemSize : draggableContent.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
transform: Translate {
|
||||
x: !root.isVerticalBar ? draggableContent.shiftOffset : 0
|
||||
y: root.isVerticalBar ? draggableContent.shiftOffset : 0
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutQuad
|
||||
Logger.d("Taskbar", "Dropped! Source: " + (drop.source ? drop.source.objectName : "null") + " Index: " + (drop.source ? drop.source.modelIndex : "?") + " -> Target Index: " + taskbarItem.modelIndex);
|
||||
if (drop.source && drop.source.objectName === "taskbarAppItem" && drop.source !== taskbarItem) {
|
||||
root.reorderApps(drop.source.modelIndex, taskbarItem.modelIndex);
|
||||
} else {
|
||||
Logger.d("Taskbar", "Drop ignored. Source objectName: " + (drop.source ? drop.source.objectName : "null"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property bool dragging: taskbarMouseArea.drag.active
|
||||
onDraggingChanged: {
|
||||
if (dragging) {
|
||||
root.dragSourceIndex = index;
|
||||
} else {
|
||||
// Don't reset immediately on release to allow drop to handle it,
|
||||
// or use a timer if needed, but drop handler usually fires.
|
||||
// However, if dropped outside, we need to reset.
|
||||
// Let's reset if not handled by drop area quickly?
|
||||
// Actually, drag.active becomes false on release.
|
||||
// We might want to clear it if no drop happened.
|
||||
if (root.dragSourceIndex === index) {
|
||||
// Slight delay/check? For now, let DropArea handle reset on success.
|
||||
// If cancelled (dropped nowhere), we should reset.
|
||||
Qt.callLater(() => {
|
||||
if (!taskbarMouseArea.drag.active && root.dragSourceIndex === index) {
|
||||
root.dragSourceIndex = -1;
|
||||
root.dragTargetIndex = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Drag.active: dragging
|
||||
Drag.source: taskbarItem
|
||||
Drag.hotSpot.x: width / 2
|
||||
Drag.hotSpot.y: height / 2
|
||||
Drag.keys: ["taskbar-app"]
|
||||
|
||||
z: dragging ? 1000 : 0
|
||||
scale: dragging ? 1.05 : 1.0
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: titleBackground
|
||||
visible: shouldShowTitle
|
||||
anchors.centerIn: parent
|
||||
Item {
|
||||
id: draggableContent
|
||||
width: parent.width
|
||||
height: root.height
|
||||
color: titleBgColor
|
||||
radius: Style.radiusM
|
||||
height: parent.height
|
||||
anchors.centerIn: dragging ? undefined : parent
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
// Visual shifting logic
|
||||
readonly property bool isDragged: root.dragSourceIndex === index
|
||||
property real shiftOffset: 0
|
||||
|
||||
// Calculate shift based on drag state
|
||||
// If I am NOT the dragged item, but I am in the path of the drag
|
||||
Binding on shiftOffset {
|
||||
value: {
|
||||
if (root.dragSourceIndex !== -1 && root.dragTargetIndex !== -1 && !draggableContent.isDragged) {
|
||||
if (root.dragSourceIndex < root.dragTargetIndex) {
|
||||
// Dragging Right: Items between source and target shift Left
|
||||
if (index > root.dragSourceIndex && index <= root.dragTargetIndex) {
|
||||
return -1 * (root.isVerticalBar ? root.itemSize : draggableContent.width); // Simple approximation, could be refined
|
||||
}
|
||||
} else if (root.dragSourceIndex > root.dragTargetIndex) {
|
||||
// Dragging Left: Items between target and source shift Right
|
||||
if (index >= root.dragTargetIndex && index < root.dragSourceIndex) {
|
||||
return (root.isVerticalBar ? root.itemSize : draggableContent.width);
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: taskbarItem.contentWidth
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
transform: Translate {
|
||||
x: !root.isVerticalBar ? draggableContent.shiftOffset : 0
|
||||
y: root.isVerticalBar ? draggableContent.shiftOffset : 0
|
||||
|
||||
RowLayout {
|
||||
id: itemLayout
|
||||
anchors.fill: parent
|
||||
spacing: taskbarItem.itemSpacing
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.OutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: root.itemSize
|
||||
Layout.preferredHeight: root.itemSize
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
property bool dragging: taskbarMouseArea.drag.active
|
||||
onDraggingChanged: {
|
||||
if (dragging) {
|
||||
root.dragSourceIndex = index;
|
||||
} else {
|
||||
// Don't reset immediately on release to allow drop to handle it,
|
||||
// or use a timer if needed, but drop handler usually fires.
|
||||
// However, if dropped outside, we need to reset.
|
||||
// Let's reset if not handled by drop area quickly?
|
||||
// Actually, drag.active becomes false on release.
|
||||
// We might want to clear it if no drop happened.
|
||||
if (root.dragSourceIndex === index) {
|
||||
// Slight delay/check? For now, let DropArea handle reset on success.
|
||||
// If cancelled (dropped nowhere), we should reset.
|
||||
Qt.callLater(() => {
|
||||
if (!taskbarMouseArea.drag.active && root.dragSourceIndex === index) {
|
||||
root.dragSourceIndex = -1;
|
||||
root.dragTargetIndex = -1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IconImage {
|
||||
id: appIcon
|
||||
anchors.fill: parent
|
||||
Drag.active: dragging
|
||||
Drag.source: taskbarItem
|
||||
Drag.hotSpot.x: width / 2
|
||||
Drag.hotSpot.y: height / 2
|
||||
Drag.keys: ["taskbar-app"]
|
||||
|
||||
source: ThemeIcons.iconForAppId(taskbarItem.modelData.appId)
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
z: dragging ? 1000 : 0
|
||||
scale: dragging ? 1.05 : 1.0
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
}
|
||||
}
|
||||
|
||||
// Apply dock shader to all taskbar icons
|
||||
layer.enabled: widgetSettings.colorizeIcons !== false
|
||||
layer.effect: ShaderEffect {
|
||||
property color targetColor: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant
|
||||
property real colorizeMode: 0.0 // Dock mode (grayscale)
|
||||
Rectangle {
|
||||
id: titleBackground
|
||||
visible: shouldShowTitle
|
||||
anchors.centerIn: parent
|
||||
width: parent.width
|
||||
height: root.height
|
||||
color: titleBgColor
|
||||
radius: Style.radiusM
|
||||
|
||||
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: taskbarItem.contentWidth
|
||||
height: parent.height
|
||||
color: "transparent"
|
||||
|
||||
RowLayout {
|
||||
id: itemLayout
|
||||
anchors.fill: parent
|
||||
spacing: taskbarItem.itemSpacing
|
||||
|
||||
Item {
|
||||
Layout.preferredWidth: root.itemSize
|
||||
Layout.preferredHeight: root.itemSize
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
|
||||
IconImage {
|
||||
id: appIcon
|
||||
anchors.fill: parent
|
||||
|
||||
source: ThemeIcons.iconForAppId(taskbarItem.modelData.appId)
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
|
||||
// Apply dock shader to all taskbar icons
|
||||
layer.enabled: widgetSettings.colorizeIcons !== false
|
||||
layer.effect: ShaderEffect {
|
||||
property color targetColor: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mSurfaceVariant
|
||||
property real colorizeMode: 0.0 // Dock mode (grayscale)
|
||||
|
||||
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: iconBackground
|
||||
visible: !shouldShowTitle
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: Style.toOdd(root.itemSize * 0.25)
|
||||
height: 4
|
||||
color: taskbarItem.isFocused ? Color.mPrimary : "transparent"
|
||||
radius: Math.min(Style.radiusXXS, width / 2)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: iconBackground
|
||||
visible: !shouldShowTitle
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: Style.toOdd(root.itemSize * 0.25)
|
||||
height: 4
|
||||
color: taskbarItem.isFocused ? Color.mPrimary : "transparent"
|
||||
radius: Math.min(Style.radiusXXS, width / 2)
|
||||
NText {
|
||||
id: titleText
|
||||
visible: shouldShowTitle
|
||||
Layout.preferredWidth: root.titleWidth
|
||||
Layout.preferredHeight: root.itemSize
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.fillWidth: false
|
||||
|
||||
text: taskbarItem.title
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
|
||||
pointSize: barFontSize
|
||||
color: titleFgColor
|
||||
opacity: Style.opacityFull
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
id: titleText
|
||||
visible: shouldShowTitle
|
||||
Layout.preferredWidth: root.titleWidth
|
||||
Layout.preferredHeight: root.itemSize
|
||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
|
||||
Layout.fillWidth: false
|
||||
|
||||
text: taskbarItem.title
|
||||
elide: Text.ElideRight
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
|
||||
pointSize: barFontSize
|
||||
color: titleFgColor
|
||||
opacity: Style.opacityFull
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: taskbarMouseArea
|
||||
objectName: "taskbarMouseArea"
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
MouseArea {
|
||||
id: taskbarMouseArea
|
||||
objectName: "taskbarMouseArea"
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
drag.target: draggableContent
|
||||
drag.axis: root.isVerticalBar ? Drag.YAxis : Drag.XAxis
|
||||
preventStealing: true
|
||||
drag.target: draggableContent
|
||||
drag.axis: root.isVerticalBar ? Drag.YAxis : Drag.XAxis
|
||||
preventStealing: true
|
||||
|
||||
onPressed: {
|
||||
// Constrain drag to roughly the taskbar area but allow some freedom
|
||||
// Or just let it be free since we only care about drops
|
||||
}
|
||||
|
||||
onReleased: {
|
||||
if (draggableContent.Drag.active) {
|
||||
draggableContent.Drag.drop();
|
||||
onPressed: {
|
||||
// Constrain drag to roughly the taskbar area but allow some freedom
|
||||
// Or just let it be free since we only care about drops
|
||||
}
|
||||
}
|
||||
|
||||
onClicked: function (mouse) {
|
||||
if (!modelData)
|
||||
return;
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isRunning && modelData.window) {
|
||||
// Running app - focus it
|
||||
try {
|
||||
CompositorService.focusWindow(modelData.window);
|
||||
} catch (error) {
|
||||
Logger.e("Taskbar", "Failed to activate toplevel: " + error);
|
||||
}
|
||||
} else if (isPinned) {
|
||||
// Pinned app not running - launch it
|
||||
root.launchPinnedApp(modelData.appId);
|
||||
onReleased: {
|
||||
if (draggableContent.Drag.active) {
|
||||
draggableContent.Drag.drop();
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
}
|
||||
|
||||
onClicked: function (mouse) {
|
||||
if (!modelData)
|
||||
return;
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isRunning && modelData.window) {
|
||||
// Running app - focus it
|
||||
try {
|
||||
CompositorService.focusWindow(modelData.window);
|
||||
} catch (error) {
|
||||
Logger.e("Taskbar", "Failed to activate toplevel: " + error);
|
||||
}
|
||||
} else if (isPinned) {
|
||||
// Pinned app not running - launch it
|
||||
root.launchPinnedApp(modelData.appId);
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
TooltipService.hide();
|
||||
// Only show context menu for running apps
|
||||
if (isRunning && modelData.window) {
|
||||
root.selectedWindowId = modelData.id;
|
||||
root.selectedAppId = modelData.appId;
|
||||
root.openTaskbarContextMenu(taskbarItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
root.hoveredWindowId = taskbarItem.modelData.id;
|
||||
TooltipService.show(taskbarItem, taskbarItem.title, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
onExited: {
|
||||
root.hoveredWindowId = "";
|
||||
TooltipService.hide();
|
||||
// Only show context menu for running apps
|
||||
if (isRunning && modelData.window) {
|
||||
root.selectedWindowId = modelData.id;
|
||||
root.selectedAppId = modelData.appId;
|
||||
root.openTaskbarContextMenu(taskbarItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
root.hoveredWindowId = taskbarItem.modelData.id;
|
||||
TooltipService.show(taskbarItem, taskbarItem.title, BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
onExited: {
|
||||
root.hoveredWindowId = "";
|
||||
TooltipService.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -964,30 +978,6 @@ Rectangle {
|
||||
// Set the model directly
|
||||
contextMenu.model = items;
|
||||
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.open();
|
||||
|
||||
// Calculate menu position
|
||||
const globalPos = item.mapToItem(root, 0, 0);
|
||||
let menuX, menuY;
|
||||
if (root.barPosition === "top") {
|
||||
menuX = globalPos.x + (item.width / 2) - (contextMenu.implicitWidth / 2);
|
||||
menuY = barHeight + Style.marginS;
|
||||
} else if (root.barPosition === "bottom") {
|
||||
const menuHeight = 12 + contextMenu.model.length * contextMenu.itemHeight;
|
||||
menuX = globalPos.x + (item.width / 2) - (contextMenu.implicitWidth / 2);
|
||||
menuY = -menuHeight - Style.marginS;
|
||||
} else if (root.barPosition === "left") {
|
||||
menuX = barHeight + Style.marginS;
|
||||
menuY = globalPos.y + (item.height / 2) - (contextMenu.implicitHeight / 2);
|
||||
} else {
|
||||
// right
|
||||
menuX = -contextMenu.implicitWidth - Style.marginS;
|
||||
menuY = globalPos.y + (item.height / 2) - (contextMenu.implicitHeight / 2);
|
||||
}
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, item, screen);
|
||||
}
|
||||
}
|
||||
|
||||
+114
-83
@@ -10,7 +10,7 @@ import qs.Modules.Bar.Extras
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property ShellScreen screen
|
||||
@@ -43,9 +43,11 @@ Rectangle {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -53,10 +55,10 @@ Rectangle {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screenName)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
readonly property bool density: Settings.data.bar.density
|
||||
readonly property int iconSize: Style.toOdd(capsuleHeight * 0.65)
|
||||
|
||||
@@ -115,8 +117,8 @@ Rectangle {
|
||||
function _performFilteredItemsUpdate() {
|
||||
// Force a fresh read of settings to ensure we have the latest blacklist
|
||||
var currentSettings = {};
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var w = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var w = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (w && sectionWidgetIndex < w.length) {
|
||||
currentSettings = w[sectionWidgetIndex];
|
||||
}
|
||||
@@ -284,35 +286,51 @@ Rectangle {
|
||||
Component.onCompleted: {
|
||||
root.updateFilteredItems(); // Initial update
|
||||
}
|
||||
implicitWidth: isVertical ? capsuleHeight : Math.round(trayFlow.implicitWidth)
|
||||
implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight) : capsuleHeight
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
// Content dimensions for implicit sizing
|
||||
readonly property real capsuleWidth: isVertical ? capsuleHeight : Math.round(trayFlow.implicitWidth)
|
||||
readonly property real capsuleContentHeight: isVertical ? Math.round(trayFlow.implicitHeight) : capsuleHeight
|
||||
|
||||
implicitWidth: isVertical ? barHeight : Math.round(trayFlow.implicitWidth)
|
||||
implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight) : barHeight
|
||||
visible: filteredItems.length > 0 || dropdownItems.length > 0
|
||||
opacity: (filteredItems.length > 0 || dropdownItems.length > 0) ? 1.0 : 0.0
|
||||
|
||||
// Visual capsule centered in parent
|
||||
Rectangle {
|
||||
id: visualCapsule
|
||||
width: capsuleWidth
|
||||
height: capsuleContentHeight
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
radius: Style.radiusM
|
||||
color: Style.capsuleColor
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: trayFlow
|
||||
spacing: Style.marginXS
|
||||
flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
|
||||
// Pixel-perfect centering
|
||||
x: isVertical ? Style.pixelAlignCenter(parent.width, width) : 0
|
||||
y: isVertical ? 0 : Style.pixelAlignCenter(parent.height, height)
|
||||
// Position at edge for full click area
|
||||
x: isVertical ? 0 : 0
|
||||
y: isVertical ? 0 : 0
|
||||
|
||||
// Drawer opener (before items if opposite direction)
|
||||
NIconButton {
|
||||
id: chevronIconBefore
|
||||
visible: root.drawerEnabled && dropdownItems.length > 0 && BarService.getPillDirection(root)
|
||||
width: isVertical ? barHeight : capsuleHeight
|
||||
height: isVertical ? capsuleHeight : barHeight
|
||||
tooltipText: I18n.tr("tooltips.open-tray-dropdown")
|
||||
tooltipDirection: BarService.getTooltipDirection(root.screen?.name)
|
||||
baseSize: capsuleHeight
|
||||
applyUiScale: false
|
||||
customRadius: Style.radiusL
|
||||
colorBg: "transparent"
|
||||
colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary
|
||||
colorFg: Color.mOnSurface
|
||||
colorBorder: "transparent"
|
||||
colorBorderHover: "transparent"
|
||||
icon: {
|
||||
@@ -338,10 +356,20 @@ Rectangle {
|
||||
model: root.filteredItems
|
||||
|
||||
delegate: Item {
|
||||
width: capsuleHeight
|
||||
height: capsuleHeight
|
||||
id: trayDelegate
|
||||
width: isVertical ? barHeight : capsuleHeight
|
||||
height: isVertical ? capsuleHeight : barHeight
|
||||
visible: modelData
|
||||
|
||||
// Tooltip anchor representing the visual area (for proper tooltip positioning)
|
||||
Item {
|
||||
id: tooltipAnchor
|
||||
width: capsuleHeight
|
||||
height: capsuleHeight
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
}
|
||||
|
||||
IconImage {
|
||||
id: trayIcon
|
||||
width: iconSize
|
||||
@@ -351,8 +379,6 @@ Rectangle {
|
||||
asynchronous: true
|
||||
backer.fillMode: Image.PreserveAspectFit
|
||||
|
||||
property bool menuJustOpened: false
|
||||
|
||||
source: {
|
||||
let icon = modelData?.icon || "";
|
||||
if (!icon) {
|
||||
@@ -378,82 +404,85 @@ Rectangle {
|
||||
|
||||
fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb")
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: mouse => {
|
||||
if (!modelData) {
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onClicked: mouse => {
|
||||
if (!modelData) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
// Close any open menu first
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
|
||||
if (!modelData.onlyMenu) {
|
||||
modelData.activate();
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
// Close the menu if it was visible
|
||||
if (popupMenuWindow && popupMenuWindow.visible) {
|
||||
popupMenuWindow.close();
|
||||
return;
|
||||
}
|
||||
modelData.secondaryActivate && modelData.secondaryActivate();
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
TooltipService.hideImmediately();
|
||||
|
||||
// Close the menu if it was visible
|
||||
if (popupMenuWindow && popupMenuWindow.visible) {
|
||||
popupMenuWindow.close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
// Close any open menu first
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
// Close any opened panel
|
||||
if ((PanelService.openedPanel !== null) && !PanelService.openedPanel.isClosing) {
|
||||
PanelService.openedPanel.close();
|
||||
}
|
||||
|
||||
if (!modelData.onlyMenu) {
|
||||
modelData.activate();
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
// Close the menu if it was visible
|
||||
if (popupMenuWindow && popupMenuWindow.visible) {
|
||||
popupMenuWindow.close();
|
||||
return;
|
||||
}
|
||||
modelData.secondaryActivate && modelData.secondaryActivate();
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
TooltipService.hideImmediately();
|
||||
|
||||
// Close the menu if it was visible
|
||||
if (popupMenuWindow && popupMenuWindow.visible) {
|
||||
popupMenuWindow.close();
|
||||
return;
|
||||
}
|
||||
|
||||
// Close any opened panel
|
||||
if ((PanelService.openedPanel !== null) && !PanelService.openedPanel.isClosing) {
|
||||
PanelService.openedPanel.close();
|
||||
}
|
||||
|
||||
if (modelData.hasMenu && modelData.menu && popupMenuWindow && trayMenu && trayMenu.item) {
|
||||
popupMenuWindow.open();
|
||||
|
||||
// Position menu based on bar position
|
||||
if (modelData.hasMenu && modelData.menu && trayMenu && trayMenu.item) {
|
||||
// Calculate menu position after ensuring menu is loaded
|
||||
const calculateAndShow = () => {
|
||||
// Position menu based on bar position, using tooltipAnchor for proper positioning
|
||||
// Increased spacing for better alignment with other context menus
|
||||
let menuX, menuY;
|
||||
if (barPosition === "left") {
|
||||
// For left bar: position menu to the right of the bar
|
||||
menuX = width + Style.marginM;
|
||||
// For left bar: position menu to the right of the visual area
|
||||
menuX = tooltipAnchor.width + Style.marginL;
|
||||
menuY = 0;
|
||||
} else if (barPosition === "right") {
|
||||
// For right bar: position menu to the left of the bar
|
||||
menuX = -trayMenu.item.width - Style.marginM;
|
||||
// For right bar: position menu to the left of the visual area
|
||||
menuX = -trayMenu.item.implicitWidth - Style.marginL;
|
||||
menuY = 0;
|
||||
} else {
|
||||
// For horizontal bars: center horizontally and position below
|
||||
menuX = (width / 2) - (trayMenu.item.width / 2);
|
||||
menuY = (barPosition === "top") ? barHeight + Style.marginS - 2 : barHeight + Style.marginS - 2;
|
||||
// For horizontal bars: center horizontally and position below visual area
|
||||
menuX = (tooltipAnchor.width / 2) - (trayMenu.item.implicitWidth / 2);
|
||||
menuY = tooltipAnchor.height + Style.marginL;
|
||||
}
|
||||
trayMenu.item.trayItem = modelData;
|
||||
trayMenu.item.widgetSection = root.section;
|
||||
trayMenu.item.widgetIndex = root.sectionWidgetIndex;
|
||||
trayMenu.item.showAt(parent, menuX, menuY);
|
||||
} else {
|
||||
Logger.d("Tray", "No menu available for", modelData.id, "or trayMenu not set");
|
||||
}
|
||||
|
||||
PanelService.showTrayMenu(root.screen, modelData, trayMenu.item, tooltipAnchor, menuX, menuY, root.section, root.sectionWidgetIndex);
|
||||
};
|
||||
|
||||
// Use Qt.callLater to ensure menu dimensions are calculated
|
||||
Qt.callLater(calculateAndShow);
|
||||
} else {
|
||||
Logger.d("Tray", "No menu available for", modelData.id, "or trayMenu not set");
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
TooltipService.show(trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
onEntered: {
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
onExited: TooltipService.hide()
|
||||
TooltipService.show(tooltipAnchor, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection(root.screen?.name));
|
||||
}
|
||||
onExited: TooltipService.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,6 +491,8 @@ Rectangle {
|
||||
NIconButton {
|
||||
id: chevronIconAfter
|
||||
visible: root.drawerEnabled && dropdownItems.length > 0 && !BarService.getPillDirection(root)
|
||||
width: isVertical ? barHeight : capsuleHeight
|
||||
height: isVertical ? capsuleHeight : barHeight
|
||||
tooltipText: I18n.tr("tooltips.open-tray-dropdown")
|
||||
tooltipDirection: BarService.getTooltipDirection(root.screen?.name)
|
||||
baseSize: capsuleHeight
|
||||
@@ -487,5 +518,5 @@ Rectangle {
|
||||
onClicked: toggleDrawer(this)
|
||||
onRightClicked: toggleDrawer(this)
|
||||
}
|
||||
}
|
||||
} // closes Flow
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -28,7 +30,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: widgetSettings.displayMode !== undefined ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
|
||||
@@ -71,10 +73,9 @@ Item {
|
||||
}
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
@@ -122,11 +123,7 @@ Item {
|
||||
forceOpen: !isBarVertical && root.displayMode === "alwaysShow"
|
||||
forceClose: isBarVertical || root.displayMode === "alwaysHide" || !pill.text
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
tooltipText: {
|
||||
if (pill.text !== "") {
|
||||
|
||||
@@ -21,9 +21,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -31,7 +33,7 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isBarVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||
readonly property string middleClickCommand: (widgetSettings.middleClickCommand !== undefined) ? widgetSettings.middleClickCommand : widgetMetadata.middleClickCommand
|
||||
@@ -91,11 +93,8 @@ Item {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
// Close the popup menu window before handling the action
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "toggle-mute") {
|
||||
AudioService.setOutputMuted(!AudioService.muted);
|
||||
@@ -147,12 +146,7 @@ Item {
|
||||
PanelService.getPanel("audioPanel", screen)?.toggle(this);
|
||||
}
|
||||
onRightClicked: {
|
||||
// Get the shared popup menu window for this screen
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(pill, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, pill, screen);
|
||||
}
|
||||
onMiddleClicked: {
|
||||
Quickshell.execDetached(["sh", "-lc", middleClickCommand]);
|
||||
|
||||
@@ -38,10 +38,8 @@ NIconButton {
|
||||
]
|
||||
|
||||
onTriggered: action => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
if (action === "random-wallpaper") {
|
||||
WallpaperService.setRandomWallpaper();
|
||||
@@ -58,10 +56,6 @@ NIconButton {
|
||||
}
|
||||
}
|
||||
onRightClicked: {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(root, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, root, screen);
|
||||
}
|
||||
}
|
||||
|
||||
+143
-387
@@ -24,9 +24,11 @@ Item {
|
||||
property int sectionWidgetsCount: 0
|
||||
|
||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||
// Explicit screenName property ensures reactive binding when screen changes
|
||||
readonly property string screenName: screen ? screen.name : ""
|
||||
property var widgetSettings: {
|
||||
if (section && sectionWidgetIndex >= 0) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screen?.name)[section];
|
||||
if (section && sectionWidgetIndex >= 0 && screenName) {
|
||||
var widgets = Settings.getBarWidgetsForScreen(screenName)[section];
|
||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||
return widgets[sectionWidgetIndex];
|
||||
}
|
||||
@@ -34,12 +36,12 @@ Item {
|
||||
return {};
|
||||
}
|
||||
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
|
||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screen?.name)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screen?.name)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screen?.name)
|
||||
readonly property real baseDimensionRatio: 0.65 * (widgetSettings.labelMode === "none" ? 0.75 : 1)
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screenName)
|
||||
readonly property real capsuleHeight: Style.getCapsuleHeightForScreen(screenName)
|
||||
readonly property real barFontSize: Style.getBarFontSizeForScreen(screenName)
|
||||
readonly property real baseDimensionRatio: 0.65
|
||||
|
||||
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
||||
readonly property bool hasLabel: (labelMode !== "none")
|
||||
@@ -54,7 +56,36 @@ Item {
|
||||
readonly property real unfocusedIconsOpacity: (widgetSettings.unfocusedIconsOpacity !== undefined) ? widgetSettings.unfocusedIconsOpacity : widgetMetadata.unfocusedIconsOpacity
|
||||
readonly property real groupedBorderOpacity: (widgetSettings.groupedBorderOpacity !== undefined) ? widgetSettings.groupedBorderOpacity : widgetMetadata.groupedBorderOpacity
|
||||
readonly property bool enableScrollWheel: (widgetSettings.enableScrollWheel !== undefined) ? widgetSettings.enableScrollWheel : widgetMetadata.enableScrollWheel
|
||||
readonly property bool reverseScroll: (widgetSettings.reverseScroll !== undefined) ? widgetSettings.reverseScroll : (widgetMetadata.reverseScroll || false)
|
||||
readonly property real iconScale: (widgetSettings.iconScale !== undefined) ? widgetSettings.iconScale : widgetMetadata.iconScale
|
||||
readonly property string focusedColor: (widgetSettings.focusedColor !== undefined) ? widgetSettings.focusedColor : widgetMetadata.focusedColor
|
||||
readonly property string occupiedColor: (widgetSettings.occupiedColor !== undefined) ? widgetSettings.occupiedColor : widgetMetadata.occupiedColor
|
||||
readonly property string emptyColor: (widgetSettings.emptyColor !== undefined) ? widgetSettings.emptyColor : widgetMetadata.emptyColor
|
||||
readonly property bool showBadge: (widgetSettings.showBadge !== undefined) ? widgetSettings.showBadge : widgetMetadata.showBadge
|
||||
|
||||
readonly property var colorMap: {
|
||||
"primary": [Color.mPrimary, Color.mOnPrimary],
|
||||
"secondary": [Color.mSecondary, Color.mOnSecondary],
|
||||
"tertiary": [Color.mTertiary, Color.mOnTertiary],
|
||||
"onSurface": [Color.mOnSurface, Color.mSurface]
|
||||
}
|
||||
|
||||
// Helper to safely get colors with proper reactivity
|
||||
// Accesses Color singleton directly to ensure fresh values
|
||||
function getColorPair(colorKey) {
|
||||
switch (colorKey) {
|
||||
case "primary":
|
||||
return [Color.mPrimary, Color.mOnPrimary];
|
||||
case "secondary":
|
||||
return [Color.mSecondary, Color.mOnSecondary];
|
||||
case "tertiary":
|
||||
return [Color.mTertiary, Color.mOnTertiary];
|
||||
case "onSurface":
|
||||
return [Color.mOnSurface, Color.mSurface];
|
||||
default:
|
||||
return [Color.mPrimary, Color.mOnPrimary];
|
||||
}
|
||||
}
|
||||
|
||||
// Only for grouped mode / show apps
|
||||
readonly property int baseItemSize: Style.toOdd(capsuleHeight * 0.8)
|
||||
@@ -69,16 +100,12 @@ Item {
|
||||
function getSelectedWindow() {
|
||||
if (!selectedWindowId)
|
||||
return null;
|
||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||
var ws = localWorkspaces.get(i);
|
||||
if (ws && ws.windows) {
|
||||
for (var j = 0; j < ws.windows.count; j++) {
|
||||
var win = ws.windows.get(j);
|
||||
// Using loose equality on purpose (==)
|
||||
if (win && (win.id == selectedWindowId || win.address == selectedWindowId)) {
|
||||
return win;
|
||||
}
|
||||
}
|
||||
// Search directly in CompositorService to get the live window object
|
||||
for (var i = 0; i < CompositorService.windows.count; i++) {
|
||||
var win = CompositorService.windows.get(i);
|
||||
// Using loose equality on purpose (==)
|
||||
if (win && (win.id == selectedWindowId || win.address == selectedWindowId)) {
|
||||
return win;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -89,6 +116,8 @@ Item {
|
||||
|
||||
// Revision counter to force icon re-evaluation
|
||||
property int iconRevision: 0
|
||||
// Revision counter to force window list re-evaluation (for liveWindows binding in grouped mode)
|
||||
property int windowRevision: 0
|
||||
|
||||
property ListModel localWorkspaces: ListModel {}
|
||||
property int lastFocusedWorkspaceId: -1
|
||||
@@ -115,7 +144,7 @@ Item {
|
||||
|
||||
// Don't calculate text width if labels are off
|
||||
if (labelMode === "none") {
|
||||
return Math.round(d * factor);
|
||||
return Style.toOdd(d * factor);
|
||||
}
|
||||
|
||||
var displayText = ws.idx.toString();
|
||||
@@ -229,7 +258,9 @@ Item {
|
||||
}
|
||||
|
||||
onScreenChanged: refreshWorkspaces()
|
||||
onScreenNameChanged: refreshWorkspaces()
|
||||
onHideUnoccupiedChanged: refreshWorkspaces()
|
||||
onShowApplicationsChanged: refreshWorkspaces()
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
@@ -238,11 +269,13 @@ Item {
|
||||
}
|
||||
function onWindowListChanged() {
|
||||
if (showApplications || showLabelsOnlyWhenOccupied) {
|
||||
root.windowRevision++;
|
||||
refreshWorkspaces();
|
||||
}
|
||||
}
|
||||
function onActiveWindowChanged() {
|
||||
if (showApplications) {
|
||||
root.windowRevision++;
|
||||
refreshWorkspaces();
|
||||
}
|
||||
}
|
||||
@@ -290,10 +323,13 @@ Item {
|
||||
isOccupied: ws.isOccupied
|
||||
};
|
||||
|
||||
if (showApplications) {
|
||||
workspaceData.windows = CompositorService.getWindowsForWorkspace(ws.id);
|
||||
if (ws.handle !== null && ws.handle !== undefined) {
|
||||
workspaceData.handle = ws.handle;
|
||||
}
|
||||
|
||||
// Windows are fetched live via liveWindows property in grouped mode
|
||||
// to avoid Qt 6.9 ListModel nested array serialization issues
|
||||
|
||||
targetList.push(workspaceData);
|
||||
}
|
||||
}
|
||||
@@ -424,10 +460,8 @@ Item {
|
||||
}
|
||||
|
||||
onTriggered: (action, item) => {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.close();
|
||||
}
|
||||
contextMenu.close();
|
||||
PanelService.closeContextMenu(screen);
|
||||
|
||||
const selectedWindow = root.getSelectedWindow();
|
||||
|
||||
@@ -469,11 +503,7 @@ Item {
|
||||
acceptedButtons: Qt.RightButton
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(workspaceBackground, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, workspaceBackground, screen);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,6 +539,8 @@ Item {
|
||||
var step = 120;
|
||||
if (Math.abs(root.wheelAccumulatedDelta) >= step) {
|
||||
var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1;
|
||||
if (root.reverseScroll)
|
||||
direction *= -1;
|
||||
// For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign)
|
||||
// For horizontal layout, same mapping using vertical wheel
|
||||
root.switchByOffset(direction);
|
||||
@@ -525,173 +557,32 @@ Item {
|
||||
id: pillRow
|
||||
spacing: spacingBetweenPills
|
||||
x: horizontalPadding
|
||||
y: workspaceBackground.y + Style.pixelAlignCenter(workspaceBackground.height, height)
|
||||
y: 0
|
||||
visible: !isVertical && !showApplications
|
||||
|
||||
Repeater {
|
||||
id: workspaceRepeaterHorizontal
|
||||
model: localWorkspaces
|
||||
Item {
|
||||
id: workspacePillContainer
|
||||
height: Style.toOdd(capsuleHeight * root.baseDimensionRatio)
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "active"
|
||||
when: model.isActive
|
||||
PropertyChanges {
|
||||
target: workspacePillContainer
|
||||
width: root.getWorkspaceWidth(model, true)
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "inactive"
|
||||
when: !model.isActive
|
||||
PropertyChanges {
|
||||
target: workspacePillContainer
|
||||
width: root.getWorkspaceWidth(model, false)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "inactive"
|
||||
to: "active"
|
||||
NumberAnimation {
|
||||
property: "width"
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "active"
|
||||
to: "inactive"
|
||||
NumberAnimation {
|
||||
property: "width"
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Rectangle {
|
||||
id: pill
|
||||
anchors.fill: parent
|
||||
|
||||
Loader {
|
||||
active: (labelMode !== "none") && (!root.showLabelsOnlyWhenOccupied || model.isOccupied || model.isFocused)
|
||||
sourceComponent: Component {
|
||||
NText {
|
||||
x: Style.pixelAlignCenter(pill.width, width)
|
||||
y: Style.pixelAlignCenter(pill.height, height)
|
||||
text: {
|
||||
if (model.name && model.name.length > 0) {
|
||||
if (root.labelMode === "name") {
|
||||
return model.name.substring(0, characterCount);
|
||||
}
|
||||
if (root.labelMode === "index+name") {
|
||||
return (model.idx.toString() + " " + model.name.substring(0, characterCount));
|
||||
}
|
||||
}
|
||||
return model.idx.toString();
|
||||
}
|
||||
family: Settings.data.ui.fontFixed
|
||||
pointSize: workspacePillContainer.height * root.textRatio
|
||||
applyUiScale: false
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.weight: Style.fontWeightBold
|
||||
wrapMode: Text.Wrap
|
||||
color: {
|
||||
if (model.isFocused)
|
||||
return Color.mOnPrimary;
|
||||
if (model.isUrgent)
|
||||
return Color.mOnError;
|
||||
if (model.isOccupied)
|
||||
return Color.mOnSecondary;
|
||||
|
||||
return Color.mOnSecondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radius: Style.radiusM
|
||||
color: {
|
||||
if (model.isFocused)
|
||||
return Color.mPrimary;
|
||||
if (model.isUrgent)
|
||||
return Color.mError;
|
||||
if (model.isOccupied)
|
||||
return Color.mSecondary;
|
||||
|
||||
return Qt.alpha(Color.mSecondary, 0.3);
|
||||
}
|
||||
z: 0
|
||||
|
||||
MouseArea {
|
||||
id: pillMouseArea
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
CompositorService.switchToWorkspace(model);
|
||||
}
|
||||
hoverEnabled: true
|
||||
}
|
||||
// Material 3-inspired smooth animation for scale, color, opacity, and radius
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on color {
|
||||
enabled: !Color.isTransitioning
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
// Burst effect overlay for focused pill (smaller outline)
|
||||
Rectangle {
|
||||
id: pillBurst
|
||||
anchors.centerIn: workspacePillContainer
|
||||
width: workspacePillContainer.width + 18 * root.masterProgress * scale
|
||||
height: workspacePillContainer.height + 18 * root.masterProgress * scale
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
border.color: root.effectColor
|
||||
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress))))
|
||||
opacity: root.effectsActive && model.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0
|
||||
visible: root.effectsActive && model.isFocused
|
||||
z: 1
|
||||
}
|
||||
delegate: WorkspacePill {
|
||||
required property var model
|
||||
workspace: model
|
||||
isVertical: false
|
||||
baseDimensionRatio: root.baseDimensionRatio
|
||||
capsuleHeight: root.capsuleHeight
|
||||
barHeight: root.barHeight
|
||||
labelMode: root.labelMode
|
||||
characterCount: root.characterCount
|
||||
textRatio: root.textRatio
|
||||
showLabelsOnlyWhenOccupied: root.showLabelsOnlyWhenOccupied
|
||||
colorMap: root.colorMap
|
||||
focusedColor: root.focusedColor
|
||||
occupiedColor: root.occupiedColor
|
||||
emptyColor: root.emptyColor
|
||||
masterProgress: root.masterProgress
|
||||
effectsActive: root.effectsActive
|
||||
effectColor: root.effectColor
|
||||
getWorkspaceWidth: root.getWorkspaceWidth
|
||||
getWorkspaceHeight: root.getWorkspaceHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -700,174 +591,33 @@ Item {
|
||||
Column {
|
||||
id: pillColumn
|
||||
spacing: spacingBetweenPills
|
||||
x: workspaceBackground.x + Style.pixelAlignCenter(workspaceBackground.width, width)
|
||||
x: 0
|
||||
y: horizontalPadding
|
||||
visible: isVertical && !showApplications
|
||||
|
||||
Repeater {
|
||||
id: workspaceRepeaterVertical
|
||||
model: localWorkspaces
|
||||
Item {
|
||||
id: workspacePillContainerVertical
|
||||
width: Style.toOdd(capsuleHeight * root.baseDimensionRatio)
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "active"
|
||||
when: model.isActive
|
||||
PropertyChanges {
|
||||
target: workspacePillContainerVertical
|
||||
height: root.getWorkspaceHeight(model, true)
|
||||
}
|
||||
},
|
||||
State {
|
||||
name: "inactive"
|
||||
when: !model.isActive
|
||||
PropertyChanges {
|
||||
target: workspacePillContainerVertical
|
||||
height: root.getWorkspaceHeight(model, false)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
transitions: [
|
||||
Transition {
|
||||
from: "inactive"
|
||||
to: "active"
|
||||
NumberAnimation {
|
||||
property: "height"
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
},
|
||||
Transition {
|
||||
from: "active"
|
||||
to: "inactive"
|
||||
NumberAnimation {
|
||||
property: "height"
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
Rectangle {
|
||||
id: pillVertical
|
||||
anchors.fill: parent
|
||||
|
||||
Loader {
|
||||
active: (labelMode !== "none") && (!root.showLabelsOnlyWhenOccupied || model.isOccupied || model.isFocused)
|
||||
sourceComponent: Component {
|
||||
NText {
|
||||
x: Style.pixelAlignCenter(pillVertical.width, width)
|
||||
y: Style.pixelAlignCenter(pillVertical.height, height)
|
||||
text: {
|
||||
if (model.name && model.name.length > 0) {
|
||||
if (root.labelMode === "name") {
|
||||
return model.name.substring(0, characterCount);
|
||||
}
|
||||
if (root.labelMode === "index+name") {
|
||||
return (model.idx.toString() + model.name.substring(0, 1));
|
||||
}
|
||||
}
|
||||
return model.idx.toString();
|
||||
}
|
||||
family: Settings.data.ui.fontFixed
|
||||
pointSize: workspacePillContainerVertical.width * root.textRatio
|
||||
applyUiScale: false
|
||||
font.capitalization: Font.AllUppercase
|
||||
font.weight: Style.fontWeightBold
|
||||
wrapMode: Text.Wrap
|
||||
color: {
|
||||
if (model.isFocused)
|
||||
return Color.mOnPrimary;
|
||||
if (model.isUrgent)
|
||||
return Color.mOnError;
|
||||
if (model.isOccupied)
|
||||
return Color.mOnSecondary;
|
||||
|
||||
return Color.mOnSecondary;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
radius: Style.radiusM
|
||||
color: {
|
||||
if (model.isFocused)
|
||||
return Color.mPrimary;
|
||||
if (model.isUrgent)
|
||||
return Color.mError;
|
||||
if (model.isOccupied)
|
||||
return Color.mSecondary;
|
||||
|
||||
return Qt.alpha(Color.mSecondary, 0.3);
|
||||
}
|
||||
z: 0
|
||||
|
||||
MouseArea {
|
||||
id: pillMouseAreaVertical
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
CompositorService.switchToWorkspace(model);
|
||||
}
|
||||
hoverEnabled: true
|
||||
}
|
||||
// Material 3-inspired smooth animation for scale, color, opacity, and radius
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on color {
|
||||
enabled: !Color.isTransitioning
|
||||
ColorAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutCubic
|
||||
}
|
||||
}
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Style.animationNormal
|
||||
easing.type: Easing.OutBack
|
||||
}
|
||||
}
|
||||
// Burst effect overlay for focused pill (smaller outline)
|
||||
Rectangle {
|
||||
id: pillBurstVertical
|
||||
anchors.centerIn: workspacePillContainerVertical
|
||||
width: workspacePillContainerVertical.width + 18 * root.masterProgress * scale
|
||||
height: workspacePillContainerVertical.height + 18 * root.masterProgress * scale
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
border.color: root.effectColor
|
||||
border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress))))
|
||||
opacity: root.effectsActive && model.isFocused ? (1.0 - root.masterProgress) * 0.7 : 0
|
||||
visible: root.effectsActive && model.isFocused
|
||||
z: 1
|
||||
}
|
||||
delegate: WorkspacePill {
|
||||
required property var model
|
||||
workspace: model
|
||||
isVertical: true
|
||||
baseDimensionRatio: root.baseDimensionRatio
|
||||
capsuleHeight: root.capsuleHeight
|
||||
barHeight: root.barHeight
|
||||
labelMode: root.labelMode
|
||||
characterCount: root.characterCount
|
||||
textRatio: root.textRatio
|
||||
showLabelsOnlyWhenOccupied: root.showLabelsOnlyWhenOccupied
|
||||
colorMap: root.colorMap
|
||||
focusedColor: root.focusedColor
|
||||
occupiedColor: root.occupiedColor
|
||||
emptyColor: root.emptyColor
|
||||
masterProgress: root.masterProgress
|
||||
effectsActive: root.effectsActive
|
||||
effectColor: root.effectColor
|
||||
getWorkspaceWidth: root.getWorkspaceWidth
|
||||
getWorkspaceHeight: root.getWorkspaceHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -875,7 +625,6 @@ Item {
|
||||
// ========================================
|
||||
// Grouped mode (showApplications = true)
|
||||
// ========================================
|
||||
|
||||
Component {
|
||||
id: groupedWorkspaceDelegate
|
||||
|
||||
@@ -884,7 +633,28 @@ Item {
|
||||
|
||||
required property var model
|
||||
property var workspaceModel: model
|
||||
property bool hasWindows: (workspaceModel?.windows?.length > 0 || workspaceModel?.windows?.count > 0)
|
||||
// Fetch windows directly from service to avoid Qt 6.9 ListModel nested array issues
|
||||
property var liveWindows: []
|
||||
property bool hasWindows: liveWindows.length > 0
|
||||
|
||||
function updateWindows() {
|
||||
var wsId = workspaceModel?.id;
|
||||
if (wsId !== undefined && wsId !== null) {
|
||||
liveWindows = CompositorService.getWindowsForWorkspace(wsId);
|
||||
} else {
|
||||
liveWindows = [];
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: updateWindows()
|
||||
onWorkspaceModelChanged: updateWindows()
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onWindowRevisionChanged() {
|
||||
groupedContainer.updateWindows();
|
||||
}
|
||||
}
|
||||
|
||||
width: Style.toOdd((hasWindows ? groupedIconsFlow.implicitWidth : root.iconSize) + (root.isVertical ? (root.baseItemSize - root.iconSize + Style.marginXS) : Style.marginXL))
|
||||
height: Style.toOdd((hasWindows ? groupedIconsFlow.implicitHeight : root.iconSize) + (root.isVertical ? Style.marginL : (root.baseItemSize - root.iconSize + Style.marginXS)))
|
||||
@@ -938,7 +708,7 @@ Item {
|
||||
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
|
||||
Repeater {
|
||||
model: groupedContainer.workspaceModel.windows
|
||||
model: groupedContainer.liveWindows
|
||||
|
||||
delegate: Item {
|
||||
id: groupedTaskbarItem
|
||||
@@ -955,17 +725,16 @@ Item {
|
||||
height: parent.height
|
||||
source: {
|
||||
root.iconRevision; // Force re-evaluation when revision changes
|
||||
const win = (typeof modelData !== "undefined") ? modelData : model;
|
||||
return ThemeIcons.iconForAppId(win.appId?.toLowerCase());
|
||||
return ThemeIcons.iconForAppId(modelData.appId?.toLowerCase());
|
||||
}
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
opacity: (typeof modelData !== "undefined" ? modelData.isFocused : model.isFocused) ? Style.opacityFull : unfocusedIconsOpacity
|
||||
layer.enabled: root.colorizeIcons && !(typeof modelData !== "undefined" ? modelData.isFocused : model.isFocused)
|
||||
opacity: modelData.isFocused ? Style.opacityFull : unfocusedIconsOpacity
|
||||
layer.enabled: root.colorizeIcons && !modelData.isFocused
|
||||
|
||||
Rectangle {
|
||||
id: groupedFocusIndicator
|
||||
visible: (typeof modelData !== "undefined" ? modelData.isFocused : model.isFocused)
|
||||
visible: modelData.isFocused
|
||||
anchors.bottomMargin: -2
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -990,30 +759,23 @@ Item {
|
||||
preventStealing: true
|
||||
|
||||
onPressed: mouse => {
|
||||
const win = (typeof modelData !== "undefined") ? modelData : model;
|
||||
if (!win)
|
||||
return;
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
CompositorService.focusWindow(win);
|
||||
CompositorService.focusWindow(modelData);
|
||||
}
|
||||
}
|
||||
|
||||
onReleased: mouse => {
|
||||
const win = (typeof modelData !== "undefined") ? modelData : model;
|
||||
if (!win)
|
||||
return;
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
mouse.accepted = true;
|
||||
TooltipService.hide();
|
||||
root.selectedWindowId = win.id || win.address || "";
|
||||
root.selectedAppId = win.appId;
|
||||
root.selectedWindowId = modelData.id || modelData.address || "";
|
||||
root.selectedAppId = modelData.appId;
|
||||
openGroupedContextMenu(groupedTaskbarItem);
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
const win = (typeof modelData !== "undefined") ? modelData : model;
|
||||
groupedTaskbarItem.itemHovered = true;
|
||||
TooltipService.show(groupedTaskbarItem, win.title || win.appId || "Unknown app.", BarService.getTooltipDirection(root.screen?.name));
|
||||
TooltipService.show(groupedTaskbarItem, modelData.title || modelData.appId || "Unknown app.", BarService.getTooltipDirection(root.screenName));
|
||||
}
|
||||
onExited: {
|
||||
groupedTaskbarItem.itemHovered = false;
|
||||
@@ -1027,7 +789,7 @@ Item {
|
||||
Item {
|
||||
id: groupedWorkspaceNumberContainer
|
||||
|
||||
visible: root.labelMode !== "none" && (!root.showLabelsOnlyWhenOccupied || groupedContainer.hasWindows || groupedContainer.workspaceModel.isFocused)
|
||||
visible: root.labelMode !== "none" && root.showBadge && (!root.showLabelsOnlyWhenOccupied || groupedContainer.hasWindows || groupedContainer.workspaceModel.isFocused)
|
||||
|
||||
anchors {
|
||||
left: parent.left
|
||||
@@ -1047,17 +809,13 @@ Item {
|
||||
|
||||
color: {
|
||||
if (groupedContainer.workspaceModel.isFocused)
|
||||
return Color.mPrimary;
|
||||
return root.getColorPair(root.focusedColor)[0];
|
||||
if (groupedContainer.workspaceModel.isUrgent)
|
||||
return Color.mError;
|
||||
if (groupedContainer.hasWindows)
|
||||
return Color.mSecondary;
|
||||
return root.getColorPair(root.occupiedColor)[0];
|
||||
|
||||
if (Settings.data.colorSchemes.darkMode) {
|
||||
return Qt.darker(Color.mSecondary, 1.5);
|
||||
} else {
|
||||
return Qt.lighter(Color.mSecondary, 1.5);
|
||||
}
|
||||
return root.getColorPair(root.emptyColor)[0];
|
||||
}
|
||||
|
||||
scale: groupedContainer.workspaceModel.isActive ? 1.0 : 0.8
|
||||
@@ -1120,11 +878,13 @@ Item {
|
||||
|
||||
color: {
|
||||
if (groupedContainer.workspaceModel.isFocused)
|
||||
return Color.mOnPrimary;
|
||||
return root.getColorPair(root.focusedColor)[1];
|
||||
if (groupedContainer.workspaceModel.isUrgent)
|
||||
return Color.mOnError;
|
||||
if (groupedContainer.hasWindows)
|
||||
return root.getColorPair(root.occupiedColor)[1];
|
||||
|
||||
return Color.mOnSecondary;
|
||||
return root.getColorPair(root.emptyColor)[1];
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -1162,10 +922,6 @@ Item {
|
||||
}
|
||||
|
||||
function openGroupedContextMenu(item) {
|
||||
var popupMenuWindow = PanelService.getPopupMenuWindow(screen);
|
||||
if (popupMenuWindow) {
|
||||
popupMenuWindow.showContextMenu(contextMenu);
|
||||
contextMenu.openAtItem(item, screen);
|
||||
}
|
||||
PanelService.showContextMenu(contextMenu, item, screen);
|
||||
}
|
||||
}
|
||||
|
||||
+85
-25
@@ -110,6 +110,15 @@ Loader {
|
||||
property int dragSourceIndex: -1
|
||||
property int dragTargetIndex: -1
|
||||
|
||||
// when dragging ended but the cursor is outside the dock area, restart the timer
|
||||
onDragSourceIndexChanged: {
|
||||
if (dragSourceIndex === -1) {
|
||||
if (autoHide && !dockHovered && !anyAppHovered && !peekHovered && !menuHovered) {
|
||||
hideTimer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Revision counter to force icon re-evaluation
|
||||
property int iconRevision: 0
|
||||
|
||||
@@ -123,10 +132,17 @@ Loader {
|
||||
function getAppKey(appData) {
|
||||
if (!appData)
|
||||
return null;
|
||||
// prefer toplevel object identity for running apps to distinguish instances
|
||||
|
||||
// Use stable appId for pinned apps to maintain their slot regardless of running state
|
||||
if (appData.type === "pinned" || appData.type === "pinned-running") {
|
||||
return appData.appId;
|
||||
}
|
||||
|
||||
// prefer toplevel object identity for unpinned running apps to distinguish instances
|
||||
if (appData.toplevel)
|
||||
return appData.toplevel;
|
||||
// fallback to appId for pinned-only apps
|
||||
|
||||
// fallback to appId
|
||||
return appData.appId;
|
||||
}
|
||||
|
||||
@@ -138,17 +154,23 @@ Loader {
|
||||
const sorted = [];
|
||||
const remaining = [...apps];
|
||||
|
||||
// 1. Pick apps that are in the session order
|
||||
// Pick apps that are in the session order
|
||||
for (let i = 0; i < sessionAppOrder.length; i++) {
|
||||
const key = sessionAppOrder[i];
|
||||
const idx = remaining.findIndex(app => getAppKey(app) === key);
|
||||
if (idx !== -1) {
|
||||
sorted.push(remaining[idx]);
|
||||
remaining.splice(idx, 1);
|
||||
|
||||
// Pick ALL matching apps (e.g. all instances of a pinned app)
|
||||
while (true) {
|
||||
const idx = remaining.findIndex(app => getAppKey(app) === key);
|
||||
if (idx !== -1) {
|
||||
sorted.push(remaining[idx]);
|
||||
remaining.splice(idx, 1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Append any new/remaining apps
|
||||
// Append any new/remaining apps
|
||||
remaining.forEach(app => sorted.push(app));
|
||||
|
||||
return sorted;
|
||||
@@ -201,7 +223,10 @@ Loader {
|
||||
function normalizeAppId(appId) {
|
||||
if (!appId || typeof appId !== 'string')
|
||||
return "";
|
||||
return appId.toLowerCase().trim();
|
||||
let id = appId.toLowerCase().trim();
|
||||
if (id.endsWith(".desktop"))
|
||||
id = id.substring(0, id.length - 8);
|
||||
return id;
|
||||
}
|
||||
|
||||
// Helper function to check if an app ID matches a pinned app (case-insensitive)
|
||||
@@ -249,6 +274,9 @@ Loader {
|
||||
|
||||
//push an app onto combined with the given appType
|
||||
function pushApp(appType, toplevel, appId, title) {
|
||||
// Use canonical ID for pinned apps to ensure key stability
|
||||
const canonicalId = isAppIdPinned(appId, pinnedApps) ? (pinnedApps.find(p => normalizeAppId(p) === normalizeAppId(appId)) || appId) : appId;
|
||||
|
||||
// For running apps, track by toplevel object to allow multiple instances
|
||||
if (toplevel) {
|
||||
if (processedToplevels.has(toplevel)) {
|
||||
@@ -260,30 +288,30 @@ Loader {
|
||||
combined.push({
|
||||
"type": appType,
|
||||
"toplevel": toplevel,
|
||||
"appId": appId,
|
||||
"appId": canonicalId,
|
||||
"title": title
|
||||
});
|
||||
processedToplevels.add(toplevel);
|
||||
} else {
|
||||
// For pinned apps that aren't running, track by appId to avoid duplicates
|
||||
if (processedPinnedAppIds.has(appId)) {
|
||||
if (processedPinnedAppIds.has(canonicalId)) {
|
||||
return; // Already processed this pinned app
|
||||
}
|
||||
combined.push({
|
||||
"type": appType,
|
||||
"toplevel": toplevel,
|
||||
"appId": appId,
|
||||
"appId": canonicalId,
|
||||
"title": title
|
||||
});
|
||||
processedPinnedAppIds.add(appId);
|
||||
processedPinnedAppIds.add(canonicalId);
|
||||
}
|
||||
}
|
||||
|
||||
function pushRunning(first) {
|
||||
runningApps.forEach(toplevel => {
|
||||
if (toplevel) {
|
||||
// Skip pinned apps if they were already processed (when pinnedStatic is true)
|
||||
const isPinned = pinnedApps.includes(toplevel.appId);
|
||||
// Use robust matching to check if pinned
|
||||
const isPinned = isAppIdPinned(toplevel.appId, pinnedApps);
|
||||
if (!first && isPinned && processedToplevels.has(toplevel)) {
|
||||
return; // Already added by pushPinned()
|
||||
}
|
||||
@@ -294,8 +322,8 @@ Loader {
|
||||
|
||||
function pushPinned() {
|
||||
pinnedApps.forEach(pinnedAppId => {
|
||||
// Find all running instances of this pinned app
|
||||
const matchingToplevels = runningApps.filter(app => app && app.appId === pinnedAppId);
|
||||
// Find all running instances of this pinned app using robust matching
|
||||
const matchingToplevels = runningApps.filter(app => app && normalizeAppId(app.appId) === normalizeAppId(pinnedAppId));
|
||||
|
||||
if (matchingToplevels.length > 0) {
|
||||
// Add all running instances as pinned-running
|
||||
@@ -321,9 +349,36 @@ Loader {
|
||||
}
|
||||
|
||||
dockApps = sortDockApps(combined);
|
||||
// Sync session order if needed (e.g. first run or new apps added)
|
||||
if (!sessionAppOrder || sessionAppOrder.length === 0 || sessionAppOrder.length !== dockApps.length) {
|
||||
|
||||
// Sync session order if needed
|
||||
// Instead of resetting everything when length changes, we reconcile the keys
|
||||
if (!sessionAppOrder || sessionAppOrder.length === 0) {
|
||||
sessionAppOrder = dockApps.map(getAppKey);
|
||||
} else {
|
||||
const currentKeys = new Set(dockApps.map(getAppKey));
|
||||
const existingKeys = new Set();
|
||||
const newOrder = [];
|
||||
|
||||
// Keep existing keys that are still present
|
||||
sessionAppOrder.forEach(key => {
|
||||
if (currentKeys.has(key)) {
|
||||
newOrder.push(key);
|
||||
existingKeys.add(key);
|
||||
}
|
||||
});
|
||||
|
||||
// Add new keys at the end
|
||||
dockApps.forEach(app => {
|
||||
const key = getAppKey(app);
|
||||
if (!existingKeys.has(key)) {
|
||||
newOrder.push(key);
|
||||
existingKeys.add(key);
|
||||
}
|
||||
});
|
||||
|
||||
if (JSON.stringify(newOrder) !== JSON.stringify(sessionAppOrder)) {
|
||||
sessionAppOrder = newOrder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -343,6 +398,11 @@ Loader {
|
||||
id: hideTimer
|
||||
interval: hideDelay
|
||||
onTriggered: {
|
||||
// do not hide if dragging
|
||||
if (root.dragSourceIndex !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Force menuHovered to false if no menu is current or visible
|
||||
if (!root.currentContextMenu || !root.currentContextMenu.visible) {
|
||||
menuHovered = false;
|
||||
@@ -471,8 +531,8 @@ Loader {
|
||||
WlrLayershell.namespace: "noctalia-dock-" + (screen?.name || "unknown")
|
||||
WlrLayershell.exclusionMode: exclusive ? ExclusionMode.Auto : ExclusionMode.Ignore
|
||||
|
||||
implicitWidth: dockContainerWrapper.width
|
||||
implicitHeight: dockContainerWrapper.height
|
||||
implicitWidth: Math.round(dockContainerWrapper.width + (root.isVertical ? 0 : Style.marginXL * 6))
|
||||
implicitHeight: Math.round(dockContainerWrapper.height)
|
||||
|
||||
// Position based on dock setting
|
||||
anchors.top: dockPosition === "top"
|
||||
@@ -566,12 +626,13 @@ Loader {
|
||||
showTimer.stop();
|
||||
hideTimer.stop();
|
||||
unloadTimer.stop(); // Cancel unload if hovering
|
||||
hidden = false; // Make sure dock is visible
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
dockHovered = false;
|
||||
if (autoHide && !anyAppHovered && !peekHovered && !menuHovered) {
|
||||
if (autoHide && !anyAppHovered && !peekHovered && !menuHovered && root.dragSourceIndex === -1) {
|
||||
hideTimer.restart();
|
||||
}
|
||||
}
|
||||
@@ -825,12 +886,10 @@ Loader {
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
root.currentContextMenu = contextMenu;
|
||||
anyAppHovered = false;
|
||||
} else if (root.currentContextMenu === contextMenu) {
|
||||
root.currentContextMenu = null;
|
||||
hideTimer.stop();
|
||||
menuHovered = false;
|
||||
anyAppHovered = false;
|
||||
// Restart hide timer after menu closes
|
||||
if (autoHide && !dockHovered && !anyAppHovered && !peekHovered && !menuHovered) {
|
||||
hideTimer.restart();
|
||||
@@ -878,6 +937,7 @@ Loader {
|
||||
showTimer.stop();
|
||||
hideTimer.stop();
|
||||
unloadTimer.stop(); // Cancel unload if hovering app
|
||||
hidden = false; // Make sure dock is visible
|
||||
}
|
||||
}
|
||||
|
||||
@@ -888,7 +948,7 @@ Loader {
|
||||
if (!root.currentContextMenu || !root.currentContextMenu.visible) {
|
||||
menuHovered = false;
|
||||
}
|
||||
if (autoHide && !dockHovered && !peekHovered && !menuHovered) {
|
||||
if (autoHide && !dockHovered && !peekHovered && !menuHovered && root.dragSourceIndex === -1) {
|
||||
hideTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ PopupWindow {
|
||||
property real menuContentWidth: 160
|
||||
|
||||
implicitWidth: menuContentWidth + (Style.marginXL)
|
||||
implicitHeight: contextMenuColumn.implicitHeight + (Style.marginXL)
|
||||
implicitHeight: (root.items.length * 32) + (Style.marginXL)
|
||||
color: "transparent"
|
||||
visible: false
|
||||
|
||||
@@ -256,14 +256,9 @@ PopupWindow {
|
||||
toplevel = toplevelData;
|
||||
initItems();
|
||||
|
||||
// Force a complete re-evaluation by waiting for the next frame
|
||||
Qt.callLater(() => {
|
||||
Qt.callLater(() => {
|
||||
visible = true;
|
||||
canAutoClose = false;
|
||||
gracePeriodTimer.restart();
|
||||
});
|
||||
});
|
||||
visible = true;
|
||||
canAutoClose = false;
|
||||
gracePeriodTimer.restart();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
|
||||
@@ -17,18 +17,49 @@ Scope {
|
||||
property bool showInfo: false
|
||||
property string errorMessage: ""
|
||||
property string infoMessage: ""
|
||||
property bool fprintdAvailable: false
|
||||
|
||||
readonly property string pamConfigDirectory: Quickshell.env("NOCTALIA_PAM_CONFIG") ? "/etc/pam.d" : Settings.configDir + "pam"
|
||||
readonly property string pamConfig: Quickshell.env("NOCTALIA_PAM_CONFIG") || "password.conf"
|
||||
readonly property string pamConfigDirectory: "/etc/pam.d"
|
||||
property string pamConfig: Quickshell.env("NOCTALIA_PAM_SERVICE") || "login"
|
||||
property bool pamReady: false
|
||||
|
||||
Component.onCompleted: {
|
||||
checkFprintdProc.running = true;
|
||||
|
||||
if (Quickshell.env("NOCTALIA_PAM_CONFIG")) {
|
||||
Logger.i("LockContext", "NOCTALIA_PAM_CONFIG is set, using system PAM config: /etc/pam.d/" + pamConfig);
|
||||
if (Quickshell.env("NOCTALIA_PAM_SERVICE")) {
|
||||
Logger.i("LockContext", "NOCTALIA_PAM_SERVICE is set, using system PAM config: /etc/pam.d/" + pamConfig);
|
||||
pamReady = true;
|
||||
} else {
|
||||
Logger.i("LockContext", "Using generated PAM config:", pamConfigDirectory + "/" + pamConfig);
|
||||
Logger.i("LockContext", "Probing for best PAM service...");
|
||||
detectPamServiceProc.running = true;
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: detectPamServiceProc
|
||||
command: ["sh", "-c", "
|
||||
if [ -f /etc/pam.d/login ]; then echo 'login'; exit 0; fi;
|
||||
if [ -f /etc/pam.d/system-auth ]; then echo 'system-auth'; exit 0; fi;
|
||||
if [ -f /etc/pam.d/common-auth ]; then echo 'common-auth'; exit 0; fi;
|
||||
echo 'login';
|
||||
"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
const service = String(text || "").trim();
|
||||
if (service.length > 0) {
|
||||
root.pamConfig = service;
|
||||
Logger.i("LockContext", "Detected PAM service: " + service);
|
||||
} else {
|
||||
Logger.w("LockContext", "Failed to detect PAM service, defaulting to login");
|
||||
}
|
||||
root.pamReady = true;
|
||||
}
|
||||
}
|
||||
stderr: StdioCollector {}
|
||||
}
|
||||
|
||||
onPamReadyChanged: {
|
||||
if (pamReady) {
|
||||
if (Settings.data.general.autoStartAuth && currentText === "") {
|
||||
pam.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,16 +82,23 @@ Scope {
|
||||
if (!waitingForPassword) {
|
||||
pam.abort();
|
||||
}
|
||||
if (fprintdAvailable) {
|
||||
if (Settings.data.general.allowPasswordWithFprintd) {
|
||||
occupyFingerprintSensorProc.running = true;
|
||||
}
|
||||
} else {
|
||||
occupyFingerprintSensorProc.running = false;
|
||||
pam.start();
|
||||
if (pamReady && Settings.data.general.autoStartAuth) {
|
||||
pam.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function tryUnlock() {
|
||||
if (!pamReady) {
|
||||
Logger.w("LockContext", "PAM not ready yet, ignoring unlock attempt");
|
||||
return;
|
||||
}
|
||||
|
||||
if (waitingForPassword) {
|
||||
pam.respond(currentText);
|
||||
unlockInProgress = true;
|
||||
@@ -73,14 +111,6 @@ Scope {
|
||||
pam.start();
|
||||
}
|
||||
|
||||
Process {
|
||||
id: checkFprintdProc
|
||||
command: ["sh", "-c", "command -v fprintd-verify"]
|
||||
onExited: function (exitCode) {
|
||||
fprintdAvailable = (exitCode === 0);
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: occupyFingerprintSensorProc
|
||||
command: ["fprintd-verify"]
|
||||
|
||||
@@ -77,18 +77,12 @@ Loader {
|
||||
|
||||
Item {
|
||||
id: batteryIndicator
|
||||
property bool initializationComplete: false
|
||||
Timer {
|
||||
interval: 500
|
||||
running: true
|
||||
onTriggered: batteryIndicator.initializationComplete = true
|
||||
}
|
||||
|
||||
property bool isReady: initializationComplete && BatteryService.batteryReady
|
||||
property bool isReady: BatteryService.ready && BatteryService.batteryReady
|
||||
property real percent: BatteryService.batteryPercentage
|
||||
property bool charging: BatteryService.batteryCharging
|
||||
property bool pluggedIn: BatteryService.batteryPluggedIn
|
||||
property bool batteryVisible: isReady && percent > 0 && BatteryService.hasAnyBattery()
|
||||
property bool batteryVisible: isReady && percent >= 0 && BatteryService.hasAnyBattery()
|
||||
}
|
||||
|
||||
Item {
|
||||
|
||||
@@ -21,7 +21,9 @@ Item {
|
||||
required property TextInput passwordInput
|
||||
|
||||
Component.onCompleted: {
|
||||
doUnlock();
|
||||
if (Settings.data.general.autoStartAuth) {
|
||||
doUnlock();
|
||||
}
|
||||
}
|
||||
|
||||
function doUnlock() {
|
||||
|
||||
@@ -13,6 +13,7 @@ import qs.Services.UI
|
||||
Variants {
|
||||
model: Quickshell.screens
|
||||
delegate: Item {
|
||||
id: windowItem
|
||||
required property ShellScreen modelData
|
||||
|
||||
property bool shouldBeActive: {
|
||||
@@ -76,23 +77,27 @@ Variants {
|
||||
|
||||
// BarExclusionZone - created after MainScreen has fully loaded
|
||||
// Disabled when bar is hidden or not configured for this screen
|
||||
Loader {
|
||||
active: {
|
||||
if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible)
|
||||
return false;
|
||||
Repeater {
|
||||
model: Settings.data.bar.barType === "framed" ? ["top", "bottom", "left", "right"] : [Settings.getBarPositionForScreen(windowItem.modelData?.name)]
|
||||
delegate: Loader {
|
||||
active: {
|
||||
if (!windowItem.windowLoaded || !windowItem.shouldBeActive || !BarService.effectivelyVisible)
|
||||
return false;
|
||||
|
||||
// Check if bar is configured for this screen
|
||||
var monitors = Settings.data.bar.monitors || [];
|
||||
return monitors.length === 0 || monitors.includes(modelData?.name);
|
||||
}
|
||||
asynchronous: false
|
||||
// Check if bar is configured for this screen
|
||||
var monitors = Settings.data.bar.monitors || [];
|
||||
return monitors.length === 0 || monitors.includes(windowItem.modelData?.name);
|
||||
}
|
||||
asynchronous: false
|
||||
|
||||
sourceComponent: BarExclusionZone {
|
||||
screen: modelData
|
||||
}
|
||||
sourceComponent: BarExclusionZone {
|
||||
screen: windowItem.modelData
|
||||
edge: modelData
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
Logger.d("AllScreens", "BarExclusionZone created for", modelData?.name);
|
||||
onLoaded: {
|
||||
Logger.d("AllScreens", "BarExclusionZone (" + modelData + ") created for", windowItem.modelData?.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,11 @@ ShapePath {
|
||||
// Corner radius (from Style)
|
||||
readonly property real radius: Style.radiusL
|
||||
|
||||
// Framed bar properties
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 12
|
||||
readonly property real frameRadius: Settings.data.bar.frameRadius ?? 20
|
||||
|
||||
// Bar position - since bar's parent fills the screen and Shape also fills the screen,
|
||||
// we can use bar.x and bar.y directly (they're already in screen coordinates)
|
||||
readonly property point barMappedPos: bar ? Qt.point(bar.x, bar.y) : Qt.point(0, 0)
|
||||
@@ -56,6 +61,18 @@ ShapePath {
|
||||
readonly property real barWidth: (bar && shouldShow) ? bar.width : 0
|
||||
readonly property real barHeight: (bar && shouldShow) ? bar.height : 0
|
||||
|
||||
// Screen dimensions for frame
|
||||
readonly property real screenWidth: windowRoot?.screen?.width || 0
|
||||
readonly property real screenHeight: windowRoot?.screen?.height || 0
|
||||
|
||||
// Inner hole dimensions for framed mode - always relative to screen
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(windowRoot?.screen?.name)
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real holeX: (barPosition === "left") ? barWidth : frameThickness
|
||||
readonly property real holeY: (barPosition === "top") ? barHeight : frameThickness
|
||||
readonly property real holeWidth: screenWidth - (barPosition === "left" || barPosition === "right" ? (barWidth + frameThickness) : (frameThickness * 2))
|
||||
readonly property real holeHeight: screenHeight - (barPosition === "top" || barPosition === "bottom" ? (barHeight + frameThickness) : (frameThickness * 2))
|
||||
|
||||
// Flatten corners if bar is too small (handle null bar)
|
||||
readonly property bool shouldFlatten: bar ? ShapeCornerHelper.shouldFlatten(barWidth, barHeight, radius) : false
|
||||
readonly property real effectiveRadius: shouldFlatten ? (bar ? ShapeCornerHelper.getFlattenedRadius(Math.min(barWidth, barHeight), radius) : 0) : radius
|
||||
@@ -89,73 +106,159 @@ ShapePath {
|
||||
// ShapePath configuration
|
||||
strokeWidth: -1 // No stroke, fill only
|
||||
fillColor: backgroundColor
|
||||
fillRule: isFramed ? ShapePath.OddEvenFill : ShapePath.WindingFill
|
||||
|
||||
// Starting position (top-left corner, after the arc)
|
||||
// Use mapped coordinates relative to the Shape container
|
||||
startX: barMappedPos.x + tlRadius * tlMultX
|
||||
startY: barMappedPos.y
|
||||
// Starting position
|
||||
// In framed mode, we start at (0,0) to draw the screen rectangle first
|
||||
startX: isFramed ? 0 : (barMappedPos.x + tlRadius * tlMultX)
|
||||
startY: isFramed ? 0 : barMappedPos.y
|
||||
|
||||
// ========== PATH DEFINITION ==========
|
||||
// Draws a rectangle with potentially inverted corners
|
||||
// All coordinates are relative to startX/startY
|
||||
|
||||
// Top edge (moving right)
|
||||
// 1. Main Bar / Outer Screen Rectangle
|
||||
PathLine {
|
||||
relativeX: root.barWidth - root.tlRadius * root.tlMultX - root.trRadius * root.trMultX
|
||||
relativeY: 0
|
||||
x: {
|
||||
if (!root.shouldShow)
|
||||
return 0;
|
||||
if (root.isFramed)
|
||||
return root.screenWidth;
|
||||
return root.barMappedPos.x + root.barWidth - root.trRadius * root.trMultX;
|
||||
}
|
||||
y: root.isFramed ? 0 : root.barMappedPos.y
|
||||
}
|
||||
|
||||
// Top-right corner arc
|
||||
// Bar top-right corner (only if not framed)
|
||||
PathArc {
|
||||
relativeX: root.trRadius * root.trMultX
|
||||
relativeY: root.trRadius * root.trMultY
|
||||
radiusX: root.trRadius
|
||||
radiusY: root.trRadius
|
||||
x: root.isFramed ? (root.shouldShow ? root.screenWidth : 0) : (root.barMappedPos.x + root.barWidth)
|
||||
y: root.isFramed ? 0 : (root.barMappedPos.y + root.trRadius * root.trMultY)
|
||||
radiusX: root.isFramed ? 0 : root.trRadius
|
||||
radiusY: root.isFramed ? 0 : root.trRadius
|
||||
direction: ShapeCornerHelper.getArcDirection(root.trMultX, root.trMultY)
|
||||
}
|
||||
|
||||
// Right edge (moving down)
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: root.barHeight - root.trRadius * root.trMultY - root.brRadius * root.brMultY
|
||||
x: root.isFramed ? (root.shouldShow ? root.screenWidth : 0) : (root.barMappedPos.x + root.barWidth)
|
||||
y: {
|
||||
if (!root.shouldShow)
|
||||
return 0;
|
||||
if (root.isFramed)
|
||||
return root.screenHeight;
|
||||
return root.barMappedPos.y + root.barHeight - root.brRadius * root.brMultY;
|
||||
}
|
||||
}
|
||||
|
||||
// Bottom-right corner arc
|
||||
// Bar bottom-right corner (only if not framed)
|
||||
PathArc {
|
||||
relativeX: -root.brRadius * root.brMultX
|
||||
relativeY: root.brRadius * root.brMultY
|
||||
radiusX: root.brRadius
|
||||
radiusY: root.brRadius
|
||||
x: root.isFramed ? (root.shouldShow ? root.screenWidth : 0) : (root.barMappedPos.x + root.barWidth - root.brRadius * root.brMultX)
|
||||
y: root.isFramed ? (root.shouldShow ? root.screenHeight : 0) : (root.barMappedPos.y + root.barHeight)
|
||||
radiusX: root.isFramed ? 0 : root.brRadius
|
||||
radiusY: root.isFramed ? 0 : root.brRadius
|
||||
direction: ShapeCornerHelper.getArcDirection(root.brMultX, root.brMultY)
|
||||
}
|
||||
|
||||
// Bottom edge (moving left)
|
||||
PathLine {
|
||||
relativeX: -(root.barWidth - root.brRadius * root.brMultX - root.blRadius * root.blMultX)
|
||||
relativeY: 0
|
||||
x: {
|
||||
if (!root.shouldShow)
|
||||
return 0;
|
||||
if (root.isFramed)
|
||||
return 0;
|
||||
return root.barMappedPos.x + root.blRadius * root.blMultX;
|
||||
}
|
||||
y: root.isFramed ? (root.shouldShow ? root.screenHeight : 0) : (root.barMappedPos.y + root.barHeight)
|
||||
}
|
||||
|
||||
// Bottom-left corner arc
|
||||
// Bar bottom-left corner (only if not framed)
|
||||
PathArc {
|
||||
relativeX: -root.blRadius * root.blMultX
|
||||
relativeY: -root.blRadius * root.blMultY
|
||||
radiusX: root.blRadius
|
||||
radiusY: root.blRadius
|
||||
x: root.isFramed ? 0 : root.barMappedPos.x
|
||||
y: root.isFramed ? (root.shouldShow ? root.screenHeight : 0) : (root.barMappedPos.y + root.barHeight - root.blRadius * root.blMultY)
|
||||
radiusX: root.isFramed ? 0 : root.blRadius
|
||||
radiusY: root.isFramed ? 0 : root.blRadius
|
||||
direction: ShapeCornerHelper.getArcDirection(root.blMultX, root.blMultY)
|
||||
}
|
||||
|
||||
// Left edge (moving up) - closes the path back to start
|
||||
PathLine {
|
||||
relativeX: 0
|
||||
relativeY: -(root.barHeight - root.blRadius * root.blMultY - root.tlRadius * root.tlMultY)
|
||||
x: root.isFramed ? 0 : root.barMappedPos.x
|
||||
y: {
|
||||
if (!root.shouldShow)
|
||||
return 0;
|
||||
if (root.isFramed)
|
||||
return 0;
|
||||
return root.barMappedPos.y + root.tlRadius * root.tlMultY;
|
||||
}
|
||||
}
|
||||
|
||||
// Top-left corner arc (back to start)
|
||||
// Bar top-left corner (only if not framed, back to start)
|
||||
PathArc {
|
||||
relativeX: root.tlRadius * root.tlMultX
|
||||
relativeY: -root.tlRadius * root.tlMultY
|
||||
radiusX: root.tlRadius
|
||||
radiusY: root.tlRadius
|
||||
x: root.isFramed ? 0 : (root.barMappedPos.x + root.tlRadius * root.tlMultX)
|
||||
y: root.isFramed ? 0 : root.barMappedPos.y
|
||||
radiusX: root.isFramed ? 0 : root.tlRadius
|
||||
radiusY: root.isFramed ? 0 : root.tlRadius
|
||||
direction: ShapeCornerHelper.getArcDirection(root.tlMultX, root.tlMultY)
|
||||
}
|
||||
|
||||
// 2. Inner Hole for Framed Mode (Clockwise)
|
||||
PathMove {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.frameRadius) : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? root.holeY : root.startY
|
||||
}
|
||||
|
||||
// Top edge
|
||||
PathLine {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.holeWidth - root.frameRadius) : ((root.isFramed && root.shouldShow) ? (root.holeX + root.frameRadius) : root.startX)
|
||||
y: (root.isFramed && root.shouldShow) ? root.holeY : ((root.isFramed && root.shouldShow) ? root.holeY : root.startY)
|
||||
}
|
||||
|
||||
// Top-right corner
|
||||
PathArc {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.holeWidth) : ((root.isFramed && root.shouldShow) ? (root.holeX + root.holeWidth - root.frameRadius) : root.startX)
|
||||
y: (root.isFramed && root.shouldShow) ? (root.holeY + root.frameRadius) : ((root.isFramed && root.shouldShow) ? root.holeY : root.startY)
|
||||
radiusX: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
radiusY: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
// Right edge
|
||||
PathLine {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.holeWidth) : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? (root.holeY + root.holeHeight - root.frameRadius) : root.startY
|
||||
}
|
||||
|
||||
// Bottom-right corner
|
||||
PathArc {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.holeWidth - root.frameRadius) : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? (root.holeY + root.holeHeight) : root.startY
|
||||
radiusX: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
radiusY: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
// Bottom edge
|
||||
PathLine {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.frameRadius) : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? (root.holeY + root.holeHeight) : root.startY
|
||||
}
|
||||
|
||||
// Bottom-left corner
|
||||
PathArc {
|
||||
x: (root.isFramed && root.shouldShow) ? root.holeX : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? (root.holeY + root.holeHeight - root.frameRadius) : root.startY
|
||||
radiusX: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
radiusY: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
|
||||
// Left edge
|
||||
PathLine {
|
||||
x: (root.isFramed && root.shouldShow) ? root.holeX : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? (root.holeY + root.frameRadius) : root.startY
|
||||
}
|
||||
|
||||
// Top-left corner (back to start)
|
||||
PathArc {
|
||||
x: (root.isFramed && root.shouldShow) ? (root.holeX + root.frameRadius) : root.startX
|
||||
y: (root.isFramed && root.shouldShow) ? root.holeY : root.startY
|
||||
radiusX: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
radiusY: (root.isFramed && root.shouldShow) ? root.frameRadius : 0
|
||||
direction: PathArc.Clockwise
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,8 @@ PanelWindow {
|
||||
// Position and size to match bar location (per-screen)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(barWindow.screen?.name)
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 12
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: Math.ceil(barFloating ? Settings.data.bar.marginHorizontal : 0)
|
||||
readonly property real barMarginV: Math.ceil(barFloating ? Settings.data.bar.marginVertical : 0)
|
||||
@@ -45,12 +47,12 @@ PanelWindow {
|
||||
right: barPosition === "right" || !barIsVertical
|
||||
}
|
||||
|
||||
// Handle floating margins
|
||||
// Handle floating margins and framed mode offsets
|
||||
margins {
|
||||
top: barPosition === "top" || barIsVertical ? barMarginV : 0
|
||||
bottom: barPosition === "bottom" || barIsVertical ? barMarginV : 0
|
||||
left: barPosition === "left" || !barIsVertical ? barMarginH : 0
|
||||
right: barPosition === "right" || !barIsVertical ? barMarginH : 0
|
||||
top: (barPosition === "top") ? barMarginV : (isFramed ? frameThickness : barMarginV)
|
||||
bottom: (barPosition === "bottom") ? barMarginV : (isFramed ? frameThickness : barMarginV)
|
||||
left: (barPosition === "left") ? barMarginH : (isFramed ? frameThickness : barMarginH)
|
||||
right: (barPosition === "right") ? barMarginH : (isFramed ? frameThickness : barMarginH)
|
||||
}
|
||||
|
||||
// Set a tight window size
|
||||
|
||||
@@ -13,13 +13,14 @@ import qs.Services.Compositor
|
||||
PanelWindow {
|
||||
id: root
|
||||
|
||||
// Edge to anchor to and thickness to reserve
|
||||
property string edge: Settings.getBarPositionForScreen(screen?.name)
|
||||
property real thickness: (edge === Settings.getBarPositionForScreen(screen?.name)) ? Style.getBarHeightForScreen(screen?.name) : (Settings.data.bar.frameThickness ?? 12)
|
||||
|
||||
readonly property bool exclusive: Settings.data.bar.exclusive
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screen?.name)
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal) : 0
|
||||
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical) : 0
|
||||
readonly property real barMarginH: (barFloating && edge === Settings.getBarPositionForScreen(screen?.name)) ? Math.ceil(Settings.data.bar.marginHorizontal) : 0
|
||||
readonly property real barMarginV: (barFloating && edge === Settings.getBarPositionForScreen(screen?.name)) ? Math.ceil(Settings.data.bar.marginVertical) : 0
|
||||
readonly property real fractOffset: CompositorService.getDisplayScale(screen?.name) % 1.0
|
||||
|
||||
// Invisible - just reserves space
|
||||
@@ -29,30 +30,28 @@ PanelWindow {
|
||||
|
||||
// Wayland layer shell configuration
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
WlrLayershell.namespace: "noctalia-bar-exclusion-" + (screen?.name || "unknown")
|
||||
WlrLayershell.namespace: "noctalia-bar-exclusion-" + edge + "-" + (screen?.name || "unknown")
|
||||
WlrLayershell.exclusionMode: exclusive ? ExclusionMode.Auto : ExclusionMode.Ignore
|
||||
|
||||
// Anchor based on bar position
|
||||
// Anchor based on specified edge
|
||||
anchors {
|
||||
top: barPosition === "top"
|
||||
bottom: barPosition === "bottom"
|
||||
left: barPosition === "left" || barPosition === "top" || barPosition === "bottom"
|
||||
right: barPosition === "right" || barPosition === "top" || barPosition === "bottom"
|
||||
top: edge === "top"
|
||||
bottom: edge === "bottom"
|
||||
left: edge === "left" || edge === "top" || edge === "bottom"
|
||||
right: edge === "right" || edge === "top" || edge === "bottom"
|
||||
}
|
||||
|
||||
// Size based on bar orientation
|
||||
// Size based on orientation
|
||||
implicitWidth: {
|
||||
if (barIsVertical) {
|
||||
// Vertical bar: reserve bar height + margin on the anchored edge only
|
||||
return barHeight + barMarginH - fractOffset;
|
||||
if (edge === "left" || edge === "right") {
|
||||
return thickness + barMarginH - fractOffset;
|
||||
}
|
||||
return 0; // Auto-width when left/right anchors are true
|
||||
}
|
||||
|
||||
implicitHeight: {
|
||||
if (!barIsVertical) {
|
||||
// Horizontal bar: reserve bar height + margin on the anchored edge only
|
||||
return barHeight + barMarginV - fractOffset;
|
||||
if (edge === "top" || edge === "bottom") {
|
||||
return thickness + barMarginV - fractOffset;
|
||||
}
|
||||
return 0; // Auto-height when top/bottom anchors are true
|
||||
}
|
||||
|
||||
@@ -134,13 +134,58 @@ PanelWindow {
|
||||
Region {
|
||||
id: barMaskRegion
|
||||
|
||||
x: barPlaceholder.x
|
||||
y: barPlaceholder.y
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real barThickness: Style.barHeight
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 12
|
||||
readonly property string barPos: Settings.data.bar.position || "top"
|
||||
|
||||
// Set width/height to 0 if bar shouldn't show on this screen (makes region empty)
|
||||
width: root.barShouldShow ? barPlaceholder.width : 0
|
||||
height: root.barShouldShow ? barPlaceholder.height : 0
|
||||
intersection: Intersection.Subtract
|
||||
// Bar / Frame Mask
|
||||
Region {
|
||||
// Mode: Simple or Floating
|
||||
x: barPlaceholder.x
|
||||
y: barPlaceholder.y
|
||||
width: (!barMaskRegion.isFramed && root.barShouldShow) ? barPlaceholder.width : 0
|
||||
height: (!barMaskRegion.isFramed && root.barShouldShow) ? barPlaceholder.height : 0
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
|
||||
// Mode: Framed - 4 sides
|
||||
Region {
|
||||
// Top side
|
||||
Region {
|
||||
x: 0
|
||||
y: 0
|
||||
width: (barMaskRegion.isFramed && root.barShouldShow) ? root.width : 0
|
||||
height: (barMaskRegion.isFramed && root.barShouldShow) ? (barMaskRegion.barPos === "top" ? barMaskRegion.barThickness : barMaskRegion.frameThickness) : 0
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
|
||||
// Bottom side
|
||||
Region {
|
||||
x: 0
|
||||
y: (barMaskRegion.isFramed && root.barShouldShow) ? (root.height - (barMaskRegion.barPos === "bottom" ? barMaskRegion.barThickness : barMaskRegion.frameThickness)) : 0
|
||||
width: (barMaskRegion.isFramed && root.barShouldShow) ? root.width : 0
|
||||
height: (barMaskRegion.isFramed && root.barShouldShow) ? (barMaskRegion.barPos === "bottom" ? barMaskRegion.barThickness : barMaskRegion.frameThickness) : 0
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
|
||||
// Left side
|
||||
Region {
|
||||
x: 0
|
||||
y: 0
|
||||
width: (barMaskRegion.isFramed && root.barShouldShow) ? (barMaskRegion.barPos === "left" ? barMaskRegion.barThickness : barMaskRegion.frameThickness) : 0
|
||||
height: (barMaskRegion.isFramed && root.barShouldShow) ? root.height : 0
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
|
||||
// Right side
|
||||
Region {
|
||||
x: (barMaskRegion.isFramed && root.barShouldShow) ? (root.width - (barMaskRegion.barPos === "right" ? barMaskRegion.barThickness : barMaskRegion.frameThickness)) : 0
|
||||
width: (barMaskRegion.isFramed && root.barShouldShow) ? (barMaskRegion.barPos === "right" ? barMaskRegion.barThickness : barMaskRegion.frameThickness) : 0
|
||||
height: (barMaskRegion.isFramed && root.barShouldShow) ? root.height : 0
|
||||
intersection: Intersection.Subtract
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Background region for click-to-close - reactive sizing
|
||||
@@ -323,6 +368,8 @@ PanelWindow {
|
||||
// Bar background positioning properties (per-screen)
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 12
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: barFloating ? Math.floor(Settings.data.bar.marginHorizontal) : 0
|
||||
readonly property real barMarginV: barFloating ? Math.floor(Settings.data.bar.marginVertical) : 0
|
||||
@@ -333,24 +380,32 @@ PanelWindow {
|
||||
x: {
|
||||
if (barPosition === "right")
|
||||
return screen.width - barHeight - barMarginH;
|
||||
if (isFramed && !barIsVertical)
|
||||
return frameThickness;
|
||||
return barMarginH;
|
||||
}
|
||||
y: {
|
||||
if (barPosition === "bottom")
|
||||
return screen.height - barHeight - barMarginV;
|
||||
if (isFramed && barIsVertical)
|
||||
return frameThickness;
|
||||
return barMarginV;
|
||||
}
|
||||
width: {
|
||||
if (barIsVertical) {
|
||||
return barHeight;
|
||||
}
|
||||
if (isFramed)
|
||||
return screen.width - frameThickness * 2;
|
||||
return screen.width - barMarginH * 2;
|
||||
}
|
||||
height: {
|
||||
if (barIsVertical) {
|
||||
return screen.height - barMarginV * 2;
|
||||
if (!barIsVertical) {
|
||||
return barHeight;
|
||||
}
|
||||
return barHeight;
|
||||
if (isFramed)
|
||||
return screen.height - frameThickness * 2;
|
||||
return screen.height - barMarginV * 2;
|
||||
}
|
||||
|
||||
// Corner states (same as Bar.qml)
|
||||
|
||||
@@ -2,6 +2,7 @@ import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Commons
|
||||
import qs.Services.Compositor
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
@@ -31,8 +32,10 @@ PanelWindow {
|
||||
visible: false
|
||||
color: "transparent"
|
||||
|
||||
// Use Top layer (same as MainScreen) for proper event handling
|
||||
WlrLayershell.layer: WlrLayer.Top
|
||||
// Use Top layer for proper event handling, but on labwc use Bottom
|
||||
// to avoid stealing input from popups while still catching outside clicks.
|
||||
// However, when a dialog is open, always use Top so dialogs appear above apps.
|
||||
WlrLayershell.layer: (CompositorService.isLabwc && !hasDialog) ? WlrLayer.Bottom : WlrLayer.Top
|
||||
WlrLayershell.keyboardFocus: hasDialog ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None
|
||||
WlrLayershell.namespace: "noctalia-" + windowType + "-" + (screen?.name || "unknown")
|
||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||
|
||||
@@ -91,6 +91,8 @@ Item {
|
||||
readonly property string barPosition: Settings.getBarPositionForScreen(screen?.name)
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(screen?.name)
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 12
|
||||
readonly property bool barFloating: Settings.data.bar.floating
|
||||
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal) : 0
|
||||
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical) : 0
|
||||
@@ -172,15 +174,19 @@ Item {
|
||||
barWindowX = screenWidth - root.barMarginH - root.barHeight;
|
||||
} else if (root.barPosition === "left") {
|
||||
barWindowX = root.barMarginH;
|
||||
} else if (root.isFramed) {
|
||||
barWindowX = root.frameThickness;
|
||||
}
|
||||
// For top/bottom bars, barWindowX stays 0 (full width window)
|
||||
// For top/bottom bars, barWindowX stays 0 (full width window) unless framed
|
||||
|
||||
if (root.barPosition === "bottom") {
|
||||
barWindowY = screenHeight - root.barMarginV - root.barHeight;
|
||||
} else if (root.barPosition === "top") {
|
||||
barWindowY = root.barMarginV;
|
||||
} else if (root.isFramed) {
|
||||
barWindowY = root.frameThickness;
|
||||
}
|
||||
// For left/right bars, barWindowY stays 0 (full height window)
|
||||
// For left/right bars, barWindowY stays 0 (full height window) unless framed
|
||||
|
||||
root.buttonPosition = Qt.point(barWindowX + buttonLocal.x, barWindowY + buttonLocal.y);
|
||||
root.buttonWidth = buttonItem.width;
|
||||
@@ -298,6 +304,12 @@ Item {
|
||||
return;
|
||||
}
|
||||
|
||||
// Effective screen margins (account for frame thickness)
|
||||
var effMarginL = Style.marginL + (root.isFramed ? root.frameThickness : 0);
|
||||
var effMarginR = Style.marginL + (root.isFramed ? root.frameThickness : 0);
|
||||
var effMarginT = Style.marginL + (root.isFramed ? root.frameThickness : 0);
|
||||
var effMarginB = Style.marginL + (root.isFramed ? root.frameThickness : 0);
|
||||
|
||||
// Calculate panel dimensions first (needed for positioning)
|
||||
var w;
|
||||
// Priority 1: Content-driven size (dynamic)
|
||||
@@ -310,7 +322,7 @@ Item {
|
||||
else {
|
||||
w = root.preferredWidth;
|
||||
}
|
||||
var panelWidth = Math.min(w, root.width - Style.marginL * 2);
|
||||
var panelWidth = Math.min(w, root.width - effMarginL - effMarginR);
|
||||
|
||||
var h;
|
||||
// Priority 1: Content-driven size (dynamic)
|
||||
@@ -323,7 +335,7 @@ Item {
|
||||
else {
|
||||
h = root.preferredHeight;
|
||||
}
|
||||
var panelHeight = Math.min(h, root.height - root.barHeight - Style.marginL * 2);
|
||||
var panelHeight = Math.min(h, root.height - root.barHeight - effMarginT - effMarginB);
|
||||
|
||||
// Update panelBackground target size (will be animated)
|
||||
panelBackground.targetWidth = panelWidth;
|
||||
@@ -337,6 +349,17 @@ Item {
|
||||
var topBarEdgeWithOverlap = root.barMarginV + root.barHeight - overlap;
|
||||
var bottomBarEdgeWithOverlap = root.height - root.barMarginV - root.barHeight + overlap;
|
||||
|
||||
if (root.isFramed) {
|
||||
if (root.barPosition === "left")
|
||||
leftBarEdgeWithOverlap = root.barHeight - overlap;
|
||||
if (root.barPosition === "right")
|
||||
rightBarEdgeWithOverlap = root.width - root.barHeight + overlap;
|
||||
if (root.barPosition === "top")
|
||||
topBarEdgeWithOverlap = root.barHeight - overlap;
|
||||
if (root.barPosition === "bottom")
|
||||
bottomBarEdgeWithOverlap = root.height - root.barHeight + overlap;
|
||||
}
|
||||
|
||||
// Calculate position
|
||||
var calculatedX;
|
||||
var calculatedY;
|
||||
@@ -355,14 +378,14 @@ Item {
|
||||
} else {
|
||||
// Detached panels: center on button X position
|
||||
var panelX = root.buttonPosition.x + root.buttonWidth / 2 - panelWidth / 2;
|
||||
var minX = Style.marginL;
|
||||
var maxX = root.width - panelWidth - Style.marginL;
|
||||
var minX = effMarginL;
|
||||
var maxX = root.width - panelWidth - effMarginR;
|
||||
|
||||
// Account for vertical bar taking up space
|
||||
if (root.barPosition === "left") {
|
||||
minX = root.barMarginH + root.barHeight + Style.marginL;
|
||||
minX = (root.isFramed ? 0 : root.barMarginH) + root.barHeight + Style.marginL;
|
||||
} else if (root.barPosition === "right") {
|
||||
maxX = root.width - root.barMarginH - root.barHeight - panelWidth - Style.marginL;
|
||||
maxX = root.width - (root.isFramed ? 0 : root.barMarginH) - root.barHeight - panelWidth - Style.marginL;
|
||||
}
|
||||
|
||||
panelX = Math.max(minX, Math.min(panelX, maxX));
|
||||
@@ -373,11 +396,11 @@ Item {
|
||||
var panelX = root.buttonPosition.x + root.buttonWidth / 2 - panelWidth / 2;
|
||||
if (panelContent.allowAttach) {
|
||||
var cornerInset = root.barFloating ? Style.radiusL * 2 : 0;
|
||||
var barLeftEdge = root.barMarginH + cornerInset;
|
||||
var barRightEdge = root.width - root.barMarginH - cornerInset;
|
||||
var barLeftEdge = (root.isFramed ? root.frameThickness : root.barMarginH) + cornerInset;
|
||||
var barRightEdge = root.width - (root.isFramed ? root.frameThickness : root.barMarginH) - cornerInset;
|
||||
panelX = Math.max(barLeftEdge, Math.min(panelX, barRightEdge - panelWidth));
|
||||
} else {
|
||||
panelX = Math.max(Style.marginL, Math.min(panelX, root.width - panelWidth - Style.marginL));
|
||||
panelX = Math.max(effMarginL, Math.min(panelX, root.width - panelWidth - effMarginR));
|
||||
}
|
||||
calculatedX = panelX;
|
||||
}
|
||||
@@ -386,12 +409,12 @@ Item {
|
||||
if (root.panelAnchorHorizontalCenter) {
|
||||
if (root.barIsVertical) {
|
||||
if (root.barPosition === "left") {
|
||||
var availableStart = root.barMarginH + root.barHeight;
|
||||
var availableWidth = root.width - availableStart;
|
||||
var availableStart = (root.isFramed ? 0 : root.barMarginH) + root.barHeight;
|
||||
var availableWidth = root.width - availableStart - (root.isFramed ? root.frameThickness : 0);
|
||||
calculatedX = availableStart + (availableWidth - panelWidth) / 2;
|
||||
} else if (root.barPosition === "right") {
|
||||
var availableWidth = root.width - root.barMarginH - root.barHeight;
|
||||
calculatedX = (availableWidth - panelWidth) / 2;
|
||||
var availableWidth = root.width - (root.isFramed ? 0 : root.barMarginH) - root.barHeight - (root.isFramed ? root.frameThickness : 0);
|
||||
calculatedX = (root.isFramed ? root.frameThickness : 0) + (availableWidth - panelWidth) / 2;
|
||||
} else {
|
||||
calculatedX = (root.width - panelWidth) / 2;
|
||||
}
|
||||
@@ -410,12 +433,12 @@ Item {
|
||||
var rightCornerInset = Style.radiusL * 2;
|
||||
calculatedX = root.width - root.barMarginH - rightCornerInset - panelWidth;
|
||||
} else {
|
||||
calculatedX = root.width - panelWidth;
|
||||
calculatedX = root.width - panelWidth - (root.isFramed ? root.frameThickness : 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not attached: position at right with margin
|
||||
calculatedX = root.width - panelWidth - Style.marginL;
|
||||
calculatedX = root.width - panelWidth - effMarginR;
|
||||
}
|
||||
} else if (root.panelAnchorLeft) {
|
||||
// Use raw panelAnchorLeft for positioning decision
|
||||
@@ -429,12 +452,12 @@ Item {
|
||||
var leftCornerInset = Style.radiusL * 2;
|
||||
calculatedX = root.barMarginH + leftCornerInset;
|
||||
} else {
|
||||
calculatedX = 0;
|
||||
calculatedX = (root.isFramed ? root.frameThickness : 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Not attached: position at left with margin
|
||||
calculatedX = Style.marginL;
|
||||
calculatedX = effMarginL;
|
||||
}
|
||||
} else {
|
||||
// No explicit anchor: attach to bar if allowAttach, otherwise center
|
||||
@@ -449,19 +472,19 @@ Item {
|
||||
} else {
|
||||
// Not attached: center in available space
|
||||
if (root.barPosition === "left") {
|
||||
var availableStart = root.barMarginH + root.barHeight;
|
||||
var availableWidth = root.width - availableStart - Style.marginL;
|
||||
var availableStart = (root.isFramed ? 0 : root.barMarginH) + root.barHeight;
|
||||
var availableWidth = root.width - availableStart - effMarginR;
|
||||
calculatedX = availableStart + (availableWidth - panelWidth) / 2;
|
||||
} else {
|
||||
var availableWidth = root.width - root.barMarginH - root.barHeight - Style.marginL;
|
||||
calculatedX = Style.marginL + (availableWidth - panelWidth) / 2;
|
||||
var availableWidth = root.width - (root.isFramed ? 0 : root.barMarginH) - root.barHeight - effMarginL;
|
||||
calculatedX = effMarginL + (availableWidth - panelWidth) / 2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (panelContent.allowAttach) {
|
||||
var cornerInset = Style.radiusL + (root.barFloating ? Style.radiusL : 0);
|
||||
var barLeftEdge = root.barMarginH + cornerInset;
|
||||
var barRightEdge = root.width - root.barMarginH - cornerInset;
|
||||
var barLeftEdge = (root.isFramed ? root.frameThickness : root.barMarginH) + cornerInset;
|
||||
var barRightEdge = root.width - (root.isFramed ? root.frameThickness : root.barMarginH) - cornerInset;
|
||||
var centeredX = (root.width - panelWidth) / 2;
|
||||
calculatedX = Math.max(barLeftEdge, Math.min(centeredX, barRightEdge - panelWidth));
|
||||
} else {
|
||||
@@ -473,8 +496,8 @@ Item {
|
||||
|
||||
// Edge snapping for X
|
||||
if (panelContent.allowAttach && !root.barFloating && root.width > 0 && panelWidth > 0) {
|
||||
var leftEdgePos = root.barPosition === "left" ? leftBarEdgeWithOverlap : root.barMarginH;
|
||||
var rightEdgePos = root.barPosition === "right" ? rightBarEdgeWithOverlap - panelWidth : root.width - root.barMarginH - panelWidth;
|
||||
var leftEdgePos = root.barPosition === "left" ? leftBarEdgeWithOverlap : (root.isFramed ? root.frameThickness : root.barMarginH);
|
||||
var rightEdgePos = root.barPosition === "right" ? rightBarEdgeWithOverlap - panelWidth : root.width - (root.isFramed ? root.frameThickness : root.barMarginH) - panelWidth;
|
||||
|
||||
// Only snap to left edge if panel is actually meant to be at left (or no explicit anchor)
|
||||
var shouldSnapToLeft = root.effectivePanelAnchorLeft || (!root.hasExplicitHorizontalAnchor && root.barPosition === "left");
|
||||
@@ -494,30 +517,30 @@ Item {
|
||||
if (panelContent.allowAttach) {
|
||||
calculatedY = topBarEdgeWithOverlap;
|
||||
} else {
|
||||
calculatedY = root.barMarginV + root.barHeight + Style.marginM;
|
||||
calculatedY = (root.isFramed ? 0 : root.barMarginV) + root.barHeight + Style.marginM;
|
||||
}
|
||||
} else if (root.barPosition === "bottom") {
|
||||
if (panelContent.allowAttach) {
|
||||
calculatedY = bottomBarEdgeWithOverlap - panelHeight;
|
||||
} else {
|
||||
calculatedY = root.height - root.barMarginV - root.barHeight - panelHeight - Style.marginM;
|
||||
calculatedY = root.height - (root.isFramed ? 0 : root.barMarginV) - root.barHeight - panelHeight - Style.marginM;
|
||||
}
|
||||
} else if (root.barIsVertical) {
|
||||
var panelY = root.buttonPosition.y + root.buttonHeight / 2 - panelHeight / 2;
|
||||
var extraPadding = (panelContent.allowAttach && root.barFloating) ? Style.radiusL : 0;
|
||||
if (panelContent.allowAttach) {
|
||||
var cornerInset = extraPadding + (root.barFloating ? Style.radiusL : 0);
|
||||
var barTopEdge = root.barMarginV + cornerInset;
|
||||
var barBottomEdge = root.height - root.barMarginV - cornerInset;
|
||||
var barTopEdge = (root.isFramed ? root.frameThickness : root.barMarginV) + cornerInset;
|
||||
var barBottomEdge = root.height - (root.isFramed ? root.frameThickness : root.barMarginV) - cornerInset;
|
||||
panelY = Math.max(barTopEdge, Math.min(panelY, barBottomEdge - panelHeight));
|
||||
} else {
|
||||
panelY = Math.max(Style.marginL + extraPadding, Math.min(panelY, root.height - panelHeight - Style.marginL - extraPadding));
|
||||
panelY = Math.max(effMarginT + extraPadding, Math.min(panelY, root.height - panelHeight - effMarginB - extraPadding));
|
||||
}
|
||||
calculatedY = panelY;
|
||||
}
|
||||
} else {
|
||||
// Standard anchor positioning
|
||||
var barOffset = !panelContent.allowAttach && (root.barPosition === "top" || root.barPosition === "bottom") ? root.barMarginV + root.barHeight + Style.marginM : 0;
|
||||
var barOffset = !panelContent.allowAttach && (root.barPosition === "top" || root.barPosition === "bottom") ? (root.isFramed ? 0 : root.barMarginV) + root.barHeight + Style.marginM : 0;
|
||||
|
||||
if (panelContent.allowAttach && !root.barIsVertical) {
|
||||
// Attached to horizontal bar: position with overlap
|
||||
@@ -532,12 +555,12 @@ Item {
|
||||
if (root.panelAnchorVerticalCenter) {
|
||||
if (!root.barIsVertical) {
|
||||
if (root.barPosition === "top") {
|
||||
var availableStart = root.barMarginV + root.barHeight;
|
||||
var availableHeight = root.height - availableStart;
|
||||
var availableStart = (root.isFramed ? 0 : root.barMarginV) + root.barHeight;
|
||||
var availableHeight = root.height - availableStart - (root.isFramed ? root.frameThickness : 0);
|
||||
calculatedY = availableStart + (availableHeight - panelHeight) / 2;
|
||||
} else if (root.barPosition === "bottom") {
|
||||
var availableHeight = root.height - root.barMarginV - root.barHeight;
|
||||
calculatedY = (availableHeight - panelHeight) / 2;
|
||||
var availableHeight = root.height - (root.isFramed ? 0 : root.barMarginV) - root.barHeight - (root.isFramed ? root.frameThickness : 0);
|
||||
calculatedY = (root.isFramed ? root.frameThickness : 0) + (availableHeight - panelHeight) / 2;
|
||||
} else {
|
||||
calculatedY = (root.height - panelHeight) / 2;
|
||||
}
|
||||
@@ -546,25 +569,25 @@ Item {
|
||||
}
|
||||
} else if (root.panelAnchorTop) {
|
||||
if (root.effectivePanelAnchorTop) {
|
||||
calculatedY = root.barPosition === "top" ? topBarEdgeWithOverlap : 0;
|
||||
calculatedY = root.barPosition === "top" ? topBarEdgeWithOverlap : (root.isFramed ? root.frameThickness : 0);
|
||||
} else {
|
||||
var topBarOffset = (root.barPosition === "top") ? barOffset : 0;
|
||||
calculatedY = topBarOffset + Style.marginL;
|
||||
calculatedY = topBarOffset + effMarginT;
|
||||
}
|
||||
} else if (root.panelAnchorBottom) {
|
||||
if (root.effectivePanelAnchorBottom) {
|
||||
calculatedY = root.barPosition === "bottom" ? bottomBarEdgeWithOverlap - panelHeight : root.height - panelHeight;
|
||||
calculatedY = root.barPosition === "bottom" ? bottomBarEdgeWithOverlap - panelHeight : root.height - panelHeight - (root.isFramed ? root.frameThickness : 0);
|
||||
} else {
|
||||
var bottomBarOffset = (root.barPosition === "bottom") ? barOffset : 0;
|
||||
calculatedY = root.height - panelHeight - bottomBarOffset - Style.marginL;
|
||||
calculatedY = root.height - panelHeight - bottomBarOffset - effMarginB;
|
||||
}
|
||||
} else {
|
||||
// No explicit vertical anchor
|
||||
if (root.barIsVertical) {
|
||||
if (panelContent.allowAttach) {
|
||||
var cornerInset = root.barFloating ? Style.radiusL * 2 : 0;
|
||||
var barTopEdge = root.barMarginV + cornerInset;
|
||||
var barBottomEdge = root.height - root.barMarginV - cornerInset;
|
||||
var barTopEdge = (root.isFramed ? root.frameThickness : root.barMarginV) + cornerInset;
|
||||
var barBottomEdge = root.height - (root.isFramed ? root.frameThickness : root.barMarginV) - cornerInset;
|
||||
var centeredY = (root.height - panelHeight) / 2;
|
||||
calculatedY = Math.max(barTopEdge, Math.min(centeredY, barBottomEdge - panelHeight));
|
||||
} else {
|
||||
@@ -573,11 +596,11 @@ Item {
|
||||
} else {
|
||||
// Horizontal bar, not attached
|
||||
if (root.barPosition === "top") {
|
||||
calculatedY = barOffset + Style.marginL;
|
||||
calculatedY = barOffset + effMarginT;
|
||||
} else if (root.barPosition === "bottom") {
|
||||
calculatedY = Style.marginL;
|
||||
calculatedY = effMarginT;
|
||||
} else {
|
||||
calculatedY = Style.marginL;
|
||||
calculatedY = effMarginT;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -586,8 +609,8 @@ Item {
|
||||
|
||||
// Edge snapping for Y
|
||||
if (panelContent.allowAttach && !root.barFloating && root.height > 0 && panelHeight > 0) {
|
||||
var topEdgePos = root.barPosition === "top" ? topBarEdgeWithOverlap : root.barMarginV;
|
||||
var bottomEdgePos = root.barPosition === "bottom" ? bottomBarEdgeWithOverlap - panelHeight : root.height - root.barMarginV - panelHeight;
|
||||
var topEdgePos = root.barPosition === "top" ? topBarEdgeWithOverlap : (root.isFramed ? root.frameThickness : root.barMarginV);
|
||||
var bottomEdgePos = root.barPosition === "bottom" ? bottomBarEdgeWithOverlap - panelHeight : root.height - (root.isFramed ? root.frameThickness : root.barMarginV) - panelHeight;
|
||||
|
||||
// Only snap to top edge if panel is actually meant to be at top (or no explicit anchor)
|
||||
var shouldSnapToTop = root.effectivePanelAnchorTop || (!root.hasExplicitVerticalAnchor && root.barPosition === "top");
|
||||
@@ -755,16 +778,16 @@ Item {
|
||||
}
|
||||
|
||||
// Edge detection - detect if panel is touching screen edges
|
||||
readonly property bool touchingLeftEdge: allowAttach && panelBackground.x <= 1
|
||||
readonly property bool touchingRightEdge: allowAttach && (panelBackground.x + panelBackground.width) >= (root.width - 1)
|
||||
readonly property bool touchingTopEdge: allowAttach && panelBackground.y <= 1
|
||||
readonly property bool touchingBottomEdge: allowAttach && (panelBackground.y + panelBackground.height) >= (root.height - 1)
|
||||
readonly property bool touchingLeftEdge: allowAttach && panelBackground.x <= (isFramed ? frameThickness + 1 : 1)
|
||||
readonly property bool touchingRightEdge: allowAttach && (panelBackground.x + panelBackground.width) >= (root.width - (isFramed ? frameThickness + 1 : 1))
|
||||
readonly property bool touchingTopEdge: allowAttach && panelBackground.y <= (isFramed ? frameThickness + 1 : 1)
|
||||
readonly property bool touchingBottomEdge: allowAttach && (panelBackground.y + panelBackground.height) >= (root.height - (isFramed ? frameThickness + 1 : 1))
|
||||
|
||||
// Bar edge detection - detect if panel is touching bar edges (for cases where centered panels snap to bar due to height constraints)
|
||||
readonly property bool touchingTopBar: allowAttachToBar && root.barPosition === "top" && !root.barIsVertical && Math.abs(panelBackground.y - (root.barMarginV + root.barHeight)) <= 1
|
||||
readonly property bool touchingBottomBar: allowAttachToBar && root.barPosition === "bottom" && !root.barIsVertical && Math.abs((panelBackground.y + panelBackground.height) - (root.height - root.barMarginV - root.barHeight)) <= 1
|
||||
readonly property bool touchingLeftBar: allowAttachToBar && root.barPosition === "left" && root.barIsVertical && Math.abs(panelBackground.x - (root.barMarginH + root.barHeight)) <= 1
|
||||
readonly property bool touchingRightBar: allowAttachToBar && root.barPosition === "right" && root.barIsVertical && Math.abs((panelBackground.x + panelBackground.width) - (root.width - root.barMarginH - root.barHeight)) <= 1
|
||||
readonly property bool touchingTopBar: allowAttachToBar && root.barPosition === "top" && !root.barIsVertical && Math.abs(panelBackground.y - ((isFramed ? 0 : root.barMarginV) + root.barHeight)) <= 1
|
||||
readonly property bool touchingBottomBar: allowAttachToBar && root.barPosition === "bottom" && !root.barIsVertical && Math.abs((panelBackground.y + panelBackground.height) - (root.height - (isFramed ? 0 : root.barMarginV) - root.barHeight)) <= 1
|
||||
readonly property bool touchingLeftBar: allowAttachToBar && root.barPosition === "left" && root.barIsVertical && Math.abs(panelBackground.x - ((isFramed ? 0 : root.barMarginH) + root.barHeight)) <= 1
|
||||
readonly property bool touchingRightBar: allowAttachToBar && root.barPosition === "right" && root.barIsVertical && Math.abs((panelBackground.x + panelBackground.width) - (root.width - (isFramed ? 0 : root.barMarginH) - root.barHeight)) <= 1
|
||||
|
||||
// Expose panelBackground for geometry placeholder
|
||||
property alias geometryPlaceholder: panelBackground
|
||||
@@ -792,31 +815,31 @@ Item {
|
||||
readonly property bool willTouchTopBar: {
|
||||
if (!panelContent.allowAttachToBar || root.barPosition !== "top" || root.barIsVertical)
|
||||
return false;
|
||||
var targetTopBarY = root.barMarginV + root.barHeight;
|
||||
var targetTopBarY = (isFramed ? 0 : root.barMarginV) + root.barHeight;
|
||||
return Math.abs(panelBackground.targetY - targetTopBarY) <= 1;
|
||||
}
|
||||
readonly property bool willTouchBottomBar: {
|
||||
if (!panelContent.allowAttachToBar || root.barPosition !== "bottom" || root.barIsVertical)
|
||||
return false;
|
||||
var targetBottomBarY = root.height - root.barMarginV - root.barHeight - panelBackground.targetHeight;
|
||||
var targetBottomBarY = root.height - (isFramed ? 0 : root.barMarginV) - root.barHeight - panelBackground.targetHeight;
|
||||
return Math.abs(panelBackground.targetY - targetBottomBarY) <= 1;
|
||||
}
|
||||
readonly property bool willTouchLeftBar: {
|
||||
if (!panelContent.allowAttachToBar || root.barPosition !== "left" || !root.barIsVertical)
|
||||
return false;
|
||||
var targetLeftBarX = root.barMarginH + root.barHeight;
|
||||
var targetLeftBarX = (isFramed ? 0 : root.barMarginH) + root.barHeight;
|
||||
return Math.abs(panelBackground.targetX - targetLeftBarX) <= 1;
|
||||
}
|
||||
readonly property bool willTouchRightBar: {
|
||||
if (!panelContent.allowAttachToBar || root.barPosition !== "right" || !root.barIsVertical)
|
||||
return false;
|
||||
var targetRightBarX = root.width - root.barMarginH - root.barHeight - panelBackground.targetWidth;
|
||||
var targetRightBarX = root.width - (isFramed ? 0 : root.barMarginH) - root.barHeight - panelBackground.targetWidth;
|
||||
return Math.abs(panelBackground.targetX - targetRightBarX) <= 1;
|
||||
}
|
||||
readonly property bool willTouchTopEdge: panelContent.allowAttach && panelBackground.targetY <= 1
|
||||
readonly property bool willTouchBottomEdge: panelContent.allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1)
|
||||
readonly property bool willTouchLeftEdge: panelContent.allowAttach && panelBackground.targetX <= 1
|
||||
readonly property bool willTouchRightEdge: panelContent.allowAttach && (panelBackground.targetX + panelBackground.targetWidth) >= (root.width - 1)
|
||||
readonly property bool willTouchTopEdge: panelContent.allowAttach && panelBackground.targetY <= (isFramed ? frameThickness + 1 : 1)
|
||||
readonly property bool willTouchBottomEdge: panelContent.allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - (isFramed ? frameThickness + 1 : 1))
|
||||
readonly property bool willTouchLeftEdge: panelContent.allowAttach && panelBackground.targetX <= (isFramed ? frameThickness + 1 : 1)
|
||||
readonly property bool willTouchRightEdge: panelContent.allowAttach && (panelBackground.targetX + panelBackground.targetWidth) >= (root.width - (isFramed ? frameThickness + 1 : 1))
|
||||
|
||||
readonly property bool isActuallyAttachedToAnyEdge: {
|
||||
return willTouchTopBar || willTouchBottomBar || willTouchLeftBar || willTouchRightBar || willTouchTopEdge || willTouchBottomEdge || willTouchLeftEdge || willTouchRightEdge;
|
||||
|
||||
@@ -80,34 +80,37 @@ Variants {
|
||||
readonly property bool isFloating: Settings.data.bar.floating
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(notifWindow.screen?.name)
|
||||
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 8
|
||||
|
||||
readonly property int notifWidth: Math.round(440 * Style.uiScaleRatio)
|
||||
readonly property int shadowPadding: Style.shadowBlurMax + Style.marginL
|
||||
|
||||
// Calculate bar offsets for each edge separately
|
||||
// Calculate bar and frame offsets for each edge separately
|
||||
readonly property int barOffsetTop: {
|
||||
if (barPos !== "top")
|
||||
return 0;
|
||||
return isFramed ? frameThickness : 0;
|
||||
const floatMarginV = isFloating ? Math.ceil(Settings.data.bar.marginVertical) : 0;
|
||||
return barHeight + floatMarginV;
|
||||
}
|
||||
|
||||
readonly property int barOffsetBottom: {
|
||||
if (barPos !== "bottom")
|
||||
return 0;
|
||||
return isFramed ? frameThickness : 0;
|
||||
const floatMarginV = isFloating ? Math.ceil(Settings.data.bar.marginVertical) : 0;
|
||||
return barHeight + floatMarginV;
|
||||
}
|
||||
|
||||
readonly property int barOffsetLeft: {
|
||||
if (barPos !== "left")
|
||||
return 0;
|
||||
return isFramed ? frameThickness : 0;
|
||||
const floatMarginH = isFloating ? Math.ceil(Settings.data.bar.marginHorizontal) : 0;
|
||||
return barHeight + floatMarginH;
|
||||
}
|
||||
|
||||
readonly property int barOffsetRight: {
|
||||
if (barPos !== "right")
|
||||
return 0;
|
||||
return isFramed ? frameThickness : 0;
|
||||
const floatMarginH = isFloating ? Math.ceil(Settings.data.bar.marginHorizontal) : 0;
|
||||
return barHeight + floatMarginH;
|
||||
}
|
||||
@@ -120,7 +123,7 @@ Variants {
|
||||
|
||||
// Margins for PanelWindow - only apply bar offset for the specific edge where the bar is
|
||||
margins.top: isTop ? barOffsetTop - shadowPadding + Style.marginM : 0
|
||||
margins.bottom: isBottom ? barOffsetBottom - shadowPadding + Style.marginM : 0
|
||||
margins.bottom: isBottom ? barOffsetBottom - shadowPadding : 0
|
||||
margins.left: isLeft ? barOffsetLeft - shadowPadding + Style.marginM : 0
|
||||
margins.right: isRight ? barOffsetRight - shadowPadding + Style.marginM : 0
|
||||
|
||||
@@ -233,13 +236,12 @@ Variants {
|
||||
height: 2
|
||||
color: "transparent"
|
||||
|
||||
readonly property real availableWidth: parent.width - (2 * parent.radius)
|
||||
|
||||
Rectangle {
|
||||
id: progressBar
|
||||
readonly property real progressWidth: cardBackground.width - (2 * cardBackground.radius)
|
||||
height: parent.height
|
||||
x: parent.parent.radius + (parent.availableWidth * (1 - model.progress)) / 2
|
||||
width: parent.availableWidth * model.progress
|
||||
x: cardBackground.radius + (progressWidth * (1 - model.progress)) / 2
|
||||
width: progressWidth * model.progress
|
||||
|
||||
color: {
|
||||
var baseColor = model.urgency === 2 ? Color.mError : model.urgency === 0 ? Color.mOnSurface : Color.mPrimary;
|
||||
|
||||
@@ -422,6 +422,8 @@ Variants {
|
||||
|
||||
readonly property string screenBarPosition: Settings.getBarPositionForScreen(root.modelData?.name)
|
||||
readonly property real barHeight: Style.getBarHeightForScreen(root.modelData?.name)
|
||||
readonly property bool isFramed: Settings.data.bar.barType === "framed"
|
||||
readonly property real frameThickness: Settings.data.bar.frameThickness ?? 8
|
||||
|
||||
function calculateMargin(isAnchored, position) {
|
||||
if (!isAnchored)
|
||||
@@ -433,6 +435,11 @@ Variants {
|
||||
const floatExtra = Math.ceil(Settings.data.bar.floating ? (isVertical ? Settings.data.bar.marginVertical : Settings.data.bar.marginHorizontal) : 0);
|
||||
return barHeight + base + floatExtra;
|
||||
}
|
||||
|
||||
if (isFramed) {
|
||||
return base + frameThickness;
|
||||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
|
||||
@@ -339,8 +339,6 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// Tab Bar
|
||||
|
||||
// Content Stack
|
||||
StackLayout {
|
||||
Layout.fillWidth: true
|
||||
@@ -349,14 +347,16 @@ SmartPanel {
|
||||
|
||||
// Applications Tab (Volume)
|
||||
NScrollView {
|
||||
id: volumeScrollView
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
contentWidth: availableWidth
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
ColumnLayout {
|
||||
spacing: Style.marginM
|
||||
width: parent.width
|
||||
width: volumeScrollView.availableWidth
|
||||
|
||||
// Output Volume
|
||||
NBox {
|
||||
@@ -801,15 +801,17 @@ SmartPanel {
|
||||
|
||||
// Devices Tab
|
||||
NScrollView {
|
||||
id: devicesScrollView
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
contentWidth: availableWidth
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
// AudioService Devices
|
||||
ColumnLayout {
|
||||
spacing: Style.marginM
|
||||
width: parent.width
|
||||
width: devicesScrollView.availableWidth
|
||||
|
||||
// -------------------------------
|
||||
// Output Devices
|
||||
|
||||
@@ -34,128 +34,34 @@ SmartPanel {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Helper function to find battery device by nativePath
|
||||
function findBatteryDevice(nativePath) {
|
||||
if (!nativePath || nativePath === "") {
|
||||
return UPower.displayDevice;
|
||||
}
|
||||
|
||||
if (!UPower.devices) {
|
||||
return UPower.displayDevice;
|
||||
}
|
||||
|
||||
var deviceArray = UPower.devices.values || [];
|
||||
for (var i = 0; i < deviceArray.length; i++) {
|
||||
var device = deviceArray[i];
|
||||
if (device && device.nativePath === nativePath) {
|
||||
if (device.type === UPowerDeviceType.LinePower) {
|
||||
continue;
|
||||
}
|
||||
if (device.percentage !== undefined) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
}
|
||||
return UPower.displayDevice;
|
||||
}
|
||||
|
||||
// Helper function to find Bluetooth device by MAC address from nativePath
|
||||
function findBluetoothDevice(nativePath) {
|
||||
if (!nativePath || !BluetoothService.devices) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var macMatch = nativePath.match(/([0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2}:[0-9a-fA-F]{2})/);
|
||||
if (!macMatch) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var macAddress = macMatch[1].toUpperCase();
|
||||
var deviceArray = BluetoothService.devices.values || [];
|
||||
|
||||
for (var i = 0; i < deviceArray.length; i++) {
|
||||
var device = deviceArray[i];
|
||||
if (device && device.address && device.address.toUpperCase() === macAddress) {
|
||||
return device;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
readonly property string deviceNativePath: getBatteryDevicePath()
|
||||
readonly property var battery: findBatteryDevice(deviceNativePath)
|
||||
readonly property var bluetoothDevice: deviceNativePath ? findBluetoothDevice(deviceNativePath) : null
|
||||
readonly property bool hasBluetoothBattery: bluetoothDevice && bluetoothDevice.batteryAvailable && bluetoothDevice.battery !== undefined
|
||||
readonly property bool isBluetoothConnected: bluetoothDevice && bluetoothDevice.connected !== undefined ? bluetoothDevice.connected : false
|
||||
|
||||
// Check if device is actually present/connected
|
||||
readonly property bool isDevicePresent: {
|
||||
if (deviceNativePath && deviceNativePath !== "") {
|
||||
if (bluetoothDevice) {
|
||||
return isBluetoothConnected;
|
||||
}
|
||||
if (battery && battery.nativePath === deviceNativePath) {
|
||||
if (battery.type === UPowerDeviceType.Battery && battery.isPresent !== undefined) {
|
||||
return battery.isPresent;
|
||||
}
|
||||
return battery.ready && battery.percentage !== undefined && (battery.percentage > 0 || battery.state === UPowerDeviceState.Charging);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (battery) {
|
||||
if (battery.type === UPowerDeviceType.Battery && battery.isPresent !== undefined) {
|
||||
return battery.isPresent;
|
||||
}
|
||||
return battery.ready && battery.percentage !== undefined;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Use the centralized helper to find the specific device or fallback to primary
|
||||
readonly property var selectedDevice: BatteryService.resolveDevice(deviceNativePath)
|
||||
|
||||
readonly property bool isReady: battery && battery.ready && isDevicePresent && (battery.percentage !== undefined || hasBluetoothBattery)
|
||||
readonly property int percent: isReady ? Math.round(hasBluetoothBattery ? (bluetoothDevice.battery * 100) : (battery.percentage * 100)) : -1
|
||||
readonly property bool isCharging: isReady ? battery.state === UPowerDeviceState.Charging : false
|
||||
readonly property bool isPluggedIn: isReady ? (battery.state === UPowerDeviceState.FullyCharged || battery.state === UPowerDeviceState.PendingCharge) : false
|
||||
readonly property bool healthAvailable: (isReady && battery.healthSupported) || BatteryService.healthAvailable
|
||||
readonly property int healthPercent: (isReady && battery.healthSupported) ? Math.round(battery.healthPercentage) : BatteryService.healthPercent
|
||||
// Check if selected device is actually present/connected
|
||||
readonly property bool isDevicePresent: BatteryService.isDevicePresent(selectedDevice)
|
||||
readonly property bool isReady: BatteryService.isDeviceReady(selectedDevice)
|
||||
|
||||
function getDeviceName() {
|
||||
if (!isReady) {
|
||||
return "";
|
||||
}
|
||||
// Don't show name for laptop batteries
|
||||
if (battery && battery.isLaptopBattery) {
|
||||
return "";
|
||||
}
|
||||
if (bluetoothDevice && bluetoothDevice.name) {
|
||||
return bluetoothDevice.name;
|
||||
}
|
||||
if (battery && battery.model) {
|
||||
return battery.model;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
readonly property int percent: isReady ? Math.round(BatteryService.getPercentage(selectedDevice)) : -1
|
||||
readonly property bool isCharging: BatteryService.isCharging(selectedDevice)
|
||||
readonly property bool isPluggedIn: BatteryService.isPluggedIn(selectedDevice)
|
||||
|
||||
readonly property string deviceName: getDeviceName()
|
||||
readonly property bool isLaptopBattery: selectedDevice && !BatteryService.isBluetoothDevice(selectedDevice)
|
||||
|
||||
readonly property bool healthAvailable: (isReady && isLaptopBattery && selectedDevice.healthSupported) || (isLaptopBattery && BatteryService.healthAvailable)
|
||||
readonly property int healthPercent: (isReady && isLaptopBattery && selectedDevice.healthSupported) ? Math.round(selectedDevice.healthPercentage) : BatteryService.healthPercent
|
||||
|
||||
readonly property string deviceName: BatteryService.getDeviceName(selectedDevice)
|
||||
readonly property string panelTitle: deviceName ? `${I18n.tr("common.battery")} - ${deviceName}` : I18n.tr("common.battery")
|
||||
|
||||
readonly property string timeText: {
|
||||
if (!isReady || !isDevicePresent)
|
||||
return I18n.tr("battery.no-battery-detected");
|
||||
if (isPluggedIn) {
|
||||
return I18n.tr("battery.plugged-in");
|
||||
}
|
||||
if (battery.timeToFull > 0) {
|
||||
return I18n.tr("battery.time-until-full", {
|
||||
"time": Time.formatVagueHumanReadableDuration(battery.timeToFull)
|
||||
});
|
||||
}
|
||||
if (battery.timeToEmpty > 0) {
|
||||
return I18n.tr("battery.time-left", {
|
||||
"time": Time.formatVagueHumanReadableDuration(battery.timeToEmpty)
|
||||
});
|
||||
}
|
||||
return I18n.tr("common.idle");
|
||||
}
|
||||
// Use the centralized list of all devices
|
||||
readonly property var allDevices: BatteryService.devices
|
||||
|
||||
readonly property var laptopBatteries: BatteryService.laptopBatteries
|
||||
readonly property var otherDevices: BatteryService.externalBatteries
|
||||
|
||||
readonly property string timeText: BatteryService.getTimeRemainingText(selectedDevice)
|
||||
readonly property string iconName: BatteryService.getIcon(percent, isCharging, isPluggedIn, isReady)
|
||||
|
||||
property var batteryWidgetInstance: BarService.lookupWidget("Battery", screen ? screen.name : null)
|
||||
@@ -262,95 +168,196 @@ SmartPanel {
|
||||
NBox {
|
||||
Layout.fillWidth: true
|
||||
implicitHeight: chargeLayout.implicitHeight + Style.marginL * 2
|
||||
visible: isReady
|
||||
visible: allDevices.length > 0
|
||||
|
||||
ColumnLayout {
|
||||
id: chargeLayout
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginL
|
||||
spacing: Style.marginS
|
||||
spacing: Style.marginL
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
// Laptop batteries section
|
||||
Repeater {
|
||||
model: laptopBatteries
|
||||
delegate: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
|
||||
ColumnLayout {
|
||||
NText {
|
||||
text: I18n.tr("battery.battery-level")
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
|
||||
RowLayout {
|
||||
NIcon {
|
||||
color: (isCharging || isPluggedIn) ? Color.mPrimary : Color.mOnSurface
|
||||
icon: iconName
|
||||
}
|
||||
|
||||
NText {
|
||||
readonly property string dName: BatteryService.getDeviceName(modelData)
|
||||
text: dName ? dName : I18n.tr("common.battery")
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: Math.round(8 * Style.uiScaleRatio)
|
||||
radius: Math.min(Style.radiusL, height / 2)
|
||||
color: Color.mSurface
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
width: {
|
||||
var p = BatteryService.getPercentage(modelData);
|
||||
var ratio = Math.max(0, Math.min(1, p / 100));
|
||||
return parent.width * ratio;
|
||||
}
|
||||
color: Color.mPrimary
|
||||
}
|
||||
}
|
||||
NText {
|
||||
Layout.preferredWidth: 40 * Style.uiScaleRatio
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: `${Math.round(BatteryService.getPercentage(modelData))}%`
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
// Health for this specific laptop battery
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
height: Math.round(8 * Style.uiScaleRatio)
|
||||
radius: Math.min(Style.radiusL, height / 2)
|
||||
color: Color.mSurfaceVariant
|
||||
spacing: Style.marginS
|
||||
visible: modelData.healthSupported || (modelData === BatteryService.primaryDevice && BatteryService.healthAvailable)
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
width: {
|
||||
var ratio = Math.max(0, Math.min(1, percent / 100));
|
||||
return parent.width * ratio;
|
||||
NIcon {
|
||||
icon: "heart"
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("battery.battery-health")
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
height: Math.round(8 * Style.uiScaleRatio)
|
||||
radius: height / 2
|
||||
color: Color.mSurface
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
width: {
|
||||
var h = modelData.healthSupported ? modelData.healthPercentage : (modelData === BatteryService.primaryDevice ? BatteryService.healthPercent : 0);
|
||||
if (h <= 0)
|
||||
return 0;
|
||||
var ratio = Math.max(0, Math.min(1, h / 100));
|
||||
return parent.width * ratio;
|
||||
}
|
||||
color: {
|
||||
var h = modelData.healthSupported ? modelData.healthPercentage : (modelData === BatteryService.primaryDevice ? BatteryService.healthPercent : 0);
|
||||
return h >= 80 ? Color.mPrimary : (h >= 50 ? Color.mTertiary : Color.mError);
|
||||
}
|
||||
}
|
||||
}
|
||||
NText {
|
||||
Layout.preferredWidth: 40 * Style.uiScaleRatio
|
||||
horizontalAlignment: Text.AlignRight
|
||||
|
||||
readonly property int h: modelData.healthSupported ? Math.round(modelData.healthPercentage) : (modelData === BatteryService.primaryDevice ? BatteryService.healthPercent : -1)
|
||||
text: h >= 0 ? `${h}%` : "--"
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
color: Color.mPrimary
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: percent >= 0 ? `${percent}%` : "--"
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
visible: healthAvailable
|
||||
visible: laptopBatteries.length > 0 && otherDevices.length > 0
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
// Other devices (Bluetooth) section
|
||||
Repeater {
|
||||
model: otherDevices
|
||||
delegate: ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
RowLayout {
|
||||
spacing: Style.marginXS
|
||||
Layout.fillWidth: true
|
||||
spacing: Style.marginS
|
||||
|
||||
NIcon {
|
||||
icon: BluetoothService.getDeviceIcon(modelData)
|
||||
}
|
||||
|
||||
NText {
|
||||
text: I18n.tr("battery.battery-health")
|
||||
readonly property string dName: BatteryService.getDeviceName(modelData)
|
||||
text: dName ? dName : I18n.tr("common.bluetooth")
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
height: Math.round(8 * Style.uiScaleRatio)
|
||||
radius: Math.min(Style.radiusL, height / 2)
|
||||
color: Color.mSurfaceVariant
|
||||
spacing: Style.marginS
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
width: {
|
||||
if (!healthAvailable || healthPercent <= 0)
|
||||
return 0;
|
||||
var ratio = Math.max(0, Math.min(1, healthPercent / 100));
|
||||
return parent.width * ratio;
|
||||
Layout.fillWidth: true
|
||||
height: Math.round(8 * Style.uiScaleRatio)
|
||||
radius: Math.min(Style.radiusL, height / 2)
|
||||
color: Color.mSurface
|
||||
|
||||
Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
height: parent.height
|
||||
radius: parent.radius
|
||||
width: {
|
||||
var p = BatteryService.getPercentage(modelData);
|
||||
var ratio = Math.max(0, Math.min(1, p / 100));
|
||||
return parent.width * ratio;
|
||||
}
|
||||
color: Color.mPrimary
|
||||
}
|
||||
color: healthPercent >= 80 ? Color.mPrimary : (healthPercent >= 50 ? Color.mTertiary : Color.mError)
|
||||
}
|
||||
NText {
|
||||
Layout.preferredWidth: 40 * Style.uiScaleRatio
|
||||
horizontalAlignment: Text.AlignRight
|
||||
text: `${Math.round(BatteryService.getPercentage(modelData))}%`
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NText {
|
||||
text: healthPercent >= 0 ? `${healthPercent}%` : "--"
|
||||
color: Color.mOnSurface
|
||||
pointSize: Style.fontSizeS
|
||||
font.weight: Style.fontWeightBold
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -429,7 +436,7 @@ SmartPanel {
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
visible: showPowerProfiles && showNoctaliaPerformance
|
||||
visible: showPowerProfiles && PowerProfileService.available && showNoctaliaPerformance
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
|
||||
@@ -218,12 +218,6 @@ NBox {
|
||||
enabled: (canConnect || canDisconnect || canPair) && !isBusy
|
||||
outlined: !button.hovered
|
||||
fontSize: Style.fontSizeS
|
||||
backgroundColor: {
|
||||
if (device.canDisconnect && !isBusy) {
|
||||
return Color.mError;
|
||||
}
|
||||
return Color.mPrimary;
|
||||
}
|
||||
tooltipText: root.tooltipText
|
||||
text: {
|
||||
if (modelData.pairing) {
|
||||
|
||||
@@ -90,15 +90,17 @@ SmartPanel {
|
||||
}
|
||||
|
||||
NScrollView {
|
||||
id: bluetoothScrollView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
ColumnLayout {
|
||||
id: devicesList
|
||||
width: parent.width
|
||||
width: bluetoothScrollView.availableWidth
|
||||
spacing: Style.marginM
|
||||
|
||||
// Adapter not available of disabled
|
||||
|
||||
@@ -75,17 +75,19 @@ SmartPanel {
|
||||
}
|
||||
|
||||
NScrollView {
|
||||
id: brightnessScrollView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
contentWidth: availableWidth
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
// AudioService Devices
|
||||
ColumnLayout {
|
||||
spacing: Style.marginM
|
||||
width: parent.width
|
||||
width: brightnessScrollView.availableWidth
|
||||
|
||||
Repeater {
|
||||
model: Quickshell.screens || []
|
||||
|
||||
@@ -126,6 +126,7 @@ SmartPanel {
|
||||
}
|
||||
|
||||
NScrollView {
|
||||
id: changelogScrollView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
@@ -133,7 +134,7 @@ SmartPanel {
|
||||
padding: 0
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
width: changelogScrollView.availableWidth
|
||||
spacing: Style.marginM
|
||||
|
||||
NText {
|
||||
|
||||
@@ -157,14 +157,14 @@ Item {
|
||||
visible: !isImageContent && !loadingFullContent
|
||||
|
||||
NScrollView {
|
||||
id: clipboardScrollView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
horizontalPolicy: Settings.data.appLauncher.clipboardWrapText ? ScrollBar.AlwaysOff : ScrollBar.AsNeeded
|
||||
|
||||
NText {
|
||||
text: fullContent
|
||||
width: Settings.data.appLauncher.clipboardWrapText ? parent.width : implicitWidth
|
||||
width: Settings.data.appLauncher.clipboardWrapText ? clipboardScrollView.availableWidth : implicitWidth
|
||||
wrapMode: Settings.data.appLauncher.clipboardWrapText ? Text.Wrap : Text.NoWrap
|
||||
textFormat: Text.PlainText
|
||||
font.pointSize: Style.fontSizeM
|
||||
|
||||
@@ -755,6 +755,14 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
SessionProvider {
|
||||
id: sessionProvider
|
||||
Component.onCompleted: {
|
||||
registerProvider(this);
|
||||
Logger.d("Launcher", "Registered: SessionProvider");
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------
|
||||
panelContent: Rectangle {
|
||||
id: ui
|
||||
@@ -877,8 +885,8 @@ SmartPanel {
|
||||
|
||||
RowLayout {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Style.marginL // Apply overall margins here
|
||||
spacing: Style.marginM // Apply spacing between elements here
|
||||
anchors.margins: Style.marginL
|
||||
spacing: Style.marginM
|
||||
|
||||
// Left Pane
|
||||
ColumnLayout {
|
||||
@@ -992,6 +1000,8 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// LIST VIEW
|
||||
Component {
|
||||
id: listViewComponent
|
||||
NListView {
|
||||
@@ -999,6 +1009,9 @@ SmartPanel {
|
||||
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AlwaysOff
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
wheelScrollMultiplier: 4.0
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
@@ -1031,7 +1044,7 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
width: resultsList.width
|
||||
width: resultsList.availableWidth
|
||||
implicitHeight: entryHeight
|
||||
clip: true
|
||||
color: entry.isSelected ? Color.mHover : Color.mSurface
|
||||
@@ -1271,6 +1284,8 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// SINGLE ITEM VIEW, ex: kaggi
|
||||
Component {
|
||||
id: singleViewComponent
|
||||
|
||||
@@ -1300,17 +1315,17 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
ScrollView {
|
||||
NScrollView {
|
||||
id: descriptionScrollView
|
||||
Layout.alignment: Qt.AlignTop | Qt.AlignLeft
|
||||
Layout.topMargin: Style.fontSizeL + Style.marginXL
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
clip: true
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
contentWidth: availableWidth
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
reserveScrollbarSpace: false
|
||||
|
||||
NText {
|
||||
width: parent.width
|
||||
width: descriptionScrollView.availableWidth
|
||||
text: root.results.length > 0 ? root.results[0].description : ""
|
||||
pointSize: Style.fontSizeM
|
||||
font.weight: Font.Bold
|
||||
@@ -1326,6 +1341,8 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// GRID VIEW
|
||||
Component {
|
||||
id: gridViewComponent
|
||||
NGridView {
|
||||
@@ -1333,6 +1350,9 @@ SmartPanel {
|
||||
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AlwaysOff
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: "transparent" //Color.mSurface
|
||||
wheelScrollMultiplier: 4.0
|
||||
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
|
||||
@@ -443,11 +443,12 @@ Item {
|
||||
return [];
|
||||
|
||||
// Set category mode based on whether there's a query
|
||||
showsCategories = !query || query.trim() === "";
|
||||
const isSearching = !!(query && query.trim() !== "");
|
||||
showsCategories = !isSearching;
|
||||
|
||||
// Filter by category first
|
||||
// Filter by category only when NOT searching
|
||||
let filteredEntries = entries;
|
||||
if (selectedCategory && selectedCategory !== "all") {
|
||||
if (!isSearching && selectedCategory && selectedCategory !== "all") {
|
||||
filteredEntries = entries.filter(app => appMatchesCategory(app, selectedCategory));
|
||||
}
|
||||
|
||||
@@ -543,7 +544,7 @@ Item {
|
||||
"description": app.genericName || app.comment || "",
|
||||
"icon": app.icon || "application-x-executable",
|
||||
"isImage": false,
|
||||
"_score": (score !== undefined ? score : 0) + 1,
|
||||
"_score": (score !== undefined ? score : 0),
|
||||
"provider": root,
|
||||
"onActivate": function () {
|
||||
// Close the launcher/SmartPanel immediately without any animations.
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.Compositor
|
||||
import qs.Services.UI
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
// Provider metadata
|
||||
property string name: I18n.tr("tooltips.session-menu")
|
||||
property var launcher: null
|
||||
property bool handleSearch: true
|
||||
property string supportedLayouts: "list"
|
||||
|
||||
// Session actions with search keywords
|
||||
readonly property var sessionActions: [
|
||||
{
|
||||
"action": "lock",
|
||||
"labelKey": "common.lock",
|
||||
"icon": "lock",
|
||||
"keywords": ["lock", "screen", "secure"]
|
||||
},
|
||||
{
|
||||
"action": "suspend",
|
||||
"labelKey": "common.suspend",
|
||||
"icon": "suspend",
|
||||
"keywords": ["suspend", "sleep", "standby"]
|
||||
},
|
||||
{
|
||||
"action": "hibernate",
|
||||
"labelKey": "common.hibernate",
|
||||
"icon": "hibernate",
|
||||
"keywords": ["hibernate", "disk"]
|
||||
},
|
||||
{
|
||||
"action": "reboot",
|
||||
"labelKey": "common.reboot",
|
||||
"icon": "reboot",
|
||||
"keywords": ["reboot", "restart", "reload"]
|
||||
},
|
||||
{
|
||||
"action": "logout",
|
||||
"labelKey": "common.logout",
|
||||
"icon": "logout",
|
||||
"keywords": ["logout", "sign out", "exit", "leave"]
|
||||
},
|
||||
{
|
||||
"action": "shutdown",
|
||||
"labelKey": "common.shutdown",
|
||||
"icon": "shutdown",
|
||||
"keywords": ["shutdown", "power off", "turn off", "poweroff"]
|
||||
}
|
||||
]
|
||||
|
||||
function init() {
|
||||
Logger.d("SessionProvider", "Initialized");
|
||||
}
|
||||
|
||||
function getEnabledActions() {
|
||||
var powerOptions = Settings.data.sessionMenu.powerOptions || [];
|
||||
var enabledSet = {};
|
||||
|
||||
for (var i = 0; i < powerOptions.length; i++) {
|
||||
if (powerOptions[i].enabled) {
|
||||
enabledSet[powerOptions[i].action] = powerOptions[i];
|
||||
}
|
||||
}
|
||||
|
||||
var enabled = [];
|
||||
for (var j = 0; j < sessionActions.length; j++) {
|
||||
var action = sessionActions[j];
|
||||
if (enabledSet[action.action]) {
|
||||
enabled.push({
|
||||
"action": action.action,
|
||||
"labelKey": action.labelKey,
|
||||
"icon": action.icon,
|
||||
"keywords": action.keywords,
|
||||
"command": enabledSet[action.action].command || ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return enabled;
|
||||
}
|
||||
|
||||
function getResults(query) {
|
||||
if (!query)
|
||||
return [];
|
||||
|
||||
var trimmed = query.trim();
|
||||
if (!trimmed || trimmed.length < 2)
|
||||
return [];
|
||||
|
||||
var enabledActions = getEnabledActions();
|
||||
if (enabledActions.length === 0)
|
||||
return [];
|
||||
|
||||
// Build searchable items with resolved translations
|
||||
var items = [];
|
||||
for (var i = 0; i < enabledActions.length; i++) {
|
||||
var action = enabledActions[i];
|
||||
var label = I18n.tr(action.labelKey);
|
||||
items.push({
|
||||
"action": action.action,
|
||||
"icon": action.icon,
|
||||
"label": label,
|
||||
"command": action.command,
|
||||
"searchText": [label.toLowerCase()].concat(action.keywords).join(" ")
|
||||
});
|
||||
}
|
||||
|
||||
var results = FuzzySort.go(trimmed, items, {
|
||||
"keys": ["label", "searchText"],
|
||||
"limit": 6
|
||||
});
|
||||
|
||||
var launcherItems = [];
|
||||
for (var j = 0; j < results.length; j++) {
|
||||
var entry = results[j].obj;
|
||||
var score = results[j].score;
|
||||
|
||||
launcherItems.push({
|
||||
"name": entry.label,
|
||||
"description": I18n.tr("tooltips.session-menu"),
|
||||
"icon": entry.icon,
|
||||
"isTablerIcon": true,
|
||||
"isImage": false,
|
||||
"_score": score - 1,
|
||||
"provider": root,
|
||||
"onActivate": createActivateHandler(entry.action, entry.command)
|
||||
});
|
||||
}
|
||||
|
||||
return launcherItems;
|
||||
}
|
||||
|
||||
function createActivateHandler(action, command) {
|
||||
return function () {
|
||||
if (launcher)
|
||||
launcher.close();
|
||||
|
||||
Qt.callLater(() => {
|
||||
executeAction(action, command);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function executeAction(action, command) {
|
||||
// If custom command is defined, execute it
|
||||
if (command && command.trim() !== "") {
|
||||
Logger.i("SessionProvider", "Executing custom command for action:", action, "Command:", command);
|
||||
Quickshell.execDetached(["sh", "-lc", command]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, use default behavior
|
||||
switch (action) {
|
||||
case "lock":
|
||||
if (PanelService.lockScreen && !PanelService.lockScreen.active) {
|
||||
PanelService.lockScreen.active = true;
|
||||
}
|
||||
break;
|
||||
case "suspend":
|
||||
if (Settings.data.general.lockOnSuspend) {
|
||||
CompositorService.lockAndSuspend();
|
||||
} else {
|
||||
CompositorService.suspend();
|
||||
}
|
||||
break;
|
||||
case "hibernate":
|
||||
CompositorService.hibernate();
|
||||
break;
|
||||
case "reboot":
|
||||
CompositorService.reboot();
|
||||
break;
|
||||
case "logout":
|
||||
CompositorService.logout();
|
||||
break;
|
||||
case "shutdown":
|
||||
CompositorService.shutdown();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,7 +85,7 @@ Item {
|
||||
"icon": "settings",
|
||||
"isTablerIcon": true,
|
||||
"isImage": false,
|
||||
"_score": score,
|
||||
"_score": score - 2,
|
||||
"provider": root,
|
||||
"onActivate": createActivateHandler(entry)
|
||||
});
|
||||
|
||||
@@ -284,11 +284,12 @@ SmartPanel {
|
||||
Layout.fillHeight: true
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
ColumnLayout {
|
||||
id: contentColumn
|
||||
width: parent.width
|
||||
width: contentScroll.availableWidth
|
||||
spacing: Style.marginM
|
||||
|
||||
// Wi‑Fi disabled state
|
||||
|
||||
@@ -255,15 +255,16 @@ SmartPanel {
|
||||
NScrollView {
|
||||
id: scrollView
|
||||
anchors.fill: parent
|
||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||
clip: true
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
reserveScrollbarSpace: false
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
// Track which notification is expanded
|
||||
property string expandedId: ""
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
width: scrollView.availableWidth
|
||||
spacing: Style.marginM
|
||||
|
||||
// Empty state when no notifications
|
||||
@@ -541,39 +542,6 @@ SmartPanel {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay gradient to smooth the hard cut due to scrolling at the bottom (only visible when scrollable)
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
visible: scrollView.ScrollBar.vertical && scrollView.ScrollBar.vertical.size < 1.0
|
||||
opacity: {
|
||||
const scrollBar = scrollView.ScrollBar.vertical;
|
||||
return (scrollBar.position + scrollBar.size >= 0.99) ? 0 : 1;
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Style.animationFast
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
gradient: Gradient {
|
||||
GradientStop {
|
||||
position: 0.0
|
||||
color: "transparent"
|
||||
}
|
||||
GradientStop {
|
||||
position: 0.85
|
||||
color: "transparent"
|
||||
}
|
||||
GradientStop {
|
||||
position: 1.0
|
||||
color: Qt.alpha(Color.mSurface, 0.95)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -553,8 +553,8 @@ SmartPanel {
|
||||
Repeater {
|
||||
model: powerOptions
|
||||
delegate: LargeButton {
|
||||
Layout.preferredWidth: 200 * Style.uiScaleRatio
|
||||
Layout.preferredHeight: 200 * Style.uiScaleRatio
|
||||
Layout.preferredWidth: Math.round(200 * Style.uiScaleRatio)
|
||||
Layout.preferredHeight: Math.round(200 * Style.uiScaleRatio)
|
||||
icon: modelData.icon
|
||||
title: modelData.title
|
||||
isShutdown: modelData.isShutdown || false
|
||||
@@ -909,6 +909,9 @@ SmartPanel {
|
||||
border.width: Style.borderS
|
||||
border.color: Color.mOutline
|
||||
|
||||
layer.enabled: hoverScale !== 1.0
|
||||
layer.smooth: true
|
||||
|
||||
// Scale transform for hover effect
|
||||
transform: Scale {
|
||||
origin.x: largeButtonRoot.width / 2
|
||||
@@ -958,13 +961,16 @@ SmartPanel {
|
||||
return Color.mOnPrimary;
|
||||
return Color.mOnSurface;
|
||||
}
|
||||
pointSize: Style.fontSizeXXXL * 2
|
||||
width: 80 * Style.uiScaleRatio
|
||||
height: 80 * Style.uiScaleRatio
|
||||
pointSize: Style.fontSizeXXXL * 2.25
|
||||
width: 90 * Style.uiScaleRatio
|
||||
height: 90 * Style.uiScaleRatio
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
|
||||
property real iconScale: (largeButtonRoot.isSelected || largeButtonRoot.effectiveHover) ? 1.1 : 1.0
|
||||
property real iconScale: (largeButtonRoot.isSelected || largeButtonRoot.effectiveHover) ? 1.15 : 1.0
|
||||
|
||||
layer.enabled: iconScale !== 1.0
|
||||
layer.smooth: true
|
||||
|
||||
transform: Scale {
|
||||
origin.x: iconElement.width / 2
|
||||
|
||||
@@ -20,7 +20,7 @@ Popup {
|
||||
|
||||
readonly property real maxHeight: screen ? screen.height * 0.9 : 800
|
||||
|
||||
width: Math.max(content.implicitWidth + padding * 2, 500)
|
||||
width: Math.max(content.implicitWidth + padding * 2, 640)
|
||||
height: Math.min(content.implicitHeight + padding * 2, maxHeight)
|
||||
padding: Style.marginXL
|
||||
modal: true
|
||||
@@ -73,7 +73,7 @@ Popup {
|
||||
NIconButton {
|
||||
icon: "close"
|
||||
tooltipText: I18n.tr("common.close")
|
||||
onClicked: root.close()
|
||||
onClicked: saveAndClose()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +91,10 @@ Popup {
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: 100
|
||||
gradientColor: Color.mSurface
|
||||
|
||||
ColumnLayout {
|
||||
width: scrollView.width
|
||||
width: scrollView.availableWidth
|
||||
spacing: Style.marginM
|
||||
|
||||
// Settings based on widget type
|
||||
@@ -151,26 +152,34 @@ Popup {
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("common.cancel")
|
||||
text: I18n.tr("common.close")
|
||||
outlined: true
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("common.apply")
|
||||
icon: "check"
|
||||
onClicked: {
|
||||
if (settingsLoader.item && settingsLoader.item.saveSettings) {
|
||||
var newSettings = settingsLoader.item.saveSettings();
|
||||
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
onClicked: saveAndClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: settingsLoader.item
|
||||
function onSettingsChanged(newSettings) {
|
||||
if (newSettings) {
|
||||
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings);
|
||||
}
|
||||
}
|
||||
ignoreUnknownSignals: true
|
||||
}
|
||||
|
||||
function saveAndClose() {
|
||||
if (settingsLoader.item && typeof settingsLoader.item.saveSettings === 'function') {
|
||||
var newSettings = settingsLoader.item.saveSettings();
|
||||
if (newSettings) {
|
||||
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings);
|
||||
}
|
||||
}
|
||||
root.close();
|
||||
}
|
||||
|
||||
function loadWidgetSettings() {
|
||||
const source = BarWidgetRegistry.widgetSettingsMap[widgetId];
|
||||
if (source) {
|
||||
|
||||
@@ -12,6 +12,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property bool valueShowIcon: widgetData.showIcon !== undefined ? widgetData.showIcon : widgetMetadata.showIcon
|
||||
property string valueHideMode: "hidden" // Default to 'Hide When Empty'
|
||||
@@ -56,7 +58,10 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: root.valueHideMode
|
||||
onSelected: key => root.valueHideMode = key
|
||||
onSelected: key => {
|
||||
root.valueHideMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
@@ -64,7 +69,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.active-window.show-app-icon-label")
|
||||
description: I18n.tr("bar.active-window.show-app-icon-description")
|
||||
checked: root.valueShowIcon
|
||||
onToggled: checked => root.valueShowIcon = checked
|
||||
onToggled: checked => {
|
||||
root.valueShowIcon = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
@@ -72,7 +80,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.tray.colorize-icons-label")
|
||||
description: I18n.tr("bar.active-window.colorize-icons-description")
|
||||
checked: root.valueColorizeIcons
|
||||
onToggled: checked => root.valueColorizeIcons = checked
|
||||
onToggled: checked => {
|
||||
root.valueColorizeIcons = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
@@ -82,6 +93,7 @@ ColumnLayout {
|
||||
description: I18n.tr("bar.media-mini.max-width-description")
|
||||
placeholderText: widgetMetadata.maxWidth
|
||||
text: valueMaxWidth
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NToggle {
|
||||
@@ -89,7 +101,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.media-mini.use-fixed-width-label")
|
||||
description: I18n.tr("bar.media-mini.use-fixed-width-description")
|
||||
checked: valueUseFixedWidth
|
||||
onToggled: checked => valueUseFixedWidth = checked
|
||||
onToggled: checked => {
|
||||
valueUseFixedWidth = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
@@ -110,7 +125,10 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: valueScrollingMode
|
||||
onSelected: key => valueScrollingMode = key
|
||||
onSelected: key => {
|
||||
valueScrollingMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
minimumWidth: 200
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property bool valueHideWhenIdle: widgetData.hideWhenIdle !== undefined ? widgetData.hideWhenIdle : widgetMetadata.hideWhenIdle
|
||||
property string valueColorName: widgetData.colorName !== undefined ? widgetData.colorName : widgetMetadata.colorName
|
||||
@@ -31,6 +33,7 @@ ColumnLayout {
|
||||
description: I18n.tr("bar.audio-visualizer.width-description")
|
||||
text: widgetData.width || widgetMetadata.width
|
||||
placeholderText: I18n.tr("placeholders.enter-width-pixels")
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
@@ -60,13 +63,19 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: root.valueColorName
|
||||
onSelected: key => root.valueColorName = key
|
||||
onSelected: key => {
|
||||
root.valueColorName = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.audio-visualizer.hide-when-idle-label")
|
||||
description: I18n.tr("bar.audio-visualizer.hide-when-idle-description")
|
||||
checked: valueHideWhenIdle
|
||||
onToggled: checked => valueHideWhenIdle = checked
|
||||
onToggled: checked => {
|
||||
valueHideWhenIdle = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Commons
|
||||
import qs.Services.Hardware
|
||||
import qs.Widgets
|
||||
import qs.Services.Hardware
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
@@ -13,6 +14,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||
property int valueWarningThreshold: widgetData.warningThreshold !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
|
||||
@@ -22,60 +25,7 @@ ColumnLayout {
|
||||
property bool valueHideIfNotDetected: widgetData.hideIfNotDetected !== undefined ? widgetData.hideIfNotDetected : widgetMetadata.hideIfNotDetected
|
||||
property bool valueHideIfIdle: widgetData.hideIfIdle !== undefined ? widgetData.hideIfIdle : widgetMetadata.hideIfIdle
|
||||
|
||||
// Build model of available battery devices
|
||||
function buildDeviceModel() {
|
||||
var model = [
|
||||
{
|
||||
"key": "",
|
||||
"name": I18n.tr("bar.battery.device-default")
|
||||
}
|
||||
];
|
||||
|
||||
if (!UPower.devices) {
|
||||
return model;
|
||||
}
|
||||
|
||||
var deviceArray = UPower.devices.values || [];
|
||||
for (var i = 0; i < deviceArray.length; i++) {
|
||||
var device = deviceArray[i];
|
||||
if (!device || device.type === UPowerDeviceType.LinePower) {
|
||||
continue;
|
||||
}
|
||||
var displayName = device.model || device.nativePath || "Unknown";
|
||||
model.push({
|
||||
"key": device.nativePath || "",
|
||||
"name": displayName
|
||||
});
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
readonly property int _deviceCount: (UPower.devices && UPower.devices.values) ? UPower.devices.values.length : 0
|
||||
property var deviceModel: buildDeviceModel()
|
||||
|
||||
on_DeviceCountChanged: {
|
||||
deviceModel = buildDeviceModel();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: UPower.devices
|
||||
function onValuesChanged() {
|
||||
deviceModel = buildDeviceModel();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: refreshTimer
|
||||
interval: 2000
|
||||
running: true
|
||||
repeat: true
|
||||
onTriggered: {
|
||||
var currentCount = (UPower.devices && UPower.devices.values) ? UPower.devices.values.length : 0;
|
||||
if (currentCount !== root._deviceCount) {
|
||||
deviceModel = buildDeviceModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
property var deviceModel: BatteryService.devicesModel
|
||||
|
||||
function saveSettings() {
|
||||
var settings = Object.assign({}, widgetData || {});
|
||||
@@ -105,10 +55,13 @@ ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.battery.device-label")
|
||||
description: I18n.tr("bar.battery.device-description")
|
||||
minimumWidth: 134
|
||||
minimumWidth: 200
|
||||
model: root.deviceModel
|
||||
currentKey: root.valueDeviceNativePath
|
||||
onSelected: key => root.valueDeviceNativePath = key
|
||||
onSelected: key => {
|
||||
root.valueDeviceNativePath = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
// Update currentKey when model changes to ensure selection is preserved
|
||||
@@ -122,15 +75,17 @@ ColumnLayout {
|
||||
|
||||
NIconButton {
|
||||
icon: "refresh"
|
||||
// TODO i18n
|
||||
tooltipText: "Refresh device list"
|
||||
onClicked: deviceModel = buildDeviceModel()
|
||||
onClicked: BatteryService.devicesModel = BatteryService.buildDeviceModel()
|
||||
}
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.volume.display-mode-label")
|
||||
description: I18n.tr("bar.volume.display-mode-description")
|
||||
minimumWidth: 134
|
||||
minimumWidth: 240
|
||||
model: [
|
||||
{
|
||||
"key": "onhover",
|
||||
@@ -146,7 +101,10 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: root.valueDisplayMode
|
||||
onSelected: key => root.valueDisplayMode = key
|
||||
onSelected: key => {
|
||||
root.valueDisplayMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NSpinBox {
|
||||
@@ -156,34 +114,49 @@ ColumnLayout {
|
||||
suffix: "%"
|
||||
minimum: 5
|
||||
maximum: 50
|
||||
onValueChanged: valueWarningThreshold = value
|
||||
onValueChanged: {
|
||||
valueWarningThreshold = value;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.battery.show-power-profile-label")
|
||||
description: I18n.tr("bar.battery.show-power-profile-description")
|
||||
checked: valueShowPowerProfiles
|
||||
onToggled: checked => valueShowPowerProfiles = checked
|
||||
onToggled: checked => {
|
||||
valueShowPowerProfiles = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.battery.show-noctalia-performance-label")
|
||||
description: I18n.tr("bar.battery.show-noctalia-performance-description")
|
||||
checked: valueShowNoctaliaPerformance
|
||||
onToggled: checked => valueShowNoctaliaPerformance = checked
|
||||
onToggled: checked => {
|
||||
valueShowNoctaliaPerformance = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.battery.hide-if-not-detected-label")
|
||||
description: I18n.tr("bar.battery.hide-if-not-detected-description")
|
||||
checked: valueHideIfNotDetected
|
||||
onToggled: checked => valueHideIfNotDetected = checked
|
||||
onToggled: checked => {
|
||||
valueHideIfNotDetected = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.battery.hide-if-idle-label")
|
||||
description: I18n.tr("bar.battery.hide-if-idle-description")
|
||||
checked: valueHideIfIdle
|
||||
onToggled: checked => valueHideIfIdle = checked
|
||||
onToggled: checked => {
|
||||
valueHideIfIdle = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||
|
||||
@@ -39,6 +41,9 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: root.valueDisplayMode
|
||||
onSelected: key => root.valueDisplayMode = key
|
||||
onSelected: key => {
|
||||
root.valueDisplayMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||
|
||||
@@ -40,6 +42,9 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: valueDisplayMode
|
||||
onSelected: key => valueDisplayMode = key
|
||||
onSelected: key => {
|
||||
valueDisplayMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property bool valueUsePrimaryColor: widgetData.usePrimaryColor !== undefined ? widgetData.usePrimaryColor : widgetMetadata.usePrimaryColor
|
||||
property bool valueUseCustomFont: widgetData.useCustomFont !== undefined ? widgetData.useCustomFont : widgetMetadata.useCustomFont
|
||||
@@ -71,7 +73,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.clock.use-primary-color-label")
|
||||
description: I18n.tr("bar.clock.use-primary-color-description")
|
||||
checked: valueUsePrimaryColor
|
||||
onToggled: checked => valueUsePrimaryColor = checked
|
||||
onToggled: checked => {
|
||||
valueUsePrimaryColor = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
@@ -79,7 +84,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.clock.use-custom-font-label")
|
||||
description: I18n.tr("bar.clock.use-custom-font-description")
|
||||
checked: valueUseCustomFont
|
||||
onToggled: checked => valueUseCustomFont = checked
|
||||
onToggled: checked => {
|
||||
valueUseCustomFont = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NSearchableComboBox {
|
||||
@@ -95,6 +103,7 @@ ColumnLayout {
|
||||
minimumWidth: 300
|
||||
onSelected: function (key) {
|
||||
valueCustomFont = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +138,7 @@ ColumnLayout {
|
||||
placeholderText: "HH:mm ddd, MMM dd"
|
||||
text: valueFormatHorizontal
|
||||
onTextChanged: valueFormatHorizontal = text
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
Component.onCompleted: {
|
||||
if (inputItem) {
|
||||
inputItem.onActiveFocusChanged.connect(function () {
|
||||
@@ -153,6 +163,7 @@ ColumnLayout {
|
||||
placeholderText: "HH mm dd MM"
|
||||
text: valueFormatVertical
|
||||
onTextChanged: valueFormatVertical = text
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
Component.onCompleted: {
|
||||
if (inputItem) {
|
||||
inputItem.onActiveFocusChanged.connect(function () {
|
||||
@@ -172,6 +183,7 @@ ColumnLayout {
|
||||
placeholderText: "HH:mm, ddd MMM dd"
|
||||
text: valueTooltipFormat
|
||||
onTextChanged: valueTooltipFormat = text
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
Component.onCompleted: {
|
||||
if (inputItem) {
|
||||
inputItem.onActiveFocusChanged.connect(function () {
|
||||
@@ -283,7 +295,7 @@ ColumnLayout {
|
||||
|
||||
NDateTimeTokens {
|
||||
Layout.fillWidth: true
|
||||
height: 200
|
||||
Layout.preferredHeight: 300
|
||||
|
||||
// Connect to token clicked signal if NDateTimeTokens provides it
|
||||
onTokenClicked: token => root.insertToken(token)
|
||||
|
||||
@@ -14,6 +14,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property string valueIcon: widgetData.icon !== undefined ? widgetData.icon : widgetMetadata.icon
|
||||
property bool valueUseDistroLogo: widgetData.useDistroLogo !== undefined ? widgetData.useDistroLogo : widgetMetadata.useDistroLogo
|
||||
@@ -35,14 +37,20 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.control-center.use-distro-logo-label")
|
||||
description: I18n.tr("bar.control-center.use-distro-logo-description")
|
||||
checked: valueUseDistroLogo
|
||||
onToggled: checked => valueUseDistroLogo = checked
|
||||
onToggled: checked => {
|
||||
valueUseDistroLogo = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.custom-button.enable-colorization-label")
|
||||
description: I18n.tr("bar.control-center.enable-colorization-description")
|
||||
checked: valueEnableColorization
|
||||
onToggled: checked => valueEnableColorization = checked
|
||||
onToggled: checked => {
|
||||
valueEnableColorization = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
@@ -74,6 +82,7 @@ ColumnLayout {
|
||||
currentKey: valueColorizeSystemIcon
|
||||
onSelected: function (key) {
|
||||
valueColorizeSystemIcon = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,6 +132,7 @@ ColumnLayout {
|
||||
onIconSelected: iconName => {
|
||||
valueIcon = iconName;
|
||||
valueCustomIconPath = "";
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +145,7 @@ ColumnLayout {
|
||||
onAccepted: paths => {
|
||||
if (paths.length > 0) {
|
||||
valueCustomIconPath = paths[0]; // Use first selected file
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
property string valueIcon: widgetData.icon !== undefined ? widgetData.icon : widgetMetadata.icon
|
||||
property bool valueTextStream: widgetData.textStream !== undefined ? widgetData.textStream : widgetMetadata.textStream
|
||||
property bool valueParseJson: widgetData.parseJson !== undefined ? widgetData.parseJson : widgetMetadata.parseJson
|
||||
@@ -57,365 +59,404 @@ ColumnLayout {
|
||||
return settings;
|
||||
}
|
||||
|
||||
NScrollView {
|
||||
Layout.preferredWidth: Math.round(600 * Style.uiScaleRatio)
|
||||
Layout.preferredHeight: Math.round(700 * Style.uiScaleRatio)
|
||||
horizontalPolicy: ScrollBar.AlwaysOff
|
||||
verticalPolicy: ScrollBar.AsNeeded
|
||||
padding: Style.marginL
|
||||
focus: true
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
ColumnLayout {
|
||||
width: parent.width
|
||||
NLabel {
|
||||
label: I18n.tr("common.icon")
|
||||
description: I18n.tr("bar.custom-button.icon-description")
|
||||
}
|
||||
|
||||
NIcon {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
icon: valueIcon
|
||||
pointSize: Style.fontSizeXL
|
||||
visible: valueIcon !== ""
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("common.browse")
|
||||
onClicked: iconPicker.open()
|
||||
}
|
||||
}
|
||||
|
||||
NIconPicker {
|
||||
id: iconPicker
|
||||
initialIcon: valueIcon
|
||||
onIconSelected: function (iconName) {
|
||||
valueIcon = iconName;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: showIconToggle
|
||||
label: I18n.tr("bar.custom-button.show-icon-label", "Show icon")
|
||||
description: I18n.tr("bar.custom-button.show-icon-description", "Toggles the visibility of the widget's icon.")
|
||||
checked: valueShowIcon
|
||||
onToggled: checked => {
|
||||
valueShowIcon = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
visible: textCommandInput.text !== ""
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.custom-button.enable-colorization-label")
|
||||
description: I18n.tr("bar.custom-button.enable-colorization-description")
|
||||
checked: valueEnableColorization
|
||||
onToggled: checked => {
|
||||
valueEnableColorization = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
visible: valueEnableColorization
|
||||
label: I18n.tr("bar.custom-button.color-selection-label")
|
||||
description: I18n.tr("bar.custom-button.color-selection-description")
|
||||
model: [
|
||||
{
|
||||
"name": I18n.tr("common.none"),
|
||||
"key": "none"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.primary"),
|
||||
"key": "primary"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.secondary"),
|
||||
"key": "secondary"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.tertiary"),
|
||||
"key": "tertiary"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.error"),
|
||||
"key": "error"
|
||||
}
|
||||
]
|
||||
currentKey: valueColorizeSystemIcon
|
||||
onSelected: key => {
|
||||
valueColorizeSystemIcon = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.ipc-identifier-label")
|
||||
description: I18n.tr("bar.custom-button.ipc-identifier-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-ipc-identifier")
|
||||
text: valueIpcIdentifier
|
||||
onTextChanged: valueIpcIdentifier = text
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: leftClickExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.left-click-label")
|
||||
description: I18n.tr("bar.custom-button.left-click-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.leftClickExec || widgetMetadata.leftClickExec
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: leftClickUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(leftClickUpdateText, I18n.tr("bar.custom-button.left-click-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.leftClickUpdateText ?? widgetMetadata.leftClickUpdateText
|
||||
onToggled: isChecked => {
|
||||
checked = isChecked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: rightClickExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.right-click-label")
|
||||
description: I18n.tr("bar.custom-button.right-click-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.rightClickExec || widgetMetadata.rightClickExec
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: rightClickUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(rightClickUpdateText, I18n.tr("bar.custom-button.right-click-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.rightClickUpdateText ?? widgetMetadata.rightClickUpdateText
|
||||
onToggled: isChecked => {
|
||||
checked = isChecked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: middleClickExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.middle-click-label")
|
||||
description: I18n.tr("bar.custom-button.middle-click-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData.middleClickExec || widgetMetadata.middleClickExec
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: middleClickUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(middleClickUpdateText, I18n.tr("bar.custom-button.middle-click-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.middleClickUpdateText ?? widgetMetadata.middleClickUpdateText
|
||||
onToggled: isChecked => {
|
||||
checked = isChecked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wheel command settings
|
||||
NToggle {
|
||||
id: separateWheelToggle
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.wheel-mode-separate-label", "Separate wheel commands")
|
||||
description: I18n.tr("bar.custom-button.wheel-mode-separate-description", "Enable separate commands for wheel up and down")
|
||||
property bool internalChecked: (widgetData?.wheelMode || widgetMetadata?.wheelMode) === "separate"
|
||||
checked: internalChecked
|
||||
onToggled: checked => {
|
||||
internalChecked = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
|
||||
RowLayout {
|
||||
id: unifiedWheelLayout
|
||||
visible: !separateWheelToggle.checked
|
||||
spacing: Style.marginM
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NLabel {
|
||||
label: I18n.tr("common.icon")
|
||||
description: I18n.tr("bar.custom-button.icon-description")
|
||||
}
|
||||
|
||||
NIcon {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
icon: valueIcon
|
||||
pointSize: Style.fontSizeXL
|
||||
visible: valueIcon !== ""
|
||||
}
|
||||
|
||||
NButton {
|
||||
text: I18n.tr("common.browse")
|
||||
onClicked: iconPicker.open()
|
||||
}
|
||||
}
|
||||
|
||||
NIconPicker {
|
||||
id: iconPicker
|
||||
initialIcon: valueIcon
|
||||
onIconSelected: function (iconName) {
|
||||
valueIcon = iconName;
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: showIconToggle
|
||||
label: I18n.tr("bar.custom-button.show-icon-label", "Show icon")
|
||||
description: I18n.tr("bar.custom-button.show-icon-description", "Toggles the visibility of the widget's icon.")
|
||||
checked: valueShowIcon
|
||||
onToggled: checked => valueShowIcon = checked
|
||||
visible: textCommandInput.text !== ""
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.custom-button.enable-colorization-label")
|
||||
description: I18n.tr("bar.custom-button.enable-colorization-description")
|
||||
checked: valueEnableColorization
|
||||
onToggled: checked => valueEnableColorization = checked
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
visible: valueEnableColorization
|
||||
label: I18n.tr("bar.custom-button.color-selection-label")
|
||||
description: I18n.tr("bar.custom-button.color-selection-description")
|
||||
model: [
|
||||
{
|
||||
"name": I18n.tr("common.none"),
|
||||
"key": "none"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.primary"),
|
||||
"key": "primary"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.secondary"),
|
||||
"key": "secondary"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.tertiary"),
|
||||
"key": "tertiary"
|
||||
},
|
||||
{
|
||||
"name": I18n.tr("colors.error"),
|
||||
"key": "error"
|
||||
}
|
||||
]
|
||||
currentKey: valueColorizeSystemIcon
|
||||
onSelected: key => valueColorizeSystemIcon = key
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: wheelExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.ipc-identifier-label")
|
||||
description: I18n.tr("bar.custom-button.ipc-identifier-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-ipc-identifier")
|
||||
text: valueIpcIdentifier
|
||||
onTextChanged: valueIpcIdentifier = text
|
||||
label: I18n.tr("bar.custom-button.wheel-label")
|
||||
description: I18n.tr("bar.custom-button.wheel-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.wheelExec || widgetMetadata?.wheelExec
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: leftClickExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.left-click-label")
|
||||
description: I18n.tr("bar.custom-button.left-click-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.leftClickExec || widgetMetadata.leftClickExec
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: leftClickUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(leftClickUpdateText, I18n.tr("bar.custom-button.left-click-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.leftClickUpdateText ?? widgetMetadata.leftClickUpdateText
|
||||
onToggled: isChecked => checked = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: rightClickExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.right-click-label")
|
||||
description: I18n.tr("bar.custom-button.right-click-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.rightClickExec || widgetMetadata.rightClickExec
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: rightClickUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(rightClickUpdateText, I18n.tr("bar.custom-button.right-click-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.rightClickUpdateText ?? widgetMetadata.rightClickUpdateText
|
||||
onToggled: isChecked => checked = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: middleClickExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.middle-click-label")
|
||||
description: I18n.tr("bar.custom-button.middle-click-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData.middleClickExec || widgetMetadata.middleClickExec
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: middleClickUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(middleClickUpdateText, I18n.tr("bar.custom-button.middle-click-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.middleClickUpdateText ?? widgetMetadata.middleClickUpdateText
|
||||
onToggled: isChecked => checked = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
// Wheel command settings
|
||||
NToggle {
|
||||
id: separateWheelToggle
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.wheel-mode-separate-label", "Separate wheel commands")
|
||||
description: I18n.tr("bar.custom-button.wheel-mode-separate-description", "Enable separate commands for wheel up and down")
|
||||
property bool internalChecked: (widgetData?.wheelMode || widgetMetadata?.wheelMode) === "separate"
|
||||
checked: internalChecked
|
||||
onToggled: checked => {
|
||||
internalChecked = checked;
|
||||
id: wheelUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(wheelUpdateText, I18n.tr("bar.custom-button.wheel-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.wheelUpdateText ?? widgetMetadata?.wheelUpdateText
|
||||
onToggled: isChecked => {
|
||||
checked = isChecked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredWidth: parent.width
|
||||
ColumnLayout {
|
||||
id: separatedWheelLayout
|
||||
Layout.fillWidth: true
|
||||
visible: separateWheelToggle.checked
|
||||
|
||||
RowLayout {
|
||||
id: unifiedWheelLayout
|
||||
visible: !separateWheelToggle.checked
|
||||
spacing: Style.marginM
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: wheelExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.wheel-label")
|
||||
description: I18n.tr("bar.custom-button.wheel-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.wheelExec || widgetMetadata?.wheelExec
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: wheelUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(wheelUpdateText, I18n.tr("bar.custom-button.wheel-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: widgetData?.wheelUpdateText ?? widgetMetadata?.wheelUpdateText
|
||||
onToggled: isChecked => checked = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
id: separatedWheelLayout
|
||||
NTextInput {
|
||||
id: wheelUpExecInput
|
||||
Layout.fillWidth: true
|
||||
visible: separateWheelToggle.checked
|
||||
label: I18n.tr("bar.custom-button.wheel-up-label")
|
||||
description: I18n.tr("bar.custom-button.wheel-up-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.wheelUpExec || widgetMetadata?.wheelUpExec
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: wheelUpExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.wheel-up-label")
|
||||
description: I18n.tr("bar.custom-button.wheel-up-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.wheelUpExec || widgetMetadata?.wheelUpExec
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: wheelUpUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(wheelUpUpdateText, I18n.tr("bar.custom-button.wheel-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: (widgetData?.wheelUpUpdateText !== undefined) ? widgetData.wheelUpUpdateText : widgetMetadata?.wheelUpUpdateText
|
||||
onToggled: isChecked => checked = isChecked
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NTextInput {
|
||||
id: wheelDownExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.wheel-down-label")
|
||||
description: I18n.tr("bar.custom-button.wheel-down-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.wheelDownExec || widgetMetadata?.wheelDownExec
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: wheelDownUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(wheelDownUpdateText, I18n.tr("bar.custom-button.wheel-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: (widgetData?.wheelDownUpdateText !== undefined) ? widgetData.wheelDownUpdateText : widgetMetadata?.wheelDownUpdateText
|
||||
onToggled: isChecked => checked = isChecked
|
||||
}
|
||||
}
|
||||
NToggle {
|
||||
id: wheelUpUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(wheelUpUpdateText, I18n.tr("bar.custom-button.wheel-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: (widgetData?.wheelUpUpdateText !== undefined) ? widgetData.wheelUpUpdateText : widgetMetadata?.wheelUpUpdateText
|
||||
onToggled: isChecked => {
|
||||
checked = isChecked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
RowLayout {
|
||||
spacing: Style.marginM
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("bar.custom-button.dynamic-text")
|
||||
}
|
||||
NTextInput {
|
||||
id: wheelDownExecInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.wheel-down-label")
|
||||
description: I18n.tr("bar.custom-button.wheel-down-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-command")
|
||||
text: widgetData?.wheelDownExec || widgetMetadata?.wheelDownExec
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NSpinBox {
|
||||
label: I18n.tr("bar.custom-button.max-text-length-horizontal-label", "Max text length (horizontal)")
|
||||
description: I18n.tr("bar.custom-button.max-text-length-horizontal-description", "Maximum number of characters to show in horizontal bar (0 to hide text)")
|
||||
from: 0
|
||||
to: 100
|
||||
value: valueMaxTextLengthHorizontal
|
||||
onValueChanged: valueMaxTextLengthHorizontal = value
|
||||
}
|
||||
|
||||
NSpinBox {
|
||||
label: I18n.tr("bar.custom-button.max-text-length-vertical-label", "Max text length (vertical)")
|
||||
description: I18n.tr("bar.custom-button.max-text-length-vertical-description", "Maximum number of characters to show in vertical bar (0 to hide text)")
|
||||
from: 0
|
||||
to: 100
|
||||
value: valueMaxTextLengthVertical
|
||||
onValueChanged: valueMaxTextLengthVertical = value
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: textStreamInput
|
||||
label: I18n.tr("bar.custom-button.text-stream-label")
|
||||
description: I18n.tr("bar.custom-button.text-stream-description")
|
||||
checked: valueTextStream
|
||||
onToggled: checked => valueTextStream = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: parseJsonInput
|
||||
label: I18n.tr("bar.custom-button.parse-json-label", "Parse output as JSON")
|
||||
description: I18n.tr("bar.custom-button.parse-json-description", "Parse the command output as a JSON object to dynamically set text and icon.")
|
||||
checked: valueParseJson
|
||||
onToggled: checked => valueParseJson = checked
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: textCommandInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.display-command-output-label")
|
||||
description: valueTextStream ? I18n.tr("bar.custom-button.display-command-output-stream-description") : I18n.tr("bar.custom-button.display-command-output-description")
|
||||
placeholderText: I18n.tr("placeholders.command-example")
|
||||
text: widgetData?.textCommand || widgetMetadata.textCommand
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: textCollapseInput
|
||||
Layout.fillWidth: true
|
||||
visible: valueTextStream
|
||||
label: I18n.tr("bar.custom-button.collapse-condition-label")
|
||||
description: I18n.tr("bar.custom-button.collapse-condition-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-text-to-collapse")
|
||||
text: widgetData?.textCollapse || widgetMetadata.textCollapse
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: textIntervalInput
|
||||
Layout.fillWidth: true
|
||||
visible: !valueTextStream
|
||||
label: I18n.tr("bar.custom-button.refresh-interval-label")
|
||||
description: I18n.tr("bar.custom-button.refresh-interval-description")
|
||||
placeholderText: String(widgetMetadata.textIntervalMs)
|
||||
text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : ""
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: hideModeComboBox
|
||||
label: I18n.tr("bar.custom-button.hide-mode-label", "Hide mode")
|
||||
description: I18n.tr("bar.custom-button.hide-mode-description", "Controls widget visibility when the command has no output.")
|
||||
model: [
|
||||
{
|
||||
name: I18n.tr("bar.custom-button.hide-mode-always-expanded", "Always expanded"),
|
||||
key: "alwaysExpanded"
|
||||
},
|
||||
{
|
||||
name: I18n.tr("bar.custom-button.hide-mode-expand-with-output", "Expand when has output"),
|
||||
key: "expandWithOutput"
|
||||
},
|
||||
{
|
||||
name: I18n.tr("bar.custom-button.hide-mode-max-transparent", "Max expanded but transparent"),
|
||||
key: "maxTransparent"
|
||||
}
|
||||
]
|
||||
currentKey: valueHideMode
|
||||
onSelected: key => valueHideMode = key
|
||||
visible: textCommandInput.text !== "" && valueTextStream == true
|
||||
NToggle {
|
||||
id: wheelDownUpdateText
|
||||
enabled: !valueTextStream
|
||||
Layout.alignment: Qt.AlignRight | Qt.AlignBottom
|
||||
Layout.bottomMargin: Style.marginS
|
||||
onEntered: TooltipService.show(wheelDownUpdateText, I18n.tr("bar.custom-button.wheel-update-text"), "auto")
|
||||
onExited: TooltipService.hide()
|
||||
checked: (widgetData?.wheelDownUpdateText !== undefined) ? widgetData.wheelDownUpdateText : widgetMetadata?.wheelDownUpdateText
|
||||
onToggled: isChecked => {
|
||||
checked = isChecked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NDivider {
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
|
||||
NHeader {
|
||||
label: I18n.tr("bar.custom-button.dynamic-text")
|
||||
}
|
||||
|
||||
NSpinBox {
|
||||
label: I18n.tr("bar.custom-button.max-text-length-horizontal-label", "Max text length (horizontal)")
|
||||
description: I18n.tr("bar.custom-button.max-text-length-horizontal-description", "Maximum number of characters to show in horizontal bar (0 to hide text)")
|
||||
from: 0
|
||||
to: 100
|
||||
value: valueMaxTextLengthHorizontal
|
||||
onValueChanged: {
|
||||
valueMaxTextLengthHorizontal = value;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NSpinBox {
|
||||
label: I18n.tr("bar.custom-button.max-text-length-vertical-label", "Max text length (vertical)")
|
||||
description: I18n.tr("bar.custom-button.max-text-length-vertical-description", "Maximum number of characters to show in vertical bar (0 to hide text)")
|
||||
from: 0
|
||||
to: 100
|
||||
value: valueMaxTextLengthVertical
|
||||
onValueChanged: {
|
||||
valueMaxTextLengthVertical = value;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: textStreamInput
|
||||
label: I18n.tr("bar.custom-button.text-stream-label")
|
||||
description: I18n.tr("bar.custom-button.text-stream-description")
|
||||
checked: valueTextStream
|
||||
onToggled: checked => {
|
||||
valueTextStream = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
id: parseJsonInput
|
||||
label: I18n.tr("bar.custom-button.parse-json-label", "Parse output as JSON")
|
||||
description: I18n.tr("bar.custom-button.parse-json-description", "Parse the command output as a JSON object to dynamically set text and icon.")
|
||||
checked: valueParseJson
|
||||
onToggled: checked => {
|
||||
valueParseJson = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: textCommandInput
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("bar.custom-button.display-command-output-label")
|
||||
description: valueTextStream ? I18n.tr("bar.custom-button.display-command-output-stream-description") : I18n.tr("bar.custom-button.display-command-output-description")
|
||||
placeholderText: I18n.tr("placeholders.command-example")
|
||||
text: widgetData?.textCommand || widgetMetadata.textCommand
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: textCollapseInput
|
||||
Layout.fillWidth: true
|
||||
visible: valueTextStream
|
||||
label: I18n.tr("bar.custom-button.collapse-condition-label")
|
||||
description: I18n.tr("bar.custom-button.collapse-condition-description")
|
||||
placeholderText: I18n.tr("placeholders.enter-text-to-collapse")
|
||||
text: widgetData?.textCollapse || widgetMetadata.textCollapse
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NTextInput {
|
||||
id: textIntervalInput
|
||||
Layout.fillWidth: true
|
||||
visible: !valueTextStream
|
||||
label: I18n.tr("bar.custom-button.refresh-interval-label")
|
||||
description: I18n.tr("bar.custom-button.refresh-interval-description")
|
||||
placeholderText: String(widgetMetadata.textIntervalMs)
|
||||
text: widgetData && widgetData.textIntervalMs !== undefined ? String(widgetData.textIntervalMs) : ""
|
||||
onEditingFinished: settingsChanged(saveSettings())
|
||||
}
|
||||
|
||||
NComboBox {
|
||||
id: hideModeComboBox
|
||||
label: I18n.tr("bar.custom-button.hide-mode-label", "Hide mode")
|
||||
description: I18n.tr("bar.custom-button.hide-mode-description", "Controls widget visibility when the command has no output.")
|
||||
model: [
|
||||
{
|
||||
name: I18n.tr("bar.custom-button.hide-mode-always-expanded", "Always expanded"),
|
||||
key: "alwaysExpanded"
|
||||
},
|
||||
{
|
||||
name: I18n.tr("bar.custom-button.hide-mode-expand-with-output", "Expand when has output"),
|
||||
key: "expandWithOutput"
|
||||
},
|
||||
{
|
||||
name: I18n.tr("bar.custom-button.hide-mode-max-transparent", "Max expanded but transparent"),
|
||||
key: "maxTransparent"
|
||||
}
|
||||
]
|
||||
currentKey: valueHideMode
|
||||
onSelected: key => {
|
||||
valueHideMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
visible: textCommandInput.text !== "" && valueTextStream == true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||
property bool valueShowIcon: widgetData.showIcon !== undefined ? widgetData.showIcon : widgetMetadata.showIcon
|
||||
@@ -43,13 +45,19 @@ ColumnLayout {
|
||||
}
|
||||
]
|
||||
currentKey: valueDisplayMode
|
||||
onSelected: key => valueDisplayMode = key
|
||||
onSelected: key => {
|
||||
valueDisplayMode = key;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
label: I18n.tr("bar.custom-button.show-icon-label")
|
||||
description: I18n.tr("bar.keyboard-layout.show-icon-description")
|
||||
checked: valueShowIcon
|
||||
onToggled: checked => valueShowIcon = checked
|
||||
onToggled: checked => {
|
||||
valueShowIcon = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property bool valueUsePrimaryColor: widgetData.usePrimaryColor !== undefined ? widgetData.usePrimaryColor : (widgetMetadata ? widgetMetadata.usePrimaryColor : false)
|
||||
|
||||
@@ -26,6 +28,9 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.clock.use-primary-color-label")
|
||||
description: I18n.tr("bar.clock.use-primary-color-description")
|
||||
checked: valueUsePrimaryColor
|
||||
onToggled: checked => valueUsePrimaryColor = checked
|
||||
onToggled: checked => {
|
||||
valueUsePrimaryColor = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@ ColumnLayout {
|
||||
property var widgetData: null
|
||||
property var widgetMetadata: null
|
||||
|
||||
signal settingsChanged(var settings)
|
||||
|
||||
// Local state
|
||||
property bool valueShowCapsLock: widgetData.showCapsLock !== undefined ? widgetData.showCapsLock : widgetMetadata.showCapsLock
|
||||
property bool valueShowNumLock: widgetData.showNumLock !== undefined ? widgetData.showNumLock : widgetMetadata.showNumLock
|
||||
@@ -42,7 +44,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.lock-keys.show-caps-lock-label")
|
||||
description: I18n.tr("bar.lock-keys.show-caps-lock-description")
|
||||
checked: valueShowCapsLock
|
||||
onToggled: checked => valueShowCapsLock = checked
|
||||
onToggled: checked => {
|
||||
valueShowCapsLock = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NIcon {
|
||||
@@ -65,6 +70,7 @@ ColumnLayout {
|
||||
query: "letter-c"
|
||||
onIconSelected: function (iconName) {
|
||||
capsIcon = iconName;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,7 +81,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.lock-keys.show-num-lock-label")
|
||||
description: I18n.tr("bar.lock-keys.show-num-lock-description")
|
||||
checked: valueShowNumLock
|
||||
onToggled: checked => valueShowNumLock = checked
|
||||
onToggled: checked => {
|
||||
valueShowNumLock = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NIcon {
|
||||
@@ -98,6 +107,7 @@ ColumnLayout {
|
||||
query: "letter-n"
|
||||
onIconSelected: function (iconName) {
|
||||
numIcon = iconName;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +118,10 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.lock-keys.show-scroll-lock-label")
|
||||
description: I18n.tr("bar.lock-keys.show-scroll-lock-description")
|
||||
checked: valueShowScrollLock
|
||||
onToggled: checked => valueShowScrollLock = checked
|
||||
onToggled: checked => {
|
||||
valueShowScrollLock = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
NIcon {
|
||||
@@ -131,6 +144,7 @@ ColumnLayout {
|
||||
query: "letter-s"
|
||||
onIconSelected: function (iconName) {
|
||||
scrollIcon = iconName;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,6 +157,9 @@ ColumnLayout {
|
||||
label: I18n.tr("bar.lock-keys.hide-when-off-label")
|
||||
description: I18n.tr("bar.lock-keys.hide-when-off-description")
|
||||
checked: valueHideWhenOff
|
||||
onToggled: checked => valueHideWhenOff = checked
|
||||
onToggled: checked => {
|
||||
valueHideWhenOff = checked;
|
||||
settingsChanged(saveSettings());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user