mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
Compare commits
12 Commits
8161fd6acb
...
ad0f3fa33b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad0f3fa33b | ||
|
|
63d121b796 | ||
|
|
4291cfe82f | ||
|
|
f312868154 | ||
|
|
5b42d34ac8 | ||
|
|
397a8c275d | ||
|
|
2aabee453b | ||
|
|
185333a615 | ||
|
|
7d177eb1d4 | ||
|
|
705a84051d | ||
|
|
f6821f80e1 | ||
|
|
e7a6f5228d |
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -517,7 +517,6 @@ jobs:
|
|||||||
Recommends: cava
|
Recommends: cava
|
||||||
Recommends: cliphist
|
Recommends: cliphist
|
||||||
Recommends: danksearch
|
Recommends: danksearch
|
||||||
Recommends: hyprpicker
|
|
||||||
Recommends: matugen
|
Recommends: matugen
|
||||||
Recommends: wl-clipboard
|
Recommends: wl-clipboard
|
||||||
Recommends: NetworkManager
|
Recommends: NetworkManager
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ Requires: dgop
|
|||||||
Recommends: cava
|
Recommends: cava
|
||||||
Recommends: cliphist
|
Recommends: cliphist
|
||||||
Recommends: danksearch
|
Recommends: danksearch
|
||||||
Recommends: hyprpicker
|
|
||||||
Recommends: matugen
|
Recommends: matugen
|
||||||
Recommends: quickshell-git
|
Recommends: quickshell-git
|
||||||
Recommends: wl-clipboard
|
Recommends: wl-clipboard
|
||||||
|
|||||||
@@ -3,122 +3,139 @@ pragma ComponentBehavior: Bound
|
|||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
readonly property int noTimeout: -1
|
||||||
property int defaultDebounceMs: 50
|
property int defaultDebounceMs: 50
|
||||||
property int defaultTimeoutMs: 10000
|
property int defaultTimeoutMs: 10000
|
||||||
property var _procDebouncers: ({})
|
property var _procDebouncers: ({})
|
||||||
|
|
||||||
function runCommand(id, command, callback, debounceMs, timeoutMs) {
|
function runCommand(id, command, callback, debounceMs, timeoutMs) {
|
||||||
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs
|
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs;
|
||||||
const timeout = (typeof timeoutMs === "number" && timeoutMs > 0) ? timeoutMs : defaultTimeoutMs
|
const timeout = (typeof timeoutMs === "number") ? timeoutMs : defaultTimeoutMs;
|
||||||
let procId = id ? id : Math.random()
|
let procId = id ? id : Math.random();
|
||||||
const isRandomId = !id
|
const isRandomId = !id;
|
||||||
|
|
||||||
if (!_procDebouncers[procId]) {
|
if (!_procDebouncers[procId]) {
|
||||||
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root);
|
||||||
t.triggered.connect(function() { _launchProc(procId, isRandomId) })
|
t.triggered.connect(function () {
|
||||||
_procDebouncers[procId] = { timer: t, command: command, callback: callback, waitMs: wait, timeoutMs: timeout, isRandomId: isRandomId }
|
_launchProc(procId, isRandomId);
|
||||||
|
});
|
||||||
|
_procDebouncers[procId] = {
|
||||||
|
timer: t,
|
||||||
|
command: command,
|
||||||
|
callback: callback,
|
||||||
|
waitMs: wait,
|
||||||
|
timeoutMs: timeout,
|
||||||
|
isRandomId: isRandomId
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
_procDebouncers[procId].command = command
|
_procDebouncers[procId].command = command;
|
||||||
_procDebouncers[procId].callback = callback
|
_procDebouncers[procId].callback = callback;
|
||||||
_procDebouncers[procId].waitMs = wait
|
_procDebouncers[procId].waitMs = wait;
|
||||||
_procDebouncers[procId].timeoutMs = timeout
|
_procDebouncers[procId].timeoutMs = timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entry = _procDebouncers[procId]
|
const entry = _procDebouncers[procId];
|
||||||
entry.timer.interval = entry.waitMs
|
entry.timer.interval = entry.waitMs;
|
||||||
entry.timer.restart()
|
entry.timer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _launchProc(id, isRandomId) {
|
function _launchProc(id, isRandomId) {
|
||||||
const entry = _procDebouncers[id]
|
const entry = _procDebouncers[id];
|
||||||
if (!entry) return
|
if (!entry)
|
||||||
|
return;
|
||||||
|
const proc = Qt.createQmlObject('import Quickshell.Io; Process { running: false }', root);
|
||||||
|
const out = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc);
|
||||||
|
const err = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc);
|
||||||
|
const timeoutTimer = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root);
|
||||||
|
|
||||||
const proc = Qt.createQmlObject('import Quickshell.Io; Process { running: false }', root)
|
proc.stdout = out;
|
||||||
const out = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc)
|
proc.stderr = err;
|
||||||
const err = Qt.createQmlObject('import Quickshell.Io; StdioCollector {}', proc)
|
proc.command = entry.command;
|
||||||
const timeoutTimer = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
|
||||||
|
|
||||||
proc.stdout = out
|
let capturedOut = "";
|
||||||
proc.stderr = err
|
let capturedErr = "";
|
||||||
proc.command = entry.command
|
let exitSeen = false;
|
||||||
|
let exitCodeValue = -1;
|
||||||
|
let outSeen = false;
|
||||||
|
let errSeen = false;
|
||||||
|
let timedOut = false;
|
||||||
|
|
||||||
let capturedOut = ""
|
timeoutTimer.interval = entry.timeoutMs;
|
||||||
let capturedErr = ""
|
timeoutTimer.triggered.connect(function () {
|
||||||
let exitSeen = false
|
|
||||||
let exitCodeValue = -1
|
|
||||||
let outSeen = false
|
|
||||||
let errSeen = false
|
|
||||||
let timedOut = false
|
|
||||||
|
|
||||||
timeoutTimer.interval = entry.timeoutMs
|
|
||||||
timeoutTimer.triggered.connect(function() {
|
|
||||||
if (!exitSeen) {
|
if (!exitSeen) {
|
||||||
timedOut = true
|
timedOut = true;
|
||||||
proc.running = false
|
proc.running = false;
|
||||||
exitSeen = true
|
exitSeen = true;
|
||||||
exitCodeValue = 124
|
exitCodeValue = 124;
|
||||||
maybeComplete()
|
maybeComplete();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
out.streamFinished.connect(function() {
|
out.streamFinished.connect(function () {
|
||||||
try {
|
try {
|
||||||
capturedOut = out.text || ""
|
capturedOut = out.text || "";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
capturedOut = ""
|
capturedOut = "";
|
||||||
}
|
}
|
||||||
outSeen = true
|
outSeen = true;
|
||||||
maybeComplete()
|
maybeComplete();
|
||||||
})
|
});
|
||||||
|
|
||||||
err.streamFinished.connect(function() {
|
err.streamFinished.connect(function () {
|
||||||
try {
|
try {
|
||||||
capturedErr = err.text || ""
|
capturedErr = err.text || "";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
capturedErr = ""
|
capturedErr = "";
|
||||||
}
|
}
|
||||||
errSeen = true
|
errSeen = true;
|
||||||
maybeComplete()
|
maybeComplete();
|
||||||
})
|
});
|
||||||
|
|
||||||
proc.exited.connect(function(code) {
|
proc.exited.connect(function (code) {
|
||||||
timeoutTimer.stop()
|
timeoutTimer.stop();
|
||||||
exitSeen = true
|
exitSeen = true;
|
||||||
exitCodeValue = code
|
exitCodeValue = code;
|
||||||
maybeComplete()
|
maybeComplete();
|
||||||
})
|
});
|
||||||
|
|
||||||
function maybeComplete() {
|
function maybeComplete() {
|
||||||
if (!exitSeen || !outSeen || !errSeen) return
|
if (!exitSeen || !outSeen || !errSeen)
|
||||||
timeoutTimer.stop()
|
return;
|
||||||
|
timeoutTimer.stop();
|
||||||
if (entry && entry.callback && typeof entry.callback === "function") {
|
if (entry && entry.callback && typeof entry.callback === "function") {
|
||||||
try {
|
try {
|
||||||
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : ""
|
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : "";
|
||||||
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1
|
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1;
|
||||||
entry.callback(safeOutput, safeExitCode)
|
entry.callback(safeOutput, safeExitCode);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn("runCommand callback error for command:", entry.command, "Error:", e)
|
console.warn("runCommand callback error for command:", entry.command, "Error:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
try { proc.destroy() } catch (_) {}
|
try {
|
||||||
try { timeoutTimer.destroy() } catch (_) {}
|
proc.destroy();
|
||||||
|
} catch (_) {}
|
||||||
|
try {
|
||||||
|
timeoutTimer.destroy();
|
||||||
|
} catch (_) {}
|
||||||
|
|
||||||
if (isRandomId || entry.isRandomId) {
|
if (isRandomId || entry.isRandomId) {
|
||||||
Qt.callLater(function() {
|
Qt.callLater(function () {
|
||||||
if (_procDebouncers[id]) {
|
if (_procDebouncers[id]) {
|
||||||
try { _procDebouncers[id].timer.destroy() } catch (_) {}
|
try {
|
||||||
delete _procDebouncers[id]
|
_procDebouncers[id].timer.destroy();
|
||||||
|
} catch (_) {}
|
||||||
|
delete _procDebouncers[id];
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
proc.running = true
|
proc.running = true;
|
||||||
timeoutTimer.start()
|
if (entry.timeoutMs !== noTimeout)
|
||||||
|
timeoutTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -648,6 +648,13 @@ Item {
|
|||||||
return "SETTINGS_OPEN_SUCCESS";
|
return "SETTINGS_OPEN_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openWith(tab: string): string {
|
||||||
|
if (!tab)
|
||||||
|
return "SETTINGS_OPEN_FAILED: No tab specified";
|
||||||
|
PopoutService.openSettingsWithTab(tab);
|
||||||
|
return `SETTINGS_OPEN_SUCCESS: ${tab}`;
|
||||||
|
}
|
||||||
|
|
||||||
function close(): string {
|
function close(): string {
|
||||||
PopoutService.closeSettings();
|
PopoutService.closeSettings();
|
||||||
return "SETTINGS_CLOSE_SUCCESS";
|
return "SETTINGS_CLOSE_SUCCESS";
|
||||||
@@ -658,11 +665,47 @@ Item {
|
|||||||
return "SETTINGS_TOGGLE_SUCCESS";
|
return "SETTINGS_TOGGLE_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleWith(tab: string): string {
|
||||||
|
if (!tab)
|
||||||
|
return "SETTINGS_TOGGLE_FAILED: No tab specified";
|
||||||
|
PopoutService.toggleSettingsWithTab(tab);
|
||||||
|
return `SETTINGS_TOGGLE_SUCCESS: ${tab}`;
|
||||||
|
}
|
||||||
|
|
||||||
function focusOrToggle(): string {
|
function focusOrToggle(): string {
|
||||||
PopoutService.focusOrToggleSettings();
|
PopoutService.focusOrToggleSettings();
|
||||||
return "SETTINGS_FOCUS_OR_TOGGLE_SUCCESS";
|
return "SETTINGS_FOCUS_OR_TOGGLE_SUCCESS";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function focusOrToggleWith(tab: string): string {
|
||||||
|
if (!tab)
|
||||||
|
return "SETTINGS_FOCUS_OR_TOGGLE_FAILED: No tab specified";
|
||||||
|
PopoutService.focusOrToggleSettingsWithTab(tab);
|
||||||
|
return `SETTINGS_FOCUS_OR_TOGGLE_SUCCESS: ${tab}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tabs(): string {
|
||||||
|
if (!PopoutService.settingsModal)
|
||||||
|
return "wallpaper\ntheme\ntypography\ntime_weather\nsounds\ndankbar\ndankbar_settings\ndankbar_widgets\nworkspaces\nmedia_player\nnotifications\nosd\nrunning_apps\nupdater\ndock\nlauncher\nkeybinds\ndisplays\nnetwork\nprinters\nlock_screen\npower_sleep\nplugins\nabout";
|
||||||
|
var modal = PopoutService.settingsModal;
|
||||||
|
var ids = [];
|
||||||
|
var structure = modal.sidebar?.categoryStructure ?? [];
|
||||||
|
for (var i = 0; i < structure.length; i++) {
|
||||||
|
var cat = structure[i];
|
||||||
|
if (cat.separator)
|
||||||
|
continue;
|
||||||
|
if (cat.id)
|
||||||
|
ids.push(cat.id);
|
||||||
|
if (cat.children) {
|
||||||
|
for (var j = 0; j < cat.children.length; j++) {
|
||||||
|
if (cat.children[j].id)
|
||||||
|
ids.push(cat.children[j].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ids.join("\n");
|
||||||
|
}
|
||||||
|
|
||||||
function get(key: string): string {
|
function get(key: string): string {
|
||||||
return JSON.stringify(SettingsData?.[key]);
|
return JSON.stringify(SettingsData?.[key]);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ DankModal {
|
|||||||
console.warn("Failed to parse dms color pick JSON:", e);
|
console.warn("Failed to parse dms color pick JSON:", e);
|
||||||
root.show();
|
root.show();
|
||||||
}
|
}
|
||||||
});
|
}, 0, Proc.noTimeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
modalWidth: 680
|
modalWidth: 680
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ FloatingWindow {
|
|||||||
|
|
||||||
property alias profileBrowser: profileBrowser
|
property alias profileBrowser: profileBrowser
|
||||||
property alias wallpaperBrowser: wallpaperBrowser
|
property alias wallpaperBrowser: wallpaperBrowser
|
||||||
|
property alias sidebar: sidebar
|
||||||
property int currentTabIndex: 0
|
property int currentTabIndex: 0
|
||||||
property bool shouldHaveFocus: visible
|
property bool shouldHaveFocus: visible
|
||||||
property bool allowFocusOverride: false
|
property bool allowFocusOverride: false
|
||||||
@@ -32,6 +33,23 @@ FloatingWindow {
|
|||||||
visible = !visible;
|
visible = !visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showWithTab(tabIndex: int) {
|
||||||
|
if (tabIndex >= 0)
|
||||||
|
currentTabIndex = tabIndex;
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showWithTabName(tabName: string) {
|
||||||
|
var idx = sidebar.resolveTabIndex(tabName);
|
||||||
|
if (idx >= 0)
|
||||||
|
currentTabIndex = idx;
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function resolveTabIndex(tabName: string): int {
|
||||||
|
return sidebar.resolveTabIndex(tabName);
|
||||||
|
}
|
||||||
|
|
||||||
function toggleMenu() {
|
function toggleMenu() {
|
||||||
enableAnimations = true;
|
enableAnimations = true;
|
||||||
menuVisible = !menuVisible;
|
menuVisible = !menuVisible;
|
||||||
|
|||||||
@@ -21,26 +21,31 @@ Rectangle {
|
|||||||
"icon": "palette",
|
"icon": "palette",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
"id": "wallpaper",
|
||||||
"text": I18n.tr("Wallpaper"),
|
"text": I18n.tr("Wallpaper"),
|
||||||
"icon": "wallpaper",
|
"icon": "wallpaper",
|
||||||
"tabIndex": 0
|
"tabIndex": 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "theme",
|
||||||
"text": I18n.tr("Theme & Colors"),
|
"text": I18n.tr("Theme & Colors"),
|
||||||
"icon": "format_paint",
|
"icon": "format_paint",
|
||||||
"tabIndex": 10
|
"tabIndex": 10
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "typography",
|
||||||
"text": I18n.tr("Typography & Motion"),
|
"text": I18n.tr("Typography & Motion"),
|
||||||
"icon": "text_fields",
|
"icon": "text_fields",
|
||||||
"tabIndex": 14
|
"tabIndex": 14
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "time_weather",
|
||||||
"text": I18n.tr("Time & Weather"),
|
"text": I18n.tr("Time & Weather"),
|
||||||
"icon": "schedule",
|
"icon": "schedule",
|
||||||
"tabIndex": 1
|
"tabIndex": 1
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "sounds",
|
||||||
"text": I18n.tr("Sounds"),
|
"text": I18n.tr("Sounds"),
|
||||||
"icon": "volume_up",
|
"icon": "volume_up",
|
||||||
"tabIndex": 15,
|
"tabIndex": 15,
|
||||||
@@ -54,11 +59,13 @@ Rectangle {
|
|||||||
"icon": "toolbar",
|
"icon": "toolbar",
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
"id": "dankbar_settings",
|
||||||
"text": I18n.tr("Settings"),
|
"text": I18n.tr("Settings"),
|
||||||
"icon": "tune",
|
"icon": "tune",
|
||||||
"tabIndex": 3
|
"tabIndex": 3
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "dankbar_widgets",
|
||||||
"text": I18n.tr("Widgets"),
|
"text": I18n.tr("Widgets"),
|
||||||
"icon": "widgets",
|
"icon": "widgets",
|
||||||
"tabIndex": 22
|
"tabIndex": 22
|
||||||
@@ -72,32 +79,38 @@ Rectangle {
|
|||||||
"collapsedByDefault": true,
|
"collapsedByDefault": true,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
"id": "workspaces",
|
||||||
"text": I18n.tr("Workspaces"),
|
"text": I18n.tr("Workspaces"),
|
||||||
"icon": "view_module",
|
"icon": "view_module",
|
||||||
"tabIndex": 4
|
"tabIndex": 4
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "media_player",
|
||||||
"text": I18n.tr("Media Player"),
|
"text": I18n.tr("Media Player"),
|
||||||
"icon": "music_note",
|
"icon": "music_note",
|
||||||
"tabIndex": 16
|
"tabIndex": 16
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "notifications",
|
||||||
"text": I18n.tr("Notifications"),
|
"text": I18n.tr("Notifications"),
|
||||||
"icon": "notifications",
|
"icon": "notifications",
|
||||||
"tabIndex": 17
|
"tabIndex": 17
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "osd",
|
||||||
"text": I18n.tr("On-screen Displays"),
|
"text": I18n.tr("On-screen Displays"),
|
||||||
"icon": "tune",
|
"icon": "tune",
|
||||||
"tabIndex": 18
|
"tabIndex": 18
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "running_apps",
|
||||||
"text": I18n.tr("Running Apps"),
|
"text": I18n.tr("Running Apps"),
|
||||||
"icon": "apps",
|
"icon": "apps",
|
||||||
"tabIndex": 19,
|
"tabIndex": 19,
|
||||||
"hyprlandNiriOnly": true
|
"hyprlandNiriOnly": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "updater",
|
||||||
"text": I18n.tr("System Updater"),
|
"text": I18n.tr("System Updater"),
|
||||||
"icon": "refresh",
|
"icon": "refresh",
|
||||||
"tabIndex": 20
|
"tabIndex": 20
|
||||||
@@ -111,11 +124,13 @@ Rectangle {
|
|||||||
"collapsedByDefault": true,
|
"collapsedByDefault": true,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
"id": "dock",
|
||||||
"text": I18n.tr("Dock"),
|
"text": I18n.tr("Dock"),
|
||||||
"icon": "dock_to_bottom",
|
"icon": "dock_to_bottom",
|
||||||
"tabIndex": 5
|
"tabIndex": 5
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "launcher",
|
||||||
"text": I18n.tr("Launcher"),
|
"text": I18n.tr("Launcher"),
|
||||||
"icon": "grid_view",
|
"icon": "grid_view",
|
||||||
"tabIndex": 9
|
"tabIndex": 9
|
||||||
@@ -123,7 +138,7 @@ Rectangle {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "input",
|
"id": "keybinds",
|
||||||
"text": I18n.tr("Keyboard Shortcuts"),
|
"text": I18n.tr("Keyboard Shortcuts"),
|
||||||
"icon": "keyboard",
|
"icon": "keyboard",
|
||||||
"tabIndex": 2,
|
"tabIndex": 2,
|
||||||
@@ -156,11 +171,13 @@ Rectangle {
|
|||||||
"collapsedByDefault": true,
|
"collapsedByDefault": true,
|
||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
|
"id": "lock_screen",
|
||||||
"text": I18n.tr("Lock Screen"),
|
"text": I18n.tr("Lock Screen"),
|
||||||
"icon": "lock",
|
"icon": "lock",
|
||||||
"tabIndex": 11
|
"tabIndex": 11
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"id": "power_sleep",
|
||||||
"text": I18n.tr("Power & Sleep"),
|
"text": I18n.tr("Power & Sleep"),
|
||||||
"icon": "power_settings_new",
|
"icon": "power_settings_new",
|
||||||
"tabIndex": 21
|
"tabIndex": 21
|
||||||
@@ -338,6 +355,37 @@ Rectangle {
|
|||||||
return items;
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveTabIndex(name: string): int {
|
||||||
|
if (!name)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
var normalized = name.toLowerCase().replace(/[_\-\s]/g, "");
|
||||||
|
|
||||||
|
for (var i = 0; i < categoryStructure.length; i++) {
|
||||||
|
var cat = categoryStructure[i];
|
||||||
|
if (cat.separator)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var catId = (cat.id || "").toLowerCase().replace(/[_\-\s]/g, "");
|
||||||
|
if (catId === normalized) {
|
||||||
|
if (cat.tabIndex !== undefined)
|
||||||
|
return cat.tabIndex;
|
||||||
|
if (cat.children && cat.children.length > 0)
|
||||||
|
return cat.children[0].tabIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cat.children) {
|
||||||
|
for (var j = 0; j < cat.children.length; j++) {
|
||||||
|
var child = cat.children[j];
|
||||||
|
var childId = (child.id || "").toLowerCase().replace(/[_\-\s]/g, "");
|
||||||
|
if (childId === normalized)
|
||||||
|
return child.tabIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
width: 270
|
width: 270
|
||||||
height: parent.height
|
height: parent.height
|
||||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||||
|
|||||||
@@ -312,7 +312,7 @@ Item {
|
|||||||
Row {
|
Row {
|
||||||
id: viewModeButtons
|
id: viewModeButtons
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
visible: searchMode === "apps" && appLauncher.model.count > 0
|
visible: searchMode === "apps"
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -17,20 +16,18 @@ PluginComponent {
|
|||||||
ccWidgetPrimaryText: I18n.tr("Printers")
|
ccWidgetPrimaryText: I18n.tr("Printers")
|
||||||
ccWidgetSecondaryText: {
|
ccWidgetSecondaryText: {
|
||||||
if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) {
|
if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) {
|
||||||
return I18n.tr("Printers: ") + CupsService.getPrintersNum() + " - " + I18n.tr("Jobs: ") + CupsService.getTotalJobsNum()
|
return I18n.tr("Printers: ") + CupsService.getPrintersNum() + " - " + I18n.tr("Jobs: ") + CupsService.getTotalJobsNum();
|
||||||
} else {
|
} else {
|
||||||
if (!CupsService.cupsAvailable) {
|
if (!CupsService.cupsAvailable) {
|
||||||
return I18n.tr("Print Server not available")
|
return I18n.tr("Print Server not available");
|
||||||
} else {
|
} else {
|
||||||
return I18n.tr("No printer found")
|
return I18n.tr("No printer found");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ccWidgetIsActive: CupsService.cupsAvailable && CupsService.getTotalJobsNum() > 0
|
ccWidgetIsActive: CupsService.cupsAvailable && CupsService.getTotalJobsNum() > 0
|
||||||
|
|
||||||
onCcWidgetToggled: {
|
onCcWidgetToggled: {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ccDetailContent: Component {
|
ccDetailContent: Component {
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -39,6 +36,21 @@ PluginComponent {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceContainerHigh
|
color: Theme.surfaceContainerHigh
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.topMargin: Theme.spacingS
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
iconName: "settings"
|
||||||
|
buttonSize: 24
|
||||||
|
iconSize: 14
|
||||||
|
iconColor: Theme.surfaceVariantText
|
||||||
|
onClicked: {
|
||||||
|
PopoutService.closeControlCenter();
|
||||||
|
PopoutService.openSettingsWithTab("printers");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
visible: !CupsService.cupsAvailable || CupsService.getPrintersNum() == 0
|
visible: !CupsService.cupsAvailable || CupsService.getPrintersNum() == 0
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -58,7 +70,7 @@ PluginComponent {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: detailColumn
|
id: detailColumn
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
@@ -78,12 +90,12 @@ PluginComponent {
|
|||||||
Layout.maximumWidth: parent.width - 180
|
Layout.maximumWidth: parent.width - 180
|
||||||
description: ""
|
description: ""
|
||||||
currentValue: {
|
currentValue: {
|
||||||
CupsService.getSelectedPrinter()
|
CupsService.getSelectedPrinter();
|
||||||
}
|
}
|
||||||
options: CupsService.getPrintersNames()
|
options: CupsService.getPrintersNames()
|
||||||
onValueChanged: value => {
|
onValueChanged: value => {
|
||||||
CupsService.setSelectedPrinter(value)
|
CupsService.setSelectedPrinter(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
@@ -135,11 +147,11 @@ PluginComponent {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
enabled: true
|
enabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const selected = CupsService.getSelectedPrinter()
|
const selected = CupsService.getSelectedPrinter();
|
||||||
if (CupsService.getCurrentPrinterState() === "stopped") {
|
if (CupsService.getCurrentPrinterState() === "stopped") {
|
||||||
CupsService.resumePrinter(selected)
|
CupsService.resumePrinter(selected);
|
||||||
} else {
|
} else {
|
||||||
CupsService.pausePrinter(selected)
|
CupsService.pausePrinter(selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,8 +192,8 @@ PluginComponent {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
enabled: true
|
enabled: true
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const selected = CupsService.getSelectedPrinter()
|
const selected = CupsService.getSelectedPrinter();
|
||||||
CupsService.purgeJobs(selected)
|
CupsService.purgeJobs(selected);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,8 +287,8 @@ PluginComponent {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: {
|
text: {
|
||||||
var date = new Date(modelData.timeCreated)
|
var date = new Date(modelData.timeCreated);
|
||||||
return date.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
return date.toLocaleString(Qt.locale(), Locale.ShortFormat);
|
||||||
}
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Theme.surfaceTextMedium
|
color: Theme.surfaceTextMedium
|
||||||
@@ -296,7 +308,7 @@ PluginComponent {
|
|||||||
iconName: "delete"
|
iconName: "delete"
|
||||||
buttonSize: 36
|
buttonSize: 36
|
||||||
onClicked: {
|
onClicked: {
|
||||||
CupsService.cancelJob(CupsService.getSelectedPrinter(), modelData.id)
|
CupsService.cancelJob(CupsService.getSelectedPrinter(), modelData.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -69,8 +69,8 @@ Rectangle {
|
|||||||
height: 40
|
height: 40
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
id: headerText
|
id: headerLeft
|
||||||
text: I18n.tr("Network Settings")
|
text: I18n.tr("Network")
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -79,7 +79,7 @@ Rectangle {
|
|||||||
|
|
||||||
Item {
|
Item {
|
||||||
height: 1
|
height: 1
|
||||||
width: parent.width - headerText.width - rightControls.width
|
width: parent.width - headerLeft.width - rightControls.width
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
@@ -115,6 +115,8 @@ Rectangle {
|
|||||||
id: preferenceControls
|
id: preferenceControls
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10
|
visible: NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10
|
||||||
|
buttonHeight: 28
|
||||||
|
textSize: Theme.fontSizeSmall
|
||||||
|
|
||||||
model: ["Ethernet", "WiFi"]
|
model: ["Ethernet", "WiFi"]
|
||||||
currentIndex: currentPreferenceIndex
|
currentIndex: currentPreferenceIndex
|
||||||
@@ -125,6 +127,18 @@ Rectangle {
|
|||||||
NetworkService.setNetworkPreference(index === 0 ? "ethernet" : "wifi");
|
NetworkService.setNetworkPreference(index === 0 ? "ethernet" : "wifi");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
iconName: "settings"
|
||||||
|
buttonSize: 28
|
||||||
|
iconSize: 16
|
||||||
|
iconColor: Theme.surfaceVariantText
|
||||||
|
onClicked: {
|
||||||
|
PopoutService.closeControlCenter();
|
||||||
|
PopoutService.openSettingsWithTab("network");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -19,7 +18,7 @@ Item {
|
|||||||
property bool forceVerticalLayout: false
|
property bool forceVerticalLayout: false
|
||||||
|
|
||||||
readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false)
|
readonly property bool isVertical: overrideAxisLayout ? forceVerticalLayout : (axis?.isVertical ?? false)
|
||||||
readonly property real spacing: {
|
readonly property real widgetSpacing: {
|
||||||
const baseSpacing = noBackground ? 2 : Theme.spacingXS;
|
const baseSpacing = noBackground ? 2 : Theme.spacingXS;
|
||||||
const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
const outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||||
return baseSpacing + (outlineThickness * 2);
|
return baseSpacing + (outlineThickness * 2);
|
||||||
@@ -33,36 +32,32 @@ Item {
|
|||||||
if (SettingsData.centeringMode === "geometric") {
|
if (SettingsData.centeringMode === "geometric") {
|
||||||
applyGeometricLayout();
|
applyGeometricLayout();
|
||||||
} else {
|
} else {
|
||||||
// Default to index layout or if value is not 'geometric'
|
|
||||||
applyIndexLayout();
|
applyIndexLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyGeometricLayout() {
|
function applyGeometricLayout() {
|
||||||
if ((isVertical ? height : width) <= 0 || !visible) {
|
if ((isVertical ? height : width) <= 0 || !visible)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
centerWidgets = [];
|
centerWidgets = [];
|
||||||
totalWidgets = 0;
|
totalWidgets = 0;
|
||||||
totalSize = 0;
|
totalSize = 0;
|
||||||
|
|
||||||
for (var i = 0; i < centerRepeater.count; i++) {
|
for (var i = 0; i < centerRepeater.count; i++) {
|
||||||
const item = centerRepeater.itemAt(i);
|
const loader = centerRepeater.itemAt(i);
|
||||||
if (item && item.active && item.item && getWidgetVisible(item.widgetId)) {
|
if (loader && loader.active && loader.item) {
|
||||||
centerWidgets.push(item.item);
|
centerWidgets.push(loader.item);
|
||||||
totalWidgets++;
|
totalWidgets++;
|
||||||
totalSize += isVertical ? item.item.height : item.item.width;
|
totalSize += isVertical ? loader.item.height : loader.item.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalWidgets === 0) {
|
if (totalWidgets === 0)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (totalWidgets > 1) {
|
if (totalWidgets > 1)
|
||||||
totalSize += spacing * (totalWidgets - 1);
|
totalSize += widgetSpacing * (totalWidgets - 1);
|
||||||
}
|
|
||||||
|
|
||||||
positionWidgetsGeometric();
|
positionWidgetsGeometric();
|
||||||
}
|
}
|
||||||
@@ -70,7 +65,6 @@ Item {
|
|||||||
function positionWidgetsGeometric() {
|
function positionWidgetsGeometric() {
|
||||||
const parentLength = isVertical ? height : width;
|
const parentLength = isVertical ? height : width;
|
||||||
const parentCenter = parentLength / 2;
|
const parentCenter = parentLength / 2;
|
||||||
|
|
||||||
let currentPos = parentCenter - (totalSize / 2);
|
let currentPos = parentCenter - (totalSize / 2);
|
||||||
|
|
||||||
centerWidgets.forEach(widget => {
|
centerWidgets.forEach(widget => {
|
||||||
@@ -81,67 +75,53 @@ Item {
|
|||||||
widget.anchors.horizontalCenter = undefined;
|
widget.anchors.horizontalCenter = undefined;
|
||||||
widget.x = currentPos;
|
widget.x = currentPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
const widgetSize = isVertical ? widget.height : widget.width;
|
const widgetSize = isVertical ? widget.height : widget.width;
|
||||||
currentPos += widgetSize + spacing;
|
currentPos += widgetSize + widgetSpacing;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function applyIndexLayout() {
|
function applyIndexLayout() {
|
||||||
if ((isVertical ? height : width) <= 0 || !visible) {
|
if ((isVertical ? height : width) <= 0 || !visible)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
centerWidgets = [];
|
centerWidgets = [];
|
||||||
totalWidgets = 0;
|
totalWidgets = 0;
|
||||||
totalSize = 0;
|
totalSize = 0;
|
||||||
|
|
||||||
let configuredWidgets = 0;
|
|
||||||
let configuredMiddleWidget = null;
|
let configuredMiddleWidget = null;
|
||||||
let configuredLeftWidget = null;
|
let configuredLeftWidget = null;
|
||||||
let configuredRightWidget = null;
|
let configuredRightWidget = null;
|
||||||
|
|
||||||
for (var i = 0; i < centerRepeater.count; i++) {
|
const configuredWidgets = centerRepeater.count;
|
||||||
const item = centerRepeater.itemAt(i);
|
|
||||||
if (item && getWidgetVisible(item.widgetId)) {
|
|
||||||
configuredWidgets++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const isOddConfigured = configuredWidgets % 2 === 1;
|
const isOddConfigured = configuredWidgets % 2 === 1;
|
||||||
const configuredMiddlePos = Math.floor(configuredWidgets / 2);
|
const configuredMiddlePos = Math.floor(configuredWidgets / 2);
|
||||||
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1);
|
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1);
|
||||||
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2);
|
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2);
|
||||||
let currentConfigIndex = 0;
|
|
||||||
|
|
||||||
for (var i = 0; i < centerRepeater.count; i++) {
|
for (var i = 0; i < centerRepeater.count; i++) {
|
||||||
const item = centerRepeater.itemAt(i);
|
const wrapper = centerRepeater.itemAt(i);
|
||||||
if (item && getWidgetVisible(item.widgetId)) {
|
if (!wrapper)
|
||||||
if (isOddConfigured && currentConfigIndex === configuredMiddlePos && item.active && item.item) {
|
continue;
|
||||||
configuredMiddleWidget = item.item;
|
|
||||||
}
|
if (isOddConfigured && i === configuredMiddlePos && wrapper.active && wrapper.item)
|
||||||
if (!isOddConfigured && currentConfigIndex === configuredLeftPos && item.active && item.item) {
|
configuredMiddleWidget = wrapper.item;
|
||||||
configuredLeftWidget = item.item;
|
if (!isOddConfigured && i === configuredLeftPos && wrapper.active && wrapper.item)
|
||||||
}
|
configuredLeftWidget = wrapper.item;
|
||||||
if (!isOddConfigured && currentConfigIndex === configuredRightPos && item.active && item.item) {
|
if (!isOddConfigured && i === configuredRightPos && wrapper.active && wrapper.item)
|
||||||
configuredRightWidget = item.item;
|
configuredRightWidget = wrapper.item;
|
||||||
}
|
|
||||||
if (item.active && item.item) {
|
if (wrapper.active && wrapper.item) {
|
||||||
centerWidgets.push(item.item);
|
centerWidgets.push(wrapper.item);
|
||||||
totalWidgets++;
|
totalWidgets++;
|
||||||
totalSize += isVertical ? item.item.height : item.item.width;
|
totalSize += isVertical ? wrapper.item.height : wrapper.item.width;
|
||||||
}
|
|
||||||
currentConfigIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totalWidgets === 0) {
|
if (totalWidgets === 0)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (totalWidgets > 1) {
|
if (totalWidgets > 1)
|
||||||
totalSize += spacing * (totalWidgets - 1);
|
totalSize += widgetSpacing * (totalWidgets - 1);
|
||||||
}
|
|
||||||
|
|
||||||
positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget);
|
positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget);
|
||||||
}
|
}
|
||||||
@@ -151,11 +131,10 @@ Item {
|
|||||||
const isOddConfigured = configuredWidgets % 2 === 1;
|
const isOddConfigured = configuredWidgets % 2 === 1;
|
||||||
|
|
||||||
centerWidgets.forEach(widget => {
|
centerWidgets.forEach(widget => {
|
||||||
if (isVertical) {
|
if (isVertical)
|
||||||
widget.anchors.verticalCenter = undefined;
|
widget.anchors.verticalCenter = undefined;
|
||||||
} else {
|
else
|
||||||
widget.anchors.horizontalCenter = undefined;
|
widget.anchors.horizontalCenter = undefined;
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (isOddConfigured && configuredMiddleWidget) {
|
if (isOddConfigured && configuredMiddleWidget) {
|
||||||
@@ -163,222 +142,154 @@ Item {
|
|||||||
const middleIndex = centerWidgets.indexOf(middleWidget);
|
const middleIndex = centerWidgets.indexOf(middleWidget);
|
||||||
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
|
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
|
||||||
|
|
||||||
if (isVertical) {
|
if (isVertical)
|
||||||
middleWidget.y = parentCenter - (middleSize / 2);
|
middleWidget.y = parentCenter - (middleSize / 2);
|
||||||
} else {
|
else
|
||||||
middleWidget.x = parentCenter - (middleSize / 2);
|
middleWidget.x = parentCenter - (middleSize / 2);
|
||||||
}
|
|
||||||
|
|
||||||
let currentPos = isVertical ? middleWidget.y : middleWidget.x;
|
let currentPos = isVertical ? middleWidget.y : middleWidget.x;
|
||||||
for (var i = middleIndex - 1; i >= 0; i--) {
|
for (var i = middleIndex - 1; i >= 0; i--) {
|
||||||
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
currentPos -= (spacing + size);
|
currentPos -= (widgetSpacing + size);
|
||||||
if (isVertical) {
|
if (isVertical)
|
||||||
centerWidgets[i].y = currentPos;
|
centerWidgets[i].y = currentPos;
|
||||||
} else {
|
else
|
||||||
centerWidgets[i].x = currentPos;
|
centerWidgets[i].x = currentPos;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
|
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
|
||||||
for (var i = middleIndex + 1; i < totalWidgets; i++) {
|
for (var i = middleIndex + 1; i < totalWidgets; i++) {
|
||||||
currentPos += spacing;
|
currentPos += widgetSpacing;
|
||||||
if (isVertical) {
|
if (isVertical)
|
||||||
centerWidgets[i].y = currentPos;
|
centerWidgets[i].y = currentPos;
|
||||||
} else {
|
else
|
||||||
centerWidgets[i].x = currentPos;
|
centerWidgets[i].x = currentPos;
|
||||||
}
|
|
||||||
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
}
|
}
|
||||||
} else {
|
return;
|
||||||
if (totalWidgets === 1) {
|
}
|
||||||
const widget = centerWidgets[0];
|
|
||||||
const size = isVertical ? widget.height : widget.width;
|
if (totalWidgets === 1) {
|
||||||
if (isVertical) {
|
const widget = centerWidgets[0];
|
||||||
widget.y = parentCenter - (size / 2);
|
const size = isVertical ? widget.height : widget.width;
|
||||||
} else {
|
if (isVertical)
|
||||||
widget.x = parentCenter - (size / 2);
|
widget.y = parentCenter - (size / 2);
|
||||||
|
else
|
||||||
|
widget.x = parentCenter - (size / 2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!configuredLeftWidget || !configuredRightWidget) {
|
||||||
|
if (totalWidgets % 2 === 1) {
|
||||||
|
const middleIndex = Math.floor(totalWidgets / 2);
|
||||||
|
const middleWidget = centerWidgets[middleIndex];
|
||||||
|
|
||||||
|
if (!middleWidget)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
|
||||||
|
|
||||||
|
if (isVertical)
|
||||||
|
middleWidget.y = parentCenter - (middleSize / 2);
|
||||||
|
else
|
||||||
|
middleWidget.x = parentCenter - (middleSize / 2);
|
||||||
|
|
||||||
|
let currentPos = isVertical ? middleWidget.y : middleWidget.x;
|
||||||
|
for (var i = middleIndex - 1; i >= 0; i--) {
|
||||||
|
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
|
currentPos -= (widgetSpacing + size);
|
||||||
|
if (isVertical)
|
||||||
|
centerWidgets[i].y = currentPos;
|
||||||
|
else
|
||||||
|
centerWidgets[i].x = currentPos;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!configuredLeftWidget || !configuredRightWidget) {
|
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
|
||||||
if (totalWidgets % 2 === 1) {
|
for (var i = middleIndex + 1; i < totalWidgets; i++) {
|
||||||
const middleIndex = Math.floor(totalWidgets / 2);
|
currentPos += widgetSpacing;
|
||||||
const middleWidget = centerWidgets[middleIndex];
|
if (isVertical)
|
||||||
|
centerWidgets[i].y = currentPos;
|
||||||
if (!middleWidget) {
|
else
|
||||||
return;
|
centerWidgets[i].x = currentPos;
|
||||||
}
|
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
|
|
||||||
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
|
|
||||||
|
|
||||||
if (isVertical) {
|
|
||||||
middleWidget.y = parentCenter - (middleSize / 2);
|
|
||||||
} else {
|
|
||||||
middleWidget.x = parentCenter - (middleSize / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentPos = isVertical ? middleWidget.y : middleWidget.x;
|
|
||||||
for (var i = middleIndex - 1; i >= 0; i--) {
|
|
||||||
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
|
||||||
currentPos -= (spacing + size);
|
|
||||||
if (isVertical) {
|
|
||||||
centerWidgets[i].y = currentPos;
|
|
||||||
} else {
|
|
||||||
centerWidgets[i].x = currentPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
|
|
||||||
for (var i = middleIndex + 1; i < totalWidgets; i++) {
|
|
||||||
currentPos += spacing;
|
|
||||||
if (isVertical) {
|
|
||||||
centerWidgets[i].y = currentPos;
|
|
||||||
} else {
|
|
||||||
centerWidgets[i].x = currentPos;
|
|
||||||
}
|
|
||||||
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const leftIndex = (totalWidgets / 2) - 1;
|
|
||||||
const rightIndex = totalWidgets / 2;
|
|
||||||
const fallbackLeft = centerWidgets[leftIndex];
|
|
||||||
const fallbackRight = centerWidgets[rightIndex];
|
|
||||||
|
|
||||||
if (!fallbackLeft || !fallbackRight) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const halfSpacing = spacing / 2;
|
|
||||||
const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width;
|
|
||||||
|
|
||||||
if (isVertical) {
|
|
||||||
fallbackLeft.y = parentCenter - halfSpacing - leftSize;
|
|
||||||
fallbackRight.y = parentCenter + halfSpacing;
|
|
||||||
} else {
|
|
||||||
fallbackLeft.x = parentCenter - halfSpacing - leftSize;
|
|
||||||
fallbackRight.x = parentCenter + halfSpacing;
|
|
||||||
}
|
|
||||||
|
|
||||||
let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x;
|
|
||||||
for (var i = leftIndex - 1; i >= 0; i--) {
|
|
||||||
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
|
||||||
currentPos -= (spacing + size);
|
|
||||||
if (isVertical) {
|
|
||||||
centerWidgets[i].y = currentPos;
|
|
||||||
} else {
|
|
||||||
centerWidgets[i].x = currentPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width);
|
|
||||||
for (var i = rightIndex + 1; i < totalWidgets; i++) {
|
|
||||||
currentPos += spacing;
|
|
||||||
if (isVertical) {
|
|
||||||
centerWidgets[i].y = currentPos;
|
|
||||||
} else {
|
|
||||||
centerWidgets[i].x = currentPos;
|
|
||||||
}
|
|
||||||
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const leftWidget = configuredLeftWidget;
|
|
||||||
const rightWidget = configuredRightWidget;
|
|
||||||
const leftIndex = centerWidgets.indexOf(leftWidget);
|
|
||||||
const rightIndex = centerWidgets.indexOf(rightWidget);
|
|
||||||
const halfSpacing = spacing / 2;
|
|
||||||
const leftSize = isVertical ? leftWidget.height : leftWidget.width;
|
|
||||||
|
|
||||||
if (isVertical) {
|
|
||||||
leftWidget.y = parentCenter - halfSpacing - leftSize;
|
|
||||||
rightWidget.y = parentCenter + halfSpacing;
|
|
||||||
} else {
|
} else {
|
||||||
leftWidget.x = parentCenter - halfSpacing - leftSize;
|
const leftIndex = (totalWidgets / 2) - 1;
|
||||||
rightWidget.x = parentCenter + halfSpacing;
|
const rightIndex = totalWidgets / 2;
|
||||||
}
|
const fallbackLeft = centerWidgets[leftIndex];
|
||||||
|
const fallbackRight = centerWidgets[rightIndex];
|
||||||
|
|
||||||
|
if (!fallbackLeft || !fallbackRight)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const halfSpacing = widgetSpacing / 2;
|
||||||
|
const leftSize = isVertical ? fallbackLeft.height : fallbackLeft.width;
|
||||||
|
|
||||||
let currentPos = isVertical ? leftWidget.y : leftWidget.x;
|
|
||||||
for (var i = leftIndex - 1; i >= 0; i--) {
|
|
||||||
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
|
||||||
currentPos -= (spacing + size);
|
|
||||||
if (isVertical) {
|
if (isVertical) {
|
||||||
centerWidgets[i].y = currentPos;
|
fallbackLeft.y = parentCenter - halfSpacing - leftSize;
|
||||||
|
fallbackRight.y = parentCenter + halfSpacing;
|
||||||
} else {
|
} else {
|
||||||
centerWidgets[i].x = currentPos;
|
fallbackLeft.x = parentCenter - halfSpacing - leftSize;
|
||||||
|
fallbackRight.x = parentCenter + halfSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentPos = isVertical ? fallbackLeft.y : fallbackLeft.x;
|
||||||
|
for (var i = leftIndex - 1; i >= 0; i--) {
|
||||||
|
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
|
currentPos -= (widgetSpacing + size);
|
||||||
|
if (isVertical)
|
||||||
|
centerWidgets[i].y = currentPos;
|
||||||
|
else
|
||||||
|
centerWidgets[i].x = currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos = (isVertical ? fallbackRight.y + fallbackRight.height : fallbackRight.x + fallbackRight.width);
|
||||||
|
for (var i = rightIndex + 1; i < totalWidgets; i++) {
|
||||||
|
currentPos += widgetSpacing;
|
||||||
|
if (isVertical)
|
||||||
|
centerWidgets[i].y = currentPos;
|
||||||
|
else
|
||||||
|
centerWidgets[i].x = currentPos;
|
||||||
|
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width);
|
|
||||||
for (var i = rightIndex + 1; i < totalWidgets; i++) {
|
|
||||||
currentPos += spacing;
|
|
||||||
if (isVertical) {
|
|
||||||
centerWidgets[i].y = currentPos;
|
|
||||||
} else {
|
|
||||||
centerWidgets[i].x = currentPos;
|
|
||||||
}
|
|
||||||
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWidgetVisible(widgetId) {
|
|
||||||
const widgetVisibility = {
|
|
||||||
"cpuUsage": DgopService.dgopAvailable,
|
|
||||||
"memUsage": DgopService.dgopAvailable,
|
|
||||||
"cpuTemp": DgopService.dgopAvailable,
|
|
||||||
"gpuTemp": DgopService.dgopAvailable,
|
|
||||||
"network_speed_monitor": DgopService.dgopAvailable
|
|
||||||
};
|
|
||||||
return widgetVisibility[widgetId] ?? true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getWidgetComponent(widgetId) {
|
|
||||||
// Build dynamic component map including plugins
|
|
||||||
let baseMap = {
|
|
||||||
"launcherButton": "launcherButtonComponent",
|
|
||||||
"workspaceSwitcher": "workspaceSwitcherComponent",
|
|
||||||
"focusedWindow": "focusedWindowComponent",
|
|
||||||
"runningApps": "runningAppsComponent",
|
|
||||||
"clock": "clockComponent",
|
|
||||||
"music": "mediaComponent",
|
|
||||||
"weather": "weatherComponent",
|
|
||||||
"systemTray": "systemTrayComponent",
|
|
||||||
"privacyIndicator": "privacyIndicatorComponent",
|
|
||||||
"clipboard": "clipboardComponent",
|
|
||||||
"cpuUsage": "cpuUsageComponent",
|
|
||||||
"memUsage": "memUsageComponent",
|
|
||||||
"diskUsage": "diskUsageComponent",
|
|
||||||
"cpuTemp": "cpuTempComponent",
|
|
||||||
"gpuTemp": "gpuTempComponent",
|
|
||||||
"notificationButton": "notificationButtonComponent",
|
|
||||||
"battery": "batteryComponent",
|
|
||||||
"controlCenterButton": "controlCenterButtonComponent",
|
|
||||||
"idleInhibitor": "idleInhibitorComponent",
|
|
||||||
"spacer": "spacerComponent",
|
|
||||||
"separator": "separatorComponent",
|
|
||||||
"network_speed_monitor": "networkComponent",
|
|
||||||
"keyboard_layout_name": "keyboardLayoutNameComponent",
|
|
||||||
"vpn": "vpnComponent",
|
|
||||||
"notepadButton": "notepadButtonComponent",
|
|
||||||
"colorPicker": "colorPickerComponent",
|
|
||||||
"systemUpdate": "systemUpdateComponent"
|
|
||||||
};
|
|
||||||
|
|
||||||
// For built-in components, get from components property
|
|
||||||
const componentKey = baseMap[widgetId];
|
|
||||||
if (componentKey && root.components[componentKey]) {
|
|
||||||
return root.components[componentKey];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For plugin components, get from PluginService
|
const leftWidget = configuredLeftWidget;
|
||||||
var parts = widgetId.split(":");
|
const rightWidget = configuredRightWidget;
|
||||||
var pluginId = parts[0];
|
const leftIndex = centerWidgets.indexOf(leftWidget);
|
||||||
let pluginComponents = PluginService.getWidgetComponents();
|
const rightIndex = centerWidgets.indexOf(rightWidget);
|
||||||
return pluginComponents[pluginId] || null;
|
const halfSpacing = widgetSpacing / 2;
|
||||||
|
const leftSize = isVertical ? leftWidget.height : leftWidget.width;
|
||||||
|
|
||||||
|
if (isVertical) {
|
||||||
|
leftWidget.y = parentCenter - halfSpacing - leftSize;
|
||||||
|
rightWidget.y = parentCenter + halfSpacing;
|
||||||
|
} else {
|
||||||
|
leftWidget.x = parentCenter - halfSpacing - leftSize;
|
||||||
|
rightWidget.x = parentCenter + halfSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
let currentPos = isVertical ? leftWidget.y : leftWidget.x;
|
||||||
|
for (var i = leftIndex - 1; i >= 0; i--) {
|
||||||
|
const size = isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
|
currentPos -= (widgetSpacing + size);
|
||||||
|
if (isVertical)
|
||||||
|
centerWidgets[i].y = currentPos;
|
||||||
|
else
|
||||||
|
centerWidgets[i].x = currentPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width);
|
||||||
|
for (var i = rightIndex + 1; i < totalWidgets; i++) {
|
||||||
|
currentPos += widgetSpacing;
|
||||||
|
if (isVertical)
|
||||||
|
centerWidgets[i].y = currentPos;
|
||||||
|
else
|
||||||
|
centerWidgets[i].x = currentPos;
|
||||||
|
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
height: parent.height
|
height: parent.height
|
||||||
@@ -392,177 +303,71 @@ Item {
|
|||||||
onTriggered: root.updateLayout()
|
onTriggered: root.updateLayout()
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: layoutTimer.restart()
|
||||||
layoutTimer.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
onWidthChanged: {
|
onWidthChanged: {
|
||||||
if (width > 0) {
|
if (width > 0)
|
||||||
layoutTimer.restart();
|
layoutTimer.restart();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onHeightChanged: {
|
onHeightChanged: {
|
||||||
if (height > 0) {
|
if (height > 0)
|
||||||
layoutTimer.restart();
|
layoutTimer.restart();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible && (isVertical ? height : width) > 0) {
|
if (visible && (isVertical ? height : width) > 0)
|
||||||
layoutTimer.restart();
|
layoutTimer.restart();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
id: centerRepeater
|
id: centerRepeater
|
||||||
model: root.widgetsModel
|
model: root.widgetsModel
|
||||||
|
|
||||||
Loader {
|
onCountChanged: layoutTimer.restart()
|
||||||
|
|
||||||
|
Item {
|
||||||
property var itemData: modelData
|
property var itemData: modelData
|
||||||
property string widgetId: itemData.widgetId
|
readonly property real itemSpacing: root.widgetSpacing
|
||||||
property var widgetData: itemData
|
|
||||||
property int spacerSize: itemData.size || 20
|
|
||||||
|
|
||||||
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
|
width: widgetLoader.item ? widgetLoader.item.width : 0
|
||||||
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
|
height: widgetLoader.item ? widgetLoader.item.height : 0
|
||||||
active: root.getWidgetVisible(itemData.widgetId) && (itemData.widgetId !== "music" || MprisController.activePlayer !== null)
|
|
||||||
sourceComponent: root.getWidgetComponent(itemData.widgetId)
|
|
||||||
opacity: (itemData.enabled !== false) ? 1 : 0
|
|
||||||
asynchronous: false
|
|
||||||
|
|
||||||
onLoaded: {
|
readonly property bool active: widgetLoader.active
|
||||||
if (!item) {
|
readonly property var item: widgetLoader.item
|
||||||
return;
|
|
||||||
}
|
WidgetHost {
|
||||||
item.widthChanged.connect(() => {
|
id: widgetLoader
|
||||||
if (layoutTimer)
|
|
||||||
layoutTimer.restart();
|
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
|
||||||
});
|
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
|
||||||
item.heightChanged.connect(() => {
|
|
||||||
if (layoutTimer)
|
widgetId: itemData.widgetId
|
||||||
layoutTimer.restart();
|
widgetData: itemData
|
||||||
});
|
spacerSize: itemData.size || 20
|
||||||
if (root.axis && "axis" in item) {
|
components: root.components
|
||||||
item.axis = Qt.binding(() => root.axis);
|
isInColumn: root.isVertical
|
||||||
}
|
axis: root.axis
|
||||||
if (root.axis && "isVertical" in item) {
|
section: "center"
|
||||||
try {
|
parentScreen: root.parentScreen
|
||||||
item.isVertical = Qt.binding(() => root.axis.isVertical);
|
widgetThickness: root.widgetThickness
|
||||||
} catch (e) {}
|
barThickness: root.barThickness
|
||||||
|
barSpacing: root.barSpacing
|
||||||
|
barConfig: root.barConfig
|
||||||
|
isFirst: index === 0
|
||||||
|
isLast: index === centerRepeater.count - 1
|
||||||
|
sectionSpacing: parent.itemSpacing
|
||||||
|
isLeftBarEdge: false
|
||||||
|
isRightBarEdge: false
|
||||||
|
isTopBarEdge: false
|
||||||
|
isBottomBarEdge: false
|
||||||
|
|
||||||
|
onContentItemReady: contentItem => {
|
||||||
|
contentItem.widthChanged.connect(() => layoutTimer.restart());
|
||||||
|
contentItem.heightChanged.connect(() => layoutTimer.restart());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject properties for plugin widgets
|
onActiveChanged: layoutTimer.restart()
|
||||||
if ("section" in item) {
|
|
||||||
item.section = root.section;
|
|
||||||
}
|
|
||||||
if ("parentScreen" in item) {
|
|
||||||
item.parentScreen = Qt.binding(() => root.parentScreen);
|
|
||||||
}
|
|
||||||
if ("widgetThickness" in item) {
|
|
||||||
item.widgetThickness = Qt.binding(() => root.widgetThickness);
|
|
||||||
}
|
|
||||||
if ("barThickness" in item) {
|
|
||||||
item.barThickness = Qt.binding(() => root.barThickness);
|
|
||||||
}
|
|
||||||
if ("barSpacing" in item) {
|
|
||||||
item.barSpacing = Qt.binding(() => root.barSpacing);
|
|
||||||
}
|
|
||||||
if ("barConfig" in item) {
|
|
||||||
item.barConfig = Qt.binding(() => root.barConfig);
|
|
||||||
}
|
|
||||||
if ("sectionSpacing" in item) {
|
|
||||||
item.sectionSpacing = Qt.binding(() => root.spacing);
|
|
||||||
}
|
|
||||||
if ("widgetData" in item) {
|
|
||||||
item.widgetData = Qt.binding(() => widgetData);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("isFirst" in item) {
|
|
||||||
item.isFirst = Qt.binding(() => {
|
|
||||||
for (var i = 0; i < centerRepeater.count; i++) {
|
|
||||||
const checkItem = centerRepeater.itemAt(i);
|
|
||||||
if (checkItem && checkItem.active && checkItem.item) {
|
|
||||||
return checkItem.item === item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("isLast" in item) {
|
|
||||||
item.isLast = Qt.binding(() => {
|
|
||||||
for (var i = centerRepeater.count - 1; i >= 0; i--) {
|
|
||||||
const checkItem = centerRepeater.itemAt(i);
|
|
||||||
if (checkItem && checkItem.active && checkItem.item) {
|
|
||||||
return checkItem.item === item;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if ("isLeftBarEdge" in item) {
|
|
||||||
item.isLeftBarEdge = false;
|
|
||||||
}
|
|
||||||
if ("isRightBarEdge" in item) {
|
|
||||||
item.isRightBarEdge = false;
|
|
||||||
}
|
|
||||||
if ("isTopBarEdge" in item) {
|
|
||||||
item.isTopBarEdge = false;
|
|
||||||
}
|
|
||||||
if ("isBottomBarEdge" in item) {
|
|
||||||
item.isBottomBarEdge = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.pluginService !== undefined) {
|
|
||||||
var parts = model.widgetId.split(":");
|
|
||||||
var pluginId = parts[0];
|
|
||||||
var variantId = parts.length > 1 ? parts[1] : null;
|
|
||||||
|
|
||||||
if (item.pluginId !== undefined) {
|
|
||||||
item.pluginId = pluginId;
|
|
||||||
}
|
|
||||||
if (item.variantId !== undefined) {
|
|
||||||
item.variantId = variantId;
|
|
||||||
}
|
|
||||||
if (item.variantData !== undefined && variantId) {
|
|
||||||
item.variantData = PluginService.getPluginVariantData(pluginId, variantId);
|
|
||||||
}
|
|
||||||
item.pluginService = PluginService;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.popoutService !== undefined) {
|
|
||||||
item.popoutService = PopoutService;
|
|
||||||
}
|
|
||||||
|
|
||||||
layoutTimer.restart();
|
|
||||||
}
|
|
||||||
|
|
||||||
onActiveChanged: {
|
|
||||||
layoutTimer.restart();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
|
||||||
target: PluginService
|
|
||||||
function onPluginLoaded(pluginId) {
|
|
||||||
// Force refresh of component lookups
|
|
||||||
for (var i = 0; i < centerRepeater.count; i++) {
|
|
||||||
var item = centerRepeater.itemAt(i);
|
|
||||||
if (item && item.widgetId.startsWith(pluginId)) {
|
|
||||||
item.sourceComponent = root.getWidgetComponent(item.widgetId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function onPluginUnloaded(pluginId) {
|
|
||||||
// Force refresh of component lookups
|
|
||||||
for (var i = 0; i < centerRepeater.count; i++) {
|
|
||||||
var item = centerRepeater.itemAt(i);
|
|
||||||
if (item && item.widgetId.startsWith(pluginId)) {
|
|
||||||
item.sourceComponent = root.getWidgetComponent(item.widgetId);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ Item {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === Qt.Key_Right) {
|
if (event.key === Qt.Key_Right || event.key === Qt.Key_L) {
|
||||||
if (gridIndex + 1 < visibleCount) {
|
if (gridIndex + 1 < visibleCount) {
|
||||||
gridIndex++;
|
gridIndex++;
|
||||||
} else if (currentPage < totalPages - 1) {
|
} else if (currentPage < totalPages - 1) {
|
||||||
@@ -104,7 +104,7 @@ Item {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === Qt.Key_Left) {
|
if (event.key === Qt.Key_Left || event.key === Qt.Key_H) {
|
||||||
if (gridIndex > 0) {
|
if (gridIndex > 0) {
|
||||||
gridIndex--;
|
gridIndex--;
|
||||||
} else if (currentPage > 0) {
|
} else if (currentPage > 0) {
|
||||||
@@ -115,7 +115,7 @@ Item {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === Qt.Key_Down) {
|
if (event.key === Qt.Key_Down || event.key === Qt.Key_J) {
|
||||||
if (gridIndex + columns < visibleCount) {
|
if (gridIndex + columns < visibleCount) {
|
||||||
gridIndex += columns;
|
gridIndex += columns;
|
||||||
} else if (currentPage < totalPages - 1) {
|
} else if (currentPage < totalPages - 1) {
|
||||||
@@ -125,7 +125,7 @@ Item {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event.key === Qt.Key_Up) {
|
if (event.key === Qt.Key_Up || event.key === Qt.Key_K) {
|
||||||
if (gridIndex >= columns) {
|
if (gridIndex >= columns) {
|
||||||
gridIndex -= columns;
|
gridIndex -= columns;
|
||||||
} else if (currentPage > 0) {
|
} else if (currentPage > 0) {
|
||||||
|
|||||||
@@ -208,14 +208,11 @@ SWAY_EOF
|
|||||||
;;
|
;;
|
||||||
|
|
||||||
mangowc)
|
mangowc)
|
||||||
TEMP_DIR=$(mktemp -d)
|
|
||||||
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
||||||
cp "$COMPOSITOR_CONFIG" "$TEMP_DIR/config.conf"
|
exec mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit"
|
||||||
else
|
else
|
||||||
touch "$TEMP_DIR/config.conf"
|
exec mango -s "$QS_CMD && mmsg -d quit"
|
||||||
fi
|
fi
|
||||||
export MANGOCONFIG="$TEMP_DIR"
|
|
||||||
exec mango -s "$QS_CMD && mmsg -d quit"
|
|
||||||
;;
|
;;
|
||||||
|
|
||||||
*)
|
*)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -18,262 +19,365 @@ Rectangle {
|
|||||||
property int gridRows: 2
|
property int gridRows: 2
|
||||||
property bool useGridLayout: false
|
property bool useGridLayout: false
|
||||||
|
|
||||||
signal closed()
|
property string holdAction: ""
|
||||||
|
property int holdActionIndex: -1
|
||||||
|
property real holdProgress: 0
|
||||||
|
property bool showHoldHint: false
|
||||||
|
|
||||||
|
readonly property bool needsConfirmation: SettingsData.powerActionConfirm
|
||||||
|
readonly property int holdDurationMs: SettingsData.powerActionHoldDuration * 1000
|
||||||
|
|
||||||
|
signal closed
|
||||||
|
|
||||||
function updateVisibleActions() {
|
function updateVisibleActions() {
|
||||||
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions)
|
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"];
|
||||||
? SettingsData.powerMenuActions
|
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false;
|
||||||
: ["logout", "suspend", "hibernate", "reboot", "poweroff"]
|
|
||||||
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false
|
|
||||||
let filtered = allActions.filter(action => {
|
let filtered = allActions.filter(action => {
|
||||||
if (action === "hibernate" && !hibernateSupported) return false
|
if (action === "hibernate" && !hibernateSupported)
|
||||||
if (action === "lock") return false
|
return false;
|
||||||
if (action === "restart") return false
|
if (action === "lock")
|
||||||
if (action === "logout" && !showLogout) return false
|
return false;
|
||||||
return true
|
if (action === "restart")
|
||||||
})
|
return false;
|
||||||
|
if (action === "logout" && !showLogout)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
visibleActions = filtered
|
visibleActions = filtered;
|
||||||
|
|
||||||
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined)
|
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false;
|
||||||
? SettingsData.powerMenuGridLayout
|
if (!useGridLayout)
|
||||||
: false
|
return;
|
||||||
if (!useGridLayout) return
|
const count = visibleActions.length;
|
||||||
|
|
||||||
const count = visibleActions.length
|
|
||||||
if (count === 0) {
|
if (count === 0) {
|
||||||
gridColumns = 1
|
gridColumns = 1;
|
||||||
gridRows = 1
|
gridRows = 1;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count <= 3) {
|
if (count <= 3) {
|
||||||
gridColumns = 1
|
gridColumns = 1;
|
||||||
gridRows = count
|
gridRows = count;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count === 4) {
|
if (count === 4) {
|
||||||
gridColumns = 2
|
gridColumns = 2;
|
||||||
gridRows = 2
|
gridRows = 2;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
gridColumns = 3
|
gridColumns = 3;
|
||||||
gridRows = Math.ceil(count / 3)
|
gridRows = Math.ceil(count / 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDefaultActionIndex() {
|
function getDefaultActionIndex() {
|
||||||
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction)
|
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend";
|
||||||
? SettingsData.powerMenuDefaultAction
|
const index = visibleActions.indexOf(defaultAction);
|
||||||
: "suspend"
|
return index >= 0 ? index : 0;
|
||||||
const index = visibleActions.indexOf(defaultAction)
|
|
||||||
return index >= 0 ? index : 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActionAtIndex(index) {
|
function getActionAtIndex(index) {
|
||||||
if (index < 0 || index >= visibleActions.length) return ""
|
if (index < 0 || index >= visibleActions.length)
|
||||||
return visibleActions[index]
|
return "";
|
||||||
|
return visibleActions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getActionData(action) {
|
function getActionData(action) {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "reboot":
|
case "reboot":
|
||||||
return { "icon": "restart_alt", "label": I18n.tr("Reboot"), "key": "R" }
|
return {
|
||||||
|
"icon": "restart_alt",
|
||||||
|
"label": I18n.tr("Reboot"),
|
||||||
|
"key": "R"
|
||||||
|
};
|
||||||
case "logout":
|
case "logout":
|
||||||
return { "icon": "logout", "label": I18n.tr("Log Out"), "key": "X" }
|
return {
|
||||||
|
"icon": "logout",
|
||||||
|
"label": I18n.tr("Log Out"),
|
||||||
|
"key": "X"
|
||||||
|
};
|
||||||
case "poweroff":
|
case "poweroff":
|
||||||
return { "icon": "power_settings_new", "label": I18n.tr("Power Off"), "key": "P" }
|
return {
|
||||||
|
"icon": "power_settings_new",
|
||||||
|
"label": I18n.tr("Power Off"),
|
||||||
|
"key": "P"
|
||||||
|
};
|
||||||
case "suspend":
|
case "suspend":
|
||||||
return { "icon": "bedtime", "label": I18n.tr("Suspend"), "key": "S" }
|
return {
|
||||||
|
"icon": "bedtime",
|
||||||
|
"label": I18n.tr("Suspend"),
|
||||||
|
"key": "S"
|
||||||
|
};
|
||||||
case "hibernate":
|
case "hibernate":
|
||||||
return { "icon": "ac_unit", "label": I18n.tr("Hibernate"), "key": "H" }
|
return {
|
||||||
|
"icon": "ac_unit",
|
||||||
|
"label": I18n.tr("Hibernate"),
|
||||||
|
"key": "H"
|
||||||
|
};
|
||||||
default:
|
default:
|
||||||
return { "icon": "help", "label": action, "key": "?" }
|
return {
|
||||||
|
"icon": "help",
|
||||||
|
"label": action,
|
||||||
|
"key": "?"
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectOption(action) {
|
function actionNeedsConfirm(action) {
|
||||||
if (!action) return
|
return action !== "lock" && action !== "restart";
|
||||||
if (typeof SessionService === "undefined") return
|
}
|
||||||
hide()
|
|
||||||
|
function startHold(action, actionIndex) {
|
||||||
|
if (!needsConfirmation || !actionNeedsConfirm(action)) {
|
||||||
|
executeAction(action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
holdAction = action;
|
||||||
|
holdActionIndex = actionIndex;
|
||||||
|
holdProgress = 0;
|
||||||
|
showHoldHint = false;
|
||||||
|
holdTimer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
function cancelHold() {
|
||||||
|
if (holdAction === "")
|
||||||
|
return;
|
||||||
|
const wasHolding = holdProgress > 0;
|
||||||
|
holdTimer.stop();
|
||||||
|
if (wasHolding && holdProgress < 1) {
|
||||||
|
showHoldHint = true;
|
||||||
|
hintTimer.restart();
|
||||||
|
}
|
||||||
|
holdAction = "";
|
||||||
|
holdActionIndex = -1;
|
||||||
|
holdProgress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function completeHold() {
|
||||||
|
if (holdProgress < 1) {
|
||||||
|
cancelHold();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const action = holdAction;
|
||||||
|
holdTimer.stop();
|
||||||
|
holdAction = "";
|
||||||
|
holdActionIndex = -1;
|
||||||
|
holdProgress = 0;
|
||||||
|
executeAction(action);
|
||||||
|
}
|
||||||
|
|
||||||
|
function executeAction(action) {
|
||||||
|
if (!action)
|
||||||
|
return;
|
||||||
|
if (typeof SessionService === "undefined")
|
||||||
|
return;
|
||||||
|
hide();
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "logout":
|
case "logout":
|
||||||
SessionService.logout()
|
SessionService.logout();
|
||||||
break
|
break;
|
||||||
case "suspend":
|
case "suspend":
|
||||||
SessionService.suspend()
|
SessionService.suspend();
|
||||||
break
|
break;
|
||||||
case "hibernate":
|
case "hibernate":
|
||||||
SessionService.hibernate()
|
SessionService.hibernate();
|
||||||
break
|
break;
|
||||||
case "reboot":
|
case "reboot":
|
||||||
SessionService.reboot()
|
SessionService.reboot();
|
||||||
break
|
break;
|
||||||
case "poweroff":
|
case "poweroff":
|
||||||
SessionService.poweroff()
|
SessionService.poweroff();
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function selectOption(action, actionIndex) {
|
||||||
|
startHold(action, actionIndex !== undefined ? actionIndex : -1);
|
||||||
|
}
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
updateVisibleActions()
|
holdAction = "";
|
||||||
const defaultIndex = getDefaultActionIndex()
|
holdActionIndex = -1;
|
||||||
|
holdProgress = 0;
|
||||||
|
showHoldHint = false;
|
||||||
|
updateVisibleActions();
|
||||||
|
const defaultIndex = getDefaultActionIndex();
|
||||||
if (useGridLayout) {
|
if (useGridLayout) {
|
||||||
selectedRow = Math.floor(defaultIndex / gridColumns)
|
selectedRow = Math.floor(defaultIndex / gridColumns);
|
||||||
selectedCol = defaultIndex % gridColumns
|
selectedCol = defaultIndex % gridColumns;
|
||||||
selectedIndex = defaultIndex
|
selectedIndex = defaultIndex;
|
||||||
} else {
|
} else {
|
||||||
selectedIndex = defaultIndex
|
selectedIndex = defaultIndex;
|
||||||
}
|
}
|
||||||
isVisible = true
|
isVisible = true;
|
||||||
Qt.callLater(() => powerMenuFocusScope.forceActiveFocus())
|
Qt.callLater(() => powerMenuFocusScope.forceActiveFocus());
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
isVisible = false
|
cancelHold();
|
||||||
closed()
|
isVisible = false;
|
||||||
|
closed();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleListNavigation(event) {
|
function handleListNavigation(event, isPressed) {
|
||||||
|
if (!isPressed) {
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_S || event.key === Qt.Key_H || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) {
|
||||||
|
cancelHold();
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case Qt.Key_Up:
|
case Qt.Key_Up:
|
||||||
case Qt.Key_Backtab:
|
case Qt.Key_Backtab:
|
||||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Down:
|
case Qt.Key_Down:
|
||||||
case Qt.Key_Tab:
|
case Qt.Key_Tab:
|
||||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
selectedIndex = (selectedIndex + 1) % visibleActions.length;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
selectOption(getActionAtIndex(selectedIndex))
|
startHold(getActionAtIndex(selectedIndex), selectedIndex);
|
||||||
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) {
|
||||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
selectedIndex = (selectedIndex + 1) % visibleActions.length;
|
||||||
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)) {
|
||||||
selectOption("poweroff")
|
const idx = visibleActions.indexOf("poweroff");
|
||||||
event.accepted = true
|
startHold("poweroff", idx);
|
||||||
|
event.accepted = true;
|
||||||
} else {
|
} else {
|
||||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length;
|
||||||
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) {
|
||||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
selectedIndex = (selectedIndex + 1) % visibleActions.length;
|
||||||
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) {
|
||||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
case Qt.Key_R:
|
case Qt.Key_R:
|
||||||
selectOption("reboot")
|
startHold("reboot", visibleActions.indexOf("reboot"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_X:
|
case Qt.Key_X:
|
||||||
selectOption("logout")
|
startHold("logout", visibleActions.indexOf("logout"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_S:
|
case Qt.Key_S:
|
||||||
selectOption("suspend")
|
startHold("suspend", visibleActions.indexOf("suspend"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_H:
|
case Qt.Key_H:
|
||||||
selectOption("hibernate")
|
startHold("hibernate", visibleActions.indexOf("hibernate"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleGridNavigation(event) {
|
function handleGridNavigation(event, isPressed) {
|
||||||
|
if (!isPressed) {
|
||||||
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter || event.key === Qt.Key_R || event.key === Qt.Key_X || event.key === Qt.Key_S || event.key === Qt.Key_H || (event.key === Qt.Key_P && !(event.modifiers & Qt.ControlModifier))) {
|
||||||
|
cancelHold();
|
||||||
|
event.accepted = true;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event.key) {
|
switch (event.key) {
|
||||||
case Qt.Key_Left:
|
case Qt.Key_Left:
|
||||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
|
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Right:
|
case Qt.Key_Right:
|
||||||
selectedCol = (selectedCol + 1) % gridColumns
|
selectedCol = (selectedCol + 1) % gridColumns;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Up:
|
case Qt.Key_Up:
|
||||||
case Qt.Key_Backtab:
|
case Qt.Key_Backtab:
|
||||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows
|
selectedRow = (selectedRow - 1 + gridRows) % gridRows;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Down:
|
case Qt.Key_Down:
|
||||||
case Qt.Key_Tab:
|
case Qt.Key_Tab:
|
||||||
selectedRow = (selectedRow + 1) % gridRows
|
selectedRow = (selectedRow + 1) % gridRows;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_Return:
|
case Qt.Key_Return:
|
||||||
case Qt.Key_Enter:
|
case Qt.Key_Enter:
|
||||||
selectOption(getActionAtIndex(selectedIndex))
|
startHold(getActionAtIndex(selectedIndex), selectedIndex);
|
||||||
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) {
|
||||||
selectedCol = (selectedCol + 1) % gridColumns
|
selectedCol = (selectedCol + 1) % gridColumns;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
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)) {
|
||||||
selectOption("poweroff")
|
const idx = visibleActions.indexOf("poweroff");
|
||||||
event.accepted = true
|
startHold("poweroff", idx);
|
||||||
|
event.accepted = true;
|
||||||
} else {
|
} else {
|
||||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
|
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
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) {
|
||||||
selectedRow = (selectedRow + 1) % gridRows
|
selectedRow = (selectedRow + 1) % gridRows;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
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) {
|
||||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows
|
selectedRow = (selectedRow - 1 + gridRows) % gridRows;
|
||||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
case Qt.Key_R:
|
case Qt.Key_R:
|
||||||
selectOption("reboot")
|
startHold("reboot", visibleActions.indexOf("reboot"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_X:
|
case Qt.Key_X:
|
||||||
selectOption("logout")
|
startHold("logout", visibleActions.indexOf("logout"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_S:
|
case Qt.Key_S:
|
||||||
selectOption("suspend")
|
startHold("suspend", visibleActions.indexOf("suspend"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
case Qt.Key_H:
|
case Qt.Key_H:
|
||||||
selectOption("hibernate")
|
startHold("hibernate", visibleActions.indexOf("hibernate"));
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,29 +391,62 @@ Rectangle {
|
|||||||
onClicked: root.hide()
|
onClicked: root.hide()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: holdTimer
|
||||||
|
interval: 16
|
||||||
|
repeat: true
|
||||||
|
onTriggered: {
|
||||||
|
root.holdProgress = Math.min(1, root.holdProgress + (interval / root.holdDurationMs));
|
||||||
|
if (root.holdProgress >= 1) {
|
||||||
|
stop();
|
||||||
|
root.completeHold();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: hintTimer
|
||||||
|
interval: 2000
|
||||||
|
onTriggered: root.showHoldHint = false
|
||||||
|
}
|
||||||
|
|
||||||
FocusScope {
|
FocusScope {
|
||||||
id: powerMenuFocusScope
|
id: powerMenuFocusScope
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: root.isVisible
|
focus: root.isVisible
|
||||||
|
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) Qt.callLater(() => forceActiveFocus())
|
if (visible)
|
||||||
|
Qt.callLater(() => forceActiveFocus());
|
||||||
}
|
}
|
||||||
|
|
||||||
Keys.onEscapePressed: root.hide()
|
Keys.onEscapePressed: root.hide()
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
|
if (event.isAutoRepeat) {
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (useGridLayout) {
|
if (useGridLayout) {
|
||||||
handleGridNavigation(event)
|
handleGridNavigation(event, true);
|
||||||
} else {
|
} else {
|
||||||
handleListNavigation(event)
|
handleListNavigation(event, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Keys.onReleased: event => {
|
||||||
|
if (event.isAutoRepeat) {
|
||||||
|
event.accepted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (useGridLayout) {
|
||||||
|
handleGridNavigation(event, false);
|
||||||
|
} else {
|
||||||
|
handleListNavigation(event, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
width: useGridLayout
|
width: useGridLayout ? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2) : 320
|
||||||
? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2)
|
|
||||||
: 320
|
|
||||||
height: contentItem.implicitHeight + Theme.spacingL * 2
|
height: contentItem.implicitHeight + Theme.spacingL * 2
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: Theme.surfaceContainer
|
color: Theme.surfaceContainer
|
||||||
@@ -320,7 +457,7 @@ Rectangle {
|
|||||||
id: contentItem
|
id: contentItem
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
implicitHeight: headerRow.height + Theme.spacingM + (useGridLayout ? buttonGrid.implicitHeight : buttonColumn.implicitHeight)
|
implicitHeight: headerRow.height + Theme.spacingM + (useGridLayout ? buttonGrid.implicitHeight : buttonColumn.implicitHeight) + (root.needsConfirmation ? hintRow.height + Theme.spacingM : 0)
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
id: headerRow
|
id: headerRow
|
||||||
@@ -363,48 +500,86 @@ Rectangle {
|
|||||||
model: root.visibleActions
|
model: root.visibleActions
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: gridButtonRect
|
||||||
required property int index
|
required property int index
|
||||||
required property string modelData
|
required property string modelData
|
||||||
|
|
||||||
readonly property var actionData: root.getActionData(modelData)
|
readonly property var actionData: root.getActionData(modelData)
|
||||||
readonly property bool isSelected: root.selectedIndex === index
|
readonly property bool isSelected: root.selectedIndex === index
|
||||||
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
||||||
|
readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0
|
||||||
|
|
||||||
width: (contentItem.width - Theme.spacingS * (root.gridColumns - 1)) / root.gridColumns
|
width: (contentItem.width - Theme.spacingS * (root.gridColumns - 1)) / root.gridColumns
|
||||||
height: 100
|
height: 100
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (isSelected) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
if (isSelected)
|
||||||
if (mouseArea.containsMouse) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
if (mouseArea.containsMouse)
|
||||||
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||||
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||||
}
|
}
|
||||||
border.color: isSelected ? Theme.primary : "transparent"
|
border.color: isSelected ? Theme.primary : "transparent"
|
||||||
border.width: isSelected ? 2 : 0
|
border.width: isSelected ? 2 : 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: gridProgressMask
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: parent.radius
|
||||||
|
visible: false
|
||||||
|
layer.enabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: gridButtonRect.isHolding
|
||||||
|
layer.enabled: gridButtonRect.isHolding
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: gridProgressMask
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: parent.width * root.holdProgress
|
||||||
|
color: {
|
||||||
|
if (gridButtonRect.modelData === "poweroff")
|
||||||
|
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3);
|
||||||
|
if (gridButtonRect.modelData === "reboot")
|
||||||
|
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3);
|
||||||
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: parent.parent.actionData.icon
|
name: gridButtonRect.actionData.icon
|
||||||
size: Theme.iconSize + 8
|
size: Theme.iconSize + 8
|
||||||
color: {
|
color: {
|
||||||
if (parent.parent.showWarning && mouseArea.containsMouse) {
|
if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) {
|
||||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||||
}
|
}
|
||||||
return Theme.surfaceText
|
return Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: parent.parent.actionData.label
|
text: gridButtonRect.actionData.label
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: {
|
color: {
|
||||||
if (parent.parent.showWarning && mouseArea.containsMouse) {
|
if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) {
|
||||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||||
}
|
}
|
||||||
return Theme.surfaceText
|
return Theme.surfaceText;
|
||||||
}
|
}
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
@@ -418,7 +593,7 @@ Rectangle {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: parent.parent.parent.actionData.key
|
text: gridButtonRect.actionData.key
|
||||||
font.pixelSize: Theme.fontSizeSmall - 1
|
font.pixelSize: Theme.fontSizeSmall - 1
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -432,11 +607,14 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onPressed: {
|
||||||
root.selectedRow = Math.floor(index / root.gridColumns)
|
root.selectedRow = Math.floor(index / root.gridColumns);
|
||||||
root.selectedCol = index % root.gridColumns
|
root.selectedCol = index % root.gridColumns;
|
||||||
root.selectOption(modelData)
|
root.selectedIndex = index;
|
||||||
|
root.startHold(modelData, index);
|
||||||
}
|
}
|
||||||
|
onReleased: root.cancelHold()
|
||||||
|
onCanceled: root.cancelHold()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,24 +633,62 @@ Rectangle {
|
|||||||
model: root.visibleActions
|
model: root.visibleActions
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: listButtonRect
|
||||||
required property int index
|
required property int index
|
||||||
required property string modelData
|
required property string modelData
|
||||||
|
|
||||||
readonly property var actionData: root.getActionData(modelData)
|
readonly property var actionData: root.getActionData(modelData)
|
||||||
readonly property bool isSelected: root.selectedIndex === index
|
readonly property bool isSelected: root.selectedIndex === index
|
||||||
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
||||||
|
readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 50
|
height: 50
|
||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: {
|
color: {
|
||||||
if (isSelected) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
if (isSelected)
|
||||||
if (listMouseArea.containsMouse) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08)
|
if (listMouseArea.containsMouse)
|
||||||
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08);
|
||||||
|
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08);
|
||||||
}
|
}
|
||||||
border.color: isSelected ? Theme.primary : "transparent"
|
border.color: isSelected ? Theme.primary : "transparent"
|
||||||
border.width: isSelected ? 2 : 0
|
border.width: isSelected ? 2 : 0
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: listProgressMask
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: parent.radius
|
||||||
|
visible: false
|
||||||
|
layer.enabled: true
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: listButtonRect.isHolding
|
||||||
|
layer.enabled: listButtonRect.isHolding
|
||||||
|
layer.effect: MultiEffect {
|
||||||
|
maskEnabled: true
|
||||||
|
maskSource: listProgressMask
|
||||||
|
maskSpreadAtMin: 1
|
||||||
|
maskThresholdMin: 0.5
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
width: parent.width * root.holdProgress
|
||||||
|
color: {
|
||||||
|
if (listButtonRect.modelData === "poweroff")
|
||||||
|
return Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3);
|
||||||
|
if (listButtonRect.modelData === "reboot")
|
||||||
|
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.3);
|
||||||
|
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Row {
|
Row {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
@@ -482,25 +698,25 @@ Rectangle {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
DankIcon {
|
DankIcon {
|
||||||
name: parent.parent.actionData.icon
|
name: listButtonRect.actionData.icon
|
||||||
size: Theme.iconSize + 4
|
size: Theme.iconSize + 4
|
||||||
color: {
|
color: {
|
||||||
if (parent.parent.showWarning && listMouseArea.containsMouse) {
|
if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) {
|
||||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||||
}
|
}
|
||||||
return Theme.surfaceText
|
return Theme.surfaceText;
|
||||||
}
|
}
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: parent.parent.actionData.label
|
text: listButtonRect.actionData.label
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: {
|
color: {
|
||||||
if (parent.parent.showWarning && listMouseArea.containsMouse) {
|
if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) {
|
||||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||||
}
|
}
|
||||||
return Theme.surfaceText
|
return Theme.surfaceText;
|
||||||
}
|
}
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -517,7 +733,7 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: parent.parent.actionData.key
|
text: listButtonRect.actionData.key
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -530,14 +746,53 @@ Rectangle {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onPressed: {
|
||||||
root.selectedIndex = index
|
root.selectedIndex = index;
|
||||||
root.selectOption(modelData)
|
root.startHold(modelData, index);
|
||||||
}
|
}
|
||||||
|
onReleased: root.cancelHold()
|
||||||
|
onCanceled: root.cancelHold()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: hintRow
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.bottomMargin: Theme.spacingS
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
visible: root.needsConfirmation
|
||||||
|
opacity: root.showHoldHint ? 1 : 0.5
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: 150
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: root.showHoldHint ? "warning" : "touch_app"
|
||||||
|
size: Theme.fontSizeSmall
|
||||||
|
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
readonly property int remainingSeconds: Math.ceil(SettingsData.powerActionHoldDuration * (1 - root.holdProgress))
|
||||||
|
text: {
|
||||||
|
if (root.showHoldHint)
|
||||||
|
return I18n.tr("Hold longer to confirm");
|
||||||
|
if (root.holdProgress > 0)
|
||||||
|
return I18n.tr("Hold to confirm (%1s)").arg(remainingSeconds);
|
||||||
|
return I18n.tr("Hold to confirm (%1s)").arg(SettingsData.powerActionHoldDuration);
|
||||||
|
}
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: root.showHoldHint ? Theme.warning : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,9 @@ Item {
|
|||||||
readonly property bool hasVerticalPill: verticalBarPill !== null
|
readonly property bool hasVerticalPill: verticalBarPill !== null
|
||||||
readonly property bool hasPopout: popoutContent !== null
|
readonly property bool hasPopout: popoutContent !== null
|
||||||
|
|
||||||
|
readonly property int iconSize: Theme.barIconSize(barThickness, -4)
|
||||||
|
readonly property int iconSizeLarge: Theme.barIconSize(barThickness)
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
loadPluginData();
|
loadPluginData();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,10 +45,14 @@ Item {
|
|||||||
Item {
|
Item {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: logoModeGroup.implicitHeight
|
height: logoModeGroup.implicitHeight
|
||||||
|
clip: true
|
||||||
|
|
||||||
DankButtonGroup {
|
DankButtonGroup {
|
||||||
id: logoModeGroup
|
id: logoModeGroup
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
buttonPadding: parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
||||||
|
minButtonWidth: parent.width < 480 ? 44 : 64
|
||||||
|
textSize: parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||||
model: {
|
model: {
|
||||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")];
|
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")];
|
||||||
if (CompositorService.isNiri) {
|
if (CompositorService.isNiri) {
|
||||||
@@ -153,78 +157,88 @@ Item {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
|
|
||||||
Row {
|
Item {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
height: colorOverrideRow.implicitHeight
|
||||||
|
clip: true
|
||||||
|
|
||||||
DankButtonGroup {
|
Row {
|
||||||
id: colorModeGroup
|
id: colorOverrideRow
|
||||||
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
currentIndex: {
|
spacing: Theme.spacingM
|
||||||
const override = SettingsData.launcherLogoColorOverride;
|
|
||||||
if (override === "")
|
DankButtonGroup {
|
||||||
return 0;
|
id: colorModeGroup
|
||||||
if (override === "primary")
|
buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
||||||
return 1;
|
minButtonWidth: parent.parent.width < 480 ? 44 : 64
|
||||||
if (override === "surface")
|
textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||||
return 2;
|
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
||||||
return 3;
|
currentIndex: {
|
||||||
}
|
const override = SettingsData.launcherLogoColorOverride;
|
||||||
onSelectionChanged: (index, selected) => {
|
if (override === "")
|
||||||
if (!selected)
|
return 0;
|
||||||
return;
|
if (override === "primary")
|
||||||
switch (index) {
|
return 1;
|
||||||
case 0:
|
if (override === "surface")
|
||||||
SettingsData.set("launcherLogoColorOverride", "");
|
return 2;
|
||||||
break;
|
return 3;
|
||||||
case 1:
|
|
||||||
SettingsData.set("launcherLogoColorOverride", "primary");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
SettingsData.set("launcherLogoColorOverride", "surface");
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
const currentOverride = SettingsData.launcherLogoColorOverride;
|
|
||||||
const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface";
|
|
||||||
if (isPreset) {
|
|
||||||
SettingsData.set("launcherLogoColorOverride", "#ffffff");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
onSelectionChanged: (index, selected) => {
|
||||||
}
|
if (!selected)
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
visible: {
|
|
||||||
const override = SettingsData.launcherLogoColorOverride;
|
|
||||||
return override !== "" && override !== "primary" && override !== "surface";
|
|
||||||
}
|
|
||||||
width: 36
|
|
||||||
height: 36
|
|
||||||
radius: 18
|
|
||||||
color: {
|
|
||||||
const override = SettingsData.launcherLogoColorOverride;
|
|
||||||
if (override !== "" && override !== "primary" && override !== "surface") {
|
|
||||||
return override;
|
|
||||||
}
|
|
||||||
return "#ffffff";
|
|
||||||
}
|
|
||||||
border.color: Theme.outline
|
|
||||||
border.width: 1
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
if (!PopoutService.colorPickerModal)
|
|
||||||
return;
|
return;
|
||||||
PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride;
|
switch (index) {
|
||||||
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color");
|
case 0:
|
||||||
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
SettingsData.set("launcherLogoColorOverride", "");
|
||||||
SettingsData.set("launcherLogoColorOverride", selectedColor);
|
break;
|
||||||
};
|
case 1:
|
||||||
PopoutService.colorPickerModal.show();
|
SettingsData.set("launcherLogoColorOverride", "primary");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
SettingsData.set("launcherLogoColorOverride", "surface");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
const currentOverride = SettingsData.launcherLogoColorOverride;
|
||||||
|
const isPreset = currentOverride === "" || currentOverride === "primary" || currentOverride === "surface";
|
||||||
|
if (isPreset) {
|
||||||
|
SettingsData.set("launcherLogoColorOverride", "#ffffff");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: colorPickerCircle
|
||||||
|
visible: {
|
||||||
|
const override = SettingsData.launcherLogoColorOverride;
|
||||||
|
return override !== "" && override !== "primary" && override !== "surface";
|
||||||
|
}
|
||||||
|
width: 36
|
||||||
|
height: 36
|
||||||
|
radius: 18
|
||||||
|
color: {
|
||||||
|
const override = SettingsData.launcherLogoColorOverride;
|
||||||
|
if (override !== "" && override !== "primary" && override !== "surface")
|
||||||
|
return override;
|
||||||
|
return "#ffffff";
|
||||||
|
}
|
||||||
|
border.color: Theme.outline
|
||||||
|
border.width: 1
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
if (!PopoutService.colorPickerModal)
|
||||||
|
return;
|
||||||
|
PopoutService.colorPickerModal.selectedColor = SettingsData.launcherLogoColorOverride;
|
||||||
|
PopoutService.colorPickerModal.pickerTitle = I18n.tr("Choose Launcher Logo Color");
|
||||||
|
PopoutService.colorPickerModal.onColorSelectedCallback = function (selectedColor) {
|
||||||
|
SettingsData.set("launcherLogoColorOverride", selectedColor);
|
||||||
|
};
|
||||||
|
PopoutService.colorPickerModal.show();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -329,28 +343,32 @@ Item {
|
|||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
text: I18n.tr("Close Overview on Launch")
|
text: I18n.tr("Close Overview on Launch")
|
||||||
description: I18n.tr("When enabled, launching an app from the launcher will automatically close the Niri overview if it's open.")
|
description: I18n.tr("Auto-close Niri overview when launching apps.")
|
||||||
checked: SettingsData.spotlightCloseNiriOverview
|
checked: SettingsData.spotlightCloseNiriOverview
|
||||||
onToggled: checked => SettingsData.set("spotlightCloseNiriOverview", checked)
|
onToggled: checked => SettingsData.set("spotlightCloseNiriOverview", checked)
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsToggleRow {
|
SettingsToggleRow {
|
||||||
text: I18n.tr("Enable Overview Overlay")
|
text: I18n.tr("Enable Overview Overlay")
|
||||||
description: I18n.tr("When enabled, shows the launcher overlay when typing in Niri overview mode. Disable this if you prefer to not have the launcher when typing on Niri overview or want to use other launcher in the overview.")
|
description: I18n.tr("Show launcher overlay when typing in Niri overview. Disable to use another launcher.")
|
||||||
checked: SettingsData.niriOverviewOverlayEnabled
|
checked: SettingsData.niriOverviewOverlayEnabled
|
||||||
onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked)
|
onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SettingsCard {
|
SettingsCard {
|
||||||
|
id: recentAppsCard
|
||||||
width: parent.width
|
width: parent.width
|
||||||
iconName: "history"
|
iconName: "history"
|
||||||
title: I18n.tr("Recently Used Apps")
|
title: I18n.tr("Recently Used Apps")
|
||||||
|
|
||||||
property var rankedAppsModel: {
|
property var rankedAppsModel: {
|
||||||
|
var ranking = AppUsageHistoryData.appUsageRanking;
|
||||||
|
if (!ranking)
|
||||||
|
return [];
|
||||||
var apps = [];
|
var apps = [];
|
||||||
for (var appId in (AppUsageHistoryData.appUsageRanking || {})) {
|
for (var appId in ranking) {
|
||||||
var appData = (AppUsageHistoryData.appUsageRanking || {})[appId];
|
var appData = ranking[appId];
|
||||||
apps.push({
|
apps.push({
|
||||||
"id": appId,
|
"id": appId,
|
||||||
"name": appData.name,
|
"name": appData.name,
|
||||||
@@ -401,7 +419,7 @@ Item {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: parent.parent.rankedAppsModel
|
model: recentAppsCard.rankedAppsModel
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
width: rankedAppsList.width
|
width: rankedAppsList.width
|
||||||
@@ -496,11 +514,11 @@ Item {
|
|||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
text: parent.parent.rankedAppsModel.length === 0 ? "No apps have been launched yet." : ""
|
text: "No apps have been launched yet."
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
visible: parent.parent.rankedAppsModel.length === 0
|
visible: recentAppsCard.rankedAppsModel.length === 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ Item {
|
|||||||
{
|
{
|
||||||
"id": "gpuTemp",
|
"id": "gpuTemp",
|
||||||
"text": I18n.tr("GPU Temperature"),
|
"text": I18n.tr("GPU Temperature"),
|
||||||
"description": I18n.tr("GPU temperature display"),
|
"description": "",
|
||||||
"icon": "auto_awesome_mosaic",
|
"icon": "auto_awesome_mosaic",
|
||||||
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : I18n.tr("This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics."),
|
"warning": !DgopService.dgopAvailable ? I18n.tr("Requires 'dgop' tool") : I18n.tr("This widget prevents GPU power off states, which can significantly impact battery life on laptops. It is not recommended to use this on laptops with hybrid graphics."),
|
||||||
"enabled": DgopService.dgopAvailable
|
"enabled": DgopService.dgopAvailable
|
||||||
|
|||||||
@@ -168,7 +168,17 @@ Column {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StyledText {
|
StyledText {
|
||||||
text: modelData.description
|
text: {
|
||||||
|
if (modelData.id === "gpuTemp") {
|
||||||
|
var selectedIdx = modelData.selectedGpuIndex !== undefined ? modelData.selectedGpuIndex : 0;
|
||||||
|
if (DgopService.availableGpus && DgopService.availableGpus.length > selectedIdx) {
|
||||||
|
var gpu = DgopService.availableGpus[selectedIdx];
|
||||||
|
return gpu.driver ? gpu.driver.toUpperCase() : "";
|
||||||
|
}
|
||||||
|
return I18n.tr("No GPU detected");
|
||||||
|
}
|
||||||
|
return modelData.description;
|
||||||
|
}
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
|
color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
@@ -185,39 +195,37 @@ Column {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Item {
|
DankActionButton {
|
||||||
width: 60
|
id: gpuMenuButton
|
||||||
height: 32
|
|
||||||
visible: modelData.id === "gpuTemp"
|
visible: modelData.id === "gpuTemp"
|
||||||
|
buttonSize: 32
|
||||||
|
iconName: "more_vert"
|
||||||
|
iconSize: 18
|
||||||
|
iconColor: Theme.outline
|
||||||
|
onClicked: {
|
||||||
|
gpuContextMenu.widgetData = modelData;
|
||||||
|
gpuContextMenu.sectionId = root.sectionId;
|
||||||
|
gpuContextMenu.widgetIndex = index;
|
||||||
|
|
||||||
DankDropdown {
|
var buttonPos = gpuMenuButton.mapToItem(root, 0, 0);
|
||||||
id: gpuDropdown
|
var popupWidth = gpuContextMenu.width;
|
||||||
anchors.fill: parent
|
var popupHeight = gpuContextMenu.height;
|
||||||
popupWidth: -1
|
|
||||||
currentValue: {
|
var xPos = buttonPos.x - popupWidth - Theme.spacingS;
|
||||||
var selectedIndex = modelData.selectedGpuIndex !== undefined ? modelData.selectedGpuIndex : 0;
|
if (xPos < 0) {
|
||||||
if (DgopService.availableGpus && DgopService.availableGpus.length > selectedIndex && selectedIndex >= 0) {
|
xPos = buttonPos.x + gpuMenuButton.width + Theme.spacingS;
|
||||||
var gpu = DgopService.availableGpus[selectedIndex];
|
|
||||||
return gpu.driver.toUpperCase();
|
|
||||||
}
|
|
||||||
return DgopService.availableGpus && DgopService.availableGpus.length > 0 ? DgopService.availableGpus[0].driver.toUpperCase() : "";
|
|
||||||
}
|
}
|
||||||
options: {
|
|
||||||
var gpuOptions = [];
|
var yPos = buttonPos.y - popupHeight / 2 + gpuMenuButton.height / 2;
|
||||||
if (DgopService.availableGpus && DgopService.availableGpus.length > 0) {
|
if (yPos < 0) {
|
||||||
for (var i = 0; i < DgopService.availableGpus.length; i++) {
|
yPos = Theme.spacingS;
|
||||||
var gpu = DgopService.availableGpus[i];
|
} else if (yPos + popupHeight > root.height) {
|
||||||
gpuOptions.push(gpu.driver.toUpperCase());
|
yPos = root.height - popupHeight - Theme.spacingS;
|
||||||
}
|
|
||||||
}
|
|
||||||
return gpuOptions;
|
|
||||||
}
|
|
||||||
onValueChanged: value => {
|
|
||||||
var gpuIndex = options.indexOf(value);
|
|
||||||
if (gpuIndex >= 0) {
|
|
||||||
root.gpuSelectionChanged(root.sectionId, index, gpuIndex);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gpuContextMenu.x = xPos;
|
||||||
|
gpuContextMenu.y = yPos;
|
||||||
|
gpuContextMenu.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1123,4 +1131,112 @@ Column {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Popup {
|
||||||
|
id: gpuContextMenu
|
||||||
|
|
||||||
|
property var widgetData: null
|
||||||
|
property string sectionId: ""
|
||||||
|
property int widgetIndex: -1
|
||||||
|
|
||||||
|
width: 250
|
||||||
|
height: gpuMenuColumn.implicitHeight + Theme.spacingS * 2
|
||||||
|
padding: 0
|
||||||
|
modal: true
|
||||||
|
focus: true
|
||||||
|
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||||
|
|
||||||
|
background: Rectangle {
|
||||||
|
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||||
|
border.width: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: Item {
|
||||||
|
Column {
|
||||||
|
id: gpuMenuColumn
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: DgopService.availableGpus || []
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
required property var modelData
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
width: gpuMenuColumn.width
|
||||||
|
height: 40
|
||||||
|
radius: Theme.cornerRadius
|
||||||
|
color: gpuOptionArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||||
|
|
||||||
|
property bool isSelected: {
|
||||||
|
var selectedIdx = gpuContextMenu.widgetData ? (gpuContextMenu.widgetData.selectedGpuIndex !== undefined ? gpuContextMenu.widgetData.selectedGpuIndex : 0) : 0;
|
||||||
|
return index === selectedIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.leftMargin: Theme.spacingS
|
||||||
|
anchors.right: checkIcon.left
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: "memory"
|
||||||
|
size: 18
|
||||||
|
color: isSelected ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
spacing: 2
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.driver ? modelData.driver.toUpperCase() : ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
font.weight: Font.Medium
|
||||||
|
color: isSelected ? Theme.primary : Theme.surfaceText
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: modelData.displayName || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
width: 180
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
id: checkIcon
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.rightMargin: Theme.spacingS
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
name: "check"
|
||||||
|
size: 18
|
||||||
|
color: Theme.primary
|
||||||
|
visible: isSelected
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: gpuOptionArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
root.gpuSelectionChanged(gpuContextMenu.sectionId, gpuContextMenu.widgetIndex, index);
|
||||||
|
gpuContextMenu.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -357,6 +357,35 @@ Singleton {
|
|||||||
return devices.length > 0 ? devices[0].id : "";
|
return devices.length > 0 ? devices[0].id : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPinnedDeviceForFocusedScreen() {
|
||||||
|
const focusedScreen = CompositorService.getFocusedScreen();
|
||||||
|
if (!focusedScreen)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
const pins = SettingsData.brightnessDevicePins || {};
|
||||||
|
const screenKey = SettingsData.getScreenDisplayName(focusedScreen);
|
||||||
|
if (!screenKey)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
const pinnedDevice = pins[screenKey];
|
||||||
|
if (!pinnedDevice)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
const deviceExists = devices.some(d => d.id === pinnedDevice);
|
||||||
|
if (!deviceExists)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
return pinnedDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPreferredDevice() {
|
||||||
|
const pinned = getPinnedDeviceForFocusedScreen();
|
||||||
|
if (pinned)
|
||||||
|
return pinned;
|
||||||
|
|
||||||
|
return getDefaultDevice();
|
||||||
|
}
|
||||||
|
|
||||||
function getCurrentDeviceInfo() {
|
function getCurrentDeviceInfo() {
|
||||||
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice);
|
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice);
|
||||||
if (!deviceToUse) {
|
if (!deviceToUse) {
|
||||||
@@ -809,110 +838,95 @@ Singleton {
|
|||||||
// IPC Handler for external control
|
// IPC Handler for external control
|
||||||
IpcHandler {
|
IpcHandler {
|
||||||
function set(percentage: string, device: string): string {
|
function set(percentage: string, device: string): string {
|
||||||
if (!root.brightnessAvailable) {
|
if (!root.brightnessAvailable)
|
||||||
return "Brightness control not available";
|
return "Brightness control not available";
|
||||||
}
|
|
||||||
|
|
||||||
const value = parseInt(percentage);
|
const value = parseInt(percentage);
|
||||||
if (isNaN(value)) {
|
if (isNaN(value))
|
||||||
return "Invalid brightness value: " + percentage;
|
return "Invalid brightness value: " + percentage;
|
||||||
}
|
|
||||||
|
|
||||||
const targetDevice = device || "";
|
const actualDevice = device || root.getPreferredDevice();
|
||||||
|
|
||||||
if (targetDevice && !root.devices.some(d => d.id === targetDevice)) {
|
if (actualDevice && !root.devices.some(d => d.id === actualDevice))
|
||||||
return "Device not found: " + targetDevice;
|
return "Device not found: " + actualDevice;
|
||||||
}
|
|
||||||
|
|
||||||
const deviceInfo = targetDevice ? root.getCurrentDeviceInfoByName(targetDevice) : null;
|
const deviceInfo = actualDevice ? root.getCurrentDeviceInfoByName(actualDevice) : null;
|
||||||
const minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
|
const minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
|
||||||
const clampedValue = Math.max(minValue, Math.min(100, value));
|
const clampedValue = Math.max(minValue, Math.min(100, value));
|
||||||
|
|
||||||
root.lastIpcDevice = targetDevice;
|
root.lastIpcDevice = actualDevice;
|
||||||
if (targetDevice && targetDevice !== root.currentDevice) {
|
if (actualDevice && actualDevice !== root.currentDevice)
|
||||||
root.setCurrentDevice(targetDevice, false);
|
root.setCurrentDevice(actualDevice, false);
|
||||||
}
|
|
||||||
root.setBrightness(clampedValue, targetDevice);
|
|
||||||
|
|
||||||
if (targetDevice) {
|
root.setBrightness(clampedValue, actualDevice);
|
||||||
return "Brightness set to " + clampedValue + "% on " + targetDevice;
|
|
||||||
} else {
|
return actualDevice ? "Brightness set to " + clampedValue + "% on " + actualDevice : "Brightness set to " + clampedValue + "%";
|
||||||
return "Brightness set to " + clampedValue + "%";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function increment(step: string, device: string): string {
|
function increment(step: string, device: string): string {
|
||||||
if (!root.brightnessAvailable) {
|
if (!root.brightnessAvailable)
|
||||||
return "Brightness control not available";
|
return "Brightness control not available";
|
||||||
}
|
|
||||||
|
|
||||||
const targetDevice = device || "";
|
const actualDevice = device || root.getPreferredDevice();
|
||||||
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice;
|
|
||||||
|
|
||||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice)) {
|
if (actualDevice && !root.devices.some(d => d.id === actualDevice))
|
||||||
return "Device not found: " + actualDevice;
|
return "Device not found: " + actualDevice;
|
||||||
}
|
|
||||||
|
|
||||||
const stepValue = parseInt(step || "5");
|
const stepValue = parseInt(step || "5");
|
||||||
|
|
||||||
root.lastIpcDevice = actualDevice;
|
root.lastIpcDevice = actualDevice;
|
||||||
if (actualDevice && actualDevice !== root.currentDevice) {
|
if (actualDevice && actualDevice !== root.currentDevice)
|
||||||
root.setCurrentDevice(actualDevice, false);
|
root.setCurrentDevice(actualDevice, false);
|
||||||
}
|
|
||||||
|
|
||||||
const isExponential = SessionData.getBrightnessExponential(actualDevice);
|
const isExponential = SessionData.getBrightnessExponential(actualDevice);
|
||||||
const currentBrightness = root.getDeviceBrightness(actualDevice);
|
const currentBrightness = root.getDeviceBrightness(actualDevice);
|
||||||
const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
|
const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
|
||||||
|
|
||||||
let maxValue = 100;
|
const maxValue = isExponential ? 100 : (deviceInfo?.displayMax || 100);
|
||||||
if (isExponential) {
|
|
||||||
maxValue = 100;
|
|
||||||
} else {
|
|
||||||
maxValue = deviceInfo?.displayMax || 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
const newBrightness = Math.min(maxValue, currentBrightness + stepValue);
|
const newBrightness = Math.min(maxValue, currentBrightness + stepValue);
|
||||||
|
|
||||||
root.setBrightness(newBrightness, actualDevice);
|
root.setBrightness(newBrightness, actualDevice);
|
||||||
|
|
||||||
return "Brightness increased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
return "Brightness increased by " + stepValue + "%" + (device ? " on " + actualDevice : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrement(step: string, device: string): string {
|
function decrement(step: string, device: string): string {
|
||||||
if (!root.brightnessAvailable) {
|
if (!root.brightnessAvailable)
|
||||||
return "Brightness control not available";
|
return "Brightness control not available";
|
||||||
}
|
|
||||||
|
|
||||||
const targetDevice = device || "";
|
const actualDevice = device || root.getPreferredDevice();
|
||||||
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice;
|
|
||||||
|
|
||||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice)) {
|
if (actualDevice && !root.devices.some(d => d.id === actualDevice))
|
||||||
return "Device not found: " + actualDevice;
|
return "Device not found: " + actualDevice;
|
||||||
}
|
|
||||||
|
|
||||||
const stepValue = parseInt(step || "5");
|
const stepValue = parseInt(step || "5");
|
||||||
|
|
||||||
root.lastIpcDevice = actualDevice;
|
root.lastIpcDevice = actualDevice;
|
||||||
if (actualDevice && actualDevice !== root.currentDevice) {
|
if (actualDevice && actualDevice !== root.currentDevice)
|
||||||
root.setCurrentDevice(actualDevice, false);
|
root.setCurrentDevice(actualDevice, false);
|
||||||
}
|
|
||||||
|
|
||||||
const isExponential = SessionData.getBrightnessExponential(actualDevice);
|
const isExponential = SessionData.getBrightnessExponential(actualDevice);
|
||||||
const currentBrightness = root.getDeviceBrightness(actualDevice);
|
const currentBrightness = root.getDeviceBrightness(actualDevice);
|
||||||
const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
|
const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
|
||||||
|
|
||||||
let minValue = 0;
|
let minValue = 0;
|
||||||
if (isExponential) {
|
switch (true) {
|
||||||
|
case isExponential:
|
||||||
minValue = 1;
|
minValue = 1;
|
||||||
} else {
|
break;
|
||||||
minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
|
case deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc"):
|
||||||
|
minValue = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
minValue = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newBrightness = Math.max(minValue, currentBrightness - stepValue);
|
const newBrightness = Math.max(minValue, currentBrightness - stepValue);
|
||||||
|
|
||||||
root.setBrightness(newBrightness, actualDevice);
|
root.setBrightness(newBrightness, actualDevice);
|
||||||
|
|
||||||
return "Brightness decreased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
return "Brightness decreased by " + stepValue + "%" + (device ? " on " + actualDevice : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function status(): string {
|
function status(): string {
|
||||||
|
|||||||
@@ -197,6 +197,8 @@ Singleton {
|
|||||||
property bool _settingsWantsOpen: false
|
property bool _settingsWantsOpen: false
|
||||||
property bool _settingsWantsToggle: false
|
property bool _settingsWantsToggle: false
|
||||||
|
|
||||||
|
property string _settingsPendingTab: ""
|
||||||
|
|
||||||
function openSettings() {
|
function openSettings() {
|
||||||
if (settingsModal) {
|
if (settingsModal) {
|
||||||
settingsModal.show();
|
settingsModal.show();
|
||||||
@@ -207,6 +209,19 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openSettingsWithTab(tabName: string) {
|
||||||
|
if (settingsModal) {
|
||||||
|
settingsModal.showWithTabName(tabName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (settingsModalLoader) {
|
||||||
|
_settingsPendingTab = tabName;
|
||||||
|
_settingsWantsOpen = true;
|
||||||
|
_settingsWantsToggle = false;
|
||||||
|
settingsModalLoader.activeAsync = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function closeSettings() {
|
function closeSettings() {
|
||||||
settingsModal?.close();
|
settingsModal?.close();
|
||||||
}
|
}
|
||||||
@@ -221,6 +236,22 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleSettingsWithTab(tabName: string) {
|
||||||
|
if (settingsModal) {
|
||||||
|
var idx = settingsModal.resolveTabIndex(tabName);
|
||||||
|
if (idx >= 0)
|
||||||
|
settingsModal.currentTabIndex = idx;
|
||||||
|
settingsModal.toggle();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (settingsModalLoader) {
|
||||||
|
_settingsPendingTab = tabName;
|
||||||
|
_settingsWantsToggle = true;
|
||||||
|
_settingsWantsOpen = false;
|
||||||
|
settingsModalLoader.activeAsync = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function focusOrToggleSettings() {
|
function focusOrToggleSettings() {
|
||||||
if (settingsModal?.visible) {
|
if (settingsModal?.visible) {
|
||||||
const settingsTitle = I18n.tr("Settings", "settings window title");
|
const settingsTitle = I18n.tr("Settings", "settings window title");
|
||||||
@@ -238,6 +269,26 @@ Singleton {
|
|||||||
openSettings();
|
openSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function focusOrToggleSettingsWithTab(tabName: string) {
|
||||||
|
if (settingsModal?.visible) {
|
||||||
|
const settingsTitle = I18n.tr("Settings", "settings window title");
|
||||||
|
for (const toplevel of ToplevelManager.toplevels.values) {
|
||||||
|
if (toplevel.title !== "Settings" && toplevel.title !== settingsTitle)
|
||||||
|
continue;
|
||||||
|
if (toplevel.activated) {
|
||||||
|
settingsModal.hide();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var idx = settingsModal.resolveTabIndex(tabName);
|
||||||
|
if (idx >= 0)
|
||||||
|
settingsModal.currentTabIndex = idx;
|
||||||
|
toplevel.activate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
openSettingsWithTab(tabName);
|
||||||
|
}
|
||||||
|
|
||||||
function unloadSettings() {
|
function unloadSettings() {
|
||||||
if (settingsModalLoader) {
|
if (settingsModalLoader) {
|
||||||
settingsModal = null;
|
settingsModal = null;
|
||||||
@@ -248,9 +299,22 @@ Singleton {
|
|||||||
function _onSettingsModalLoaded() {
|
function _onSettingsModalLoaded() {
|
||||||
if (_settingsWantsOpen) {
|
if (_settingsWantsOpen) {
|
||||||
_settingsWantsOpen = false;
|
_settingsWantsOpen = false;
|
||||||
settingsModal?.show();
|
if (_settingsPendingTab) {
|
||||||
} else if (_settingsWantsToggle) {
|
settingsModal?.showWithTabName(_settingsPendingTab);
|
||||||
|
_settingsPendingTab = "";
|
||||||
|
} else {
|
||||||
|
settingsModal?.show();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_settingsWantsToggle) {
|
||||||
_settingsWantsToggle = false;
|
_settingsWantsToggle = false;
|
||||||
|
if (_settingsPendingTab) {
|
||||||
|
var idx = settingsModal?.resolveTabIndex(_settingsPendingTab) ?? -1;
|
||||||
|
if (idx >= 0)
|
||||||
|
settingsModal.currentTabIndex = idx;
|
||||||
|
_settingsPendingTab = "";
|
||||||
|
}
|
||||||
settingsModal?.toggle();
|
settingsModal?.toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,6 +37,6 @@ StyledRect {
|
|||||||
onClicked: root.clicked()
|
onClicked: root.clicked()
|
||||||
onEntered: root.entered()
|
onEntered: root.entered()
|
||||||
onExited: root.exited()
|
onExited: root.exited()
|
||||||
tooltipText: tooltipText
|
tooltipText: root.tooltipText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,9 +122,10 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
x: Theme.snap(slideContainer.slideOffset, root.dpr)
|
x: Theme.snap(slideContainer.slideOffset, root.dpr)
|
||||||
|
|
||||||
DankRectangle {
|
Rectangle {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
color: Theme.surfaceContainer
|
color: Theme.surfaceContainer
|
||||||
|
radius: Theme.cornerRadius
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
|
|||||||
@@ -11,7 +11,17 @@ Item {
|
|||||||
if (!item)
|
if (!item)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const windowContentItem = item.Window.window?.contentItem;
|
let windowContentItem = item.Window?.window?.contentItem;
|
||||||
|
if (!windowContentItem) {
|
||||||
|
let current = item;
|
||||||
|
while (current) {
|
||||||
|
if (current.Window?.window?.contentItem) {
|
||||||
|
windowContentItem = current.Window.window.contentItem;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
current = current.parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!windowContentItem)
|
if (!windowContentItem)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|||||||
@@ -21,29 +21,29 @@ MouseArea {
|
|||||||
color: Qt.rgba(stateColor.r, stateColor.g, stateColor.b, stateOpacity)
|
color: Qt.rgba(stateColor.r, stateColor.g, stateColor.b, stateOpacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
id: hoverDelay
|
id: hoverDelay
|
||||||
interval: 1000
|
interval: 1000
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
const p = root.mapToItem(null, parent.width / 2, parent.height + Theme.spacingXS)
|
tooltip.show(root.tooltipText, root, 0, 0, "bottom");
|
||||||
tooltip.show(I18n.tr(""), p.x, p.y, null)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if (!tooltipText) { return }
|
if (!tooltipText)
|
||||||
hoverDelay.restart()
|
return;
|
||||||
|
hoverDelay.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
if (!tooltipText) { return }
|
if (!tooltipText)
|
||||||
hoverDelay.stop()
|
return;
|
||||||
tooltip.hide()
|
hoverDelay.stop();
|
||||||
|
tooltip.hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
DankTooltip {
|
DankTooltipV2 {
|
||||||
id: tooltip
|
id: tooltip
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,6 +133,18 @@ Rectangle {
|
|||||||
onClicked: DMSNetworkService.disconnectAllActive()
|
onClicked: DMSNetworkService.disconnectAllActive()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DankActionButton {
|
||||||
|
Layout.alignment: Qt.AlignVCenter
|
||||||
|
iconName: "settings"
|
||||||
|
buttonSize: 28
|
||||||
|
iconSize: 16
|
||||||
|
iconColor: Theme.surfaceVariantText
|
||||||
|
onClicked: {
|
||||||
|
PopoutService.closeControlCenter();
|
||||||
|
PopoutService.openSettingsWithTab("network");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
Reference in New Issue
Block a user