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: cliphist
|
||||
Recommends: danksearch
|
||||
Recommends: hyprpicker
|
||||
Recommends: matugen
|
||||
Recommends: wl-clipboard
|
||||
Recommends: NetworkManager
|
||||
|
||||
@@ -33,7 +33,6 @@ Requires: dgop
|
||||
Recommends: cava
|
||||
Recommends: cliphist
|
||||
Recommends: danksearch
|
||||
Recommends: hyprpicker
|
||||
Recommends: matugen
|
||||
Recommends: quickshell-git
|
||||
Recommends: wl-clipboard
|
||||
|
||||
@@ -3,122 +3,139 @@ pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property int noTimeout: -1
|
||||
property int defaultDebounceMs: 50
|
||||
property int defaultTimeoutMs: 10000
|
||||
property var _procDebouncers: ({})
|
||||
|
||||
function runCommand(id, command, callback, debounceMs, timeoutMs) {
|
||||
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs
|
||||
const timeout = (typeof timeoutMs === "number" && timeoutMs > 0) ? timeoutMs : defaultTimeoutMs
|
||||
let procId = id ? id : Math.random()
|
||||
const isRandomId = !id
|
||||
const wait = (typeof debounceMs === "number" && debounceMs >= 0) ? debounceMs : defaultDebounceMs;
|
||||
const timeout = (typeof timeoutMs === "number") ? timeoutMs : defaultTimeoutMs;
|
||||
let procId = id ? id : Math.random();
|
||||
const isRandomId = !id;
|
||||
|
||||
if (!_procDebouncers[procId]) {
|
||||
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root)
|
||||
t.triggered.connect(function() { _launchProc(procId, isRandomId) })
|
||||
_procDebouncers[procId] = { timer: t, command: command, callback: callback, waitMs: wait, timeoutMs: timeout, isRandomId: isRandomId }
|
||||
const t = Qt.createQmlObject('import QtQuick; Timer { repeat: false }', root);
|
||||
t.triggered.connect(function () {
|
||||
_launchProc(procId, isRandomId);
|
||||
});
|
||||
_procDebouncers[procId] = {
|
||||
timer: t,
|
||||
command: command,
|
||||
callback: callback,
|
||||
waitMs: wait,
|
||||
timeoutMs: timeout,
|
||||
isRandomId: isRandomId
|
||||
};
|
||||
} else {
|
||||
_procDebouncers[procId].command = command
|
||||
_procDebouncers[procId].callback = callback
|
||||
_procDebouncers[procId].waitMs = wait
|
||||
_procDebouncers[procId].timeoutMs = timeout
|
||||
_procDebouncers[procId].command = command;
|
||||
_procDebouncers[procId].callback = callback;
|
||||
_procDebouncers[procId].waitMs = wait;
|
||||
_procDebouncers[procId].timeoutMs = timeout;
|
||||
}
|
||||
|
||||
const entry = _procDebouncers[procId]
|
||||
entry.timer.interval = entry.waitMs
|
||||
entry.timer.restart()
|
||||
const entry = _procDebouncers[procId];
|
||||
entry.timer.interval = entry.waitMs;
|
||||
entry.timer.restart();
|
||||
}
|
||||
|
||||
function _launchProc(id, isRandomId) {
|
||||
const entry = _procDebouncers[id]
|
||||
if (!entry) return
|
||||
const entry = _procDebouncers[id];
|
||||
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)
|
||||
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)
|
||||
proc.stdout = out;
|
||||
proc.stderr = err;
|
||||
proc.command = entry.command;
|
||||
|
||||
proc.stdout = out
|
||||
proc.stderr = err
|
||||
proc.command = entry.command
|
||||
let capturedOut = "";
|
||||
let capturedErr = "";
|
||||
let exitSeen = false;
|
||||
let exitCodeValue = -1;
|
||||
let outSeen = false;
|
||||
let errSeen = false;
|
||||
let timedOut = false;
|
||||
|
||||
let capturedOut = ""
|
||||
let capturedErr = ""
|
||||
let exitSeen = false
|
||||
let exitCodeValue = -1
|
||||
let outSeen = false
|
||||
let errSeen = false
|
||||
let timedOut = false
|
||||
|
||||
timeoutTimer.interval = entry.timeoutMs
|
||||
timeoutTimer.triggered.connect(function() {
|
||||
timeoutTimer.interval = entry.timeoutMs;
|
||||
timeoutTimer.triggered.connect(function () {
|
||||
if (!exitSeen) {
|
||||
timedOut = true
|
||||
proc.running = false
|
||||
exitSeen = true
|
||||
exitCodeValue = 124
|
||||
maybeComplete()
|
||||
timedOut = true;
|
||||
proc.running = false;
|
||||
exitSeen = true;
|
||||
exitCodeValue = 124;
|
||||
maybeComplete();
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
out.streamFinished.connect(function() {
|
||||
out.streamFinished.connect(function () {
|
||||
try {
|
||||
capturedOut = out.text || ""
|
||||
capturedOut = out.text || "";
|
||||
} catch (e) {
|
||||
capturedOut = ""
|
||||
capturedOut = "";
|
||||
}
|
||||
outSeen = true
|
||||
maybeComplete()
|
||||
})
|
||||
outSeen = true;
|
||||
maybeComplete();
|
||||
});
|
||||
|
||||
err.streamFinished.connect(function() {
|
||||
err.streamFinished.connect(function () {
|
||||
try {
|
||||
capturedErr = err.text || ""
|
||||
capturedErr = err.text || "";
|
||||
} catch (e) {
|
||||
capturedErr = ""
|
||||
capturedErr = "";
|
||||
}
|
||||
errSeen = true
|
||||
maybeComplete()
|
||||
})
|
||||
errSeen = true;
|
||||
maybeComplete();
|
||||
});
|
||||
|
||||
proc.exited.connect(function(code) {
|
||||
timeoutTimer.stop()
|
||||
exitSeen = true
|
||||
exitCodeValue = code
|
||||
maybeComplete()
|
||||
})
|
||||
proc.exited.connect(function (code) {
|
||||
timeoutTimer.stop();
|
||||
exitSeen = true;
|
||||
exitCodeValue = code;
|
||||
maybeComplete();
|
||||
});
|
||||
|
||||
function maybeComplete() {
|
||||
if (!exitSeen || !outSeen || !errSeen) return
|
||||
timeoutTimer.stop()
|
||||
if (!exitSeen || !outSeen || !errSeen)
|
||||
return;
|
||||
timeoutTimer.stop();
|
||||
if (entry && entry.callback && typeof entry.callback === "function") {
|
||||
try {
|
||||
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : ""
|
||||
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1
|
||||
entry.callback(safeOutput, safeExitCode)
|
||||
const safeOutput = capturedOut !== null && capturedOut !== undefined ? capturedOut : "";
|
||||
const safeExitCode = exitCodeValue !== null && exitCodeValue !== undefined ? exitCodeValue : -1;
|
||||
entry.callback(safeOutput, safeExitCode);
|
||||
} 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 { timeoutTimer.destroy() } catch (_) {}
|
||||
try {
|
||||
proc.destroy();
|
||||
} catch (_) {}
|
||||
try {
|
||||
timeoutTimer.destroy();
|
||||
} catch (_) {}
|
||||
|
||||
if (isRandomId || entry.isRandomId) {
|
||||
Qt.callLater(function() {
|
||||
Qt.callLater(function () {
|
||||
if (_procDebouncers[id]) {
|
||||
try { _procDebouncers[id].timer.destroy() } catch (_) {}
|
||||
delete _procDebouncers[id]
|
||||
try {
|
||||
_procDebouncers[id].timer.destroy();
|
||||
} catch (_) {}
|
||||
delete _procDebouncers[id];
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
proc.running = true
|
||||
timeoutTimer.start()
|
||||
proc.running = true;
|
||||
if (entry.timeoutMs !== noTimeout)
|
||||
timeoutTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -648,6 +648,13 @@ Item {
|
||||
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 {
|
||||
PopoutService.closeSettings();
|
||||
return "SETTINGS_CLOSE_SUCCESS";
|
||||
@@ -658,11 +665,47 @@ Item {
|
||||
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 {
|
||||
PopoutService.focusOrToggleSettings();
|
||||
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 {
|
||||
return JSON.stringify(SettingsData?.[key]);
|
||||
}
|
||||
|
||||
@@ -110,7 +110,7 @@ DankModal {
|
||||
console.warn("Failed to parse dms color pick JSON:", e);
|
||||
root.show();
|
||||
}
|
||||
});
|
||||
}, 0, Proc.noTimeout);
|
||||
}
|
||||
|
||||
modalWidth: 680
|
||||
|
||||
@@ -10,6 +10,7 @@ FloatingWindow {
|
||||
|
||||
property alias profileBrowser: profileBrowser
|
||||
property alias wallpaperBrowser: wallpaperBrowser
|
||||
property alias sidebar: sidebar
|
||||
property int currentTabIndex: 0
|
||||
property bool shouldHaveFocus: visible
|
||||
property bool allowFocusOverride: false
|
||||
@@ -32,6 +33,23 @@ FloatingWindow {
|
||||
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() {
|
||||
enableAnimations = true;
|
||||
menuVisible = !menuVisible;
|
||||
|
||||
@@ -21,26 +21,31 @@ Rectangle {
|
||||
"icon": "palette",
|
||||
"children": [
|
||||
{
|
||||
"id": "wallpaper",
|
||||
"text": I18n.tr("Wallpaper"),
|
||||
"icon": "wallpaper",
|
||||
"tabIndex": 0
|
||||
},
|
||||
{
|
||||
"id": "theme",
|
||||
"text": I18n.tr("Theme & Colors"),
|
||||
"icon": "format_paint",
|
||||
"tabIndex": 10
|
||||
},
|
||||
{
|
||||
"id": "typography",
|
||||
"text": I18n.tr("Typography & Motion"),
|
||||
"icon": "text_fields",
|
||||
"tabIndex": 14
|
||||
},
|
||||
{
|
||||
"id": "time_weather",
|
||||
"text": I18n.tr("Time & Weather"),
|
||||
"icon": "schedule",
|
||||
"tabIndex": 1
|
||||
},
|
||||
{
|
||||
"id": "sounds",
|
||||
"text": I18n.tr("Sounds"),
|
||||
"icon": "volume_up",
|
||||
"tabIndex": 15,
|
||||
@@ -54,11 +59,13 @@ Rectangle {
|
||||
"icon": "toolbar",
|
||||
"children": [
|
||||
{
|
||||
"id": "dankbar_settings",
|
||||
"text": I18n.tr("Settings"),
|
||||
"icon": "tune",
|
||||
"tabIndex": 3
|
||||
},
|
||||
{
|
||||
"id": "dankbar_widgets",
|
||||
"text": I18n.tr("Widgets"),
|
||||
"icon": "widgets",
|
||||
"tabIndex": 22
|
||||
@@ -72,32 +79,38 @@ Rectangle {
|
||||
"collapsedByDefault": true,
|
||||
"children": [
|
||||
{
|
||||
"id": "workspaces",
|
||||
"text": I18n.tr("Workspaces"),
|
||||
"icon": "view_module",
|
||||
"tabIndex": 4
|
||||
},
|
||||
{
|
||||
"id": "media_player",
|
||||
"text": I18n.tr("Media Player"),
|
||||
"icon": "music_note",
|
||||
"tabIndex": 16
|
||||
},
|
||||
{
|
||||
"id": "notifications",
|
||||
"text": I18n.tr("Notifications"),
|
||||
"icon": "notifications",
|
||||
"tabIndex": 17
|
||||
},
|
||||
{
|
||||
"id": "osd",
|
||||
"text": I18n.tr("On-screen Displays"),
|
||||
"icon": "tune",
|
||||
"tabIndex": 18
|
||||
},
|
||||
{
|
||||
"id": "running_apps",
|
||||
"text": I18n.tr("Running Apps"),
|
||||
"icon": "apps",
|
||||
"tabIndex": 19,
|
||||
"hyprlandNiriOnly": true
|
||||
},
|
||||
{
|
||||
"id": "updater",
|
||||
"text": I18n.tr("System Updater"),
|
||||
"icon": "refresh",
|
||||
"tabIndex": 20
|
||||
@@ -111,11 +124,13 @@ Rectangle {
|
||||
"collapsedByDefault": true,
|
||||
"children": [
|
||||
{
|
||||
"id": "dock",
|
||||
"text": I18n.tr("Dock"),
|
||||
"icon": "dock_to_bottom",
|
||||
"tabIndex": 5
|
||||
},
|
||||
{
|
||||
"id": "launcher",
|
||||
"text": I18n.tr("Launcher"),
|
||||
"icon": "grid_view",
|
||||
"tabIndex": 9
|
||||
@@ -123,7 +138,7 @@ Rectangle {
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "input",
|
||||
"id": "keybinds",
|
||||
"text": I18n.tr("Keyboard Shortcuts"),
|
||||
"icon": "keyboard",
|
||||
"tabIndex": 2,
|
||||
@@ -156,11 +171,13 @@ Rectangle {
|
||||
"collapsedByDefault": true,
|
||||
"children": [
|
||||
{
|
||||
"id": "lock_screen",
|
||||
"text": I18n.tr("Lock Screen"),
|
||||
"icon": "lock",
|
||||
"tabIndex": 11
|
||||
},
|
||||
{
|
||||
"id": "power_sleep",
|
||||
"text": I18n.tr("Power & Sleep"),
|
||||
"icon": "power_settings_new",
|
||||
"tabIndex": 21
|
||||
@@ -338,6 +355,37 @@ Rectangle {
|
||||
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
|
||||
height: parent.height
|
||||
color: Theme.withAlpha(Theme.surfaceContainer, Theme.popupTransparency)
|
||||
|
||||
@@ -312,7 +312,7 @@ Item {
|
||||
Row {
|
||||
id: viewModeButtons
|
||||
spacing: Theme.spacingXS
|
||||
visible: searchMode === "apps" && appLauncher.model.count > 0
|
||||
visible: searchMode === "apps"
|
||||
anchors.right: parent.right
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -17,20 +16,18 @@ PluginComponent {
|
||||
ccWidgetPrimaryText: I18n.tr("Printers")
|
||||
ccWidgetSecondaryText: {
|
||||
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 {
|
||||
if (!CupsService.cupsAvailable) {
|
||||
return I18n.tr("Print Server not available")
|
||||
return I18n.tr("Print Server not available");
|
||||
} else {
|
||||
return I18n.tr("No printer found")
|
||||
return I18n.tr("No printer found");
|
||||
}
|
||||
}
|
||||
}
|
||||
ccWidgetIsActive: CupsService.cupsAvailable && CupsService.getTotalJobsNum() > 0
|
||||
|
||||
onCcWidgetToggled: {
|
||||
|
||||
}
|
||||
onCcWidgetToggled: {}
|
||||
|
||||
ccDetailContent: Component {
|
||||
Rectangle {
|
||||
@@ -39,6 +36,21 @@ PluginComponent {
|
||||
radius: Theme.cornerRadius
|
||||
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 {
|
||||
visible: !CupsService.cupsAvailable || CupsService.getPrintersNum() == 0
|
||||
anchors.centerIn: parent
|
||||
@@ -78,12 +90,12 @@ PluginComponent {
|
||||
Layout.maximumWidth: parent.width - 180
|
||||
description: ""
|
||||
currentValue: {
|
||||
CupsService.getSelectedPrinter()
|
||||
CupsService.getSelectedPrinter();
|
||||
}
|
||||
options: CupsService.getPrintersNames()
|
||||
onValueChanged: value => {
|
||||
CupsService.setSelectedPrinter(value)
|
||||
}
|
||||
CupsService.setSelectedPrinter(value);
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -135,11 +147,11 @@ PluginComponent {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: true
|
||||
onClicked: {
|
||||
const selected = CupsService.getSelectedPrinter()
|
||||
const selected = CupsService.getSelectedPrinter();
|
||||
if (CupsService.getCurrentPrinterState() === "stopped") {
|
||||
CupsService.resumePrinter(selected)
|
||||
CupsService.resumePrinter(selected);
|
||||
} else {
|
||||
CupsService.pausePrinter(selected)
|
||||
CupsService.pausePrinter(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,8 +192,8 @@ PluginComponent {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: true
|
||||
onClicked: {
|
||||
const selected = CupsService.getSelectedPrinter()
|
||||
CupsService.purgeJobs(selected)
|
||||
const selected = CupsService.getSelectedPrinter();
|
||||
CupsService.purgeJobs(selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -275,8 +287,8 @@ PluginComponent {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
var date = new Date(modelData.timeCreated)
|
||||
return date.toLocaleString(Qt.locale(), Locale.ShortFormat)
|
||||
var date = new Date(modelData.timeCreated);
|
||||
return date.toLocaleString(Qt.locale(), Locale.ShortFormat);
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceTextMedium
|
||||
@@ -296,7 +308,7 @@ PluginComponent {
|
||||
iconName: "delete"
|
||||
buttonSize: 36
|
||||
onClicked: {
|
||||
CupsService.cancelJob(CupsService.getSelectedPrinter(), modelData.id)
|
||||
CupsService.cancelJob(CupsService.getSelectedPrinter(), modelData.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +69,8 @@ Rectangle {
|
||||
height: 40
|
||||
|
||||
StyledText {
|
||||
id: headerText
|
||||
text: I18n.tr("Network Settings")
|
||||
id: headerLeft
|
||||
text: I18n.tr("Network")
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
color: Theme.surfaceText
|
||||
font.weight: Font.Medium
|
||||
@@ -79,7 +79,7 @@ Rectangle {
|
||||
|
||||
Item {
|
||||
height: 1
|
||||
width: parent.width - headerText.width - rightControls.width
|
||||
width: parent.width - headerLeft.width - rightControls.width
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -115,6 +115,8 @@ Rectangle {
|
||||
id: preferenceControls
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: NetworkService.backend === "networkmanager" && DMSService.apiVersion > 10
|
||||
buttonHeight: 28
|
||||
textSize: Theme.fontSizeSmall
|
||||
|
||||
model: ["Ethernet", "WiFi"]
|
||||
currentIndex: currentPreferenceIndex
|
||||
@@ -125,6 +127,18 @@ Rectangle {
|
||||
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 qs.Common
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
@@ -19,7 +18,7 @@ Item {
|
||||
property bool forceVerticalLayout: 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 outlineThickness = (barConfig?.widgetOutlineEnabled ?? false) ? (barConfig?.widgetOutlineThickness ?? 1) : 0;
|
||||
return baseSpacing + (outlineThickness * 2);
|
||||
@@ -33,36 +32,32 @@ Item {
|
||||
if (SettingsData.centeringMode === "geometric") {
|
||||
applyGeometricLayout();
|
||||
} else {
|
||||
// Default to index layout or if value is not 'geometric'
|
||||
applyIndexLayout();
|
||||
}
|
||||
}
|
||||
|
||||
function applyGeometricLayout() {
|
||||
if ((isVertical ? height : width) <= 0 || !visible) {
|
||||
if ((isVertical ? height : width) <= 0 || !visible)
|
||||
return;
|
||||
}
|
||||
|
||||
centerWidgets = [];
|
||||
totalWidgets = 0;
|
||||
totalSize = 0;
|
||||
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
const item = centerRepeater.itemAt(i);
|
||||
if (item && item.active && item.item && getWidgetVisible(item.widgetId)) {
|
||||
centerWidgets.push(item.item);
|
||||
const loader = centerRepeater.itemAt(i);
|
||||
if (loader && loader.active && loader.item) {
|
||||
centerWidgets.push(loader.item);
|
||||
totalWidgets++;
|
||||
totalSize += isVertical ? item.item.height : item.item.width;
|
||||
totalSize += isVertical ? loader.item.height : loader.item.width;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWidgets === 0) {
|
||||
if (totalWidgets === 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalWidgets > 1) {
|
||||
totalSize += spacing * (totalWidgets - 1);
|
||||
}
|
||||
if (totalWidgets > 1)
|
||||
totalSize += widgetSpacing * (totalWidgets - 1);
|
||||
|
||||
positionWidgetsGeometric();
|
||||
}
|
||||
@@ -70,7 +65,6 @@ Item {
|
||||
function positionWidgetsGeometric() {
|
||||
const parentLength = isVertical ? height : width;
|
||||
const parentCenter = parentLength / 2;
|
||||
|
||||
let currentPos = parentCenter - (totalSize / 2);
|
||||
|
||||
centerWidgets.forEach(widget => {
|
||||
@@ -81,67 +75,53 @@ Item {
|
||||
widget.anchors.horizontalCenter = undefined;
|
||||
widget.x = currentPos;
|
||||
}
|
||||
|
||||
const widgetSize = isVertical ? widget.height : widget.width;
|
||||
currentPos += widgetSize + spacing;
|
||||
currentPos += widgetSize + widgetSpacing;
|
||||
});
|
||||
}
|
||||
|
||||
function applyIndexLayout() {
|
||||
if ((isVertical ? height : width) <= 0 || !visible) {
|
||||
if ((isVertical ? height : width) <= 0 || !visible)
|
||||
return;
|
||||
}
|
||||
|
||||
centerWidgets = [];
|
||||
totalWidgets = 0;
|
||||
totalSize = 0;
|
||||
|
||||
let configuredWidgets = 0;
|
||||
let configuredMiddleWidget = null;
|
||||
let configuredLeftWidget = null;
|
||||
let configuredRightWidget = null;
|
||||
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
const item = centerRepeater.itemAt(i);
|
||||
if (item && getWidgetVisible(item.widgetId)) {
|
||||
configuredWidgets++;
|
||||
}
|
||||
}
|
||||
|
||||
const configuredWidgets = centerRepeater.count;
|
||||
const isOddConfigured = configuredWidgets % 2 === 1;
|
||||
const configuredMiddlePos = Math.floor(configuredWidgets / 2);
|
||||
const configuredLeftPos = isOddConfigured ? -1 : ((configuredWidgets / 2) - 1);
|
||||
const configuredRightPos = isOddConfigured ? -1 : (configuredWidgets / 2);
|
||||
let currentConfigIndex = 0;
|
||||
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
const item = centerRepeater.itemAt(i);
|
||||
if (item && getWidgetVisible(item.widgetId)) {
|
||||
if (isOddConfigured && currentConfigIndex === configuredMiddlePos && item.active && item.item) {
|
||||
configuredMiddleWidget = item.item;
|
||||
}
|
||||
if (!isOddConfigured && currentConfigIndex === configuredLeftPos && item.active && item.item) {
|
||||
configuredLeftWidget = item.item;
|
||||
}
|
||||
if (!isOddConfigured && currentConfigIndex === configuredRightPos && item.active && item.item) {
|
||||
configuredRightWidget = item.item;
|
||||
}
|
||||
if (item.active && item.item) {
|
||||
centerWidgets.push(item.item);
|
||||
totalWidgets++;
|
||||
totalSize += isVertical ? item.item.height : item.item.width;
|
||||
}
|
||||
currentConfigIndex++;
|
||||
const wrapper = centerRepeater.itemAt(i);
|
||||
if (!wrapper)
|
||||
continue;
|
||||
|
||||
if (isOddConfigured && i === configuredMiddlePos && wrapper.active && wrapper.item)
|
||||
configuredMiddleWidget = wrapper.item;
|
||||
if (!isOddConfigured && i === configuredLeftPos && wrapper.active && wrapper.item)
|
||||
configuredLeftWidget = wrapper.item;
|
||||
if (!isOddConfigured && i === configuredRightPos && wrapper.active && wrapper.item)
|
||||
configuredRightWidget = wrapper.item;
|
||||
|
||||
if (wrapper.active && wrapper.item) {
|
||||
centerWidgets.push(wrapper.item);
|
||||
totalWidgets++;
|
||||
totalSize += isVertical ? wrapper.item.height : wrapper.item.width;
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWidgets === 0) {
|
||||
if (totalWidgets === 0)
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalWidgets > 1) {
|
||||
totalSize += spacing * (totalWidgets - 1);
|
||||
}
|
||||
if (totalWidgets > 1)
|
||||
totalSize += widgetSpacing * (totalWidgets - 1);
|
||||
|
||||
positionWidgetsByIndex(configuredWidgets, configuredMiddleWidget, configuredLeftWidget, configuredRightWidget);
|
||||
}
|
||||
@@ -151,11 +131,10 @@ Item {
|
||||
const isOddConfigured = configuredWidgets % 2 === 1;
|
||||
|
||||
centerWidgets.forEach(widget => {
|
||||
if (isVertical) {
|
||||
if (isVertical)
|
||||
widget.anchors.verticalCenter = undefined;
|
||||
} else {
|
||||
else
|
||||
widget.anchors.horizontalCenter = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
if (isOddConfigured && configuredMiddleWidget) {
|
||||
@@ -163,222 +142,154 @@ Item {
|
||||
const middleIndex = centerWidgets.indexOf(middleWidget);
|
||||
const middleSize = isVertical ? middleWidget.height : middleWidget.width;
|
||||
|
||||
if (isVertical) {
|
||||
if (isVertical)
|
||||
middleWidget.y = parentCenter - (middleSize / 2);
|
||||
} else {
|
||||
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) {
|
||||
currentPos -= (widgetSpacing + size);
|
||||
if (isVertical)
|
||||
centerWidgets[i].y = currentPos;
|
||||
} else {
|
||||
else
|
||||
centerWidgets[i].x = currentPos;
|
||||
}
|
||||
}
|
||||
|
||||
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
|
||||
for (var i = middleIndex + 1; i < totalWidgets; i++) {
|
||||
currentPos += spacing;
|
||||
if (isVertical) {
|
||||
currentPos += widgetSpacing;
|
||||
if (isVertical)
|
||||
centerWidgets[i].y = currentPos;
|
||||
} else {
|
||||
else
|
||||
centerWidgets[i].x = currentPos;
|
||||
}
|
||||
currentPos += isVertical ? centerWidgets[i].height : centerWidgets[i].width;
|
||||
}
|
||||
} else {
|
||||
if (totalWidgets === 1) {
|
||||
const widget = centerWidgets[0];
|
||||
const size = isVertical ? widget.height : widget.width;
|
||||
if (isVertical) {
|
||||
widget.y = parentCenter - (size / 2);
|
||||
} else {
|
||||
widget.x = parentCenter - (size / 2);
|
||||
return;
|
||||
}
|
||||
|
||||
if (totalWidgets === 1) {
|
||||
const widget = centerWidgets[0];
|
||||
const size = isVertical ? widget.height : widget.width;
|
||||
if (isVertical)
|
||||
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) {
|
||||
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 -= (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;
|
||||
}
|
||||
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize;
|
||||
for (var i = middleIndex + 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;
|
||||
}
|
||||
|
||||
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 {
|
||||
leftWidget.x = parentCenter - halfSpacing - leftSize;
|
||||
rightWidget.x = parentCenter + halfSpacing;
|
||||
}
|
||||
const leftIndex = (totalWidgets / 2) - 1;
|
||||
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) {
|
||||
centerWidgets[i].y = currentPos;
|
||||
fallbackLeft.y = parentCenter - halfSpacing - leftSize;
|
||||
fallbackRight.y = parentCenter + halfSpacing;
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
return;
|
||||
}
|
||||
|
||||
// For plugin components, get from PluginService
|
||||
var parts = widgetId.split(":");
|
||||
var pluginId = parts[0];
|
||||
let pluginComponents = PluginService.getWidgetComponents();
|
||||
return pluginComponents[pluginId] || null;
|
||||
const leftWidget = configuredLeftWidget;
|
||||
const rightWidget = configuredRightWidget;
|
||||
const leftIndex = centerWidgets.indexOf(leftWidget);
|
||||
const rightIndex = centerWidgets.indexOf(rightWidget);
|
||||
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
|
||||
@@ -392,177 +303,71 @@ Item {
|
||||
onTriggered: root.updateLayout()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
layoutTimer.restart();
|
||||
}
|
||||
Component.onCompleted: layoutTimer.restart()
|
||||
|
||||
onWidthChanged: {
|
||||
if (width > 0) {
|
||||
if (width > 0)
|
||||
layoutTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
onHeightChanged: {
|
||||
if (height > 0) {
|
||||
if (height > 0)
|
||||
layoutTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && (isVertical ? height : width) > 0) {
|
||||
if (visible && (isVertical ? height : width) > 0)
|
||||
layoutTimer.restart();
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: centerRepeater
|
||||
model: root.widgetsModel
|
||||
|
||||
Loader {
|
||||
onCountChanged: layoutTimer.restart()
|
||||
|
||||
Item {
|
||||
property var itemData: modelData
|
||||
property string widgetId: itemData.widgetId
|
||||
property var widgetData: itemData
|
||||
property int spacerSize: itemData.size || 20
|
||||
readonly property real itemSpacing: root.widgetSpacing
|
||||
|
||||
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
|
||||
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
|
||||
active: root.getWidgetVisible(itemData.widgetId) && (itemData.widgetId !== "music" || MprisController.activePlayer !== null)
|
||||
sourceComponent: root.getWidgetComponent(itemData.widgetId)
|
||||
opacity: (itemData.enabled !== false) ? 1 : 0
|
||||
asynchronous: false
|
||||
width: widgetLoader.item ? widgetLoader.item.width : 0
|
||||
height: widgetLoader.item ? widgetLoader.item.height : 0
|
||||
|
||||
onLoaded: {
|
||||
if (!item) {
|
||||
return;
|
||||
}
|
||||
item.widthChanged.connect(() => {
|
||||
if (layoutTimer)
|
||||
layoutTimer.restart();
|
||||
});
|
||||
item.heightChanged.connect(() => {
|
||||
if (layoutTimer)
|
||||
layoutTimer.restart();
|
||||
});
|
||||
if (root.axis && "axis" in item) {
|
||||
item.axis = Qt.binding(() => root.axis);
|
||||
}
|
||||
if (root.axis && "isVertical" in item) {
|
||||
try {
|
||||
item.isVertical = Qt.binding(() => root.axis.isVertical);
|
||||
} catch (e) {}
|
||||
readonly property bool active: widgetLoader.active
|
||||
readonly property var item: widgetLoader.item
|
||||
|
||||
WidgetHost {
|
||||
id: widgetLoader
|
||||
|
||||
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
|
||||
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
|
||||
|
||||
widgetId: itemData.widgetId
|
||||
widgetData: itemData
|
||||
spacerSize: itemData.size || 20
|
||||
components: root.components
|
||||
isInColumn: root.isVertical
|
||||
axis: root.axis
|
||||
section: "center"
|
||||
parentScreen: root.parentScreen
|
||||
widgetThickness: root.widgetThickness
|
||||
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
|
||||
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);
|
||||
}
|
||||
onActiveChanged: layoutTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ Item {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Right) {
|
||||
if (event.key === Qt.Key_Right || event.key === Qt.Key_L) {
|
||||
if (gridIndex + 1 < visibleCount) {
|
||||
gridIndex++;
|
||||
} else if (currentPage < totalPages - 1) {
|
||||
@@ -104,7 +104,7 @@ Item {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Left) {
|
||||
if (event.key === Qt.Key_Left || event.key === Qt.Key_H) {
|
||||
if (gridIndex > 0) {
|
||||
gridIndex--;
|
||||
} else if (currentPage > 0) {
|
||||
@@ -115,7 +115,7 @@ Item {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Down) {
|
||||
if (event.key === Qt.Key_Down || event.key === Qt.Key_J) {
|
||||
if (gridIndex + columns < visibleCount) {
|
||||
gridIndex += columns;
|
||||
} else if (currentPage < totalPages - 1) {
|
||||
@@ -125,7 +125,7 @@ Item {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Up) {
|
||||
if (event.key === Qt.Key_Up || event.key === Qt.Key_K) {
|
||||
if (gridIndex >= columns) {
|
||||
gridIndex -= columns;
|
||||
} else if (currentPage > 0) {
|
||||
|
||||
@@ -208,14 +208,11 @@ SWAY_EOF
|
||||
;;
|
||||
|
||||
mangowc)
|
||||
TEMP_DIR=$(mktemp -d)
|
||||
if [[ -n "$COMPOSITOR_CONFIG" ]]; then
|
||||
cp "$COMPOSITOR_CONFIG" "$TEMP_DIR/config.conf"
|
||||
exec mango -c "$COMPOSITOR_CONFIG" -s "$QS_CMD && mmsg -d quit"
|
||||
else
|
||||
touch "$TEMP_DIR/config.conf"
|
||||
exec mango -s "$QS_CMD && mmsg -d quit"
|
||||
fi
|
||||
export MANGOCONFIG="$TEMP_DIR"
|
||||
exec mango -s "$QS_CMD && mmsg -d quit"
|
||||
;;
|
||||
|
||||
*)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -18,262 +19,365 @@ Rectangle {
|
||||
property int gridRows: 2
|
||||
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() {
|
||||
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions)
|
||||
? SettingsData.powerMenuActions
|
||||
: ["logout", "suspend", "hibernate", "reboot", "poweroff"]
|
||||
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false
|
||||
const allActions = (typeof SettingsData !== "undefined" && SettingsData.powerMenuActions) ? SettingsData.powerMenuActions : ["logout", "suspend", "hibernate", "reboot", "poweroff"];
|
||||
const hibernateSupported = (typeof SessionService !== "undefined" && SessionService.hibernateSupported) || false;
|
||||
let filtered = allActions.filter(action => {
|
||||
if (action === "hibernate" && !hibernateSupported) return false
|
||||
if (action === "lock") return false
|
||||
if (action === "restart") return false
|
||||
if (action === "logout" && !showLogout) return false
|
||||
return true
|
||||
})
|
||||
if (action === "hibernate" && !hibernateSupported)
|
||||
return false;
|
||||
if (action === "lock")
|
||||
return false;
|
||||
if (action === "restart")
|
||||
return false;
|
||||
if (action === "logout" && !showLogout)
|
||||
return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
visibleActions = filtered
|
||||
visibleActions = filtered;
|
||||
|
||||
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined)
|
||||
? SettingsData.powerMenuGridLayout
|
||||
: false
|
||||
if (!useGridLayout) return
|
||||
|
||||
const count = visibleActions.length
|
||||
useGridLayout = (typeof SettingsData !== "undefined" && SettingsData.powerMenuGridLayout !== undefined) ? SettingsData.powerMenuGridLayout : false;
|
||||
if (!useGridLayout)
|
||||
return;
|
||||
const count = visibleActions.length;
|
||||
if (count === 0) {
|
||||
gridColumns = 1
|
||||
gridRows = 1
|
||||
return
|
||||
gridColumns = 1;
|
||||
gridRows = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (count <= 3) {
|
||||
gridColumns = 1
|
||||
gridRows = count
|
||||
return
|
||||
gridColumns = 1;
|
||||
gridRows = count;
|
||||
return;
|
||||
}
|
||||
|
||||
if (count === 4) {
|
||||
gridColumns = 2
|
||||
gridRows = 2
|
||||
return
|
||||
gridColumns = 2;
|
||||
gridRows = 2;
|
||||
return;
|
||||
}
|
||||
|
||||
gridColumns = 3
|
||||
gridRows = Math.ceil(count / 3)
|
||||
gridColumns = 3;
|
||||
gridRows = Math.ceil(count / 3);
|
||||
}
|
||||
|
||||
function getDefaultActionIndex() {
|
||||
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction)
|
||||
? SettingsData.powerMenuDefaultAction
|
||||
: "suspend"
|
||||
const index = visibleActions.indexOf(defaultAction)
|
||||
return index >= 0 ? index : 0
|
||||
const defaultAction = (typeof SettingsData !== "undefined" && SettingsData.powerMenuDefaultAction) ? SettingsData.powerMenuDefaultAction : "suspend";
|
||||
const index = visibleActions.indexOf(defaultAction);
|
||||
return index >= 0 ? index : 0;
|
||||
}
|
||||
|
||||
function getActionAtIndex(index) {
|
||||
if (index < 0 || index >= visibleActions.length) return ""
|
||||
return visibleActions[index]
|
||||
if (index < 0 || index >= visibleActions.length)
|
||||
return "";
|
||||
return visibleActions[index];
|
||||
}
|
||||
|
||||
function getActionData(action) {
|
||||
switch (action) {
|
||||
case "reboot":
|
||||
return { "icon": "restart_alt", "label": I18n.tr("Reboot"), "key": "R" }
|
||||
return {
|
||||
"icon": "restart_alt",
|
||||
"label": I18n.tr("Reboot"),
|
||||
"key": "R"
|
||||
};
|
||||
case "logout":
|
||||
return { "icon": "logout", "label": I18n.tr("Log Out"), "key": "X" }
|
||||
return {
|
||||
"icon": "logout",
|
||||
"label": I18n.tr("Log Out"),
|
||||
"key": "X"
|
||||
};
|
||||
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":
|
||||
return { "icon": "bedtime", "label": I18n.tr("Suspend"), "key": "S" }
|
||||
return {
|
||||
"icon": "bedtime",
|
||||
"label": I18n.tr("Suspend"),
|
||||
"key": "S"
|
||||
};
|
||||
case "hibernate":
|
||||
return { "icon": "ac_unit", "label": I18n.tr("Hibernate"), "key": "H" }
|
||||
return {
|
||||
"icon": "ac_unit",
|
||||
"label": I18n.tr("Hibernate"),
|
||||
"key": "H"
|
||||
};
|
||||
default:
|
||||
return { "icon": "help", "label": action, "key": "?" }
|
||||
return {
|
||||
"icon": "help",
|
||||
"label": action,
|
||||
"key": "?"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function selectOption(action) {
|
||||
if (!action) return
|
||||
if (typeof SessionService === "undefined") return
|
||||
hide()
|
||||
function actionNeedsConfirm(action) {
|
||||
return action !== "lock" && action !== "restart";
|
||||
}
|
||||
|
||||
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) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
SessionService.logout();
|
||||
break;
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
SessionService.suspend();
|
||||
break;
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
SessionService.hibernate();
|
||||
break;
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
SessionService.reboot();
|
||||
break;
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
SessionService.poweroff();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function selectOption(action, actionIndex) {
|
||||
startHold(action, actionIndex !== undefined ? actionIndex : -1);
|
||||
}
|
||||
|
||||
function show() {
|
||||
updateVisibleActions()
|
||||
const defaultIndex = getDefaultActionIndex()
|
||||
holdAction = "";
|
||||
holdActionIndex = -1;
|
||||
holdProgress = 0;
|
||||
showHoldHint = false;
|
||||
updateVisibleActions();
|
||||
const defaultIndex = getDefaultActionIndex();
|
||||
if (useGridLayout) {
|
||||
selectedRow = Math.floor(defaultIndex / gridColumns)
|
||||
selectedCol = defaultIndex % gridColumns
|
||||
selectedIndex = defaultIndex
|
||||
selectedRow = Math.floor(defaultIndex / gridColumns);
|
||||
selectedCol = defaultIndex % gridColumns;
|
||||
selectedIndex = defaultIndex;
|
||||
} else {
|
||||
selectedIndex = defaultIndex
|
||||
selectedIndex = defaultIndex;
|
||||
}
|
||||
isVisible = true
|
||||
Qt.callLater(() => powerMenuFocusScope.forceActiveFocus())
|
||||
isVisible = true;
|
||||
Qt.callLater(() => powerMenuFocusScope.forceActiveFocus());
|
||||
}
|
||||
|
||||
function hide() {
|
||||
isVisible = false
|
||||
closed()
|
||||
cancelHold();
|
||||
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) {
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Backtab:
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
||||
event.accepted = true
|
||||
break
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Tab:
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
||||
event.accepted = true
|
||||
break
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
selectOption(getActionAtIndex(selectedIndex))
|
||||
event.accepted = true
|
||||
break
|
||||
startHold(getActionAtIndex(selectedIndex), selectedIndex);
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_N:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
||||
event.accepted = true
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_P:
|
||||
if (!(event.modifiers & Qt.ControlModifier)) {
|
||||
selectOption("poweroff")
|
||||
event.accepted = true
|
||||
const idx = visibleActions.indexOf("poweroff");
|
||||
startHold("poweroff", idx);
|
||||
event.accepted = true;
|
||||
} else {
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
||||
event.accepted = true
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length
|
||||
event.accepted = true
|
||||
selectedIndex = (selectedIndex + 1) % visibleActions.length;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length
|
||||
event.accepted = true
|
||||
selectedIndex = (selectedIndex - 1 + visibleActions.length) % visibleActions.length;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_R:
|
||||
selectOption("reboot")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("reboot", visibleActions.indexOf("reboot"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_X:
|
||||
selectOption("logout")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("logout", visibleActions.indexOf("logout"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_S:
|
||||
selectOption("suspend")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("suspend", visibleActions.indexOf("suspend"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_H:
|
||||
selectOption("hibernate")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("hibernate", visibleActions.indexOf("hibernate"));
|
||||
event.accepted = true;
|
||||
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) {
|
||||
case Qt.Key_Left:
|
||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Right:
|
||||
selectedCol = (selectedCol + 1) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
selectedCol = (selectedCol + 1) % gridColumns;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Backtab:
|
||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Tab:
|
||||
selectedRow = (selectedRow + 1) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
break
|
||||
selectedRow = (selectedRow + 1) % gridRows;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Return:
|
||||
case Qt.Key_Enter:
|
||||
selectOption(getActionAtIndex(selectedIndex))
|
||||
event.accepted = true
|
||||
break
|
||||
startHold(getActionAtIndex(selectedIndex), selectedIndex);
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_N:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedCol = (selectedCol + 1) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
selectedCol = (selectedCol + 1) % gridColumns;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_P:
|
||||
if (!(event.modifiers & Qt.ControlModifier)) {
|
||||
selectOption("poweroff")
|
||||
event.accepted = true
|
||||
const idx = visibleActions.indexOf("poweroff");
|
||||
startHold("poweroff", idx);
|
||||
event.accepted = true;
|
||||
} else {
|
||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
selectedCol = (selectedCol - 1 + gridColumns) % gridColumns;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedRow = (selectedRow + 1) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
selectedRow = (selectedRow + 1) % gridRows;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol
|
||||
event.accepted = true
|
||||
selectedRow = (selectedRow - 1 + gridRows) % gridRows;
|
||||
selectedIndex = selectedRow * gridColumns + selectedCol;
|
||||
event.accepted = true;
|
||||
}
|
||||
break
|
||||
break;
|
||||
case Qt.Key_R:
|
||||
selectOption("reboot")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("reboot", visibleActions.indexOf("reboot"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_X:
|
||||
selectOption("logout")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("logout", visibleActions.indexOf("logout"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_S:
|
||||
selectOption("suspend")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("suspend", visibleActions.indexOf("suspend"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_H:
|
||||
selectOption("hibernate")
|
||||
event.accepted = true
|
||||
break
|
||||
startHold("hibernate", visibleActions.indexOf("hibernate"));
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,29 +391,62 @@ Rectangle {
|
||||
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 {
|
||||
id: powerMenuFocusScope
|
||||
anchors.fill: parent
|
||||
focus: root.isVisible
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) Qt.callLater(() => forceActiveFocus())
|
||||
if (visible)
|
||||
Qt.callLater(() => forceActiveFocus());
|
||||
}
|
||||
|
||||
Keys.onEscapePressed: root.hide()
|
||||
Keys.onPressed: event => {
|
||||
if (event.isAutoRepeat) {
|
||||
event.accepted = true;
|
||||
return;
|
||||
}
|
||||
if (useGridLayout) {
|
||||
handleGridNavigation(event)
|
||||
handleGridNavigation(event, true);
|
||||
} 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 {
|
||||
anchors.centerIn: parent
|
||||
width: useGridLayout
|
||||
? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2)
|
||||
: 320
|
||||
width: useGridLayout ? Math.min(550, gridColumns * 180 + Theme.spacingS * (gridColumns - 1) + Theme.spacingL * 2) : 320
|
||||
height: contentItem.implicitHeight + Theme.spacingL * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
@@ -320,7 +457,7 @@ Rectangle {
|
||||
id: contentItem
|
||||
anchors.fill: parent
|
||||
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 {
|
||||
id: headerRow
|
||||
@@ -363,48 +500,86 @@ Rectangle {
|
||||
model: root.visibleActions
|
||||
|
||||
Rectangle {
|
||||
id: gridButtonRect
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
readonly property var actionData: root.getActionData(modelData)
|
||||
readonly property bool isSelected: root.selectedIndex === index
|
||||
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
|
||||
height: 100
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isSelected) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
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)
|
||||
if (isSelected)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
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.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 {
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: parent.parent.actionData.icon
|
||||
name: gridButtonRect.actionData.icon
|
||||
size: Theme.iconSize + 8
|
||||
color: {
|
||||
if (parent.parent.showWarning && mouseArea.containsMouse) {
|
||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
||||
if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) {
|
||||
return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||
}
|
||||
return Theme.surfaceText
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: parent.parent.actionData.label
|
||||
text: gridButtonRect.actionData.label
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (parent.parent.showWarning && mouseArea.containsMouse) {
|
||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
||||
if (gridButtonRect.showWarning && (mouseArea.containsMouse || gridButtonRect.isHolding)) {
|
||||
return gridButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||
}
|
||||
return Theme.surfaceText
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
font.weight: Font.Medium
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -418,7 +593,7 @@ Rectangle {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: parent.parent.parent.actionData.key
|
||||
text: gridButtonRect.actionData.key
|
||||
font.pixelSize: Theme.fontSizeSmall - 1
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
@@ -432,11 +607,14 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.selectedRow = Math.floor(index / root.gridColumns)
|
||||
root.selectedCol = index % root.gridColumns
|
||||
root.selectOption(modelData)
|
||||
onPressed: {
|
||||
root.selectedRow = Math.floor(index / root.gridColumns);
|
||||
root.selectedCol = index % root.gridColumns;
|
||||
root.selectedIndex = index;
|
||||
root.startHold(modelData, index);
|
||||
}
|
||||
onReleased: root.cancelHold()
|
||||
onCanceled: root.cancelHold()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -455,24 +633,62 @@ Rectangle {
|
||||
model: root.visibleActions
|
||||
|
||||
Rectangle {
|
||||
id: listButtonRect
|
||||
required property int index
|
||||
required property string modelData
|
||||
|
||||
readonly property var actionData: root.getActionData(modelData)
|
||||
readonly property bool isSelected: root.selectedIndex === index
|
||||
readonly property bool showWarning: modelData === "reboot" || modelData === "poweroff"
|
||||
readonly property bool isHolding: root.holdActionIndex === index && root.holdProgress > 0
|
||||
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isSelected) return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
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)
|
||||
if (isSelected)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12);
|
||||
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.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 {
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
@@ -482,25 +698,25 @@ Rectangle {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: parent.parent.actionData.icon
|
||||
name: listButtonRect.actionData.icon
|
||||
size: Theme.iconSize + 4
|
||||
color: {
|
||||
if (parent.parent.showWarning && listMouseArea.containsMouse) {
|
||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
||||
if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) {
|
||||
return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||
}
|
||||
return Theme.surfaceText
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: parent.parent.actionData.label
|
||||
text: listButtonRect.actionData.label
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: {
|
||||
if (parent.parent.showWarning && listMouseArea.containsMouse) {
|
||||
return parent.parent.modelData === "poweroff" ? Theme.error : Theme.warning
|
||||
if (listButtonRect.showWarning && (listMouseArea.containsMouse || listButtonRect.isHolding)) {
|
||||
return listButtonRect.modelData === "poweroff" ? Theme.error : Theme.warning;
|
||||
}
|
||||
return Theme.surfaceText
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -517,7 +733,7 @@ Rectangle {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: parent.parent.actionData.key
|
||||
text: listButtonRect.actionData.key
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
font.weight: Font.Medium
|
||||
@@ -530,14 +746,53 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.selectedIndex = index
|
||||
root.selectOption(modelData)
|
||||
onPressed: {
|
||||
root.selectedIndex = index;
|
||||
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 hasPopout: popoutContent !== null
|
||||
|
||||
readonly property int iconSize: Theme.barIconSize(barThickness, -4)
|
||||
readonly property int iconSizeLarge: Theme.barIconSize(barThickness)
|
||||
|
||||
Component.onCompleted: {
|
||||
loadPluginData();
|
||||
}
|
||||
|
||||
@@ -45,10 +45,14 @@ Item {
|
||||
Item {
|
||||
width: parent.width
|
||||
height: logoModeGroup.implicitHeight
|
||||
clip: true
|
||||
|
||||
DankButtonGroup {
|
||||
id: logoModeGroup
|
||||
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: {
|
||||
const modes = [I18n.tr("Apps Icon"), I18n.tr("OS Logo"), I18n.tr("Dank")];
|
||||
if (CompositorService.isNiri) {
|
||||
@@ -153,78 +157,88 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
Item {
|
||||
width: parent.width
|
||||
height: colorOverrideRow.implicitHeight
|
||||
clip: true
|
||||
|
||||
DankButtonGroup {
|
||||
id: colorModeGroup
|
||||
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
||||
currentIndex: {
|
||||
const override = SettingsData.launcherLogoColorOverride;
|
||||
if (override === "")
|
||||
return 0;
|
||||
if (override === "primary")
|
||||
return 1;
|
||||
if (override === "surface")
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
return;
|
||||
switch (index) {
|
||||
case 0:
|
||||
SettingsData.set("launcherLogoColorOverride", "");
|
||||
break;
|
||||
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;
|
||||
Row {
|
||||
id: colorOverrideRow
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankButtonGroup {
|
||||
id: colorModeGroup
|
||||
buttonPadding: parent.parent.width < 480 ? Theme.spacingS : Theme.spacingL
|
||||
minButtonWidth: parent.parent.width < 480 ? 44 : 64
|
||||
textSize: parent.parent.width < 480 ? Theme.fontSizeSmall : Theme.fontSizeMedium
|
||||
model: [I18n.tr("Default"), I18n.tr("Primary"), I18n.tr("Surface"), I18n.tr("Custom")]
|
||||
currentIndex: {
|
||||
const override = SettingsData.launcherLogoColorOverride;
|
||||
if (override === "")
|
||||
return 0;
|
||||
if (override === "primary")
|
||||
return 1;
|
||||
if (override === "surface")
|
||||
return 2;
|
||||
return 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
onSelectionChanged: (index, selected) => {
|
||||
if (!selected)
|
||||
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();
|
||||
switch (index) {
|
||||
case 0:
|
||||
SettingsData.set("launcherLogoColorOverride", "");
|
||||
break;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
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
|
||||
onToggled: checked => SettingsData.set("spotlightCloseNiriOverview", checked)
|
||||
}
|
||||
|
||||
SettingsToggleRow {
|
||||
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
|
||||
onToggled: checked => SettingsData.set("niriOverviewOverlayEnabled", checked)
|
||||
}
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
id: recentAppsCard
|
||||
width: parent.width
|
||||
iconName: "history"
|
||||
title: I18n.tr("Recently Used Apps")
|
||||
|
||||
property var rankedAppsModel: {
|
||||
var ranking = AppUsageHistoryData.appUsageRanking;
|
||||
if (!ranking)
|
||||
return [];
|
||||
var apps = [];
|
||||
for (var appId in (AppUsageHistoryData.appUsageRanking || {})) {
|
||||
var appData = (AppUsageHistoryData.appUsageRanking || {})[appId];
|
||||
for (var appId in ranking) {
|
||||
var appData = ranking[appId];
|
||||
apps.push({
|
||||
"id": appId,
|
||||
"name": appData.name,
|
||||
@@ -401,7 +419,7 @@ Item {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: parent.parent.rankedAppsModel
|
||||
model: recentAppsCard.rankedAppsModel
|
||||
|
||||
delegate: Rectangle {
|
||||
width: rankedAppsList.width
|
||||
@@ -496,11 +514,11 @@ Item {
|
||||
|
||||
StyledText {
|
||||
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
|
||||
color: Theme.surfaceVariantText
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: parent.parent.rankedAppsModel.length === 0
|
||||
visible: recentAppsCard.rankedAppsModel.length === 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ Item {
|
||||
{
|
||||
"id": "gpuTemp",
|
||||
"text": I18n.tr("GPU Temperature"),
|
||||
"description": I18n.tr("GPU temperature display"),
|
||||
"description": "",
|
||||
"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."),
|
||||
"enabled": DgopService.dgopAvailable
|
||||
|
||||
@@ -168,7 +168,17 @@ Column {
|
||||
}
|
||||
|
||||
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
|
||||
color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
|
||||
elide: Text.ElideRight
|
||||
@@ -185,39 +195,37 @@ Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
Item {
|
||||
width: 60
|
||||
height: 32
|
||||
DankActionButton {
|
||||
id: gpuMenuButton
|
||||
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 {
|
||||
id: gpuDropdown
|
||||
anchors.fill: parent
|
||||
popupWidth: -1
|
||||
currentValue: {
|
||||
var selectedIndex = modelData.selectedGpuIndex !== undefined ? modelData.selectedGpuIndex : 0;
|
||||
if (DgopService.availableGpus && DgopService.availableGpus.length > selectedIndex && selectedIndex >= 0) {
|
||||
var gpu = DgopService.availableGpus[selectedIndex];
|
||||
return gpu.driver.toUpperCase();
|
||||
}
|
||||
return DgopService.availableGpus && DgopService.availableGpus.length > 0 ? DgopService.availableGpus[0].driver.toUpperCase() : "";
|
||||
var buttonPos = gpuMenuButton.mapToItem(root, 0, 0);
|
||||
var popupWidth = gpuContextMenu.width;
|
||||
var popupHeight = gpuContextMenu.height;
|
||||
|
||||
var xPos = buttonPos.x - popupWidth - Theme.spacingS;
|
||||
if (xPos < 0) {
|
||||
xPos = buttonPos.x + gpuMenuButton.width + Theme.spacingS;
|
||||
}
|
||||
options: {
|
||||
var gpuOptions = [];
|
||||
if (DgopService.availableGpus && DgopService.availableGpus.length > 0) {
|
||||
for (var i = 0; i < DgopService.availableGpus.length; i++) {
|
||||
var gpu = DgopService.availableGpus[i];
|
||||
gpuOptions.push(gpu.driver.toUpperCase());
|
||||
}
|
||||
}
|
||||
return gpuOptions;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var gpuIndex = options.indexOf(value);
|
||||
if (gpuIndex >= 0) {
|
||||
root.gpuSelectionChanged(root.sectionId, index, gpuIndex);
|
||||
}
|
||||
|
||||
var yPos = buttonPos.y - popupHeight / 2 + gpuMenuButton.height / 2;
|
||||
if (yPos < 0) {
|
||||
yPos = Theme.spacingS;
|
||||
} else if (yPos + popupHeight > root.height) {
|
||||
yPos = root.height - popupHeight - Theme.spacingS;
|
||||
}
|
||||
|
||||
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 : "";
|
||||
}
|
||||
|
||||
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() {
|
||||
const deviceToUse = lastIpcDevice === "" ? getDefaultDevice() : (lastIpcDevice || currentDevice);
|
||||
if (!deviceToUse) {
|
||||
@@ -809,110 +838,95 @@ Singleton {
|
||||
// IPC Handler for external control
|
||||
IpcHandler {
|
||||
function set(percentage: string, device: string): string {
|
||||
if (!root.brightnessAvailable) {
|
||||
if (!root.brightnessAvailable)
|
||||
return "Brightness control not available";
|
||||
}
|
||||
|
||||
const value = parseInt(percentage);
|
||||
if (isNaN(value)) {
|
||||
if (isNaN(value))
|
||||
return "Invalid brightness value: " + percentage;
|
||||
}
|
||||
|
||||
const targetDevice = device || "";
|
||||
const actualDevice = device || root.getPreferredDevice();
|
||||
|
||||
if (targetDevice && !root.devices.some(d => d.id === targetDevice)) {
|
||||
return "Device not found: " + targetDevice;
|
||||
}
|
||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice))
|
||||
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 clampedValue = Math.max(minValue, Math.min(100, value));
|
||||
|
||||
root.lastIpcDevice = targetDevice;
|
||||
if (targetDevice && targetDevice !== root.currentDevice) {
|
||||
root.setCurrentDevice(targetDevice, false);
|
||||
}
|
||||
root.setBrightness(clampedValue, targetDevice);
|
||||
root.lastIpcDevice = actualDevice;
|
||||
if (actualDevice && actualDevice !== root.currentDevice)
|
||||
root.setCurrentDevice(actualDevice, false);
|
||||
|
||||
if (targetDevice) {
|
||||
return "Brightness set to " + clampedValue + "% on " + targetDevice;
|
||||
} else {
|
||||
return "Brightness set to " + clampedValue + "%";
|
||||
}
|
||||
root.setBrightness(clampedValue, actualDevice);
|
||||
|
||||
return actualDevice ? "Brightness set to " + clampedValue + "% on " + actualDevice : "Brightness set to " + clampedValue + "%";
|
||||
}
|
||||
|
||||
function increment(step: string, device: string): string {
|
||||
if (!root.brightnessAvailable) {
|
||||
if (!root.brightnessAvailable)
|
||||
return "Brightness control not available";
|
||||
}
|
||||
|
||||
const targetDevice = device || "";
|
||||
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice;
|
||||
const actualDevice = device || root.getPreferredDevice();
|
||||
|
||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice)) {
|
||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice))
|
||||
return "Device not found: " + actualDevice;
|
||||
}
|
||||
|
||||
const stepValue = parseInt(step || "5");
|
||||
|
||||
root.lastIpcDevice = actualDevice;
|
||||
if (actualDevice && actualDevice !== root.currentDevice) {
|
||||
if (actualDevice && actualDevice !== root.currentDevice)
|
||||
root.setCurrentDevice(actualDevice, false);
|
||||
}
|
||||
|
||||
const isExponential = SessionData.getBrightnessExponential(actualDevice);
|
||||
const currentBrightness = root.getDeviceBrightness(actualDevice);
|
||||
const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
|
||||
|
||||
let maxValue = 100;
|
||||
if (isExponential) {
|
||||
maxValue = 100;
|
||||
} else {
|
||||
maxValue = deviceInfo?.displayMax || 100;
|
||||
}
|
||||
|
||||
const maxValue = isExponential ? 100 : (deviceInfo?.displayMax || 100);
|
||||
const newBrightness = Math.min(maxValue, currentBrightness + stepValue);
|
||||
|
||||
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 {
|
||||
if (!root.brightnessAvailable) {
|
||||
if (!root.brightnessAvailable)
|
||||
return "Brightness control not available";
|
||||
}
|
||||
|
||||
const targetDevice = device || "";
|
||||
const actualDevice = targetDevice === "" ? root.getDefaultDevice() : targetDevice;
|
||||
const actualDevice = device || root.getPreferredDevice();
|
||||
|
||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice)) {
|
||||
if (actualDevice && !root.devices.some(d => d.id === actualDevice))
|
||||
return "Device not found: " + actualDevice;
|
||||
}
|
||||
|
||||
const stepValue = parseInt(step || "5");
|
||||
|
||||
root.lastIpcDevice = actualDevice;
|
||||
if (actualDevice && actualDevice !== root.currentDevice) {
|
||||
if (actualDevice && actualDevice !== root.currentDevice)
|
||||
root.setCurrentDevice(actualDevice, false);
|
||||
}
|
||||
|
||||
const isExponential = SessionData.getBrightnessExponential(actualDevice);
|
||||
const currentBrightness = root.getDeviceBrightness(actualDevice);
|
||||
const deviceInfo = root.getCurrentDeviceInfoByName(actualDevice);
|
||||
|
||||
let minValue = 0;
|
||||
if (isExponential) {
|
||||
switch (true) {
|
||||
case isExponential:
|
||||
minValue = 1;
|
||||
} else {
|
||||
minValue = (deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc")) ? 1 : 0;
|
||||
break;
|
||||
case deviceInfo && (deviceInfo.class === "backlight" || deviceInfo.class === "ddc"):
|
||||
minValue = 1;
|
||||
break;
|
||||
default:
|
||||
minValue = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
const newBrightness = Math.max(minValue, currentBrightness - stepValue);
|
||||
|
||||
root.setBrightness(newBrightness, actualDevice);
|
||||
|
||||
return "Brightness decreased by " + stepValue + "%" + (targetDevice ? " on " + targetDevice : "");
|
||||
return "Brightness decreased by " + stepValue + "%" + (device ? " on " + actualDevice : "");
|
||||
}
|
||||
|
||||
function status(): string {
|
||||
|
||||
@@ -197,6 +197,8 @@ Singleton {
|
||||
property bool _settingsWantsOpen: false
|
||||
property bool _settingsWantsToggle: false
|
||||
|
||||
property string _settingsPendingTab: ""
|
||||
|
||||
function openSettings() {
|
||||
if (settingsModal) {
|
||||
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() {
|
||||
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() {
|
||||
if (settingsModal?.visible) {
|
||||
const settingsTitle = I18n.tr("Settings", "settings window title");
|
||||
@@ -238,6 +269,26 @@ Singleton {
|
||||
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() {
|
||||
if (settingsModalLoader) {
|
||||
settingsModal = null;
|
||||
@@ -248,9 +299,22 @@ Singleton {
|
||||
function _onSettingsModalLoaded() {
|
||||
if (_settingsWantsOpen) {
|
||||
_settingsWantsOpen = false;
|
||||
settingsModal?.show();
|
||||
} else if (_settingsWantsToggle) {
|
||||
if (_settingsPendingTab) {
|
||||
settingsModal?.showWithTabName(_settingsPendingTab);
|
||||
_settingsPendingTab = "";
|
||||
} else {
|
||||
settingsModal?.show();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (_settingsWantsToggle) {
|
||||
_settingsWantsToggle = false;
|
||||
if (_settingsPendingTab) {
|
||||
var idx = settingsModal?.resolveTabIndex(_settingsPendingTab) ?? -1;
|
||||
if (idx >= 0)
|
||||
settingsModal.currentTabIndex = idx;
|
||||
_settingsPendingTab = "";
|
||||
}
|
||||
settingsModal?.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,6 @@ StyledRect {
|
||||
onClicked: root.clicked()
|
||||
onEntered: root.entered()
|
||||
onExited: root.exited()
|
||||
tooltipText: tooltipText
|
||||
tooltipText: root.tooltipText
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,9 +122,10 @@ PanelWindow {
|
||||
width: parent.width
|
||||
x: Theme.snap(slideContainer.slideOffset, root.dpr)
|
||||
|
||||
DankRectangle {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
Column {
|
||||
|
||||
@@ -11,7 +11,17 @@ Item {
|
||||
if (!item)
|
||||
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)
|
||||
return;
|
||||
|
||||
|
||||
@@ -21,29 +21,29 @@ MouseArea {
|
||||
color: Qt.rgba(stateColor.r, stateColor.g, stateColor.b, stateOpacity)
|
||||
}
|
||||
|
||||
|
||||
Timer {
|
||||
id: hoverDelay
|
||||
interval: 1000
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
const p = root.mapToItem(null, parent.width / 2, parent.height + Theme.spacingXS)
|
||||
tooltip.show(I18n.tr(""), p.x, p.y, null)
|
||||
tooltip.show(root.tooltipText, root, 0, 0, "bottom");
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
if (!tooltipText) { return }
|
||||
hoverDelay.restart()
|
||||
if (!tooltipText)
|
||||
return;
|
||||
hoverDelay.restart();
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (!tooltipText) { return }
|
||||
hoverDelay.stop()
|
||||
tooltip.hide()
|
||||
if (!tooltipText)
|
||||
return;
|
||||
hoverDelay.stop();
|
||||
tooltip.hide();
|
||||
}
|
||||
|
||||
DankTooltip {
|
||||
DankTooltipV2 {
|
||||
id: tooltip
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,6 +133,18 @@ Rectangle {
|
||||
onClicked: DMSNetworkService.disconnectAllActive()
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
iconName: "settings"
|
||||
buttonSize: 28
|
||||
iconSize: 16
|
||||
iconColor: Theme.surfaceVariantText
|
||||
onClicked: {
|
||||
PopoutService.closeControlCenter();
|
||||
PopoutService.openSettingsWithTab("network");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
||||
Reference in New Issue
Block a user