diff --git a/core/internal/config/embedded/hyprland.conf b/core/internal/config/embedded/hyprland.conf index f44208c9..082c9289 100644 --- a/core/internal/config/embedded/hyprland.conf +++ b/core/internal/config/embedded/hyprland.conf @@ -125,6 +125,10 @@ windowrulev2 = noborder, class:^(kitty)$ windowrulev2 = float, class:^(firefox)$, title:^(Picture-in-Picture)$ windowrulev2 = float, class:^(zoom)$ +# DMS windows floating by default +windowrulev2 = float, class:^(org.quickshell)$, title:^(Settings)$ +windowrulev2 = float, class:^(org.quickshell)$, title:^(File)$ + windowrulev2 = opacity 0.9 0.9, floating:0, focus:0 layerrule = noanim, ^(quickshell)$ diff --git a/core/internal/config/embedded/niri.kdl b/core/internal/config/embedded/niri.kdl index 1faa139a..6ce37b88 100644 --- a/core/internal/config/embedded/niri.kdl +++ b/core/internal/config/embedded/niri.kdl @@ -218,6 +218,18 @@ window-rule { geometry-corner-radius 12 clip-to-geometry true } +// Open dms settings as floating by default +window-rule { + match app-id=r#"org.quickshell$"# + match title="Settings" + open-floating true +} +// dms file browser +window-rule { + match app-id=r#"org.quickshell$"# + match title=r#"File$"# + open-floating true +} binds { // === System & Overview === Mod+D { spawn "niri" "msg" "action" "toggle-overview"; } diff --git a/quickshell/Common/SettingsData.qml b/quickshell/Common/SettingsData.qml index 560509dd..e929f062 100644 --- a/quickshell/Common/SettingsData.qml +++ b/quickshell/Common/SettingsData.qml @@ -1236,7 +1236,6 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr const txt = settingsFile.text() const obj = (txt && txt.trim()) ? JSON.parse(txt) : null Store.parse(root, obj) - Store.migrate(root, obj) } catch (e) { console.warn("SettingsData: Failed to reload settings:", e.message) } diff --git a/quickshell/DMSShell.qml b/quickshell/DMSShell.qml index dc8d5441..e661b28e 100644 --- a/quickshell/DMSShell.qml +++ b/quickshell/DMSShell.qml @@ -508,6 +508,7 @@ Item { hyprKeybindsModalLoader: hyprKeybindsModalLoader dankBarRepeater: dankBarRepeater hyprlandOverviewLoader: hyprlandOverviewLoader + settingsModal: settingsModal } Variants { diff --git a/quickshell/DMSShellIPC.qml b/quickshell/DMSShellIPC.qml index 683591ab..e6755bef 100644 --- a/quickshell/DMSShellIPC.qml +++ b/quickshell/DMSShellIPC.qml @@ -15,6 +15,7 @@ Item { required property var hyprKeybindsModalLoader required property var dankBarRepeater required property var hyprlandOverviewLoader + required property var settingsModal function getFirstBar() { if (!root.dankBarRepeater || root.dankBarRepeater.count === 0) @@ -529,4 +530,37 @@ Item { target: "bar" } + + IpcHandler { + function open(): string { + root.settingsModal.show(); + return "SETTINGS_OPEN_SUCCESS"; + } + + function close(): string { + root.settingsModal.hide(); + return "SETTINGS_CLOSE_SUCCESS"; + } + + function toggle(): string { + root.settingsModal.toggle(); + return "SETTINGS_TOGGLE_SUCCESS"; + } + + target: "settings" + } + + IpcHandler { + function browse(type: string) { + if (type === "wallpaper") { + root.settingsModal.wallpaperBrowser.allowStacking = false; + root.settingsModal.wallpaperBrowser.open(); + } else if (type === "profile") { + root.settingsModal.profileBrowser.allowStacking = false; + root.settingsModal.profileBrowser.open(); + } + } + + target: "file" + } } diff --git a/quickshell/Modals/FileBrowser/FileBrowserModal.qml b/quickshell/Modals/FileBrowser/FileBrowserModal.qml index 6bfa6f7e..d0a9ae49 100644 --- a/quickshell/Modals/FileBrowser/FileBrowserModal.qml +++ b/quickshell/Modals/FileBrowser/FileBrowserModal.qml @@ -3,26 +3,15 @@ import QtCore import QtQuick import QtQuick.Controls import Quickshell -import Quickshell.Hyprland import Quickshell.Io import qs.Common -import qs.Modals.Common import qs.Modals.FileBrowser import qs.Services import qs.Widgets -DankModal { +FloatingWindow { id: fileBrowserModal - layerNamespace: "dms:file-browser" - - HyprlandFocusGrab { - windows: [fileBrowserModal] - active: CompositorService.isHyprland && fileBrowserModal.shouldHaveFocus - } - - keepPopoutsOpen: true - property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation) property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation) property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation) @@ -62,49 +51,61 @@ DankModal { property bool pathInputHasFocus: false property int actualGridColumns: 5 property bool _initialized: false + property bool shouldHaveFocus: visible + property bool allowFocusOverride: false + property bool shouldBeVisible: visible + property bool allowStacking: true signal fileSelected(string path) + signal dialogClosed + + function open() { + visible = true; + } + + function close() { + visible = false; + } function loadSettings() { - const type = browserType || "default" - const settings = CacheData.fileBrowserSettings[type] - const isImageBrowser = ["wallpaper", "profile"].includes(browserType) + const type = browserType || "default"; + const settings = CacheData.fileBrowserSettings[type]; + const isImageBrowser = ["wallpaper", "profile"].includes(browserType); if (settings) { - viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list") - sortBy = settings.sortBy || "name" - sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true - iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1 - showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true + viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list"); + sortBy = settings.sortBy || "name"; + sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true; + iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1; + showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true; } else { - viewMode = isImageBrowser ? "grid" : "list" + viewMode = isImageBrowser ? "grid" : "list"; } } function saveSettings() { if (!_initialized) - return - - const type = browserType || "default" - let settings = CacheData.fileBrowserSettings + return; + const type = browserType || "default"; + let settings = CacheData.fileBrowserSettings; if (!settings[type]) { - settings[type] = {} + settings[type] = {}; } - settings[type].viewMode = viewMode - settings[type].sortBy = sortBy - settings[type].sortAscending = sortAscending - settings[type].iconSizeIndex = iconSizeIndex - settings[type].showSidebar = showSidebar - settings[type].lastPath = currentPath - CacheData.fileBrowserSettings = settings + settings[type].viewMode = viewMode; + settings[type].sortBy = sortBy; + settings[type].sortAscending = sortAscending; + settings[type].iconSizeIndex = iconSizeIndex; + settings[type].showSidebar = showSidebar; + settings[type].lastPath = currentPath; + CacheData.fileBrowserSettings = settings; if (browserType === "wallpaper") { - CacheData.wallpaperLastPath = currentPath + CacheData.wallpaperLastPath = currentPath; } else if (browserType === "profile") { - CacheData.profileLastPath = currentPath + CacheData.profileLastPath = currentPath; } - CacheData.saveCache() + CacheData.saveCache(); } onViewModeChanged: saveSettings() @@ -115,163 +116,155 @@ DankModal { function isImageFile(fileName) { if (!fileName) { - return false + return false; } - const ext = fileName.toLowerCase().split('.').pop() - return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext) + const ext = fileName.toLowerCase().split('.').pop(); + return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext); } function getLastPath() { - const type = browserType || "default" - const settings = CacheData.fileBrowserSettings[type] - const lastPath = settings?.lastPath || "" - return (lastPath && lastPath !== "") ? lastPath : homeDir + const type = browserType || "default"; + const settings = CacheData.fileBrowserSettings[type]; + const lastPath = settings?.lastPath || ""; + return (lastPath && lastPath !== "") ? lastPath : homeDir; } function saveLastPath(path) { - const type = browserType || "default" - let settings = CacheData.fileBrowserSettings + const type = browserType || "default"; + let settings = CacheData.fileBrowserSettings; if (!settings[type]) { - settings[type] = {} + settings[type] = {}; } - settings[type].lastPath = path - CacheData.fileBrowserSettings = settings - CacheData.saveCache() + settings[type].lastPath = path; + CacheData.fileBrowserSettings = settings; + CacheData.saveCache(); if (browserType === "wallpaper") { - CacheData.wallpaperLastPath = path + CacheData.wallpaperLastPath = path; } else if (browserType === "profile") { - CacheData.profileLastPath = path + CacheData.profileLastPath = path; } } function setSelectedFileData(path, name, isDir) { - selectedFilePath = path - selectedFileName = name - selectedFileIsDir = isDir + selectedFilePath = path; + selectedFileName = name; + selectedFileIsDir = isDir; } function navigateUp() { - const path = currentPath + const path = currentPath; if (path === homeDir) - return - - const lastSlash = path.lastIndexOf('/') + return; + const lastSlash = path.lastIndexOf('/'); if (lastSlash > 0) { - const newPath = path.substring(0, lastSlash) + const newPath = path.substring(0, lastSlash); if (newPath.length < homeDir.length) { - currentPath = homeDir - saveLastPath(homeDir) + currentPath = homeDir; + saveLastPath(homeDir); } else { - currentPath = newPath - saveLastPath(newPath) + currentPath = newPath; + saveLastPath(newPath); } } } function navigateTo(path) { - currentPath = path - saveLastPath(path) - selectedIndex = -1 - backButtonFocused = false + currentPath = path; + saveLastPath(path); + selectedIndex = -1; + backButtonFocused = false; } function keyboardFileSelection(index) { if (index >= 0) { - keyboardSelectionTimer.targetIndex = index - keyboardSelectionTimer.start() + keyboardSelectionTimer.targetIndex = index; + keyboardSelectionTimer.start(); } } function executeKeyboardSelection(index) { - keyboardSelectionIndex = index - keyboardSelectionRequested = true + keyboardSelectionIndex = index; + keyboardSelectionRequested = true; } function handleSaveFile(filePath) { - var normalizedPath = filePath + var normalizedPath = filePath; if (!normalizedPath.startsWith("file://")) { - normalizedPath = "file://" + filePath + normalizedPath = "file://" + filePath; } - var exists = false - var fileName = filePath.split('/').pop() + var exists = false; + var fileName = filePath.split('/').pop(); for (var i = 0; i < folderModel.count; i++) { if (folderModel.get(i, "fileName") === fileName && !folderModel.get(i, "fileIsDir")) { - exists = true - break + exists = true; + break; } } if (exists) { - pendingFilePath = normalizedPath - showOverwriteConfirmation = true + pendingFilePath = normalizedPath; + showOverwriteConfirmation = true; } else { - fileSelected(normalizedPath) - fileBrowserModal.close() + fileSelected(normalizedPath); + fileBrowserModal.close(); } } objectName: "fileBrowserModal" - allowStacking: true - closeOnEscapeKey: false - shouldHaveFocus: shouldBeVisible + title: "Files - " + browserTitle + implicitWidth: 800 + implicitHeight: 600 + color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) + visible: false + Component.onCompleted: { - loadSettings() - currentPath = getLastPath() - _initialized = true + loadSettings(); + currentPath = getLastPath(); + _initialized = true; } - property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation( - StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation( - StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation( - StandardPaths.HomeLocation) + "/snap/steam/common/.local/share/Steam/steamapps/workshop/content/431960"] + property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.var/app/com.valvesoftware.Steam/.local/share/Steam/steamapps/workshop/content/431960", StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/snap/steam/common/.local/share/Steam/steamapps/workshop/content/431960"] property int currentPathIndex: 0 - width: 800 - height: 600 - enableShadow: true - visible: false - onBackgroundClicked: close() - onOpened: { - if (parentModal) { - parentModal.shouldHaveFocus = false - parentModal.allowFocusOverride = true - } - Qt.callLater(() => { - if (contentLoader && contentLoader.item) { - contentLoader.item.forceActiveFocus() - } - }) - } - onDialogClosed: { - if (parentModal) { - parentModal.allowFocusOverride = false - parentModal.shouldHaveFocus = Qt.binding(() => { - return parentModal.shouldBeVisible - }) - } - } onVisibleChanged: { if (visible) { - currentPath = getLastPath() - selectedIndex = -1 - keyboardNavigationActive = false - backButtonFocused = false + if (parentModal) { + parentModal.shouldHaveFocus = false; + parentModal.allowFocusOverride = true; + } + currentPath = getLastPath(); + selectedIndex = -1; + keyboardNavigationActive = false; + backButtonFocused = false; + Qt.callLater(() => { + if (contentFocusScope) { + contentFocusScope.forceActiveFocus(); + } + }); + } else { + if (parentModal) { + parentModal.allowFocusOverride = false; + parentModal.shouldHaveFocus = Qt.binding(() => { + return parentModal.shouldBeVisible; + }); + } + dialogClosed(); } } onCurrentPathChanged: { - selectedFilePath = "" - selectedFileName = "" - selectedFileIsDir = false - saveSettings() + selectedFilePath = ""; + selectedFileName = ""; + selectedFileIsDir = false; + saveSettings(); } onSelectedIndexChanged: { if (selectedIndex >= 0 && folderModel && selectedIndex < folderModel.count) { - selectedFilePath = "" - selectedFileName = "" - selectedFileIsDir = false + selectedFilePath = ""; + selectedFileName = ""; + selectedFileIsDir = false; } } @@ -288,49 +281,57 @@ DankModal { sortField: { switch (sortBy) { case "name": - return FolderListModel.Name + return FolderListModel.Name; case "size": - return FolderListModel.Size + return FolderListModel.Size; case "modified": - return FolderListModel.Time + return FolderListModel.Time; case "type": - return FolderListModel.Type + return FolderListModel.Type; default: - return FolderListModel.Name + return FolderListModel.Name; } } sortReversed: !sortAscending } - property var quickAccessLocations: [{ + property var quickAccessLocations: [ + { "name": "Home", "path": homeDir, "icon": "home" - }, { + }, + { "name": "Documents", "path": docsDir, "icon": "description" - }, { + }, + { "name": "Downloads", "path": downloadDir, "icon": "download" - }, { + }, + { "name": "Pictures", "path": picsDir, "icon": "image" - }, { + }, + { "name": "Music", "path": musicDir, "icon": "music_note" - }, { + }, + { "name": "Videos", "path": videosDir, "icon": "movie" - }, { + }, + { "name": "Desktop", "path": desktopDir, "icon": "computer" - }] + } + ] QtObject { id: keyboardController @@ -340,213 +341,210 @@ DankModal { function handleKey(event) { if (event.key === Qt.Key_Escape) { - close() - event.accepted = true - return + close(); + event.accepted = true; + return; } if (event.key === Qt.Key_F10) { - showKeyboardHints = !showKeyboardHints - event.accepted = true - return + showKeyboardHints = !showKeyboardHints; + event.accepted = true; + return; } if (event.key === Qt.Key_F1 || event.key === Qt.Key_I) { - showFileInfo = !showFileInfo - event.accepted = true - return + showFileInfo = !showFileInfo; + event.accepted = true; + return; } if ((event.modifiers & Qt.AltModifier && event.key === Qt.Key_Left) || event.key === Qt.Key_Backspace) { if (currentPath !== homeDir) { - navigateUp() - event.accepted = true + navigateUp(); + event.accepted = true; } - return + return; } if (!keyboardNavigationActive) { - const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key - === Qt.Key_Right || (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier) + const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right || (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) || (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier); if (isInitKey) { - keyboardNavigationActive = true + keyboardNavigationActive = true; if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } else { - backButtonFocused = false - selectedIndex = 0 + backButtonFocused = false; + selectedIndex = 0; } - event.accepted = true + event.accepted = true; } - return + return; } switch (event.key) { case Qt.Key_Tab: if (backButtonFocused) { - backButtonFocused = false - selectedIndex = 0 + backButtonFocused = false; + selectedIndex = 0; } else if (selectedIndex < totalItems - 1) { - selectedIndex++ + selectedIndex++; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } else { - selectedIndex = 0 + selectedIndex = 0; } - event.accepted = true - break + event.accepted = true; + break; case Qt.Key_Backtab: if (backButtonFocused) { - backButtonFocused = false - selectedIndex = totalItems - 1 + backButtonFocused = false; + selectedIndex = totalItems - 1; } else if (selectedIndex > 0) { - selectedIndex-- + selectedIndex--; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } else { - selectedIndex = totalItems - 1 + selectedIndex = totalItems - 1; } - event.accepted = true - break + event.accepted = true; + break; case Qt.Key_N: if (event.modifiers & Qt.ControlModifier) { if (backButtonFocused) { - backButtonFocused = false - selectedIndex = 0 + backButtonFocused = false; + selectedIndex = 0; } else if (selectedIndex < totalItems - 1) { - selectedIndex++ + selectedIndex++; } - event.accepted = true + event.accepted = true; } - break + break; case Qt.Key_P: if (event.modifiers & Qt.ControlModifier) { if (selectedIndex > 0) { - selectedIndex-- + selectedIndex--; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } - event.accepted = true + event.accepted = true; } - break + break; case Qt.Key_J: if (event.modifiers & Qt.ControlModifier) { if (selectedIndex < totalItems - 1) { - selectedIndex++ + selectedIndex++; } - event.accepted = true + event.accepted = true; } - break + break; case Qt.Key_K: if (event.modifiers & Qt.ControlModifier) { if (selectedIndex > 0) { - selectedIndex-- + selectedIndex--; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } - event.accepted = true + event.accepted = true; } - break + break; case Qt.Key_H: if (event.modifiers & Qt.ControlModifier) { if (!backButtonFocused && selectedIndex > 0) { - selectedIndex-- + selectedIndex--; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } - event.accepted = true + event.accepted = true; } - break + break; case Qt.Key_L: if (event.modifiers & Qt.ControlModifier) { if (backButtonFocused) { - backButtonFocused = false - selectedIndex = 0 + backButtonFocused = false; + selectedIndex = 0; } else if (selectedIndex < totalItems - 1) { - selectedIndex++ + selectedIndex++; } - event.accepted = true + event.accepted = true; } - break + break; case Qt.Key_Left: if (pathInputHasFocus) - return + return; if (backButtonFocused) - return - + return; if (selectedIndex > 0) { - selectedIndex-- + selectedIndex--; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } - event.accepted = true - break + event.accepted = true; + break; case Qt.Key_Right: if (pathInputHasFocus) - return - + return; if (backButtonFocused) { - backButtonFocused = false - selectedIndex = 0 + backButtonFocused = false; + selectedIndex = 0; } else if (selectedIndex < totalItems - 1) { - selectedIndex++ + selectedIndex++; } - event.accepted = true - break + event.accepted = true; + break; case Qt.Key_Up: if (backButtonFocused) { - backButtonFocused = false + backButtonFocused = false; if (gridColumns === 1) { - selectedIndex = 0 + selectedIndex = 0; } else { - var col = selectedIndex % gridColumns - selectedIndex = Math.min(col, totalItems - 1) + var col = selectedIndex % gridColumns; + selectedIndex = Math.min(col, totalItems - 1); } } else if (selectedIndex >= gridColumns) { - selectedIndex -= gridColumns + selectedIndex -= gridColumns; } else if (selectedIndex > 0 && gridColumns === 1) { - selectedIndex-- + selectedIndex--; } else if (currentPath !== homeDir) { - backButtonFocused = true - selectedIndex = -1 + backButtonFocused = true; + selectedIndex = -1; } - event.accepted = true - break + event.accepted = true; + break; case Qt.Key_Down: if (backButtonFocused) { - backButtonFocused = false - selectedIndex = 0 + backButtonFocused = false; + selectedIndex = 0; } else if (gridColumns === 1) { if (selectedIndex < totalItems - 1) { - selectedIndex++ + selectedIndex++; } } else { - var newIndex = selectedIndex + gridColumns + var newIndex = selectedIndex + gridColumns; if (newIndex < totalItems) { - selectedIndex = newIndex + selectedIndex = newIndex; } else { - var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns - var col = selectedIndex % gridColumns - var targetIndex = lastRowStart + col + var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns; + var col = selectedIndex % gridColumns; + var targetIndex = lastRowStart + col; if (targetIndex < totalItems && targetIndex > selectedIndex) { - selectedIndex = targetIndex + selectedIndex = targetIndex; } } } - event.accepted = true - break + event.accepted = true; + break; case Qt.Key_Return: case Qt.Key_Enter: case Qt.Key_Space: if (backButtonFocused) - navigateUp() + navigateUp(); else if (selectedIndex >= 0 && selectedIndex < totalItems) - fileBrowserModal.keyboardFileSelection(selectedIndex) - event.accepted = true - break + fileBrowserModal.keyboardFileSelection(selectedIndex); + event.accepted = true; + break; } } } @@ -558,368 +556,363 @@ DankModal { interval: 1 onTriggered: { - executeKeyboardSelection(targetIndex) + executeKeyboardSelection(targetIndex); } } - content: Component { - Item { + FocusScope { + id: contentFocusScope + + anchors.fill: parent + focus: true + + Keys.onPressed: event => { + keyboardController.handleKey(event); + } + + Column { anchors.fill: parent + spacing: 0 - Keys.onPressed: event => { - keyboardController.handleKey(event) - } + Item { + width: parent.width + height: 48 - onVisibleChanged: { - if (visible) { - forceActiveFocus() + Row { + spacing: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + anchors.left: parent.left + anchors.leftMargin: Theme.spacingL + + DankIcon { + name: browserIcon + size: Theme.iconSizeLarge + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter + } + + StyledText { + text: browserTitle + font.pixelSize: Theme.fontSizeXLarge + color: Theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter + } + } + + Row { + anchors.right: parent.right + anchors.rightMargin: Theme.spacingM + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingS + + DankActionButton { + circular: false + iconName: showHiddenFiles ? "visibility_off" : "visibility" + iconSize: Theme.iconSize - 4 + iconColor: showHiddenFiles ? Theme.primary : Theme.surfaceText + onClicked: showHiddenFiles = !showHiddenFiles + } + + DankActionButton { + circular: false + iconName: viewMode === "grid" ? "view_list" : "grid_view" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + onClicked: viewMode = viewMode === "grid" ? "list" : "grid" + } + + DankActionButton { + circular: false + iconName: iconSizeIndex === 0 ? "photo_size_select_small" : iconSizeIndex === 1 ? "photo_size_select_large" : iconSizeIndex === 2 ? "photo_size_select_actual" : "zoom_in" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + visible: viewMode === "grid" + onClicked: iconSizeIndex = (iconSizeIndex + 1) % iconSizes.length + } + + DankActionButton { + circular: false + iconName: "info" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + onClicked: fileBrowserModal.showKeyboardHints = !fileBrowserModal.showKeyboardHints + } + + DankActionButton { + circular: false + iconName: "close" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + onClicked: fileBrowserModal.close() + } } } - Column { - anchors.fill: parent - spacing: 0 + StyledRect { + width: parent.width + height: 1 + color: Theme.outline + } - Item { - width: parent.width - height: 48 + Item { + width: parent.width + height: parent.height - 49 + + Row { + anchors.fill: parent + spacing: 0 Row { - spacing: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: Theme.spacingL + width: showSidebar ? 201 : 0 + height: parent.height + spacing: 0 + visible: showSidebar - DankIcon { - name: browserIcon - size: Theme.iconSizeLarge - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter + FileBrowserSidebar { + height: parent.height + quickAccessLocations: fileBrowserModal.quickAccessLocations + currentPath: fileBrowserModal.currentPath + onLocationSelected: path => navigateTo(path) } - StyledText { - text: browserTitle - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter + StyledRect { + width: 1 + height: parent.height + color: Theme.outline } } - Row { - anchors.right: parent.right - anchors.rightMargin: Theme.spacingM - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingS - - DankActionButton { - circular: false - iconName: showHiddenFiles ? "visibility_off" : "visibility" - iconSize: Theme.iconSize - 4 - iconColor: showHiddenFiles ? Theme.primary : Theme.surfaceText - onClicked: showHiddenFiles = !showHiddenFiles - } - - DankActionButton { - circular: false - iconName: viewMode === "grid" ? "view_list" : "grid_view" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: viewMode = viewMode === "grid" ? "list" : "grid" - } - - DankActionButton { - circular: false - iconName: iconSizeIndex === 0 ? "photo_size_select_small" : iconSizeIndex === 1 ? "photo_size_select_large" : iconSizeIndex === 2 ? "photo_size_select_actual" : "zoom_in" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - visible: viewMode === "grid" - onClicked: iconSizeIndex = (iconSizeIndex + 1) % iconSizes.length - } - - DankActionButton { - circular: false - iconName: "info" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: fileBrowserModal.showKeyboardHints = !fileBrowserModal.showKeyboardHints - } - - DankActionButton { - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: fileBrowserModal.close() - } - } - } - - StyledRect { - width: parent.width - height: 1 - color: Theme.outline - } - - Item { - width: parent.width - height: parent.height - 49 - - Row { - anchors.fill: parent + Column { + width: parent.width - (showSidebar ? 201 : 0) + height: parent.height spacing: 0 - Row { - width: showSidebar ? 201 : 0 - height: parent.height - spacing: 0 - visible: showSidebar - - FileBrowserSidebar { - height: parent.height - quickAccessLocations: fileBrowserModal.quickAccessLocations - currentPath: fileBrowserModal.currentPath - onLocationSelected: path => navigateTo(path) - } - - StyledRect { - width: 1 - height: parent.height - color: Theme.outline + FileBrowserNavigation { + width: parent.width + currentPath: fileBrowserModal.currentPath + homeDir: fileBrowserModal.homeDir + backButtonFocused: fileBrowserModal.backButtonFocused + keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive + showSidebar: fileBrowserModal.showSidebar + pathEditMode: fileBrowserModal.pathEditMode + onNavigateUp: fileBrowserModal.navigateUp() + onNavigateTo: path => fileBrowserModal.navigateTo(path) + onPathInputFocusChanged: hasFocus => { + fileBrowserModal.pathInputHasFocus = hasFocus; + if (hasFocus) { + fileBrowserModal.pathEditMode = true; + } } } - Column { - width: parent.width - (showSidebar ? 201 : 0) - height: parent.height - spacing: 0 + StyledRect { + width: parent.width + height: 1 + color: Theme.outline + } - FileBrowserNavigation { - width: parent.width - currentPath: fileBrowserModal.currentPath - homeDir: fileBrowserModal.homeDir - backButtonFocused: fileBrowserModal.backButtonFocused - keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive - showSidebar: fileBrowserModal.showSidebar - pathEditMode: fileBrowserModal.pathEditMode - onNavigateUp: fileBrowserModal.navigateUp() - onNavigateTo: path => fileBrowserModal.navigateTo(path) - onPathInputFocusChanged: hasFocus => { - fileBrowserModal.pathInputHasFocus = hasFocus - if (hasFocus) { - fileBrowserModal.pathEditMode = true - } - } + Item { + id: gridContainer + width: parent.width + height: parent.height - 41 + clip: true + + property real gridCellWidth: iconSizes[iconSizeIndex] + 24 + property real gridCellHeight: iconSizes[iconSizeIndex] + 56 + property real availableGridWidth: width - Theme.spacingM * 2 + property int gridColumns: Math.max(1, Math.floor(availableGridWidth / gridCellWidth)) + property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2) + + onGridColumnsChanged: { + fileBrowserModal.actualGridColumns = gridColumns; + } + Component.onCompleted: { + fileBrowserModal.actualGridColumns = gridColumns; } - StyledRect { - width: parent.width - height: 1 - color: Theme.outline - } - - Item { - id: gridContainer - width: parent.width - height: parent.height - 41 - clip: true - - property real gridCellWidth: iconSizes[iconSizeIndex] + 24 - property real gridCellHeight: iconSizes[iconSizeIndex] + 56 - property real availableGridWidth: width - Theme.spacingM * 2 - property int gridColumns: Math.max(1, Math.floor(availableGridWidth / gridCellWidth)) - property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2) - - onGridColumnsChanged: { - fileBrowserModal.actualGridColumns = gridColumns - } - Component.onCompleted: { - fileBrowserModal.actualGridColumns = gridColumns + DankGridView { + id: fileGrid + anchors.fill: parent + anchors.leftMargin: gridContainer.gridLeftMargin + anchors.rightMargin: Theme.spacingM + anchors.topMargin: Theme.spacingS + anchors.bottomMargin: Theme.spacingS + visible: viewMode === "grid" + cellWidth: gridContainer.gridCellWidth + cellHeight: gridContainer.gridCellHeight + cacheBuffer: 260 + model: folderModel + currentIndex: selectedIndex + onCurrentIndexChanged: { + if (keyboardNavigationActive && currentIndex >= 0) + positionViewAtIndex(currentIndex, GridView.Contain); } - DankGridView { - id: fileGrid - anchors.fill: parent - anchors.leftMargin: gridContainer.gridLeftMargin - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - visible: viewMode === "grid" - cellWidth: gridContainer.gridCellWidth - cellHeight: gridContainer.gridCellHeight - cacheBuffer: 260 - model: folderModel - currentIndex: selectedIndex - onCurrentIndexChanged: { - if (keyboardNavigationActive && currentIndex >= 0) - positionViewAtIndex(currentIndex, GridView.Contain) - } + ScrollBar.vertical: DankScrollbar { + id: gridScrollbar + } - ScrollBar.vertical: DankScrollbar { - id: gridScrollbar - } + ScrollBar.horizontal: ScrollBar { + policy: ScrollBar.AlwaysOff + } - ScrollBar.horizontal: ScrollBar { - policy: ScrollBar.AlwaysOff - } - - delegate: FileBrowserGridDelegate { - iconSizes: fileBrowserModal.iconSizes - iconSizeIndex: fileBrowserModal.iconSizeIndex - selectedIndex: fileBrowserModal.selectedIndex - keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive - onItemClicked: (index, path, name, isDir) => { - selectedIndex = index - setSelectedFileData(path, name, isDir) - if (isDir) { - navigateTo(path) - } else { - fileSelected(path) - fileBrowserModal.close() - } - } - onItemSelected: (index, path, name, isDir) => { - setSelectedFileData(path, name, isDir) - } - - Connections { - function onKeyboardSelectionRequestedChanged() { - if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) { - fileBrowserModal.keyboardSelectionRequested = false - selectedIndex = index - setSelectedFileData(filePath, fileName, fileIsDir) - if (fileIsDir) { - navigateTo(filePath) - } else { - fileSelected(filePath) - fileBrowserModal.close() - } - } - } - - target: fileBrowserModal + delegate: FileBrowserGridDelegate { + iconSizes: fileBrowserModal.iconSizes + iconSizeIndex: fileBrowserModal.iconSizeIndex + selectedIndex: fileBrowserModal.selectedIndex + keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive + onItemClicked: (index, path, name, isDir) => { + selectedIndex = index; + setSelectedFileData(path, name, isDir); + if (isDir) { + navigateTo(path); + } else { + fileSelected(path); + fileBrowserModal.close(); } } - } - - DankListView { - id: fileList - anchors.fill: parent - anchors.leftMargin: Theme.spacingM - anchors.rightMargin: Theme.spacingM - anchors.topMargin: Theme.spacingS - anchors.bottomMargin: Theme.spacingS - visible: viewMode === "list" - spacing: 2 - model: folderModel - currentIndex: selectedIndex - onCurrentIndexChanged: { - if (keyboardNavigationActive && currentIndex >= 0) - positionViewAtIndex(currentIndex, ListView.Contain) + onItemSelected: (index, path, name, isDir) => { + setSelectedFileData(path, name, isDir); } - ScrollBar.vertical: DankScrollbar { - id: listScrollbar - } - - delegate: FileBrowserListDelegate { - width: fileList.width - selectedIndex: fileBrowserModal.selectedIndex - keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive - onItemClicked: (index, path, name, isDir) => { - selectedIndex = index - setSelectedFileData(path, name, isDir) - if (isDir) { - navigateTo(path) - } else { - fileSelected(path) - fileBrowserModal.close() - } - } - onItemSelected: (index, path, name, isDir) => { - setSelectedFileData(path, name, isDir) - } - - Connections { - function onKeyboardSelectionRequestedChanged() { - if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) { - fileBrowserModal.keyboardSelectionRequested = false - selectedIndex = index - setSelectedFileData(filePath, fileName, fileIsDir) - if (fileIsDir) { - navigateTo(filePath) - } else { - fileSelected(filePath) - fileBrowserModal.close() - } + Connections { + function onKeyboardSelectionRequestedChanged() { + if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) { + fileBrowserModal.keyboardSelectionRequested = false; + selectedIndex = index; + setSelectedFileData(filePath, fileName, fileIsDir); + if (fileIsDir) { + navigateTo(filePath); + } else { + fileSelected(filePath); + fileBrowserModal.close(); } } - - target: fileBrowserModal } + + target: fileBrowserModal + } + } + } + + DankListView { + id: fileList + anchors.fill: parent + anchors.leftMargin: Theme.spacingM + anchors.rightMargin: Theme.spacingM + anchors.topMargin: Theme.spacingS + anchors.bottomMargin: Theme.spacingS + visible: viewMode === "list" + spacing: 2 + model: folderModel + currentIndex: selectedIndex + onCurrentIndexChanged: { + if (keyboardNavigationActive && currentIndex >= 0) + positionViewAtIndex(currentIndex, ListView.Contain); + } + + ScrollBar.vertical: DankScrollbar { + id: listScrollbar + } + + delegate: FileBrowserListDelegate { + width: fileList.width + selectedIndex: fileBrowserModal.selectedIndex + keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive + onItemClicked: (index, path, name, isDir) => { + selectedIndex = index; + setSelectedFileData(path, name, isDir); + if (isDir) { + navigateTo(path); + } else { + fileSelected(path); + fileBrowserModal.close(); + } + } + onItemSelected: (index, path, name, isDir) => { + setSelectedFileData(path, name, isDir); + } + + Connections { + function onKeyboardSelectionRequestedChanged() { + if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) { + fileBrowserModal.keyboardSelectionRequested = false; + selectedIndex = index; + setSelectedFileData(filePath, fileName, fileIsDir); + if (fileIsDir) { + navigateTo(filePath); + } else { + fileSelected(filePath); + fileBrowserModal.close(); + } + } + } + + target: fileBrowserModal } } } } } + } - FileBrowserSaveRow { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - saveMode: fileBrowserModal.saveMode - defaultFileName: fileBrowserModal.defaultFileName - currentPath: fileBrowserModal.currentPath - onSaveRequested: filePath => handleSaveFile(filePath) + FileBrowserSaveRow { + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Theme.spacingL + saveMode: fileBrowserModal.saveMode + defaultFileName: fileBrowserModal.defaultFileName + currentPath: fileBrowserModal.currentPath + onSaveRequested: filePath => handleSaveFile(filePath) + } + + KeyboardHints { + id: keyboardHints + + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + anchors.margins: Theme.spacingL + showHints: fileBrowserModal.showKeyboardHints + } + + FileInfo { + id: fileInfo + + anchors.top: parent.top + anchors.right: parent.right + anchors.margins: Theme.spacingL + width: 300 + showFileInfo: fileBrowserModal.showFileInfo + selectedIndex: fileBrowserModal.selectedIndex + sourceFolderModel: folderModel + currentPath: fileBrowserModal.currentPath + currentFileName: fileBrowserModal.selectedFileName + currentFileIsDir: fileBrowserModal.selectedFileIsDir + currentFileExtension: { + if (fileBrowserModal.selectedFileIsDir || !fileBrowserModal.selectedFileName) + return ""; + + var lastDot = fileBrowserModal.selectedFileName.lastIndexOf('.'); + return lastDot > 0 ? fileBrowserModal.selectedFileName.substring(lastDot + 1).toLowerCase() : ""; } + } - KeyboardHints { - id: keyboardHints - - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - anchors.margins: Theme.spacingL - showHints: fileBrowserModal.showKeyboardHints + FileBrowserSortMenu { + id: sortMenu + anchors.top: parent.top + anchors.right: parent.right + anchors.topMargin: 120 + anchors.rightMargin: Theme.spacingL + sortBy: fileBrowserModal.sortBy + sortAscending: fileBrowserModal.sortAscending + onSortBySelected: value => { + fileBrowserModal.sortBy = value; } - - FileInfo { - id: fileInfo - - anchors.top: parent.top - anchors.right: parent.right - anchors.margins: Theme.spacingL - width: 300 - showFileInfo: fileBrowserModal.showFileInfo - selectedIndex: fileBrowserModal.selectedIndex - sourceFolderModel: folderModel - currentPath: fileBrowserModal.currentPath - currentFileName: fileBrowserModal.selectedFileName - currentFileIsDir: fileBrowserModal.selectedFileIsDir - currentFileExtension: { - if (fileBrowserModal.selectedFileIsDir || !fileBrowserModal.selectedFileName) - return "" - - var lastDot = fileBrowserModal.selectedFileName.lastIndexOf('.') - return lastDot > 0 ? fileBrowserModal.selectedFileName.substring(lastDot + 1).toLowerCase() : "" - } - } - - FileBrowserSortMenu { - id: sortMenu - anchors.top: parent.top - anchors.right: parent.right - anchors.topMargin: 120 - anchors.rightMargin: Theme.spacingL - sortBy: fileBrowserModal.sortBy - sortAscending: fileBrowserModal.sortAscending - onSortBySelected: value => { - fileBrowserModal.sortBy = value - } - onSortOrderSelected: ascending => { - fileBrowserModal.sortAscending = ascending - } + onSortOrderSelected: ascending => { + fileBrowserModal.sortAscending = ascending; } } } @@ -929,14 +922,14 @@ DankModal { showDialog: showOverwriteConfirmation pendingFilePath: fileBrowserModal.pendingFilePath onConfirmed: filePath => { - showOverwriteConfirmation = false - fileSelected(filePath) - pendingFilePath = "" - Qt.callLater(() => fileBrowserModal.close()) - } + showOverwriteConfirmation = false; + fileSelected(filePath); + pendingFilePath = ""; + Qt.callLater(() => fileBrowserModal.close()); + } onCancelled: { - showOverwriteConfirmation = false - pendingFilePath = "" + showOverwriteConfirmation = false; + pendingFilePath = ""; } } } diff --git a/quickshell/Modals/Settings/SettingsModal.qml b/quickshell/Modals/Settings/SettingsModal.qml index b3075740..da41e7f4 100644 --- a/quickshell/Modals/Settings/SettingsModal.qml +++ b/quickshell/Modals/Settings/SettingsModal.qml @@ -1,124 +1,52 @@ import QtQuick -import QtQuick.Effects import Quickshell -import Quickshell.Hyprland -import Quickshell.Io import qs.Common -import qs.Modals.Common import qs.Modals.FileBrowser -import qs.Modules.Settings import qs.Services import qs.Widgets -DankModal { +FloatingWindow { id: settingsModal - layerNamespace: "dms:settings" - - HyprlandFocusGrab { - windows: [settingsModal] - active: CompositorService.isHyprland && settingsModal.shouldHaveFocus - } - - property Component settingsContent property alias profileBrowser: profileBrowser + property alias wallpaperBrowser: wallpaperBrowser property int currentTabIndex: 0 + property bool shouldHaveFocus: visible + property bool allowFocusOverride: false + property alias shouldBeVisible: settingsModal.visible - signal closingModal() + signal closingModal function show() { - open(); + visible = true; } function hide() { - close(); + visible = false; } function toggle() { - if (shouldBeVisible) { - hide(); - } else { - show(); - } + visible = !visible; } objectName: "settingsModal" - width: Math.min(800, screenWidth * 0.9) - height: Math.min(800, screenHeight * 0.85) - backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) + title: "Settings" + implicitWidth: 800 + implicitHeight: 800 + color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) visible: false - onBackgroundClicked: () => { - return hide(); - } - content: settingsContent - onOpened: () => { - Qt.callLater(() => { - modalFocusScope.forceActiveFocus() - if (contentLoader.item) { - contentLoader.item.forceActiveFocus() - } - }) - } onVisibleChanged: { - if (visible && shouldBeVisible) { + if (!visible) { + closingModal(); + } else { Qt.callLater(() => { - modalFocusScope.forceActiveFocus() - if (contentLoader.item) { - contentLoader.item.forceActiveFocus() + if (contentFocusScope) { + contentFocusScope.forceActiveFocus(); } - }) + }); } } - modalFocusScope.Keys.onPressed: event => { - const tabCount = 11 - if (event.key === Qt.Key_Down) { - currentTabIndex = (currentTabIndex + 1) % tabCount - event.accepted = true - } else if (event.key === Qt.Key_Up) { - currentTabIndex = (currentTabIndex - 1 + tabCount) % tabCount - event.accepted = true - } else if (event.key === Qt.Key_Tab && !event.modifiers) { - currentTabIndex = (currentTabIndex + 1) % tabCount - event.accepted = true - } else if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && event.modifiers & Qt.ShiftModifier)) { - currentTabIndex = (currentTabIndex - 1 + tabCount) % tabCount - event.accepted = true - } - } - - IpcHandler { - function open(): string { - settingsModal.show(); - return "SETTINGS_OPEN_SUCCESS"; - } - - function close(): string { - settingsModal.hide(); - return "SETTINGS_CLOSE_SUCCESS"; - } - - function toggle(): string { - settingsModal.toggle(); - return "SETTINGS_TOGGLE_SUCCESS"; - } - - target: "settings" - } - - IpcHandler { - function browse(type: string) { - if (type === "wallpaper") { - wallpaperBrowser.allowStacking = false; - wallpaperBrowser.open(); - } else if (type === "profile") { - profileBrowser.allowStacking = false; - profileBrowser.open(); - } - } - - target: "file" - } FileBrowserModal { id: profileBrowser @@ -130,20 +58,12 @@ DankModal { browserType: "profile" showHiddenFiles: true fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] - onFileSelected: (path) => { + onFileSelected: path => { PortalService.setProfileImage(path); close(); } onDialogClosed: () => { allowStacking = true; - if (settingsModal.shouldBeVisible) { - Qt.callLater(() => { - settingsModal.modalFocusScope.forceActiveFocus() - if (settingsModal.contentLoader.item) { - settingsModal.contentLoader.item.forceActiveFocus() - } - }) - } } } @@ -157,111 +77,120 @@ DankModal { browserType: "wallpaper" showHiddenFiles: true fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] - onFileSelected: (path) => { + onFileSelected: path => { SessionData.setWallpaper(path); close(); } onDialogClosed: () => { allowStacking = true; - if (settingsModal.shouldBeVisible) { - Qt.callLater(() => { - settingsModal.modalFocusScope.forceActiveFocus() - if (settingsModal.contentLoader.item) { - settingsModal.contentLoader.item.forceActiveFocus() - } - }) - } } } - settingsContent: Component { - Item { - id: rootScope - anchors.fill: parent + FocusScope { + id: contentFocusScope - Keys.onEscapePressed: event => { - settingsModal.hide() - event.accepted = true + anchors.fill: parent + focus: true + + Keys.onPressed: event => { + const tabCount = 11; + if (event.key === Qt.Key_Escape) { + hide(); + event.accepted = true; + return; } + if (event.key === Qt.Key_Down) { + currentTabIndex = (currentTabIndex + 1) % tabCount; + event.accepted = true; + return; + } + if (event.key === Qt.Key_Up) { + currentTabIndex = (currentTabIndex - 1 + tabCount) % tabCount; + event.accepted = true; + return; + } + if (event.key === Qt.Key_Tab && !event.modifiers) { + currentTabIndex = (currentTabIndex + 1) % tabCount; + event.accepted = true; + return; + } + if (event.key === Qt.Key_Backtab || (event.key === Qt.Key_Tab && event.modifiers & Qt.ShiftModifier)) { + currentTabIndex = (currentTabIndex - 1 + tabCount) % tabCount; + event.accepted = true; + return; + } + } - Column { - anchors.fill: parent - anchors.leftMargin: Theme.spacingL - anchors.rightMargin: Theme.spacingL - anchors.topMargin: Theme.spacingM - anchors.bottomMargin: Theme.spacingL - spacing: 0 + Column { + anchors.fill: parent + anchors.leftMargin: Theme.spacingL + anchors.rightMargin: Theme.spacingL + anchors.topMargin: Theme.spacingM + anchors.bottomMargin: Theme.spacingL + spacing: 0 - Item { - width: parent.width - height: 35 - - Row { - anchors.left: parent.left - anchors.verticalCenter: parent.verticalCenter - spacing: Theme.spacingM - - DankIcon { - name: "settings" - size: Theme.iconSize - color: Theme.primary - anchors.verticalCenter: parent.verticalCenter - } - - StyledText { - text: I18n.tr("Settings") - font.pixelSize: Theme.fontSizeXLarge - color: Theme.surfaceText - font.weight: Font.Medium - anchors.verticalCenter: parent.verticalCenter - } - - } - - DankActionButton { - anchors.right: parent.right - anchors.verticalCenter: parent.verticalCenter - circular: false - iconName: "close" - iconSize: Theme.iconSize - 4 - iconColor: Theme.surfaceText - onClicked: () => { - return settingsModal.hide(); - } - } - - } + Item { + width: parent.width + height: 35 Row { - width: parent.width - height: parent.height - 35 - spacing: 0 + anchors.left: parent.left + anchors.verticalCenter: parent.verticalCenter + spacing: Theme.spacingM - SettingsSidebar { - id: sidebar - - parentModal: settingsModal - currentIndex: settingsModal.currentTabIndex - onCurrentIndexChanged: { - settingsModal.currentTabIndex = currentIndex - } + DankIcon { + name: "settings" + size: Theme.iconSize + color: Theme.primary + anchors.verticalCenter: parent.verticalCenter } - SettingsContent { - id: content - - width: parent.width - sidebar.width - height: parent.height - parentModal: settingsModal - currentIndex: settingsModal.currentTabIndex + StyledText { + text: I18n.tr("Settings") + font.pixelSize: Theme.fontSizeXLarge + color: Theme.surfaceText + font.weight: Font.Medium + anchors.verticalCenter: parent.verticalCenter } - } + DankActionButton { + anchors.right: parent.right + anchors.verticalCenter: parent.verticalCenter + circular: false + iconName: "close" + iconSize: Theme.iconSize - 4 + iconColor: Theme.surfaceText + onClicked: () => { + settingsModal.hide(); + } + } } + Row { + width: parent.width + height: parent.height - 35 + spacing: 0 + + SettingsSidebar { + id: sidebar + + parentModal: settingsModal + currentIndex: settingsModal.currentTabIndex + onCurrentIndexChanged: { + settingsModal.currentTabIndex = currentIndex; + } + } + + SettingsContent { + id: content + + width: parent.width - sidebar.width + height: parent.height + parentModal: settingsModal + currentIndex: settingsModal.currentTabIndex + } + } } - } - } diff --git a/quickshell/Modules/Notepad/Notepad.qml b/quickshell/Modules/Notepad/Notepad.qml index e95d0b1b..470d2e2f 100644 --- a/quickshell/Modules/Notepad/Notepad.qml +++ b/quickshell/Modules/Notepad/Notepad.qml @@ -1,8 +1,5 @@ +pragma ComponentBehavior: Bound import QtQuick -import QtQuick.Controls -import QtCore -import Quickshell -import Quickshell.Wayland import Quickshell.Io import qs.Common import qs.Modals.Common @@ -10,8 +7,6 @@ import qs.Modals.FileBrowser import qs.Services import qs.Widgets -pragma ComponentBehavior: Bound - Item { id: root @@ -26,119 +21,119 @@ Item { property bool showSettingsMenu: false property string pendingSaveContent: "" - signal hideRequested() + signal hideRequested Ref { service: NotepadStorageService } function hasUnsavedChanges() { - return textEditor.hasUnsavedChanges() + return textEditor.hasUnsavedChanges(); } function hasUnsavedTemporaryContent() { - return hasUnsavedChanges() + return hasUnsavedChanges(); } function createNewTab() { - performCreateNewTab() + performCreateNewTab(); } function performCreateNewTab() { - NotepadStorageService.createNewTab() - textEditor.text = "" - textEditor.lastSavedContent = "" - textEditor.contentLoaded = true - textEditor.textArea.forceActiveFocus() + NotepadStorageService.createNewTab(); + textEditor.text = ""; + textEditor.lastSavedContent = ""; + textEditor.contentLoaded = true; + textEditor.textArea.forceActiveFocus(); } function closeTab(tabIndex) { if (tabIndex === NotepadStorageService.currentTabIndex && hasUnsavedChanges()) { - root.pendingAction = "close_tab_" + tabIndex - root.confirmationDialogOpen = true - confirmationDialog.open() + root.pendingAction = "close_tab_" + tabIndex; + root.confirmationDialogOpen = true; + confirmationDialog.open(); } else { - performCloseTab(tabIndex) + performCloseTab(tabIndex); } } function performCloseTab(tabIndex) { - NotepadStorageService.closeTab(tabIndex) + NotepadStorageService.closeTab(tabIndex); Qt.callLater(() => { - textEditor.loadCurrentTabContent() - }) + textEditor.loadCurrentTabContent(); + }); } function switchToTab(tabIndex) { - if (tabIndex < 0 || tabIndex >= NotepadStorageService.tabs.length) return - + if (tabIndex < 0 || tabIndex >= NotepadStorageService.tabs.length) + return; if (textEditor.contentLoaded) { - textEditor.autoSaveToSession() + textEditor.autoSaveToSession(); } - NotepadStorageService.switchToTab(tabIndex) + NotepadStorageService.switchToTab(tabIndex); Qt.callLater(() => { - textEditor.loadCurrentTabContent() + textEditor.loadCurrentTabContent(); if (currentTab) { - root.currentFileName = currentTab.fileName || "" - root.currentFileUrl = currentTab.fileUrl || "" + root.currentFileName = currentTab.fileName || ""; + root.currentFileUrl = currentTab.fileUrl || ""; } - }) + }); } function saveToFile(fileUrl) { - if (!currentTab) return + if (!currentTab) + return; + var content = textEditor.text; + var filePath = fileUrl.toString().replace(/^file:\/\//, ''); - var content = textEditor.text - var filePath = fileUrl.toString().replace(/^file:\/\//, '') - - saveFileView.path = "" - pendingSaveContent = content - saveFileView.path = filePath + saveFileView.path = ""; + pendingSaveContent = content; + saveFileView.path = filePath; Qt.callLater(() => { - saveFileView.setText(pendingSaveContent) - }) + saveFileView.setText(pendingSaveContent); + }); } function loadFromFile(fileUrl) { if (hasUnsavedTemporaryContent()) { - root.pendingFileUrl = fileUrl - root.pendingAction = "load_file" - root.confirmationDialogOpen = true - confirmationDialog.open() + root.pendingFileUrl = fileUrl; + root.pendingAction = "load_file"; + root.confirmationDialogOpen = true; + confirmationDialog.open(); } else { - performLoadFromFile(fileUrl) + performLoadFromFile(fileUrl); } } function performLoadFromFile(fileUrl) { - const filePath = fileUrl.toString().replace(/^file:\/\//, '') - const fileName = filePath.split('/').pop() + const filePath = fileUrl.toString().replace(/^file:\/\//, ''); + const fileName = filePath.split('/').pop(); - loadFileView.path = "" - loadFileView.path = filePath + loadFileView.path = ""; + loadFileView.path = filePath; if (loadFileView.waitForJob()) { Qt.callLater(() => { - var content = loadFileView.text() + var content = loadFileView.text(); if (currentTab && content !== undefined && content !== null) { - textEditor.text = content - textEditor.lastSavedContent = content - textEditor.contentLoaded = true - root.lastSavedFileContent = content + textEditor.text = content; + textEditor.lastSavedContent = content; + textEditor.contentLoaded = true; + root.lastSavedFileContent = content; NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { title: fileName, filePath: filePath, isTemporary: false - }) + }); - root.currentFileName = fileName - root.currentFileUrl = fileUrl - textEditor.saveCurrentTabContent() + root.currentFileName = fileName; + root.currentFileUrl = fileUrl; + textEditor.saveCurrentTabContent(); } - }) + }); } } @@ -151,16 +146,16 @@ Item { width: parent.width contentLoaded: textEditor.contentLoaded - onTabSwitched: (tabIndex) => { - switchToTab(tabIndex) + onTabSwitched: tabIndex => { + switchToTab(tabIndex); } - onTabClosed: (tabIndex) => { - closeTab(tabIndex) + onTabClosed: tabIndex => { + closeTab(tabIndex); } onNewTabRequested: { - createNewTab() + createNewTab(); } } @@ -171,41 +166,41 @@ Item { onSaveRequested: { if (currentTab && !currentTab.isTemporary && currentTab.filePath) { - var fileUrl = "file://" + currentTab.filePath - saveToFile(fileUrl) + var fileUrl = "file://" + currentTab.filePath; + saveToFile(fileUrl); } else { - root.fileDialogOpen = true - saveBrowser.open() + root.fileDialogOpen = true; + saveBrowser.open(); } } onOpenRequested: { if (hasUnsavedChanges()) { - root.pendingAction = "open" - root.confirmationDialogOpen = true - confirmationDialog.open() + root.pendingAction = "open"; + root.confirmationDialogOpen = true; + confirmationDialog.open(); } else { - root.fileDialogOpen = true - loadBrowser.open() + root.fileDialogOpen = true; + loadBrowser.open(); } } onNewRequested: { if (hasUnsavedChanges()) { - root.pendingAction = "new" - root.confirmationDialogOpen = true - confirmationDialog.open() + root.pendingAction = "new"; + root.confirmationDialogOpen = true; + confirmationDialog.open(); } else { - createNewTab() + createNewTab(); } } onEscapePressed: { - root.hideRequested() + root.hideRequested(); } onSettingsRequested: { - showSettingsMenu = !showSettingsMenu + showSettingsMenu = !showSettingsMenu; } } } @@ -216,8 +211,8 @@ Item { isVisible: showSettingsMenu onSettingsRequested: showSettingsMenu = !showSettingsMenu onFindRequested: { - showSettingsMenu = false - textEditor.showSearch() + showSettingsMenu = false; + textEditor.showSearch(); } } @@ -233,14 +228,14 @@ Item { NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { hasUnsavedChanges: false, lastSavedContent: pendingSaveContent - }) - root.lastSavedFileContent = pendingSaveContent - pendingSaveContent = "" + }); + root.lastSavedFileContent = pendingSaveContent; + pendingSaveContent = ""; } } - onSaveFailed: (error) => { - pendingSaveContent = "" + onSaveFailed: error => { + pendingSaveContent = ""; } } @@ -251,8 +246,7 @@ Item { atomicWrites: true printErrors: true - onLoadFailed: (error) => { - } + onLoadFailed: error => {} } FileBrowserModal { @@ -266,56 +260,51 @@ Item { saveMode: true defaultFileName: { if (currentTab && currentTab.title && currentTab.title !== "Untitled") { - return currentTab.title + return currentTab.title; } else if (currentTab && !currentTab.isTemporary && currentTab.filePath) { - return currentTab.filePath.split('/').pop() + return currentTab.filePath.split('/').pop(); } else { - return "note.txt" + return "note.txt"; } } - WlrLayershell.layer: WlrLayershell.Overlay + onFileSelected: path => { + root.fileDialogOpen = false; + const cleanPath = path.toString().replace(/^file:\/\//, ''); + const fileName = cleanPath.split('/').pop(); + const fileUrl = "file://" + cleanPath; - onFileSelected: (path) => { - root.fileDialogOpen = false - const cleanPath = path.toString().replace(/^file:\/\//, '') - const fileName = cleanPath.split('/').pop() - const fileUrl = "file://" + cleanPath - - root.currentFileName = fileName - root.currentFileUrl = fileUrl + root.currentFileName = fileName; + root.currentFileUrl = fileUrl; if (currentTab) { - NotepadStorageService.saveTabAs( - NotepadStorageService.currentTabIndex, - cleanPath - ) + NotepadStorageService.saveTabAs(NotepadStorageService.currentTabIndex, cleanPath); } - saveToFile(fileUrl) + saveToFile(fileUrl); if (root.pendingAction === "new") { Qt.callLater(() => { - createNewTab() - }) + createNewTab(); + }); } else if (root.pendingAction === "open") { Qt.callLater(() => { - root.fileDialogOpen = true - loadBrowser.open() - }) + root.fileDialogOpen = true; + loadBrowser.open(); + }); } else if (root.pendingAction.startsWith("close_tab_")) { Qt.callLater(() => { - var tabIndex = parseInt(root.pendingAction.split("_")[2]) - performCloseTab(tabIndex) - }) + var tabIndex = parseInt(root.pendingAction.split("_")[2]); + performCloseTab(tabIndex); + }); } - root.pendingAction = "" + root.pendingAction = ""; - close() + close(); } onDialogClosed: { - root.fileDialogOpen = false + root.fileDialogOpen = false; } } @@ -328,23 +317,21 @@ Item { fileExtensions: ["*.txt", "*.md", "*.*"] allowStacking: true - WlrLayershell.layer: WlrLayershell.Overlay + onFileSelected: path => { + root.fileDialogOpen = false; + const cleanPath = path.toString().replace(/^file:\/\//, ''); + const fileName = cleanPath.split('/').pop(); + const fileUrl = "file://" + cleanPath; - onFileSelected: (path) => { - root.fileDialogOpen = false - const cleanPath = path.toString().replace(/^file:\/\//, '') - const fileName = cleanPath.split('/').pop() - const fileUrl = "file://" + cleanPath + root.currentFileName = fileName; + root.currentFileUrl = fileUrl; - root.currentFileName = fileName - root.currentFileUrl = fileUrl - - loadFromFile(fileUrl) - close() + loadFromFile(fileUrl); + close(); } onDialogClosed: { - root.fileDialogOpen = false + root.fileDialogOpen = false; } } @@ -357,8 +344,8 @@ Item { allowStacking: true onBackgroundClicked: { - close() - root.confirmationDialogOpen = false + close(); + root.confirmationDialogOpen = false; } content: Component { @@ -367,9 +354,9 @@ Item { focus: true Keys.onEscapePressed: event => { - confirmationDialog.close() - root.confirmationDialogOpen = false - event.accepted = true + confirmationDialog.close(); + root.confirmationDialogOpen = false; + event.accepted = true; } Column { @@ -392,13 +379,7 @@ Item { } StyledText { - text: root.pendingAction === "new" ? - I18n.tr("You have unsaved changes. Save before creating a new file?") : - root.pendingAction.startsWith("close_tab_") ? - I18n.tr("You have unsaved changes. Save before closing this tab?") : - root.pendingAction === "load_file" || root.pendingAction === "open" ? - I18n.tr("You have unsaved changes. Save before opening a file?") : - I18n.tr("You have unsaved changes. Save before continuing?") + text: root.pendingAction === "new" ? I18n.tr("You have unsaved changes. Save before creating a new file?") : root.pendingAction.startsWith("close_tab_") ? I18n.tr("You have unsaved changes. Save before closing this tab?") : root.pendingAction === "load_file" || root.pendingAction === "open" ? I18n.tr("You have unsaved changes. Save before opening a file?") : I18n.tr("You have unsaved changes. Save before continuing?") font.pixelSize: Theme.fontSizeMedium color: Theme.surfaceTextMedium width: parent.width @@ -411,8 +392,8 @@ Item { iconSize: Theme.iconSize - 4 iconColor: Theme.surfaceText onClicked: { - confirmationDialog.close() - root.confirmationDialogOpen = false + confirmationDialog.close(); + root.confirmationDialogOpen = false; } } } @@ -449,21 +430,21 @@ Item { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { - confirmationDialog.close() - root.confirmationDialogOpen = false + confirmationDialog.close(); + root.confirmationDialogOpen = false; if (root.pendingAction === "new") { - createNewTab() + createNewTab(); } else if (root.pendingAction === "open") { - root.fileDialogOpen = true - loadBrowser.open() + root.fileDialogOpen = true; + loadBrowser.open(); } else if (root.pendingAction === "load_file") { - performLoadFromFile(root.pendingFileUrl) + performLoadFromFile(root.pendingFileUrl); } else if (root.pendingAction.startsWith("close_tab_")) { - var tabIndex = parseInt(root.pendingAction.split("_")[2]) - performCloseTab(tabIndex) + var tabIndex = parseInt(root.pendingAction.split("_")[2]); + performCloseTab(tabIndex); } - root.pendingAction = "" - root.pendingFileUrl = "" + root.pendingAction = ""; + root.pendingFileUrl = ""; } } } @@ -489,10 +470,10 @@ Item { hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { - confirmationDialog.close() - root.confirmationDialogOpen = false - root.fileDialogOpen = true - saveBrowser.open() + confirmationDialog.close(); + root.confirmationDialogOpen = false; + root.fileDialogOpen = true; + saveBrowser.open(); } } @@ -503,11 +484,10 @@ Item { } } } - } } } } } } -} \ No newline at end of file +} diff --git a/quickshell/Modules/Notepad/NotepadSettings.qml b/quickshell/Modules/Notepad/NotepadSettings.qml index 6955f5af..53bb5faf 100644 --- a/quickshell/Modules/Notepad/NotepadSettings.qml +++ b/quickshell/Modules/Notepad/NotepadSettings.qml @@ -1,10 +1,7 @@ -import QtQuick -import QtQuick.Controls -import qs.Common -import qs.Services -import qs.Widgets - pragma ComponentBehavior: Bound +import QtQuick +import qs.Common +import qs.Widgets Item { id: root @@ -14,60 +11,54 @@ Item { property var cachedMonoFamilies: [] property bool fontsEnumerated: false - signal settingsRequested() - signal findRequested() + signal settingsRequested + signal findRequested function enumerateFonts() { - var fonts = ["Default"] - var availableFonts = Qt.fontFamilies() - var rootFamilies = [] - var seenFamilies = new Set() + var fonts = ["Default"]; + var availableFonts = Qt.fontFamilies(); + var rootFamilies = []; + var seenFamilies = new Set(); for (var i = 0; i < availableFonts.length; i++) { - var fontName = availableFonts[i] + var fontName = availableFonts[i]; if (fontName.startsWith(".")) - continue - + continue; if (fontName === SettingsData.defaultFontFamily) - continue - - var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, - "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function (match, suffix) { - return match - }).trim() + continue; + var rootName = fontName.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function (match, suffix) { + return match; + }).trim(); if (!seenFamilies.has(rootName) && rootName !== "") { - seenFamilies.add(rootName) - rootFamilies.push(rootName) + seenFamilies.add(rootName); + rootFamilies.push(rootName); } } - cachedFontFamilies = fonts.concat(rootFamilies.sort()) - var monoFonts = ["Default"] - var monoFamilies = [] - var seenMonoFamilies = new Set() + cachedFontFamilies = fonts.concat(rootFamilies.sort()); + var monoFonts = ["Default"]; + var monoFamilies = []; + var seenMonoFamilies = new Set(); for (var j = 0; j < availableFonts.length; j++) { - var fontName2 = availableFonts[j] + var fontName2 = availableFonts[j]; if (fontName2.startsWith(".")) - continue - + continue; if (fontName2 === SettingsData.defaultMonoFontFamily) - continue - - var lowerName = fontName2.toLowerCase() - if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes( - "jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) { - var rootName2 = fontName2.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim() + continue; + var lowerName = fontName2.toLowerCase(); + if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes("jetbrains") || lowerName.includes("fira") || lowerName.includes("hack") || lowerName.includes("source code") || lowerName.includes("ubuntu mono") || lowerName.includes("cascadia")) { + var rootName2 = fontName2.replace(/ (Thin|Extra Light|Light|Regular|Medium|Semi Bold|Demi Bold|Bold|Extra Bold|Black|Heavy)$/i, "").replace(/ (Italic|Oblique|Condensed|Extended|Narrow|Wide)$/i, "").trim(); if (!seenMonoFamilies.has(rootName2) && rootName2 !== "") { - seenMonoFamilies.add(rootName2) - monoFamilies.push(rootName2) + seenMonoFamilies.add(rootName2); + monoFamilies.push(rootName2); } } } - cachedMonoFamilies = monoFonts.concat(monoFamilies.sort()) - fontsEnumerated = true + cachedMonoFamilies = monoFonts.concat(monoFamilies.sort()); + fontsEnumerated = true; } Component.onCompleted: { if (!fontsEnumerated) { - enumerateFonts() + enumerateFonts(); } } @@ -140,7 +131,7 @@ Item { description: "Toggle fonts" checked: SettingsData.notepadUseMonospace onToggled: checked => { - SettingsData.notepadUseMonospace = checked + SettingsData.notepadUseMonospace = checked; } } @@ -152,7 +143,7 @@ Item { description: "Display line numbers in editor" checked: SettingsData.notepadShowLineNumbers onToggled: checked => { - SettingsData.notepadShowLineNumbers = checked + SettingsData.notepadShowLineNumbers = checked; } } @@ -214,23 +205,23 @@ Item { DankDropdown { id: fontDropdown - anchors.left: parent.left + anchors.left: parent.left anchors.leftMargin: -Theme.spacingM width: parent.width + Theme.spacingM text: I18n.tr("Font Family") options: cachedFontFamilies currentValue: { if (!SettingsData.notepadFontFamily || SettingsData.notepadFontFamily === "") - return "Default (Global)" + return "Default (Global)"; else - return SettingsData.notepadFontFamily + return SettingsData.notepadFontFamily; } enableFuzzySearch: true onValueChanged: value => { if (value && (value.startsWith("Default") || value === "Default (Global)")) { - SettingsData.notepadFontFamily = "" + SettingsData.notepadFontFamily = ""; } else { - SettingsData.notepadFontFamily = value + SettingsData.notepadFontFamily = value; } } } @@ -278,8 +269,8 @@ Item { backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) iconColor: Theme.surfaceText onClicked: { - var newSize = Math.max(8, SettingsData.notepadFontSize - 1) - SettingsData.notepadFontSize = newSize + var newSize = Math.max(8, SettingsData.notepadFontSize - 1); + SettingsData.notepadFontSize = newSize; } } @@ -308,8 +299,8 @@ Item { backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) iconColor: Theme.surfaceText onClicked: { - var newSize = Math.min(48, SettingsData.notepadFontSize + 1) - SettingsData.notepadFontSize = newSize + var newSize = Math.min(48, SettingsData.notepadFontSize + 1); + SettingsData.notepadFontSize = newSize; } } } @@ -335,9 +326,9 @@ Item { checked: SettingsData.notepadTransparencyOverride >= 0 onToggled: checked => { if (checked) { - SettingsData.notepadTransparencyOverride = SettingsData.notepadLastCustomTransparency + SettingsData.notepadTransparencyOverride = SettingsData.notepadLastCustomTransparency; } else { - SettingsData.notepadTransparencyOverride = -1 + SettingsData.notepadTransparencyOverride = -1; } } } @@ -356,7 +347,7 @@ Item { wheelEnabled: false onSliderValueChanged: newValue => { if (SettingsData.notepadTransparencyOverride >= 0) { - SettingsData.notepadTransparencyOverride = newValue / 100 + SettingsData.notepadTransparencyOverride = newValue / 100; } } } @@ -365,9 +356,7 @@ Item { StyledText { width: parent.width - text: SettingsData.notepadUseMonospace ? - "Using global monospace font from Settings → Personalization" : - "Global fonts can be configured in Settings → Personalization" + text: SettingsData.notepadUseMonospace ? "Using global monospace font from Settings → Personalization" : "Global fonts can be configured in Settings → Personalization" font.pixelSize: Theme.fontSizeSmall color: Theme.surfaceTextMedium wrapMode: Text.WordWrap @@ -375,4 +364,4 @@ Item { } } } -} \ No newline at end of file +} diff --git a/quickshell/Modules/Notepad/NotepadTabs.qml b/quickshell/Modules/Notepad/NotepadTabs.qml index ec027d88..975da5d1 100644 --- a/quickshell/Modules/Notepad/NotepadTabs.qml +++ b/quickshell/Modules/Notepad/NotepadTabs.qml @@ -1,11 +1,10 @@ +pragma ComponentBehavior: Bound import QtQuick import QtQuick.Controls import qs.Common import qs.Services import qs.Widgets -pragma ComponentBehavior: Bound - Column { id: root @@ -14,15 +13,16 @@ Column { signal tabSwitched(int tabIndex) signal tabClosed(int tabIndex) - signal newTabRequested() + signal newTabRequested function hasUnsavedChangesForTab(tab) { - if (!tab) return false + if (!tab) + return false; if (tab.id === currentTab?.id) { - return root.parent?.hasUnsavedChanges ? root.parent.hasUnsavedChanges() : false + return root.parent?.hasUnsavedChanges ? root.parent.hasUnsavedChanges() : false; } - return false + return false; } spacing: Theme.spacingXS @@ -53,11 +53,11 @@ Column { readonly property bool isActive: NotepadStorageService.currentTabIndex === index readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse readonly property real calculatedWidth: { - const textWidth = tabText.paintedWidth || 100 - const closeButtonWidth = NotepadStorageService.tabs.length > 1 ? 20 : 0 - const spacing = Theme.spacingXS - const padding = Theme.spacingM * 2 - return Math.max(120, Math.min(200, textWidth + closeButtonWidth + spacing + padding)) + const textWidth = tabText.paintedWidth || 100; + const closeButtonWidth = NotepadStorageService.tabs.length > 1 ? 20 : 0; + const spacing = Theme.spacingXS; + const padding = Theme.spacingM * 2; + return Math.max(120, Math.min(200, textWidth + closeButtonWidth + spacing + padding)); } width: calculatedWidth @@ -85,11 +85,11 @@ Column { StyledText { id: tabText text: { - var prefix = "" + var prefix = ""; if (hasUnsavedChangesForTab(modelData)) { - prefix = "● " + prefix = "● "; } - return prefix + (modelData.title || "Untitled") + return prefix + (modelData.title || "Untitled"); } font.pixelSize: Theme.fontSizeSmall color: isActive ? Theme.primary : Theme.surfaceText @@ -123,7 +123,7 @@ Column { z: 100 onClicked: { - root.tabClosed(index) + root.tabClosed(index); } } } @@ -150,4 +150,4 @@ Column { onClicked: root.newTabRequested() } } -} \ No newline at end of file +}