1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-04-17 03:02:05 -04:00

settings: make settings and file browser normal windows

- add default floating rules for dankinstall
This commit is contained in:
bbedward
2025-11-23 01:23:06 -05:00
parent 61ec0c697a
commit 1c7201fb04
10 changed files with 924 additions and 983 deletions

View File

@@ -125,6 +125,10 @@ windowrulev2 = noborder, class:^(kitty)$
windowrulev2 = float, class:^(firefox)$, title:^(Picture-in-Picture)$ windowrulev2 = float, class:^(firefox)$, title:^(Picture-in-Picture)$
windowrulev2 = float, class:^(zoom)$ 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 windowrulev2 = opacity 0.9 0.9, floating:0, focus:0
layerrule = noanim, ^(quickshell)$ layerrule = noanim, ^(quickshell)$

View File

@@ -218,6 +218,18 @@ window-rule {
geometry-corner-radius 12 geometry-corner-radius 12
clip-to-geometry true 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 { binds {
// === System & Overview === // === System & Overview ===
Mod+D { spawn "niri" "msg" "action" "toggle-overview"; } Mod+D { spawn "niri" "msg" "action" "toggle-overview"; }

View File

@@ -1236,7 +1236,6 @@ rm -rf '${home}'/.cache/icon-cache '${home}'/.cache/thumbnails 2>/dev/null || tr
const txt = settingsFile.text() const txt = settingsFile.text()
const obj = (txt && txt.trim()) ? JSON.parse(txt) : null const obj = (txt && txt.trim()) ? JSON.parse(txt) : null
Store.parse(root, obj) Store.parse(root, obj)
Store.migrate(root, obj)
} catch (e) { } catch (e) {
console.warn("SettingsData: Failed to reload settings:", e.message) console.warn("SettingsData: Failed to reload settings:", e.message)
} }

View File

@@ -508,6 +508,7 @@ Item {
hyprKeybindsModalLoader: hyprKeybindsModalLoader hyprKeybindsModalLoader: hyprKeybindsModalLoader
dankBarRepeater: dankBarRepeater dankBarRepeater: dankBarRepeater
hyprlandOverviewLoader: hyprlandOverviewLoader hyprlandOverviewLoader: hyprlandOverviewLoader
settingsModal: settingsModal
} }
Variants { Variants {

View File

@@ -15,6 +15,7 @@ Item {
required property var hyprKeybindsModalLoader required property var hyprKeybindsModalLoader
required property var dankBarRepeater required property var dankBarRepeater
required property var hyprlandOverviewLoader required property var hyprlandOverviewLoader
required property var settingsModal
function getFirstBar() { function getFirstBar() {
if (!root.dankBarRepeater || root.dankBarRepeater.count === 0) if (!root.dankBarRepeater || root.dankBarRepeater.count === 0)
@@ -529,4 +530,37 @@ Item {
target: "bar" 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"
}
} }

View File

@@ -3,26 +3,15 @@ import QtCore
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import Quickshell import Quickshell
import Quickshell.Hyprland
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Modals.Common
import qs.Modals.FileBrowser import qs.Modals.FileBrowser
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
DankModal { FloatingWindow {
id: fileBrowserModal 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 homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation)
property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation) property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation) property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation)
@@ -62,49 +51,61 @@ DankModal {
property bool pathInputHasFocus: false property bool pathInputHasFocus: false
property int actualGridColumns: 5 property int actualGridColumns: 5
property bool _initialized: false 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 fileSelected(string path)
signal dialogClosed
function open() {
visible = true;
}
function close() {
visible = false;
}
function loadSettings() { function loadSettings() {
const type = browserType || "default" const type = browserType || "default";
const settings = CacheData.fileBrowserSettings[type] const settings = CacheData.fileBrowserSettings[type];
const isImageBrowser = ["wallpaper", "profile"].includes(browserType) const isImageBrowser = ["wallpaper", "profile"].includes(browserType);
if (settings) { if (settings) {
viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list") viewMode = settings.viewMode || (isImageBrowser ? "grid" : "list");
sortBy = settings.sortBy || "name" sortBy = settings.sortBy || "name";
sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true sortAscending = settings.sortAscending !== undefined ? settings.sortAscending : true;
iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1 iconSizeIndex = settings.iconSizeIndex !== undefined ? settings.iconSizeIndex : 1;
showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true showSidebar = settings.showSidebar !== undefined ? settings.showSidebar : true;
} else { } else {
viewMode = isImageBrowser ? "grid" : "list" viewMode = isImageBrowser ? "grid" : "list";
} }
} }
function saveSettings() { function saveSettings() {
if (!_initialized) if (!_initialized)
return return;
const type = browserType || "default";
const type = browserType || "default" let settings = CacheData.fileBrowserSettings;
let settings = CacheData.fileBrowserSettings
if (!settings[type]) { if (!settings[type]) {
settings[type] = {} settings[type] = {};
} }
settings[type].viewMode = viewMode settings[type].viewMode = viewMode;
settings[type].sortBy = sortBy settings[type].sortBy = sortBy;
settings[type].sortAscending = sortAscending settings[type].sortAscending = sortAscending;
settings[type].iconSizeIndex = iconSizeIndex settings[type].iconSizeIndex = iconSizeIndex;
settings[type].showSidebar = showSidebar settings[type].showSidebar = showSidebar;
settings[type].lastPath = currentPath settings[type].lastPath = currentPath;
CacheData.fileBrowserSettings = settings CacheData.fileBrowserSettings = settings;
if (browserType === "wallpaper") { if (browserType === "wallpaper") {
CacheData.wallpaperLastPath = currentPath CacheData.wallpaperLastPath = currentPath;
} else if (browserType === "profile") { } else if (browserType === "profile") {
CacheData.profileLastPath = currentPath CacheData.profileLastPath = currentPath;
} }
CacheData.saveCache() CacheData.saveCache();
} }
onViewModeChanged: saveSettings() onViewModeChanged: saveSettings()
@@ -115,163 +116,155 @@ DankModal {
function isImageFile(fileName) { function isImageFile(fileName) {
if (!fileName) { if (!fileName) {
return false return false;
} }
const ext = fileName.toLowerCase().split('.').pop() const ext = fileName.toLowerCase().split('.').pop();
return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext) return ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp', 'svg'].includes(ext);
} }
function getLastPath() { function getLastPath() {
const type = browserType || "default" const type = browserType || "default";
const settings = CacheData.fileBrowserSettings[type] const settings = CacheData.fileBrowserSettings[type];
const lastPath = settings?.lastPath || "" const lastPath = settings?.lastPath || "";
return (lastPath && lastPath !== "") ? lastPath : homeDir return (lastPath && lastPath !== "") ? lastPath : homeDir;
} }
function saveLastPath(path) { function saveLastPath(path) {
const type = browserType || "default" const type = browserType || "default";
let settings = CacheData.fileBrowserSettings let settings = CacheData.fileBrowserSettings;
if (!settings[type]) { if (!settings[type]) {
settings[type] = {} settings[type] = {};
} }
settings[type].lastPath = path settings[type].lastPath = path;
CacheData.fileBrowserSettings = settings CacheData.fileBrowserSettings = settings;
CacheData.saveCache() CacheData.saveCache();
if (browserType === "wallpaper") { if (browserType === "wallpaper") {
CacheData.wallpaperLastPath = path CacheData.wallpaperLastPath = path;
} else if (browserType === "profile") { } else if (browserType === "profile") {
CacheData.profileLastPath = path CacheData.profileLastPath = path;
} }
} }
function setSelectedFileData(path, name, isDir) { function setSelectedFileData(path, name, isDir) {
selectedFilePath = path selectedFilePath = path;
selectedFileName = name selectedFileName = name;
selectedFileIsDir = isDir selectedFileIsDir = isDir;
} }
function navigateUp() { function navigateUp() {
const path = currentPath const path = currentPath;
if (path === homeDir) if (path === homeDir)
return return;
const lastSlash = path.lastIndexOf('/');
const lastSlash = path.lastIndexOf('/')
if (lastSlash > 0) { if (lastSlash > 0) {
const newPath = path.substring(0, lastSlash) const newPath = path.substring(0, lastSlash);
if (newPath.length < homeDir.length) { if (newPath.length < homeDir.length) {
currentPath = homeDir currentPath = homeDir;
saveLastPath(homeDir) saveLastPath(homeDir);
} else { } else {
currentPath = newPath currentPath = newPath;
saveLastPath(newPath) saveLastPath(newPath);
} }
} }
} }
function navigateTo(path) { function navigateTo(path) {
currentPath = path currentPath = path;
saveLastPath(path) saveLastPath(path);
selectedIndex = -1 selectedIndex = -1;
backButtonFocused = false backButtonFocused = false;
} }
function keyboardFileSelection(index) { function keyboardFileSelection(index) {
if (index >= 0) { if (index >= 0) {
keyboardSelectionTimer.targetIndex = index keyboardSelectionTimer.targetIndex = index;
keyboardSelectionTimer.start() keyboardSelectionTimer.start();
} }
} }
function executeKeyboardSelection(index) { function executeKeyboardSelection(index) {
keyboardSelectionIndex = index keyboardSelectionIndex = index;
keyboardSelectionRequested = true keyboardSelectionRequested = true;
} }
function handleSaveFile(filePath) { function handleSaveFile(filePath) {
var normalizedPath = filePath var normalizedPath = filePath;
if (!normalizedPath.startsWith("file://")) { if (!normalizedPath.startsWith("file://")) {
normalizedPath = "file://" + filePath normalizedPath = "file://" + filePath;
} }
var exists = false var exists = false;
var fileName = filePath.split('/').pop() var fileName = filePath.split('/').pop();
for (var i = 0; i < folderModel.count; i++) { for (var i = 0; i < folderModel.count; i++) {
if (folderModel.get(i, "fileName") === fileName && !folderModel.get(i, "fileIsDir")) { if (folderModel.get(i, "fileName") === fileName && !folderModel.get(i, "fileIsDir")) {
exists = true exists = true;
break break;
} }
} }
if (exists) { if (exists) {
pendingFilePath = normalizedPath pendingFilePath = normalizedPath;
showOverwriteConfirmation = true showOverwriteConfirmation = true;
} else { } else {
fileSelected(normalizedPath) fileSelected(normalizedPath);
fileBrowserModal.close() fileBrowserModal.close();
} }
} }
objectName: "fileBrowserModal" objectName: "fileBrowserModal"
allowStacking: true title: "Files - " + browserTitle
closeOnEscapeKey: false implicitWidth: 800
shouldHaveFocus: shouldBeVisible implicitHeight: 600
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
visible: false
Component.onCompleted: { Component.onCompleted: {
loadSettings() loadSettings();
currentPath = getLastPath() currentPath = getLastPath();
_initialized = true _initialized = true;
} }
property var steamPaths: [StandardPaths.writableLocation(StandardPaths.HomeLocation) + "/.steam/steam/steamapps/workshop/content/431960", StandardPaths.writableLocation( 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"]
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 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: { onVisibleChanged: {
if (visible) { if (visible) {
currentPath = getLastPath() if (parentModal) {
selectedIndex = -1 parentModal.shouldHaveFocus = false;
keyboardNavigationActive = false parentModal.allowFocusOverride = true;
backButtonFocused = false }
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: { onCurrentPathChanged: {
selectedFilePath = "" selectedFilePath = "";
selectedFileName = "" selectedFileName = "";
selectedFileIsDir = false selectedFileIsDir = false;
saveSettings() saveSettings();
} }
onSelectedIndexChanged: { onSelectedIndexChanged: {
if (selectedIndex >= 0 && folderModel && selectedIndex < folderModel.count) { if (selectedIndex >= 0 && folderModel && selectedIndex < folderModel.count) {
selectedFilePath = "" selectedFilePath = "";
selectedFileName = "" selectedFileName = "";
selectedFileIsDir = false selectedFileIsDir = false;
} }
} }
@@ -288,49 +281,57 @@ DankModal {
sortField: { sortField: {
switch (sortBy) { switch (sortBy) {
case "name": case "name":
return FolderListModel.Name return FolderListModel.Name;
case "size": case "size":
return FolderListModel.Size return FolderListModel.Size;
case "modified": case "modified":
return FolderListModel.Time return FolderListModel.Time;
case "type": case "type":
return FolderListModel.Type return FolderListModel.Type;
default: default:
return FolderListModel.Name return FolderListModel.Name;
} }
} }
sortReversed: !sortAscending sortReversed: !sortAscending
} }
property var quickAccessLocations: [{ property var quickAccessLocations: [
{
"name": "Home", "name": "Home",
"path": homeDir, "path": homeDir,
"icon": "home" "icon": "home"
}, { },
{
"name": "Documents", "name": "Documents",
"path": docsDir, "path": docsDir,
"icon": "description" "icon": "description"
}, { },
{
"name": "Downloads", "name": "Downloads",
"path": downloadDir, "path": downloadDir,
"icon": "download" "icon": "download"
}, { },
{
"name": "Pictures", "name": "Pictures",
"path": picsDir, "path": picsDir,
"icon": "image" "icon": "image"
}, { },
{
"name": "Music", "name": "Music",
"path": musicDir, "path": musicDir,
"icon": "music_note" "icon": "music_note"
}, { },
{
"name": "Videos", "name": "Videos",
"path": videosDir, "path": videosDir,
"icon": "movie" "icon": "movie"
}, { },
{
"name": "Desktop", "name": "Desktop",
"path": desktopDir, "path": desktopDir,
"icon": "computer" "icon": "computer"
}] }
]
QtObject { QtObject {
id: keyboardController id: keyboardController
@@ -340,213 +341,210 @@ DankModal {
function handleKey(event) { function handleKey(event) {
if (event.key === Qt.Key_Escape) { if (event.key === Qt.Key_Escape) {
close() close();
event.accepted = true event.accepted = true;
return return;
} }
if (event.key === Qt.Key_F10) { if (event.key === Qt.Key_F10) {
showKeyboardHints = !showKeyboardHints showKeyboardHints = !showKeyboardHints;
event.accepted = true event.accepted = true;
return return;
} }
if (event.key === Qt.Key_F1 || event.key === Qt.Key_I) { if (event.key === Qt.Key_F1 || event.key === Qt.Key_I) {
showFileInfo = !showFileInfo showFileInfo = !showFileInfo;
event.accepted = true event.accepted = true;
return return;
} }
if ((event.modifiers & Qt.AltModifier && event.key === Qt.Key_Left) || event.key === Qt.Key_Backspace) { if ((event.modifiers & Qt.AltModifier && event.key === Qt.Key_Left) || event.key === Qt.Key_Backspace) {
if (currentPath !== homeDir) { if (currentPath !== homeDir) {
navigateUp() navigateUp();
event.accepted = true event.accepted = true;
} }
return return;
} }
if (!keyboardNavigationActive) { if (!keyboardNavigationActive) {
const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key 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);
=== 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) { if (isInitKey) {
keyboardNavigationActive = true keyboardNavigationActive = true;
if (currentPath !== homeDir) { if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} else { } else {
backButtonFocused = false backButtonFocused = false;
selectedIndex = 0 selectedIndex = 0;
} }
event.accepted = true event.accepted = true;
} }
return return;
} }
switch (event.key) { switch (event.key) {
case Qt.Key_Tab: case Qt.Key_Tab:
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
selectedIndex = 0 selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) { } else if (selectedIndex < totalItems - 1) {
selectedIndex++ selectedIndex++;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} else { } else {
selectedIndex = 0 selectedIndex = 0;
} }
event.accepted = true event.accepted = true;
break break;
case Qt.Key_Backtab: case Qt.Key_Backtab:
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
selectedIndex = totalItems - 1 selectedIndex = totalItems - 1;
} else if (selectedIndex > 0) { } else if (selectedIndex > 0) {
selectedIndex-- selectedIndex--;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} else { } else {
selectedIndex = totalItems - 1 selectedIndex = totalItems - 1;
} }
event.accepted = true event.accepted = true;
break break;
case Qt.Key_N: case Qt.Key_N:
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
selectedIndex = 0 selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) { } else if (selectedIndex < totalItems - 1) {
selectedIndex++ selectedIndex++;
} }
event.accepted = true event.accepted = true;
} }
break break;
case Qt.Key_P: case Qt.Key_P:
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) { if (selectedIndex > 0) {
selectedIndex-- selectedIndex--;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} }
event.accepted = true event.accepted = true;
} }
break break;
case Qt.Key_J: case Qt.Key_J:
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex < totalItems - 1) { if (selectedIndex < totalItems - 1) {
selectedIndex++ selectedIndex++;
} }
event.accepted = true event.accepted = true;
} }
break break;
case Qt.Key_K: case Qt.Key_K:
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
if (selectedIndex > 0) { if (selectedIndex > 0) {
selectedIndex-- selectedIndex--;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} }
event.accepted = true event.accepted = true;
} }
break break;
case Qt.Key_H: case Qt.Key_H:
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
if (!backButtonFocused && selectedIndex > 0) { if (!backButtonFocused && selectedIndex > 0) {
selectedIndex-- selectedIndex--;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} }
event.accepted = true event.accepted = true;
} }
break break;
case Qt.Key_L: case Qt.Key_L:
if (event.modifiers & Qt.ControlModifier) { if (event.modifiers & Qt.ControlModifier) {
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
selectedIndex = 0 selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) { } else if (selectedIndex < totalItems - 1) {
selectedIndex++ selectedIndex++;
} }
event.accepted = true event.accepted = true;
} }
break break;
case Qt.Key_Left: case Qt.Key_Left:
if (pathInputHasFocus) if (pathInputHasFocus)
return return;
if (backButtonFocused) if (backButtonFocused)
return return;
if (selectedIndex > 0) { if (selectedIndex > 0) {
selectedIndex-- selectedIndex--;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} }
event.accepted = true event.accepted = true;
break break;
case Qt.Key_Right: case Qt.Key_Right:
if (pathInputHasFocus) if (pathInputHasFocus)
return return;
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
selectedIndex = 0 selectedIndex = 0;
} else if (selectedIndex < totalItems - 1) { } else if (selectedIndex < totalItems - 1) {
selectedIndex++ selectedIndex++;
} }
event.accepted = true event.accepted = true;
break break;
case Qt.Key_Up: case Qt.Key_Up:
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
if (gridColumns === 1) { if (gridColumns === 1) {
selectedIndex = 0 selectedIndex = 0;
} else { } else {
var col = selectedIndex % gridColumns var col = selectedIndex % gridColumns;
selectedIndex = Math.min(col, totalItems - 1) selectedIndex = Math.min(col, totalItems - 1);
} }
} else if (selectedIndex >= gridColumns) { } else if (selectedIndex >= gridColumns) {
selectedIndex -= gridColumns selectedIndex -= gridColumns;
} else if (selectedIndex > 0 && gridColumns === 1) { } else if (selectedIndex > 0 && gridColumns === 1) {
selectedIndex-- selectedIndex--;
} else if (currentPath !== homeDir) { } else if (currentPath !== homeDir) {
backButtonFocused = true backButtonFocused = true;
selectedIndex = -1 selectedIndex = -1;
} }
event.accepted = true event.accepted = true;
break break;
case Qt.Key_Down: case Qt.Key_Down:
if (backButtonFocused) { if (backButtonFocused) {
backButtonFocused = false backButtonFocused = false;
selectedIndex = 0 selectedIndex = 0;
} else if (gridColumns === 1) { } else if (gridColumns === 1) {
if (selectedIndex < totalItems - 1) { if (selectedIndex < totalItems - 1) {
selectedIndex++ selectedIndex++;
} }
} else { } else {
var newIndex = selectedIndex + gridColumns var newIndex = selectedIndex + gridColumns;
if (newIndex < totalItems) { if (newIndex < totalItems) {
selectedIndex = newIndex selectedIndex = newIndex;
} else { } else {
var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns var lastRowStart = Math.floor((totalItems - 1) / gridColumns) * gridColumns;
var col = selectedIndex % gridColumns var col = selectedIndex % gridColumns;
var targetIndex = lastRowStart + col var targetIndex = lastRowStart + col;
if (targetIndex < totalItems && targetIndex > selectedIndex) { if (targetIndex < totalItems && targetIndex > selectedIndex) {
selectedIndex = targetIndex selectedIndex = targetIndex;
} }
} }
} }
event.accepted = true event.accepted = true;
break break;
case Qt.Key_Return: case Qt.Key_Return:
case Qt.Key_Enter: case Qt.Key_Enter:
case Qt.Key_Space: case Qt.Key_Space:
if (backButtonFocused) if (backButtonFocused)
navigateUp() navigateUp();
else if (selectedIndex >= 0 && selectedIndex < totalItems) else if (selectedIndex >= 0 && selectedIndex < totalItems)
fileBrowserModal.keyboardFileSelection(selectedIndex) fileBrowserModal.keyboardFileSelection(selectedIndex);
event.accepted = true event.accepted = true;
break break;
} }
} }
} }
@@ -558,22 +556,18 @@ DankModal {
interval: 1 interval: 1
onTriggered: { onTriggered: {
executeKeyboardSelection(targetIndex) executeKeyboardSelection(targetIndex);
} }
} }
content: Component { FocusScope {
Item { id: contentFocusScope
anchors.fill: parent anchors.fill: parent
focus: true
Keys.onPressed: event => { Keys.onPressed: event => {
keyboardController.handleKey(event) keyboardController.handleKey(event);
}
onVisibleChanged: {
if (visible) {
forceActiveFocus()
}
} }
Column { Column {
@@ -705,9 +699,9 @@ DankModal {
onNavigateUp: fileBrowserModal.navigateUp() onNavigateUp: fileBrowserModal.navigateUp()
onNavigateTo: path => fileBrowserModal.navigateTo(path) onNavigateTo: path => fileBrowserModal.navigateTo(path)
onPathInputFocusChanged: hasFocus => { onPathInputFocusChanged: hasFocus => {
fileBrowserModal.pathInputHasFocus = hasFocus fileBrowserModal.pathInputHasFocus = hasFocus;
if (hasFocus) { if (hasFocus) {
fileBrowserModal.pathEditMode = true fileBrowserModal.pathEditMode = true;
} }
} }
} }
@@ -731,10 +725,10 @@ DankModal {
property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2) property real gridLeftMargin: Theme.spacingM + Math.max(0, (availableGridWidth - (gridColumns * gridCellWidth)) / 2)
onGridColumnsChanged: { onGridColumnsChanged: {
fileBrowserModal.actualGridColumns = gridColumns fileBrowserModal.actualGridColumns = gridColumns;
} }
Component.onCompleted: { Component.onCompleted: {
fileBrowserModal.actualGridColumns = gridColumns fileBrowserModal.actualGridColumns = gridColumns;
} }
DankGridView { DankGridView {
@@ -752,7 +746,7 @@ DankModal {
currentIndex: selectedIndex currentIndex: selectedIndex
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0) if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, GridView.Contain) positionViewAtIndex(currentIndex, GridView.Contain);
} }
ScrollBar.vertical: DankScrollbar { ScrollBar.vertical: DankScrollbar {
@@ -769,30 +763,30 @@ DankModal {
selectedIndex: fileBrowserModal.selectedIndex selectedIndex: fileBrowserModal.selectedIndex
keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive
onItemClicked: (index, path, name, isDir) => { onItemClicked: (index, path, name, isDir) => {
selectedIndex = index selectedIndex = index;
setSelectedFileData(path, name, isDir) setSelectedFileData(path, name, isDir);
if (isDir) { if (isDir) {
navigateTo(path) navigateTo(path);
} else { } else {
fileSelected(path) fileSelected(path);
fileBrowserModal.close() fileBrowserModal.close();
} }
} }
onItemSelected: (index, path, name, isDir) => { onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir) setSelectedFileData(path, name, isDir);
} }
Connections { Connections {
function onKeyboardSelectionRequestedChanged() { function onKeyboardSelectionRequestedChanged() {
if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) { if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) {
fileBrowserModal.keyboardSelectionRequested = false fileBrowserModal.keyboardSelectionRequested = false;
selectedIndex = index selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir) setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) { if (fileIsDir) {
navigateTo(filePath) navigateTo(filePath);
} else { } else {
fileSelected(filePath) fileSelected(filePath);
fileBrowserModal.close() fileBrowserModal.close();
} }
} }
} }
@@ -815,7 +809,7 @@ DankModal {
currentIndex: selectedIndex currentIndex: selectedIndex
onCurrentIndexChanged: { onCurrentIndexChanged: {
if (keyboardNavigationActive && currentIndex >= 0) if (keyboardNavigationActive && currentIndex >= 0)
positionViewAtIndex(currentIndex, ListView.Contain) positionViewAtIndex(currentIndex, ListView.Contain);
} }
ScrollBar.vertical: DankScrollbar { ScrollBar.vertical: DankScrollbar {
@@ -827,30 +821,30 @@ DankModal {
selectedIndex: fileBrowserModal.selectedIndex selectedIndex: fileBrowserModal.selectedIndex
keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive keyboardNavigationActive: fileBrowserModal.keyboardNavigationActive
onItemClicked: (index, path, name, isDir) => { onItemClicked: (index, path, name, isDir) => {
selectedIndex = index selectedIndex = index;
setSelectedFileData(path, name, isDir) setSelectedFileData(path, name, isDir);
if (isDir) { if (isDir) {
navigateTo(path) navigateTo(path);
} else { } else {
fileSelected(path) fileSelected(path);
fileBrowserModal.close() fileBrowserModal.close();
} }
} }
onItemSelected: (index, path, name, isDir) => { onItemSelected: (index, path, name, isDir) => {
setSelectedFileData(path, name, isDir) setSelectedFileData(path, name, isDir);
} }
Connections { Connections {
function onKeyboardSelectionRequestedChanged() { function onKeyboardSelectionRequestedChanged() {
if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) { if (fileBrowserModal.keyboardSelectionRequested && fileBrowserModal.keyboardSelectionIndex === index) {
fileBrowserModal.keyboardSelectionRequested = false fileBrowserModal.keyboardSelectionRequested = false;
selectedIndex = index selectedIndex = index;
setSelectedFileData(filePath, fileName, fileIsDir) setSelectedFileData(filePath, fileName, fileIsDir);
if (fileIsDir) { if (fileIsDir) {
navigateTo(filePath) navigateTo(filePath);
} else { } else {
fileSelected(filePath) fileSelected(filePath);
fileBrowserModal.close() fileBrowserModal.close();
} }
} }
} }
@@ -899,10 +893,10 @@ DankModal {
currentFileIsDir: fileBrowserModal.selectedFileIsDir currentFileIsDir: fileBrowserModal.selectedFileIsDir
currentFileExtension: { currentFileExtension: {
if (fileBrowserModal.selectedFileIsDir || !fileBrowserModal.selectedFileName) if (fileBrowserModal.selectedFileIsDir || !fileBrowserModal.selectedFileName)
return "" return "";
var lastDot = fileBrowserModal.selectedFileName.lastIndexOf('.') var lastDot = fileBrowserModal.selectedFileName.lastIndexOf('.');
return lastDot > 0 ? fileBrowserModal.selectedFileName.substring(lastDot + 1).toLowerCase() : "" return lastDot > 0 ? fileBrowserModal.selectedFileName.substring(lastDot + 1).toLowerCase() : "";
} }
} }
@@ -915,11 +909,10 @@ DankModal {
sortBy: fileBrowserModal.sortBy sortBy: fileBrowserModal.sortBy
sortAscending: fileBrowserModal.sortAscending sortAscending: fileBrowserModal.sortAscending
onSortBySelected: value => { onSortBySelected: value => {
fileBrowserModal.sortBy = value fileBrowserModal.sortBy = value;
} }
onSortOrderSelected: ascending => { onSortOrderSelected: ascending => {
fileBrowserModal.sortAscending = ascending fileBrowserModal.sortAscending = ascending;
}
} }
} }
} }
@@ -929,14 +922,14 @@ DankModal {
showDialog: showOverwriteConfirmation showDialog: showOverwriteConfirmation
pendingFilePath: fileBrowserModal.pendingFilePath pendingFilePath: fileBrowserModal.pendingFilePath
onConfirmed: filePath => { onConfirmed: filePath => {
showOverwriteConfirmation = false showOverwriteConfirmation = false;
fileSelected(filePath) fileSelected(filePath);
pendingFilePath = "" pendingFilePath = "";
Qt.callLater(() => fileBrowserModal.close()) Qt.callLater(() => fileBrowserModal.close());
} }
onCancelled: { onCancelled: {
showOverwriteConfirmation = false showOverwriteConfirmation = false;
pendingFilePath = "" pendingFilePath = "";
} }
} }
} }

