mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-05-04 03:22:12 -04:00
Compare commits
15 Commits
c49a875ec2
...
3bc6461e2a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bc6461e2a | ||
|
|
d3194e15e2 | ||
|
|
2db79ef202 | ||
|
|
b3c07edef6 | ||
|
|
b773fdca34 | ||
|
|
2e9f9f7b7e | ||
|
|
30cbfe729d | ||
|
|
b036da2446 | ||
|
|
c8a9fb1674 | ||
|
|
43bea80cad | ||
|
|
23538c0323 | ||
|
|
2ae911230d | ||
|
|
5ce1cb87ea | ||
|
|
2a37028b6a | ||
|
|
8130feb2a0 |
@@ -1,5 +1,4 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
@@ -23,79 +22,79 @@ Singleton {
|
||||
property string profileLastPath: ""
|
||||
|
||||
property var fileBrowserSettings: ({
|
||||
"wallpaper": {
|
||||
"lastPath": "",
|
||||
"viewMode": "grid",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"profile": {
|
||||
"lastPath": "",
|
||||
"viewMode": "grid",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"notepad_save": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"notepad_load": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"generic": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"default": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
}
|
||||
})
|
||||
"wallpaper": {
|
||||
"lastPath": "",
|
||||
"viewMode": "grid",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"profile": {
|
||||
"lastPath": "",
|
||||
"viewMode": "grid",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"notepad_save": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"notepad_load": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"generic": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
},
|
||||
"default": {
|
||||
"lastPath": "",
|
||||
"viewMode": "list",
|
||||
"sortBy": "name",
|
||||
"sortAscending": true,
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
}
|
||||
})
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
loadCache()
|
||||
loadCache();
|
||||
}
|
||||
}
|
||||
|
||||
function loadCache() {
|
||||
_loading = true
|
||||
parseCache(cacheFile.text())
|
||||
_loading = false
|
||||
_loading = true;
|
||||
parseCache(cacheFile.text());
|
||||
_loading = false;
|
||||
}
|
||||
|
||||
function parseCache(content) {
|
||||
_loading = true
|
||||
_loading = true;
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const cache = JSON.parse(content)
|
||||
const cache = JSON.parse(content);
|
||||
|
||||
wallpaperLastPath = cache.wallpaperLastPath !== undefined ? cache.wallpaperLastPath : ""
|
||||
profileLastPath = cache.profileLastPath !== undefined ? cache.profileLastPath : ""
|
||||
wallpaperLastPath = cache.wallpaperLastPath !== undefined ? cache.wallpaperLastPath : "";
|
||||
profileLastPath = cache.profileLastPath !== undefined ? cache.profileLastPath : "";
|
||||
|
||||
if (cache.fileBrowserSettings !== undefined) {
|
||||
fileBrowserSettings = cache.fileBrowserSettings
|
||||
fileBrowserSettings = cache.fileBrowserSettings;
|
||||
} else if (cache.fileBrowserViewMode !== undefined) {
|
||||
fileBrowserSettings = {
|
||||
"wallpaper": {
|
||||
@@ -122,65 +121,60 @@ Singleton {
|
||||
"iconSizeIndex": 1,
|
||||
"showSidebar": true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if (cache.configVersion === undefined) {
|
||||
migrateFromUndefinedToV1(cache)
|
||||
cleanupUnusedKeys()
|
||||
saveCache()
|
||||
migrateFromUndefinedToV1(cache);
|
||||
cleanupUnusedKeys();
|
||||
saveCache();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CacheData: Failed to parse cache:", e.message)
|
||||
console.warn("CacheData: Failed to parse cache:", e.message);
|
||||
} finally {
|
||||
_loading = false
|
||||
_loading = false;
|
||||
}
|
||||
}
|
||||
|
||||
function saveCache() {
|
||||
if (_loading)
|
||||
return
|
||||
return;
|
||||
cacheFile.setText(JSON.stringify({
|
||||
"wallpaperLastPath": wallpaperLastPath,
|
||||
"profileLastPath": profileLastPath,
|
||||
"fileBrowserSettings": fileBrowserSettings,
|
||||
"configVersion": cacheConfigVersion
|
||||
}, null, 2))
|
||||
"wallpaperLastPath": wallpaperLastPath,
|
||||
"profileLastPath": profileLastPath,
|
||||
"fileBrowserSettings": fileBrowserSettings,
|
||||
"configVersion": cacheConfigVersion
|
||||
}, null, 2));
|
||||
}
|
||||
|
||||
function migrateFromUndefinedToV1(cache) {
|
||||
console.info("CacheData: Migrating configuration from undefined to version 1")
|
||||
console.info("CacheData: Migrating configuration from undefined to version 1");
|
||||
}
|
||||
|
||||
function cleanupUnusedKeys() {
|
||||
const validKeys = [
|
||||
"wallpaperLastPath",
|
||||
"profileLastPath",
|
||||
"fileBrowserSettings",
|
||||
"configVersion"
|
||||
]
|
||||
const validKeys = ["wallpaperLastPath", "profileLastPath", "fileBrowserSettings", "configVersion"];
|
||||
|
||||
try {
|
||||
const content = cacheFile.text()
|
||||
if (!content || !content.trim()) return
|
||||
|
||||
const cache = JSON.parse(content)
|
||||
let needsSave = false
|
||||
const content = cacheFile.text();
|
||||
if (!content || !content.trim())
|
||||
return;
|
||||
const cache = JSON.parse(content);
|
||||
let needsSave = false;
|
||||
|
||||
for (const key in cache) {
|
||||
if (!validKeys.includes(key)) {
|
||||
console.log("CacheData: Removing unused key:", key)
|
||||
delete cache[key]
|
||||
needsSave = true
|
||||
console.log("CacheData: Removing unused key:", key);
|
||||
delete cache[key];
|
||||
needsSave = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsSave) {
|
||||
cacheFile.setText(JSON.stringify(cache, null, 2))
|
||||
cacheFile.setText(JSON.stringify(cache, null, 2));
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("CacheData: Failed to cleanup unused keys:", e.message)
|
||||
console.warn("CacheData: Failed to cleanup unused keys:", e.message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,12 +188,12 @@ Singleton {
|
||||
watchChanges: !isGreeterMode
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
parseCache(cacheFile.text())
|
||||
parseCache(cacheFile.text());
|
||||
}
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode) {
|
||||
console.info("CacheData: No cache file found, starting fresh")
|
||||
console.info("CacheData: No cache file found, starting fresh");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,28 +1,24 @@
|
||||
import Quickshell
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
// Clear all image cache
|
||||
function clearImageCache() {
|
||||
Quickshell.execDetached(["rm", "-rf", Paths.stringify(
|
||||
Paths.imagecache)])
|
||||
Paths.mkdir(Paths.imagecache)
|
||||
Quickshell.execDetached(["rm", "-rf", Paths.stringify(Paths.imagecache)]);
|
||||
Paths.mkdir(Paths.imagecache);
|
||||
}
|
||||
|
||||
// Clear cache older than specified minutes
|
||||
function clearOldCache(ageInMinutes) {
|
||||
Quickshell.execDetached(
|
||||
["find", Paths.stringify(
|
||||
Paths.imagecache), "-name", "*.png", "-mmin", `+${ageInMinutes}`, "-delete"])
|
||||
Quickshell.execDetached(["find", Paths.stringify(Paths.imagecache), "-name", "*.png", "-mmin", `+${ageInMinutes}`, "-delete"]);
|
||||
}
|
||||
|
||||
// Clear cache for specific size
|
||||
function clearCacheForSize(size) {
|
||||
Quickshell.execDetached(
|
||||
["find", Paths.stringify(
|
||||
Paths.imagecache), "-name", `*@${size}x${size}.png`, "-delete"])
|
||||
Quickshell.execDetached(["find", Paths.stringify(Paths.imagecache), "-name", `*@${size}x${size}.png`, "-delete"]);
|
||||
}
|
||||
|
||||
// Get cache size in MB
|
||||
@@ -30,8 +26,7 @@ Singleton {
|
||||
var process = Qt.createQmlObject(`
|
||||
import Quickshell.Io
|
||||
Process {
|
||||
command: ["du", "-sm", "${Paths.stringify(
|
||||
Paths.imagecache)}"]
|
||||
command: ["du", "-sm", "${Paths.stringify(Paths.imagecache)}"]
|
||||
running: true
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
@@ -40,6 +35,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
}
|
||||
`, root)
|
||||
`, root);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,26 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
import QtQuick
|
||||
import Qt.labs.folderlistmodel
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string _rawLocale: Qt.locale().name
|
||||
readonly property string _lang: _rawLocale.split(/[_-]/)[0]
|
||||
readonly property var _candidates: {
|
||||
readonly property var _candidates: {
|
||||
const fullUnderscore = _rawLocale;
|
||||
const fullHyphen = _rawLocale.replace("_", "-");
|
||||
const fullHyphen = _rawLocale.replace("_", "-");
|
||||
return [fullUnderscore, fullHyphen, _lang].filter(c => c && c !== "en");
|
||||
}
|
||||
|
||||
|
||||
readonly property url translationsFolder: Qt.resolvedUrl("../translations/poexports")
|
||||
|
||||
property string currentLocale: "en"
|
||||
property var translations: ({})
|
||||
property bool translationsLoaded: false
|
||||
property var translations: ({})
|
||||
property bool translationsLoaded: false
|
||||
|
||||
property url _selectedPath: ""
|
||||
|
||||
@@ -32,7 +31,8 @@ Singleton {
|
||||
showDirs: false
|
||||
showDotAndDotDot: false
|
||||
|
||||
onStatusChanged: if (status === FolderListModel.Ready) root._pickTranslation()
|
||||
onStatusChanged: if (status === FolderListModel.Ready)
|
||||
root._pickTranslation()
|
||||
}
|
||||
|
||||
FileView {
|
||||
@@ -41,73 +41,75 @@ Singleton {
|
||||
|
||||
onLoaded: {
|
||||
try {
|
||||
root.translations = JSON.parse(text())
|
||||
root.translationsLoaded = true
|
||||
console.info(`I18n: Loaded translations for '${root.currentLocale}' ` +
|
||||
`(${Object.keys(root.translations).length} contexts)`)
|
||||
root.translations = JSON.parse(text());
|
||||
root.translationsLoaded = true;
|
||||
console.info(`I18n: Loaded translations for '${root.currentLocale}' ` + `(${Object.keys(root.translations).length} contexts)`);
|
||||
} catch (e) {
|
||||
console.warn(`I18n: Error parsing '${root.currentLocale}':`, e,
|
||||
"- falling back to English")
|
||||
root._fallbackToEnglish()
|
||||
console.warn(`I18n: Error parsing '${root.currentLocale}':`, e, "- falling back to English");
|
||||
root._fallbackToEnglish();
|
||||
}
|
||||
}
|
||||
|
||||
onLoadFailed: (error) => {
|
||||
console.warn(`I18n: Failed to load '${root.currentLocale}' (${error}), ` +
|
||||
"falling back to English")
|
||||
root._fallbackToEnglish()
|
||||
onLoadFailed: error => {
|
||||
console.warn(`I18n: Failed to load '${root.currentLocale}' (${error}), ` + "falling back to English");
|
||||
root._fallbackToEnglish();
|
||||
}
|
||||
}
|
||||
|
||||
function _pickTranslation() {
|
||||
const present = new Set()
|
||||
const present = new Set();
|
||||
for (let i = 0; i < dir.count; i++) {
|
||||
const name = dir.get(i, "fileName") // e.g. "zh_CN.json"
|
||||
const name = dir.get(i, "fileName"); // e.g. "zh_CN.json"
|
||||
if (name && name.endsWith(".json")) {
|
||||
present.add(name.slice(0, -5))
|
||||
present.add(name.slice(0, -5));
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < _candidates.length; i++) {
|
||||
const cand = _candidates[i]
|
||||
const cand = _candidates[i];
|
||||
if (present.has(cand)) {
|
||||
_useLocale(cand, dir.folder + "/" + cand + ".json")
|
||||
return
|
||||
_useLocale(cand, dir.folder + "/" + cand + ".json");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_fallbackToEnglish()
|
||||
_fallbackToEnglish();
|
||||
}
|
||||
|
||||
function _useLocale(localeTag, fileUrl) {
|
||||
currentLocale = localeTag
|
||||
_selectedPath = fileUrl
|
||||
translationsLoaded = false
|
||||
translations = ({})
|
||||
console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`)
|
||||
currentLocale = localeTag;
|
||||
_selectedPath = fileUrl;
|
||||
translationsLoaded = false;
|
||||
translations = ({});
|
||||
console.info(`I18n: Using locale '${localeTag}' from ${fileUrl}`);
|
||||
}
|
||||
|
||||
function _fallbackToEnglish() {
|
||||
currentLocale = "en"
|
||||
_selectedPath = ""
|
||||
translationsLoaded = false
|
||||
translations = ({})
|
||||
console.warn("I18n: Falling back to built-in English strings")
|
||||
currentLocale = "en";
|
||||
_selectedPath = "";
|
||||
translationsLoaded = false;
|
||||
translations = ({});
|
||||
console.warn("I18n: Falling back to built-in English strings");
|
||||
}
|
||||
|
||||
function tr(term, context) {
|
||||
if (!translationsLoaded || !translations) return term
|
||||
const ctx = context || term
|
||||
if (translations[ctx] && translations[ctx][term]) return translations[ctx][term]
|
||||
if (!translationsLoaded || !translations)
|
||||
return term;
|
||||
const ctx = context || term;
|
||||
if (translations[ctx] && translations[ctx][term])
|
||||
return translations[ctx][term];
|
||||
for (const c in translations) {
|
||||
if (translations[c] && translations[c][term]) return translations[c][term]
|
||||
if (translations[c] && translations[c][term])
|
||||
return translations[c][term];
|
||||
}
|
||||
return term
|
||||
return term;
|
||||
}
|
||||
|
||||
function trContext(context, term) {
|
||||
if (!translationsLoaded || !translations) return term
|
||||
if (translations[context] && translations[context][term]) return translations[context][term]
|
||||
return term
|
||||
if (!translationsLoaded || !translations)
|
||||
return term;
|
||||
if (translations[context] && translations[context][term])
|
||||
return translations[context][term];
|
||||
return term;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
@@ -10,11 +11,11 @@ Singleton {
|
||||
|
||||
function openModal(modal) {
|
||||
if (!modal.allowStacking) {
|
||||
closeAllModalsExcept(modal)
|
||||
closeAllModalsExcept(modal);
|
||||
}
|
||||
if (!modal.keepPopoutsOpen) {
|
||||
PopoutManager.closeAllPopouts()
|
||||
PopoutManager.closeAllPopouts();
|
||||
}
|
||||
TrayMenuManager.closeAllMenus()
|
||||
TrayMenuManager.closeAllMenus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtQuick
|
||||
@@ -10,15 +11,14 @@ Singleton {
|
||||
|
||||
function showOSD(osd) {
|
||||
if (!osd || !osd.screen)
|
||||
return
|
||||
|
||||
const screenName = osd.screen.name
|
||||
const currentOSD = currentOSDsByScreen[screenName]
|
||||
return;
|
||||
const screenName = osd.screen.name;
|
||||
const currentOSD = currentOSDsByScreen[screenName];
|
||||
|
||||
if (currentOSD && currentOSD !== osd) {
|
||||
currentOSD.hide()
|
||||
currentOSD.hide();
|
||||
}
|
||||
|
||||
currentOSDsByScreen[screenName] = osd
|
||||
currentOSDsByScreen[screenName] = osd;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import Quickshell
|
||||
import QtCore
|
||||
@@ -6,60 +7,74 @@ import QtCore
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property url home: StandardPaths.standardLocations(
|
||||
StandardPaths.HomeLocation)[0]
|
||||
readonly property url pictures: StandardPaths.standardLocations(
|
||||
StandardPaths.PicturesLocation)[0]
|
||||
readonly property url home: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0]
|
||||
readonly property url pictures: StandardPaths.standardLocations(StandardPaths.PicturesLocation)[0]
|
||||
|
||||
readonly property url data: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericDataLocation)[0]}/DankMaterialShell`
|
||||
readonly property url state: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericStateLocation)[0]}/DankMaterialShell`
|
||||
readonly property url cache: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericCacheLocation)[0]}/DankMaterialShell`
|
||||
readonly property url config: `${StandardPaths.standardLocations(
|
||||
StandardPaths.GenericConfigLocation)[0]}/DankMaterialShell`
|
||||
readonly property url data: `${StandardPaths.standardLocations(StandardPaths.GenericDataLocation)[0]}/DankMaterialShell`
|
||||
readonly property url state: `${StandardPaths.standardLocations(StandardPaths.GenericStateLocation)[0]}/DankMaterialShell`
|
||||
readonly property url cache: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/DankMaterialShell`
|
||||
readonly property url config: `${StandardPaths.standardLocations(StandardPaths.GenericConfigLocation)[0]}/DankMaterialShell`
|
||||
|
||||
readonly property url imagecache: `${cache}/imagecache`
|
||||
|
||||
function stringify(path: url): string {
|
||||
return path.toString().replace(/%20/g, " ")
|
||||
return path.toString().replace(/%20/g, " ");
|
||||
}
|
||||
|
||||
function expandTilde(path: string): string {
|
||||
return strip(path.replace("~", stringify(root.home)))
|
||||
return strip(path.replace("~", stringify(root.home)));
|
||||
}
|
||||
|
||||
function shortenHome(path: string): string {
|
||||
return path.replace(strip(root.home), "~")
|
||||
return path.replace(strip(root.home), "~");
|
||||
}
|
||||
|
||||
function strip(path: url): string {
|
||||
return stringify(path).replace("file://", "")
|
||||
return stringify(path).replace("file://", "");
|
||||
}
|
||||
|
||||
function toFileUrl(path: string): string {
|
||||
return path.startsWith("file://") ? path : "file://" + path
|
||||
return path.startsWith("file://") ? path : "file://" + path;
|
||||
}
|
||||
|
||||
function mkdir(path: url): void {
|
||||
Quickshell.execDetached(["mkdir", "-p", strip(path)])
|
||||
Quickshell.execDetached(["mkdir", "-p", strip(path)]);
|
||||
}
|
||||
|
||||
function copy(from: url, to: url): void {
|
||||
Quickshell.execDetached(["cp", strip(from), strip(to)])
|
||||
Quickshell.execDetached(["cp", strip(from), strip(to)]);
|
||||
}
|
||||
|
||||
// ! Spotify and maybe some other apps report the wrong app id in toplevels, hardcode special case
|
||||
function moddedAppId(appId: string): string {
|
||||
if (appId === "Spotify")
|
||||
return "spotify"
|
||||
return "spotify";
|
||||
if (appId === "beepertexts")
|
||||
return "beeper"
|
||||
return "beeper";
|
||||
if (appId === "home assistant desktop")
|
||||
return "homeassistant-desktop"
|
||||
return "homeassistant-desktop";
|
||||
if (appId.includes("com.transmissionbt.transmission"))
|
||||
return "transmission-gtk"
|
||||
return appId
|
||||
return "transmission-gtk";
|
||||
return appId;
|
||||
}
|
||||
|
||||
function getAppIcon(appId: string, desktopEntry: var): string {
|
||||
if (appId === "org.quickshell") {
|
||||
return Qt.resolvedUrl("../assets/danklogo.svg");
|
||||
}
|
||||
|
||||
const moddedId = moddedAppId(appId);
|
||||
if (moddedId.toLowerCase().includes("steam_app")) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return desktopEntry && desktopEntry.icon ? Quickshell.iconPath(desktopEntry.icon, true) : "";
|
||||
}
|
||||
|
||||
function getAppName(appId: string, desktopEntry: var): string {
|
||||
if (appId === "org.quickshell") {
|
||||
return "dms";
|
||||
}
|
||||
|
||||
return desktopEntry && desktopEntry.name ? desktopEntry.name : appId;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ var SPEC = {
|
||||
osdIdleInhibitorEnabled: { def: true },
|
||||
osdMicMuteEnabled: { def: true },
|
||||
osdCapsLockEnabled: { def: true },
|
||||
osdPowerProfileEnabled: { def: true },
|
||||
osdPowerProfileEnabled: { def: false },
|
||||
|
||||
powerActionConfirm: { def: true },
|
||||
powerMenuActions: { def: ["reboot", "logout", "poweroff", "lock", "suspend", "restart"] },
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Modals
|
||||
import qs.Modals.Clipboard
|
||||
@@ -19,11 +18,9 @@ import qs.Widgets
|
||||
import qs.Modules.Notifications.Popup
|
||||
import qs.Modules.OSD
|
||||
import qs.Modules.ProcessList
|
||||
import qs.Modules.Settings
|
||||
import qs.Modules.DankBar
|
||||
import qs.Modules.DankBar.Popouts
|
||||
import qs.Modules.WorkspaceOverlays
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
@@ -41,12 +38,12 @@ Item {
|
||||
|
||||
onLoaded: {
|
||||
if (item) {
|
||||
item.pluginService = PluginService
|
||||
item.pluginService = PluginService;
|
||||
if (item.popoutService !== undefined) {
|
||||
item.popoutService = PopoutService
|
||||
item.popoutService = PopoutService;
|
||||
}
|
||||
item.pluginId = pluginId
|
||||
console.info("Daemon plugin loaded:", pluginId)
|
||||
item.pluginId = pluginId;
|
||||
console.info("Daemon plugin loaded:", pluginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -85,9 +82,9 @@ Item {
|
||||
|
||||
onColorPickerRequested: {
|
||||
if (colorPickerModal.shouldBeVisible) {
|
||||
colorPickerModal.close()
|
||||
colorPickerModal.close();
|
||||
} else {
|
||||
colorPickerModal.show()
|
||||
colorPickerModal.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -108,21 +105,20 @@ Item {
|
||||
|
||||
onLoaded: {
|
||||
if (item) {
|
||||
dockContextMenuLoader.active = true
|
||||
dockContextMenuLoader.active = true;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
initialized = true
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
onCurrentPositionChanged: {
|
||||
if (!initialized)
|
||||
return
|
||||
|
||||
const comp = sourceComponent
|
||||
sourceComponent = null
|
||||
sourceComponent = comp
|
||||
return;
|
||||
const comp = sourceComponent;
|
||||
sourceComponent = null;
|
||||
sourceComponent = comp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,7 +133,7 @@ Item {
|
||||
id: dankDashPopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.dankDashPopout = dankDashPopout
|
||||
PopoutService.dankDashPopout = dankDashPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -162,7 +158,7 @@ Item {
|
||||
id: notificationCenter
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.notificationCenterPopout = notificationCenter
|
||||
PopoutService.notificationCenterPopout = notificationCenter;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,11 +185,11 @@ Item {
|
||||
powerMenuModalLoader: controlCenterLoader.powerModalLoaderRef
|
||||
|
||||
onLockRequested: {
|
||||
lock.activate()
|
||||
lock.activate();
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.controlCenterPopout = controlCenterPopout
|
||||
PopoutService.controlCenterPopout = controlCenterPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -202,7 +198,7 @@ Item {
|
||||
id: wifiPasswordModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.wifiPasswordModal = wifiPasswordModal
|
||||
PopoutService.wifiPasswordModal = wifiPasswordModal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,7 +210,7 @@ Item {
|
||||
id: bluetoothPairingModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.bluetoothPairingModal = bluetoothPairingModal
|
||||
PopoutService.bluetoothPairingModal = bluetoothPairingModal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -225,20 +221,20 @@ Item {
|
||||
target: NetworkService
|
||||
|
||||
function onCredentialsNeeded(token, ssid, setting, fields, hints, reason, connType, connName, vpnService) {
|
||||
const now = Date.now()
|
||||
const timeSinceLastPrompt = now - lastCredentialsTime
|
||||
const now = Date.now();
|
||||
const timeSinceLastPrompt = now - lastCredentialsTime;
|
||||
|
||||
if (wifiPasswordModal.shouldBeVisible && timeSinceLastPrompt < 1000) {
|
||||
NetworkService.cancelCredentials(lastCredentialsToken)
|
||||
lastCredentialsToken = token
|
||||
lastCredentialsTime = now
|
||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService)
|
||||
return
|
||||
NetworkService.cancelCredentials(lastCredentialsToken);
|
||||
lastCredentialsToken = token;
|
||||
lastCredentialsTime = now;
|
||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService);
|
||||
return;
|
||||
}
|
||||
|
||||
lastCredentialsToken = token
|
||||
lastCredentialsTime = now
|
||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService)
|
||||
lastCredentialsToken = token;
|
||||
lastCredentialsTime = now;
|
||||
wifiPasswordModal.showFromPrompt(token, ssid, setting, fields, hints, reason, connType, connName, vpnService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,7 +247,7 @@ Item {
|
||||
id: networkInfoModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.networkInfoModal = networkInfoModal
|
||||
PopoutService.networkInfoModal = networkInfoModal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -265,7 +261,7 @@ Item {
|
||||
id: batteryPopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.batteryPopout = batteryPopout
|
||||
PopoutService.batteryPopout = batteryPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,7 +275,7 @@ Item {
|
||||
id: layoutPopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.layoutPopout = layoutPopout
|
||||
PopoutService.layoutPopout = layoutPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,7 +289,7 @@ Item {
|
||||
id: vpnPopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.vpnPopout = vpnPopout
|
||||
PopoutService.vpnPopout = vpnPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -317,7 +313,7 @@ Item {
|
||||
id: processListPopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.processListPopout = processListPopout
|
||||
PopoutService.processListPopout = processListPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -326,7 +322,7 @@ Item {
|
||||
id: settingsModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.settingsModal = settingsModal
|
||||
PopoutService.settingsModal = settingsModal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +335,7 @@ Item {
|
||||
id: appDrawerPopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.appDrawerPopout = appDrawerPopout
|
||||
PopoutService.appDrawerPopout = appDrawerPopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -348,7 +344,7 @@ Item {
|
||||
id: spotlightModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.spotlightModal = spotlightModal
|
||||
PopoutService.spotlightModal = spotlightModal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,7 +352,7 @@ Item {
|
||||
id: clipboardHistoryModalPopup
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup
|
||||
PopoutService.clipboardHistoryModal = clipboardHistoryModalPopup;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +360,7 @@ Item {
|
||||
id: notificationModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.notificationModal = notificationModal
|
||||
PopoutService.notificationModal = notificationModal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -372,7 +368,7 @@ Item {
|
||||
id: colorPickerModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.colorPickerModal = colorPickerModal
|
||||
PopoutService.colorPickerModal = colorPickerModal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +381,7 @@ Item {
|
||||
id: processListModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.processListModal = processListModal
|
||||
PopoutService.processListModal = processListModal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +395,7 @@ Item {
|
||||
id: systemUpdatePopout
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.systemUpdatePopout = systemUpdatePopout
|
||||
PopoutService.systemUpdatePopout = systemUpdatePopout;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -420,16 +416,16 @@ Item {
|
||||
content: Component {
|
||||
Notepad {
|
||||
onHideRequested: {
|
||||
notepadSlideout.hide()
|
||||
notepadSlideout.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (isVisible) {
|
||||
hide()
|
||||
hide();
|
||||
} else {
|
||||
show()
|
||||
show();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,43 +440,43 @@ Item {
|
||||
id: powerMenuModal
|
||||
|
||||
onPowerActionRequested: (action, title, message) => {
|
||||
if (SettingsData.powerActionConfirm) {
|
||||
powerConfirmModalLoader.active = true
|
||||
if (powerConfirmModalLoader.item) {
|
||||
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
|
||||
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {})
|
||||
}
|
||||
} else {
|
||||
actionApply(action)
|
||||
}
|
||||
}
|
||||
if (SettingsData.powerActionConfirm) {
|
||||
powerConfirmModalLoader.active = true;
|
||||
if (powerConfirmModalLoader.item) {
|
||||
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary;
|
||||
powerConfirmModalLoader.item.show(title, message, () => actionApply(action), function () {});
|
||||
}
|
||||
} else {
|
||||
actionApply(action);
|
||||
}
|
||||
}
|
||||
|
||||
onLockRequested: {
|
||||
lock.activate()
|
||||
lock.activate();
|
||||
}
|
||||
|
||||
function actionApply(action) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.powerMenuModal = powerMenuModal
|
||||
PopoutService.powerMenuModal = powerMenuModal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,7 +490,7 @@ Item {
|
||||
id: keybindsModal
|
||||
|
||||
Component.onCompleted: {
|
||||
PopoutService.hyprKeybindsModal = keybindsModal
|
||||
PopoutService.hyprKeybindsModal = keybindsModal;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -560,8 +556,14 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: powerProfileWatcherLoader
|
||||
active: SettingsData.osdPowerProfileEnabled
|
||||
source: "Services/PowerProfileWatcher.qml"
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("osd")
|
||||
model: SettingsData.osdPowerProfileEnabled ? SettingsData.getFilteredScreens("osd") : []
|
||||
|
||||
delegate: PowerProfileOSD {
|
||||
modelData: item
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Services.Pipewire
|
||||
import qs.Common
|
||||
@@ -10,8 +9,8 @@ Rectangle {
|
||||
id: root
|
||||
|
||||
property bool hasVolumeSliderInCC: {
|
||||
const widgets = SettingsData.controlCenterWidgets || []
|
||||
return widgets.some(widget => widget.id === "volumeSlider")
|
||||
const widgets = SettingsData.controlCenterWidgets || [];
|
||||
return widgets.some(widget => widget.id === "volumeSlider");
|
||||
}
|
||||
|
||||
implicitHeight: headerRow.height + (!hasVolumeSliderInCC ? volumeSlider.height : 0) + audioContent.height + Theme.spacingM
|
||||
@@ -66,7 +65,7 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted
|
||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,13 +73,17 @@ Rectangle {
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
if (!AudioService.sink || !AudioService.sink.audio) return "volume_off"
|
||||
let muted = AudioService.sink.audio.muted
|
||||
let volume = AudioService.sink.audio.volume
|
||||
if (muted || volume === 0.0) return "volume_off"
|
||||
if (volume <= 0.33) return "volume_down"
|
||||
if (volume <= 0.66) return "volume_up"
|
||||
return "volume_up"
|
||||
if (!AudioService.sink || !AudioService.sink.audio)
|
||||
return "volume_off";
|
||||
let muted = AudioService.sink.audio.muted;
|
||||
let volume = AudioService.sink.audio.volume;
|
||||
if (muted || volume === 0.0)
|
||||
return "volume_off";
|
||||
if (volume <= 0.33)
|
||||
return "volume_down";
|
||||
if (volume <= 0.66)
|
||||
return "volume_up";
|
||||
return "volume_up";
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: AudioService.sink && AudioService.sink.audio && !AudioService.sink.audio.muted && AudioService.sink.audio.volume > 0 ? Theme.primary : Theme.surfaceText
|
||||
@@ -101,13 +104,13 @@ Rectangle {
|
||||
valueOverride: actualVolumePercent
|
||||
thumbOutlineColor: Theme.surfaceVariant
|
||||
|
||||
onSliderValueChanged: function(newValue) {
|
||||
onSliderValueChanged: function (newValue) {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.volume = newValue / 100
|
||||
AudioService.sink.audio.volume = newValue / 100;
|
||||
if (newValue > 0 && AudioService.sink.audio.muted) {
|
||||
AudioService.sink.audio.muted = false
|
||||
AudioService.sink.audio.muted = false;
|
||||
}
|
||||
AudioService.volumeChanged()
|
||||
AudioService.volumeChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,22 +136,26 @@ Rectangle {
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const nodes = Pipewire.nodes.values.filter(node => {
|
||||
return node.audio && node.isSink && !node.isStream
|
||||
})
|
||||
const pins = SettingsData.audioOutputDevicePins || {}
|
||||
const pinnedName = pins["preferredOutput"]
|
||||
|
||||
let sorted = [...nodes]
|
||||
return node.audio && node.isSink && !node.isStream;
|
||||
});
|
||||
const pins = SettingsData.audioOutputDevicePins || {};
|
||||
const pinnedName = pins["preferredOutput"];
|
||||
|
||||
let sorted = [...nodes];
|
||||
sorted.sort((a, b) => {
|
||||
// Pinned device first
|
||||
if (a.name === pinnedName && b.name !== pinnedName) return -1
|
||||
if (b.name === pinnedName && a.name !== pinnedName) return 1
|
||||
if (a.name === pinnedName && b.name !== pinnedName)
|
||||
return -1;
|
||||
if (b.name === pinnedName && a.name !== pinnedName)
|
||||
return 1;
|
||||
// Then active device
|
||||
if (a === AudioService.sink && b !== AudioService.sink) return -1
|
||||
if (b === AudioService.sink && a !== AudioService.sink) return 1
|
||||
return 0
|
||||
})
|
||||
return sorted
|
||||
if (a === AudioService.sink && b !== AudioService.sink)
|
||||
return -1;
|
||||
if (b === AudioService.sink && a !== AudioService.sink)
|
||||
return 1;
|
||||
return 0;
|
||||
});
|
||||
return sorted;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -172,13 +179,13 @@ Rectangle {
|
||||
DankIcon {
|
||||
name: {
|
||||
if (modelData.name.includes("bluez"))
|
||||
return "headset"
|
||||
return "headset";
|
||||
else if (modelData.name.includes("hdmi"))
|
||||
return "tv"
|
||||
return "tv";
|
||||
else if (modelData.name.includes("usb"))
|
||||
return "headset"
|
||||
return "headset";
|
||||
else
|
||||
return "speaker"
|
||||
return "speaker";
|
||||
}
|
||||
size: Theme.iconSize - 4
|
||||
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
||||
@@ -188,9 +195,9 @@ Rectangle {
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: {
|
||||
const iconWidth = Theme.iconSize
|
||||
const pinButtonWidth = pinOutputRow.width + Theme.spacingS * 4 + Theme.spacingM
|
||||
return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2
|
||||
const iconWidth = Theme.iconSize;
|
||||
const pinButtonWidth = pinOutputRow.width + Theme.spacingS * 4 + Theme.spacingM;
|
||||
return parent.parent.width - iconWidth - parent.spacing - pinButtonWidth - Theme.spacingM * 2;
|
||||
}
|
||||
|
||||
StyledText {
|
||||
@@ -222,8 +229,8 @@ Rectangle {
|
||||
height: 28
|
||||
radius: height / 2
|
||||
color: {
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name
|
||||
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05)
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
||||
return isThisDevicePinned ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.surfaceText, 0.05);
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -235,21 +242,21 @@ Rectangle {
|
||||
name: "push_pin"
|
||||
size: 16
|
||||
color: {
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name
|
||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name
|
||||
return isThisDevicePinned ? "Pinned" : "Pin"
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
||||
return isThisDevicePinned ? "Pinned" : "Pin";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: {
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name
|
||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText
|
||||
const isThisDevicePinned = (SettingsData.audioOutputDevicePins || {})["preferredOutput"] === modelData.name;
|
||||
return isThisDevicePinned ? Theme.primary : Theme.surfaceText;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
@@ -259,16 +266,16 @@ Rectangle {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}))
|
||||
const isCurrentlyPinned = pins["preferredOutput"] === modelData.name
|
||||
|
||||
const pins = JSON.parse(JSON.stringify(SettingsData.audioOutputDevicePins || {}));
|
||||
const isCurrentlyPinned = pins["preferredOutput"] === modelData.name;
|
||||
|
||||
if (isCurrentlyPinned) {
|
||||
delete pins["preferredOutput"]
|
||||
delete pins["preferredOutput"];
|
||||
} else {
|
||||
pins["preferredOutput"] = modelData.name
|
||||
pins["preferredOutput"] = modelData.name;
|
||||
}
|
||||
|
||||
SettingsData.set("audioOutputDevicePins", pins)
|
||||
|
||||
SettingsData.set("audioOutputDevicePins", pins);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -281,12 +288,186 @@ Rectangle {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
Pipewire.preferredDefaultAudioSink = modelData
|
||||
Pipewire.preferredDefaultAudioSink = modelData;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Row {
|
||||
id: playbackHeaderRow
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
height: 28
|
||||
|
||||
StyledText {
|
||||
id: playbackHeaderText
|
||||
text: I18n.tr("Playback")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: ScriptModel {
|
||||
values: {
|
||||
const nodes = Pipewire.nodes.values.filter(node => {
|
||||
return node.audio && node.isSink && node.isStream;
|
||||
});
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
||||
delegate: Rectangle {
|
||||
required property var modelData
|
||||
required property int index
|
||||
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHighest, Theme.popupTransparency)
|
||||
border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "album"
|
||||
size: Theme.iconSize - 4
|
||||
color: !modelData.audio.muted ? Theme.primary : Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: {
|
||||
const iconWidth = Theme.iconSize;
|
||||
return parent.parent.width - iconWidth - parent.spacing - Theme.spacingM * 2;
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: AudioService.displayName(modelData)
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
color: Theme.surfaceText
|
||||
font.weight: modelData === AudioService.sink ? Font.Medium : Font.Normal
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 120
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: appVolumeRow.width
|
||||
height: 28
|
||||
radius: height / 2
|
||||
|
||||
Item {
|
||||
id: appVolumeRow
|
||||
property color sliderTrackColor: "transparent"
|
||||
anchors.centerIn: parent
|
||||
|
||||
height: 40
|
||||
width: parent.width
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
width: Theme.iconSize + Theme.spacingS * 2
|
||||
height: Theme.iconSize + Theme.spacingS * 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: Theme.cornerRadius
|
||||
color: appIconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
|
||||
MouseArea {
|
||||
id: appIconArea
|
||||
anchors.fill: parent
|
||||
visible: modelData !== null
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (modelData) {
|
||||
AudioService.suppressOSD = true;
|
||||
modelData.audio.muted = !modelData.audio.muted;
|
||||
AudioService.suppressOSD = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
if (!modelData)
|
||||
return "volume_off";
|
||||
|
||||
let volume = modelData.audio.volume;
|
||||
let muted = modelData.audio.muted;
|
||||
|
||||
if (muted || volume === 0.0)
|
||||
return "volume_off";
|
||||
if (volume <= 0.33)
|
||||
return "volume_down";
|
||||
if (volume <= 0.66)
|
||||
return "volume_up";
|
||||
return "volume_up";
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: modelData && !modelData.audio.muted && modelData.audio.volume > 0 ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
}
|
||||
|
||||
DankSlider {
|
||||
readonly property real actualVolumePercent: modelData ? Math.round(modelData.audio.volume * 100) : 0
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 100
|
||||
enabled: modelData !== null
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
value: modelData ? Math.min(100, Math.round(modelData.audio.volume * 100)) : 0
|
||||
showValue: true
|
||||
unit: "%"
|
||||
valueOverride: actualVolumePercent
|
||||
thumbOutlineColor: Theme.surfaceContainer
|
||||
trackColor: appVolumeRow.sliderTrackColor.a > 0 ? appVolumeRow.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
|
||||
onIsDraggingChanged: {
|
||||
if (isDragging) {
|
||||
AudioService.suppressOSD = true;
|
||||
} else {
|
||||
Qt.callLater(() => {
|
||||
AudioService.suppressOSD = false;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onSliderValueChanged: function (newValue) {
|
||||
if (modelData) {
|
||||
modelData.audio.volume = newValue / 100.0;
|
||||
if (newValue > 0 && modelData.audio.muted) {
|
||||
modelData.audio.muted = false;
|
||||
}
|
||||
AudioService.playVolumeChangeSoundIfEnabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
PwObjectTracker {
|
||||
objects: [modelData]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -18,65 +16,69 @@ Row {
|
||||
height: 40
|
||||
spacing: 0
|
||||
|
||||
DankTooltipV2 {
|
||||
id: sharedTooltip
|
||||
}
|
||||
|
||||
property string targetDeviceName: {
|
||||
if (!DisplayService.brightnessAvailable || !DisplayService.devices || DisplayService.devices.length === 0) {
|
||||
return ""
|
||||
return "";
|
||||
}
|
||||
|
||||
if (screenName && screenName.length > 0) {
|
||||
const pins = SettingsData.brightnessDevicePins || {}
|
||||
const pinnedDevice = pins[screenName]
|
||||
const pins = SettingsData.brightnessDevicePins || {};
|
||||
const pinnedDevice = pins[screenName];
|
||||
if (pinnedDevice && pinnedDevice.length > 0) {
|
||||
const found = DisplayService.devices.find(dev => dev.name === pinnedDevice)
|
||||
const found = DisplayService.devices.find(dev => dev.name === pinnedDevice);
|
||||
if (found) {
|
||||
return found.name
|
||||
return found.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (deviceName && deviceName.length > 0) {
|
||||
const found = DisplayService.devices.find(dev => dev.name === deviceName)
|
||||
const found = DisplayService.devices.find(dev => dev.name === deviceName);
|
||||
if (found) {
|
||||
return found.name
|
||||
return found.name;
|
||||
}
|
||||
}
|
||||
|
||||
const currentDeviceName = DisplayService.currentDevice
|
||||
const currentDeviceName = DisplayService.currentDevice;
|
||||
if (currentDeviceName) {
|
||||
const found = DisplayService.devices.find(dev => dev.name === currentDeviceName)
|
||||
const found = DisplayService.devices.find(dev => dev.name === currentDeviceName);
|
||||
if (found) {
|
||||
return found.name
|
||||
return found.name;
|
||||
}
|
||||
}
|
||||
|
||||
const backlight = DisplayService.devices.find(d => d.class === "backlight")
|
||||
const backlight = DisplayService.devices.find(d => d.class === "backlight");
|
||||
if (backlight) {
|
||||
return backlight.name
|
||||
return backlight.name;
|
||||
}
|
||||
|
||||
const ddc = DisplayService.devices.find(d => d.class === "ddc")
|
||||
const ddc = DisplayService.devices.find(d => d.class === "ddc");
|
||||
if (ddc) {
|
||||
return ddc.name
|
||||
return ddc.name;
|
||||
}
|
||||
|
||||
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : ""
|
||||
return DisplayService.devices.length > 0 ? DisplayService.devices[0].name : "";
|
||||
}
|
||||
|
||||
property var targetDevice: {
|
||||
if (!targetDeviceName || !DisplayService.devices) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return DisplayService.devices.find(dev => dev.name === targetDeviceName) || null
|
||||
return DisplayService.devices.find(dev => dev.name === targetDeviceName) || null;
|
||||
}
|
||||
|
||||
property real targetBrightness: {
|
||||
DisplayService.brightnessVersion
|
||||
DisplayService.brightnessVersion;
|
||||
if (!targetDeviceName) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
return DisplayService.getDeviceBrightness(targetDeviceName)
|
||||
return DisplayService.getDeviceBrightness(targetDeviceName);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -94,46 +96,37 @@ Row {
|
||||
|
||||
onClicked: {
|
||||
if (DisplayService.devices && DisplayService.devices.length > 1) {
|
||||
root.iconClicked()
|
||||
root.iconClicked();
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
tooltipLoader.active = true
|
||||
if (tooltipLoader.item) {
|
||||
const tooltipText = targetDevice ? "bl device: " + targetDevice.name : "Backlight Control"
|
||||
const globalPos = iconArea.mapToGlobal(iconArea.width / 2, iconArea.height / 2)
|
||||
const screenY = root.parentScreen?.y ?? 0
|
||||
const relativeY = globalPos.y - screenY - 55
|
||||
tooltipLoader.item.show(tooltipText, globalPos.x, relativeY, root.parentScreen)
|
||||
}
|
||||
const tooltipText = targetDevice ? "bl device: " + targetDevice.name : "Backlight Control";
|
||||
sharedTooltip.show(tooltipText, iconArea, 0, 0, "bottom");
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
if (!DisplayService.brightnessAvailable || !targetDevice) {
|
||||
return "brightness_low"
|
||||
return "brightness_low";
|
||||
}
|
||||
|
||||
if (targetDevice.class === "backlight" || targetDevice.class === "ddc") {
|
||||
const brightness = targetBrightness
|
||||
const brightness = targetBrightness;
|
||||
if (brightness <= 33)
|
||||
return "brightness_low"
|
||||
return "brightness_low";
|
||||
if (brightness <= 66)
|
||||
return "brightness_medium"
|
||||
return "brightness_high"
|
||||
return "brightness_medium";
|
||||
return "brightness_high";
|
||||
} else if (targetDevice.name.includes("kbd")) {
|
||||
return "keyboard"
|
||||
return "keyboard";
|
||||
} else {
|
||||
return "lightbulb"
|
||||
return "lightbulb";
|
||||
}
|
||||
}
|
||||
size: Theme.iconSize
|
||||
@@ -149,43 +142,40 @@ Row {
|
||||
width: parent.width - (Theme.iconSize + Theme.spacingS * 2)
|
||||
enabled: DisplayService.brightnessAvailable && targetDeviceName.length > 0
|
||||
minimum: {
|
||||
if (!targetDevice) return 1
|
||||
const isExponential = SessionData.getBrightnessExponential(targetDevice.id)
|
||||
if (!targetDevice)
|
||||
return 1;
|
||||
const isExponential = SessionData.getBrightnessExponential(targetDevice.id);
|
||||
if (isExponential) {
|
||||
return 1
|
||||
return 1;
|
||||
}
|
||||
return (targetDevice.class === "backlight" || targetDevice.class === "ddc") ? 1 : 0
|
||||
return (targetDevice.class === "backlight" || targetDevice.class === "ddc") ? 1 : 0;
|
||||
}
|
||||
maximum: {
|
||||
if (!targetDevice) return 100
|
||||
const isExponential = SessionData.getBrightnessExponential(targetDevice.id)
|
||||
if (!targetDevice)
|
||||
return 100;
|
||||
const isExponential = SessionData.getBrightnessExponential(targetDevice.id);
|
||||
if (isExponential) {
|
||||
return 100
|
||||
return 100;
|
||||
}
|
||||
return targetDevice.displayMax || 100
|
||||
return targetDevice.displayMax || 100;
|
||||
}
|
||||
value: !isDragging ? targetBrightness : value
|
||||
showValue: true
|
||||
unit: {
|
||||
if (!targetDevice) return "%"
|
||||
const isExponential = SessionData.getBrightnessExponential(targetDevice.id)
|
||||
if (!targetDevice)
|
||||
return "%";
|
||||
const isExponential = SessionData.getBrightnessExponential(targetDevice.id);
|
||||
if (isExponential) {
|
||||
return "%"
|
||||
return "%";
|
||||
}
|
||||
return targetDevice.class === "ddc" ? "" : "%"
|
||||
return targetDevice.class === "ddc" ? "" : "%";
|
||||
}
|
||||
onSliderValueChanged: function (newValue) {
|
||||
if (DisplayService.brightnessAvailable && targetDeviceName) {
|
||||
DisplayService.setBrightness(newValue, targetDeviceName, true)
|
||||
DisplayService.setBrightness(newValue, targetDeviceName, true);
|
||||
}
|
||||
}
|
||||
thumbOutlineColor: Theme.surfaceContainer
|
||||
trackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: tooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,16 +445,27 @@ PanelWindow {
|
||||
|
||||
onHasActivePopoutChanged: evaluateReveal()
|
||||
|
||||
function updateActivePopoutState() {
|
||||
const screenName = barWindow.screen.name;
|
||||
const activePopout = PopoutManager.currentPopoutsByScreen[screenName];
|
||||
const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName];
|
||||
const trayOpen = rootWindow.systemTrayMenuOpen;
|
||||
|
||||
const hasVisiblePopout = activePopout && activePopout.shouldBeVisible;
|
||||
topBarCore.hasActivePopout = !!(hasVisiblePopout || activeTrayMenu || trayOpen);
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: PopoutManager
|
||||
function onPopoutChanged() {
|
||||
const screenName = barWindow.screen.name;
|
||||
const activePopout = PopoutManager.currentPopoutsByScreen[screenName];
|
||||
const activeTrayMenu = TrayMenuManager.activeTrayMenus[screenName];
|
||||
const trayOpen = rootWindow.systemTrayMenuOpen;
|
||||
topBarCore.updateActivePopoutState();
|
||||
}
|
||||
}
|
||||
|
||||
const hasVisiblePopout = activePopout && activePopout.shouldBeVisible;
|
||||
topBarCore.hasActivePopout = !!(hasVisiblePopout || activeTrayMenu || trayOpen);
|
||||
Connections {
|
||||
target: TrayMenuManager
|
||||
function onActiveTrayMenusChanged() {
|
||||
topBarCore.updateActivePopoutState();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
@@ -15,7 +14,7 @@ BasePill {
|
||||
property var widgetData: null
|
||||
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
|
||||
|
||||
signal cpuClicked()
|
||||
signal cpuClicked
|
||||
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["cpu"]);
|
||||
@@ -26,7 +25,7 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuContent.implicitWidth
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? cpuColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
|
||||
Column {
|
||||
@@ -66,55 +65,78 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: cpuContent
|
||||
Item {
|
||||
id: cpuContentRoot
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: 3
|
||||
|
||||
DankIcon {
|
||||
name: "memory"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuUsage > 80) {
|
||||
return Theme.tempDanger;
|
||||
implicitWidth: cpuRow.implicitWidth
|
||||
implicitHeight: cpuRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: cpuRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: cpuIcon
|
||||
name: "memory"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuUsage > 80) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (DgopService.cpuUsage > 60) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
if (DgopService.cpuUsage > 60) {
|
||||
return Theme.tempWarning;
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(cpuBaseline.width, cpuText.paintedWidth) : cpuText.paintedWidth
|
||||
implicitHeight: cpuText.implicitHeight
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (DgopService.cpuUsage === undefined || DgopService.cpuUsage === null || DgopService.cpuUsage === 0) {
|
||||
return "--%";
|
||||
StyledTextMetrics {
|
||||
id: cpuBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88%"
|
||||
}
|
||||
|
||||
return DgopService.cpuUsage.toFixed(0) + "%";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideNone
|
||||
StyledText {
|
||||
id: cpuText
|
||||
text: {
|
||||
const v = DgopService.cpuUsage;
|
||||
if (v === undefined || v === null || v === 0) {
|
||||
return "--%";
|
||||
}
|
||||
return v.toFixed(0) + "%";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
StyledTextMetrics {
|
||||
id: cpuBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "100%"
|
||||
}
|
||||
|
||||
width: root.minimumWidth ? Math.max(cpuBaseline.width, paintedWidth) : paintedWidth
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,8 +149,8 @@ BasePill {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
DgopService.setSortBy("cpu")
|
||||
cpuClicked()
|
||||
DgopService.setSortBy("cpu");
|
||||
cpuClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
@@ -15,7 +14,7 @@ BasePill {
|
||||
property var widgetData: null
|
||||
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
|
||||
|
||||
signal cpuTempClicked()
|
||||
signal cpuTempClicked
|
||||
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["cpu"]);
|
||||
@@ -26,7 +25,7 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuTempContent.implicitWidth
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : cpuTempContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? cpuTempColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
|
||||
Column {
|
||||
@@ -66,55 +65,78 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: cpuTempContent
|
||||
Item {
|
||||
id: cpuTempContentRoot
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: 3
|
||||
|
||||
DankIcon {
|
||||
name: "device_thermostat"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuTemperature > 85) {
|
||||
return Theme.tempDanger;
|
||||
implicitWidth: cpuTempRow.implicitWidth
|
||||
implicitHeight: cpuTempRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: cpuTempRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: cpuTempIcon
|
||||
name: "device_thermostat"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.cpuTemperature > 85) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (DgopService.cpuTemperature > 69) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
if (DgopService.cpuTemperature > 69) {
|
||||
return Theme.tempWarning;
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(tempBaseline.width, cpuTempText.paintedWidth) : cpuTempText.paintedWidth
|
||||
implicitHeight: cpuTempText.implicitHeight
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) {
|
||||
return "--°";
|
||||
StyledTextMetrics {
|
||||
id: tempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88°"
|
||||
}
|
||||
|
||||
return Math.round(DgopService.cpuTemperature) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideNone
|
||||
StyledText {
|
||||
id: cpuTempText
|
||||
text: {
|
||||
if (DgopService.cpuTemperature === undefined || DgopService.cpuTemperature === null || DgopService.cpuTemperature < 0) {
|
||||
return "--°";
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: tempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "100°"
|
||||
}
|
||||
return Math.round(DgopService.cpuTemperature) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
width: root.minimumWidth ? Math.max(tempBaseline.width, paintedWidth) : paintedWidth
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -127,8 +149,8 @@ BasePill {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
DgopService.setSortBy("cpu")
|
||||
cpuTempClicked()
|
||||
DgopService.setSortBy("cpu");
|
||||
cpuTempClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
@@ -22,86 +23,87 @@ BasePill {
|
||||
|
||||
readonly property real minTooltipY: {
|
||||
if (!parentScreen || !isVerticalOrientation) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isAutoHideBar) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parentScreen.y > 0) {
|
||||
return barThickness + (barSpacing || 4)
|
||||
return barThickness + (barSpacing || 4);
|
||||
}
|
||||
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
updateDesktopEntry()
|
||||
updateDesktopEntry();
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DesktopEntries
|
||||
function onApplicationsChanged() {
|
||||
root.updateDesktopEntry()
|
||||
root.updateDesktopEntry();
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: root
|
||||
function onActiveWindowChanged() {
|
||||
root.updateDesktopEntry()
|
||||
root.updateDesktopEntry();
|
||||
}
|
||||
}
|
||||
|
||||
function updateDesktopEntry() {
|
||||
if (activeWindow && activeWindow.appId) {
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId)
|
||||
activeDesktopEntry = DesktopEntries.heuristicLookup(moddedId)
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
||||
activeDesktopEntry = DesktopEntries.heuristicLookup(moddedId);
|
||||
} else {
|
||||
activeDesktopEntry = null
|
||||
activeDesktopEntry = null;
|
||||
}
|
||||
}
|
||||
readonly property bool hasWindowsOnCurrentWorkspace: {
|
||||
if (CompositorService.isNiri) {
|
||||
let currentWorkspaceId = null
|
||||
let currentWorkspaceId = null;
|
||||
for (var i = 0; i < NiriService.allWorkspaces.length; i++) {
|
||||
const ws = NiriService.allWorkspaces[i]
|
||||
const ws = NiriService.allWorkspaces[i];
|
||||
if (ws.is_focused) {
|
||||
currentWorkspaceId = ws.id
|
||||
break
|
||||
currentWorkspaceId = ws.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!currentWorkspaceId) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId)
|
||||
return workspaceWindows.length > 0 && activeWindow && activeWindow.title
|
||||
const workspaceWindows = NiriService.windows.filter(w => w.workspace_id === currentWorkspaceId);
|
||||
return workspaceWindows.length > 0 && activeWindow && activeWindow.title;
|
||||
}
|
||||
|
||||
if (CompositorService.isHyprland) {
|
||||
if (!Hyprland.focusedWorkspace || !activeWindow || !activeWindow.title) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!Hyprland.toplevels) return false
|
||||
const hyprlandToplevels = Array.from(Hyprland.toplevels.values)
|
||||
const activeHyprToplevel = hyprlandToplevels.find(t => t?.wayland === activeWindow)
|
||||
if (!Hyprland.toplevels)
|
||||
return false;
|
||||
const hyprlandToplevels = Array.from(Hyprland.toplevels.values);
|
||||
const activeHyprToplevel = hyprlandToplevels.find(t => t?.wayland === activeWindow);
|
||||
|
||||
if (!activeHyprToplevel || !activeHyprToplevel.workspace) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id
|
||||
return activeHyprToplevel.workspace.id === Hyprland.focusedWorkspace.id;
|
||||
} catch (e) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return activeWindow && activeWindow.title
|
||||
return activeWindow && activeWindow.title;
|
||||
}
|
||||
|
||||
width: hasWindowsOnCurrentWorkspace ? (isVerticalOrientation ? barThickness : visualWidth) : 0
|
||||
@@ -111,10 +113,12 @@ BasePill {
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: {
|
||||
if (!root.hasWindowsOnCurrentWorkspace) return 0
|
||||
if (root.isVerticalOrientation) return root.widgetThickness - root.horizontalPadding * 2
|
||||
const baseWidth = contentRow.implicitWidth
|
||||
return compactMode ? Math.min(baseWidth, maxCompactWidth - root.horizontalPadding * 2) : Math.min(baseWidth, maxNormalWidth - root.horizontalPadding * 2)
|
||||
if (!root.hasWindowsOnCurrentWorkspace)
|
||||
return 0;
|
||||
if (root.isVerticalOrientation)
|
||||
return root.widgetThickness - root.horizontalPadding * 2;
|
||||
const baseWidth = contentRow.implicitWidth;
|
||||
return compactMode ? Math.min(baseWidth, maxCompactWidth - root.horizontalPadding * 2) : Math.min(baseWidth, maxNormalWidth - root.horizontalPadding * 2);
|
||||
}
|
||||
implicitHeight: root.widgetThickness - root.horizontalPadding * 2
|
||||
clip: false
|
||||
@@ -126,14 +130,21 @@ BasePill {
|
||||
height: 18
|
||||
visible: root.isVerticalOrientation && activeWindow && status === Image.Ready
|
||||
source: {
|
||||
if (!activeWindow || !activeWindow.appId) return ""
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId)
|
||||
if (moddedId.toLowerCase().includes("steam_app")) return ""
|
||||
return Quickshell.iconPath(activeDesktopEntry?.icon, true)
|
||||
if (!activeWindow || !activeWindow.appId)
|
||||
return "";
|
||||
return Paths.getAppIcon(activeWindow.appId, activeDesktopEntry);
|
||||
}
|
||||
smooth: true
|
||||
mipmap: true
|
||||
asynchronous: true
|
||||
layer.enabled: activeWindow && activeWindow.appId === "org.quickshell"
|
||||
layer.smooth: true
|
||||
layer.mipmap: true
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -142,26 +153,28 @@ BasePill {
|
||||
name: "sports_esports"
|
||||
color: Theme.widgetTextColor
|
||||
visible: {
|
||||
if (!root.isVerticalOrientation || !activeWindow || !activeWindow.appId) return false
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId)
|
||||
return moddedId.toLowerCase().includes("steam_app")
|
||||
if (!root.isVerticalOrientation || !activeWindow || !activeWindow.appId)
|
||||
return false;
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
||||
return moddedId.toLowerCase().includes("steam_app");
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: {
|
||||
if (!root.isVerticalOrientation || !activeWindow || !activeWindow.appId) return false
|
||||
if (appIcon.status === Image.Ready) return false
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId)
|
||||
return !moddedId.toLowerCase().includes("steam_app")
|
||||
if (!root.isVerticalOrientation || !activeWindow || !activeWindow.appId)
|
||||
return false;
|
||||
if (appIcon.status === Image.Ready)
|
||||
return false;
|
||||
const moddedId = Paths.moddedAppId(activeWindow.appId);
|
||||
return !moddedId.toLowerCase().includes("steam_app");
|
||||
}
|
||||
text: {
|
||||
if (!activeWindow || !activeWindow.appId) return "?"
|
||||
if (activeDesktopEntry && activeDesktopEntry.name) {
|
||||
return activeDesktopEntry.name.charAt(0).toUpperCase()
|
||||
}
|
||||
return activeWindow.appId.charAt(0).toUpperCase()
|
||||
if (!activeWindow || !activeWindow.appId)
|
||||
return "?";
|
||||
const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry);
|
||||
return appName.charAt(0).toUpperCase();
|
||||
}
|
||||
font.pixelSize: 10
|
||||
color: Theme.widgetTextColor
|
||||
@@ -176,12 +189,9 @@ BasePill {
|
||||
StyledText {
|
||||
id: appText
|
||||
text: {
|
||||
if (!activeWindow || !activeWindow.appId) {
|
||||
if (!activeWindow || !activeWindow.appId)
|
||||
return "";
|
||||
}
|
||||
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(activeWindow.appId);
|
||||
return desktopEntry && desktopEntry.name ? desktopEntry.name : activeWindow.appId;
|
||||
return Paths.getAppName(activeWindow.appId, activeDesktopEntry);
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
@@ -238,31 +248,31 @@ BasePill {
|
||||
acceptedButtons: Qt.NoButton
|
||||
onEntered: {
|
||||
if (root.isVerticalOrientation && activeWindow && activeWindow.appId && root.parentScreen) {
|
||||
tooltipLoader.active = true
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
const globalPos = mapToGlobal(width / 2, height / 2)
|
||||
const currentScreen = root.parentScreen
|
||||
const screenX = currentScreen ? currentScreen.x : 0
|
||||
const screenY = currentScreen ? currentScreen.y : 0
|
||||
const relativeY = globalPos.y - screenY
|
||||
const globalPos = mapToGlobal(width / 2, height / 2);
|
||||
const currentScreen = root.parentScreen;
|
||||
const screenX = currentScreen ? currentScreen.x : 0;
|
||||
const screenY = currentScreen ? currentScreen.y : 0;
|
||||
const relativeY = globalPos.y - screenY;
|
||||
// Add minTooltipY offset to account for top bar
|
||||
const adjustedY = relativeY + root.minTooltipY
|
||||
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS)
|
||||
const adjustedY = relativeY + root.minTooltipY;
|
||||
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (currentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS);
|
||||
|
||||
const appName = activeDesktopEntry && activeDesktopEntry.name ? activeDesktopEntry.name : activeWindow.appId
|
||||
const title = activeWindow.title || ""
|
||||
const tooltipText = appName + (title ? " • " + title : "")
|
||||
const appName = Paths.getAppName(activeWindow.appId, activeDesktopEntry);
|
||||
const title = activeWindow.title || "";
|
||||
const tooltipText = appName + (title ? " • " + title : "");
|
||||
|
||||
const isLeft = root.axis?.edge === "left"
|
||||
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft)
|
||||
const isLeft = root.axis?.edge === "left";
|
||||
tooltipLoader.item.show(tooltipText, screenX + tooltipX, adjustedY, currentScreen, isLeft, !isLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
tooltipLoader.active = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
@@ -16,7 +15,7 @@ BasePill {
|
||||
property int selectedGpuIndex: (widgetData && widgetData.selectedGpuIndex !== undefined) ? widgetData.selectedGpuIndex : 0
|
||||
property bool minimumWidth: (widgetData && widgetData.minimumWidth !== undefined) ? widgetData.minimumWidth : true
|
||||
|
||||
signal gpuTempClicked()
|
||||
signal gpuTempClicked
|
||||
|
||||
property real displayTemp: {
|
||||
if (!DgopService.availableGpus || DgopService.availableGpus.length === 0) {
|
||||
@@ -32,9 +31,9 @@ BasePill {
|
||||
|
||||
function updateWidgetPciId(pciId) {
|
||||
const sections = ["left", "center", "right"];
|
||||
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default")
|
||||
if (!defaultBar) return
|
||||
|
||||
const defaultBar = SettingsData.barConfigs[0] || SettingsData.getBarConfig("default");
|
||||
if (!defaultBar)
|
||||
return;
|
||||
for (let s = 0; s < sections.length; s++) {
|
||||
const sectionId = sections[s];
|
||||
let widgets = [];
|
||||
@@ -61,7 +60,7 @@ BasePill {
|
||||
} else if (sectionId === "right") {
|
||||
SettingsData.setDankBarRightWidgets(widgets);
|
||||
}
|
||||
return ;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -94,7 +93,7 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : gpuTempContent.implicitWidth
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : gpuTempContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? gpuTempColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
|
||||
Column {
|
||||
@@ -134,55 +133,78 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: gpuTempContent
|
||||
Item {
|
||||
id: gpuTempContentRoot
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: 3
|
||||
|
||||
DankIcon {
|
||||
name: "auto_awesome_mosaic"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (root.displayTemp > 80) {
|
||||
return Theme.tempDanger;
|
||||
implicitWidth: gpuTempRow.implicitWidth
|
||||
implicitHeight: gpuTempRow.implicitHeight
|
||||
|
||||
Row {
|
||||
id: gpuTempRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
id: gpuTempIcon
|
||||
name: "auto_awesome_mosaic"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (root.displayTemp > 80) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
|
||||
if (root.displayTemp > 65) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
if (root.displayTemp > 65) {
|
||||
return Theme.tempWarning;
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
implicitWidth: root.minimumWidth ? Math.max(gpuTempBaseline.width, gpuTempText.paintedWidth) : gpuTempText.paintedWidth
|
||||
implicitHeight: gpuTempText.implicitHeight
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
|
||||
return "--°";
|
||||
StyledTextMetrics {
|
||||
id: gpuTempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "88°"
|
||||
}
|
||||
|
||||
return Math.round(root.displayTemp) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideNone
|
||||
StyledText {
|
||||
id: gpuTempText
|
||||
text: {
|
||||
if (root.displayTemp === undefined || root.displayTemp === null || root.displayTemp === 0) {
|
||||
return "--°";
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: gpuTempBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: "100°"
|
||||
}
|
||||
return Math.round(root.displayTemp) + "°";
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
width: root.minimumWidth ? Math.max(gpuTempBaseline.width, paintedWidth) : paintedWidth
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -195,8 +217,8 @@ BasePill {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
DgopService.setSortBy("cpu")
|
||||
gpuTempClicked()
|
||||
DgopService.setSortBy("cpu");
|
||||
gpuTempClicked();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
@@ -17,7 +16,7 @@ BasePill {
|
||||
property bool showSwap: (widgetData && widgetData.showSwap !== undefined) ? widgetData.showSwap : false
|
||||
readonly property real swapUsage: DgopService.totalSwapKB > 0 ? (DgopService.usedSwapKB / DgopService.totalSwapKB) * 100 : 0
|
||||
|
||||
signal ramClicked()
|
||||
signal ramClicked
|
||||
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["memory"]);
|
||||
@@ -28,7 +27,7 @@ BasePill {
|
||||
|
||||
content: Component {
|
||||
Item {
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : ramContent.implicitWidth
|
||||
implicitWidth: root.isVerticalOrientation ? (root.widgetThickness - root.horizontalPadding * 2) : ramContentRoot.implicitWidth
|
||||
implicitHeight: root.isVerticalOrientation ? ramColumn.implicitHeight : (root.widgetThickness - root.horizontalPadding * 2)
|
||||
|
||||
Column {
|
||||
@@ -76,68 +75,91 @@ BasePill {
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: ramContent
|
||||
Item {
|
||||
id: ramContentRoot
|
||||
visible: !root.isVerticalOrientation
|
||||
anchors.centerIn: parent
|
||||
spacing: 3
|
||||
|
||||
DankIcon {
|
||||
name: "developer_board"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.memoryUsage > 90) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
implicitWidth: ramRow.implicitWidth
|
||||
implicitHeight: ramRow.implicitHeight
|
||||
|
||||
if (DgopService.memoryUsage > 75) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
Row {
|
||||
id: ramRow
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
|
||||
return "--%";
|
||||
}
|
||||
|
||||
let ramText = DgopService.memoryUsage.toFixed(0) + "%";
|
||||
if (root.showSwap && DgopService.totalSwapKB > 0) {
|
||||
return ramText + " · " + root.swapUsage.toFixed(0) + "%";
|
||||
}
|
||||
return ramText;
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
horizontalAlignment: Text.AlignLeft
|
||||
elide: Text.ElideNone
|
||||
wrapMode: Text.NoWrap
|
||||
|
||||
StyledTextMetrics {
|
||||
id: ramBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: {
|
||||
if (!root.showSwap) {
|
||||
return "100%";
|
||||
DankIcon {
|
||||
id: ramIcon
|
||||
name: "developer_board"
|
||||
size: Theme.barIconSize(root.barThickness)
|
||||
color: {
|
||||
if (DgopService.memoryUsage > 90) {
|
||||
return Theme.tempDanger;
|
||||
}
|
||||
if (root.swapUsage < 10) {
|
||||
return "100% · 0%";
|
||||
|
||||
if (DgopService.memoryUsage > 75) {
|
||||
return Theme.tempWarning;
|
||||
}
|
||||
return "100% · 100%";
|
||||
|
||||
return Theme.widgetIconColor;
|
||||
}
|
||||
|
||||
implicitWidth: size
|
||||
implicitHeight: size
|
||||
width: size
|
||||
height: size
|
||||
}
|
||||
|
||||
width: root.minimumWidth ? Math.max(ramBaseline.width, paintedWidth) : paintedWidth
|
||||
Item {
|
||||
id: textBox
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 120
|
||||
easing.type: Easing.OutCubic
|
||||
implicitWidth: root.minimumWidth ? Math.max(ramBaseline.width, ramText.paintedWidth) : ramText.paintedWidth
|
||||
implicitHeight: ramText.implicitHeight
|
||||
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
StyledTextMetrics {
|
||||
id: ramBaseline
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
text: {
|
||||
if (!root.showSwap) {
|
||||
return "88%";
|
||||
}
|
||||
if (root.swapUsage < 10) {
|
||||
return "88% · 0%";
|
||||
}
|
||||
return "88% · 88%";
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: ramText
|
||||
text: {
|
||||
if (DgopService.memoryUsage === undefined || DgopService.memoryUsage === null || DgopService.memoryUsage === 0) {
|
||||
return "--%";
|
||||
}
|
||||
|
||||
let ramText = DgopService.memoryUsage.toFixed(0) + "%";
|
||||
if (root.showSwap && DgopService.totalSwapKB > 0) {
|
||||
return ramText + " · " + root.swapUsage.toFixed(0) + "%";
|
||||
}
|
||||
return ramText;
|
||||
}
|
||||
font.pixelSize: Theme.barTextSize(root.barThickness, root.barConfig?.fontScale)
|
||||
color: Theme.widgetTextColor
|
||||
|
||||
anchors.fill: parent
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
elide: Text.ElideNone
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -150,8 +172,8 @@ BasePill {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
DgopService.setSortBy("memory")
|
||||
ramClicked()
|
||||
DgopService.setSortBy("memory");
|
||||
ramClicked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
@@ -27,105 +27,112 @@ Item {
|
||||
|
||||
readonly property real effectiveBarThickness: {
|
||||
if (barThickness > 0 && barSpacing > 0) {
|
||||
return barThickness + barSpacing
|
||||
return barThickness + barSpacing;
|
||||
}
|
||||
const innerPadding = barConfig?.innerPadding ?? 4
|
||||
const spacing = barConfig?.spacing ?? 4
|
||||
return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing
|
||||
const innerPadding = barConfig?.innerPadding ?? 4;
|
||||
const spacing = barConfig?.spacing ?? 4;
|
||||
return Math.max(26 + innerPadding * 0.6, Theme.barHeight - 4 - (8 - innerPadding)) + spacing;
|
||||
}
|
||||
|
||||
readonly property var barBounds: {
|
||||
if (!parentScreen || !barConfig) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
return {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"wingSize": 0
|
||||
};
|
||||
}
|
||||
const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1))
|
||||
return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig)
|
||||
const barPosition = axis.edge === "left" ? 2 : (axis.edge === "right" ? 3 : (axis.edge === "top" ? 0 : 1));
|
||||
return SettingsData.getBarBounds(parentScreen, effectiveBarThickness, barPosition, barConfig);
|
||||
}
|
||||
|
||||
readonly property real barY: barBounds.y
|
||||
|
||||
readonly property real minTooltipY: {
|
||||
if (!parentScreen || !isVertical) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (isAutoHideBar) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (parentScreen.y > 0) {
|
||||
return effectiveBarThickness
|
||||
return effectiveBarThickness;
|
||||
}
|
||||
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
property int _desktopEntriesUpdateTrigger: 0
|
||||
property int _toplevelsUpdateTrigger: 0
|
||||
|
||||
readonly property var sortedToplevels: {
|
||||
_toplevelsUpdateTrigger
|
||||
const toplevels = CompositorService.sortedToplevels
|
||||
if (!toplevels || toplevels.length === 0) return []
|
||||
_toplevelsUpdateTrigger;
|
||||
const toplevels = CompositorService.sortedToplevels;
|
||||
if (!toplevels || toplevels.length === 0)
|
||||
return [];
|
||||
|
||||
if (SettingsData.runningAppsCurrentWorkspace) {
|
||||
return CompositorService.filterCurrentWorkspace(toplevels, parentScreen?.name) || []
|
||||
return CompositorService.filterCurrentWorkspace(toplevels, parentScreen?.name) || [];
|
||||
}
|
||||
return toplevels
|
||||
return toplevels;
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: CompositorService
|
||||
function onToplevelsChanged() {
|
||||
_toplevelsUpdateTrigger++
|
||||
_toplevelsUpdateTrigger++;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: DesktopEntries
|
||||
function onApplicationsChanged() {
|
||||
_desktopEntriesUpdateTrigger++
|
||||
_desktopEntriesUpdateTrigger++;
|
||||
}
|
||||
}
|
||||
readonly property var groupedWindows: {
|
||||
if (!SettingsData.runningAppsGroupByApp) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
try {
|
||||
if (!sortedToplevels || sortedToplevels.length === 0) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
const appGroups = new Map()
|
||||
const appGroups = new Map();
|
||||
sortedToplevels.forEach((toplevel, index) => {
|
||||
if (!toplevel)
|
||||
return
|
||||
const appId = toplevel?.appId || "unknown"
|
||||
if (!appGroups.has(appId)) {
|
||||
appGroups.set(appId, {
|
||||
"appId": appId,
|
||||
"windows": []
|
||||
})
|
||||
}
|
||||
appGroups.get(appId).windows.push({
|
||||
"toplevel": toplevel,
|
||||
"windowId": index,
|
||||
"windowTitle": toplevel?.title || "(Unnamed)"
|
||||
})
|
||||
})
|
||||
return Array.from(appGroups.values())
|
||||
if (!toplevel)
|
||||
return;
|
||||
const appId = toplevel?.appId || "unknown";
|
||||
if (!appGroups.has(appId)) {
|
||||
appGroups.set(appId, {
|
||||
"appId": appId,
|
||||
"windows": []
|
||||
});
|
||||
}
|
||||
appGroups.get(appId).windows.push({
|
||||
"toplevel": toplevel,
|
||||
"windowId": index,
|
||||
"windowTitle": toplevel?.title || "(Unnamed)"
|
||||
});
|
||||
});
|
||||
return Array.from(appGroups.values());
|
||||
} catch (e) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
}
|
||||
readonly property int windowCount: SettingsData.runningAppsGroupByApp ? (groupedWindows?.length || 0) : (sortedToplevels?.length || 0)
|
||||
readonly property int calculatedSize: {
|
||||
if (windowCount === 0) {
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
if (SettingsData.runningAppsCompactMode) {
|
||||
return windowCount * 24 + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2
|
||||
return windowCount * 24 + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2;
|
||||
} else {
|
||||
return windowCount * (24 + Theme.spacingXS + 120) + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2
|
||||
return windowCount * (24 + Theme.spacingXS + 120) + (windowCount - 1) * Theme.spacingXS + horizontalPadding * 2;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,7 +140,6 @@ Item {
|
||||
height: windowCount > 0 ? (isVertical ? calculatedSize : barThickness) : 0
|
||||
visible: windowCount > 0
|
||||
|
||||
|
||||
Rectangle {
|
||||
id: visualBackground
|
||||
width: root.isVertical ? root.widgetThickness : root.calculatedSize
|
||||
@@ -143,19 +149,19 @@ Item {
|
||||
clip: false
|
||||
color: {
|
||||
if (windowCount === 0) {
|
||||
return "transparent"
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
if ((barConfig?.noBackground ?? false)) {
|
||||
return "transparent"
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = Theme.widgetBaseBackgroundColor
|
||||
const baseColor = Theme.widgetBaseBackgroundColor;
|
||||
if (Theme.widgetBackgroundHasAlpha) {
|
||||
return baseColor
|
||||
return baseColor;
|
||||
}
|
||||
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0
|
||||
return Theme.withAlpha(baseColor, transparency)
|
||||
const transparency = (root.barConfig && root.barConfig.widgetTransparency !== undefined) ? root.barConfig.widgetTransparency : 1.0;
|
||||
return Theme.withAlpha(baseColor, transparency);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,82 +174,82 @@ Item {
|
||||
property real touchpadThreshold: 500
|
||||
|
||||
onWheel: wheel => {
|
||||
const deltaY = wheel.angleDelta.y
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0
|
||||
const deltaY = wheel.angleDelta.y;
|
||||
const isMouseWheel = Math.abs(deltaY) >= 120 && (Math.abs(deltaY) % 120) === 0;
|
||||
|
||||
const windows = root.sortedToplevels
|
||||
if (windows.length < 2) {
|
||||
return
|
||||
}
|
||||
const windows = root.sortedToplevels;
|
||||
if (windows.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMouseWheel) {
|
||||
// Direct mouse wheel action
|
||||
let currentIndex = -1
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (isMouseWheel) {
|
||||
// Direct mouse wheel action
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let nextIndex
|
||||
if (deltaY < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0
|
||||
} else {
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1)
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1
|
||||
} else {
|
||||
nextIndex = Math.max(currentIndex - 1, 0)
|
||||
}
|
||||
}
|
||||
let nextIndex;
|
||||
if (deltaY < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1);
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1;
|
||||
} else {
|
||||
nextIndex = Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const nextWindow = windows[nextIndex]
|
||||
if (nextWindow) {
|
||||
nextWindow.activate()
|
||||
}
|
||||
} else {
|
||||
// Touchpad - accumulate small deltas
|
||||
scrollAccumulator += deltaY
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
nextWindow.activate();
|
||||
}
|
||||
} else {
|
||||
// Touchpad - accumulate small deltas
|
||||
scrollAccumulator += deltaY;
|
||||
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
let currentIndex = -1
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if (Math.abs(scrollAccumulator) >= touchpadThreshold) {
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < windows.length; i++) {
|
||||
if (windows[i].activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let nextIndex
|
||||
if (scrollAccumulator < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0
|
||||
} else {
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1)
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1
|
||||
} else {
|
||||
nextIndex = Math.max(currentIndex - 1, 0)
|
||||
}
|
||||
}
|
||||
let nextIndex;
|
||||
if (scrollAccumulator < 0) {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = 0;
|
||||
} else {
|
||||
nextIndex = Math.min(currentIndex + 1, windows.length - 1);
|
||||
}
|
||||
} else {
|
||||
if (currentIndex === -1) {
|
||||
nextIndex = windows.length - 1;
|
||||
} else {
|
||||
nextIndex = Math.max(currentIndex - 1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
const nextWindow = windows[nextIndex]
|
||||
if (nextWindow) {
|
||||
nextWindow.activate()
|
||||
}
|
||||
const nextWindow = windows[nextIndex];
|
||||
if (nextWindow) {
|
||||
nextWindow.activate();
|
||||
}
|
||||
|
||||
scrollAccumulator = 0
|
||||
}
|
||||
}
|
||||
scrollAccumulator = 0;
|
||||
}
|
||||
}
|
||||
|
||||
wheel.accepted = true
|
||||
}
|
||||
wheel.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -276,16 +282,14 @@ Item {
|
||||
property var toplevelObject: toplevelData
|
||||
property int windowCount: isGrouped ? modelData.windows.length : 1
|
||||
property string tooltipText: {
|
||||
root._desktopEntriesUpdateTrigger
|
||||
let appName = "Unknown"
|
||||
if (appId) {
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId)
|
||||
appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appId
|
||||
}
|
||||
root._desktopEntriesUpdateTrigger;
|
||||
const desktopEntry = appId ? DesktopEntries.heuristicLookup(appId) : null;
|
||||
const appName = appId ? Paths.getAppName(appId, desktopEntry) : "Unknown";
|
||||
|
||||
if (isGrouped && windowCount > 1) {
|
||||
return appName + " (" + windowCount + " windows)"
|
||||
return appName + " (" + windowCount + " windows)";
|
||||
}
|
||||
return appName + (windowTitle ? " • " + windowTitle : "")
|
||||
return appName + (windowTitle ? " • " + windowTitle : "");
|
||||
}
|
||||
readonly property real visualWidth: SettingsData.runningAppsCompactMode ? 24 : (24 + Theme.spacingXS + 120)
|
||||
|
||||
@@ -300,9 +304,9 @@ Item {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isFocused) {
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2);
|
||||
} else {
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primaryHover.r, Theme.primaryHover.g, Theme.primaryHover.b, 0.1) : "transparent"
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primaryHover.r, Theme.primaryHover.g, Theme.primaryHover.b, 0.1) : "transparent";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -315,17 +319,24 @@ Item {
|
||||
width: Theme.barIconSize(root.barThickness)
|
||||
height: Theme.barIconSize(root.barThickness)
|
||||
source: {
|
||||
root._desktopEntriesUpdateTrigger
|
||||
const moddedId = Paths.moddedAppId(appId)
|
||||
if (moddedId.toLowerCase().includes("steam_app")) {
|
||||
return ""
|
||||
}
|
||||
return Quickshell.iconPath(DesktopEntries.heuristicLookup(moddedId)?.icon, true)
|
||||
root._desktopEntriesUpdateTrigger;
|
||||
if (!appId)
|
||||
return "";
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId);
|
||||
return Paths.getAppIcon(appId, desktopEntry);
|
||||
}
|
||||
smooth: true
|
||||
mipmap: true
|
||||
asynchronous: true
|
||||
visible: status === Image.Ready
|
||||
layer.enabled: appId === "org.quickshell"
|
||||
layer.smooth: true
|
||||
layer.mipmap: true
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -336,8 +347,8 @@ Item {
|
||||
name: "sports_esports"
|
||||
color: Theme.widgetTextColor
|
||||
visible: {
|
||||
const moddedId = Paths.moddedAppId(appId)
|
||||
return moddedId.toLowerCase().includes("steam_app")
|
||||
const moddedId = Paths.moddedAppId(appId);
|
||||
return moddedId.toLowerCase().includes("steam_app");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,22 +356,18 @@ Item {
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: {
|
||||
const moddedId = Paths.moddedAppId(appId)
|
||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app")
|
||||
return !iconImg.visible && !isSteamApp
|
||||
const moddedId = Paths.moddedAppId(appId);
|
||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app");
|
||||
return !iconImg.visible && !isSteamApp;
|
||||
}
|
||||
text: {
|
||||
root._desktopEntriesUpdateTrigger
|
||||
if (!appId) {
|
||||
return "?"
|
||||
}
|
||||
root._desktopEntriesUpdateTrigger;
|
||||
if (!appId)
|
||||
return "?";
|
||||
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId)
|
||||
if (desktopEntry && desktopEntry.name) {
|
||||
return desktopEntry.name.charAt(0).toUpperCase()
|
||||
}
|
||||
|
||||
return appId.charAt(0).toUpperCase()
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId);
|
||||
const appName = Paths.getAppName(appId, desktopEntry);
|
||||
return appName.charAt(0).toUpperCase();
|
||||
}
|
||||
font.pixelSize: 10
|
||||
color: Theme.widgetTextColor
|
||||
@@ -409,86 +416,84 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isGrouped && windowCount > 1) {
|
||||
let currentIndex = -1
|
||||
for (var i = 0; i < groupData.windows.length; i++) {
|
||||
if (groupData.windows[i].toplevel.activated) {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % groupData.windows.length
|
||||
groupData.windows[nextIndex].toplevel.activate()
|
||||
} else if (toplevelObject) {
|
||||
toplevelObject.activate()
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isGrouped && windowCount > 1) {
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < groupData.windows.length; i++) {
|
||||
if (groupData.windows[i].toplevel.activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % groupData.windows.length;
|
||||
groupData.windows[nextIndex].toplevel.activate();
|
||||
} else if (toplevelObject) {
|
||||
toplevelObject.activate();
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
tooltipLoader.active = false;
|
||||
|
||||
windowContextMenuLoader.active = true
|
||||
if (windowContextMenuLoader.item) {
|
||||
windowContextMenuLoader.item.currentWindow = toplevelObject
|
||||
// Pass bar context
|
||||
windowContextMenuLoader.item.triggerBarConfig = root.barConfig
|
||||
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1))
|
||||
windowContextMenuLoader.item.triggerBarThickness = root.barThickness
|
||||
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing
|
||||
if (root.isVertical) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0
|
||||
const relativeY = globalPos.y - screenY
|
||||
// Add minTooltipY offset to account for top bar
|
||||
const adjustedY = relativeY + root.minTooltipY
|
||||
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
|
||||
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge)
|
||||
} else {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const relativeX = globalPos.x - screenX
|
||||
const yPos = root.barThickness + root.barSpacing - 7
|
||||
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
windowContextMenuLoader.active = true;
|
||||
if (windowContextMenuLoader.item) {
|
||||
windowContextMenuLoader.item.currentWindow = toplevelObject;
|
||||
// Pass bar context
|
||||
windowContextMenuLoader.item.triggerBarConfig = root.barConfig;
|
||||
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1));
|
||||
windowContextMenuLoader.item.triggerBarThickness = root.barThickness;
|
||||
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing;
|
||||
if (root.isVertical) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
const relativeY = globalPos.y - screenY;
|
||||
// Add minTooltipY offset to account for top bar
|
||||
const adjustedY = relativeY + root.minTooltipY;
|
||||
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS);
|
||||
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge);
|
||||
} else {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const relativeX = globalPos.x - screenX;
|
||||
const yPos = root.barThickness + root.barSpacing - 7;
|
||||
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
root.hoveredItem = delegateItem
|
||||
tooltipLoader.active = true
|
||||
root.hoveredItem = delegateItem;
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
if (root.isVertical) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0
|
||||
const relativeY = globalPos.y - screenY
|
||||
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS)
|
||||
const isLeft = root.axis?.edge === "left"
|
||||
const adjustedY = relativeY + root.minTooltipY
|
||||
const finalX = screenX + tooltipX
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft)
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
const relativeY = globalPos.y - screenY;
|
||||
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS);
|
||||
const isLeft = root.axis?.edge === "left";
|
||||
const adjustedY = relativeY + root.minTooltipY;
|
||||
const finalX = screenX + tooltipX;
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft);
|
||||
} else {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
|
||||
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
|
||||
const isBottom = root.axis?.edge === "bottom"
|
||||
const tooltipY = isBottom
|
||||
? (screenHeight - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS - 35)
|
||||
: (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS)
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height);
|
||||
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height;
|
||||
const isBottom = root.axis?.edge === "bottom";
|
||||
const tooltipY = isBottom ? (screenHeight - Theme.barHeight - (barConfig?.spacing ?? 4) - Theme.spacingXS - 35) : (Theme.barHeight + (barConfig?.spacing ?? 4) + Theme.spacingXS);
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (root.hoveredItem === delegateItem) {
|
||||
root.hoveredItem = null
|
||||
root.hoveredItem = null;
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
|
||||
tooltipLoader.active = false
|
||||
tooltipLoader.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,16 +526,14 @@ Item {
|
||||
property var toplevelObject: toplevelData
|
||||
property int windowCount: isGrouped ? modelData.windows.length : 1
|
||||
property string tooltipText: {
|
||||
root._desktopEntriesUpdateTrigger
|
||||
let appName = "Unknown"
|
||||
if (appId) {
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId)
|
||||
appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appId
|
||||
}
|
||||
root._desktopEntriesUpdateTrigger;
|
||||
const desktopEntry = appId ? DesktopEntries.heuristicLookup(appId) : null;
|
||||
const appName = appId ? Paths.getAppName(appId, desktopEntry) : "Unknown";
|
||||
|
||||
if (isGrouped && windowCount > 1) {
|
||||
return appName + " (" + windowCount + " windows)"
|
||||
return appName + " (" + windowCount + " windows)";
|
||||
}
|
||||
return appName + (windowTitle ? " • " + windowTitle : "")
|
||||
return appName + (windowTitle ? " • " + windowTitle : "");
|
||||
}
|
||||
readonly property real visualWidth: SettingsData.runningAppsCompactMode ? 24 : (24 + Theme.spacingXS + 120)
|
||||
|
||||
@@ -545,9 +548,9 @@ Item {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isFocused) {
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2);
|
||||
} else {
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primaryHover.r, Theme.primaryHover.g, Theme.primaryHover.b, 0.1) : "transparent"
|
||||
return mouseArea.containsMouse ? Qt.rgba(Theme.primaryHover.r, Theme.primaryHover.g, Theme.primaryHover.b, 0.1) : "transparent";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,17 +562,24 @@ Item {
|
||||
width: Theme.barIconSize(root.barThickness)
|
||||
height: Theme.barIconSize(root.barThickness)
|
||||
source: {
|
||||
root._desktopEntriesUpdateTrigger
|
||||
const moddedId = Paths.moddedAppId(appId)
|
||||
if (moddedId.toLowerCase().includes("steam_app")) {
|
||||
return ""
|
||||
}
|
||||
return Quickshell.iconPath(DesktopEntries.heuristicLookup(moddedId)?.icon, true)
|
||||
root._desktopEntriesUpdateTrigger;
|
||||
if (!appId)
|
||||
return "";
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId);
|
||||
return Paths.getAppIcon(appId, desktopEntry);
|
||||
}
|
||||
smooth: true
|
||||
mipmap: true
|
||||
asynchronous: true
|
||||
visible: status === Image.Ready
|
||||
layer.enabled: appId === "org.quickshell"
|
||||
layer.smooth: true
|
||||
layer.mipmap: true
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -580,30 +590,26 @@ Item {
|
||||
name: "sports_esports"
|
||||
color: Theme.widgetTextColor
|
||||
visible: {
|
||||
const moddedId = Paths.moddedAppId(appId)
|
||||
return moddedId.toLowerCase().includes("steam_app")
|
||||
const moddedId = Paths.moddedAppId(appId);
|
||||
return moddedId.toLowerCase().includes("steam_app");
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
anchors.centerIn: parent
|
||||
visible: {
|
||||
const moddedId = Paths.moddedAppId(appId)
|
||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app")
|
||||
return !iconImg.visible && !isSteamApp
|
||||
const moddedId = Paths.moddedAppId(appId);
|
||||
const isSteamApp = moddedId.toLowerCase().includes("steam_app");
|
||||
return !iconImg.visible && !isSteamApp;
|
||||
}
|
||||
text: {
|
||||
root._desktopEntriesUpdateTrigger
|
||||
if (!appId) {
|
||||
return "?"
|
||||
}
|
||||
root._desktopEntriesUpdateTrigger;
|
||||
if (!appId)
|
||||
return "?";
|
||||
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId)
|
||||
if (desktopEntry && desktopEntry.name) {
|
||||
return desktopEntry.name.charAt(0).toUpperCase()
|
||||
}
|
||||
|
||||
return appId.charAt(0).toUpperCase()
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appId);
|
||||
const appName = Paths.getAppName(appId, desktopEntry);
|
||||
return appName.charAt(0).toUpperCase();
|
||||
}
|
||||
font.pixelSize: 10
|
||||
color: Theme.widgetTextColor
|
||||
@@ -651,86 +657,84 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isGrouped && windowCount > 1) {
|
||||
let currentIndex = -1
|
||||
for (var i = 0; i < groupData.windows.length; i++) {
|
||||
if (groupData.windows[i].toplevel.activated) {
|
||||
currentIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % groupData.windows.length
|
||||
groupData.windows[nextIndex].toplevel.activate()
|
||||
} else if (toplevelObject) {
|
||||
toplevelObject.activate()
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (isGrouped && windowCount > 1) {
|
||||
let currentIndex = -1;
|
||||
for (var i = 0; i < groupData.windows.length; i++) {
|
||||
if (groupData.windows[i].toplevel.activated) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const nextIndex = (currentIndex + 1) % groupData.windows.length;
|
||||
groupData.windows[nextIndex].toplevel.activate();
|
||||
} else if (toplevelObject) {
|
||||
toplevelObject.activate();
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
tooltipLoader.active = false;
|
||||
|
||||
windowContextMenuLoader.active = true
|
||||
if (windowContextMenuLoader.item) {
|
||||
windowContextMenuLoader.item.currentWindow = toplevelObject
|
||||
// Pass bar context
|
||||
windowContextMenuLoader.item.triggerBarConfig = root.barConfig
|
||||
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1))
|
||||
windowContextMenuLoader.item.triggerBarThickness = root.barThickness
|
||||
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing
|
||||
if (root.isVertical) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0
|
||||
const relativeY = globalPos.y - screenY
|
||||
// Add minTooltipY offset to account for top bar
|
||||
const adjustedY = relativeY + root.minTooltipY
|
||||
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
|
||||
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge)
|
||||
} else {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const relativeX = globalPos.x - screenX
|
||||
const yPos = root.barThickness + root.barSpacing - 7
|
||||
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
windowContextMenuLoader.active = true;
|
||||
if (windowContextMenuLoader.item) {
|
||||
windowContextMenuLoader.item.currentWindow = toplevelObject;
|
||||
// Pass bar context
|
||||
windowContextMenuLoader.item.triggerBarConfig = root.barConfig;
|
||||
windowContextMenuLoader.item.triggerBarPosition = root.axis.edge === "left" ? 2 : (root.axis.edge === "right" ? 3 : (root.axis.edge === "top" ? 0 : 1));
|
||||
windowContextMenuLoader.item.triggerBarThickness = root.barThickness;
|
||||
windowContextMenuLoader.item.triggerBarSpacing = root.barSpacing;
|
||||
if (root.isVertical) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
const relativeY = globalPos.y - screenY;
|
||||
// Add minTooltipY offset to account for top bar
|
||||
const adjustedY = relativeY + root.minTooltipY;
|
||||
const xPos = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS);
|
||||
windowContextMenuLoader.item.showAt(xPos, adjustedY, true, root.axis?.edge);
|
||||
} else {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, 0);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const relativeX = globalPos.x - screenX;
|
||||
const yPos = root.barThickness + root.barSpacing - 7;
|
||||
windowContextMenuLoader.item.showAt(relativeX, yPos, false, "top");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
root.hoveredItem = delegateItem
|
||||
tooltipLoader.active = true
|
||||
root.hoveredItem = delegateItem;
|
||||
tooltipLoader.active = true;
|
||||
if (tooltipLoader.item) {
|
||||
if (root.isVertical) {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0
|
||||
const relativeY = globalPos.y - screenY
|
||||
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS)
|
||||
const isLeft = root.axis?.edge === "left"
|
||||
const adjustedY = relativeY + root.minTooltipY
|
||||
const finalX = screenX + tooltipX
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft)
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height / 2);
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0;
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0;
|
||||
const relativeY = globalPos.y - screenY;
|
||||
const tooltipX = root.axis?.edge === "left" ? (root.barThickness + root.barSpacing + Theme.spacingXS) : (root.parentScreen.width - root.barThickness - root.barSpacing - Theme.spacingXS);
|
||||
const isLeft = root.axis?.edge === "left";
|
||||
const adjustedY = relativeY + root.minTooltipY;
|
||||
const finalX = screenX + tooltipX;
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, finalX, adjustedY, root.parentScreen, isLeft, !isLeft);
|
||||
} else {
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height)
|
||||
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height
|
||||
const isBottom = root.axis?.edge === "bottom"
|
||||
const tooltipY = isBottom
|
||||
? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35)
|
||||
: (root.barThickness + root.barSpacing + Theme.spacingXS)
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
|
||||
const globalPos = delegateItem.mapToGlobal(delegateItem.width / 2, delegateItem.height);
|
||||
const screenHeight = root.parentScreen ? root.parentScreen.height : Screen.height;
|
||||
const isBottom = root.axis?.edge === "bottom";
|
||||
const tooltipY = isBottom ? (screenHeight - root.barThickness - root.barSpacing - Theme.spacingXS - 35) : (root.barThickness + root.barSpacing + Theme.spacingXS);
|
||||
tooltipLoader.item.show(delegateItem.tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (root.hoveredItem === delegateItem) {
|
||||
root.hoveredItem = null
|
||||
root.hoveredItem = null;
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
tooltipLoader.item.hide();
|
||||
}
|
||||
|
||||
tooltipLoader.active = false
|
||||
tooltipLoader.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -767,33 +771,39 @@ Item {
|
||||
|
||||
readonly property real effectiveBarThickness: {
|
||||
if (triggerBarThickness > 0 && triggerBarSpacing > 0) {
|
||||
return triggerBarThickness + triggerBarSpacing
|
||||
return triggerBarThickness + triggerBarSpacing;
|
||||
}
|
||||
return Math.max(26 + (barConfig?.innerPadding ?? 4) * 0.6, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))) + (barConfig?.spacing ?? 4)
|
||||
return Math.max(26 + (barConfig?.innerPadding ?? 4) * 0.6, Theme.barHeight - 4 - (8 - (barConfig?.innerPadding ?? 4))) + (barConfig?.spacing ?? 4);
|
||||
}
|
||||
|
||||
property var barBounds: {
|
||||
if (!contextMenuWindow.screen || !triggerBarConfig) {
|
||||
return { "x": 0, "y": 0, "width": 0, "height": 0, "wingSize": 0 }
|
||||
return {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"wingSize": 0
|
||||
};
|
||||
}
|
||||
return SettingsData.getBarBounds(contextMenuWindow.screen, effectiveBarThickness, triggerBarPosition, triggerBarConfig)
|
||||
return SettingsData.getBarBounds(contextMenuWindow.screen, effectiveBarThickness, triggerBarPosition, triggerBarConfig);
|
||||
}
|
||||
|
||||
property real barY: barBounds.y
|
||||
|
||||
function showAt(x, y, vertical, barEdge) {
|
||||
screen = root.parentScreen
|
||||
anchorPos = Qt.point(x, y)
|
||||
isVertical = vertical ?? false
|
||||
edge = barEdge ?? "top"
|
||||
isVisible = true
|
||||
visible = true
|
||||
screen = root.parentScreen;
|
||||
anchorPos = Qt.point(x, y);
|
||||
isVertical = vertical ?? false;
|
||||
edge = barEdge ?? "top";
|
||||
isVisible = true;
|
||||
visible = true;
|
||||
}
|
||||
|
||||
function close() {
|
||||
isVisible = false
|
||||
visible = false
|
||||
windowContextMenuLoader.active = false
|
||||
isVisible = false;
|
||||
visible = false;
|
||||
windowContextMenuLoader.active = false;
|
||||
}
|
||||
|
||||
implicitWidth: 100
|
||||
@@ -821,25 +831,25 @@ Item {
|
||||
x: {
|
||||
if (contextMenuWindow.isVertical) {
|
||||
if (contextMenuWindow.edge === "left") {
|
||||
return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x)
|
||||
return Math.min(contextMenuWindow.width - width - 10, contextMenuWindow.anchorPos.x);
|
||||
} else {
|
||||
return Math.max(10, contextMenuWindow.anchorPos.x - width)
|
||||
return Math.max(10, contextMenuWindow.anchorPos.x - width);
|
||||
}
|
||||
} else {
|
||||
const left = 10
|
||||
const right = contextMenuWindow.width - width - 10
|
||||
const want = contextMenuWindow.anchorPos.x - width / 2
|
||||
return Math.max(left, Math.min(right, want))
|
||||
const left = 10;
|
||||
const right = contextMenuWindow.width - width - 10;
|
||||
const want = contextMenuWindow.anchorPos.x - width / 2;
|
||||
return Math.max(left, Math.min(right, want));
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (contextMenuWindow.isVertical) {
|
||||
const top = Math.max(barY, 10)
|
||||
const bottom = contextMenuWindow.height - height - 10
|
||||
const want = contextMenuWindow.anchorPos.y - height / 2
|
||||
return Math.max(top, Math.min(bottom, want))
|
||||
const top = Math.max(barY, 10);
|
||||
const bottom = contextMenuWindow.height - height - 10;
|
||||
const want = contextMenuWindow.anchorPos.y - height / 2;
|
||||
return Math.max(top, Math.min(bottom, want));
|
||||
} else {
|
||||
return contextMenuWindow.anchorPos.y
|
||||
return contextMenuWindow.anchorPos.y;
|
||||
}
|
||||
}
|
||||
width: 100
|
||||
@@ -869,9 +879,9 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (contextMenuWindow.currentWindow) {
|
||||
contextMenuWindow.currentWindow.close()
|
||||
contextMenuWindow.currentWindow.close();
|
||||
}
|
||||
contextMenuWindow.close()
|
||||
contextMenuWindow.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +1,7 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Effects
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Hyprland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
@@ -32,11 +31,11 @@ Item {
|
||||
|
||||
function updateDesktopEntry() {
|
||||
if (!appData || appData.appId === "__SEPARATOR__") {
|
||||
cachedDesktopEntry = null
|
||||
return
|
||||
cachedDesktopEntry = null;
|
||||
return;
|
||||
}
|
||||
const moddedId = Paths.moddedAppId(appData.appId)
|
||||
cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId)
|
||||
const moddedId = Paths.moddedAppId(appData.appId);
|
||||
cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId);
|
||||
}
|
||||
|
||||
Component.onCompleted: updateDesktopEntry()
|
||||
@@ -46,80 +45,81 @@ Item {
|
||||
Connections {
|
||||
target: DesktopEntries
|
||||
function onApplicationsChanged() {
|
||||
updateDesktopEntry()
|
||||
updateDesktopEntry();
|
||||
}
|
||||
}
|
||||
property bool isWindowFocused: {
|
||||
if (!appData) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
if (appData.type === "window") {
|
||||
const toplevel = getToplevelObject()
|
||||
const toplevel = getToplevelObject();
|
||||
if (!toplevel) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
return toplevel.activated
|
||||
return toplevel.activated;
|
||||
} else if (appData.type === "grouped") {
|
||||
// For grouped apps, check if any window is focused
|
||||
const allToplevels = ToplevelManager.toplevels.values
|
||||
const allToplevels = ToplevelManager.toplevels.values;
|
||||
for (let i = 0; i < allToplevels.length; i++) {
|
||||
const toplevel = allToplevels[i]
|
||||
const toplevel = allToplevels[i];
|
||||
if (toplevel.appId === appData.appId && toplevel.activated) {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
property string tooltipText: {
|
||||
if (!appData) {
|
||||
return ""
|
||||
if (!appData || !appData.appId) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const appName = Paths.getAppName(appData.appId, cachedDesktopEntry);
|
||||
|
||||
if ((appData.type === "window" && showWindowTitle) || (appData.type === "grouped" && appData.windowTitle)) {
|
||||
const appName = cachedDesktopEntry && cachedDesktopEntry.name ? cachedDesktopEntry.name : appData.appId
|
||||
const title = appData.type === "window" ? windowTitle : appData.windowTitle
|
||||
return appName + (title ? " • " + title : "")
|
||||
const title = appData.type === "window" ? windowTitle : appData.windowTitle;
|
||||
return appName + (title ? " • " + title : "");
|
||||
}
|
||||
|
||||
if (!appData.appId) {
|
||||
return ""
|
||||
}
|
||||
|
||||
return cachedDesktopEntry && cachedDesktopEntry.name ? cachedDesktopEntry.name : appData.appId
|
||||
return appName;
|
||||
}
|
||||
|
||||
function getToplevelObject() {
|
||||
return appData?.toplevel || null
|
||||
return appData?.toplevel || null;
|
||||
}
|
||||
|
||||
function getGroupedToplevels() {
|
||||
return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || []
|
||||
return appData?.allWindows?.map(w => w.toplevel).filter(t => t !== null) || [];
|
||||
}
|
||||
onIsHoveredChanged: {
|
||||
if (mouseArea.pressed) return
|
||||
|
||||
if (mouseArea.pressed)
|
||||
return;
|
||||
if (isHovered) {
|
||||
exitAnimation.stop()
|
||||
exitAnimation.stop();
|
||||
if (!bounceAnimation.running) {
|
||||
bounceAnimation.restart()
|
||||
bounceAnimation.restart();
|
||||
}
|
||||
} else {
|
||||
bounceAnimation.stop()
|
||||
exitAnimation.restart()
|
||||
bounceAnimation.stop();
|
||||
exitAnimation.restart();
|
||||
}
|
||||
}
|
||||
|
||||
readonly property bool animateX: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
readonly property real animationDistance: actualIconSize
|
||||
readonly property real animationDirection: {
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom) return -1
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Top) return 1
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) return -1
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Left) return 1
|
||||
return -1
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom)
|
||||
return -1;
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Top)
|
||||
return 1;
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right)
|
||||
return -1;
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Left)
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
SequentialAnimation {
|
||||
@@ -165,7 +165,7 @@ Item {
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
if (appData && appData.isPinned) {
|
||||
longPressing = true
|
||||
longPressing = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -180,134 +180,137 @@ Item {
|
||||
cursorShape: longPressing ? Qt.DragMoveCursor : Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||
onPressed: mouse => {
|
||||
if (mouse.button === Qt.LeftButton && appData && appData.isPinned) {
|
||||
dragStartPos = Qt.point(mouse.x, mouse.y)
|
||||
longPressTimer.start()
|
||||
}
|
||||
}
|
||||
if (mouse.button === Qt.LeftButton && appData && appData.isPinned) {
|
||||
dragStartPos = Qt.point(mouse.x, mouse.y);
|
||||
longPressTimer.start();
|
||||
}
|
||||
}
|
||||
onReleased: mouse => {
|
||||
longPressTimer.stop()
|
||||
if (longPressing) {
|
||||
if (dragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps) {
|
||||
dockApps.movePinnedApp(originalIndex, targetIndex)
|
||||
}
|
||||
longPressTimer.stop();
|
||||
if (longPressing) {
|
||||
if (dragging && targetIndex >= 0 && targetIndex !== originalIndex && dockApps) {
|
||||
dockApps.movePinnedApp(originalIndex, targetIndex);
|
||||
}
|
||||
|
||||
longPressing = false
|
||||
dragging = false
|
||||
dragOffset = Qt.point(0, 0)
|
||||
targetIndex = -1
|
||||
originalIndex = -1
|
||||
longPressing = false;
|
||||
dragging = false;
|
||||
dragOffset = Qt.point(0, 0);
|
||||
targetIndex = -1;
|
||||
originalIndex = -1;
|
||||
}
|
||||
}
|
||||
onPositionChanged: mouse => {
|
||||
if (longPressing && !dragging) {
|
||||
const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2));
|
||||
if (distance > 5) {
|
||||
dragging = true;
|
||||
targetIndex = index;
|
||||
originalIndex = index;
|
||||
}
|
||||
}
|
||||
if (dragging) {
|
||||
dragOffset = Qt.point(mouse.x - dragStartPos.x, mouse.y - dragStartPos.y);
|
||||
if (dockApps) {
|
||||
const threshold = actualIconSize;
|
||||
let newTargetIndex = targetIndex;
|
||||
if (dragOffset.x > threshold && targetIndex < dockApps.pinnedAppCount - 1) {
|
||||
newTargetIndex = targetIndex + 1;
|
||||
} else if (dragOffset.x < -threshold && targetIndex > 0) {
|
||||
newTargetIndex = targetIndex - 1;
|
||||
}
|
||||
if (newTargetIndex !== targetIndex) {
|
||||
targetIndex = newTargetIndex;
|
||||
dragStartPos = Qt.point(mouse.x, mouse.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (!appData || longPressing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (appData.type === "pinned") {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry;
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry);
|
||||
}
|
||||
} else if (appData.type === "window") {
|
||||
const toplevel = getToplevelObject();
|
||||
if (toplevel) {
|
||||
toplevel.activate();
|
||||
}
|
||||
} else if (appData.type === "grouped") {
|
||||
if (appData.windowCount === 0) {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry;
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry);
|
||||
}
|
||||
} else if (appData.windowCount === 1) {
|
||||
// For single window, activate directly
|
||||
const toplevel = getToplevelObject();
|
||||
if (toplevel) {
|
||||
console.log("Activating grouped app window:", appData.windowTitle);
|
||||
toplevel.activate();
|
||||
} else {
|
||||
console.warn("No toplevel found for grouped app");
|
||||
}
|
||||
} else {
|
||||
if (contextMenu) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height + 25, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
}
|
||||
}
|
||||
onPositionChanged: mouse => {
|
||||
if (longPressing && !dragging) {
|
||||
const distance = Math.sqrt(Math.pow(mouse.x - dragStartPos.x, 2) + Math.pow(mouse.y - dragStartPos.y, 2))
|
||||
if (distance > 5) {
|
||||
dragging = true
|
||||
targetIndex = index
|
||||
originalIndex = index
|
||||
}
|
||||
}
|
||||
if (dragging) {
|
||||
dragOffset = Qt.point(mouse.x - dragStartPos.x, mouse.y - dragStartPos.y)
|
||||
if (dockApps) {
|
||||
const threshold = actualIconSize
|
||||
let newTargetIndex = targetIndex
|
||||
if (dragOffset.x > threshold && targetIndex < dockApps.pinnedAppCount - 1) {
|
||||
newTargetIndex = targetIndex + 1
|
||||
} else if (dragOffset.x < -threshold && targetIndex > 0) {
|
||||
newTargetIndex = targetIndex - 1
|
||||
}
|
||||
if (newTargetIndex !== targetIndex) {
|
||||
targetIndex = newTargetIndex
|
||||
dragStartPos = Qt.point(mouse.x, mouse.y)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onClicked: mouse => {
|
||||
if (!appData || longPressing) {
|
||||
return
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (appData.type === "pinned") {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
})
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry)
|
||||
}
|
||||
} else if (appData.type === "window") {
|
||||
const toplevel = getToplevelObject()
|
||||
if (toplevel) {
|
||||
toplevel.activate()
|
||||
}
|
||||
} else if (appData.type === "grouped") {
|
||||
if (appData.windowCount === 0) {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
})
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry)
|
||||
}
|
||||
} else if (appData.windowCount === 1) {
|
||||
// For single window, activate directly
|
||||
const toplevel = getToplevelObject()
|
||||
if (toplevel) {
|
||||
console.log("Activating grouped app window:", appData.windowTitle)
|
||||
toplevel.activate()
|
||||
} else {
|
||||
console.warn("No toplevel found for grouped app")
|
||||
}
|
||||
} else {
|
||||
if (contextMenu) {
|
||||
contextMenu.showForButton(root, appData, root.height + 25, true, cachedDesktopEntry, parentDockScreen)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
if (appData?.type === "window") {
|
||||
appData?.toplevel?.close()
|
||||
} else if (appData?.type === "grouped") {
|
||||
if (contextMenu) {
|
||||
contextMenu.showForButton(root, appData, root.height, false, cachedDesktopEntry, parentDockScreen)
|
||||
}
|
||||
} else if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
})
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry)
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (contextMenu && appData) {
|
||||
contextMenu.showForButton(root, appData, root.height, false, cachedDesktopEntry, parentDockScreen)
|
||||
} else {
|
||||
console.warn("No context menu or appData available")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
if (appData?.type === "window") {
|
||||
appData?.toplevel?.close();
|
||||
} else if (appData?.type === "grouped") {
|
||||
if (contextMenu) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
}
|
||||
} else if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry;
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
"name": desktopEntry.name || appData.appId,
|
||||
"icon": desktopEntry.icon || "",
|
||||
"exec": desktopEntry.exec || "",
|
||||
"comment": desktopEntry.comment || ""
|
||||
});
|
||||
}
|
||||
SessionService.launchDesktopEntry(desktopEntry);
|
||||
}
|
||||
} else if (mouse.button === Qt.RightButton) {
|
||||
if (contextMenu && appData) {
|
||||
const shouldHidePin = appData.appId === "org.quickshell";
|
||||
contextMenu.showForButton(root, appData, root.height, shouldHidePin, cachedDesktopEntry, parentDockScreen);
|
||||
} else {
|
||||
console.warn("No context menu or appData available");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -334,21 +337,25 @@ Item {
|
||||
id: iconImg
|
||||
|
||||
anchors.centerIn: parent
|
||||
implicitSize: actualIconSize
|
||||
implicitSize: appData && appData.appId === "org.quickshell" ? actualIconSize * 0.85 : actualIconSize
|
||||
source: {
|
||||
if (appData.appId === "__SEPARATOR__") {
|
||||
return ""
|
||||
if (!appData || appData.appId === "__SEPARATOR__") {
|
||||
return "";
|
||||
}
|
||||
const moddedId = Paths.moddedAppId(appData.appId)
|
||||
if (moddedId.toLowerCase().includes("steam_app")) {
|
||||
return ""
|
||||
}
|
||||
return cachedDesktopEntry && cachedDesktopEntry.icon ? Quickshell.iconPath(cachedDesktopEntry.icon, true) : ""
|
||||
return Paths.getAppIcon(appData.appId, cachedDesktopEntry);
|
||||
}
|
||||
mipmap: true
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
visible: status === Image.Ready
|
||||
layer.enabled: appData && appData.appId === "org.quickshell"
|
||||
layer.smooth: true
|
||||
layer.mipmap: true
|
||||
layer.effect: MultiEffect {
|
||||
saturation: 0
|
||||
colorization: 1
|
||||
colorizationColor: Theme.primary
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
@@ -358,10 +365,10 @@ Item {
|
||||
color: Theme.surfaceText
|
||||
visible: {
|
||||
if (!appData || !appData.appId || appData.appId === "__SEPARATOR__") {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
const moddedId = Paths.moddedAppId(appData.appId)
|
||||
return moddedId.toLowerCase().includes("steam_app")
|
||||
const moddedId = Paths.moddedAppId(appData.appId);
|
||||
return moddedId.toLowerCase().includes("steam_app");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,15 +386,11 @@ Item {
|
||||
anchors.centerIn: parent
|
||||
text: {
|
||||
if (!appData || !appData.appId) {
|
||||
return "?"
|
||||
return "?";
|
||||
}
|
||||
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
if (desktopEntry && desktopEntry.name) {
|
||||
return desktopEntry.name.charAt(0).toUpperCase()
|
||||
}
|
||||
|
||||
return appData.appId.charAt(0).toUpperCase()
|
||||
const appName = Paths.getAppName(appData.appId, cachedDesktopEntry);
|
||||
return appName.charAt(0).toUpperCase();
|
||||
}
|
||||
font.pixelSize: Math.max(8, parent.width * 0.35)
|
||||
color: Theme.primary
|
||||
@@ -410,10 +413,13 @@ Item {
|
||||
sourceComponent: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right ? columnIndicator : rowIndicator
|
||||
|
||||
visible: {
|
||||
if (!appData) return false
|
||||
if (appData.type === "window") return true
|
||||
if (appData.type === "grouped") return appData.windowCount > 0
|
||||
return appData.isRunning
|
||||
if (!appData)
|
||||
return false;
|
||||
if (appData.type === "window")
|
||||
return true;
|
||||
if (appData.type === "grouped")
|
||||
return appData.windowCount > 0;
|
||||
return appData.isRunning;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,49 +432,50 @@ Item {
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!appData) return 0
|
||||
if (!appData)
|
||||
return 0;
|
||||
if (appData.type === "grouped") {
|
||||
return Math.min(appData.windowCount, 4)
|
||||
return Math.min(appData.windowCount, 4);
|
||||
} else if (appData.type === "window" || appData.isRunning) {
|
||||
return 1
|
||||
return 1;
|
||||
}
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: {
|
||||
if (SettingsData.dockIndicatorStyle === "circle") {
|
||||
return Math.max(4, actualIconSize * 0.1)
|
||||
return Math.max(4, actualIconSize * 0.1);
|
||||
}
|
||||
return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2)
|
||||
return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2);
|
||||
}
|
||||
height: {
|
||||
if (SettingsData.dockIndicatorStyle === "circle") {
|
||||
return Math.max(4, actualIconSize * 0.1)
|
||||
return Math.max(4, actualIconSize * 0.1);
|
||||
}
|
||||
return Math.max(2, actualIconSize * 0.05)
|
||||
return Math.max(2, actualIconSize * 0.05);
|
||||
}
|
||||
radius: SettingsData.dockIndicatorStyle === "circle" ? width / 2 : Theme.cornerRadius
|
||||
color: {
|
||||
if (!appData) {
|
||||
return "transparent"
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
if (appData.type !== "grouped" || appData.windowCount === 1) {
|
||||
if (isWindowFocused) {
|
||||
return Theme.primary
|
||||
return Theme.primary;
|
||||
}
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6);
|
||||
}
|
||||
|
||||
if (appData.type === "grouped" && appData.windowCount > 1) {
|
||||
const groupToplevels = getGroupedToplevels()
|
||||
const groupToplevels = getGroupedToplevels();
|
||||
if (index < groupToplevels.length && groupToplevels[index].activated) {
|
||||
return Theme.primary
|
||||
return Theme.primary;
|
||||
}
|
||||
}
|
||||
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -483,49 +490,50 @@ Item {
|
||||
|
||||
Repeater {
|
||||
model: {
|
||||
if (!appData) return 0
|
||||
if (!appData)
|
||||
return 0;
|
||||
if (appData.type === "grouped") {
|
||||
return Math.min(appData.windowCount, 4)
|
||||
return Math.min(appData.windowCount, 4);
|
||||
} else if (appData.type === "window" || appData.isRunning) {
|
||||
return 1
|
||||
return 1;
|
||||
}
|
||||
return 0
|
||||
return 0;
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: {
|
||||
if (SettingsData.dockIndicatorStyle === "circle") {
|
||||
return Math.max(4, actualIconSize * 0.1)
|
||||
return Math.max(4, actualIconSize * 0.1);
|
||||
}
|
||||
return Math.max(2, actualIconSize * 0.05)
|
||||
return Math.max(2, actualIconSize * 0.05);
|
||||
}
|
||||
height: {
|
||||
if (SettingsData.dockIndicatorStyle === "circle") {
|
||||
return Math.max(4, actualIconSize * 0.1)
|
||||
return Math.max(4, actualIconSize * 0.1);
|
||||
}
|
||||
return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2)
|
||||
return appData && appData.type === "grouped" && appData.windowCount > 1 ? Math.max(3, actualIconSize * 0.1) : Math.max(6, actualIconSize * 0.2);
|
||||
}
|
||||
radius: SettingsData.dockIndicatorStyle === "circle" ? width / 2 : Theme.cornerRadius
|
||||
color: {
|
||||
if (!appData) {
|
||||
return "transparent"
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
if (appData.type !== "grouped" || appData.windowCount === 1) {
|
||||
if (isWindowFocused) {
|
||||
return Theme.primary
|
||||
return Theme.primary;
|
||||
}
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6);
|
||||
}
|
||||
|
||||
if (appData.type === "grouped" && appData.windowCount > 1) {
|
||||
const groupToplevels = getGroupedToplevels()
|
||||
const groupToplevels = getGroupedToplevels();
|
||||
if (index < groupToplevels.length && groupToplevels[index].activated) {
|
||||
return Theme.primary
|
||||
return Theme.primary;
|
||||
}
|
||||
}
|
||||
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||
return Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ PanelWindow {
|
||||
property int margin: 10
|
||||
property bool hidePin: false
|
||||
property var desktopEntry: null
|
||||
property bool isDmsWindow: appData?.appId === "org.quickshell"
|
||||
|
||||
function showForButton(button, data, dockHeight, hidePinOption, entry, dockScreen) {
|
||||
if (dockScreen) {
|
||||
@@ -351,7 +352,12 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.desktopEntry && root.desktopEntry.actions && root.desktopEntry.actions.length > 0
|
||||
visible: {
|
||||
if (!root.desktopEntry?.actions || root.desktopEntry.actions.length === 0) {
|
||||
return false
|
||||
}
|
||||
return !root.hidePin || (!root.isDmsWindow && root.desktopEntry && SessionService.hasPrimeRun)
|
||||
}
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
@@ -398,14 +404,20 @@ PanelWindow {
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: (root.appData && root.appData.type === "window") || (root.desktopEntry && SessionService.hasPrimeRun)
|
||||
visible: {
|
||||
const hasPrimeRun = !root.isDmsWindow && root.desktopEntry && SessionService.hasPrimeRun
|
||||
const hasWindow = root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0))
|
||||
const hasPinOption = !root.hidePin
|
||||
const hasContentAbove = hasPinOption || hasPrimeRun
|
||||
return hasContentAbove && hasWindow
|
||||
}
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.desktopEntry && SessionService.hasPrimeRun
|
||||
visible: !root.isDmsWindow && root.desktopEntry && SessionService.hasPrimeRun
|
||||
width: parent.width
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
@@ -439,13 +451,6 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0))
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: root.appData && (root.appData.type === "window" || (root.appData.type === "grouped" && root.appData.windowCount > 0))
|
||||
width: parent.width
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
@@ -13,6 +12,10 @@ Item {
|
||||
width: parent.width
|
||||
height: 32
|
||||
|
||||
DankTooltipV2 {
|
||||
id: sharedTooltip
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -35,17 +38,10 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
||||
onEntered: {
|
||||
tooltipLoader.active = true
|
||||
if (tooltipLoader.item) {
|
||||
const p = mapToItem(null, width / 2, 0)
|
||||
tooltipLoader.item.show(I18n.tr("Do Not Disturb"), p.x, p.y - 40, null)
|
||||
}
|
||||
sharedTooltip.show(I18n.tr("Do Not Disturb"), doNotDisturbButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +60,7 @@ Item {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
onClicked: {
|
||||
if (keyboardController) {
|
||||
keyboardController.showKeyboardHints = !keyboardController.showKeyboardHints
|
||||
keyboardController.showKeyboardHints = !keyboardController.showKeyboardHints;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -115,14 +111,6 @@ Item {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: NotificationService.clearAllNotifications()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: tooltipLoader
|
||||
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,33 +7,36 @@ import qs.Widgets
|
||||
DankOSD {
|
||||
id: root
|
||||
|
||||
property int currentProfile: 0
|
||||
property string profileIcon: "settings"
|
||||
|
||||
osdWidth: Theme.iconSize + Theme.spacingS * 2
|
||||
osdHeight: Theme.iconSize + Theme.spacingS * 2
|
||||
autoHideInterval: 2000
|
||||
enableMouseInteraction: false
|
||||
|
||||
property int lastProfile: -1
|
||||
|
||||
Connections {
|
||||
target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null
|
||||
target: PowerProfileWatcher
|
||||
|
||||
function onProfileChanged() {
|
||||
if (lastProfile !== -1 && lastProfile !== PowerProfiles.profile && SettingsData.osdPowerProfileEnabled) {
|
||||
root.show()
|
||||
function onProfileChanged(profile) {
|
||||
if (SettingsData.osdPowerProfileEnabled) {
|
||||
root.currentProfile = profile;
|
||||
root.profileIcon = Theme.getPowerProfileIcon(profile);
|
||||
root.show();
|
||||
}
|
||||
lastProfile = PowerProfiles.profile
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (typeof PowerProfiles !== "undefined") {
|
||||
lastProfile = PowerProfiles.profile
|
||||
if (SettingsData.osdPowerProfileEnabled && typeof PowerProfileWatcher !== "undefined") {
|
||||
root.currentProfile = PowerProfileWatcher.currentProfile;
|
||||
root.profileIcon = Theme.getPowerProfileIcon(PowerProfileWatcher.currentProfile);
|
||||
}
|
||||
}
|
||||
|
||||
content: DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: typeof PowerProfiles !== "undefined" ? Theme.getPowerProfileIcon(PowerProfiles.profile) : "settings"
|
||||
name: root.profileIcon
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
}
|
||||
|
||||
@@ -11,6 +11,10 @@ Item {
|
||||
property var parentModal: null
|
||||
property string selectedBarId: "default"
|
||||
|
||||
DankTooltipV2 {
|
||||
id: sharedTooltip
|
||||
}
|
||||
|
||||
property var selectedBarConfig: {
|
||||
selectedBarId;
|
||||
SettingsData.barConfigs;
|
||||
@@ -49,6 +53,120 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: edgeSpacingDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 4
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
spacing: pendingValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: exclusiveZoneDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 0
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
bottomGap: pendingValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: sizeDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 4
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
innerPadding: pendingValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: popupGapsManualDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 4
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
popupGapsManual: pendingValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: gothCornerRadiusDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 12
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
gothCornerRadiusValue: pendingValue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: borderOpacityDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 1.0
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
borderOpacity: pendingValue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: borderThicknessDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 1
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
borderThickness: pendingValue
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: barTransparencyDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 1.0
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
transparency: pendingValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: widgetTransparencyDebounce
|
||||
interval: 100
|
||||
repeat: false
|
||||
property real pendingValue: 1.0
|
||||
onTriggered: {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
widgetTransparency: pendingValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
// ! Hacky workaround because we want to re-register any vertical bars after changing a hBar
|
||||
// ! That allows them to re-make with the right exclusiveZone
|
||||
function notifyHorizontalBarChange() {
|
||||
@@ -1706,10 +1824,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
spacing: newValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
edgeSpacingDebounce.pendingValue = newValue;
|
||||
edgeSpacingDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -1782,10 +1898,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
bottomGap: newValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
exclusiveZoneDebounce.pendingValue = newValue;
|
||||
exclusiveZoneDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -1858,10 +1972,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
innerPadding: newValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
sizeDebounce.pendingValue = newValue;
|
||||
sizeDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -1964,10 +2076,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
popupGapsManual: newValue
|
||||
});
|
||||
notifyHorizontalBarChange();
|
||||
popupGapsManualDebounce.pendingValue = newValue;
|
||||
popupGapsManualDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -2096,9 +2206,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
gothCornerRadiusValue: newValue
|
||||
});
|
||||
gothCornerRadiusDebounce.pendingValue = newValue;
|
||||
gothCornerRadiusDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -2263,9 +2372,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
borderOpacity: newValue / 100
|
||||
});
|
||||
borderOpacityDebounce.pendingValue = newValue / 100;
|
||||
borderOpacityDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -2338,9 +2446,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
borderThickness: newValue
|
||||
});
|
||||
borderThicknessDebounce.pendingValue = newValue;
|
||||
borderThicknessDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -2422,10 +2529,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
transparency: newValue / 100
|
||||
});
|
||||
notifyHorizontalBarChange()
|
||||
barTransparencyDebounce.pendingValue = newValue / 100;
|
||||
barTransparencyDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -2477,7 +2582,7 @@ Item {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
widgetTransparency: 1.0
|
||||
});
|
||||
notifyHorizontalBarChange()
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2499,10 +2604,8 @@ Item {
|
||||
wheelEnabled: false
|
||||
thumbOutlineColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
onSliderValueChanged: newValue => {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
widgetTransparency: newValue / 100
|
||||
});
|
||||
notifyHorizontalBarChange()
|
||||
widgetTransparencyDebounce.pendingValue = newValue / 100;
|
||||
widgetTransparencyDebounce.restart();
|
||||
}
|
||||
|
||||
Binding {
|
||||
@@ -2573,7 +2676,7 @@ Item {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
fontScale: newScale
|
||||
});
|
||||
notifyHorizontalBarChange()
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2607,7 +2710,7 @@ Item {
|
||||
SettingsData.updateBarConfig(selectedBarId, {
|
||||
fontScale: newScale
|
||||
});
|
||||
notifyHorizontalBarChange()
|
||||
notifyHorizontalBarChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Modals.Common
|
||||
@@ -18,108 +17,108 @@ DankModal {
|
||||
property bool isLoading: false
|
||||
property var parentModal: null
|
||||
|
||||
width: 600
|
||||
height: 650
|
||||
modalWidth: 600
|
||||
modalHeight: 650
|
||||
allowStacking: true
|
||||
backgroundOpacity: 0
|
||||
closeOnEscapeKey: false
|
||||
|
||||
function updateFilteredPlugins() {
|
||||
var filtered = []
|
||||
var query = searchQuery ? searchQuery.toLowerCase() : ""
|
||||
var filtered = [];
|
||||
var query = searchQuery ? searchQuery.toLowerCase() : "";
|
||||
|
||||
for (var i = 0; i < allPlugins.length; i++) {
|
||||
var plugin = allPlugins[i]
|
||||
var isFirstParty = plugin.firstParty || false
|
||||
var plugin = allPlugins[i];
|
||||
var isFirstParty = plugin.firstParty || false;
|
||||
|
||||
if (!SessionData.showThirdPartyPlugins && !isFirstParty) {
|
||||
continue
|
||||
continue;
|
||||
}
|
||||
|
||||
if (query.length > 0) {
|
||||
var name = plugin.name ? plugin.name.toLowerCase() : ""
|
||||
var description = plugin.description ? plugin.description.toLowerCase() : ""
|
||||
var author = plugin.author ? plugin.author.toLowerCase() : ""
|
||||
var name = plugin.name ? plugin.name.toLowerCase() : "";
|
||||
var description = plugin.description ? plugin.description.toLowerCase() : "";
|
||||
var author = plugin.author ? plugin.author.toLowerCase() : "";
|
||||
|
||||
if (name.indexOf(query) !== -1 ||
|
||||
description.indexOf(query) !== -1 ||
|
||||
author.indexOf(query) !== -1) {
|
||||
filtered.push(plugin)
|
||||
if (name.indexOf(query) !== -1 || description.indexOf(query) !== -1 || author.indexOf(query) !== -1) {
|
||||
filtered.push(plugin);
|
||||
}
|
||||
} else {
|
||||
filtered.push(plugin)
|
||||
filtered.push(plugin);
|
||||
}
|
||||
}
|
||||
|
||||
filteredPlugins = filtered
|
||||
selectedIndex = -1
|
||||
keyboardNavigationActive = false
|
||||
filteredPlugins = filtered;
|
||||
selectedIndex = -1;
|
||||
keyboardNavigationActive = false;
|
||||
}
|
||||
|
||||
function selectNext() {
|
||||
if (filteredPlugins.length === 0) return
|
||||
keyboardNavigationActive = true
|
||||
selectedIndex = Math.min(selectedIndex + 1, filteredPlugins.length - 1)
|
||||
if (filteredPlugins.length === 0)
|
||||
return;
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = Math.min(selectedIndex + 1, filteredPlugins.length - 1);
|
||||
}
|
||||
|
||||
function selectPrevious() {
|
||||
if (filteredPlugins.length === 0) return
|
||||
keyboardNavigationActive = true
|
||||
selectedIndex = Math.max(selectedIndex - 1, -1)
|
||||
if (filteredPlugins.length === 0)
|
||||
return;
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = Math.max(selectedIndex - 1, -1);
|
||||
if (selectedIndex === -1) {
|
||||
keyboardNavigationActive = false
|
||||
keyboardNavigationActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
function installPlugin(pluginName) {
|
||||
ToastService.showInfo("Installing plugin: " + pluginName)
|
||||
ToastService.showInfo("Installing plugin: " + pluginName);
|
||||
DMSService.install(pluginName, response => {
|
||||
if (response.error) {
|
||||
ToastService.showError("Install failed: " + response.error)
|
||||
ToastService.showError("Install failed: " + response.error);
|
||||
} else {
|
||||
ToastService.showInfo("Plugin installed: " + pluginName)
|
||||
PluginService.scanPlugins()
|
||||
refreshPlugins()
|
||||
ToastService.showInfo("Plugin installed: " + pluginName);
|
||||
PluginService.scanPlugins();
|
||||
refreshPlugins();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function refreshPlugins() {
|
||||
isLoading = true
|
||||
DMSService.listPlugins()
|
||||
isLoading = true;
|
||||
DMSService.listPlugins();
|
||||
if (DMSService.apiVersion >= 8) {
|
||||
DMSService.listInstalled()
|
||||
DMSService.listInstalled();
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
if (parentModal) {
|
||||
parentModal.shouldHaveFocus = false
|
||||
parentModal.shouldHaveFocus = false;
|
||||
}
|
||||
open()
|
||||
open();
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.searchField) {
|
||||
contentLoader.item.searchField.forceActiveFocus()
|
||||
contentLoader.item.searchField.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function hide() {
|
||||
close()
|
||||
close();
|
||||
if (parentModal) {
|
||||
parentModal.shouldHaveFocus = Qt.binding(() => {
|
||||
return parentModal.shouldBeVisible
|
||||
})
|
||||
return parentModal.shouldBeVisible;
|
||||
});
|
||||
Qt.callLater(() => {
|
||||
if (parentModal.modalFocusScope) {
|
||||
parentModal.modalFocusScope.forceActiveFocus()
|
||||
parentModal.modalFocusScope.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onOpened: {
|
||||
refreshPlugins()
|
||||
refreshPlugins();
|
||||
}
|
||||
|
||||
Connections {
|
||||
@@ -127,23 +126,23 @@ DankModal {
|
||||
function onLoaded() {
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.searchField) {
|
||||
contentLoader.item.searchField.forceActiveFocus()
|
||||
contentLoader.item.searchField.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onDialogClosed: () => {
|
||||
allPlugins = []
|
||||
searchQuery = ""
|
||||
filteredPlugins = []
|
||||
selectedIndex = -1
|
||||
keyboardNavigationActive = false
|
||||
isLoading = false
|
||||
allPlugins = [];
|
||||
searchQuery = "";
|
||||
filteredPlugins = [];
|
||||
selectedIndex = -1;
|
||||
keyboardNavigationActive = false;
|
||||
isLoading = false;
|
||||
}
|
||||
|
||||
onBackgroundClicked: () => {
|
||||
hide()
|
||||
hide();
|
||||
}
|
||||
|
||||
content: Component {
|
||||
@@ -155,19 +154,19 @@ DankModal {
|
||||
focus: true
|
||||
|
||||
Component.onCompleted: {
|
||||
browserSearchField.forceActiveFocus()
|
||||
browserSearchField.forceActiveFocus();
|
||||
}
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.selectNext()
|
||||
event.accepted = true
|
||||
root.selectNext();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
root.selectPrevious();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,10 +214,10 @@ DankModal {
|
||||
height: 28
|
||||
onClicked: {
|
||||
if (SessionData.showThirdPartyPlugins) {
|
||||
SessionData.setShowThirdPartyPlugins(false)
|
||||
root.updateFilteredPlugins()
|
||||
SessionData.setShowThirdPartyPlugins(false);
|
||||
root.updateFilteredPlugins();
|
||||
} else {
|
||||
thirdPartyConfirmModal.open()
|
||||
thirdPartyConfirmModal.open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,8 +277,8 @@ DankModal {
|
||||
ignoreLeftRightKeys: true
|
||||
keyForwardTargets: [browserKeyHandler]
|
||||
onTextEdited: {
|
||||
root.searchQuery = text
|
||||
root.updateFilteredPlugins()
|
||||
root.searchQuery = text;
|
||||
root.updateFilteredPlugins();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -350,13 +349,8 @@ DankModal {
|
||||
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
|
||||
property bool isInstalled: modelData.installed || false
|
||||
property bool isFirstParty: modelData.firstParty || false
|
||||
color: isSelected ? Theme.primarySelected :
|
||||
Qt.rgba(Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.3)
|
||||
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
color: isSelected ? Theme.primarySelected : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: isSelected ? 2 : 1
|
||||
|
||||
Column {
|
||||
@@ -435,9 +429,9 @@ DankModal {
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const author = "by " + (modelData.author || "Unknown")
|
||||
const source = modelData.repo ? ` • <a href="${modelData.repo}" style="text-decoration:none; color:${Theme.primary};">source</a>` : ""
|
||||
return author + source
|
||||
const author = "by " + (modelData.author || "Unknown");
|
||||
const source = modelData.repo ? ` • <a href="${modelData.repo}" style="text-decoration:none; color:${Theme.primary};">source</a>` : "";
|
||||
return author + source;
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
@@ -502,7 +496,7 @@ DankModal {
|
||||
enabled: !isInstalled
|
||||
onClicked: {
|
||||
if (!isInstalled) {
|
||||
root.installPlugin(modelData.name)
|
||||
root.installPlugin(modelData.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -563,8 +557,8 @@ DankModal {
|
||||
DankModal {
|
||||
id: thirdPartyConfirmModal
|
||||
|
||||
width: 500
|
||||
height: 300
|
||||
modalWidth: 500
|
||||
modalHeight: 300
|
||||
allowStacking: true
|
||||
backgroundOpacity: 0.4
|
||||
closeOnEscapeKey: true
|
||||
@@ -576,8 +570,8 @@ DankModal {
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
thirdPartyConfirmModal.close()
|
||||
event.accepted = true
|
||||
thirdPartyConfirmModal.close();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -656,9 +650,9 @@ DankModal {
|
||||
text: I18n.tr("I Understand")
|
||||
iconName: "check"
|
||||
onClicked: {
|
||||
SessionData.setShowThirdPartyPlugins(true)
|
||||
root.updateFilteredPlugins()
|
||||
thirdPartyConfirmModal.close()
|
||||
SessionData.setShowThirdPartyPlugins(true);
|
||||
root.updateFilteredPlugins();
|
||||
thirdPartyConfirmModal.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,327 +20,318 @@ DankModal {
|
||||
|
||||
function updateFilteredWidgets() {
|
||||
if (!searchQuery || searchQuery.length === 0) {
|
||||
filteredWidgets = allWidgets.slice()
|
||||
return
|
||||
filteredWidgets = allWidgets.slice();
|
||||
return;
|
||||
}
|
||||
|
||||
var filtered = []
|
||||
var query = searchQuery.toLowerCase()
|
||||
var filtered = [];
|
||||
var query = searchQuery.toLowerCase();
|
||||
|
||||
for (var i = 0; i < allWidgets.length; i++) {
|
||||
var widget = allWidgets[i]
|
||||
var text = widget.text ? widget.text.toLowerCase() : ""
|
||||
var description = widget.description ? widget.description.toLowerCase() : ""
|
||||
var id = widget.id ? widget.id.toLowerCase() : ""
|
||||
var widget = allWidgets[i];
|
||||
var text = widget.text ? widget.text.toLowerCase() : "";
|
||||
var description = widget.description ? widget.description.toLowerCase() : "";
|
||||
var id = widget.id ? widget.id.toLowerCase() : "";
|
||||
|
||||
if (text.indexOf(query) !== -1 ||
|
||||
description.indexOf(query) !== -1 ||
|
||||
id.indexOf(query) !== -1) {
|
||||
filtered.push(widget)
|
||||
if (text.indexOf(query) !== -1 || description.indexOf(query) !== -1 || id.indexOf(query) !== -1) {
|
||||
filtered.push(widget);
|
||||
}
|
||||
}
|
||||
|
||||
filteredWidgets = filtered
|
||||
selectedIndex = -1
|
||||
keyboardNavigationActive = false
|
||||
filteredWidgets = filtered;
|
||||
selectedIndex = -1;
|
||||
keyboardNavigationActive = false;
|
||||
}
|
||||
|
||||
onAllWidgetsChanged: {
|
||||
updateFilteredWidgets()
|
||||
updateFilteredWidgets();
|
||||
}
|
||||
|
||||
function selectNext() {
|
||||
if (filteredWidgets.length === 0) return
|
||||
keyboardNavigationActive = true
|
||||
selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1)
|
||||
if (filteredWidgets.length === 0)
|
||||
return;
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = Math.min(selectedIndex + 1, filteredWidgets.length - 1);
|
||||
}
|
||||
|
||||
function selectPrevious() {
|
||||
if (filteredWidgets.length === 0) return
|
||||
keyboardNavigationActive = true
|
||||
selectedIndex = Math.max(selectedIndex - 1, -1)
|
||||
if (filteredWidgets.length === 0)
|
||||
return;
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = Math.max(selectedIndex - 1, -1);
|
||||
if (selectedIndex === -1) {
|
||||
keyboardNavigationActive = false
|
||||
keyboardNavigationActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
function selectWidget() {
|
||||
if (selectedIndex >= 0 && selectedIndex < filteredWidgets.length) {
|
||||
var widget = filteredWidgets[selectedIndex]
|
||||
root.widgetSelected(widget.id, root.targetSection)
|
||||
root.close()
|
||||
var widget = filteredWidgets[selectedIndex];
|
||||
root.widgetSelected(widget.id, root.targetSection);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
|
||||
function show() {
|
||||
if (parentModal) {
|
||||
parentModal.shouldHaveFocus = false
|
||||
parentModal.shouldHaveFocus = false;
|
||||
}
|
||||
open()
|
||||
open();
|
||||
Qt.callLater(() => {
|
||||
if (contentLoader.item && contentLoader.item.searchField) {
|
||||
contentLoader.item.searchField.forceActiveFocus()
|
||||
contentLoader.item.searchField.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
function hide() {
|
||||
close()
|
||||
close();
|
||||
if (parentModal) {
|
||||
parentModal.shouldHaveFocus = Qt.binding(() => {
|
||||
return parentModal.shouldBeVisible
|
||||
})
|
||||
return parentModal.shouldBeVisible;
|
||||
});
|
||||
Qt.callLater(() => {
|
||||
if (parentModal && parentModal.modalFocusScope) {
|
||||
parentModal.modalFocusScope.forceActiveFocus()
|
||||
parentModal.modalFocusScope.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
width: 500
|
||||
height: 550
|
||||
modalWidth: 500
|
||||
modalHeight: 550
|
||||
allowStacking: true
|
||||
backgroundOpacity: 0
|
||||
closeOnEscapeKey: false
|
||||
onDialogClosed: () => {
|
||||
allWidgets = []
|
||||
targetSection = ""
|
||||
searchQuery = ""
|
||||
filteredWidgets = []
|
||||
selectedIndex = -1
|
||||
keyboardNavigationActive = false
|
||||
allWidgets = [];
|
||||
targetSection = "";
|
||||
searchQuery = "";
|
||||
filteredWidgets = [];
|
||||
selectedIndex = -1;
|
||||
keyboardNavigationActive = false;
|
||||
if (parentModal) {
|
||||
parentModal.shouldHaveFocus = Qt.binding(() => {
|
||||
return parentModal.shouldBeVisible
|
||||
})
|
||||
return parentModal.shouldBeVisible;
|
||||
});
|
||||
Qt.callLater(() => {
|
||||
if (parentModal && parentModal.modalFocusScope) {
|
||||
parentModal.modalFocusScope.forceActiveFocus()
|
||||
parentModal.modalFocusScope.forceActiveFocus();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
onBackgroundClicked: () => {
|
||||
return hide()
|
||||
return hide();
|
||||
}
|
||||
content: widgetSelectionContent
|
||||
|
||||
widgetSelectionContent: Component {
|
||||
FocusScope {
|
||||
id: widgetKeyHandler
|
||||
property alias searchField: searchField
|
||||
id: widgetKeyHandler
|
||||
property alias searchField: searchField
|
||||
|
||||
anchors.fill: parent
|
||||
focus: true
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
if (root.keyboardNavigationActive) {
|
||||
root.selectWidget()
|
||||
} else if (root.filteredWidgets.length > 0) {
|
||||
var firstWidget = root.filteredWidgets[0]
|
||||
root.widgetSelected(firstWidget.id, root.targetSection)
|
||||
root.close()
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 2
|
||||
iconColor: Theme.outline
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.spacingM
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
|
||||
spacing: Theme.spacingM
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
anchors.topMargin: Theme.spacingL + 30 // Space for close button
|
||||
focus: true
|
||||
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
root.selectNext();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
root.selectPrevious();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectNext();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectPrevious();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectNext();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
root.selectPrevious();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
if (root.keyboardNavigationActive) {
|
||||
root.selectWidget();
|
||||
} else if (root.filteredWidgets.length > 0) {
|
||||
var firstWidget = root.filteredWidgets[0];
|
||||
root.widgetSelected(firstWidget.id, root.targetSection);
|
||||
root.close();
|
||||
}
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "close"
|
||||
iconSize: Theme.iconSize - 2
|
||||
iconColor: Theme.outline
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.spacingM
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
onClicked: root.close()
|
||||
}
|
||||
|
||||
Column {
|
||||
id: contentColumn
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
anchors.topMargin: Theme.spacingL + 30 // Space for close button
|
||||
|
||||
DankIcon {
|
||||
name: "add_circle"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "add_circle"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Add Widget to ") + root.targetSection + " Section"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Add Widget to ") + root.targetSection + " Section"
|
||||
font.pixelSize: Theme.fontSizeLarge
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: I18n.tr("Select a widget to add to the ") + root.targetSection.toLowerCase() + " section of the top bar. You can add multiple instances of the same widget if needed."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Select a widget to add to the ") + root.targetSection.toLowerCase(
|
||||
) + " section of the top bar. You can add multiple instances of the same widget if needed."
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
id: searchField
|
||||
width: parent.width
|
||||
height: 48
|
||||
cornerRadius: Theme.cornerRadius
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
leftIconName: "search"
|
||||
leftIconSize: Theme.iconSize
|
||||
leftIconColor: Theme.surfaceVariantText
|
||||
leftIconFocusedColor: Theme.primary
|
||||
showClearButton: true
|
||||
textColor: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
placeholderText: ""
|
||||
text: root.searchQuery
|
||||
focus: true
|
||||
ignoreLeftRightKeys: true
|
||||
keyForwardTargets: [widgetKeyHandler]
|
||||
onTextEdited: {
|
||||
root.searchQuery = text
|
||||
updateFilteredWidgets()
|
||||
}
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up ||
|
||||
((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
|
||||
event.accepted = false
|
||||
DankTextField {
|
||||
id: searchField
|
||||
width: parent.width
|
||||
height: 48
|
||||
cornerRadius: Theme.cornerRadius
|
||||
backgroundColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
normalBorderColor: Theme.outlineMedium
|
||||
focusedBorderColor: Theme.primary
|
||||
leftIconName: "search"
|
||||
leftIconSize: Theme.iconSize
|
||||
leftIconColor: Theme.surfaceVariantText
|
||||
leftIconFocusedColor: Theme.primary
|
||||
showClearButton: true
|
||||
textColor: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
placeholderText: ""
|
||||
text: root.searchQuery
|
||||
focus: true
|
||||
ignoreLeftRightKeys: true
|
||||
keyForwardTargets: [widgetKeyHandler]
|
||||
onTextEdited: {
|
||||
root.searchQuery = text;
|
||||
updateFilteredWidgets();
|
||||
}
|
||||
Keys.onPressed: event => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
|
||||
event.accepted = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankListView {
|
||||
id: widgetList
|
||||
DankListView {
|
||||
id: widgetList
|
||||
|
||||
width: parent.width
|
||||
height: parent.height - y
|
||||
spacing: Theme.spacingS
|
||||
model: root.filteredWidgets
|
||||
clip: true
|
||||
width: parent.width
|
||||
height: parent.height - y
|
||||
spacing: Theme.spacingS
|
||||
model: root.filteredWidgets
|
||||
clip: true
|
||||
|
||||
delegate: Rectangle {
|
||||
width: widgetList.width
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
|
||||
color: isSelected ? Theme.primarySelected :
|
||||
widgetArea.containsMouse ? Theme.primaryHover : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b,
|
||||
0.3)
|
||||
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
border.width: isSelected ? 2 : 1
|
||||
delegate: Rectangle {
|
||||
width: widgetList.width
|
||||
height: 60
|
||||
radius: Theme.cornerRadius
|
||||
property bool isSelected: root.keyboardNavigationActive && index === root.selectedIndex
|
||||
color: isSelected ? Theme.primarySelected : widgetArea.containsMouse ? Theme.primaryHover : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: isSelected ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: isSelected ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: modelData.icon
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM * 3
|
||||
|
||||
StyledText {
|
||||
text: modelData.text
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
DankIcon {
|
||||
name: modelData.icon
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 2
|
||||
width: parent.width - Theme.iconSize - Theme.spacingM * 3
|
||||
|
||||
StyledText {
|
||||
text: modelData.text
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: modelData.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outline
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "add"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "add"
|
||||
size: Theme.iconSize - 4
|
||||
color: Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
MouseArea {
|
||||
id: widgetArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.widgetSelected(modelData.id, root.targetSection);
|
||||
root.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: widgetArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.widgetSelected(modelData.id,
|
||||
root.targetSection)
|
||||
root.close()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,10 @@ Column {
|
||||
property string titleIcon: "widgets"
|
||||
property string sectionId: ""
|
||||
|
||||
DankTooltipV2 {
|
||||
id: sharedTooltip
|
||||
}
|
||||
|
||||
signal itemEnabledChanged(string sectionId, string itemId, bool enabled)
|
||||
signal itemOrderChanged(var newOrder)
|
||||
signal addWidget(string sectionId)
|
||||
@@ -80,11 +84,8 @@ Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r,
|
||||
Theme.surfaceContainer.g,
|
||||
Theme.surfaceContainer.b, 0.8)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.8)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
|
||||
DankIcon {
|
||||
@@ -126,10 +127,7 @@ Column {
|
||||
StyledText {
|
||||
text: modelData.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: modelData.enabled ? Theme.outline : Qt.rgba(
|
||||
Theme.outline.r,
|
||||
Theme.outline.g,
|
||||
Theme.outline.b, 0.6)
|
||||
color: modelData.enabled ? Theme.outline : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.6)
|
||||
elide: Text.ElideRight
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -154,41 +152,29 @@ Column {
|
||||
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()
|
||||
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(
|
||||
) : ""
|
||||
return DgopService.availableGpus && DgopService.availableGpus.length > 0 ? DgopService.availableGpus[0].driver.toUpperCase() : "";
|
||||
}
|
||||
options: {
|
||||
var gpuOptions = []
|
||||
if (DgopService.availableGpus
|
||||
&& DgopService.availableGpus.length > 0) {
|
||||
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(
|
||||
))
|
||||
var gpu = DgopService.availableGpus[i];
|
||||
gpuOptions.push(gpu.driver.toUpperCase());
|
||||
}
|
||||
}
|
||||
return gpuOptions
|
||||
return gpuOptions;
|
||||
}
|
||||
onValueChanged: value => {
|
||||
var gpuIndex = options.indexOf(
|
||||
value)
|
||||
if (gpuIndex >= 0) {
|
||||
root.gpuSelectionChanged(
|
||||
root.sectionId,
|
||||
index, gpuIndex)
|
||||
}
|
||||
}
|
||||
var gpuIndex = options.indexOf(value);
|
||||
if (gpuIndex >= 0) {
|
||||
root.gpuSelectionChanged(root.sectionId, index, gpuIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -200,26 +186,26 @@ Column {
|
||||
id: diskMountDropdown
|
||||
anchors.fill: parent
|
||||
currentValue: {
|
||||
const mountPath = modelData.mountPath || "/"
|
||||
const mountPath = modelData.mountPath || "/";
|
||||
if (mountPath === "/") {
|
||||
return "root (/)"
|
||||
return "root (/)";
|
||||
}
|
||||
return mountPath
|
||||
return mountPath;
|
||||
}
|
||||
options: {
|
||||
if (!DgopService.diskMounts || DgopService.diskMounts.length === 0) {
|
||||
return ["root (/)"]
|
||||
return ["root (/)"];
|
||||
}
|
||||
return DgopService.diskMounts.map(mount => {
|
||||
if (mount.mount === "/") {
|
||||
return "root (/)"
|
||||
return "root (/)";
|
||||
}
|
||||
return mount.mount
|
||||
})
|
||||
return mount.mount;
|
||||
});
|
||||
}
|
||||
onValueChanged: value => {
|
||||
const newPath = value === "root (/)" ? "/" : value
|
||||
root.diskMountSelectionChanged(root.sectionId, index, newPath)
|
||||
const newPath = value === "root (/)" ? "/" : value;
|
||||
root.diskMountSelectionChanged(root.sectionId, index, newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -247,20 +233,15 @@ Column {
|
||||
Rectangle {
|
||||
id: warningTooltip
|
||||
|
||||
property string warningText: (modelData.warning !== undefined
|
||||
&& modelData.warning
|
||||
!== "") ? modelData.warning : ""
|
||||
property string warningText: (modelData.warning !== undefined && modelData.warning !== "") ? modelData.warning : ""
|
||||
|
||||
width: Math.min(
|
||||
250,
|
||||
warningTooltipText.implicitWidth) + Theme.spacingM * 2
|
||||
width: Math.min(250, warningTooltipText.implicitWidth) + Theme.spacingM * 2
|
||||
height: warningTooltipText.implicitHeight + Theme.spacingS * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 0
|
||||
visible: warningArea.containsMouse
|
||||
&& warningText !== ""
|
||||
visible: warningArea.containsMouse && warningText !== ""
|
||||
opacity: visible ? 1 : 0
|
||||
x: -width - Theme.spacingS
|
||||
y: (parent.height - height) / 2
|
||||
@@ -289,31 +270,21 @@ Column {
|
||||
DankActionButton {
|
||||
id: minimumWidthButton
|
||||
buttonSize: 28
|
||||
visible: modelData.id === "cpuUsage"
|
||||
|| modelData.id === "memUsage"
|
||||
|| modelData.id === "cpuTemp"
|
||||
|| modelData.id === "gpuTemp"
|
||||
visible: modelData.id === "cpuUsage" || modelData.id === "memUsage" || modelData.id === "cpuTemp" || modelData.id === "gpuTemp"
|
||||
iconName: "straighten"
|
||||
iconSize: 16
|
||||
iconColor: (modelData.minimumWidth !== undefined ? modelData.minimumWidth : true) ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true
|
||||
root.minimumWidthChanged(root.sectionId, index, !currentEnabled)
|
||||
var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true;
|
||||
root.minimumWidthChanged(root.sectionId, index, !currentEnabled);
|
||||
}
|
||||
onEntered: {
|
||||
minimumWidthTooltipLoader.active = true
|
||||
if (minimumWidthTooltipLoader.item) {
|
||||
var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true
|
||||
const tooltipText = currentEnabled ? "Force Padding" : "Dynamic Width"
|
||||
const p = minimumWidthButton.mapToItem(null, minimumWidthButton.width / 2, 0)
|
||||
minimumWidthTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
|
||||
}
|
||||
var currentEnabled = modelData.minimumWidth !== undefined ? modelData.minimumWidth : true;
|
||||
const tooltipText = currentEnabled ? "Force Padding" : "Dynamic Width";
|
||||
sharedTooltip.show(tooltipText, minimumWidthButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (minimumWidthTooltipLoader.item) {
|
||||
minimumWidthTooltipLoader.item.hide()
|
||||
}
|
||||
minimumWidthTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,33 +296,22 @@ Column {
|
||||
iconSize: 16
|
||||
iconColor: (modelData.showSwap !== undefined ? modelData.showSwap : false) ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
var currentEnabled = modelData.showSwap !== undefined ? modelData.showSwap : false
|
||||
root.showSwapChanged(root.sectionId, index, !currentEnabled)
|
||||
var currentEnabled = modelData.showSwap !== undefined ? modelData.showSwap : false;
|
||||
root.showSwapChanged(root.sectionId, index, !currentEnabled);
|
||||
}
|
||||
onEntered: {
|
||||
showSwapTooltipLoader.active = true
|
||||
if (showSwapTooltipLoader.item) {
|
||||
var currentEnabled = modelData.showSwap !== undefined ? modelData.showSwap : false
|
||||
const tooltipText = currentEnabled ? "Hide Swap" : "Show Swap"
|
||||
const p = showSwapButton.mapToItem(null, showSwapButton.width / 2, 0)
|
||||
showSwapTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
|
||||
}
|
||||
var currentEnabled = modelData.showSwap !== undefined ? modelData.showSwap : false;
|
||||
const tooltipText = currentEnabled ? "Hide Swap" : "Show Swap";
|
||||
sharedTooltip.show(tooltipText, showSwapButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (showSwapTooltipLoader.item) {
|
||||
showSwapTooltipLoader.item.hide()
|
||||
}
|
||||
showSwapTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingXS
|
||||
visible: modelData.id === "clock"
|
||||
|| modelData.id === "music"
|
||||
|| modelData.id === "focusedWindow"
|
||||
|| modelData.id === "runningApps"
|
||||
|| modelData.id === "keyboard_layout_name"
|
||||
visible: modelData.id === "clock" || modelData.id === "music" || modelData.id === "focusedWindow" || modelData.id === "runningApps" || modelData.id === "keyboard_layout_name"
|
||||
|
||||
DankActionButton {
|
||||
id: smallSizeButton
|
||||
@@ -359,23 +319,15 @@ Column {
|
||||
visible: modelData.id === "music"
|
||||
iconName: "photo_size_select_small"
|
||||
iconSize: 16
|
||||
iconColor: SettingsData.mediaSize
|
||||
=== 0 ? Theme.primary : Theme.outline
|
||||
iconColor: SettingsData.mediaSize === 0 ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
root.compactModeChanged("music", 0)
|
||||
root.compactModeChanged("music", 0);
|
||||
}
|
||||
onEntered: {
|
||||
smallTooltipLoader.active = true
|
||||
if (smallTooltipLoader.item) {
|
||||
const p = smallSizeButton.mapToItem(null, smallSizeButton.width / 2, 0)
|
||||
smallTooltipLoader.item.show("Small", p.x, p.y - 40, null)
|
||||
}
|
||||
sharedTooltip.show("Small", smallSizeButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (smallTooltipLoader.item) {
|
||||
smallTooltipLoader.item.hide()
|
||||
}
|
||||
smallTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,23 +337,15 @@ Column {
|
||||
visible: modelData.id === "music"
|
||||
iconName: "photo_size_select_actual"
|
||||
iconSize: 16
|
||||
iconColor: SettingsData.mediaSize
|
||||
=== 1 ? Theme.primary : Theme.outline
|
||||
iconColor: SettingsData.mediaSize === 1 ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
root.compactModeChanged("music", 1)
|
||||
root.compactModeChanged("music", 1);
|
||||
}
|
||||
onEntered: {
|
||||
mediumTooltipLoader.active = true
|
||||
if (mediumTooltipLoader.item) {
|
||||
const p = mediumSizeButton.mapToItem(null, mediumSizeButton.width / 2, 0)
|
||||
mediumTooltipLoader.item.show("Medium", p.x, p.y - 40, null)
|
||||
}
|
||||
sharedTooltip.show("Medium", mediumSizeButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (mediumTooltipLoader.item) {
|
||||
mediumTooltipLoader.item.hide()
|
||||
}
|
||||
mediumTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,97 +355,71 @@ Column {
|
||||
visible: modelData.id === "music"
|
||||
iconName: "photo_size_select_large"
|
||||
iconSize: 16
|
||||
iconColor: SettingsData.mediaSize
|
||||
=== 2 ? Theme.primary : Theme.outline
|
||||
iconColor: SettingsData.mediaSize === 2 ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
root.compactModeChanged("music", 2)
|
||||
root.compactModeChanged("music", 2);
|
||||
}
|
||||
onEntered: {
|
||||
largeTooltipLoader.active = true
|
||||
if (largeTooltipLoader.item) {
|
||||
const p = largeSizeButton.mapToItem(null, largeSizeButton.width / 2, 0)
|
||||
largeTooltipLoader.item.show("Large", p.x, p.y - 40, null)
|
||||
}
|
||||
sharedTooltip.show("Large", largeSizeButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (largeTooltipLoader.item) {
|
||||
largeTooltipLoader.item.hide()
|
||||
}
|
||||
largeTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
id: compactModeButton
|
||||
buttonSize: 28
|
||||
visible: modelData.id === "clock"
|
||||
|| modelData.id === "focusedWindow"
|
||||
|| modelData.id === "runningApps"
|
||||
|| modelData.id === "keyboard_layout_name"
|
||||
visible: modelData.id === "clock" || modelData.id === "focusedWindow" || modelData.id === "runningApps" || modelData.id === "keyboard_layout_name"
|
||||
iconName: {
|
||||
if (modelData.id === "clock")
|
||||
return SettingsData.clockCompactMode ? "zoom_out" : "zoom_in"
|
||||
return SettingsData.clockCompactMode ? "zoom_out" : "zoom_in";
|
||||
if (modelData.id === "focusedWindow")
|
||||
return SettingsData.focusedWindowCompactMode ? "zoom_out" : "zoom_in"
|
||||
return SettingsData.focusedWindowCompactMode ? "zoom_out" : "zoom_in";
|
||||
if (modelData.id === "runningApps")
|
||||
return SettingsData.runningAppsCompactMode ? "zoom_out" : "zoom_in"
|
||||
return SettingsData.runningAppsCompactMode ? "zoom_out" : "zoom_in";
|
||||
if (modelData.id === "keyboard_layout_name")
|
||||
return SettingsData.keyboardLayoutNameCompactMode ? "zoom_out" : "zoom_in"
|
||||
return "zoom_in"
|
||||
return SettingsData.keyboardLayoutNameCompactMode ? "zoom_out" : "zoom_in";
|
||||
return "zoom_in";
|
||||
}
|
||||
iconSize: 16
|
||||
iconColor: {
|
||||
if (modelData.id === "clock")
|
||||
return SettingsData.clockCompactMode ? Theme.primary : Theme.outline
|
||||
return SettingsData.clockCompactMode ? Theme.primary : Theme.outline;
|
||||
if (modelData.id === "focusedWindow")
|
||||
return SettingsData.focusedWindowCompactMode ? Theme.primary : Theme.outline
|
||||
return SettingsData.focusedWindowCompactMode ? Theme.primary : Theme.outline;
|
||||
if (modelData.id === "runningApps")
|
||||
return SettingsData.runningAppsCompactMode ? Theme.primary : Theme.outline
|
||||
return SettingsData.runningAppsCompactMode ? Theme.primary : Theme.outline;
|
||||
if (modelData.id === "keyboard_layout_name")
|
||||
return SettingsData.keyboardLayoutNameCompactMode ? Theme.primary : Theme.outline
|
||||
return Theme.outline
|
||||
return SettingsData.keyboardLayoutNameCompactMode ? Theme.primary : Theme.outline;
|
||||
return Theme.outline;
|
||||
}
|
||||
onClicked: {
|
||||
if (modelData.id === "clock") {
|
||||
root.compactModeChanged(
|
||||
"clock",
|
||||
!SettingsData.clockCompactMode)
|
||||
root.compactModeChanged("clock", !SettingsData.clockCompactMode);
|
||||
} else if (modelData.id === "focusedWindow") {
|
||||
root.compactModeChanged(
|
||||
"focusedWindow",
|
||||
!SettingsData.focusedWindowCompactMode)
|
||||
root.compactModeChanged("focusedWindow", !SettingsData.focusedWindowCompactMode);
|
||||
} else if (modelData.id === "runningApps") {
|
||||
root.compactModeChanged(
|
||||
"runningApps",
|
||||
!SettingsData.runningAppsCompactMode)
|
||||
root.compactModeChanged("runningApps", !SettingsData.runningAppsCompactMode);
|
||||
} else if (modelData.id === "keyboard_layout_name") {
|
||||
root.compactModeChanged(
|
||||
"keyboard_layout_name",
|
||||
!SettingsData.keyboardLayoutNameCompactMode)
|
||||
root.compactModeChanged("keyboard_layout_name", !SettingsData.keyboardLayoutNameCompactMode);
|
||||
}
|
||||
}
|
||||
onEntered: {
|
||||
compactTooltipLoader.active = true
|
||||
if (compactTooltipLoader.item) {
|
||||
let tooltipText = "Toggle Compact Mode"
|
||||
if (modelData.id === "clock") {
|
||||
tooltipText = SettingsData.clockCompactMode ? "Full Size" : "Compact"
|
||||
} else if (modelData.id === "focusedWindow") {
|
||||
tooltipText = SettingsData.focusedWindowCompactMode ? "Full Size" : "Compact"
|
||||
} else if (modelData.id === "runningApps") {
|
||||
tooltipText = SettingsData.runningAppsCompactMode ? "Full Size" : "Compact"
|
||||
} else if (modelData.id === "keyboard_layout_name") {
|
||||
tooltipText = SettingsData.keyboardLayoutNameCompactMode ? "Full Size" : "Compact"
|
||||
}
|
||||
const p = compactModeButton.mapToItem(null, compactModeButton.width / 2, 0)
|
||||
compactTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
|
||||
let tooltipText = "Toggle Compact Mode";
|
||||
if (modelData.id === "clock") {
|
||||
tooltipText = SettingsData.clockCompactMode ? "Full Size" : "Compact";
|
||||
} else if (modelData.id === "focusedWindow") {
|
||||
tooltipText = SettingsData.focusedWindowCompactMode ? "Full Size" : "Compact";
|
||||
} else if (modelData.id === "runningApps") {
|
||||
tooltipText = SettingsData.runningAppsCompactMode ? "Full Size" : "Compact";
|
||||
} else if (modelData.id === "keyboard_layout_name") {
|
||||
tooltipText = SettingsData.keyboardLayoutNameCompactMode ? "Full Size" : "Compact";
|
||||
}
|
||||
sharedTooltip.show(tooltipText, compactModeButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (compactTooltipLoader.item) {
|
||||
compactTooltipLoader.item.hide()
|
||||
}
|
||||
compactTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -513,21 +431,14 @@ Column {
|
||||
iconSize: 16
|
||||
iconColor: SettingsData.runningAppsGroupByApp ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
SettingsData.set("runningAppsGroupByApp", !SettingsData.runningAppsGroupByApp)
|
||||
SettingsData.set("runningAppsGroupByApp", !SettingsData.runningAppsGroupByApp);
|
||||
}
|
||||
onEntered: {
|
||||
groupByAppTooltipLoader.active = true
|
||||
if (groupByAppTooltipLoader.item) {
|
||||
const tooltipText = SettingsData.runningAppsGroupByApp ? "Ungroup" : "Group by App"
|
||||
const p = groupByAppButton.mapToItem(null, groupByAppButton.width / 2, 0)
|
||||
groupByAppTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
|
||||
}
|
||||
const tooltipText = SettingsData.runningAppsGroupByApp ? "Ungroup" : "Group by App";
|
||||
sharedTooltip.show(tooltipText, groupByAppButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (groupByAppTooltipLoader.item) {
|
||||
groupByAppTooltipLoader.item.hide()
|
||||
}
|
||||
groupByAppTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -569,15 +480,15 @@ Column {
|
||||
iconSize: 18
|
||||
iconColor: Theme.outline
|
||||
onClicked: {
|
||||
console.log("Control Center three-dot button clicked for widget:", modelData.id)
|
||||
controlCenterContextMenu.widgetData = modelData
|
||||
controlCenterContextMenu.sectionId = root.sectionId
|
||||
controlCenterContextMenu.widgetIndex = index
|
||||
console.log("Control Center three-dot button clicked for widget:", modelData.id);
|
||||
controlCenterContextMenu.widgetData = modelData;
|
||||
controlCenterContextMenu.sectionId = root.sectionId;
|
||||
controlCenterContextMenu.widgetIndex = index;
|
||||
// Position relative to the action buttons row, not the specific button
|
||||
var parentPos = parent.mapToItem(root, 0, 0)
|
||||
controlCenterContextMenu.x = parentPos.x - 210 // Position to the left with margin
|
||||
controlCenterContextMenu.y = parentPos.y - 10 // Slightly above
|
||||
controlCenterContextMenu.open()
|
||||
var parentPos = parent.mapToItem(root, 0, 0);
|
||||
controlCenterContextMenu.x = parentPos.x - 210; // Position to the left with margin
|
||||
controlCenterContextMenu.y = parentPos.y - 10; // Slightly above
|
||||
controlCenterContextMenu.open();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -588,15 +499,15 @@ Column {
|
||||
iconSize: 18
|
||||
iconColor: Theme.outline
|
||||
onClicked: {
|
||||
console.log("Privacy three-dot button clicked for widget:", modelData.id)
|
||||
privacyContextMenu.widgetData = modelData
|
||||
privacyContextMenu.sectionId = root.sectionId
|
||||
privacyContextMenu.widgetIndex = index
|
||||
console.log("Privacy three-dot button clicked for widget:", modelData.id);
|
||||
privacyContextMenu.widgetData = modelData;
|
||||
privacyContextMenu.sectionId = root.sectionId;
|
||||
privacyContextMenu.widgetIndex = index;
|
||||
// Position relative to the action buttons row, not the specific button
|
||||
var parentPos = parent.mapToItem(root, 0, 0)
|
||||
privacyContextMenu.x = parentPos.x - 210 // Position to the left with margin
|
||||
privacyContextMenu.y = parentPos.y - 10 // Slightly above
|
||||
privacyContextMenu.open()
|
||||
var parentPos = parent.mapToItem(root, 0, 0);
|
||||
privacyContextMenu.x = parentPos.x - 210; // Position to the left with margin
|
||||
privacyContextMenu.y = parentPos.y - 10; // Slightly above
|
||||
privacyContextMenu.open();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -608,23 +519,14 @@ Column {
|
||||
iconSize: 18
|
||||
iconColor: modelData.enabled ? Theme.primary : Theme.outline
|
||||
onClicked: {
|
||||
root.itemEnabledChanged(root.sectionId,
|
||||
modelData.id,
|
||||
!modelData.enabled)
|
||||
root.itemEnabledChanged(root.sectionId, modelData.id, !modelData.enabled);
|
||||
}
|
||||
onEntered: {
|
||||
visibilityTooltipLoader.active = true
|
||||
if (visibilityTooltipLoader.item) {
|
||||
const tooltipText = modelData.enabled ? "Hide" : "Show"
|
||||
const p = visibilityButton.mapToItem(null, visibilityButton.width / 2, 0)
|
||||
visibilityTooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
|
||||
}
|
||||
const tooltipText = modelData.enabled ? "Hide" : "Show";
|
||||
sharedTooltip.show(tooltipText, visibilityButton, 0, 0, "bottom");
|
||||
}
|
||||
onExited: {
|
||||
if (visibilityTooltipLoader.item) {
|
||||
visibilityTooltipLoader.item.hide()
|
||||
}
|
||||
visibilityTooltipLoader.active = false
|
||||
sharedTooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -639,11 +541,9 @@ Column {
|
||||
iconSize: 14
|
||||
iconColor: Theme.outline
|
||||
onClicked: {
|
||||
var currentSize = modelData.size || 20
|
||||
var newSize = Math.max(5, currentSize - 5)
|
||||
root.spacerSizeChanged(root.sectionId,
|
||||
index,
|
||||
newSize)
|
||||
var currentSize = modelData.size || 20;
|
||||
var newSize = Math.max(5, currentSize - 5);
|
||||
root.spacerSizeChanged(root.sectionId, index, newSize);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,12 +560,9 @@ Column {
|
||||
iconSize: 14
|
||||
iconColor: Theme.outline
|
||||
onClicked: {
|
||||
var currentSize = modelData.size || 20
|
||||
var newSize = Math.min(5000,
|
||||
currentSize + 5)
|
||||
root.spacerSizeChanged(root.sectionId,
|
||||
index,
|
||||
newSize)
|
||||
var currentSize = modelData.size || 20;
|
||||
var newSize = Math.min(5000, currentSize + 5);
|
||||
root.spacerSizeChanged(root.sectionId, index, newSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -676,7 +573,7 @@ Column {
|
||||
iconSize: 18
|
||||
iconColor: Theme.error
|
||||
onClicked: {
|
||||
root.removeWidget(root.sectionId, index)
|
||||
root.removeWidget(root.sectionId, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -696,34 +593,29 @@ Column {
|
||||
drag.maximumY: itemsList.height
|
||||
preventStealing: true
|
||||
onPressed: {
|
||||
delegateItem.z = 2
|
||||
delegateItem.originalY = delegateItem.y
|
||||
delegateItem.z = 2;
|
||||
delegateItem.originalY = delegateItem.y;
|
||||
}
|
||||
onReleased: {
|
||||
delegateItem.z = 1
|
||||
delegateItem.z = 1;
|
||||
if (drag.active) {
|
||||
var newIndex = Math.round(
|
||||
delegateItem.y / (delegateItem.height
|
||||
+ itemsList.spacing))
|
||||
newIndex = Math.max(
|
||||
0, Math.min(newIndex,
|
||||
root.items.length - 1))
|
||||
var newIndex = Math.round(delegateItem.y / (delegateItem.height + itemsList.spacing));
|
||||
newIndex = Math.max(0, Math.min(newIndex, root.items.length - 1));
|
||||
if (newIndex !== index) {
|
||||
var newItems = root.items.slice()
|
||||
var draggedItem = newItems.splice(index,
|
||||
1)[0]
|
||||
newItems.splice(newIndex, 0, draggedItem)
|
||||
var newItems = root.items.slice();
|
||||
var draggedItem = newItems.splice(index, 1)[0];
|
||||
newItems.splice(newIndex, 0, draggedItem);
|
||||
root.itemOrderChanged(newItems.map(item => {
|
||||
return ({
|
||||
"id": item.id,
|
||||
"enabled": item.enabled,
|
||||
"size": item.size
|
||||
})
|
||||
}))
|
||||
return ({
|
||||
"id": item.id,
|
||||
"enabled": item.enabled,
|
||||
"size": item.size
|
||||
});
|
||||
}));
|
||||
}
|
||||
}
|
||||
delegateItem.x = 0
|
||||
delegateItem.y = delegateItem.originalY
|
||||
delegateItem.x = 0;
|
||||
delegateItem.y = delegateItem.originalY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -744,12 +636,8 @@ Column {
|
||||
width: 200
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: addButtonArea.containsMouse ? Theme.primaryContainer : Qt.rgba(
|
||||
Theme.surfaceVariant.r,
|
||||
Theme.surfaceVariant.g,
|
||||
Theme.surfaceVariant.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.2)
|
||||
color: addButtonArea.containsMouse ? Theme.primaryContainer : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
@@ -769,7 +657,7 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.addWidget(root.sectionId)
|
||||
root.addWidget(root.sectionId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -788,7 +676,6 @@ Column {
|
||||
property string sectionId: ""
|
||||
property int widgetIndex: -1
|
||||
|
||||
|
||||
width: 200
|
||||
height: 120
|
||||
padding: 0
|
||||
@@ -797,11 +684,11 @@ Column {
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
onOpened: {
|
||||
console.log("Control Center context menu opened")
|
||||
console.log("Control Center context menu opened");
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
console.log("Control Center context menu closed")
|
||||
console.log("Control Center context menu closed");
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
@@ -856,7 +743,7 @@ Column {
|
||||
height: 20
|
||||
checked: SettingsData.controlCenterShowNetworkIcon
|
||||
onToggled: {
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showNetworkIcon", toggled)
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showNetworkIcon", toggled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -866,8 +753,8 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
networkToggle.checked = !networkToggle.checked
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showNetworkIcon", networkToggle.checked)
|
||||
networkToggle.checked = !networkToggle.checked;
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showNetworkIcon", networkToggle.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -909,7 +796,7 @@ Column {
|
||||
height: 20
|
||||
checked: SettingsData.controlCenterShowBluetoothIcon
|
||||
onToggled: {
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showBluetoothIcon", toggled)
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showBluetoothIcon", toggled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,8 +806,8 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
bluetoothToggle.checked = !bluetoothToggle.checked
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showBluetoothIcon", bluetoothToggle.checked)
|
||||
bluetoothToggle.checked = !bluetoothToggle.checked;
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showBluetoothIcon", bluetoothToggle.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -962,7 +849,7 @@ Column {
|
||||
height: 20
|
||||
checked: SettingsData.controlCenterShowAudioIcon
|
||||
onToggled: {
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showAudioIcon", toggled)
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showAudioIcon", toggled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -972,13 +859,12 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
audioToggle.checked = !audioToggle.checked
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showAudioIcon", audioToggle.checked)
|
||||
audioToggle.checked = !audioToggle.checked;
|
||||
root.controlCenterSettingChanged(controlCenterContextMenu.sectionId, controlCenterContextMenu.widgetIndex, "showAudioIcon", audioToggle.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -989,7 +875,6 @@ Column {
|
||||
property string sectionId: ""
|
||||
property int widgetIndex: -1
|
||||
|
||||
|
||||
width: 200
|
||||
height: 160
|
||||
padding: 0
|
||||
@@ -998,11 +883,11 @@ Column {
|
||||
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
|
||||
|
||||
onOpened: {
|
||||
console.log("Privacy context menu opened")
|
||||
console.log("Privacy context menu opened");
|
||||
}
|
||||
|
||||
onClosed: {
|
||||
console.log("Privacy Center context menu closed")
|
||||
console.log("Privacy Center context menu closed");
|
||||
}
|
||||
|
||||
background: Rectangle {
|
||||
@@ -1079,7 +964,7 @@ Column {
|
||||
height: 20
|
||||
checked: SettingsData.privacyShowMicIcon
|
||||
onToggled: toggled => {
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", toggled)
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", toggled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1089,8 +974,8 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
micToggle.checked = !micToggle.checked
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", micToggle.checked)
|
||||
micToggle.checked = !micToggle.checked;
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showMicIcon", micToggle.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1131,7 +1016,7 @@ Column {
|
||||
height: 20
|
||||
checked: SettingsData.privacyShowCameraIcon
|
||||
onToggled: toggled => {
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", toggled)
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", toggled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1141,8 +1026,8 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
cameraToggle.checked = !cameraToggle.checked
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", cameraToggle.checked)
|
||||
cameraToggle.checked = !cameraToggle.checked;
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showCameraIcon", cameraToggle.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1183,7 +1068,7 @@ Column {
|
||||
height: 20
|
||||
checked: SettingsData.privacyShowScreenShareIcon
|
||||
onToggled: toggled => {
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", toggled)
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", toggled);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1193,61 +1078,12 @@ Column {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
screenshareToggle.checked = !screenshareToggle.checked
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", screenshareToggle.checked)
|
||||
screenshareToggle.checked = !screenshareToggle.checked;
|
||||
root.privacySettingChanged(privacyContextMenu.sectionId, privacyContextMenu.widgetIndex, "showScreenSharingIcon", screenshareToggle.checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: smallTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: mediumTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: largeTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: compactTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: visibilityTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: minimumWidthTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: groupByAppTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: showSwapTooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
pragma Singleton
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Common
|
||||
|
||||
@@ -31,25 +29,28 @@ Singleton {
|
||||
|
||||
// Main battery (for backward compatibility)
|
||||
readonly property UPowerDevice device: {
|
||||
var preferredDev
|
||||
var preferredDev;
|
||||
if (usePreferred) {
|
||||
preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase()))
|
||||
preferredDev = batteries.find(dev => dev.nativePath.toLowerCase().includes(preferredBatteryOverride.toLowerCase()));
|
||||
}
|
||||
return preferredDev || batteries[0] || null
|
||||
return preferredDev || batteries[0] || null;
|
||||
}
|
||||
// Whether at least one battery is available
|
||||
readonly property bool batteryAvailable: batteries.length > 0
|
||||
// Aggregated charge level (percentage)
|
||||
readonly property real batteryLevel: {
|
||||
if (!batteryAvailable) return 0
|
||||
if (!batteryAvailable)
|
||||
return 0;
|
||||
if (batteryCapacity === 0) {
|
||||
if (usePreferred && device && device.ready) return Math.round(device.percentage * 100)
|
||||
const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0)
|
||||
if (validBatteries.length === 0) return 0
|
||||
const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length
|
||||
return Math.round(avgPercentage * 100)
|
||||
if (usePreferred && device && device.ready)
|
||||
return Math.round(device.percentage * 100);
|
||||
const validBatteries = batteries.filter(b => b.ready && b.percentage >= 0);
|
||||
if (validBatteries.length === 0)
|
||||
return 0;
|
||||
const avgPercentage = validBatteries.reduce((sum, b) => sum + b.percentage, 0) / validBatteries.length;
|
||||
return Math.round(avgPercentage * 100);
|
||||
}
|
||||
return Math.round((batteryEnergy * 100) / batteryCapacity)
|
||||
return Math.round((batteryEnergy * 100) / batteryCapacity);
|
||||
}
|
||||
readonly property bool isCharging: batteryAvailable && batteries.some(b => b.state === UPowerDeviceState.Charging)
|
||||
|
||||
@@ -59,170 +60,182 @@ Singleton {
|
||||
|
||||
onIsPluggedInChanged: {
|
||||
if (suppressSound || !batteryAvailable) {
|
||||
previousPluggedState = isPluggedIn
|
||||
return
|
||||
previousPluggedState = isPluggedIn;
|
||||
return;
|
||||
}
|
||||
|
||||
if (SettingsData.soundsEnabled && SettingsData.soundPluggedIn) {
|
||||
if (isPluggedIn && !previousPluggedState) {
|
||||
AudioService.playPowerPlugSound()
|
||||
AudioService.playPowerPlugSound();
|
||||
} else if (!isPluggedIn && previousPluggedState) {
|
||||
AudioService.playPowerUnplugSound()
|
||||
AudioService.playPowerUnplugSound();
|
||||
}
|
||||
}
|
||||
|
||||
previousPluggedState = isPluggedIn
|
||||
previousPluggedState = isPluggedIn;
|
||||
}
|
||||
|
||||
// Aggregated charge/discharge rate
|
||||
readonly property real changeRate: {
|
||||
if (!batteryAvailable) return 0
|
||||
if (usePreferred && device && device.ready) return device.changeRate
|
||||
return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0
|
||||
if (!batteryAvailable)
|
||||
return 0;
|
||||
if (usePreferred && device && device.ready)
|
||||
return device.changeRate;
|
||||
return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.changeRate, 0) : 0;
|
||||
}
|
||||
|
||||
// Aggregated battery health
|
||||
readonly property string batteryHealth: {
|
||||
if (!batteryAvailable) return "N/A"
|
||||
if (!batteryAvailable)
|
||||
return "N/A";
|
||||
|
||||
// If a preferred battery is selected and ready
|
||||
if (usePreferred && device && device.ready && device.healthSupported) return `${Math.round(device.healthPercentage)}%`
|
||||
if (usePreferred && device && device.ready && device.healthSupported)
|
||||
return `${Math.round(device.healthPercentage)}%`;
|
||||
|
||||
// Otherwise, calculate the average health of all laptop batteries
|
||||
const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0)
|
||||
if (validBatteries.length === 0) return "N/A"
|
||||
const validBatteries = batteries.filter(b => b.healthSupported && b.healthPercentage > 0);
|
||||
if (validBatteries.length === 0)
|
||||
return "N/A";
|
||||
|
||||
const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length
|
||||
return `${Math.round(avgHealth)}%`
|
||||
const avgHealth = validBatteries.reduce((sum, b) => sum + b.healthPercentage, 0) / validBatteries.length;
|
||||
return `${Math.round(avgHealth)}%`;
|
||||
}
|
||||
|
||||
readonly property real batteryEnergy: {
|
||||
if (!batteryAvailable) return 0
|
||||
if (usePreferred && device && device.ready) return device.energy
|
||||
return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0
|
||||
if (!batteryAvailable)
|
||||
return 0;
|
||||
if (usePreferred && device && device.ready)
|
||||
return device.energy;
|
||||
return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energy, 0) : 0;
|
||||
}
|
||||
|
||||
// Total battery capacity (Wh)
|
||||
readonly property real batteryCapacity: {
|
||||
if (!batteryAvailable) return 0
|
||||
if (usePreferred && device && device.ready) return device.energyCapacity
|
||||
return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0
|
||||
if (!batteryAvailable)
|
||||
return 0;
|
||||
if (usePreferred && device && device.ready)
|
||||
return device.energyCapacity;
|
||||
return batteries.length > 0 ? batteries.reduce((sum, b) => sum + b.energyCapacity, 0) : 0;
|
||||
}
|
||||
|
||||
// Aggregated battery status
|
||||
readonly property string batteryStatus: {
|
||||
if (!batteryAvailable) {
|
||||
return "No Battery"
|
||||
return "No Battery";
|
||||
}
|
||||
|
||||
if (isCharging && !batteries.some(b => b.changeRate > 0)) return "Plugged In"
|
||||
if (isCharging && !batteries.some(b => b.changeRate > 0))
|
||||
return "Plugged In";
|
||||
|
||||
const states = batteries.map(b => b.state)
|
||||
if (states.every(s => s === states[0])) return UPowerDeviceState.toString(states[0])
|
||||
const states = batteries.map(b => b.state);
|
||||
if (states.every(s => s === states[0]))
|
||||
return UPowerDeviceState.toString(states[0]);
|
||||
|
||||
return isCharging ? "Charging" : (isPluggedIn ? "Plugged In" : "Discharging")
|
||||
return isCharging ? "Charging" : (isPluggedIn ? "Plugged In" : "Discharging");
|
||||
}
|
||||
|
||||
readonly property bool suggestPowerSaver: batteryAvailable && isLowBattery && UPower.onBattery && (typeof PowerProfiles !== "undefined" && PowerProfiles.profile !== PowerProfile.PowerSaver)
|
||||
readonly property bool suggestPowerSaver: false
|
||||
|
||||
readonly property var bluetoothDevices: {
|
||||
const btDevices = []
|
||||
const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers]
|
||||
const btDevices = [];
|
||||
const bluetoothTypes = [UPowerDeviceType.BluetoothGeneric, UPowerDeviceType.Headphones, UPowerDeviceType.Headset, UPowerDeviceType.Keyboard, UPowerDeviceType.Mouse, UPowerDeviceType.Speakers];
|
||||
|
||||
for (var i = 0; i < UPower.devices.count; i++) {
|
||||
const dev = UPower.devices.get(i)
|
||||
const dev = UPower.devices.get(i);
|
||||
if (dev && dev.ready && bluetoothTypes.includes(dev.type)) {
|
||||
btDevices.push({
|
||||
"name": dev.model || UPowerDeviceType.toString(dev.type),
|
||||
"percentage": Math.round(dev.percentage * 100),
|
||||
"type": dev.type
|
||||
})
|
||||
"name": dev.model || UPowerDeviceType.toString(dev.type),
|
||||
"percentage": Math.round(dev.percentage * 100),
|
||||
"type": dev.type
|
||||
});
|
||||
}
|
||||
}
|
||||
return btDevices
|
||||
return btDevices;
|
||||
}
|
||||
|
||||
// Format time remaining for charge/discharge
|
||||
function formatTimeRemaining() {
|
||||
if (!batteryAvailable) {
|
||||
return "Unknown"
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
let totalTime = 0
|
||||
totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate)
|
||||
const avgTime = Math.abs(totalTime * 3600)
|
||||
if (!avgTime || avgTime <= 0 || avgTime > 86400) return "Unknown"
|
||||
let totalTime = 0;
|
||||
totalTime = (isCharging) ? ((batteryCapacity - batteryEnergy) / changeRate) : (batteryEnergy / changeRate);
|
||||
const avgTime = Math.abs(totalTime * 3600);
|
||||
if (!avgTime || avgTime <= 0 || avgTime > 86400)
|
||||
return "Unknown";
|
||||
|
||||
const hours = Math.floor(avgTime / 3600)
|
||||
const minutes = Math.floor((avgTime % 3600) / 60)
|
||||
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`
|
||||
const hours = Math.floor(avgTime / 3600);
|
||||
const minutes = Math.floor((avgTime % 3600) / 60);
|
||||
return hours > 0 ? `${hours}h ${minutes}m` : `${minutes}m`;
|
||||
}
|
||||
|
||||
function getBatteryIcon() {
|
||||
if (!batteryAvailable) {
|
||||
return "power"
|
||||
return "power";
|
||||
}
|
||||
|
||||
if (isCharging) {
|
||||
if (batteryLevel >= 90) {
|
||||
return "battery_charging_full"
|
||||
return "battery_charging_full";
|
||||
}
|
||||
if (batteryLevel >= 80) {
|
||||
return "battery_charging_90"
|
||||
return "battery_charging_90";
|
||||
}
|
||||
if (batteryLevel >= 60) {
|
||||
return "battery_charging_80"
|
||||
return "battery_charging_80";
|
||||
}
|
||||
if (batteryLevel >= 50) {
|
||||
return "battery_charging_60"
|
||||
return "battery_charging_60";
|
||||
}
|
||||
if (batteryLevel >= 30) {
|
||||
return "battery_charging_50"
|
||||
return "battery_charging_50";
|
||||
}
|
||||
if (batteryLevel >= 20) {
|
||||
return "battery_charging_30"
|
||||
return "battery_charging_30";
|
||||
}
|
||||
return "battery_charging_20"
|
||||
return "battery_charging_20";
|
||||
}
|
||||
if (isPluggedIn) {
|
||||
if (batteryLevel >= 90) {
|
||||
return "battery_charging_full"
|
||||
return "battery_charging_full";
|
||||
}
|
||||
if (batteryLevel >= 80) {
|
||||
return "battery_charging_90"
|
||||
return "battery_charging_90";
|
||||
}
|
||||
if (batteryLevel >= 60) {
|
||||
return "battery_charging_80"
|
||||
return "battery_charging_80";
|
||||
}
|
||||
if (batteryLevel >= 50) {
|
||||
return "battery_charging_60"
|
||||
return "battery_charging_60";
|
||||
}
|
||||
if (batteryLevel >= 30) {
|
||||
return "battery_charging_50"
|
||||
return "battery_charging_50";
|
||||
}
|
||||
if (batteryLevel >= 20) {
|
||||
return "battery_charging_30"
|
||||
return "battery_charging_30";
|
||||
}
|
||||
return "battery_charging_20"
|
||||
return "battery_charging_20";
|
||||
}
|
||||
if (batteryLevel >= 95) {
|
||||
return "battery_full"
|
||||
return "battery_full";
|
||||
}
|
||||
if (batteryLevel >= 85) {
|
||||
return "battery_6_bar"
|
||||
return "battery_6_bar";
|
||||
}
|
||||
if (batteryLevel >= 70) {
|
||||
return "battery_5_bar"
|
||||
return "battery_5_bar";
|
||||
}
|
||||
if (batteryLevel >= 55) {
|
||||
return "battery_4_bar"
|
||||
return "battery_4_bar";
|
||||
}
|
||||
if (batteryLevel >= 40) {
|
||||
return "battery_3_bar"
|
||||
return "battery_3_bar";
|
||||
}
|
||||
if (batteryLevel >= 25) {
|
||||
return "battery_2_bar"
|
||||
return "battery_2_bar";
|
||||
}
|
||||
return "battery_1_bar"
|
||||
return "battery_1_bar";
|
||||
}
|
||||
}
|
||||
|
||||
36
quickshell/Services/PowerProfileWatcher.qml
Normal file
36
quickshell/Services/PowerProfileWatcher.qml
Normal file
@@ -0,0 +1,36 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Services.UPower
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property int currentProfile: -1
|
||||
property int previousProfile: -1
|
||||
|
||||
signal profileChanged(int profile)
|
||||
|
||||
Connections {
|
||||
target: typeof PowerProfiles !== "undefined" ? PowerProfiles : null
|
||||
|
||||
function onProfileChanged() {
|
||||
if (typeof PowerProfiles !== "undefined") {
|
||||
root.previousProfile = root.currentProfile;
|
||||
root.currentProfile = PowerProfiles.profile;
|
||||
if (root.previousProfile !== -1) {
|
||||
root.profileChanged(root.currentProfile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (typeof PowerProfiles !== "undefined") {
|
||||
root.currentProfile = PowerProfiles.profile;
|
||||
root.previousProfile = PowerProfiles.profile;
|
||||
}
|
||||
}
|
||||
}
|
||||
145
quickshell/Widgets/DankTooltipV2.qml
Normal file
145
quickshell/Widgets/DankTooltipV2.qml
Normal file
@@ -0,0 +1,145 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string text: ""
|
||||
|
||||
function show(text, item, offsetX, offsetY, preferredSide) {
|
||||
if (!item)
|
||||
return;
|
||||
|
||||
const windowContentItem = item.Window.window?.contentItem;
|
||||
if (!windowContentItem)
|
||||
return;
|
||||
|
||||
tooltip.parent = windowContentItem;
|
||||
tooltip.text = text;
|
||||
|
||||
const itemPos = item.mapToItem(windowContentItem, 0, 0);
|
||||
const parentWidth = windowContentItem.width;
|
||||
const parentHeight = windowContentItem.height;
|
||||
const tooltipWidth = tooltip.implicitWidth;
|
||||
const tooltipHeight = tooltip.implicitHeight;
|
||||
|
||||
const side = preferredSide || _determineBestSide(itemPos, item, parentWidth, parentHeight, tooltipWidth, tooltipHeight);
|
||||
|
||||
let targetX = 0;
|
||||
let targetY = 0;
|
||||
|
||||
switch (side) {
|
||||
case "left":
|
||||
targetX = itemPos.x - tooltipWidth - 8;
|
||||
targetY = itemPos.y + (item.height - tooltipHeight) / 2;
|
||||
break;
|
||||
case "right":
|
||||
targetX = itemPos.x + item.width + 8;
|
||||
targetY = itemPos.y + (item.height - tooltipHeight) / 2;
|
||||
break;
|
||||
case "top":
|
||||
targetX = itemPos.x + (item.width - tooltipWidth) / 2;
|
||||
targetY = itemPos.y - tooltipHeight - 8;
|
||||
break;
|
||||
case "bottom":
|
||||
default:
|
||||
targetX = itemPos.x + (item.width - tooltipWidth) / 2;
|
||||
targetY = itemPos.y + item.height + 8;
|
||||
break;
|
||||
}
|
||||
|
||||
tooltip.x = Math.max(4, Math.min(parentWidth - tooltipWidth - 4, targetX + (offsetX || 0)));
|
||||
tooltip.y = Math.max(4, Math.min(parentHeight - tooltipHeight - 4, targetY + (offsetY || 0)));
|
||||
|
||||
tooltip.open();
|
||||
}
|
||||
|
||||
function _determineBestSide(itemPos, item, parentWidth, parentHeight, tooltipWidth, tooltipHeight) {
|
||||
const itemCenterX = itemPos.x + item.width / 2;
|
||||
const itemCenterY = itemPos.y + item.height / 2;
|
||||
|
||||
const spaceLeft = itemPos.x;
|
||||
const spaceRight = parentWidth - (itemPos.x + item.width);
|
||||
const spaceTop = itemPos.y;
|
||||
const spaceBottom = parentHeight - (itemPos.y + item.height);
|
||||
|
||||
if (spaceRight >= tooltipWidth + 16) {
|
||||
return "right";
|
||||
}
|
||||
if (spaceLeft >= tooltipWidth + 16) {
|
||||
return "left";
|
||||
}
|
||||
if (spaceBottom >= tooltipHeight + 16) {
|
||||
return "bottom";
|
||||
}
|
||||
if (spaceTop >= tooltipHeight + 16) {
|
||||
return "top";
|
||||
}
|
||||
|
||||
if (itemCenterX > parentWidth / 2) {
|
||||
return "left";
|
||||
}
|
||||
return "right";
|
||||
}
|
||||
|
||||
function hide() {
|
||||
tooltip.close();
|
||||
}
|
||||
|
||||
Popup {
|
||||
id: tooltip
|
||||
|
||||
property string text: ""
|
||||
|
||||
implicitWidth: Math.min(300, Math.max(120, textContent.implicitWidth + Theme.spacingM * 2))
|
||||
implicitHeight: textContent.implicitHeight + Theme.spacingS * 2
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
|
||||
padding: 0
|
||||
closePolicy: Popup.NoAutoClose
|
||||
modal: false
|
||||
dim: false
|
||||
|
||||
background: Rectangle {
|
||||
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
}
|
||||
|
||||
contentItem: Text {
|
||||
id: textContent
|
||||
|
||||
text: tooltip.text
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
wrapMode: Text.NoWrap
|
||||
maximumLineCount: 1
|
||||
elide: Text.ElideRight
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
}
|
||||
|
||||
enter: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 0
|
||||
to: 1
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
exit: Transition {
|
||||
NumberAnimation {
|
||||
property: "opacity"
|
||||
from: 1
|
||||
to: 0
|
||||
duration: Theme.shorterDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user