diff --git a/.github/funding.yml b/.github/funding.yml new file mode 100644 index 00000000..ae4a88c0 --- /dev/null +++ b/.github/funding.yml @@ -0,0 +1 @@ +ko_fi: lysec \ No newline at end of file diff --git a/.zed/settings.json b/.zed/settings.json deleted file mode 100644 index 5f7d4f63..00000000 --- a/.zed/settings.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "languages": { - "QML": { - "format_on_save": "on", - "formatter": { - "external": { - "command": "qmlfmt", - "arguments": ["-e", "-b", "360", "-t", "2", "-i", "2"] - } - } - } - } -} diff --git a/Assets/Translations/de.json b/Assets/Translations/de.json index 6ba6381a..e04f43ed 100644 --- a/Assets/Translations/de.json +++ b/Assets/Translations/de.json @@ -13,32 +13,6 @@ }, "select-avatar": "Avatar-Bild auswählen" }, - "ui": { - "section": { - "label": "Benutzeroberfläche", - "description": "Passen Sie das Aussehen, die Haptik und das Verhalten der Oberfläche an." - }, - "tooltips": { - "label": "Tooltips anzeigen", - "description": "Tooltips in der gesamten Benutzeroberfläche aktivieren oder deaktivieren." - }, - "dim-desktop": { - "label": "Desktop abdunkeln", - "description": "Desktop abdunkeln, wenn Panels oder Menüs geöffnet sind." - }, - "border-radius": { - "label": "Eckenradius", - "description": "Steuert die Rundung der Ecken von Fenstern, Buttons und anderen Elementen." - }, - "animation-speed": { - "label": "Animationsgeschwindigkeit", - "description": "Globale Animationsgeschwindigkeit anpassen." - }, - "animation-disable": { - "label": "UI-Animationen deaktivieren", - "description": "Alle Animationen für eine schnellere, reaktionsschnellere Erfahrung deaktivieren." - } - }, "screen-corners": { "section": { "label": "Bildschirmecken", @@ -54,7 +28,8 @@ }, "radius": { "label": "Bildschirmecken-Radius", - "description": "Rundung der Bildschirmecken anpassen." + "description": "Rundung der Bildschirmecken anpassen.", + "reset": "Eckenradius des Bildschirms zurücksetzen" } }, "fonts": { @@ -83,33 +58,6 @@ } }, "reset-scaling": "Skalierung zurücksetzen" - }, - "control-center": { - "title": "Kontrollzentrum", - "section": { - "label": "Kontrollzentrum", - "description": "Konfigurieren Sie die Positionierung und das Verhalten des Kontrollzentrum-Panels." - }, - "position": { - "label": "Position", - "description": "Wählen Sie, wo das Kontrollzentrum-Panel beim Öffnen erscheint." - }, - "quickSettingsStyle": { - "section": { - "label": "Schnelleinstellungen-Stil", - "description": "Passen Sie das Aussehen und Verhalten der Schnelleinstellungen im Kontrollzentrum an." - }, - "style": { - "label": "Schnelleinstellungen-Stil", - "description": "Wählen Sie den visuellen Stil für Schnelleinstellungs-Schalter und -Steuerungen." - } - }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Konfigurieren und verwalten Sie Kontrollzentrum-Widgets und deren Anzeigeoptionen." - } - } } }, "audio": { @@ -196,11 +144,9 @@ "monitors": { "section": { "label": "Monitor-spezifische Einstellungen", - "description": "Skalierung und Helligkeit für jeden Bildschirm anpassen." + "description": "Helligkeitseinstellungen für jedes Display anpassen." }, - "scale": "Skalierung", "brightness": "Helligkeit", - "reset-scaling": "Skalierung zurücksetzen", "brightness-step": { "label": "Helligkeits-Schrittgröße", "description": "Schrittgröße für Helligkeitsänderungen anpassen (Mausrad und Tastenkombinationen)." @@ -318,6 +264,10 @@ "floating-distance": { "label": "Dock-Schwebeabstand", "description": "Schwebeabstand vom Bildschirmrand anpassen." + }, + "colorize-icons": { + "label": "Symbole einfärben", + "description": "Theme-Farben auf Dock-App-Symbole anwenden (nur nicht fokussierte Apps)." } }, "monitors": { @@ -430,6 +380,10 @@ "label": "Bildschirmanzeige aktivieren", "description": "Lautstärke- und Helligkeitsänderungen in Echtzeit anzeigen." }, + "always-on-top": { + "label": "Immer im Vordergrund", + "description": "Bildschirmanzeige über Vollbildfenstern und anderen Ebenen anzeigen." + }, "location": { "label": "Position", "description": "Wo Bildschirmanzeigen erscheinen." @@ -734,29 +688,8 @@ "description": "Ein Dankeschön an unseren {count} großartigen Mitwirkenden!", "description_plural": "Ein Dankeschön an unsere {count} großartigen Mitwirkenden!" } - } - }, - "control-center": { - "title": "Kontrollzentrum", - "quickSettingsStyle": { - "section": { - "label": "Schnelleinstellungen-Stil", - "description": "Passen Sie das Aussehen und Verhalten der Schnelleinstellungen im Kontrollzentrum an." - }, - "style": { - "label": "Schnelleinstellungen-Stil", - "description": "Wählen Sie den visuellen Stil für Schnelleinstellungs-Schalter und -Steuerungen." - } }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Konfigurieren und verwalten Sie Kontrollzentrum-Widgets und deren Anzeigeoptionen." - } - }, - "quickSettings": { - "sectionName": "Schnelleinstellungen" - } + "support": "Unterstützen Sie uns" }, "hooks": { "title": "Hooks", @@ -790,6 +723,69 @@ "description": "• Hintergrundbild-Hook: $1 = Hintergrundbild-Pfad, $2 = Bildschirmname\n• Theme-Wechsel-Hook: $1 = true/false (Dunkelmodus-Status)" } } + }, + "control-center": { + "position": { + "description": "Wählen Sie aus, wo das Kontrollzentrum angezeigt wird, wenn es geöffnet wird.", + "label": "Position" + }, + "section": { + "description": "Konfigurieren Sie die Positionierung und das Verhalten des Control Center-Panels.", + "label": "Aussehen" + }, + "title": "Kontrollzentrum", + "cards": { + "section": { + "description": "Passen Sie an, welche Steuerelemente im Kontrollzentrum angezeigt werden und in welcher Reihenfolge.", + "label": "Karten" + } + }, + "shortcuts": { + "section": { + "description": "Konfigurieren und verwalten Sie die Verknüpfungs-Widgets.", + "label": "Widgets für Kurzbefehle" + }, + "sectionLeft": "Links", + "sectionRight": "Richtig" + } + }, + "user-interface": { + "animation-disable": { + "description": "Deaktivieren Sie alle Animationen für eine schnellere und reaktionsfreudigere Erfahrung.", + "label": "UI-Animationen deaktivieren" + }, + "animation-speed": { + "description": "Globale Animationsgeschwindigkeit anpassen.", + "label": "Animationsgeschwindigkeit", + "reset": "Animationsgeschwindigkeit zurücksetzen" + }, + "border-radius": { + "description": "Steuert die Eckenrundung von Fenstern, Schaltflächen und anderen Elementen.", + "label": "Eckenradius", + "reset": "Rahmenradius zurücksetzen" + }, + "compact-lockscreen": { + "description": "Zeige nur die Login-Eingabe und Systemsteuerung, blende Wetter- und Medien-Widgets aus.", + "label": "Kompakter Sperrbildschirm" + }, + "dim-desktop": { + "description": "Den Desktop abdunkeln, wenn Bedienfelder oder Menüs geöffnet sind.", + "label": "Dim Desktop" + }, + "scaling": { + "description": "Ändert die Größe der allgemeinen Benutzeroberfläche, mit Ausnahme der Leiste.", + "label": "Oberflächenskalierung", + "reset-scaling": "Schnittstellenskalierung zurücksetzen" + }, + "section": { + "description": "Passen Sie das Aussehen, die Haptik und das Verhalten der Benutzeroberfläche an.", + "label": "Aussehen" + }, + "title": "Benutzeroberfläche", + "tooltips": { + "description": "Tooltips in der gesamten Benutzeroberfläche aktivieren oder deaktivieren.", + "label": "Tooltips anzeigen" + } } }, "general": { @@ -910,9 +906,9 @@ "search-placeholder": "Widgets suchen..." }, "active-window": { - "auto-hide": { - "label": "Automatisch ausblenden", - "description": "Widget automatisch ausblenden, wenn kein Fenster aktiv ist." + "hide-mode": { + "label": "Ausblendmodus", + "description": "Steuert das Verhalten des Widgets, wenn kein Fenster aktiv ist." }, "show-app-icon": { "label": "App-Symbol anzeigen", @@ -925,6 +921,10 @@ "width": { "description": "Steuert die horizontale Größe des Widgets.", "label": "Widget-Breite" + }, + "colorize-icons": { + "label": "Symbole einfärben", + "description": "Theme-Farben auf das aktive Fenster-Symbol anwenden." } }, "system-monitor": { @@ -1055,9 +1055,9 @@ } }, "media-mini": { - "auto-hide": { - "label": "Automatisch ausblenden", - "description": "Widget automatisch ausblenden, wenn keine Medien abgespielt werden." + "hide-mode": { + "label": "Ausblendmodus", + "description": "Steuert das Verhalten des Widgets, wenn keine Medien abgespielt werden." }, "show-album-art": { "label": "Albumcover anzeigen", @@ -1118,6 +1118,16 @@ "only-same-output": { "label": "Nur vom gleichen Bildschirm", "description": "Zeige nur Apps vom dem Bildschirm an, wo sich die Taskbar befindet." + }, + "colorize-icons": { + "label": "Symbole einfärben", + "description": "Theme-Farben auf Taskbar-Symbole anwenden." + } + }, + "tray": { + "colorize-icons": { + "label": "Symbole einfärben", + "description": "Theme-Farben auf Tray-Symbole anwenden." } } } @@ -1287,7 +1297,8 @@ "density": { "compact": "Kompakt", "default": "Standard", - "comfortable": "Bequem" + "comfortable": "Bequem", + "mini": "Mini" } }, "launcher": { @@ -1376,6 +1387,11 @@ "microphone-input": "Mikrofon-Eingabe", "both": "System-Ausgabe + Mikrofon-Eingabe" } + }, + "hide-modes": { + "hidden": "Ausblenden, wenn leer", + "transparent": "Transparent, wenn leer", + "visible": "Immer sichtbar" } }, "session-menu": { @@ -1568,6 +1584,9 @@ "enabled": "Aktiviert", "disabled": "Deaktiviert" }, + "kofi": { + "opened": "Ko-fi-Seite in Ihrem Browser geöffnet" + }, "do-not-disturb": { "enabled": "'Nicht stören' aktiviert", "disabled": "'Nicht stören' deaktiviert", diff --git a/Assets/Translations/en.json b/Assets/Translations/en.json index 361903a8..3819ebbc 100644 --- a/Assets/Translations/en.json +++ b/Assets/Translations/en.json @@ -13,32 +13,6 @@ }, "select-avatar": "Select avatar image" }, - "ui": { - "section": { - "label": "User interface", - "description": "Customize the look, feel, and behavior of the interface." - }, - "tooltips": { - "label": "Show tooltips", - "description": "Enable or disable tooltips throughout the interface." - }, - "dim-desktop": { - "label": "Dim desktop", - "description": "Dim the desktop when panels or menus are open." - }, - "border-radius": { - "label": "Border radius", - "description": "Controls the corner roundness of windows, buttons, and other elements." - }, - "animation-speed": { - "label": "Animation speed", - "description": "Adjust global animation speed." - }, - "animation-disable": { - "label": "Disable UI Animations", - "description": "Disable all animations for a faster, more responsive experience." - } - }, "screen-corners": { "section": { "label": "Screen corners", @@ -54,7 +28,8 @@ }, "radius": { "label": "Screen corners radius", - "description": "Adjust the rounded corners of the screen." + "description": "Adjust the rounded corners of the screen.", + "reset": "Reset screen corners radius" } }, "fonts": { @@ -83,34 +58,8 @@ "description": "Increase or decrease the size of the monospaced text." } } - }, - "control-center": { - "title": "Control Center", - "section": { - "label": "Control Center", - "description": "Configure the Control Center panel positioning and behavior." - }, - "position": { - "label": "Position", - "description": "Choose where the Control Center panel appears when opened." - }, - "quickSettingsStyle": { - "section": { - "label": "Quick Settings Style", - "description": "Customize the appearance and behavior of quick settings in the Control Center." - }, - "style": { - "label": "Quick Settings Style", - "description": "Choose the visual style for quick settings toggles and controls." - } - }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configure and manage Control Center widgets and their display options." - } - } } + }, "audio": { "title": "Audio", @@ -196,11 +145,9 @@ "monitors": { "section": { "label": "Per-monitor settings", - "description": "Adjust scaling and brightness for each display." + "description": "Adjust settings brightness for each display." }, - "scale": "Scale", "brightness": "Brightness", - "reset-scaling": "Reset scaling", "brightness-step": { "label": "Brightness step size", "description": "Adjust the step size for brightness changes (scroll wheel and keyboard shortcuts)." @@ -318,6 +265,10 @@ "floating-distance": { "label": "Dock floating distance", "description": "Adjust the floating distance from the screen edge." + }, + "colorize-icons": { + "label": "Colorize Icons", + "description": "Apply theme colors to dock app icons (non-focused apps only)." } }, "monitors": { @@ -430,6 +381,10 @@ "label": "Enable on screen display", "description": "Show volume and brightness changes in real-time." }, + "always-on-top": { + "label": "Always on top", + "description": "Display OSD above fullscreen windows and other layers." + }, "location": { "label": "Location", "description": "Where on-screen displays appear." @@ -734,29 +689,8 @@ "description": "Shout-out to our {count} awesome contributor!", "description_plural": "Shout-out to our {count} awesome contributors!" } - } - }, - "control-center": { - "title": "Control Center", - "quickSettingsStyle": { - "section": { - "label": "Quick Settings Style", - "description": "Customize the appearance and behavior of quick settings in the Control Center." - }, - "style": { - "label": "Quick Settings Style", - "description": "Choose the visual style for quick settings toggles and controls." - } }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configure and manage Control Center widgets and their display options." - } - }, - "quickSettings": { - "sectionName": "Quick Settings" - } + "support": "Support us" }, "hooks": { "title": "Hooks", @@ -790,6 +724,69 @@ "description": "• Wallpaper Hook: $1 = wallpaper path, $2 = screen name\n• Theme Toggle Hook: $1 = true/false (dark mode state)" } } + }, + "control-center": { + "title": "Control Center", + "section": { + "label": "Appearance", + "description": "Configure the Control Center panel positioning and behavior." + }, + "position": { + "label": "Position", + "description": "Choose where the Control Center panel appears when opened." + }, + "cards": { + "section": { + "label": "Cards", + "description": "Customize which controls appear in the Control Center and in what order." + } + }, + "shortcuts": { + "section": { + "label": "Shortcuts widgets", + "description": "Configure and manage the shortcuts widgets." + }, + "sectionLeft": "Left", + "sectionRight": "Right" + } + }, + "user-interface": { + "title": "User interface", + "section": { + "label": "Appearance", + "description": "Customize the look, feel, and behavior of the interface." + }, + "tooltips": { + "label": "Show tooltips", + "description": "Enable or disable tooltips throughout the interface." + }, + "scaling": { + "label": "Interface scaling", + "description": "Changes the size of the general user interface, excluding the bar.", + "reset-scaling": "Reset interface scaling" + }, + "dim-desktop": { + "label": "Dim desktop", + "description": "Dim the desktop when panels or menus are open." + }, + "compact-lockscreen": { + "label": "Compact lock screen", + "description": "Show only the login input and system controls, hiding weather and media widgets." + }, + "border-radius": { + "label": "Border radius", + "description": "Controls the corner roundness of windows, buttons, and other elements.", + "reset": "Reset border radius" + }, + "animation-speed": { + "label": "Animation speed", + "description": "Adjust global animation speed.", + "reset": "Reset animation speed" + }, + "animation-disable": { + "label": "Disable UI Animations", + "description": "Disable all animations for a faster, more responsive experience." + } } }, "widgets": { @@ -893,9 +890,9 @@ "search-placeholder": "Search widget..." }, "active-window": { - "auto-hide": { - "label": "Hide automatically", - "description": "Automatically hide the widget when no window is active." + "hide-mode": { + "label": "Hiding mode", + "description": "Controls how the widget behaves when no window is active." }, "show-app-icon": { "label": "Show app icon", @@ -908,6 +905,10 @@ "width": { "label": "Widget Width", "description": "Controls the horizontal size of the widget." + }, + "colorize-icons": { + "label": "Colorize Icons", + "description": "Apply theme colors to active window icon." } }, "system-monitor": { @@ -1038,9 +1039,9 @@ } }, "media-mini": { - "auto-hide": { - "label": "Hide automatically", - "description": "Automatically hide the widget when no media is playing." + "hide-mode": { + "label": "Hiding mode", + "description": "Controls how the widget behaves when no media is playing." }, "show-album-art": { "label": "Show album art", @@ -1101,6 +1102,16 @@ "only-same-output": { "label": "Only from same output", "description": "Show only apps from the output where the bar is located." + }, + "colorize-icons": { + "label": "Colorize Icons", + "description": "Apply theme colors to taskbar icons." + } + }, + "tray": { + "colorize-icons": { + "label": "Colorize Icons", + "description": "Apply theme colors to tray icons." } } } @@ -1268,6 +1279,7 @@ "right": "Right" }, "density": { + "mini": "Mini", "compact": "Compact", "default": "Default", "comfortable": "Comfortable" @@ -1336,6 +1348,11 @@ "hover": "Scroll On Hover", "never": "Never Scroll" }, + "hide-modes": { + "visible": "Always Visible", + "hidden": "Hide When Empty", + "transparent": "Transparent When Empty" + }, "frame-rates": { "fps": "{fps} FPS" }, @@ -1540,6 +1557,9 @@ "enabled": "Enabled", "disabled": "Disabled" }, + "kofi": { + "opened": "Ko-fi page opened in your browser" + }, "do-not-disturb": { "enabled": "'Do not disturb' enabled", "disabled": "'Do not disturb' disabled", diff --git a/Assets/Translations/es.json b/Assets/Translations/es.json index 08d7aac8..cc8f14a3 100644 --- a/Assets/Translations/es.json +++ b/Assets/Translations/es.json @@ -13,32 +13,6 @@ }, "select-avatar": "Seleccionar imagen de avatar" }, - "ui": { - "section": { - "label": "Interfaz de usuario", - "description": "Personaliza la apariencia, sensación y comportamiento de la interfaz." - }, - "tooltips": { - "label": "Mostrar tooltips", - "description": "Activar o desactivar tooltips en toda la interfaz." - }, - "dim-desktop": { - "label": "Atenuar escritorio", - "description": "Atenúa el escritorio cuando los paneles o menús están abiertos." - }, - "border-radius": { - "label": "Radio del borde", - "description": "Controla la redondez de las esquinas de ventanas, botones y otros elementos." - }, - "animation-speed": { - "label": "Velocidad de la animación", - "description": "Ajusta la velocidad de la animación global." - }, - "animation-disable": { - "label": "Desactivar animaciones de UI", - "description": "Desactivar todas las animaciones para una experiencia más rápida y responsiva." - } - }, "screen-corners": { "section": { "label": "Esquinas de la pantalla", @@ -54,7 +28,8 @@ }, "radius": { "label": "Radio de las esquinas de la pantalla", - "description": "Ajusta las esquinas redondeadas de la pantalla." + "description": "Ajusta las esquinas redondeadas de la pantalla.", + "reset": "Restablecer el radio de las esquinas de la pantalla" } }, "fonts": { @@ -83,33 +58,6 @@ } }, "reset-scaling": "Restablecer la escala" - }, - "control-center": { - "title": "Centro de control", - "section": { - "label": "Centro de control", - "description": "Configurar el posicionamiento y comportamiento del panel del centro de control." - }, - "position": { - "label": "Posición", - "description": "Elige dónde aparece el panel del centro de control cuando se abre." - }, - "quickSettingsStyle": { - "section": { - "label": "Estilo de configuración rápida", - "description": "Personaliza la apariencia y el comportamiento de las configuraciones rápidas en el centro de control." - }, - "style": { - "label": "Estilo de configuración rápida", - "description": "Elige el estilo visual para los interruptores y controles de configuración rápida." - } - }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configura y gestiona los widgets del centro de control y sus opciones de visualización." - } - } } }, "audio": { @@ -196,11 +144,9 @@ "monitors": { "section": { "label": "Configuración por monitor", - "description": "Ajusta la escala y el brillo para cada pantalla." + "description": "Ajustar el brillo de la configuración para cada pantalla." }, - "scale": "Escala", "brightness": "Brillo", - "reset-scaling": "Restablecer escala", "brightness-step": { "label": "Tamaño del paso de brillo", "description": "Ajusta el tamaño del paso para los cambios de brillo (rueda de desplazamiento y atajos de teclado)." @@ -318,6 +264,10 @@ "floating-distance": { "label": "Distancia de flotación del dock", "description": "Ajusta la distancia de flotación desde el borde de la pantalla." + }, + "colorize-icons": { + "label": "Colorear iconos", + "description": "Aplicar colores del tema a los iconos de aplicaciones del dock (solo aplicaciones no enfocadas)." } }, "monitors": { @@ -430,6 +380,10 @@ "label": "Activar visualización en pantalla", "description": "Mostrar cambios de volumen y brillo en tiempo real." }, + "always-on-top": { + "label": "Siempre encima", + "description": "Mostrar OSD por encima de ventanas de pantalla completa y otras capas." + }, "location": { "label": "Ubicación", "description": "Dónde aparece la visualización en pantalla." @@ -734,29 +688,8 @@ "description": "¡Un saludo a nuestro increíble colaborador número {count}!", "description_plural": "¡Un saludo a nuestros {count} increíbles colaboradores!" } - } - }, - "control-center": { - "title": "Centro de control", - "quickSettingsStyle": { - "section": { - "label": "Estilo de configuración rápida", - "description": "Personaliza la apariencia y el comportamiento de las configuraciones rápidas en el centro de control." - }, - "style": { - "label": "Estilo de configuración rápida", - "description": "Elige el estilo visual para los interruptores y controles de configuración rápida." - } }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configura y gestiona los widgets del centro de control y sus opciones de visualización." - } - }, - "quickSettings": { - "sectionName": "Ajustes rápidos" - } + "support": "Apóyanos" }, "hooks": { "title": "Hooks", @@ -790,6 +723,69 @@ "description": "• Hook de fondo de pantalla: $1 = ruta del fondo de pantalla, $2 = nombre de la pantalla\n• Hook de cambio de tema: $1 = true/false (estado del modo oscuro)" } } + }, + "control-center": { + "position": { + "description": "Elige dónde aparece el panel del Centro de control cuando se abre.", + "label": "Posición" + }, + "section": { + "description": "Configurar el posicionamiento y el comportamiento del panel del Centro de control.", + "label": "Apariencia" + }, + "title": "Centro de control", + "cards": { + "section": { + "description": "Personaliza qué controles aparecen en el Centro de control y en qué orden.", + "label": "Tarjetas" + } + }, + "shortcuts": { + "section": { + "description": "Configurar y administrar los widgets de accesos directos.", + "label": "Widgets de accesos directos" + }, + "sectionLeft": "Izquierda", + "sectionRight": "Derecha" + } + }, + "user-interface": { + "animation-disable": { + "description": "Desactiva todas las animaciones para una experiencia más rápida y con mayor capacidad de respuesta.", + "label": "Desactivar animaciones de la interfaz de usuario" + }, + "animation-speed": { + "description": "Ajustar la velocidad global de la animación.", + "label": "Velocidad de animación", + "reset": "Restablecer la velocidad de la animación" + }, + "border-radius": { + "description": "Controla la redondez de las esquinas de las ventanas, los botones y otros elementos.", + "label": "Radio de borde", + "reset": "Restablecer el radio del borde" + }, + "compact-lockscreen": { + "description": "Mostrar solo el campo de inicio de sesión y los controles del sistema, ocultando los widgets del clima y multimedia.", + "label": "Pantalla de bloqueo compacta" + }, + "dim-desktop": { + "description": "Atenuar el escritorio cuando los paneles o menús estén abiertos.", + "label": "Dim escritorio" + }, + "scaling": { + "description": "Cambia el tamaño de la interfaz de usuario general, excluyendo la barra.", + "label": "Escalado de la interfaz", + "reset-scaling": "Restablecer el escalado de la interfaz" + }, + "section": { + "description": "Personaliza la apariencia, el ambiente y el comportamiento de la interfaz.", + "label": "Apariencia" + }, + "title": "Interfaz de usuario", + "tooltips": { + "description": "Activar o desactivar los avisos emergentes en toda la interfaz.", + "label": "Mostrar sugerencias" + } } }, "widgets": { @@ -893,9 +889,9 @@ "search-placeholder": "Buscar widgets..." }, "active-window": { - "auto-hide": { - "label": "Ocultar automáticamente", - "description": "Ocultar automáticamente el widget cuando no hay ventana activa." + "hide-mode": { + "label": "Modo de ocultación", + "description": "Controla el comportamiento del widget cuando no hay ventana activa." }, "show-app-icon": { "label": "Mostrar icono de la aplicación", @@ -908,6 +904,10 @@ "width": { "description": "Controla el tamaño horizontal del widget.", "label": "Ancho del widget" + }, + "colorize-icons": { + "label": "Colorear iconos", + "description": "Aplicar colores del tema al icono de la ventana activa." } }, "system-monitor": { @@ -1038,9 +1038,9 @@ } }, "media-mini": { - "auto-hide": { - "label": "Ocultar automáticamente", - "description": "Ocultar automáticamente el widget cuando no se está reproduciendo ningún medio." + "hide-mode": { + "label": "Modo de ocultación", + "description": "Controla el comportamiento del widget cuando no se está reproduciendo ningún medio." }, "show-album-art": { "label": "Mostrar arte del álbum", @@ -1101,6 +1101,16 @@ "only-same-output": { "description": "Muestra solo las aplicaciones del resultado donde se encuentra la barra.", "label": "Solo de la misma salida" + }, + "colorize-icons": { + "label": "Colorear iconos", + "description": "Aplicar colores del tema a los iconos de la barra de tareas." + } + }, + "tray": { + "colorize-icons": { + "label": "Colorear iconos", + "description": "Aplicar colores del tema a los iconos de la bandeja del sistema." } } } @@ -1270,7 +1280,8 @@ "density": { "compact": "Compacta", "default": "Predeterminada", - "comfortable": "Cómoda" + "comfortable": "Cómoda", + "mini": "Mini" } }, "launcher": { @@ -1359,6 +1370,11 @@ "microphone-input": "Entrada del micrófono", "both": "Salida del sistema + entrada del micrófono" } + }, + "hide-modes": { + "hidden": "Ocultar cuando esté vacío", + "transparent": "Transparente cuando está vacío", + "visible": "Siempre visible" } }, "session-menu": { @@ -1540,6 +1556,9 @@ "enabled": "Activado", "disabled": "Desactivado" }, + "kofi": { + "opened": "Página de Ko-fi abierta en tu navegador" + }, "do-not-disturb": { "enabled": "'No molestar' activado", "disabled": "'No molestar' desactivado", diff --git a/Assets/Translations/fr.json b/Assets/Translations/fr.json index 5f7bec3a..9cb02955 100644 --- a/Assets/Translations/fr.json +++ b/Assets/Translations/fr.json @@ -13,32 +13,6 @@ }, "select-avatar": "Sélectionner une image d'avatar" }, - "ui": { - "section": { - "label": "Interface utilisateur", - "description": "Personnalisez l'apparence, l'ergonomie et le comportement de l'interface." - }, - "tooltips": { - "label": "Afficher les tooltips", - "description": "Activer ou désactiver les tooltips dans toute l'interface." - }, - "dim-desktop": { - "label": "Assombrir le bureau", - "description": "Assombrir le bureau lorsque des panneaux ou des menus sont ouverts." - }, - "border-radius": { - "label": "Rayon de bordure", - "description": "Contrôle l'arrondi des coins des fenêtres, des boutons et d'autres éléments." - }, - "animation-speed": { - "label": "Vitesse d'animation", - "description": "Ajustez la vitesse globale des animations." - }, - "animation-disable": { - "label": "Désactiver les animations de l'interface", - "description": "Désactiver toutes les animations pour une expérience plus rapide et réactive." - } - }, "screen-corners": { "section": { "label": "Coins de l'écran", @@ -54,7 +28,8 @@ }, "radius": { "label": "Rayon des coins de l'écran", - "description": "Ajustez l'arrondi des coins de l'écran." + "description": "Ajustez l'arrondi des coins de l'écran.", + "reset": "Réinitialiser le rayon des coins de l'écran" } }, "fonts": { @@ -83,33 +58,6 @@ } }, "reset-scaling": "Réinitialiser l'échelle" - }, - "control-center": { - "title": "Centre de contrôle", - "section": { - "label": "Centre de contrôle", - "description": "Configurer le positionnement et le comportement du panneau du centre de contrôle." - }, - "position": { - "label": "Position", - "description": "Choisissez où apparaît le panneau du centre de contrôle lors de l'ouverture." - }, - "quickSettingsStyle": { - "section": { - "label": "Style des paramètres rapides", - "description": "Personnalisez l'apparence et le comportement des paramètres rapides dans le centre de contrôle." - }, - "style": { - "label": "Style des paramètres rapides", - "description": "Choisissez le style visuel pour les commutateurs et contrôles des paramètres rapides." - } - }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configurez et gérez les widgets du centre de contrôle et leurs options d'affichage." - } - } } }, "audio": { @@ -196,11 +144,9 @@ "monitors": { "section": { "label": "Paramètres par moniteur", - "description": "Ajustez la mise à l'échelle et la luminosité pour chaque écran." + "description": "Ajustez la luminosité pour chaque écran." }, - "scale": "Mise à l'échelle", "brightness": "Luminosité", - "reset-scaling": "Réinitialiser la mise à l'échelle", "brightness-step": { "label": "Incrément de luminosité", "description": "Ajustez l'incrément pour les changements de luminosité (molette de la souris et raccourcis clavier)." @@ -318,6 +264,10 @@ "floating-distance": { "label": "Distance de flottaison du dock", "description": "Ajustez la distance de flottaison par rapport au bord de l'écran." + }, + "colorize-icons": { + "label": "Coloriser les icônes", + "description": "Appliquer les couleurs du thème aux icônes d'applications du dock (applications non focalisées uniquement)." } }, "monitors": { @@ -430,6 +380,10 @@ "label": "Activer l'affichage à l'écran", "description": "Afficher en temps réel les changements de volume et de luminosité." }, + "always-on-top": { + "label": "Toujours au premier plan", + "description": "Afficher l'OSD au-dessus des fenêtres plein écran et autres couches." + }, "location": { "label": "Emplacement", "description": "Emplacement des affichages à l'écran." @@ -734,29 +688,8 @@ "description": "Un grand merci à notre {count} super contributeur !", "description_plural": "Un grand merci à nos {count} super contributeurs !" } - } - }, - "control-center": { - "title": "Centre de contrôle", - "quickSettingsStyle": { - "section": { - "label": "Style des paramètres rapides", - "description": "Personnalisez l'apparence et le comportement des paramètres rapides dans le centre de contrôle." - }, - "style": { - "label": "Style des paramètres rapides", - "description": "Choisissez le style visuel pour les commutateurs et contrôles des paramètres rapides." - } }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configurez et gérez les widgets du centre de contrôle et leurs options d'affichage." - } - }, - "quickSettings": { - "sectionName": "Paramètres rapides" - } + "support": "Soutenez-nous" }, "hooks": { "title": "Hooks", @@ -790,6 +723,69 @@ "description": "• Hook Fond d'écran : $1 = chemin du fond d'écran, $2 = nom de l'écran\n• Hook de bascule de thème : $1 = true/false (état du mode sombre)" } } + }, + "control-center": { + "position": { + "description": "Choisissez où le panneau du Centre de contrôle apparaît lorsqu'il est ouvert.", + "label": "Position" + }, + "section": { + "description": "Configurer le positionnement et le comportement du panneau du Centre de contrôle.", + "label": "Apparence" + }, + "title": "Centre de contrôle", + "cards": { + "section": { + "description": "Personnalisez les commandes qui apparaissent dans le Centre de contrôle et leur ordre d'affichage.", + "label": "Cartes" + } + }, + "shortcuts": { + "section": { + "description": "Configurer et gérer les widgets de raccourcis.", + "label": "Widgets de raccourcis" + }, + "sectionLeft": "Gauche", + "sectionRight": "Droite" + } + }, + "user-interface": { + "animation-disable": { + "description": "Désactiver toutes les animations pour une expérience plus rapide et plus réactive.", + "label": "Désactiver les animations de l'interface utilisateur" + }, + "animation-speed": { + "description": "Ajuster la vitesse globale de l'animation.", + "label": "Vitesse d'animation", + "reset": "Réinitialiser la vitesse de l'animation" + }, + "border-radius": { + "description": "Contrôle l'arrondi des angles des fenêtres, des boutons et d'autres éléments.", + "label": "Rayon de bordure", + "reset": "Réinitialiser le rayon de la bordure" + }, + "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.", + "label": "Écran de verrouillage compact" + }, + "dim-desktop": { + "description": "Atténuer le bureau lorsque des panneaux ou des menus sont ouverts.", + "label": "Dim bureau" + }, + "scaling": { + "description": "Modifie la taille de l'interface utilisateur générale, à l'exception de la barre.", + "label": "Mise à l'échelle de l'interface", + "reset-scaling": "Réinitialiser l'échelle de l'interface" + }, + "section": { + "description": "Personnaliser l'apparence, l'ergonomie et le comportement de l'interface.", + "label": "Apparence" + }, + "title": "Interface utilisateur", + "tooltips": { + "description": "Activer ou désactiver les info-bulles dans toute l'interface.", + "label": "Afficher les infobulles" + } } }, "widgets": { @@ -901,13 +897,17 @@ "label": "Mode de défilement", "description": "Contrôler quand le défilement de texte est activé pour les titres de fenêtre longs." }, - "auto-hide": { - "label": "Masquer automatiquement", - "description": "Masquer automatiquement le widget quand aucune fenêtre n'est active." + "hide-mode": { + "label": "Mode de masquage", + "description": "Contrôle le comportement du widget lorsqu'aucune fenêtre n'est active." }, "width": { "description": "Contrôle la taille horizontale du widget.", "label": "Largeur du widget" + }, + "colorize-icons": { + "label": "Coloriser les icônes", + "description": "Appliquer les couleurs du thème à l'icône de la fenêtre active." } }, "system-monitor": { @@ -1054,9 +1054,9 @@ "label": "Mode de défilement", "description": "Contrôler quand le défilement de texte est activé pour les titres de piste longs." }, - "auto-hide": { - "label": "Masquer automatiquement", - "description": "Masquer automatiquement le widget quand aucun média n'est en cours de lecture." + "hide-mode": { + "label": "Mode de masquage", + "description": "Contrôle le comportement du widget lorsqu'aucun média n'est en cours de lecture." }, "no-active-player": "Aucun lecteur actif" }, @@ -1101,6 +1101,16 @@ "only-same-output": { "description": "Afficher uniquement les applications de la sortie où la barre est située.", "label": "Seulement à partir de la même sortie" + }, + "colorize-icons": { + "label": "Coloriser les icônes", + "description": "Appliquer les couleurs du thème aux icônes de la barre des tâches." + } + }, + "tray": { + "colorize-icons": { + "label": "Coloriser les icônes", + "description": "Appliquer les couleurs du thème aux icônes de la barre système." } } } @@ -1270,7 +1280,8 @@ "density": { "compact": "Compact", "default": "Défaut", - "comfortable": "Confortable" + "comfortable": "Confortable", + "mini": "Mini" } }, "launcher": { @@ -1359,6 +1370,11 @@ "microphone-input": "Entrée microphone", "both": "Sortie système + entrée microphone" } + }, + "hide-modes": { + "hidden": "Masquer si vide", + "transparent": "Transparent quand vide", + "visible": "Toujours visible" } }, "session-menu": { @@ -1540,6 +1556,9 @@ "enabled": "Activé", "disabled": "Désactivé" }, + "kofi": { + "opened": "Page Ko-fi ouverte dans votre navigateur" + }, "do-not-disturb": { "enabled": "'Ne pas déranger' activé", "disabled": "'Ne pas déranger' désactivé", diff --git a/Assets/Translations/pt.json b/Assets/Translations/pt.json index e46f67cb..2b90a189 100644 --- a/Assets/Translations/pt.json +++ b/Assets/Translations/pt.json @@ -13,32 +13,6 @@ }, "select-avatar": "Selecionar imagem de avatar" }, - "ui": { - "section": { - "label": "Interface do usuário", - "description": "Personalize a aparência, a sensação e o comportamento da interface." - }, - "tooltips": { - "label": "Mostrar tooltips", - "description": "Ativar ou desativar tooltips em toda a interface." - }, - "dim-desktop": { - "label": "Escurecer área de trabalho", - "description": "Escurece a área de trabalho quando painéis ou menus estão abertos." - }, - "border-radius": { - "label": "Raio da borda", - "description": "Controla o arredondamento dos cantos de janelas, botões e outros elementos." - }, - "animation-speed": { - "label": "Velocidade da animação", - "description": "Ajuste a velocidade global da animação." - }, - "animation-disable": { - "label": "Desativar animações da interface", - "description": "Desativar todas as animações para uma experiência mais rápida e responsiva." - } - }, "screen-corners": { "section": { "label": "Cantos da tela", @@ -54,7 +28,8 @@ }, "radius": { "label": "Raio dos cantos da tela", - "description": "Ajuste os cantos arredondados da tela." + "description": "Ajuste os cantos arredondados da tela.", + "reset": "Redefinir raio dos cantos da tela" } }, "fonts": { @@ -83,33 +58,6 @@ } }, "reset-scaling": "Redefinir escala" - }, - "control-center": { - "title": "Centro de controle", - "section": { - "label": "Centro de controle", - "description": "Configurar o posicionamento e comportamento do painel do centro de controle." - }, - "position": { - "label": "Posição", - "description": "Escolha onde o painel do centro de controle aparece quando aberto." - }, - "quickSettingsStyle": { - "section": { - "label": "Estilo de configurações rápidas", - "description": "Personalize a aparência e o comportamento das configurações rápidas no centro de controle." - }, - "style": { - "label": "Estilo de configurações rápidas", - "description": "Escolha o estilo visual para os interruptores e controles de configurações rápidas." - } - }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configure e gerencie os widgets do centro de controle e suas opções de exibição." - } - } } }, "audio": { @@ -196,11 +144,9 @@ "monitors": { "section": { "label": "Configurações por monitor", - "description": "Ajuste a escala e o brilho para cada tela." + "description": "Ajustar o brilho das configurações para cada tela." }, - "scale": "Escala", "brightness": "Brilho", - "reset-scaling": "Redefinir escala", "brightness-step": { "label": "Tamanho do passo do brilho", "description": "Ajuste o tamanho do passo para alterações de brilho (roda do mouse e atalhos de teclado)." @@ -318,6 +264,10 @@ "floating-distance": { "label": "Distância de flutuação da dock", "description": "Ajuste a distância de flutuação da borda da tela." + }, + "colorize-icons": { + "label": "Colorir ícones", + "description": "Aplicar cores do tema aos ícones de aplicativos da dock (apenas aplicativos não focados)." } }, "monitors": { @@ -700,29 +650,8 @@ "description": "Agradecimentos ao nosso incrível colaborador!", "description_plural": "Agradecimentos aos nossos {count} incríveis colaboradores!" } - } - }, - "control-center": { - "title": "Centro de controle", - "quickSettingsStyle": { - "section": { - "label": "Estilo de configurações rápidas", - "description": "Personalize a aparência e o comportamento das configurações rápidas no centro de controle." - }, - "style": { - "label": "Estilo de configurações rápidas", - "description": "Escolha o estilo visual para os interruptores e controles de configurações rápidas." - } }, - "widgets": { - "section": { - "label": "Widgets", - "description": "Configure e gerencie os widgets do centro de controle e suas opções de exibição." - } - }, - "quickSettings": { - "sectionName": "Configurações rápidas" - } + "support": "Apoie-nos" }, "hooks": { "title": "Hooks", @@ -770,6 +699,10 @@ "label": "Ativar exibição na tela", "description": "Mostrar alterações de volume e brilho em tempo real." }, + "always-on-top": { + "label": "Sempre no topo", + "description": "Exibir OSD acima de janelas em tela cheia e outras camadas." + }, "location": { "label": "Localização", "description": "Onde a exibição na tela aparece." @@ -790,6 +723,69 @@ "description": "Mostrar a OSD em monitores específicos. Padrão é todos se nenhum for escolhido." } } + }, + "control-center": { + "position": { + "description": "Escolha onde o painel da Central de Controle aparece quando aberto.", + "label": "Posição" + }, + "section": { + "description": "Configurar o posicionamento e o comportamento do painel da Central de Controle.", + "label": "Aparência" + }, + "title": "Central de Controle", + "cards": { + "section": { + "description": "Personalize quais controles aparecem na Central de Controle e em que ordem.", + "label": "Cartas" + } + }, + "shortcuts": { + "section": { + "description": "Configure e gerencie os widgets de atalhos.", + "label": "Widgets de atalhos" + }, + "sectionLeft": "Esquerda", + "sectionRight": "Direito/Certo/À direita" + } + }, + "user-interface": { + "animation-disable": { + "description": "Desative todas as animações para uma experiência mais rápida e responsiva.", + "label": "Desativar animações da interface do usuário" + }, + "animation-speed": { + "description": "Ajustar a velocidade global da animação.", + "label": "Velocidade da animação", + "reset": "Redefinir velocidade da animação" + }, + "border-radius": { + "description": "Controla o arredondamento dos cantos de janelas, botões e outros elementos.", + "label": "Raio da borda", + "reset": "Redefinir raio da borda" + }, + "compact-lockscreen": { + "description": "Mostrar apenas a entrada de login e os controles do sistema, ocultando widgets de clima e mídia.", + "label": "Tela de bloqueio compacta" + }, + "dim-desktop": { + "description": "Escurecer a área de trabalho quando painéis ou menus estiverem abertos.", + "label": "Dim área de trabalho" + }, + "scaling": { + "description": "Altera o tamanho da interface geral do usuário, excluindo a barra.", + "label": "Escalonamento da interface", + "reset-scaling": "Redefinir escala da interface" + }, + "section": { + "description": "Personalize a aparência, a sensação e o comportamento da interface.", + "label": "Aparência" + }, + "title": "Interface do usuário", + "tooltips": { + "description": "Ativar ou desativar dicas de ferramentas em toda a interface.", + "label": "Mostrar dicas de ferramenta" + } } }, "widgets": { @@ -893,9 +889,9 @@ "search-placeholder": "Pesquisar widgets..." }, "active-window": { - "auto-hide": { - "label": "Ocultar automaticamente", - "description": "Ocultar automaticamente o widget quando nenhuma janela está ativa." + "hide-mode": { + "label": "Modo de ocultação", + "description": "Controla o comportamento do widget quando nenhuma janela está ativa." }, "show-app-icon": { "label": "Mostrar ícone do aplicativo", @@ -908,6 +904,10 @@ "width": { "description": "Controla o tamanho horizontal do widget.", "label": "Largura do Widget" + }, + "colorize-icons": { + "label": "Colorir ícones", + "description": "Aplicar cores do tema ao ícone da janela ativa." } }, "system-monitor": { @@ -1038,9 +1038,9 @@ } }, "media-mini": { - "auto-hide": { - "label": "Ocultar automaticamente", - "description": "Ocultar automaticamente o widget quando nenhuma mídia está sendo reproduzida." + "hide-mode": { + "label": "Modo de ocultação", + "description": "Controla o comportamento do widget quando nenhuma mídia está sendo reproduzida." }, "show-album-art": { "label": "Mostrar arte do álbum", @@ -1101,6 +1101,16 @@ "only-same-output": { "description": "Mostrar apenas os aplicativos da saída onde a barra está localizada.", "label": "Apenas da mesma saída" + }, + "colorize-icons": { + "label": "Colorir ícones", + "description": "Aplicar cores do tema aos ícones da barra de tarefas." + } + }, + "tray": { + "colorize-icons": { + "label": "Colorir ícones", + "description": "Aplicar cores do tema aos ícones da bandeja do sistema." } } } @@ -1311,7 +1321,8 @@ "density": { "compact": "Compacta", "default": "Padrão", - "comfortable": "Confortável" + "comfortable": "Confortável", + "mini": "Mini" } }, "display-mode": { @@ -1359,6 +1370,11 @@ "microphone-input": "Entrada do microfone", "both": "Saída do sistema + entrada do microfone" } + }, + "hide-modes": { + "hidden": "Ocultar Quando Vazio", + "transparent": "Transparente quando vazio", + "visible": "Sempre Visível" } }, "session-menu": { @@ -1540,6 +1556,9 @@ "enabled": "Ativado", "disabled": "Desativado" }, + "kofi": { + "opened": "Página do Ko-fi aberta no seu navegador" + }, "do-not-disturb": { "enabled": "'Não perturbe' ativado", "disabled": "'Não perturbe' desativado", diff --git a/Assets/Translations/zh-CN.json b/Assets/Translations/zh-CN.json index c6ff1c0f..88758343 100644 --- a/Assets/Translations/zh-CN.json +++ b/Assets/Translations/zh-CN.json @@ -13,32 +13,6 @@ }, "select-avatar": "选择头像图片" }, - "ui": { - "section": { - "label": "用户界面", - "description": "自定义界面的外观、风格和行为。" - }, - "tooltips": { - "label": "显示工具提示", - "description": "在整个界面中启用或禁用工具提示。" - }, - "dim-desktop": { - "label": "调暗桌面", - "description": "当面板或菜单打开时调暗桌面。" - }, - "border-radius": { - "label": "边框圆角", - "description": "控制窗口、按钮及其他元素的边角圆度。" - }, - "animation-speed": { - "label": "动画速度", - "description": "调整全局动画速度。" - }, - "animation-disable": { - "label": "关闭动画", - "description": "禁用所有动画效果,以获得更快速、更灵敏的体验。" - } - }, "screen-corners": { "section": { "label": "屏幕边角", @@ -54,7 +28,8 @@ }, "radius": { "label": "屏幕边角半径", - "description": "调整屏幕圆角的弧度。" + "description": "调整屏幕圆角的弧度。", + "reset": "重置屏幕圆角半径" } }, "fonts": { @@ -83,33 +58,6 @@ "description": "增大或减小等宽文本的尺寸" } } - }, - "control-center": { - "title": "控制中心", - "section": { - "label": "控制中心", - "description": "配置控制中心面板的定位和行为。" - }, - "position": { - "label": "位置", - "description": "选择控制中心面板打开时出现的位置。" - }, - "quickSettingsStyle": { - "section": { - "label": "快速设置样式", - "description": "自定义控制中心中快速设置的外观和行为。" - }, - "style": { - "label": "快速设置样式", - "description": "选择快速设置开关和控件的视觉样式。" - } - }, - "widgets": { - "section": { - "label": "小部件", - "description": "配置和管理控制中心小部件及其显示选项。" - } - } } }, "audio": { @@ -196,11 +144,9 @@ "monitors": { "section": { "label": "显示器设置", - "description": "调整每个显示器的缩放比例和亮度。" + "description": "调整每个显示器的亮度设置。" }, - "scale": "缩放比例", "brightness": "亮度", - "reset-scaling": "重置缩放", "brightness-step": { "label": "亮度步长", "description": "调整亮度变化的步长(滚轮和键盘快捷键)。" @@ -318,6 +264,10 @@ "floating-distance": { "label": "Dock 浮动距离", "description": "调整距离屏幕边缘的浮动距离。" + }, + "colorize-icons": { + "label": "着色图标", + "description": "将主题颜色应用到 Dock 应用图标(仅限非聚焦应用)。" } }, "monitors": { @@ -430,6 +380,10 @@ "label": "启用屏幕显示", "description": "实时显示音量与亮度变化。" }, + "always-on-top": { + "label": "始终置顶", + "description": "在全屏窗口和其他图层之上显示OSD。" + }, "location": { "label": "位置", "description": "屏幕显示出现的位置。" @@ -734,29 +688,8 @@ "description": "向我们 {count} 位超棒的贡献者致敬!", "description_plural": "向我们 {count} 位超棒的贡献者致敬!" } - } - }, - "control-center": { - "title": "控制中心", - "quickSettingsStyle": { - "section": { - "label": "快速设置样式", - "description": "自定义控制中心中快速设置的外观和行为。" - }, - "style": { - "label": "快速设置样式", - "description": "选择快速设置开关和控件的视觉样式。" - } }, - "widgets": { - "section": { - "label": "小部件", - "description": "配置和管理控制中心小部件及其显示选项。" - } - }, - "quickSettings": { - "sectionName": "快速设置" - } + "support": "支持我们" }, "hooks": { "title": "钩子", @@ -790,6 +723,69 @@ "description": "• 壁纸钩子: $1 = 壁纸路径, $2 = 屏幕名称\n• 主题切换钩子: $1 = true/false (深色模式状态)" } } + }, + "control-center": { + "position": { + "description": "选择打开控制中心时面板出现的位置。", + "label": "位置" + }, + "section": { + "description": "配置控制中心面板的位置和行为。", + "label": "外观" + }, + "title": "控制中心", + "cards": { + "section": { + "description": "自定义在控制中心显示的控制项及其顺序。", + "label": "卡片" + } + }, + "shortcuts": { + "section": { + "description": "配置和管理快捷方式小部件。", + "label": "快捷方式小部件" + }, + "sectionLeft": "左", + "sectionRight": "右" + } + }, + "user-interface": { + "animation-disable": { + "description": "禁用所有动画以获得更快、更流畅的体验。", + "label": "禁用 UI 动画" + }, + "animation-speed": { + "description": "调整全局动画速度。", + "label": "动画速度", + "reset": "重置动画速度" + }, + "border-radius": { + "description": "控制窗口、按钮和其他元素的圆角程度。", + "label": "边框半径", + "reset": "重置边框半径" + }, + "compact-lockscreen": { + "description": "仅显示登录输入和系统控制,隐藏天气和媒体小部件。", + "label": "紧凑型锁屏" + }, + "dim-desktop": { + "description": "当面板或菜单打开时,桌面变暗。", + "label": "昏暗的桌面" + }, + "scaling": { + "description": "更改通用用户界面大小,不包括栏。", + "label": "界面缩放", + "reset-scaling": "重置界面缩放" + }, + "section": { + "description": "自定义界面的外观、感觉和行为。", + "label": "外观" + }, + "title": "用户界面", + "tooltips": { + "description": "启用或禁用整个界面的工具提示。", + "label": "显示工具提示" + } } }, "widgets": { @@ -893,9 +889,9 @@ "search-placeholder": "搜索小部件..." }, "active-window": { - "auto-hide": { - "label": "自动隐藏", - "description": "当没有活动窗口时自动隐藏小部件。" + "hide-mode": { + "label": "隐藏模式", + "description": "控制当没有活动窗口时小部件的行为。" }, "show-app-icon": { "label": "显示应用图标", @@ -908,6 +904,10 @@ "width": { "description": "控制小部件的水平尺寸。", "label": "小部件宽度" + }, + "colorize-icons": { + "label": "着色图标", + "description": "将主题颜色应用到活动窗口图标。" } }, "system-monitor": { @@ -1038,9 +1038,9 @@ } }, "media-mini": { - "auto-hide": { - "label": "自动隐藏", - "description": "当没有媒体播放时自动隐藏小部件。" + "hide-mode": { + "label": "隐藏模式", + "description": "控制当没有媒体播放时小部件的行为。" }, "show-album-art": { "label": "显示专辑封面", @@ -1101,6 +1101,16 @@ "only-same-output": { "label": "仅显示同屏幕", "description": "仅显示任务栏所在屏幕上的应用程序" + }, + "colorize-icons": { + "label": "着色图标", + "description": "将主题颜色应用到任务栏图标。" + } + }, + "tray": { + "colorize-icons": { + "label": "着色图标", + "description": "将主题颜色应用到系统托盘图标。" } } } @@ -1270,7 +1280,8 @@ "density": { "compact": "紧凑", "default": "默认", - "comfortable": "舒适" + "comfortable": "舒适", + "mini": "迷你" } }, "launcher": { @@ -1359,6 +1370,11 @@ "microphone-input": "麦克风输入", "both": "系统输出 + 麦克风输入" } + }, + "hide-modes": { + "hidden": "当为空时隐藏", + "transparent": "空时透明", + "visible": "始终可见" } }, "session-menu": { @@ -1540,6 +1556,9 @@ "enabled": "已启用", "disabled": "已禁用" }, + "kofi": { + "opened": "Ko-fi页面已在您的浏览器中打开" + }, "do-not-disturb": { "enabled": "'勿扰模式'已启用", "disabled": "'勿扰模式'已禁用", diff --git a/Assets/settings-default.json b/Assets/settings-default.json index 7f9e9a9f..63418a1b 100644 --- a/Assets/settings-default.json +++ b/Assets/settings-default.json @@ -61,10 +61,12 @@ "dimDesktop": true, "showScreenCorners": false, "forceBlackScreenCorners": false, + "scaleRatio": 1, "radiusRatio": 1, "screenRadiusRatio": 1, "animationSpeed": 1, - "animationDisabled": false + "animationDisabled": false, + "compactLockScreen": false }, "location": { "name": "Tokyo", @@ -109,9 +111,8 @@ }, "controlCenter": { "position": "close_to_bar_button", - "quickSettingsStyle": "compact", - "widgets": { - "quickSettings": [ + "shortcuts": { + "left": [ { "id": "WiFi" }, @@ -119,19 +120,49 @@ "id": "Bluetooth" }, { - "id": "Notifications" + "id": "ScreenRecorder" }, { - "id": "ScreenRecorder" + "id": "WallpaperSelector" + } + ], + "right": [ + { + "id": "Notifications" }, { "id": "PowerProfile" }, { - "id": "WallpaperSelector" + "id": "KeepAwake" + }, + { + "id": "NightLight" } ] - } + }, + "cards": [ + { + "enabled": true, + "id": "profile-card" + }, + { + "enabled": true, + "id": "shortcuts-card" + }, + { + "enabled": true, + "id": "audio-card" + }, + { + "enabled": true, + "id": "weather-card" + }, + { + "enabled": true, + "id": "media-sysmon-card" + } + ] }, "dock": { "displayMode": "always_visible", @@ -139,7 +170,8 @@ "floatingRatio": 1, "onlySameOutput": true, "monitors": [], - "pinnedApps": [] + "pinnedApps": [], + "colorizeIcons": false }, "network": { "wifiEnabled": true @@ -159,7 +191,8 @@ "enabled": true, "location": "top_right", "monitors": [], - "autoHideMs": 2000 + "autoHideMs": 2000, + "alwaysOnTop": false }, "audio": { "volumeStep": 5, @@ -174,7 +207,6 @@ "fontFixed": "DejaVu Sans Mono", "fontDefaultScale": 1, "fontFixedScale": 1, - "monitorsScaling": [], "idleInhibitorEnabled": false, "tooltipsEnabled": true }, @@ -191,6 +223,7 @@ "templates": { "gtk": false, "qt": false, + "kcolorscheme": false, "kitty": false, "ghostty": false, "foot": false, diff --git a/Bin/dev/i18n-json-check.sh b/Bin/dev/i18n-json.sh similarity index 99% rename from Bin/dev/i18n-json-check.sh rename to Bin/dev/i18n-json.sh index a847d66c..0db1585b 100755 --- a/Bin/dev/i18n-json-check.sh +++ b/Bin/dev/i18n-json.sh @@ -123,13 +123,13 @@ EOF # Make API call to Gemini local api_url="https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key=${api_key}" - print_color $BLUE " API URL: $api_url" >&2 + # print_color $BLUE " API URL: $api_url" >&2 local response=$(curl -s -X POST "$api_url" \ -H "Content-Type: application/json" \ -d "$request_body" 2>/dev/null) - print_color $BLUE " API Response: $response" >&2 + # print_color $BLUE " API Response: $response" >&2 # Extract the translation from response - try multiple parsing approaches local translation=$(echo "$response" | jq -r '.candidates[0].content.parts[0].text // .text // empty' 2>/dev/null | sed 's/^[[:space:]]*//;s/[[:space:]]*$//') diff --git a/Commons/Settings.qml b/Commons/Settings.qml index a9ff52c9..167254db 100644 --- a/Commons/Settings.qml +++ b/Commons/Settings.qml @@ -162,10 +162,6 @@ Singleton { "id": "Tray" }, { "id": "NotificationHistory" - }, { - "id": "WiFi" - }, { - "id": "Bluetooth" }, { "id": "Battery" }, { @@ -186,10 +182,12 @@ Singleton { property bool dimDesktop: true property bool showScreenCorners: false property bool forceBlackScreenCorners: false + property real scaleRatio: 1.0 property real radiusRatio: 1.0 property real screenRadiusRatio: 1.0 property real animationSpeed: 1.0 property bool animationDisabled: false + property bool compactLockScreen: false } // location @@ -246,23 +244,43 @@ Singleton { property JsonObject controlCenter: JsonObject { // Position: close_to_bar_button, center, top_left, top_right, bottom_left, bottom_right, bottom_center, top_center property string position: "close_to_bar_button" - property string quickSettingsStyle: "compact" // "compact", "classic", or "modern" - property JsonObject widgets - widgets: JsonObject { - property list quickSettings: [{ + property JsonObject shortcuts + shortcuts: JsonObject { + property list left: [{ "id": "WiFi" }, { "id": "Bluetooth" - }, { - "id": "Notifications" }, { "id": "ScreenRecorder" - }, { - "id": "PowerProfile" }, { "id": "WallpaperSelector" }] + property list right: [{ + "id": "Notifications" + }, { + "id": "PowerProfile" + }, { + "id": "KeepAwake" + }, { + "id": "NightLight" + }] } + property list cards: [{ + "id": "profile-card", + "enabled": true + }, { + "id": "shortcuts-card", + "enabled": true + }, { + "id": "audio-card", + "enabled": true + }, { + "id": "weather-card", + "enabled": true + }, { + "id": "media-sysmon-card", + "enabled": true + }] } // dock @@ -274,6 +292,7 @@ Singleton { property list monitors: [] // Desktop entry IDs pinned to the dock (e.g., "org.kde.konsole", "firefox.desktop") property list pinnedApps: [] + property bool colorizeIcons: false } // network @@ -300,6 +319,7 @@ Singleton { property string location: "top_right" property list monitors: [] property int autoHideMs: 2000 + property bool alwaysOnTop: false } // audio @@ -318,7 +338,6 @@ Singleton { property string fontFixed: "DejaVu Sans Mono" property real fontDefaultScale: 1.0 property real fontFixedScale: 1.0 - property list monitorsScaling: [] property bool idleInhibitorEnabled: false property bool tooltipsEnabled: true } @@ -375,6 +394,23 @@ Singleton { } } + // ----------------------------------------------------- + // Function to preprocess paths by expanding "~" to user's home directory + function preprocessPath(path) { + if (typeof path !== "string" || path === "") { + return path + } + + // Expand "~" to user's home directory + if (path.startsWith("~/")) { + return Quickshell.env("HOME") + path.substring(1) + } else if (path === "~") { + return Quickshell.env("HOME") + } + + return path + } + // ----------------------------------------------------- // Public function to trigger immediate settings saving function saveImmediate() { diff --git a/Commons/Style.qml b/Commons/Style.qml index ab09232f..aaad6128 100644 --- a/Commons/Style.qml +++ b/Commons/Style.qml @@ -29,27 +29,25 @@ Singleton { property int fontWeightBold: 700 // Radii - property int radiusXXS: 4 * Settings.data.general.radiusRatio - property int radiusXS: 8 * Settings.data.general.radiusRatio - property int radiusS: 12 * Settings.data.general.radiusRatio - property int radiusM: 16 * Settings.data.general.radiusRatio - property int radiusL: 20 * Settings.data.general.radiusRatio - - //screen Radii - property int screenRadius: 20 * Settings.data.general.screenRadiusRatio + property int radiusXXS: Math.round(4 * Settings.data.general.radiusRatio) + property int radiusXS: Math.round(8 * Settings.data.general.radiusRatio) + property int radiusS: Math.round(12 * Settings.data.general.radiusRatio) + property int radiusM: Math.round(16 * Settings.data.general.radiusRatio) + property int radiusL: Math.round(20 * Settings.data.general.radiusRatio) + property int screenRadius: Math.round(20 * Settings.data.general.screenRadiusRatio) // Border - property int borderS: 1 - property int borderM: 2 - property int borderL: 3 + property int borderS: Math.round(1 * uiScaleRatio) + property int borderM: Math.round(2 * uiScaleRatio) + property int borderL: Math.round(3 * uiScaleRatio) // Margins (for margins and spacing) - property int marginXXS: 2 - property int marginXS: 4 - property int marginS: 8 - property int marginM: 12 - property int marginL: 16 - property int marginXL: 24 + property int marginXXS: Math.round(2 * uiScaleRatio) + property int marginXS: Math.round(4 * uiScaleRatio) + property int marginS: Math.round(6 * uiScaleRatio) + property int marginM: Math.round(9 * uiScaleRatio) + property int marginL: Math.round(13 * uiScaleRatio) + property int marginXL: Math.round(18 * uiScaleRatio) // Opacity property real opacityNone: 0.0 @@ -70,31 +68,39 @@ Singleton { property int tooltipDelayLong: 1200 property int pillDelay: 500 - // Settings widgets base size + // Widgets base size property real baseWidgetSize: 33 property real sliderWidth: 200 + property real uiScaleRatio: Settings.data.general.scaleRatio + // Bar Dimensions property real barHeight: { - if (Settings.data.bar.density === "compact") { + switch (Settings.data.bar.density) { + case "mini": + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 22 : 20 + case "compact": return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 27 : 25 - } - if (Settings.data.bar.density === "default") { - return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31 - } - if (Settings.data.bar.density === "comfortable") { + case "comfortable": return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37 + default: + + case "default": + return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31 } } property real capsuleHeight: { - if (Settings.data.bar.density === "compact") { + switch (Settings.data.bar.density) { + case "mini": + return barHeight * 1.0 + case "compact": return barHeight * 0.85 - } - if (Settings.data.bar.density === "default") { - return barHeight * 0.82 - } - if (Settings.data.bar.density === "comfortable") { + case "comfortable": return barHeight * 0.73 + default: + + case "default": + return barHeight * 0.82 } } } diff --git a/Commons/TablerIcons.qml b/Commons/TablerIcons.qml index 39743adb..3522e30d 100644 --- a/Commons/TablerIcons.qml +++ b/Commons/TablerIcons.qml @@ -101,7 +101,9 @@ Singleton { "brightness-low": "brightness-down-filled", "brightness-high": "brightness-up-filled", "settings-general": "adjustments-horizontal", - "settings-bar": "capsule-horizontal", + "settings-bar": "crop-16-9", + "settings-user-interface": "layout-board", + "settings-control-center": "adjustments-horizontal", "settings-dock": "layout-bottombar", "settings-launcher": "rocket", "settings-audio": "device-speaker", diff --git a/Modules/Background/ScreenCorners.qml b/Modules/Background/ScreenCorners.qml index c8302ca6..7ddda724 100644 --- a/Modules/Background/ScreenCorners.qml +++ b/Modules/Background/ScreenCorners.qml @@ -16,21 +16,11 @@ Loader { id: root required property ShellScreen modelData - property real scaling: ScalingService.getScreenScale(screen) screen: modelData property color cornerColor: Settings.data.general.forceBlackScreenCorners ? Qt.rgba(0, 0, 0, 1) : Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity) - property real cornerRadius: Style.screenRadius * scaling - property real cornerSize: Style.screenRadius * scaling - - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if (screenName === screen.name) { - scaling = scale - } - } - } + property real cornerRadius: Style.screenRadius + property real cornerSize: Style.screenRadius color: Color.transparent @@ -48,10 +38,10 @@ Loader { margins { // When bar is floating, corners should be at screen edges (no margins) // When bar is not floating, respect bar margins as before - top: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0 - bottom: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0 - left: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "left" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0 - right: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "right" && Settings.data.bar.backgroundOpacity > 0 ? Math.round(Style.barHeight * scaling) : 0 + top: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "top" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0 + bottom: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "bottom" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0 + left: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "left" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0 + right: !Settings.data.bar.floating && BarService.isVisible && ((modelData && Settings.data.bar.monitors.includes(modelData.name)) || (Settings.data.bar.monitors.length === 0)) && Settings.data.bar.position === "right" && Settings.data.bar.backgroundOpacity > 0 ? Style.barHeight : 0 } mask: Region {} diff --git a/Modules/Bar/Bar.qml b/Modules/Bar/Bar.qml index 701d71c1..8cc33280 100644 --- a/Modules/Bar/Bar.qml +++ b/Modules/Bar/Bar.qml @@ -105,8 +105,8 @@ Variants { // When auto-hide is enabled, actually toggle window visibility after animations visible: root.autoHide ? root.barWindowVisible : true - implicitHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? screen.height : Math.round(Style.barHeight * scaling) - implicitWidth: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? Math.round(Style.barHeight * scaling) : screen.width + implicitHeight: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? screen.height : Style.barHeight + implicitWidth: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? Style.barHeight : screen.width color: Color.transparent anchors { @@ -119,10 +119,10 @@ Variants { // Floating bar margins - only apply when floating is enabled // Also don't apply margin on the opposite side ot the bar orientation, ex: if bar is floating on top, margin is only applied on top, not bottom. margins { - top: Settings.data.bar.floating && Settings.data.bar.position !== "bottom" ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - bottom: Settings.data.bar.floating && Settings.data.bar.position !== "top" ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - left: Settings.data.bar.floating && Settings.data.bar.position !== "right" ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - right: Settings.data.bar.floating && Settings.data.bar.position !== "left" ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 + top: Settings.data.bar.floating && Settings.data.bar.position !== "bottom" ? Settings.data.bar.marginVertical * Style.marginXL : 0 + bottom: Settings.data.bar.floating && Settings.data.bar.position !== "top" ? Settings.data.bar.marginVertical * Style.marginXL : 0 + left: Settings.data.bar.floating && Settings.data.bar.position !== "right" ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + right: Settings.data.bar.floating && Settings.data.bar.position !== "left" ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 } Component.onCompleted: { @@ -244,8 +244,8 @@ Variants { ColumnLayout { anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top - anchors.topMargin: Style.marginM * root.scaling - spacing: Style.marginS * root.scaling + anchors.topMargin: Style.marginM + spacing: Style.marginS Repeater { model: Settings.data.bar.widgets.left @@ -253,7 +253,6 @@ Variants { widgetId: (modelData.id !== undefined ? modelData.id : "") widgetProps: { "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), "widgetId": modelData.id, "section": "left", "sectionWidgetIndex": index, @@ -268,7 +267,7 @@ Variants { ColumnLayout { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * root.scaling + spacing: Style.marginS Repeater { model: Settings.data.bar.widgets.center @@ -276,7 +275,6 @@ Variants { widgetId: (modelData.id !== undefined ? modelData.id : "") widgetProps: { "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), "widgetId": modelData.id, "section": "center", "sectionWidgetIndex": index, @@ -291,8 +289,8 @@ Variants { ColumnLayout { anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom - anchors.bottomMargin: Style.marginM * root.scaling - spacing: Style.marginS * root.scaling + anchors.bottomMargin: Style.marginM + spacing: Style.marginS Repeater { model: Settings.data.bar.widgets.right @@ -300,7 +298,6 @@ Variants { widgetId: (modelData.id !== undefined ? modelData.id : "") widgetProps: { "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), "widgetId": modelData.id, "section": "right", "sectionWidgetIndex": index, @@ -324,9 +321,9 @@ Variants { id: leftSection objectName: "leftSection" anchors.left: parent.left - anchors.leftMargin: Style.marginS * root.scaling + anchors.leftMargin: Style.marginS anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * root.scaling + spacing: Style.marginS Repeater { model: Settings.data.bar.widgets.left @@ -334,7 +331,6 @@ Variants { widgetId: (modelData.id !== undefined ? modelData.id : "") widgetProps: { "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), "widgetId": modelData.id, "section": "left", "sectionWidgetIndex": index, @@ -351,7 +347,7 @@ Variants { objectName: "centerSection" anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * root.scaling + spacing: Style.marginS Repeater { model: Settings.data.bar.widgets.center @@ -359,7 +355,6 @@ Variants { widgetId: (modelData.id !== undefined ? modelData.id : "") widgetProps: { "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), "widgetId": modelData.id, "section": "center", "sectionWidgetIndex": index, @@ -375,9 +370,9 @@ Variants { id: rightSection objectName: "rightSection" anchors.right: parent.right - anchors.rightMargin: Style.marginS * root.scaling + anchors.rightMargin: Style.marginS anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * root.scaling + spacing: Style.marginS Repeater { model: Settings.data.bar.widgets.right @@ -385,7 +380,6 @@ Variants { widgetId: (modelData.id !== undefined ? modelData.id : "") widgetProps: { "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), "widgetId": modelData.id, "section": "right", "sectionWidgetIndex": index, diff --git a/Modules/Bar/Bluetooth/BluetoothDevicesList.qml b/Modules/Bar/Bluetooth/BluetoothDevicesList.qml index f40b13e1..8e144c31 100644 --- a/Modules/Bar/Bluetooth/BluetoothDevicesList.qml +++ b/Modules/Bar/Bluetooth/BluetoothDevicesList.qml @@ -18,11 +18,11 @@ ColumnLayout { } Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: root.label - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mSecondary font.weight: Style.fontWeightMedium Layout.fillWidth: true @@ -51,35 +51,35 @@ ColumnLayout { } Layout.fillWidth: true - Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * scaling * 2) - radius: Style.radiusM * scaling + Layout.preferredHeight: deviceLayout.implicitHeight + (Style.marginM * 2) + radius: Style.radiusM color: Color.mSurface - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) border.color: getContentColor(Color.mOutline) RowLayout { id: deviceLayout anchors.fill: parent - anchors.margins: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginM + spacing: Style.marginM Layout.alignment: Qt.AlignVCenter // One device BT icon NIcon { icon: BluetoothService.getDeviceIcon(modelData) - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: getContentColor(Color.mOnSurface) Layout.alignment: Qt.AlignVCenter } ColumnLayout { Layout.fillWidth: true - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS // Device name NText { text: modelData.name || modelData.deviceName - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium elide: Text.ElideRight color: getContentColor(Color.mOnSurface) @@ -90,7 +90,7 @@ ColumnLayout { NText { text: BluetoothService.getStatusString(modelData) visible: text !== "" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: getContentColor(Color.mOnSurfaceVariant) } @@ -98,26 +98,26 @@ ColumnLayout { RowLayout { visible: modelData.signalStrength !== undefined Layout.fillWidth: true - spacing: Style.marginXS * scaling + spacing: Style.marginXS // Device signal strength - "Unknown" when not connected NText { text: BluetoothService.getSignalStrength(modelData) - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: getContentColor(Color.mOnSurfaceVariant) } NIcon { visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked text: BluetoothService.getSignalIcon(modelData) - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: getContentColor(Color.mOnSurface) } NText { visible: modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked text: (modelData.signalStrength !== undefined && modelData.signalStrength > 0) ? modelData.signalStrength + "%" : "" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: getContentColor(Color.mOnSurface) } } @@ -126,7 +126,7 @@ ColumnLayout { NText { visible: modelData.batteryAvailable text: BluetoothService.getBattery(modelData) - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: getContentColor(Color.mOnSurfaceVariant) } } @@ -142,7 +142,7 @@ ColumnLayout { visible: (modelData.state !== BluetoothDeviceState.Connecting) enabled: (canConnect || canDisconnect) && !isBusy outlined: !button.hovered - fontSize: Style.fontSizeXS * scaling + fontSize: Style.fontSizeXS fontWeight: Style.fontWeightMedium backgroundColor: { if (device.canDisconnect && !isBusy) { diff --git a/Modules/Bar/Bluetooth/BluetoothPanel.qml b/Modules/Bar/Bluetooth/BluetoothPanel.qml index c11d38eb..7e08efef 100644 --- a/Modules/Bar/Bluetooth/BluetoothPanel.qml +++ b/Modules/Bar/Bluetooth/BluetoothPanel.qml @@ -11,8 +11,8 @@ import qs.Widgets NPanel { id: root - preferredWidth: 380 - preferredHeight: 500 + preferredWidth: 380 * Style.uiScaleRatio + preferredHeight: 500 * Style.uiScaleRatio panelKeyboardFocus: true panelContent: Rectangle { @@ -20,23 +20,23 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM // HEADER RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NIcon { icon: "bluetooth" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mPrimary } NText { text: I18n.tr("bluetooth.panel.title") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface Layout.fillWidth: true @@ -46,7 +46,7 @@ NPanel { id: bluetoothSwitch checked: BluetoothService.enabled onToggled: checked => BluetoothService.setBluetoothEnabled(checked) - baseSize: Style.baseWidgetSize * 0.65 * scaling + baseSize: Style.baseWidgetSize * 0.65 } NIconButton { @@ -84,25 +84,25 @@ NPanel { // Center the content within this rectangle ColumnLayout { anchors.centerIn: parent - spacing: Style.marginM * scaling + spacing: Style.marginM NIcon { icon: "bluetooth-off" - pointSize: 64 * scaling + pointSize: 64 color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("bluetooth.panel.disabled") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("bluetooth.panel.enable-message") - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } @@ -120,7 +120,7 @@ NPanel { ColumnLayout { width: parent.width - spacing: Style.marginM * scaling + spacing: Style.marginM // Connected devices BluetoothDevicesList { @@ -168,7 +168,7 @@ NPanel { // Fallback - No devices, scanning ColumnLayout { Layout.alignment: Qt.AlignHCenter - spacing: Style.marginM * scaling + spacing: Style.marginM visible: { if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices) { return false @@ -182,11 +182,11 @@ NPanel { RowLayout { Layout.alignment: Qt.AlignHCenter - spacing: Style.marginXS * scaling + spacing: Style.marginXS NIcon { icon: "refresh" - pointSize: Style.fontSizeXXL * 1.5 * scaling + pointSize: Style.fontSizeXXL * 1.5 color: Color.mPrimary RotationAnimation on rotation { @@ -200,14 +200,14 @@ NPanel { NText { text: I18n.tr("bluetooth.panel.scanning") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnSurface } } NText { text: I18n.tr("bluetooth.panel.pairing-mode") - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } diff --git a/Modules/Bar/Calendar/CalendarPanel.qml b/Modules/Bar/Calendar/CalendarPanel.qml index fc520bf2..68b27ab3 100644 --- a/Modules/Bar/Calendar/CalendarPanel.qml +++ b/Modules/Bar/Calendar/CalendarPanel.qml @@ -10,14 +10,17 @@ import qs.Widgets NPanel { id: root - preferredWidth: Settings.data.location.showWeekNumberInCalendar ? 400 : 380 - preferredHeight: 520 + readonly property var now: Time.date + + preferredWidth: (Settings.data.location.showWeekNumberInCalendar ? 400 : 380) * Style.uiScaleRatio + preferredHeight: 520 * Style.uiScaleRatio + panelKeyboardFocus: true panelContent: ColumnLayout { id: content anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM readonly property int firstDayOfWeek: Qt.locale().firstDayOfWeek property bool isCurrentMonth: checkIsCurrentMonth() @@ -27,6 +30,20 @@ NPanel { return (Time.date.getMonth() === grid.month) && (Time.date.getFullYear() === grid.year) } + Shortcut { + sequence: "Escape" + onActivated: { + if (timerActive) { + cancelTimer() + } else { + cancelTimer() + root.close() + } + } + context: Qt.WidgetShortcut + enabled: root.opened + } + Connections { target: Time function onDateChanged() { @@ -37,8 +54,8 @@ NPanel { // Combined blue banner with date/time and weather summary Rectangle { Layout.fillWidth: true - Layout.preferredHeight: blueColumn.implicitHeight + Style.marginM * scaling * 2 - radius: Style.radiusL * scaling + Layout.preferredHeight: blueColumn.implicitHeight + Style.marginM * 2 + radius: Style.radiusL color: Color.mPrimary ColumnLayout { @@ -46,28 +63,28 @@ NPanel { anchors.top: parent.top anchors.left: parent.left anchors.bottom: parent.bottom - anchors.topMargin: Style.marginM * scaling - anchors.leftMargin: Style.marginM * scaling - anchors.bottomMargin: Style.marginM * scaling - anchors.rightMargin: clockItem.width + (Style.marginM * scaling * 2) + anchors.topMargin: Style.marginM + anchors.leftMargin: Style.marginM + anchors.bottomMargin: Style.marginM + anchors.rightMargin: clockItem.width + (Style.marginM * 2) spacing: 0 // Combined layout for weather icon, date, and weather text RowLayout { Layout.fillWidth: true - height: 60 * scaling + height: 60 * Style.uiScaleRatio clip: true - spacing: Style.marginS * scaling + spacing: Style.marginS // Weather icon and temperature ColumnLayout { Layout.alignment: Qt.AlignVCenter - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS NIcon { Layout.alignment: Qt.AlignHCenter icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : "cloud" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mOnPrimary } @@ -85,7 +102,7 @@ NPanel { temp = Math.round(temp) return `${temp}°${suffix}` } - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold color: Color.mOnPrimary } @@ -100,7 +117,7 @@ NPanel { Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft text: Time.date.getDate() - pointSize: Style.fontSizeXXXL * 1.5 * scaling + pointSize: Style.fontSizeXXXL * 1.5 font.weight: Style.fontWeightBold color: Color.mOnPrimary @@ -119,17 +136,18 @@ NPanel { // Month, year, location ColumnLayout { - // Give the whole column a fixed width to stabilize the layout - Layout.preferredWidth: 170 * scaling + Layout.preferredWidth: 170 * Style.uiScaleRatio Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft - spacing: -Style.marginXS * scaling + Layout.bottomMargin: Style.marginXXS + Layout.topMargin: -Style.marginXXS + spacing: -Style.marginXS RowLayout { spacing: 0 NText { text: Qt.locale().monthName(grid.month, Locale.LongFormat).toUpperCase() - pointSize: Style.fontSizeXL * 1.2 * scaling + pointSize: Style.fontSizeXL * 1.1 font.weight: Style.fontWeightBold color: Color.mOnPrimary Layout.alignment: Qt.AlignBaseline @@ -138,7 +156,7 @@ NPanel { NText { text: ` ${grid.year}` - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold color: Qt.alpha(Color.mOnPrimary, 0.7) Layout.alignment: Qt.AlignBaseline @@ -155,16 +173,16 @@ NPanel { const chunks = Settings.data.location.name.split(",") return chunks[0] } - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium color: Color.mOnPrimary - Layout.maximumWidth: 150 * scaling + Layout.maximumWidth: 150 elide: Text.ElideRight } NText { text: weatherReady ? ` (${LocationService.data.weather.timezone_abbreviation})` : "" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS font.weight: Style.fontWeightMedium color: Qt.alpha(Color.mOnPrimary, 0.7) } @@ -178,24 +196,26 @@ NPanel { } } - // The Clock, anchored separately for stability + // Digital clock with circular progress Item { id: clockItem + Layout.alignment: Qt.AlignVCenter anchors.right: parent.right - anchors.rightMargin: Style.marginM * scaling + anchors.rightMargin: Style.marginM anchors.verticalCenter: parent.verticalCenter - width: Style.fontSizeXXXL * 1.9 * scaling - height: Style.fontSizeXXXL * 1.9 * scaling + height: Math.round((Style.fontSizeXXXL * 1.9) / 2 * Style.uiScaleRatio) * 2 + width: clockItem.height + // Seconds circular progress Canvas { id: secondsProgress anchors.fill: parent - property real progress: Time.date.getSeconds() / 60 + property real progress: now.getSeconds() / 60 onProgressChanged: requestPaint() Connections { target: Time function onDateChanged() { - const total = Time.date.getSeconds() * 1000 + Time.date.getMilliseconds() + const total = now.getSeconds() * 1000 + now.getMilliseconds() secondsProgress.progress = total / 60000 } } @@ -203,39 +223,47 @@ NPanel { var ctx = getContext("2d") var centerX = width / 2 var centerY = height / 2 - var radius = Math.min(width, height) / 2 - 3 * scaling + var radius = Math.min(width, height) / 2 - 3 ctx.reset() + + // Background circle ctx.beginPath() ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI) - ctx.lineWidth = 2.5 * scaling + ctx.lineWidth = 2.5 ctx.strokeStyle = Qt.alpha(Color.mOnPrimary, 0.15) ctx.stroke() + + // Progress arc ctx.beginPath() ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progress * 2 * Math.PI) - ctx.lineWidth = 2.5 * scaling + ctx.lineWidth = 2.5 ctx.strokeStyle = Color.mOnPrimary ctx.lineCap = "round" ctx.stroke() } } + // Digital clock ColumnLayout { anchors.centerIn: parent - spacing: -Style.marginXXS * scaling + spacing: -Style.marginXXS + NText { text: { - var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(new Date(), "hh AP") : Qt.locale().toString(new Date(), "HH") + var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(now, "hh AP") : Qt.locale().toString(now, "HH") return t.split(" ")[0] } - pointSize: Style.fontSizeXS * scaling + + pointSize: Style.fontSizeXS font.weight: Style.fontWeightBold color: Color.mOnPrimary family: Settings.data.ui.fontFixed Layout.alignment: Qt.AlignHCenter } + NText { - text: Qt.formatTime(Time.date, "mm") - pointSize: Style.fontSizeXXS * scaling + text: Qt.formatTime(now, "mm") + pointSize: Style.fontSizeXXS font.weight: Style.fontWeightBold color: Color.mOnPrimary family: Settings.data.ui.fontFixed @@ -250,28 +278,28 @@ NPanel { visible: weatherReady Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter - spacing: Style.marginL * scaling + spacing: Style.marginL Repeater { model: weatherReady ? Math.min(6, LocationService.data.weather.daily.time.length) : 0 delegate: ColumnLayout { Layout.preferredWidth: 0 Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter - spacing: Style.marginS * scaling + spacing: Style.marginS NText { text: { var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/")) return Qt.locale().toString(weatherDate, "ddd") } color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignHCenter } NIcon { Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index]) - pointSize: Style.fontSizeXXL * 1.5 * scaling + pointSize: Style.fontSizeXXL * 1.5 color: Color.mPrimary } NText { @@ -287,7 +315,7 @@ NPanel { min = Math.round(min) return `${max}°/${min}°` } - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant font.weight: Style.fontWeightMedium } @@ -303,7 +331,7 @@ NPanel { Item {} RowLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS NDivider { Layout.fillWidth: true } @@ -339,7 +367,7 @@ NPanel { spacing: 0 Item { visible: Settings.data.location.showWeekNumberInCalendar - Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 * scaling : 0 + Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 : 0 } GridLayout { Layout.fillWidth: true @@ -351,7 +379,7 @@ NPanel { model: 7 Item { Layout.fillWidth: true - Layout.preferredHeight: Style.baseWidgetSize * 0.6 * scaling + Layout.preferredHeight: Style.baseWidgetSize * 0.6 NText { anchors.centerIn: parent text: { @@ -360,7 +388,7 @@ NPanel { return dayNames[dayIndex] } color: Color.mPrimary - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: Style.fontWeightBold horizontalAlignment: Text.AlignHCenter } @@ -374,7 +402,7 @@ NPanel { spacing: 0 ColumnLayout { visible: Settings.data.location.showWeekNumberInCalendar - Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 * scaling : 0 + Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 : 0 Layout.fillHeight: true spacing: 0 Repeater { @@ -385,7 +413,7 @@ NPanel { NText { anchors.centerIn: parent color: Color.mOutline - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS font.weight: Style.fontWeightMedium text: { let firstOfMonth = new Date(grid.year, grid.month, 1) @@ -417,16 +445,16 @@ NPanel { id: grid Layout.fillWidth: true Layout.fillHeight: true - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS month: Time.date.getMonth() year: Time.date.getFullYear() locale: Qt.locale() delegate: Item { Rectangle { - width: Style.baseWidgetSize * 0.9 * scaling - height: Style.baseWidgetSize * 0.9 * scaling + width: Style.baseWidgetSize * 0.9 + height: Style.baseWidgetSize * 0.9 anchors.centerIn: parent - radius: Style.radiusM * scaling + radius: Style.radiusM color: model.today ? Color.mSecondary : Color.transparent NText { anchors.centerIn: parent @@ -439,7 +467,7 @@ NPanel { return Color.mOnSurfaceVariant } opacity: model.month === grid.month ? 1.0 : 0.4 - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: model.today ? Style.fontWeightBold : Style.fontWeightMedium } Behavior on color { diff --git a/Modules/Bar/Extras/BarPill.qml b/Modules/Bar/Extras/BarPill.qml index ff4ae3bb..ba1601d3 100644 --- a/Modules/Bar/Extras/BarPill.qml +++ b/Modules/Bar/Extras/BarPill.qml @@ -12,13 +12,13 @@ Item { property string text: "" property string suffix: "" property string tooltipText: "" + property string density: "" property bool autoHide: false property bool forceOpen: false property bool forceClose: false property bool disableOpen: false property bool rightOpen: false property bool hovered: false - property bool compact: false readonly property string barPosition: Settings.data.bar.position readonly property bool isVerticalBar: barPosition === "left" || barPosition === "right" @@ -54,7 +54,7 @@ Item { disableOpen: root.disableOpen rightOpen: root.rightOpen hovered: root.hovered - compact: root.compact + density: root.density onShown: root.shown() onHidden: root.hidden() onEntered: root.entered() @@ -79,7 +79,7 @@ Item { disableOpen: root.disableOpen rightOpen: root.rightOpen hovered: root.hovered - compact: root.compact + density: root.density onShown: root.shown() onHidden: root.hidden() onEntered: root.entered() diff --git a/Modules/Bar/Extras/BarPillHorizontal.qml b/Modules/Bar/Extras/BarPillHorizontal.qml index a7da0d1d..0c2b5e90 100644 --- a/Modules/Bar/Extras/BarPillHorizontal.qml +++ b/Modules/Bar/Extras/BarPillHorizontal.qml @@ -14,13 +14,13 @@ Item { property string text: "" property string suffix: "" property string tooltipText: "" + property string density: "" property bool autoHide: false property bool forceOpen: false property bool forceClose: false property bool disableOpen: false property bool rightOpen: false property bool hovered: false - property bool compact: false // Effective shown state (true if hovered/animated open or forced) readonly property bool revealed: !forceClose && (forceOpen || showPill) @@ -38,13 +38,28 @@ Item { property bool showPill: false property bool shouldAnimateHide: false - readonly property int pillHeight: Math.round(Style.capsuleHeight * scaling) - readonly property int pillPaddingHorizontal: Math.round(Style.capsuleHeight * 0.2 * scaling) - readonly property int pillOverlap: Math.round(Style.capsuleHeight * 0.5 * scaling) - readonly property int pillMaxWidth: Math.max(1, textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap) + readonly property int pillHeight: Style.capsuleHeight + readonly property int pillPaddingHorizontal: Math.round(Style.capsuleHeight * 0.2) + readonly property int pillOverlap: Math.round(Style.capsuleHeight * 0.5) + readonly property int pillMaxWidth: Math.max(1, Math.round(textItem.implicitWidth + pillPaddingHorizontal * 2 + pillOverlap)) - readonly property real iconSize: Math.max(1, compact ? pillHeight * 0.65 : pillHeight * 0.48) - readonly property real textSize: Math.max(1, compact ? pillHeight * 0.45 : pillHeight * 0.33) + readonly property real iconSize: { + switch (root.density) { + case "compact": + return Math.max(1, Math.round(pillHeight * 0.65)) + default: + return Math.max(1, Math.round(pillHeight * 0.48)) + } + } + + readonly property real textSize: { + switch (root.density) { + case "compact": + return Math.max(1, Math.round(pillHeight * 0.45)) + default: + return Math.max(1, Math.round(pillHeight * 0.33)) + } + } width: pillHeight + Math.max(0, pill.width - pillOverlap) height: pillHeight @@ -68,10 +83,12 @@ Item { opacity: revealed ? Style.opacityFull : Style.opacityNone color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent - topLeftRadius: rightOpen ? 0 : pillHeight * 0.5 - bottomLeftRadius: rightOpen ? 0 : pillHeight * 0.5 - topRightRadius: rightOpen ? pillHeight * 0.5 : 0 - bottomRightRadius: rightOpen ? pillHeight * 0.5 : 0 + readonly property int halfPillHeight: Math.round(pillHeight * 0.5) + + topLeftRadius: rightOpen ? 0 : halfPillHeight + bottomLeftRadius: rightOpen ? 0 : halfPillHeight + topRightRadius: rightOpen ? halfPillHeight : 0 + bottomRightRadius: rightOpen ? halfPillHeight : 0 anchors.verticalCenter: parent.verticalCenter NText { @@ -80,16 +97,17 @@ Item { x: { // Better text horizontal centering var centerX = (parent.width - width) / 2 - var offset = rightOpen ? Style.marginXS * scaling : -Style.marginXS * scaling + var offset = rightOpen ? Style.marginXS : -Style.marginXS if (forceOpen) { // If its force open, the icon disc background is the same color as the bg pill move text slightly - offset += rightOpen ? -Style.marginXXS * scaling : Style.marginXXS * scaling + offset += rightOpen ? -Style.marginXXS : Style.marginXXS } return centerX + offset } text: root.text + root.suffix family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightBold color: forceOpen ? Color.mOnSurface : Color.mPrimary visible: revealed @@ -131,6 +149,7 @@ Item { NIcon { icon: root.icon pointSize: iconSize + applyUiScale: false color: hovered ? Color.mOnTertiary : Color.mOnSurface // Center horizontally x: (iconCircle.width - width) / 2 diff --git a/Modules/Bar/Extras/BarPillVertical.qml b/Modules/Bar/Extras/BarPillVertical.qml index f11b06e6..c8b53997 100644 --- a/Modules/Bar/Extras/BarPillVertical.qml +++ b/Modules/Bar/Extras/BarPillVertical.qml @@ -12,13 +12,13 @@ Item { property string text: "" property string suffix: "" property string tooltipText: "" + property string density: "" property bool autoHide: false property bool forceOpen: false property bool forceClose: false property bool disableOpen: false property bool rightOpen: false property bool hovered: false - property bool compact: false // Bar position detection for pill direction readonly property string barPosition: Settings.data.bar.position @@ -45,15 +45,30 @@ Item { property bool shouldAnimateHide: false // Sizing logic for vertical bars - readonly property int buttonSize: Math.round(Style.capsuleHeight * scaling) + readonly property int buttonSize: Style.capsuleHeight readonly property int pillHeight: buttonSize - readonly property int pillPaddingVertical: 3 * 2 * scaling // Very precise adjustment don't replace by Style.margin - readonly property int pillOverlap: buttonSize * 0.5 + readonly property int pillPaddingVertical: 3 * 2 // Very precise adjustment don't replace by Style.margin + readonly property int pillOverlap: Math.round(buttonSize * 0.5) readonly property int maxPillWidth: buttonSize - readonly property int maxPillHeight: Math.max(1, textItem.implicitHeight + pillPaddingVertical * 4) + readonly property int maxPillHeight: Math.max(1, Math.round(textItem.implicitHeight + pillPaddingVertical * 4)) - readonly property real iconSize: Math.max(1, compact ? pillHeight * 0.65 : pillHeight * 0.48) - readonly property real textSize: Math.max(1, compact ? pillHeight * 0.38 : pillHeight * 0.33) + readonly property real iconSize: { + switch (root.density) { + case "compact": + return Math.max(1, Math.round(pillHeight * 0.65)) + default: + return Math.max(1, Math.round(pillHeight * 0.48)) + } + } + + readonly property real textSize: { + switch (root.density) { + case "compact": + return Math.max(1, Math.round(pillHeight * 0.38)) + default: + return Math.max(1, Math.round(pillHeight * 0.33)) + } + } // For vertical bars: width is just icon size, height includes pill space width: buttonSize @@ -79,11 +94,13 @@ Item { opacity: revealed ? Style.opacityFull : Style.opacityNone color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent + readonly property int halfButtonSize: Math.round(buttonSize * 0.5) + // Radius logic for vertical expansion - rounded on the side that connects to icon - topLeftRadius: openUpward ? buttonSize * 0.5 : 0 - bottomLeftRadius: openDownward ? buttonSize * 0.5 : 0 - topRightRadius: openUpward ? buttonSize * 0.5 : 0 - bottomRightRadius: openDownward ? buttonSize * 0.5 : 0 + topLeftRadius: openUpward ? halfButtonSize : 0 + bottomLeftRadius: openDownward ? halfButtonSize : 0 + topRightRadius: openUpward ? halfButtonSize : 0 + bottomRightRadius: openDownward ? halfButtonSize : 0 anchors.horizontalCenter: parent.horizontalCenter @@ -92,16 +109,17 @@ Item { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter anchors.verticalCenterOffset: { - var offset = openDownward ? pillPaddingVertical * 0.75 : -pillPaddingVertical * 0.75 + var offset = openDownward ? Math.round(pillPaddingVertical * 0.75) : -Math.round(pillPaddingVertical * 0.75) if (forceOpen) { // If its force open, the icon disc background is the same color as the bg pill move text slightly - offset += rightOpen ? -Style.marginXXS * scaling : Style.marginXXS * scaling + offset += rightOpen ? -Style.marginXXS : Style.marginXXS } return offset } text: root.text + root.suffix family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -154,6 +172,7 @@ Item { NIcon { icon: root.icon pointSize: iconSize + applyUiScale: false color: hovered ? Color.mOnTertiary : Color.mOnSurface // Center horizontally x: (iconCircle.width - width) / 2 diff --git a/Modules/Bar/Extras/BarWidgetLoader.qml b/Modules/Bar/Extras/BarWidgetLoader.qml index d4194d1e..fff11ebf 100644 --- a/Modules/Bar/Extras/BarWidgetLoader.qml +++ b/Modules/Bar/Extras/BarWidgetLoader.qml @@ -16,16 +16,6 @@ Item { implicitWidth: getImplicitSize(loader.item, "implicitWidth") implicitHeight: getImplicitSize(loader.item, "implicitHeight") - Connections { - target: ScalingService - enabled: loader.item && (loader.item.screen !== undefined) - function onScaleChanged(aScreenName, scale) { - if (loader.item && loader.item.screen && aScreenName === screenName) { - loader.item['scaling'] = scale - } - } - } - function getImplicitSize(item, prop) { return (item && item.visible) ? Math.round(item[prop]) : 0 } diff --git a/Modules/Bar/Extras/TrayMenu.qml b/Modules/Bar/Extras/TrayMenu.qml index 9b6088b9..c0f15e0e 100644 --- a/Modules/Bar/Extras/TrayMenu.qml +++ b/Modules/Bar/Extras/TrayMenu.qml @@ -15,23 +15,13 @@ PopupWindow { property bool isSubMenu: false property bool isHovered: rootMouseArea.containsMouse property ShellScreen screen - property real scaling: ScalingService.getScreenScale(screen) - - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if ((screen != null) && (screenName === screen.name)) { - scaling = scale - } - } - } readonly property int menuWidth: 180 - implicitWidth: Math.round(menuWidth * scaling) + implicitWidth: menuWidth // Use the content height of the Flickable for implicit height - implicitHeight: Math.min(screen ? screen.height * 0.9 : Screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2 * scaling)) + implicitHeight: Math.min(screen ? screen.height * 0.9 : Screen.height * 0.9, flickable.contentHeight + (Style.marginS * 2)) visible: false color: Color.transparent anchor.item: anchorItem @@ -98,14 +88,14 @@ PopupWindow { anchors.fill: parent color: Color.mSurface border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM } Flickable { id: flickable anchors.fill: parent - anchors.margins: Style.marginS * scaling + anchors.margins: Style.marginS contentHeight: columnLayout.implicitHeight interactive: true @@ -125,11 +115,11 @@ PopupWindow { Layout.preferredWidth: parent.width Layout.preferredHeight: { if (modelData?.isSeparator) { - return 8 * scaling + return 8 } else { // Calculate based on text content - const textHeight = text.contentHeight || (Style.fontSizeS * scaling * 1.2) - return Math.max(28 * scaling, textHeight + (Style.marginS * 2 * scaling)) + const textHeight = text.contentHeight || (Style.fontSizeS * 1.2) + return Math.max(28, textHeight + (Style.marginS * 2)) } } @@ -138,35 +128,35 @@ PopupWindow { NDivider { anchors.centerIn: parent - width: parent.width - (Style.marginM * scaling * 2) + width: parent.width - (Style.marginM * 2) visible: modelData?.isSeparator ?? false } Rectangle { anchors.fill: parent color: mouseArea.containsMouse ? Color.mTertiary : Color.transparent - radius: Style.radiusS * scaling + radius: Style.radiusS visible: !(modelData?.isSeparator ?? false) RowLayout { anchors.fill: parent - anchors.leftMargin: Style.marginM * scaling - anchors.rightMargin: Style.marginM * scaling - spacing: Style.marginS * scaling + anchors.leftMargin: Style.marginM + anchors.rightMargin: Style.marginM + spacing: Style.marginS NText { id: text Layout.fillWidth: true color: (modelData?.enabled ?? true) ? (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) : Color.mOnSurfaceVariant text: modelData?.text !== "" ? modelData?.text.replace(/[\n\r]+/g, ' ') : "..." - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap } Image { - Layout.preferredWidth: Style.marginL * scaling - Layout.preferredHeight: Style.marginL * scaling + Layout.preferredWidth: Style.marginL + Layout.preferredHeight: Style.marginL source: modelData?.icon ?? "" visible: (modelData?.icon ?? "") !== "" fillMode: Image.PreserveAspectFit @@ -174,7 +164,8 @@ PopupWindow { NIcon { icon: modelData?.hasChildren ? "menu" : "" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS + applyUiScale: false verticalAlignment: Text.AlignVCenter visible: modelData?.hasChildren ?? false color: (mouseArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface) @@ -216,8 +207,8 @@ PopupWindow { } // Need a slight overlap so that menu don't close when moving the mouse to a submenu - const submenuWidth = menuWidth * scaling // Assuming a similar width as the parent - const overlap = 4 * scaling // A small overlap to bridge the mouse path + const submenuWidth = menuWidth // Assuming a similar width as the parent + const overlap = 4 // A small overlap to bridge the mouse path // Determine submenu opening direction based on bar position and available space let openLeft = false diff --git a/Modules/Bar/WiFi/WiFiPanel.qml b/Modules/Bar/WiFi/WiFiPanel.qml index 4bd32b47..9bab6f25 100644 --- a/Modules/Bar/WiFi/WiFiPanel.qml +++ b/Modules/Bar/WiFi/WiFiPanel.qml @@ -10,8 +10,8 @@ import qs.Widgets NPanel { id: root - preferredWidth: 400 - preferredHeight: 500 + preferredWidth: 400 * Style.uiScaleRatio + preferredHeight: 500 * Style.uiScaleRatio panelKeyboardFocus: true property string passwordSsid: "" @@ -25,23 +25,23 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM // Header RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NIcon { icon: Settings.data.network.wifiEnabled ? "wifi" : "wifi-off" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Settings.data.network.wifiEnabled ? Color.mPrimary : Color.mOnSurfaceVariant } NText { text: I18n.tr("wifi.panel.title") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface Layout.fillWidth: true @@ -51,7 +51,7 @@ NPanel { id: wifiSwitch checked: Settings.data.network.wifiEnabled onToggled: checked => NetworkService.setWifiEnabled(checked) - baseSize: Style.baseWidgetSize * 0.65 * scaling + baseSize: Style.baseWidgetSize * 0.65 } NIconButton { @@ -78,28 +78,28 @@ NPanel { Rectangle { visible: NetworkService.lastError.length > 0 Layout.fillWidth: true - Layout.preferredHeight: errorRow.implicitHeight + (Style.marginM * scaling * 2) + Layout.preferredHeight: errorRow.implicitHeight + (Style.marginM * 2) color: Qt.rgba(Color.mError.r, Color.mError.g, Color.mError.b, 0.1) - radius: Style.radiusS * scaling - border.width: Math.max(1, Style.borderS * scaling) + radius: Style.radiusS + border.width: Math.max(1, Style.borderS) border.color: Color.mError RowLayout { id: errorRow anchors.fill: parent - anchors.margins: Style.marginM * scaling - spacing: Style.marginS * scaling + anchors.margins: Style.marginM + spacing: Style.marginS NIcon { icon: "warning" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mError } NText { text: NetworkService.lastError color: Color.mError - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS wrapMode: Text.Wrap Layout.fillWidth: true } @@ -122,7 +122,7 @@ NPanel { ColumnLayout { visible: !Settings.data.network.wifiEnabled anchors.fill: parent - spacing: Style.marginM * scaling + spacing: Style.marginM Item { Layout.fillHeight: true @@ -130,21 +130,21 @@ NPanel { NIcon { icon: "wifi-off" - pointSize: 64 * scaling + pointSize: 64 color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("wifi.panel.disabled") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("wifi.panel.enable-message") - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } @@ -158,7 +158,7 @@ NPanel { ColumnLayout { visible: Settings.data.network.wifiEnabled && NetworkService.scanning && Object.keys(NetworkService.networks).length === 0 anchors.fill: parent - spacing: Style.marginL * scaling + spacing: Style.marginL Item { Layout.fillHeight: true @@ -167,13 +167,13 @@ NPanel { NBusyIndicator { running: true color: Color.mPrimary - size: Style.baseWidgetSize * scaling + size: Style.baseWidgetSize Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("wifi.panel.searching") - pointSize: Style.fontSizeNormal * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } @@ -193,7 +193,7 @@ NPanel { ColumnLayout { width: parent.width - spacing: Style.marginM * scaling + spacing: Style.marginM // Network list Repeater { @@ -211,14 +211,14 @@ NPanel { Rectangle { Layout.fillWidth: true - implicitHeight: netColumn.implicitHeight + (Style.marginM * scaling * 2) - radius: Style.radiusM * scaling + implicitHeight: netColumn.implicitHeight + (Style.marginM * 2) + radius: Style.radiusM // Add opacity for operations in progress opacity: (NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid) ? 0.6 : 1.0 color: modelData.connected ? Qt.rgba(Color.mPrimary.r, Color.mPrimary.g, Color.mPrimary.b, 0.05) : Color.mSurface - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) border.color: modelData.connected ? Color.mPrimary : Color.mOutline // Smooth opacity animation @@ -230,29 +230,29 @@ NPanel { ColumnLayout { id: netColumn - width: parent.width - (Style.marginM * scaling * 2) - x: Style.marginM * scaling - y: Style.marginM * scaling - spacing: Style.marginS * scaling + width: parent.width - (Style.marginM * 2) + x: Style.marginM + y: Style.marginM + spacing: Style.marginS // Main row RowLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS NIcon { icon: NetworkService.signalIcon(modelData.signal) - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: modelData.connected ? Color.mPrimary : Color.mOnSurface } ColumnLayout { Layout.fillWidth: true - spacing: 2 * scaling + spacing: 2 NText { text: modelData.ssid - pointSize: Style.fontSizeNormal * scaling + pointSize: Style.fontSizeM font.weight: modelData.connected ? Style.fontWeightBold : Style.fontWeightMedium color: Color.mOnSurface elide: Text.ElideRight @@ -260,30 +260,30 @@ NPanel { } RowLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS NText { text: I18n.tr("system.signal-strength", { "signal": modelData.signal }) - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnSurfaceVariant } NText { text: "•" - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnSurfaceVariant } NText { text: NetworkService.isSecured(modelData.security) ? modelData.security : "Open" - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnSurfaceVariant } Item { - Layout.preferredWidth: Style.marginXXS * scaling + Layout.preferredWidth: Style.marginXXS } // Update the status badges area (around line 237) @@ -291,14 +291,14 @@ NPanel { visible: modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid color: Color.mPrimary radius: height * 0.5 - width: connectedText.implicitWidth + (Style.marginS * scaling * 2) - height: connectedText.implicitHeight + (Style.marginXXS * scaling * 2) + width: connectedText.implicitWidth + (Style.marginS * 2) + height: connectedText.implicitHeight + (Style.marginXXS * 2) NText { id: connectedText anchors.centerIn: parent text: I18n.tr("wifi.panel.connected") - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnPrimary } } @@ -307,14 +307,14 @@ NPanel { visible: NetworkService.disconnectingFrom === modelData.ssid color: Color.mError radius: height * 0.5 - width: disconnectingText.implicitWidth + (Style.marginS * scaling * 2) - height: disconnectingText.implicitHeight + (Style.marginXXS * scaling * 2) + width: disconnectingText.implicitWidth + (Style.marginS * 2) + height: disconnectingText.implicitHeight + (Style.marginXXS * 2) NText { id: disconnectingText anchors.centerIn: parent text: I18n.tr("wifi.panel.disconnecting") - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnPrimary } } @@ -323,14 +323,14 @@ NPanel { visible: NetworkService.forgettingNetwork === modelData.ssid color: Color.mError radius: height * 0.5 - width: forgettingText.implicitWidth + (Style.marginS * scaling * 2) - height: forgettingText.implicitHeight + (Style.marginXXS * scaling * 2) + width: forgettingText.implicitWidth + (Style.marginS * 2) + height: forgettingText.implicitHeight + (Style.marginXXS * 2) NText { id: forgettingText anchors.centerIn: parent text: I18n.tr("wifi.panel.forgetting") - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnPrimary } } @@ -339,16 +339,16 @@ NPanel { visible: modelData.cached && !modelData.connected && NetworkService.forgettingNetwork !== modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid color: Color.transparent border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) radius: height * 0.5 - width: savedText.implicitWidth + (Style.marginS * scaling * 2) - height: savedText.implicitHeight + (Style.marginXXS * scaling * 2) + width: savedText.implicitWidth + (Style.marginS * 2) + height: savedText.implicitHeight + (Style.marginXXS * 2) NText { id: savedText anchors.centerIn: parent text: I18n.tr("wifi.panel.saved") - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mOnSurfaceVariant } } @@ -357,13 +357,13 @@ NPanel { // Action area RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS NBusyIndicator { visible: NetworkService.connectingTo === modelData.ssid || NetworkService.disconnectingFrom === modelData.ssid || NetworkService.forgettingNetwork === modelData.ssid running: visible color: Color.mPrimary - size: Style.baseWidgetSize * 0.5 * scaling + size: Style.baseWidgetSize * 0.5 } NIconButton { @@ -384,7 +384,7 @@ NPanel { return I18n.tr("wifi.panel.password") } outlined: !hovered - fontSize: Style.fontSizeXS * scaling + fontSize: Style.fontSizeXS enabled: !NetworkService.connecting onClicked: { if (modelData.existing || modelData.cached || !NetworkService.isSecured(modelData.security)) { @@ -401,7 +401,7 @@ NPanel { visible: modelData.connected && NetworkService.disconnectingFrom !== modelData.ssid text: I18n.tr("wifi.panel.disconnect") outlined: !hovered - fontSize: Style.fontSizeXS * scaling + fontSize: Style.fontSizeXS backgroundColor: Color.mError onClicked: NetworkService.disconnect(modelData.ssid) } @@ -412,35 +412,35 @@ NPanel { Rectangle { visible: passwordSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid Layout.fillWidth: true - height: passwordRow.implicitHeight + Style.marginS * scaling * 2 + height: passwordRow.implicitHeight + Style.marginS * 2 color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusS * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusS RowLayout { id: passwordRow anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginS + spacing: Style.marginM Rectangle { Layout.fillWidth: true Layout.fillHeight: true - radius: Style.radiusXS * scaling + radius: Style.radiusXS color: Color.mSurface border.color: pwdInput.activeFocus ? Color.mSecondary : Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) TextInput { id: pwdInput anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: Style.marginS * scaling + anchors.margins: Style.marginS text: passwordInput font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeS * scaling + font.pointSize: Style.fontSizeS color: Color.mOnSurface echoMode: TextInput.Password selectByMouse: true @@ -462,14 +462,14 @@ NPanel { anchors.verticalCenter: parent.verticalCenter text: I18n.tr("wifi.panel.enter-password") color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS } } } NButton { text: I18n.tr("wifi.panel.connect") - fontSize: Style.fontSizeXXS * scaling + fontSize: Style.fontSizeXXS enabled: passwordInput.length > 0 && !NetworkService.connecting outlined: true onClicked: { @@ -494,28 +494,28 @@ NPanel { Rectangle { visible: expandedSsid === modelData.ssid && NetworkService.disconnectingFrom !== modelData.ssid && NetworkService.forgettingNetwork !== modelData.ssid Layout.fillWidth: true - height: forgetRow.implicitHeight + Style.marginS * 2 * scaling + height: forgetRow.implicitHeight + Style.marginS * 2 color: Color.mSurfaceVariant - radius: Style.radiusS * scaling - border.width: Math.max(1, Style.borderS * scaling) + radius: Style.radiusS + border.width: Math.max(1, Style.borderS) border.color: Color.mOutline RowLayout { id: forgetRow anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginS + spacing: Style.marginM RowLayout { NIcon { icon: "trash" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mError } NText { text: I18n.tr("wifi.panel.forget-network") - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mError Layout.fillWidth: true } @@ -524,7 +524,7 @@ NPanel { NButton { id: forgetButton text: I18n.tr("wifi.panel.forget") - fontSize: Style.fontSizeXXS * scaling + fontSize: Style.fontSizeXXS backgroundColor: Color.mError outlined: forgetButton.hovered ? false : true onClicked: { @@ -550,7 +550,7 @@ NPanel { ColumnLayout { visible: Settings.data.network.wifiEnabled && !NetworkService.scanning && Object.keys(NetworkService.networks).length === 0 anchors.fill: parent - spacing: Style.marginL * scaling + spacing: Style.marginL Item { Layout.fillHeight: true @@ -558,14 +558,14 @@ NPanel { NIcon { icon: "search" - pointSize: 64 * scaling + pointSize: 64 color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("wifi.panel.no-networks") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } diff --git a/Modules/Bar/Widgets/ActiveWindow.qml b/Modules/Bar/Widgets/ActiveWindow.qml index de10760d..6a10a095 100644 --- a/Modules/Bar/Widgets/ActiveWindow.qml +++ b/Modules/Bar/Widgets/ActiveWindow.qml @@ -12,7 +12,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -31,23 +30,24 @@ Item { return {} } - readonly property bool hasActiveWindow: CompositorService.getFocusedWindowTitle() !== "" + readonly property bool hasFocusedWindow: CompositorService.getFocusedWindow() !== null readonly property string windowTitle: CompositorService.getFocusedWindowTitle() || "No active window" readonly property string fallbackIcon: "user-desktop" readonly property string barPosition: Settings.data.bar.position - readonly property bool compact: (Settings.data.bar.density === "compact") // Widget settings - matching MediaMini pattern readonly property bool showIcon: (widgetSettings.showIcon !== undefined) ? widgetSettings.showIcon : widgetMetadata.showIcon - readonly property bool autoHide: (widgetSettings.autoHide !== undefined) ? widgetSettings.autoHide : widgetMetadata.autoHide + readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : widgetMetadata.hideMode readonly property string scrollingMode: (widgetSettings.scrollingMode !== undefined) ? widgetSettings.scrollingMode : (widgetMetadata.scrollingMode !== undefined ? widgetMetadata.scrollingMode : "hover") readonly property int widgetWidth: (widgetSettings.width !== undefined) ? widgetSettings.width : Math.max(widgetMetadata.width, screen.width * 0.06) - implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)) : 0 - implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)) : 0 + implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Style.barHeight) : 0 + implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8) : (widgetWidth)) : 0 - opacity: !autoHide || hasActiveWindow ? 1.0 : 0 + // "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty + visible: hideMode !== "hidden" || hasFocusedWindow + opacity: hideMode !== "transparent" || hasFocusedWindow ? 1.0 : 0 Behavior on opacity { NumberAnimation { duration: Style.animationNormal @@ -56,7 +56,7 @@ Item { } function calculatedVerticalHeight() { - return Math.round(Style.baseWidgetSize * 0.8 * scaling) + return Math.round(Style.baseWidgetSize * 0.8) } function getAppIcon() { @@ -107,7 +107,8 @@ Item { id: fullTitleMetrics visible: false text: windowTitle - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS + applyUiScale: false font.weight: Style.fontWeightMedium } @@ -116,29 +117,29 @@ Item { visible: root.visible anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling) - height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : Math.round(Style.capsuleHeight * scaling) - radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Math.round(Style.radiusM * scaling) + width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8) : (widgetWidth) + height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8) : Style.capsuleHeight + radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Item { id: mainContainer anchors.fill: parent - anchors.leftMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling - anchors.rightMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling + anchors.leftMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS + anchors.rightMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS // Horizontal layout for top/bottom bars RowLayout { id: rowLayout anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * scaling + spacing: Style.marginS visible: barPosition === "top" || barPosition === "bottom" z: 1 // Window icon Item { - Layout.preferredWidth: Math.round(18 * scaling) - Layout.preferredHeight: Math.round(18 * scaling) + Layout.preferredWidth: 18 + Layout.preferredHeight: 18 Layout.alignment: Qt.AlignVCenter visible: showIcon @@ -149,6 +150,15 @@ Item { asynchronous: true smooth: true visible: source !== "" + + // Apply dock shader to active window icon (always themed) + layer.enabled: widgetSettings.colorizeIcons !== false + layer.effect: ShaderEffect { + property color targetColor: Color.mOnSurface + property real colorizeMode: 0.0 // Dock mode (grayscale) + + fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") + } } } @@ -157,10 +167,10 @@ Item { id: titleContainer Layout.preferredWidth: { // Calculate available width based on other elements - var iconWidth = (showIcon && windowIcon.visible ? (18 * scaling + Style.marginS * scaling) : 0) - var totalMargins = Style.marginXXS * scaling * 2 + var iconWidth = (showIcon && windowIcon.visible ? (18 + Style.marginS) : 0) + var totalMargins = Style.marginXXS * 2 var availableWidth = mainContainer.width - iconWidth - totalMargins - return Math.max(20 * scaling, availableWidth) + return Math.max(20, availableWidth) } Layout.maximumWidth: Layout.preferredWidth Layout.alignment: Qt.AlignVCenter @@ -239,12 +249,13 @@ Item { x: scrollX RowLayout { - spacing: 50 * scaling // Gap between text copies + spacing: 50 // Gap between text copies NText { id: titleText text: windowTitle - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS + applyUiScale: false font.weight: Style.fontWeightMedium verticalAlignment: Text.AlignVCenter color: Color.mOnSurface @@ -254,6 +265,8 @@ Item { NText { text: windowTitle font: titleText.font + pointSize: Style.fontSizeS + applyUiScale: false verticalAlignment: Text.AlignVCenter color: Color.mOnSurface visible: titleContainer.needsScrolling && titleContainer.isScrolling @@ -276,7 +289,7 @@ Item { id: infiniteScroll running: titleContainer.isScrolling && !titleContainer.isResetting from: 0 - to: -(titleContainer.textWidth + 50 * scaling) + to: -(titleContainer.textWidth + 50) duration: Math.max(4000, windowTitle.length * 100) loops: Animation.Infinite easing.type: Easing.Linear @@ -296,15 +309,15 @@ Item { Item { id: verticalLayout anchors.centerIn: parent - width: parent.width - Style.marginM * scaling * 2 - height: parent.height - Style.marginM * scaling * 2 + width: parent.width - Style.marginM * 2 + height: parent.height - Style.marginM * 2 visible: barPosition === "left" || barPosition === "right" z: 1 // Window icon Item { - width: Style.baseWidgetSize * 0.5 * scaling - height: Style.baseWidgetSize * 0.5 * scaling + width: Style.baseWidgetSize * 0.5 + height: Style.baseWidgetSize * 0.5 anchors.centerIn: parent visible: windowTitle !== "" @@ -315,6 +328,15 @@ Item { asynchronous: true smooth: true visible: source !== "" + + // Apply dock shader to active window icon (always themed) + layer.enabled: widgetSettings.colorizeIcons !== false + layer.effect: ShaderEffect { + property color targetColor: Color.mOnSurface + property real colorizeMode: 0.0 // Dock mode (grayscale) + + fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") + } } } } diff --git a/Modules/Bar/Widgets/Battery.qml b/Modules/Bar/Widgets/Battery.qml index 336ee925..02032cd9 100644 --- a/Modules/Bar/Widgets/Battery.qml +++ b/Modules/Bar/Widgets/Battery.qml @@ -11,7 +11,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -87,7 +86,7 @@ Item { BarPill { id: pill - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density rightOpen: BarService.getPillDirection(root) icon: testMode ? BatteryService.getIcon(testPercent, testCharging, true) : BatteryService.getIcon(percent, charging, isReady) text: (isReady || testMode) ? Math.round(percent) : "-" diff --git a/Modules/Bar/Widgets/Bluetooth.qml b/Modules/Bar/Widgets/Bluetooth.qml index e76fa234..e6f50f0f 100644 --- a/Modules/Bar/Widgets/Bluetooth.qml +++ b/Modules/Bar/Widgets/Bluetooth.qml @@ -11,10 +11,10 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 baseSize: Style.capsuleHeight - compact: (Settings.data.bar.density === "compact") + applyUiScale: false + density: Settings.data.bar.density colorBg: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent colorFg: Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/Brightness.qml b/Modules/Bar/Widgets/Brightness.qml index 652660c0..5c02e490 100644 --- a/Modules/Bar/Widgets/Brightness.qml +++ b/Modules/Bar/Widgets/Brightness.qml @@ -10,7 +10,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -77,7 +76,7 @@ Item { BarPill { id: pill - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density rightOpen: BarService.getPillDirection(root) icon: getIcon() autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/Clock.qml b/Modules/Bar/Widgets/Clock.qml index 26ae5762..cbbecd2f 100644 --- a/Modules/Bar/Widgets/Clock.qml +++ b/Modules/Bar/Widgets/Clock.qml @@ -9,7 +9,6 @@ Rectangle { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -30,7 +29,7 @@ Rectangle { readonly property string barPosition: Settings.data.bar.position readonly property bool isBarVertical: barPosition === "left" || barPosition === "right" - readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property bool density: Settings.data.bar.density readonly property var now: Time.date @@ -41,11 +40,11 @@ Rectangle { readonly property string formatHorizontal: widgetSettings.formatHorizontal !== undefined ? widgetSettings.formatHorizontal : widgetMetadata.formatHorizontal readonly property string formatVertical: widgetSettings.formatVertical !== undefined ? widgetSettings.formatVertical : widgetMetadata.formatVertical - implicitWidth: isBarVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round((isBarVertical ? verticalLoader.implicitWidth : horizontalLoader.implicitWidth) + Style.marginM * 2 * scaling) + implicitWidth: isBarVertical ? Style.capsuleHeight : Math.round((isBarVertical ? verticalLoader.implicitWidth : horizontalLoader.implicitWidth) + Style.marginM * 2) - implicitHeight: isBarVertical ? Math.round(verticalLoader.implicitHeight + Style.marginS * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) + implicitHeight: isBarVertical ? Math.round(verticalLoader.implicitHeight + Style.marginS * 2) : Style.capsuleHeight - radius: Math.round(Style.radiusS * scaling) + radius: Style.radiusS color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Item { @@ -59,7 +58,7 @@ Rectangle { anchors.centerIn: parent sourceComponent: ColumnLayout { anchors.centerIn: parent - spacing: Settings.data.bar.showCapsule ? -4 * scaling : -2 * scaling + spacing: Settings.data.bar.showCapsule ? -4 : -2 Repeater { id: repeater model: Qt.locale().toString(now, formatHorizontal.trim()).split("\\n") @@ -69,11 +68,12 @@ Rectangle { family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault pointSize: { if (repeater.model.length == 1) { - return Style.fontSizeS * scaling + return Style.fontSizeS } else { - return (index == 0) ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling + return (index == 0) ? Style.fontSizeXS : Style.fontSizeXXS } } + applyUiScale: false font.weight: Style.fontWeightBold color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface wrapMode: Text.WordWrap @@ -90,14 +90,15 @@ Rectangle { anchors.centerIn: parent // Now this works without layout conflicts sourceComponent: ColumnLayout { anchors.centerIn: parent - spacing: -2 * scaling + spacing: -2 Repeater { model: Qt.locale().toString(now, formatVertical.trim()).split(" ") delegate: NText { visible: text !== "" text: modelData family: useCustomFont && customFont ? customFont : Settings.data.ui.fontDefault - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS + applyUiScale: false font.weight: Style.fontWeightBold color: usePrimaryColor ? Color.mPrimary : Color.mOnSurface wrapMode: Text.WordWrap diff --git a/Modules/Bar/Widgets/ControlCenter.qml b/Modules/Bar/Widgets/ControlCenter.qml index 65eb3b8c..b0ceea69 100644 --- a/Modules/Bar/Widgets/ControlCenter.qml +++ b/Modules/Bar/Widgets/ControlCenter.qml @@ -10,7 +10,6 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -38,7 +37,8 @@ NIconButton { tooltipText: I18n.tr("tooltips.open-control-center") tooltipDirection: BarService.getTooltipDirection() baseSize: Style.capsuleHeight - compact: (Settings.data.bar.density === "compact") + applyUiScale: false + density: Settings.data.bar.density colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Color.mOnSurface colorBgHover: useDistroLogo ? Color.mSurfaceVariant : Color.mTertiary diff --git a/Modules/Bar/Widgets/CustomButton.qml b/Modules/Bar/Widgets/CustomButton.qml index 50310b24..af0e58cd 100644 --- a/Modules/Bar/Widgets/CustomButton.qml +++ b/Modules/Bar/Widgets/CustomButton.qml @@ -12,7 +12,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -49,7 +48,7 @@ Item { rightOpen: BarService.getPillDirection(root) icon: customIcon text: _dynamicText - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density autoHide: false forceOpen: _dynamicText !== "" forceClose: false diff --git a/Modules/Bar/Widgets/DarkMode.qml b/Modules/Bar/Widgets/DarkMode.qml index b35dd236..d9a2cb25 100644 --- a/Modules/Bar/Widgets/DarkMode.qml +++ b/Modules/Bar/Widgets/DarkMode.qml @@ -7,13 +7,13 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 icon: "dark-mode" tooltipText: Settings.data.colorSchemes.darkMode ? I18n.tr("tooltips.switch-to-light-mode") : I18n.tr("tooltips.switch-to-dark-mode") tooltipDirection: BarService.getTooltipDirection() - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density baseSize: Style.capsuleHeight + applyUiScale: false colorBg: Settings.data.colorSchemes.darkMode ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary colorFg: Settings.data.colorSchemes.darkMode ? Color.mOnSurface : Color.mOnPrimary colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/KeepAwake.qml b/Modules/Bar/Widgets/KeepAwake.qml index ba09d92a..c0546884 100644 --- a/Modules/Bar/Widgets/KeepAwake.qml +++ b/Modules/Bar/Widgets/KeepAwake.qml @@ -9,10 +9,10 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 baseSize: Style.capsuleHeight - compact: (Settings.data.bar.density === "compact") + applyUiScale: false + density: Settings.data.bar.density icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off" tooltipText: IdleInhibitorService.isInhibited ? I18n.tr("tooltips.disable-keep-awake") : I18n.tr("tooltips.enable-keep-awake") tooltipDirection: BarService.getTooltipDirection() diff --git a/Modules/Bar/Widgets/KeyboardLayout.qml b/Modules/Bar/Widgets/KeyboardLayout.qml index ec83b71e..6d597227 100644 --- a/Modules/Bar/Widgets/KeyboardLayout.qml +++ b/Modules/Bar/Widgets/KeyboardLayout.qml @@ -12,7 +12,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -43,7 +42,7 @@ Item { id: pill anchors.verticalCenter: parent.verticalCenter - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density rightOpen: BarService.getPillDirection(root) icon: "keyboard" autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/MediaMini.qml b/Modules/Bar/Widgets/MediaMini.qml index e33be8f2..f3502781 100644 --- a/Modules/Bar/Widgets/MediaMini.qml +++ b/Modules/Bar/Widgets/MediaMini.qml @@ -11,7 +11,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -31,9 +30,9 @@ Item { } readonly property string barPosition: Settings.data.bar.position - readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property bool density: Settings.data.bar.density - readonly property bool autoHide: (widgetSettings.autoHide !== undefined) ? widgetSettings.autoHide : widgetMetadata.autoHide + readonly property string hideMode: (widgetSettings.hideMode !== undefined) ? widgetSettings.hideMode : "hidden" // "visible", "hidden", "transparent" readonly property bool showAlbumArt: (widgetSettings.showAlbumArt !== undefined) ? widgetSettings.showAlbumArt : widgetMetadata.showAlbumArt readonly property bool showVisualizer: (widgetSettings.showVisualizer !== undefined) ? widgetSettings.showVisualizer : widgetMetadata.showVisualizer readonly property string visualizerType: (widgetSettings.visualizerType !== undefined && widgetSettings.visualizerType !== "") ? widgetSettings.visualizerType : widgetMetadata.visualizerType @@ -42,7 +41,7 @@ Item { // Fixed width - no expansion readonly property real widgetWidth: Math.max(145, screen.width * 0.06) - readonly property bool hasActivePlayer: MediaService.currentPlayer !== null && getTitle() !== "" + readonly property bool hasActivePlayer: MediaService.currentPlayer !== null readonly property string placeholderText: I18n.tr("bar.widget-settings.media-mini.no-active-player") readonly property string tooltipText: { @@ -60,10 +59,12 @@ Item { return title } - implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Math.round(Style.barHeight * scaling)) : 0 - implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling)) : 0 + implicitHeight: visible ? ((barPosition === "left" || barPosition === "right") ? calculatedVerticalHeight() : Style.barHeight) : 0 + implicitWidth: visible ? ((barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8) : (widgetWidth)) : 0 - opacity: !autoHide || hasActivePlayer || (!hasActivePlayer && !autoHide) ? 1.0 : 0 + // "visible": Always Visible, "hidden": Hide When Empty, "transparent": Transparent When Empty + visible: hideMode !== "hidden" || hasActivePlayer + opacity: hideMode !== "transparent" || hasActivePlayer ? 1.0 : 0 Behavior on opacity { NumberAnimation { duration: Style.animationNormal @@ -76,7 +77,7 @@ Item { } function calculatedVerticalHeight() { - return Math.round(Style.baseWidgetSize * 0.8 * scaling) + return Math.round(Style.baseWidgetSize * 0.8) } // A hidden text element to safely measure the full title width @@ -85,6 +86,7 @@ Item { visible: false text: titleText.text font: titleText.font + applyUiScale: false } Rectangle { @@ -92,16 +94,16 @@ Item { visible: root.visible anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter - width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : (widgetWidth * scaling) - height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8 * scaling) : Math.round(Style.capsuleHeight * scaling) - radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Math.round(Style.radiusM * scaling) + width: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8) : (widgetWidth) + height: (barPosition === "left" || barPosition === "right") ? Math.round(Style.baseWidgetSize * 0.8) : Style.capsuleHeight + radius: (barPosition === "left" || barPosition === "right") ? width / 2 : Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Item { id: mainContainer anchors.fill: parent - anchors.leftMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling - anchors.rightMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS * scaling + anchors.leftMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS + anchors.rightMargin: (barPosition === "left" || barPosition === "right") ? 0 : Style.marginS Loader { anchors.verticalCenter: parent.verticalCenter @@ -110,8 +112,8 @@ Item { z: 0 sourceComponent: LinearSpectrum { - width: mainContainer.width - Style.marginS * scaling - height: 20 * scaling + width: mainContainer.width - Style.marginS + height: 20 values: CavaService.values fillColor: Color.mPrimary opacity: 0.4 @@ -125,8 +127,8 @@ Item { z: 0 sourceComponent: MirroredSpectrum { - width: mainContainer.width - Style.marginS * scaling - height: mainContainer.height - Style.marginS * scaling + width: mainContainer.width - Style.marginS + height: mainContainer.height - Style.marginS values: CavaService.values fillColor: Color.mPrimary opacity: 0.4 @@ -140,8 +142,8 @@ Item { z: 0 sourceComponent: WaveSpectrum { - width: mainContainer.width - Style.marginS * scaling - height: mainContainer.height - Style.marginS * scaling + width: mainContainer.width - Style.marginS + height: mainContainer.height - Style.marginS values: CavaService.values fillColor: Color.mPrimary opacity: 0.4 @@ -153,7 +155,7 @@ Item { id: rowLayout anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * scaling + spacing: Style.marginS visible: (barPosition === "top" || barPosition === "bottom") z: 1 // Above the visualizer @@ -161,7 +163,7 @@ Item { id: windowIcon icon: hasActivePlayer ? (MediaService.isPlaying ? "media-pause" : "media-play") : "disc" color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL verticalAlignment: Text.AlignVCenter Layout.alignment: Qt.AlignVCenter visible: !hasActivePlayer || (!showAlbumArt && !trackArt.visible) @@ -173,15 +175,15 @@ Item { spacing: 0 Item { - Layout.preferredWidth: Math.round(21 * scaling) - Layout.preferredHeight: Math.round(21 * scaling) + Layout.preferredWidth: Math.round(21 * Style.uiScaleRatio) + Layout.preferredHeight: Math.round(21 * Style.uiScaleRatio) NImageCircled { id: trackArt anchors.fill: parent imagePath: MediaService.trackArtUrl fallbackIcon: MediaService.isPlaying ? "media-pause" : "media-play" - fallbackIconSize: 10 * scaling + fallbackIconSize: 10 borderWidth: 0 border.color: Color.transparent } @@ -192,11 +194,11 @@ Item { id: titleContainer Layout.preferredWidth: { // Calculate available width based on other elements in the row - var iconWidth = (windowIcon.visible ? (Style.fontSizeL * scaling + Style.marginS * scaling) : 0) - var albumArtWidth = (hasActivePlayer && showAlbumArt ? (18 * scaling + Style.marginS * scaling) : 0) - var totalMargins = Style.marginXXS * scaling * 2 + var iconWidth = (windowIcon.visible ? (Style.fontSizeL + Style.marginS) : 0) + var albumArtWidth = (hasActivePlayer && showAlbumArt ? (18 + Style.marginS) : 0) + var totalMargins = Style.marginXXS * 2 var availableWidth = mainContainer.width - iconWidth - albumArtWidth - totalMargins - return Math.max(20 * scaling, availableWidth) + return Math.max(20, availableWidth) } Layout.maximumWidth: Layout.preferredWidth Layout.alignment: Qt.AlignVCenter @@ -281,12 +283,13 @@ Item { x: scrollX RowLayout { - spacing: 50 * scaling // Gap between text copies + spacing: 50 // Gap between text copies NText { id: titleText text: hasActivePlayer ? getTitle() : placeholderText - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS + applyUiScale: false font.weight: Style.fontWeightMedium verticalAlignment: Text.AlignVCenter horizontalAlignment: hasActivePlayer ? Text.AlignLeft : Text.AlignHCenter @@ -296,6 +299,7 @@ Item { NText { text: hasActivePlayer ? getTitle() : placeholderText font: titleText.font + applyUiScale: false verticalAlignment: Text.AlignVCenter horizontalAlignment: hasActivePlayer ? Text.AlignLeft : Text.AlignHCenter color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant @@ -319,7 +323,7 @@ Item { id: infiniteScroll running: titleContainer.isScrolling && !titleContainer.isResetting from: 0 - to: -(titleContainer.textWidth + 50 * scaling) // Scroll one complete text width + gap + to: -(titleContainer.textWidth + 50) // Scroll one complete text width + gap duration: Math.max(4000, getTitle().length * 120) loops: Animation.Infinite easing.type: Easing.Linear @@ -339,15 +343,15 @@ Item { Item { id: verticalLayout anchors.centerIn: parent - width: parent.width - Style.marginM * scaling * 2 - height: parent.height - Style.marginM * scaling * 2 + width: parent.width - Style.marginM * 2 + height: parent.height - Style.marginM * 2 visible: barPosition === "left" || barPosition === "right" z: 1 // Above the visualizer // Media icon Item { - width: Style.baseWidgetSize * 0.5 * scaling - height: Style.baseWidgetSize * 0.5 * scaling + width: Style.baseWidgetSize * 0.5 + height: Style.baseWidgetSize * 0.5 anchors.centerIn: parent NIcon { @@ -355,7 +359,7 @@ Item { anchors.fill: parent icon: hasActivePlayer ? (MediaService.isPlaying ? "media-pause" : "media-play") : "disc" color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignHCenter } diff --git a/Modules/Bar/Widgets/Microphone.qml b/Modules/Bar/Widgets/Microphone.qml index d0d35727..a3058e36 100644 --- a/Modules/Bar/Widgets/Microphone.qml +++ b/Modules/Bar/Widgets/Microphone.qml @@ -12,7 +12,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -92,7 +91,7 @@ Item { rightOpen: BarService.getPillDirection(root) icon: getIcon() - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density autoHide: false // Important to be false so we can hover as long as we want text: Math.round(AudioService.inputVolume * 100) suffix: "%" diff --git a/Modules/Bar/Widgets/NightLight.qml b/Modules/Bar/Widgets/NightLight.qml index b972d37d..80d2c01d 100644 --- a/Modules/Bar/Widgets/NightLight.qml +++ b/Modules/Bar/Widgets/NightLight.qml @@ -12,10 +12,10 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density baseSize: Style.capsuleHeight + applyUiScale: false colorBg: Settings.data.nightLight.forced ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Settings.data.nightLight.forced ? Color.mOnPrimary : Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/NotificationHistory.qml b/Modules/Bar/Widgets/NotificationHistory.qml index aee73598..6d6652fe 100644 --- a/Modules/Bar/Widgets/NotificationHistory.qml +++ b/Modules/Bar/Widgets/NotificationHistory.qml @@ -11,7 +11,6 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -50,7 +49,8 @@ NIconButton { } baseSize: Style.capsuleHeight - compact: (Settings.data.bar.density === "compact") + applyUiScale: false + density: Settings.data.bar.density icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell" tooltipText: Settings.data.notifications.doNotDisturb ? I18n.tr("tooltips.open-notification-history-disable-dnd") : I18n.tr("tooltips.open-notification-history-enable-dnd") tooltipDirection: BarService.getTooltipDirection() @@ -69,14 +69,14 @@ NIconButton { Loader { anchors.right: parent.right anchors.top: parent.top - anchors.rightMargin: 2 * scaling - anchors.topMargin: 1 * scaling + anchors.rightMargin: 2 + anchors.topMargin: 1 z: 2 active: showUnreadBadge && (!hideWhenZero || computeUnreadCount() > 0) sourceComponent: Rectangle { id: badge readonly property int count: computeUnreadCount() - height: 8 * scaling + height: 8 width: height radius: height / 2 color: Color.mError diff --git a/Modules/Bar/Widgets/PowerProfile.qml b/Modules/Bar/Widgets/PowerProfile.qml index fbd2a719..da96fcf1 100644 --- a/Modules/Bar/Widgets/PowerProfile.qml +++ b/Modules/Bar/Widgets/PowerProfile.qml @@ -10,17 +10,16 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 baseSize: Style.capsuleHeight + applyUiScale: false + density: Settings.data.bar.density visible: PowerProfileService.available - icon: PowerProfileService.getIcon() tooltipText: I18n.tr("tooltips.power-profile", { "profile": PowerProfileService.getName() }) tooltipDirection: BarService.getTooltipDirection() - compact: (Settings.data.bar.density === "compact") colorBg: (PowerProfileService.profile === PowerProfile.Balanced) ? (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) : Color.mPrimary colorFg: (PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnSurface : Color.mOnPrimary colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/ScreenRecorder.qml b/Modules/Bar/Widgets/ScreenRecorder.qml index 16b57804..4e528c2f 100644 --- a/Modules/Bar/Widgets/ScreenRecorder.qml +++ b/Modules/Bar/Widgets/ScreenRecorder.qml @@ -8,13 +8,13 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 icon: "camera-video" tooltipText: ScreenRecorderService.isRecording ? I18n.tr("tooltips.click-to-stop-recording") : I18n.tr("tooltips.click-to-start-recording") tooltipDirection: BarService.getTooltipDirection() - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density baseSize: Style.capsuleHeight + applyUiScale: false colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/SessionMenu.qml b/Modules/Bar/Widgets/SessionMenu.qml index f8f09929..bb24f446 100644 --- a/Modules/Bar/Widgets/SessionMenu.qml +++ b/Modules/Bar/Widgets/SessionMenu.qml @@ -9,10 +9,10 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density baseSize: Style.capsuleHeight + applyUiScale: false icon: "power" tooltipText: I18n.tr("tooltips.session-menu") tooltipDirection: BarService.getTooltipDirection() diff --git a/Modules/Bar/Widgets/Spacer.qml b/Modules/Bar/Widgets/Spacer.qml index d8e4abcb..3af0e792 100644 --- a/Modules/Bar/Widgets/Spacer.qml +++ b/Modules/Bar/Widgets/Spacer.qml @@ -9,7 +9,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -32,8 +31,8 @@ Item { readonly property int spacerWidth: widgetSettings.width !== undefined ? widgetSettings.width : widgetMetadata.width // Set the width based on user settings - implicitWidth: spacerWidth * scaling - implicitHeight: Style.barHeight * scaling + implicitWidth: spacerWidth + implicitHeight: Style.barHeight width: implicitWidth height: implicitHeight } diff --git a/Modules/Bar/Widgets/SystemMonitor.qml b/Modules/Bar/Widgets/SystemMonitor.qml index cda66b11..7609f3bf 100644 --- a/Modules/Bar/Widgets/SystemMonitor.qml +++ b/Modules/Bar/Widgets/SystemMonitor.qml @@ -9,7 +9,6 @@ Rectangle { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -30,7 +29,7 @@ Rectangle { readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" - readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property bool density: Settings.data.bar.density readonly property bool showCpuUsage: (widgetSettings.showCpuUsage !== undefined) ? widgetSettings.showCpuUsage : widgetMetadata.showCpuUsage readonly property bool showCpuTemp: (widgetSettings.showCpuTemp !== undefined) ? widgetSettings.showCpuTemp : widgetMetadata.showCpuTemp @@ -42,12 +41,12 @@ Rectangle { readonly property real iconSize: textSize * 1.4 readonly property real textSize: { var base = isVertical ? width * 0.82 : height - return Math.max(1, compact ? base * 0.43 : base * 0.33) + return Math.max(1, (density === "compact") ? base * 0.43 : base * 0.33) } - readonly property int percentTextWidth: Math.ceil(percentMetrics.boundingRect.width + 3 * scaling) - readonly property int tempTextWidth: Math.ceil(tempMetrics.boundingRect.width + 3 * scaling) - readonly property int memTextWidth: Math.ceil(memMetrics.boundingRect.width + 3 * scaling) + readonly property int percentTextWidth: Math.ceil(percentMetrics.boundingRect.width + 3) + readonly property int tempTextWidth: Math.ceil(tempMetrics.boundingRect.width + 3) + readonly property int memTextWidth: Math.ceil(memMetrics.boundingRect.width + 3) TextMetrics { id: percentMetrics @@ -74,9 +73,9 @@ Rectangle { } anchors.centerIn: parent - implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(mainGrid.implicitWidth + Style.marginM * 2 * scaling) - implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) - radius: Math.round(Style.radiusM * scaling) + implicitWidth: isVertical ? Style.capsuleHeight : Math.round(mainGrid.implicitWidth + Style.marginM * 2) + implicitHeight: isVertical ? Math.round(mainGrid.implicitHeight + Style.marginM * 2) : Style.capsuleHeight + radius: Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent GridLayout { @@ -85,13 +84,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? -1 : 1 columns: isVertical ? 1 : -1 - rowSpacing: isVertical ? (Style.marginM * scaling) : 0 - columnSpacing: isVertical ? 0 : (Style.marginM * scaling) + rowSpacing: isVertical ? (Style.marginM) : 0 + columnSpacing: isVertical ? 0 : (Style.marginM) // CPU Usage Component Item { - Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS * scaling) - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) + Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS) + Layout.preferredHeight: Style.capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuUsage @@ -101,12 +100,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? 2 : 1 columns: isVertical ? 1 : 2 - rowSpacing: Style.marginXXS * scaling - columnSpacing: Style.marginXXS * scaling + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS NIcon { icon: "cpu-usage" pointSize: iconSize + applyUiScale: false Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -116,6 +116,7 @@ Rectangle { text: `${Math.round(SystemStatService.cpuUsage)}%` family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter Layout.preferredWidth: isVertical ? -1 : percentTextWidth @@ -131,8 +132,8 @@ Rectangle { // CPU Temperature Component Item { - Layout.preferredWidth: isVertical ? root.width : (iconSize + tempTextWidth) + (Style.marginXXS * scaling) - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) + Layout.preferredWidth: isVertical ? root.width : (iconSize + tempTextWidth) + (Style.marginXXS) + Layout.preferredHeight: Style.capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showCpuTemp @@ -142,12 +143,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? 2 : 1 columns: isVertical ? 1 : 2 - rowSpacing: Style.marginXXS * scaling - columnSpacing: Style.marginXXS * scaling + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS NIcon { icon: "cpu-temperature" pointSize: iconSize + applyUiScale: false Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -157,6 +159,7 @@ Rectangle { text: `${Math.round(SystemStatService.cpuTemp)}°` family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter Layout.preferredWidth: isVertical ? -1 : tempTextWidth @@ -172,8 +175,8 @@ Rectangle { // Memory Usage Component Item { - Layout.preferredWidth: isVertical ? root.width : iconSize + (showMemoryAsPercent ? percentTextWidth : memTextWidth) + (Style.marginXXS * scaling) - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) + Layout.preferredWidth: isVertical ? root.width : iconSize + (showMemoryAsPercent ? percentTextWidth : memTextWidth) + (Style.marginXXS) + Layout.preferredHeight: Style.capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showMemoryUsage @@ -183,12 +186,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? 2 : 1 columns: isVertical ? 1 : 2 - rowSpacing: Style.marginXXS * scaling - columnSpacing: Style.marginXXS * scaling + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS NIcon { icon: "memory" pointSize: iconSize + applyUiScale: false Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -198,6 +202,7 @@ Rectangle { text: showMemoryAsPercent ? `${Math.round(SystemStatService.memPercent)}%` : `${SystemStatService.memGb.toFixed(1)}G` family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter Layout.preferredWidth: isVertical ? -1 : (showMemoryAsPercent ? percentTextWidth : memTextWidth) @@ -213,8 +218,8 @@ Rectangle { // Network Download Speed Component Item { - Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS * scaling) - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) + Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS) + Layout.preferredHeight: Style.capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showNetworkStats @@ -224,12 +229,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? 2 : 1 columns: isVertical ? 1 : 2 - rowSpacing: Style.marginXXS * scaling - columnSpacing: Style.marginXXS * scaling + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS NIcon { icon: "download-speed" pointSize: iconSize + applyUiScale: false Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -239,6 +245,7 @@ Rectangle { text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.rxSpeed) : SystemStatService.formatSpeed(SystemStatService.rxSpeed) family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter Layout.preferredWidth: isVertical ? -1 : memTextWidth @@ -254,8 +261,8 @@ Rectangle { // Network Upload Speed Component Item { - Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS * scaling) - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) + Layout.preferredWidth: isVertical ? root.width : iconSize + memTextWidth + (Style.marginXXS) + Layout.preferredHeight: Style.capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showNetworkStats @@ -265,12 +272,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? 2 : 1 columns: isVertical ? 1 : 2 - rowSpacing: Style.marginXXS * scaling - columnSpacing: Style.marginXXS * scaling + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS NIcon { icon: "upload-speed" pointSize: iconSize + applyUiScale: false Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -280,6 +288,7 @@ Rectangle { text: isVertical ? SystemStatService.formatCompactSpeed(SystemStatService.txSpeed) : SystemStatService.formatSpeed(SystemStatService.txSpeed) family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter Layout.preferredWidth: isVertical ? -1 : memTextWidth @@ -295,8 +304,8 @@ Rectangle { // Disk Usage Component (primary drive) Item { - Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS * scaling) - Layout.preferredHeight: Math.round(Style.capsuleHeight * scaling) + Layout.preferredWidth: isVertical ? root.width : iconSize + percentTextWidth + (Style.marginXXS) + Layout.preferredHeight: Style.capsuleHeight Layout.alignment: isVertical ? Qt.AlignHCenter : Qt.AlignVCenter visible: showDiskUsage @@ -306,12 +315,13 @@ Rectangle { flow: isVertical ? GridLayout.TopToBottom : GridLayout.LeftToRight rows: isVertical ? 2 : 1 columns: isVertical ? 1 : 2 - rowSpacing: Style.marginXXS * scaling - columnSpacing: Style.marginXXS * scaling + rowSpacing: Style.marginXXS + columnSpacing: Style.marginXXS NIcon { icon: "storage" pointSize: iconSize + applyUiScale: false Layout.alignment: Qt.AlignCenter Layout.row: isVertical ? 1 : 0 Layout.column: 0 @@ -321,6 +331,7 @@ Rectangle { text: `${SystemStatService.diskPercent}%` family: Settings.data.ui.fontFixed pointSize: textSize + applyUiScale: false font.weight: Style.fontWeightMedium Layout.alignment: Qt.AlignCenter Layout.preferredWidth: isVertical ? -1 : percentTextWidth diff --git a/Modules/Bar/Widgets/Taskbar.qml b/Modules/Bar/Widgets/Taskbar.qml index e9035002..8dcab751 100644 --- a/Modules/Bar/Widgets/Taskbar.qml +++ b/Modules/Bar/Widgets/Taskbar.qml @@ -12,7 +12,6 @@ Rectangle { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -21,8 +20,8 @@ Rectangle { property int sectionWidgetsCount: 0 readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right" - readonly property bool compact: (Settings.data.bar.density === "compact") - readonly property real itemSize: compact ? Style.capsuleHeight * 0.9 * scaling : Style.capsuleHeight * 0.8 * scaling + readonly property bool density: Settings.data.bar.density + readonly property real itemSize: (density === "compact") ? Style.capsuleHeight * 0.9 : Style.capsuleHeight * 0.8 property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId] property var widgetSettings: { @@ -36,27 +35,27 @@ Rectangle { } // Always visible when there are toplevels - implicitWidth: isVerticalBar ? Math.round(Style.capsuleHeight * scaling) : Math.round(taskbarLayout.implicitWidth + Style.marginM * scaling * 2) - implicitHeight: isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginM * scaling * 2) : Math.round(Style.capsuleHeight * scaling) - radius: Math.round(Style.radiusM * scaling) + implicitWidth: isVerticalBar ? Style.capsuleHeight : Math.round(taskbarLayout.implicitWidth + Style.marginM * 2) + implicitHeight: isVerticalBar ? Math.round(taskbarLayout.implicitHeight + Style.marginM * 2) : Style.capsuleHeight + radius: Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent GridLayout { id: taskbarLayout anchors.fill: parent anchors { - leftMargin: isVerticalBar ? undefined : Style.marginM * scaling - rightMargin: isVerticalBar ? undefined : Style.marginM * scaling - topMargin: compact ? 0 : isVerticalBar ? Style.marginM * scaling : undefined - bottomMargin: compact ? 0 : isVerticalBar ? Style.marginM * scaling : undefined + leftMargin: isVerticalBar ? undefined : Style.marginM + rightMargin: isVerticalBar ? undefined : Style.marginM + topMargin: (density === "compact") ? 0 : isVerticalBar ? Style.marginM : undefined + bottomMargin: (density === "compact") ? 0 : isVerticalBar ? Style.marginM : undefined } // Configure GridLayout to behave like RowLayout or ColumnLayout rows: isVerticalBar ? -1 : 1 // -1 means unlimited columns: isVerticalBar ? 1 : -1 // -1 means unlimited - rowSpacing: isVerticalBar ? Style.marginXXS * root.scaling : 0 - columnSpacing: isVerticalBar ? 0 : Style.marginXXS * root.scaling + rowSpacing: isVerticalBar ? Style.marginXXS : 0 + columnSpacing: isVerticalBar ? 0 : Style.marginXXS Repeater { model: CompositorService.windows @@ -81,13 +80,22 @@ Rectangle { asynchronous: true opacity: modelData.isFocused ? Style.opacityFull : 0.6 + // Apply dock shader to all taskbar icons + layer.enabled: widgetSettings.colorizeIcons !== false + layer.effect: ShaderEffect { + property color targetColor: Color.mOnSurface + property real colorizeMode: 0.0 // Dock mode (grayscale) + + fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") + } + Rectangle { - anchors.bottomMargin: -2 * scaling + anchors.bottomMargin: -2 anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter id: iconBackground - width: 4 * scaling - height: 4 * scaling + width: 4 + height: 4 color: modelData.isFocused ? Color.mPrimary : Color.transparent radius: width * 0.5 } diff --git a/Modules/Bar/Widgets/Tray.qml b/Modules/Bar/Widgets/Tray.qml index 0365cc2e..f76be377 100644 --- a/Modules/Bar/Widgets/Tray.qml +++ b/Modules/Bar/Widgets/Tray.qml @@ -14,7 +14,6 @@ Rectangle { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -35,8 +34,8 @@ Rectangle { readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" - readonly property bool compact: (Settings.data.bar.density === "compact") - property real itemSize: Math.round(Style.capsuleHeight * 0.65 * scaling) + readonly property bool density: Settings.data.bar.density + property real itemSize: Math.round(Style.capsuleHeight * 0.65) property list blacklist: widgetSettings.blacklist || widgetMetadata.blacklist || [] // Read from settings property var filteredItems: [] @@ -145,9 +144,9 @@ Rectangle { } visible: filteredItems.length > 0 - implicitWidth: isVertical ? Math.round(Style.capsuleHeight * scaling) : Math.round(trayFlow.implicitWidth + Style.marginM * 2 * scaling) - implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight + Style.marginM * 2 * scaling) : Math.round(Style.capsuleHeight * scaling) - radius: Math.round(Style.radiusM * scaling) + implicitWidth: isVertical ? Style.capsuleHeight : Math.round(trayFlow.implicitWidth + Style.marginM * 2) + implicitHeight: isVertical ? Math.round(trayFlow.implicitHeight + Style.marginM * 2) : Style.capsuleHeight + radius: Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent Layout.alignment: Qt.AlignVCenter @@ -155,7 +154,7 @@ Rectangle { Flow { id: trayFlow anchors.centerIn: parent - spacing: Style.marginM * scaling + spacing: Style.marginM flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight Repeater { @@ -193,6 +192,14 @@ Rectangle { } opacity: status === Image.Ready ? 1 : 0 + layer.enabled: widgetSettings.colorizeIcons !== false + layer.effect: ShaderEffect { + property color targetColor: Color.mOnSurface + property real colorizeMode: 1.0 // Tray mode (intensity-based) + + fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") + } + MouseArea { anchors.fill: parent hoverEnabled: true @@ -231,16 +238,16 @@ Rectangle { let menuX, menuY if (barPosition === "left") { // For left bar: position menu to the right of the bar - menuX = width + Style.marginM * scaling + menuX = width + Style.marginM menuY = 0 } else if (barPosition === "right") { // For right bar: position menu to the left of the bar - menuX = -trayMenu.item.width - Style.marginM * scaling + menuX = -trayMenu.item.width - Style.marginM menuY = 0 } else { // For horizontal bars: center horizontally and position below menuX = (width / 2) - (trayMenu.item.width / 2) - menuY = Math.round(Style.barHeight * scaling) + menuY = Style.barHeight } trayMenu.item.menu = modelData.menu trayMenu.item.showAt(parent, menuX, menuY) diff --git a/Modules/Bar/Widgets/Volume.qml b/Modules/Bar/Widgets/Volume.qml index 775a31d6..4254b842 100644 --- a/Modules/Bar/Widgets/Volume.qml +++ b/Modules/Bar/Widgets/Volume.qml @@ -12,7 +12,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -75,7 +74,7 @@ Item { BarPill { id: pill - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density rightOpen: BarService.getPillDirection(root) icon: getIcon() autoHide: false // Important to be false so we can hover as long as we want diff --git a/Modules/Bar/Widgets/WallpaperSelector.qml b/Modules/Bar/Widgets/WallpaperSelector.qml index 4be3e9a1..e48f368a 100644 --- a/Modules/Bar/Widgets/WallpaperSelector.qml +++ b/Modules/Bar/Widgets/WallpaperSelector.qml @@ -9,10 +9,10 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 baseSize: Style.capsuleHeight - compact: (Settings.data.bar.density === "compact") + applyUiScale: false + density: Settings.data.bar.density icon: "wallpaper-selector" tooltipText: I18n.tr("tooltips.open-wallpaper-selector") tooltipDirection: BarService.getTooltipDirection() diff --git a/Modules/Bar/Widgets/WiFi.qml b/Modules/Bar/Widgets/WiFi.qml index 00fefab6..a9156e3e 100644 --- a/Modules/Bar/Widgets/WiFi.qml +++ b/Modules/Bar/Widgets/WiFi.qml @@ -11,10 +11,10 @@ NIconButton { id: root property ShellScreen screen - property real scaling: 1.0 - compact: (Settings.data.bar.density === "compact") + density: Settings.data.bar.density baseSize: Style.capsuleHeight + applyUiScale: false colorBg: (Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent) colorFg: Color.mOnSurface colorBorder: Color.transparent diff --git a/Modules/Bar/Widgets/Workspace.qml b/Modules/Bar/Widgets/Workspace.qml index f093df3e..389cf148 100644 --- a/Modules/Bar/Widgets/Workspace.qml +++ b/Modules/Bar/Widgets/Workspace.qml @@ -13,7 +13,6 @@ Item { id: root property ShellScreen screen - property real scaling: 1.0 // Widget properties passed from Bar.qml for per-instance settings property string widgetId: "" @@ -34,9 +33,9 @@ Item { readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" - readonly property bool compact: (Settings.data.bar.density === "compact") + readonly property bool density: Settings.data.bar.density readonly property real baseDimensionRatio: { - const b = compact ? 0.85 : 0.65 + const b = (density === "compact") ? 0.85 : 0.65 if (widgetSettings.labelMode === "none") { return b * 0.75 } @@ -54,8 +53,8 @@ Item { property bool effectsActive: false property color effectColor: Color.mPrimary - property int horizontalPadding: Math.round(Style.marginS * scaling) - property int spacingBetweenPills: Math.round(Style.marginXS * scaling) + property int horizontalPadding: Math.round(Style.marginS) + property int spacingBetweenPills: Math.round(Style.marginXS) // Wheel scroll handling property int wheelAccumulatedDelta: 0 @@ -63,19 +62,19 @@ Item { signal workspaceChanged(int workspaceId, color accentColor) - implicitWidth: isVertical ? Math.round(Style.barHeight * scaling) : computeWidth() - implicitHeight: isVertical ? computeHeight() : Math.round(Style.barHeight * scaling) + implicitWidth: isVertical ? Style.barHeight : computeWidth() + implicitHeight: isVertical ? computeHeight() : Style.barHeight function getWorkspaceWidth(ws) { const d = Style.capsuleHeight * root.baseDimensionRatio const factor = ws.isFocused ? 2.2 : 1 - return d * factor * scaling + return d * factor } function getWorkspaceHeight(ws) { const d = Style.capsuleHeight * root.baseDimensionRatio const factor = ws.isFocused ? 2.2 : 1 - return d * factor * scaling + return d * factor } function computeWidth() { @@ -203,9 +202,9 @@ Item { Rectangle { id: workspaceBackground - width: isVertical ? Math.round(Style.capsuleHeight * scaling) : parent.width - height: isVertical ? parent.height : Math.round(Style.capsuleHeight * scaling) - radius: Math.round(Style.radiusM * scaling) + width: isVertical ? Style.capsuleHeight : parent.width + height: isVertical ? parent.height : Style.capsuleHeight + radius: Style.radiusM color: Settings.data.bar.showCapsule ? Color.mSurfaceVariant : Color.transparent anchors.horizontalCenter: parent.horizontalCenter @@ -266,7 +265,7 @@ Item { Item { id: workspacePillContainer width: root.getWorkspaceWidth(model) - height: Style.capsuleHeight * root.baseDimensionRatio * scaling + height: Style.capsuleHeight * root.baseDimensionRatio Rectangle { id: pill @@ -287,6 +286,7 @@ Item { } family: Settings.data.ui.fontFixed pointSize: model.isFocused ? workspacePillContainer.height * 0.45 : workspacePillContainer.height * 0.42 + applyUiScale: false font.capitalization: Font.AllUppercase font.weight: Style.fontWeightBold wrapMode: Text.Wrap @@ -387,7 +387,7 @@ Item { radius: width / 2 color: Color.transparent border.color: root.effectColor - border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress)) * scaling)) + 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 @@ -409,7 +409,7 @@ Item { model: localWorkspaces Item { id: workspacePillContainerVertical - width: Style.capsuleHeight * root.baseDimensionRatio * scaling + width: Style.capsuleHeight * root.baseDimensionRatio height: root.getWorkspaceHeight(model) Rectangle { @@ -431,6 +431,7 @@ Item { } family: Settings.data.ui.fontFixed pointSize: model.isFocused ? workspacePillContainerVertical.width * 0.45 : workspacePillContainerVertical.width * 0.42 + applyUiScale: false font.capitalization: Font.AllUppercase font.weight: Style.fontWeightBold wrapMode: Text.Wrap @@ -531,7 +532,7 @@ Item { radius: width / 2 color: Color.transparent border.color: root.effectColor - border.width: Math.max(1, Math.round((2 + 6 * (1.0 - root.masterProgress)) * scaling)) + 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 diff --git a/Modules/ControlCenter/Cards/AudioCard.qml b/Modules/ControlCenter/Cards/AudioCard.qml index 8436aa13..c09b05bf 100644 --- a/Modules/ControlCenter/Cards/AudioCard.qml +++ b/Modules/ControlCenter/Cards/AudioCard.qml @@ -41,12 +41,12 @@ NBox { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginM * scaling + anchors.margins: Style.marginM spacing: 0 // Output Volume Section ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true opacity: AudioService.sink ? 1.0 : 0.5 enabled: AudioService.sink @@ -54,7 +54,7 @@ NBox { // Output Volume Header RowLayout { Layout.fillWidth: true - spacing: Style.marginXS * scaling + spacing: Style.marginXS NIconButton { icon: AudioService.muted ? "volume-off" : "volume-high" @@ -71,19 +71,19 @@ NBox { } RowLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NText { text: I18n.tr("settings.audio.volumes.output-volume.label") - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurface font.weight: Style.fontWeightMedium } NText { text: AudioService.sink ? AudioService.sink.description : "No output device" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant font.weight: Style.fontWeightMedium elide: Text.ElideRight @@ -100,7 +100,7 @@ NBox { value: localOutputVolume || 0 stepSize: 0.01 text: Math.round((AudioService.volume || 0) * 100) + "%" - textSize: Style.fontSizeXS * scaling + textSize: Style.fontSizeXS customHeightRatio: 0.6 onMoved: value => localOutputVolume = value } @@ -108,7 +108,7 @@ NBox { // Input Volume Section ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true opacity: AudioService.source ? 1.0 : 0.5 enabled: AudioService.source @@ -116,7 +116,7 @@ NBox { // Input Volume Header RowLayout { Layout.fillWidth: true - spacing: Style.marginXS * scaling + spacing: Style.marginXS NIconButton { icon: AudioService.inputMuted ? "microphone-off" : "microphone" @@ -129,19 +129,19 @@ NBox { } RowLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NText { text: I18n.tr("settings.audio.volumes.input-volume.label") - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurface font.weight: Style.fontWeightMedium } NText { text: AudioService.source ? AudioService.source.description : "No input device" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant font.weight: Style.fontWeightMedium elide: Text.ElideRight @@ -158,7 +158,7 @@ NBox { value: AudioService.inputVolume || 0 stepSize: 0.01 text: Math.round((AudioService.inputVolume || 0) * 100) + "%" - textSize: Style.fontSizeXS * scaling + textSize: Style.fontSizeXS customHeightRatio: 0.6 onMoved: value => AudioService.setInputVolume(value) } diff --git a/Modules/ControlCenter/Cards/MediaCard.qml b/Modules/ControlCenter/Cards/MediaCard.qml index b4d7b7a6..06891868 100644 --- a/Modules/ControlCenter/Cards/MediaCard.qml +++ b/Modules/ControlCenter/Cards/MediaCard.qml @@ -20,7 +20,7 @@ NBox { id: bgArtImage anchors.fill: parent imagePath: MediaService.trackArtUrl - imageRadius: Style.radiusM * scaling + imageRadius: Style.radiusM visible: MediaService.trackArtUrl !== "" } @@ -29,7 +29,7 @@ NBox { anchors.fill: parent color: Color.mSurfaceVariant opacity: 0.85 - radius: Style.radiusM * scaling + radius: Style.radiusM } // Border @@ -38,7 +38,7 @@ NBox { color: Color.transparent border.color: Color.mOutline border.width: 1 - radius: Style.radiusM * scaling + radius: Style.radiusM } } @@ -55,7 +55,7 @@ NBox { sourceItem: Rectangle { width: root.width height: root.height - radius: Style.radiusM * scaling + radius: Style.radiusM color: "white" } } @@ -116,29 +116,29 @@ NBox { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - anchors.topMargin: Style.marginXS * scaling - anchors.leftMargin: Style.marginM * scaling - anchors.rightMargin: Style.marginM * scaling - height: Style.barHeight * scaling + anchors.topMargin: Style.marginXS + anchors.leftMargin: Style.marginM + anchors.rightMargin: Style.marginM + height: Style.barHeight visible: MediaService.getAvailablePlayers().length > 1 - radius: Style.radiusM * scaling + radius: Style.radiusM color: Color.transparent property var currentPlayer: MediaService.getAvailablePlayers()[MediaService.selectedPlayerIndex] RowLayout { anchors.fill: parent - spacing: Style.marginS * scaling + spacing: Style.marginS NIcon { icon: "caret-down" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mOnSurfaceVariant } NText { text: playerSelectorButton.currentPlayer ? playerSelectorButton.currentPlayer.identity : "" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant Layout.fillWidth: true } @@ -170,7 +170,7 @@ NBox { NContextMenu { id: playerContextMenu parent: root - width: 200 * scaling + width: 200 onTriggered: function (action) { var index = parseInt(action) @@ -184,14 +184,14 @@ NBox { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginM * scaling + anchors.margins: Style.marginM // No media player detected ColumnLayout { id: fallback visible: !main.visible - spacing: Style.marginS * scaling + spacing: Style.marginS Item { Layout.fillWidth: true @@ -204,12 +204,12 @@ NBox { ColumnLayout { anchors.centerIn: parent - spacing: Style.marginL * scaling + spacing: Style.marginL Item { Layout.alignment: Qt.AlignHCenter - Layout.preferredWidth: Style.fontSizeXXXL * 4 * scaling - Layout.preferredHeight: Style.fontSizeXXXL * 4 * scaling + Layout.preferredWidth: Style.fontSizeXXXL * 4 + Layout.preferredHeight: Style.fontSizeXXXL * 4 // Pulsating audio circles (background) Repeater { @@ -258,7 +258,7 @@ NBox { NIcon { anchors.centerIn: parent icon: "disc" - pointSize: Style.fontSizeXXXL * 3 * scaling + pointSize: Style.fontSizeXXXL * 3 color: Color.mOnSurfaceVariant RotationAnimator on rotation { @@ -274,7 +274,7 @@ NBox { // Descriptive text ColumnLayout { Layout.alignment: Qt.AlignHCenter - spacing: Style.marginXS * scaling + spacing: Style.marginXS } } } @@ -290,23 +290,23 @@ NBox { id: main visible: MediaService.currentPlayer && MediaService.canPlay - spacing: Style.marginS * scaling + spacing: Style.marginS // Spacer to push content down Item { - Layout.preferredHeight: Style.marginM * scaling + Layout.preferredHeight: Style.marginM } // Metadata at the bottom left ColumnLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignLeft - spacing: Style.marginXS * scaling + spacing: Style.marginXS NText { visible: MediaService.trackTitle !== "" text: MediaService.trackTitle - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold elide: Text.ElideRight wrapMode: Text.Wrap @@ -318,7 +318,7 @@ NBox { visible: MediaService.trackArtist !== "" text: MediaService.trackArtist color: Color.mPrimary - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS elide: Text.ElideRight Layout.fillWidth: true } @@ -327,7 +327,7 @@ NBox { visible: MediaService.trackAlbum !== "" text: MediaService.trackAlbum color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM elide: Text.ElideRight Layout.fillWidth: true } @@ -338,7 +338,7 @@ NBox { id: progressWrapper visible: (MediaService.currentPlayer && MediaService.trackLength > 0) Layout.fillWidth: true - height: Style.baseWidgetSize * 0.5 * scaling + height: Style.baseWidgetSize * 0.5 property real localSeekRatio: -1 property real lastSentSeekRatio: -1 @@ -408,12 +408,12 @@ NBox { // Spacer to push media controls down Item { - Layout.preferredHeight: Style.marginL * scaling + Layout.preferredHeight: Style.marginL } // Media controls RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter diff --git a/Modules/ControlCenter/Cards/PowerProfilesCard.qml b/Modules/ControlCenter/Cards/PowerProfilesCard.qml deleted file mode 100644 index d93b26ba..00000000 --- a/Modules/ControlCenter/Cards/PowerProfilesCard.qml +++ /dev/null @@ -1,66 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell -import Quickshell.Services.UPower -import qs.Commons -import qs.Services -import qs.Widgets - -// Power Profiles: performance, balanced, eco -NBox { - - property real spacing: 0 - - // Centralized service - readonly property bool hasPP: PowerProfileService.available - - RowLayout { - id: powerRow - anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: spacing - Item { - Layout.fillWidth: true - } - // Performance - NIconButton { - icon: PowerProfileService.getIcon(PowerProfile.Performance) - tooltipText: I18n.tr("tooltips.set-power-profile", { - "profile": PowerProfileService.getName(PowerProfile.Performance) - }) - enabled: hasPP - opacity: enabled ? Style.opacityFull : Style.opacityMedium - colorBg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mPrimary : Color.mSurfaceVariant - colorFg: (enabled && PowerProfileService.profile === PowerProfile.Performance) ? Color.mOnPrimary : Color.mPrimary - onClicked: PowerProfileService.setProfile(PowerProfile.Performance) - } - // Balanced - NIconButton { - icon: PowerProfileService.getIcon(PowerProfile.Balanced) - tooltipText: I18n.tr("tooltips.set-power-profile", { - "profile": PowerProfileService.getName(PowerProfile.Balanced) - }) - enabled: hasPP - opacity: enabled ? Style.opacityFull : Style.opacityMedium - colorBg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mPrimary : Color.mSurfaceVariant - colorFg: (enabled && PowerProfileService.profile === PowerProfile.Balanced) ? Color.mOnPrimary : Color.mPrimary - onClicked: PowerProfileService.setProfile(PowerProfile.Balanced) - } - // Eco - NIconButton { - icon: PowerProfileService.getIcon(PowerProfile.PowerSaver) - tooltipText: I18n.tr("tooltips.set-power-profile", { - "profile": PowerProfileService.getName(PowerProfile.PowerSaver) - }) - enabled: hasPP - opacity: enabled ? Style.opacityFull : Style.opacityMedium - colorBg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mPrimary : Color.mSurfaceVariant - colorFg: (enabled && PowerProfileService.profile === PowerProfile.PowerSaver) ? Color.mOnPrimary : Color.mPrimary - onClicked: PowerProfileService.setProfile(PowerProfile.PowerSaver) - } - Item { - Layout.fillWidth: true - } - } -} diff --git a/Modules/ControlCenter/Cards/ProfileCard.qml b/Modules/ControlCenter/Cards/ProfileCard.qml index ec9b4527..7c891182 100644 --- a/Modules/ControlCenter/Cards/ProfileCard.qml +++ b/Modules/ControlCenter/Cards/ProfileCard.qml @@ -17,25 +17,25 @@ NBox { property string uptimeText: "--" RowLayout { - id: content anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.margins: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.bottom: parent.bottom + anchors.margins: Style.marginM + spacing: Style.marginM NImageCircled { - width: Style.baseWidgetSize * 1.25 * scaling - height: Style.baseWidgetSize * 1.25 * scaling - imagePath: Settings.data.general.avatarImage + Layout.preferredWidth: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio) + Layout.preferredHeight: Math.round(Style.baseWidgetSize * 1.25 * Style.uiScaleRatio) + imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" borderColor: Color.mPrimary - borderWidth: Math.max(1, Style.borderM * scaling) + borderWidth: Math.max(1, Style.borderM) } ColumnLayout { Layout.fillWidth: true - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS NText { text: Quickshell.env("USER") || "user" font.weight: Style.fontWeightBold @@ -45,13 +45,13 @@ NBox { text: I18n.tr("system.uptime", { "uptime": uptimeText }) - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant } } RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.alignment: Qt.AlignRight | Qt.AlignVCenter Item { Layout.fillWidth: true diff --git a/Modules/ControlCenter/Cards/ShortcutsCard.qml b/Modules/ControlCenter/Cards/ShortcutsCard.qml new file mode 100644 index 00000000..bf45b879 --- /dev/null +++ b/Modules/ControlCenter/Cards/ShortcutsCard.qml @@ -0,0 +1,84 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs.Modules.ControlCenter.Cards +import qs.Commons +import qs.Services +import qs.Widgets +import qs.Modules.ControlCenter.Extras + +RowLayout { + Layout.fillWidth: true + spacing: Style.marginL + + NBox { + Layout.fillWidth: true + Layout.preferredHeight: root.shortcutsHeight + + RowLayout { + id: leftContent + anchors.fill: parent + spacing: Style.marginS + + Item { + Layout.fillWidth: true + } + + Repeater { + model: Settings.data.controlCenter.shortcuts.left + delegate: ControlCenterWidgetLoader { + Layout.fillWidth: false + widgetId: (modelData.id !== undefined ? modelData.id : "") + widgetProps: { + "screen": root.modelData || null, + "widgetId": modelData.id, + "section": "quickSettings", + "sectionWidgetIndex": index, + "sectionWidgetsCount": Settings.data.controlCenter.shortcuts.left.length + } + Layout.alignment: Qt.AlignVCenter + } + } + + Item { + Layout.fillWidth: true + } + } + } + + NBox { + Layout.fillWidth: true + Layout.preferredHeight: root.shortcutsHeight + + RowLayout { + id: rightContent + anchors.fill: parent + spacing: Style.marginS + + Item { + Layout.fillWidth: true + } + + Repeater { + model: Settings.data.controlCenter.shortcuts.right + delegate: ControlCenterWidgetLoader { + Layout.fillWidth: false + widgetId: (modelData.id !== undefined ? modelData.id : "") + widgetProps: { + "screen": root.modelData || null, + "widgetId": modelData.id, + "section": "quickSettings", + "sectionWidgetIndex": index, + "sectionWidgetsCount": Settings.data.controlCenter.shortcuts.right.length + } + Layout.alignment: Qt.AlignVCenter + } + } + + Item { + Layout.fillWidth: true + } + } + } +} diff --git a/Modules/ControlCenter/Cards/SystemMonitorCard.qml b/Modules/ControlCenter/Cards/SystemMonitorCard.qml index 4e7254a3..3e23aa89 100644 --- a/Modules/ControlCenter/Cards/SystemMonitorCard.qml +++ b/Modules/ControlCenter/Cards/SystemMonitorCard.qml @@ -12,7 +12,9 @@ NBox { Item { id: content anchors.fill: parent - anchors.margins: Style.marginS * scaling + anchors.margins: Style.marginS + + property int widgetHeight: Math.round(65 * Style.uiScaleRatio) ColumnLayout { anchors.centerIn: parent @@ -23,8 +25,7 @@ NBox { icon: "cpu-usage" flat: true contentScale: 0.8 - width: 70 * scaling - height: 65 * scaling + height: content.widgetHeight Layout.alignment: Qt.AlignHCenter } NCircleStat { @@ -33,8 +34,7 @@ NBox { icon: "cpu-temperature" flat: true contentScale: 0.8 - width: 70 * scaling - height: 65 * scaling + height: content.widgetHeight Layout.alignment: Qt.AlignHCenter } NCircleStat { @@ -42,8 +42,7 @@ NBox { icon: "memory" flat: true contentScale: 0.8 - width: 70 * scaling - height: 65 * scaling + height: content.widgetHeight Layout.alignment: Qt.AlignHCenter } NCircleStat { @@ -51,8 +50,7 @@ NBox { icon: "storage" flat: true contentScale: 0.8 - width: 70 * scaling - height: 65 * scaling + height: content.widgetHeight Layout.alignment: Qt.AlignHCenter } } diff --git a/Modules/ControlCenter/Cards/TopCard.qml b/Modules/ControlCenter/Cards/TopCard.qml deleted file mode 100644 index 21b68eca..00000000 --- a/Modules/ControlCenter/Cards/TopCard.qml +++ /dev/null @@ -1,157 +0,0 @@ -import QtQuick -import QtQuick.Effects -import QtQuick.Layouts -import Quickshell -import Quickshell.Io -import Quickshell.Widgets -import qs.Modules.Settings -import qs.Modules.ControlCenter -import qs.Modules.ControlCenter.Extras -import qs.Commons -import qs.Services -import qs.Widgets - -// Header card with avatar, user and quick actions -NBox { - id: root - - property string uptimeText: "--" - property real spacing: Style.marginS * scaling - - ColumnLayout { - anchors.fill: parent - anchors.margins: Style.marginM * scaling - - // Profile, Uptime, Settings, SessionMenu, Close - RowLayout { - id: content - - spacing: root.spacing - Layout.alignment: Qt.AlignVCenter - - NImageCircled { - width: Style.baseWidgetSize * 1.25 * scaling - height: width - imagePath: Settings.data.general.avatarImage - fallbackIcon: "person" - borderColor: Color.mPrimary - borderWidth: Math.max(1, Style.borderM * scaling) - Layout.alignment: Qt.AlignVCenter - Layout.topMargin: Style.marginXS * scaling - } - - ColumnLayout { - Layout.fillWidth: true - spacing: Style.marginXXS * scaling - NText { - text: Quickshell.env("USER") || "user" - font.weight: Style.fontWeightBold - font.capitalization: Font.Capitalize - } - NText { - text: I18n.tr("system.uptime", { - "uptime": uptimeText - }) - pointSize: Style.fontSizeXS * scaling - color: Color.mOnSurfaceVariant - } - } - - Item { - Layout.fillWidth: true - } - - RowLayout { - spacing: root.spacing - Layout.alignment: Qt.AlignRight | Qt.AlignVCenter - - NIconButton { - baseSize: Style.baseWidgetSize * 0.9 - icon: "settings" - tooltipText: I18n.tr("tooltips.open-settings") - onClicked: { - settingsPanel.requestedTab = SettingsPanel.Tab.General - settingsPanel.open() - } - } - - NIconButton { - baseSize: Style.baseWidgetSize * 0.9 - icon: "power" - tooltipText: I18n.tr("tooltips.session-menu") - onClicked: { - sessionMenuPanel.open() - controlCenterPanel.close() - } - } - - NIconButton { - baseSize: Style.baseWidgetSize * 0.9 - icon: "close" - tooltipText: I18n.tr("tooltips.close") - onClicked: { - controlCenterPanel.close() - } - } - } - } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginS * scaling - Layout.bottomMargin: Style.marginS * scaling - } - - GridLayout { - id: grid - Layout.fillWidth: true - columns: (Settings.data.controlCenter.quickSettingsStyle === "compact") ? 4 : 3 - columnSpacing: Style.marginS * scaling - rowSpacing: Style.marginS * scaling - - Repeater { - model: Settings.data.controlCenter.widgets.quickSettings - delegate: ControlCenterWidgetLoader { - Layout.fillWidth: true - widgetId: (modelData.id !== undefined ? modelData.id : "") - widgetProps: { - "screen": root.modelData || null, - "scaling": ScalingService.getScreenScale(screen), - "widgetId": modelData.id, - "section": "quickSettings", - "sectionWidgetIndex": index, - "sectionWidgetsCount": Settings.data.controlCenter.widgets.quickSettings.length - } - Layout.alignment: Qt.AlignVCenter - } - } - } - } - - // ---------------------------------- - // Uptime - Timer { - interval: 60000 - repeat: true - running: true - onTriggered: uptimeProcess.running = true - } - - Process { - id: uptimeProcess - command: ["cat", "/proc/uptime"] - running: true - - stdout: StdioCollector { - onStreamFinished: { - var uptimeSeconds = parseFloat(this.text.trim().split(' ')[0]) - uptimeText = Time.formatVagueHumanReadableDuration(uptimeSeconds) - uptimeProcess.running = false - } - } - } - - function updateSystemInfo() { - uptimeProcess.running = true - } -} diff --git a/Modules/ControlCenter/Cards/UtilitiesCard.qml b/Modules/ControlCenter/Cards/UtilitiesCard.qml deleted file mode 100644 index decd9659..00000000 --- a/Modules/ControlCenter/Cards/UtilitiesCard.qml +++ /dev/null @@ -1,66 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import Quickshell -import qs.Commons -import qs.Modules.Settings -import qs.Services -import qs.Widgets - -// Utilities: record & wallpaper -NBox { - - property real spacing: 0 - - RowLayout { - id: utilRow - anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: spacing - Item { - Layout.fillWidth: true - } - // Screen Recorder - NIconButton { - icon: "camera-video" - enabled: ScreenRecorderService.isAvailable - tooltipText: ScreenRecorderService.isAvailable ? (ScreenRecorderService.isRecording ? I18n.tr("tooltips.stop-screen-recording") : I18n.tr("tooltips.start-screen-recording")) : I18n.tr("tooltips.screen-recorder-not-installed") - colorBg: ScreenRecorderService.isRecording ? Color.mPrimary : Color.mSurfaceVariant - colorFg: ScreenRecorderService.isRecording ? Color.mOnPrimary : Color.mPrimary - onClicked: { - if (!ScreenRecorderService.isAvailable) - return - ScreenRecorderService.toggleRecording() - // If we were not recording and we just initiated a start, close the panel - if (!ScreenRecorderService.isRecording) { - var panel = PanelService.getPanel("controlCenterPanel") - panel?.close() - } - } - } - - // Idle Inhibitor - NIconButton { - icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off" - tooltipText: IdleInhibitorService.isInhibited ? I18n.tr("tooltips.disable-keep-awake") : I18n.tr("tooltips.enable-keep-awake") - colorBg: IdleInhibitorService.isInhibited ? Color.mPrimary : Color.mSurfaceVariant - colorFg: IdleInhibitorService.isInhibited ? Color.mOnPrimary : Color.mPrimary - onClicked: { - IdleInhibitorService.manualToggle() - } - } - - // Wallpaper - NIconButton { - visible: Settings.data.wallpaper.enabled - icon: "wallpaper-selector" - tooltipText: I18n.tr("tooltips.wallpaper-selector") - onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this) - onRightClicked: WallpaperService.setRandomWallpaper() - } - - Item { - Layout.fillWidth: true - } - } -} diff --git a/Modules/ControlCenter/Cards/WeatherCard.qml b/Modules/ControlCenter/Cards/WeatherCard.qml index 9b7d6aec..e6b366ff 100644 --- a/Modules/ControlCenter/Cards/WeatherCard.qml +++ b/Modules/ControlCenter/Cards/WeatherCard.qml @@ -16,28 +16,28 @@ NBox { anchors.left: parent.left anchors.right: parent.right anchors.top: parent.top - anchors.margins: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginM + spacing: Style.marginM clip: true RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS NIcon { Layout.alignment: Qt.AlignVCenter icon: weatherReady ? LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) : "" - pointSize: Style.fontSizeXXXL * 1.75 * scaling + pointSize: Style.fontSizeXXXL * 1.75 color: Color.mPrimary } ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS NText { text: { // Ensure the name is not too long if one had to specify the country const chunks = Settings.data.location.name.split(",") return chunks[0] } - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold } @@ -57,13 +57,13 @@ NBox { temp = Math.round(temp) return `${temp}°${suffix}` } - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL font.weight: Style.fontWeightBold } NText { text: weatherReady ? `(${LocationService.data.weather.timezone_abbreviation})` : "" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant visible: LocationService.data.weather } @@ -80,12 +80,12 @@ NBox { visible: weatherReady Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter - spacing: Style.marginL * scaling + spacing: Style.marginL Repeater { model: weatherReady ? LocationService.data.weather.daily.time : [] delegate: ColumnLayout { Layout.alignment: Qt.AlignHCenter - spacing: Style.marginXS * scaling + spacing: Style.marginXS NText { text: { var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/")) @@ -97,7 +97,7 @@ NBox { NIcon { Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index]) - pointSize: Style.fontSizeXXL * 1.6 * scaling + pointSize: Style.fontSizeXXL * 1.6 color: Color.mPrimary } NText { @@ -113,7 +113,7 @@ NBox { min = Math.round(min) return `${max}°/${min}°` } - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant } } diff --git a/Modules/ControlCenter/ControlCenterPanel.qml b/Modules/ControlCenter/ControlCenterPanel.qml index 19e6e30a..4f997b17 100644 --- a/Modules/ControlCenter/ControlCenterPanel.qml +++ b/Modules/ControlCenter/ControlCenterPanel.qml @@ -10,9 +10,39 @@ import qs.Widgets NPanel { id: root - preferredWidth: 460 - preferredHeight: 790 panelKeyboardFocus: true + preferredWidth: Math.round(460 * Style.uiScaleRatio) + preferredHeight: { + var height = 0 + var count = 0 + for (var i = 0; i < Settings.data.controlCenter.cards.length; i++) { + const card = Settings.data.controlCenter.cards[i] + if (!card.enabled) { + continue + } + count++ + switch (card.id) { + case "profile-card": + height += profileHeight + break + case "shortcuts-card": + height += shortcutsHeight + break + case "audio-card": + height += audioHeight + break + case "weather-card": + height += weatherHeight + break + case "media-sysmon-card": + height += mediaSysMonHeight + break + default: + break + } + } + return height + (count + 1) * Style.marginL + } // Positioning readonly property string controlCenterPosition: Settings.data.controlCenter.position @@ -23,35 +53,86 @@ NPanel { panelAnchorBottom: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("bottom_") panelAnchorTop: controlCenterPosition !== "close_to_bar_button" && controlCenterPosition.startsWith("top_") + readonly property int profileHeight: Math.round(64 * Style.uiScaleRatio) + readonly property int shortcutsHeight: Math.round(52 * Style.uiScaleRatio) + readonly property int audioHeight: Math.round(120 * Style.uiScaleRatio) + readonly property int weatherHeight: Math.round(190 * Style.uiScaleRatio) + readonly property int mediaSysMonHeight: Math.round(260 * Style.uiScaleRatio) + panelContent: Item { id: content - property real cardSpacing: Style.marginL * scaling - - // Layout content ColumnLayout { id: layout - x: content.cardSpacing - y: content.cardSpacing - width: parent.width - (2 * content.cardSpacing) - spacing: content.cardSpacing + x: Style.marginL + y: Style.marginL + width: parent.width - (Style.marginL * 2) + spacing: Style.marginL - // Cards (consistent inter-card spacing via ColumnLayout spacing) - ProfileCard { - Layout.fillWidth: true - Layout.preferredHeight: Math.max(64 * scaling) + Repeater { + model: Settings.data.controlCenter.cards + Loader { + active: modelData.enabled + visible: active + Layout.fillWidth: true + Layout.preferredHeight: { + switch (modelData.id) { + case "profile-card": + return profileHeight + case "shortcuts-card": + return shortcutsHeight + case "audio-card": + return audioHeight + case "weather-card": + return weatherHeight + case "media-sysmon-card": + return mediaSysMonHeight + default: + return 0 + } + } + sourceComponent: { + switch (modelData.id) { + case "profile-card": + return profileCard + case "shortcuts-card": + return shortcutsCard + case "audio-card": + return audioCard + case "weather-card": + return weatherCard + case "media-sysmon-card": + return mediaSysMonCard + } + } + } } + } - WeatherCard { - Layout.fillWidth: true - Layout.preferredHeight: Math.max(190 * scaling) - } + Component { + id: profileCard + ProfileCard {} + } - // Middle section: media + stats column + Component { + id: shortcutsCard + ShortcutsCard {} + } + + Component { + id: audioCard + AudioCard {} + } + + Component { + id: weatherCard + WeatherCard {} + } + + Component { + id: mediaSysMonCard RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: Math.max(260 * scaling) - spacing: content.cardSpacing + spacing: Style.marginL // Media card MediaCard { @@ -61,37 +142,10 @@ NPanel { // System monitors combined in one card SystemMonitorCard { - Layout.preferredWidth: Style.baseWidgetSize * 2.625 * scaling + Layout.preferredWidth: Math.round(Style.baseWidgetSize * 2.625) Layout.fillHeight: true } } - - // Audio card below media and system monitor - AudioCard { - Layout.fillWidth: true - Layout.preferredHeight: Math.max(120 * scaling) - } - - // Bottom actions (two grouped rows of round buttons) - RowLayout { - Layout.fillWidth: true - Layout.preferredHeight: Math.max(60 * scaling) - spacing: content.cardSpacing - - // Power Profiles switcher - PowerProfilesCard { - Layout.fillWidth: true - Layout.fillHeight: true - spacing: content.cardSpacing - } - - // Utilities buttons - UtilitiesCard { - Layout.fillWidth: true - Layout.fillHeight: true - spacing: content.cardSpacing - } - } } } } diff --git a/Modules/ControlCenter/Extras/ControlCenterWidgetLoader.qml b/Modules/ControlCenter/Extras/ControlCenterWidgetLoader.qml index 4e7577ee..5dbe1338 100644 --- a/Modules/ControlCenter/Extras/ControlCenterWidgetLoader.qml +++ b/Modules/ControlCenter/Extras/ControlCenterWidgetLoader.qml @@ -16,16 +16,6 @@ Item { implicitWidth: getImplicitSize(loader.item, "implicitWidth") implicitHeight: getImplicitSize(loader.item, "implicitHeight") - Connections { - target: ScalingService - enabled: loader.item && (loader.item.screen !== undefined) - function onScaleChanged(aScreenName, scale) { - if (loader.item && loader.item.screen && aScreenName === screenName) { - loader.item['scaling'] = scale - } - } - } - function getImplicitSize(item, prop) { return (item && item.visible) ? item[prop] : 0 } diff --git a/Modules/ControlCenter/Widgets/Bluetooth.qml b/Modules/ControlCenter/Widgets/Bluetooth.qml index e9886a4f..e4549a31 100644 --- a/Modules/ControlCenter/Widgets/Bluetooth.qml +++ b/Modules/ControlCenter/Widgets/Bluetooth.qml @@ -4,13 +4,10 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 - text: I18n.tr("quickSettings.bluetooth.label.enabled") icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off" tooltipText: I18n.tr("quickSettings.bluetooth.tooltip.action") - style: Settings.data.controlCenter.quickSettingsStyle || "modern" onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(this) } diff --git a/Modules/ControlCenter/Widgets/KeepAwake.qml b/Modules/ControlCenter/Widgets/KeepAwake.qml index 044734e4..96d60733 100644 --- a/Modules/ControlCenter/Widgets/KeepAwake.qml +++ b/Modules/ControlCenter/Widgets/KeepAwake.qml @@ -4,15 +4,11 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 - text: I18n.tr("quickSettings.keepAwake.label.enabled") icon: IdleInhibitorService.isInhibited ? "keep-awake-on" : "keep-awake-off" hot: IdleInhibitorService.isInhibited tooltipText: I18n.tr("quickSettings.keepAwake.tooltip.action") - style: Settings.data.controlCenter.quickSettingsStyle || "modern" - onClicked: IdleInhibitorService.manualToggle() } diff --git a/Modules/ControlCenter/Widgets/NightLight.qml b/Modules/ControlCenter/Widgets/NightLight.qml index 19cdd669..eb338882 100644 --- a/Modules/ControlCenter/Widgets/NightLight.qml +++ b/Modules/ControlCenter/Widgets/NightLight.qml @@ -4,15 +4,12 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 enabled: ProgramCheckerService.wlsunsetAvailable - text: I18n.tr("quickSettings.nightLight.label.enabled") icon: Settings.data.nightLight.enabled ? (Settings.data.nightLight.forced ? "nightlight-forced" : "nightlight-on") : "nightlight-off" hot: !Settings.data.nightLight.enabled || Settings.data.nightLight.forced - style: Settings.data.controlCenter.quickSettingsStyle || "modern" tooltipText: I18n.tr("quickSettings.nightLight.tooltip.action") onClicked: { diff --git a/Modules/ControlCenter/Widgets/Notifications.qml b/Modules/ControlCenter/Widgets/Notifications.qml index 19c22a82..ae291517 100644 --- a/Modules/ControlCenter/Widgets/Notifications.qml +++ b/Modules/ControlCenter/Widgets/Notifications.qml @@ -4,16 +4,12 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 - text: Settings.data.notifications.doNotDisturb ? I18n.tr("quickSettings.notifications.label.disabled") : I18n.tr("quickSettings.notifications.label.enabled") icon: Settings.data.notifications.doNotDisturb ? "bell-off" : "bell" hot: Settings.data.notifications.doNotDisturb tooltipText: I18n.tr("quickSettings.notifications.tooltip.action") - style: Settings.data.controlCenter.quickSettingsStyle || "modern" - onClicked: PanelService.getPanel("notificationHistoryPanel")?.toggle(this) onRightClicked: Settings.data.notifications.doNotDisturb = !Settings.data.notifications.doNotDisturb } diff --git a/Modules/ControlCenter/Widgets/PowerProfile.qml b/Modules/ControlCenter/Widgets/PowerProfile.qml index 1a504963..ca5f497f 100644 --- a/Modules/ControlCenter/Widgets/PowerProfile.qml +++ b/Modules/ControlCenter/Widgets/PowerProfile.qml @@ -6,18 +6,15 @@ import qs.Services import qs.Widgets // Performance -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 + readonly property bool hasPP: PowerProfileService.available enabled: hasPP - text: hasPP ? PowerProfileService.getName() : I18n.tr("quickSettings.powerProfile.label.unavailable") icon: PowerProfileService.getIcon() hot: !PowerProfileService.isDefault() tooltipText: I18n.tr("quickSettings.powerProfile.tooltip.action") - style: Settings.data.controlCenter.quickSettingsStyle || "modern" - onClicked: { PowerProfileService.cycleProfile() } diff --git a/Modules/ControlCenter/Widgets/ScreenRecorder.qml b/Modules/ControlCenter/Widgets/ScreenRecorder.qml index f9ad8786..7a58c8f3 100644 --- a/Modules/ControlCenter/Widgets/ScreenRecorder.qml +++ b/Modules/ControlCenter/Widgets/ScreenRecorder.qml @@ -4,21 +4,13 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 enabled: ProgramCheckerService.gpuScreenRecorderAvailable icon: "camera-video" - text: ScreenRecorderService.isRecording ? I18n.tr("quickSettings.screenRecorder.label.recording") : I18n.tr("quickSettings.screenRecorder.label.stopped") hot: ScreenRecorderService.isRecording tooltipText: I18n.tr("quickSettings.screenRecorder.tooltip.action") - style: Settings.data.controlCenter.quickSettingsStyle || "modern" - - // Force hover state when recording to get hover colors - property bool originalHovered: hovered - hovered: ScreenRecorderService.isRecording || originalHovered - onClicked: { ScreenRecorderService.toggleRecording() if (!ScreenRecorderService.isRecording) { diff --git a/Modules/ControlCenter/Widgets/WallpaperSelector.qml b/Modules/ControlCenter/Widgets/WallpaperSelector.qml index 95a50af3..ff513bc1 100644 --- a/Modules/ControlCenter/Widgets/WallpaperSelector.qml +++ b/Modules/ControlCenter/Widgets/WallpaperSelector.qml @@ -4,16 +4,12 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 enabled: Settings.data.wallpaper.enabled icon: "wallpaper-selector" - text: I18n.tr("quickSettings.wallpaperSelector.label") tooltipText: I18n.tr("quickSettings.wallpaperSelector.tooltip.action") - style: Settings.data.controlCenter.quickSettingsStyle || "modern" - onClicked: PanelService.getPanel("wallpaperPanel")?.toggle(this) onRightClicked: WallpaperService.setRandomWallpaper() } diff --git a/Modules/ControlCenter/Widgets/WiFi.qml b/Modules/ControlCenter/Widgets/WiFi.qml index 7f739866..faaedc73 100644 --- a/Modules/ControlCenter/Widgets/WiFi.qml +++ b/Modules/ControlCenter/Widgets/WiFi.qml @@ -4,9 +4,8 @@ import qs.Commons import qs.Services import qs.Widgets -NQuickSetting { +NIconButtonHot { property ShellScreen screen - property real scaling: 1.0 icon: { try { @@ -29,21 +28,6 @@ NQuickSetting { } } - text: { - if (NetworkService.ethernetConnected) { - return I18n.tr("quickSettings.wifi.label.ethernet") - } - let connected = false - for (const net in NetworkService.networks) { - if (NetworkService.networks[net].connected) { - connected = true - break - } - } - return connected ? I18n.tr("quickSettings.wifi.label.wifi") : I18n.tr("quickSettings.wifi.label.disconnected") - } - - style: Settings.data.controlCenter.quickSettingsStyle || "modern" tooltipText: I18n.tr("quickSettings.wifi.tooltip.action") onClicked: PanelService.getPanel("wifiPanel")?.toggle(this) } diff --git a/Modules/Dock/Dock.qml b/Modules/Dock/Dock.qml index b23c90bc..56a932e5 100644 --- a/Modules/Dock/Dock.qml +++ b/Modules/Dock/Dock.qml @@ -16,7 +16,7 @@ Variants { id: root required property ShellScreen modelData - property real scaling: ScalingService.getScreenScale(modelData) + property bool barIsReady: modelData ? BarService.isBarReady(modelData.name) : false Connections { @@ -28,15 +28,6 @@ Variants { } } - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if (screenName === modelData.name) { - scaling = scale - } - } - } - // Update dock apps when toplevels change Connections { target: ToplevelManager ? ToplevelManager.toplevels : null @@ -71,14 +62,14 @@ Variants { readonly property int showDelay: 100 readonly property int hideAnimationDuration: Style.animationFast readonly property int showAnimationDuration: Style.animationFast - readonly property int peekHeight: 1 // no scaling for peek - readonly property int iconSize: 36 * scaling - readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL * scaling + readonly property int peekHeight: 1 + readonly property int iconSize: 36 + readonly property int floatingMargin: Settings.data.dock.floatingRatio * Style.marginL // Bar detection and positioning properties readonly property bool hasBar: modelData && modelData.name ? (Settings.data.bar.monitors.includes(modelData.name) || (Settings.data.bar.monitors.length === 0)) : false readonly property bool barAtBottom: hasBar && Settings.data.bar.position === "bottom" - readonly property int barHeight: Style.barHeight * scaling + readonly property int barHeight: Style.barHeight // Shared state between windows property bool dockHovered: false @@ -264,7 +255,7 @@ Variants { margins.bottom: { switch (Settings.data.bar.position) { case "bottom": - return (Style.barHeight + Style.marginM) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling + floatingMargin : floatingMargin) + return (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL + floatingMargin : floatingMargin) default: return floatingMargin } @@ -305,12 +296,12 @@ Variants { Rectangle { id: dockContainer - width: dockLayout.implicitWidth + Style.marginM * scaling * 2 + width: dockLayout.implicitWidth + Style.marginM * 2 height: Math.round(iconSize * 1.5) color: Qt.alpha(Color.mSurface, Settings.data.dock.backgroundOpacity) anchors.centerIn: parent - radius: Style.radiusL * scaling - border.width: Math.max(1, Style.borderS * scaling) + radius: Style.radiusL + border.width: Math.max(1, Style.borderS) border.color: Qt.alpha(Color.mOutline, Settings.data.dock.backgroundOpacity) MouseArea { @@ -343,7 +334,7 @@ Variants { Item { id: dock width: dockLayout.implicitWidth - height: parent.height - (Style.marginM * 2 * scaling) + height: parent.height - (Style.marginM * 2) anchors.centerIn: parent function getAppIcon(appData): string { @@ -354,7 +345,7 @@ Variants { RowLayout { id: dockLayout - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.preferredHeight: parent.height anchors.centerIn: parent @@ -401,6 +392,15 @@ Variants { scale: appButton.hovered ? 1.15 : 1.0 + // Apply dock-specific colorization shader only to non-focused apps + layer.enabled: !appButton.isActive && Settings.data.dock.colorizeIcons + layer.effect: ShaderEffect { + property color targetColor: Color.mOnSurface + property real colorizeMode: 0.0 // Dock mode (grayscale) + + fragmentShader: Qt.resolvedUrl(Quickshell.shellDir + "/Shaders/qsb/appicon_colorize.frag.qsb") + } + Behavior on scale { NumberAnimation { duration: Style.animationNormal @@ -446,7 +446,6 @@ Variants { // Context menu popup DockMenu { id: contextMenu - scaling: root.scaling onHoveredChanged: menuHovered = hovered onRequestClose: { contextMenu.hide() @@ -542,7 +541,7 @@ Variants { width: iconSize * 0.2 height: iconSize * 0.1 color: Color.mPrimary - radius: Style.radiusXS * scaling + radius: Style.radiusXS anchors.top: parent.bottom anchors.horizontalCenter: parent.horizontalCenter diff --git a/Modules/Dock/DockMenu.qml b/Modules/Dock/DockMenu.qml index 255e3b9d..d09ea6e7 100644 --- a/Modules/Dock/DockMenu.qml +++ b/Modules/Dock/DockMenu.qml @@ -13,7 +13,7 @@ PopupWindow { property var toplevel: null property Item anchorItem: null - property real scaling: 1.0 + property bool hovered: menuMouseArea.containsMouse property var onAppClosed: null // Callback function for when an app is closed property bool canAutoClose: false @@ -25,8 +25,8 @@ PopupWindow { signal requestClose - implicitWidth: Math.max(160 * scaling, contextMenuColumn.implicitWidth) - implicitHeight: contextMenuColumn.implicitHeight + (Style.marginM * scaling * 2) + implicitWidth: Math.max(160, contextMenuColumn.implicitWidth) + implicitHeight: contextMenuColumn.implicitHeight + (Style.marginM * 2) color: Color.transparent visible: false @@ -117,7 +117,7 @@ PopupWindow { anchor.item: anchorItem anchor.rect.x: anchorItem ? (anchorItem.width - implicitWidth) / 2 : 0 - anchor.rect.y: anchorItem ? -implicitHeight - (Style.marginM * scaling) : 0 + anchor.rect.y: anchorItem ? -implicitHeight - (Style.marginM) : 0 function show(item, toplevelData) { if (!item) { @@ -140,8 +140,8 @@ PopupWindow { // Helper function to determine which menu item is under the mouse function getHoveredItem(mouseY) { - const itemHeight = 32 * scaling - const startY = Style.marginM * scaling + const itemHeight = 32 + const startY = Style.marginM const relativeY = mouseY - startY if (relativeY < 0) @@ -208,9 +208,9 @@ PopupWindow { Rectangle { anchors.fill: parent color: Color.mSurfaceVariant - radius: Style.radiusS * scaling + radius: Style.radiusS border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Single MouseArea to handle both auto-close and menu interactions MouseArea { @@ -246,7 +246,7 @@ PopupWindow { ColumnLayout { id: contextMenuColumn anchors.fill: parent - anchors.margins: Style.marginM * scaling + anchors.margins: Style.marginM spacing: 0 Repeater { @@ -254,26 +254,26 @@ PopupWindow { Rectangle { Layout.fillWidth: true - height: 32 * scaling + height: 32 color: root.hoveredItem === index ? Color.mTertiary : Color.transparent - radius: Style.radiusXS * scaling + radius: Style.radiusXS RowLayout { anchors.left: parent.left - anchors.leftMargin: Style.marginS * scaling + anchors.leftMargin: Style.marginS anchors.verticalCenter: parent.verticalCenter - spacing: Style.marginS * scaling + spacing: Style.marginS NIcon { icon: modelData.icon - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: root.hoveredItem === index ? Color.mOnTertiary : Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter } NText { text: modelData.text - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: root.hoveredItem === index ? Color.mOnTertiary : Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter elide: Text.ElideRight diff --git a/Modules/Launcher/Launcher.qml b/Modules/Launcher/Launcher.qml index f6ec7ae9..271d4c4b 100644 --- a/Modules/Launcher/Launcher.qml +++ b/Modules/Launcher/Launcher.qml @@ -37,8 +37,8 @@ NPanel { property bool resultsReady: false property bool ignoreMouseHover: false - readonly property int badgeSize: Math.round(Style.baseWidgetSize * 1.6 * scaling) - readonly property int entryHeight: Math.round(badgeSize + Style.marginM * 2 * scaling) + readonly property int badgeSize: Math.round(Style.baseWidgetSize * 1.6) + readonly property int entryHeight: Math.round(badgeSize + Style.marginM * 2) // Public API for plugins function setSearchText(text) { @@ -192,10 +192,8 @@ NPanel { // Reset when launcher opens Connections { target: root - function onOpenedChanged() { - if (root.opened) { - mouseMovementDetector.initialized = false - } + function onOpened() { + mouseMovementDetector.initialized = false } } } @@ -295,14 +293,14 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM NTextInput { id: searchInput Layout.fillWidth: true - fontSize: Style.fontSizeL * scaling + fontSize: Style.fontSizeL fontWeight: Style.fontWeightSemiBold text: searchText @@ -350,7 +348,7 @@ NPanel { Layout.fillWidth: true Layout.fillHeight: true - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS model: results currentIndex: selectedIndex cacheBuffer: resultsList.height * 2 @@ -401,9 +399,9 @@ NPanel { } } - width: resultsList.width - Style.marginS * scaling + width: resultsList.width - Style.marginS implicitHeight: entryHeight - radius: Style.radiusM * scaling + radius: Style.radiusM color: entry.isSelected ? Color.mTertiary : Color.mSurface Behavior on color { @@ -416,19 +414,19 @@ NPanel { ColumnLayout { id: contentLayout anchors.fill: parent - anchors.margins: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginM + spacing: Style.marginM // Top row - Main entry content with pin button RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM // Icon badge or Image preview Rectangle { Layout.preferredWidth: badgeSize Layout.preferredHeight: badgeSize - radius: Style.radiusM * scaling + radius: Style.radiusM color: Color.mSurfaceVariant // Image preview for clipboard images @@ -436,7 +434,7 @@ NPanel { id: imagePreview anchors.fill: parent visible: modelData.isImage - imageRadius: Style.radiusM * scaling + imageRadius: Style.radiusM // This property creates a dependency on the service's revision counter readonly property int _rev: ClipboardService.revision @@ -457,7 +455,7 @@ NPanel { BusyIndicator { anchors.centerIn: parent running: true - width: Style.baseWidgetSize * 0.5 * scaling + width: Style.baseWidgetSize * 0.5 height: width } } @@ -475,7 +473,7 @@ NPanel { Loader { id: iconLoader anchors.fill: parent - anchors.margins: Style.marginXS * scaling + anchors.margins: Style.marginXS visible: !modelData.isImage || imagePreview.status === Image.Error active: visible @@ -495,7 +493,7 @@ NPanel { anchors.centerIn: parent visible: !imagePreview.visible && !iconLoader.visible text: modelData.name ? modelData.name.charAt(0).toUpperCase() : "?" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL font.weight: Style.fontWeightBold color: Color.mOnPrimary } @@ -505,10 +503,10 @@ NPanel { visible: modelData.isImage && imagePreview.visible anchors.bottom: parent.bottom anchors.right: parent.right - anchors.margins: 2 * scaling - width: formatLabel.width + 6 * scaling - height: formatLabel.height + 2 * scaling - radius: Style.radiusM * scaling + anchors.margins: 2 + width: formatLabel.width + 6 + height: formatLabel.height + 2 + radius: Style.radiusM color: Color.mSurfaceVariant NText { @@ -521,7 +519,7 @@ NPanel { const parts = desc.split(" • ") return parts[0] || "IMG" } - pointSize: Style.fontSizeXXS * scaling + pointSize: Style.fontSizeXXS color: Color.mPrimary } } @@ -530,11 +528,11 @@ NPanel { // Text content ColumnLayout { Layout.fillWidth: true - spacing: 0 * scaling + spacing: 0 NText { text: modelData.name || "Unknown" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: entry.isSelected ? Color.mOnTertiary : Color.mOnSurface elide: Text.ElideRight @@ -543,7 +541,7 @@ NPanel { NText { text: modelData.description || "" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: entry.isSelected ? Color.mOnTertiary : Color.mOnSurfaceVariant elide: Text.ElideRight Layout.fillWidth: true @@ -598,7 +596,7 @@ NPanel { const prefix = activePlugin?.name ? `${activePlugin.name}: ` : "" return prefix + `${results.length} result${results.length !== 1 ? 's' : ''}` } - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant horizontalAlignment: Text.AlignCenter } diff --git a/Modules/LockScreen/LockScreen.qml b/Modules/LockScreen/LockScreen.qml index 82654abf..8b646e57 100644 --- a/Modules/LockScreen/LockScreen.qml +++ b/Modules/LockScreen/LockScreen.qml @@ -49,7 +49,7 @@ Loader { locked: lockScreen.active WlSessionLockSurface { - readonly property real scaling: ScalingService.dynamicScale(screen) + readonly property var now: Time.date Item { id: batteryIndicator @@ -103,8 +103,8 @@ Loader { visible: Settings.data.general.showScreenCorners property color cornerColor: Settings.data.general.forceBlackScreenCorners ? Qt.rgba(0, 0, 0, 1) : Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity) - property real cornerRadius: Style.screenRadius * scaling - property real cornerSize: Style.screenRadius * scaling + property real cornerRadius: Style.screenRadius + property real cornerSize: Style.screenRadius // Top-left concave corner Canvas { @@ -248,12 +248,12 @@ Loader { // Time, Date, and User Profile Container Rectangle { - width: Math.max(500 * scaling, contentRow.implicitWidth + 24 * scaling) - height: 120 * scaling + width: Math.max(500, contentRow.implicitWidth + 32) + height: Math.max(120, contentRow.implicitHeight + 32) anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top - anchors.topMargin: 100 * scaling - radius: 32 * scaling + anchors.topMargin: 100 + radius: Style.radiusL color: Color.mSurface border.color: Qt.alpha(Color.mOutline, 0.2) border.width: 1 @@ -261,13 +261,13 @@ Loader { RowLayout { id: contentRow anchors.fill: parent - anchors.margins: 12 * scaling - spacing: 8 * scaling + anchors.margins: 16 + spacing: 32 // Left side: Avatar Rectangle { - Layout.preferredWidth: 70 * scaling - Layout.preferredHeight: 70 * scaling + Layout.preferredWidth: 70 + Layout.preferredHeight: 70 Layout.alignment: Qt.AlignVCenter radius: width * 0.5 color: Color.transparent @@ -296,9 +296,9 @@ Loader { NImageCircled { anchors.centerIn: parent - width: 66 * scaling - height: 66 * scaling - imagePath: Settings.data.general.avatarImage + width: 66 + height: 66 + imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" SequentialAnimation on scale { @@ -317,20 +317,15 @@ Loader { } } - // Spacer to center the text section - Item { - Layout.fillWidth: true - } - // Center: User Info Column (left-aligned text) ColumnLayout { Layout.alignment: Qt.AlignVCenter - spacing: 2 * scaling + spacing: 2 // Welcome back + Username on one line NText { - text: I18n.tr("lock-screen.welcome-back") + " " + Quickshell.env("USER") + "!" - pointSize: Style.fontSizeXXXL * scaling + text: I18n.tr("lock-screen.welcome-back") + " " + (Quickshell.env("USER").charAt(0).toUpperCase() + Quickshell.env("USER").slice(1)) + "!" + pointSize: Style.fontSizeXXL font.weight: Font.Medium color: Color.mOnSurface horizontalAlignment: Text.AlignLeft @@ -339,22 +334,21 @@ Loader { // Date below NText { text: Qt.locale().toString(Time.date, "dddd, MMMM d") - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXL font.weight: Font.Medium color: Color.mOnSurfaceVariant horizontalAlignment: Text.AlignLeft } } - // Spacer to push cool time to the right + // Spacer to push time to the right Item { Layout.fillWidth: true } - // Right side: Cool Time (from Calendar) Item { - Layout.preferredWidth: 70 * scaling - Layout.preferredHeight: 70 * scaling + Layout.preferredWidth: 70 + Layout.preferredHeight: 70 Layout.alignment: Qt.AlignVCenter // Seconds circular progress @@ -377,21 +371,21 @@ Loader { var ctx = getContext("2d") var centerX = width / 2 var centerY = height / 2 - var radius = Math.min(width, height) / 2 - 3 * scaling + var radius = Math.min(width, height) / 2 - 3 ctx.reset() // Background circle ctx.beginPath() ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI) - ctx.lineWidth = 2.5 * scaling + ctx.lineWidth = 2.5 ctx.strokeStyle = Qt.alpha(Color.mOnSurface, 0.15) ctx.stroke() // Progress arc ctx.beginPath() ctx.arc(centerX, centerY, radius, -Math.PI / 2, -Math.PI / 2 + progress * 2 * Math.PI) - ctx.lineWidth = 2.5 * scaling + ctx.lineWidth = 2.5 ctx.strokeStyle = Color.mPrimary ctx.lineCap = "round" ctx.stroke() @@ -405,11 +399,12 @@ Loader { NText { text: { - var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(new Date(), "hh AP") : Qt.locale().toString(new Date(), "HH") + var t = Settings.data.location.use12hourFormat ? Qt.locale().toString(Time.date, "hh AP") : Qt.locale().toString(Time.date, "HH") return t } - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold + family: Settings.data.ui.fontFixed color: Color.mOnSurface horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignHCenter @@ -417,8 +412,9 @@ Loader { NText { text: Qt.formatTime(Time.date, "mm") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold + family: Settings.data.ui.fontFixed color: Color.mOnSurfaceVariant horizontalAlignment: Text.AlignHCenter Layout.alignment: Qt.AlignHCenter @@ -430,12 +426,12 @@ Loader { // Error notification Rectangle { - width: 450 * scaling - height: 60 * scaling + width: 450 + height: 60 anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom - anchors.bottomMargin: 300 * scaling - radius: 30 * scaling + anchors.bottomMargin: (Settings.data.general.compactLockScreen ? 240 : 320) * Style.uiScaleRatio + radius: 30 color: Color.mError border.color: Color.mError border.width: 1 @@ -444,18 +440,18 @@ Loader { RowLayout { anchors.centerIn: parent - spacing: 10 * scaling + spacing: 10 NIcon { icon: "alert-circle" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnError } NText { text: lockContext.errorMessage || "Authentication failed" color: Color.mOnError - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Font.Medium horizontalAlignment: Text.AlignHCenter } @@ -469,42 +465,108 @@ Loader { } } - // Bottom container with weather, password input and controls + // Compact status indicators container (compact mode only) Rectangle { - width: 750 * scaling - height: 220 * scaling + width: { + var hasBattery = UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.isPresent + var hasKeyboard = keyboardLayout.currentLayout !== "Unknown" + + if (hasBattery && hasKeyboard) { + return 200 + } else if (hasBattery || hasKeyboard) { + return 120 + } else { + return 0 + } + } + height: 40 anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom - anchors.bottomMargin: 100 * scaling - radius: 32 * scaling + anchors.bottomMargin: 96 + (Settings.data.general.compactLockScreen ? 116 : 220) + topLeftRadius: Style.radiusL + topRightRadius: Style.radiusL + color: Color.mSurface + visible: Settings.data.general.compactLockScreen && ((UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.isPresent) || keyboardLayout.currentLayout !== "Unknown") + + RowLayout { + anchors.centerIn: parent + spacing: 16 + + // Battery indicator + RowLayout { + spacing: 6 + visible: UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.isPresent + + NIcon { + icon: BatteryService.getIcon(Math.round(UPower.displayDevice.percentage * 100), UPower.displayDevice.state === UPowerDeviceState.Charging, true) + pointSize: Style.fontSizeM + color: UPower.displayDevice.state === UPowerDeviceState.Charging ? Color.mPrimary : Color.mOnSurfaceVariant + } + + NText { + text: Math.round(UPower.displayDevice.percentage * 100) + "%" + color: Color.mOnSurfaceVariant + pointSize: Style.fontSizeM + font.weight: Font.Medium + } + } + + // Keyboard layout indicator + RowLayout { + spacing: 6 + visible: keyboardLayout.currentLayout !== "Unknown" + + NIcon { + icon: "keyboard" + pointSize: Style.fontSizeM + color: Color.mOnSurfaceVariant + } + + NText { + text: keyboardLayout.currentLayout + color: Color.mOnSurfaceVariant + pointSize: Style.fontSizeM + font.weight: Font.Medium + elide: Text.ElideRight + } + } + } + } + + // Bottom container with weather, password input and controls + Rectangle { + width: 750 + height: Settings.data.general.compactLockScreen ? 120 : 220 + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: 100 + radius: Style.radiusL color: Color.mSurface - border.color: Qt.alpha(Color.mOutline, 0.2) - border.width: 1 ColumnLayout { anchors.fill: parent - anchors.margins: 14 * scaling - spacing: 14 * scaling + anchors.margins: 14 + spacing: 14 // Weather section RowLayout { Layout.fillWidth: true - Layout.preferredHeight: 65 * scaling - spacing: 18 * scaling - visible: LocationService.coordinatesReady && LocationService.data.weather !== null + Layout.preferredHeight: 65 + spacing: 18 + visible: !Settings.data.general.compactLockScreen && LocationService.coordinatesReady && LocationService.data.weather !== null // Media widget with visualizer Rectangle { - Layout.preferredWidth: 220 * scaling - Layout.preferredHeight: 50 * scaling - radius: 25 * scaling + Layout.preferredWidth: 220 + Layout.preferredHeight: 50 + radius: 25 color: Color.transparent clip: true visible: MediaService.currentPlayer && MediaService.canPlay Loader { anchors.fill: parent - anchors.margins: 4 * scaling + anchors.margins: 4 active: Settings.data.audio.visualizerType === "linear" z: 0 sourceComponent: LinearSpectrum { @@ -517,7 +579,7 @@ Loader { Loader { anchors.fill: parent - anchors.margins: 4 * scaling + anchors.margins: 4 active: Settings.data.audio.visualizerType === "mirrored" z: 0 sourceComponent: MirroredSpectrum { @@ -530,7 +592,7 @@ Loader { Loader { anchors.fill: parent - anchors.margins: 4 * scaling + anchors.margins: 4 active: Settings.data.audio.visualizerType === "wave" z: 0 sourceComponent: WaveSpectrum { @@ -543,35 +605,35 @@ Loader { RowLayout { anchors.fill: parent - anchors.margins: 8 * scaling - spacing: 8 * scaling + anchors.margins: 8 + spacing: 8 z: 1 Rectangle { - Layout.preferredWidth: 34 * scaling - Layout.preferredHeight: 34 * scaling + Layout.preferredWidth: 34 + Layout.preferredHeight: 34 radius: width * 0.5 color: Color.transparent clip: true NImageCircled { anchors.fill: parent - anchors.margins: 2 * scaling + anchors.margins: 2 imagePath: MediaService.trackArtUrl fallbackIcon: "disc" - fallbackIconSize: Style.fontSizeM * scaling + fallbackIconSize: Style.fontSizeM borderColor: Color.mOutline - borderWidth: Math.max(1, Style.borderS * scaling) + borderWidth: Math.max(1, Style.borderS) } } ColumnLayout { Layout.fillWidth: true - spacing: 2 * scaling + spacing: 2 NText { text: MediaService.trackTitle || "No media" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium color: Color.mOnSurface Layout.fillWidth: true @@ -580,7 +642,7 @@ Loader { NText { text: MediaService.trackArtist || "" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant Layout.fillWidth: true elide: Text.ElideRight @@ -592,46 +654,64 @@ Loader { Rectangle { Layout.preferredWidth: 1 Layout.fillHeight: true - Layout.rightMargin: 4 * scaling + Layout.rightMargin: 4 color: Qt.alpha(Color.mOutline, 0.3) visible: MediaService.currentPlayer && MediaService.canPlay } Item { - Layout.preferredWidth: Style.marginM * scaling + Layout.preferredWidth: Style.marginM visible: !(MediaService.currentPlayer && MediaService.canPlay) } // Current weather RowLayout { - Layout.preferredWidth: 180 * scaling - spacing: 8 * scaling + Layout.preferredWidth: 180 + spacing: 8 NIcon { Layout.alignment: Qt.AlignVCenter icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.current_weather.weathercode) - pointSize: Style.fontSizeXXXL * scaling + pointSize: Style.fontSizeXXXL color: Color.mPrimary } ColumnLayout { Layout.fillWidth: true - spacing: 2 * scaling + spacing: 2 RowLayout { Layout.fillWidth: true - spacing: 12 * scaling + spacing: 12 NText { - text: Math.round(LocationService.data.weather.current_weather.temperature) + "°" - pointSize: Style.fontSizeXL * scaling + text: { + var temp = LocationService.data.weather.current_weather.temperature + var suffix = "C" + if (Settings.data.location.useFahrenheit) { + temp = LocationService.celsiusToFahrenheit(temp) + suffix = "F" + } + temp = Math.round(temp) + return temp + "°" + suffix + } + pointSize: Style.fontSizeXL font.weight: Style.fontWeightBold color: Color.mOnSurface } NText { - text: LocationService.data.weather.current_weather.windspeed + " km/h" - pointSize: Style.fontSizeM * scaling + text: { + var wind = LocationService.data.weather.current_weather.windspeed + var unit = "km/h" + if (Settings.data.location.useFahrenheit) { + wind = wind * 0.621371 // Convert km/h to mph + unit = "mph" + } + wind = Math.round(wind) + return wind + " " + unit + } + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant font.weight: Font.Normal } @@ -639,17 +719,17 @@ Loader { RowLayout { Layout.fillWidth: true - spacing: 8 * scaling + spacing: 8 NText { text: Settings.data.location.name.split(",")[0] - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant } NText { text: (LocationService.data.weather.current && LocationService.data.weather.current.relativehumidity_2m) ? LocationService.data.weather.current.relativehumidity_2m + "% humidity" : "" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant } } @@ -658,19 +738,19 @@ Loader { // 3-day forecast RowLayout { - Layout.preferredWidth: 260 * scaling - Layout.rightMargin: 8 * scaling - spacing: 4 * scaling + Layout.preferredWidth: 260 + Layout.rightMargin: 8 + spacing: 4 Repeater { model: 3 delegate: ColumnLayout { Layout.fillWidth: true - spacing: 3 * scaling + spacing: 3 NText { - text: Qt.locale().toString(new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/")), "ddd") - pointSize: Style.fontSizeM * scaling + text: Qt.locale().toString(now, "ddd") + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant horizontalAlignment: Text.AlignHCenter Layout.fillWidth: true @@ -679,13 +759,23 @@ Loader { NIcon { Layout.alignment: Qt.AlignHCenter icon: LocationService.weatherSymbolFromCode(LocationService.data.weather.daily.weathercode[index]) - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL color: Color.mOnSurfaceVariant } NText { - text: Math.round(LocationService.data.weather.daily.temperature_2m_max[index]) + "°/" + Math.round(LocationService.data.weather.daily.temperature_2m_min[index]) + "°" - pointSize: Style.fontSizeM * scaling + text: { + var max = LocationService.data.weather.daily.temperature_2m_max[index] + var min = LocationService.data.weather.daily.temperature_2m_min[index] + if (Settings.data.location.useFahrenheit) { + max = LocationService.celsiusToFahrenheit(max) + min = LocationService.celsiusToFahrenheit(min) + } + max = Math.round(max) + min = Math.round(min) + return max + "°/" + min + "°" + } + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium color: Color.mOnSurfaceVariant horizontalAlignment: Text.AlignHCenter @@ -695,47 +785,50 @@ Loader { } } - // Battery and Keyboard Layout + // Battery and Keyboard Layout (full mode only) ColumnLayout { - Layout.preferredWidth: 60 * scaling - spacing: 4 * scaling + Layout.preferredWidth: 60 + spacing: 8 + // Battery RowLayout { - Layout.preferredWidth: 60 * scaling - Layout.preferredHeight: 22 * scaling - spacing: 4 * scaling + spacing: 4 visible: UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.isPresent NIcon { icon: BatteryService.getIcon(Math.round(UPower.displayDevice.percentage * 100), UPower.displayDevice.state === UPowerDeviceState.Charging, true) - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: UPower.displayDevice.state === UPowerDeviceState.Charging ? Color.mPrimary : Color.mOnSurfaceVariant } NText { text: Math.round(UPower.displayDevice.percentage * 100) + "%" color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Font.Medium + elide: Text.ElideRight + Layout.fillWidth: true } } + // Keyboard Layout RowLayout { - Layout.preferredWidth: 60 * scaling - Layout.preferredHeight: 22 * scaling - spacing: 4 * scaling + spacing: 4 + visible: keyboardLayout.currentLayout !== "Unknown" NIcon { icon: "keyboard" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant } NText { text: keyboardLayout.currentLayout color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Font.Medium + elide: Text.ElideRight + Layout.fillWidth: true } } } @@ -747,26 +840,26 @@ Loader { spacing: 0 Item { - Layout.preferredWidth: Style.marginM * scaling + Layout.preferredWidth: Style.marginM } Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 48 * scaling - radius: 24 * scaling + Layout.preferredHeight: 48 + radius: 24 color: Color.mSurface border.color: passwordInput.activeFocus ? Color.mPrimary : Qt.alpha(Color.mOutline, 0.3) border.width: passwordInput.activeFocus ? 2 : 1 Row { anchors.left: parent.left - anchors.leftMargin: 18 * scaling + anchors.leftMargin: 18 anchors.verticalCenter: parent.verticalCenter - spacing: 14 * scaling + spacing: 14 NIcon { icon: "lock" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: passwordInput.activeFocus ? Color.mPrimary : Color.mOnSurfaceVariant anchors.verticalCenter: parent.verticalCenter } @@ -778,7 +871,7 @@ Loader { height: 0 visible: false enabled: !lockContext.unlockInProgress - font.pointSize: Style.fontSizeM * scaling + font.pointSize: Style.fontSizeM color: Color.mPrimary echoMode: TextInput.Password passwordCharacter: "•" @@ -799,8 +892,8 @@ Loader { spacing: 0 Rectangle { - width: 2 * scaling - height: 20 * scaling + width: 2 + height: 20 color: Color.mPrimary visible: passwordInput.activeFocus && passwordInput.text.length === 0 anchors.verticalCenter: parent.verticalCenter @@ -820,7 +913,7 @@ Loader { } Row { - spacing: 6 * scaling + spacing: 6 visible: passwordInput.text.length > 0 anchors.verticalCenter: parent.verticalCenter @@ -829,7 +922,7 @@ Loader { NIcon { icon: "circle-filled" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mPrimary opacity: 1.0 } @@ -837,8 +930,8 @@ Loader { } Rectangle { - width: 2 * scaling - height: 20 * scaling + width: 2 + height: 20 color: Color.mPrimary visible: passwordInput.activeFocus && passwordInput.text.length > 0 anchors.verticalCenter: parent.verticalCenter @@ -861,10 +954,10 @@ Loader { Rectangle { anchors.right: parent.right - anchors.rightMargin: 8 * scaling + anchors.rightMargin: 8 anchors.verticalCenter: parent.verticalCenter - width: 36 * scaling - height: 36 * scaling + width: 36 + height: 36 radius: width * 0.5 color: submitButtonArea.containsMouse ? Color.mPrimary : Qt.alpha(Color.mPrimary, 0.8) border.color: Color.mPrimary @@ -874,7 +967,7 @@ Loader { NIcon { anchors.centerIn: parent icon: "arrow-forward" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnPrimary } @@ -895,40 +988,42 @@ Loader { } Item { - Layout.preferredWidth: Style.marginM * scaling + Layout.preferredWidth: Style.marginM } } // System control buttons RowLayout { Layout.fillWidth: true - Layout.preferredHeight: 48 * scaling - spacing: 10 * scaling + Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48 + spacing: 10 Item { - Layout.preferredWidth: Style.marginM * scaling + Layout.preferredWidth: Style.marginM } Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 48 * scaling - radius: 24 * scaling + Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48 + radius: Settings.data.general.compactLockScreen ? 18 : 24 color: logoutButtonArea.containsMouse ? Color.mTertiary : "transparent" + border.color: Color.mOutline + border.width: 1 RowLayout { anchors.centerIn: parent - spacing: 6 * scaling + spacing: 6 NIcon { icon: "logout" - pointSize: Style.fontSizeL * scaling + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL color: logoutButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant } NText { text: I18n.tr("session-menu.logout") color: logoutButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM font.weight: Font.Medium } } @@ -946,28 +1041,85 @@ Loader { easing.type: Easing.OutCubic } } + + Behavior on border.color { + ColorAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } } Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 48 * scaling - radius: 24 * scaling - color: rebootButtonArea.containsMouse ? Color.mTertiary : "transparent" + Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48 + radius: Settings.data.general.compactLockScreen ? 18 : 24 + color: suspendButtonArea.containsMouse ? Color.mTertiary : "transparent" + border.color: Color.mOutline + border.width: 1 RowLayout { anchors.centerIn: parent - spacing: 6 * scaling + spacing: 6 + + NIcon { + icon: "suspend" + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL + color: suspendButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant + } + + NText { + text: I18n.tr("session-menu.suspend") + color: suspendButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM + font.weight: Font.Medium + } + } + + MouseArea { + id: suspendButtonArea + anchors.fill: parent + hoverEnabled: true + onClicked: CompositorService.suspend() + } + + Behavior on color { + ColorAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + + Behavior on border.color { + ColorAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } + } + + Rectangle { + Layout.fillWidth: true + Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48 + radius: Settings.data.general.compactLockScreen ? 18 : 24 + color: rebootButtonArea.containsMouse ? Color.mTertiary : "transparent" + border.color: Color.mOutline + border.width: 1 + + RowLayout { + anchors.centerIn: parent + spacing: 6 NIcon { icon: "reboot" - pointSize: Style.fontSizeL * scaling + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL color: rebootButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant } NText { text: I18n.tr("session-menu.reboot") color: rebootButtonArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM font.weight: Font.Medium } } @@ -985,30 +1137,37 @@ Loader { easing.type: Easing.OutCubic } } + + Behavior on border.color { + ColorAnimation { + duration: 200 + easing.type: Easing.OutCubic + } + } } Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 48 * scaling - radius: 24 * scaling + Layout.preferredHeight: Settings.data.general.compactLockScreen ? 36 : 48 + radius: Settings.data.general.compactLockScreen ? 18 : 24 color: shutdownButtonArea.containsMouse ? Color.mError : "transparent" - border.color: shutdownButtonArea.containsMouse ? Color.mError : Color.transparent + border.color: shutdownButtonArea.containsMouse ? Color.mError : Color.mOutline border.width: 1 RowLayout { anchors.centerIn: parent - spacing: 6 * scaling + spacing: 6 NIcon { icon: "shutdown" - pointSize: Style.fontSizeL * scaling + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeM : Style.fontSizeL color: shutdownButtonArea.containsMouse ? Color.mOnError : Color.mOnSurfaceVariant } NText { text: I18n.tr("session-menu.shutdown") color: shutdownButtonArea.containsMouse ? Color.mOnError : Color.mOnSurfaceVariant - pointSize: Style.fontSizeM * scaling + pointSize: Settings.data.general.compactLockScreen ? Style.fontSizeS : Style.fontSizeM font.weight: Font.Medium } } @@ -1036,7 +1195,7 @@ Loader { } Item { - Layout.preferredWidth: Style.marginM * scaling + Layout.preferredWidth: Style.marginM } } } diff --git a/Modules/Notification/Notification.qml b/Modules/Notification/Notification.qml index b6dd8672..3c97971a 100644 --- a/Modules/Notification/Notification.qml +++ b/Modules/Notification/Notification.qml @@ -17,7 +17,6 @@ Variants { id: root required property ShellScreen modelData - property real scaling: ScalingService.getScreenScale(modelData) // Access the notification model from the service property ListModel notificationModel: NotificationService.activeList @@ -42,15 +41,6 @@ Variants { } } - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if (root.modelData && screenName === root.modelData.name) { - root.scaling = scale - } - } - } - sourceComponent: PanelWindow { screen: modelData @@ -79,10 +69,10 @@ Variants { margins.top: { if (!(anchors.top)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "top") { - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraV + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraV } return base } @@ -90,10 +80,10 @@ Variants { margins.bottom: { if (!(anchors.bottom)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "bottom") { - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraV + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraV } return base } @@ -101,10 +91,10 @@ Variants { margins.left: { if (!(anchors.left)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "left") { - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraH + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraH } return base } @@ -112,15 +102,15 @@ Variants { margins.right: { if (!(anchors.right)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "right") { - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraH + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraH } return base } - implicitWidth: 360 * scaling + implicitWidth: 360 implicitHeight: notificationStack.implicitHeight WlrLayershell.exclusionMode: ExclusionMode.Ignore @@ -165,10 +155,20 @@ Variants { anchors.left: parent.isLeft ? parent.left : undefined anchors.right: parent.isRight ? parent.right : undefined anchors.horizontalCenter: parent.isCentered ? parent.horizontalCenter : undefined - spacing: Style.marginS * scaling - width: 360 * scaling + spacing: Style.marginS + width: 360 visible: true + // Animate when notifications are added/removed + Behavior on implicitHeight { + SpringAnimation { + spring: 2.0 + damping: 0.4 + epsilon: 0.01 + mass: 0.8 + } + } + // Multiple notifications display Repeater { model: notificationModel @@ -178,15 +178,14 @@ Variants { // Store the notification ID and data for reference property string notificationId: model.id property var notificationData: model - property real cardScaling: root.scaling - Layout.preferredWidth: 360 * cardScaling - Layout.preferredHeight: notificationLayout.implicitHeight + (Style.marginL * 2 * cardScaling) + Layout.preferredWidth: 360 + Layout.preferredHeight: notificationLayout.implicitHeight + (Style.marginL * 2) Layout.maximumHeight: Layout.preferredHeight - radius: Style.radiusL * cardScaling + radius: Style.radiusL border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * cardScaling) + border.width: Math.max(1, Style.borderS) color: Color.mSurface // Optimized progress bar container @@ -195,7 +194,7 @@ Variants { anchors.top: parent.top anchors.left: parent.left anchors.right: parent.right - height: 2 * cardScaling + height: 2 color: Color.transparent // Pre-calculate available width for the progress bar @@ -243,8 +242,12 @@ Variants { // Animation properties property real scaleValue: 0.8 property real opacityValue: 0.0 + property real slideOffset: 0 property bool isRemoving: false + // Staggered animation delay based on index + readonly property int animationDelay: index * 100 + // Right-click to dismiss MouseArea { anchors.fill: parent @@ -256,14 +259,55 @@ Variants { } } - // Scale and fade-in animation + // Scale, fade, and slide animation scale: scaleValue opacity: opacityValue + // Slide animation based on notification position (vertical only for stacking) + y: slideOffset + + // Calculate slide direction based on notification location + readonly property real slideDistance: 300 + readonly property real slideInOffset: { + // For vertical stacking, always slide from top + if (parent.isTop) + return -slideDistance + if (parent.isBottom) + return slideDistance + return 0 + } + readonly property real slideOutOffset: { + // Slide out in the same direction as slide in + if (parent.isTop) + return -slideDistance + if (parent.isBottom) + return slideDistance + return 0 + } + // Animate in when the item is created Component.onCompleted: { - scaleValue = 1.0 - opacityValue = 1.0 + // Start from slide position + slideOffset = slideInOffset + scaleValue = 0.8 + opacityValue = 0.0 + + // Delay animation based on index for staggered effect + delayTimer.interval = animationDelay + delayTimer.start() + } + + // Timer for staggered animation start + Timer { + id: delayTimer + interval: 0 + repeat: false + onTriggered: { + // Animate to final position + slideOffset = 0 + scaleValue = 1.0 + opacityValue = 1.0 + } } // Animate out when being removed @@ -272,6 +316,7 @@ Variants { return // Prevent multiple animations isRemoving = true + slideOffset = slideOutOffset scaleValue = 0.8 opacityValue = 0.0 } @@ -293,46 +338,57 @@ Variants { } } - // Animation behaviors + // Animation behaviors with spring physics Behavior on scale { - NumberAnimation { - duration: Style.animationNormal - easing.type: Easing.OutExpo + SpringAnimation { + spring: 3 + damping: 0.4 + epsilon: 0.01 + mass: 0.8 } } Behavior on opacity { NumberAnimation { duration: Style.animationNormal - easing.type: Easing.OutQuad + easing.type: Easing.OutCubic + } + } + + Behavior on y { + SpringAnimation { + spring: 2.5 + damping: 0.3 + epsilon: 0.01 + mass: 0.6 } } ColumnLayout { id: notificationLayout anchors.fill: parent - anchors.margins: Style.marginM * cardScaling - anchors.rightMargin: (Style.marginM + 32) * cardScaling // Leave space for close button - spacing: Style.marginM * cardScaling + anchors.margins: Style.marginM + anchors.rightMargin: (Style.marginM + 32) // Leave space for close button + spacing: Style.marginM // Main content section RowLayout { Layout.fillWidth: true - spacing: Style.marginM * cardScaling + spacing: Style.marginM ColumnLayout { // For real-time notification always show the original image // as the cached version is most likely still processing. NImageCircled { - Layout.preferredWidth: 40 * cardScaling - Layout.preferredHeight: 40 * cardScaling + Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio) + Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio) Layout.alignment: Qt.AlignTop - Layout.topMargin: 30 * cardScaling + Layout.topMargin: 30 imagePath: model.originalImage || "" borderColor: Color.transparent borderWidth: 0 fallbackIcon: "bell" - fallbackIconSize: 24 * cardScaling + fallbackIconSize: 24 } Item { Layout.fillHeight: true @@ -342,17 +398,17 @@ Variants { // Text content ColumnLayout { Layout.fillWidth: true - spacing: Style.marginS * cardScaling + spacing: Style.marginS // Header section with app name and timestamp RowLayout { Layout.fillWidth: true - spacing: Style.marginS * cardScaling + spacing: Style.marginS Rectangle { - Layout.preferredWidth: 6 * cardScaling - Layout.preferredHeight: 6 * cardScaling - radius: Style.radiusXS * cardScaling + Layout.preferredWidth: 6 + Layout.preferredHeight: 6 + radius: Style.radiusXS color: { if (model.urgency === NotificationUrgency.Critical || model.urgency === 2) return Color.mError @@ -367,7 +423,7 @@ Variants { NText { text: `${model.appName || I18n.tr("system.unknown-app")} · ${Time.formatRelativeTime(model.timestamp)}` color: Color.mSecondary - pointSize: Style.fontSizeXS * cardScaling + pointSize: Style.fontSizeXS } Item { @@ -377,7 +433,7 @@ Variants { NText { text: model.summary || I18n.tr("general.no-summary") - pointSize: Style.fontSizeL * cardScaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightMedium color: Color.mOnSurface textFormat: Text.PlainText @@ -390,7 +446,7 @@ Variants { NText { text: model.body || "" - pointSize: Style.fontSizeM * cardScaling + pointSize: Style.fontSizeM color: Color.mOnSurface textFormat: Text.PlainText wrapMode: Text.WrapAtWordBoundaryOrAnywhere @@ -403,8 +459,8 @@ Variants { // Notification actions Flow { Layout.fillWidth: true - spacing: Style.marginS * cardScaling - Layout.topMargin: Style.marginM * cardScaling + spacing: Style.marginS + Layout.topMargin: Style.marginM flow: Flow.LeftToRight layoutDirection: Qt.LeftToRight @@ -436,12 +492,12 @@ Variants { } return actionText } - fontSize: Style.fontSizeS * cardScaling + fontSize: Style.fontSizeS backgroundColor: Color.mPrimary textColor: hovered ? Color.mOnTertiary : Color.mOnPrimary hoverColor: Color.mTertiary outlined: false - implicitHeight: 24 * cardScaling + implicitHeight: 24 onClicked: { NotificationService.invokeAction(parent.parentNotificationId, actionData.identifier) } @@ -458,9 +514,9 @@ Variants { tooltipText: I18n.tr("tooltips.close") baseSize: Style.baseWidgetSize * 0.6 anchors.top: parent.top - anchors.topMargin: Style.marginM * cardScaling + anchors.topMargin: Style.marginM anchors.right: parent.right - anchors.rightMargin: Style.marginM * cardScaling + anchors.rightMargin: Style.marginM onClicked: { animateOut() diff --git a/Modules/Notification/NotificationHistoryPanel.qml b/Modules/Notification/NotificationHistoryPanel.qml index bd830f21..8bf5583f 100644 --- a/Modules/Notification/NotificationHistoryPanel.qml +++ b/Modules/Notification/NotificationHistoryPanel.qml @@ -26,23 +26,23 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM // Header section RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NIcon { icon: "bell" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mPrimary } NText { text: I18n.tr("notifications.panel.title") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface Layout.fillWidth: true @@ -84,7 +84,7 @@ NPanel { Layout.fillHeight: true Layout.alignment: Qt.AlignHCenter visible: NotificationService.historyList.count === 0 - spacing: Style.marginL * scaling + spacing: Style.marginL Item { Layout.fillHeight: true @@ -92,21 +92,21 @@ NPanel { NIcon { icon: "bell-off" - pointSize: 64 * scaling + pointSize: 64 color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("notifications.panel.no-notifications") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter } NText { text: I18n.tr("notifications.panel.description") - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true @@ -128,7 +128,7 @@ NPanel { verticalPolicy: ScrollBar.AsNeeded model: NotificationService.historyList - spacing: Style.marginM * scaling + spacing: Style.marginM clip: true boundsBehavior: Flickable.StopAtBounds visible: NotificationService.historyList.count > 0 @@ -141,11 +141,11 @@ NPanel { property bool isExpanded: notificationList.expandedId === notificationId width: notificationList.width - height: notificationLayout.implicitHeight + (Style.marginM * scaling * 2) - radius: Style.radiusM * scaling + height: notificationLayout.implicitHeight + (Style.marginM * 2) + radius: Style.radiusM color: Color.mSurfaceVariant border.color: Qt.alpha(Color.mOutline, Style.opacityMedium) - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on height { NumberAnimation { @@ -165,7 +165,7 @@ NPanel { MouseArea { anchors.fill: parent // Don't capture clicks on the delete button - anchors.rightMargin: 48 * scaling + anchors.rightMargin: 48 enabled: (summaryText.truncated || bodyText.truncated) onClicked: { if (notificationList.expandedId === notificationId) { @@ -180,20 +180,20 @@ NPanel { RowLayout { id: notificationLayout anchors.fill: parent - anchors.margins: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginM + spacing: Style.marginM ColumnLayout { NImageCircled { - Layout.preferredWidth: 40 * scaling - Layout.preferredHeight: 40 * scaling + Layout.preferredWidth: Math.round(40 * Style.uiScaleRatio) + Layout.preferredHeight: Math.round(40 * Style.uiScaleRatio) Layout.alignment: Qt.AlignTop - Layout.topMargin: 20 * scaling + Layout.topMargin: 20 imagePath: model.cachedImage || model.originalImage || "" borderColor: Color.transparent borderWidth: 0 fallbackIcon: "bell" - fallbackIconSize: 24 * scaling + fallbackIconSize: 24 } Item { Layout.fillHeight: true @@ -204,20 +204,20 @@ NPanel { ColumnLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignTop - spacing: Style.marginXS * scaling - Layout.rightMargin: -(Style.marginM + Style.baseWidgetSize * 0.6) * scaling + spacing: Style.marginXS + Layout.rightMargin: -(Style.marginM + Style.baseWidgetSize * 0.6) // Header row with app name and timestamp RowLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS // Urgency indicator Rectangle { - Layout.preferredWidth: 6 * scaling - Layout.preferredHeight: 6 * scaling + Layout.preferredWidth: 6 + Layout.preferredHeight: 6 Layout.alignment: Qt.AlignVCenter - radius: 3 * scaling + radius: 3 visible: model.urgency !== 1 color: { if (model.urgency === 2) @@ -231,13 +231,13 @@ NPanel { NText { text: model.appName || "Unknown App" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mSecondary } NText { text: Time.formatRelativeTime(model.timestamp) - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mSecondary } @@ -250,7 +250,7 @@ NPanel { NText { id: summaryText text: model.summary || I18n.tr("general.no-summary") - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Font.Medium color: Color.mOnSurface textFormat: Text.PlainText @@ -264,7 +264,7 @@ NPanel { NText { id: bodyText text: model.body || "" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant textFormat: Text.PlainText wrapMode: Text.Wrap @@ -277,14 +277,14 @@ NPanel { // Spacer for expand indicator Item { Layout.fillWidth: true - Layout.preferredHeight: (!isExpanded && (summaryText.truncated || bodyText.truncated)) ? (Style.marginS * scaling) : 0 + Layout.preferredHeight: (!isExpanded && (summaryText.truncated || bodyText.truncated)) ? (Style.marginS) : 0 } // Expand indicator RowLayout { Layout.fillWidth: true visible: !isExpanded && (summaryText.truncated || bodyText.truncated) - spacing: Style.marginXS * scaling + spacing: Style.marginXS Item { Layout.fillWidth: true @@ -292,14 +292,14 @@ NPanel { NText { text: I18n.tr("notifications.panel.click-to-expand") || "Click to expand" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mPrimary font.weight: Font.Medium } NIcon { icon: "chevron-down" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mPrimary } } diff --git a/Modules/OSD/OSD.qml b/Modules/OSD/OSD.qml index a4ec5701..23c63a0b 100644 --- a/Modules/OSD/OSD.qml +++ b/Modules/OSD/OSD.qml @@ -16,7 +16,6 @@ Variants { id: root required property ShellScreen modelData - property real scaling: ScalingService.getScreenScale(modelData) // Access the notification model from the service property ListModel notificationModel: NotificationService.activeList @@ -40,13 +39,9 @@ Variants { property bool inputMuteInitialized: false // Brightness properties + property real lastUpdatedBrightness: 0 + readonly property real currentBrightness: lastUpdatedBrightness property bool brightnessInitialized: false - readonly property real currentBrightness: { - if (BrightnessService.monitors.length > 0) { - return BrightnessService.monitors[0].brightness || 0 - } - return 0 - } // Get appropriate icon based on current OSD type function getIcon() { @@ -130,20 +125,13 @@ Variants { readonly property bool isRight: (location.indexOf("_right") >= 0) || (location === "right") readonly property bool isCentered: (location === "top" || location === "bottom") readonly property bool verticalMode: (location === "left" || location === "right") - readonly property int hWidth: Math.round(320 * root.scaling) - readonly property int hHeight: Math.round(64 * root.scaling) + readonly property int hWidth: Math.round(320 * Style.uiScaleRatio) + readonly property int hHeight: Math.round(64 * Style.uiScaleRatio) + readonly property int vHeight: hWidth // Vertical OSD height (matches horizontal width) // Ensure an even width to keep the vertical bar perfectly centered - readonly property int barThickness: (function () { - const base = Math.max(6, Math.round(6 * root.scaling)) + readonly property int barThickness: { + const base = Math.max(8, Math.round(8 * Style.uiScaleRatio)) return (base % 2 === 0) ? base : base + 1 - })() - - Component.onCompleted: { - connectBrightnessMonitors() - } - - Component.onDestruction: { - disconnectBrightnessMonitors() } // Anchor selection based on location (window edges) @@ -156,10 +144,10 @@ Variants { margins.top: { if (!(anchors.top)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "top") { - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraV + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0 + return Style.barHeight + base + floatExtraV } return base } @@ -167,10 +155,10 @@ Variants { margins.bottom: { if (!(anchors.bottom)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "bottom") { - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraV + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0 + return Style.barHeight + base + floatExtraV } return base } @@ -178,10 +166,10 @@ Variants { margins.left: { if (!(anchors.left)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "left") { - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraH + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + return Style.barHeight + base + floatExtraH } return base } @@ -189,10 +177,10 @@ Variants { margins.right: { if (!(anchors.right)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "right") { - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraH + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + return Style.barHeight + base + floatExtraH } return base } @@ -203,26 +191,29 @@ Variants { color: Color.transparent WlrLayershell.keyboardFocus: WlrKeyboardFocus.None + WlrLayershell.layer: (Settings.data.osd && Settings.data.osd.alwaysOnTop) ? WlrLayer.Overlay : WlrLayer.Top exclusionMode: PanelWindow.ExclusionMode.Ignore Rectangle { id: osdItem width: parent.width - height: panel.verticalMode ? panel.hWidth : Math.round(64 * root.scaling) - radius: Style.radiusL * root.scaling + height: panel.verticalMode ? panel.vHeight : Math.round(64 * Style.uiScaleRatio) + radius: Style.radiusL color: Color.mSurface border.color: Color.mOutline - border.width: (function () { - const bw = Math.max(2, Math.round(Style.borderM * root.scaling)) + border.width: { + const bw = Math.max(2, Style.borderM) return (bw % 2 === 0) ? bw : bw + 1 - })() + } visible: false opacity: 0 - scale: 0.85 + scale: 0.85 // initial scale for a little zoom effect - anchors.horizontalCenter: verticalMode ? undefined : parent.horizontalCenter - anchors.verticalCenter: verticalMode ? parent.verticalCenter : undefined + // Only horizontally center when the window itself is centered (top/bottom positions) + // For left/right vertical mode, fill the parent width + anchors.horizontalCenter: (!panel.verticalMode && panel.isCentered) ? parent.horizontalCenter : undefined + anchors.verticalCenter: panel.verticalMode ? parent.verticalCenter : undefined Behavior on opacity { NumberAnimation { @@ -274,13 +265,13 @@ Variants { anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.margins: Style.marginM * root.scaling - spacing: Style.marginM * root.scaling + anchors.margins: Style.marginL + spacing: Style.marginM NIcon { icon: root.getIcon() color: root.getIconColor() - pointSize: Style.fontSizeXL * root.scaling + pointSize: Style.fontSizeXL Layout.alignment: Qt.AlignVCenter Behavior on color { @@ -293,7 +284,7 @@ Variants { // Progress bar with calculated width Rectangle { - Layout.preferredWidth: Math.round(220 * root.scaling) + Layout.fillWidth: true height: panel.barThickness radius: Math.round(panel.barThickness / 2) color: Color.mSurfaceVariant @@ -326,12 +317,12 @@ Variants { NText { text: root.getDisplayPercentage() color: Color.mOnSurface - pointSize: Style.fontSizeS * root.scaling + pointSize: Style.fontSizeS family: Settings.data.ui.fontFixed - Layout.alignment: Qt.AlignVCenter - horizontalAlignment: Text.AlignLeft + Layout.alignment: Qt.AlignVCenter | Qt.AlignRight + horizontalAlignment: Text.AlignRight verticalAlignment: Text.AlignVCenter - Layout.preferredWidth: Math.round(50 * root.scaling) + Layout.preferredWidth: Math.round(50 * Style.uiScaleRatio) } } } @@ -339,90 +330,88 @@ Variants { Component { id: verticalContent - ColumnLayout { - // Ensure inner padding respects the rounded corners; avoid clipping the icon/text - property int vMargin: (function () { - const styleMargin = Math.round(Style.marginL * root.scaling) - const cornerGuard = Math.round(osdItem.radius) - return Math.max(styleMargin, cornerGuard) - })() - property int vMarginTop: Math.max(Math.round(osdItem.radius), Math.round(Style.marginS * root.scaling)) - property int balanceDelta: Math.round(Style.marginS * root.scaling) - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.topMargin: vMarginTop - anchors.bottomMargin: vMargin - width: (function () { - const w = parent.width - (vMargin * 2) - return (w % 2 === 0) ? w : w - 1 - })() - spacing: Math.round(Style.marginS * root.scaling) + Item { + anchors.fill: parent - // Percentage text at top - Item { - Layout.fillWidth: true - Layout.preferredHeight: percentText.implicitHeight - NText { - id: percentText - text: root.getDisplayPercentage() - color: Color.mOnSurface - pointSize: Style.fontSizeS * root.scaling - family: Settings.data.ui.fontFixed - anchors.horizontalCenter: parent.horizontalCenter - anchors.verticalCenter: parent.verticalCenter - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter + ColumnLayout { + // Ensure inner padding respects the rounded corners; avoid clipping the icon/text + property int vMargin: { + const styleMargin = Style.marginL + const cornerGuard = Math.round(osdItem.radius) + return Math.max(styleMargin, cornerGuard) } - } + property int vMarginTop: Math.round(Math.max(osdItem.radius, Style.marginS)) + property int balanceDelta: Style.marginS + anchors.fill: parent + anchors.topMargin: vMargin + anchors.bottomMargin: vMargin + spacing: Style.marginS - // Progress bar - Item { - Layout.fillWidth: true - Layout.fillHeight: true - Rectangle { - anchors.horizontalCenter: parent.horizontalCenter - anchors.top: parent.top - anchors.bottom: parent.bottom - width: panel.barThickness - radius: Math.round(panel.barThickness / 2) - color: Color.mSurfaceVariant + // Percentage text at top + Item { + Layout.fillWidth: true + Layout.preferredHeight: Math.round(20 * Style.uiScaleRatio) + NText { + id: percentText + text: root.getDisplayPercentage() + color: Color.mOnSurface + pointSize: Style.fontSizeS + family: Settings.data.ui.fontFixed + width: Math.round(50 * Style.uiScaleRatio) + height: parent.height + anchors.centerIn: parent + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + } + } + // Progress bar + Item { + Layout.fillWidth: true + Layout.fillHeight: true // Fill remaining space between text and icon Rectangle { - anchors.left: parent.left - anchors.right: parent.right + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top anchors.bottom: parent.bottom - height: parent.height * Math.min(1.0, root.getCurrentValue()) - radius: parent.radius - color: root.getProgressColor() + width: panel.barThickness + radius: Math.round(panel.barThickness / 2) + color: Color.mSurfaceVariant - Behavior on height { - NumberAnimation { - duration: Style.animationNormal - easing.type: Easing.InOutQuad + Rectangle { + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: parent.bottom + height: parent.height * Math.min(1.0, root.getCurrentValue()) + radius: parent.radius + color: root.getProgressColor() + + Behavior on height { + NumberAnimation { + duration: Style.animationNormal + easing.type: Easing.InOutQuad + } } - } - Behavior on color { - ColorAnimation { - duration: Style.animationNormal - easing.type: Easing.InOutQuad + Behavior on color { + ColorAnimation { + duration: Style.animationNormal + easing.type: Easing.InOutQuad + } } } } } - } - // Icon at bottom - NIcon { - icon: root.getIcon() - color: root.getIconColor() - pointSize: Style.fontSizeXL * root.scaling - Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom - Layout.bottomMargin: vMargin + Math.round(Style.marginM * root.scaling) + balanceDelta - Behavior on color { - ColorAnimation { - duration: Style.animationNormal - easing.type: Easing.InOutQuad + // Icon at bottom + NIcon { + icon: root.getIcon() + color: root.getIconColor() + pointSize: Style.fontSizeL + Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom + Behavior on color { + ColorAnimation { + duration: Style.animationNormal + easing.type: Easing.InOutQuad + } } } } @@ -513,6 +502,8 @@ Variants { muteInitialized = true inputVolumeInitialized = true inputMuteInitialized = true + // Don't initialize brightness here - let it initialize on first change like volume + connectBrightnessMonitors() } } @@ -542,11 +533,14 @@ Variants { } function onBrightnessChanged(newBrightness) { + root.lastUpdatedBrightness = newBrightness + if (!brightnessInitialized) { brightnessInitialized = true - } else { - showOSD("brightness") + return } + + showOSD("brightness") } function showOSD(type) { diff --git a/Modules/SessionMenu/SessionMenu.qml b/Modules/SessionMenu/SessionMenu.qml index 039c2c98..034a362c 100644 --- a/Modules/SessionMenu/SessionMenu.qml +++ b/Modules/SessionMenu/SessionMenu.qml @@ -13,8 +13,8 @@ import qs.Widgets NPanel { id: root - preferredWidth: 440 - preferredHeight: 480 + preferredWidth: 380 * Style.uiScaleRatio + preferredHeight: 440 * Style.uiScaleRatio panelAnchorHorizontalCenter: true panelAnchorVerticalCenter: true panelKeyboardFocus: true @@ -259,16 +259,16 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.topMargin: Style.marginL * scaling - anchors.leftMargin: Style.marginL * scaling - anchors.rightMargin: Style.marginL * scaling - anchors.bottomMargin: Style.marginM * scaling - spacing: Style.marginS * scaling + anchors.topMargin: Style.marginL + anchors.leftMargin: Style.marginL + anchors.rightMargin: Style.marginL + anchors.bottomMargin: Style.marginM + spacing: Style.marginS // Header with title and close button RowLayout { Layout.fillWidth: true - Layout.preferredHeight: Style.baseWidgetSize * 0.8 * scaling + Layout.preferredHeight: Style.baseWidgetSize * 0.8 NText { text: timerActive ? I18n.tr("session-menu.action-in-seconds", { @@ -276,7 +276,7 @@ NPanel { "seconds": Math.ceil(timeRemaining / 1000) }) : I18n.tr("session-menu.title") font.weight: Style.fontWeightBold - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: timerActive ? Color.mPrimary : Color.mOnSurface Layout.alignment: Qt.AlignVCenter verticalAlignment: Text.AlignVCenter @@ -310,7 +310,7 @@ NPanel { // Power options ColumnLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM Repeater { model: powerOptions @@ -345,8 +345,8 @@ NPanel { signal clicked - height: Style.baseWidgetSize * 1.6 * scaling - radius: Style.radiusS * scaling + height: Style.baseWidgetSize * 1.6 * Style.uiScaleRatio + radius: Style.radiusS color: { if (pending) { return Qt.alpha(Color.mPrimary, 0.08) @@ -357,7 +357,7 @@ NPanel { return Color.transparent } - border.width: pending ? Math.max(Style.borderM * scaling) : 0 + border.width: pending ? Math.max(Style.borderM) : 0 border.color: pending ? Color.mPrimary : Color.mOutline Behavior on color { @@ -368,7 +368,7 @@ NPanel { Item { anchors.fill: parent - anchors.margins: Style.marginL * scaling + anchors.margins: Style.marginL // Icon on the left NIcon { @@ -385,8 +385,8 @@ NPanel { return Color.mOnTertiary return Color.mOnSurface } - pointSize: Style.fontSizeXXXL * scaling - width: Style.baseWidgetSize * 0.6 * scaling + pointSize: Style.fontSizeXXXL + width: Style.baseWidgetSize * 0.6 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -402,14 +402,14 @@ NPanel { anchors.left: iconElement.right anchors.right: pendingIndicator.visible ? pendingIndicator.left : parent.right anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Style.marginXL * scaling - anchors.rightMargin: pendingIndicator.visible ? Style.marginM * scaling : 0 + anchors.leftMargin: Style.marginXL + anchors.rightMargin: pendingIndicator.visible ? Style.marginM : 0 spacing: 0 NText { text: buttonRoot.title font.weight: Style.fontWeightMedium - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: { if (buttonRoot.pending) return Color.mPrimary @@ -434,7 +434,7 @@ NPanel { } return buttonRoot.subtitle } - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: { if (buttonRoot.pending) return Color.mPrimary @@ -455,8 +455,8 @@ NPanel { id: pendingIndicator anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - width: 24 * scaling - height: 24 * scaling + width: 24 + height: 24 radius: width * 0.5 color: Color.mPrimary visible: buttonRoot.pending @@ -464,7 +464,7 @@ NPanel { NText { anchors.centerIn: parent text: Math.ceil(timeRemaining / 1000) - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: Style.fontWeightBold color: Color.mOnPrimary } diff --git a/Modules/Settings/Bar/BarWidgetSettingsDialog.qml b/Modules/Settings/Bar/BarWidgetSettingsDialog.qml index 363a7e63..4b35b7fd 100644 --- a/Modules/Settings/Bar/BarWidgetSettingsDialog.qml +++ b/Modules/Settings/Bar/BarWidgetSettingsDialog.qml @@ -19,9 +19,9 @@ Popup { x: (parent.width - width) * 0.5 y: (parent.height - height) * 0.5 - width: Math.max(content.implicitWidth + padding * 2, 500 * scaling) + width: Math.max(content.implicitWidth + padding * 2, 500) height: content.implicitHeight + padding * 2 - padding: Style.marginXL * scaling + padding: Style.marginXL modal: true onOpened: { @@ -42,16 +42,16 @@ Popup { id: bgRect color: Color.mSurface - radius: Style.radiusL * scaling + radius: Style.radiusL border.color: Color.mPrimary - border.width: Math.max(1, Style.borderM * scaling) + border.width: Math.max(1, Style.borderM) } contentItem: ColumnLayout { id: content width: parent.width - spacing: Style.marginM * scaling + spacing: Style.marginM // Title RowLayout { @@ -61,7 +61,7 @@ Popup { text: I18n.tr("system.widget-settings-title", { "widget": widgetSettings.widgetId }) - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mPrimary Layout.fillWidth: true @@ -91,8 +91,8 @@ Popup { // Action buttons RowLayout { Layout.fillWidth: true - Layout.topMargin: Style.marginM * scaling - spacing: Style.marginM * scaling + Layout.topMargin: Style.marginM + spacing: Style.marginM Item { Layout.fillWidth: true diff --git a/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml b/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml index 3d1be163..643684dd 100644 --- a/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/ActiveWindowSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -15,25 +15,43 @@ ColumnLayout { // Local state property bool valueShowIcon: widgetData.showIcon !== undefined ? widgetData.showIcon : widgetMetadata.showIcon - property bool valueAutoHide: widgetData.autoHide !== undefined ? widgetData.autoHide : widgetMetadata.autoHide + property string valueHideMode: "hidden" // Default to 'Hide When Empty' property string valueScrollingMode: widgetData.scrollingMode || widgetMetadata.scrollingMode property int valueWidth: widgetData.width !== undefined ? widgetData.width : widgetMetadata.width + property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons + + Component.onCompleted: { + if (widgetData && widgetData.hideMode !== undefined) { + valueHideMode = widgetData.hideMode + } + } function saveSettings() { var settings = Object.assign({}, widgetData || {}) - settings.autoHide = valueAutoHide + settings.hideMode = valueHideMode settings.showIcon = valueShowIcon settings.scrollingMode = valueScrollingMode settings.width = parseInt(widthInput.text) || widgetMetadata.width + settings.colorizeIcons = valueColorizeIcons return settings } - NToggle { + NComboBox { Layout.fillWidth: true - label: I18n.tr("bar.widget-settings.active-window.auto-hide.label") - description: I18n.tr("bar.widget-settings.active-window.auto-hide.description") - checked: root.valueAutoHide - onToggled: checked => root.valueAutoHide = checked + label: I18n.tr("bar.widget-settings.active-window.hide-mode.label") + description: I18n.tr("bar.widget-settings.active-window.hide-mode.description") + model: [{ + "key": "visible", + "name": I18n.tr("options.hide-modes.visible") + }, { + "key": "hidden", + "name": I18n.tr("options.hide-modes.hidden") + }, { + "key": "transparent", + "name": I18n.tr("options.hide-modes.transparent") + }] + currentKey: root.valueHideMode + onSelected: key => root.valueHideMode = key } NToggle { @@ -44,6 +62,14 @@ ColumnLayout { onToggled: checked => root.valueShowIcon = checked } + NToggle { + Layout.fillWidth: true + label: I18n.tr("bar.widget-settings.active-window.colorize-icons.label") + description: I18n.tr("bar.widget-settings.active-window.colorize-icons.description") + checked: root.valueColorizeIcons + onToggled: checked => root.valueColorizeIcons = checked + } + NTextInput { id: widthInput Layout.fillWidth: true @@ -68,6 +94,6 @@ ColumnLayout { }] currentKey: valueScrollingMode onSelected: key => valueScrollingMode = key - minimumWidth: 200 * scaling + minimumWidth: 200 } } diff --git a/Modules/Settings/Bar/WidgetSettings/BatterySettings.qml b/Modules/Settings/Bar/WidgetSettings/BatterySettings.qml index addf7ff8..8377958d 100644 --- a/Modules/Settings/Bar/WidgetSettings/BatterySettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/BatterySettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -27,7 +27,7 @@ ColumnLayout { NComboBox { label: I18n.tr("bar.widget-settings.battery.display-mode.label") description: I18n.tr("bar.widget-settings.battery.display-mode.description") - minimumWidth: 134 * scaling + minimumWidth: 134 model: [{ "key": "onhover", "name": I18n.tr("options.display-mode.on-hover") diff --git a/Modules/Settings/Bar/WidgetSettings/BrightnessSettings.qml b/Modules/Settings/Bar/WidgetSettings/BrightnessSettings.qml index c21d7aae..bc572776 100644 --- a/Modules/Settings/Bar/WidgetSettings/BrightnessSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/BrightnessSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -25,7 +25,7 @@ ColumnLayout { NComboBox { label: I18n.tr("bar.widget-settings.brightness.display-mode.label") description: I18n.tr("bar.widget-settings.brightness.display-mode.description") - minimumWidth: 134 * scaling + minimumWidth: 134 model: [{ "key": "onhover", "name": I18n.tr("options.display-mode.on-hover") diff --git a/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml b/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml index d76c8d48..9729ccce 100644 --- a/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/ClockSettings.qml @@ -7,8 +7,8 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling - width: 700 * scaling + spacing: Style.marginM + width: 700 // Properties to receive data from parent property var widgetData: null @@ -89,8 +89,8 @@ ColumnLayout { currentKey: valueCustomFont placeholder: I18n.tr("bar.widget-settings.clock.custom-font.placeholder") searchPlaceholder: I18n.tr("bar.widget-settings.clock.custom-font.search-placeholder") - popupHeight: 420 * scaling - minimumWidth: 300 * scaling + popupHeight: 420 + minimumWidth: 300 onSelected: function (key) { valueCustomFont = key } @@ -108,12 +108,12 @@ ColumnLayout { RowLayout { id: main - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignTop ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true Layout.preferredWidth: 1 // Equal sizing hint @@ -175,13 +175,13 @@ ColumnLayout { } Rectangle { - Layout.preferredWidth: 320 * scaling - Layout.preferredHeight: 160 * scaling // Fixed height instead of fillHeight + Layout.preferredWidth: 320 + Layout.preferredHeight: 160 // Fixed height instead of fillHeight color: Color.mSurfaceVariant - radius: Style.radiusM * scaling + radius: Style.radiusM border.color: Color.mSecondary - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on border.color { ColorAnimation { @@ -190,22 +190,22 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM anchors.centerIn: parent ColumnLayout { - spacing: -2 * scaling + spacing: -2 Layout.alignment: Qt.AlignHCenter // Horizontal Repeater { - Layout.topMargin: Style.marginM * scaling + Layout.topMargin: Style.marginM model: Qt.locale().toString(now, valueFormatHorizontal.trim()).split("\\n") delegate: NText { visible: text !== "" text: modelData family: valueUseCustomFont && valueCustomFont ? valueCustomFont : Settings.data.ui.fontDefault - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold color: valueUsePrimaryColor ? Color.mPrimary : Color.mOnSurface wrapMode: Text.WordWrap @@ -226,17 +226,17 @@ ColumnLayout { // Vertical ColumnLayout { - spacing: -2 * scaling + spacing: -2 Layout.alignment: Qt.AlignHCenter Repeater { - Layout.topMargin: Style.marginM * scaling + Layout.topMargin: Style.marginM model: Qt.locale().toString(now, valueFormatVertical.trim()).split(" ") delegate: NText { visible: text !== "" text: modelData family: valueUseCustomFont && valueCustomFont ? valueCustomFont : Settings.data.ui.fontDefault - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold color: valueUsePrimaryColor ? Color.mPrimary : Color.mOnSurface wrapMode: Text.WordWrap @@ -256,13 +256,13 @@ ColumnLayout { } NDivider { - Layout.topMargin: Style.marginM * scaling - Layout.bottomMargin: Style.marginM * scaling + Layout.topMargin: Style.marginM + Layout.bottomMargin: Style.marginM } NDateTimeTokens { Layout.fillWidth: true - height: 200 * scaling + height: 200 // Connect to token clicked signal if NDateTimeTokens provides it onTokenClicked: token => root.insertToken(token) diff --git a/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml b/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml index ac4ae04c..2c0383e2 100644 --- a/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/ControlCenterSettings.qml @@ -8,7 +8,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -41,7 +41,7 @@ ColumnLayout { } RowLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM NLabel { label: I18n.tr("bar.widget-settings.control-center.icon.label") @@ -49,23 +49,23 @@ ColumnLayout { } NImageCircled { + Layout.preferredWidth: Style.fontSizeXL * 2 + Layout.preferredHeight: Style.fontSizeXL * 2 Layout.alignment: Qt.AlignVCenter imagePath: valueCustomIconPath visible: valueCustomIconPath !== "" - width: Style.fontSizeXL * 2 * scaling - height: Style.fontSizeXL * 2 * scaling } NIcon { Layout.alignment: Qt.AlignVCenter icon: valueIcon - pointSize: Style.fontSizeXXL * 1.5 * scaling + pointSize: Style.fontSizeXXL * 1.5 visible: valueIcon !== "" && valueCustomIconPath === "" } } RowLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM NButton { enabled: !valueUseDistroLogo text: I18n.tr("bar.widget-settings.control-center.browse-library") diff --git a/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml b/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml index 0520740f..c3a6aefe 100644 --- a/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/CustomButtonSettings.qml @@ -8,7 +8,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM property var widgetData: null property var widgetMetadata: null @@ -27,7 +27,7 @@ ColumnLayout { } RowLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM NLabel { label: I18n.tr("bar.widget-settings.custom-button.icon.label") @@ -37,7 +37,7 @@ ColumnLayout { NIcon { Layout.alignment: Qt.AlignVCenter icon: valueIcon - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL visible: valueIcon !== "" } diff --git a/Modules/Settings/Bar/WidgetSettings/KeyboardLayoutSettings.qml b/Modules/Settings/Bar/WidgetSettings/KeyboardLayoutSettings.qml index d3551044..86ada35a 100644 --- a/Modules/Settings/Bar/WidgetSettings/KeyboardLayoutSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/KeyboardLayoutSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -25,7 +25,7 @@ ColumnLayout { NComboBox { label: I18n.tr("bar.widget-settings.keyboard-layout.display-mode.label") description: I18n.tr("bar.widget-settings.keyboard-layout.display-mode.description") - minimumWidth: 134 * scaling + minimumWidth: 134 model: [{ "key": "onhover", "name": I18n.tr("options.display-mode.on-hover") diff --git a/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml b/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml index 184a37e5..1d03c87f 100644 --- a/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/MediaMiniSettings.qml @@ -7,22 +7,28 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null property var widgetMetadata: null // Local state - property bool valueAutoHide: widgetData.autoHide !== undefined ? widgetData.autoHide : widgetMetadata.autoHide + property string valueHideMode: "hidden" // Default to 'Hide When Empty' property bool valueShowAlbumArt: widgetData.showAlbumArt !== undefined ? widgetData.showAlbumArt : widgetMetadata.showAlbumArt property bool valueShowVisualizer: widgetData.showVisualizer !== undefined ? widgetData.showVisualizer : widgetMetadata.showVisualizer property string valueVisualizerType: widgetData.visualizerType || widgetMetadata.visualizerType property string valueScrollingMode: widgetData.scrollingMode || widgetMetadata.scrollingMode + Component.onCompleted: { + if (widgetData && widgetData.hideMode !== undefined) { + valueHideMode = widgetData.hideMode + } + } + function saveSettings() { var settings = Object.assign({}, widgetData || {}) - settings.autoHide = valueAutoHide + settings.hideMode = valueHideMode settings.showAlbumArt = valueShowAlbumArt settings.showVisualizer = valueShowVisualizer settings.visualizerType = valueVisualizerType @@ -30,12 +36,22 @@ ColumnLayout { return settings } - NToggle { + NComboBox { Layout.fillWidth: true - label: I18n.tr("bar.widget-settings.media-mini.auto-hide.label") - description: I18n.tr("bar.widget-settings.media-mini.auto-hide.description") - checked: root.valueAutoHide - onToggled: checked => root.valueAutoHide = checked + label: I18n.tr("bar.widget-settings.media-mini.hide-mode.label") + description: I18n.tr("bar.widget-settings.media-mini.hide-mode.description") + model: [{ + "key": "visible", + "name": I18n.tr("options.hide-modes.visible") + }, { + "key": "hidden", + "name": I18n.tr("options.hide-modes.hidden") + }, { + "key": "transparent", + "name": I18n.tr("options.hide-modes.transparent") + }] + currentKey: root.valueHideMode + onSelected: key => root.valueHideMode = key } NToggle { @@ -68,7 +84,7 @@ ColumnLayout { }] currentKey: valueVisualizerType onSelected: key => valueVisualizerType = key - minimumWidth: 200 * scaling + minimumWidth: 200 } NComboBox { @@ -86,6 +102,6 @@ ColumnLayout { }] currentKey: valueScrollingMode onSelected: key => valueScrollingMode = key - minimumWidth: 200 * scaling + minimumWidth: 200 } } diff --git a/Modules/Settings/Bar/WidgetSettings/MicrophoneSettings.qml b/Modules/Settings/Bar/WidgetSettings/MicrophoneSettings.qml index 5091474d..e62ac1da 100644 --- a/Modules/Settings/Bar/WidgetSettings/MicrophoneSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/MicrophoneSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -25,7 +25,7 @@ ColumnLayout { NComboBox { label: I18n.tr("bar.widget-settings.microphone.display-mode.label") description: I18n.tr("bar.widget-settings.microphone.display-mode.description") - minimumWidth: 134 * scaling + minimumWidth: 134 model: [{ "key": "onhover", "name": I18n.tr("options.display-mode.on-hover") diff --git a/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml b/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml index 4510a605..61c4e10d 100644 --- a/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/NotificationHistorySettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null diff --git a/Modules/Settings/Bar/WidgetSettings/SpacerSettings.qml b/Modules/Settings/Bar/WidgetSettings/SpacerSettings.qml index 7c6b8b17..9679c619 100644 --- a/Modules/Settings/Bar/WidgetSettings/SpacerSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/SpacerSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null diff --git a/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml b/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml index 852ea8d8..8133ab18 100644 --- a/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/SystemMonitorSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null diff --git a/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml b/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml index c80dd09f..e98c0eaa 100644 --- a/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/TaskbarSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -16,11 +16,13 @@ ColumnLayout { // Local state property bool valueOnlyActiveWorkspaces: widgetData.onlyActiveWorkspaces !== undefined ? widgetData.onlyActiveWorkspaces : widgetMetadata.onlyActiveWorkspaces property bool valueOnlySameOutput: widgetData.onlySameOutput !== undefined ? widgetData.onlySameOutput : widgetMetadata.onlySameOutput + property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons function saveSettings() { var settings = Object.assign({}, widgetData || {}) settings.onlySameOutput = valueOnlySameOutput settings.onlyActiveWorkspaces = valueOnlyActiveWorkspaces + settings.colorizeIcons = valueColorizeIcons return settings } @@ -39,4 +41,12 @@ ColumnLayout { checked: root.valueOnlyActiveWorkspaces onToggled: checked => root.valueOnlyActiveWorkspaces = checked } + + NToggle { + Layout.fillWidth: true + label: I18n.tr("bar.widget-settings.taskbar.colorize-icons.label") + description: I18n.tr("bar.widget-settings.taskbar.colorize-icons.description") + checked: root.valueColorizeIcons + onToggled: checked => root.valueColorizeIcons = checked + } } diff --git a/Modules/Settings/Bar/WidgetSettings/TraySettings.qml b/Modules/Settings/Bar/WidgetSettings/TraySettings.qml index 25d08bce..a9a41243 100644 --- a/Modules/Settings/Bar/WidgetSettings/TraySettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/TraySettings.qml @@ -5,12 +5,14 @@ import qs.Commons import qs.Widgets ColumnLayout { + id: root // Properties to receive data from parent property var widgetData: ({}) // Expected by BarWidgetSettingsDialog property var widgetMetadata: ({}) // Expected by BarWidgetSettingsDialog - // Local state for the blacklist + // Local state property var localBlacklist: widgetData.blacklist || [] + property bool valueColorizeIcons: widgetData.colorizeIcons !== undefined ? widgetData.colorizeIcons : widgetMetadata.colorizeIcons ListModel { id: blacklistModel @@ -25,11 +27,19 @@ ColumnLayout { } } - spacing: Style.marginM * scaling + spacing: Style.marginM + + NToggle { + Layout.fillWidth: true + label: I18n.tr("bar.widget-settings.tray.colorize-icons.label") + description: I18n.tr("bar.widget-settings.tray.colorize-icons.description") + checked: root.valueColorizeIcons + onToggled: checked => root.valueColorizeIcons = checked + } ColumnLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS NLabel { label: I18n.tr("settings.bar.tray.blacklist.label") @@ -38,7 +48,7 @@ ColumnLayout { RowLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS NTextInput { id: newRuleInput @@ -49,7 +59,7 @@ ColumnLayout { NIconButton { Layout.alignment: Qt.AlignVCenter icon: "add" - baseSize: Style.baseWidgetSize * 0.8 * scaling + baseSize: Style.baseWidgetSize * 0.8 onClicked: { if (newRuleInput.text.length > 0) { var newRule = newRuleInput.text.trim() @@ -76,30 +86,30 @@ ColumnLayout { // List of current blacklist items ListView { Layout.fillWidth: true - Layout.preferredHeight: 150 * scaling - Layout.topMargin: Style.marginL * scaling // Increased top margin + Layout.preferredHeight: 150 + Layout.topMargin: Style.marginL // Increased top margin clip: true model: blacklistModel delegate: Item { width: ListView.width - height: 40 * scaling + height: 40 Rectangle { id: itemBackground anchors.fill: parent - anchors.margins: Style.marginXS * scaling + anchors.margins: Style.marginXS color: Color.transparent // Make background transparent border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusS * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusS visible: model.rule !== undefined && model.rule !== "" // Only visible if rule exists } Row { anchors.fill: parent - anchors.leftMargin: Style.marginS * scaling - anchors.rightMargin: Style.marginS * scaling - spacing: Style.marginS * scaling + anchors.leftMargin: Style.marginS + anchors.rightMargin: Style.marginS + spacing: Style.marginS NText { text: model.rule @@ -109,10 +119,10 @@ ColumnLayout { } NIconButton { - width: 16 * scaling - height: 16 * scaling + width: 16 + height: 16 icon: "close" - baseSize: 8 * scaling + baseSize: 8 colorBg: Color.mSurfaceVariant colorFg: Color.mOnSurface colorBgHover: Color.mError @@ -135,6 +145,7 @@ ColumnLayout { // Return the updated settings for this widget instance var settings = Object.assign({}, widgetData || {}) settings.blacklist = newBlacklist + settings.colorizeIcons = root.valueColorizeIcons return settings } } diff --git a/Modules/Settings/Bar/WidgetSettings/VolumeSettings.qml b/Modules/Settings/Bar/WidgetSettings/VolumeSettings.qml index 2781f4a6..3b131d38 100644 --- a/Modules/Settings/Bar/WidgetSettings/VolumeSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/VolumeSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -25,7 +25,7 @@ ColumnLayout { NComboBox { label: I18n.tr("bar.widget-settings.volume.display-mode.label") description: I18n.tr("bar.widget-settings.volume.display-mode.description") - minimumWidth: 134 * scaling + minimumWidth: 134 model: [{ "key": "onhover", "name": I18n.tr("options.display-mode.on-hover") diff --git a/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml b/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml index b44f16b9..fb63a593 100644 --- a/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml +++ b/Modules/Settings/Bar/WidgetSettings/WorkspaceSettings.qml @@ -7,7 +7,7 @@ import qs.Services ColumnLayout { id: root - spacing: Style.marginM * scaling + spacing: Style.marginM // Properties to receive data from parent property var widgetData: null @@ -37,7 +37,7 @@ ColumnLayout { }] currentKey: widgetData.labelMode || widgetMetadata.labelMode onSelected: key => labelModeCombo.currentKey = key - minimumWidth: 200 * scaling + minimumWidth: 200 } NToggle { diff --git a/Modules/Settings/Extras/SectionEditor.qml b/Modules/Settings/Extras/SectionEditor.qml index af5a8380..f6d2ef4a 100644 --- a/Modules/Settings/Extras/SectionEditor.qml +++ b/Modules/Settings/Extras/SectionEditor.qml @@ -13,12 +13,14 @@ NBox { property string sectionId: "" property var widgetModel: [] property var availableWidgets: [] - property bool enableMoveBetweenSections: true + property var availableSections: ["left", "center", "right"] + property int maxWidgets: -1 // -1 means unlimited property var widgetRegistry: null property string settingsDialogComponent: "BarWidgetSettingsDialog.qml" readonly property real miniButtonSize: Style.baseWidgetSize * 0.65 + readonly property bool isAtMaxCapacity: maxWidgets > 0 && widgetModel.length >= maxWidgets signal addWidget(string widgetId, string section) signal removeWidget(string section, int index) @@ -31,16 +33,26 @@ NBox { color: Color.mSurface Layout.fillWidth: true Layout.minimumHeight: { - var widgetCount = widgetModel.length - if (widgetCount === 0) - return 140 * scaling + // header + minimal content area + var absoluteMin = (Style.marginL * 2) + (Style.fontSizeL * 2) + Style.marginM + (65 * Style.uiScaleRatio) - var availableWidth = parent.width - var avgWidgetWidth = 150 * scaling + var widgetCount = widgetModel.length + if (widgetCount === 0) { + return absoluteMin + } + + // Calculate rows based on estimated widget layout + var availableWidth = parent.width - (Style.marginL * 2) + var avgWidgetWidth = 120 * Style.uiScaleRatio // More accurate estimate var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth)) var rows = Math.ceil(widgetCount / widgetsPerRow) - return (50 + 20 + (rows * 48) + ((rows - 1) * Style.marginS) + 20) * scaling + // Header height + spacing + (rows * widget height) + (spacing between rows) + margins + var headerHeight = Style.fontSizeL * 2 + var widgetHeight = Style.baseWidgetSize * 1.15 * Style.uiScaleRatio + var widgetAreaHeight = ((rows + 1) * widgetHeight) + ((rows - 1) * Style.marginS) + + return Math.max(absoluteMin, (Style.marginL * 2) + headerHeight + Style.marginM + widgetAreaHeight) } // Generate widget color from name checksum @@ -66,23 +78,34 @@ NBox { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM RowLayout { Layout.fillWidth: true NText { - text: sectionName + " Section" - pointSize: Style.fontSizeL * scaling + text: sectionName + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface Layout.alignment: Qt.AlignVCenter } + // Widget count indicator (when max is set) + NText { + visible: root.maxWidgets > 0 + text: "(" + widgetModel.length + "/" + root.maxWidgets + ")" + pointSize: Style.fontSizeS + color: root.isAtMaxCapacity ? Color.mError : Color.mOnSurfaceVariant + Layout.alignment: Qt.AlignVCenter + Layout.leftMargin: Style.marginXS + } + Item { Layout.fillWidth: true } + NSearchableComboBox { id: comboBox model: availableWidgets @@ -91,8 +114,9 @@ NBox { placeholder: I18n.tr("bar.widget-settings.section-editor.placeholder") searchPlaceholder: I18n.tr("bar.widget-settings.section-editor.search-placeholder") onSelected: key => comboBox.currentKey = key - popupHeight: 340 * scaling - minimumWidth: 200 * scaling + popupHeight: 300 * Style.uiScaleRatio + minimumWidth: 200 * Style.uiScaleRatio + enabled: !root.isAtMaxCapacity Layout.alignment: Qt.AlignVCenter @@ -114,12 +138,12 @@ NBox { colorFg: Color.mOnPrimary colorBgHover: Color.mSecondary colorFgHover: Color.mOnSecondary - enabled: comboBox.currentKey !== "" - tooltipText: I18n.tr("tooltips.add-widget") + enabled: comboBox.currentKey !== "" && !root.isAtMaxCapacity + tooltipText: root.isAtMaxCapacity ? I18n.tr("tooltips.max-widgets-reached") : I18n.tr("tooltips.add-widget") Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling + Layout.leftMargin: Style.marginS onClicked: { - if (comboBox.currentKey !== "") { + if (comboBox.currentKey !== "" && !root.isAtMaxCapacity) { addWidget(comboBox.currentKey, sectionId) comboBox.currentKey = "" } @@ -131,13 +155,13 @@ NBox { Item { Layout.fillWidth: true Layout.fillHeight: true - Layout.minimumHeight: 65 * scaling + Layout.minimumHeight: 65 * Style.uiScaleRatio clip: false // Don't clip children so ghost can move freely Flow { id: widgetFlow anchors.fill: parent - spacing: Style.marginS * scaling + spacing: Style.marginS flow: Flow.LeftToRight Repeater { @@ -148,16 +172,16 @@ NBox { required property int index required property var modelData - width: widgetContent.implicitWidth + Style.marginL * scaling - height: Style.baseWidgetSize * 1.15 * scaling - radius: Style.radiusL * scaling + width: widgetContent.implicitWidth + Style.marginL + height: Style.baseWidgetSize * 1.15 * Style.uiScaleRatio + radius: Style.radiusL color: root.getWidgetColor(modelData)[0] border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Store the widget index for drag operations property int widgetIndex: index - readonly property int buttonsWidth: Math.round(20 * scaling) + readonly property int buttonsWidth: Math.round(20) readonly property int buttonsCount: 1 + (root.widgetRegistry ? root.widgetRegistry.widgetHasUserSettings(modelData.id) : 0) // Visual feedback during drag @@ -180,22 +204,22 @@ NBox { NContextMenu { id: contextMenu parent: Overlay.overlay - width: 240 * scaling + width: 240 * Style.uiScaleRatio model: [{ "label": I18n.tr("tooltips.move-to-left-section"), "action": "left", "icon": "arrow-bar-to-left", - "visible": root.sectionId !== "left" + "visible": root.availableSections.includes("left") && root.sectionId !== "left" }, { "label": I18n.tr("tooltips.move-to-center-section"), "action": "center", "icon": "layout-columns", - "visible": root.sectionId !== "center" + "visible": root.availableSections.includes("center") && root.sectionId !== "center" }, { "label": I18n.tr("tooltips.move-to-right-section"), "action": "right", "icon": "arrow-bar-to-right", - "visible": root.sectionId !== "right" + "visible": root.availableSections.includes("right") && root.sectionId !== "right" }] onTriggered: action => root.moveWidget(root.sectionId, index, action) @@ -204,7 +228,7 @@ NBox { // MouseArea for the context menu MouseArea { id: contextMouseArea - enabled: enableMoveBetweenSections + enabled: root.availableSections.length > 1 // Enable if there are other sections to move to anchors.fill: parent acceptedButtons: Qt.RightButton z: -1 // Below the buttons but above background @@ -223,20 +247,20 @@ NBox { RowLayout { id: widgetContent anchors.centerIn: parent - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS NText { text: modelData.id - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeXS color: root.getWidgetColor(modelData)[1] horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight - Layout.preferredWidth: 80 * scaling + Layout.preferredWidth: 60 * Style.uiScaleRatio } RowLayout { spacing: 0 - Layout.preferredWidth: buttonsCount * buttonsWidth + Layout.preferredWidth: buttonsCount * buttonsWidth * Style.uiScaleRatio Loader { active: root.widgetRegistry && root.widgetRegistry.widgetHasUserSettings(modelData.id) @@ -261,19 +285,19 @@ NBox { if (dialog) { dialog.open() } else { - Logger.error("WidgetSectionEditor", "Failed to create settings dialog instance") + Logger.error("SectionEditor", "Failed to create settings dialog instance") } } if (component.status === Component.Ready) { instantiateAndOpen() } else if (component.status === Component.Error) { - Logger.error("WidgetSectionEditor", component.errorString()) + Logger.error("SectionEditor", component.errorString()) } else { component.statusChanged.connect(function () { if (component.status === Component.Ready) { instantiateAndOpen() } else if (component.status === Component.Error) { - Logger.error("WidgetSectionEditor", component.errorString()) + Logger.error("SectionEditor", component.errorString()) } }) } @@ -304,11 +328,11 @@ NBox { Rectangle { id: dragGhost width: 0 - height: Style.baseWidgetSize * 1.15 * scaling - radius: Style.radiusL * scaling + height: Style.baseWidgetSize * 1.15 + radius: Style.radiusL color: Color.transparent border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) opacity: 0.7 visible: flowDragArea.dragStarted z: 2000 @@ -317,7 +341,7 @@ NBox { NText { id: ghostText anchors.centerIn: parent - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnPrimary } } @@ -325,8 +349,8 @@ NBox { // Drop indicator - visual feedback for where the widget will be inserted Rectangle { id: dropIndicator - width: 3 * scaling - height: Style.baseWidgetSize * 1.15 * scaling + width: 3 + height: Style.baseWidgetSize * 1.15 radius: width / 2 color: Color.mPrimary opacity: 0 @@ -378,7 +402,7 @@ NBox { property bool dragStarted: false property bool potentialDrag: false // Track if we're in a potential drag interaction property int draggedIndex: -1 - property real dragThreshold: 15 * scaling + property real dragThreshold: 15 property Item draggedWidget: null property int dropTargetIndex: -1 property var draggedModelData: null @@ -413,13 +437,13 @@ NBox { if (leftDist < minDistance) { minDistance = leftDist bestIndex = i - bestPosition = Qt.point(widget.x - dropIndicator.width / 2 - Style.marginXS * scaling, widget.y) + bestPosition = Qt.point(widget.x - dropIndicator.width / 2 - Style.marginXS, widget.y) } if (rightDist < minDistance) { minDistance = rightDist bestIndex = i + 1 - bestPosition = Qt.point(widget.x + widget.width + Style.marginXS * scaling - dropIndicator.width / 2, widget.y) + bestPosition = Qt.point(widget.x + widget.width + Style.marginXS - dropIndicator.width / 2, widget.y) } } @@ -431,13 +455,13 @@ NBox { if (dist < minDistance && mouseX < firstWidget.x + firstWidget.width / 2) { minDistance = dist bestIndex = 0 - bestPosition = Qt.point(Math.max(0, firstWidget.x - dropIndicator.width - Style.marginS * scaling), firstWidget.y) + bestPosition = Qt.point(Math.max(0, firstWidget.x - dropIndicator.width - Style.marginS), firstWidget.y) } } } // Only show indicator if we're close enough and it's a different position - if (minDistance < 80 * scaling && bestIndex !== -1) { + if (minDistance < 80 && bestIndex !== -1) { // Adjust index if we're moving forward let adjustedIndex = bestIndex if (bestIndex > draggedIndex) { diff --git a/Modules/Settings/SettingsPanel.qml b/Modules/Settings/SettingsPanel.qml index ff499cfe..e5b64566 100644 --- a/Modules/Settings/SettingsPanel.qml +++ b/Modules/Settings/SettingsPanel.qml @@ -11,14 +11,11 @@ import qs.Widgets NPanel { id: root - preferredWidth: 1000 - preferredHeight: 1000 - preferredWidthRatio: 0.4 - preferredHeightRatio: 0.75 + preferredWidth: 820 * Style.uiScaleRatio + preferredHeight: 940 * Style.uiScaleRatio panelAnchorHorizontalCenter: true panelAnchorVerticalCenter: true - panelKeyboardFocus: true draggable: !PanelService.hasOpenedPopup @@ -40,6 +37,7 @@ NPanel { Network, Notifications, ScreenRecorder, + UserInterface, Wallpaper } @@ -116,7 +114,10 @@ NPanel { id: controlCenterTab ControlCenterTab {} } - + Component { + id: userInterfaceTab + UserInterfaceTab {} + } // Order *DOES* matter function updateTabsModel() { let newTabs = [{ @@ -124,18 +125,22 @@ NPanel { "label": "settings.general.title", "icon": "settings-general", "source": generalTab + }, { + "id": SettingsPanel.Tab.UserInterface, + "label": "settings.user-interface.title", + "icon": "settings-user-interface", + "source": userInterfaceTab }, { "id": SettingsPanel.Tab.Bar, "label": "settings.bar.title", "icon": "settings-bar", "source": barTab - }, //{ - // "id": SettingsPanel.Tab.ControlCenter, - // "label": "settings.control-center.title", - // "icon": "settings-bar", - // "source": controlCenterTab - //}, - { + }, { + "id": SettingsPanel.Tab.ControlCenter, + "label": "settings.control-center.title", + "icon": "settings-control-center", + "source": controlCenterTab + }, { "id": SettingsPanel.Tab.Dock, "label": "settings.dock.title", "icon": "settings-dock", @@ -273,7 +278,7 @@ NPanel { // Main layout container that fills the panel ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling + anchors.margins: Style.marginL spacing: 0 // Keyboard shortcuts container @@ -336,18 +341,18 @@ NPanel { RowLayout { Layout.fillWidth: true Layout.fillHeight: true - spacing: Style.marginM * scaling + spacing: Style.marginL // Sidebar Rectangle { id: sidebar - Layout.preferredWidth: 220 * scaling + Layout.preferredWidth: 220 * Style.uiScaleRatio Layout.fillHeight: true Layout.alignment: Qt.AlignTop color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM MouseArea { anchors.fill: parent @@ -368,8 +373,8 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginXS * scaling + anchors.margins: Style.marginS + spacing: Style.marginXS Repeater { id: sections @@ -377,8 +382,8 @@ NPanel { delegate: Rectangle { id: tabItem Layout.fillWidth: true - Layout.preferredHeight: tabEntryRow.implicitHeight + Style.marginS * scaling * 2 - radius: Style.radiusS * scaling + Layout.preferredHeight: tabEntryRow.implicitHeight + Style.marginM * 2 + radius: Style.radiusS color: selected ? Color.mPrimary : (tabItem.hovering ? Color.mTertiary : Color.transparent) readonly property bool selected: index === currentTabIndex property bool hovering: false @@ -399,22 +404,22 @@ NPanel { RowLayout { id: tabEntryRow anchors.fill: parent - anchors.leftMargin: Style.marginS * scaling - anchors.rightMargin: Style.marginS * scaling - spacing: Style.marginM * scaling + anchors.leftMargin: Style.marginS + anchors.rightMargin: Style.marginS + spacing: Style.marginM // Tab icon NIcon { icon: modelData.icon color: tabTextColor - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL } // Tab label NText { text: I18n.tr(modelData.label) color: tabTextColor - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter @@ -445,34 +450,34 @@ NPanel { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignTop - radius: Style.radiusM * scaling + radius: Style.radiusM color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) ColumnLayout { id: contentLayout anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginS * scaling + anchors.margins: Style.marginL + spacing: Style.marginS // Header row RowLayout { id: headerRow Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS // Main icon NIcon { icon: root.tabsModel[currentTabIndex]?.icon color: Color.mPrimary - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL } // Main title NText { text: I18n.tr(root.tabsModel[currentTabIndex]?.label) || "" - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL font.weight: Style.fontWeightBold color: Color.mPrimary Layout.fillWidth: true @@ -527,7 +532,7 @@ NPanel { anchors.fill: parent horizontalPolicy: ScrollBar.AlwaysOff verticalPolicy: ScrollBar.AsNeeded - padding: Style.marginL * scaling + padding: Style.marginL Component.onCompleted: { root.activeScrollView = scrollView } diff --git a/Modules/Settings/Tabs/AboutTab.qml b/Modules/Settings/Tabs/AboutTab.qml index 6e226e1b..1faf3a53 100644 --- a/Modules/Settings/Tabs/AboutTab.qml +++ b/Modules/Settings/Tabs/AboutTab.qml @@ -15,7 +15,7 @@ ColumnLayout { property string currentVersion: UpdateService.currentVersion property var contributors: GitHubService.contributors - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.about.noctalia.section.label") @@ -23,13 +23,13 @@ ColumnLayout { } RowLayout { - spacing: Style.marginXL * scaling + spacing: Style.marginXL // Versions GridLayout { columns: 2 - rowSpacing: Style.marginXS * scaling - columnSpacing: Style.marginS * scaling + rowSpacing: Style.marginXS + columnSpacing: Style.marginS NText { text: I18n.tr("settings.about.noctalia.latest-version") @@ -76,17 +76,66 @@ ColumnLayout { icon: "download" text: I18n.tr("settings.about.noctalia.download-latest") outlined: !hovered - fontSize: Style.fontSizeXS * scaling + fontSize: Style.fontSizeXS onClicked: { Quickshell.execDetached(["xdg-open", "https://github.com/Ly-sec/Noctalia/releases/latest"]) } } } + // Ko-fi support button + Rectangle { + Layout.alignment: Qt.AlignHCenter + Layout.topMargin: Style.marginM + Layout.bottomMargin: Style.marginM + width: supportRow.implicitWidth + Style.marginXL + height: supportRow.implicitHeight + Style.marginM + radius: Style.radiusS + color: supportArea.containsMouse ? Qt.alpha(Color.mOnSurface, 0.05) : Color.transparent + border.width: 0 + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + + RowLayout { + id: supportRow + anchors.centerIn: parent + spacing: Style.marginS + + NText { + text: I18n.tr("settings.about.support") + pointSize: Style.fontSizeXS + color: Color.mOnSurface + opacity: supportArea.containsMouse ? Style.opacityFull : Style.opacityMedium + } + + NIcon { + icon: supportArea.containsMouse ? "heart-filled" : "heart" + pointSize: 14 + color: Color.mOnSurface + opacity: supportArea.containsMouse ? Style.opacityFull : Style.opacityMedium + } + } + + MouseArea { + id: supportArea + anchors.fill: parent + hoverEnabled: true + cursorShape: Qt.PointingHandCursor + onClicked: { + Quickshell.execDetached(["xdg-open", "https://ko-fi.com/lysec"]) + ToastService.showNotice(I18n.tr("settings.about.support"), I18n.tr("toast.kofi.opened"), 3000) + } + } + } + NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXXXL + Layout.bottomMargin: Style.marginXL } // Contributors @@ -101,23 +150,26 @@ ColumnLayout { GridView { id: contributorsGrid + + readonly property int columnsCount: 2 + Layout.alignment: Qt.AlignHCenter - Layout.preferredWidth: cellWidth * 3 // Fixed 3 columns + Layout.preferredWidth: cellWidth * columnsCount Layout.preferredHeight: { if (root.contributors.length === 0) return 0 - const columns = 3 - const rows = Math.ceil(root.contributors.length / columns) + + const rows = Math.ceil(root.contributors.length / columnsCount) return rows * cellHeight } - cellWidth: Style.baseWidgetSize * 7 * scaling - cellHeight: Style.baseWidgetSize * 3 * scaling + cellWidth: Math.round(Style.baseWidgetSize * 7) + cellHeight: Math.round(Style.baseWidgetSize * 2.5) model: root.contributors delegate: Rectangle { - width: contributorsGrid.cellWidth - Style.marginM * scaling - height: contributorsGrid.cellHeight - Style.marginM * scaling - radius: Style.radiusL * scaling + width: contributorsGrid.cellWidth - Style.marginM + height: contributorsGrid.cellHeight - Style.marginM + radius: Style.radiusL color: contributorArea.containsMouse ? Color.mTertiary : Color.transparent Behavior on color { @@ -128,21 +180,21 @@ ColumnLayout { RowLayout { anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginS + spacing: Style.marginM Item { Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: Style.baseWidgetSize * 2 * scaling - Layout.preferredHeight: Style.baseWidgetSize * 2 * scaling + Layout.preferredWidth: Style.baseWidgetSize * 2 * Style.uiScaleRatio + Layout.preferredHeight: Style.baseWidgetSize * 2 * Style.uiScaleRatio NImageCircled { imagePath: modelData.avatar_url || "" anchors.fill: parent - anchors.margins: Style.marginXS * scaling + anchors.margins: Style.marginXS fallbackIcon: "person" borderColor: contributorArea.containsMouse ? Color.mOnTertiary : Color.mPrimary - borderWidth: Math.max(1, Style.borderM * scaling) + borderWidth: Math.max(1, Style.borderM) Behavior on borderColor { ColorAnimation { @@ -153,7 +205,7 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS Layout.alignment: Qt.AlignVCenter Layout.fillWidth: true @@ -167,8 +219,8 @@ ColumnLayout { NText { text: (modelData.contributions || 0) + " " + ((modelData.contributions || 0) === 1 ? "commit" : "commits") - pointSize: Style.fontSizeXS * scaling - color: contributorArea.containsMouse ? Color.mOnTertiary : Color.mOnSurface + pointSize: Style.fontSizeXS + color: contributorArea.containsMouse ? Color.mOnTertiary : Color.mOnSurfaceVariant } } } @@ -186,8 +238,4 @@ ColumnLayout { } } } - - Item { - Layout.fillHeight: true - } } diff --git a/Modules/Settings/Tabs/AudioTab.qml b/Modules/Settings/Tabs/AudioTab.qml index e4f70407..ef73bbdd 100644 --- a/Modules/Settings/Tabs/AudioTab.qml +++ b/Modules/Settings/Tabs/AudioTab.qml @@ -8,7 +8,7 @@ import qs.Widgets ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.audio.volumes.section.label") @@ -26,7 +26,7 @@ ColumnLayout { // Master Volume ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NLabel { @@ -61,7 +61,7 @@ ColumnLayout { // Mute Toggle ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NToggle { @@ -78,7 +78,7 @@ ColumnLayout { // Input Volume ColumnLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS Layout.fillWidth: true NLabel { @@ -99,7 +99,7 @@ ColumnLayout { // Input Mute Toggle ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NToggle { @@ -112,7 +112,7 @@ ColumnLayout { // Volume Step Size ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NSpinBox { @@ -130,7 +130,7 @@ ColumnLayout { // Raise maximum volume above 100% ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NToggle { @@ -143,13 +143,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // AudioService Devices ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NHeader { @@ -164,9 +164,9 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS Layout.fillWidth: true - Layout.bottomMargin: Style.marginL * scaling + Layout.bottomMargin: Style.marginL NLabel { label: I18n.tr("settings.audio.devices.output-device.label") @@ -196,7 +196,7 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS Layout.fillWidth: true NLabel { @@ -222,13 +222,13 @@ ColumnLayout { // Divider NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Media Player Preferences ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.audio.media.section.label") @@ -249,11 +249,11 @@ ColumnLayout { // Blacklist editor ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NTextInput { @@ -267,7 +267,7 @@ ColumnLayout { NIconButton { icon: "add" Layout.alignment: Qt.AlignBottom - Layout.bottomMargin: blacklistInput.description ? Style.marginS * scaling : 0 + Layout.bottomMargin: blacklistInput.description ? Style.marginS : 0 onClicked: { const val = (blacklistInput.text || "").trim() if (val !== "") { @@ -285,40 +285,40 @@ ColumnLayout { // Current blacklist entries Flow { Layout.fillWidth: true - Layout.leftMargin: Style.marginS * scaling - spacing: Style.marginS * scaling + Layout.leftMargin: Style.marginS + spacing: Style.marginS Repeater { model: Settings.data.audio.mprisBlacklist delegate: Rectangle { required property string modelData // Padding around the inner row - property real pad: Style.marginS * scaling + property real pad: Style.marginS // Visuals color: Qt.alpha(Color.mOnSurface, 0.125) border.color: Qt.alpha(Color.mOnSurface, Style.opacityLight) - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Content RowLayout { id: chipRow - spacing: Style.marginXS * scaling + spacing: Style.marginXS anchors.fill: parent anchors.margins: pad NText { text: modelData color: Color.mOnSurface - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS Layout.alignment: Qt.AlignVCenter - Layout.leftMargin: Style.marginS * scaling + Layout.leftMargin: Style.marginS } NIconButton { icon: "close" baseSize: Style.baseWidgetSize * 0.8 Layout.alignment: Qt.AlignVCenter - Layout.rightMargin: Style.marginXS * scaling + Layout.rightMargin: Style.marginXS onClicked: { const arr = (Settings.data.audio.mprisBlacklist || []) const idx = arr.findIndex(x => String(x) === modelData) @@ -333,8 +333,8 @@ ColumnLayout { // Intrinsic size derived from inner row + padding implicitWidth: chipRow.implicitWidth + pad * 2 - implicitHeight: Math.max(chipRow.implicitHeight + pad * 2, Style.baseWidgetSize * 0.8 * scaling) - radius: Style.radiusM * scaling + implicitHeight: Math.max(chipRow.implicitHeight + pad * 2, Style.baseWidgetSize * 0.8) + radius: Style.radiusM } } } @@ -407,7 +407,7 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/BarTab.qml b/Modules/Settings/Tabs/BarTab.qml index 272740f3..e8fb026e 100644 --- a/Modules/Settings/Tabs/BarTab.qml +++ b/Modules/Settings/Tabs/BarTab.qml @@ -9,7 +9,7 @@ import qs.Modules.Settings.Extras ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL // Helper functions to update arrays immutably function addMonitor(list, name) { @@ -71,6 +71,9 @@ ColumnLayout { label: I18n.tr("settings.bar.appearance.density.label") description: I18n.tr("settings.bar.appearance.density.description") model: [{ + "key": "mini", + "name": I18n.tr("options.bar.density.mini") + }, { "key": "compact", "name": I18n.tr("options.bar.density.compact") }, { @@ -84,26 +87,6 @@ ColumnLayout { onSelected: key => Settings.data.bar.density = key } - ColumnLayout { - spacing: Style.marginXXS * scaling - Layout.fillWidth: true - - NLabel { - label: I18n.tr("settings.bar.appearance.background-opacity.label") - description: I18n.tr("settings.bar.appearance.background-opacity.description") - } - - NValueSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.bar.backgroundOpacity - onMoved: value => Settings.data.bar.backgroundOpacity = value - text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%" - } - } - NToggle { Layout.fillWidth: true label: I18n.tr("settings.bar.appearance.show-capsule.label") @@ -131,7 +114,7 @@ ColumnLayout { // Floating bar options - only show when floating is enabled ColumnLayout { visible: Settings.data.bar.floating - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NLabel { @@ -141,14 +124,14 @@ ColumnLayout { RowLayout { Layout.fillWidth: true - spacing: Style.marginL * scaling + spacing: Style.marginL ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS NText { text: I18n.tr("settings.bar.appearance.margins.vertical") - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant } @@ -164,11 +147,11 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS NText { text: I18n.tr("settings.bar.appearance.margins.horizontal") - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant } @@ -185,15 +168,35 @@ ColumnLayout { } } + ColumnLayout { + spacing: Style.marginXXS + Layout.fillWidth: true + + NLabel { + label: I18n.tr("settings.bar.appearance.background-opacity.label") + description: I18n.tr("settings.bar.appearance.background-opacity.description") + } + + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.bar.backgroundOpacity + onMoved: value => Settings.data.bar.backgroundOpacity = value + text: Math.floor(Settings.data.bar.backgroundOpacity * 100) + "%" + } + } + NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Widgets Management Section ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NHeader { @@ -205,8 +208,8 @@ ColumnLayout { ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true - Layout.topMargin: Style.marginM * scaling - spacing: Style.marginM * scaling + Layout.topMargin: Style.marginM + spacing: Style.marginM // Left Section SectionEditor { @@ -263,13 +266,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Monitor Configuration ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true NHeader { @@ -282,11 +285,15 @@ ColumnLayout { delegate: NCheckbox { Layout.fillWidth: true label: modelData.name || "Unknown" - description: I18n.tr("system.monitor-description", { - "model": modelData.model, - "width": modelData.width, - "height": modelData.height - }) + description: { + const compositorScale = CompositorService.getDisplayScale(modelData.name) + I18n.tr("system.monitor-description", { + "model": modelData.model, + "width": modelData.width * compositorScale, + "height": modelData.height * compositorScale, + "scale": compositorScale + }) + } checked: (Settings.data.bar.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { @@ -301,8 +308,8 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // --------------------------------- diff --git a/Modules/Settings/Tabs/ColorSchemeTab.qml b/Modules/Settings/Tabs/ColorSchemeTab.qml index a5c66ead..b38d521e 100644 --- a/Modules/Settings/Tabs/ColorSchemeTab.qml +++ b/Modules/Settings/Tabs/ColorSchemeTab.qml @@ -13,7 +13,7 @@ ColumnLayout { property var schemeColorsCache: ({}) property int cacheVersion: 0 // Increment to trigger UI updates - spacing: Style.marginL * scaling + spacing: Style.marginL // Helper function to extract scheme name from path function extractSchemeName(schemePath) { @@ -211,14 +211,14 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL visible: !Settings.data.colorSchemes.useWallpaperColors } // Predefined Color Schemes ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true visible: !Settings.data.colorSchemes.useWallpaperColors @@ -230,8 +230,8 @@ ColumnLayout { // Color Schemes Grid GridLayout { columns: 3 - rowSpacing: Style.marginM * scaling - columnSpacing: Style.marginM * scaling + rowSpacing: Style.marginM + columnSpacing: Style.marginM Layout.fillWidth: true Repeater { @@ -245,10 +245,10 @@ ColumnLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter - height: 50 * scaling - radius: Style.radiusS * scaling + height: 50 + radius: Style.radiusS color: root.getSchemeColor(schemeName, "mSurface") - border.width: Math.max(1, Style.borderL * scaling) + border.width: Math.max(1, Style.borderL) border.color: { if (Settings.data.colorSchemes.predefinedScheme === schemeName) { return Color.mSecondary @@ -261,12 +261,12 @@ ColumnLayout { RowLayout { anchors.fill: parent - anchors.margins: Style.marginM * scaling - spacing: Style.marginXS * scaling + anchors.margins: Style.marginL + spacing: Style.marginXS NText { text: schemeItem.schemeName - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: Style.fontWeightMedium color: Color.mOnSurface Layout.fillWidth: true @@ -277,29 +277,29 @@ ColumnLayout { } Rectangle { - width: 14 * scaling - height: 14 * scaling + width: 14 + height: 14 radius: width * 0.5 color: root.getSchemeColor(schemeItem.schemeName, "mPrimary") } Rectangle { - width: 14 * scaling - height: 14 * scaling + width: 14 + height: 14 radius: width * 0.5 color: root.getSchemeColor(schemeItem.schemeName, "mSecondary") } Rectangle { - width: 14 * scaling - height: 14 * scaling + width: 14 + height: 14 radius: width * 0.5 color: root.getSchemeColor(schemeItem.schemeName, "mTertiary") } Rectangle { - width: 14 * scaling - height: 14 * scaling + width: 14 + height: 14 radius: width * 0.5 color: root.getSchemeColor(schemeItem.schemeName, "mError") } @@ -324,18 +324,18 @@ ColumnLayout { visible: (Settings.data.colorSchemes.predefinedScheme === schemeItem.schemeName) anchors.right: parent.right anchors.top: parent.top - anchors.rightMargin: -3 * scaling - anchors.topMargin: -3 * scaling - width: 20 * scaling - height: 20 * scaling + anchors.rightMargin: -3 + anchors.topMargin: -3 + width: 20 + height: 20 radius: width * 0.5 color: Color.mSecondary - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) border.color: Color.mOnSecondary NIcon { icon: "check" - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS font.weight: Style.fontWeightBold color: Color.mOnSecondary anchors.centerIn: parent @@ -363,20 +363,20 @@ ColumnLayout { ColorSchemeService.applyScheme(Settings.data.colorSchemes.predefinedScheme) } } - Layout.topMargin: Style.marginL * scaling + Layout.topMargin: Style.marginL } } NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Template toggles organized by category ColumnLayout { Layout.fillWidth: true - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.color-scheme.templates.section.label") @@ -536,7 +536,7 @@ ColumnLayout { visible: ProgramCheckerService.availableDiscordClients.length === 0 text: I18n.tr("settings.color-scheme.templates.programs.discord.description-missing") color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS } NCheckbox { diff --git a/Modules/Settings/Tabs/ControlCenterTab.qml b/Modules/Settings/Tabs/ControlCenterTab.qml index a880334c..f2212806 100644 --- a/Modules/Settings/Tabs/ControlCenterTab.qml +++ b/Modules/Settings/Tabs/ControlCenterTab.qml @@ -9,7 +9,35 @@ import qs.Modules.Settings.Extras ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL + + property list cardsModel: [] + property list cardsDefault: [{ + "id": "profile-card", + "text": "Profile", + "enabled": true, + "required": true + }, { + "id": "shortcuts-card", + "text": "Shortcuts", + "enabled": true, + "required": false + }, { + "id": "audio-card", + "text": "Audio Sliders", + "enabled": true, + "required": false + }, { + "id": "weather-card", + "text": "Weather", + "enabled": true, + "required": false + }, { + "id": "media-sysmon-card", + "text": "Media and System Monitor", + "enabled": true, + "required": false + }] // Handler for drag start - disables panel background clicks function handleDragStart() { @@ -27,74 +55,205 @@ ColumnLayout { } } - // Quick Settings Style Section + function saveCards() { + var toSave = [] + for (var i = 0; i < cardsModel.length; i++) { + toSave.push({ + "id": cardsModel[i].id, + "enabled": cardsModel[i].enabled + }) + } + Settings.data.controlCenter.cards = toSave + } + + Component.onCompleted: { + // Fill out availableWidgets ListModel + availableWidgets.clear() + ControlCenterWidgetRegistry.getAvailableWidgets().forEach(entry => { + availableWidgets.append({ + "key": entry, + "name": entry + }) + }) + // Starts empty + cardsModel = [] + + // Add the cards available in settings + for (var i = 0; i < Settings.data.controlCenter.cards.length; i++) { + const settingCard = Settings.data.controlCenter.cards[i] + + for (var j = 0; j < cardsDefault.length; j++) { + if (settingCard.id === cardsDefault[j].id) { + var card = cardsDefault[j] + card.enabled = settingCard.enabled + cardsModel.push(card) + } + } + } + + // Add any missing cards from default + for (var i = 0; i < cardsDefault.length; i++) { + var found = false + for (var j = 0; j < cardsModel.length; j++) { + if (cardsModel[j].id === cardsDefault[i].id) { + found = true + break + } + } + + if (!found) { + cardsModel.push(cardsDefault[i]) + } + } + + saveCards() + } + ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { - label: I18n.tr("settings.control-center.quickSettingsStyle.section.label") - description: I18n.tr("settings.control-center.quickSettingsStyle.section.description") + label: I18n.tr("settings.control-center.section.label") + description: I18n.tr("settings.control-center.section.description") } NComboBox { - id: quickSettingsStyle - label: I18n.tr("settings.control-center.quickSettingsStyle.style.label") - description: I18n.tr("settings.control-center.quickSettingsStyle.style.description") + id: controlCenterPosition + label: I18n.tr("settings.control-center.position.label") + description: I18n.tr("settings.control-center.position.description") Layout.fillWidth: true model: [{ - "key": "compact", - "name": I18n.tr("options.control-center.quickSettingsStyle.compact") + "key": "close_to_bar_button", + "name": I18n.tr("options.control-center.position.close_to_bar_button") }, { - "key": "classic", - "name": I18n.tr("options.control-center.quickSettingsStyle.classic") + "key": "top_left", + "name": I18n.tr("options.control-center.position.top_left") }, { - "key": "modern", - "name": I18n.tr("options.control-center.quickSettingsStyle.modern") + "key": "top_right", + "name": I18n.tr("options.control-center.position.top_right") + }, { + "key": "bottom_left", + "name": I18n.tr("options.control-center.position.bottom_left") + }, { + "key": "bottom_right", + "name": I18n.tr("options.control-center.position.bottom_right") + }, { + "key": "bottom_center", + "name": I18n.tr("options.control-center.position.bottom_center") + }, { + "key": "top_center", + "name": I18n.tr("options.control-center.position.top_center") }] - currentKey: Settings.data.controlCenter.quickSettingsStyle || "compact" + currentKey: Settings.data.controlCenter.position onSelected: function (key) { - Settings.data.controlCenter.quickSettingsStyle = key + Settings.data.controlCenter.position = key } } } NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Widgets Management Section ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NHeader { - label: I18n.tr("settings.control-center.widgets.section.label") - description: I18n.tr("settings.control-center.widgets.section.description") + label: I18n.tr("settings.control-center.cards.section.label") + description: I18n.tr("settings.control-center.cards.section.description") } - // Bar Sections + NReorderCheckboxes { + Layout.fillWidth: true + model: cardsModel + onDragPotentialStarted: { + root.handleDragStart() + } + onDragPotentialEnded: { + root.handleDragEnd() + } + onItemToggled: function (index, enabled) { + //Logger.log("ControlCenterTab", "Item", index, "toggled to", enabled) + var newModel = cardsModel.slice() + newModel[index] = Object.assign({}, newModel[index], { + "enabled": enabled + }) + cardsModel = newModel + saveCards() + } + onItemsReordered: function (fromIndex, toIndex) { + //Logger.log("ControlCenterTab", "Item moved from", fromIndex, "to", toIndex) + var newModel = cardsModel.slice() + var item = newModel.splice(fromIndex, 1)[0] + newModel.splice(toIndex, 0, item) + cardsModel = newModel + saveCards() + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL + } + + // Widgets Management Section + ColumnLayout { + spacing: Style.marginXXS + Layout.fillWidth: true + + NHeader { + label: I18n.tr("settings.control-center.shortcuts.section.label") + description: I18n.tr("settings.control-center.shortcuts.section.description") + } + + // Sections ColumnLayout { Layout.fillWidth: true Layout.fillHeight: true - Layout.topMargin: Style.marginM * scaling - spacing: Style.marginM * scaling + Layout.topMargin: Style.marginM + spacing: Style.marginM - // Quick Settings + // Left SectionEditor { - sectionName: I18n.tr("settings.control-center.quickSettings.sectionName") - sectionId: "quickSettings" + sectionName: I18n.tr("settings.control-center.shortcuts.sectionLeft") + sectionId: "left" settingsDialogComponent: "" + maxWidgets: 5 widgetRegistry: ControlCenterWidgetRegistry - widgetModel: Settings.data.controlCenter.widgets["quickSettings"] + widgetModel: Settings.data.controlCenter.shortcuts["left"] availableWidgets: availableWidgets - enableMoveBetweenSections: false + availableSections: ["left", "right"] onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section) onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index) onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex) onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection) + onDragPotentialStarted: root.handleDragStart() + onDragPotentialEnded: root.handleDragEnd() + } + + // Right + SectionEditor { + sectionName: I18n.tr("settings.control-center.shortcuts.sectionRight") + sectionId: "right" + settingsDialogComponent: "" + maxWidgets: 5 + widgetRegistry: ControlCenterWidgetRegistry + widgetModel: Settings.data.controlCenter.shortcuts["right"] + availableWidgets: availableWidgets + availableSections: ["left", "right"] + onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section) + onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index) + onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex) + onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings) + onMoveWidget: (fromSection, index, toSection) => _moveWidgetBetweenSections(fromSection, index, toSection) onDragPotentialStarted: root.handleDragStart() onDragPotentialEnded: root.handleDragEnd() } @@ -103,8 +262,8 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // --------------------------------- @@ -124,55 +283,56 @@ ColumnLayout { }) } } - Settings.data.controlCenter.widgets[section].push(newWidget) + Settings.data.controlCenter.shortcuts[section].push(newWidget) } function _removeWidgetFromSection(section, index) { - if (index >= 0 && index < Settings.data.controlCenter.widgets[section].length) { - var newArray = Settings.data.controlCenter.widgets[section].slice() + if (index >= 0 && index < Settings.data.controlCenter.shortcuts[section].length) { + var newArray = Settings.data.controlCenter.shortcuts[section].slice() var removedWidgets = newArray.splice(index, 1) - Settings.data.controlCenter.widgets[section] = newArray - - // Check that we still have a control center - if (removedWidgets[0].id === "ControlCenter" && BarService.lookupWidget("ControlCenter") === undefined) { - ToastService.showWarning(I18n.tr("toast.missing-control-center.label"), I18n.tr("toast.missing-control-center.description"), 12000) - } + Settings.data.controlCenter.shortcuts[section] = newArray } } function _reorderWidgetInSection(section, fromIndex, toIndex) { - if (fromIndex >= 0 && fromIndex < Settings.data.controlCenter.widgets[section].length && toIndex >= 0 && toIndex < Settings.data.controlCenter.widgets[section].length) { + if (fromIndex >= 0 && fromIndex < Settings.data.controlCenter.shortcuts[section].length && toIndex >= 0 && toIndex < Settings.data.controlCenter.shortcuts[section].length) { // Create a new array to avoid modifying the original - var newArray = Settings.data.controlCenter.widgets[section].slice() + var newArray = Settings.data.controlCenter.shortcuts[section].slice() var item = newArray[fromIndex] newArray.splice(fromIndex, 1) newArray.splice(toIndex, 0, item) - Settings.data.controlCenter.widgets[section] = newArray - //Logger.log("BarTab", "Widget reordered. New array:", JSON.stringify(newArray)) + Settings.data.controlCenter.shortcuts[section] = newArray + } + } + + function _moveWidgetBetweenSections(fromSection, index, toSection) { + // Get the widget from the source section + if (index >= 0 && index < Settings.data.controlCenter.shortcuts[fromSection].length) { + var widget = Settings.data.controlCenter.shortcuts[fromSection][index] + + // Remove from source section + var sourceArray = Settings.data.controlCenter.shortcuts[fromSection].slice() + sourceArray.splice(index, 1) + Settings.data.controlCenter.shortcuts[fromSection] = sourceArray + + // Add to target section + var targetArray = Settings.data.controlCenter.shortcuts[toSection].slice() + targetArray.push(widget) + Settings.data.controlCenter.shortcuts[toSection] = targetArray + + //Logger.log("BarTab", `Moved widget ${widget.id} from ${fromSection} to ${toSection}`) } } function _updateWidgetSettingsInSection(section, index, settings) { // Update the widget settings in the Settings data - Settings.data.controlCenter.widgets[section][index] = settings - //Logger.log("BarTab", `Updated widget settings for ${settings.id} in ${section} section`) + Settings.data.controlCenter.shortcuts[section][index] = settings } // Base list model for all combo boxes ListModel { id: availableWidgets } - - Component.onCompleted: { - // Fill out availableWidgets ListModel - availableWidgets.clear() - ControlCenterWidgetRegistry.getAvailableWidgets().forEach(entry => { - availableWidgets.append({ - "key": entry, - "name": entry - }) - }) - } } diff --git a/Modules/Settings/Tabs/DisplayTab.qml b/Modules/Settings/Tabs/DisplayTab.qml index 6eed0a7b..d1823fa1 100644 --- a/Modules/Settings/Tabs/DisplayTab.qml +++ b/Modules/Settings/Tabs/DisplayTab.qml @@ -49,7 +49,7 @@ ColumnLayout { stderr: StdioCollector {} } - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.display.monitors.section.label") @@ -57,36 +57,26 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Repeater { model: Quickshell.screens || [] delegate: Rectangle { Layout.fillWidth: true - implicitHeight: contentCol.implicitHeight + Style.marginL * 2 * scaling - radius: Style.radiusM * scaling + implicitHeight: contentCol.implicitHeight + Style.marginL * 2 + radius: Style.radiusM color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) - property real localScaling: ScalingService.getScreenScale(modelData) property var brightnessMonitor: BrightnessService.getMonitorForScreen(modelData) - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if (screenName === modelData.name) { - localScaling = scale - } - } - } - ColumnLayout { id: contentCol - width: parent.width - 2 * Style.marginL * scaling - x: Style.marginL * scaling - y: Style.marginL * scaling - spacing: Style.marginXXS * scaling + width: parent.width - 2 * Style.marginL + x: Style.marginL + y: Style.marginL + spacing: Style.marginXXS NLabel { label: modelData.name || "Unknown" @@ -101,67 +91,19 @@ ColumnLayout { } } - // Scale - ColumnLayout { - spacing: Style.marginS * scaling - Layout.fillWidth: true - - RowLayout { - spacing: Style.marginL * scaling - Layout.fillWidth: true - - NText { - text: I18n.tr("settings.display.monitors.scale") - Layout.preferredWidth: 90 * scaling - Layout.alignment: Qt.AlignVCenter - } - - NValueSlider { - id: scaleSlider - from: 0.7 - to: 1.8 - stepSize: 0.01 - value: localScaling - onPressedChanged: (pressed, value) => ScalingService.setScreenScale(modelData, value) - Layout.fillWidth: true - } - - NText { - text: I18n.tr("system.scaling-percentage", { - "percentage": Math.round(scaleSlider.value * 100) - }) - Layout.preferredWidth: 55 * scaling - horizontalAlignment: Text.AlignRight - Layout.alignment: Qt.AlignVCenter - } - - Item { - Layout.preferredWidth: 30 * scaling - Layout.fillHeight: true - NIconButton { - icon: "refresh" - baseSize: Style.baseWidgetSize * 0.8 - tooltipText: I18n.tr("settings.display.monitors.reset-scaling") - onClicked: ScalingService.setScreenScale(modelData, 1.0) - anchors.centerIn: parent - } - } - } - } - // Brightness ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true visible: brightnessMonitor !== undefined && brightnessMonitor !== null RowLayout { Layout.fillWidth: true - spacing: Style.marginL * scaling + spacing: Style.marginL NText { text: I18n.tr("settings.display.monitors.brightness") - Layout.preferredWidth: 90 * scaling + Layout.preferredWidth: 90 Layout.alignment: Qt.AlignVCenter } @@ -182,13 +124,13 @@ ColumnLayout { NText { text: brightnessMonitor ? Math.round(brightnessSlider.value * 100) + "%" : "N/A" - Layout.preferredWidth: 55 * scaling + Layout.preferredWidth: 55 horizontalAlignment: Text.AlignRight Layout.alignment: Qt.AlignVCenter } Item { - Layout.preferredWidth: 30 * scaling + Layout.preferredWidth: 30 Layout.fillHeight: true NIcon { icon: brightnessMonitor.method == "internal" ? "device-laptop" : "device-desktop" @@ -217,13 +159,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Night Light Section ColumnLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS Layout.fillWidth: true NHeader { @@ -251,7 +193,7 @@ ColumnLayout { // Temperature ColumnLayout { - spacing: Style.marginXS * scaling + spacing: Style.marginXS Layout.alignment: Qt.AlignVCenter NLabel { @@ -261,14 +203,14 @@ ColumnLayout { RowLayout { visible: Settings.data.nightLight.enabled - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: false Layout.fillHeight: true Layout.alignment: Qt.AlignVCenter NText { text: I18n.tr("settings.display.night-light.temperature.night") - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter } @@ -290,7 +232,7 @@ ColumnLayout { NText { text: I18n.tr("settings.display.night-light.temperature.day") - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter } @@ -323,7 +265,7 @@ ColumnLayout { // Manual scheduling ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS visible: Settings.data.nightLight.enabled && !Settings.data.nightLight.autoSchedule && !Settings.data.nightLight.forced NLabel { @@ -333,11 +275,11 @@ ColumnLayout { RowLayout { Layout.fillWidth: false - spacing: Style.marginS * scaling + spacing: Style.marginS NText { text: I18n.tr("settings.display.night-light.manual-schedule.sunrise") - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant } @@ -346,16 +288,16 @@ ColumnLayout { currentKey: Settings.data.nightLight.manualSunrise placeholder: I18n.tr("settings.display.night-light.manual-schedule.select-start") onSelected: key => Settings.data.nightLight.manualSunrise = key - minimumWidth: 120 * scaling + minimumWidth: 120 } Item { - Layout.preferredWidth: 20 * scaling + Layout.preferredWidth: 20 } NText { text: I18n.tr("settings.display.night-light.manual-schedule.sunset") - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant } @@ -364,7 +306,7 @@ ColumnLayout { currentKey: Settings.data.nightLight.manualSunset placeholder: I18n.tr("settings.display.night-light.manual-schedule.select-stop") onSelected: key => Settings.data.nightLight.manualSunset = key - minimumWidth: 120 * scaling + minimumWidth: 120 } } } @@ -388,7 +330,7 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/DockTab.qml b/Modules/Settings/Tabs/DockTab.qml index 5d31c074..3203446e 100644 --- a/Modules/Settings/Tabs/DockTab.qml +++ b/Modules/Settings/Tabs/DockTab.qml @@ -9,7 +9,7 @@ import qs.Widgets ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL // Helper functions to update arrays immutably function addMonitor(list, name) { @@ -50,7 +50,7 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NLabel { label: I18n.tr("settings.dock.appearance.background-opacity.label") @@ -68,7 +68,7 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NLabel { @@ -87,15 +87,30 @@ ColumnLayout { } } + NToggle { + label: I18n.tr("settings.dock.monitors.only-same-output.label") + description: I18n.tr("settings.dock.monitors.only-same-output.description") + checked: Settings.data.dock.onlySameOutput + onToggled: checked => Settings.data.dock.onlySameOutput = checked + } + + NToggle { + Layout.fillWidth: true + label: I18n.tr("settings.dock.appearance.colorize-icons.label") + description: I18n.tr("settings.dock.appearance.colorize-icons.description") + checked: Settings.data.dock.colorizeIcons + onToggled: checked => Settings.data.dock.colorizeIcons = checked + } + NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Monitor Configuration ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true NHeader { @@ -108,11 +123,15 @@ ColumnLayout { delegate: NCheckbox { Layout.fillWidth: true label: modelData.name || "Unknown" - description: I18n.tr("system.monitor-description", { - "model": modelData.model, - "width": modelData.width, - "height": modelData.height - }) + description: { + const compositorScale = CompositorService.getDisplayScale(modelData.name) + I18n.tr("system.monitor-description", { + "model": modelData.model, + "width": modelData.width * compositorScale, + "height": modelData.height * compositorScale, + "scale": compositorScale + }) + } checked: (Settings.data.dock.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { @@ -125,16 +144,9 @@ ColumnLayout { } } - NToggle { - label: I18n.tr("settings.dock.monitors.only-same-output.label") - description: I18n.tr("settings.dock.monitors.only-same-output.description") - checked: Settings.data.dock.onlySameOutput - onToggled: checked => Settings.data.dock.onlySameOutput = checked - } - NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/GeneralTab.qml b/Modules/Settings/Tabs/GeneralTab.qml index 4f9183a1..c4554145 100644 --- a/Modules/Settings/Tabs/GeneralTab.qml +++ b/Modules/Settings/Tabs/GeneralTab.qml @@ -17,16 +17,16 @@ ColumnLayout { // Profile section RowLayout { Layout.fillWidth: true - spacing: Style.marginL * scaling + spacing: Style.marginL // Avatar preview NImageCircled { - width: 108 * scaling - height: 108 * scaling - imagePath: Settings.data.general.avatarImage + Layout.preferredWidth: 88 * Style.uiScaleRatio + Layout.preferredHeight: width + imagePath: Settings.preprocessPath(Settings.data.general.avatarImage) fallbackIcon: "person" borderColor: Color.mPrimary - borderWidth: Math.max(1, Style.borderM * scaling) + borderWidth: Math.max(1, Style.borderM) Layout.alignment: Qt.AlignTop } @@ -50,7 +50,7 @@ ColumnLayout { id: avatarPicker title: I18n.tr("settings.general.profile.select-avatar") selectionMode: "files" - initialPath: Settings.data.general.avatarImage.substr(0, Settings.data.general.avatarImage.lastIndexOf("/")) || Quickshell.env("HOME") + initialPath: Settings.preprocessPath(Settings.data.general.avatarImage).substr(0, Settings.preprocessPath(Settings.data.general.avatarImage).lastIndexOf("/")) || Quickshell.env("HOME") nameFilters: ["*.jpg", "*.jpeg", "*.png", "*.gif", "*.pnm", "*.bmp"] onAccepted: paths => { if (paths.length > 0) { @@ -61,199 +61,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling - } - - // User Interface - ColumnLayout { - spacing: Style.marginL * scaling - Layout.fillWidth: true - - NHeader { - label: I18n.tr("settings.general.ui.section.label") - description: I18n.tr("settings.general.ui.section.description") - } - - NToggle { - label: I18n.tr("settings.general.ui.dim-desktop.label") - description: I18n.tr("settings.general.ui.dim-desktop.description") - checked: Settings.data.general.dimDesktop - onToggled: checked => Settings.data.general.dimDesktop = checked - } - - NToggle { - label: I18n.tr("settings.general.ui.tooltips.label") - description: I18n.tr("settings.general.ui.tooltips.description") - checked: Settings.data.ui.tooltipsEnabled - onToggled: checked => Settings.data.ui.tooltipsEnabled = checked - } - - ColumnLayout { - spacing: Style.marginXXS * scaling - Layout.fillWidth: true - - NLabel { - label: I18n.tr("settings.general.ui.border-radius.label") - description: I18n.tr("settings.general.ui.border-radius.description") - } - - NValueSlider { - Layout.fillWidth: true - from: 0 - to: 1 - stepSize: 0.01 - value: Settings.data.general.radiusRatio - onMoved: value => Settings.data.general.radiusRatio = value - text: Math.floor(Settings.data.general.radiusRatio * 100) + "%" - } - } - - // Animation Speed - ColumnLayout { - spacing: Style.marginL * scaling - Layout.fillWidth: true - - NToggle { - label: I18n.tr("settings.general.ui.animation-disable.label") - description: I18n.tr("settings.general.ui.animation-disable.description") - checked: Settings.data.general.animationDisabled - onToggled: checked => Settings.data.general.animationDisabled = checked - } - - ColumnLayout { - spacing: Style.marginXXS * scaling - Layout.fillWidth: true - visible: !Settings.data.general.animationDisabled - - NLabel { - label: I18n.tr("settings.general.ui.animation-speed.label") - description: I18n.tr("settings.general.ui.animation-speed.description") - } - - NValueSlider { - Layout.fillWidth: true - from: 0.1 - to: 2.0 - stepSize: 0.01 - value: Settings.data.general.animationSpeed - onMoved: value => Settings.data.general.animationSpeed = value - text: Math.round(Settings.data.general.animationSpeed * 100) + "%" - } - } - } - } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling - } - - // Dock - ColumnLayout { - spacing: Style.marginL * scaling - Layout.fillWidth: true - - NHeader { - label: I18n.tr("settings.general.screen-corners.section.label") - description: I18n.tr("settings.general.screen-corners.section.description") - } - - NToggle { - label: I18n.tr("settings.general.screen-corners.show-corners.label") - description: I18n.tr("settings.general.screen-corners.show-corners.description") - checked: Settings.data.general.showScreenCorners - onToggled: checked => Settings.data.general.showScreenCorners = checked - } - - NToggle { - label: I18n.tr("settings.general.screen-corners.solid-black.label") - description: I18n.tr("settings.general.screen-corners.solid-black.description") - checked: Settings.data.general.forceBlackScreenCorners - onToggled: checked => Settings.data.general.forceBlackScreenCorners = checked - } - - ColumnLayout { - spacing: Style.marginXXS * scaling - Layout.fillWidth: true - - NLabel { - label: I18n.tr("settings.general.screen-corners.radius.label") - description: I18n.tr("settings.general.screen-corners.radius.description") - } - - NValueSlider { - Layout.fillWidth: true - from: 0 - to: 2 - stepSize: 0.01 - value: Settings.data.general.screenRadiusRatio - onMoved: value => Settings.data.general.screenRadiusRatio = value - text: Math.floor(Settings.data.general.screenRadiusRatio * 100) + "%" - } - } - } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling - } - - // Control Center - ColumnLayout { - spacing: Style.marginL * scaling - Layout.fillWidth: true - - NHeader { - label: I18n.tr("settings.general.control-center.section.label") - description: I18n.tr("settings.general.control-center.section.description") - } - - NComboBox { - id: controlCenterPosition - label: I18n.tr("settings.general.control-center.position.label") - description: I18n.tr("settings.general.control-center.position.description") - Layout.fillWidth: true - model: [{ - "key": "close_to_bar_button", - "name": I18n.tr("options.control-center.position.close_to_bar_button") - }, { - "key": "top_left", - "name": I18n.tr("options.control-center.position.top_left") - }, { - "key": "top_right", - "name": I18n.tr("options.control-center.position.top_right") - }, { - "key": "bottom_left", - "name": I18n.tr("options.control-center.position.bottom_left") - }, { - "key": "bottom_right", - "name": I18n.tr("options.control-center.position.bottom_right") - }, { - "key": "bottom_center", - "name": I18n.tr("options.control-center.position.bottom_center") - }, { - "key": "top_center", - "name": I18n.tr("options.control-center.position.top_center") - }] - currentKey: Settings.data.controlCenter.position - onSelected: function (key) { - Settings.data.controlCenter.position = key - } - } - } - - NDivider { - Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Fonts ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -263,7 +77,7 @@ ColumnLayout { // Font configuration section ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NSearchableComboBox { @@ -273,8 +87,8 @@ ColumnLayout { currentKey: Settings.data.ui.fontDefault placeholder: I18n.tr("settings.general.fonts.default.placeholder") searchPlaceholder: I18n.tr("settings.general.fonts.default.search-placeholder") - popupHeight: 420 * scaling - minimumWidth: 300 * scaling + popupHeight: 420 + minimumWidth: 300 onSelected: function (key) { Settings.data.ui.fontDefault = key } @@ -287,8 +101,8 @@ ColumnLayout { currentKey: Settings.data.ui.fontFixed placeholder: I18n.tr("settings.general.fonts.monospace.placeholder") searchPlaceholder: I18n.tr("settings.general.fonts.monospace.search-placeholder") - popupHeight: 320 * scaling - minimumWidth: 300 * scaling + popupHeight: 320 + minimumWidth: 300 onSelected: function (key) { Settings.data.ui.fontFixed = key } @@ -301,7 +115,7 @@ ColumnLayout { } RowLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NValueSlider { @@ -316,8 +130,8 @@ ColumnLayout { // Reset button container Item { - Layout.preferredWidth: 30 * scaling - Layout.preferredHeight: 30 * scaling + Layout.preferredWidth: 30 * Style.uiScaleRatio + Layout.preferredHeight: 30 * Style.uiScaleRatio NIconButton { icon: "refresh" @@ -338,7 +152,7 @@ ColumnLayout { } RowLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NValueSlider { @@ -353,8 +167,8 @@ ColumnLayout { // Reset button container Item { - Layout.preferredWidth: 30 * scaling - Layout.preferredHeight: 30 * scaling + Layout.preferredWidth: 30 * Style.uiScaleRatio + Layout.preferredHeight: 30 * Style.uiScaleRatio NIconButton { icon: "refresh" @@ -369,4 +183,10 @@ ColumnLayout { } } } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL + } } diff --git a/Modules/Settings/Tabs/HooksTab.qml b/Modules/Settings/Tabs/HooksTab.qml index ae339d1e..0b664cd3 100644 --- a/Modules/Settings/Tabs/HooksTab.qml +++ b/Modules/Settings/Tabs/HooksTab.qml @@ -7,7 +7,7 @@ import qs.Widgets ColumnLayout { id: contentColumn - spacing: Style.marginL * scaling + spacing: Style.marginL width: root.width NHeader { @@ -25,7 +25,7 @@ ColumnLayout { ColumnLayout { visible: Settings.data.hooks.enabled - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NDivider { @@ -78,7 +78,7 @@ ColumnLayout { // Info section ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true NLabel { diff --git a/Modules/Settings/Tabs/LauncherTab.qml b/Modules/Settings/Tabs/LauncherTab.qml index a01c13fb..b64f26b6 100644 --- a/Modules/Settings/Tabs/LauncherTab.qml +++ b/Modules/Settings/Tabs/LauncherTab.qml @@ -7,7 +7,7 @@ import qs.Widgets ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.launcher.settings.section.label") @@ -48,19 +48,19 @@ ColumnLayout { } ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NText { text: I18n.tr("settings.launcher.settings.background-opacity.label") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface } NText { text: I18n.tr("settings.launcher.settings.background-opacity.description") - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS color: Color.mOnSurfaceVariant wrapMode: Text.WordWrap Layout.fillWidth: true @@ -111,7 +111,7 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/LocationTab.qml b/Modules/Settings/Tabs/LocationTab.qml index 769735d2..b4ccfe4f 100644 --- a/Modules/Settings/Tabs/LocationTab.qml +++ b/Modules/Settings/Tabs/LocationTab.qml @@ -7,7 +7,7 @@ import qs.Widgets ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.location.location.section.label") @@ -17,7 +17,7 @@ ColumnLayout { // Location section RowLayout { Layout.fillWidth: true - spacing: Style.marginL * scaling + spacing: Style.marginL NTextInput { label: I18n.tr("settings.location.location.search.label") @@ -37,7 +37,7 @@ ColumnLayout { LocationService.resetWeather() } } - Layout.maximumWidth: 420 * scaling + Layout.maximumWidth: 420 } NText { @@ -46,24 +46,24 @@ ColumnLayout { "name": LocationService.stableName, "coordinates": LocationService.displayCoordinates }) - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant verticalAlignment: Text.AlignVCenter horizontalAlignment: Text.AlignRight Layout.alignment: Qt.AlignBottom - Layout.bottomMargin: Style.marginM * scaling + Layout.bottomMargin: Style.marginM } } NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Weather section ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true NHeader { @@ -81,13 +81,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Date & time section ColumnLayout { - spacing: Style.marginM * scaling + spacing: Style.marginM Layout.fillWidth: true NHeader { @@ -112,7 +112,7 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/NetworkTab.qml b/Modules/Settings/Tabs/NetworkTab.qml index b19a0819..90e3216f 100644 --- a/Modules/Settings/Tabs/NetworkTab.qml +++ b/Modules/Settings/Tabs/NetworkTab.qml @@ -9,7 +9,7 @@ import qs.Widgets ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { description: I18n.tr("settings.network.section.description") @@ -29,7 +29,7 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/NotificationsTab.qml b/Modules/Settings/Tabs/NotificationsTab.qml index 6673305d..beae8cdc 100644 --- a/Modules/Settings/Tabs/NotificationsTab.qml +++ b/Modules/Settings/Tabs/NotificationsTab.qml @@ -24,7 +24,7 @@ ColumnLayout { // General Notification Settings ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -77,13 +77,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Duration ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -101,7 +101,7 @@ ColumnLayout { // Low Urgency Duration ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NLabel { @@ -122,7 +122,7 @@ ColumnLayout { // Normal Urgency Duration ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NLabel { @@ -143,7 +143,7 @@ ColumnLayout { // Critical Urgency Duration ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NLabel { @@ -164,8 +164,8 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Monitor Configuration @@ -179,11 +179,15 @@ ColumnLayout { delegate: NCheckbox { Layout.fillWidth: true label: modelData.name || I18n.tr("system.unknown") - description: I18n.tr("system.monitor-description", { - "model": modelData.model, - "width": modelData.width, - "height": modelData.height - }) + description: { + const compositorScale = CompositorService.getDisplayScale(modelData.name) + I18n.tr("system.monitor-description", { + "model": modelData.model, + "width": modelData.width * compositorScale, + "height": modelData.height * compositorScale, + "scale": compositorScale + }) + } checked: (Settings.data.notifications.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { @@ -198,7 +202,7 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } } diff --git a/Modules/Settings/Tabs/OsdTab.qml b/Modules/Settings/Tabs/OsdTab.qml index 93e4a733..edb16fd3 100644 --- a/Modules/Settings/Tabs/OsdTab.qml +++ b/Modules/Settings/Tabs/OsdTab.qml @@ -24,7 +24,7 @@ ColumnLayout { // Display ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NComboBox { @@ -62,13 +62,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // General ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -83,6 +83,13 @@ ColumnLayout { onToggled: checked => Settings.data.osd.enabled = checked } + NToggle { + label: I18n.tr("settings.osd.always-on-top.label") + description: I18n.tr("settings.osd.always-on-top.description") + checked: Settings.data.osd.alwaysOnTop + onToggled: checked => Settings.data.osd.alwaysOnTop = checked + } + NLabel { label: I18n.tr("settings.osd.duration.auto-hide.label") description: I18n.tr("settings.osd.duration.auto-hide.description") @@ -101,13 +108,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Monitor Configuration ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -120,11 +127,15 @@ ColumnLayout { delegate: NCheckbox { Layout.fillWidth: true label: modelData.name || I18n.tr("system.unknown") - description: I18n.tr("system.monitor-description", { - "model": modelData.model, - "width": modelData.width, - "height": modelData.height - }) + description: { + const compositorScale = CompositorService.getDisplayScale(modelData.name) + I18n.tr("system.monitor-description", { + "model": modelData.model, + "width": modelData.width * compositorScale, + "height": modelData.height * compositorScale, + "scale": compositorScale + }) + } checked: (Settings.data.osd.monitors || []).indexOf(modelData.name) !== -1 onToggled: checked => { if (checked) { diff --git a/Modules/Settings/Tabs/ScreenRecorderTab.qml b/Modules/Settings/Tabs/ScreenRecorderTab.qml index 957579bf..f1bed075 100644 --- a/Modules/Settings/Tabs/ScreenRecorderTab.qml +++ b/Modules/Settings/Tabs/ScreenRecorderTab.qml @@ -9,7 +9,7 @@ import qs.Widgets ColumnLayout { id: root - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.screen-recorder.general.section.label") @@ -18,7 +18,7 @@ ColumnLayout { // Output Folder ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS Layout.fillWidth: true NTextInputButton { @@ -43,13 +43,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Video Settings ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -179,13 +179,13 @@ ColumnLayout { NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } // Audio Settings ColumnLayout { - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { diff --git a/Modules/Settings/Tabs/UserInterfaceTab.qml b/Modules/Settings/Tabs/UserInterfaceTab.qml new file mode 100644 index 00000000..13557c29 --- /dev/null +++ b/Modules/Settings/Tabs/UserInterfaceTab.qml @@ -0,0 +1,260 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs.Commons +import qs.Services +import qs.Widgets + +ColumnLayout { + id: root + + // User Interface + ColumnLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NHeader { + label: I18n.tr("settings.user-interface.section.label") + description: I18n.tr("settings.user-interface.section.description") + } + + NToggle { + label: I18n.tr("settings.user-interface.dim-desktop.label") + description: I18n.tr("settings.user-interface.dim-desktop.description") + checked: Settings.data.general.dimDesktop + onToggled: checked => Settings.data.general.dimDesktop = checked + } + + NToggle { + label: I18n.tr("settings.user-interface.tooltips.label") + description: I18n.tr("settings.user-interface.tooltips.description") + checked: Settings.data.ui.tooltipsEnabled + onToggled: checked => Settings.data.ui.tooltipsEnabled = checked + } + + NToggle { + label: I18n.tr("settings.user-interface.compact-lockscreen.label") + description: I18n.tr("settings.user-interface.compact-lockscreen.description") + checked: Settings.data.general.compactLockScreen + onToggled: checked => Settings.data.general.compactLockScreen = checked + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginL + Layout.bottomMargin: Style.marginL + } + + ColumnLayout { + spacing: Style.marginXXS + Layout.fillWidth: true + + NLabel { + label: I18n.tr("settings.user-interface.scaling.label") + description: I18n.tr("settings.user-interface.scaling.description") + } + + RowLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NValueSlider { + Layout.fillWidth: true + from: 0.8 + to: 1.2 + stepSize: 0.05 + value: Settings.data.general.scaleRatio + onMoved: value => Settings.data.general.scaleRatio = value + text: Math.floor(Settings.data.general.scaleRatio * 100) + "%" + } + + // Reset button container + Item { + Layout.preferredWidth: 30 * Style.uiScaleRatio + Layout.preferredHeight: 30 * Style.uiScaleRatio + + NIconButton { + icon: "refresh" + baseSize: Style.baseWidgetSize * 0.8 + tooltipText: I18n.tr("settings.user-interface.scaling.reset-scaling") + onClicked: Settings.data.general.scaleRatio = 1.0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + + ColumnLayout { + spacing: Style.marginXXS + Layout.fillWidth: true + + NLabel { + label: I18n.tr("settings.user-interface.border-radius.label") + description: I18n.tr("settings.user-interface.border-radius.description") + } + + RowLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 1 + stepSize: 0.01 + value: Settings.data.general.radiusRatio + onMoved: value => Settings.data.general.radiusRatio = value + text: Math.floor(Settings.data.general.radiusRatio * 100) + "%" + } + + // Reset button container + Item { + Layout.preferredWidth: 30 * Style.uiScaleRatio + Layout.preferredHeight: 30 * Style.uiScaleRatio + + NIconButton { + icon: "refresh" + baseSize: Style.baseWidgetSize * 0.8 + tooltipText: I18n.tr("settings.user-interface.border-radius.reset") + onClicked: Settings.data.general.radiusRatio = 1.0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + + // Animation Speed + ColumnLayout { + spacing: Style.marginL + Layout.fillWidth: true + + ColumnLayout { + spacing: Style.marginXXS + Layout.fillWidth: true + visible: !Settings.data.general.animationDisabled + + NLabel { + label: I18n.tr("settings.user-interface.animation-speed.label") + description: I18n.tr("settings.user-interface.animation-speed.description") + } + + RowLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NValueSlider { + Layout.fillWidth: true + from: 0.1 + to: 2.0 + stepSize: 0.01 + value: Settings.data.general.animationSpeed + onMoved: value => Settings.data.general.animationSpeed = value + text: Math.round(Settings.data.general.animationSpeed * 100) + "%" + } + + // Reset button container + Item { + Layout.preferredWidth: 30 * Style.uiScaleRatio + Layout.preferredHeight: 30 * Style.uiScaleRatio + + NIconButton { + icon: "refresh" + baseSize: Style.baseWidgetSize * 0.8 + tooltipText: I18n.tr("settings.user-interface.animation-speed.reset") + onClicked: Settings.data.general.animationSpeed = 1.0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + + NToggle { + label: I18n.tr("settings.user-interface.animation-disable.label") + description: I18n.tr("settings.user-interface.animation-disable.description") + checked: Settings.data.general.animationDisabled + onToggled: checked => Settings.data.general.animationDisabled = checked + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL + } + + // Dock + ColumnLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NHeader { + label: I18n.tr("settings.general.screen-corners.section.label") + description: I18n.tr("settings.general.screen-corners.section.description") + } + + NToggle { + label: I18n.tr("settings.general.screen-corners.show-corners.label") + description: I18n.tr("settings.general.screen-corners.show-corners.description") + checked: Settings.data.general.showScreenCorners + onToggled: checked => Settings.data.general.showScreenCorners = checked + } + + NToggle { + label: I18n.tr("settings.general.screen-corners.solid-black.label") + description: I18n.tr("settings.general.screen-corners.solid-black.description") + checked: Settings.data.general.forceBlackScreenCorners + onToggled: checked => Settings.data.general.forceBlackScreenCorners = checked + } + + ColumnLayout { + spacing: Style.marginXXS + Layout.fillWidth: true + + NLabel { + label: I18n.tr("settings.general.screen-corners.radius.label") + description: I18n.tr("settings.general.screen-corners.radius.description") + } + + RowLayout { + spacing: Style.marginL + Layout.fillWidth: true + + NValueSlider { + Layout.fillWidth: true + from: 0 + to: 2 + stepSize: 0.01 + value: Settings.data.general.screenRadiusRatio + onMoved: value => Settings.data.general.screenRadiusRatio = value + text: Math.floor(Settings.data.general.screenRadiusRatio * 100) + "%" + } + + // Reset button container + Item { + Layout.preferredWidth: 30 * Style.uiScaleRatio + Layout.preferredHeight: 30 * Style.uiScaleRatio + + NIconButton { + icon: "refresh" + baseSize: Style.baseWidgetSize * 0.8 + tooltipText: I18n.tr("settings.general.screen-corners.radius.reset") + onClicked: Settings.data.general.screenRadiusRatio = 1.0 + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + } + } + } + } + } + + NDivider { + Layout.fillWidth: true + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL + } +} diff --git a/Modules/Settings/Tabs/WallpaperTab.qml b/Modules/Settings/Tabs/WallpaperTab.qml index d8a2bc56..c93c60da 100644 --- a/Modules/Settings/Tabs/WallpaperTab.qml +++ b/Modules/Settings/Tabs/WallpaperTab.qml @@ -12,7 +12,7 @@ ColumnLayout { property string specificFolderMonitorName: "" - spacing: Style.marginL * scaling + spacing: Style.marginL NHeader { label: I18n.tr("settings.wallpaper.settings.section.label") @@ -24,12 +24,12 @@ ColumnLayout { description: I18n.tr("settings.wallpaper.settings.enable-management.description") checked: Settings.data.wallpaper.enabled onToggled: checked => Settings.data.wallpaper.enabled = checked - Layout.bottomMargin: Style.marginL * scaling + Layout.bottomMargin: Style.marginL } ColumnLayout { visible: Settings.data.wallpaper.enabled - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NTextInputButton { @@ -56,29 +56,28 @@ ColumnLayout { visible: Settings.data.wallpaper.enableMultiMonitorDirectories Layout.fillWidth: true - Layout.minimumWidth: 550 * scaling - radius: Style.radiusM * scaling + radius: Style.radiusM color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - implicitHeight: contentCol.implicitHeight + Style.marginXL * 2 * scaling + border.width: Math.max(1, Style.borderS) + implicitHeight: contentCol.implicitHeight + Style.marginL * 2 ColumnLayout { id: contentCol anchors.fill: parent - anchors.margins: Style.marginXL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM Repeater { model: Quickshell.screens || [] delegate: ColumnLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS NText { text: (modelData.name || "Unknown") color: Color.mPrimary font.weight: Style.fontWeightBold - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM } NTextInputButton { @@ -101,13 +100,13 @@ ColumnLayout { NDivider { visible: Settings.data.wallpaper.enabled Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } ColumnLayout { visible: Settings.data.wallpaper.enabled - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -184,13 +183,13 @@ ColumnLayout { NDivider { visible: Settings.data.wallpaper.enabled Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } ColumnLayout { visible: Settings.data.wallpaper.enabled - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true NHeader { @@ -225,7 +224,7 @@ ColumnLayout { // Preset chips using Repeater RowLayout { id: presetRow - spacing: Style.marginS * scaling + spacing: Style.marginS // Factorized presets data property var intervalPresets: [5 * 60, 10 * 60, 15 * 60, 30 * 60, 45 * 60, 60 * 60, 90 * 60, 120 * 60] @@ -272,8 +271,8 @@ ColumnLayout { RowLayout { id: customRow visible: presetRow.customForcedVisible || !presetRow.isCurrentPreset - spacing: Style.marginS * scaling - Layout.topMargin: Style.marginS * scaling + spacing: Style.marginS + Layout.topMargin: Style.marginS NTextInput { label: I18n.tr("settings.wallpaper.automation.custom-interval.label") @@ -313,8 +312,8 @@ ColumnLayout { radius: height * 0.5 color: selected ? Color.mPrimary : Color.mSurfaceVariant - implicitHeight: Math.max(Style.baseWidgetSize * 0.55 * scaling, 24 * scaling) - implicitWidth: chipLabel.implicitWidth + Style.marginM * 1.5 * scaling + implicitHeight: Math.max(Style.baseWidgetSize * 0.55, 24) + implicitWidth: chipLabel.implicitWidth + Style.marginM * 1.5 border.width: 1 border.color: selected ? Color.transparent : Color.mOutline @@ -328,15 +327,15 @@ ColumnLayout { id: chipLabel anchors.centerIn: parent text: parent.label - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: parent.selected ? Color.mOnPrimary : Color.mOnSurface } } NDivider { Layout.fillWidth: true - Layout.topMargin: Style.marginXL * scaling - Layout.bottomMargin: Style.marginXL * scaling + Layout.topMargin: Style.marginXL + Layout.bottomMargin: Style.marginXL } NFilePicker { diff --git a/Modules/Toast/SimpleToast.qml b/Modules/Toast/SimpleToast.qml index 339e09c6..1575c4a4 100644 --- a/Modules/Toast/SimpleToast.qml +++ b/Modules/Toast/SimpleToast.qml @@ -16,8 +16,8 @@ Rectangle { signal hidden width: parent.width - height: Math.round(contentLayout.implicitHeight + Style.marginL * 2 * scaling) - radius: Style.radiusL * scaling + height: Math.round(contentLayout.implicitHeight + Style.marginL * 2) + radius: Style.radiusL visible: false opacity: 0 scale: initialScale @@ -34,7 +34,7 @@ Rectangle { return Color.mOutline } } - border.width: Math.max(2, Style.borderM * scaling) + border.width: Math.max(2, Style.borderM) Behavior on opacity { NumberAnimation { @@ -74,8 +74,8 @@ Rectangle { RowLayout { id: contentLayout anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginL * scaling + anchors.margins: Style.marginL + spacing: Style.marginL // Icon NIcon { @@ -100,13 +100,13 @@ Rectangle { return Color.mOnSurface } } - pointSize: Style.fontSizeXXL * 1.5 * scaling + pointSize: Style.fontSizeXXL * 1.5 Layout.alignment: Qt.AlignVCenter } // Label and description ColumnLayout { - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter @@ -114,7 +114,7 @@ Rectangle { Layout.fillWidth: true text: root.message color: Color.mOnSurface - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold wrapMode: Text.WordWrap visible: text.length > 0 @@ -124,7 +124,7 @@ Rectangle { Layout.fillWidth: true text: root.description color: Color.mOnSurface - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM wrapMode: Text.WordWrap visible: text.length > 0 } diff --git a/Modules/Toast/ToastOverlay.qml b/Modules/Toast/ToastOverlay.qml index 1c8cabab..3051108d 100644 --- a/Modules/Toast/ToastOverlay.qml +++ b/Modules/Toast/ToastOverlay.qml @@ -11,8 +11,6 @@ Variants { delegate: ToastScreen { required property ShellScreen modelData - screen: modelData - scaling: ScalingService.getScreenScale(modelData) } } diff --git a/Modules/Toast/ToastScreen.qml b/Modules/Toast/ToastScreen.qml index 0c732184..ee19a625 100644 --- a/Modules/Toast/ToastScreen.qml +++ b/Modules/Toast/ToastScreen.qml @@ -10,7 +10,6 @@ Item { id: root required property ShellScreen screen - required property real scaling // Local queue for this screen only (bounded to prevent memory issues) property var messageQueue: [] @@ -20,15 +19,6 @@ Item { // If true, immediately show new toasts property bool replaceOnNew: true - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if (screenName === root.screen.name) { - root.scaling = scale - } - } - } - Connections { target: ToastService @@ -161,10 +151,10 @@ Item { margins.top: { if (!(anchors.top)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "top") { - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraV + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraV } return base } @@ -172,10 +162,10 @@ Item { margins.bottom: { if (!(anchors.bottom)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "bottom") { - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraV + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraV } return base } @@ -183,10 +173,10 @@ Item { margins.left: { if (!(anchors.left)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "left") { - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraH + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraH } return base } @@ -194,15 +184,15 @@ Item { margins.right: { if (!(anchors.right)) return 0 - var base = Style.marginM * scaling + var base = Style.marginM if (Settings.data.bar.position === "right") { - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0 - return (Style.barHeight * scaling) + base + floatExtraH + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0 + return (Style.barHeight) + base + floatExtraH } return base } - implicitWidth: 420 * root.scaling + implicitWidth: 420 implicitHeight: toastItem.height color: Color.transparent diff --git a/Modules/Tooltip/Tooltip.qml b/Modules/Tooltip/Tooltip.qml index 8e8e532a..43a6850c 100644 --- a/Modules/Tooltip/Tooltip.qml +++ b/Modules/Tooltip/Tooltip.qml @@ -8,7 +8,6 @@ import qs.Widgets PopupWindow { id: root - property real scaling: 1.0 property int screenWidth: 0 property int screenHeight: 0 @@ -114,7 +113,6 @@ PopupWindow { if (!screen || !target || !tipText || tipText === "") return - root.scaling = ScalingService.getScreenScaleByName(screen.name) root.screenWidth = screen.width root.screenHeight = screen.height @@ -153,10 +151,10 @@ PopupWindow { } // Calculate tooltip dimensions - const tipWidth = Math.min(tooltipText.implicitWidth + (padding * 2 * scaling), maxWidth * scaling) + const tipWidth = Math.min(tooltipText.implicitWidth + (padding * 2), maxWidth) root.implicitWidth = tipWidth - const tipHeight = tooltipText.implicitHeight + (padding * 2 * scaling) + const tipHeight = tooltipText.implicitHeight + (padding * 2) root.implicitHeight = tipHeight // Get target's global position @@ -179,26 +177,26 @@ PopupWindow { "dir": "bottom", "space": spaceBottom, "x": (targetWidth - tipWidth) / 2, - "y": targetHeight + margin * scaling, - "fits": spaceBottom >= tipHeight + margin * scaling + "y": targetHeight + margin, + "fits": spaceBottom >= tipHeight + margin }, { "dir": "top", "space": spaceTop, "x": (targetWidth - tipWidth) / 2, - "y": -tipHeight - margin * scaling, - "fits": spaceTop >= tipHeight + margin * scaling + "y": -tipHeight - margin, + "fits": spaceTop >= tipHeight + margin }, { "dir": "right", "space": spaceRight, - "x": targetWidth + margin * scaling, + "x": targetWidth + margin, "y": (targetHeight - tipHeight) / 2, - "fits": spaceRight >= tipWidth + margin * scaling + "fits": spaceRight >= tipWidth + margin }, { "dir": "left", "space": spaceLeft, - "x": -tipWidth - margin * scaling, + "x": -tipWidth - margin, "y": (targetHeight - tipHeight) / 2, - "fits": spaceLeft >= tipWidth + margin * scaling + "fits": spaceLeft >= tipWidth + margin }] // Find first position that fits @@ -226,29 +224,29 @@ PopupWindow { if (direction === "auto") { const globalX = targetGlobal.x + newAnchorX if (globalX < 0) { - newAnchorX = -targetGlobal.x + margin * scaling + newAnchorX = -targetGlobal.x + margin } else if (globalX + tipWidth > screenWidth) { - newAnchorX = screenWidth - targetGlobal.x - tipWidth - margin * scaling + newAnchorX = screenWidth - targetGlobal.x - tipWidth - margin } } } else { // Manual direction positioning switch (direction) { case "left": - newAnchorX = -tipWidth - margin * scaling + newAnchorX = -tipWidth - margin newAnchorY = (targetHeight - tipHeight) / 2 break case "right": - newAnchorX = targetWidth + margin * scaling + newAnchorX = targetWidth + margin newAnchorY = (targetHeight - tipHeight) / 2 break case "top": newAnchorX = (targetWidth - tipWidth) / 2 - newAnchorY = -tipHeight - margin * scaling + newAnchorY = -tipHeight - margin break case "bottom": newAnchorX = (targetWidth - tipWidth) / 2 - newAnchorY = targetHeight + margin * scaling + newAnchorY = targetHeight + margin break } } @@ -370,8 +368,8 @@ PopupWindow { anchors.fill: parent color: Color.mSurface border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * root.scaling) - radius: Style.radiusS * root.scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusS // Only show content when we have text visible: root.text !== "" @@ -379,14 +377,14 @@ PopupWindow { NText { id: tooltipText anchors.centerIn: parent - anchors.margins: root.padding * root.scaling + anchors.margins: root.padding text: root.text - pointSize: Style.fontSizeS * root.scaling + pointSize: Style.fontSizeS color: Color.mOnSurfaceVariant horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter wrapMode: Text.WordWrap - width: root.maxWidth * root.scaling - (root.padding * 2 * root.scaling) + width: root.maxWidth - (root.padding * 2) } } } diff --git a/Modules/Wallpaper/WallpaperPanel.qml b/Modules/Wallpaper/WallpaperPanel.qml index 6ff2ed49..be3a526b 100644 --- a/Modules/Wallpaper/WallpaperPanel.qml +++ b/Modules/Wallpaper/WallpaperPanel.qml @@ -58,23 +58,23 @@ NPanel { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM // Header RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NIcon { icon: "settings-wallpaper-selector" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mPrimary } NText { text: I18n.tr("wallpaper.panel.title") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mOnSurface Layout.fillWidth: true @@ -125,7 +125,7 @@ NPanel { Layout.fillWidth: true currentIndex: currentScreenIndex onCurrentIndexChanged: currentScreenIndex = currentIndex - spacing: Style.marginM * scaling + spacing: Style.marginM background: Rectangle { color: Color.transparent @@ -135,12 +135,12 @@ NPanel { model: Quickshell.screens delegate: TabButton { text: modelData.name || `Screen ${index + 1}` - width: implicitWidth + Style.marginS * 2 * scaling + width: implicitWidth + Style.marginS * 2 background: Rectangle { color: screenTabBar.currentIndex === index ? Color.mSecondary : Color.transparent - radius: Style.radiusS * scaling - border.width: screenTabBar.currentIndex === index ? 0 : Math.max(1, Style.borderS * scaling) + radius: Style.radiusS + border.width: screenTabBar.currentIndex === index ? 0 : Math.max(1, Style.borderS) border.color: Color.mOutline Behavior on color { @@ -152,7 +152,7 @@ NPanel { contentItem: NText { text: parent.text - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: screenTabBar.currentIndex === index ? Style.fontWeightBold : Style.fontWeightRegular family: Settings.data.ui.fontDefault color: screenTabBar.currentIndex === index ? Color.mOnSecondary : Color.mOnSurfaceVariant @@ -169,7 +169,7 @@ NPanel { anchors.fill: parent color: Color.mOnSurface opacity: tabHover.hovered && screenTabBar.currentIndex !== index ? 0.08 : 0 - radius: Style.radiusS * scaling + radius: Style.radiusS Behavior on opacity { NumberAnimation { @@ -200,12 +200,12 @@ NPanel { // Filter input RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: I18n.tr("wallpaper.panel.search") color: Color.mOnSurface - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM Layout.preferredWidth: implicitWidth } @@ -306,7 +306,7 @@ NPanel { ColumnLayout { anchors.fill: parent - spacing: Style.marginM * scaling + spacing: Style.marginM GridView { id: wallpaperGridView @@ -327,12 +327,12 @@ NPanel { property int itemSize: cellWidth cellWidth: Math.floor((width - leftMargin - rightMargin) / columns) - cellHeight: Math.floor(itemSize * 0.7) + Style.marginXS * scaling + Style.fontSizeXS * scaling + Style.marginM * scaling + cellHeight: Math.floor(itemSize * 0.7) + Style.marginXS + Style.fontSizeXS + Style.marginM - leftMargin: Style.marginS * scaling - rightMargin: Style.marginS * scaling - topMargin: Style.marginS * scaling - bottomMargin: Style.marginS * scaling + leftMargin: Style.marginS + rightMargin: Style.marginS + topMargin: Style.marginS + bottomMargin: Style.marginS onCurrentIndexChanged: { // Synchronize scroll with current item position @@ -377,7 +377,7 @@ NPanel { property string filename: wallpaperPath.split('/').pop() width: wallpaperGridView.itemSize - spacing: Style.marginXS * scaling + spacing: Style.marginXS Rectangle { id: imageContainer @@ -405,24 +405,24 @@ NPanel { } return Color.mSurface } - border.width: Math.max(1, Style.borderL * 1.5 * scaling) + border.width: Math.max(1, Style.borderL * 1.5) } Rectangle { anchors.top: parent.top anchors.right: parent.right - anchors.margins: Style.marginS * scaling - width: 28 * scaling - height: 28 * scaling + anchors.margins: Style.marginS + width: 28 + height: 28 radius: width / 2 color: Color.mSecondary border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) visible: isSelected NIcon { icon: "check" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightBold color: Color.mOnSecondary anchors.centerIn: parent @@ -461,10 +461,10 @@ NPanel { NText { text: filename color: (hoverHandler.hovered || isSelected || wallpaperGridView.currentIndex === index) ? Color.mOnSurface : Color.mOnSurfaceVariant - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS Layout.fillWidth: true - Layout.leftMargin: Style.marginS * scaling - Layout.rightMargin: Style.marginS * scaling + Layout.leftMargin: Style.marginS + Layout.rightMargin: Style.marginS Layout.alignment: Qt.AlignHCenter horizontalAlignment: Text.AlignHCenter elide: Text.ElideRight @@ -475,12 +475,12 @@ NPanel { // Empty / scanning state Rectangle { color: Color.mSurface - radius: Style.radiusM * scaling + radius: Style.radiusM border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) visible: (filteredWallpapers.length === 0 && !WallpaperService.scanning) || WallpaperService.scanning Layout.fillWidth: true - Layout.preferredHeight: 130 * scaling + Layout.preferredHeight: 130 ColumnLayout { anchors.fill: parent @@ -498,7 +498,7 @@ NPanel { } NIcon { icon: "folder-open" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mOnSurface Layout.alignment: Qt.AlignHCenter } diff --git a/Services/AppThemeService.qml b/Services/AppThemeService.qml index 3fbf1153..6117fcdb 100644 --- a/Services/AppThemeService.qml +++ b/Services/AppThemeService.qml @@ -91,11 +91,13 @@ Singleton { Logger.log("AppThemeService", "Service started") } + // -------------------------------------------------------------------------------- function generate() { if (Settings.data.colorSchemes.useWallpaperColors) { generateFromWallpaper() } else { - generateFromPredefinedScheme() + // Re-apply the scheme, this is the best way to regenerate all templates too. + ColorSchemeService.applyScheme(Settings.data.colorSchemes.predefinedScheme) } } diff --git a/Services/AudioService.qml b/Services/AudioService.qml index f600f9d9..c187c87f 100644 --- a/Services/AudioService.qml +++ b/Services/AudioService.qml @@ -111,6 +111,14 @@ Singleton { } } + function increaseInputVolume() { + setInputVolume(inputVolume + stepVolume) + } + + function decreaseInputVolume() { + setInputVolume(inputVolume - stepVolume) + } + function setInputVolume(newVolume: real) { if (source?.ready && source?.audio) { // Clamp it accordingly diff --git a/Services/BarWidgetRegistry.qml b/Services/BarWidgetRegistry.qml index efb85537..1bb0199c 100644 --- a/Services/BarWidgetRegistry.qml +++ b/Services/BarWidgetRegistry.qml @@ -41,9 +41,11 @@ Singleton { "ActiveWindow": { "allowUserSettings": true, "showIcon": true, - "autoHide": false, - "scrollingMode": "hover", - "width": 145 + "hideMode": "hidden", + "scrollingMode"// "visible", "hidden", "transparent" + : "hover", + "width": 145, + "colorizeIcons": false }, "Battery": { "allowUserSettings": true, @@ -83,8 +85,9 @@ Singleton { }, "MediaMini": { "allowUserSettings": true, - "autoHide": false, - "scrollingMode": "hover", + "hideMode": "hidden", + "scrollingMode"// "visible", "hidden", "transparent" + : "hover", "showAlbumArt": false, "showVisualizer": false, "visualizerType": "linear" @@ -114,11 +117,13 @@ Singleton { "Taskbar": { "allowUserSettings": true, "onlySameOutput": true, - "onlyActiveWorkspaces": true + "onlyActiveWorkspaces": true, + "colorizeIcons": false }, "Tray": { "allowUserSettings": true, - "blacklist": [] + "blacklist": [], + "colorizeIcons": false }, "Workspace": { "allowUserSettings": true, diff --git a/Services/ColorSchemeService.qml b/Services/ColorSchemeService.qml index 19d5fc05..7e07f27a 100644 --- a/Services/ColorSchemeService.qml +++ b/Services/ColorSchemeService.qml @@ -150,7 +150,7 @@ Singleton { Logger.log("ColorScheme", "Applying color scheme:", getBasename(path)) // Generate Matugen templates if any are enabled and setting allows it - if (Settings.data.colorSchemes.generateTemplatesForPredefined && hasEnabledMatugenTemplates()) { + if (Settings.data.colorSchemes.generateTemplatesForPredefined && hasEnabledTemplates()) { AppThemeService.generateFromPredefinedScheme(data) } } catch (e) { @@ -159,8 +159,8 @@ Singleton { } } - // Check if any Matugen templates are enabled - function hasEnabledMatugenTemplates() { + // Check if any templates are enabled + function hasEnabledTemplates() { return Settings.data.templates.gtk || Settings.data.templates.qt || Settings.data.templates.kitty || Settings.data.templates.ghostty || Settings.data.templates.foot || Settings.data.templates.fuzzel || Settings.data.templates.discord || Settings.data.templates.discord_vesktop || Settings.data.templates.discord_webcord || Settings.data.templates.discord_armcord || Settings.data.templates.discord_equibop || Settings.data.templates.discord_lightcord || Settings.data.templates.discord_dorion || Settings.data.templates.pywalfox } diff --git a/Services/IPCService.qml b/Services/IPCService.qml index 70999aa1..a62e2474 100644 --- a/Services/IPCService.qml +++ b/Services/IPCService.qml @@ -43,6 +43,14 @@ Item { function clear() { NotificationService.clearHistory() } + + function dismissOldest() { + NotificationService.dismissOldestActive() + } + + function dismissAll() { + NotificationService.dismissAllActive() + } } IpcHandler { @@ -128,6 +136,10 @@ Item { function toggle() { sessionMenuPanel.toggle() } + + function lockAndSuspend() { + CompositorService.lockAndSuspend() + } } IpcHandler { diff --git a/Services/NotificationService.qml b/Services/NotificationService.qml index 2a4d23ce..249a5845 100644 --- a/Services/NotificationService.qml +++ b/Services/NotificationService.qml @@ -414,6 +414,13 @@ Singleton { removeActive(id) } + function dismissOldestActive() { + if (activeList.count > 0) { + const lastNotif = activeList.get(activeList.count - 1) + dismissActiveNotification(lastNotif.id) + } + } + function dismissAllActive() { Object.values(activeMap).forEach(n => n.dismiss()) activeList.clear() diff --git a/Services/ScalingService.qml b/Services/ScalingService.qml deleted file mode 100644 index d85b9a3e..00000000 --- a/Services/ScalingService.qml +++ /dev/null @@ -1,131 +0,0 @@ -pragma Singleton - -import QtQuick -import Quickshell -import qs.Commons - -Singleton { - id: root - - // Cache for current scales - updated via signals - property var currentScales: ({}) - - // Signal emitted when scale changes - signal scaleChanged(string screenName, real scale) - - Component.onCompleted: { - Logger.log("Scaling", "Service started") - // Initialize cache from Settings once they are loaded on startup - var monitors = Settings.data.ui.monitorsScaling || [] - for (var i = 0; i < monitors.length; i++) { - if (monitors[i].name && monitors[i].scale !== undefined) { - currentScales[monitors[i].name] = monitors[i].scale - root.scaleChanged(monitors[i].name, monitors[i].scale) - Logger.log("Scaling", "Caching scaling for", monitors[i].name, ":", monitors[i].scale) - } - } - } - - // ------------------------------------------- - // Manual scaling via Settings - function getScreenScale(aScreen) { - try { - if (aScreen !== undefined && aScreen.name !== undefined) { - return getScreenScaleByName(aScreen.name) - } - } catch (e) { - - //Logger.warn(e) - } - return 1.0 - } - - // ------------------------------------------- - // Get scale from cache for better performance - function getScreenScaleByName(aScreenName) { - try { - var scale = currentScales[aScreenName] - if ((scale !== undefined) && (scale != null)) { - return scale - } - } catch (e) { - - //Logger.warn(e) - } - return 1.0 - } - - // ------------------------------------------- - function setScreenScale(aScreen, scale) { - try { - if (aScreen !== undefined && aScreen.name !== undefined) { - return setScreenScaleByName(aScreen.name, scale) - } - } catch (e) { - - //Logger.warn(e) - } - } - - // ------------------------------------------- - function setScreenScaleByName(aScreenName, scale) { - try { - // Check if scale actually changed - var oldScale = currentScales[aScreenName] || 1.0 - if (oldScale === scale) { - return - // No change needed - } - - // Update cache directly - currentScales[aScreenName] = scale - - // Update Settings with immutable update for proper persistence - var monitors = Settings.data.ui.monitorsScaling || [] - var found = false - - var newMonitors = monitors.map(function (monitor) { - if (monitor.name === aScreenName) { - found = true - return { - "name": aScreenName, - "scale": scale - } - } - return monitor - }) - - if (!found) { - newMonitors.push({ - "name": aScreenName, - "scale": scale - }) - } - - // Use slice() to ensure Settings detects the change - Settings.data.ui.monitorsScaling = newMonitors.slice() - - // Emit signal for components to react - root.scaleChanged(aScreenName, scale) - - Logger.log("Scaling", "Scale changed for", aScreenName, "to", scale) - } catch (e) { - Logger.warn("Scaling", "Error setting scale:", e) - } - } - - // ------------------------------------------- - // Dynamic scaling based on resolution - // Design reference resolution (for scale = 1.0) - readonly property int designScreenWidth: 2560 - readonly property int designScreenHeight: 1440 - function dynamicScale(aScreen) { - return 1.0 - // if (aScreen != null) { - // var ratioW = aScreen.width / designScreenWidth - // var ratioH = aScreen.height / designScreenHeight - // return Math.min(ratioW, ratioH) - // } - // return 1.0 - } -} diff --git a/Services/ScreenRecorderService.qml b/Services/ScreenRecorderService.qml index 7e57ce75..57fc578a 100644 --- a/Services/ScreenRecorderService.qml +++ b/Services/ScreenRecorderService.qml @@ -49,7 +49,7 @@ Singleton { function launchRecorder() { var filename = Time.getFormattedTimestamp() + ".mp4" - var videoDir = settings.directory + var videoDir = Settings.preprocessPath(settings.directory) if (videoDir && !videoDir.endsWith("/")) { videoDir += "/" } diff --git a/Services/UpdateService.qml b/Services/UpdateService.qml index b826fc69..c738d6e3 100644 --- a/Services/UpdateService.qml +++ b/Services/UpdateService.qml @@ -8,7 +8,7 @@ Singleton { id: root // Public properties - property string baseVersion: "2.17.2" + property string baseVersion: "2.17.3" property bool isDevelopment: true property string currentVersion: `v${!isDevelopment ? baseVersion : baseVersion + "-dev"}` diff --git a/Services/WallpaperService.qml b/Services/WallpaperService.qml index c60f2eba..2046f6cc 100644 --- a/Services/WallpaperService.qml +++ b/Services/WallpaperService.qml @@ -10,6 +10,7 @@ Singleton { id: root readonly property ListModel fillModeModel: ListModel {} + readonly property string defaultDirectory: Settings.preprocessPath(Settings.data.wallpaper.directory) // All available wallpaper transitions readonly property ListModel transitionsModel: ListModel {} @@ -44,7 +45,7 @@ Singleton { if (!Settings.data.wallpaper.enableMultiMonitorDirectories) { // All monitors use the main directory for (var i = 0; i < Quickshell.screens.length; i++) { - root.wallpaperDirectoryChanged(Quickshell.screens[i].name, Settings.data.wallpaper.directory) + root.wallpaperDirectoryChanged(Quickshell.screens[i].name, root.defaultDirectory) } } else { // Only monitors without custom directories are affected @@ -52,7 +53,7 @@ Singleton { var screenName = Quickshell.screens[i].name var monitor = root.getMonitorConfig(screenName) if (!monitor || !monitor.directory) { - root.wallpaperDirectoryChanged(screenName, Settings.data.wallpaper.directory) + root.wallpaperDirectoryChanged(screenName, root.defaultDirectory) } } } @@ -177,16 +178,16 @@ Singleton { // Get specific monitor directory function getMonitorDirectory(screenName) { if (!Settings.data.wallpaper.enableMultiMonitorDirectories) { - return Settings.data.wallpaper.directory + return root.defaultDirectory } var monitor = getMonitorConfig(screenName) if (monitor !== undefined && monitor.directory !== undefined) { - return monitor.directory + return Settings.preprocessPath(monitor.directory) } // Fall back to the main/single directory - return Settings.data.wallpaper.directory + return root.defaultDirectory } // ------------------------------------------------------------------- @@ -218,7 +219,7 @@ Singleton { // Update Settings with new array to ensure proper persistence Settings.data.wallpaper.monitors = newMonitors.slice() - root.wallpaperDirectoryChanged(screenName, directory) + root.wallpaperDirectoryChanged(screenName, Settings.preprocessPath(directory)) } // ------------------------------------------------------------------- @@ -274,7 +275,7 @@ Singleton { found = true return { "name": screenName, - "directory": monitor.directory || getMonitorDirectory(screenName), + "directory": Settings.preprocessPath(monitor.directory) || getMonitorDirectory(screenName), "wallpaper": path } } diff --git a/Shaders/frag/appicon_colorize.frag b/Shaders/frag/appicon_colorize.frag new file mode 100644 index 00000000..ae108701 --- /dev/null +++ b/Shaders/frag/appicon_colorize.frag @@ -0,0 +1,29 @@ +#version 450 +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; +layout(binding = 1) uniform sampler2D source; +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + vec4 targetColor; + float colorizeMode; // 0.0 = dock mode (grayscale), 1.0 = tray mode (intensity) +} ubuf; + +void main() { + vec4 tex = texture(source, qt_TexCoord0); + + float intensity; + + if (ubuf.colorizeMode < 0.5) { + // Dock mode: Convert to grayscale using proper luminance weights + intensity = dot(tex.rgb, vec3(0.299, 0.587, 0.114)); + } else { + // Tray mode: Use the maximum RGB channel value as intensity + intensity = max(max(tex.r, tex.g), tex.b); + + // Normalize intensity to make all icons more uniform + intensity = smoothstep(0.1, 0.9, intensity); + } + + fragColor = vec4(ubuf.targetColor.rgb * intensity, tex.a) * ubuf.qt_Opacity; +} diff --git a/Shaders/qsb/appicon_colorize.frag.qsb b/Shaders/qsb/appicon_colorize.frag.qsb new file mode 100644 index 00000000..15618b86 Binary files /dev/null and b/Shaders/qsb/appicon_colorize.frag.qsb differ diff --git a/Shaders/qsb/progress_border.frag.qsb b/Shaders/qsb/progress_border.frag.qsb new file mode 100644 index 00000000..e6e8f315 Binary files /dev/null and b/Shaders/qsb/progress_border.frag.qsb differ diff --git a/Widgets/NBox.qml b/Widgets/NBox.qml index 4dad5c68..72ab90f0 100644 --- a/Widgets/NBox.qml +++ b/Widgets/NBox.qml @@ -12,7 +12,7 @@ Rectangle { implicitHeight: childrenRect.height color: Color.mSurfaceVariant - radius: Style.radiusM * scaling + radius: Style.radiusM border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) } diff --git a/Widgets/NBusyIndicator.qml b/Widgets/NBusyIndicator.qml index 67f104ae..bf93abe8 100644 --- a/Widgets/NBusyIndicator.qml +++ b/Widgets/NBusyIndicator.qml @@ -7,8 +7,8 @@ Item { property bool running: true property color color: Color.mPrimary - property int size: Style.baseWidgetSize * scaling - property int strokeWidth: Style.borderL * scaling + property int size: Style.baseWidgetSize + property int strokeWidth: Style.borderL property int duration: Style.animationSlow * 2 implicitWidth: size diff --git a/Widgets/NButton.qml b/Widgets/NButton.qml index 3d1b05a3..654de952 100644 --- a/Widgets/NButton.qml +++ b/Widgets/NButton.qml @@ -15,9 +15,9 @@ Rectangle { property color textColor: Color.mOnPrimary property color hoverColor: Color.mTertiary property bool enabled: true - property real fontSize: Style.fontSizeM * scaling + property real fontSize: Style.fontSizeM property int fontWeight: Style.fontWeightBold - property real iconSize: Style.fontSizeL * scaling + property real iconSize: Style.fontSizeL property bool outlined: false property int horizontalAlignment: Qt.AlignHCenter @@ -30,11 +30,11 @@ Rectangle { property bool hovered: false // Dimensions - implicitWidth: contentRow.implicitWidth + (Style.marginL * 2 * scaling) - implicitHeight: Math.max(Style.baseWidgetSize * scaling, contentRow.implicitHeight + (Style.marginM * scaling)) + implicitWidth: contentRow.implicitWidth + (Style.marginL * 2) + implicitHeight: Math.max(Style.baseWidgetSize, contentRow.implicitHeight + (Style.marginM)) // Appearance - radius: Style.radiusS * scaling + radius: Style.radiusS color: { if (!enabled) return outlined ? Color.transparent : Qt.lighter(Color.mSurfaceVariant, 1.2) @@ -43,7 +43,7 @@ Rectangle { return outlined ? Color.transparent : backgroundColor } - border.width: outlined ? Math.max(1, Style.borderS * scaling) : 0 + border.width: outlined ? Math.max(1, Style.borderS) : 0 border.color: { if (!enabled) return Color.mOutline @@ -74,8 +74,8 @@ Rectangle { anchors.verticalCenter: parent.verticalCenter anchors.left: root.horizontalAlignment === Qt.AlignLeft ? parent.left : undefined anchors.horizontalCenter: root.horizontalAlignment === Qt.AlignHCenter ? parent.horizontalCenter : undefined - anchors.leftMargin: root.horizontalAlignment === Qt.AlignLeft ? Style.marginL * scaling : 0 - spacing: Style.marginXS * scaling + anchors.leftMargin: root.horizontalAlignment === Qt.AlignLeft ? Style.marginL : 0 + spacing: Style.marginXS // Icon (optional) NIcon { diff --git a/Widgets/NCheckbox.qml b/Widgets/NCheckbox.qml index 4ea76318..f27694e6 100644 --- a/Widgets/NCheckbox.qml +++ b/Widgets/NCheckbox.qml @@ -6,7 +6,7 @@ import qs.Commons RowLayout { id: root - // Public API (mirrors NToggle but compact) + // Public API property string label: "" property string description: "" property bool checked: false @@ -35,12 +35,12 @@ RowLayout { Rectangle { id: box - implicitWidth: Math.round(root.baseSize * scaling) - implicitHeight: Math.round(root.baseSize * scaling) - radius: Style.radiusXS * scaling + implicitWidth: Math.round(root.baseSize) + implicitHeight: Math.round(root.baseSize) + radius: Style.radiusXS color: root.checked ? root.activeColor : Color.mSurface border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on color { ColorAnimation { @@ -57,10 +57,10 @@ RowLayout { NIcon { visible: root.checked anchors.centerIn: parent - anchors.horizontalCenterOffset: -1 * scaling + anchors.horizontalCenterOffset: -1 icon: "check" color: root.activeOnColor - pointSize: Math.max(Style.fontSizeXS, root.baseSize * 0.5) * scaling + pointSize: Math.max(Style.fontSizeXS, root.baseSize * 0.5) font.weight: Style.fontWeightBold } diff --git a/Widgets/NCircleStat.qml b/Widgets/NCircleStat.qml index f6d4332d..3279084e 100644 --- a/Widgets/NCircleStat.qml +++ b/Widgets/NCircleStat.qml @@ -17,12 +17,12 @@ Rectangle { // outer width/height footprint of the component property real contentScale: 1.0 - width: 68 * scaling - height: 92 * scaling + width: 68 + height: 92 color: flat ? Color.transparent : Color.mSurface - radius: Style.radiusS * scaling + radius: Style.radiusS border.color: flat ? Color.transparent : Color.mSurfaceVariant - border.width: flat ? 0 : Math.max(1, Style.borderS * scaling) + border.width: flat ? 0 : Math.max(1, Style.borderS) // Repaint gauge when the bound value changes onValueChanged: gauge.requestPaint() @@ -30,7 +30,7 @@ Rectangle { ColumnLayout { id: mainLayout anchors.fill: parent - anchors.margins: Style.marginS * scaling * contentScale + anchors.margins: Style.marginS * contentScale spacing: 0 // Main gauge container @@ -39,19 +39,19 @@ Rectangle { Layout.fillWidth: true Layout.fillHeight: true Layout.alignment: Qt.AlignCenter - Layout.preferredWidth: 68 * scaling * contentScale - Layout.preferredHeight: 68 * scaling * contentScale + Layout.preferredWidth: 68 * contentScale + Layout.preferredHeight: 68 * contentScale Canvas { id: gauge anchors.fill: parent - renderStrategy: Canvas.Cooperative + renderStrategy: Canvas.Immediate onPaint: { const ctx = getContext("2d") const w = width, h = height const cx = w / 2, cy = h / 2 - const r = Math.min(w, h) / 2 - 5 * scaling * contentScale + const r = Math.min(w, h) / 2 - 5 * contentScale // Rotated 90° to the right: gap at the bottom // Start at 150° and end at 390° (30°) → bottom opening @@ -59,7 +59,7 @@ Rectangle { const endBg = Math.PI * 13 / 6 // 390° (equivalent to 30°) ctx.reset() - ctx.lineWidth = 6 * scaling * contentScale + ctx.lineWidth = 6 * contentScale // Track uses surface for stronger contrast ctx.strokeStyle = Color.mSurface @@ -96,9 +96,9 @@ Rectangle { NText { id: valueLabel anchors.centerIn: parent - anchors.verticalCenterOffset: -4 * scaling * contentScale + anchors.verticalCenterOffset: -4 * contentScale text: `${root.value}${root.suffix}` - pointSize: Style.fontSizeM * scaling * contentScale * 0.9 + pointSize: Style.fontSizeM * contentScale * 0.9 font.weight: Style.fontWeightBold color: Color.mOnSurface horizontalAlignment: Text.AlignHCenter @@ -108,10 +108,10 @@ Rectangle { id: iconText anchors.horizontalCenter: parent.horizontalCenter anchors.top: valueLabel.bottom - anchors.topMargin: 8 * scaling * contentScale + anchors.topMargin: 8 * contentScale icon: root.icon color: Color.mPrimary - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter } diff --git a/Widgets/NCollapsible.qml b/Widgets/NCollapsible.qml index 6b78f4fd..3834220e 100644 --- a/Widgets/NCollapsible.qml +++ b/Widgets/NCollapsible.qml @@ -8,7 +8,7 @@ ColumnLayout { property string description: "" property bool expanded: false property bool defaultExpanded: false - property real contentSpacing: Style.marginM * scaling + property real contentSpacing: Style.marginM signal toggled(bool expanded) Layout.fillWidth: true @@ -21,15 +21,15 @@ ColumnLayout { Rectangle { id: headerContainer Layout.fillWidth: true - Layout.preferredHeight: headerContent.implicitHeight + (Style.marginM * scaling * 2) + Layout.preferredHeight: headerContent.implicitHeight + (Style.marginM * 2) // Material 3 style background color: root.expanded ? Color.mSecondary : Color.mSurfaceVariant - radius: Style.radiusL * scaling + radius: Style.radiusL // Subtle border border.color: root.expanded ? Color.mOnSecondary : Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Smooth color transitions Behavior on color { @@ -75,14 +75,14 @@ ColumnLayout { RowLayout { id: headerContent anchors.fill: parent - anchors.margins: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginM + spacing: Style.marginM // Expand/collapse icon with rotation animation NIcon { id: chevronIcon icon: "chevron-right" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: root.expanded ? Color.mOnSecondary : Color.mOnSurfaceVariant Layout.alignment: Qt.AlignVCenter @@ -105,11 +105,11 @@ ColumnLayout { RowLayout { Layout.fillWidth: true Layout.alignment: Qt.AlignVCenter - spacing: Style.marginL * scaling + spacing: Style.marginL NText { text: root.label - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightSemiBold color: root.expanded ? Color.mOnSecondary : Color.mOnSurface wrapMode: Text.WordWrap @@ -123,7 +123,7 @@ ColumnLayout { NText { text: root.description - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: Style.fontWeightRegular color: root.expanded ? Color.mOnSecondary : Color.mOnSurfaceVariant Layout.fillWidth: true @@ -145,16 +145,16 @@ ColumnLayout { Rectangle { id: contentContainer Layout.fillWidth: true - Layout.topMargin: Style.marginS * scaling + Layout.topMargin: Style.marginS visible: root.expanded color: Color.mSurface - radius: Style.radiusL * scaling + radius: Style.radiusL border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Dynamic height based on content - Layout.preferredHeight: visible ? contentLayout.implicitHeight + (Style.marginL * scaling * 2) : 0 + Layout.preferredHeight: visible ? contentLayout.implicitHeight + (Style.marginL * 2) : 0 // Smooth height animation Behavior on Layout.preferredHeight { @@ -168,7 +168,7 @@ ColumnLayout { ColumnLayout { id: contentLayout anchors.fill: parent - anchors.margins: Style.marginL * scaling + anchors.margins: Style.marginL spacing: root.contentSpacing } diff --git a/Widgets/NColorPicker.qml b/Widgets/NColorPicker.qml index 642d74a9..4aa9b46f 100644 --- a/Widgets/NColorPicker.qml +++ b/Widgets/NColorPicker.qml @@ -12,13 +12,13 @@ Rectangle { signal colorSelected(color color) - implicitWidth: 150 * scaling - implicitHeight: Math.round(Style.baseWidgetSize * 1.1 * scaling) + implicitWidth: 150 + implicitHeight: Math.round(Style.baseWidgetSize * 1.1) - radius: Style.radiusM * scaling + radius: Style.radiusM color: Color.mSurface border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Minimized Look MouseArea { @@ -41,19 +41,19 @@ Rectangle { RowLayout { anchors.fill: parent anchors { - leftMargin: Style.marginL * scaling - rightMargin: Style.marginL * scaling + leftMargin: Style.marginL + rightMargin: Style.marginL } - spacing: Style.marginS * scaling + spacing: Style.marginS // Color preview circle Rectangle { - Layout.preferredWidth: root.height * 0.6 * scaling - Layout.preferredHeight: root.height * 0.6 * scaling + Layout.preferredWidth: root.height * 0.6 + Layout.preferredHeight: root.height * 0.6 radius: Layout.preferredWidth * 0.5 color: root.selectedColor border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) } NText { diff --git a/Widgets/NColorPickerDialog.qml b/Widgets/NColorPickerDialog.qml index de6bb0e9..364dd8f9 100644 --- a/Widgets/NColorPickerDialog.qml +++ b/Widgets/NColorPickerDialog.qml @@ -14,12 +14,12 @@ Popup { signal colorSelected(color color) - width: 580 * scaling + width: 580 height: { const h = scrollView.implicitHeight + padding * 2 - Math.min(h, screen?.height - Style.barHeight * scaling - Style.marginL * 2) + Math.min(h, screen?.height - Style.barHeight - Style.marginL * 2) } - padding: Style.marginXL * scaling + padding: Style.marginXL // Center popup in parent x: (parent.width - width) * 0.5 @@ -112,9 +112,9 @@ Popup { background: Rectangle { color: Color.mSurface - radius: Style.radiusS * scaling + radius: Style.radiusS border.color: Color.mPrimary - border.width: Math.max(1, Style.borderM * scaling) + border.width: Math.max(1, Style.borderM) } contentItem: NScrollView { @@ -126,24 +126,24 @@ Popup { ColumnLayout { width: scrollView.availableWidth - spacing: Style.marginL * scaling + spacing: Style.marginL // Header RowLayout { Layout.fillWidth: true RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS NIcon { icon: "color-picker" - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL color: Color.mPrimary } NText { text: I18n.tr("widgets.color-picker.title") - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL font.weight: Style.fontWeightBold color: Color.mPrimary } @@ -162,11 +162,11 @@ Popup { // Color preview section Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 80 * scaling - radius: Style.radiusS * scaling + Layout.preferredHeight: 80 + radius: Style.radiusS color: root.selectedColor border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) ColumnLayout { spacing: 0 @@ -179,7 +179,7 @@ Popup { NText { text: root.selectedColor.toString().toUpperCase() family: Settings.data.ui.fontFixed - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Font.Bold color: root.selectedColor.r + root.selectedColor.g + root.selectedColor.b > 1.5 ? "#000000" : "#FFFFFF" Layout.alignment: Qt.AlignHCenter @@ -188,7 +188,7 @@ Popup { NText { text: "RGB(" + Math.round(root.selectedColor.r * 255) + ", " + Math.round(root.selectedColor.g * 255) + ", " + Math.round(root.selectedColor.b * 255) + ")" family: Settings.data.ui.fontFixed - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: root.selectedColor.r + root.selectedColor.g + root.selectedColor.b > 1.5 ? "#000000" : "#FFFFFF" Layout.alignment: Qt.AlignHCenter } @@ -202,7 +202,7 @@ Popup { // Hex input RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NLabel { label: I18n.tr("widgets.color-picker.hex.label") @@ -225,13 +225,13 @@ Popup { // RGB sliders section NBox { Layout.fillWidth: true - Layout.preferredHeight: slidersSection.implicitHeight + Style.marginL * scaling * 2 + Layout.preferredHeight: slidersSection.implicitHeight + Style.marginL * 2 ColumnLayout { id: slidersSection anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginL + spacing: Style.marginM NLabel { label: I18n.tr("widgets.color-picker.rgb.label") @@ -241,12 +241,12 @@ Popup { RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: "R" font.weight: Font.Bold - Layout.preferredWidth: 20 * scaling + Layout.preferredWidth: 20 } NValueSlider { @@ -267,12 +267,12 @@ Popup { RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: "G" font.weight: Font.Bold - Layout.preferredWidth: 20 * scaling + Layout.preferredWidth: 20 } NValueSlider { @@ -294,12 +294,12 @@ Popup { RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: "B" font.weight: Font.Bold - Layout.preferredWidth: 20 * scaling + Layout.preferredWidth: 20 } NValueSlider { @@ -321,12 +321,12 @@ Popup { RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: I18n.tr("widgets.color-picker.brightness") font.weight: Font.Bold - Layout.preferredWidth: 80 * scaling + Layout.preferredWidth: 80 } NValueSlider { @@ -361,13 +361,13 @@ Popup { NBox { Layout.fillWidth: true - Layout.preferredHeight: themePalette.implicitHeight + Style.marginL * scaling * 2 + Layout.preferredHeight: themePalette.implicitHeight + Style.marginL * 2 ColumnLayout { id: themePalette anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginS * scaling + anchors.margins: Style.marginL + spacing: Style.marginS NLabel { label: I18n.tr("widgets.color-picker.theme-colors.label") @@ -376,7 +376,7 @@ Popup { } Flow { - spacing: 6 * scaling + spacing: 6 Layout.fillWidth: true flow: Flow.LeftToRight @@ -384,12 +384,12 @@ Popup { model: [Color.mPrimary, Color.mSecondary, Color.mTertiary, Color.mError, Color.mSurface, Color.mSurfaceVariant, Color.mOutline, "#FFFFFF", "#000000"] Rectangle { - width: 24 * scaling - height: 24 * scaling - radius: 4 * scaling + width: 24 + height: 24 + radius: 4 color: modelData border.color: root.selectedColor === modelData ? Color.mPrimary : Color.mOutline - border.width: root.selectedColor === modelData ? 2 * scaling : 1 * scaling + border.width: root.selectedColor === modelData ? 2 : 1 MouseArea { anchors.fill: parent @@ -409,13 +409,13 @@ Popup { NBox { Layout.fillWidth: true - Layout.preferredHeight: genericPalette.implicitHeight + Style.marginL * scaling * 2 + Layout.preferredHeight: genericPalette.implicitHeight + Style.marginL * 2 ColumnLayout { id: genericPalette anchors.fill: parent - anchors.margins: Style.marginL * scaling - spacing: Style.marginS * scaling + anchors.margins: Style.marginL + spacing: Style.marginS NLabel { label: I18n.tr("widgets.color-picker.palette.label") @@ -426,19 +426,19 @@ Popup { Flow { Layout.fillWidth: true Layout.fillHeight: true - spacing: 6 * scaling + spacing: 6 flow: Flow.LeftToRight Repeater { model: ["#F44336", "#E91E63", "#9C27B0", "#673AB7", "#3F51B5", "#2196F3", "#03A9F4", "#00BCD4", "#009688", "#4CAF50", "#8BC34A", "#CDDC39", "#FFEB3B", "#FFC107", "#FF9800", "#FF5722", "#795548", "#9E9E9E", "#E74C3C", "#E67E22", "#F1C40F", "#2ECC71", "#1ABC9C", "#3498DB", "#2980B9", "#9B59B6", "#34495E", "#2C3E50", "#95A5A6", "#7F8C8D", "#FFFFFF", "#000000"] Rectangle { - width: 24 * scaling - height: 24 * scaling - radius: Style.radiusXXS * scaling + width: 24 + height: 24 + radius: Style.radiusXXS color: modelData border.color: root.selectedColor === modelData ? Color.mPrimary : Color.mOutline - border.width: Math.max(1, root.selectedColor === modelData ? Style.borderM * scaling : Style.borderS * scaling) + border.width: Math.max(1, root.selectedColor === modelData ? Style.borderM : Style.borderS) MouseArea { anchors.fill: parent @@ -458,9 +458,9 @@ Popup { RowLayout { Layout.fillWidth: true - Layout.topMargin: 20 * scaling - Layout.bottomMargin: 20 * scaling - spacing: 10 * scaling + Layout.topMargin: 20 + Layout.bottomMargin: 20 + spacing: 10 Item { Layout.fillWidth: true diff --git a/Widgets/NComboBox.qml b/Widgets/NComboBox.qml index a7a054b5..00f29bb1 100644 --- a/Widgets/NComboBox.qml +++ b/Widgets/NComboBox.qml @@ -8,8 +8,8 @@ import qs.Widgets RowLayout { id: root - property real minimumWidth: 280 * scaling - property real popupHeight: 180 * scaling + property real minimumWidth: 280 * Style.uiScaleRatio + property real popupHeight: 180 * Style.uiScaleRatio property string label: "" property string description: "" @@ -17,11 +17,11 @@ RowLayout { property string currentKey: "" property string placeholder: "" - readonly property real preferredHeight: Style.baseWidgetSize * 1.1 * scaling + readonly property real preferredHeight: Style.baseWidgetSize * 1.1 * Style.uiScaleRatio signal selected(string key) - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true function itemCount() { @@ -72,12 +72,12 @@ RowLayout { } background: Rectangle { - implicitWidth: Style.baseWidgetSize * 3.75 * scaling + implicitWidth: Style.baseWidgetSize * 3.75 implicitHeight: preferredHeight color: Color.mSurface border.color: combo.activeFocus ? Color.mSecondary : Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM Behavior on border.color { ColorAnimation { @@ -87,9 +87,9 @@ RowLayout { } contentItem: NText { - leftPadding: Style.marginL * scaling - rightPadding: combo.indicator.width + Style.marginL * scaling - pointSize: Style.fontSizeM * scaling + leftPadding: Style.marginL + rightPadding: combo.indicator.width + Style.marginL + pointSize: Style.fontSizeM verticalAlignment: Text.AlignVCenter elide: Text.ElideRight color: (combo.currentIndex >= 0 && combo.currentIndex < itemCount()) ? Color.mOnSurface : Color.mOnSurfaceVariant @@ -97,17 +97,17 @@ RowLayout { } indicator: NIcon { - x: combo.width - width - Style.marginM * scaling + x: combo.width - width - Style.marginM y: combo.topPadding + (combo.availableHeight - height) / 2 icon: "caret-down" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL } popup: Popup { y: combo.height - implicitWidth: combo.width - Style.marginM * scaling - implicitHeight: Math.min(root.popupHeight, contentItem.implicitHeight + Style.marginM * scaling * 2) - padding: Style.marginM * scaling + implicitWidth: combo.width - Style.marginM + implicitHeight: Math.min(root.popupHeight, contentItem.implicitHeight + Style.marginM * 2) + padding: Style.marginM onOpened: { PanelService.willOpenPopup(root) @@ -144,9 +144,9 @@ RowLayout { } background: Rectangle { - width: combo.width - Style.marginM * scaling * 3 + width: combo.width - Style.marginM * 3 color: highlighted ? Color.mTertiary : Color.transparent - radius: Style.radiusS * scaling + radius: Style.radiusS Behavior on color { ColorAnimation { duration: Style.animationFast @@ -159,7 +159,7 @@ RowLayout { var item = root.getItem(index) return item && item.name ? item.name : "" } - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: highlighted ? Color.mOnTertiary : Color.mOnSurface verticalAlignment: Text.AlignVCenter elide: Text.ElideRight @@ -175,8 +175,8 @@ RowLayout { background: Rectangle { color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM } } diff --git a/Widgets/NContextMenu.qml b/Widgets/NContextMenu.qml index 126f2892..9f8e833e 100644 --- a/Widgets/NContextMenu.qml +++ b/Widgets/NContextMenu.qml @@ -8,13 +8,13 @@ Popup { id: root property alias model: listView.model - property real itemHeight: 36 * scaling - property real itemPadding: Style.marginM * scaling + property real itemHeight: 36 + property real itemPadding: Style.marginM signal triggered(string action) - width: 180 * scaling - padding: Style.marginS * scaling + width: 180 + padding: Style.marginS onOpened: PanelService.willOpenPopup(root) onClosed: PanelService.willClosePopup(root) @@ -22,14 +22,14 @@ Popup { background: Rectangle { color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM } contentItem: NListView { id: listView implicitHeight: contentHeight - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS interactive: contentHeight > root.height delegate: ItemDelegate { @@ -45,7 +45,7 @@ Popup { background: Rectangle { color: menuItem.hovered && menuItem.enabled ? Color.mTertiary : Color.transparent - radius: Style.radiusS * scaling + radius: Style.radiusS Behavior on color { ColorAnimation { @@ -55,13 +55,13 @@ Popup { } contentItem: RowLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS // Optional icon NIcon { visible: modelData.icon !== undefined icon: modelData.icon || "" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: menuItem.hovered && menuItem.enabled ? Color.mOnTertiary : Color.mOnSurface Layout.leftMargin: root.itemPadding @@ -74,7 +74,7 @@ Popup { NText { text: modelData.label || modelData.text || "" - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: menuItem.hovered && menuItem.enabled ? Color.mOnTertiary : Color.mOnSurface verticalAlignment: Text.AlignVCenter Layout.fillWidth: true diff --git a/Widgets/NDateTimeTokens.qml b/Widgets/NDateTimeTokens.qml index 1ad1ec94..4f6c2b9e 100644 --- a/Widgets/NDateTimeTokens.qml +++ b/Widgets/NDateTimeTokens.qml @@ -7,8 +7,8 @@ Rectangle { id: root color: Color.mSurface border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM property date sampleDate: new Date() // Dec 25, 2023, 2:30:45.123 PM @@ -18,8 +18,8 @@ Rectangle { ColumnLayout { id: column anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginS * scaling + anchors.margins: Style.marginS + spacing: Style.marginS NListView { id: tokensList @@ -174,8 +174,8 @@ Rectangle { delegate: Rectangle { id: tokenDelegate width: tokensList.width - height: layout.implicitHeight + Style.marginS * scaling - radius: Style.radiusS * scaling + height: layout.implicitHeight + Style.marginS + radius: Style.radiusS color: { if (tokenMouseArea.containsMouse) { return Qt.alpha(Color.mPrimary, 0.1) @@ -216,16 +216,16 @@ Rectangle { RowLayout { id: layout anchors.fill: parent - anchors.margins: Style.marginXS * scaling - spacing: Style.marginM * scaling + anchors.margins: Style.marginXS + spacing: Style.marginM // Category badge Rectangle { Layout.alignment: Qt.AlignVCenter - width: 70 * scaling - height: 22 * scaling + width: 70 + height: 22 color: getCategoryColor(modelData.category)[0] - radius: Style.radiusS * scaling + radius: Style.radiusS opacity: tokenMouseArea.containsMouse ? 0.9 : 1.0 Behavior on opacity { @@ -238,7 +238,7 @@ Rectangle { anchors.centerIn: parent text: modelData.category color: getCategoryColor(modelData.category)[1] - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS } } @@ -246,10 +246,10 @@ Rectangle { Rectangle { id: tokenButton Layout.alignment: Qt.AlignVCenter // Added this line - width: 100 * scaling - height: 22 * scaling + width: 100 + height: 22 color: tokenMouseArea.containsMouse ? Color.mPrimary : Color.mOnSurface - radius: Style.radiusS * scaling + radius: Style.radiusS Behavior on color { ColorAnimation { @@ -261,7 +261,7 @@ Rectangle { anchors.centerIn: parent text: modelData.token color: tokenMouseArea.containsMouse ? Color.mOnPrimary : Color.mSurface - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: Style.fontWeightBold Behavior on color { @@ -278,7 +278,7 @@ Rectangle { Layout.alignment: Qt.AlignVCenter // Added this line text: modelData.description color: tokenMouseArea.containsMouse ? Color.mOnSurface : Color.mOnSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS wrapMode: Text.WordWrap Behavior on color { @@ -291,12 +291,12 @@ Rectangle { // Live example Rectangle { Layout.alignment: Qt.AlignVCenter // Added this line - width: 90 * scaling - height: 22 * scaling + width: 90 + height: 22 color: tokenMouseArea.containsMouse ? Color.mPrimary : Color.mOnSurfaceVariant - radius: Style.radiusS * scaling + radius: Style.radiusS border.color: tokenMouseArea.containsMouse ? Color.mPrimary : Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on color { ColorAnimation { @@ -314,7 +314,7 @@ Rectangle { anchors.centerIn: parent text: Qt.locale().toString(root.sampleDate, modelData.token) color: tokenMouseArea.containsMouse ? Color.mOnPrimary : Color.mSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS Behavior on color { ColorAnimation { diff --git a/Widgets/NDivider.qml b/Widgets/NDivider.qml index a95df11d..98f4d1d4 100644 --- a/Widgets/NDivider.qml +++ b/Widgets/NDivider.qml @@ -6,7 +6,7 @@ import qs.Services Rectangle { width: parent.width - height: Math.max(1, Style.borderS * scaling) + height: Math.max(1, Style.borderS) gradient: Gradient { orientation: Gradient.Horizontal GradientStop { diff --git a/Widgets/NFilePicker.qml b/Widgets/NFilePicker.qml index 4013c59c..4fd7875e 100644 --- a/Widgets/NFilePicker.qml +++ b/Widgets/NFilePicker.qml @@ -19,7 +19,7 @@ Popup { property var nameFilters: ["*"] property bool showDirs: true property bool showHiddenFiles: false - property real scaling: 1.0 + property var selectedPaths: [] property string currentPath: initialPath property bool shouldResetSelection: false @@ -137,23 +137,23 @@ Popup { } } - width: 900 * scaling - height: 700 * scaling + width: 900 + height: 700 modal: true closePolicy: Popup.CloseOnEscape anchors.centerIn: Overlay.overlay background: Rectangle { color: Color.mSurfaceVariant - radius: Style.radiusL * scaling + radius: Style.radiusL border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) } Rectangle { id: filePickerPanel anchors.fill: parent - anchors.margins: Style.marginL * scaling + anchors.margins: Style.marginL color: Color.transparent property string filterText: "" @@ -181,21 +181,21 @@ Popup { ColumnLayout { anchors.fill: parent - spacing: Style.marginM * scaling + spacing: Style.marginM // Header RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NIcon { icon: "filepicker-folder" color: Color.mPrimary - pointSize: Style.fontSizeXXL * scaling + pointSize: Style.fontSizeXXL } NText { text: root.title - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL font.weight: Style.fontWeightBold color: Color.mPrimary Layout.fillWidth: true @@ -240,19 +240,19 @@ Popup { // Navigation toolbar Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 45 * scaling + Layout.preferredHeight: 45 color: Color.mSurfaceVariant - radius: Style.radiusS * scaling + radius: Style.radiusS border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) RowLayout { anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Style.marginS * scaling - anchors.rightMargin: Style.marginS * scaling - spacing: Style.marginS * scaling + anchors.leftMargin: Style.marginS + anchors.rightMargin: Style.marginS + spacing: Style.marginS NIconButton { icon: "filepicker-arrow-up" @@ -339,25 +339,25 @@ Popup { // Search bar Rectangle { Layout.fillWidth: true - Layout.preferredHeight: 45 * scaling + Layout.preferredHeight: 45 color: Color.mSurfaceVariant - radius: Style.radiusS * scaling + radius: Style.radiusS border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) visible: filePickerPanel.showSearchBar RowLayout { anchors.left: parent.left anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter - anchors.leftMargin: Style.marginS * scaling - anchors.rightMargin: Style.marginS * scaling - spacing: Style.marginS * scaling + anchors.leftMargin: Style.marginS + anchors.rightMargin: Style.marginS + spacing: Style.marginS NIcon { icon: "filepicker-search" color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS } NTextInput { id: searchInput @@ -396,9 +396,9 @@ Popup { Layout.fillWidth: true Layout.fillHeight: true color: Color.mSurface - radius: Style.radiusM * scaling + radius: Style.radiusM border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) FolderListModel { id: folderModel @@ -447,9 +447,9 @@ Popup { ScrollBar { policy: ScrollBar.AsNeeded contentItem: Rectangle { - implicitWidth: 6 * scaling + implicitWidth: 6 implicitHeight: 100 - radius: Style.radiusM * scaling + radius: Style.radiusM color: parent.pressed ? Qt.alpha(Color.mTertiary, 0.8) : parent.hovered ? Qt.alpha(Color.mTertiary, 0.8) : Qt.alpha(Color.mTertiary, 0.8) opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 1.0 : 0.0 Behavior on opacity { @@ -464,11 +464,11 @@ Popup { } } background: Rectangle { - implicitWidth: 6 * scaling + implicitWidth: 6 implicitHeight: 100 color: Color.transparent opacity: parent.policy === ScrollBar.AlwaysOn || parent.active ? 0.3 : 0.0 - radius: (Style.radiusM * scaling) / 2 + radius: (Style.radiusM) / 2 Behavior on opacity { NumberAnimation { duration: Style.animationFast @@ -482,22 +482,22 @@ Popup { GridView { id: gridView anchors.fill: parent - anchors.margins: Style.marginM * scaling + anchors.margins: Style.marginM model: filteredModel visible: filePickerPanel.viewMode clip: true reuseItems: true - property int columns: Math.max(1, Math.floor(width / (120 * scaling))) - property int itemSize: Math.floor((width - leftMargin - rightMargin - (columns * Style.marginS * scaling)) / columns) + property int columns: Math.max(1, Math.floor(width / (120))) + property int itemSize: Math.floor((width - leftMargin - rightMargin - (columns * Style.marginS)) / columns) cellWidth: Math.floor((width - leftMargin - rightMargin) / columns) - cellHeight: Math.floor(itemSize * 0.8) + Style.marginXS * scaling + Style.fontSizeS * scaling + Style.marginM * scaling + cellHeight: Math.floor(itemSize * 0.8) + Style.marginXS + Style.fontSizeS + Style.marginM - leftMargin: Style.marginS * scaling - rightMargin: Style.marginS * scaling - topMargin: Style.marginS * scaling - bottomMargin: Style.marginS * scaling + leftMargin: Style.marginS + rightMargin: Style.marginS + topMargin: Style.marginS + bottomMargin: Style.marginS ScrollBar.vertical: scrollBarComponent.createObject(gridView, { "parent": gridView, @@ -511,7 +511,7 @@ Popup { width: gridView.itemSize height: gridView.cellHeight color: Color.transparent - radius: Style.radiusM * scaling + radius: Style.radiusM property bool isSelected: filePickerPanel.currentSelection.includes(model.filePath) @@ -520,7 +520,7 @@ Popup { color: Color.transparent radius: parent.radius border.color: isSelected ? Color.mSecondary : Color.mSurface - border.width: Math.max(1, Style.borderL * scaling) + border.width: Math.max(1, Style.borderL) Behavior on color { ColorAnimation { duration: Style.animationFast @@ -533,7 +533,7 @@ Popup { color: (mouseArea.containsMouse && !isSelected) ? Color.mTertiary : Color.transparent radius: parent.radius border.color: (mouseArea.containsMouse && !isSelected) ? Color.mTertiary : Color.transparent - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on color { ColorAnimation { duration: Style.animationFast @@ -548,8 +548,8 @@ Popup { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginXS * scaling + anchors.margins: Style.marginS + spacing: Style.marginXS Rectangle { id: iconContainer @@ -567,15 +567,15 @@ Popup { Image { id: thumbnail anchors.fill: parent - anchors.margins: Style.marginXS * scaling + anchors.margins: Style.marginXS source: iconContainer.isImage ? "file://" + model.filePath : "" fillMode: Image.PreserveAspectFit visible: iconContainer.isImage && status === Image.Ready smooth: false cache: true asynchronous: true - sourceSize.width: 120 * scaling - sourceSize.height: 120 * scaling + sourceSize.width: 120 + sourceSize.height: 120 onStatusChanged: { if (status === Image.Error) visible = false @@ -584,11 +584,11 @@ Popup { Rectangle { anchors.fill: parent color: Color.mSurfaceVariant - radius: Style.radiusS * scaling + radius: Style.radiusS visible: thumbnail.status === Image.Loading NIcon { icon: "filepicker-photo" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: Color.mOnSurfaceVariant anchors.centerIn: parent } @@ -597,7 +597,7 @@ Popup { NIcon { icon: model.fileIsDir ? "filepicker-folder" : root.getFileIcon(model.fileName) - pointSize: Style.fontSizeXXL * 2 * scaling + pointSize: Style.fontSizeXXL * 2 color: { if (isSelected) return Color.mSecondary @@ -613,17 +613,17 @@ Popup { Rectangle { anchors.top: parent.top anchors.right: parent.right - anchors.margins: Style.marginS * scaling - width: 24 * scaling - height: 24 * scaling + anchors.margins: Style.marginS + width: 24 + height: 24 radius: width / 2 color: Color.mSecondary border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) visible: isSelected NIcon { icon: "filepicker-check" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: Style.fontWeightBold color: Color.mOnSecondary anchors.centerIn: parent @@ -641,7 +641,7 @@ Popup { else return Color.mOnSurfaceVariant } - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS font.weight: isSelected ? Style.fontWeightBold : Style.fontWeightRegular Layout.fillWidth: true horizontalAlignment: Text.AlignHCenter @@ -697,14 +697,14 @@ Popup { NListView { id: listView anchors.fill: parent - anchors.margins: Style.marginS * scaling + anchors.margins: Style.marginS model: filteredModel visible: !filePickerPanel.viewMode delegate: Rectangle { id: listItem width: listView.width - height: 40 * scaling + height: 40 color: { if (filePickerPanel.currentSelection.includes(model.filePath)) return Color.mSecondary @@ -712,7 +712,7 @@ Popup { return Color.mTertiary return Color.transparent } - radius: Style.radiusS * scaling + radius: Style.radiusS Behavior on color { ColorAnimation { duration: Style.animationFast @@ -721,20 +721,20 @@ Popup { RowLayout { anchors.fill: parent - anchors.leftMargin: Style.marginM * scaling - anchors.rightMargin: Style.marginM * scaling - spacing: Style.marginM * scaling + anchors.leftMargin: Style.marginM + anchors.rightMargin: Style.marginM + spacing: Style.marginM NIcon { icon: model.fileIsDir ? "filepicker-folder" : root.getFileIcon(model.fileName) - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL color: model.fileIsDir ? (filePickerPanel.currentSelection.includes(model.filePath) ? Color.mOnSecondary : Color.mPrimary) : Color.mOnSurfaceVariant } NText { text: model.fileName color: filePickerPanel.currentSelection.includes(model.filePath) ? Color.mOnSecondary : Color.mOnSurface - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: filePickerPanel.currentSelection.includes(model.filePath) ? Style.fontWeightBold : Style.fontWeightRegular Layout.fillWidth: true elide: Text.ElideRight @@ -743,7 +743,7 @@ Popup { NText { text: model.fileIsDir ? "" : root.formatFileSize(model.fileSize) color: filePickerPanel.currentSelection.includes(model.filePath) ? Color.mOnSecondary : Color.mOnSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS visible: !model.fileIsDir Layout.preferredWidth: implicitWidth } @@ -795,7 +795,7 @@ Popup { // Footer RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NText { text: { @@ -809,7 +809,7 @@ Popup { } } color: filePickerPanel.searchText.length > 0 ? Color.mPrimary : Color.mOnSurfaceVariant - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS Layout.fillWidth: true } diff --git a/Widgets/NHeader.qml b/Widgets/NHeader.qml index dfbcfd54..08d58e01 100644 --- a/Widgets/NHeader.qml +++ b/Widgets/NHeader.qml @@ -8,13 +8,13 @@ ColumnLayout { property string label: "" property string description: "" - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true - Layout.bottomMargin: Style.marginM * scaling + Layout.bottomMargin: Style.marginM NText { text: root.label - pointSize: Style.fontSizeXL * scaling + pointSize: Style.fontSizeXL font.weight: Style.fontWeightBold color: Color.mSecondary visible: root.label !== "" @@ -22,7 +22,7 @@ ColumnLayout { NText { text: root.description - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM color: Color.mOnSurfaceVariant wrapMode: Text.WordWrap Layout.fillWidth: true diff --git a/Widgets/NIcon.qml b/Widgets/NIcon.qml index adca75f6..87e63c1f 100644 --- a/Widgets/NIcon.qml +++ b/Widgets/NIcon.qml @@ -7,7 +7,8 @@ Text { id: root property string icon: Icons.defaultIcon - property real pointSize: Style.fontSizeL * scaling + property real pointSize: Style.fontSizeL + property bool applyUiScale: true visible: (icon !== undefined) && (icon !== "") text: { @@ -22,7 +23,7 @@ Text { return Icons.get(icon) } font.family: Icons.fontFamily - font.pointSize: root.pointSize + font.pointSize: applyUiScale ? root.pointSize * Style.uiScaleRatio : root.pointSize color: Color.mOnSurface verticalAlignment: Text.AlignVCenter } diff --git a/Widgets/NIconButton.qml b/Widgets/NIconButton.qml index e2d0d0fa..4a61c1df 100644 --- a/Widgets/NIconButton.qml +++ b/Widgets/NIconButton.qml @@ -8,14 +8,15 @@ Rectangle { id: root property real baseSize: Style.baseWidgetSize + property bool applyUiScale: true property string icon property string tooltipText property string tooltipDirection: "auto" + property string density: "" property bool enabled: true property bool allowClickWhenDisabled: false property bool hovering: false - property bool compact: false property color colorBg: Color.mSurfaceVariant property color colorFg: Color.mPrimary @@ -30,14 +31,14 @@ Rectangle { signal rightClicked signal middleClicked - implicitWidth: Math.round(baseSize * scaling) - implicitHeight: Math.round(baseSize * scaling) + implicitWidth: applyUiScale ? Math.round(baseSize * Style.uiScaleRatio) : Math.round(baseSize) + implicitHeight: applyUiScale ? Math.round(baseSize * Style.uiScaleRatio) : Math.round(baseSize) opacity: root.enabled ? Style.opacityFull : Style.opacityMedium color: root.enabled && root.hovering ? colorBgHover : colorBg radius: width * 0.5 border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on color { ColorAnimation { @@ -48,7 +49,15 @@ Rectangle { NIcon { icon: root.icon - pointSize: Math.max(1, root.compact ? root.width * 0.65 : root.width * 0.48) + pointSize: { + switch (root.density) { + case "compact": + return Math.max(1, root.width * 0.65) + default: + return Math.max(1, root.width * 0.48) + } + } + applyUiScale: root.applyUiScale color: root.enabled && root.hovering ? colorFgHover : colorFg // Center horizontally x: (root.width - width) / 2 diff --git a/Widgets/NIconButtonHot.qml b/Widgets/NIconButtonHot.qml new file mode 100644 index 00000000..18df3bac --- /dev/null +++ b/Widgets/NIconButtonHot.qml @@ -0,0 +1,174 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Effects +import qs.Commons +import qs.Services + +Rectangle { + id: root + + // Public properties + property real baseSize: Style.baseWidgetSize + property bool applyUiScale: true + property string icon: "" + property string tooltipText: "" + property string tooltipDirection: "auto" + property string density: "" + property bool enabled: true + property bool allowClickWhenDisabled: false + property bool hot: false + + // Internal properties + property bool hovering: false + property bool pressed: false + + // Color properties + property color colorBg: Color.mSurfaceVariant + property color colorFg: Color.mPrimary + property color colorBgHover: Color.mTertiary + property color colorFgHover: Color.mOnTertiary + property color colorBorder: Color.mOutline + property color colorBorderHover: Color.mOutline + + // Hot state colors + property color colorBgHot: Color.mPrimary + property color colorFgHot: Color.mOnPrimary + + // Signals + signal entered + signal exited + signal clicked + signal rightClicked + signal middleClicked + + // Dimensions + implicitWidth: applyUiScale ? Math.round(baseSize * Style.uiScaleRatio) : Math.round(baseSize) + implicitHeight: applyUiScale ? Math.round(baseSize * Style.uiScaleRatio) : Math.round(baseSize) + + // Appearance + opacity: root.enabled ? Style.opacityFull : Style.opacityMedium + color: { + if (pressed) { + return colorBgHover + } + if (hot) { + return colorBgHot + } + if (root.enabled && root.hovering) { + return colorBgHover + } + return colorBg + } + radius: width * 0.5 + border.color: root.enabled && root.hovering ? colorBorderHover : colorBorder + border.width: Math.max(1, Style.borderS) + + Behavior on color { + ColorAnimation { + duration: Style.animationNormal + easing.type: Easing.InOutQuad + } + } + + Behavior on scale { + NumberAnimation { + duration: Style.animationFast + easing.type: Easing.OutCubic + } + } + + // Icon + NIcon { + icon: root.icon + pointSize: Math.max(1, Math.round(root.width * 0.48)) + applyUiScale: root.applyUiScale + color: { + if (pressed) { + return colorFgHover + } + if (hot) { + return colorFgHot + } + if (root.enabled && root.hovering) { + return colorFgHover + } + return colorFg + } + // Center horizontally + x: (root.width - width) / 2 + // Center vertically accounting for font metrics + y: (root.height - height) / 2 + (height - contentHeight) / 2 + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + easing.type: Easing.InOutQuad + } + } + } + + MouseArea { + // Always enabled to allow hover/tooltip even when the button is disabled + enabled: true + anchors.fill: parent + cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + hoverEnabled: true + + onEntered: { + hovering = root.enabled ? true : false + if (tooltipText) { + TooltipService.show(Screen, parent, tooltipText, tooltipDirection) + } + root.entered() + } + + onExited: { + hovering = false + if (tooltipText) { + TooltipService.hide() + } + root.exited() + } + + onPressed: function (mouse) { + if (root.enabled) { + root.pressed = true + root.scale = 0.92 + } + if (tooltipText) { + TooltipService.hide() + } + } + + onReleased: function (mouse) { + root.scale = 1.0 + root.pressed = false + + if (!root.enabled && !allowClickWhenDisabled) { + return + } + + // Only trigger actions if released while hovering + if (root.hovering) { + if (mouse.button === Qt.LeftButton) { + root.clicked() + } else if (mouse.button === Qt.RightButton) { + root.rightClicked() + } else if (mouse.button === Qt.MiddleButton) { + root.middleClicked() + } + } + } + + onCanceled: { + root.hovering = false + root.pressed = false + root.scale = 1.0 + if (tooltipText) { + TooltipService.hide() + } + } + } +} diff --git a/Widgets/NIconPicker.qml b/Widgets/NIconPicker.qml index 6a5cc45d..2a4916e9 100644 --- a/Widgets/NIconPicker.qml +++ b/Widgets/NIconPicker.qml @@ -15,18 +15,10 @@ Popup { signal iconSelected(string iconName) - width: { - var w = Math.round(Math.max(screen.width * 0.35, 900) * scaling) - w = Math.min(w, screen.width - Style.marginL * 2) - return w - } - height: { - var h = Math.round(Math.max(screen.height * 0.65, 700) * scaling) - h = Math.min(h, screen.height - Style.barHeight * scaling - Style.marginL * 2) - return h - } + width: 900 * Style.uiScaleRatio + height: 700 * Style.uiScaleRatio anchors.centerIn: Overlay.overlay - padding: Style.marginXL * scaling + padding: Style.marginXL property string query: "" property var allIcons: Object.keys(Icons.icons) @@ -38,7 +30,7 @@ Popup { } readonly property int columns: 6 readonly property int cellW: Math.floor(grid.width / columns) - readonly property int cellH: Math.round(cellW * 0.7 + 36 * scaling) + readonly property int cellH: Math.round(cellW * 0.7 + 36) onOpened: { selectedIcon = initialIcon @@ -53,21 +45,21 @@ Popup { background: Rectangle { color: Color.mSurface - radius: Style.radiusL * scaling + radius: Style.radiusL border.color: Color.mPrimary - border.width: Style.borderM * scaling + border.width: Style.borderM } ColumnLayout { anchors.fill: parent - spacing: Style.marginM * scaling + spacing: Style.marginM // Title row RowLayout { Layout.fillWidth: true NText { text: I18n.tr("widgets.icon-picker.title") - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: Color.mPrimary Layout.fillWidth: true @@ -84,7 +76,7 @@ Popup { RowLayout { Layout.fillWidth: true - spacing: Style.marginS * scaling + spacing: Style.marginS NTextInput { id: searchInput Layout.fillWidth: true @@ -100,7 +92,7 @@ Popup { id: grid Layout.fillWidth: true Layout.fillHeight: true - Layout.margins: Style.marginM * scaling + Layout.margins: Style.marginM cellWidth: root.cellW cellHeight: root.cellH model: root.filteredIcons @@ -109,11 +101,11 @@ Popup { delegate: Rectangle { width: grid.cellWidth height: grid.cellHeight - radius: Style.radiusS * scaling + radius: Style.radiusS color: (root.selectedIcon === modelData) ? Qt.alpha(Color.mPrimary, 0.15) : Color.transparent border.color: (root.selectedIcon === modelData) ? Color.mPrimary : Qt.rgba(0, 0, 0, 0) - border.width: (root.selectedIcon === modelData) ? Style.borderS * scaling : 0 + border.width: (root.selectedIcon === modelData) ? Style.borderS : 0 MouseArea { anchors.fill: parent @@ -127,27 +119,27 @@ Popup { ColumnLayout { anchors.fill: parent - anchors.margins: Style.marginS * scaling - spacing: Style.marginS * scaling + anchors.margins: Style.marginS + spacing: Style.marginS Item { Layout.fillHeight: true - Layout.preferredHeight: 4 * scaling + Layout.preferredHeight: 4 } NIcon { Layout.alignment: Qt.AlignHCenter icon: modelData - pointSize: 42 * scaling + pointSize: 42 } NText { Layout.alignment: Qt.AlignHCenter Layout.fillWidth: true - Layout.topMargin: Style.marginXS * scaling + Layout.topMargin: Style.marginXS elide: Text.ElideRight wrapMode: Text.NoWrap maximumLineCount: 1 horizontalAlignment: Text.AlignHCenter color: Color.mOnSurfaceVariant - pointSize: Style.fontSizeXS * scaling + pointSize: Style.fontSizeXS text: modelData } Item { @@ -159,7 +151,7 @@ Popup { RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM Item { Layout.fillWidth: true } diff --git a/Widgets/NImageCircled.qml b/Widgets/NImageCircled.qml index eb0ee9bd..55ef7568 100644 --- a/Widgets/NImageCircled.qml +++ b/Widgets/NImageCircled.qml @@ -12,11 +12,11 @@ Rectangle { property color borderColor: Color.transparent property real borderWidth: 0 property string fallbackIcon: "" - property real fallbackIconSize: Style.fontSizeXXL * scaling + property real fallbackIconSize: Style.fontSizeXXL color: Color.transparent radius: parent.width * 0.5 - anchors.margins: Style.marginXXS * scaling + anchors.margins: Style.marginXXS Rectangle { color: Color.transparent diff --git a/Widgets/NImageRounded.qml b/Widgets/NImageRounded.qml index ff55a571..32987e28 100644 --- a/Widgets/NImageRounded.qml +++ b/Widgets/NImageRounded.qml @@ -13,7 +13,7 @@ Rectangle { property real borderWidth: 0 property real imageRadius: width * 0.5 property string fallbackIcon: "" - property real fallbackIconSize: Style.fontSizeXXL * scaling + property real fallbackIconSize: Style.fontSizeXXL property real scaledRadius: imageRadius * Settings.data.general.radiusRatio @@ -21,7 +21,7 @@ Rectangle { color: Color.transparent radius: scaledRadius - anchors.margins: Style.marginXXS * scaling + anchors.margins: Style.marginXXS Rectangle { color: Color.transparent diff --git a/Widgets/NInputAction.qml b/Widgets/NInputAction.qml index d689d304..a1e683da 100644 --- a/Widgets/NInputAction.qml +++ b/Widgets/NInputAction.qml @@ -22,8 +22,7 @@ RowLayout { signal actionClicked // Internal properties - property real scaling: 1.0 - spacing: Style.marginM * scaling + spacing: Style.marginM NTextInput { id: textInput diff --git a/Widgets/NLabel.qml b/Widgets/NLabel.qml index 8348fd0c..f1a42440 100644 --- a/Widgets/NLabel.qml +++ b/Widgets/NLabel.qml @@ -10,12 +10,12 @@ ColumnLayout { property color labelColor: Color.mOnSurface property color descriptionColor: Color.mOnSurfaceVariant - spacing: Style.marginXXS * scaling + spacing: Style.marginXXS Layout.fillWidth: true NText { text: label - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL font.weight: Style.fontWeightBold color: labelColor visible: label !== "" @@ -24,7 +24,7 @@ ColumnLayout { NText { text: description - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: descriptionColor wrapMode: Text.WordWrap visible: description !== "" diff --git a/Widgets/NListView.qml b/Widgets/NListView.qml index 6731d7ce..115bac49 100644 --- a/Widgets/NListView.qml +++ b/Widgets/NListView.qml @@ -10,8 +10,8 @@ Item { property color handleHoverColor: handleColor property color handlePressedColor: handleColor property color trackColor: Color.transparent - property real handleWidth: 6 * scaling - property real handleRadius: Style.radiusM * scaling + property real handleWidth: 6 + property real handleRadius: Style.radiusM property int verticalPolicy: ScrollBar.AsNeeded property int horizontalPolicy: ScrollBar.AsNeeded diff --git a/Widgets/NPanel.qml b/Widgets/NPanel.qml index 9c7bf2db..5651d8af 100644 --- a/Widgets/NPanel.qml +++ b/Widgets/NPanel.qml @@ -8,7 +8,6 @@ Loader { id: root property ShellScreen screen - property real scaling: 1.0 property Component panelContent: null property real preferredWidth: 700 @@ -27,8 +26,6 @@ Loader { property bool panelAnchorLeft: false property bool panelAnchorRight: false - property bool isMasked: false - // Properties to support positioning relative to the opener (button) property bool useButtonPosition: false property point buttonPosition: Qt.point(0, 0) @@ -39,10 +36,8 @@ Loader { property bool backgroundClickEnabled: true // Animation properties - readonly property real originalScale: 0.7 - readonly property real originalOpacity: 0.0 + readonly property real originalScale: 0.0 property real scaleValue: originalScale - property real opacityValue: originalOpacity property real dimmingOpacity: 0 signal opened @@ -100,7 +95,6 @@ Loader { function close() { dimmingOpacity = 0 scaleValue = originalScale - opacityValue = originalOpacity root.closed() active = false useButtonPosition = false @@ -131,58 +125,40 @@ Loader { // ----------------------------------------- sourceComponent: Component { + // PanelWindow has its own screen property inherited of QsWindow PanelWindow { id: panelWindow - // PanelWindow has its own screen property inherited of QsWindow - property real scaling: ScalingService.getScreenScale(screen) - readonly property string barPosition: Settings.data.bar.position readonly property bool isVertical: barPosition === "left" || barPosition === "right" readonly property bool barIsVisible: (screen !== null) && (Settings.data.bar.monitors.includes(screen.name) || (Settings.data.bar.monitors.length === 0)) - readonly property real verticalBarWidth: Math.round(Style.barHeight * scaling) + readonly property real verticalBarWidth: Style.barHeight Component.onCompleted: { - Logger.log("NPanel", "Opened", root.objectName) + Logger.log("NPanel", "Opened", root.objectName, "on", screen.name) dimmingOpacity = Style.opacityHeavy } - Connections { - target: ScalingService - function onScaleChanged(screenName, scale) { - if ((screen !== null) && (screenName === screen.name)) { - root.scaling = scaling = scale - } - } - } - Connections { target: panelWindow function onScreenChanged() { root.screen = screen - root.scaling = scaling = ScalingService.getScreenScale(screen) - - // It's mandatory to force refresh the subloader to ensure the scaling is properly dispatched - panelContentLoader.active = false - panelContentLoader.active = true // If called from IPC always reposition if screen is updated if (buttonName) { setPosition() } - // Logger.log("NPanel", "OnScreenChanged", root.screen.name) + Logger.log("NPanel", "OnScreenChanged", root.screen.name) } } visible: true - color: Settings.data.general.dimDesktop && !root.isMasked ? Qt.alpha(Color.mShadow, dimmingOpacity) : Color.transparent + color: Settings.data.general.dimDesktop ? Qt.alpha(Color.mShadow, dimmingOpacity) : Color.transparent WlrLayershell.exclusionMode: ExclusionMode.Ignore WlrLayershell.namespace: "noctalia-panel" WlrLayershell.keyboardFocus: root.panelKeyboardFocus ? WlrKeyboardFocus.OnDemand : WlrKeyboardFocus.None - mask: root.isMasked ? maskRegion : null - Region { id: maskRegion } @@ -217,9 +193,9 @@ Loader { Rectangle { id: panelBackground color: panelBackgroundColor - radius: Style.radiusL * scaling + radius: Style.radiusL border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // Dragging support property bool draggable: root.draggable property bool isDragged: false @@ -228,9 +204,9 @@ Loader { width: { var w if (preferredWidthRatio !== undefined) { - w = Math.round(Math.max(screen?.width * preferredWidthRatio, preferredWidth) * scaling) + w = Math.round(Math.max(screen?.width * preferredWidthRatio, preferredWidth)) } else { - w = preferredWidth * scaling + w = preferredWidth } // Clamp width so it is never bigger than the screen return Math.min(w, screen?.width - Style.marginL * 2) @@ -238,17 +214,16 @@ Loader { height: { var h if (preferredHeightRatio !== undefined) { - h = Math.round(Math.max(screen?.height * preferredHeightRatio, preferredHeight) * scaling) + h = Math.round(Math.max(screen?.height * preferredHeightRatio, preferredHeight)) } else { - h = preferredHeight * scaling + h = preferredHeight } // Clamp width so it is never bigger than the screen - return Math.min(h, screen?.height - Style.barHeight * scaling - Style.marginL * 2) + return Math.min(h, screen?.height - Style.barHeight - Style.marginL * 2) } scale: root.scaleValue - opacity: root.isMasked ? 0 : root.opacityValue x: isDragged ? manualX : calculatedX y: isDragged ? manualY : calculatedY @@ -261,9 +236,9 @@ Loader { } switch (barPosition) { case "top": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0) + return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0) default: - return Style.marginS * scaling + return Style.marginS } } @@ -273,9 +248,9 @@ Loader { } switch (barPosition) { case "bottom": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL * scaling : 0) + return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL : 0) default: - return Style.marginS * scaling + return Style.marginS } } @@ -285,9 +260,9 @@ Loader { } switch (barPosition) { case "left": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0) + return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0) default: - return Style.marginS * scaling + return Style.marginS } } @@ -297,9 +272,9 @@ Loader { } switch (barPosition) { case "right": - return (Style.barHeight + Style.marginS) * scaling + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL * scaling : 0) + return (Style.barHeight + Style.marginS) + (Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0) default: - return Style.marginS * scaling + return Style.marginS } } @@ -388,7 +363,6 @@ Loader { // Animate in when component is completed Component.onCompleted: { root.scaleValue = 1.0 - root.opacityValue = 1.0 } // Reset drag position when panel closes @@ -454,14 +428,14 @@ Loader { var ny = dragStartY + translation.y // Calculate gaps so we never overlap the bar on any side - var baseGap = Style.marginS * scaling - var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL * scaling : 0 - var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL * scaling : 0 + var baseGap = Style.marginS + var floatExtraH = Settings.data.bar.floating ? Settings.data.bar.marginHorizontal * 2 * Style.marginXL : 0 + var floatExtraV = Settings.data.bar.floating ? Settings.data.bar.marginVertical * 2 * Style.marginXL : 0 - var insetLeft = baseGap + ((barIsVisible && barPosition === "left") ? (Style.barHeight * scaling + floatExtraH) : 0) - var insetRight = baseGap + ((barIsVisible && barPosition === "right") ? (Style.barHeight * scaling + floatExtraH) : 0) - var insetTop = baseGap + ((barIsVisible && barPosition === "top") ? (Style.barHeight * scaling + floatExtraV) : 0) - var insetBottom = baseGap + ((barIsVisible && barPosition === "bottom") ? (Style.barHeight * scaling + floatExtraV) : 0) + var insetLeft = baseGap + ((barIsVisible && barPosition === "left") ? (Style.barHeight + floatExtraH) : 0) + var insetRight = baseGap + ((barIsVisible && barPosition === "right") ? (Style.barHeight + floatExtraH) : 0) + var insetTop = baseGap + ((barIsVisible && barPosition === "top") ? (Style.barHeight + floatExtraV) : 0) + var insetBottom = baseGap + ((barIsVisible && barPosition === "bottom") ? (Style.barHeight + floatExtraV) : 0) // Clamp within screen bounds accounting for insets var maxX = panelWindow.width - panelBackground.width - insetRight @@ -480,7 +454,7 @@ Loader { anchors.margins: 0 color: Color.transparent border.color: Color.mPrimary - border.width: Math.max(2, Style.borderL * scaling) + border.width: Math.max(2, Style.borderL) radius: parent.radius visible: panelBackground.isDragged && dragHandler.active opacity: 0.8 @@ -492,7 +466,7 @@ Loader { anchors.margins: 0 color: Color.transparent border.color: Color.mPrimary - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) radius: parent.radius opacity: 0.3 } diff --git a/Widgets/NQuickSetting.qml b/Widgets/NQuickSetting.qml deleted file mode 100644 index 7b559019..00000000 --- a/Widgets/NQuickSetting.qml +++ /dev/null @@ -1,326 +0,0 @@ -import QtQuick -import QtQuick.Controls -import QtQuick.Layouts -import QtQuick.Effects -import qs.Commons -import qs.Services - -Rectangle { - id: root - - // Public properties - property string text: "" - property string icon: "" - property string tooltipText: "" - property bool enabled: true - property bool hot: false - property string style: "modern" // "modern", "classic", or "compact" - - // Styling properties - property real fontSize: (style === "classic") ? Style.fontSizeXS * scaling : Style.fontSizeS * scaling - property int fontWeight: Style.fontWeightMedium - property real iconSize: Style.fontSizeL * scaling - property real cornerRadius: Style.radiusM * scaling - - // Internal properties - property bool hovered: false - property bool pressed: false - - // Colors - Style-dependent colors - property color backgroundColor: { - if (pressed) { - return Color.mTertiary - } - if (hot) { - return Color.mPrimary - } - if (style === "classic") - return Color.mSurfaceVariant - if (style === "compact") - return Color.mSurface - return Color.mSurface - } - property color textColor: { - if (pressed) { - return Color.mOnTertiary - } - if (hot) { - return Color.mOnPrimary - } - return Color.mOnSurface - } - property color iconColor: { - if (pressed) { - return Color.mOnTertiary - } - if (hot) { - return Color.mOnPrimary - } - if (style !== "compact") - return Color.mPrimary - return Color.mOnSurface - } - property color borderColor: Color.mOutline - property color hoverColor: Color.mTertiary - property color hoverTextColor: Color.mOnTertiary - property color hoverIconColor: Color.mOnTertiary - - // Signals - signal clicked - signal rightClicked - signal middleClicked - - // Dimensions - Style-dependent sizing - implicitWidth: { - if (style === "classic") { - return Style.baseWidgetSize * scaling - } - if (style === "compact") { - return Style.baseWidgetSize * 0.8 * scaling - } - return Math.max(120 * scaling, contentRow.implicitWidth + (Style.marginL * scaling)) - } - implicitHeight: { - if (style === "classic") { - return Style.baseWidgetSize * scaling - } - if (style === "compact") { - return Style.baseWidgetSize * 0.8 * scaling - } - return Math.max(48 * scaling, contentRow.implicitHeight + (Style.marginL * scaling)) - } - - // Appearance - Style-dependent styling - radius: { - if (style === "classic") - return width * 0.5 - if (style === "compact") - return Style.radiusS * scaling // Smaller radius for compact - return cornerRadius - } - color: { - if (!enabled) - return Qt.lighter(Color.mSurface, 1.1) - if (hovered) - return hoverColor - return backgroundColor - } - - border.width: { - if (style === "classic") - return Math.max(1, Style.borderS * scaling) - if (style === "compact") - return 0 - return 0 - } - border.color: { - if (style === "classic") - return borderColor - return "transparent" - } - - opacity: enabled ? (style === "classic" ? Style.opacityFull : 1.0) : (style === "classic" ? Style.opacityMedium : 0.6) - - Behavior on color { - ColorAnimation { - duration: Style.animationFast - easing.type: style === "classic" ? Easing.InOutQuad : Easing.OutCubic - } - } - - Behavior on border.color { - ColorAnimation { - duration: Style.animationFast - easing.type: style === "classic" ? Easing.InOutQuad : Easing.OutCubic - } - } - - Behavior on scale { - NumberAnimation { - duration: Style.animationFast - easing.type: Easing.OutCubic - } - } - - // Modern style - icon above text - ColumnLayout { - id: contentRow - anchors.centerIn: parent - spacing: Style.marginXXS * scaling - visible: root.style !== "classic" && root.style !== "compact" - - // Icon - NIcon { - Layout.alignment: Qt.AlignHCenter - visible: root.icon !== "" - icon: root.icon - pointSize: root.iconSize - color: { - if (!root.enabled) - return Color.mOnSurfaceVariant - if (root.hovered) - return root.hoverIconColor - return root.iconColor - } - - Behavior on color { - ColorAnimation { - duration: Style.animationFast - easing.type: Easing.OutCubic - } - } - } - - // Modern - Text content - NText { - Layout.alignment: Qt.AlignHCenter - visible: root.text !== "" - text: root.text - pointSize: root.fontSize - font.weight: root.fontWeight - color: { - if (!root.enabled) - return Color.mOnSurfaceVariant - if (root.hovered) - return root.hoverTextColor - return root.textColor - } - elide: Text.ElideRight - - Behavior on color { - ColorAnimation { - duration: Style.animationFast - easing.type: Easing.OutCubic - } - } - } - } - - // Compact style - icon only, small square button - NIcon { - id: compactIcon - anchors.centerIn: parent - visible: root.style === "compact" && root.icon !== "" - icon: root.icon - pointSize: Style.fontSizeM * scaling // Smaller icon for compact - color: { - if (!root.enabled) - return Color.mOnSurfaceVariant - if (root.hovered) - return root.hoverIconColor - return root.iconColor - } - - Behavior on color { - ColorAnimation { - duration: Style.animationFast - easing.type: Easing.OutCubic - } - } - } - - // Classic style - EXACTLY like NIconButton (icon + text) - RowLayout { - anchors.centerIn: parent - visible: root.style === "classic" - spacing: Style.marginXS * scaling - - NIcon { - visible: root.icon !== "" - icon: root.icon - pointSize: Style.fontSizeM * scaling - color: { - if (!root.enabled) - return Color.mOnSurfaceVariant - if (root.hovered) - return root.hoverIconColor - return root.iconColor - } - - Behavior on color { - ColorAnimation { - duration: Style.animationFast - easing.type: Easing.OutCubic - } - } - } - - // Classic - Text content - NText { - visible: root.text !== "" - text: root.text - pointSize: root.fontSize - font.weight: root.fontWeight - color: { - if (!root.enabled) - return Color.mOnSurfaceVariant - if (root.hovered) - return root.hoverTextColor - return root.textColor - } - - Behavior on color { - ColorAnimation { - duration: Style.animationFast - easing.type: Easing.OutCubic - } - } - } - } - - MouseArea { - id: mouseArea - anchors.fill: parent - enabled: root.enabled - hoverEnabled: true - acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton - cursorShape: root.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor - - onEntered: { - root.hovered = true - if (tooltipText) { - TooltipService.show(Screen, root, root.tooltipText) - } - } - - onExited: { - root.hovered = false - if (tooltipText) { - TooltipService.hide() - } - } - - onPressed: mouse => { - root.pressed = true - root.scale = 0.92 - if (tooltipText) { - TooltipService.hide() - } - } - - onReleased: mouse => { - root.scale = 1.0 - root.pressed = false - - // Only trigger actions if released while hovering - if (root.hovered) { - if (mouse.button === Qt.LeftButton) { - root.clicked() - } else if (mouse.button === Qt.RightButton) { - root.rightClicked() - } else if (mouse.button === Qt.MiddleButton) { - root.middleClicked() - } - } - } - - onCanceled: { - root.hovered = false - root.pressed = false - root.scale = 1.0 - if (tooltipText) { - TooltipService.hide() - } - } - } -} diff --git a/Widgets/NRadioButton.qml b/Widgets/NRadioButton.qml index d04ea777..59ff2205 100644 --- a/Widgets/NRadioButton.qml +++ b/Widgets/NRadioButton.qml @@ -10,12 +10,12 @@ RadioButton { indicator: Rectangle { id: outerCircle - implicitWidth: Style.baseWidgetSize * 0.625 * scaling - implicitHeight: Style.baseWidgetSize * 0.625 * scaling + implicitWidth: Style.baseWidgetSize * 0.625 + implicitHeight: Style.baseWidgetSize * 0.625 radius: width * 0.5 color: Color.transparent border.color: root.checked ? Color.mPrimary : Color.mOnSurface - border.width: Math.max(1, Style.borderM * scaling) + border.width: Math.max(1, Style.borderM) anchors.verticalCenter: parent.verticalCenter Rectangle { @@ -41,10 +41,10 @@ RadioButton { contentItem: NText { text: root.text - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM anchors.verticalCenter: parent.verticalCenter anchors.left: outerCircle.right anchors.right: parent.right - anchors.leftMargin: Style.marginS * scaling + anchors.leftMargin: Style.marginS } } diff --git a/Widgets/NReorderCheckboxes.qml b/Widgets/NReorderCheckboxes.qml new file mode 100644 index 00000000..9a8c1abc --- /dev/null +++ b/Widgets/NReorderCheckboxes.qml @@ -0,0 +1,299 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.Commons + +Item { + id: root + + // Public API + property var model: [] + property color activeColor: Color.mPrimary + property color activeOnColor: Color.mOnPrimary + property color dragHandleColor: Color.mOutline + property int baseSize: Style.baseWidgetSize * 0.7 + property int spacing: Style.marginM + + signal itemToggled(int index, bool enabled) + signal itemsReordered(int fromIndex, int toIndex) + signal dragPotentialStarted + signal dragPotentialEnded + + implicitHeight: listView.contentHeight + + function toggleItem(index) { + if (index < 0 || index >= root.model.length) + return + + var item = root.model[index] + if (item.required) + return + + // Create a new array to trigger binding update + var newModel = root.model.slice() + newModel[index] = Object.assign({}, item, { + "enabled": !item.enabled + }) + root.model = newModel + + root.itemToggled(index, newModel[index].enabled) + } + + function moveItem(fromIndex, toIndex) { + if (fromIndex === toIndex) + return + if (fromIndex < 0 || fromIndex >= root.model.length) + return + if (toIndex < 0 || toIndex >= root.model.length) + return + + // Create a new array with item moved + var newModel = root.model.slice() + var item = newModel.splice(fromIndex, 1)[0] + newModel.splice(toIndex, 0, item) + root.model = newModel + + root.itemsReordered(fromIndex, toIndex) + } + + ListView { + id: listView + + anchors.fill: parent + spacing: root.spacing + interactive: false + clip: true + model: root.model + + delegate: Item { + id: delegateItem + + width: listView.width + height: checkboxRow.height + + required property int index + required property var modelData + + property string text: modelData.text || "" + property bool enabled: modelData.enabled || false + property bool required: modelData.required || false + property bool dragging: false + property int dragStartY: 0 + property int dragStartIndex: -1 + property int dragTargetIndex: -1 + property int itemSpacing: root.spacing + + RowLayout { + id: checkboxRow + + width: parent.width + spacing: Style.marginS + + // Drag handle + Rectangle { + id: dragHandle + + Layout.preferredWidth: root.baseSize + Layout.preferredHeight: root.baseSize + radius: Style.radiusXS + color: dragHandleMouseArea.containsMouse ? Color.mSurfaceVariant : Color.transparent + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + + ColumnLayout { + anchors.centerIn: parent + spacing: Style.marginS + + Repeater { + model: 3 + Rectangle { + Layout.preferredWidth: root.baseSize * 0.4 + Layout.preferredHeight: 2 + radius: 1 + color: root.dragHandleColor + } + } + } + + MouseArea { + id: dragHandleMouseArea + + anchors.fill: parent + cursorShape: Qt.SizeVerCursor + hoverEnabled: true + preventStealing: false + z: 1000 + + onPressed: mouse => { + delegateItem.dragStartIndex = delegateItem.index + delegateItem.dragTargetIndex = delegateItem.index + delegateItem.dragStartY = delegateItem.y + delegateItem.dragging = true + delegateItem.z = 999 + + // Signal that interaction started (prevents panel close) + preventStealing = true + root.dragPotentialStarted() + } + + onPositionChanged: mouse => { + if (delegateItem.dragging) { + var dy = mouse.y - dragHandle.height / 2 + var newY = delegateItem.y + dy + + // Constrain within bounds + newY = Math.max(0, Math.min(newY, listView.contentHeight - delegateItem.height)) + delegateItem.y = newY + + // Calculate target index (but don't apply yet) + var targetIndex = Math.floor((newY + delegateItem.height / 2) / (delegateItem.height + delegateItem.itemSpacing)) + targetIndex = Math.max(0, Math.min(targetIndex, listView.count - 1)) + + delegateItem.dragTargetIndex = targetIndex + } + } + + onReleased: { + // Always signal end of interaction + preventStealing = false + root.dragPotentialEnded() + + // Apply the model change now that drag is complete + if (delegateItem.dragStartIndex !== -1 && delegateItem.dragTargetIndex !== -1 && delegateItem.dragStartIndex !== delegateItem.dragTargetIndex) { + root.moveItem(delegateItem.dragStartIndex, delegateItem.dragTargetIndex) + } + + delegateItem.dragging = false + delegateItem.dragStartIndex = -1 + delegateItem.dragTargetIndex = -1 + delegateItem.z = 0 + } + + onCanceled: { + // Handle cancel (e.g., ESC key pressed during drag) + preventStealing = false + root.dragPotentialEnded() + + delegateItem.dragging = false + delegateItem.dragStartIndex = -1 + delegateItem.dragTargetIndex = -1 + delegateItem.z = 0 + } + } + } + + // Checkbox + Rectangle { + id: box + + Layout.preferredWidth: root.baseSize + Layout.preferredHeight: root.baseSize + radius: Style.radiusXS + color: delegateItem.enabled ? root.activeColor : Color.mSurface + border.color: delegateItem.required ? root.activeColor : Color.mOutline + border.width: Math.max(1, Style.borderS) + opacity: delegateItem.required ? 0.7 : 1.0 + + Behavior on color { + ColorAnimation { + duration: Style.animationFast + } + } + + Behavior on border.color { + ColorAnimation { + duration: Style.animationFast + } + } + + NIcon { + visible: delegateItem.enabled + anchors.centerIn: parent + anchors.horizontalCenterOffset: -1 + icon: "check" + color: root.activeOnColor + pointSize: Math.max(Style.fontSizeXS, root.baseSize * 0.5) + font.weight: Style.fontWeightBold + } + + MouseArea { + anchors.fill: parent + cursorShape: delegateItem.required ? Qt.ForbiddenCursor : Qt.PointingHandCursor + enabled: !delegateItem.required + + onClicked: { + root.toggleItem(delegateItem.index) + } + } + } + + // Label + NText { + Layout.fillWidth: true + text: delegateItem.text + color: Color.mOnSurface + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight + } + + // Required indicator + NText { + visible: delegateItem.required + text: "(required)" + color: Color.mOnSurfaceVariant + verticalAlignment: Text.AlignVCenter + } + } + + // Position binding for non-dragging state + y: { + if (delegateItem.dragging) { + return delegateItem.y + } + + // Check if any item is being dragged + var draggedIndex = -1 + var targetIndex = -1 + for (var i = 0; i < listView.count; i++) { + var item = listView.itemAtIndex(i) + if (item && item.dragging) { + draggedIndex = item.dragStartIndex + targetIndex = item.dragTargetIndex + break + } + } + + // If an item is being dragged, adjust positions + if (draggedIndex !== -1 && targetIndex !== -1 && draggedIndex !== targetIndex) { + var currentIndex = delegateItem.index + + if (draggedIndex < targetIndex) { + // Dragging down: shift items up between draggedIndex and targetIndex + if (currentIndex > draggedIndex && currentIndex <= targetIndex) { + return (currentIndex - 1) * (delegateItem.height + delegateItem.itemSpacing) + } + } else { + // Dragging up: shift items down between targetIndex and draggedIndex + if (currentIndex >= targetIndex && currentIndex < draggedIndex) { + return (currentIndex + 1) * (delegateItem.height + delegateItem.itemSpacing) + } + } + } + + return delegateItem.index * (delegateItem.height + delegateItem.itemSpacing) + } + + Behavior on y { + enabled: !delegateItem.dragging + NumberAnimation { + duration: Style.animationNormal + easing.type: Easing.OutQuad + } + } + } + } +} diff --git a/Widgets/NScrollView.qml b/Widgets/NScrollView.qml index 63e28819..af5371d9 100644 --- a/Widgets/NScrollView.qml +++ b/Widgets/NScrollView.qml @@ -10,8 +10,8 @@ T.ScrollView { property color handleHoverColor: handleColor property color handlePressedColor: handleColor property color trackColor: Color.transparent - property real handleWidth: 6 * scaling - property real handleRadius: Style.radiusM * scaling + property real handleWidth: 6 + property real handleRadius: Style.radiusM property int verticalPolicy: ScrollBar.AsNeeded property int horizontalPolicy: ScrollBar.AsNeeded property bool preventHorizontalScroll: horizontalPolicy === ScrollBar.AlwaysOff diff --git a/Widgets/NSearchableComboBox.qml b/Widgets/NSearchableComboBox.qml index 3175f126..462d5a6b 100644 --- a/Widgets/NSearchableComboBox.qml +++ b/Widgets/NSearchableComboBox.qml @@ -9,8 +9,8 @@ import "../Helpers/FuzzySort.js" as Fuzzysort RowLayout { id: root - property real minimumWidth: 280 * scaling - property real popupHeight: 180 * scaling + property real minimumWidth: 280 * Style.uiScaleRatio + property real popupHeight: 180 * Style.uiScaleRatio property string label: "" property string description: "" @@ -21,11 +21,11 @@ RowLayout { property string placeholder: "" property string searchPlaceholder: I18n.tr("placeholders.search") - readonly property real preferredHeight: Style.baseWidgetSize * 1.1 * scaling + readonly property real preferredHeight: Style.baseWidgetSize * 1.1 signal selected(string key) - spacing: Style.marginL * scaling + spacing: Style.marginL Layout.fillWidth: true // Filtered model for search results @@ -121,12 +121,12 @@ RowLayout { } background: Rectangle { - implicitWidth: Style.baseWidgetSize * 3.75 * scaling + implicitWidth: Style.baseWidgetSize * 3.75 * Style.uiScaleRatio implicitHeight: preferredHeight color: Color.mSurface border.color: combo.activeFocus ? Color.mSecondary : Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM Behavior on border.color { ColorAnimation { @@ -136,9 +136,9 @@ RowLayout { } contentItem: NText { - leftPadding: Style.marginL * scaling - rightPadding: combo.indicator.width + Style.marginL * scaling - pointSize: Style.fontSizeM * scaling + leftPadding: Style.marginL + rightPadding: combo.indicator.width + Style.marginL + pointSize: Style.fontSizeM verticalAlignment: Text.AlignVCenter elide: Text.ElideRight color: (combo.currentIndex >= 0 && combo.currentIndex < filteredModel.count) ? Color.mOnSurface : Color.mOnSurfaceVariant @@ -146,17 +146,17 @@ RowLayout { } indicator: NIcon { - x: combo.width - width - Style.marginM * scaling + x: combo.width - width - Style.marginM y: combo.topPadding + (combo.availableHeight - height) / 2 icon: "caret-down" - pointSize: Style.fontSizeL * scaling + pointSize: Style.fontSizeL } popup: Popup { y: combo.height width: combo.width - height: root.popupHeight + 60 * scaling - padding: Style.marginM * scaling + height: root.popupHeight + 60 + padding: Style.marginM onOpened: { PanelService.willOpenPopup(root) @@ -167,7 +167,7 @@ RowLayout { } contentItem: ColumnLayout { - spacing: Style.marginS * scaling + spacing: Style.marginS // Search input NTextInput { @@ -176,7 +176,7 @@ RowLayout { placeholderText: root.searchPlaceholder text: root.searchText onTextChanged: root.searchText = text - fontSize: Style.fontSizeS * scaling + fontSize: Style.fontSizeS } NListView { @@ -206,8 +206,8 @@ RowLayout { contentItem: NText { text: name - pointSize: Style.fontSizeM * scaling - color: highlighted ? Color.mSurface : Color.mOnSurface + pointSize: Style.fontSizeM + color: highlighted ? Color.mOnTertiary : Color.mOnSurface verticalAlignment: Text.AlignVCenter elide: Text.ElideRight Behavior on color { @@ -218,9 +218,9 @@ RowLayout { } background: Rectangle { - width: listView.width * scaling + width: listView.width color: highlighted ? Color.mTertiary : Color.transparent - radius: Style.radiusS * scaling + radius: Style.radiusS Behavior on color { ColorAnimation { duration: Style.animationFast @@ -234,8 +234,8 @@ RowLayout { background: Rectangle { color: Color.mSurfaceVariant border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) - radius: Style.radiusM * scaling + border.width: Math.max(1, Style.borderS) + radius: Style.radiusM } } diff --git a/Widgets/NSlider.qml b/Widgets/NSlider.qml index 77393099..e91ecdb8 100644 --- a/Widgets/NSlider.qml +++ b/Widgets/NSlider.qml @@ -11,9 +11,9 @@ Slider { property bool snapAlways: true property real heightRatio: 0.7 - readonly property real knobDiameter: Math.round((Style.baseWidgetSize * heightRatio * scaling) / 2) * 2 - readonly property real trackHeight: Math.round((knobDiameter * 0.4) / 2) * 2 - readonly property real cutoutExtra: Math.round((Style.baseWidgetSize * 0.1 * scaling) / 2) * 2 + readonly property real knobDiameter: Math.round((Style.baseWidgetSize * heightRatio * Style.uiScaleRatio) / 2) * 2 + readonly property real trackHeight: Math.round((knobDiameter * 0.4 * Style.uiScaleRatio) / 2) * 2 + readonly property real cutoutExtra: Math.round((Style.baseWidgetSize * 0.1 * Style.uiScaleRatio) / 2) * 2 padding: cutoutExtra / 2 @@ -30,7 +30,7 @@ Slider { radius: height / 2 color: Qt.alpha(Color.mSurface, 0.5) border.color: Qt.alpha(Color.mOutline, 0.5) - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) // A container composite shape that puts a semicircle on the end Item { @@ -116,7 +116,7 @@ Slider { radius: width / 2 color: root.pressed ? Color.mTertiary : Color.mSurface border.color: Color.mPrimary - border.width: Math.max(1, Style.borderL * scaling) + border.width: Math.max(1, Style.borderL) anchors.centerIn: parent Behavior on color { diff --git a/Widgets/NSpinBox.qml b/Widgets/NSpinBox.qml index 8261135c..51310439 100644 --- a/Widgets/NSpinBox.qml +++ b/Widgets/NSpinBox.qml @@ -38,8 +38,8 @@ RowLayout { // Main spinbox container Rectangle { id: spinBoxContainer - implicitWidth: 120 * scaling - implicitHeight: (root.baseSize - 4) * scaling + implicitWidth: 120 + implicitHeight: (root.baseSize - 4) radius: height * 0.5 color: Color.mSurfaceVariant border.color: (root.hovering || decreaseArea.containsMouse || increaseArea.containsMouse) ? Color.mTertiary : Color.mOutline @@ -153,7 +153,7 @@ RowLayout { anchors.leftMargin: parent.width * 0.25 anchors.verticalCenter: parent.verticalCenter icon: "chevron-left" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: decreaseArea.containsMouse ? Color.mOnTertiary : Color.mPrimary } @@ -248,7 +248,7 @@ RowLayout { anchors.rightMargin: parent.width * 0.25 anchors.verticalCenter: parent.verticalCenter icon: "chevron-right" - pointSize: Style.fontSizeS * scaling + pointSize: Style.fontSizeS color: increaseArea.containsMouse ? Color.mOnTertiary : Color.mPrimary } @@ -271,7 +271,7 @@ RowLayout { anchors.left: decreaseButton.right anchors.right: increaseButton.left anchors.verticalCenter: parent.verticalCenter - anchors.margins: 4 * scaling + anchors.margins: 4 height: parent.height color: Color.transparent @@ -283,7 +283,7 @@ RowLayout { NText { text: root.prefix family: Settings.data.ui.fontFixed - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium color: Color.mOnSurface verticalAlignment: Text.AlignVCenter @@ -296,7 +296,7 @@ RowLayout { id: valueInput text: valueInput.focus ? valueInput.text : root.value.toString() font.family: Settings.data.ui.fontFixed - font.pointSize: Style.fontSizeM * scaling + font.pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium color: Color.mOnSurface verticalAlignment: Text.AlignVCenter @@ -342,7 +342,7 @@ RowLayout { NText { text: root.suffix family: Settings.data.ui.fontFixed - pointSize: Style.fontSizeM * scaling + pointSize: Style.fontSizeM font.weight: Style.fontWeightMedium color: Color.mOnSurface verticalAlignment: Text.AlignVCenter diff --git a/Widgets/NText.qml b/Widgets/NText.qml index 9efd199e..4a9060ed 100644 --- a/Widgets/NText.qml +++ b/Widgets/NText.qml @@ -8,9 +8,14 @@ Text { id: root property string family: Settings.data.ui.fontDefault - property real pointSize: Style.fontSizeM * scaling + property real pointSize: Style.fontSizeM + property bool applyUiScale: true property real fontScale: { - return (root.family === Settings.data.ui.fontDefault ? Settings.data.ui.fontDefaultScale : Settings.data.ui.fontFixedScale) + const fontScale = (root.family === Settings.data.ui.fontDefault ? Settings.data.ui.fontDefaultScale : Settings.data.ui.fontFixedScale) + if (applyUiScale) { + return fontScale * Style.uiScaleRatio + } + return fontScale } font.family: root.family diff --git a/Widgets/NTextInput.qml b/Widgets/NTextInput.qml index 7f2ec9d7..adb83cd3 100644 --- a/Widgets/NTextInput.qml +++ b/Widgets/NTextInput.qml @@ -14,7 +14,7 @@ ColumnLayout { property color labelColor: Color.mOnSurface property color descriptionColor: Color.mOnSurfaceVariant property string fontFamily: Settings.data.ui.fontDefault - property real fontSize: Style.fontSizeS * scaling + property real fontSize: Style.fontSizeS property int fontWeight: Style.fontWeightRegular property alias text: input.text @@ -24,7 +24,7 @@ ColumnLayout { signal editingFinished - spacing: Style.marginS * scaling + spacing: Style.marginS NLabel { label: root.label @@ -40,8 +40,8 @@ ColumnLayout { id: frameControl Layout.fillWidth: true - Layout.minimumWidth: 80 * scaling - implicitHeight: Style.baseWidgetSize * 1.1 * scaling + Layout.minimumWidth: 80 * Style.uiScaleRatio + implicitHeight: Style.baseWidgetSize * 1.1 * Style.uiScaleRatio // This is important - makes the control accept focus focusPolicy: Qt.StrongFocus @@ -50,10 +50,10 @@ ColumnLayout { background: Rectangle { id: frame - radius: Style.radiusM * scaling + radius: Style.radiusM color: Color.mSurface border.color: input.activeFocus ? Color.mSecondary : Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on border.color { ColorAnimation { @@ -79,7 +79,7 @@ ColumnLayout { input.forceActiveFocus() var inputPos = mapToItem(inputContainer, mouse.x, mouse.y) if (inputPos.x >= 0 && inputPos.x <= inputContainer.width) { - var textPos = inputPos.x - Style.marginM * scaling + var textPos = inputPos.x - Style.marginM if (textPos >= 0 && textPos <= input.width) { input.cursorPosition = input.positionAt(textPos, input.height / 2) } @@ -105,8 +105,8 @@ ColumnLayout { Item { id: inputContainer anchors.fill: parent - anchors.leftMargin: Style.marginM * scaling - anchors.rightMargin: Style.marginM * scaling + anchors.leftMargin: Style.marginM + anchors.rightMargin: Style.marginM z: 1 TextField { @@ -131,7 +131,7 @@ ColumnLayout { background: null font.family: root.fontFamily - font.pointSize: root.fontSize + font.pointSize: root.fontSize * Style.uiScaleRatio font.weight: root.fontWeight onEditingFinished: root.editingFinished() diff --git a/Widgets/NTextInputButton.qml b/Widgets/NTextInputButton.qml index 5e157c1e..89ec8ffd 100644 --- a/Widgets/NTextInputButton.qml +++ b/Widgets/NTextInputButton.qml @@ -21,7 +21,7 @@ ColumnLayout { signal inputTextChanged(string text) signal inputEditingFinished - spacing: Style.marginS * scaling + spacing: Style.marginS // Label and description NLabel { @@ -34,7 +34,7 @@ ColumnLayout { // Input field with button RowLayout { Layout.fillWidth: true - spacing: Style.marginM * scaling + spacing: Style.marginM NTextInput { id: input diff --git a/Widgets/NToggle.qml b/Widgets/NToggle.qml index 3e464bb8..18259ed6 100644 --- a/Widgets/NToggle.qml +++ b/Widgets/NToggle.qml @@ -11,7 +11,7 @@ RowLayout { property string description: "" property bool checked: false property bool hovering: false - property int baseSize: Math.round(Style.baseWidgetSize * 0.8) + property int baseSize: Math.round(Style.baseWidgetSize * 0.8 * Style.uiScaleRatio) signal toggled(bool checked) signal entered @@ -27,12 +27,12 @@ RowLayout { Rectangle { id: switcher - implicitWidth: Math.round(root.baseSize * .85 * scaling) * 2 - implicitHeight: Math.round(root.baseSize * scaling * .5) * 2 + implicitWidth: Math.round(root.baseSize * .85) * 2 + implicitHeight: Math.round(root.baseSize * .5) * 2 radius: height * 0.5 color: root.checked ? Color.mPrimary : Color.mSurface border.color: Color.mOutline - border.width: Math.max(1, Style.borderS * scaling) + border.width: Math.max(1, Style.borderS) Behavior on color { ColorAnimation { @@ -48,15 +48,15 @@ RowLayout { Rectangle { - implicitWidth: Math.round(root.baseSize * 0.4 * scaling) * 2 - implicitHeight: Math.round(root.baseSize * 0.4 * scaling) * 2 + implicitWidth: Math.round(root.baseSize * 0.4) * 2 + implicitHeight: Math.round(root.baseSize * 0.4) * 2 radius: height * 0.5 color: root.checked ? Color.mOnPrimary : Color.mPrimary border.color: root.checked ? Color.mSurface : Color.mSurface - border.width: Math.max(1, Style.borderM * scaling) + border.width: Math.max(1, Style.borderM) anchors.verticalCenter: parent.verticalCenter anchors.verticalCenterOffset: 0 - x: root.checked ? switcher.width - width - 3 * scaling : 3 * scaling + x: root.checked ? switcher.width - width - 3 : 3 Behavior on x { NumberAnimation { diff --git a/Widgets/NValueSlider.qml b/Widgets/NValueSlider.qml index 3eb6538b..9449d699 100644 --- a/Widgets/NValueSlider.qml +++ b/Widgets/NValueSlider.qml @@ -16,7 +16,7 @@ RowLayout { property bool snapAlways: true property real heightRatio: 0.7 property string text: "" - property real textSize: Style.fontSizeM * scaling + property real textSize: Style.fontSizeM property real customHeight: -1 property real customHeightRatio: -1 @@ -24,7 +24,7 @@ RowLayout { signal moved(real value) signal pressedChanged(bool pressed, real value) - spacing: Style.marginL * scaling + spacing: Style.marginL implicitHeight: root.customHeight > 0 ? root.customHeight : slider.implicitHeight NSlider { @@ -47,7 +47,7 @@ RowLayout { pointSize: root.textSize family: Settings.data.ui.fontFixed Layout.alignment: Qt.AlignVCenter - Layout.preferredWidth: 45 * scaling + Layout.preferredWidth: 45 * Scale.uiScaleRatio horizontalAlignment: Text.AlignRight } }