View File

@@ -1,124 +1,52 @@
import QtQuick import QtQuick
import QtQuick.Effects
import Quickshell import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import qs.Common import qs.Common
import qs.Modals.Common
import qs.Modals.FileBrowser import qs.Modals.FileBrowser
import qs.Modules.Settings
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
DankModal { FloatingWindow {
id: settingsModal id: settingsModal
layerNamespace: "dms:settings"
HyprlandFocusGrab {
windows: [settingsModal]
active: CompositorService.isHyprland && settingsModal.shouldHaveFocus
}
property Component settingsContent
property alias profileBrowser: profileBrowser property alias profileBrowser: profileBrowser
property alias wallpaperBrowser: wallpaperBrowser
property int currentTabIndex: 0 property int currentTabIndex: 0
property bool shouldHaveFocus: visible
property bool allowFocusOverride: false
property alias shouldBeVisible: settingsModal.visible
signal closingModal() signal closingModal
function show() { function show() {
open(); visible = true;
} }
function hide() { function hide() {
close(); visible = false;
} }
function toggle() { function toggle() {
if (shouldBeVisible) { visible = !visible;
hide();
} else {
show();
}
} }
objectName: "settingsModal" objectName: "settingsModal"
width: Math.min(800, screenWidth * 0.9) title: "Settings"
height: Math.min(800, screenHeight * 0.85) implicitWidth: 800
backgroundColor: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency) implicitHeight: 800
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
visible: false visible: false
onBackgroundClicked: () => {
return hide();
}
content: settingsContent
onOpened: () => {
Qt.callLater(() => {
modalFocusScope.forceActiveFocus()
if (contentLoader.item) {
contentLoader.item.forceActiveFocus()
}
})
}
onVisibleChanged: { onVisibleChanged: {
if (visible && shouldBeVisible) { if (!visible) {
closingModal();
} else {
Qt.callLater(() => { Qt.callLater(() => {
modalFocusScope.forceActiveFocus() if (contentFocusScope) {
if (contentLoader.item) { contentFocusScope.forceActiveFocus();
contentLoader.item.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 { FileBrowserModal {
id: profileBrowser id: profileBrowser
@@ -130,20 +58,12 @@ DankModal {
browserType: "profile" browserType: "profile"
showHiddenFiles: true showHiddenFiles: true
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
onFileSelected: (path) => { onFileSelected: path => {
PortalService.setProfileImage(path); PortalService.setProfileImage(path);
close(); close();
} }
onDialogClosed: () => { onDialogClosed: () => {
allowStacking = true; allowStacking = true;
if (settingsModal.shouldBeVisible) {
Qt.callLater(() => {
settingsModal.modalFocusScope.forceActiveFocus()
if (settingsModal.contentLoader.item) {
settingsModal.contentLoader.item.forceActiveFocus()
}
})
}
} }
} }
@@ -157,31 +77,48 @@ DankModal {
browserType: "wallpaper" browserType: "wallpaper"
showHiddenFiles: true showHiddenFiles: true
fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"] fileExtensions: ["*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp"]
onFileSelected: (path) => { onFileSelected: path => {
SessionData.setWallpaper(path); SessionData.setWallpaper(path);
close(); close();
} }
onDialogClosed: () => { onDialogClosed: () => {
allowStacking = true; allowStacking = true;
if (settingsModal.shouldBeVisible) {
Qt.callLater(() => {
settingsModal.modalFocusScope.forceActiveFocus()
if (settingsModal.contentLoader.item) {
settingsModal.contentLoader.item.forceActiveFocus()
}
})
}
} }
} }
settingsContent: Component { FocusScope {
Item { id: contentFocusScope
id: rootScope
anchors.fill: parent anchors.fill: parent
focus: true
Keys.onEscapePressed: event => { Keys.onPressed: event => {
settingsModal.hide() const tabCount = 11;
event.accepted = true 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 { Column {
@@ -215,7 +152,6 @@ DankModal {
font.weight: Font.Medium font.weight: Font.Medium
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
} }
} }
DankActionButton { DankActionButton {
@@ -226,10 +162,9 @@ DankModal {
iconSize: Theme.iconSize - 4 iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
onClicked: () => { onClicked: () => {
return settingsModal.hide(); settingsModal.hide();
} }
} }
} }
Row { Row {
@@ -243,7 +178,7 @@ DankModal {
parentModal: settingsModal parentModal: settingsModal
currentIndex: settingsModal.currentTabIndex currentIndex: settingsModal.currentTabIndex
onCurrentIndexChanged: { onCurrentIndexChanged: {
settingsModal.currentTabIndex = currentIndex settingsModal.currentTabIndex = currentIndex;
} }
} }
@@ -255,13 +190,7 @@ DankModal {
parentModal: settingsModal parentModal: settingsModal
currentIndex: settingsModal.currentTabIndex currentIndex: settingsModal.currentTabIndex
} }
} }
} }
} }
}
} }

View File

@@ -1,8 +1,5 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Controls
import QtCore
import Quickshell
import Quickshell.Wayland
import Quickshell.Io import Quickshell.Io
import qs.Common import qs.Common
import qs.Modals.Common import qs.Modals.Common
@@ -10,8 +7,6 @@ import qs.Modals.FileBrowser
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
pragma ComponentBehavior: Bound
Item { Item {
id: root id: root
@@ -26,119 +21,119 @@ Item {
property bool showSettingsMenu: false property bool showSettingsMenu: false
property string pendingSaveContent: "" property string pendingSaveContent: ""
signal hideRequested() signal hideRequested
Ref { Ref {
service: NotepadStorageService service: NotepadStorageService
} }
function hasUnsavedChanges() { function hasUnsavedChanges() {
return textEditor.hasUnsavedChanges() return textEditor.hasUnsavedChanges();
} }
function hasUnsavedTemporaryContent() { function hasUnsavedTemporaryContent() {
return hasUnsavedChanges() return hasUnsavedChanges();
} }
function createNewTab() { function createNewTab() {
performCreateNewTab() performCreateNewTab();
} }
function performCreateNewTab() { function performCreateNewTab() {
NotepadStorageService.createNewTab() NotepadStorageService.createNewTab();
textEditor.text = "" textEditor.text = "";
textEditor.lastSavedContent = "" textEditor.lastSavedContent = "";
textEditor.contentLoaded = true textEditor.contentLoaded = true;
textEditor.textArea.forceActiveFocus() textEditor.textArea.forceActiveFocus();
} }
function closeTab(tabIndex) { function closeTab(tabIndex) {
if (tabIndex === NotepadStorageService.currentTabIndex && hasUnsavedChanges()) { if (tabIndex === NotepadStorageService.currentTabIndex && hasUnsavedChanges()) {
root.pendingAction = "close_tab_" + tabIndex root.pendingAction = "close_tab_" + tabIndex;
root.confirmationDialogOpen = true root.confirmationDialogOpen = true;
confirmationDialog.open() confirmationDialog.open();
} else { } else {
performCloseTab(tabIndex) performCloseTab(tabIndex);
} }
} }
function performCloseTab(tabIndex) { function performCloseTab(tabIndex) {
NotepadStorageService.closeTab(tabIndex) NotepadStorageService.closeTab(tabIndex);
Qt.callLater(() => { Qt.callLater(() => {
textEditor.loadCurrentTabContent() textEditor.loadCurrentTabContent();
}) });
} }
function switchToTab(tabIndex) { function switchToTab(tabIndex) {
if (tabIndex < 0 || tabIndex >= NotepadStorageService.tabs.length) return if (tabIndex < 0 || tabIndex >= NotepadStorageService.tabs.length)
return;
if (textEditor.contentLoaded) { if (textEditor.contentLoaded) {
textEditor.autoSaveToSession() textEditor.autoSaveToSession();
} }
NotepadStorageService.switchToTab(tabIndex) NotepadStorageService.switchToTab(tabIndex);
Qt.callLater(() => { Qt.callLater(() => {
textEditor.loadCurrentTabContent() textEditor.loadCurrentTabContent();
if (currentTab) { if (currentTab) {
root.currentFileName = currentTab.fileName || "" root.currentFileName = currentTab.fileName || "";
root.currentFileUrl = currentTab.fileUrl || "" root.currentFileUrl = currentTab.fileUrl || "";
} }
}) });
} }
function saveToFile(fileUrl) { function saveToFile(fileUrl) {
if (!currentTab) return if (!currentTab)
return;
var content = textEditor.text;
var filePath = fileUrl.toString().replace(/^file:\/\//, '');
var content = textEditor.text saveFileView.path = "";
var filePath = fileUrl.toString().replace(/^file:\/\//, '') pendingSaveContent = content;
saveFileView.path = filePath;
saveFileView.path = ""
pendingSaveContent = content
saveFileView.path = filePath
Qt.callLater(() => { Qt.callLater(() => {
saveFileView.setText(pendingSaveContent) saveFileView.setText(pendingSaveContent);
}) });
} }
function loadFromFile(fileUrl) { function loadFromFile(fileUrl) {
if (hasUnsavedTemporaryContent()) { if (hasUnsavedTemporaryContent()) {
root.pendingFileUrl = fileUrl root.pendingFileUrl = fileUrl;
root.pendingAction = "load_file" root.pendingAction = "load_file";
root.confirmationDialogOpen = true root.confirmationDialogOpen = true;
confirmationDialog.open() confirmationDialog.open();
} else { } else {
performLoadFromFile(fileUrl) performLoadFromFile(fileUrl);
} }
} }
function performLoadFromFile(fileUrl) { function performLoadFromFile(fileUrl) {
const filePath = fileUrl.toString().replace(/^file:\/\//, '') const filePath = fileUrl.toString().replace(/^file:\/\//, '');
const fileName = filePath.split('/').pop() const fileName = filePath.split('/').pop();
loadFileView.path = "" loadFileView.path = "";
loadFileView.path = filePath loadFileView.path = filePath;
if (loadFileView.waitForJob()) { if (loadFileView.waitForJob()) {
Qt.callLater(() => { Qt.callLater(() => {
var content = loadFileView.text() var content = loadFileView.text();
if (currentTab && content !== undefined && content !== null) { if (currentTab && content !== undefined && content !== null) {
textEditor.text = content textEditor.text = content;
textEditor.lastSavedContent = content textEditor.lastSavedContent = content;
textEditor.contentLoaded = true textEditor.contentLoaded = true;
root.lastSavedFileContent = content root.lastSavedFileContent = content;
NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, {
title: fileName, title: fileName,
filePath: filePath, filePath: filePath,
isTemporary: false isTemporary: false
}) });
root.currentFileName = fileName root.currentFileName = fileName;
root.currentFileUrl = fileUrl root.currentFileUrl = fileUrl;
textEditor.saveCurrentTabContent() textEditor.saveCurrentTabContent();
} }
}) });
} }
} }
@@ -151,16 +146,16 @@ Item {
width: parent.width width: parent.width
contentLoaded: textEditor.contentLoaded contentLoaded: textEditor.contentLoaded
onTabSwitched: (tabIndex) => { onTabSwitched: tabIndex => {
switchToTab(tabIndex) switchToTab(tabIndex);
} }
onTabClosed: (tabIndex) => { onTabClosed: tabIndex => {
closeTab(tabIndex) closeTab(tabIndex);
} }
onNewTabRequested: { onNewTabRequested: {
createNewTab() createNewTab();
} }
} }
@@ -171,41 +166,41 @@ Item {
onSaveRequested: { onSaveRequested: {
if (currentTab && !currentTab.isTemporary && currentTab.filePath) { if (currentTab && !currentTab.isTemporary && currentTab.filePath) {
var fileUrl = "file://" + currentTab.filePath var fileUrl = "file://" + currentTab.filePath;
saveToFile(fileUrl) saveToFile(fileUrl);
} else { } else {
root.fileDialogOpen = true root.fileDialogOpen = true;
saveBrowser.open() saveBrowser.open();
} }
} }
onOpenRequested: { onOpenRequested: {
if (hasUnsavedChanges()) { if (hasUnsavedChanges()) {
root.pendingAction = "open" root.pendingAction = "open";
root.confirmationDialogOpen = true root.confirmationDialogOpen = true;
confirmationDialog.open() confirmationDialog.open();
} else { } else {
root.fileDialogOpen = true root.fileDialogOpen = true;
loadBrowser.open() loadBrowser.open();
} }
} }
onNewRequested: { onNewRequested: {
if (hasUnsavedChanges()) { if (hasUnsavedChanges()) {
root.pendingAction = "new" root.pendingAction = "new";
root.confirmationDialogOpen = true root.confirmationDialogOpen = true;
confirmationDialog.open() confirmationDialog.open();
} else { } else {
createNewTab() createNewTab();
} }
} }
onEscapePressed: { onEscapePressed: {
root.hideRequested() root.hideRequested();
} }
onSettingsRequested: { onSettingsRequested: {
showSettingsMenu = !showSettingsMenu showSettingsMenu = !showSettingsMenu;
} }
} }
} }
@@ -216,8 +211,8 @@ Item {
isVisible: showSettingsMenu isVisible: showSettingsMenu
onSettingsRequested: showSettingsMenu = !showSettingsMenu onSettingsRequested: showSettingsMenu = !showSettingsMenu
onFindRequested: { onFindRequested: {
showSettingsMenu = false showSettingsMenu = false;
textEditor.showSearch() textEditor.showSearch();
} }
} }
@@ -233,14 +228,14 @@ Item {
NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, { NotepadStorageService.updateTabMetadata(NotepadStorageService.currentTabIndex, {
hasUnsavedChanges: false, hasUnsavedChanges: false,
lastSavedContent: pendingSaveContent lastSavedContent: pendingSaveContent
}) });
root.lastSavedFileContent = pendingSaveContent root.lastSavedFileContent = pendingSaveContent;
pendingSaveContent = "" pendingSaveContent = "";
} }
} }
onSaveFailed: (error) => { onSaveFailed: error => {
pendingSaveContent = "" pendingSaveContent = "";
} }
} }
@@ -251,8 +246,7 @@ Item {
atomicWrites: true atomicWrites: true
printErrors: true printErrors: true
onLoadFailed: (error) => { onLoadFailed: error => {}
}
} }
FileBrowserModal { FileBrowserModal {
@@ -266,56 +260,51 @@ Item {
saveMode: true saveMode: true
defaultFileName: { defaultFileName: {
if (currentTab && currentTab.title && currentTab.title !== "Untitled") { if (currentTab && currentTab.title && currentTab.title !== "Untitled") {
return currentTab.title return currentTab.title;
} else if (currentTab && !currentTab.isTemporary && currentTab.filePath) { } else if (currentTab && !currentTab.isTemporary && currentTab.filePath) {
return currentTab.filePath.split('/').pop() return currentTab.filePath.split('/').pop();
} else { } 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.currentFileName = fileName;
root.fileDialogOpen = false root.currentFileUrl = fileUrl;
const cleanPath = path.toString().replace(/^file:\/\//, '')
const fileName = cleanPath.split('/').pop()
const fileUrl = "file://" + cleanPath
root.currentFileName = fileName
root.currentFileUrl = fileUrl
if (currentTab) { if (currentTab) {
NotepadStorageService.saveTabAs( NotepadStorageService.saveTabAs(NotepadStorageService.currentTabIndex, cleanPath);
NotepadStorageService.currentTabIndex,
cleanPath
)
} }
saveToFile(fileUrl) saveToFile(fileUrl);
if (root.pendingAction === "new") { if (root.pendingAction === "new") {
Qt.callLater(() => { Qt.callLater(() => {
createNewTab() createNewTab();
}) });
} else if (root.pendingAction === "open") { } else if (root.pendingAction === "open") {
Qt.callLater(() => { Qt.callLater(() => {
root.fileDialogOpen = true root.fileDialogOpen = true;
loadBrowser.open() loadBrowser.open();
}) });
} else if (root.pendingAction.startsWith("close_tab_")) { } else if (root.pendingAction.startsWith("close_tab_")) {
Qt.callLater(() => { Qt.callLater(() => {
var tabIndex = parseInt(root.pendingAction.split("_")[2]) var tabIndex = parseInt(root.pendingAction.split("_")[2]);
performCloseTab(tabIndex) performCloseTab(tabIndex);
}) });
} }
root.pendingAction = "" root.pendingAction = "";
close() close();
} }
onDialogClosed: { onDialogClosed: {
root.fileDialogOpen = false root.fileDialogOpen = false;
} }
} }
@@ -328,23 +317,21 @@ Item {
fileExtensions: ["*.txt", "*.md", "*.*"] fileExtensions: ["*.txt", "*.md", "*.*"]
allowStacking: true 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.currentFileName = fileName;
root.fileDialogOpen = false root.currentFileUrl = fileUrl;
const cleanPath = path.toString().replace(/^file:\/\//, '')
const fileName = cleanPath.split('/').pop()
const fileUrl = "file://" + cleanPath
root.currentFileName = fileName loadFromFile(fileUrl);
root.currentFileUrl = fileUrl close();
loadFromFile(fileUrl)
close()
} }
onDialogClosed: { onDialogClosed: {
root.fileDialogOpen = false root.fileDialogOpen = false;
} }
} }
@@ -357,8 +344,8 @@ Item {
allowStacking: true allowStacking: true
onBackgroundClicked: { onBackgroundClicked: {
close() close();
root.confirmationDialogOpen = false root.confirmationDialogOpen = false;
} }
content: Component { content: Component {
@@ -367,9 +354,9 @@ Item {
focus: true focus: true
Keys.onEscapePressed: event => { Keys.onEscapePressed: event => {
confirmationDialog.close() confirmationDialog.close();
root.confirmationDialogOpen = false root.confirmationDialogOpen = false;
event.accepted = true event.accepted = true;
} }
Column { Column {
@@ -392,13 +379,7 @@ Item {
} }
StyledText { StyledText {
text: root.pendingAction === "new" ? 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?")
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 font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
width: parent.width width: parent.width
@@ -411,8 +392,8 @@ Item {
iconSize: Theme.iconSize - 4 iconSize: Theme.iconSize - 4
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
onClicked: { onClicked: {
confirmationDialog.close() confirmationDialog.close();
root.confirmationDialogOpen = false root.confirmationDialogOpen = false;
} }
} }
} }
@@ -449,21 +430,21 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
confirmationDialog.close() confirmationDialog.close();
root.confirmationDialogOpen = false root.confirmationDialogOpen = false;
if (root.pendingAction === "new") { if (root.pendingAction === "new") {
createNewTab() createNewTab();
} else if (root.pendingAction === "open") { } else if (root.pendingAction === "open") {
root.fileDialogOpen = true root.fileDialogOpen = true;
loadBrowser.open() loadBrowser.open();
} else if (root.pendingAction === "load_file") { } else if (root.pendingAction === "load_file") {
performLoadFromFile(root.pendingFileUrl) performLoadFromFile(root.pendingFileUrl);
} else if (root.pendingAction.startsWith("close_tab_")) { } else if (root.pendingAction.startsWith("close_tab_")) {
var tabIndex = parseInt(root.pendingAction.split("_")[2]) var tabIndex = parseInt(root.pendingAction.split("_")[2]);
performCloseTab(tabIndex) performCloseTab(tabIndex);
} }
root.pendingAction = "" root.pendingAction = "";
root.pendingFileUrl = "" root.pendingFileUrl = "";
} }
} }
} }
@@ -489,10 +470,10 @@ Item {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
confirmationDialog.close() confirmationDialog.close();
root.confirmationDialogOpen = false root.confirmationDialogOpen = false;
root.fileDialogOpen = true root.fileDialogOpen = true;
saveBrowser.open() saveBrowser.open();
} }
} }
@@ -503,7 +484,6 @@ Item {
} }
} }
} }
} }
} }
} }

View File

@@ -1,10 +1,7 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Services
import qs.Widgets
pragma ComponentBehavior: Bound pragma ComponentBehavior: Bound
import QtQuick
import qs.Common
import qs.Widgets
Item { Item {
id: root id: root
@@ -14,60 +11,54 @@ Item {
property var cachedMonoFamilies: [] property var cachedMonoFamilies: []
property bool fontsEnumerated: false property bool fontsEnumerated: false
signal settingsRequested() signal settingsRequested
signal findRequested() signal findRequested
function enumerateFonts() { function enumerateFonts() {
var fonts = ["Default"] var fonts = ["Default"];
var availableFonts = Qt.fontFamilies() var availableFonts = Qt.fontFamilies();
var rootFamilies = [] var rootFamilies = [];
var seenFamilies = new Set() var seenFamilies = new Set();
for (var i = 0; i < availableFonts.length; i++) { for (var i = 0; i < availableFonts.length; i++) {
var fontName = availableFonts[i] var fontName = availableFonts[i];
if (fontName.startsWith(".")) if (fontName.startsWith("."))
continue continue;
if (fontName === SettingsData.defaultFontFamily) if (fontName === SettingsData.defaultFontFamily)
continue 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) {
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, return match;
"").replace(/ (UI|Display|Text|Mono|Sans|Serif)$/i, function (match, suffix) { }).trim();
return match
}).trim()
if (!seenFamilies.has(rootName) && rootName !== "") { if (!seenFamilies.has(rootName) && rootName !== "") {
seenFamilies.add(rootName) seenFamilies.add(rootName);
rootFamilies.push(rootName) rootFamilies.push(rootName);
} }
} }
cachedFontFamilies = fonts.concat(rootFamilies.sort()) cachedFontFamilies = fonts.concat(rootFamilies.sort());
var monoFonts = ["Default"] var monoFonts = ["Default"];
var monoFamilies = [] var monoFamilies = [];
var seenMonoFamilies = new Set() var seenMonoFamilies = new Set();
for (var j = 0; j < availableFonts.length; j++) { for (var j = 0; j < availableFonts.length; j++) {
var fontName2 = availableFonts[j] var fontName2 = availableFonts[j];
if (fontName2.startsWith(".")) if (fontName2.startsWith("."))
continue continue;
if (fontName2 === SettingsData.defaultMonoFontFamily) if (fontName2 === SettingsData.defaultMonoFontFamily)
continue continue;
var lowerName = fontName2.toLowerCase();
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")) {
if (lowerName.includes("mono") || lowerName.includes("code") || lowerName.includes("console") || lowerName.includes("terminal") || lowerName.includes("courier") || lowerName.includes("dejavu sans mono") || lowerName.includes( 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();
"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 !== "") { if (!seenMonoFamilies.has(rootName2) && rootName2 !== "") {
seenMonoFamilies.add(rootName2) seenMonoFamilies.add(rootName2);
monoFamilies.push(rootName2) monoFamilies.push(rootName2);
} }
} }
} }
cachedMonoFamilies = monoFonts.concat(monoFamilies.sort()) cachedMonoFamilies = monoFonts.concat(monoFamilies.sort());
fontsEnumerated = true fontsEnumerated = true;
} }
Component.onCompleted: { Component.onCompleted: {
if (!fontsEnumerated) { if (!fontsEnumerated) {
enumerateFonts() enumerateFonts();
} }
} }
@@ -140,7 +131,7 @@ Item {
description: "Toggle fonts" description: "Toggle fonts"
checked: SettingsData.notepadUseMonospace checked: SettingsData.notepadUseMonospace
onToggled: checked => { onToggled: checked => {
SettingsData.notepadUseMonospace = checked SettingsData.notepadUseMonospace = checked;
} }
} }
@@ -152,7 +143,7 @@ Item {
description: "Display line numbers in editor" description: "Display line numbers in editor"
checked: SettingsData.notepadShowLineNumbers checked: SettingsData.notepadShowLineNumbers
onToggled: checked => { onToggled: checked => {
SettingsData.notepadShowLineNumbers = checked SettingsData.notepadShowLineNumbers = checked;
} }
} }
@@ -221,16 +212,16 @@ Item {
options: cachedFontFamilies options: cachedFontFamilies
currentValue: { currentValue: {
if (!SettingsData.notepadFontFamily || SettingsData.notepadFontFamily === "") if (!SettingsData.notepadFontFamily || SettingsData.notepadFontFamily === "")
return "Default (Global)" return "Default (Global)";
else else
return SettingsData.notepadFontFamily return SettingsData.notepadFontFamily;
} }
enableFuzzySearch: true enableFuzzySearch: true
onValueChanged: value => { onValueChanged: value => {
if (value && (value.startsWith("Default") || value === "Default (Global)")) { if (value && (value.startsWith("Default") || value === "Default (Global)")) {
SettingsData.notepadFontFamily = "" SettingsData.notepadFontFamily = "";
} else { } 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) backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
onClicked: { onClicked: {
var newSize = Math.max(8, SettingsData.notepadFontSize - 1) var newSize = Math.max(8, SettingsData.notepadFontSize - 1);
SettingsData.notepadFontSize = newSize SettingsData.notepadFontSize = newSize;
} }
} }
@@ -308,8 +299,8 @@ Item {
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5) backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.5)
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
onClicked: { onClicked: {
var newSize = Math.min(48, SettingsData.notepadFontSize + 1) var newSize = Math.min(48, SettingsData.notepadFontSize + 1);
SettingsData.notepadFontSize = newSize SettingsData.notepadFontSize = newSize;
} }
} }
} }
@@ -335,9 +326,9 @@ Item {
checked: SettingsData.notepadTransparencyOverride >= 0 checked: SettingsData.notepadTransparencyOverride >= 0
onToggled: checked => { onToggled: checked => {
if (checked) { if (checked) {
SettingsData.notepadTransparencyOverride = SettingsData.notepadLastCustomTransparency SettingsData.notepadTransparencyOverride = SettingsData.notepadLastCustomTransparency;
} else { } else {
SettingsData.notepadTransparencyOverride = -1 SettingsData.notepadTransparencyOverride = -1;
} }
} }
} }
@@ -356,7 +347,7 @@ Item {
wheelEnabled: false wheelEnabled: false
onSliderValueChanged: newValue => { onSliderValueChanged: newValue => {
if (SettingsData.notepadTransparencyOverride >= 0) { if (SettingsData.notepadTransparencyOverride >= 0) {
SettingsData.notepadTransparencyOverride = newValue / 100 SettingsData.notepadTransparencyOverride = newValue / 100;
} }
} }
} }
@@ -365,9 +356,7 @@ Item {
StyledText { StyledText {
width: parent.width width: parent.width
text: SettingsData.notepadUseMonospace ? text: SettingsData.notepadUseMonospace ? "Using global monospace font from Settings → Personalization" : "Global fonts can be configured in Settings → Personalization"
"Using global monospace font from Settings → Personalization" :
"Global fonts can be configured in Settings → Personalization"
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceTextMedium color: Theme.surfaceTextMedium
wrapMode: Text.WordWrap wrapMode: Text.WordWrap

View File

@@ -1,11 +1,10 @@
pragma ComponentBehavior: Bound
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import qs.Common import qs.Common
import qs.Services import qs.Services
import qs.Widgets import qs.Widgets
pragma ComponentBehavior: Bound
Column { Column {
id: root id: root
@@ -14,15 +13,16 @@ Column {
signal tabSwitched(int tabIndex) signal tabSwitched(int tabIndex)
signal tabClosed(int tabIndex) signal tabClosed(int tabIndex)
signal newTabRequested() signal newTabRequested
function hasUnsavedChangesForTab(tab) { function hasUnsavedChangesForTab(tab) {
if (!tab) return false if (!tab)
return false;
if (tab.id === currentTab?.id) { 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 spacing: Theme.spacingXS
@@ -53,11 +53,11 @@ Column {
readonly property bool isActive: NotepadStorageService.currentTabIndex === index readonly property bool isActive: NotepadStorageService.currentTabIndex === index
readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse readonly property bool isHovered: tabMouseArea.containsMouse && !closeMouseArea.containsMouse
readonly property real calculatedWidth: { readonly property real calculatedWidth: {
const textWidth = tabText.paintedWidth || 100 const textWidth = tabText.paintedWidth || 100;
const closeButtonWidth = NotepadStorageService.tabs.length > 1 ? 20 : 0 const closeButtonWidth = NotepadStorageService.tabs.length > 1 ? 20 : 0;
const spacing = Theme.spacingXS const spacing = Theme.spacingXS;
const padding = Theme.spacingM * 2 const padding = Theme.spacingM * 2;
return Math.max(120, Math.min(200, textWidth + closeButtonWidth + spacing + padding)) return Math.max(120, Math.min(200, textWidth + closeButtonWidth + spacing + padding));
} }
width: calculatedWidth width: calculatedWidth
@@ -85,11 +85,11 @@ Column {
StyledText { StyledText {
id: tabText id: tabText
text: { text: {
var prefix = "" var prefix = "";
if (hasUnsavedChangesForTab(modelData)) { if (hasUnsavedChangesForTab(modelData)) {
prefix = "● " prefix = "● ";
} }
return prefix + (modelData.title || "Untitled") return prefix + (modelData.title || "Untitled");
} }
font.pixelSize: Theme.fontSizeSmall font.pixelSize: Theme.fontSizeSmall
color: isActive ? Theme.primary : Theme.surfaceText color: isActive ? Theme.primary : Theme.surfaceText
@@ -123,7 +123,7 @@ Column {
z: 100 z: 100
onClicked: { onClicked: {
root.tabClosed(index) root.tabClosed(index);
} }
} }
} }