mirror of
https://github.com/zoriya/noctalia-shell.git
synced 2025-12-06 06:36:15 +00:00
Switched to qmlformat.
This commit is contained in:
@@ -2,38 +2,28 @@
|
|||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
# QML Formatter Script
|
# QML Formatter Script
|
||||||
# Uses: https://github.com/jesperhh/qmlfmt
|
|
||||||
# Install: AUR package "qmlfmt-git" (requires qt6-5compat)
|
|
||||||
|
|
||||||
if command -v qmlfmt &>/dev/null; then
|
# Find qmlformat binary
|
||||||
echo "Using 'qmlfmt' for formatting."
|
if command -v qmlformat &>/dev/null; then
|
||||||
format_file() { qmlfmt -e -b 360 -t 2 -i 2 -w "$1" || { echo "Failed: $1" >&2; return 1; }; }
|
QMLFORMAT="qmlformat"
|
||||||
|
elif [ -x "/usr/lib/qt6/bin/qmlformat" ]; then
|
||||||
|
QMLFORMAT="/usr/lib/qt6/bin/qmlformat"
|
||||||
else
|
else
|
||||||
echo "No 'qmlfmt' found in PATH." >&2
|
echo "No 'qmlformat' found in PATH or /usr/lib/qt6/bin." >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "Using 'qmlformat' for formatting: $QMLFORMAT"
|
||||||
|
export QMLFORMAT
|
||||||
|
format_file() { "$QMLFORMAT" -w 2 -W 360 -S --semicolon-rule always -i "$1" || { echo "Failed: $1" >&2; return 1; }; }
|
||||||
|
|
||||||
export -f format_file
|
export -f format_file
|
||||||
|
|
||||||
# Find all .qml files
|
# Find all .qml files
|
||||||
mapfile -t all_files < <(find "${1:-.}" -name "*.qml" -type f)
|
mapfile -t all_files < <(find "${1:-.}" -name "*.qml" -type f)
|
||||||
[ ${#all_files[@]} -eq 0 ] && { echo "No QML files found"; exit 0; }
|
[ ${#all_files[@]} -eq 0 ] && { echo "No QML files found"; exit 0; }
|
||||||
|
|
||||||
echo "Scanning ${#all_files[@]} files for array destructuring..."
|
echo "Formatting ${#all_files[@]} files..."
|
||||||
safe_files=()
|
printf '%s\0' "${all_files[@]}" | \
|
||||||
for file in "${all_files[@]}"; do
|
|
||||||
# Checks for a comma inside brackets followed by an equals sign aka "array destructuring"
|
|
||||||
# as this ES6 syntax is not supported by qmlfmt and will result in breakage.
|
|
||||||
if grep -qE '\[.*,.*\]\s*=' "$file"; then
|
|
||||||
echo "-> Skipping (Array destructuring detected): $file" >&2
|
|
||||||
else
|
|
||||||
safe_files+=("$file")
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
[ ${#safe_files[@]} -eq 0 ] && { echo "No safe files to format after filtering."; exit 0; }
|
|
||||||
|
|
||||||
echo "Formatting ${#safe_files[@]} files..."
|
|
||||||
printf '%s\0' "${safe_files[@]}" | \
|
|
||||||
xargs -0 -P "${QMLFMT_JOBS:-$(nproc)}" -I {} bash -c 'format_file "$@"' _ {} \
|
xargs -0 -P "${QMLFMT_JOBS:-$(nproc)}" -I {} bash -c 'format_file "$@"' _ {} \
|
||||||
&& echo "Done" || { echo "Errors occurred" >&2; exit 1; }
|
&& echo "Done" || { echo "Errors occurred" >&2; exit 1; }
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#!/usr/bin/env -S bash
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# QML Formatter Script
|
|
||||||
|
|
||||||
# Find qmlformat binary
|
|
||||||
if command -v qmlformat &>/dev/null; then
|
|
||||||
QMLFORMAT="qmlformat"
|
|
||||||
elif [ -x "/usr/lib/qt6/bin/qmlformat" ]; then
|
|
||||||
QMLFORMAT="/usr/lib/qt6/bin/qmlformat"
|
|
||||||
else
|
|
||||||
echo "No 'qmlformat' found in PATH or /usr/lib/qt6/bin." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Using 'qmlformat' for formatting: $QMLFORMAT"
|
|
||||||
export QMLFORMAT
|
|
||||||
format_file() { "$QMLFORMAT" -w 2 -W 360 -S --semicolon-rule always -i "$1" || { echo "Failed: $1" >&2; return 1; }; }
|
|
||||||
|
|
||||||
export -f format_file
|
|
||||||
|
|
||||||
# Find all .qml files
|
|
||||||
mapfile -t all_files < <(find "${1:-.}" -name "*.qml" -type f)
|
|
||||||
[ ${#all_files[@]} -eq 0 ] && { echo "No QML files found"; exit 0; }
|
|
||||||
|
|
||||||
echo "Formatting ${#all_files[@]} files..."
|
|
||||||
printf '%s\0' "${all_files[@]}" | \
|
|
||||||
xargs -0 -P "${QMLFMT_JOBS:-$(nproc)}" -I {} bash -c 'format_file "$@"' _ {} \
|
|
||||||
&& echo "Done" || { echo "Errors occurred" >&2; exit 1; }
|
|
||||||
@@ -5,16 +5,15 @@ import Quickshell
|
|||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Noctalia is not strictly a Material Design project, it supports both some predefined
|
Noctalia is not strictly a Material Design project, it supports both some predefined
|
||||||
color schemes and dynamic color generation from the wallpaper (using Matugen).
|
color schemes and dynamic color generation from the wallpaper (using Matugen).
|
||||||
|
|
||||||
We ultimately decided to use a restricted set of colors that follows the
|
We ultimately decided to use a restricted set of colors that follows the
|
||||||
Material Design 3 naming convention.
|
Material Design 3 naming convention.
|
||||||
|
|
||||||
NOTE: All color names are prefixed with 'm' (e.g., mPrimary) to prevent QML from
|
NOTE: All color names are prefixed with 'm' (e.g., mPrimary) to prevent QML from
|
||||||
misinterpreting them as signals (e.g., the 'onPrimary' property name).
|
misinterpreting them as signals (e.g., the 'onPrimary' property name).
|
||||||
*/
|
*/
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -87,25 +86,25 @@ Singleton {
|
|||||||
printErrors: false
|
printErrors: false
|
||||||
watchChanges: true
|
watchChanges: true
|
||||||
onFileChanged: {
|
onFileChanged: {
|
||||||
Logger.i("Color", "Reloading colors from disk")
|
Logger.i("Color", "Reloading colors from disk");
|
||||||
reload()
|
reload();
|
||||||
}
|
}
|
||||||
onAdapterUpdated: {
|
onAdapterUpdated: {
|
||||||
Logger.i("Color", "Writing colors to disk")
|
Logger.i("Color", "Writing colors to disk");
|
||||||
writeAdapter()
|
writeAdapter();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trigger initial load when path changes from empty to actual path
|
// Trigger initial load when path changes from empty to actual path
|
||||||
onPathChanged: {
|
onPathChanged: {
|
||||||
if (path !== undefined) {
|
if (path !== undefined) {
|
||||||
reload()
|
reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onLoadFailed: function (error) {
|
onLoadFailed: function (error) {
|
||||||
// Error code 2 = ENOENT (No such file or directory)
|
// Error code 2 = ENOENT (No such file or directory)
|
||||||
if (error === 2 || error.toString().includes("No such file")) {
|
if (error === 2 || error.toString().includes("No such file")) {
|
||||||
// File doesn't exist, create it with default values
|
// File doesn't exist, create it with default values
|
||||||
writeAdapter()
|
writeAdapter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
JsonAdapter {
|
JsonAdapter {
|
||||||
|
|||||||
253
Commons/I18n.qml
253
Commons/I18n.qml
@@ -33,13 +33,13 @@ Singleton {
|
|||||||
|
|
||||||
onExited: function (exitCode, exitStatus) {
|
onExited: function (exitCode, exitStatus) {
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
var output = stdoutCollector.text || ""
|
var output = stdoutCollector.text || "";
|
||||||
parseDirectoryListing(output)
|
parseDirectoryListing(output);
|
||||||
} else {
|
} else {
|
||||||
Logger.e("I18n", `Failed to scan translation directory`)
|
Logger.e("I18n", `Failed to scan translation directory`);
|
||||||
// Fallback to default languages
|
// Fallback to default languages
|
||||||
availableLanguages = ["en"]
|
availableLanguages = ["en"];
|
||||||
detectLanguage()
|
detectLanguage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,21 +51,21 @@ Singleton {
|
|||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
try {
|
try {
|
||||||
var data = JSON.parse(text())
|
var data = JSON.parse(text());
|
||||||
root.translations = data
|
root.translations = data;
|
||||||
Logger.i("I18n", `Loaded translations for "${root.langCode}"`)
|
Logger.i("I18n", `Loaded translations for "${root.langCode}"`);
|
||||||
Logger.d("I18n", `Available root keys: ${Object.keys(data).join(", ")}`)
|
Logger.d("I18n", `Available root keys: ${Object.keys(data).join(", ")}`);
|
||||||
|
|
||||||
root.isLoaded = true
|
root.isLoaded = true;
|
||||||
root.translationsLoaded()
|
root.translationsLoaded();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.e("I18n", `Failed to parse translation file: ${e}`)
|
Logger.e("I18n", `Failed to parse translation file: ${e}`);
|
||||||
setLanguage("en")
|
setLanguage("en");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onLoadFailed: function (error) {
|
onLoadFailed: function (error) {
|
||||||
setLanguage("en")
|
setLanguage("en");
|
||||||
Logger.e("I18n", `Failed to load translation file: ${error}`)
|
Logger.e("I18n", `Failed to load translation file: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,162 +76,161 @@ Singleton {
|
|||||||
onFileChanged: reload()
|
onFileChanged: reload()
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
try {
|
try {
|
||||||
var data = JSON.parse(text())
|
var data = JSON.parse(text());
|
||||||
root.fallbackTranslations = data
|
root.fallbackTranslations = data;
|
||||||
Logger.d("I18n", `Loaded english fallback translations`)
|
Logger.d("I18n", `Loaded english fallback translations`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.e("I18n", `Failed to parse fallback translation file: ${e}`)
|
Logger.e("I18n", `Failed to parse fallback translation file: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onLoadFailed: function (error) {
|
onLoadFailed: function (error) {
|
||||||
Logger.e("I18n", `Failed to load fallback translation file: ${error}`)
|
Logger.e("I18n", `Failed to load fallback translation file: ${error}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.i("I18n", "Service started")
|
Logger.i("I18n", "Service started");
|
||||||
scanAvailableLanguages()
|
scanAvailableLanguages();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
function scanAvailableLanguages() {
|
function scanAvailableLanguages() {
|
||||||
Logger.d("I18n", "Scanning for available translation files...")
|
Logger.d("I18n", "Scanning for available translation files...");
|
||||||
directoryScanner.running = true
|
directoryScanner.running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
function parseDirectoryListing(output) {
|
function parseDirectoryListing(output) {
|
||||||
var languages = []
|
var languages = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!output || output.trim() === "") {
|
if (!output || output.trim() === "") {
|
||||||
Logger.w("I18n", "Empty directory listing output")
|
Logger.w("I18n", "Empty directory listing output");
|
||||||
availableLanguages = ["en"]
|
availableLanguages = ["en"];
|
||||||
detectLanguage()
|
detectLanguage();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const entries = output.trim().split('\n')
|
const entries = output.trim().split('\n');
|
||||||
|
|
||||||
for (var i = 0; i < entries.length; i++) {
|
for (var i = 0; i < entries.length; i++) {
|
||||||
const entry = entries[i].trim()
|
const entry = entries[i].trim();
|
||||||
if (entry && entry.endsWith('.json')) {
|
if (entry && entry.endsWith('.json')) {
|
||||||
// Extract language code from filename (e.g., "en.json" -> "en")
|
// Extract language code from filename (e.g., "en.json" -> "en")
|
||||||
const langCode = entry.substring(0, entry.lastIndexOf('.json'))
|
const langCode = entry.substring(0, entry.lastIndexOf('.json'));
|
||||||
if (langCode.length >= 2 && langCode.length <= 5) {
|
if (langCode.length >= 2 && langCode.length <= 5) {
|
||||||
// Basic validation for language codes
|
// Basic validation for language codes
|
||||||
languages.push(langCode)
|
languages.push(langCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sort languages alphabetically, but ensure "en" comes first if available
|
// Sort languages alphabetically, but ensure "en" comes first if available
|
||||||
languages.sort()
|
languages.sort();
|
||||||
const enIndex = languages.indexOf("en")
|
const enIndex = languages.indexOf("en");
|
||||||
if (enIndex > 0) {
|
if (enIndex > 0) {
|
||||||
languages.splice(enIndex, 1)
|
languages.splice(enIndex, 1);
|
||||||
languages.unshift("en")
|
languages.unshift("en");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (languages.length === 0) {
|
if (languages.length === 0) {
|
||||||
Logger.w("I18n", "No translation files found, using fallback")
|
Logger.w("I18n", "No translation files found, using fallback");
|
||||||
languages = ["en"] // Fallback
|
languages = ["en"]; // Fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
availableLanguages = languages
|
availableLanguages = languages;
|
||||||
Logger.d("I18n", `Found ${languages.length} available languages: ${languages.join(', ')}`)
|
Logger.d("I18n", `Found ${languages.length} available languages: ${languages.join(', ')}`);
|
||||||
|
|
||||||
// Detect language after scanning
|
// Detect language after scanning
|
||||||
detectLanguage()
|
detectLanguage();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.e("I18n", `Failed to parse directory listing: ${e}`)
|
Logger.e("I18n", `Failed to parse directory listing: ${e}`);
|
||||||
// Fallback to default languages
|
// Fallback to default languages
|
||||||
availableLanguages = ["en"]
|
availableLanguages = ["en"];
|
||||||
detectLanguage()
|
detectLanguage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
function detectLanguage() {
|
function detectLanguage() {
|
||||||
Logger.d("I18n", `detectLanguage() called. Available languages: [${availableLanguages.join(', ')}]`)
|
Logger.d("I18n", `detectLanguage() called. Available languages: [${availableLanguages.join(', ')}]`);
|
||||||
|
|
||||||
if (availableLanguages.length === 0) {
|
if (availableLanguages.length === 0) {
|
||||||
Logger.w("I18n", "No available languages found")
|
Logger.w("I18n", "No available languages found");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var detectedLang = ""
|
var detectedLang = "";
|
||||||
var detectedFullLocale = ""
|
var detectedFullLocale = "";
|
||||||
|
|
||||||
// First, determine the system's preferred language
|
// First, determine the system's preferred language
|
||||||
for (var i = 0; i < Qt.locale().uiLanguages.length; i++) {
|
for (var i = 0; i < Qt.locale().uiLanguages.length; i++) {
|
||||||
const fullUserLang = Qt.locale().uiLanguages[i]
|
const fullUserLang = Qt.locale().uiLanguages[i];
|
||||||
|
|
||||||
if (availableLanguages.includes(fullUserLang)) {
|
if (availableLanguages.includes(fullUserLang)) {
|
||||||
detectedLang = fullUserLang
|
detectedLang = fullUserLang;
|
||||||
detectedFullLocale = fullUserLang
|
detectedFullLocale = fullUserLang;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const shortUserLang = fullUserLang.substring(0, 2)
|
const shortUserLang = fullUserLang.substring(0, 2);
|
||||||
if (availableLanguages.includes(shortUserLang)) {
|
if (availableLanguages.includes(shortUserLang)) {
|
||||||
detectedLang = shortUserLang
|
detectedLang = shortUserLang;
|
||||||
detectedFullLocale = fullUserLang
|
detectedFullLocale = fullUserLang;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no system language is found among available languages, fallback
|
// If no system language is found among available languages, fallback
|
||||||
if (detectedLang === "") {
|
if (detectedLang === "") {
|
||||||
detectedLang = availableLanguages.includes("en") ? "en" : availableLanguages[0]
|
detectedLang = availableLanguages.includes("en") ? "en" : availableLanguages[0];
|
||||||
detectedFullLocale = detectedLang
|
detectedFullLocale = detectedLang;
|
||||||
}
|
}
|
||||||
|
|
||||||
root.systemDetectedLangCode = detectedLang
|
root.systemDetectedLangCode = detectedLang;
|
||||||
root.fullLocaleCode = detectedFullLocale
|
root.fullLocaleCode = detectedFullLocale;
|
||||||
Logger.d("I18n", `System detected language: "${root.systemDetectedLangCode}" (full locale: "${root.fullLocaleCode}")`)
|
Logger.d("I18n", `System detected language: "${root.systemDetectedLangCode}" (full locale: "${root.fullLocaleCode}")`);
|
||||||
|
|
||||||
// Now, apply the language: user-defined, then system-detected
|
// Now, apply the language: user-defined, then system-detected
|
||||||
if (Settings.data.general.language !== "" && availableLanguages.includes(Settings.data.general.language)) {
|
if (Settings.data.general.language !== "" && availableLanguages.includes(Settings.data.general.language)) {
|
||||||
Logger.d("I18n", `User-defined language found: "${Settings.data.general.language}"`)
|
Logger.d("I18n", `User-defined language found: "${Settings.data.general.language}"`);
|
||||||
setLanguage(Settings.data.general.language)
|
setLanguage(Settings.data.general.language);
|
||||||
} else {
|
} else {
|
||||||
Logger.d("I18n", `No user-defined language, using system detected: "${root.systemDetectedLangCode}"`)
|
Logger.d("I18n", `No user-defined language, using system detected: "${root.systemDetectedLangCode}"`);
|
||||||
setLanguage(root.systemDetectedLangCode, root.fullLocaleCode)
|
setLanguage(root.systemDetectedLangCode, root.fullLocaleCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
function setLanguage(newLangCode, fullLocale) {
|
function setLanguage(newLangCode, fullLocale) {
|
||||||
if (typeof fullLocale === "undefined") {
|
if (typeof fullLocale === "undefined") {
|
||||||
fullLocale = newLangCode
|
fullLocale = newLangCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newLangCode !== langCode && availableLanguages.includes(newLangCode)) {
|
if (newLangCode !== langCode && availableLanguages.includes(newLangCode)) {
|
||||||
langCode = newLangCode
|
langCode = newLangCode;
|
||||||
fullLocaleCode = fullLocale
|
fullLocaleCode = fullLocale;
|
||||||
locale = Qt.locale(fullLocale)
|
locale = Qt.locale(fullLocale);
|
||||||
Logger.i("I18n", `Language set to "${langCode}" with locale "${fullLocale}"`)
|
Logger.i("I18n", `Language set to "${langCode}" with locale "${fullLocale}"`);
|
||||||
languageChanged(langCode)
|
languageChanged(langCode);
|
||||||
loadTranslations()
|
loadTranslations();
|
||||||
} else if (!availableLanguages.includes(newLangCode)) {
|
} else if (!availableLanguages.includes(newLangCode)) {
|
||||||
Logger.w("I18n", `Language "${newLangCode}" is not available`)
|
Logger.w("I18n", `Language "${newLangCode}" is not available`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
function loadTranslations() {
|
function loadTranslations() {
|
||||||
if (langCode === "")
|
if (langCode === "")
|
||||||
return
|
return;
|
||||||
|
const filePath = `file://${Quickshell.shellDir}/Assets/Translations/${langCode}.json`;
|
||||||
const filePath = `file://${Quickshell.shellDir}/Assets/Translations/${langCode}.json`
|
fileView.path = filePath;
|
||||||
fileView.path = filePath
|
isLoaded = false;
|
||||||
isLoaded = false
|
Logger.d("I18n", `Loading translations: ${langCode}`);
|
||||||
Logger.d("I18n", `Loading translations: ${langCode}`)
|
|
||||||
|
|
||||||
// Only load fallback translations if we are not using english and english is available
|
// Only load fallback translations if we are not using english and english is available
|
||||||
if (langCode !== "en" && availableLanguages.includes("en")) {
|
if (langCode !== "en" && availableLanguages.includes("en")) {
|
||||||
fallbackFileView.path = `file://${Quickshell.shellDir}/Assets/Translations/en.json`
|
fallbackFileView.path = `file://${Quickshell.shellDir}/Assets/Translations/en.json`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,133 +238,133 @@ Singleton {
|
|||||||
// Check if a translation exists
|
// Check if a translation exists
|
||||||
function hasTranslation(key) {
|
function hasTranslation(key) {
|
||||||
if (!isLoaded)
|
if (!isLoaded)
|
||||||
return false
|
return false;
|
||||||
|
|
||||||
const keys = key.split(".")
|
const keys = key.split(".");
|
||||||
var value = translations
|
var value = translations;
|
||||||
|
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
if (value && typeof value === "object" && keys[i] in value) {
|
if (value && typeof value === "object" && keys[i] in value) {
|
||||||
value = value[keys[i]]
|
value = value[keys[i]];
|
||||||
} else {
|
} else {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return typeof value === "string"
|
return typeof value === "string";
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// Get all translation keys (useful for debugging)
|
// Get all translation keys (useful for debugging)
|
||||||
function getAllKeys(obj, prefix) {
|
function getAllKeys(obj, prefix) {
|
||||||
if (typeof obj === "undefined")
|
if (typeof obj === "undefined")
|
||||||
obj = translations
|
obj = translations;
|
||||||
if (typeof prefix === "undefined")
|
if (typeof prefix === "undefined")
|
||||||
prefix = ""
|
prefix = "";
|
||||||
|
|
||||||
var keys = []
|
var keys = [];
|
||||||
for (var key in (obj || {})) {
|
for (var key in (obj || {})) {
|
||||||
const value = obj[key]
|
const value = obj[key];
|
||||||
const fullKey = prefix ? `${prefix}.${key}` : key
|
const fullKey = prefix ? `${prefix}.${key}` : key;
|
||||||
if (typeof value === "object" && value !== null) {
|
if (typeof value === "object" && value !== null) {
|
||||||
keys = keys.concat(getAllKeys(value, fullKey))
|
keys = keys.concat(getAllKeys(value, fullKey));
|
||||||
} else if (typeof value === "string") {
|
} else if (typeof value === "string") {
|
||||||
keys.push(fullKey)
|
keys.push(fullKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return keys
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// Reload translations (useful for development)
|
// Reload translations (useful for development)
|
||||||
function reload() {
|
function reload() {
|
||||||
Logger.d("I18n", "Reloading translations")
|
Logger.d("I18n", "Reloading translations");
|
||||||
loadTranslations()
|
loadTranslations();
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// Main translation function
|
// Main translation function
|
||||||
function tr(key, interpolations) {
|
function tr(key, interpolations) {
|
||||||
if (typeof interpolations === "undefined")
|
if (typeof interpolations === "undefined")
|
||||||
interpolations = {}
|
interpolations = {};
|
||||||
|
|
||||||
if (!isLoaded) {
|
if (!isLoaded) {
|
||||||
//Logger.d("I18n", "Translations not loaded yet")
|
//Logger.d("I18n", "Translations not loaded yet")
|
||||||
return key
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigate nested keys (e.g., "menu.file.open")
|
// Navigate nested keys (e.g., "menu.file.open")
|
||||||
const keys = key.split(".")
|
const keys = key.split(".");
|
||||||
|
|
||||||
// Look-up translation in the active language
|
// Look-up translation in the active language
|
||||||
var value = translations
|
var value = translations;
|
||||||
var notFound = false
|
var notFound = false;
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
if (value && typeof value === "object" && keys[i] in value) {
|
if (value && typeof value === "object" && keys[i] in value) {
|
||||||
value = value[keys[i]]
|
value = value[keys[i]];
|
||||||
} else {
|
} else {
|
||||||
Logger.d("I18n", `Translation key "${key}" not found at part "${keys[i]}"`)
|
Logger.d("I18n", `Translation key "${key}" not found at part "${keys[i]}"`);
|
||||||
Logger.d("I18n", `Available keys: ${Object.keys(value || {}).join(", ")}`)
|
Logger.d("I18n", `Available keys: ${Object.keys(value || {}).join(", ")}`);
|
||||||
notFound = true
|
notFound = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to english if not found
|
// Fallback to english if not found
|
||||||
if (notFound && availableLanguages.includes("en") && langCode !== "en") {
|
if (notFound && availableLanguages.includes("en") && langCode !== "en") {
|
||||||
value = fallbackTranslations
|
value = fallbackTranslations;
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
if (value && typeof value === "object" && keys[i] in value) {
|
if (value && typeof value === "object" && keys[i] in value) {
|
||||||
value = value[keys[i]]
|
value = value[keys[i]];
|
||||||
} else {
|
} else {
|
||||||
// Indicate this key does not even exists in the english fallback
|
// Indicate this key does not even exists in the english fallback
|
||||||
return `## ${key} ##`
|
return `## ${key} ##`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make untranslated string easy to spot
|
// Make untranslated string easy to spot
|
||||||
value = `<i>${value}</i>`
|
value = `<i>${value}</i>`;
|
||||||
} else if (notFound) {
|
} else if (notFound) {
|
||||||
// No fallback available
|
// No fallback available
|
||||||
return `## ${key} ##`
|
return `## ${key} ##`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof value !== "string") {
|
if (typeof value !== "string") {
|
||||||
Logger.d("I18n", `Translation key "${key}" is not a string`)
|
Logger.d("I18n", `Translation key "${key}" is not a string`);
|
||||||
return key
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle interpolations (e.g., "Hello {name}!")
|
// Handle interpolations (e.g., "Hello {name}!")
|
||||||
var result = value
|
var result = value;
|
||||||
for (var placeholder in interpolations) {
|
for (var placeholder in interpolations) {
|
||||||
const regex = new RegExp(`\\{${placeholder}\\}`, 'g')
|
const regex = new RegExp(`\\{${placeholder}\\}`, 'g');
|
||||||
result = result.replace(regex, interpolations[placeholder])
|
result = result.replace(regex, interpolations[placeholder]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------
|
// -------------------------------------------
|
||||||
// Plural translation function
|
// Plural translation function
|
||||||
function trp(key, count, defaultSingular, defaultPlural, interpolations) {
|
function trp(key, count, defaultSingular, defaultPlural, interpolations) {
|
||||||
if (typeof defaultSingular === "undefined")
|
if (typeof defaultSingular === "undefined")
|
||||||
defaultSingular = ""
|
defaultSingular = "";
|
||||||
if (typeof defaultPlural === "undefined")
|
if (typeof defaultPlural === "undefined")
|
||||||
defaultPlural = ""
|
defaultPlural = "";
|
||||||
if (typeof interpolations === "undefined")
|
if (typeof interpolations === "undefined")
|
||||||
interpolations = {}
|
interpolations = {};
|
||||||
|
|
||||||
const pluralKey = count === 1 ? key : `${key}_plural`
|
const pluralKey = count === 1 ? key : `${key}_plural`;
|
||||||
const defaultValue = count === 1 ? defaultSingular : defaultPlural
|
const defaultValue = count === 1 ? defaultSingular : defaultPlural;
|
||||||
|
|
||||||
// Merge interpolations with count (QML doesn't support spread operator)
|
// Merge interpolations with count (QML doesn't support spread operator)
|
||||||
var finalInterpolations = {
|
var finalInterpolations = {
|
||||||
"count": count
|
"count": count
|
||||||
}
|
};
|
||||||
for (var prop in interpolations) {
|
for (var prop in interpolations) {
|
||||||
finalInterpolations[prop] = interpolations[prop]
|
finalInterpolations[prop] = interpolations[prop];
|
||||||
}
|
}
|
||||||
|
|
||||||
return tr(pluralKey, finalInterpolations)
|
return tr(pluralKey, finalInterpolations);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,15 +26,15 @@ Singleton {
|
|||||||
signal fontReloaded
|
signal fontReloaded
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.i("Icons", "Service started")
|
Logger.i("Icons", "Service started");
|
||||||
loadFontWithCacheBusting()
|
loadFontWithCacheBusting();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Quickshell
|
target: Quickshell
|
||||||
function onReloadCompleted() {
|
function onReloadCompleted() {
|
||||||
Logger.d("Icons", "Quickshell reload completed - forcing font reload")
|
Logger.d("Icons", "Quickshell reload completed - forcing font reload");
|
||||||
reloadFont()
|
reloadFont();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,20 +42,20 @@ Singleton {
|
|||||||
function get(iconName) {
|
function get(iconName) {
|
||||||
// Check in aliases first
|
// Check in aliases first
|
||||||
if (aliases[iconName] !== undefined) {
|
if (aliases[iconName] !== undefined) {
|
||||||
iconName = aliases[iconName]
|
iconName = aliases[iconName];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the appropriate codepoint
|
// Find the appropriate codepoint
|
||||||
return icons[iconName]
|
return icons[iconName];
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadFontWithCacheBusting() {
|
function loadFontWithCacheBusting() {
|
||||||
Logger.d("Icons", "Loading font with cache busting")
|
Logger.d("Icons", "Loading font with cache busting");
|
||||||
|
|
||||||
// Destroy old loader first
|
// Destroy old loader first
|
||||||
if (currentFontLoader) {
|
if (currentFontLoader) {
|
||||||
currentFontLoader.destroy()
|
currentFontLoader.destroy();
|
||||||
currentFontLoader = null
|
currentFontLoader = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create new loader with cache-busting URL
|
// Create new loader with cache-busting URL
|
||||||
@@ -64,22 +64,22 @@ Singleton {
|
|||||||
FontLoader {
|
FontLoader {
|
||||||
source: "${cacheBustingPath}"
|
source: "${cacheBustingPath}"
|
||||||
}
|
}
|
||||||
`, root, "dynamicFontLoader_" + fontVersion)
|
`, root, "dynamicFontLoader_" + fontVersion);
|
||||||
|
|
||||||
// Connect to the new loader's status changes
|
// Connect to the new loader's status changes
|
||||||
currentFontLoader.statusChanged.connect(function () {
|
currentFontLoader.statusChanged.connect(function () {
|
||||||
if (currentFontLoader.status === FontLoader.Ready) {
|
if (currentFontLoader.status === FontLoader.Ready) {
|
||||||
Logger.d("Icons", "Font loaded successfully:", currentFontLoader.name, "(version " + fontVersion + ")")
|
Logger.d("Icons", "Font loaded successfully:", currentFontLoader.name, "(version " + fontVersion + ")");
|
||||||
fontReloaded()
|
fontReloaded();
|
||||||
} else if (currentFontLoader.status === FontLoader.Error) {
|
} else if (currentFontLoader.status === FontLoader.Error) {
|
||||||
Logger.e("Icons", "Font failed to load (version " + fontVersion + ")")
|
Logger.e("Icons", "Font failed to load (version " + fontVersion + ")");
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function reloadFont() {
|
function reloadFont() {
|
||||||
Logger.d("Icons", "Forcing font reload...")
|
Logger.d("Icons", "Forcing font reload...");
|
||||||
fontVersion++
|
fontVersion++;
|
||||||
loadFontWithCacheBusting()
|
loadFontWithCacheBusting();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -310,8 +310,8 @@ Singleton {
|
|||||||
"align-left": "\u{ea09}",
|
"align-left": "\u{ea09}",
|
||||||
"align-left-2": "\u{ff00}",
|
"align-left-2": "\u{ff00}",
|
||||||
"align-right": "\u{ea0a}",
|
"align-right": "\u{ea0a}",
|
||||||
"alpha"//"align-right-2": "\u{feff}",
|
//"align-right-2": "\u{feff}",
|
||||||
: "\u{f543}",
|
"alpha": "\u{f543}",
|
||||||
"alphabet-arabic": "\u{ff2f}",
|
"alphabet-arabic": "\u{ff2f}",
|
||||||
"alphabet-bangla": "\u{ff2e}",
|
"alphabet-bangla": "\u{ff2e}",
|
||||||
"alphabet-cyrillic": "\u{f1df}",
|
"alphabet-cyrillic": "\u{f1df}",
|
||||||
@@ -3143,8 +3143,8 @@ Singleton {
|
|||||||
"friends": "\u{eab0}",
|
"friends": "\u{eab0}",
|
||||||
"friends-off": "\u{f136}",
|
"friends-off": "\u{f136}",
|
||||||
"frustum": "\u{fa9f}",
|
"frustum": "\u{fa9f}",
|
||||||
"frustum-plus"//"frustum-off": "\u{fa9d}",
|
//"frustum-off": "\u{fa9d}",
|
||||||
: "\u{fa9e}",
|
"frustum-plus": "\u{fa9e}",
|
||||||
"function": "\u{f225}",
|
"function": "\u{f225}",
|
||||||
"function-filled": "\u{fc2b}",
|
"function-filled": "\u{fc2b}",
|
||||||
"function-off": "\u{f3f0}",
|
"function-off": "\u{f3f0}",
|
||||||
@@ -3403,13 +3403,13 @@ Singleton {
|
|||||||
"hexagon-letter-x": "\u{f479}",
|
"hexagon-letter-x": "\u{f479}",
|
||||||
"hexagon-letter-x-filled": "\u{fe30}",
|
"hexagon-letter-x-filled": "\u{fe30}",
|
||||||
"hexagon-letter-y": "\u{f47a}",
|
"hexagon-letter-y": "\u{f47a}",
|
||||||
"hexagon-letter-z"//"hexagon-letter-y-filled": "\u{fe2f}",
|
//"hexagon-letter-y-filled": "\u{fe2f}",
|
||||||
: "\u{f47b}",
|
"hexagon-letter-z": "\u{f47b}",
|
||||||
"hexagon-minus"//"hexagon-letter-z-filled": "\u{fe2e}",
|
//"hexagon-letter-z-filled": "\u{fe2e}",
|
||||||
: "\u{fc8f}",
|
"hexagon-minus": "\u{fc8f}",
|
||||||
"hexagon-minus-2": "\u{fc8e}",
|
"hexagon-minus-2": "\u{fc8e}",
|
||||||
"hexagon-number-0"//"hexagon-minus-filled": "\u{fe2d}",
|
//"hexagon-minus-filled": "\u{fe2d}",
|
||||||
: "\u{f459}",
|
"hexagon-number-0": "\u{f459}",
|
||||||
"hexagon-number-0-filled": "\u{f74c}",
|
"hexagon-number-0-filled": "\u{f74c}",
|
||||||
"hexagon-number-1": "\u{f45a}",
|
"hexagon-number-1": "\u{f45a}",
|
||||||
"hexagon-number-1-filled": "\u{f74d}",
|
"hexagon-number-1-filled": "\u{f74d}",
|
||||||
@@ -3432,8 +3432,8 @@ Singleton {
|
|||||||
"hexagon-off": "\u{ee9c}",
|
"hexagon-off": "\u{ee9c}",
|
||||||
"hexagon-plus": "\u{fc45}",
|
"hexagon-plus": "\u{fc45}",
|
||||||
"hexagon-plus-2": "\u{fc90}",
|
"hexagon-plus-2": "\u{fc90}",
|
||||||
"hexagonal-prism"//"hexagon-plus-filled": "\u{fe2c}",
|
//"hexagon-plus-filled": "\u{fe2c}",
|
||||||
: "\u{faa5}",
|
"hexagonal-prism": "\u{faa5}",
|
||||||
"hexagonal-prism-off": "\u{faa3}",
|
"hexagonal-prism-off": "\u{faa3}",
|
||||||
"hexagonal-prism-plus": "\u{faa4}",
|
"hexagonal-prism-plus": "\u{faa4}",
|
||||||
"hexagonal-pyramid": "\u{faa8}",
|
"hexagonal-pyramid": "\u{faa8}",
|
||||||
@@ -3463,8 +3463,8 @@ Singleton {
|
|||||||
"home-eco": "\u{f351}",
|
"home-eco": "\u{f351}",
|
||||||
"home-edit": "\u{f352}",
|
"home-edit": "\u{f352}",
|
||||||
"home-exclamation": "\u{f33c}",
|
"home-exclamation": "\u{f33c}",
|
||||||
"home-hand"//"home-filled": "\u{fe2b}",
|
//"home-filled": "\u{fe2b}",
|
||||||
: "\u{f504}",
|
"home-hand": "\u{f504}",
|
||||||
"home-heart": "\u{f353}",
|
"home-heart": "\u{f353}",
|
||||||
"home-infinity": "\u{f505}",
|
"home-infinity": "\u{f505}",
|
||||||
"home-link": "\u{f354}",
|
"home-link": "\u{f354}",
|
||||||
@@ -3582,8 +3582,8 @@ Singleton {
|
|||||||
"ironing-2-filled": "\u{1006e}",
|
"ironing-2-filled": "\u{1006e}",
|
||||||
"ironing-3": "\u{f2f6}",
|
"ironing-3": "\u{f2f6}",
|
||||||
"ironing-3-filled": "\u{1006d}",
|
"ironing-3-filled": "\u{1006d}",
|
||||||
"ironing-off"//"ironing-filled": "\u{fe2a}",
|
//"ironing-filled": "\u{fe2a}",
|
||||||
: "\u{f2f7}",
|
"ironing-off": "\u{f2f7}",
|
||||||
"ironing-steam": "\u{f2f9}",
|
"ironing-steam": "\u{f2f9}",
|
||||||
"ironing-steam-filled": "\u{1006c}",
|
"ironing-steam-filled": "\u{1006c}",
|
||||||
"ironing-steam-off": "\u{f2f8}",
|
"ironing-steam-off": "\u{f2f8}",
|
||||||
@@ -3593,8 +3593,8 @@ Singleton {
|
|||||||
"italic": "\u{eb93}",
|
"italic": "\u{eb93}",
|
||||||
"jacket": "\u{f661}",
|
"jacket": "\u{f661}",
|
||||||
"jetpack": "\u{f581}",
|
"jetpack": "\u{f581}",
|
||||||
"jewish-star"//"jetpack-filled": "\u{fe29}",
|
//"jetpack-filled": "\u{fe29}",
|
||||||
: "\u{f3ff}",
|
"jewish-star": "\u{f3ff}",
|
||||||
"jewish-star-filled": "\u{f67e}",
|
"jewish-star-filled": "\u{f67e}",
|
||||||
"join-bevel": "\u{ff4c}",
|
"join-bevel": "\u{ff4c}",
|
||||||
"join-round": "\u{ff4b}",
|
"join-round": "\u{ff4b}",
|
||||||
@@ -3608,8 +3608,8 @@ Singleton {
|
|||||||
"kering": "\u{efb8}",
|
"kering": "\u{efb8}",
|
||||||
"kerning": "\u{efb8}",
|
"kerning": "\u{efb8}",
|
||||||
"key": "\u{eac7}",
|
"key": "\u{eac7}",
|
||||||
"key-off"//"key-filled": "\u{fe28}",
|
//"key-filled": "\u{fe28}",
|
||||||
: "\u{f14b}",
|
"key-off": "\u{f14b}",
|
||||||
"keyboard": "\u{ebd6}",
|
"keyboard": "\u{ebd6}",
|
||||||
"keyboard-filled": "\u{100a2}",
|
"keyboard-filled": "\u{100a2}",
|
||||||
"keyboard-hide": "\u{ec7e}",
|
"keyboard-hide": "\u{ec7e}",
|
||||||
@@ -3665,20 +3665,20 @@ Singleton {
|
|||||||
"layers-union": "\u{eacb}",
|
"layers-union": "\u{eacb}",
|
||||||
"layout": "\u{eadb}",
|
"layout": "\u{eadb}",
|
||||||
"layout-2": "\u{eacc}",
|
"layout-2": "\u{eacc}",
|
||||||
"layout-align-left"//"layout-2-filled": "\u{fe27}",
|
//"layout-2-filled": "\u{fe27}",
|
||||||
// "layout-align-bottom": "\u{eacd}",
|
//"layout-align-bottom": "\u{eacd}",
|
||||||
//"layout-align-bottom-filled": "\u{fe26}",
|
//"layout-align-bottom-filled": "\u{fe26}",
|
||||||
// "layout-align-center": "\u{eace}",
|
//"layout-align-center": "\u{eace}",
|
||||||
//"layout-align-center-filled": "\u{fe25}",
|
//"layout-align-center-filled": "\u{fe25}",
|
||||||
: "\u{eacf}",
|
"layout-align-left": "\u{eacf}",
|
||||||
"layout-align-middle"// "layout-align-left-filled": "\u{fe24}",
|
//"layout-align-left-filled": "\u{fe24}",
|
||||||
: "\u{ead0}",
|
"layout-align-middle": "\u{ead0}",
|
||||||
"layout-align-right"//"layout-align-middle-filled": "\u{fe23}",
|
//"layout-align-middle-filled": "\u{fe23}",
|
||||||
: "\u{ead1}",
|
"layout-align-right": "\u{ead1}",
|
||||||
"layout-align-top"//"layout-align-right-filled": "\u{fe22}",
|
//"layout-align-right-filled": "\u{fe22}",
|
||||||
: "\u{ead2}",
|
"layout-align-top": "\u{ead2}",
|
||||||
"layout-board"//"layout-align-top-filled": "\u{fe21}",
|
//"layout-align-top-filled": "\u{fe21}",
|
||||||
: "\u{ef95}",
|
"layout-board": "\u{ef95}",
|
||||||
"layout-board-filled": "\u{10182}",
|
"layout-board-filled": "\u{10182}",
|
||||||
"layout-board-split": "\u{ef94}",
|
"layout-board-split": "\u{ef94}",
|
||||||
"layout-board-split-filled": "\u{10183}",
|
"layout-board-split-filled": "\u{10183}",
|
||||||
@@ -3690,8 +3690,8 @@ Singleton {
|
|||||||
"layout-bottombar-filled": "\u{fc37}",
|
"layout-bottombar-filled": "\u{fc37}",
|
||||||
"layout-bottombar-inactive": "\u{fd45}",
|
"layout-bottombar-inactive": "\u{fd45}",
|
||||||
"layout-cards": "\u{ec13}",
|
"layout-cards": "\u{ec13}",
|
||||||
"layout-collage"// "layout-cards-filled": "\u{fe20}",
|
//"layout-cards-filled": "\u{fe20}",
|
||||||
: "\u{f389}",
|
"layout-collage": "\u{f389}",
|
||||||
"layout-columns": "\u{ead4}",
|
"layout-columns": "\u{ead4}",
|
||||||
"layout-dashboard": "\u{f02c}",
|
"layout-dashboard": "\u{f02c}",
|
||||||
"layout-dashboard-filled": "\u{fe1f}",
|
"layout-dashboard-filled": "\u{fe1f}",
|
||||||
@@ -4172,14 +4172,14 @@ Singleton {
|
|||||||
"microphone": "\u{eaf0}",
|
"microphone": "\u{eaf0}",
|
||||||
"microphone-2": "\u{ef2c}",
|
"microphone-2": "\u{ef2c}",
|
||||||
"microphone-2-off": "\u{f40d}",
|
"microphone-2-off": "\u{f40d}",
|
||||||
"microphone-off"//"microphone-filled": "\u{fe0f}",
|
//"microphone-filled": "\u{fe0f}",
|
||||||
: "\u{ed16}",
|
"microphone-off": "\u{ed16}",
|
||||||
"microscope": "\u{ef64}",
|
"microscope": "\u{ef64}",
|
||||||
"microscope-filled": "\u{10166}",
|
"microscope-filled": "\u{10166}",
|
||||||
"microscope-off": "\u{f40e}",
|
"microscope-off": "\u{f40e}",
|
||||||
"microwave": "\u{f248}",
|
"microwave": "\u{f248}",
|
||||||
"microwave-off"//"microwave-filled": "\u{fe0e}",
|
//"microwave-filled": "\u{fe0e}",
|
||||||
: "\u{f264}",
|
"microwave-off": "\u{f264}",
|
||||||
"military-award": "\u{f079}",
|
"military-award": "\u{f079}",
|
||||||
"military-rank": "\u{efcf}",
|
"military-rank": "\u{efcf}",
|
||||||
"military-rank-filled": "\u{ff5e}",
|
"military-rank-filled": "\u{ff5e}",
|
||||||
@@ -4413,18 +4413,18 @@ Singleton {
|
|||||||
"number-4-small": "\u{fcf9}",
|
"number-4-small": "\u{fcf9}",
|
||||||
"number-40-small": "\u{fffa}",
|
"number-40-small": "\u{fffa}",
|
||||||
"number-41-small": "\u{fff9}",
|
"number-41-small": "\u{fff9}",
|
||||||
"number-5"//"number-42-small": "\u{fff8}",
|
//"number-42-small": "\u{fff8}",
|
||||||
// "number-43-small": "\u{fff7}",
|
//"number-43-small": "\u{fff7}",
|
||||||
// "number-44-small": "\u{fff6}",
|
//"number-44-small": "\u{fff6}",
|
||||||
// "number-45-small": "\u{fff5}",
|
//"number-45-small": "\u{fff5}",
|
||||||
// "number-46-small": "\u{fff4}",
|
//"number-46-small": "\u{fff4}",
|
||||||
// "number-47-small": "\u{fff3}",
|
//"number-47-small": "\u{fff3}",
|
||||||
// "number-48-small": "\u{fff2}",
|
//"number-48-small": "\u{fff2}",
|
||||||
// "number-49-small": "\u{fff1}",
|
//"number-49-small": "\u{fff1}",
|
||||||
: "\u{edf5}",
|
"number-5": "\u{edf5}",
|
||||||
"number-5-small": "\u{fcfa}",
|
"number-5-small": "\u{fcfa}",
|
||||||
"number-51-small"// "number-50-small": "\u{fff0}",
|
//"number-50-small": "\u{fff0}",
|
||||||
: "\u{ffef}",
|
"number-51-small": "\u{ffef}",
|
||||||
"number-52-small": "\u{ffee}",
|
"number-52-small": "\u{ffee}",
|
||||||
"number-53-small": "\u{ffed}",
|
"number-53-small": "\u{ffed}",
|
||||||
"number-54-small": "\u{ffec}",
|
"number-54-small": "\u{ffec}",
|
||||||
@@ -4864,11 +4864,11 @@ Singleton {
|
|||||||
"quote": "\u{efbe}",
|
"quote": "\u{efbe}",
|
||||||
"quote-filled": "\u{1009c}",
|
"quote-filled": "\u{1009c}",
|
||||||
"quote-off": "\u{f188}",
|
"quote-off": "\u{f188}",
|
||||||
"radar"//"quotes": "\u{fb1e}",
|
//"quotes": "\u{fb1e}",
|
||||||
: "\u{f017}",
|
"radar": "\u{f017}",
|
||||||
"radar-2": "\u{f016}",
|
"radar-2": "\u{f016}",
|
||||||
"radar-off"//"radar-filled": "\u{fe0d}",
|
//"radar-filled": "\u{fe0d}",
|
||||||
: "\u{f41f}",
|
"radar-off": "\u{f41f}",
|
||||||
"radio": "\u{ef2d}",
|
"radio": "\u{ef2d}",
|
||||||
"radio-off": "\u{f420}",
|
"radio-off": "\u{f420}",
|
||||||
"radioactive": "\u{ecc0}",
|
"radioactive": "\u{ecc0}",
|
||||||
@@ -4928,12 +4928,12 @@ Singleton {
|
|||||||
"regex-off": "\u{f421}",
|
"regex-off": "\u{f421}",
|
||||||
"registered": "\u{eb14}",
|
"registered": "\u{eb14}",
|
||||||
"relation-many-to-many": "\u{ed7f}",
|
"relation-many-to-many": "\u{ed7f}",
|
||||||
"relation-one-to-many"//"relation-many-to-many-filled": "\u{fe0c}",
|
//"relation-many-to-many-filled": "\u{fe0c}",
|
||||||
: "\u{ed80}",
|
"relation-one-to-many": "\u{ed80}",
|
||||||
"relation-one-to-one"//"relation-one-to-many-filled": "\u{fe0b}",
|
//"relation-one-to-many-filled": "\u{fe0b}",
|
||||||
: "\u{ed81}",
|
"relation-one-to-one": "\u{ed81}",
|
||||||
"reload"//"relation-one-to-one-filled": "\u{fe0a}",
|
//"relation-one-to-one-filled": "\u{fe0a}",
|
||||||
: "\u{f3ae}",
|
"reload": "\u{f3ae}",
|
||||||
"reorder": "\u{fc15}",
|
"reorder": "\u{fc15}",
|
||||||
"repeat": "\u{eb72}",
|
"repeat": "\u{eb72}",
|
||||||
"repeat-off": "\u{f18e}",
|
"repeat-off": "\u{f18e}",
|
||||||
@@ -5085,8 +5085,8 @@ Singleton {
|
|||||||
"search": "\u{eb1c}",
|
"search": "\u{eb1c}",
|
||||||
"search-off": "\u{f19c}",
|
"search-off": "\u{f19c}",
|
||||||
"section": "\u{eed5}",
|
"section": "\u{eed5}",
|
||||||
"section-sign"//"section-filled": "\u{fe09}",
|
//"section-filled": "\u{fe09}",
|
||||||
: "\u{f019}",
|
"section-sign": "\u{f019}",
|
||||||
"seeding": "\u{ed51}",
|
"seeding": "\u{ed51}",
|
||||||
"seeding-filled": "\u{10006}",
|
"seeding-filled": "\u{10006}",
|
||||||
"seeding-off": "\u{f19d}",
|
"seeding-off": "\u{f19d}",
|
||||||
@@ -5294,8 +5294,8 @@ Singleton {
|
|||||||
"sort-z-a": "\u{f550}",
|
"sort-z-a": "\u{f550}",
|
||||||
"sos": "\u{f24a}",
|
"sos": "\u{f24a}",
|
||||||
"soup": "\u{ef2e}",
|
"soup": "\u{ef2e}",
|
||||||
"soup-off"//"soup-filled": "\u{fe08}",
|
//"soup-filled": "\u{fe08}",
|
||||||
: "\u{f42d}",
|
"soup-off": "\u{f42d}",
|
||||||
"source-code": "\u{f4a2}",
|
"source-code": "\u{f4a2}",
|
||||||
"space": "\u{ec0c}",
|
"space": "\u{ec0c}",
|
||||||
"space-off": "\u{f1aa}",
|
"space-off": "\u{f1aa}",
|
||||||
@@ -5388,22 +5388,22 @@ Singleton {
|
|||||||
"square-half": "\u{effb}",
|
"square-half": "\u{effb}",
|
||||||
"square-key": "\u{f638}",
|
"square-key": "\u{f638}",
|
||||||
"square-letter-a": "\u{f47c}",
|
"square-letter-a": "\u{f47c}",
|
||||||
"square-letter-b"//"square-letter-a-filled": "\u{fe07}",
|
//"square-letter-a-filled": "\u{fe07}",
|
||||||
: "\u{f47d}",
|
"square-letter-b": "\u{f47d}",
|
||||||
"square-letter-c"//"square-letter-b-filled": "\u{fe06}",
|
//"square-letter-b-filled": "\u{fe06}",
|
||||||
: "\u{f47e}",
|
"square-letter-c": "\u{f47e}",
|
||||||
"square-letter-d"//"square-letter-c-filled": "\u{fe05}",
|
//"square-letter-c-filled": "\u{fe05}",
|
||||||
: "\u{f47f}",
|
"square-letter-d": "\u{f47f}",
|
||||||
"square-letter-e"//"square-letter-d-filled": "\u{fe04}",
|
//"square-letter-d-filled": "\u{fe04}",
|
||||||
: "\u{f480}",
|
"square-letter-e": "\u{f480}",
|
||||||
"square-letter-f"//"square-letter-e-filled": "\u{fe03}",
|
//"square-letter-e-filled": "\u{fe03}",
|
||||||
: "\u{f481}",
|
"square-letter-f": "\u{f481}",
|
||||||
"square-letter-g"//"square-letter-f-filled": "\u{fe02}",
|
//"square-letter-f-filled": "\u{fe02}",
|
||||||
: "\u{f482}",
|
"square-letter-g": "\u{f482}",
|
||||||
"square-letter-h"//"square-letter-g-filled": "\u{fe01}",
|
//"square-letter-g-filled": "\u{fe01}",
|
||||||
: "\u{f483}",
|
"square-letter-h": "\u{f483}",
|
||||||
"square-letter-i"//"square-letter-h-filled": "\u{fe00}",
|
//"square-letter-h-filled": "\u{fe00}",
|
||||||
: "\u{f484}",
|
"square-letter-i": "\u{f484}",
|
||||||
"square-letter-i-filled": "\u{fdff}",
|
"square-letter-i-filled": "\u{fdff}",
|
||||||
"square-letter-j": "\u{f485}",
|
"square-letter-j": "\u{f485}",
|
||||||
"square-letter-j-filled": "\u{fdfe}",
|
"square-letter-j-filled": "\u{fdfe}",
|
||||||
|
|||||||
@@ -7,63 +7,63 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
function _formatMessage(...args) {
|
function _formatMessage(...args) {
|
||||||
var t = Time.getFormattedTimestamp()
|
var t = Time.getFormattedTimestamp();
|
||||||
if (args.length > 1) {
|
if (args.length > 1) {
|
||||||
const maxLength = 14
|
const maxLength = 14;
|
||||||
var module = args.shift().substring(0, maxLength).padStart(maxLength, " ")
|
var module = args.shift().substring(0, maxLength).padStart(maxLength, " ");
|
||||||
return `\x1b[36m[${t}]\x1b[0m \x1b[35m${module}\x1b[0m ` + args.join(" ")
|
return `\x1b[36m[${t}]\x1b[0m \x1b[35m${module}\x1b[0m ` + args.join(" ");
|
||||||
} else {
|
} else {
|
||||||
return `[\x1b[36m[${t}]\x1b[0m ` + args.join(" ")
|
return `[\x1b[36m[${t}]\x1b[0m ` + args.join(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getStackTrace() {
|
function _getStackTrace() {
|
||||||
try {
|
try {
|
||||||
throw new Error("Stack trace")
|
throw new Error("Stack trace");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return e.stack
|
return e.stack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug log (only when Settings.isDebug is true)
|
// Debug log (only when Settings.isDebug is true)
|
||||||
function d(...args) {
|
function d(...args) {
|
||||||
if (Settings && Settings.isDebug) {
|
if (Settings?.isDebug) {
|
||||||
var msg = _formatMessage(...args)
|
var msg = _formatMessage(...args);
|
||||||
console.debug(msg)
|
console.debug(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info log (always visible)
|
// Info log (always visible)
|
||||||
function i(...args) {
|
function i(...args) {
|
||||||
var msg = _formatMessage(...args)
|
var msg = _formatMessage(...args);
|
||||||
console.info(msg)
|
console.info(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Warning log (always visible)
|
// Warning log (always visible)
|
||||||
function w(...args) {
|
function w(...args) {
|
||||||
var msg = _formatMessage(...args)
|
var msg = _formatMessage(...args);
|
||||||
console.warn(msg)
|
console.warn(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error log (always visible)
|
// Error log (always visible)
|
||||||
function e(...args) {
|
function e(...args) {
|
||||||
var msg = _formatMessage(...args)
|
var msg = _formatMessage(...args);
|
||||||
console.error(msg)
|
console.error(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
function callStack() {
|
function callStack() {
|
||||||
var stack = _getStackTrace()
|
var stack = _getStackTrace();
|
||||||
Logger.i("Debug", "--------------------------")
|
Logger.i("Debug", "--------------------------");
|
||||||
Logger.i("Debug", "Current call stack")
|
Logger.i("Debug", "Current call stack");
|
||||||
// Split the stack into lines and log each one
|
// Split the stack into lines and log each one
|
||||||
var stackLines = stack.split('\n')
|
var stackLines = stack.split('\n');
|
||||||
for (var i = 0; i < stackLines.length; i++) {
|
for (var i = 0; i < stackLines.length; i++) {
|
||||||
var line = stackLines[i].trim() // Remove leading/trailing whitespace
|
var line = stackLines[i].trim(); // Remove leading/trailing whitespace
|
||||||
if (line.length > 0) {
|
if (line.length > 0) {
|
||||||
// Only log non-empty lines
|
// Only log non-empty lines
|
||||||
Logger.i("Debug", `- ${line}`)
|
Logger.i("Debug", `- ${line}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.i("Debug", "--------------------------")
|
Logger.i("Debug", "--------------------------");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ pragma Singleton
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import "../Helpers/QtObj2JS.js" as QtObj2JS
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import "../Helpers/QtObj2JS.js" as QtObj2JS
|
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
@@ -42,30 +42,30 @@ Singleton {
|
|||||||
// Ensure directories exist before FileView tries to read files
|
// Ensure directories exist before FileView tries to read files
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// ensure settings dir exists
|
// ensure settings dir exists
|
||||||
Quickshell.execDetached(["mkdir", "-p", configDir])
|
Quickshell.execDetached(["mkdir", "-p", configDir]);
|
||||||
Quickshell.execDetached(["mkdir", "-p", cacheDir])
|
Quickshell.execDetached(["mkdir", "-p", cacheDir]);
|
||||||
|
|
||||||
Quickshell.execDetached(["mkdir", "-p", cacheDirImagesWallpapers])
|
Quickshell.execDetached(["mkdir", "-p", cacheDirImagesWallpapers]);
|
||||||
Quickshell.execDetached(["mkdir", "-p", cacheDirImagesNotifications])
|
Quickshell.execDetached(["mkdir", "-p", cacheDirImagesNotifications]);
|
||||||
|
|
||||||
// Mark directories as created and trigger file loading
|
// Mark directories as created and trigger file loading
|
||||||
directoriesCreated = true
|
directoriesCreated = true;
|
||||||
|
|
||||||
// This should only be activated once when the settings structure has changed
|
// This should only be activated once when the settings structure has changed
|
||||||
// Then it should be commented out again, regular users don't need to generate
|
// Then it should be commented out again, regular users don't need to generate
|
||||||
// default settings on every start
|
// default settings on every start
|
||||||
if (isDebug) {
|
if (isDebug) {
|
||||||
generateDefaultSettings()
|
generateDefaultSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Patch-in the local default, resolved to user's home
|
// Patch-in the local default, resolved to user's home
|
||||||
adapter.general.avatarImage = defaultAvatar
|
adapter.general.avatarImage = defaultAvatar;
|
||||||
adapter.screenRecorder.directory = defaultVideosDirectory
|
adapter.screenRecorder.directory = defaultVideosDirectory;
|
||||||
adapter.wallpaper.directory = defaultWallpapersDirectory
|
adapter.wallpaper.directory = defaultWallpapersDirectory;
|
||||||
adapter.wallpaper.defaultWallpaper = Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png"
|
adapter.wallpaper.defaultWallpaper = Quickshell.shellDir + "/Assets/Wallpaper/noctalia.png";
|
||||||
|
|
||||||
// Set the adapter to the settingsFileView to trigger the real settings load
|
// Set the adapter to the settingsFileView to trigger the real settings load
|
||||||
settingsFileView.adapter = adapter
|
settingsFileView.adapter = adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't write settings to disk immediately
|
// Don't write settings to disk immediately
|
||||||
@@ -75,7 +75,7 @@ Singleton {
|
|||||||
running: false
|
running: false
|
||||||
interval: 1000
|
interval: 1000
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.saveImmediate()
|
root.saveImmediate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,31 +90,31 @@ Singleton {
|
|||||||
// Trigger initial load when path changes from empty to actual path
|
// Trigger initial load when path changes from empty to actual path
|
||||||
onPathChanged: {
|
onPathChanged: {
|
||||||
if (path !== undefined) {
|
if (path !== undefined) {
|
||||||
reload()
|
reload();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onLoaded: function () {
|
onLoaded: function () {
|
||||||
if (!isLoaded) {
|
if (!isLoaded) {
|
||||||
Logger.i("Settings", "Settings loaded")
|
Logger.i("Settings", "Settings loaded");
|
||||||
|
|
||||||
upgradeSettingsData()
|
upgradeSettingsData();
|
||||||
validateMonitorConfigurations()
|
validateMonitorConfigurations();
|
||||||
isLoaded = true
|
isLoaded = true;
|
||||||
|
|
||||||
// Emit the signal
|
// Emit the signal
|
||||||
root.settingsLoaded()
|
root.settingsLoaded();
|
||||||
|
|
||||||
// Finally, update our local settings version
|
// Finally, update our local settings version
|
||||||
adapter.settingsVersion = settingsVersion
|
adapter.settingsVersion = settingsVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onLoadFailed: function (error) {
|
onLoadFailed: function (error) {
|
||||||
if (error.toString().includes("No such file") || error === 2) {
|
if (error.toString().includes("No such file") || error === 2) {
|
||||||
// File doesn't exist, create it with default values
|
// File doesn't exist, create it with default values
|
||||||
writeAdapter()
|
writeAdapter();
|
||||||
// Also write to fallback if set
|
// Also write to fallback if set
|
||||||
if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) {
|
if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) {
|
||||||
settingsFallbackFileView.writeAdapter()
|
settingsFallbackFileView.writeAdapter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,33 +156,48 @@ Singleton {
|
|||||||
// Widget configuration for modular bar system
|
// Widget configuration for modular bar system
|
||||||
property JsonObject widgets
|
property JsonObject widgets
|
||||||
widgets: JsonObject {
|
widgets: JsonObject {
|
||||||
property list<var> left: [{
|
property list<var> left: [
|
||||||
|
{
|
||||||
"id": "ControlCenter"
|
"id": "ControlCenter"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "SystemMonitor"
|
"id": "SystemMonitor"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "ActiveWindow"
|
"id": "ActiveWindow"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "MediaMini"
|
"id": "MediaMini"
|
||||||
}]
|
}
|
||||||
property list<var> center: [{
|
]
|
||||||
|
property list<var> center: [
|
||||||
|
{
|
||||||
"id": "Workspace"
|
"id": "Workspace"
|
||||||
}]
|
}
|
||||||
property list<var> right: [{
|
]
|
||||||
|
property list<var> right: [
|
||||||
|
{
|
||||||
"id": "ScreenRecorder"
|
"id": "ScreenRecorder"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "Tray"
|
"id": "Tray"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "NotificationHistory"
|
"id": "NotificationHistory"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "Battery"
|
"id": "Battery"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "Volume"
|
"id": "Volume"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "Brightness"
|
"id": "Brightness"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "Clock"
|
"id": "Clock"
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,41 +309,57 @@ Singleton {
|
|||||||
property string position: "close_to_bar_button"
|
property string position: "close_to_bar_button"
|
||||||
property JsonObject shortcuts
|
property JsonObject shortcuts
|
||||||
shortcuts: JsonObject {
|
shortcuts: JsonObject {
|
||||||
property list<var> left: [{
|
property list<var> left: [
|
||||||
|
{
|
||||||
"id": "WiFi"
|
"id": "WiFi"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "Bluetooth"
|
"id": "Bluetooth"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "ScreenRecorder"
|
"id": "ScreenRecorder"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "WallpaperSelector"
|
"id": "WallpaperSelector"
|
||||||
}]
|
}
|
||||||
property list<var> right: [{
|
]
|
||||||
|
property list<var> right: [
|
||||||
|
{
|
||||||
"id": "Notifications"
|
"id": "Notifications"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "PowerProfile"
|
"id": "PowerProfile"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "KeepAwake"
|
"id": "KeepAwake"
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "NightLight"
|
"id": "NightLight"
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
property list<var> cards: [{
|
property list<var> cards: [
|
||||||
|
{
|
||||||
"id": "profile-card",
|
"id": "profile-card",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "shortcuts-card",
|
"id": "shortcuts-card",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "audio-card",
|
"id": "audio-card",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "weather-card",
|
"id": "weather-card",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"id": "media-sysmon-card",
|
"id": "media-sysmon-card",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// system monitor
|
// system monitor
|
||||||
@@ -371,25 +402,32 @@ Singleton {
|
|||||||
property int countdownDuration: 10000
|
property int countdownDuration: 10000
|
||||||
property string position: "center"
|
property string position: "center"
|
||||||
property bool showHeader: true
|
property bool showHeader: true
|
||||||
property list<var> powerOptions: [{
|
property list<var> powerOptions: [
|
||||||
|
{
|
||||||
"action": "lock",
|
"action": "lock",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"action": "suspend",
|
"action": "suspend",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"action": "hibernate",
|
"action": "hibernate",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"action": "reboot",
|
"action": "reboot",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"action": "logout",
|
"action": "logout",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"action": "shutdown",
|
"action": "shutdown",
|
||||||
"enabled": true
|
"enabled": true
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
// notifications
|
// notifications
|
||||||
@@ -493,81 +531,81 @@ Singleton {
|
|||||||
// Function to preprocess paths by expanding "~" to user's home directory
|
// Function to preprocess paths by expanding "~" to user's home directory
|
||||||
function preprocessPath(path) {
|
function preprocessPath(path) {
|
||||||
if (typeof path !== "string" || path === "") {
|
if (typeof path !== "string" || path === "") {
|
||||||
return path
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand "~" to user's home directory
|
// Expand "~" to user's home directory
|
||||||
if (path.startsWith("~/")) {
|
if (path.startsWith("~/")) {
|
||||||
return Quickshell.env("HOME") + path.substring(1)
|
return Quickshell.env("HOME") + path.substring(1);
|
||||||
} else if (path === "~") {
|
} else if (path === "~") {
|
||||||
return Quickshell.env("HOME")
|
return Quickshell.env("HOME");
|
||||||
}
|
}
|
||||||
|
|
||||||
return path
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Public function to trigger immediate settings saving
|
// Public function to trigger immediate settings saving
|
||||||
function saveImmediate() {
|
function saveImmediate() {
|
||||||
settingsFileView.writeAdapter()
|
settingsFileView.writeAdapter();
|
||||||
// Write to fallback location if set
|
// Write to fallback location if set
|
||||||
if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) {
|
if (Quickshell.env("NOCTALIA_SETTINGS_FALLBACK")) {
|
||||||
settingsFallbackFileView.writeAdapter()
|
settingsFallbackFileView.writeAdapter();
|
||||||
}
|
}
|
||||||
root.settingsSaved() // Emit signal after saving
|
root.settingsSaved(); // Emit signal after saving
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Generate default settings at the root of the repo
|
// Generate default settings at the root of the repo
|
||||||
function generateDefaultSettings() {
|
function generateDefaultSettings() {
|
||||||
try {
|
try {
|
||||||
Logger.d("Settings", "Generating settings-default.json")
|
Logger.d("Settings", "Generating settings-default.json");
|
||||||
|
|
||||||
// Prepare a clean JSON
|
// Prepare a clean JSON
|
||||||
var plainAdapter = QtObj2JS.qtObjectToPlainObject(adapter)
|
var plainAdapter = QtObj2JS.qtObjectToPlainObject(adapter);
|
||||||
var jsonData = JSON.stringify(plainAdapter, null, 2)
|
var jsonData = JSON.stringify(plainAdapter, null, 2);
|
||||||
|
|
||||||
var defaultPath = Quickshell.shellDir + "/Assets/settings-default.json"
|
var defaultPath = Quickshell.shellDir + "/Assets/settings-default.json";
|
||||||
|
|
||||||
// Encode transfer it has base64 to avoid any escaping issue
|
// Encode transfer it has base64 to avoid any escaping issue
|
||||||
var base64Data = Qt.btoa(jsonData)
|
var base64Data = Qt.btoa(jsonData);
|
||||||
Quickshell.execDetached(["sh", "-c", `echo "${base64Data}" | base64 -d > "${defaultPath}"`])
|
Quickshell.execDetached(["sh", "-c", `echo "${base64Data}" | base64 -d > "${defaultPath}"`]);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.e("Settings", "Failed to generate default settings file: " + error)
|
Logger.e("Settings", "Failed to generate default settings file: " + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
// Function to validate monitor configurations
|
// Function to validate monitor configurations
|
||||||
function validateMonitorConfigurations() {
|
function validateMonitorConfigurations() {
|
||||||
var availableScreenNames = []
|
var availableScreenNames = [];
|
||||||
for (var i = 0; i < Quickshell.screens.length; i++) {
|
for (var i = 0; i < Quickshell.screens.length; i++) {
|
||||||
availableScreenNames.push(Quickshell.screens[i].name)
|
availableScreenNames.push(Quickshell.screens[i].name);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.d("Settings", "Available monitors: [" + availableScreenNames.join(", ") + "]")
|
Logger.d("Settings", "Available monitors: [" + availableScreenNames.join(", ") + "]");
|
||||||
Logger.d("Settings", "Configured bar monitors: [" + adapter.bar.monitors.join(", ") + "]")
|
Logger.d("Settings", "Configured bar monitors: [" + adapter.bar.monitors.join(", ") + "]");
|
||||||
|
|
||||||
// Check bar monitors
|
// Check bar monitors
|
||||||
if (adapter.bar.monitors.length > 0) {
|
if (adapter.bar.monitors.length > 0) {
|
||||||
var hasValidBarMonitor = false
|
var hasValidBarMonitor = false;
|
||||||
for (var j = 0; j < adapter.bar.monitors.length; j++) {
|
for (var j = 0; j < adapter.bar.monitors.length; j++) {
|
||||||
if (availableScreenNames.includes(adapter.bar.monitors[j])) {
|
if (availableScreenNames.includes(adapter.bar.monitors[j])) {
|
||||||
hasValidBarMonitor = true
|
hasValidBarMonitor = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasValidBarMonitor) {
|
if (!hasValidBarMonitor) {
|
||||||
Logger.w("Settings", "No configured bar monitors found on system, clearing bar monitor list to show on all screens")
|
Logger.w("Settings", "No configured bar monitors found on system, clearing bar monitor list to show on all screens");
|
||||||
adapter.bar.monitors = []
|
adapter.bar.monitors = [];
|
||||||
} else {
|
} else
|
||||||
|
|
||||||
//Logger.i("Settings", "Found valid bar monitors, keeping configuration")
|
//Logger.i("Settings", "Found valid bar monitors, keeping configuration")
|
||||||
}
|
{}
|
||||||
} else {
|
} else
|
||||||
|
|
||||||
//Logger.i("Settings", "Bar monitor list is empty, will show on all available screens")
|
//Logger.i("Settings", "Bar monitor list is empty, will show on all available screens")
|
||||||
}
|
{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
@@ -576,50 +614,50 @@ Singleton {
|
|||||||
function upgradeSettingsData() {
|
function upgradeSettingsData() {
|
||||||
// Wait for BarWidgetRegistry to be ready
|
// Wait for BarWidgetRegistry to be ready
|
||||||
if (!BarWidgetRegistry.widgets || Object.keys(BarWidgetRegistry.widgets).length === 0) {
|
if (!BarWidgetRegistry.widgets || Object.keys(BarWidgetRegistry.widgets).length === 0) {
|
||||||
Logger.w("Settings", "BarWidgetRegistry not ready, deferring upgrade")
|
Logger.w("Settings", "BarWidgetRegistry not ready, deferring upgrade");
|
||||||
Qt.callLater(upgradeSettingsData)
|
Qt.callLater(upgradeSettingsData);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sections = ["left", "center", "right"]
|
const sections = ["left", "center", "right"];
|
||||||
|
|
||||||
// -----------------
|
// -----------------
|
||||||
// 1st. convert old widget id to new id
|
// 1st. convert old widget id to new id
|
||||||
for (var s = 0; s < sections.length; s++) {
|
for (var s = 0; s < sections.length; s++) {
|
||||||
const sectionName = sections[s]
|
const sectionName = sections[s];
|
||||||
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
|
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
|
||||||
var widget = adapter.bar.widgets[sectionName][i]
|
var widget = adapter.bar.widgets[sectionName][i];
|
||||||
|
|
||||||
switch (widget.id) {
|
switch (widget.id) {
|
||||||
case "DarkModeToggle":
|
case "DarkModeToggle":
|
||||||
widget.id = "DarkMode"
|
widget.id = "DarkMode";
|
||||||
break
|
break;
|
||||||
case "PowerToggle":
|
case "PowerToggle":
|
||||||
widget.id = "SessionMenu"
|
widget.id = "SessionMenu";
|
||||||
break
|
break;
|
||||||
case "ScreenRecorderIndicator":
|
case "ScreenRecorderIndicator":
|
||||||
widget.id = "ScreenRecorder"
|
widget.id = "ScreenRecorder";
|
||||||
break
|
break;
|
||||||
case "SidePanelToggle":
|
case "SidePanelToggle":
|
||||||
widget.id = "ControlCenter"
|
widget.id = "ControlCenter";
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------
|
// -----------------
|
||||||
// 2nd. remove any non existing widget type
|
// 2nd. remove any non existing widget type
|
||||||
var removedWidget = false
|
var removedWidget = false;
|
||||||
for (var s = 0; s < sections.length; s++) {
|
for (var s = 0; s < sections.length; s++) {
|
||||||
const sectionName = sections[s]
|
const sectionName = sections[s];
|
||||||
const widgets = adapter.bar.widgets[sectionName]
|
const widgets = adapter.bar.widgets[sectionName];
|
||||||
// Iterate backward through the widgets array, so it does not break when removing a widget
|
// Iterate backward through the widgets array, so it does not break when removing a widget
|
||||||
for (var i = widgets.length - 1; i >= 0; i--) {
|
for (var i = widgets.length - 1; i >= 0; i--) {
|
||||||
var widget = widgets[i]
|
var widget = widgets[i];
|
||||||
if (!BarWidgetRegistry.hasWidget(widget.id)) {
|
if (!BarWidgetRegistry.hasWidget(widget.id)) {
|
||||||
Logger.w(`Settings`, `Deleted invalid widget ${widget.id}`)
|
Logger.w(`Settings`, `Deleted invalid widget ${widget.id}`);
|
||||||
widgets.splice(i, 1)
|
widgets.splice(i, 1);
|
||||||
removedWidget = true
|
removedWidget = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -627,18 +665,18 @@ Singleton {
|
|||||||
// -----------------
|
// -----------------
|
||||||
// 3nd. upgrade widget settings
|
// 3nd. upgrade widget settings
|
||||||
for (var s = 0; s < sections.length; s++) {
|
for (var s = 0; s < sections.length; s++) {
|
||||||
const sectionName = sections[s]
|
const sectionName = sections[s];
|
||||||
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
|
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
|
||||||
var widget = adapter.bar.widgets[sectionName][i]
|
var widget = adapter.bar.widgets[sectionName][i];
|
||||||
|
|
||||||
// Check if widget registry supports user settings, if it does not, then there is nothing to do
|
// Check if widget registry supports user settings, if it does not, then there is nothing to do
|
||||||
const reg = BarWidgetRegistry.widgetMetadata[widget.id]
|
const reg = BarWidgetRegistry.widgetMetadata[widget.id];
|
||||||
if ((reg === undefined) || (reg.allowUserSettings === undefined) || !reg.allowUserSettings) {
|
if ((reg === undefined) || (reg.allowUserSettings === undefined) || !reg.allowUserSettings) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (upgradeWidget(widget)) {
|
if (upgradeWidget(widget)) {
|
||||||
Logger.d("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget))
|
Logger.d("Settings", `Upgraded ${widget.id} widget:`, JSON.stringify(widget));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -647,14 +685,14 @@ Singleton {
|
|||||||
// 4th. safety check
|
// 4th. safety check
|
||||||
// if a widget was deleted, ensure we still have a control center
|
// if a widget was deleted, ensure we still have a control center
|
||||||
if (removedWidget) {
|
if (removedWidget) {
|
||||||
var gotControlCenter = false
|
var gotControlCenter = false;
|
||||||
for (var s = 0; s < sections.length; s++) {
|
for (var s = 0; s < sections.length; s++) {
|
||||||
const sectionName = sections[s]
|
const sectionName = sections[s];
|
||||||
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
|
for (var i = 0; i < adapter.bar.widgets[sectionName].length; i++) {
|
||||||
var widget = adapter.bar.widgets[sectionName][i]
|
var widget = adapter.bar.widgets[sectionName][i];
|
||||||
if (widget.id === "ControlCenter") {
|
if (widget.id === "ControlCenter") {
|
||||||
gotControlCenter = true
|
gotControlCenter = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -663,8 +701,8 @@ Singleton {
|
|||||||
//const obj = JSON.parse('{"id": "ControlCenter"}');
|
//const obj = JSON.parse('{"id": "ControlCenter"}');
|
||||||
adapter.bar.widgets["right"].push(({
|
adapter.bar.widgets["right"].push(({
|
||||||
"id": "ControlCenter"
|
"id": "ControlCenter"
|
||||||
}))
|
}));
|
||||||
Logger.w("Settings", "Added a ControlCenter widget to the right section")
|
Logger.w("Settings", "Added a ControlCenter widget to the right section");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -674,31 +712,31 @@ Singleton {
|
|||||||
if (adapter.settingsVersion < 21) {
|
if (adapter.settingsVersion < 21) {
|
||||||
// Read raw JSON file to access properties not in adapter schema
|
// Read raw JSON file to access properties not in adapter schema
|
||||||
try {
|
try {
|
||||||
var rawJson = settingsFileView.text()
|
var rawJson = settingsFileView.text();
|
||||||
|
|
||||||
if (rawJson) {
|
if (rawJson) {
|
||||||
var parsed = JSON.parse(rawJson)
|
var parsed = JSON.parse(rawJson);
|
||||||
var anyDiscordEnabled = false
|
var anyDiscordEnabled = false;
|
||||||
|
|
||||||
// Check if any Discord client was enabled
|
// Check if any Discord client was enabled
|
||||||
const discordClients = ["discord_vesktop", "discord_webcord", "discord_armcord", "discord_equibop", "discord_lightcord", "discord_dorion", "discord_vencord"]
|
const discordClients = ["discord_vesktop", "discord_webcord", "discord_armcord", "discord_equibop", "discord_lightcord", "discord_dorion", "discord_vencord"];
|
||||||
|
|
||||||
if (parsed.templates) {
|
if (parsed.templates) {
|
||||||
for (var i = 0; i < discordClients.length; i++) {
|
for (var i = 0; i < discordClients.length; i++) {
|
||||||
if (parsed.templates[discordClients[i]]) {
|
if (parsed.templates[discordClients[i]]) {
|
||||||
anyDiscordEnabled = true
|
anyDiscordEnabled = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set unified discord property
|
// Set unified discord property
|
||||||
adapter.templates.discord = anyDiscordEnabled
|
adapter.templates.discord = anyDiscordEnabled;
|
||||||
|
|
||||||
Logger.i("Settings", "Migrated Discord templates to unified 'discord' property (enabled:", anyDiscordEnabled + ")")
|
Logger.i("Settings", "Migrated Discord templates to unified 'discord' property (enabled:", anyDiscordEnabled + ")");
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.w("Settings", "Failed to read raw JSON for Discord migration:", error)
|
Logger.w("Settings", "Failed to read raw JSON for Discord migration:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -708,20 +746,20 @@ Singleton {
|
|||||||
if (adapter.settingsVersion < 22) {
|
if (adapter.settingsVersion < 22) {
|
||||||
// Read raw JSON file to access properties not in adapter schema
|
// Read raw JSON file to access properties not in adapter schema
|
||||||
try {
|
try {
|
||||||
var rawJson = settingsFileView.text()
|
var rawJson = settingsFileView.text();
|
||||||
|
|
||||||
if (rawJson) {
|
if (rawJson) {
|
||||||
var parsed = JSON.parse(rawJson)
|
var parsed = JSON.parse(rawJson);
|
||||||
if (parsed.appLauncher && parsed.appLauncher.backgroundOpacity !== undefined) {
|
if (parsed.appLauncher && parsed.appLauncher.backgroundOpacity !== undefined) {
|
||||||
var oldOpacity = parsed.appLauncher.backgroundOpacity
|
var oldOpacity = parsed.appLauncher.backgroundOpacity;
|
||||||
if (adapter.ui) {
|
if (adapter.ui) {
|
||||||
adapter.ui.panelBackgroundOpacity = oldOpacity
|
adapter.ui.panelBackgroundOpacity = oldOpacity;
|
||||||
Logger.i("Settings", "Migrated appLauncher.backgroundOpacity to ui.panelBackgroundOpacity (value:", oldOpacity + ")")
|
Logger.i("Settings", "Migrated appLauncher.backgroundOpacity to ui.panelBackgroundOpacity (value:", oldOpacity + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.w("Settings", "Failed to read raw JSON for migration:", error)
|
Logger.w("Settings", "Failed to read raw JSON for migration:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,23 +770,23 @@ Singleton {
|
|||||||
if (adapter.settingsVersion < 23) {
|
if (adapter.settingsVersion < 23) {
|
||||||
// Read raw JSON file to access dimDesktop property
|
// Read raw JSON file to access dimDesktop property
|
||||||
try {
|
try {
|
||||||
var rawJson = settingsFileView.text()
|
var rawJson = settingsFileView.text();
|
||||||
|
|
||||||
if (rawJson) {
|
if (rawJson) {
|
||||||
var parsed = JSON.parse(rawJson)
|
var parsed = JSON.parse(rawJson);
|
||||||
if (parsed.general && parsed.general.dimDesktop === true) {
|
if (parsed.general && parsed.general.dimDesktop === true) {
|
||||||
// Check if dimmerOpacity exists in raw JSON (not adapter default)
|
// Check if dimmerOpacity exists in raw JSON (not adapter default)
|
||||||
var dimmerOpacityInJson = parsed.general.dimmerOpacity
|
var dimmerOpacityInJson = parsed.general.dimmerOpacity;
|
||||||
|
|
||||||
// If dimmerOpacity wasn't explicitly set in JSON or was 0, set it to 0.8 (80% dimming)
|
// If dimmerOpacity wasn't explicitly set in JSON or was 0, set it to 0.8 (80% dimming)
|
||||||
if (dimmerOpacityInJson === undefined || dimmerOpacityInJson === 0) {
|
if (dimmerOpacityInJson === undefined || dimmerOpacityInJson === 0) {
|
||||||
adapter.general.dimmerOpacity = 0.8
|
adapter.general.dimmerOpacity = 0.8;
|
||||||
Logger.i("Settings", "Migrated dimDesktop=true: set dimmerOpacity to 0.8 (80% dimming)")
|
Logger.i("Settings", "Migrated dimDesktop=true: set dimmerOpacity to 0.8 (80% dimming)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.w("Settings", "Failed to read raw JSON for dimDesktop migration:", error)
|
Logger.w("Settings", "Failed to read raw JSON for dimDesktop migration:", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -756,35 +794,35 @@ Singleton {
|
|||||||
// -----------------------------------------------------
|
// -----------------------------------------------------
|
||||||
function upgradeWidget(widget) {
|
function upgradeWidget(widget) {
|
||||||
// Backup the widget definition before altering
|
// Backup the widget definition before altering
|
||||||
const widgetBefore = JSON.stringify(widget)
|
const widgetBefore = JSON.stringify(widget);
|
||||||
|
|
||||||
// Get all existing custom settings keys
|
// Get all existing custom settings keys
|
||||||
const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id])
|
const keys = Object.keys(BarWidgetRegistry.widgetMetadata[widget.id]);
|
||||||
|
|
||||||
// Delete deprecated user settings from the wiget
|
// Delete deprecated user settings from the wiget
|
||||||
for (const k of Object.keys(widget)) {
|
for (const k of Object.keys(widget)) {
|
||||||
if (k === "id" || k === "allowUserSettings") {
|
if (k === "id" || k === "allowUserSettings") {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
if (!keys.includes(k)) {
|
if (!keys.includes(k)) {
|
||||||
delete widget[k]
|
delete widget[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inject missing default setting (metaData) from BarWidgetRegistry
|
// Inject missing default setting (metaData) from BarWidgetRegistry
|
||||||
for (var i = 0; i < keys.length; i++) {
|
for (var i = 0; i < keys.length; i++) {
|
||||||
const k = keys[i]
|
const k = keys[i];
|
||||||
if (k === "id" || k === "allowUserSettings") {
|
if (k === "id" || k === "allowUserSettings") {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (widget[k] === undefined) {
|
if (widget[k] === undefined) {
|
||||||
widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k]
|
widget[k] = BarWidgetRegistry.widgetMetadata[widget.id][k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compare settings, to detect if something has been upgraded
|
// Compare settings, to detect if something has been upgraded
|
||||||
const widgetAfter = JSON.stringify(widget)
|
const widgetAfter = JSON.stringify(widget);
|
||||||
return (widgetAfter !== widgetBefore)
|
return (widgetAfter !== widgetBefore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,6 @@ import qs.Services.Power
|
|||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Preset sizes for font, radii, ?
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Font size
|
// Font size
|
||||||
readonly property real fontSizeXXS: 8
|
readonly property real fontSizeXXS: 8
|
||||||
readonly property real fontSizeXS: 9
|
readonly property real fontSizeXS: 9
|
||||||
@@ -86,29 +81,27 @@ Singleton {
|
|||||||
readonly property real barHeight: {
|
readonly property real barHeight: {
|
||||||
switch (Settings.data.bar.density) {
|
switch (Settings.data.bar.density) {
|
||||||
case "mini":
|
case "mini":
|
||||||
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 22 : 20
|
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 22 : 20;
|
||||||
case "compact":
|
case "compact":
|
||||||
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 27 : 25
|
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 27 : 25;
|
||||||
case "comfortable":
|
case "comfortable":
|
||||||
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37
|
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 39 : 37;
|
||||||
default:
|
default:
|
||||||
|
|
||||||
case "default":
|
case "default":
|
||||||
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31
|
return (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 33 : 31;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
readonly property real capsuleHeight: {
|
readonly property real capsuleHeight: {
|
||||||
switch (Settings.data.bar.density) {
|
switch (Settings.data.bar.density) {
|
||||||
case "mini":
|
case "mini":
|
||||||
return Math.round(barHeight * 1.0)
|
return Math.round(barHeight * 1.0);
|
||||||
case "compact":
|
case "compact":
|
||||||
return Math.round(barHeight * 0.85)
|
return Math.round(barHeight * 0.85);
|
||||||
case "comfortable":
|
case "comfortable":
|
||||||
return Math.round(barHeight * 0.73)
|
return Math.round(barHeight * 0.73);
|
||||||
default:
|
default:
|
||||||
|
|
||||||
case "default":
|
case "default":
|
||||||
return Math.round(barHeight * 0.82)
|
return Math.round(barHeight * 0.82);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,46 +7,46 @@ Singleton {
|
|||||||
id: root
|
id: root
|
||||||
|
|
||||||
function iconFromName(iconName, fallbackName) {
|
function iconFromName(iconName, fallbackName) {
|
||||||
const fallback = fallbackName || "application-x-executable"
|
const fallback = fallbackName || "application-x-executable";
|
||||||
try {
|
try {
|
||||||
if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) {
|
if (iconName && typeof Quickshell !== 'undefined' && Quickshell.iconPath) {
|
||||||
const p = Quickshell.iconPath(iconName, fallback)
|
const p = Quickshell.iconPath(iconName, fallback);
|
||||||
if (p && p !== "")
|
if (p && p !== "")
|
||||||
return p
|
return p;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e)
|
||||||
|
|
||||||
// ignore and fall back
|
// ignore and fall back
|
||||||
}
|
{}
|
||||||
try {
|
try {
|
||||||
return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : ""
|
return Quickshell.iconPath ? (Quickshell.iconPath(fallback, true) || "") : "";
|
||||||
} catch (e2) {
|
} catch (e2) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve icon path for a DesktopEntries appId - safe on missing entries
|
// Resolve icon path for a DesktopEntries appId - safe on missing entries
|
||||||
function iconForAppId(appId, fallbackName) {
|
function iconForAppId(appId, fallbackName) {
|
||||||
const fallback = fallbackName || "application-x-executable"
|
const fallback = fallbackName || "application-x-executable";
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return iconFromName(fallback, fallback)
|
return iconFromName(fallback, fallback);
|
||||||
try {
|
try {
|
||||||
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
|
if (typeof DesktopEntries === 'undefined' || !DesktopEntries.byId)
|
||||||
return iconFromName(fallback, fallback)
|
return iconFromName(fallback, fallback);
|
||||||
const entry = (DesktopEntries.heuristicLookup) ? DesktopEntries.heuristicLookup(appId) : DesktopEntries.byId(appId)
|
const entry = (DesktopEntries.heuristicLookup) ? DesktopEntries.heuristicLookup(appId) : DesktopEntries.byId(appId);
|
||||||
const name = entry && entry.icon ? entry.icon : ""
|
const name = entry && entry.icon ? entry.icon : "";
|
||||||
return iconFromName(name || fallback, fallback)
|
return iconFromName(name || fallback, fallback);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return iconFromName(fallback, fallback)
|
return iconFromName(fallback, fallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distro logo helper (absolute path or empty string)
|
// Distro logo helper (absolute path or empty string)
|
||||||
function distroLogoPath() {
|
function distroLogoPath() {
|
||||||
try {
|
try {
|
||||||
return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : ""
|
return (typeof OSInfo !== 'undefined' && OSInfo.distroIconPath) ? OSInfo.distroIconPath : "";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
pragma Singleton
|
pragma Singleton
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
@@ -12,7 +12,7 @@ Singleton {
|
|||||||
|
|
||||||
// Returns a Unix Timestamp (in seconds)
|
// Returns a Unix Timestamp (in seconds)
|
||||||
readonly property int timestamp: {
|
readonly property int timestamp: {
|
||||||
return Math.floor(root.now / 1000)
|
return Math.floor(root.now / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Timer {
|
Timer {
|
||||||
@@ -22,89 +22,89 @@ Singleton {
|
|||||||
running: true
|
running: true
|
||||||
triggeredOnStart: false
|
triggeredOnStart: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
var newTime = new Date()
|
var newTime = new Date();
|
||||||
root.now = newTime
|
root.now = newTime;
|
||||||
|
|
||||||
// Adjust next interval to sync with the start of the next second
|
// Adjust next interval to sync with the start of the next second
|
||||||
var msIntoSecond = newTime.getMilliseconds()
|
var msIntoSecond = newTime.getMilliseconds();
|
||||||
if (msIntoSecond > 100) {
|
if (msIntoSecond > 100) {
|
||||||
// If we're more than 100ms into the second, adjust for next time
|
// If we're more than 100ms into the second, adjust for next time
|
||||||
updateTimer.interval = 1000 - msIntoSecond + 10 // +10ms buffer
|
updateTimer.interval = 1000 - msIntoSecond + 10; // +10ms buffer
|
||||||
updateTimer.restart()
|
updateTimer.restart();
|
||||||
} else {
|
} else {
|
||||||
updateTimer.interval = 1000
|
updateTimer.interval = 1000;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// Start by syncing to the next second boundary
|
// Start by syncing to the next second boundary
|
||||||
var now = new Date()
|
var now = new Date();
|
||||||
var msUntilNextSecond = 1000 - now.getMilliseconds()
|
var msUntilNextSecond = 1000 - now.getMilliseconds();
|
||||||
updateTimer.interval = msUntilNextSecond + 10 // +10ms buffer
|
updateTimer.interval = msUntilNextSecond + 10; // +10ms buffer
|
||||||
updateTimer.restart()
|
updateTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats a Date object into a YYYYMMDD-HHMMSS string.
|
// Formats a Date object into a YYYYMMDD-HHMMSS string.
|
||||||
function getFormattedTimestamp(date) {
|
function getFormattedTimestamp(date) {
|
||||||
if (!date) {
|
if (!date) {
|
||||||
date = new Date()
|
date = new Date();
|
||||||
}
|
}
|
||||||
const year = date.getFullYear()
|
const year = date.getFullYear();
|
||||||
|
|
||||||
// getMonth() is zero-based, so we add 1
|
// getMonth() is zero-based, so we add 1
|
||||||
const month = String(date.getMonth() + 1).padStart(2, '0')
|
const month = String(date.getMonth() + 1).padStart(2, '0');
|
||||||
const day = String(date.getDate()).padStart(2, '0')
|
const day = String(date.getDate()).padStart(2, '0');
|
||||||
|
|
||||||
const hours = String(date.getHours()).padStart(2, '0')
|
const hours = String(date.getHours()).padStart(2, '0');
|
||||||
const minutes = String(date.getMinutes()).padStart(2, '0')
|
const minutes = String(date.getMinutes()).padStart(2, '0');
|
||||||
const seconds = String(date.getSeconds()).padStart(2, '0')
|
const seconds = String(date.getSeconds()).padStart(2, '0');
|
||||||
|
|
||||||
return `${year}${month}${day}-${hours}${minutes}${seconds}`
|
return `${year}${month}${day}-${hours}${minutes}${seconds}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format an easy to read approximate duration ex: 4h 32m
|
// Format an easy to read approximate duration ex: 4h 32m
|
||||||
// Used to display the time remaining on the Battery widget, computer uptime, etc..
|
// Used to display the time remaining on the Battery widget, computer uptime, etc..
|
||||||
function formatVagueHumanReadableDuration(totalSeconds) {
|
function formatVagueHumanReadableDuration(totalSeconds) {
|
||||||
if (typeof totalSeconds !== 'number' || totalSeconds < 0) {
|
if (typeof totalSeconds !== 'number' || totalSeconds < 0) {
|
||||||
return '0s'
|
return '0s';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Floor the input to handle decimal seconds
|
// Floor the input to handle decimal seconds
|
||||||
totalSeconds = Math.floor(totalSeconds)
|
totalSeconds = Math.floor(totalSeconds);
|
||||||
|
|
||||||
const days = Math.floor(totalSeconds / 86400)
|
const days = Math.floor(totalSeconds / 86400);
|
||||||
const hours = Math.floor((totalSeconds % 86400) / 3600)
|
const hours = Math.floor((totalSeconds % 86400) / 3600);
|
||||||
const minutes = Math.floor((totalSeconds % 3600) / 60)
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
||||||
const seconds = totalSeconds % 60
|
const seconds = totalSeconds % 60;
|
||||||
|
|
||||||
const parts = []
|
const parts = [];
|
||||||
if (days)
|
if (days)
|
||||||
parts.push(`${days}d`)
|
parts.push(`${days}d`);
|
||||||
if (hours)
|
if (hours)
|
||||||
parts.push(`${hours}h`)
|
parts.push(`${hours}h`);
|
||||||
if (minutes)
|
if (minutes)
|
||||||
parts.push(`${minutes}m`)
|
parts.push(`${minutes}m`);
|
||||||
|
|
||||||
// Only show seconds if no hours and no minutes
|
// Only show seconds if no hours and no minutes
|
||||||
if (!hours && !minutes) {
|
if (!hours && !minutes) {
|
||||||
parts.push(`${seconds}s`)
|
parts.push(`${seconds}s`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return parts.join(' ')
|
return parts.join(' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format a date into
|
// Format a date into
|
||||||
function formatRelativeTime(date) {
|
function formatRelativeTime(date) {
|
||||||
if (!date)
|
if (!date)
|
||||||
return ""
|
return "";
|
||||||
const diff = Date.now() - date.getTime()
|
const diff = Date.now() - date.getTime();
|
||||||
if (diff < 60000)
|
if (diff < 60000)
|
||||||
return "now"
|
return "now";
|
||||||
if (diff < 3600000)
|
if (diff < 3600000)
|
||||||
return `${Math.floor(diff / 60000)}m ago`
|
return `${Math.floor(diff / 60000)}m ago`;
|
||||||
if (diff < 86400000)
|
if (diff < 86400000)
|
||||||
return `${Math.floor(diff / 3600000)}h ago`
|
return `${Math.floor(diff / 3600000)}h ago`;
|
||||||
return `${Math.floor(diff / 86400000)}d ago`
|
return `${Math.floor(diff / 86400000)}d ago`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,17 +48,17 @@ Variants {
|
|||||||
Component.onCompleted: setWallpaperInitial()
|
Component.onCompleted: setWallpaperInitial()
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
transitionAnimation.stop()
|
transitionAnimation.stop();
|
||||||
debounceTimer.stop()
|
debounceTimer.stop();
|
||||||
shaderLoader.active = false
|
shaderLoader.active = false;
|
||||||
currentWallpaper.source = ""
|
currentWallpaper.source = "";
|
||||||
nextWallpaper.source = ""
|
nextWallpaper.source = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Settings.data.wallpaper
|
target: Settings.data.wallpaper
|
||||||
function onFillModeChanged() {
|
function onFillModeChanged() {
|
||||||
fillMode = WallpaperService.getFillModeUniform()
|
fillMode = WallpaperService.getFillModeUniform();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,8 +69,8 @@ Variants {
|
|||||||
if (screenName === modelData.name) {
|
if (screenName === modelData.name) {
|
||||||
// Update wallpaper display
|
// Update wallpaper display
|
||||||
// Set wallpaper immediately on startup
|
// Set wallpaper immediately on startup
|
||||||
futureWallpaper = path
|
futureWallpaper = path;
|
||||||
debounceTimer.restart()
|
debounceTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,9 +80,9 @@ Variants {
|
|||||||
function onDisplayScalesChanged() {
|
function onDisplayScalesChanged() {
|
||||||
// Recalculate image sizes without interrupting startup transition
|
// Recalculate image sizes without interrupting startup transition
|
||||||
if (isStartupTransition) {
|
if (isStartupTransition) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
recalculateImageSizes()
|
recalculateImageSizes();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ Variants {
|
|||||||
running: false
|
running: false
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
changeWallpaper()
|
changeWallpaper();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,18 +123,18 @@ Variants {
|
|||||||
sourceSize: undefined
|
sourceSize: undefined
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status === Image.Error) {
|
if (status === Image.Error) {
|
||||||
Logger.w("Current wallpaper failed to load:", source)
|
Logger.w("Current wallpaper failed to load:", source);
|
||||||
} else if (status === Image.Ready && !dimensionsCalculated) {
|
} else if (status === Image.Ready && !dimensionsCalculated) {
|
||||||
dimensionsCalculated = true
|
dimensionsCalculated = true;
|
||||||
const optimalSize = calculateOptimalWallpaperSize(implicitWidth, implicitHeight)
|
const optimalSize = calculateOptimalWallpaperSize(implicitWidth, implicitHeight);
|
||||||
if (optimalSize !== false) {
|
if (optimalSize !== false) {
|
||||||
sourceSize = optimalSize
|
sourceSize = optimalSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
dimensionsCalculated = false
|
dimensionsCalculated = false;
|
||||||
sourceSize = undefined
|
sourceSize = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,18 +152,18 @@ Variants {
|
|||||||
sourceSize: undefined
|
sourceSize: undefined
|
||||||
onStatusChanged: {
|
onStatusChanged: {
|
||||||
if (status === Image.Error) {
|
if (status === Image.Error) {
|
||||||
Logger.w("Next wallpaper failed to load:", source)
|
Logger.w("Next wallpaper failed to load:", source);
|
||||||
} else if (status === Image.Ready && !dimensionsCalculated) {
|
} else if (status === Image.Ready && !dimensionsCalculated) {
|
||||||
dimensionsCalculated = true
|
dimensionsCalculated = true;
|
||||||
const optimalSize = calculateOptimalWallpaperSize(implicitWidth, implicitHeight)
|
const optimalSize = calculateOptimalWallpaperSize(implicitWidth, implicitHeight);
|
||||||
if (optimalSize !== false) {
|
if (optimalSize !== false) {
|
||||||
sourceSize = optimalSize
|
sourceSize = optimalSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onSourceChanged: {
|
onSourceChanged: {
|
||||||
dimensionsCalculated = false
|
dimensionsCalculated = false;
|
||||||
sourceSize = undefined
|
sourceSize = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,15 +176,15 @@ Variants {
|
|||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
switch (transitionType) {
|
switch (transitionType) {
|
||||||
case "wipe":
|
case "wipe":
|
||||||
return wipeShaderComponent
|
return wipeShaderComponent;
|
||||||
case "disc":
|
case "disc":
|
||||||
return discShaderComponent
|
return discShaderComponent;
|
||||||
case "stripes":
|
case "stripes":
|
||||||
return stripesShaderComponent
|
return stripesShaderComponent;
|
||||||
case "fade":
|
case "fade":
|
||||||
case "none":
|
case "none":
|
||||||
default:
|
default:
|
||||||
return fadeShaderComponent
|
return fadeShaderComponent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -307,64 +307,64 @@ Variants {
|
|||||||
easing.type: Easing.InOutCubic
|
easing.type: Easing.InOutCubic
|
||||||
onFinished: {
|
onFinished: {
|
||||||
// Assign new image to current BEFORE clearing to prevent flicker
|
// Assign new image to current BEFORE clearing to prevent flicker
|
||||||
const tempSource = nextWallpaper.source
|
const tempSource = nextWallpaper.source;
|
||||||
currentWallpaper.source = tempSource
|
currentWallpaper.source = tempSource;
|
||||||
transitionProgress = 0.0
|
transitionProgress = 0.0;
|
||||||
|
|
||||||
// Now clear nextWallpaper after currentWallpaper has the new source
|
// Now clear nextWallpaper after currentWallpaper has the new source
|
||||||
// Force complete cleanup to free texture memory (~18-25MB per monitor)
|
// Force complete cleanup to free texture memory (~18-25MB per monitor)
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
nextWallpaper.source = ""
|
nextWallpaper.source = "";
|
||||||
nextWallpaper.sourceSize = undefined
|
nextWallpaper.sourceSize = undefined;
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
currentWallpaper.asynchronous = true
|
currentWallpaper.asynchronous = true;
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
function calculateOptimalWallpaperSize(wpWidth, wpHeight) {
|
function calculateOptimalWallpaperSize(wpWidth, wpHeight) {
|
||||||
const compositorScale = CompositorService.getDisplayScale(modelData.name)
|
const compositorScale = CompositorService.getDisplayScale(modelData.name);
|
||||||
const screenWidth = modelData.width * compositorScale
|
const screenWidth = modelData.width * compositorScale;
|
||||||
const screenHeight = modelData.height * compositorScale
|
const screenHeight = modelData.height * compositorScale;
|
||||||
if (wpWidth <= screenWidth || wpHeight <= screenHeight || wpWidth <= 0 || wpHeight <= 0) {
|
if (wpWidth <= screenWidth || wpHeight <= screenHeight || wpWidth <= 0 || wpHeight <= 0) {
|
||||||
// Do not resize if wallpaper is smaller than one of the screen dimension
|
// Do not resize if wallpaper is smaller than one of the screen dimension
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const imageAspectRatio = wpWidth / wpHeight
|
const imageAspectRatio = wpWidth / wpHeight;
|
||||||
var dim = Qt.size(0, 0)
|
var dim = Qt.size(0, 0);
|
||||||
if (screenWidth >= screenHeight) {
|
if (screenWidth >= screenHeight) {
|
||||||
const w = Math.min(screenWidth, wpWidth)
|
const w = Math.min(screenWidth, wpWidth);
|
||||||
dim = Qt.size(Math.round(w), Math.round(w / imageAspectRatio))
|
dim = Qt.size(Math.round(w), Math.round(w / imageAspectRatio));
|
||||||
} else {
|
} else {
|
||||||
const h = Math.min(screenHeight, wpHeight)
|
const h = Math.min(screenHeight, wpHeight);
|
||||||
dim = Qt.size(Math.round(h * imageAspectRatio), Math.round(h))
|
dim = Qt.size(Math.round(h * imageAspectRatio), Math.round(h));
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.d("Background", `Wallpaper resized on ${modelData.name} ${screenWidth}x${screenHeight} @ ${compositorScale}x`, "src:", wpWidth, wpHeight, "dst:", dim.width, dim.height)
|
Logger.d("Background", `Wallpaper resized on ${modelData.name} ${screenWidth}x${screenHeight} @ ${compositorScale}x`, "src:", wpWidth, wpHeight, "dst:", dim.width, dim.height);
|
||||||
return dim
|
return dim;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
function recalculateImageSizes() {
|
function recalculateImageSizes() {
|
||||||
// Re-evaluate and apply optimal sourceSize for both images when ready
|
// Re-evaluate and apply optimal sourceSize for both images when ready
|
||||||
if (currentWallpaper.status === Image.Ready) {
|
if (currentWallpaper.status === Image.Ready) {
|
||||||
const optimal = calculateOptimalWallpaperSize(currentWallpaper.implicitWidth, currentWallpaper.implicitHeight)
|
const optimal = calculateOptimalWallpaperSize(currentWallpaper.implicitWidth, currentWallpaper.implicitHeight);
|
||||||
if (optimal !== undefined && optimal !== false) {
|
if (optimal !== undefined && optimal !== false) {
|
||||||
currentWallpaper.sourceSize = optimal
|
currentWallpaper.sourceSize = optimal;
|
||||||
} else {
|
} else {
|
||||||
currentWallpaper.sourceSize = undefined
|
currentWallpaper.sourceSize = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nextWallpaper.status === Image.Ready) {
|
if (nextWallpaper.status === Image.Ready) {
|
||||||
const optimal2 = calculateOptimalWallpaperSize(nextWallpaper.implicitWidth, nextWallpaper.implicitHeight)
|
const optimal2 = calculateOptimalWallpaperSize(nextWallpaper.implicitWidth, nextWallpaper.implicitHeight);
|
||||||
if (optimal2 !== undefined && optimal2 !== false) {
|
if (optimal2 !== undefined && optimal2 !== false) {
|
||||||
nextWallpaper.sourceSize = optimal2
|
nextWallpaper.sourceSize = optimal2;
|
||||||
} else {
|
} else {
|
||||||
nextWallpaper.sourceSize = undefined
|
nextWallpaper.sourceSize = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,104 +373,104 @@ Variants {
|
|||||||
function setWallpaperInitial() {
|
function setWallpaperInitial() {
|
||||||
// On startup, defer assigning wallpaper until the service cache is ready, retries every tick
|
// On startup, defer assigning wallpaper until the service cache is ready, retries every tick
|
||||||
if (!WallpaperService || !WallpaperService.isInitialized) {
|
if (!WallpaperService || !WallpaperService.isInitialized) {
|
||||||
Qt.callLater(setWallpaperInitial)
|
Qt.callLater(setWallpaperInitial);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const wallpaperPath = WallpaperService.getWallpaper(modelData.name)
|
const wallpaperPath = WallpaperService.getWallpaper(modelData.name);
|
||||||
|
|
||||||
futureWallpaper = wallpaperPath
|
futureWallpaper = wallpaperPath;
|
||||||
performStartupTransition()
|
performStartupTransition();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
function setWallpaperImmediate(source) {
|
function setWallpaperImmediate(source) {
|
||||||
transitionAnimation.stop()
|
transitionAnimation.stop();
|
||||||
transitionProgress = 0.0
|
transitionProgress = 0.0;
|
||||||
|
|
||||||
// Clear nextWallpaper completely to free texture memory
|
// Clear nextWallpaper completely to free texture memory
|
||||||
nextWallpaper.source = ""
|
nextWallpaper.source = "";
|
||||||
nextWallpaper.sourceSize = undefined
|
nextWallpaper.sourceSize = undefined;
|
||||||
|
|
||||||
currentWallpaper.source = ""
|
currentWallpaper.source = "";
|
||||||
|
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
currentWallpaper.source = source
|
currentWallpaper.source = source;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
function setWallpaperWithTransition(source) {
|
function setWallpaperWithTransition(source) {
|
||||||
if (source === currentWallpaper.source) {
|
if (source === currentWallpaper.source) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (transitioning) {
|
if (transitioning) {
|
||||||
// We are interrupting a transition - handle cleanup properly
|
// We are interrupting a transition - handle cleanup properly
|
||||||
transitionAnimation.stop()
|
transitionAnimation.stop();
|
||||||
transitionProgress = 0
|
transitionProgress = 0;
|
||||||
|
|
||||||
// Assign nextWallpaper to currentWallpaper BEFORE clearing to prevent flicker
|
// Assign nextWallpaper to currentWallpaper BEFORE clearing to prevent flicker
|
||||||
const newCurrentSource = nextWallpaper.source
|
const newCurrentSource = nextWallpaper.source;
|
||||||
currentWallpaper.source = newCurrentSource
|
currentWallpaper.source = newCurrentSource;
|
||||||
|
|
||||||
// Now clear nextWallpaper after current has the new source
|
// Now clear nextWallpaper after current has the new source
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
nextWallpaper.source = ""
|
nextWallpaper.source = "";
|
||||||
|
|
||||||
// Now set the next wallpaper after a brief delay
|
// Now set the next wallpaper after a brief delay
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
nextWallpaper.source = source
|
nextWallpaper.source = source;
|
||||||
currentWallpaper.asynchronous = false
|
currentWallpaper.asynchronous = false;
|
||||||
transitionAnimation.start()
|
transitionAnimation.start();
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nextWallpaper.source = source
|
nextWallpaper.source = source;
|
||||||
currentWallpaper.asynchronous = false
|
currentWallpaper.asynchronous = false;
|
||||||
transitionAnimation.start()
|
transitionAnimation.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------
|
// ------------------------------------------------------
|
||||||
// Main method that actually trigger the wallpaper change
|
// Main method that actually trigger the wallpaper change
|
||||||
function changeWallpaper() {
|
function changeWallpaper() {
|
||||||
// Get the transitionType from the settings
|
// Get the transitionType from the settings
|
||||||
transitionType = Settings.data.wallpaper.transitionType
|
transitionType = Settings.data.wallpaper.transitionType;
|
||||||
|
|
||||||
if (transitionType == "random") {
|
if (transitionType == "random") {
|
||||||
var index = Math.floor(Math.random() * allTransitions.length)
|
var index = Math.floor(Math.random() * allTransitions.length);
|
||||||
transitionType = allTransitions[index]
|
transitionType = allTransitions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the transition type really exists
|
// Ensure the transition type really exists
|
||||||
if (transitionType !== "none" && !allTransitions.includes(transitionType)) {
|
if (transitionType !== "none" && !allTransitions.includes(transitionType)) {
|
||||||
transitionType = "fade"
|
transitionType = "fade";
|
||||||
}
|
}
|
||||||
|
|
||||||
//Logger.i("Background", "New wallpaper: ", futureWallpaper, "On:", modelData.name, "Transition:", transitionType)
|
//Logger.i("Background", "New wallpaper: ", futureWallpaper, "On:", modelData.name, "Transition:", transitionType)
|
||||||
switch (transitionType) {
|
switch (transitionType) {
|
||||||
case "none":
|
case "none":
|
||||||
setWallpaperImmediate(futureWallpaper)
|
setWallpaperImmediate(futureWallpaper);
|
||||||
break
|
break;
|
||||||
case "wipe":
|
case "wipe":
|
||||||
wipeDirection = Math.random() * 4
|
wipeDirection = Math.random() * 4;
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
case "disc":
|
case "disc":
|
||||||
discCenterX = Math.random()
|
discCenterX = Math.random();
|
||||||
discCenterY = Math.random()
|
discCenterY = Math.random();
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
case "stripes":
|
case "stripes":
|
||||||
stripesCount = Math.round(Math.random() * 20 + 4)
|
stripesCount = Math.round(Math.random() * 20 + 4);
|
||||||
stripesAngle = Math.random() * 360
|
stripesAngle = Math.random() * 360;
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,46 +478,46 @@ Variants {
|
|||||||
// Dedicated function for startup animation
|
// Dedicated function for startup animation
|
||||||
function performStartupTransition() {
|
function performStartupTransition() {
|
||||||
// Get the transitionType from the settings
|
// Get the transitionType from the settings
|
||||||
transitionType = Settings.data.wallpaper.transitionType
|
transitionType = Settings.data.wallpaper.transitionType;
|
||||||
|
|
||||||
if (transitionType == "random") {
|
if (transitionType == "random") {
|
||||||
var index = Math.floor(Math.random() * allTransitions.length)
|
var index = Math.floor(Math.random() * allTransitions.length);
|
||||||
transitionType = allTransitions[index]
|
transitionType = allTransitions[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure the transition type really exists
|
// Ensure the transition type really exists
|
||||||
if (transitionType !== "none" && !allTransitions.includes(transitionType)) {
|
if (transitionType !== "none" && !allTransitions.includes(transitionType)) {
|
||||||
transitionType = "fade"
|
transitionType = "fade";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply transitionType so the shader loader picks the correct shader
|
// Apply transitionType so the shader loader picks the correct shader
|
||||||
this.transitionType = transitionType
|
this.transitionType = transitionType;
|
||||||
|
|
||||||
switch (transitionType) {
|
switch (transitionType) {
|
||||||
case "none":
|
case "none":
|
||||||
setWallpaperImmediate(futureWallpaper)
|
setWallpaperImmediate(futureWallpaper);
|
||||||
break
|
break;
|
||||||
case "wipe":
|
case "wipe":
|
||||||
wipeDirection = Math.random() * 4
|
wipeDirection = Math.random() * 4;
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
case "disc":
|
case "disc":
|
||||||
// Force center origin for elegant startup animation
|
// Force center origin for elegant startup animation
|
||||||
discCenterX = 0.5
|
discCenterX = 0.5;
|
||||||
discCenterY = 0.5
|
discCenterY = 0.5;
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
case "stripes":
|
case "stripes":
|
||||||
stripesCount = Math.round(Math.random() * 20 + 4)
|
stripesCount = Math.round(Math.random() * 20 + 4);
|
||||||
stripesAngle = Math.random() * 360
|
stripesAngle = Math.random() * 360;
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
setWallpaperWithTransition(futureWallpaper)
|
setWallpaperWithTransition(futureWallpaper);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
// Mark startup transition complete
|
// Mark startup transition complete
|
||||||
isStartupTransition = false
|
isStartupTransition = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.Compositor
|
import qs.Services.Compositor
|
||||||
@@ -20,16 +20,16 @@ Loader {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (modelData) {
|
if (modelData) {
|
||||||
Logger.d("Overview", "Loading overview for Niri on", modelData.name)
|
Logger.d("Overview", "Loading overview for Niri on", modelData.name);
|
||||||
}
|
}
|
||||||
setWallpaperInitial()
|
setWallpaperInitial();
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
// Clean up resources to prevent memory leak when overviewEnabled is toggled off
|
// Clean up resources to prevent memory leak when overviewEnabled is toggled off
|
||||||
timerDisableFx.stop()
|
timerDisableFx.stop();
|
||||||
bgImage.layer.enabled = false
|
bgImage.layer.enabled = false;
|
||||||
bgImage.source = ""
|
bgImage.source = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// External state management
|
// External state management
|
||||||
@@ -37,19 +37,19 @@ Loader {
|
|||||||
target: WallpaperService
|
target: WallpaperService
|
||||||
function onWallpaperChanged(screenName, path) {
|
function onWallpaperChanged(screenName, path) {
|
||||||
if (screenName === modelData.name) {
|
if (screenName === modelData.name) {
|
||||||
wallpaper = path
|
wallpaper = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setWallpaperInitial() {
|
function setWallpaperInitial() {
|
||||||
if (!WallpaperService || !WallpaperService.isInitialized) {
|
if (!WallpaperService || !WallpaperService.isInitialized) {
|
||||||
Qt.callLater(setWallpaperInitial)
|
Qt.callLater(setWallpaperInitial);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const wallpaperPath = WallpaperService.getWallpaper(modelData.name)
|
const wallpaperPath = WallpaperService.getWallpaper(modelData.name);
|
||||||
if (wallpaperPath && wallpaperPath !== wallpaper) {
|
if (wallpaperPath && wallpaperPath !== wallpaper) {
|
||||||
wallpaper = wallpaperPath
|
wallpaper = wallpaperPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.Bar.Extras
|
||||||
|
import qs.Modules.Notification
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.Notification
|
|
||||||
import qs.Modules.Bar.Extras
|
|
||||||
|
|
||||||
// Bar Component
|
// Bar Component
|
||||||
Item {
|
Item {
|
||||||
@@ -34,9 +34,9 @@ Item {
|
|||||||
// Register bar when screen becomes available
|
// Register bar when screen becomes available
|
||||||
onScreenChanged: {
|
onScreenChanged: {
|
||||||
if (screen && screen.name) {
|
if (screen && screen.name) {
|
||||||
Logger.d("Bar", "Bar screen set to:", screen.name)
|
Logger.d("Bar", "Bar screen set to:", screen.name);
|
||||||
Logger.d("Bar", " Position:", barPosition, "Floating:", barFloating)
|
Logger.d("Bar", " Position:", barPosition, "Floating:", barFloating);
|
||||||
BarService.registerBar(screen.name)
|
BarService.registerBar(screen.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,12 +46,12 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: {
|
active: {
|
||||||
if (root.screen === null || root.screen === undefined) {
|
if (root.screen === null || root.screen === undefined) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
var result = monitors.length === 0 || monitors.includes(root.screen.name)
|
var result = monitors.length === 0 || monitors.includes(root.screen.name);
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceComponent: Item {
|
sourceComponent: Item {
|
||||||
@@ -75,73 +75,73 @@ Item {
|
|||||||
readonly property int topLeftCornerState: {
|
readonly property int topLeftCornerState: {
|
||||||
// Floating bar: always simple rounded corners
|
// Floating bar: always simple rounded corners
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
// Top bar: top corners against screen edge = no radius
|
// Top bar: top corners against screen edge = no radius
|
||||||
if (barPosition === "top")
|
if (barPosition === "top")
|
||||||
return -1
|
return -1;
|
||||||
// Left bar: top-left against screen edge = no radius
|
// Left bar: top-left against screen edge = no radius
|
||||||
if (barPosition === "left")
|
if (barPosition === "left")
|
||||||
return -1
|
return -1;
|
||||||
// Bottom/Right bar with outerCorners: inverted corner
|
// Bottom/Right bar with outerCorners: inverted corner
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "right")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "right")) {
|
||||||
return barIsVertical ? 1 : 2 // horizontal invert for vertical bars, vertical invert for horizontal
|
return barIsVertical ? 1 : 2; // horizontal invert for vertical bars, vertical invert for horizontal
|
||||||
}
|
}
|
||||||
// No outerCorners = square
|
// No outerCorners = square
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int topRightCornerState: {
|
readonly property int topRightCornerState: {
|
||||||
// Floating bar: always simple rounded corners
|
// Floating bar: always simple rounded corners
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
// Top bar: top corners against screen edge = no radius
|
// Top bar: top corners against screen edge = no radius
|
||||||
if (barPosition === "top")
|
if (barPosition === "top")
|
||||||
return -1
|
return -1;
|
||||||
// Right bar: top-right against screen edge = no radius
|
// Right bar: top-right against screen edge = no radius
|
||||||
if (barPosition === "right")
|
if (barPosition === "right")
|
||||||
return -1
|
return -1;
|
||||||
// Bottom/Left bar with outerCorners: inverted corner
|
// Bottom/Left bar with outerCorners: inverted corner
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "left")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "left")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
// No outerCorners = square
|
// No outerCorners = square
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int bottomLeftCornerState: {
|
readonly property int bottomLeftCornerState: {
|
||||||
// Floating bar: always simple rounded corners
|
// Floating bar: always simple rounded corners
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
// Bottom bar: bottom corners against screen edge = no radius
|
// Bottom bar: bottom corners against screen edge = no radius
|
||||||
if (barPosition === "bottom")
|
if (barPosition === "bottom")
|
||||||
return -1
|
return -1;
|
||||||
// Left bar: bottom-left against screen edge = no radius
|
// Left bar: bottom-left against screen edge = no radius
|
||||||
if (barPosition === "left")
|
if (barPosition === "left")
|
||||||
return -1
|
return -1;
|
||||||
// Top/Right bar with outerCorners: inverted corner
|
// Top/Right bar with outerCorners: inverted corner
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "right")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "right")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
// No outerCorners = square
|
// No outerCorners = square
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int bottomRightCornerState: {
|
readonly property int bottomRightCornerState: {
|
||||||
// Floating bar: always simple rounded corners
|
// Floating bar: always simple rounded corners
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
// Bottom bar: bottom corners against screen edge = no radius
|
// Bottom bar: bottom corners against screen edge = no radius
|
||||||
if (barPosition === "bottom")
|
if (barPosition === "bottom")
|
||||||
return -1
|
return -1;
|
||||||
// Right bar: bottom-right against screen edge = no radius
|
// Right bar: bottom-right against screen edge = no radius
|
||||||
if (barPosition === "right")
|
if (barPosition === "right")
|
||||||
return -1
|
return -1;
|
||||||
// Top/Left bar with outerCorners: inverted corner
|
// Top/Left bar with outerCorners: inverted corner
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "left")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "left")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
// No outerCorners = square
|
// No outerCorners = square
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -151,14 +151,14 @@ Item {
|
|||||||
preventStealing: true
|
preventStealing: true
|
||||||
onClicked: function (mouse) {
|
onClicked: function (mouse) {
|
||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
var controlCenterPanel = PanelService.getPanel("controlCenterPanel", screen)
|
var controlCenterPanel = PanelService.getPanel("controlCenterPanel", screen);
|
||||||
if (Settings.data.controlCenter.position === "close_to_bar_button") {
|
if (Settings.data.controlCenter.position === "close_to_bar_button") {
|
||||||
// Will attempt to open the panel next to the bar button if any.
|
// Will attempt to open the panel next to the bar button if any.
|
||||||
controlCenterPanel?.toggle(null, "ControlCenter")
|
controlCenterPanel?.toggle(null, "ControlCenter");
|
||||||
} else {
|
} else {
|
||||||
controlCenterPanel?.toggle()
|
controlCenterPanel?.toggle();
|
||||||
}
|
}
|
||||||
mouse.accepted = true
|
mouse.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ import Quickshell
|
|||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BarExclusionZone - Invisible PanelWindow that reserves exclusive space for the bar
|
* BarExclusionZone - Invisible PanelWindow that reserves exclusive space for the bar
|
||||||
*
|
*
|
||||||
* This is a minimal window that works with the compositor to reserve space,
|
* This is a minimal window that works with the compositor to reserve space,
|
||||||
* while the actual bar UI is rendered in NFullScreenWindow.
|
* while the actual bar UI is rendered in NFullScreenWindow.
|
||||||
*/
|
*/
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -46,11 +45,11 @@ PanelWindow {
|
|||||||
// Vertical bar: reserve bar height + margin on the anchored edge only
|
// Vertical bar: reserve bar height + margin on the anchored edge only
|
||||||
if (barFloating) {
|
if (barFloating) {
|
||||||
// For left bar, reserve left margin; for right bar, reserve right margin
|
// For left bar, reserve left margin; for right bar, reserve right margin
|
||||||
return Style.barHeight + barMarginH
|
return Style.barHeight + barMarginH;
|
||||||
}
|
}
|
||||||
return Style.barHeight
|
return Style.barHeight;
|
||||||
}
|
}
|
||||||
return 0 // Auto-width when left/right anchors are true
|
return 0; // Auto-width when left/right anchors are true
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitHeight: {
|
implicitHeight: {
|
||||||
@@ -58,17 +57,17 @@ PanelWindow {
|
|||||||
// Horizontal bar: reserve bar height + margin on the anchored edge only
|
// Horizontal bar: reserve bar height + margin on the anchored edge only
|
||||||
if (barFloating) {
|
if (barFloating) {
|
||||||
// For top bar, reserve top margin; for bottom bar, reserve bottom margin
|
// For top bar, reserve top margin; for bottom bar, reserve bottom margin
|
||||||
return Style.barHeight + barMarginV
|
return Style.barHeight + barMarginV;
|
||||||
}
|
}
|
||||||
return Style.barHeight
|
return Style.barHeight;
|
||||||
}
|
}
|
||||||
return 0 // Auto-height when top/bottom anchors are true
|
return 0; // Auto-height when top/bottom anchors are true
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.d("BarExclusionZone", "Created for screen:", screen?.name)
|
Logger.d("BarExclusionZone", "Created for screen:", screen?.name);
|
||||||
Logger.d("BarExclusionZone", " Position:", barPosition, "Exclusive:", exclusive, "Floating:", barFloating)
|
Logger.d("BarExclusionZone", " Position:", barPosition, "Exclusive:", exclusive, "Floating:", barFloating);
|
||||||
Logger.d("BarExclusionZone", " Anchors - top:", anchors.top, "bottom:", anchors.bottom, "left:", anchors.left, "right:", anchors.right)
|
Logger.d("BarExclusionZone", " Anchors - top:", anchors.top, "bottom:", anchors.bottom, "left:", anchors.left, "right:", anchors.right);
|
||||||
Logger.d("BarExclusionZone", " Size:", width, "x", height, "implicitWidth:", implicitWidth, "implicitHeight:", implicitHeight)
|
Logger.d("BarExclusionZone", " Size:", width, "x", height, "implicitWidth:", implicitWidth, "implicitHeight:", implicitHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,19 +92,19 @@ Item {
|
|||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
if (pillLoader.item && pillLoader.item.show) {
|
if (pillLoader.item && pillLoader.item.show) {
|
||||||
pillLoader.item.show()
|
pillLoader.item.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
if (pillLoader.item && pillLoader.item.hide) {
|
if (pillLoader.item && pillLoader.item.hide) {
|
||||||
pillLoader.item.hide()
|
pillLoader.item.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showDelayed() {
|
function showDelayed() {
|
||||||
if (pillLoader.item && pillLoader.item.showDelayed) {
|
if (pillLoader.item && pillLoader.item.showDelayed) {
|
||||||
pillLoader.item.showDelayed()
|
pillLoader.item.showDelayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,18 +45,18 @@ Item {
|
|||||||
readonly property real iconSize: {
|
readonly property real iconSize: {
|
||||||
switch (root.density) {
|
switch (root.density) {
|
||||||
case "compact":
|
case "compact":
|
||||||
return Math.max(1, Math.round(pillHeight * 0.65))
|
return Math.max(1, Math.round(pillHeight * 0.65));
|
||||||
default:
|
default:
|
||||||
return Math.max(1, Math.round(pillHeight * 0.48))
|
return Math.max(1, Math.round(pillHeight * 0.48));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real textSize: {
|
readonly property real textSize: {
|
||||||
switch (root.density) {
|
switch (root.density) {
|
||||||
case "compact":
|
case "compact":
|
||||||
return Math.max(1, Math.round(pillHeight * 0.45))
|
return Math.max(1, Math.round(pillHeight * 0.45));
|
||||||
default:
|
default:
|
||||||
return Math.max(1, Math.round(pillHeight * 0.33))
|
return Math.max(1, Math.round(pillHeight * 0.33));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,7 +67,7 @@ Item {
|
|||||||
target: root
|
target: root
|
||||||
function onTooltipTextChanged() {
|
function onTooltipTextChanged() {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
TooltipService.updateText(root.tooltipText)
|
TooltipService.updateText(root.tooltipText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -97,13 +97,13 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
x: {
|
x: {
|
||||||
// Better text horizontal centering
|
// Better text horizontal centering
|
||||||
var centerX = (parent.width - width) / 2
|
var centerX = (parent.width - width) / 2;
|
||||||
var offset = oppositeDirection ? Style.marginXS : -Style.marginXS
|
var offset = oppositeDirection ? Style.marginXS : -Style.marginXS;
|
||||||
if (forceOpen) {
|
if (forceOpen) {
|
||||||
// If its force open, the icon disc background is the same color as the bg pill move text slightly
|
// If its force open, the icon disc background is the same color as the bg pill move text slightly
|
||||||
offset += oppositeDirection ? -Style.marginXXS : Style.marginXXS
|
offset += oppositeDirection ? -Style.marginXXS : Style.marginXXS;
|
||||||
}
|
}
|
||||||
return centerX + offset
|
return centerX + offset;
|
||||||
}
|
}
|
||||||
text: root.text + root.suffix
|
text: root.text + root.suffix
|
||||||
family: Settings.data.ui.fontFixed
|
family: Settings.data.ui.fontFixed
|
||||||
@@ -179,11 +179,11 @@ Item {
|
|||||||
easing.type: Easing.OutCubic
|
easing.type: Easing.OutCubic
|
||||||
}
|
}
|
||||||
onStarted: {
|
onStarted: {
|
||||||
showPill = true
|
showPill = true;
|
||||||
}
|
}
|
||||||
onStopped: {
|
onStopped: {
|
||||||
delayedHideAnim.start()
|
delayedHideAnim.start();
|
||||||
root.shown()
|
root.shown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ Item {
|
|||||||
}
|
}
|
||||||
ScriptAction {
|
ScriptAction {
|
||||||
script: if (shouldAnimateHide) {
|
script: if (shouldAnimateHide) {
|
||||||
hideAnim.start()
|
hideAnim.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -220,9 +220,9 @@ Item {
|
|||||||
easing.type: Easing.InCubic
|
easing.type: Easing.InCubic
|
||||||
}
|
}
|
||||||
onStopped: {
|
onStopped: {
|
||||||
showPill = false
|
showPill = false;
|
||||||
shouldAnimateHide = false
|
shouldAnimateHide = false;
|
||||||
root.hidden()
|
root.hidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ Item {
|
|||||||
interval: Style.pillDelay
|
interval: Style.pillDelay
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (!showPill) {
|
if (!showPill) {
|
||||||
showAnim.start()
|
showAnim.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -241,31 +241,31 @@ Item {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onEntered: {
|
onEntered: {
|
||||||
hovered = true
|
hovered = true;
|
||||||
root.entered()
|
root.entered();
|
||||||
TooltipService.show(Screen, pill, root.tooltipText, BarService.getTooltipDirection(), Style.tooltipDelayLong)
|
TooltipService.show(Screen, pill, root.tooltipText, BarService.getTooltipDirection(), Style.tooltipDelayLong);
|
||||||
if (forceClose) {
|
if (forceClose) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!forceOpen) {
|
if (!forceOpen) {
|
||||||
showDelayed()
|
showDelayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
hovered = false
|
hovered = false;
|
||||||
root.exited()
|
root.exited();
|
||||||
if (!forceOpen && !forceClose) {
|
if (!forceOpen && !forceClose) {
|
||||||
hide()
|
hide();
|
||||||
}
|
}
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
onClicked: function (mouse) {
|
onClicked: function (mouse) {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
root.clicked()
|
root.clicked();
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
root.rightClicked()
|
root.rightClicked();
|
||||||
} else if (mouse.button === Qt.MiddleButton) {
|
} else if (mouse.button === Qt.MiddleButton) {
|
||||||
root.middleClicked()
|
root.middleClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onWheel: wheel => root.wheel(wheel.angleDelta.y)
|
onWheel: wheel => root.wheel(wheel.angleDelta.y)
|
||||||
@@ -273,43 +273,43 @@ Item {
|
|||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
if (!showPill) {
|
if (!showPill) {
|
||||||
shouldAnimateHide = autoHide
|
shouldAnimateHide = autoHide;
|
||||||
showAnim.start()
|
showAnim.start();
|
||||||
} else {
|
} else {
|
||||||
hideAnim.stop()
|
hideAnim.stop();
|
||||||
delayedHideAnim.restart()
|
delayedHideAnim.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
if (forceOpen) {
|
if (forceOpen) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (showPill) {
|
if (showPill) {
|
||||||
hideAnim.start()
|
hideAnim.start();
|
||||||
}
|
}
|
||||||
showTimer.stop()
|
showTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showDelayed() {
|
function showDelayed() {
|
||||||
if (!showPill) {
|
if (!showPill) {
|
||||||
shouldAnimateHide = autoHide
|
shouldAnimateHide = autoHide;
|
||||||
showTimer.start()
|
showTimer.start();
|
||||||
} else {
|
} else {
|
||||||
hideAnim.stop()
|
hideAnim.stop();
|
||||||
delayedHideAnim.restart()
|
delayedHideAnim.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onForceOpenChanged: {
|
onForceOpenChanged: {
|
||||||
if (forceOpen) {
|
if (forceOpen) {
|
||||||
// Immediately lock open without animations
|
// Immediately lock open without animations
|
||||||
showAnim.stop()
|
showAnim.stop();
|
||||||
hideAnim.stop()
|
hideAnim.stop();
|
||||||
delayedHideAnim.stop()
|
delayedHideAnim.stop();
|
||||||
showPill = true
|
showPill = true;
|
||||||
} else {
|
} else {
|
||||||
hide()
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,18 +55,18 @@ Item {
|
|||||||
readonly property real iconSize: {
|
readonly property real iconSize: {
|
||||||
switch (root.density) {
|
switch (root.density) {
|
||||||
case "compact":
|
case "compact":
|
||||||
return Math.max(1, Math.round(pillHeight * 0.65))
|
return Math.max(1, Math.round(pillHeight * 0.65));
|
||||||
default:
|
default:
|
||||||
return Math.max(1, Math.round(pillHeight * 0.48))
|
return Math.max(1, Math.round(pillHeight * 0.48));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real textSize: {
|
readonly property real textSize: {
|
||||||
switch (root.density) {
|
switch (root.density) {
|
||||||
case "compact":
|
case "compact":
|
||||||
return Math.max(1, Math.round(pillHeight * 0.38))
|
return Math.max(1, Math.round(pillHeight * 0.38));
|
||||||
default:
|
default:
|
||||||
return Math.max(1, Math.round(pillHeight * 0.33))
|
return Math.max(1, Math.round(pillHeight * 0.33));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,7 +78,7 @@ Item {
|
|||||||
target: root
|
target: root
|
||||||
function onTooltipTextChanged() {
|
function onTooltipTextChanged() {
|
||||||
if (hovered) {
|
if (hovered) {
|
||||||
TooltipService.updateText(root.tooltipText)
|
TooltipService.updateText(root.tooltipText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,11 +123,11 @@ Item {
|
|||||||
visible: revealed
|
visible: revealed
|
||||||
|
|
||||||
function getVerticalCenterOffset() {
|
function getVerticalCenterOffset() {
|
||||||
var offset = openDownward ? Math.round(pillPaddingVertical * 0.75) : -Math.round(pillPaddingVertical * 0.75)
|
var offset = openDownward ? Math.round(pillPaddingVertical * 0.75) : -Math.round(pillPaddingVertical * 0.75);
|
||||||
if (forceOpen) {
|
if (forceOpen) {
|
||||||
offset += oppositeDirection ? -Style.marginXXS : Style.marginXXS
|
offset += oppositeDirection ? -Style.marginXXS : Style.marginXXS;
|
||||||
}
|
}
|
||||||
return offset
|
return offset;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
@@ -212,11 +212,11 @@ Item {
|
|||||||
easing.type: Easing.OutCubic
|
easing.type: Easing.OutCubic
|
||||||
}
|
}
|
||||||
onStarted: {
|
onStarted: {
|
||||||
showPill = true
|
showPill = true;
|
||||||
}
|
}
|
||||||
onStopped: {
|
onStopped: {
|
||||||
delayedHideAnim.start()
|
delayedHideAnim.start();
|
||||||
root.shown()
|
root.shown();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ Item {
|
|||||||
}
|
}
|
||||||
ScriptAction {
|
ScriptAction {
|
||||||
script: if (shouldAnimateHide) {
|
script: if (shouldAnimateHide) {
|
||||||
hideAnim.start()
|
hideAnim.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,9 +261,9 @@ Item {
|
|||||||
easing.type: Easing.InCubic
|
easing.type: Easing.InCubic
|
||||||
}
|
}
|
||||||
onStopped: {
|
onStopped: {
|
||||||
showPill = false
|
showPill = false;
|
||||||
shouldAnimateHide = false
|
shouldAnimateHide = false;
|
||||||
root.hidden()
|
root.hidden();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +272,7 @@ Item {
|
|||||||
interval: Style.pillDelay
|
interval: Style.pillDelay
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (!showPill) {
|
if (!showPill) {
|
||||||
showAnim.start()
|
showAnim.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -282,31 +282,31 @@ Item {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onEntered: {
|
onEntered: {
|
||||||
hovered = true
|
hovered = true;
|
||||||
root.entered()
|
root.entered();
|
||||||
TooltipService.show(Screen, pill, root.tooltipText, BarService.getTooltipDirection(), Style.tooltipDelayLong)
|
TooltipService.show(Screen, pill, root.tooltipText, BarService.getTooltipDirection(), Style.tooltipDelayLong);
|
||||||
if (forceClose) {
|
if (forceClose) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!forceOpen) {
|
if (!forceOpen) {
|
||||||
showDelayed()
|
showDelayed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
hovered = false
|
hovered = false;
|
||||||
root.exited()
|
root.exited();
|
||||||
if (!forceOpen && !forceClose) {
|
if (!forceOpen && !forceClose) {
|
||||||
hide()
|
hide();
|
||||||
}
|
}
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
onClicked: function (mouse) {
|
onClicked: function (mouse) {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
root.clicked()
|
root.clicked();
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
root.rightClicked()
|
root.rightClicked();
|
||||||
} else if (mouse.button === Qt.MiddleButton) {
|
} else if (mouse.button === Qt.MiddleButton) {
|
||||||
root.middleClicked()
|
root.middleClicked();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onWheel: wheel => root.wheel(wheel.angleDelta.y)
|
onWheel: wheel => root.wheel(wheel.angleDelta.y)
|
||||||
@@ -314,43 +314,43 @@ Item {
|
|||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
if (!showPill) {
|
if (!showPill) {
|
||||||
shouldAnimateHide = autoHide
|
shouldAnimateHide = autoHide;
|
||||||
showAnim.start()
|
showAnim.start();
|
||||||
} else {
|
} else {
|
||||||
hideAnim.stop()
|
hideAnim.stop();
|
||||||
delayedHideAnim.restart()
|
delayedHideAnim.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
if (forceOpen) {
|
if (forceOpen) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (showPill) {
|
if (showPill) {
|
||||||
hideAnim.start()
|
hideAnim.start();
|
||||||
}
|
}
|
||||||
showTimer.stop()
|
showTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showDelayed() {
|
function showDelayed() {
|
||||||
if (!showPill) {
|
if (!showPill) {
|
||||||
shouldAnimateHide = autoHide
|
shouldAnimateHide = autoHide;
|
||||||
showTimer.start()
|
showTimer.start();
|
||||||
} else {
|
} else {
|
||||||
hideAnim.stop()
|
hideAnim.stop();
|
||||||
delayedHideAnim.restart()
|
delayedHideAnim.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onForceOpenChanged: {
|
onForceOpenChanged: {
|
||||||
if (forceOpen) {
|
if (forceOpen) {
|
||||||
// Immediately lock open without animations
|
// Immediately lock open without animations
|
||||||
showAnim.stop()
|
showAnim.stop();
|
||||||
hideAnim.stop()
|
hideAnim.stop();
|
||||||
delayedHideAnim.stop()
|
delayedHideAnim.stop();
|
||||||
showPill = true
|
showPill = true;
|
||||||
} else {
|
} else {
|
||||||
hide()
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -25,7 +25,7 @@ Item {
|
|||||||
visible: loader.item ? ((loader.item.opacity > 0.0) || (loader.item.hasOwnProperty("hideMode") && loader.item.hideMode === "transparent")) : false
|
visible: loader.item ? ((loader.item.opacity > 0.0) || (loader.item.hasOwnProperty("hideMode") && loader.item.hideMode === "transparent")) : false
|
||||||
|
|
||||||
function getImplicitSize(item, prop) {
|
function getImplicitSize(item, prop) {
|
||||||
return (item && item.visible) ? Math.round(item[prop]) : 0
|
return (item && item.visible) ? Math.round(item[prop]) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -36,42 +36,41 @@ Item {
|
|||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (!item)
|
if (!item)
|
||||||
return
|
return;
|
||||||
|
Logger.d("BarWidgetLoader", "Loading widget", widgetId, "on screen:", widgetScreen.name);
|
||||||
Logger.d("BarWidgetLoader", "Loading widget", widgetId, "on screen:", widgetScreen.name)
|
|
||||||
|
|
||||||
// Apply properties to loaded widget
|
// Apply properties to loaded widget
|
||||||
for (var prop in widgetProps) {
|
for (var prop in widgetProps) {
|
||||||
if (item.hasOwnProperty(prop)) {
|
if (item.hasOwnProperty(prop)) {
|
||||||
item[prop] = widgetProps[prop]
|
item[prop] = widgetProps[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set screen property
|
// Set screen property
|
||||||
if (item.hasOwnProperty("screen")) {
|
if (item.hasOwnProperty("screen")) {
|
||||||
item.screen = widgetScreen
|
item.screen = widgetScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set scaling property
|
// Set scaling property
|
||||||
if (item.hasOwnProperty("scaling")) {
|
if (item.hasOwnProperty("scaling")) {
|
||||||
item.scaling = Qt.binding(function () {
|
item.scaling = Qt.binding(function () {
|
||||||
return root.scaling
|
return root.scaling;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register this widget instance with BarService
|
// Register this widget instance with BarService
|
||||||
BarService.registerWidget(widgetScreen.name, section, widgetId, sectionIndex, item)
|
BarService.registerWidget(widgetScreen.name, section, widgetId, sectionIndex, item);
|
||||||
|
|
||||||
// Call custom onLoaded if it exists
|
// Call custom onLoaded if it exists
|
||||||
if (item.hasOwnProperty("onLoaded")) {
|
if (item.hasOwnProperty("onLoaded")) {
|
||||||
item.onLoaded()
|
item.onLoaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
// Unregister when destroyed
|
// Unregister when destroyed
|
||||||
if (widgetScreen && section) {
|
if (widgetScreen && section) {
|
||||||
BarService.unregisterWidget(widgetScreen.name, section, widgetId, sectionIndex)
|
BarService.unregisterWidget(widgetScreen.name, section, widgetId, sectionIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,7 +78,7 @@ Item {
|
|||||||
// Error handling
|
// Error handling
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (!BarWidgetRegistry.hasWidget(widgetId)) {
|
if (!BarWidgetRegistry.hasWidget(widgetId)) {
|
||||||
Logger.w("BarWidgetLoader", "Widget not found in registry:", widgetId)
|
Logger.w("BarWidgetLoader", "Widget not found in registry:", widgetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,20 +25,20 @@ PopupWindow {
|
|||||||
// Compute if current tray item is pinned
|
// Compute if current tray item is pinned
|
||||||
readonly property bool isPinned: {
|
readonly property bool isPinned: {
|
||||||
if (!trayItem || widgetSection === "" || widgetIndex < 0)
|
if (!trayItem || widgetSection === "" || widgetIndex < 0)
|
||||||
return false
|
return false;
|
||||||
var widgets = Settings.data.bar.widgets[widgetSection]
|
var widgets = Settings.data.bar.widgets[widgetSection];
|
||||||
if (!widgets || widgetIndex >= widgets.length)
|
if (!widgets || widgetIndex >= widgets.length)
|
||||||
return false
|
return false;
|
||||||
var widgetSettings = widgets[widgetIndex]
|
var widgetSettings = widgets[widgetIndex];
|
||||||
if (!widgetSettings || widgetSettings.id !== "Tray")
|
if (!widgetSettings || widgetSettings.id !== "Tray")
|
||||||
return false
|
return false;
|
||||||
var pinnedList = widgetSettings.pinned || []
|
var pinnedList = widgetSettings.pinned || [];
|
||||||
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || ""
|
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || "";
|
||||||
for (var i = 0; i < pinnedList.length; i++) {
|
for (var i = 0; i < pinnedList.length; i++) {
|
||||||
if (pinnedList[i] === itemName)
|
if (pinnedList[i] === itemName)
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int menuWidth: 220
|
readonly property int menuWidth: 220
|
||||||
@@ -53,47 +53,47 @@ PopupWindow {
|
|||||||
anchor.rect.x: anchorX
|
anchor.rect.x: anchorX
|
||||||
anchor.rect.y: {
|
anchor.rect.y: {
|
||||||
if (isSubMenu) {
|
if (isSubMenu) {
|
||||||
const offsetY = Settings.data.bar.position === "bottom" ? -10 : 10
|
const offsetY = Settings.data.bar.position === "bottom" ? -10 : 10;
|
||||||
return anchorY + offsetY
|
return anchorY + offsetY;
|
||||||
}
|
}
|
||||||
return anchorY + Settings.data.bar.position === "bottom" ? -implicitHeight : Style.barHeight
|
return anchorY + Settings.data.bar.position === "bottom" ? -implicitHeight : Style.barHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
function showAt(item, x, y) {
|
function showAt(item, x, y) {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
Logger.w("TrayMenu", "anchorItem is undefined, won't show menu.")
|
Logger.w("TrayMenu", "anchorItem is undefined, won't show menu.");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opener.children || opener.children.values.length === 0) {
|
if (!opener.children || opener.children.values.length === 0) {
|
||||||
//Logger.w("TrayMenu", "Menu not ready, delaying show")
|
//Logger.w("TrayMenu", "Menu not ready, delaying show")
|
||||||
Qt.callLater(() => showAt(item, x, y))
|
Qt.callLater(() => showAt(item, x, y));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
anchorItem = item
|
anchorItem = item;
|
||||||
anchorX = x
|
anchorX = x;
|
||||||
anchorY = y
|
anchorY = y;
|
||||||
|
|
||||||
visible = true
|
visible = true;
|
||||||
forceActiveFocus()
|
forceActiveFocus();
|
||||||
|
|
||||||
// Force update after showing.
|
// Force update after showing.
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
root.anchor.updateAnchor()
|
root.anchor.updateAnchor();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideMenu() {
|
function hideMenu() {
|
||||||
visible = false
|
visible = false;
|
||||||
|
|
||||||
// Clean up all submenus recursively
|
// Clean up all submenus recursively
|
||||||
for (var i = 0; i < columnLayout.children.length; i++) {
|
for (var i = 0; i < columnLayout.children.length; i++) {
|
||||||
const child = columnLayout.children[i]
|
const child = columnLayout.children[i];
|
||||||
if (child?.subMenu) {
|
if (child?.subMenu) {
|
||||||
child.subMenu.hideMenu()
|
child.subMenu.hideMenu();
|
||||||
child.subMenu.destroy()
|
child.subMenu.destroy();
|
||||||
child.subMenu = null
|
child.subMenu = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -166,11 +166,11 @@ PopupWindow {
|
|||||||
Layout.preferredWidth: parent.width
|
Layout.preferredWidth: parent.width
|
||||||
Layout.preferredHeight: {
|
Layout.preferredHeight: {
|
||||||
if (modelData?.isSeparator) {
|
if (modelData?.isSeparator) {
|
||||||
return 8
|
return 8;
|
||||||
} else {
|
} else {
|
||||||
// Calculate based on text content
|
// Calculate based on text content
|
||||||
const textHeight = text.contentHeight || (Style.fontSizeS * 1.2)
|
const textHeight = text.contentHeight || (Style.fontSizeS * 1.2);
|
||||||
return Math.max(28, textHeight + (Style.marginS * 2))
|
return Math.max(28, textHeight + (Style.marginS * 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,31 +237,31 @@ PopupWindow {
|
|||||||
// Click on items with children toggles submenu
|
// Click on items with children toggles submenu
|
||||||
if (entry.subMenu) {
|
if (entry.subMenu) {
|
||||||
// Close existing submenu
|
// Close existing submenu
|
||||||
entry.subMenu.hideMenu()
|
entry.subMenu.hideMenu();
|
||||||
entry.subMenu.destroy()
|
entry.subMenu.destroy();
|
||||||
entry.subMenu = null
|
entry.subMenu = null;
|
||||||
} else {
|
} else {
|
||||||
// Close any other open submenus first
|
// Close any other open submenus first
|
||||||
for (var i = 0; i < columnLayout.children.length; i++) {
|
for (var i = 0; i < columnLayout.children.length; i++) {
|
||||||
const sibling = columnLayout.children[i]
|
const sibling = columnLayout.children[i];
|
||||||
if (sibling !== entry && sibling.subMenu) {
|
if (sibling !== entry && sibling.subMenu) {
|
||||||
sibling.subMenu.hideMenu()
|
sibling.subMenu.hideMenu();
|
||||||
sibling.subMenu.destroy()
|
sibling.subMenu.destroy();
|
||||||
sibling.subMenu = null
|
sibling.subMenu = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine submenu opening direction
|
// Determine submenu opening direction
|
||||||
let openLeft = false
|
let openLeft = false;
|
||||||
const barPosition = Settings.data.bar.position
|
const barPosition = Settings.data.bar.position;
|
||||||
const globalPos = entry.mapToItem(null, 0, 0)
|
const globalPos = entry.mapToItem(null, 0, 0);
|
||||||
|
|
||||||
if (barPosition === "right") {
|
if (barPosition === "right") {
|
||||||
openLeft = true
|
openLeft = true;
|
||||||
} else if (barPosition === "left") {
|
} else if (barPosition === "left") {
|
||||||
openLeft = false
|
openLeft = false;
|
||||||
} else {
|
} else {
|
||||||
openLeft = (root.widgetSection === "right")
|
openLeft = (root.widgetSection === "right");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open new submenu
|
// Open new submenu
|
||||||
@@ -269,30 +269,30 @@ PopupWindow {
|
|||||||
"menu": modelData,
|
"menu": modelData,
|
||||||
"isSubMenu": true,
|
"isSubMenu": true,
|
||||||
"screen": root.screen
|
"screen": root.screen
|
||||||
})
|
});
|
||||||
|
|
||||||
if (entry.subMenu) {
|
if (entry.subMenu) {
|
||||||
const overlap = 60
|
const overlap = 60;
|
||||||
entry.subMenu.anchorItem = entry
|
entry.subMenu.anchorItem = entry;
|
||||||
entry.subMenu.anchorX = openLeft ? -overlap : overlap
|
entry.subMenu.anchorX = openLeft ? -overlap : overlap;
|
||||||
entry.subMenu.anchorY = 0
|
entry.subMenu.anchorY = 0;
|
||||||
entry.subMenu.visible = true
|
entry.subMenu.visible = true;
|
||||||
// Force anchor update with new position
|
// Force anchor update with new position
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
entry.subMenu.anchor.updateAnchor()
|
entry.subMenu.anchor.updateAnchor();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Click on regular items triggers them
|
// Click on regular items triggers them
|
||||||
modelData.triggered()
|
modelData.triggered();
|
||||||
root.hideMenu()
|
root.hideMenu();
|
||||||
|
|
||||||
// Close the drawer if it's open
|
// Close the drawer if it's open
|
||||||
if (root.screen) {
|
if (root.screen) {
|
||||||
const panel = PanelService.getPanel("trayDrawerPanel", root.screen)
|
const panel = PanelService.getPanel("trayDrawerPanel", root.screen);
|
||||||
if (panel && panel.visible) {
|
if (panel && panel.visible) {
|
||||||
panel.close()
|
panel.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,8 +303,8 @@ PopupWindow {
|
|||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
if (subMenu) {
|
if (subMenu) {
|
||||||
subMenu.destroy()
|
subMenu.destroy();
|
||||||
subMenu = null
|
subMenu = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -351,9 +351,9 @@ PopupWindow {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (root.isPinned) {
|
if (root.isPinned) {
|
||||||
root.removeFromPinned()
|
root.removeFromPinned();
|
||||||
} else {
|
} else {
|
||||||
root.addToPinned()
|
root.addToPinned();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -363,72 +363,72 @@ PopupWindow {
|
|||||||
|
|
||||||
function addToPinned() {
|
function addToPinned() {
|
||||||
if (!trayItem || widgetSection === "" || widgetIndex < 0) {
|
if (!trayItem || widgetSection === "" || widgetIndex < 0) {
|
||||||
Logger.w("TrayMenu", "Cannot pin: missing tray item or widget info")
|
Logger.w("TrayMenu", "Cannot pin: missing tray item or widget info");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || ""
|
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || "";
|
||||||
if (!itemName) {
|
if (!itemName) {
|
||||||
Logger.w("TrayMenu", "Cannot pin: tray item has no name")
|
Logger.w("TrayMenu", "Cannot pin: tray item has no name");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
var widgets = Settings.data.bar.widgets[widgetSection]
|
var widgets = Settings.data.bar.widgets[widgetSection];
|
||||||
if (!widgets || widgetIndex >= widgets.length) {
|
if (!widgets || widgetIndex >= widgets.length) {
|
||||||
Logger.w("TrayMenu", "Cannot pin: invalid widget index")
|
Logger.w("TrayMenu", "Cannot pin: invalid widget index");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
var widgetSettings = widgets[widgetIndex]
|
var widgetSettings = widgets[widgetIndex];
|
||||||
if (!widgetSettings || widgetSettings.id !== "Tray") {
|
if (!widgetSettings || widgetSettings.id !== "Tray") {
|
||||||
Logger.w("TrayMenu", "Cannot pin: widget is not a Tray widget")
|
Logger.w("TrayMenu", "Cannot pin: widget is not a Tray widget");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
var pinnedList = widgetSettings.pinned || []
|
var pinnedList = widgetSettings.pinned || [];
|
||||||
var newPinned = pinnedList.slice()
|
var newPinned = pinnedList.slice();
|
||||||
newPinned.push(itemName)
|
newPinned.push(itemName);
|
||||||
var newSettings = Object.assign({}, widgetSettings)
|
var newSettings = Object.assign({}, widgetSettings);
|
||||||
newSettings.pinned = newPinned
|
newSettings.pinned = newPinned;
|
||||||
widgets[widgetIndex] = newSettings
|
widgets[widgetIndex] = newSettings;
|
||||||
Settings.data.bar.widgets[widgetSection] = widgets
|
Settings.data.bar.widgets[widgetSection] = widgets;
|
||||||
Settings.saveImmediate()
|
Settings.saveImmediate();
|
||||||
|
|
||||||
// Close drawer when pinning (drawer needs to resize)
|
// Close drawer when pinning (drawer needs to resize)
|
||||||
if (screen) {
|
if (screen) {
|
||||||
const panel = PanelService.getPanel("trayDrawerPanel", screen)
|
const panel = PanelService.getPanel("trayDrawerPanel", screen);
|
||||||
if (panel)
|
if (panel)
|
||||||
panel.close()
|
panel.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeFromPinned() {
|
function removeFromPinned() {
|
||||||
if (!trayItem || widgetSection === "" || widgetIndex < 0) {
|
if (!trayItem || widgetSection === "" || widgetIndex < 0) {
|
||||||
Logger.w("TrayMenu", "Cannot unpin: missing tray item or widget info")
|
Logger.w("TrayMenu", "Cannot unpin: missing tray item or widget info");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || ""
|
const itemName = trayItem.tooltipTitle || trayItem.name || trayItem.id || "";
|
||||||
if (!itemName) {
|
if (!itemName) {
|
||||||
Logger.w("TrayMenu", "Cannot unpin: tray item has no name")
|
Logger.w("TrayMenu", "Cannot unpin: tray item has no name");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
var widgets = Settings.data.bar.widgets[widgetSection]
|
var widgets = Settings.data.bar.widgets[widgetSection];
|
||||||
if (!widgets || widgetIndex >= widgets.length) {
|
if (!widgets || widgetIndex >= widgets.length) {
|
||||||
Logger.w("TrayMenu", "Cannot unpin: invalid widget index")
|
Logger.w("TrayMenu", "Cannot unpin: invalid widget index");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
var widgetSettings = widgets[widgetIndex]
|
var widgetSettings = widgets[widgetIndex];
|
||||||
if (!widgetSettings || widgetSettings.id !== "Tray") {
|
if (!widgetSettings || widgetSettings.id !== "Tray") {
|
||||||
Logger.w("TrayMenu", "Cannot unpin: widget is not a Tray widget")
|
Logger.w("TrayMenu", "Cannot unpin: widget is not a Tray widget");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
var pinnedList = widgetSettings.pinned || []
|
var pinnedList = widgetSettings.pinned || [];
|
||||||
var newPinned = []
|
var newPinned = [];
|
||||||
for (var i = 0; i < pinnedList.length; i++) {
|
for (var i = 0; i < pinnedList.length; i++) {
|
||||||
if (pinnedList[i] !== itemName) {
|
if (pinnedList[i] !== itemName) {
|
||||||
newPinned.push(pinnedList[i])
|
newPinned.push(pinnedList[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var newSettings = Object.assign({}, widgetSettings)
|
var newSettings = Object.assign({}, widgetSettings);
|
||||||
newSettings.pinned = newPinned
|
newSettings.pinned = newPinned;
|
||||||
widgets[widgetIndex] = newSettings
|
widgets[widgetIndex] = newSettings;
|
||||||
Settings.data.bar.widgets[widgetSection] = widgets
|
Settings.data.bar.widgets[widgetSection] = widgets;
|
||||||
Settings.saveImmediate()
|
Settings.saveImmediate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Widget settings - matching MediaMini pattern
|
// Widget settings - matching MediaMini pattern
|
||||||
@@ -73,60 +73,60 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function calculatedVerticalDimension() {
|
function calculatedVerticalDimension() {
|
||||||
return Math.round((Style.baseWidgetSize - 5) * scaling)
|
return Math.round((Style.baseWidgetSize - 5) * scaling);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateContentWidth() {
|
function calculateContentWidth() {
|
||||||
// Calculate the actual content width based on visible elements
|
// Calculate the actual content width based on visible elements
|
||||||
var contentWidth = 0
|
var contentWidth = 0;
|
||||||
var margins = Style.marginS * scaling * 2 // Left and right margins
|
var margins = Style.marginS * scaling * 2; // Left and right margins
|
||||||
|
|
||||||
// Icon width (if visible)
|
// Icon width (if visible)
|
||||||
if (showIcon) {
|
if (showIcon) {
|
||||||
contentWidth += 18 * scaling
|
contentWidth += 18 * scaling;
|
||||||
contentWidth += Style.marginS * scaling // Spacing after icon
|
contentWidth += Style.marginS * scaling; // Spacing after icon
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text width (use the measured width)
|
// Text width (use the measured width)
|
||||||
contentWidth += fullTitleMetrics.contentWidth
|
contentWidth += fullTitleMetrics.contentWidth;
|
||||||
|
|
||||||
// Additional small margin for text
|
// Additional small margin for text
|
||||||
contentWidth += Style.marginXXS * 2
|
contentWidth += Style.marginXXS * 2;
|
||||||
|
|
||||||
// Add container margins
|
// Add container margins
|
||||||
contentWidth += margins
|
contentWidth += margins;
|
||||||
|
|
||||||
return Math.ceil(contentWidth)
|
return Math.ceil(contentWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic width: adapt to content but respect maximum width setting
|
// Dynamic width: adapt to content but respect maximum width setting
|
||||||
readonly property real dynamicWidth: {
|
readonly property real dynamicWidth: {
|
||||||
// If using fixed width mode, always use maxWidth
|
// If using fixed width mode, always use maxWidth
|
||||||
if (useFixedWidth) {
|
if (useFixedWidth) {
|
||||||
return maxWidth
|
return maxWidth;
|
||||||
}
|
}
|
||||||
// Otherwise, adapt to content
|
// Otherwise, adapt to content
|
||||||
if (!hasFocusedWindow) {
|
if (!hasFocusedWindow) {
|
||||||
return Math.min(calculateContentWidth(), maxWidth)
|
return Math.min(calculateContentWidth(), maxWidth);
|
||||||
}
|
}
|
||||||
// Use content width but don't exceed user-set maximum width
|
// Use content width but don't exceed user-set maximum width
|
||||||
return Math.min(calculateContentWidth(), maxWidth)
|
return Math.min(calculateContentWidth(), maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAppIcon() {
|
function getAppIcon() {
|
||||||
try {
|
try {
|
||||||
// Try CompositorService first
|
// Try CompositorService first
|
||||||
const focusedWindow = CompositorService.getFocusedWindow()
|
const focusedWindow = CompositorService.getFocusedWindow();
|
||||||
if (focusedWindow && focusedWindow.appId) {
|
if (focusedWindow && focusedWindow.appId) {
|
||||||
try {
|
try {
|
||||||
const idValue = focusedWindow.appId
|
const idValue = focusedWindow.appId;
|
||||||
const normalizedId = (typeof idValue === 'string') ? idValue : String(idValue)
|
const normalizedId = (typeof idValue === 'string') ? idValue : String(idValue);
|
||||||
const iconResult = ThemeIcons.iconForAppId(normalizedId.toLowerCase())
|
const iconResult = ThemeIcons.iconForAppId(normalizedId.toLowerCase());
|
||||||
if (iconResult && iconResult !== "") {
|
if (iconResult && iconResult !== "") {
|
||||||
return iconResult
|
return iconResult;
|
||||||
}
|
}
|
||||||
} catch (iconError) {
|
} catch (iconError) {
|
||||||
Logger.w("ActiveWindow", "Error getting icon from CompositorService:", iconError)
|
Logger.w("ActiveWindow", "Error getting icon from CompositorService:", iconError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,25 +134,25 @@ Item {
|
|||||||
// Fallback to ToplevelManager
|
// Fallback to ToplevelManager
|
||||||
if (ToplevelManager && ToplevelManager.activeToplevel) {
|
if (ToplevelManager && ToplevelManager.activeToplevel) {
|
||||||
try {
|
try {
|
||||||
const activeToplevel = ToplevelManager.activeToplevel
|
const activeToplevel = ToplevelManager.activeToplevel;
|
||||||
if (activeToplevel.appId) {
|
if (activeToplevel.appId) {
|
||||||
const idValue2 = activeToplevel.appId
|
const idValue2 = activeToplevel.appId;
|
||||||
const normalizedId2 = (typeof idValue2 === 'string') ? idValue2 : String(idValue2)
|
const normalizedId2 = (typeof idValue2 === 'string') ? idValue2 : String(idValue2);
|
||||||
const iconResult2 = ThemeIcons.iconForAppId(normalizedId2.toLowerCase())
|
const iconResult2 = ThemeIcons.iconForAppId(normalizedId2.toLowerCase());
|
||||||
if (iconResult2 && iconResult2 !== "") {
|
if (iconResult2 && iconResult2 !== "") {
|
||||||
return iconResult2
|
return iconResult2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (fallbackError) {
|
} catch (fallbackError) {
|
||||||
Logger.w("ActiveWindow", "Error getting icon from ToplevelManager:", fallbackError)
|
Logger.w("ActiveWindow", "Error getting icon from ToplevelManager:", fallbackError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ThemeIcons.iconFromName(fallbackIcon)
|
return ThemeIcons.iconFromName(fallbackIcon);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.w("ActiveWindow", "Error in getAppIcon:", e)
|
Logger.w("ActiveWindow", "Error in getAppIcon:", e);
|
||||||
return ThemeIcons.iconFromName(fallbackIcon)
|
return ThemeIcons.iconFromName(fallbackIcon);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,10 +228,10 @@ Item {
|
|||||||
id: titleContainer
|
id: titleContainer
|
||||||
Layout.preferredWidth: {
|
Layout.preferredWidth: {
|
||||||
// Calculate available width based on other elements
|
// Calculate available width based on other elements
|
||||||
var iconWidth = (showIcon && windowIcon.visible ? (18 + Style.marginS) : 0)
|
var iconWidth = (showIcon && windowIcon.visible ? (18 + Style.marginS) : 0);
|
||||||
var totalMargins = Style.marginXXS * 2
|
var totalMargins = Style.marginXXS * 2;
|
||||||
var availableWidth = mainContainer.width - iconWidth - totalMargins
|
var availableWidth = mainContainer.width - iconWidth - totalMargins;
|
||||||
return Math.max(20, availableWidth)
|
return Math.max(20, availableWidth);
|
||||||
}
|
}
|
||||||
Layout.maximumWidth: Layout.preferredWidth
|
Layout.maximumWidth: Layout.preferredWidth
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
@@ -252,8 +252,8 @@ Item {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (scrollingMode === "always" && titleContainer.needsScrolling) {
|
if (scrollingMode === "always" && titleContainer.needsScrolling) {
|
||||||
titleContainer.isScrolling = true
|
titleContainer.isScrolling = true;
|
||||||
titleContainer.isResetting = false
|
titleContainer.isResetting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -261,29 +261,29 @@ Item {
|
|||||||
// Update scrolling state based on mode
|
// Update scrolling state based on mode
|
||||||
property var updateScrollingState: function () {
|
property var updateScrollingState: function () {
|
||||||
if (scrollingMode === "never") {
|
if (scrollingMode === "never") {
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
isResetting = false
|
isResetting = false;
|
||||||
} else if (scrollingMode === "always") {
|
} else if (scrollingMode === "always") {
|
||||||
if (needsScrolling) {
|
if (needsScrolling) {
|
||||||
if (mouseArea.containsMouse) {
|
if (mouseArea.containsMouse) {
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
isResetting = true
|
isResetting = true;
|
||||||
} else {
|
} else {
|
||||||
scrollStartTimer.restart()
|
scrollStartTimer.restart();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scrollStartTimer.stop()
|
scrollStartTimer.stop();
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
isResetting = false
|
isResetting = false;
|
||||||
}
|
}
|
||||||
} else if (scrollingMode === "hover") {
|
} else if (scrollingMode === "hover") {
|
||||||
if (mouseArea.containsMouse && needsScrolling) {
|
if (mouseArea.containsMouse && needsScrolling) {
|
||||||
isScrolling = true
|
isScrolling = true;
|
||||||
isResetting = false
|
isResetting = false;
|
||||||
} else {
|
} else {
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
if (needsScrolling) {
|
if (needsScrolling) {
|
||||||
isResetting = true
|
isResetting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,7 +296,7 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: mouseArea
|
target: mouseArea
|
||||||
function onContainsMouseChanged() {
|
function onContainsMouseChanged() {
|
||||||
titleContainer.updateScrollingState()
|
titleContainer.updateScrollingState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,10 +322,10 @@ Item {
|
|||||||
color: Color.mOnSurface
|
color: Color.mOnSurface
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
if (root.scrollingMode === "always") {
|
if (root.scrollingMode === "always") {
|
||||||
titleContainer.isScrolling = false
|
titleContainer.isScrolling = false;
|
||||||
titleContainer.isResetting = false
|
titleContainer.isResetting = false;
|
||||||
scrollContainer.scrollX = 0
|
scrollContainer.scrollX = 0;
|
||||||
scrollStartTimer.restart()
|
scrollStartTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -349,7 +349,7 @@ Item {
|
|||||||
duration: 300
|
duration: 300
|
||||||
easing.type: Easing.OutQuad
|
easing.type: Easing.OutQuad
|
||||||
onFinished: {
|
onFinished: {
|
||||||
titleContainer.isResetting = false
|
titleContainer.isResetting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -412,11 +412,11 @@ Item {
|
|||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if ((windowTitle !== "") && isVerticalBar || (scrollingMode === "never")) {
|
if ((windowTitle !== "") && isVerticalBar || (scrollingMode === "never")) {
|
||||||
TooltipService.show(Screen, root, windowTitle, BarService.getTooltipDirection())
|
TooltipService.show(Screen, root, windowTitle, BarService.getTooltipDirection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -426,18 +426,18 @@ Item {
|
|||||||
target: CompositorService
|
target: CompositorService
|
||||||
function onActiveWindowChanged() {
|
function onActiveWindowChanged() {
|
||||||
try {
|
try {
|
||||||
windowIcon.source = Qt.binding(getAppIcon)
|
windowIcon.source = Qt.binding(getAppIcon);
|
||||||
windowIconVertical.source = Qt.binding(getAppIcon)
|
windowIconVertical.source = Qt.binding(getAppIcon);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.w("ActiveWindow", "Error in onActiveWindowChanged:", e)
|
Logger.w("ActiveWindow", "Error in onActiveWindowChanged:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function onWindowListChanged() {
|
function onWindowListChanged() {
|
||||||
try {
|
try {
|
||||||
windowIcon.source = Qt.binding(getAppIcon)
|
windowIcon.source = Qt.binding(getAppIcon);
|
||||||
windowIconVertical.source = Qt.binding(getAppIcon)
|
windowIconVertical.source = Qt.binding(getAppIcon);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.w("ActiveWindow", "Error in onWindowListChanged:", e)
|
Logger.w("ActiveWindow", "Error in onWindowListChanged:", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Widgets.AudioSpectrum
|
import qs.Widgets.AudioSpectrum
|
||||||
|
|
||||||
@@ -22,12 +22,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
// Resolve settings: try user settings or defaults from BarWidgetRegistry
|
||||||
@@ -38,16 +38,16 @@ Item {
|
|||||||
readonly property color fillColor: {
|
readonly property color fillColor: {
|
||||||
switch (colorName) {
|
switch (colorName) {
|
||||||
case "primary":
|
case "primary":
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
case "secondary":
|
case "secondary":
|
||||||
return Color.mSecondary
|
return Color.mSecondary;
|
||||||
case "tertiary":
|
case "tertiary":
|
||||||
return Color.mTertiary
|
return Color.mTertiary;
|
||||||
case "error":
|
case "error":
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
case "onSurface":
|
case "onSurface":
|
||||||
default:
|
default:
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,13 +92,13 @@ Item {
|
|||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
switch (currentVisualizerType) {
|
switch (currentVisualizerType) {
|
||||||
case "linear":
|
case "linear":
|
||||||
return linearComponent
|
return linearComponent;
|
||||||
case "mirrored":
|
case "mirrored":
|
||||||
return mirroredComponent
|
return mirroredComponent;
|
||||||
case "wave":
|
case "wave":
|
||||||
return waveComponent
|
return waveComponent;
|
||||||
default:
|
default:
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,13 +112,13 @@ Item {
|
|||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
|
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
const types = ["linear", "mirrored", "wave"]
|
const types = ["linear", "mirrored", "wave"];
|
||||||
const currentIndex = types.indexOf(currentVisualizerType)
|
const currentIndex = types.indexOf(currentVisualizerType);
|
||||||
const nextIndex = (currentIndex + 1) % types.length
|
const nextIndex = (currentIndex + 1) % types.length;
|
||||||
const newType = types[nextIndex]
|
const newType = types[nextIndex];
|
||||||
|
|
||||||
// Update settings directly, maybe this should be a widget setting...
|
// Update settings directly, maybe this should be a widget setting...
|
||||||
Settings.data.audio.visualizerType = newType
|
Settings.data.audio.visualizerType = newType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
import QtQuick.Layouts
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.Hardware
|
|
||||||
import qs.Widgets
|
|
||||||
import qs.Modules.Bar.Extras
|
import qs.Modules.Bar.Extras
|
||||||
|
import qs.Services.Hardware
|
||||||
|
import qs.Services.UI
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -22,12 +22,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -53,13 +53,13 @@ Item {
|
|||||||
function maybeNotify(percent, charging) {
|
function maybeNotify(percent, charging) {
|
||||||
// Only notify once we are a below threshold
|
// Only notify once we are a below threshold
|
||||||
if (!charging && !root.hasNotifiedLowBattery && percent <= warningThreshold) {
|
if (!charging && !root.hasNotifiedLowBattery && percent <= warningThreshold) {
|
||||||
root.hasNotifiedLowBattery = true
|
root.hasNotifiedLowBattery = true;
|
||||||
ToastService.showWarning(I18n.tr("toast.battery.low"), I18n.tr("toast.battery.low-desc", {
|
ToastService.showWarning(I18n.tr("toast.battery.low"), I18n.tr("toast.battery.low-desc", {
|
||||||
"percent": Math.round(percent)
|
"percent": Math.round(percent)
|
||||||
}))
|
}));
|
||||||
} else if (root.hasNotifiedLowBattery && (charging || percent > warningThreshold + 5)) {
|
} else if (root.hasNotifiedLowBattery && (charging || percent > warningThreshold + 5)) {
|
||||||
// Reset when charging starts or when battery recovers 5% above threshold
|
// Reset when charging starts or when battery recovers 5% above threshold
|
||||||
root.hasNotifiedLowBattery = false
|
root.hasNotifiedLowBattery = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,20 +67,20 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: UPower.displayDevice
|
target: UPower.displayDevice
|
||||||
function onPercentageChanged() {
|
function onPercentageChanged() {
|
||||||
var currentPercent = UPower.displayDevice.percentage * 100
|
var currentPercent = UPower.displayDevice.percentage * 100;
|
||||||
var isCharging = UPower.displayDevice.state === UPowerDeviceState.Charging
|
var isCharging = UPower.displayDevice.state === UPowerDeviceState.Charging;
|
||||||
root.maybeNotify(currentPercent, isCharging)
|
root.maybeNotify(currentPercent, isCharging);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onStateChanged() {
|
function onStateChanged() {
|
||||||
var isCharging = UPower.displayDevice.state === UPowerDeviceState.Charging
|
var isCharging = UPower.displayDevice.state === UPowerDeviceState.Charging;
|
||||||
// Reset notification flag when charging starts
|
// Reset notification flag when charging starts
|
||||||
if (isCharging) {
|
if (isCharging) {
|
||||||
root.hasNotifiedLowBattery = false
|
root.hasNotifiedLowBattery = false;
|
||||||
}
|
}
|
||||||
// Also re-evaluate maybeNotify, as state might have changed
|
// Also re-evaluate maybeNotify, as state might have changed
|
||||||
var currentPercent = UPower.displayDevice.percentage * 100
|
var currentPercent = UPower.displayDevice.percentage * 100;
|
||||||
root.maybeNotify(currentPercent, isCharging)
|
root.maybeNotify(currentPercent, isCharging);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,49 +97,49 @@ Item {
|
|||||||
forceClose: displayMode === "alwaysHide" || !isReady || (!testMode && !battery.isLaptopBattery)
|
forceClose: displayMode === "alwaysHide" || !isReady || (!testMode && !battery.isLaptopBattery)
|
||||||
onClicked: PanelService.getPanel("batteryPanel", screen)?.toggle(this)
|
onClicked: PanelService.getPanel("batteryPanel", screen)?.toggle(this)
|
||||||
tooltipText: {
|
tooltipText: {
|
||||||
let lines = []
|
let lines = [];
|
||||||
if (testMode) {
|
if (testMode) {
|
||||||
lines.push(`Time left: ${Time.formatVagueHumanReadableDuration(12345)}.`)
|
lines.push(`Time left: ${Time.formatVagueHumanReadableDuration(12345)}.`);
|
||||||
return lines.join("\n")
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
if (!isReady || !battery.isLaptopBattery) {
|
if (!isReady || !battery.isLaptopBattery) {
|
||||||
return I18n.tr("battery.no-battery-detected")
|
return I18n.tr("battery.no-battery-detected");
|
||||||
}
|
}
|
||||||
if (battery.timeToEmpty > 0) {
|
if (battery.timeToEmpty > 0) {
|
||||||
lines.push(I18n.tr("battery.time-left", {
|
lines.push(I18n.tr("battery.time-left", {
|
||||||
"time": Time.formatVagueHumanReadableDuration(battery.timeToEmpty)
|
"time": Time.formatVagueHumanReadableDuration(battery.timeToEmpty)
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
if (battery.timeToFull > 0) {
|
if (battery.timeToFull > 0) {
|
||||||
lines.push(I18n.tr("battery.time-until-full", {
|
lines.push(I18n.tr("battery.time-until-full", {
|
||||||
"time": Time.formatVagueHumanReadableDuration(battery.timeToFull)
|
"time": Time.formatVagueHumanReadableDuration(battery.timeToFull)
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
if (battery.changeRate !== undefined) {
|
if (battery.changeRate !== undefined) {
|
||||||
const rate = battery.changeRate
|
const rate = battery.changeRate;
|
||||||
if (rate > 0) {
|
if (rate > 0) {
|
||||||
lines.push(charging ? I18n.tr("battery.charging-rate", {
|
lines.push(charging ? I18n.tr("battery.charging-rate", {
|
||||||
"rate": rate.toFixed(2)
|
"rate": rate.toFixed(2)
|
||||||
}) : I18n.tr("battery.discharging-rate", {
|
}) : I18n.tr("battery.discharging-rate", {
|
||||||
"rate": rate.toFixed(2)
|
"rate": rate.toFixed(2)
|
||||||
}))
|
}));
|
||||||
} else if (rate < 0) {
|
} else if (rate < 0) {
|
||||||
lines.push(I18n.tr("battery.discharging-rate", {
|
lines.push(I18n.tr("battery.discharging-rate", {
|
||||||
"rate": Math.abs(rate).toFixed(2)
|
"rate": Math.abs(rate).toFixed(2)
|
||||||
}))
|
}));
|
||||||
} else {
|
} else {
|
||||||
// Rate is 0 - check if plugged in (charging state) or idle
|
// Rate is 0 - check if plugged in (charging state) or idle
|
||||||
lines.push(charging ? I18n.tr("battery.plugged-in") : I18n.tr("battery.idle"))
|
lines.push(charging ? I18n.tr("battery.plugged-in") : I18n.tr("battery.idle"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
lines.push(charging ? I18n.tr("battery.charging") : I18n.tr("battery.discharging"))
|
lines.push(charging ? I18n.tr("battery.charging") : I18n.tr("battery.discharging"));
|
||||||
}
|
}
|
||||||
if (battery.healthPercentage !== undefined && battery.healthPercentage > 0) {
|
if (battery.healthPercentage !== undefined && battery.healthPercentage > 0) {
|
||||||
lines.push(I18n.tr("battery.health", {
|
lines.push(I18n.tr("battery.health", {
|
||||||
"percent": Math.round(battery.healthPercentage)
|
"percent": Math.round(battery.healthPercentage)
|
||||||
}))
|
}));
|
||||||
}
|
}
|
||||||
return lines.join("\n")
|
return lines.join("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -41,16 +41,16 @@ Item {
|
|||||||
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
|
icon: BluetoothService.enabled ? "bluetooth" : "bluetooth-off"
|
||||||
text: {
|
text: {
|
||||||
if (BluetoothService.connectedDevices && BluetoothService.connectedDevices.length > 0) {
|
if (BluetoothService.connectedDevices && BluetoothService.connectedDevices.length > 0) {
|
||||||
const firstDevice = BluetoothService.connectedDevices[0]
|
const firstDevice = BluetoothService.connectedDevices[0];
|
||||||
return firstDevice.name || firstDevice.deviceName
|
return firstDevice.name || firstDevice.deviceName;
|
||||||
}
|
}
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
suffix: {
|
suffix: {
|
||||||
if (BluetoothService.connectedDevices && BluetoothService.connectedDevices.length > 1) {
|
if (BluetoothService.connectedDevices && BluetoothService.connectedDevices.length > 1) {
|
||||||
return ` + ${BluetoothService.connectedDevices.length - 1}`
|
return ` + ${BluetoothService.connectedDevices.length - 1}`;
|
||||||
}
|
}
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
autoHide: false
|
autoHide: false
|
||||||
forceOpen: !isBarVertical && root.displayMode === "alwaysShow"
|
forceOpen: !isBarVertical && root.displayMode === "alwaysShow"
|
||||||
@@ -59,9 +59,9 @@ Item {
|
|||||||
onRightClicked: BluetoothService.setBluetoothEnabled(!BluetoothService.enabled)
|
onRightClicked: BluetoothService.setBluetoothEnabled(!BluetoothService.enabled)
|
||||||
tooltipText: {
|
tooltipText: {
|
||||||
if (pill.text !== "") {
|
if (pill.text !== "") {
|
||||||
return pill.text
|
return pill.text;
|
||||||
}
|
}
|
||||||
return I18n.tr("tooltips.bluetooth-devices")
|
return I18n.tr("tooltips.bluetooth-devices");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -40,13 +40,13 @@ Item {
|
|||||||
visible: getMonitor() !== null
|
visible: getMonitor() !== null
|
||||||
|
|
||||||
function getMonitor() {
|
function getMonitor() {
|
||||||
return BrightnessService.getMonitorForScreen(screen) || null
|
return BrightnessService.getMonitorForScreen(screen) || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIcon() {
|
function getIcon() {
|
||||||
var monitor = getMonitor()
|
var monitor = getMonitor();
|
||||||
var brightness = monitor ? monitor.brightness : 0
|
var brightness = monitor ? monitor.brightness : 0;
|
||||||
return brightness <= 0.5 ? "brightness-low" : "brightness-high"
|
return brightness <= 0.5 ? "brightness-low" : "brightness-high";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connection used to open the pill when brightness changes
|
// Connection used to open the pill when brightness changes
|
||||||
@@ -57,12 +57,12 @@ Item {
|
|||||||
// Ignore if this is the first time we receive an update.
|
// Ignore if this is the first time we receive an update.
|
||||||
// Most likely service just kicked off.
|
// Most likely service just kicked off.
|
||||||
if (!firstBrightnessReceived) {
|
if (!firstBrightnessReceived) {
|
||||||
firstBrightnessReceived = true
|
firstBrightnessReceived = true;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pill.show()
|
pill.show();
|
||||||
hideTimerAfterChange.restart()
|
hideTimerAfterChange.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,42 +82,42 @@ Item {
|
|||||||
icon: getIcon()
|
icon: getIcon()
|
||||||
autoHide: false // Important to be false so we can hover as long as we want
|
autoHide: false // Important to be false so we can hover as long as we want
|
||||||
text: {
|
text: {
|
||||||
var monitor = getMonitor()
|
var monitor = getMonitor();
|
||||||
return monitor ? Math.round(monitor.brightness * 100) : ""
|
return monitor ? Math.round(monitor.brightness * 100) : "";
|
||||||
}
|
}
|
||||||
suffix: text.length > 0 ? "%" : "-"
|
suffix: text.length > 0 ? "%" : "-"
|
||||||
forceOpen: displayMode === "alwaysShow"
|
forceOpen: displayMode === "alwaysShow"
|
||||||
forceClose: displayMode === "alwaysHide"
|
forceClose: displayMode === "alwaysHide"
|
||||||
tooltipText: {
|
tooltipText: {
|
||||||
var monitor = getMonitor()
|
var monitor = getMonitor();
|
||||||
if (!monitor)
|
if (!monitor)
|
||||||
return ""
|
return "";
|
||||||
return I18n.tr("tooltips.brightness-at", {
|
return I18n.tr("tooltips.brightness-at", {
|
||||||
"brightness": Math.round(monitor.brightness * 100)
|
"brightness": Math.round(monitor.brightness * 100)
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onWheel: function (angle) {
|
onWheel: function (angle) {
|
||||||
var monitor = getMonitor()
|
var monitor = getMonitor();
|
||||||
if (!monitor)
|
if (!monitor)
|
||||||
return
|
return;
|
||||||
if (angle > 0) {
|
if (angle > 0) {
|
||||||
monitor.increaseBrightness()
|
monitor.increaseBrightness();
|
||||||
} else if (angle < 0) {
|
} else if (angle < 0) {
|
||||||
monitor.decreaseBrightness()
|
monitor.decreaseBrightness();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen)
|
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
settingsPanel.requestedTab = SettingsPanel.Tab.Display;
|
||||||
settingsPanel.open()
|
settingsPanel.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen)
|
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
settingsPanel.requestedTab = SettingsPanel.Tab.Display;
|
||||||
settingsPanel.open()
|
settingsPanel.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ Rectangle {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string barPosition: Settings.data.bar.position
|
readonly property string barPosition: Settings.data.bar.position
|
||||||
@@ -70,9 +70,9 @@ Rectangle {
|
|||||||
Binding on pointSize {
|
Binding on pointSize {
|
||||||
value: {
|
value: {
|
||||||
if (repeater.model.length == 1) {
|
if (repeater.model.length == 1) {
|
||||||
return Style.fontSizeS * scaling
|
return Style.fontSizeS * scaling;
|
||||||
} else {
|
} else {
|
||||||
return (index == 0) ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling
|
return (index == 0) ? Style.fontSizeXS * scaling : Style.fontSizeXXS * scaling;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,15 +122,15 @@ Rectangle {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if (!PanelService.getPanel("calendarPanel", screen)?.active) {
|
if (!PanelService.getPanel("calendarPanel", screen)?.active) {
|
||||||
TooltipService.show(Screen, root, I18n.tr("clock.tooltip"), BarService.getTooltipDirection())
|
TooltipService.show(Screen, root, I18n.tr("clock.tooltip"), BarService.getTooltipDirection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
PanelService.getPanel("calendarPanel", screen)?.toggle(this)
|
PanelService.getPanel("calendarPanel", screen)?.toggle(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Effects
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import QtQuick.Effects
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Services.UI
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
id: root
|
id: root
|
||||||
@@ -21,12 +21,12 @@ NIconButton {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string customIcon: widgetSettings.icon || widgetMetadata.icon
|
readonly property string customIcon: widgetSettings.icon || widgetMetadata.icon
|
||||||
@@ -34,8 +34,8 @@ NIconButton {
|
|||||||
readonly property string customIconPath: widgetSettings.customIconPath || ""
|
readonly property string customIconPath: widgetSettings.customIconPath || ""
|
||||||
readonly property bool colorizeDistroLogo: {
|
readonly property bool colorizeDistroLogo: {
|
||||||
if (widgetSettings.colorizeDistroLogo !== undefined)
|
if (widgetSettings.colorizeDistroLogo !== undefined)
|
||||||
return widgetSettings.colorizeDistroLogo
|
return widgetSettings.colorizeDistroLogo;
|
||||||
return widgetMetadata.colorizeDistroLogo !== undefined ? widgetMetadata.colorizeDistroLogo : false
|
return widgetMetadata.colorizeDistroLogo !== undefined ? widgetMetadata.colorizeDistroLogo : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we have a custom path or distro logo, don't use the theme icon.
|
// If we have a custom path or distro logo, don't use the theme icon.
|
||||||
@@ -51,12 +51,12 @@ NIconButton {
|
|||||||
colorBorder: Color.transparent
|
colorBorder: Color.transparent
|
||||||
colorBorderHover: useDistroLogo ? Color.mHover : Color.transparent
|
colorBorderHover: useDistroLogo ? Color.mHover : Color.transparent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var controlCenterPanel = PanelService.getPanel("controlCenterPanel", screen)
|
var controlCenterPanel = PanelService.getPanel("controlCenterPanel", screen);
|
||||||
if (Settings.data.controlCenter.position === "close_to_bar_button") {
|
if (Settings.data.controlCenter.position === "close_to_bar_button") {
|
||||||
// Willopen the panel next to the bar button.
|
// Willopen the panel next to the bar button.
|
||||||
controlCenterPanel?.toggle(this)
|
controlCenterPanel?.toggle(this);
|
||||||
} else {
|
} else {
|
||||||
controlCenterPanel?.toggle()
|
controlCenterPanel?.toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onRightClicked: PanelService.getPanel("settingsPanel", screen)?.toggle()
|
onRightClicked: PanelService.getPanel("settingsPanel", screen)?.toggle()
|
||||||
@@ -69,10 +69,10 @@ NIconButton {
|
|||||||
height: width
|
height: width
|
||||||
source: {
|
source: {
|
||||||
if (customIconPath !== "")
|
if (customIconPath !== "")
|
||||||
return customIconPath.startsWith("file://") ? customIconPath : "file://" + customIconPath
|
return customIconPath.startsWith("file://") ? customIconPath : "file://" + customIconPath;
|
||||||
if (useDistroLogo)
|
if (useDistroLogo)
|
||||||
return HostService.osLogo
|
return HostService.osLogo;
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
visible: source !== ""
|
visible: source !== ""
|
||||||
smooth: true
|
smooth: true
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import QtQuick.Layouts
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.Bar.Extras
|
||||||
|
import qs.Modules.Panels.Settings
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.Panels.Settings
|
|
||||||
import qs.Modules.Bar.Extras
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -22,12 +22,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isVerticalBar: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -63,31 +63,31 @@ Item {
|
|||||||
autoHide: false
|
autoHide: false
|
||||||
forceOpen: _dynamicText !== ""
|
forceOpen: _dynamicText !== ""
|
||||||
tooltipText: {
|
tooltipText: {
|
||||||
var tooltipLines = []
|
var tooltipLines = [];
|
||||||
|
|
||||||
if (hasExec) {
|
if (hasExec) {
|
||||||
if (leftClickExec !== "") {
|
if (leftClickExec !== "") {
|
||||||
tooltipLines.push(`Left click: ${leftClickExec}.`)
|
tooltipLines.push(`Left click: ${leftClickExec}.`);
|
||||||
}
|
}
|
||||||
if (rightClickExec !== "") {
|
if (rightClickExec !== "") {
|
||||||
tooltipLines.push(`Right click: ${rightClickExec}.`)
|
tooltipLines.push(`Right click: ${rightClickExec}.`);
|
||||||
}
|
}
|
||||||
if (middleClickExec !== "") {
|
if (middleClickExec !== "") {
|
||||||
tooltipLines.push(`Middle click: ${middleClickExec}.`)
|
tooltipLines.push(`Middle click: ${middleClickExec}.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_dynamicTooltip !== "") {
|
if (_dynamicTooltip !== "") {
|
||||||
if (tooltipLines.length > 0) {
|
if (tooltipLines.length > 0) {
|
||||||
tooltipLines.push("")
|
tooltipLines.push("");
|
||||||
}
|
}
|
||||||
tooltipLines.push(_dynamicTooltip)
|
tooltipLines.push(_dynamicTooltip);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tooltipLines.length === 0) {
|
if (tooltipLines.length === 0) {
|
||||||
return "Custom button, configure in settings."
|
return "Custom button, configure in settings.";
|
||||||
} else {
|
} else {
|
||||||
return tooltipLines.join("\n")
|
return tooltipLines.join("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -135,121 +135,121 @@ Item {
|
|||||||
stderr: StdioCollector {}
|
stderr: StdioCollector {}
|
||||||
onExited: (exitCode, exitStatus) => {
|
onExited: (exitCode, exitStatus) => {
|
||||||
if (textStream) {
|
if (textStream) {
|
||||||
Logger.w("CustomButton", `Streaming text command exited (code: ${exitCode}), restarting...`)
|
Logger.w("CustomButton", `Streaming text command exited (code: ${exitCode}), restarting...`);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseDynamicContent(content) {
|
function parseDynamicContent(content) {
|
||||||
var contentStr = String(content || "").trim()
|
var contentStr = String(content || "").trim();
|
||||||
|
|
||||||
if (parseJson) {
|
if (parseJson) {
|
||||||
var lineToParse = contentStr
|
var lineToParse = contentStr;
|
||||||
|
|
||||||
if (!textStream && contentStr.includes('\n')) {
|
if (!textStream && contentStr.includes('\n')) {
|
||||||
const lines = contentStr.split('\n').filter(line => line.trim() !== '')
|
const lines = contentStr.split('\n').filter(line => line.trim() !== '');
|
||||||
if (lines.length > 0) {
|
if (lines.length > 0) {
|
||||||
lineToParse = lines[lines.length - 1]
|
lineToParse = lines[lines.length - 1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(lineToParse)
|
const parsed = JSON.parse(lineToParse);
|
||||||
const text = parsed.text || ""
|
const text = parsed.text || "";
|
||||||
const icon = parsed.icon || ""
|
const icon = parsed.icon || "";
|
||||||
const tooltip = parsed.tooltip || ""
|
const tooltip = parsed.tooltip || "";
|
||||||
|
|
||||||
if (checkCollapse(text)) {
|
if (checkCollapse(text)) {
|
||||||
_dynamicText = ""
|
_dynamicText = "";
|
||||||
_dynamicIcon = ""
|
_dynamicIcon = "";
|
||||||
_dynamicTooltip = ""
|
_dynamicTooltip = "";
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dynamicText = text
|
_dynamicText = text;
|
||||||
_dynamicIcon = icon
|
_dynamicIcon = icon;
|
||||||
_dynamicTooltip = tooltip
|
_dynamicTooltip = tooltip;
|
||||||
return
|
return;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.w("CustomButton", `Failed to parse JSON. Content: "${lineToParse}"`)
|
Logger.w("CustomButton", `Failed to parse JSON. Content: "${lineToParse}"`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (checkCollapse(contentStr)) {
|
if (checkCollapse(contentStr)) {
|
||||||
_dynamicText = ""
|
_dynamicText = "";
|
||||||
_dynamicIcon = ""
|
_dynamicIcon = "";
|
||||||
_dynamicTooltip = ""
|
_dynamicTooltip = "";
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_dynamicText = contentStr
|
_dynamicText = contentStr;
|
||||||
_dynamicIcon = ""
|
_dynamicIcon = "";
|
||||||
_dynamicTooltip = ""
|
_dynamicTooltip = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkCollapse(text) {
|
function checkCollapse(text) {
|
||||||
if (!textCollapse || textCollapse.length === 0) {
|
if (!textCollapse || textCollapse.length === 0) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textCollapse.startsWith("/") && textCollapse.endsWith("/") && textCollapse.length > 1) {
|
if (textCollapse.startsWith("/") && textCollapse.endsWith("/") && textCollapse.length > 1) {
|
||||||
// Treat as regex
|
// Treat as regex
|
||||||
var pattern = textCollapse.substring(1, textCollapse.length - 1)
|
var pattern = textCollapse.substring(1, textCollapse.length - 1);
|
||||||
try {
|
try {
|
||||||
var regex = new RegExp(pattern)
|
var regex = new RegExp(pattern);
|
||||||
return regex.test(text)
|
return regex.test(text);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.w("CustomButton", `Invalid regex for textCollapse: ${textCollapse} - ${e.message}`)
|
Logger.w("CustomButton", `Invalid regex for textCollapse: ${textCollapse} - ${e.message}`);
|
||||||
return (textCollapse === text) // Fallback to exact match on invalid regex
|
return (textCollapse === text); // Fallback to exact match on invalid regex
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Treat as plain string
|
// Treat as plain string
|
||||||
return (textCollapse === text)
|
return (textCollapse === text);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onClicked() {
|
function onClicked() {
|
||||||
if (leftClickExec) {
|
if (leftClickExec) {
|
||||||
Quickshell.execDetached(["sh", "-c", leftClickExec])
|
Quickshell.execDetached(["sh", "-c", leftClickExec]);
|
||||||
Logger.i("CustomButton", `Executing command: ${leftClickExec}`)
|
Logger.i("CustomButton", `Executing command: ${leftClickExec}`);
|
||||||
} else if (!hasExec && !leftClickUpdateText) {
|
} else if (!hasExec && !leftClickUpdateText) {
|
||||||
// No script was defined, open settings
|
// No script was defined, open settings
|
||||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen)
|
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||||
settingsPanel.requestedTab = SettingsPanel.Tab.Bar
|
settingsPanel.requestedTab = SettingsPanel.Tab.Bar;
|
||||||
settingsPanel.open()
|
settingsPanel.open();
|
||||||
}
|
}
|
||||||
if (!textStream && leftClickUpdateText) {
|
if (!textStream && leftClickUpdateText) {
|
||||||
runTextCommand()
|
runTextCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRightClicked() {
|
function onRightClicked() {
|
||||||
if (rightClickExec) {
|
if (rightClickExec) {
|
||||||
Quickshell.execDetached(["sh", "-c", rightClickExec])
|
Quickshell.execDetached(["sh", "-c", rightClickExec]);
|
||||||
Logger.i("CustomButton", `Executing command: ${rightClickExec}`)
|
Logger.i("CustomButton", `Executing command: ${rightClickExec}`);
|
||||||
}
|
}
|
||||||
if (!textStream && rightClickUpdateText) {
|
if (!textStream && rightClickUpdateText) {
|
||||||
runTextCommand()
|
runTextCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMiddleClicked() {
|
function onMiddleClicked() {
|
||||||
if (middleClickExec) {
|
if (middleClickExec) {
|
||||||
Quickshell.execDetached(["sh", "-c", middleClickExec])
|
Quickshell.execDetached(["sh", "-c", middleClickExec]);
|
||||||
Logger.i("CustomButton", `Executing command: ${middleClickExec}`)
|
Logger.i("CustomButton", `Executing command: ${middleClickExec}`);
|
||||||
}
|
}
|
||||||
if (!textStream && middleClickUpdateText) {
|
if (!textStream && middleClickUpdateText) {
|
||||||
runTextCommand()
|
runTextCommand();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runTextCommand() {
|
function runTextCommand() {
|
||||||
if (!textCommand || textCommand.length === 0)
|
if (!textCommand || textCommand.length === 0)
|
||||||
return
|
return;
|
||||||
if (textProc.running)
|
if (textProc.running)
|
||||||
return
|
return;
|
||||||
textProc.command = ["sh", "-lc", textCommand]
|
textProc.command = ["sh", "-lc", textCommand];
|
||||||
textProc.running = true
|
textProc.running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
id: root
|
id: root
|
||||||
|
|||||||
@@ -2,10 +2,10 @@ import QtQuick
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.Bar.Extras
|
||||||
import qs.Services.Power
|
import qs.Services.Power
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.Bar.Extras
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -21,12 +21,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -47,20 +47,20 @@ Item {
|
|||||||
forceOpen: IdleInhibitorService.timeout !== null
|
forceOpen: IdleInhibitorService.timeout !== null
|
||||||
forceClose: IdleInhibitorService.timeout == null
|
forceClose: IdleInhibitorService.timeout == null
|
||||||
onWheel: function (delta) {
|
onWheel: function (delta) {
|
||||||
var sign = delta > 0 ? 1 : -1
|
var sign = delta > 0 ? 1 : -1;
|
||||||
// the offset makes scrolling down feel symmetrical to scrolling up
|
// the offset makes scrolling down feel symmetrical to scrolling up
|
||||||
var timeout = IdleInhibitorService.timeout - (delta < 0 ? 60 : 0)
|
var timeout = IdleInhibitorService.timeout - (delta < 0 ? 60 : 0);
|
||||||
if (timeout == null || timeout < 600) {
|
if (timeout == null || timeout < 600) {
|
||||||
delta = 60 // <= 10m, increment at 1m interval
|
delta = 60; // <= 10m, increment at 1m interval
|
||||||
} else if (timeout >= 600 && timeout < 1800) {
|
} else if (timeout >= 600 && timeout < 1800) {
|
||||||
delta = 300 // >= 10m, increment at 5m interval
|
delta = 300; // >= 10m, increment at 5m interval
|
||||||
} else if (timeout >= 1800 && timeout < 3600) {
|
} else if (timeout >= 1800 && timeout < 3600) {
|
||||||
delta = 600 // >= 30m, increment at 10m interval
|
delta = 600; // >= 30m, increment at 10m interval
|
||||||
} else if (timeout >= 3600) {
|
} else if (timeout >= 3600) {
|
||||||
delta = 1800 // > 1h, increment at 30m interval
|
delta = 1800; // > 1h, increment at 30m interval
|
||||||
}
|
}
|
||||||
|
|
||||||
IdleInhibitorService.changeTimeout(delta * sign)
|
IdleInhibitorService.changeTimeout(delta * sign);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.Keyboard
|
|
||||||
import qs.Widgets
|
|
||||||
import qs.Modules.Bar.Extras
|
import qs.Modules.Bar.Extras
|
||||||
|
import qs.Services.Keyboard
|
||||||
|
import qs.Services.UI
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -23,12 +23,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
|
readonly property string displayMode: (widgetSettings.displayMode !== undefined) ? widgetSettings.displayMode : widgetMetadata.displayMode
|
||||||
@@ -53,9 +53,9 @@ Item {
|
|||||||
})
|
})
|
||||||
forceOpen: root.displayMode === "forceOpen"
|
forceOpen: root.displayMode === "forceOpen"
|
||||||
forceClose: root.displayMode === "alwaysHide"
|
forceClose: root.displayMode === "alwaysHide"
|
||||||
onClicked: {
|
onClicked:
|
||||||
|
|
||||||
// You could open keyboard settings here if needed.
|
// You could open keyboard settings here if needed.
|
||||||
}
|
{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ Rectangle {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string barPosition: Settings.data.bar.position
|
readonly property string barPosition: Settings.data.bar.position
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Widgets.AudioSpectrum
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
import qs.Widgets.AudioSpectrum
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -23,12 +23,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isVerticalBar: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right")
|
readonly property bool isVerticalBar: (Settings.data.bar.position === "left" || Settings.data.bar.position === "right")
|
||||||
@@ -49,18 +49,18 @@ Item {
|
|||||||
readonly property string placeholderText: I18n.tr("bar.widget-settings.media-mini.no-active-player")
|
readonly property string placeholderText: I18n.tr("bar.widget-settings.media-mini.no-active-player")
|
||||||
|
|
||||||
readonly property string tooltipText: {
|
readonly property string tooltipText: {
|
||||||
var title = getTitle()
|
var title = getTitle();
|
||||||
var controls = ""
|
var controls = "";
|
||||||
if (MediaService.canGoNext) {
|
if (MediaService.canGoNext) {
|
||||||
controls += "Right click for next.\n"
|
controls += "Right click for next.\n";
|
||||||
}
|
}
|
||||||
if (MediaService.canGoPrevious) {
|
if (MediaService.canGoPrevious) {
|
||||||
controls += "Middle click for previous."
|
controls += "Middle click for previous.";
|
||||||
}
|
}
|
||||||
if (controls !== "") {
|
if (controls !== "") {
|
||||||
return title + "\n\n" + controls
|
return title + "\n\n" + controls;
|
||||||
}
|
}
|
||||||
return title
|
return title;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide conditions
|
// Hide conditions
|
||||||
@@ -94,57 +94,57 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getTitle() {
|
function getTitle() {
|
||||||
return MediaService.trackTitle + (MediaService.trackArtist !== "" ? ` - ${MediaService.trackArtist}` : "")
|
return MediaService.trackTitle + (MediaService.trackArtist !== "" ? ` - ${MediaService.trackArtist}` : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculatedVerticalDimension() {
|
function calculatedVerticalDimension() {
|
||||||
return Math.round((Style.baseWidgetSize - 5) * scaling)
|
return Math.round((Style.baseWidgetSize - 5) * scaling);
|
||||||
}
|
}
|
||||||
|
|
||||||
function calculateContentWidth() {
|
function calculateContentWidth() {
|
||||||
// Calculate the actual content width based on visible elements
|
// Calculate the actual content width based on visible elements
|
||||||
var contentWidth = 0
|
var contentWidth = 0;
|
||||||
var margins = Style.marginS * scaling * 2 // Left and right margins
|
var margins = Style.marginS * scaling * 2; // Left and right margins
|
||||||
|
|
||||||
// Icon or album art width
|
// Icon or album art width
|
||||||
if (!hasActivePlayer || !showAlbumArt) {
|
if (!hasActivePlayer || !showAlbumArt) {
|
||||||
// Icon width
|
// Icon width
|
||||||
contentWidth += Math.round(18 * scaling)
|
contentWidth += Math.round(18 * scaling);
|
||||||
} else if (showAlbumArt && hasActivePlayer) {
|
} else if (showAlbumArt && hasActivePlayer) {
|
||||||
// Album art width
|
// Album art width
|
||||||
contentWidth += 21 * scaling
|
contentWidth += 21 * scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spacing between icon/art and text; only if there is text
|
// Spacing between icon/art and text; only if there is text
|
||||||
if (fullTitleMetrics.contentWidth > 0) {
|
if (fullTitleMetrics.contentWidth > 0) {
|
||||||
contentWidth += Style.marginS * scaling
|
contentWidth += Style.marginS * scaling;
|
||||||
|
|
||||||
// Text width (use the measured width)
|
// Text width (use the measured width)
|
||||||
contentWidth += fullTitleMetrics.contentWidth
|
contentWidth += fullTitleMetrics.contentWidth;
|
||||||
|
|
||||||
// Additional small margin for text
|
// Additional small margin for text
|
||||||
contentWidth += Style.marginXXS * 2
|
contentWidth += Style.marginXXS * 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add container margins
|
// Add container margins
|
||||||
contentWidth += margins
|
contentWidth += margins;
|
||||||
|
|
||||||
return Math.ceil(contentWidth)
|
return Math.ceil(contentWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dynamic width: adapt to content but respect maximum width setting
|
// Dynamic width: adapt to content but respect maximum width setting
|
||||||
readonly property real dynamicWidth: {
|
readonly property real dynamicWidth: {
|
||||||
// If using fixed width mode, always use maxWidth
|
// If using fixed width mode, always use maxWidth
|
||||||
if (useFixedWidth) {
|
if (useFixedWidth) {
|
||||||
return maxWidth
|
return maxWidth;
|
||||||
}
|
}
|
||||||
// Otherwise, adapt to content
|
// Otherwise, adapt to content
|
||||||
if (!hasActivePlayer) {
|
if (!hasActivePlayer) {
|
||||||
// Keep compact when no active player
|
// Keep compact when no active player
|
||||||
return calculateContentWidth()
|
return calculateContentWidth();
|
||||||
}
|
}
|
||||||
// Use content width but don't exceed user-set maximum width
|
// Use content width but don't exceed user-set maximum width
|
||||||
return Math.min(calculateContentWidth(), maxWidth)
|
return Math.min(calculateContentWidth(), maxWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
// A hidden text element to safely measure the full title width
|
// A hidden text element to safely measure the full title width
|
||||||
@@ -279,11 +279,11 @@ Item {
|
|||||||
id: titleContainer
|
id: titleContainer
|
||||||
Layout.preferredWidth: {
|
Layout.preferredWidth: {
|
||||||
// Calculate available width based on other elements in the row
|
// Calculate available width based on other elements in the row
|
||||||
var iconWidth = (windowIcon.visible ? (18 * scaling + Style.marginS * scaling) : 0)
|
var iconWidth = (windowIcon.visible ? (18 * scaling + Style.marginS * scaling) : 0);
|
||||||
var albumArtWidth = (hasActivePlayer && showAlbumArt ? (21 * scaling + Style.marginS * scaling) : 0)
|
var albumArtWidth = (hasActivePlayer && showAlbumArt ? (21 * scaling + Style.marginS * scaling) : 0);
|
||||||
var totalMargins = Style.marginXXS * 2
|
var totalMargins = Style.marginXXS * 2;
|
||||||
var availableWidth = mainContainer.width - iconWidth - albumArtWidth - totalMargins
|
var availableWidth = mainContainer.width - iconWidth - albumArtWidth - totalMargins;
|
||||||
return Math.max(20, availableWidth)
|
return Math.max(20, availableWidth);
|
||||||
}
|
}
|
||||||
Layout.maximumWidth: Layout.preferredWidth
|
Layout.maximumWidth: Layout.preferredWidth
|
||||||
Layout.alignment: Qt.AlignVCenter
|
Layout.alignment: Qt.AlignVCenter
|
||||||
@@ -304,8 +304,8 @@ Item {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (scrollingMode === "always" && titleContainer.needsScrolling) {
|
if (scrollingMode === "always" && titleContainer.needsScrolling) {
|
||||||
titleContainer.isScrolling = true
|
titleContainer.isScrolling = true;
|
||||||
titleContainer.isResetting = false
|
titleContainer.isResetting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -313,48 +313,48 @@ Item {
|
|||||||
// Update scrolling state based on mode
|
// Update scrolling state based on mode
|
||||||
property var updateScrollingState: function () {
|
property var updateScrollingState: function () {
|
||||||
if (scrollingMode === "never") {
|
if (scrollingMode === "never") {
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
isResetting = false
|
isResetting = false;
|
||||||
} else if (scrollingMode === "always") {
|
} else if (scrollingMode === "always") {
|
||||||
if (needsScrolling) {
|
if (needsScrolling) {
|
||||||
if (mouseArea.containsMouse) {
|
if (mouseArea.containsMouse) {
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
isResetting = true
|
isResetting = true;
|
||||||
} else {
|
} else {
|
||||||
scrollStartTimer.restart()
|
scrollStartTimer.restart();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
scrollStartTimer.stop()
|
scrollStartTimer.stop();
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
isResetting = false
|
isResetting = false;
|
||||||
}
|
}
|
||||||
} else if (scrollingMode === "hover") {
|
} else if (scrollingMode === "hover") {
|
||||||
if (mouseArea.containsMouse && needsScrolling) {
|
if (mouseArea.containsMouse && needsScrolling) {
|
||||||
isScrolling = true
|
isScrolling = true;
|
||||||
isResetting = false
|
isResetting = false;
|
||||||
} else {
|
} else {
|
||||||
isScrolling = false
|
isScrolling = false;
|
||||||
if (needsScrolling) {
|
if (needsScrolling) {
|
||||||
isResetting = true
|
isResetting = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onWidthChanged: {
|
onWidthChanged: {
|
||||||
containerWidth = width
|
containerWidth = width;
|
||||||
updateScrollingState()
|
updateScrollingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
containerWidth = width
|
containerWidth = width;
|
||||||
updateScrollingState()
|
updateScrollingState();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: mouseArea
|
target: mouseArea
|
||||||
function onContainsMouseChanged() {
|
function onContainsMouseChanged() {
|
||||||
titleContainer.updateScrollingState()
|
titleContainer.updateScrollingState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -380,11 +380,11 @@ Item {
|
|||||||
horizontalAlignment: hasActivePlayer ? Text.AlignLeft : Text.AlignHCenter
|
horizontalAlignment: hasActivePlayer ? Text.AlignLeft : Text.AlignHCenter
|
||||||
color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant
|
color: hasActivePlayer ? Color.mOnSurface : Color.mOnSurfaceVariant
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
titleContainer.isScrolling = false
|
titleContainer.isScrolling = false;
|
||||||
titleContainer.isResetting = false
|
titleContainer.isResetting = false;
|
||||||
scrollContainer.scrollX = 0
|
scrollContainer.scrollX = 0;
|
||||||
if (titleContainer.needsScrolling) {
|
if (titleContainer.needsScrolling) {
|
||||||
scrollStartTimer.restart()
|
scrollStartTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,7 +408,7 @@ Item {
|
|||||||
duration: 300
|
duration: 300
|
||||||
easing.type: Easing.OutQuad
|
easing.type: Easing.OutQuad
|
||||||
onFinished: {
|
onFinished: {
|
||||||
titleContainer.isResetting = false
|
titleContainer.isResetting = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,28 +462,28 @@ Item {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
if (!hasActivePlayer || !MediaService.currentPlayer || !MediaService.canPlay) {
|
if (!hasActivePlayer || !MediaService.currentPlayer || !MediaService.canPlay) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
MediaService.playPause()
|
MediaService.playPause();
|
||||||
} else if (mouse.button == Qt.RightButton) {
|
} else if (mouse.button == Qt.RightButton) {
|
||||||
MediaService.next()
|
MediaService.next();
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
} else if (mouse.button == Qt.MiddleButton) {
|
} else if (mouse.button == Qt.MiddleButton) {
|
||||||
MediaService.previous()
|
MediaService.previous();
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
var textToShow = hasActivePlayer ? tooltipText : placeholderText
|
var textToShow = hasActivePlayer ? tooltipText : placeholderText;
|
||||||
if ((textToShow !== "") && isVerticalBar || (scrollingMode === "never")) {
|
if ((textToShow !== "") && isVerticalBar || (scrollingMode === "never")) {
|
||||||
TooltipService.show(Screen, root, textToShow, BarService.getTooltipDirection())
|
TooltipService.show(Screen, root, textToShow, BarService.getTooltipDirection());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -48,13 +48,13 @@ Item {
|
|||||||
// Logger.i("Bar:Microphone", "onInputVolumeChanged")
|
// Logger.i("Bar:Microphone", "onInputVolumeChanged")
|
||||||
if (!firstInputVolumeReceived) {
|
if (!firstInputVolumeReceived) {
|
||||||
// Ignore the first volume change
|
// Ignore the first volume change
|
||||||
firstInputVolumeReceived = true
|
firstInputVolumeReceived = true;
|
||||||
} else {
|
} else {
|
||||||
// If a tooltip is visible while we show the pill
|
// If a tooltip is visible while we show the pill
|
||||||
// hide it so it doesn't overlap the volume slider.
|
// hide it so it doesn't overlap the volume slider.
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
pill.show()
|
pill.show();
|
||||||
externalHideTimer.restart()
|
externalHideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,11 +66,11 @@ Item {
|
|||||||
// Logger.i("Bar:Microphone", "onInputMutedChanged")
|
// Logger.i("Bar:Microphone", "onInputMutedChanged")
|
||||||
if (!firstInputVolumeReceived) {
|
if (!firstInputVolumeReceived) {
|
||||||
// Ignore the first mute change
|
// Ignore the first mute change
|
||||||
firstInputVolumeReceived = true
|
firstInputVolumeReceived = true;
|
||||||
} else {
|
} else {
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
pill.show()
|
pill.show();
|
||||||
externalHideTimer.restart()
|
externalHideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +80,7 @@ Item {
|
|||||||
running: false
|
running: false
|
||||||
interval: 1500
|
interval: 1500
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
pill.hide()
|
pill.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,25 +101,25 @@ Item {
|
|||||||
|
|
||||||
onWheel: function (delta) {
|
onWheel: function (delta) {
|
||||||
// As soon as we start scrolling to adjust volume, hide the tooltip
|
// As soon as we start scrolling to adjust volume, hide the tooltip
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
|
|
||||||
wheelAccumulator += delta
|
wheelAccumulator += delta;
|
||||||
if (wheelAccumulator >= 120) {
|
if (wheelAccumulator >= 120) {
|
||||||
wheelAccumulator = 0
|
wheelAccumulator = 0;
|
||||||
AudioService.setInputVolume(AudioService.inputVolume + AudioService.stepVolume)
|
AudioService.setInputVolume(AudioService.inputVolume + AudioService.stepVolume);
|
||||||
} else if (wheelAccumulator <= -120) {
|
} else if (wheelAccumulator <= -120) {
|
||||||
wheelAccumulator = 0
|
wheelAccumulator = 0;
|
||||||
AudioService.setInputVolume(AudioService.inputVolume - AudioService.stepVolume)
|
AudioService.setInputVolume(AudioService.inputVolume - AudioService.stepVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PanelService.getPanel("audioPanel", screen)?.toggle(this)
|
PanelService.getPanel("audioPanel", screen)?.toggle(this);
|
||||||
}
|
}
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
AudioService.setInputMuted(!AudioService.inputMuted)
|
AudioService.setInputMuted(!AudioService.inputMuted);
|
||||||
}
|
}
|
||||||
onMiddleClicked: {
|
onMiddleClicked: {
|
||||||
Quickshell.execDetached(["pwvucontrol"])
|
Quickshell.execDetached(["pwvucontrol"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
@@ -28,24 +28,24 @@ NIconButton {
|
|||||||
onClicked: {
|
onClicked: {
|
||||||
// Check if wlsunset is available before enabling night light
|
// Check if wlsunset is available before enabling night light
|
||||||
if (!ProgramCheckerService.wlsunsetAvailable) {
|
if (!ProgramCheckerService.wlsunsetAvailable) {
|
||||||
ToastService.showWarning(I18n.tr("settings.display.night-light.section.label"), I18n.tr("toast.night-light.not-installed"))
|
ToastService.showWarning(I18n.tr("settings.display.night-light.section.label"), I18n.tr("toast.night-light.not-installed"));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Settings.data.nightLight.enabled) {
|
if (!Settings.data.nightLight.enabled) {
|
||||||
Settings.data.nightLight.enabled = true
|
Settings.data.nightLight.enabled = true;
|
||||||
Settings.data.nightLight.forced = false
|
Settings.data.nightLight.forced = false;
|
||||||
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
|
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
|
||||||
Settings.data.nightLight.forced = true
|
Settings.data.nightLight.forced = true;
|
||||||
} else {
|
} else {
|
||||||
Settings.data.nightLight.enabled = false
|
Settings.data.nightLight.enabled = false;
|
||||||
Settings.data.nightLight.forced = false
|
Settings.data.nightLight.forced = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen)
|
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
settingsPanel.requestedTab = SettingsPanel.Tab.Display;
|
||||||
settingsPanel.open()
|
settingsPanel.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
@@ -26,6 +26,6 @@ NIconButton {
|
|||||||
tooltipText: PowerProfileService.noctaliaPerformanceMode ? I18n.tr("tooltips.noctalia-performance-enabled") : I18n.tr("tooltips.noctalia-performance-disabled")
|
tooltipText: PowerProfileService.noctaliaPerformanceMode ? I18n.tr("tooltips.noctalia-performance-enabled") : I18n.tr("tooltips.noctalia-performance-disabled")
|
||||||
tooltipDirection: BarService.getTooltipDirection()
|
tooltipDirection: BarService.getTooltipDirection()
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PowerProfileService.toggleNoctaliaPerformance()
|
PowerProfileService.toggleNoctaliaPerformance();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
@@ -22,27 +22,27 @@ NIconButton {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
readonly property bool showUnreadBadge: (widgetSettings.showUnreadBadge !== undefined) ? widgetSettings.showUnreadBadge : widgetMetadata.showUnreadBadge
|
readonly property bool showUnreadBadge: (widgetSettings.showUnreadBadge !== undefined) ? widgetSettings.showUnreadBadge : widgetMetadata.showUnreadBadge
|
||||||
readonly property bool hideWhenZero: (widgetSettings.hideWhenZero !== undefined) ? widgetSettings.hideWhenZero : widgetMetadata.hideWhenZero
|
readonly property bool hideWhenZero: (widgetSettings.hideWhenZero !== undefined) ? widgetSettings.hideWhenZero : widgetMetadata.hideWhenZero
|
||||||
|
|
||||||
function computeUnreadCount() {
|
function computeUnreadCount() {
|
||||||
var since = NotificationService.lastSeenTs
|
var since = NotificationService.lastSeenTs;
|
||||||
var count = 0
|
var count = 0;
|
||||||
var model = NotificationService.historyList
|
var model = NotificationService.historyList;
|
||||||
for (var i = 0; i < model.count; i++) {
|
for (var i = 0; i < model.count; i++) {
|
||||||
var item = model.get(i)
|
var item = model.get(i);
|
||||||
var ts = item.timestamp instanceof Date ? item.timestamp.getTime() : item.timestamp
|
var ts = item.timestamp instanceof Date ? item.timestamp.getTime() : item.timestamp;
|
||||||
if (ts > since)
|
if (ts > since)
|
||||||
count++
|
count++;
|
||||||
}
|
}
|
||||||
return count
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
baseSize: Style.capsuleHeight
|
baseSize: Style.capsuleHeight
|
||||||
@@ -57,8 +57,8 @@ NIconButton {
|
|||||||
colorBorderHover: Color.transparent
|
colorBorderHover: Color.transparent
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var panel = PanelService.getPanel("notificationHistoryPanel", screen)
|
var panel = PanelService.getPanel("notificationHistoryPanel", screen);
|
||||||
panel?.toggle(this)
|
panel?.toggle(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightClicked: NotificationService.doNotDisturb = !NotificationService.doNotDisturb
|
onRightClicked: NotificationService.doNotDisturb = !NotificationService.doNotDisturb
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
// Screen Recording Indicator
|
// Screen Recording Indicator
|
||||||
@@ -24,10 +24,10 @@ NIconButton {
|
|||||||
|
|
||||||
function handleClick() {
|
function handleClick() {
|
||||||
if (!ScreenRecorderService.isAvailable) {
|
if (!ScreenRecorderService.isAvailable) {
|
||||||
ToastService.showError(I18n.tr("toast.recording.not-installed"), I18n.tr("toast.recording.not-installed-desc"))
|
ToastService.showError(I18n.tr("toast.recording.not-installed"), I18n.tr("toast.recording.not-installed-desc"));
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
ScreenRecorderService.toggleRecording()
|
ScreenRecorderService.toggleRecording();
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: handleClick()
|
onClicked: handleClick()
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ NIconButton {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string colorName: widgetSettings.colorName !== undefined ? widgetSettings.colorName : widgetMetadata.colorName
|
readonly property string colorName: widgetSettings.colorName !== undefined ? widgetSettings.colorName : widgetMetadata.colorName
|
||||||
@@ -32,16 +32,16 @@ NIconButton {
|
|||||||
readonly property color iconColor: {
|
readonly property color iconColor: {
|
||||||
switch (colorName) {
|
switch (colorName) {
|
||||||
case "primary":
|
case "primary":
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
case "secondary":
|
case "secondary":
|
||||||
return Color.mSecondary
|
return Color.mSecondary;
|
||||||
case "tertiary":
|
case "tertiary":
|
||||||
return Color.mTertiary
|
return Color.mTertiary;
|
||||||
case "error":
|
case "error":
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
case "onSurface":
|
case "onSurface":
|
||||||
default:
|
default:
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,12 +19,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use settings or defaults from BarWidgetRegistry
|
// Use settings or defaults from BarWidgetRegistry
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import QtQuick.Layouts
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Modules.Panels.Settings
|
import qs.Modules.Panels.Settings
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -21,12 +21,12 @@ Rectangle {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string barPosition: Settings.data.bar.position
|
readonly property string barPosition: Settings.data.bar.position
|
||||||
@@ -43,8 +43,8 @@ Rectangle {
|
|||||||
|
|
||||||
readonly property real iconSize: textSize * 1.4
|
readonly property real iconSize: textSize * 1.4
|
||||||
readonly property real textSize: {
|
readonly property real textSize: {
|
||||||
var base = isVertical ? width * 0.82 : height
|
var base = isVertical ? width * 0.82 : height;
|
||||||
return Math.max(1, (density === "compact") ? base * 0.43 : base * 0.33)
|
return Math.max(1, (density === "compact") ? base * 0.43 : base * 0.33);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Match Workspace widget pill sizing: base ratio depends on bar density
|
// Match Workspace widget pill sizing: base ratio depends on bar density
|
||||||
@@ -178,11 +178,11 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
item.warning = Qt.binding(() => cpuWarning)
|
item.warning = Qt.binding(() => cpuWarning);
|
||||||
item.critical = Qt.binding(() => cpuCritical)
|
item.critical = Qt.binding(() => cpuCritical);
|
||||||
item.indicatorWidth = Qt.binding(() => cpuUsageContainer.width)
|
item.indicatorWidth = Qt.binding(() => cpuUsageContainer.width);
|
||||||
item.warningColor = Qt.binding(() => root.warningColor)
|
item.warningColor = Qt.binding(() => root.warningColor);
|
||||||
item.criticalColor = Qt.binding(() => root.criticalColor)
|
item.criticalColor = Qt.binding(() => root.criticalColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,11 +214,11 @@ Rectangle {
|
|||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
let usage = Math.round(SystemStatService.cpuUsage)
|
let usage = Math.round(SystemStatService.cpuUsage);
|
||||||
if (usage < 100) {
|
if (usage < 100) {
|
||||||
return `${usage}%`
|
return `${usage}%`;
|
||||||
} else {
|
} else {
|
||||||
return usage
|
return usage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
family: Settings.data.ui.fontFixed
|
family: Settings.data.ui.fontFixed
|
||||||
@@ -252,11 +252,11 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
item.warning = Qt.binding(() => tempWarning)
|
item.warning = Qt.binding(() => tempWarning);
|
||||||
item.critical = Qt.binding(() => tempCritical)
|
item.critical = Qt.binding(() => tempCritical);
|
||||||
item.indicatorWidth = Qt.binding(() => cpuTempContainer.width)
|
item.indicatorWidth = Qt.binding(() => cpuTempContainer.width);
|
||||||
item.warningColor = Qt.binding(() => root.warningColor)
|
item.warningColor = Qt.binding(() => root.warningColor);
|
||||||
item.criticalColor = Qt.binding(() => root.criticalColor)
|
item.criticalColor = Qt.binding(() => root.criticalColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -319,11 +319,11 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
item.warning = Qt.binding(() => memWarning)
|
item.warning = Qt.binding(() => memWarning);
|
||||||
item.critical = Qt.binding(() => memCritical)
|
item.critical = Qt.binding(() => memCritical);
|
||||||
item.indicatorWidth = Qt.binding(() => memoryContainer.width)
|
item.indicatorWidth = Qt.binding(() => memoryContainer.width);
|
||||||
item.warningColor = Qt.binding(() => root.warningColor)
|
item.warningColor = Qt.binding(() => root.warningColor);
|
||||||
item.criticalColor = Qt.binding(() => root.criticalColor)
|
item.criticalColor = Qt.binding(() => root.criticalColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -472,11 +472,11 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
item.warning = Qt.binding(() => diskWarning)
|
item.warning = Qt.binding(() => diskWarning);
|
||||||
item.critical = Qt.binding(() => diskCritical)
|
item.critical = Qt.binding(() => diskCritical);
|
||||||
item.indicatorWidth = Qt.binding(() => diskContainer.width)
|
item.indicatorWidth = Qt.binding(() => diskContainer.width);
|
||||||
item.warningColor = Qt.binding(() => root.warningColor)
|
item.warningColor = Qt.binding(() => root.warningColor);
|
||||||
item.criticalColor = Qt.binding(() => root.criticalColor)
|
item.criticalColor = Qt.binding(() => root.criticalColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.Compositor
|
import qs.Services.Compositor
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
@@ -27,12 +27,12 @@ Rectangle {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
property bool hasWindow: false
|
property bool hasWindow: false
|
||||||
@@ -42,35 +42,35 @@ Rectangle {
|
|||||||
|
|
||||||
function updateHasWindow() {
|
function updateHasWindow() {
|
||||||
try {
|
try {
|
||||||
var total = CompositorService.windows.count || 0
|
var total = CompositorService.windows.count || 0;
|
||||||
var activeIds = CompositorService.getActiveWorkspaces().map(function (ws) {
|
var activeIds = CompositorService.getActiveWorkspaces().map(function (ws) {
|
||||||
return ws.id
|
return ws.id;
|
||||||
})
|
});
|
||||||
var found = false
|
var found = false;
|
||||||
for (var i = 0; i < total; i++) {
|
for (var i = 0; i < total; i++) {
|
||||||
var w = CompositorService.windows.get(i)
|
var w = CompositorService.windows.get(i);
|
||||||
if (!w)
|
if (!w)
|
||||||
continue
|
continue;
|
||||||
var passOutput = (!onlySameOutput) || (w.output == screen.name)
|
var passOutput = (!onlySameOutput) || (w.output == screen.name);
|
||||||
var passWorkspace = (!onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId))
|
var passWorkspace = (!onlyActiveWorkspaces) || (activeIds.includes(w.workspaceId));
|
||||||
if (passOutput && passWorkspace) {
|
if (passOutput && passWorkspace) {
|
||||||
found = true
|
found = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hasWindow = found
|
hasWindow = found;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
hasWindow = false
|
hasWindow = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: CompositorService
|
target: CompositorService
|
||||||
function onWindowListChanged() {
|
function onWindowListChanged() {
|
||||||
updateHasWindow()
|
updateHasWindow();
|
||||||
}
|
}
|
||||||
function onWorkspaceChanged() {
|
function onWorkspaceChanged() {
|
||||||
updateHasWindow()
|
updateHasWindow();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +117,7 @@ Rectangle {
|
|||||||
property ShellScreen screen: root.screen
|
property ShellScreen screen: root.screen
|
||||||
|
|
||||||
visible: (!onlySameOutput || modelData.output == screen.name) && (!onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(function (ws) {
|
visible: (!onlySameOutput || modelData.output == screen.name) && (!onlyActiveWorkspaces || CompositorService.getActiveWorkspaces().map(function (ws) {
|
||||||
return ws.id
|
return ws.id;
|
||||||
}).includes(modelData.workspaceId))
|
}).includes(modelData.workspaceId))
|
||||||
|
|
||||||
Layout.preferredWidth: root.itemSize
|
Layout.preferredWidth: root.itemSize
|
||||||
@@ -125,7 +125,6 @@ Rectangle {
|
|||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
|
||||||
IconImage {
|
IconImage {
|
||||||
|
|
||||||
id: appIcon
|
id: appIcon
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
@@ -144,10 +143,10 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
id: iconBackground
|
||||||
anchors.bottomMargin: -2
|
anchors.bottomMargin: -2
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
id: iconBackground
|
|
||||||
width: 4
|
width: 4
|
||||||
height: 4
|
height: 4
|
||||||
color: modelData.isFocused ? Color.mPrimary : Color.transparent
|
color: modelData.isFocused ? Color.mPrimary : Color.transparent
|
||||||
@@ -163,19 +162,18 @@ Rectangle {
|
|||||||
|
|
||||||
onPressed: function (mouse) {
|
onPressed: function (mouse) {
|
||||||
if (!taskbarItem.modelData)
|
if (!taskbarItem.modelData)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
try {
|
try {
|
||||||
CompositorService.focusWindow(taskbarItem.modelData)
|
CompositorService.focusWindow(taskbarItem.modelData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.e("Taskbar", "Failed to activate toplevel: " + error)
|
Logger.e("Taskbar", "Failed to activate toplevel: " + error);
|
||||||
}
|
}
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
try {
|
try {
|
||||||
CompositorService.closeWindow(taskbarItem.modelData)
|
CompositorService.closeWindow(taskbarItem.modelData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.e("Taskbar", "Failed to close toplevel: " + error)
|
Logger.e("Taskbar", "Failed to close toplevel: " + error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
||||||
readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied
|
readonly property bool hideUnoccupied: (widgetSettings.hideUnoccupied !== undefined) ? widgetSettings.hideUnoccupied : widgetMetadata.hideUnoccupied
|
||||||
@@ -49,40 +49,39 @@ Item {
|
|||||||
property bool wheelCooldown: false
|
property bool wheelCooldown: false
|
||||||
|
|
||||||
function refreshWorkspaces() {
|
function refreshWorkspaces() {
|
||||||
localWorkspaces.clear()
|
localWorkspaces.clear();
|
||||||
if (!screen)
|
if (!screen)
|
||||||
return
|
return;
|
||||||
|
const screenName = screen.name.toLowerCase();
|
||||||
const screenName = screen.name.toLowerCase()
|
|
||||||
|
|
||||||
for (var i = 0; i < CompositorService.workspaces.count; i++) {
|
for (var i = 0; i < CompositorService.workspaces.count; i++) {
|
||||||
const ws = CompositorService.workspaces.get(i)
|
const ws = CompositorService.workspaces.get(i);
|
||||||
|
|
||||||
if (ws.output.toLowerCase() !== screenName)
|
if (ws.output.toLowerCase() !== screenName)
|
||||||
continue
|
continue;
|
||||||
if (hideUnoccupied && !ws.isOccupied && !ws.isFocused)
|
if (hideUnoccupied && !ws.isOccupied && !ws.isFocused)
|
||||||
continue
|
continue;
|
||||||
|
|
||||||
// Copy all properties from ws and add windows
|
// Copy all properties from ws and add windows
|
||||||
var workspaceData = Object.assign({}, ws)
|
var workspaceData = Object.assign({}, ws);
|
||||||
workspaceData.windows = CompositorService.getWindowsForWorkspace(ws.id)
|
workspaceData.windows = CompositorService.getWindowsForWorkspace(ws.id);
|
||||||
|
|
||||||
localWorkspaces.append(workspaceData)
|
localWorkspaces.append(workspaceData);
|
||||||
}
|
}
|
||||||
updateWorkspaceFocus()
|
updateWorkspaceFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerUnifiedWave() {
|
function triggerUnifiedWave() {
|
||||||
effectColor = Color.mPrimary
|
effectColor = Color.mPrimary;
|
||||||
masterAnimation.restart()
|
masterAnimation.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWorkspaceFocus() {
|
function updateWorkspaceFocus() {
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
const ws = localWorkspaces.get(i)
|
const ws = localWorkspaces.get(i);
|
||||||
if (ws.isFocused === true) {
|
if (ws.isFocused === true) {
|
||||||
root.triggerUnifiedWave()
|
root.triggerUnifiedWave();
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,27 +89,27 @@ Item {
|
|||||||
function getFocusedLocalIndex() {
|
function getFocusedLocalIndex() {
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
if (localWorkspaces.get(i).isFocused === true)
|
if (localWorkspaces.get(i).isFocused === true)
|
||||||
return i
|
return i;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchByOffset(offset) {
|
function switchByOffset(offset) {
|
||||||
if (localWorkspaces.count === 0)
|
if (localWorkspaces.count === 0)
|
||||||
return
|
return;
|
||||||
var current = getFocusedLocalIndex()
|
var current = getFocusedLocalIndex();
|
||||||
if (current < 0)
|
if (current < 0)
|
||||||
current = 0
|
current = 0;
|
||||||
var next = (current + offset) % localWorkspaces.count
|
var next = (current + offset) % localWorkspaces.count;
|
||||||
if (next < 0)
|
if (next < 0)
|
||||||
next = localWorkspaces.count - 1
|
next = localWorkspaces.count - 1;
|
||||||
const ws = localWorkspaces.get(next)
|
const ws = localWorkspaces.get(next);
|
||||||
if (ws && ws.idx !== undefined)
|
if (ws && ws.idx !== undefined)
|
||||||
CompositorService.switchToWorkspace(ws)
|
CompositorService.switchToWorkspace(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
refreshWorkspaces()
|
refreshWorkspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
onScreenChanged: refreshWorkspaces()
|
onScreenChanged: refreshWorkspaces()
|
||||||
@@ -123,11 +122,11 @@ Item {
|
|||||||
target: CompositorService
|
target: CompositorService
|
||||||
|
|
||||||
function onWorkspacesChanged() {
|
function onWorkspacesChanged() {
|
||||||
refreshWorkspaces()
|
refreshWorkspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWindowListChanged() {
|
function onWindowListChanged() {
|
||||||
refreshWorkspaces()
|
refreshWorkspaces();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +163,8 @@ Item {
|
|||||||
interval: 150
|
interval: 150
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.wheelCooldown = false
|
root.wheelCooldown = false;
|
||||||
root.wheelAccumulatedDelta = 0
|
root.wheelAccumulatedDelta = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,24 +175,24 @@ Item {
|
|||||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||||
onWheel: function (event) {
|
onWheel: function (event) {
|
||||||
if (root.wheelCooldown)
|
if (root.wheelCooldown)
|
||||||
return
|
return;
|
||||||
// Prefer vertical delta, fall back to horizontal if needed
|
// Prefer vertical delta, fall back to horizontal if needed
|
||||||
var dy = event.angleDelta.y
|
var dy = event.angleDelta.y;
|
||||||
var dx = event.angleDelta.x
|
var dx = event.angleDelta.x;
|
||||||
var useDy = Math.abs(dy) >= Math.abs(dx)
|
var useDy = Math.abs(dy) >= Math.abs(dx);
|
||||||
var delta = useDy ? dy : dx
|
var delta = useDy ? dy : dx;
|
||||||
// One notch is typically 120
|
// One notch is typically 120
|
||||||
root.wheelAccumulatedDelta += delta
|
root.wheelAccumulatedDelta += delta;
|
||||||
var step = 120
|
var step = 120;
|
||||||
if (Math.abs(root.wheelAccumulatedDelta) >= step) {
|
if (Math.abs(root.wheelAccumulatedDelta) >= step) {
|
||||||
var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1
|
var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1;
|
||||||
// For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign)
|
// For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign)
|
||||||
// For horizontal layout, same mapping using vertical wheel
|
// For horizontal layout, same mapping using vertical wheel
|
||||||
root.switchByOffset(direction)
|
root.switchByOffset(direction);
|
||||||
root.wheelCooldown = true
|
root.wheelCooldown = true;
|
||||||
wheelDebounce.restart()
|
wheelDebounce.restart();
|
||||||
root.wheelAccumulatedDelta = 0
|
root.wheelAccumulatedDelta = 0;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -221,7 +220,7 @@ Item {
|
|||||||
enabled: !hasWindows
|
enabled: !hasWindows
|
||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
CompositorService.switchToWorkspace(workspaceModel)
|
CompositorService.switchToWorkspace(workspaceModel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,22 +296,22 @@ Item {
|
|||||||
|
|
||||||
onPressed: function (mouse) {
|
onPressed: function (mouse) {
|
||||||
if (!model) {
|
if (!model) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
CompositorService.focusWindow(model)
|
CompositorService.focusWindow(model);
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
CompositorService.closeWindow(model)
|
CompositorService.closeWindow(model);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
taskbarItem.itemHovered = true
|
taskbarItem.itemHovered = true;
|
||||||
TooltipService.show(Screen, taskbarItem, model.title || model.appId || "Unknown app.", BarService.getTooltipDirection())
|
TooltipService.show(Screen, taskbarItem, model.title || model.appId || "Unknown app.", BarService.getTooltipDirection());
|
||||||
}
|
}
|
||||||
onExited: {
|
onExited: {
|
||||||
taskbarItem.itemHovered = false
|
taskbarItem.itemHovered = false;
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -342,13 +341,13 @@ Item {
|
|||||||
|
|
||||||
color: {
|
color: {
|
||||||
if (workspaceModel.isFocused)
|
if (workspaceModel.isFocused)
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
if (workspaceModel.isUrgent)
|
if (workspaceModel.isUrgent)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
if (hasWindows)
|
if (hasWindows)
|
||||||
return Color.mSecondary
|
return Color.mSecondary;
|
||||||
|
|
||||||
return Qt.alpha(Color.mOutline, 0.3)
|
return Qt.alpha(Color.mOutline, 0.3);
|
||||||
}
|
}
|
||||||
|
|
||||||
scale: workspaceModel.isActive ? 1.0 : 0.9
|
scale: workspaceModel.isActive ? 1.0 : 0.9
|
||||||
@@ -390,9 +389,9 @@ Item {
|
|||||||
|
|
||||||
text: {
|
text: {
|
||||||
if (root.labelMode === "name" && workspaceModel.name && workspaceModel.name.length > 0) {
|
if (root.labelMode === "name" && workspaceModel.name && workspaceModel.name.length > 0) {
|
||||||
return workspaceModel.name.substring(0, root.characterCount)
|
return workspaceModel.name.substring(0, root.characterCount);
|
||||||
} else {
|
} else {
|
||||||
return workspaceModel.idx.toString()
|
return workspaceModel.idx.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,24 +405,24 @@ Item {
|
|||||||
|
|
||||||
color: {
|
color: {
|
||||||
if (workspaceModel.isFocused)
|
if (workspaceModel.isFocused)
|
||||||
return Color.mOnPrimary
|
return Color.mOnPrimary;
|
||||||
if (workspaceModel.isUrgent)
|
if (workspaceModel.isUrgent)
|
||||||
return Color.mOnError
|
return Color.mOnError;
|
||||||
if (hasWindows)
|
if (hasWindows)
|
||||||
return Color.mOnSecondary
|
return Color.mOnSecondary;
|
||||||
|
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
opacity: {
|
opacity: {
|
||||||
if (workspaceModel.isFocused)
|
if (workspaceModel.isFocused)
|
||||||
return 1.0
|
return 1.0;
|
||||||
if (workspaceModel.isUrgent)
|
if (workspaceModel.isUrgent)
|
||||||
return 0.9
|
return 0.9;
|
||||||
if (hasWindows)
|
if (hasWindows)
|
||||||
return 0.8
|
return 0.8;
|
||||||
|
|
||||||
return 0.6
|
return 0.6;
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Controls
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.SystemTray
|
import Quickshell.Services.SystemTray
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
@@ -21,8 +21,8 @@ Rectangle {
|
|||||||
// Get shared tray menu window from PanelService (reactive to trigger changes)
|
// Get shared tray menu window from PanelService (reactive to trigger changes)
|
||||||
readonly property var trayMenuWindow: {
|
readonly property var trayMenuWindow: {
|
||||||
// Reference trigger to force re-evaluation
|
// Reference trigger to force re-evaluation
|
||||||
var _ = trayMenuUpdateTrigger
|
var _ = trayMenuUpdateTrigger;
|
||||||
return PanelService.getTrayMenuWindow(screen)
|
return PanelService.getTrayMenuWindow(screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property var trayMenu: trayMenuWindow ? trayMenuWindow.trayMenuLoader : null
|
readonly property var trayMenu: trayMenuWindow ? trayMenuWindow.trayMenuLoader : null
|
||||||
@@ -31,7 +31,7 @@ Rectangle {
|
|||||||
target: PanelService
|
target: PanelService
|
||||||
function onTrayMenuWindowRegistered(registeredScreen) {
|
function onTrayMenuWindowRegistered(registeredScreen) {
|
||||||
if (registeredScreen === screen) {
|
if (registeredScreen === screen) {
|
||||||
root.trayMenuUpdateTrigger++
|
root.trayMenuUpdateTrigger++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,12 +45,12 @@ Rectangle {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string barPosition: Settings.data.bar.position
|
readonly property string barPosition: Settings.data.bar.position
|
||||||
@@ -76,149 +76,149 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _performFilteredItemsUpdate() {
|
function _performFilteredItemsUpdate() {
|
||||||
let newItems = []
|
let newItems = [];
|
||||||
if (SystemTray.items && SystemTray.items.values) {
|
if (SystemTray.items && SystemTray.items.values) {
|
||||||
const trayItems = SystemTray.items.values
|
const trayItems = SystemTray.items.values;
|
||||||
for (var i = 0; i < trayItems.length; i++) {
|
for (var i = 0; i < trayItems.length; i++) {
|
||||||
const item = trayItems[i]
|
const item = trayItems[i];
|
||||||
if (!item) {
|
if (!item) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const title = item.tooltipTitle || item.name || item.id || ""
|
const title = item.tooltipTitle || item.name || item.id || "";
|
||||||
|
|
||||||
// Check if blacklisted
|
// Check if blacklisted
|
||||||
let isBlacklisted = false
|
let isBlacklisted = false;
|
||||||
if (root.blacklist && root.blacklist.length > 0) {
|
if (root.blacklist && root.blacklist.length > 0) {
|
||||||
for (var j = 0; j < root.blacklist.length; j++) {
|
for (var j = 0; j < root.blacklist.length; j++) {
|
||||||
const rule = root.blacklist[j]
|
const rule = root.blacklist[j];
|
||||||
if (wildCardMatch(title, rule)) {
|
if (wildCardMatch(title, rule)) {
|
||||||
isBlacklisted = true
|
isBlacklisted = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isBlacklisted) {
|
if (!isBlacklisted) {
|
||||||
newItems.push(item)
|
newItems.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If drawer is disabled, show all items inline
|
// If drawer is disabled, show all items inline
|
||||||
if (!root.drawerEnabled) {
|
if (!root.drawerEnabled) {
|
||||||
filteredItems = newItems
|
filteredItems = newItems;
|
||||||
dropdownItems = []
|
dropdownItems = [];
|
||||||
} else {
|
} else {
|
||||||
// Build inline (pinned) and drawer (unpinned) lists
|
// Build inline (pinned) and drawer (unpinned) lists
|
||||||
// If pinned list is empty, all items go to drawer (none inline)
|
// If pinned list is empty, all items go to drawer (none inline)
|
||||||
// If pinned list has items, pinned items are inline, rest go to drawer
|
// If pinned list has items, pinned items are inline, rest go to drawer
|
||||||
if (pinned && pinned.length > 0) {
|
if (pinned && pinned.length > 0) {
|
||||||
let pinnedItems = []
|
let pinnedItems = [];
|
||||||
for (var k = 0; k < newItems.length; k++) {
|
for (var k = 0; k < newItems.length; k++) {
|
||||||
const item2 = newItems[k]
|
const item2 = newItems[k];
|
||||||
const title2 = item2.tooltipTitle || item2.name || item2.id || ""
|
const title2 = item2.tooltipTitle || item2.name || item2.id || "";
|
||||||
for (var m = 0; m < pinned.length; m++) {
|
for (var m = 0; m < pinned.length; m++) {
|
||||||
const rule2 = pinned[m]
|
const rule2 = pinned[m];
|
||||||
if (wildCardMatch(title2, rule2)) {
|
if (wildCardMatch(title2, rule2)) {
|
||||||
pinnedItems.push(item2)
|
pinnedItems.push(item2);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filteredItems = pinnedItems
|
filteredItems = pinnedItems;
|
||||||
|
|
||||||
// Unpinned items go to drawer
|
// Unpinned items go to drawer
|
||||||
let unpinnedItems = []
|
let unpinnedItems = [];
|
||||||
for (var v = 0; v < newItems.length; v++) {
|
for (var v = 0; v < newItems.length; v++) {
|
||||||
const cand = newItems[v]
|
const cand = newItems[v];
|
||||||
let isPinned = false
|
let isPinned = false;
|
||||||
for (var f = 0; f < filteredItems.length; f++) {
|
for (var f = 0; f < filteredItems.length; f++) {
|
||||||
if (filteredItems[f] === cand) {
|
if (filteredItems[f] === cand) {
|
||||||
isPinned = true
|
isPinned = true;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isPinned)
|
if (!isPinned)
|
||||||
unpinnedItems.push(cand)
|
unpinnedItems.push(cand);
|
||||||
}
|
}
|
||||||
dropdownItems = unpinnedItems
|
dropdownItems = unpinnedItems;
|
||||||
} else {
|
} else {
|
||||||
// No pinned items: all items go to drawer (none inline)
|
// No pinned items: all items go to drawer (none inline)
|
||||||
filteredItems = []
|
filteredItems = [];
|
||||||
dropdownItems = newItems
|
dropdownItems = newItems;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateFilteredItems() {
|
function updateFilteredItems() {
|
||||||
updateDebounceTimer.restart()
|
updateDebounceTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function wildCardMatch(str, rule) {
|
function wildCardMatch(str, rule) {
|
||||||
if (!str || !rule) {
|
if (!str || !rule) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
//Logger.d("Tray", "wildCardMatch - Input str:", str, "rule:", rule)
|
//Logger.d("Tray", "wildCardMatch - Input str:", str, "rule:", rule)
|
||||||
|
|
||||||
// Escape all special regex characters in the rule
|
// Escape all special regex characters in the rule
|
||||||
let escapedRule = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
let escapedRule = rule.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||||
// Convert '*' to '.*' for wildcard matching
|
// Convert '*' to '.*' for wildcard matching
|
||||||
let pattern = escapedRule.replace(/\\\*/g, '.*')
|
let pattern = escapedRule.replace(/\\\*/g, '.*');
|
||||||
// Add ^ and $ to match the entire string
|
// Add ^ and $ to match the entire string
|
||||||
pattern = '^' + pattern + '$'
|
pattern = '^' + pattern + '$';
|
||||||
|
|
||||||
//Logger.d("Tray", "wildCardMatch - Generated pattern:", pattern)
|
//Logger.d("Tray", "wildCardMatch - Generated pattern:", pattern)
|
||||||
try {
|
try {
|
||||||
const regex = new RegExp(pattern, 'i')
|
const regex = new RegExp(pattern, 'i');
|
||||||
// 'i' for case-insensitive
|
// 'i' for case-insensitive
|
||||||
//Logger.d("Tray", "wildCardMatch - Regex test result:", regex.test(str))
|
//Logger.d("Tray", "wildCardMatch - Regex test result:", regex.test(str))
|
||||||
return regex.test(str)
|
return regex.test(str);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
Logger.w("Tray", "Invalid regex pattern for wildcard match:", rule, e.message)
|
Logger.w("Tray", "Invalid regex pattern for wildcard match:", rule, e.message);
|
||||||
return false // If regex is invalid, it won't match
|
return false; // If regex is invalid, it won't match
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDrawer(button) {
|
function toggleDrawer(button) {
|
||||||
TooltipService.hideImmediately()
|
TooltipService.hideImmediately();
|
||||||
|
|
||||||
// Close the tray menu if it's open
|
// Close the tray menu if it's open
|
||||||
if (trayMenuWindow && trayMenuWindow.visible) {
|
if (trayMenuWindow && trayMenuWindow.visible) {
|
||||||
trayMenuWindow.close()
|
trayMenuWindow.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
const panel = PanelService.getPanel("trayDrawerPanel", root.screen)
|
const panel = PanelService.getPanel("trayDrawerPanel", root.screen);
|
||||||
if (panel) {
|
if (panel) {
|
||||||
panel.widgetSection = root.section
|
panel.widgetSection = root.section;
|
||||||
panel.widgetIndex = root.sectionWidgetIndex
|
panel.widgetIndex = root.sectionWidgetIndex;
|
||||||
panel.toggle(this)
|
panel.toggle(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onLoaded() {
|
function onLoaded() {
|
||||||
// When the widget is fully initialized with its props set the screen for the trayMenu
|
// When the widget is fully initialized with its props set the screen for the trayMenu
|
||||||
if (trayMenu && trayMenu.item) {
|
if (trayMenu && trayMenu.item) {
|
||||||
trayMenu.item.screen = screen
|
trayMenu.item.screen = screen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: SystemTray.items
|
target: SystemTray.items
|
||||||
function onValuesChanged() {
|
function onValuesChanged() {
|
||||||
root.updateFilteredItems()
|
root.updateFilteredItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Settings
|
target: Settings
|
||||||
function onSettingsSaved() {
|
function onSettingsSaved() {
|
||||||
root.updateFilteredItems()
|
root.updateFilteredItems();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
root.updateFilteredItems() // Initial update
|
root.updateFilteredItems(); // Initial update
|
||||||
}
|
}
|
||||||
|
|
||||||
visible: filteredItems.length > 0 || dropdownItems.length > 0
|
visible: filteredItems.length > 0 || dropdownItems.length > 0
|
||||||
@@ -248,14 +248,14 @@ Rectangle {
|
|||||||
icon: {
|
icon: {
|
||||||
switch (barPosition) {
|
switch (barPosition) {
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return "caret-up"
|
return "caret-up";
|
||||||
case "left":
|
case "left":
|
||||||
return "caret-right"
|
return "caret-right";
|
||||||
case "right":
|
case "right":
|
||||||
return "caret-left"
|
return "caret-left";
|
||||||
case "top":
|
case "top":
|
||||||
default:
|
default:
|
||||||
return "caret-down"
|
return "caret-down";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onClicked: toggleDrawer(this)
|
onClicked: toggleDrawer(this)
|
||||||
@@ -283,20 +283,20 @@ Rectangle {
|
|||||||
property bool menuJustOpened: false
|
property bool menuJustOpened: false
|
||||||
|
|
||||||
source: {
|
source: {
|
||||||
let icon = modelData?.icon || ""
|
let icon = modelData?.icon || "";
|
||||||
if (!icon) {
|
if (!icon) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process icon path
|
// Process icon path
|
||||||
if (icon.includes("?path=")) {
|
if (icon.includes("?path=")) {
|
||||||
const chunks = icon.split("?path=")
|
const chunks = icon.split("?path=");
|
||||||
const name = chunks[0]
|
const name = chunks[0];
|
||||||
const path = chunks[1]
|
const path = chunks[1];
|
||||||
const fileName = name.substring(name.lastIndexOf("/") + 1)
|
const fileName = name.substring(name.lastIndexOf("/") + 1);
|
||||||
return `file://${path}/${fileName}`
|
return `file://${path}/${fileName}`;
|
||||||
}
|
}
|
||||||
return icon
|
return icon;
|
||||||
}
|
}
|
||||||
opacity: status === Image.Ready ? 1 : 0
|
opacity: status === Image.Ready ? 1 : 0
|
||||||
|
|
||||||
@@ -315,71 +315,71 @@ Rectangle {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
if (!modelData) {
|
if (!modelData) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
// Close any open menu first
|
// Close any open menu first
|
||||||
if (trayMenuWindow) {
|
if (trayMenuWindow) {
|
||||||
trayMenuWindow.close()
|
trayMenuWindow.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modelData.onlyMenu) {
|
if (!modelData.onlyMenu) {
|
||||||
modelData.activate()
|
modelData.activate();
|
||||||
}
|
}
|
||||||
} else if (mouse.button === Qt.MiddleButton) {
|
} else if (mouse.button === Qt.MiddleButton) {
|
||||||
// Close the menu if it was visible
|
// Close the menu if it was visible
|
||||||
if (trayMenuWindow && trayMenuWindow.visible) {
|
if (trayMenuWindow && trayMenuWindow.visible) {
|
||||||
trayMenuWindow.close()
|
trayMenuWindow.close();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
modelData.secondaryActivate && modelData.secondaryActivate()
|
modelData.secondaryActivate && modelData.secondaryActivate();
|
||||||
} else if (mouse.button === Qt.RightButton) {
|
} else if (mouse.button === Qt.RightButton) {
|
||||||
TooltipService.hideImmediately()
|
TooltipService.hideImmediately();
|
||||||
|
|
||||||
// Close the menu if it was visible
|
// Close the menu if it was visible
|
||||||
if (trayMenuWindow && trayMenuWindow.visible) {
|
if (trayMenuWindow && trayMenuWindow.visible) {
|
||||||
trayMenuWindow.close()
|
trayMenuWindow.close();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close any opened panel
|
// Close any opened panel
|
||||||
if ((PanelService.openedPanel !== null) && !PanelService.openedPanel.isClosing) {
|
if ((PanelService.openedPanel !== null) && !PanelService.openedPanel.isClosing) {
|
||||||
PanelService.openedPanel.close()
|
PanelService.openedPanel.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (modelData.hasMenu && modelData.menu && trayMenuWindow && trayMenu && trayMenu.item) {
|
if (modelData.hasMenu && modelData.menu && trayMenuWindow && trayMenu && trayMenu.item) {
|
||||||
trayMenuWindow.open()
|
trayMenuWindow.open();
|
||||||
|
|
||||||
// Position menu based on bar position
|
// Position menu based on bar position
|
||||||
let menuX, menuY
|
let menuX, menuY;
|
||||||
if (barPosition === "left") {
|
if (barPosition === "left") {
|
||||||
// For left bar: position menu to the right of the bar
|
// For left bar: position menu to the right of the bar
|
||||||
menuX = width + Style.marginM
|
menuX = width + Style.marginM;
|
||||||
menuY = 0
|
menuY = 0;
|
||||||
} else if (barPosition === "right") {
|
} else if (barPosition === "right") {
|
||||||
// For right bar: position menu to the left of the bar
|
// For right bar: position menu to the left of the bar
|
||||||
menuX = -trayMenu.item.width - Style.marginM
|
menuX = -trayMenu.item.width - Style.marginM;
|
||||||
menuY = 0
|
menuY = 0;
|
||||||
} else {
|
} else {
|
||||||
// For horizontal bars: center horizontally and position below
|
// For horizontal bars: center horizontally and position below
|
||||||
menuX = (width / 2) - (trayMenu.item.width / 2)
|
menuX = (width / 2) - (trayMenu.item.width / 2);
|
||||||
menuY = (barPosition === "top") ? Style.barHeight : -Style.barHeight
|
menuY = (barPosition === "top") ? Style.barHeight : -Style.barHeight;
|
||||||
}
|
}
|
||||||
trayMenu.item.trayItem = modelData
|
trayMenu.item.trayItem = modelData;
|
||||||
trayMenu.item.widgetSection = root.section
|
trayMenu.item.widgetSection = root.section;
|
||||||
trayMenu.item.widgetIndex = root.sectionWidgetIndex
|
trayMenu.item.widgetIndex = root.sectionWidgetIndex;
|
||||||
trayMenu.item.showAt(parent, menuX, menuY)
|
trayMenu.item.showAt(parent, menuX, menuY);
|
||||||
} else {
|
} else {
|
||||||
Logger.d("Tray", "No menu available for", modelData.id, "or trayMenu not set")
|
Logger.d("Tray", "No menu available for", modelData.id, "or trayMenu not set");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if (trayMenuWindow) {
|
if (trayMenuWindow) {
|
||||||
trayMenuWindow.close()
|
trayMenuWindow.close();
|
||||||
}
|
}
|
||||||
TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection())
|
TooltipService.show(Screen, trayIcon, modelData.tooltipTitle || modelData.name || modelData.id || "Tray Item", BarService.getTooltipDirection());
|
||||||
}
|
}
|
||||||
onExited: TooltipService.hide()
|
onExited: TooltipService.hide()
|
||||||
}
|
}
|
||||||
@@ -403,14 +403,14 @@ Rectangle {
|
|||||||
icon: {
|
icon: {
|
||||||
switch (barPosition) {
|
switch (barPosition) {
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return "caret-up"
|
return "caret-up";
|
||||||
case "left":
|
case "left":
|
||||||
return "caret-right"
|
return "caret-right";
|
||||||
case "right":
|
case "right":
|
||||||
return "caret-left"
|
return "caret-left";
|
||||||
case "top":
|
case "top":
|
||||||
default:
|
default:
|
||||||
return "caret-down"
|
return "caret-down";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onClicked: toggleDrawer(this)
|
onClicked: toggleDrawer(this)
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import Quickshell.Services.Pipewire
|
|||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Modules.Bar.Extras
|
import qs.Modules.Bar.Extras
|
||||||
import qs.Modules.Panels.Settings
|
import qs.Modules.Panels.Settings
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
@@ -23,12 +23,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -48,12 +48,12 @@ Item {
|
|||||||
// Logger.i("Bar:Volume", "onVolumeChanged")
|
// Logger.i("Bar:Volume", "onVolumeChanged")
|
||||||
if (!firstVolumeReceived) {
|
if (!firstVolumeReceived) {
|
||||||
// Ignore the first volume change
|
// Ignore the first volume change
|
||||||
firstVolumeReceived = true
|
firstVolumeReceived = true;
|
||||||
} else {
|
} else {
|
||||||
// Hide any tooltip while the pill is visible / being updated
|
// Hide any tooltip while the pill is visible / being updated
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
pill.show()
|
pill.show();
|
||||||
externalHideTimer.restart()
|
externalHideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ Item {
|
|||||||
running: false
|
running: false
|
||||||
interval: 1500
|
interval: 1500
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
pill.hide()
|
pill.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,25 +84,25 @@ Item {
|
|||||||
|
|
||||||
onWheel: function (delta) {
|
onWheel: function (delta) {
|
||||||
// Hide tooltip as soon as the user starts scrolling to adjust volume
|
// Hide tooltip as soon as the user starts scrolling to adjust volume
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
|
|
||||||
wheelAccumulator += delta
|
wheelAccumulator += delta;
|
||||||
if (wheelAccumulator >= 120) {
|
if (wheelAccumulator >= 120) {
|
||||||
wheelAccumulator = 0
|
wheelAccumulator = 0;
|
||||||
AudioService.increaseVolume()
|
AudioService.increaseVolume();
|
||||||
} else if (wheelAccumulator <= -120) {
|
} else if (wheelAccumulator <= -120) {
|
||||||
wheelAccumulator = 0
|
wheelAccumulator = 0;
|
||||||
AudioService.decreaseVolume()
|
AudioService.decreaseVolume();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PanelService.getPanel("audioPanel", screen)?.toggle(this)
|
PanelService.getPanel("audioPanel", screen)?.toggle(this);
|
||||||
}
|
}
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
AudioService.setOutputMuted(!AudioService.muted)
|
AudioService.setOutputMuted(!AudioService.muted);
|
||||||
}
|
}
|
||||||
onMiddleClicked: {
|
onMiddleClicked: {
|
||||||
Quickshell.execDetached(["sh", "-c", "pwvucontrol || pavucontrol"])
|
Quickshell.execDetached(["sh", "-c", "pwvucontrol || pavucontrol"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ NIconButton {
|
|||||||
colorBorder: Color.transparent
|
colorBorder: Color.transparent
|
||||||
colorBorderHover: Color.transparent
|
colorBorderHover: Color.transparent
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var wallpaperPanel = PanelService.getPanel("wallpaperPanel", screen)
|
var wallpaperPanel = PanelService.getPanel("wallpaperPanel", screen);
|
||||||
if (Settings.data.wallpaper.panelPosition === "follow_bar") {
|
if (Settings.data.wallpaper.panelPosition === "follow_bar") {
|
||||||
wallpaperPanel?.toggle(this)
|
wallpaperPanel?.toggle(this);
|
||||||
} else {
|
} else {
|
||||||
wallpaperPanel?.toggle()
|
wallpaperPanel?.toggle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.Bar.Extras
|
||||||
import qs.Services.Networking
|
import qs.Services.Networking
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import qs.Modules.Bar.Extras
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -19,12 +19,12 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
readonly property bool isBarVertical: Settings.data.bar.position === "left" || Settings.data.bar.position === "right"
|
||||||
@@ -41,37 +41,37 @@ Item {
|
|||||||
icon: {
|
icon: {
|
||||||
try {
|
try {
|
||||||
if (NetworkService.ethernetConnected) {
|
if (NetworkService.ethernetConnected) {
|
||||||
return NetworkService.internetConnectivity ? "ethernet" : "ethernet-off"
|
return NetworkService.internetConnectivity ? "ethernet" : "ethernet-off";
|
||||||
}
|
}
|
||||||
let connected = false
|
let connected = false;
|
||||||
let signalStrength = 0
|
let signalStrength = 0;
|
||||||
for (const net in NetworkService.networks) {
|
for (const net in NetworkService.networks) {
|
||||||
if (NetworkService.networks[net].connected) {
|
if (NetworkService.networks[net].connected) {
|
||||||
connected = true
|
connected = true;
|
||||||
signalStrength = NetworkService.networks[net].signal
|
signalStrength = NetworkService.networks[net].signal;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return connected ? NetworkService.signalIcon(signalStrength, true) : "wifi-off"
|
return connected ? NetworkService.signalIcon(signalStrength, true) : "wifi-off";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.e("Wi-Fi", "Error getting icon:", error)
|
Logger.e("Wi-Fi", "Error getting icon:", error);
|
||||||
return "wifi-off"
|
return "wifi-off";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text: {
|
text: {
|
||||||
try {
|
try {
|
||||||
if (NetworkService.ethernetConnected) {
|
if (NetworkService.ethernetConnected) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
for (const net in NetworkService.networks) {
|
for (const net in NetworkService.networks) {
|
||||||
if (NetworkService.networks[net].connected) {
|
if (NetworkService.networks[net].connected) {
|
||||||
return net
|
return net;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ""
|
return "";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.e("Wi-Fi", "Error getting ssid:", error)
|
Logger.e("Wi-Fi", "Error getting ssid:", error);
|
||||||
return "error"
|
return "error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
autoHide: false
|
autoHide: false
|
||||||
@@ -81,9 +81,9 @@ Item {
|
|||||||
onRightClicked: NetworkService.setWifiEnabled(!Settings.data.network.wifiEnabled)
|
onRightClicked: NetworkService.setWifiEnabled(!Settings.data.network.wifiEnabled)
|
||||||
tooltipText: {
|
tooltipText: {
|
||||||
if (pill.text !== "") {
|
if (pill.text !== "") {
|
||||||
return pill.text
|
return pill.text;
|
||||||
}
|
}
|
||||||
return I18n.tr("tooltips.manage-wifi")
|
return I18n.tr("tooltips.manage-wifi");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Effects
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Effects
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
@@ -24,23 +24,23 @@ Item {
|
|||||||
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
property var widgetMetadata: BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
property var widgetSettings: {
|
property var widgetSettings: {
|
||||||
if (section && sectionWidgetIndex >= 0) {
|
if (section && sectionWidgetIndex >= 0) {
|
||||||
var widgets = Settings.data.bar.widgets[section]
|
var widgets = Settings.data.bar.widgets[section];
|
||||||
if (widgets && sectionWidgetIndex < widgets.length) {
|
if (widgets && sectionWidgetIndex < widgets.length) {
|
||||||
return widgets[sectionWidgetIndex]
|
return widgets[sectionWidgetIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string barPosition: Settings.data.bar.position
|
readonly property string barPosition: Settings.data.bar.position
|
||||||
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
readonly property bool isVertical: barPosition === "left" || barPosition === "right"
|
||||||
readonly property bool density: Settings.data.bar.density
|
readonly property bool density: Settings.data.bar.density
|
||||||
readonly property real baseDimensionRatio: {
|
readonly property real baseDimensionRatio: {
|
||||||
const b = (density === "compact") ? 0.85 : 0.65
|
const b = (density === "compact") ? 0.85 : 0.65;
|
||||||
if (widgetSettings.labelMode === "none") {
|
if (widgetSettings.labelMode === "none") {
|
||||||
return b * 0.75
|
return b * 0.75;
|
||||||
}
|
}
|
||||||
return b
|
return b;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
readonly property string labelMode: (widgetSettings.labelMode !== undefined) ? widgetSettings.labelMode : widgetMetadata.labelMode
|
||||||
@@ -68,76 +68,76 @@ Item {
|
|||||||
implicitHeight: isVertical ? computeHeight() : Style.barHeight
|
implicitHeight: isVertical ? computeHeight() : Style.barHeight
|
||||||
|
|
||||||
function getWorkspaceWidth(ws) {
|
function getWorkspaceWidth(ws) {
|
||||||
const d = Style.capsuleHeight * root.baseDimensionRatio
|
const d = Style.capsuleHeight * root.baseDimensionRatio;
|
||||||
const factor = ws.isActive ? 2.2 : 1
|
const factor = ws.isActive ? 2.2 : 1;
|
||||||
|
|
||||||
// For name mode, calculate width based on actual text content
|
// For name mode, calculate width based on actual text content
|
||||||
if (labelMode === "name" && ws.name && ws.name.length > 0) {
|
if (labelMode === "name" && ws.name && ws.name.length > 0) {
|
||||||
const displayText = ws.name.substring(0, characterCount)
|
const displayText = ws.name.substring(0, characterCount);
|
||||||
const textWidth = displayText.length * (d * 0.4) // Approximate width per character
|
const textWidth = displayText.length * (d * 0.4); // Approximate width per character
|
||||||
const padding = d * 0.6 // Padding on both sides
|
const padding = d * 0.6; // Padding on both sides
|
||||||
return Math.max(d * factor, textWidth + padding)
|
return Math.max(d * factor, textWidth + padding);
|
||||||
}
|
}
|
||||||
|
|
||||||
return d * factor
|
return d * factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWorkspaceHeight(ws) {
|
function getWorkspaceHeight(ws) {
|
||||||
const d = Style.capsuleHeight * root.baseDimensionRatio
|
const d = Style.capsuleHeight * root.baseDimensionRatio;
|
||||||
const factor = ws.isActive ? 2.2 : 1
|
const factor = ws.isActive ? 2.2 : 1;
|
||||||
return d * factor
|
return d * factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeWidth() {
|
function computeWidth() {
|
||||||
let total = 0
|
let total = 0;
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
const ws = localWorkspaces.get(i)
|
const ws = localWorkspaces.get(i);
|
||||||
total += getWorkspaceWidth(ws)
|
total += getWorkspaceWidth(ws);
|
||||||
}
|
}
|
||||||
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills
|
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills;
|
||||||
total += horizontalPadding * 2
|
total += horizontalPadding * 2;
|
||||||
return Math.round(total)
|
return Math.round(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeHeight() {
|
function computeHeight() {
|
||||||
let total = 0
|
let total = 0;
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
const ws = localWorkspaces.get(i)
|
const ws = localWorkspaces.get(i);
|
||||||
total += getWorkspaceHeight(ws)
|
total += getWorkspaceHeight(ws);
|
||||||
}
|
}
|
||||||
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills
|
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills;
|
||||||
total += horizontalPadding * 2
|
total += horizontalPadding * 2;
|
||||||
return Math.round(total)
|
return Math.round(total);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFocusedLocalIndex() {
|
function getFocusedLocalIndex() {
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
if (localWorkspaces.get(i).isFocused === true)
|
if (localWorkspaces.get(i).isFocused === true)
|
||||||
return i
|
return i;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function switchByOffset(offset) {
|
function switchByOffset(offset) {
|
||||||
if (localWorkspaces.count === 0)
|
if (localWorkspaces.count === 0)
|
||||||
return
|
return;
|
||||||
var current = getFocusedLocalIndex()
|
var current = getFocusedLocalIndex();
|
||||||
if (current < 0)
|
if (current < 0)
|
||||||
current = 0
|
current = 0;
|
||||||
var next = (current + offset) % localWorkspaces.count
|
var next = (current + offset) % localWorkspaces.count;
|
||||||
if (next < 0)
|
if (next < 0)
|
||||||
next = localWorkspaces.count - 1
|
next = localWorkspaces.count - 1;
|
||||||
const ws = localWorkspaces.get(next)
|
const ws = localWorkspaces.get(next);
|
||||||
if (ws && ws.idx !== undefined)
|
if (ws && ws.idx !== undefined)
|
||||||
CompositorService.switchToWorkspace(ws)
|
CompositorService.switchToWorkspace(ws);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
refreshWorkspaces()
|
refreshWorkspaces();
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
root.isDestroying = true
|
root.isDestroying = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onScreenChanged: refreshWorkspaces()
|
onScreenChanged: refreshWorkspaces()
|
||||||
@@ -146,40 +146,40 @@ Item {
|
|||||||
Connections {
|
Connections {
|
||||||
target: CompositorService
|
target: CompositorService
|
||||||
function onWorkspacesChanged() {
|
function onWorkspacesChanged() {
|
||||||
refreshWorkspaces()
|
refreshWorkspaces();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function refreshWorkspaces() {
|
function refreshWorkspaces() {
|
||||||
localWorkspaces.clear()
|
localWorkspaces.clear();
|
||||||
if (screen !== null) {
|
if (screen !== null) {
|
||||||
for (var i = 0; i < CompositorService.workspaces.count; i++) {
|
for (var i = 0; i < CompositorService.workspaces.count; i++) {
|
||||||
const ws = CompositorService.workspaces.get(i)
|
const ws = CompositorService.workspaces.get(i);
|
||||||
if (ws.output.toLowerCase() === screen.name.toLowerCase()) {
|
if (ws.output.toLowerCase() === screen.name.toLowerCase()) {
|
||||||
if (hideUnoccupied && !ws.isOccupied && !ws.isFocused) {
|
if (hideUnoccupied && !ws.isOccupied && !ws.isFocused) {
|
||||||
continue
|
continue;
|
||||||
}
|
}
|
||||||
localWorkspaces.append(ws)
|
localWorkspaces.append(ws);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
workspaceRepeaterHorizontal.model = localWorkspaces
|
workspaceRepeaterHorizontal.model = localWorkspaces;
|
||||||
workspaceRepeaterVertical.model = localWorkspaces
|
workspaceRepeaterVertical.model = localWorkspaces;
|
||||||
updateWorkspaceFocus()
|
updateWorkspaceFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function triggerUnifiedWave() {
|
function triggerUnifiedWave() {
|
||||||
effectColor = Color.mPrimary
|
effectColor = Color.mPrimary;
|
||||||
masterAnimation.restart()
|
masterAnimation.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWorkspaceFocus() {
|
function updateWorkspaceFocus() {
|
||||||
for (var i = 0; i < localWorkspaces.count; i++) {
|
for (var i = 0; i < localWorkspaces.count; i++) {
|
||||||
const ws = localWorkspaces.get(i)
|
const ws = localWorkspaces.get(i);
|
||||||
if (ws.isFocused === true) {
|
if (ws.isFocused === true) {
|
||||||
root.triggerUnifiedWave()
|
root.triggerUnifiedWave();
|
||||||
root.workspaceChanged(ws.id, Color.mPrimary)
|
root.workspaceChanged(ws.id, Color.mPrimary);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -228,8 +228,8 @@ Item {
|
|||||||
interval: 150
|
interval: 150
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.wheelCooldown = false
|
root.wheelCooldown = false;
|
||||||
root.wheelAccumulatedDelta = 0
|
root.wheelAccumulatedDelta = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,24 +240,24 @@ Item {
|
|||||||
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
acceptedDevices: PointerDevice.Mouse | PointerDevice.TouchPad
|
||||||
onWheel: function (event) {
|
onWheel: function (event) {
|
||||||
if (root.wheelCooldown)
|
if (root.wheelCooldown)
|
||||||
return
|
return;
|
||||||
// Prefer vertical delta, fall back to horizontal if needed
|
// Prefer vertical delta, fall back to horizontal if needed
|
||||||
var dy = event.angleDelta.y
|
var dy = event.angleDelta.y;
|
||||||
var dx = event.angleDelta.x
|
var dx = event.angleDelta.x;
|
||||||
var useDy = Math.abs(dy) >= Math.abs(dx)
|
var useDy = Math.abs(dy) >= Math.abs(dx);
|
||||||
var delta = useDy ? dy : dx
|
var delta = useDy ? dy : dx;
|
||||||
// One notch is typically 120
|
// One notch is typically 120
|
||||||
root.wheelAccumulatedDelta += delta
|
root.wheelAccumulatedDelta += delta;
|
||||||
var step = 120
|
var step = 120;
|
||||||
if (Math.abs(root.wheelAccumulatedDelta) >= step) {
|
if (Math.abs(root.wheelAccumulatedDelta) >= step) {
|
||||||
var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1
|
var direction = root.wheelAccumulatedDelta > 0 ? -1 : 1;
|
||||||
// For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign)
|
// For vertical layout, natural mapping: wheel up -> previous, down -> next (already handled by sign)
|
||||||
// For horizontal layout, same mapping using vertical wheel
|
// For horizontal layout, same mapping using vertical wheel
|
||||||
root.switchByOffset(direction)
|
root.switchByOffset(direction);
|
||||||
root.wheelCooldown = true
|
root.wheelCooldown = true;
|
||||||
wheelDebounce.restart()
|
wheelDebounce.restart();
|
||||||
root.wheelAccumulatedDelta = 0
|
root.wheelAccumulatedDelta = 0;
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -290,9 +290,9 @@ Item {
|
|||||||
y: (pill.height - height) / 2 + (height - contentHeight) / 2
|
y: (pill.height - height) / 2 + (height - contentHeight) / 2
|
||||||
text: {
|
text: {
|
||||||
if (labelMode === "name" && model.name && model.name.length > 0) {
|
if (labelMode === "name" && model.name && model.name.length > 0) {
|
||||||
return model.name.substring(0, characterCount)
|
return model.name.substring(0, characterCount);
|
||||||
} else {
|
} else {
|
||||||
return model.idx.toString()
|
return model.idx.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
family: Settings.data.ui.fontFixed
|
family: Settings.data.ui.fontFixed
|
||||||
@@ -303,13 +303,13 @@ Item {
|
|||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
color: {
|
color: {
|
||||||
if (model.isFocused)
|
if (model.isFocused)
|
||||||
return Color.mOnPrimary
|
return Color.mOnPrimary;
|
||||||
if (model.isUrgent)
|
if (model.isUrgent)
|
||||||
return Color.mOnError
|
return Color.mOnError;
|
||||||
if (model.isOccupied)
|
if (model.isOccupied)
|
||||||
return Color.mOnSecondary
|
return Color.mOnSecondary;
|
||||||
|
|
||||||
return Color.mOnSecondary
|
return Color.mOnSecondary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -318,13 +318,13 @@ Item {
|
|||||||
radius: width * 0.5
|
radius: width * 0.5
|
||||||
color: {
|
color: {
|
||||||
if (model.isFocused)
|
if (model.isFocused)
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
if (model.isUrgent)
|
if (model.isUrgent)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
if (model.isOccupied)
|
if (model.isOccupied)
|
||||||
return Color.mSecondary
|
return Color.mSecondary;
|
||||||
|
|
||||||
return Qt.alpha(Color.mSecondary, 0.3)
|
return Qt.alpha(Color.mSecondary, 0.3);
|
||||||
}
|
}
|
||||||
scale: model.isActive ? 1.0 : 0.9
|
scale: model.isActive ? 1.0 : 0.9
|
||||||
z: 0
|
z: 0
|
||||||
@@ -334,7 +334,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
CompositorService.switchToWorkspace(model)
|
CompositorService.switchToWorkspace(model);
|
||||||
}
|
}
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
}
|
}
|
||||||
@@ -435,9 +435,9 @@ Item {
|
|||||||
y: (pillVertical.height - height) / 2 + (height - contentHeight) / 2
|
y: (pillVertical.height - height) / 2 + (height - contentHeight) / 2
|
||||||
text: {
|
text: {
|
||||||
if (labelMode === "name" && model.name && model.name.length > 0) {
|
if (labelMode === "name" && model.name && model.name.length > 0) {
|
||||||
return model.name.substring(0, characterCount)
|
return model.name.substring(0, characterCount);
|
||||||
} else {
|
} else {
|
||||||
return model.idx.toString()
|
return model.idx.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
family: Settings.data.ui.fontFixed
|
family: Settings.data.ui.fontFixed
|
||||||
@@ -448,13 +448,13 @@ Item {
|
|||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
color: {
|
color: {
|
||||||
if (model.isFocused)
|
if (model.isFocused)
|
||||||
return Color.mOnPrimary
|
return Color.mOnPrimary;
|
||||||
if (model.isUrgent)
|
if (model.isUrgent)
|
||||||
return Color.mOnError
|
return Color.mOnError;
|
||||||
if (model.isOccupied)
|
if (model.isOccupied)
|
||||||
return Color.mOnSecondary
|
return Color.mOnSecondary;
|
||||||
|
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -463,13 +463,13 @@ Item {
|
|||||||
radius: width * 0.5
|
radius: width * 0.5
|
||||||
color: {
|
color: {
|
||||||
if (model.isFocused)
|
if (model.isFocused)
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
if (model.isUrgent)
|
if (model.isUrgent)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
if (model.isOccupied)
|
if (model.isOccupied)
|
||||||
return Color.mSecondary
|
return Color.mSecondary;
|
||||||
|
|
||||||
return Color.mOutline
|
return Color.mOutline;
|
||||||
}
|
}
|
||||||
scale: model.isActive ? 1.0 : 0.9
|
scale: model.isActive ? 1.0 : 0.9
|
||||||
z: 0
|
z: 0
|
||||||
@@ -479,7 +479,7 @@ Item {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
CompositorService.switchToWorkspace(model)
|
CompositorService.switchToWorkspace(model);
|
||||||
}
|
}
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
@@ -26,7 +26,7 @@ Loader {
|
|||||||
target: BarService
|
target: BarService
|
||||||
function onBarReadyChanged(screenName) {
|
function onBarReadyChanged(screenName) {
|
||||||
if (screenName === modelData.name) {
|
if (screenName === modelData.name) {
|
||||||
barIsReady = true
|
barIsReady = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,7 +35,7 @@ Loader {
|
|||||||
Connections {
|
Connections {
|
||||||
target: ToplevelManager ? ToplevelManager.toplevels : null
|
target: ToplevelManager ? ToplevelManager.toplevels : null
|
||||||
function onValuesChanged() {
|
function onValuesChanged() {
|
||||||
updateDockApps()
|
updateDockApps();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,17 +43,17 @@ Loader {
|
|||||||
Connections {
|
Connections {
|
||||||
target: Settings.data.dock
|
target: Settings.data.dock
|
||||||
function onPinnedAppsChanged() {
|
function onPinnedAppsChanged() {
|
||||||
updateDockApps()
|
updateDockApps();
|
||||||
}
|
}
|
||||||
function onOnlySameOutputChanged() {
|
function onOnlySameOutputChanged() {
|
||||||
updateDockApps()
|
updateDockApps();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial update when component is ready
|
// Initial update when component is ready
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (ToplevelManager) {
|
if (ToplevelManager) {
|
||||||
updateDockApps()
|
updateDockApps();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,33 +93,33 @@ Loader {
|
|||||||
// Function to close any open context menu
|
// Function to close any open context menu
|
||||||
function closeAllContextMenus() {
|
function closeAllContextMenus() {
|
||||||
if (currentContextMenu && currentContextMenu.visible) {
|
if (currentContextMenu && currentContextMenu.visible) {
|
||||||
currentContextMenu.hide()
|
currentContextMenu.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to update the combined dock apps model
|
// Function to update the combined dock apps model
|
||||||
function updateDockApps() {
|
function updateDockApps() {
|
||||||
const runningApps = ToplevelManager ? (ToplevelManager.toplevels.values || []) : []
|
const runningApps = ToplevelManager ? (ToplevelManager.toplevels.values || []) : [];
|
||||||
const pinnedApps = Settings.data.dock.pinnedApps || []
|
const pinnedApps = Settings.data.dock.pinnedApps || [];
|
||||||
const combined = []
|
const combined = [];
|
||||||
const processedAppIds = new Set()
|
const processedAppIds = new Set();
|
||||||
|
|
||||||
// Strategy: Maintain app positions as much as possible
|
// Strategy: Maintain app positions as much as possible
|
||||||
// 1. First pass: Add all running apps (both pinned and non-pinned) in their current order
|
// 1. First pass: Add all running apps (both pinned and non-pinned) in their current order
|
||||||
runningApps.forEach(toplevel => {
|
runningApps.forEach(toplevel => {
|
||||||
if (toplevel && toplevel.appId && !(Settings.data.dock.onlySameOutput && toplevel.screens && !toplevel.screens.includes(modelData))) {
|
if (toplevel && toplevel.appId && !(Settings.data.dock.onlySameOutput && toplevel.screens && !toplevel.screens.includes(modelData))) {
|
||||||
const isPinned = pinnedApps.includes(toplevel.appId)
|
const isPinned = pinnedApps.includes(toplevel.appId);
|
||||||
const appType = isPinned ? "pinned-running" : "running"
|
const appType = isPinned ? "pinned-running" : "running";
|
||||||
|
|
||||||
combined.push({
|
combined.push({
|
||||||
"type": appType,
|
"type": appType,
|
||||||
"toplevel": toplevel,
|
"toplevel": toplevel,
|
||||||
"appId": toplevel.appId,
|
"appId": toplevel.appId,
|
||||||
"title": toplevel.title
|
"title": toplevel.title
|
||||||
})
|
});
|
||||||
processedAppIds.add(toplevel.appId)
|
processedAppIds.add(toplevel.appId);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
// 2. Second pass: Add non-running pinned apps at the end
|
// 2. Second pass: Add non-running pinned apps at the end
|
||||||
pinnedApps.forEach(pinnedAppId => {
|
pinnedApps.forEach(pinnedAppId => {
|
||||||
@@ -130,11 +130,11 @@ Loader {
|
|||||||
"toplevel": null,
|
"toplevel": null,
|
||||||
"appId": pinnedAppId,
|
"appId": pinnedAppId,
|
||||||
"title": pinnedAppId
|
"title": pinnedAppId
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
dockApps = combined
|
dockApps = combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer to unload dock after hide animation completes
|
// Timer to unload dock after hide animation completes
|
||||||
@@ -143,7 +143,7 @@ Loader {
|
|||||||
interval: hideAnimationDuration + 50 // Add small buffer
|
interval: hideAnimationDuration + 50 // Add small buffer
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (hidden && autoHide) {
|
if (hidden && autoHide) {
|
||||||
dockLoaded = false
|
dockLoaded = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,14 +155,14 @@ Loader {
|
|||||||
onTriggered: {
|
onTriggered: {
|
||||||
// Force menuHovered to false if no menu is current or visible
|
// Force menuHovered to false if no menu is current or visible
|
||||||
if (!root.currentContextMenu || !root.currentContextMenu.visible) {
|
if (!root.currentContextMenu || !root.currentContextMenu.visible) {
|
||||||
menuHovered = false
|
menuHovered = false;
|
||||||
}
|
}
|
||||||
if (autoHide && !dockHovered && !anyAppHovered && !peekHovered && !menuHovered) {
|
if (autoHide && !dockHovered && !anyAppHovered && !peekHovered && !menuHovered) {
|
||||||
hidden = true
|
hidden = true;
|
||||||
unloadTimer.restart() // Start unload timer when hiding
|
unloadTimer.restart(); // Start unload timer when hiding
|
||||||
} else if (autoHide && !dockHovered && !peekHovered) {
|
} else if (autoHide && !dockHovered && !peekHovered) {
|
||||||
// Restart timer if menu is closing (handles race condition)
|
// Restart timer if menu is closing (handles race condition)
|
||||||
restart()
|
restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,9 +173,9 @@ Loader {
|
|||||||
interval: showDelay
|
interval: showDelay
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (autoHide) {
|
if (autoHide) {
|
||||||
dockLoaded = true // Load dock immediately
|
dockLoaded = true; // Load dock immediately
|
||||||
hidden = false // Then trigger show animation
|
hidden = false; // Then trigger show animation
|
||||||
unloadTimer.stop() // Cancel any pending unload
|
unloadTimer.stop(); // Cancel any pending unload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,14 +183,14 @@ Loader {
|
|||||||
// Watch for autoHide setting changes
|
// Watch for autoHide setting changes
|
||||||
onAutoHideChanged: {
|
onAutoHideChanged: {
|
||||||
if (!autoHide) {
|
if (!autoHide) {
|
||||||
hidden = false
|
hidden = false;
|
||||||
dockLoaded = true
|
dockLoaded = true;
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
showTimer.stop()
|
showTimer.stop();
|
||||||
unloadTimer.stop()
|
unloadTimer.stop();
|
||||||
} else {
|
} else {
|
||||||
hidden = true
|
hidden = true;
|
||||||
unloadTimer.restart() // Schedule unload after animation
|
unloadTimer.restart(); // Schedule unload after animation
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,16 +218,16 @@ Loader {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
peekHovered = true
|
peekHovered = true;
|
||||||
if (hidden) {
|
if (hidden) {
|
||||||
showTimer.start()
|
showTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
peekHovered = false
|
peekHovered = false;
|
||||||
if (!hidden && !dockHovered && !anyAppHovered && !menuHovered) {
|
if (!hidden && !dockHovered && !anyAppHovered && !menuHovered) {
|
||||||
hideTimer.restart()
|
hideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,9 +260,9 @@ Loader {
|
|||||||
margins.bottom: {
|
margins.bottom: {
|
||||||
switch (Settings.data.bar.position) {
|
switch (Settings.data.bar.position) {
|
||||||
case "bottom":
|
case "bottom":
|
||||||
return (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL + floatingMargin : floatingMargin)
|
return (Style.barHeight + Style.marginM) + (Settings.data.bar.floating ? Settings.data.bar.marginVertical * Style.marginXL + floatingMargin : floatingMargin);
|
||||||
default:
|
default:
|
||||||
return floatingMargin
|
return floatingMargin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,24 +313,24 @@ Loader {
|
|||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
dockHovered = true
|
dockHovered = true;
|
||||||
if (autoHide) {
|
if (autoHide) {
|
||||||
showTimer.stop()
|
showTimer.stop();
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
unloadTimer.stop() // Cancel unload if hovering
|
unloadTimer.stop(); // Cancel unload if hovering
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
dockHovered = false
|
dockHovered = false;
|
||||||
if (autoHide && !anyAppHovered && !peekHovered && !menuHovered) {
|
if (autoHide && !anyAppHovered && !peekHovered && !menuHovered) {
|
||||||
hideTimer.restart()
|
hideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
// Close any open context menu when clicking on the dock background
|
// Close any open context menu when clicking on the dock background
|
||||||
closeAllContextMenus()
|
closeAllContextMenus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,8 +342,8 @@ Loader {
|
|||||||
|
|
||||||
function getAppIcon(appData): string {
|
function getAppIcon(appData): string {
|
||||||
if (!appData || !appData.appId)
|
if (!appData || !appData.appId)
|
||||||
return ""
|
return "";
|
||||||
return ThemeIcons.iconForAppId(appData.appId?.toLowerCase())
|
return ThemeIcons.iconForAppId(appData.appId?.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -371,7 +371,7 @@ Loader {
|
|||||||
Connections {
|
Connections {
|
||||||
target: modelData?.toplevel
|
target: modelData?.toplevel
|
||||||
function onClosed() {
|
function onClosed() {
|
||||||
Qt.callLater(root.updateDockApps)
|
Qt.callLater(root.updateDockApps);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -452,9 +452,9 @@ Loader {
|
|||||||
onHoveredChanged: {
|
onHoveredChanged: {
|
||||||
// Only update menuHovered if this menu is current and visible
|
// Only update menuHovered if this menu is current and visible
|
||||||
if (root.currentContextMenu === contextMenu && contextMenu.visible) {
|
if (root.currentContextMenu === contextMenu && contextMenu.visible) {
|
||||||
menuHovered = hovered
|
menuHovered = hovered;
|
||||||
} else {
|
} else {
|
||||||
menuHovered = false
|
menuHovered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,26 +462,26 @@ Loader {
|
|||||||
target: contextMenu
|
target: contextMenu
|
||||||
function onRequestClose() {
|
function onRequestClose() {
|
||||||
// Clear current menu immediately to prevent hover updates
|
// Clear current menu immediately to prevent hover updates
|
||||||
root.currentContextMenu = null
|
root.currentContextMenu = null;
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
contextMenu.hide()
|
contextMenu.hide();
|
||||||
menuHovered = false
|
menuHovered = false;
|
||||||
anyAppHovered = false
|
anyAppHovered = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onAppClosed: root.updateDockApps // Force immediate dock update when app is closed
|
onAppClosed: root.updateDockApps // Force immediate dock update when app is closed
|
||||||
onVisibleChanged: {
|
onVisibleChanged: {
|
||||||
if (visible) {
|
if (visible) {
|
||||||
root.currentContextMenu = contextMenu
|
root.currentContextMenu = contextMenu;
|
||||||
anyAppHovered = false
|
anyAppHovered = false;
|
||||||
} else if (root.currentContextMenu === contextMenu) {
|
} else if (root.currentContextMenu === contextMenu) {
|
||||||
root.currentContextMenu = null
|
root.currentContextMenu = null;
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
menuHovered = false
|
menuHovered = false;
|
||||||
anyAppHovered = false
|
anyAppHovered = false;
|
||||||
// Restart hide timer after menu closes
|
// Restart hide timer after menu closes
|
||||||
if (autoHide && !dockHovered && !anyAppHovered && !peekHovered && !menuHovered) {
|
if (autoHide && !dockHovered && !anyAppHovered && !peekHovered && !menuHovered) {
|
||||||
hideTimer.restart()
|
hideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -496,28 +496,28 @@ Loader {
|
|||||||
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
anyAppHovered = true
|
anyAppHovered = true;
|
||||||
const appName = appButton.appTitle || appButton.appId || "Unknown"
|
const appName = appButton.appTitle || appButton.appId || "Unknown";
|
||||||
const tooltipText = appName.length > 40 ? appName.substring(0, 37) + "..." : appName
|
const tooltipText = appName.length > 40 ? appName.substring(0, 37) + "..." : appName;
|
||||||
if (!contextMenu.visible) {
|
if (!contextMenu.visible) {
|
||||||
TooltipService.show(Screen, appButton, tooltipText, "top")
|
TooltipService.show(Screen, appButton, tooltipText, "top");
|
||||||
}
|
}
|
||||||
if (autoHide) {
|
if (autoHide) {
|
||||||
showTimer.stop()
|
showTimer.stop();
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
unloadTimer.stop() // Cancel unload if hovering app
|
unloadTimer.stop(); // Cancel unload if hovering app
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
anyAppHovered = false
|
anyAppHovered = false;
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
// Clear menuHovered if no current menu or menu not visible
|
// Clear menuHovered if no current menu or menu not visible
|
||||||
if (!root.currentContextMenu || !root.currentContextMenu.visible) {
|
if (!root.currentContextMenu || !root.currentContextMenu.visible) {
|
||||||
menuHovered = false
|
menuHovered = false;
|
||||||
}
|
}
|
||||||
if (autoHide && !dockHovered && !peekHovered && !menuHovered) {
|
if (autoHide && !dockHovered && !peekHovered && !menuHovered) {
|
||||||
hideTimer.restart()
|
hideTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -525,33 +525,33 @@ Loader {
|
|||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
// If right-clicking on the same app with an open context menu, close it
|
// If right-clicking on the same app with an open context menu, close it
|
||||||
if (root.currentContextMenu === contextMenu && contextMenu.visible) {
|
if (root.currentContextMenu === contextMenu && contextMenu.visible) {
|
||||||
root.closeAllContextMenus()
|
root.closeAllContextMenus();
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
// Close any other existing context menu first
|
// Close any other existing context menu first
|
||||||
root.closeAllContextMenus()
|
root.closeAllContextMenus();
|
||||||
// Hide tooltip when showing context menu
|
// Hide tooltip when showing context menu
|
||||||
TooltipService.hideImmediately()
|
TooltipService.hideImmediately();
|
||||||
contextMenu.show(appButton, modelData.toplevel || modelData)
|
contextMenu.show(appButton, modelData.toplevel || modelData);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close any existing context menu for non-right-click actions
|
// Close any existing context menu for non-right-click actions
|
||||||
root.closeAllContextMenus()
|
root.closeAllContextMenus();
|
||||||
|
|
||||||
// Check if toplevel is still valid (not a stale reference)
|
// Check if toplevel is still valid (not a stale reference)
|
||||||
const isValidToplevel = modelData?.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(modelData.toplevel)
|
const isValidToplevel = modelData?.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(modelData.toplevel);
|
||||||
|
|
||||||
if (mouse.button === Qt.MiddleButton && isValidToplevel && modelData.toplevel.close) {
|
if (mouse.button === Qt.MiddleButton && isValidToplevel && modelData.toplevel.close) {
|
||||||
modelData.toplevel.close()
|
modelData.toplevel.close();
|
||||||
Qt.callLater(root.updateDockApps) // Force immediate dock update
|
Qt.callLater(root.updateDockApps); // Force immediate dock update
|
||||||
} else if (mouse.button === Qt.LeftButton) {
|
} else if (mouse.button === Qt.LeftButton) {
|
||||||
if (isValidToplevel && modelData.toplevel.activate) {
|
if (isValidToplevel && modelData.toplevel.activate) {
|
||||||
// Running app - activate it
|
// Running app - activate it
|
||||||
modelData.toplevel.activate()
|
modelData.toplevel.activate();
|
||||||
} else if (modelData?.appId) {
|
} else if (modelData?.appId) {
|
||||||
// Pinned app not running - launch it
|
// Pinned app not running - launch it
|
||||||
Quickshell.execDetached(["gtk-launch", modelData.appId])
|
Quickshell.execDetached(["gtk-launch", modelData.appId]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,21 +31,21 @@ PopupWindow {
|
|||||||
|
|
||||||
function initItems() {
|
function initItems() {
|
||||||
// Is this a running app?
|
// Is this a running app?
|
||||||
const isRunning = root.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(root.toplevel)
|
const isRunning = root.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(root.toplevel);
|
||||||
|
|
||||||
// Is this a pinned app?
|
// Is this a pinned app?
|
||||||
const isPinned = root.toplevel && root.isAppPinned(root.toplevel.appId)
|
const isPinned = root.toplevel && root.isAppPinned(root.toplevel.appId);
|
||||||
|
|
||||||
var next = []
|
var next = [];
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
// Focus item
|
// Focus item
|
||||||
next.push({
|
next.push({
|
||||||
"icon": "eye",
|
"icon": "eye",
|
||||||
"text": I18n.tr("dock.menu.focus"),
|
"text": I18n.tr("dock.menu.focus"),
|
||||||
"action": function () {
|
"action": function () {
|
||||||
handleFocus()
|
handleFocus();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pin/Unpin item
|
// Pin/Unpin item
|
||||||
@@ -53,9 +53,9 @@ PopupWindow {
|
|||||||
"icon": !isPinned ? "pin" : "unpin",
|
"icon": !isPinned ? "pin" : "unpin",
|
||||||
"text": !isPinned ? I18n.tr("dock.menu.pin") : I18n.tr("dock.menu.unpin"),
|
"text": !isPinned ? I18n.tr("dock.menu.pin") : I18n.tr("dock.menu.unpin"),
|
||||||
"action": function () {
|
"action": function () {
|
||||||
handlePin()
|
handlePin();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
if (isRunning) {
|
if (isRunning) {
|
||||||
// Close item
|
// Close item
|
||||||
@@ -63,55 +63,54 @@ PopupWindow {
|
|||||||
"icon": "close",
|
"icon": "close",
|
||||||
"text": I18n.tr("dock.menu.close"),
|
"text": I18n.tr("dock.menu.close"),
|
||||||
"action": function () {
|
"action": function () {
|
||||||
handleClose()
|
handleClose();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a menu entry for each app-specific action definied in its .desktop file
|
// Create a menu entry for each app-specific action definied in its .desktop file
|
||||||
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.byId) {
|
if (typeof DesktopEntries !== 'undefined' && DesktopEntries.byId) {
|
||||||
const entry = (DesktopEntries.heuristicLookup) ? DesktopEntries.heuristicLookup(appId) : DesktopEntries.byId(appId)
|
const entry = (DesktopEntries.heuristicLookup) ? DesktopEntries.heuristicLookup(appId) : DesktopEntries.byId(appId);
|
||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
entry.actions.forEach(function (action) {
|
entry.actions.forEach(function (action) {
|
||||||
next.push({
|
next.push({
|
||||||
"icon": "",
|
"icon": "",
|
||||||
"text": action.name,
|
"text": action.name,
|
||||||
"action": function () {
|
"action": function () {
|
||||||
action.execute()
|
action.execute();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root.items = next
|
root.items = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper functions for pin/unpin functionality
|
// Helper functions for pin/unpin functionality
|
||||||
function isAppPinned(appId) {
|
function isAppPinned(appId) {
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return false
|
return false;
|
||||||
const pinnedApps = Settings.data.dock.pinnedApps || []
|
const pinnedApps = Settings.data.dock.pinnedApps || [];
|
||||||
return pinnedApps.includes(appId)
|
return pinnedApps.includes(appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleAppPin(appId) {
|
function toggleAppPin(appId) {
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return
|
return;
|
||||||
|
let pinnedApps = (Settings.data.dock.pinnedApps || []).slice(); // Create a copy
|
||||||
let pinnedApps = (Settings.data.dock.pinnedApps || []).slice() // Create a copy
|
const isPinned = pinnedApps.includes(appId);
|
||||||
const isPinned = pinnedApps.includes(appId)
|
|
||||||
|
|
||||||
if (isPinned) {
|
if (isPinned) {
|
||||||
// Unpin: remove from array
|
// Unpin: remove from array
|
||||||
pinnedApps = pinnedApps.filter(id => id !== appId)
|
pinnedApps = pinnedApps.filter(id => id !== appId);
|
||||||
} else {
|
} else {
|
||||||
// Pin: add to array
|
// Pin: add to array
|
||||||
pinnedApps.push(appId)
|
pinnedApps.push(appId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the settings
|
// Update the settings
|
||||||
Settings.data.dock.pinnedApps = pinnedApps
|
Settings.data.dock.pinnedApps = pinnedApps;
|
||||||
}
|
}
|
||||||
|
|
||||||
anchor.item: anchorItem
|
anchor.item: anchorItem
|
||||||
@@ -120,62 +119,62 @@ PopupWindow {
|
|||||||
|
|
||||||
function show(item, toplevelData) {
|
function show(item, toplevelData) {
|
||||||
if (!item) {
|
if (!item) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
anchorItem = item
|
anchorItem = item;
|
||||||
toplevel = toplevelData
|
toplevel = toplevelData;
|
||||||
initItems()
|
initItems();
|
||||||
visible = true
|
visible = true;
|
||||||
canAutoClose = false
|
canAutoClose = false;
|
||||||
gracePeriodTimer.restart()
|
gracePeriodTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
visible = false
|
visible = false;
|
||||||
root.items.length = 0
|
root.items.length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to determine which menu item is under the mouse
|
// Helper function to determine which menu item is under the mouse
|
||||||
function getHoveredItem(mouseY) {
|
function getHoveredItem(mouseY) {
|
||||||
const itemHeight = 32
|
const itemHeight = 32;
|
||||||
const startY = Style.marginM
|
const startY = Style.marginM;
|
||||||
const relativeY = mouseY - startY
|
const relativeY = mouseY - startY;
|
||||||
|
|
||||||
if (relativeY < 0)
|
if (relativeY < 0)
|
||||||
return -1
|
return -1;
|
||||||
|
|
||||||
const itemIndex = Math.floor(relativeY / itemHeight)
|
const itemIndex = Math.floor(relativeY / itemHeight);
|
||||||
return itemIndex >= 0 && itemIndex < root.items.length ? itemIndex : -1
|
return itemIndex >= 0 && itemIndex < root.items.length ? itemIndex : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFocus() {
|
function handleFocus() {
|
||||||
if (root.toplevel?.activate) {
|
if (root.toplevel?.activate) {
|
||||||
root.toplevel.activate()
|
root.toplevel.activate();
|
||||||
}
|
}
|
||||||
root.requestClose()
|
root.requestClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handlePin() {
|
function handlePin() {
|
||||||
if (root.toplevel?.appId) {
|
if (root.toplevel?.appId) {
|
||||||
root.toggleAppPin(root.toplevel.appId)
|
root.toggleAppPin(root.toplevel.appId);
|
||||||
}
|
}
|
||||||
root.requestClose()
|
root.requestClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleClose() {
|
function handleClose() {
|
||||||
// Check if toplevel is still valid before trying to close it
|
// Check if toplevel is still valid before trying to close it
|
||||||
const isValidToplevel = root.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(root.toplevel)
|
const isValidToplevel = root.toplevel && ToplevelManager && ToplevelManager.toplevels.values.includes(root.toplevel);
|
||||||
|
|
||||||
if (isValidToplevel && root.toplevel.close) {
|
if (isValidToplevel && root.toplevel.close) {
|
||||||
root.toplevel.close()
|
root.toplevel.close();
|
||||||
// Trigger immediate dock update callback if provided
|
// Trigger immediate dock update callback if provided
|
||||||
if (root.onAppClosed && typeof root.onAppClosed === "function") {
|
if (root.onAppClosed && typeof root.onAppClosed === "function") {
|
||||||
Qt.callLater(root.onAppClosed)
|
Qt.callLater(root.onAppClosed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
root.hide()
|
root.hide();
|
||||||
root.requestClose()
|
root.requestClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Short delay to ignore spurious events
|
// Short delay to ignore spurious events
|
||||||
@@ -184,9 +183,9 @@ PopupWindow {
|
|||||||
interval: 1500
|
interval: 1500
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.canAutoClose = true
|
root.canAutoClose = true;
|
||||||
if (!menuMouseArea.containsMouse) {
|
if (!menuMouseArea.containsMouse) {
|
||||||
closeTimer.start()
|
closeTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -197,7 +196,7 @@ PopupWindow {
|
|||||||
repeat: false
|
repeat: false
|
||||||
running: false
|
running: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
root.hide()
|
root.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,25 +215,25 @@ PopupWindow {
|
|||||||
cursorShape: root.hoveredItem >= 0 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: root.hoveredItem >= 0 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
closeTimer.stop()
|
closeTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
root.hoveredItem = -1
|
root.hoveredItem = -1;
|
||||||
if (root.canAutoClose) {
|
if (root.canAutoClose) {
|
||||||
// Only close if grace period has passed
|
// Only close if grace period has passed
|
||||||
closeTimer.start()
|
closeTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onPositionChanged: mouse => {
|
onPositionChanged: mouse => {
|
||||||
root.hoveredItem = root.getHoveredItem(mouse.y)
|
root.hoveredItem = root.getHoveredItem(mouse.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
const clickedItem = root.getHoveredItem(mouse.y)
|
const clickedItem = root.getHoveredItem(mouse.y);
|
||||||
if (clickedItem >= 0) {
|
if (clickedItem >= 0) {
|
||||||
root.items[clickedItem].action.call()
|
root.items[clickedItem].action.call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,24 +18,24 @@ Scope {
|
|||||||
|
|
||||||
onCurrentTextChanged: {
|
onCurrentTextChanged: {
|
||||||
if (currentText !== "") {
|
if (currentText !== "") {
|
||||||
showFailure = false
|
showFailure = false;
|
||||||
errorMessage = ""
|
errorMessage = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryUnlock() {
|
function tryUnlock() {
|
||||||
if (!pamAvailable) {
|
if (!pamAvailable) {
|
||||||
errorMessage = "PAM not available"
|
errorMessage = "PAM not available";
|
||||||
showFailure = true
|
showFailure = true;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
root.unlockInProgress = true
|
root.unlockInProgress = true;
|
||||||
errorMessage = ""
|
errorMessage = "";
|
||||||
showFailure = false
|
showFailure = false;
|
||||||
|
|
||||||
Logger.i("LockContext", "Starting PAM authentication for user:", pam.user)
|
Logger.i("LockContext", "Starting PAM authentication for user:", pam.user);
|
||||||
pam.start()
|
pam.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
PamContext {
|
PamContext {
|
||||||
@@ -44,48 +44,48 @@ Scope {
|
|||||||
user: HostService.username
|
user: HostService.username
|
||||||
|
|
||||||
onPamMessage: {
|
onPamMessage: {
|
||||||
Logger.i("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:", responseRequired)
|
Logger.i("LockContext", "PAM message:", message, "isError:", messageIsError, "responseRequired:", responseRequired);
|
||||||
|
|
||||||
if (messageIsError) {
|
if (messageIsError) {
|
||||||
errorMessage = message
|
errorMessage = message;
|
||||||
} else {
|
} else {
|
||||||
infoMessage = message
|
infoMessage = message;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (responseRequired) {
|
if (responseRequired) {
|
||||||
Logger.i("LockContext", "Responding to PAM with password")
|
Logger.i("LockContext", "Responding to PAM with password");
|
||||||
respond(root.currentText)
|
respond(root.currentText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onResponseRequiredChanged: {
|
onResponseRequiredChanged: {
|
||||||
Logger.i("LockContext", "Response required changed:", responseRequired)
|
Logger.i("LockContext", "Response required changed:", responseRequired);
|
||||||
if (responseRequired && root.unlockInProgress) {
|
if (responseRequired && root.unlockInProgress) {
|
||||||
Logger.i("LockContext", "Automatically responding to PAM")
|
Logger.i("LockContext", "Automatically responding to PAM");
|
||||||
respond(root.currentText)
|
respond(root.currentText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onCompleted: result => {
|
onCompleted: result => {
|
||||||
Logger.i("LockContext", "PAM completed with result:", result)
|
Logger.i("LockContext", "PAM completed with result:", result);
|
||||||
if (result === PamResult.Success) {
|
if (result === PamResult.Success) {
|
||||||
Logger.i("LockContext", "Authentication successful")
|
Logger.i("LockContext", "Authentication successful");
|
||||||
root.unlocked()
|
root.unlocked();
|
||||||
} else {
|
} else {
|
||||||
Logger.i("LockContext", "Authentication failed")
|
Logger.i("LockContext", "Authentication failed");
|
||||||
errorMessage = "Authentication failed"
|
errorMessage = "Authentication failed";
|
||||||
showFailure = true
|
showFailure = true;
|
||||||
root.failed()
|
root.failed();
|
||||||
}
|
}
|
||||||
root.unlockInProgress = false
|
root.unlockInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onError: {
|
onError: {
|
||||||
Logger.i("LockContext", "PAM error:", error, "message:", message)
|
Logger.i("LockContext", "PAM error:", error, "message:", message);
|
||||||
errorMessage = message || "Authentication error"
|
errorMessage = message || "Authentication error";
|
||||||
showFailure = true
|
showFailure = true;
|
||||||
root.unlockInProgress = false
|
root.unlockInProgress = false;
|
||||||
root.failed()
|
root.failed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,21 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Io
|
||||||
import Quickshell.Services.Pam
|
import Quickshell.Services.Pam
|
||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
import Quickshell.Io
|
import Quickshell.Wayland
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Services.Compositor
|
||||||
import qs.Services.Hardware
|
import qs.Services.Hardware
|
||||||
import qs.Services.Keyboard
|
import qs.Services.Keyboard
|
||||||
import qs.Services.Location
|
import qs.Services.Location
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
import qs.Services.Compositor
|
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Widgets.AudioSpectrum
|
import qs.Widgets.AudioSpectrum
|
||||||
|
|
||||||
@@ -31,14 +31,14 @@ Loader {
|
|||||||
interval: 250
|
interval: 250
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
lockScreen.active = false
|
lockScreen.active = false;
|
||||||
// Reset the deprecation flag when unlocking
|
// Reset the deprecation flag when unlocking
|
||||||
lockScreen.triggeredViaDeprecatedCall = false
|
lockScreen.triggeredViaDeprecatedCall = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function scheduleUnloadAfterUnlock() {
|
function scheduleUnloadAfterUnlock() {
|
||||||
unloadAfterUnlockTimer.start()
|
unloadAfterUnlockTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceComponent: Component {
|
sourceComponent: Component {
|
||||||
@@ -48,12 +48,12 @@ Loader {
|
|||||||
LockContext {
|
LockContext {
|
||||||
id: lockContext
|
id: lockContext
|
||||||
onUnlocked: {
|
onUnlocked: {
|
||||||
lockSession.locked = false
|
lockSession.locked = false;
|
||||||
lockScreen.scheduleUnloadAfterUnlock()
|
lockScreen.scheduleUnloadAfterUnlock();
|
||||||
lockContext.currentText = ""
|
lockContext.currentText = "";
|
||||||
}
|
}
|
||||||
onFailed: {
|
onFailed: {
|
||||||
lockContext.currentText = ""
|
lockContext.currentText = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,21 +130,20 @@ Loader {
|
|||||||
smooth: false
|
smooth: false
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
const ctx = getContext("2d")
|
const ctx = getContext("2d");
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return
|
return;
|
||||||
|
ctx.reset();
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.reset()
|
ctx.fillStyle = parent.cornerColor;
|
||||||
ctx.clearRect(0, 0, width, height)
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.fillStyle = parent.cornerColor
|
ctx.globalCompositeOperation = "destination-out";
|
||||||
ctx.fillRect(0, 0, width, height)
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.beginPath();
|
||||||
ctx.globalCompositeOperation = "destination-out"
|
ctx.arc(width, height, parent.cornerRadius, 0, 2 * Math.PI);
|
||||||
ctx.fillStyle = "#ffffff"
|
ctx.fill();
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(width, height, parent.cornerRadius, 0, 2 * Math.PI)
|
|
||||||
ctx.fill()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onWidthChanged: if (available)
|
onWidthChanged: if (available)
|
||||||
@@ -164,21 +163,20 @@ Loader {
|
|||||||
smooth: true
|
smooth: true
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
const ctx = getContext("2d")
|
const ctx = getContext("2d");
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return
|
return;
|
||||||
|
ctx.reset();
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.reset()
|
ctx.fillStyle = parent.cornerColor;
|
||||||
ctx.clearRect(0, 0, width, height)
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.fillStyle = parent.cornerColor
|
ctx.globalCompositeOperation = "destination-out";
|
||||||
ctx.fillRect(0, 0, width, height)
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.beginPath();
|
||||||
ctx.globalCompositeOperation = "destination-out"
|
ctx.arc(0, height, parent.cornerRadius, 0, 2 * Math.PI);
|
||||||
ctx.fillStyle = "#ffffff"
|
ctx.fill();
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(0, height, parent.cornerRadius, 0, 2 * Math.PI)
|
|
||||||
ctx.fill()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onWidthChanged: if (available)
|
onWidthChanged: if (available)
|
||||||
@@ -198,21 +196,20 @@ Loader {
|
|||||||
smooth: true
|
smooth: true
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
const ctx = getContext("2d")
|
const ctx = getContext("2d");
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return
|
return;
|
||||||
|
ctx.reset();
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.reset()
|
ctx.fillStyle = parent.cornerColor;
|
||||||
ctx.clearRect(0, 0, width, height)
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.fillStyle = parent.cornerColor
|
ctx.globalCompositeOperation = "destination-out";
|
||||||
ctx.fillRect(0, 0, width, height)
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.beginPath();
|
||||||
ctx.globalCompositeOperation = "destination-out"
|
ctx.arc(width, 0, parent.cornerRadius, 0, 2 * Math.PI);
|
||||||
ctx.fillStyle = "#ffffff"
|
ctx.fill();
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(width, 0, parent.cornerRadius, 0, 2 * Math.PI)
|
|
||||||
ctx.fill()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onWidthChanged: if (available)
|
onWidthChanged: if (available)
|
||||||
@@ -232,21 +229,20 @@ Loader {
|
|||||||
smooth: true
|
smooth: true
|
||||||
|
|
||||||
onPaint: {
|
onPaint: {
|
||||||
const ctx = getContext("2d")
|
const ctx = getContext("2d");
|
||||||
if (!ctx)
|
if (!ctx)
|
||||||
return
|
return;
|
||||||
|
ctx.reset();
|
||||||
|
ctx.clearRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.reset()
|
ctx.fillStyle = parent.cornerColor;
|
||||||
ctx.clearRect(0, 0, width, height)
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
ctx.fillStyle = parent.cornerColor
|
ctx.globalCompositeOperation = "destination-out";
|
||||||
ctx.fillRect(0, 0, width, height)
|
ctx.fillStyle = "#ffffff";
|
||||||
|
ctx.beginPath();
|
||||||
ctx.globalCompositeOperation = "destination-out"
|
ctx.arc(0, 0, parent.cornerRadius, 0, 2 * Math.PI);
|
||||||
ctx.fillStyle = "#ffffff"
|
ctx.fill();
|
||||||
ctx.beginPath()
|
|
||||||
ctx.arc(0, 0, parent.cornerRadius, 0, 2 * Math.PI)
|
|
||||||
ctx.fill()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onWidthChanged: if (available)
|
onWidthChanged: if (available)
|
||||||
@@ -347,7 +343,7 @@ Loader {
|
|||||||
// Date below
|
// Date below
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
var lang = I18n.locale.name.split("_")[0]
|
var lang = I18n.locale.name.split("_")[0];
|
||||||
var formats = {
|
var formats = {
|
||||||
"de": "dddd, d. MMMM",
|
"de": "dddd, d. MMMM",
|
||||||
"es": "dddd, d 'de' MMMM",
|
"es": "dddd, d 'de' MMMM",
|
||||||
@@ -356,8 +352,8 @@ Loader {
|
|||||||
"zh": "yyyy年M月d日 dddd",
|
"zh": "yyyy年M月d日 dddd",
|
||||||
"uk": "dddd, d MMMM",
|
"uk": "dddd, d MMMM",
|
||||||
"tr": "dddd, d MMMM"
|
"tr": "dddd, d MMMM"
|
||||||
}
|
};
|
||||||
return I18n.locale.toString(Time.now, formats[lang] || "dddd, MMMM d")
|
return I18n.locale.toString(Time.now, formats[lang] || "dddd, MMMM d");
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeXL
|
pointSize: Style.fontSizeXL
|
||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
@@ -487,15 +483,15 @@ Loader {
|
|||||||
// Compact status indicators container (compact mode only)
|
// Compact status indicators container (compact mode only)
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: {
|
width: {
|
||||||
var hasBattery = UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.isPresent
|
var hasBattery = UPower.displayDevice && UPower.displayDevice.ready && UPower.displayDevice.isPresent;
|
||||||
var hasKeyboard = keyboardLayout.currentLayout !== "Unknown"
|
var hasKeyboard = keyboardLayout.currentLayout !== "Unknown";
|
||||||
|
|
||||||
if (hasBattery && hasKeyboard) {
|
if (hasBattery && hasKeyboard) {
|
||||||
return 200
|
return 200;
|
||||||
} else if (hasBattery || hasKeyboard) {
|
} else if (hasBattery || hasKeyboard) {
|
||||||
return 120
|
return 120;
|
||||||
} else {
|
} else {
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
height: 40
|
height: 40
|
||||||
@@ -708,14 +704,14 @@ Loader {
|
|||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
var temp = LocationService.data.weather.current_weather.temperature
|
var temp = LocationService.data.weather.current_weather.temperature;
|
||||||
var suffix = "C"
|
var suffix = "C";
|
||||||
if (Settings.data.location.useFahrenheit) {
|
if (Settings.data.location.useFahrenheit) {
|
||||||
temp = LocationService.celsiusToFahrenheit(temp)
|
temp = LocationService.celsiusToFahrenheit(temp);
|
||||||
suffix = "F"
|
suffix = "F";
|
||||||
}
|
}
|
||||||
temp = Math.round(temp)
|
temp = Math.round(temp);
|
||||||
return temp + "°" + suffix
|
return temp + "°" + suffix;
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeXL
|
pointSize: Style.fontSizeXL
|
||||||
font.weight: Style.fontWeightBold
|
font.weight: Style.fontWeightBold
|
||||||
@@ -724,14 +720,14 @@ Loader {
|
|||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
var wind = LocationService.data.weather.current_weather.windspeed
|
var wind = LocationService.data.weather.current_weather.windspeed;
|
||||||
var unit = "km/h"
|
var unit = "km/h";
|
||||||
if (Settings.data.location.useFahrenheit) {
|
if (Settings.data.location.useFahrenheit) {
|
||||||
wind = wind * 0.621371 // Convert km/h to mph
|
wind = wind * 0.621371; // Convert km/h to mph
|
||||||
unit = "mph"
|
unit = "mph";
|
||||||
}
|
}
|
||||||
wind = Math.round(wind)
|
wind = Math.round(wind);
|
||||||
return wind + " " + unit
|
return wind + " " + unit;
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeM
|
pointSize: Style.fontSizeM
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
@@ -773,8 +769,8 @@ Loader {
|
|||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
|
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"));
|
||||||
return I18n.locale.toString(weatherDate, "ddd")
|
return I18n.locale.toString(weatherDate, "ddd");
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeM
|
pointSize: Style.fontSizeM
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
@@ -791,15 +787,15 @@ Loader {
|
|||||||
|
|
||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
var max = LocationService.data.weather.daily.temperature_2m_max[index]
|
var max = LocationService.data.weather.daily.temperature_2m_max[index];
|
||||||
var min = LocationService.data.weather.daily.temperature_2m_min[index]
|
var min = LocationService.data.weather.daily.temperature_2m_min[index];
|
||||||
if (Settings.data.location.useFahrenheit) {
|
if (Settings.data.location.useFahrenheit) {
|
||||||
max = LocationService.celsiusToFahrenheit(max)
|
max = LocationService.celsiusToFahrenheit(max);
|
||||||
min = LocationService.celsiusToFahrenheit(min)
|
min = LocationService.celsiusToFahrenheit(min);
|
||||||
}
|
}
|
||||||
max = Math.round(max)
|
max = Math.round(max);
|
||||||
min = Math.round(min)
|
min = Math.round(min);
|
||||||
return max + "°/" + min + "°"
|
return max + "°/" + min + "°";
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeM
|
pointSize: Style.fontSizeM
|
||||||
font.weight: Style.fontWeightMedium
|
font.weight: Style.fontWeightMedium
|
||||||
@@ -916,7 +912,7 @@ Loader {
|
|||||||
|
|
||||||
Keys.onPressed: function (event) {
|
Keys.onPressed: function (event) {
|
||||||
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||||
lockContext.tryUnlock()
|
lockContext.tryUnlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import Quickshell
|
|||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Modules.MainScreen
|
import qs.Modules.MainScreen
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
// MainScreen for each screen (manages bar + all panels)
|
// MainScreen for each screen (manages bar + all panels)
|
||||||
@@ -16,10 +16,10 @@ Variants {
|
|||||||
|
|
||||||
property bool shouldBeActive: {
|
property bool shouldBeActive: {
|
||||||
if (!modelData || !modelData.name) {
|
if (!modelData || !modelData.name) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
Logger.d("Shell", "MainScreen activated for", modelData?.name)
|
Logger.d("Shell", "MainScreen activated for", modelData?.name);
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
property bool windowLoaded: false
|
property bool windowLoaded: false
|
||||||
@@ -33,7 +33,7 @@ Variants {
|
|||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
// Signal that window is loaded so exclusion zone can be created
|
// Signal that window is loaded so exclusion zone can be created
|
||||||
parent.windowLoaded = true
|
parent.windowLoaded = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceComponent: MainScreen {
|
sourceComponent: MainScreen {
|
||||||
@@ -45,11 +45,11 @@ Variants {
|
|||||||
Loader {
|
Loader {
|
||||||
active: {
|
active: {
|
||||||
if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible)
|
if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible)
|
||||||
return false
|
return false;
|
||||||
|
|
||||||
// Check if bar is configured for this screen
|
// Check if bar is configured for this screen
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
return monitors.length === 0 || monitors.includes(modelData?.name)
|
return monitors.length === 0 || monitors.includes(modelData?.name);
|
||||||
}
|
}
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
@@ -58,7 +58,7 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
Logger.d("Shell", "BarContentWindow created for", modelData?.name)
|
Logger.d("Shell", "BarContentWindow created for", modelData?.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,11 +67,11 @@ Variants {
|
|||||||
Loader {
|
Loader {
|
||||||
active: {
|
active: {
|
||||||
if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible)
|
if (!parent.windowLoaded || !parent.shouldBeActive || !BarService.isVisible)
|
||||||
return false
|
return false;
|
||||||
|
|
||||||
// Check if bar is configured for this screen
|
// Check if bar is configured for this screen
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
return monitors.length === 0 || monitors.includes(modelData?.name)
|
return monitors.length === 0 || monitors.includes(modelData?.name);
|
||||||
}
|
}
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
Logger.d("Shell", "BarExclusionZone created for", modelData?.name)
|
Logger.d("Shell", "BarExclusionZone created for", modelData?.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +95,7 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
Logger.d("Shell", "TrayMenuWindow created for", modelData?.name)
|
Logger.d("Shell", "TrayMenuWindow created for", modelData?.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,17 +3,16 @@ import QtQuick.Shapes
|
|||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AllBackgrounds - Unified Shape container for all bar and panel backgrounds
|
* AllBackgrounds - Unified Shape container for all bar and panel backgrounds
|
||||||
*
|
*
|
||||||
* Unified shadow system. This component contains a single Shape
|
* Unified shadow system. This component contains a single Shape
|
||||||
* with multiple ShapePath children (one for bar, one for each panel type).
|
* with multiple ShapePath children (one for bar, one for each panel type).
|
||||||
*
|
*
|
||||||
* Benefits:
|
* Benefits:
|
||||||
* - Single GPU-accelerated rendering pass for all backgrounds
|
* - Single GPU-accelerated rendering pass for all backgrounds
|
||||||
* - Unified shadow system (one MultiEffect for everything)
|
* - Unified shadow system (one MultiEffect for everything)
|
||||||
*/
|
*/
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -46,15 +45,14 @@ Item {
|
|||||||
enabled: false // Disable mouse input on the Shape itself
|
enabled: false // Disable mouse input on the Shape itself
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.d("AllBackgrounds", "AllBackgrounds initialized")
|
Logger.d("AllBackgrounds", "AllBackgrounds initialized");
|
||||||
Logger.d("AllBackgrounds", " bar:", root.bar)
|
Logger.d("AllBackgrounds", " bar:", root.bar);
|
||||||
Logger.d("AllBackgrounds", " windowRoot:", root.windowRoot)
|
Logger.d("AllBackgrounds", " windowRoot:", root.windowRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bar
|
* Bar
|
||||||
*/
|
*/
|
||||||
BarBackground {
|
BarBackground {
|
||||||
bar: root.bar
|
bar: root.bar
|
||||||
shapeContainer: backgroundsShape
|
shapeContainer: backgroundsShape
|
||||||
@@ -62,10 +60,9 @@ Item {
|
|||||||
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity)
|
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Panels
|
* Panels
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Audio
|
// Audio
|
||||||
PanelBackground {
|
PanelBackground {
|
||||||
|
|||||||
@@ -1,22 +1,21 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Modules.MainScreen.Backgrounds
|
import qs.Modules.MainScreen.Backgrounds
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BarBackground - ShapePath component for rendering the bar background
|
* BarBackground - ShapePath component for rendering the bar background
|
||||||
*
|
*
|
||||||
* Unified shadow system. This component is a ShapePath that will be
|
* Unified shadow system. This component is a ShapePath that will be
|
||||||
* a child of the unified AllBackgrounds Shape container.
|
* a child of the unified AllBackgrounds Shape container.
|
||||||
*
|
*
|
||||||
* Uses 4-state per-corner system for flexible corner rendering:
|
* Uses 4-state per-corner system for flexible corner rendering:
|
||||||
* - State -1: No radius (flat/square corner)
|
* - State -1: No radius (flat/square corner)
|
||||||
* - State 0: Normal (inner curve)
|
* - State 0: Normal (inner curve)
|
||||||
* - State 1: Horizontal inversion (outer curve on X-axis)
|
* - State 1: Horizontal inversion (outer curve on X-axis)
|
||||||
* - State 2: Vertical inversion (outer curve on Y-axis)
|
* - State 2: Vertical inversion (outer curve on Y-axis)
|
||||||
*/
|
*/
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -35,15 +34,15 @@ ShapePath {
|
|||||||
readonly property bool shouldShow: {
|
readonly property bool shouldShow: {
|
||||||
// Check global bar visibility
|
// Check global bar visibility
|
||||||
if (!BarService.isVisible)
|
if (!BarService.isVisible)
|
||||||
return false
|
return false;
|
||||||
|
|
||||||
// Check screen-specific configuration
|
// Check screen-specific configuration
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
var screenName = windowRoot?.screen?.name || ""
|
var screenName = windowRoot?.screen?.name || "";
|
||||||
|
|
||||||
// If no monitors specified, show on all screens
|
// If no monitors specified, show on all screens
|
||||||
// If monitors specified, only show if this screen is in the list
|
// If monitors specified, only show if this screen is in the list
|
||||||
return monitors.length === 0 || monitors.includes(screenName)
|
return monitors.length === 0 || monitors.includes(screenName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Corner radius (from Style)
|
// Corner radius (from Style)
|
||||||
@@ -65,9 +64,9 @@ ShapePath {
|
|||||||
function getCornerRadius(cornerState) {
|
function getCornerRadius(cornerState) {
|
||||||
// State -1 = no radius (flat corner)
|
// State -1 = no radius (flat corner)
|
||||||
if (cornerState === -1)
|
if (cornerState === -1)
|
||||||
return 0
|
return 0;
|
||||||
// All other states use effectiveRadius
|
// All other states use effectiveRadius
|
||||||
return effectiveRadius
|
return effectiveRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-corner multipliers and radii based on bar's corner states (handle null bar)
|
// Per-corner multipliers and radii based on bar's corner states (handle null bar)
|
||||||
|
|||||||
@@ -3,22 +3,21 @@ import QtQuick.Shapes
|
|||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Modules.MainScreen.Backgrounds
|
import qs.Modules.MainScreen.Backgrounds
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PanelBackground - ShapePath component for rendering a single background
|
* PanelBackground - ShapePath component for rendering a single background
|
||||||
*
|
*
|
||||||
* Unified shadow system. This component is a ShapePath that will
|
* Unified shadow system. This component is a ShapePath that will
|
||||||
* be a child of the unified AllBackgrounds Shape container.
|
* be a child of the unified AllBackgrounds Shape container.
|
||||||
*
|
*
|
||||||
* Reads positioning and geometry from PanelPlaceholder (via panel.panelItem).
|
* Reads positioning and geometry from PanelPlaceholder (via panel.panelItem).
|
||||||
* The actual panel content lives in a separate SmartPanelWindow.
|
* The actual panel content lives in a separate SmartPanelWindow.
|
||||||
*
|
*
|
||||||
* Uses 4-state per-corner system for flexible corner rendering:
|
* Uses 4-state per-corner system for flexible corner rendering:
|
||||||
* - State -1: No radius (flat/square corner)
|
* - State -1: No radius (flat/square corner)
|
||||||
* - State 0: Normal (inner curve)
|
* - State 0: Normal (inner curve)
|
||||||
* - State 1: Horizontal inversion (outer curve on X-axis)
|
* - State 1: Horizontal inversion (outer curve on X-axis)
|
||||||
* - State 2: Vertical inversion (outer curve on Y-axis)
|
* - State 2: Vertical inversion (outer curve on Y-axis)
|
||||||
*/
|
*/
|
||||||
ShapePath {
|
ShapePath {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -51,9 +50,9 @@ ShapePath {
|
|||||||
function getCornerRadius(cornerState) {
|
function getCornerRadius(cornerState) {
|
||||||
// State -1 = no radius (flat corner)
|
// State -1 = no radius (flat corner)
|
||||||
if (cornerState === -1)
|
if (cornerState === -1)
|
||||||
return 0
|
return 0;
|
||||||
// All other states use effectiveRadius
|
// All other states use effectiveRadius
|
||||||
return effectiveRadius
|
return effectiveRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per-corner multipliers and radii based on panelBg's corner states
|
// Per-corner multipliers and radii based on panelBg's corner states
|
||||||
|
|||||||
@@ -4,78 +4,71 @@ import QtQuick
|
|||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ShapeCornerHelper - Utility singleton for shape corner calculations
|
* ShapeCornerHelper - Utility singleton for shape corner calculations
|
||||||
*
|
*
|
||||||
* Uses 4-state per-corner system for flexible corner rendering:
|
* Uses 4-state per-corner system for flexible corner rendering:
|
||||||
* - State -1: No radius (flat/square corner)
|
* - State -1: No radius (flat/square corner)
|
||||||
* - State 0: Normal (inner curve)
|
* - State 0: Normal (inner curve)
|
||||||
* - State 1: Horizontal inversion (outer curve on X-axis)
|
* - State 1: Horizontal inversion (outer curve on X-axis)
|
||||||
* - State 2: Vertical inversion (outer curve on Y-axis)
|
* - State 2: Vertical inversion (outer curve on Y-axis)
|
||||||
*
|
*
|
||||||
* The key technique: Using PathArc direction control (Clockwise vs Counterclockwise)
|
* The key technique: Using PathArc direction control (Clockwise vs Counterclockwise)
|
||||||
* combined with multipliers to create both inner and outer corner curves.
|
* combined with multipliers to create both inner and outer corner curves.
|
||||||
*/
|
*/
|
||||||
Singleton {
|
Singleton {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get X-axis multiplier for a corner state
|
* Get X-axis multiplier for a corner state
|
||||||
* State 1 (horizontal invert) returns -1, others return 1
|
* State 1 (horizontal invert) returns -1, others return 1
|
||||||
*/
|
*/
|
||||||
function getMultX(cornerState) {
|
function getMultX(cornerState) {
|
||||||
return cornerState === 1 ? -1 : 1
|
return cornerState === 1 ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Y-axis multiplier for a corner state
|
* Get Y-axis multiplier for a corner state
|
||||||
* State 2 (vertical invert) returns -1, others return 1
|
* State 2 (vertical invert) returns -1, others return 1
|
||||||
*/
|
*/
|
||||||
function getMultY(cornerState) {
|
function getMultY(cornerState) {
|
||||||
return cornerState === 2 ? -1 : 1
|
return cornerState === 2 ? -1 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get PathArc direction for a corner based on its multipliers
|
* Get PathArc direction for a corner based on its multipliers
|
||||||
* Uses XOR logic: if X inverted differs from Y inverted, use Counterclockwise
|
* Uses XOR logic: if X inverted differs from Y inverted, use Counterclockwise
|
||||||
* This creates the outer curve effect for inverted corners
|
* This creates the outer curve effect for inverted corners
|
||||||
*/
|
*/
|
||||||
function getArcDirection(multX, multY) {
|
function getArcDirection(multX, multY) {
|
||||||
return ((multX < 0) !== (multY < 0)) ? PathArc.Counterclockwise : PathArc.Clockwise
|
return ((multX < 0) !== (multY < 0)) ? PathArc.Counterclockwise : PathArc.Clockwise;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience function to get arc direction directly from corner state
|
* Convenience function to get arc direction directly from corner state
|
||||||
*/
|
*/
|
||||||
function getArcDirectionFromState(cornerState) {
|
function getArcDirectionFromState(cornerState) {
|
||||||
const multX = getMultX(cornerState)
|
const multX = getMultX(cornerState);
|
||||||
const multY = getMultY(cornerState)
|
const multY = getMultY(cornerState);
|
||||||
return getArcDirection(multX, multY)
|
return getArcDirection(multX, multY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the "flattening" radius when shape dimensions are too small
|
* Get the "flattening" radius when shape dimensions are too small
|
||||||
* Prevents visual artifacts when radius exceeds dimensions
|
* Prevents visual artifacts when radius exceeds dimensions
|
||||||
*/
|
*/
|
||||||
function getFlattenedRadius(dimension, requestedRadius) {
|
function getFlattenedRadius(dimension, requestedRadius) {
|
||||||
if (dimension < requestedRadius * 2) {
|
if (dimension < requestedRadius * 2) {
|
||||||
return dimension / 2
|
return dimension / 2;
|
||||||
}
|
}
|
||||||
return requestedRadius
|
return requestedRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a shape should use flattened corners
|
* Check if a shape should use flattened corners
|
||||||
* Returns true if width or height is too small for the requested radius
|
* Returns true if width or height is too small for the requested radius
|
||||||
*/
|
*/
|
||||||
function shouldFlatten(width, height, radius) {
|
function shouldFlatten(width, height, radius) {
|
||||||
return width < radius * 2 || height < radius * 2
|
return width < radius * 2 || height < radius * 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,19 +2,18 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Modules.Bar
|
import qs.Modules.Bar
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BarContentWindow - Separate transparent PanelWindow for bar content
|
* BarContentWindow - Separate transparent PanelWindow for bar content
|
||||||
*
|
*
|
||||||
* This window contains only the bar widgets (content), while the background
|
* This window contains only the bar widgets (content), while the background
|
||||||
* is rendered in MainScreen's unified Shape system. This separation prevents
|
* is rendered in MainScreen's unified Shape system. This separation prevents
|
||||||
* fullscreen redraws when bar widgets redraw.
|
* fullscreen redraws when bar widgets redraw.
|
||||||
*
|
*
|
||||||
* This component should be instantiated once per screen by AllScreens.qml
|
* This component should be instantiated once per screen by AllScreens.qml
|
||||||
*/
|
*/
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: barWindow
|
id: barWindow
|
||||||
|
|
||||||
@@ -22,7 +21,7 @@ PanelWindow {
|
|||||||
color: Color.transparent // Transparent - background is in MainScreen below
|
color: Color.transparent // Transparent - background is in MainScreen below
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.d("BarContentWindow", "Bar content window created for screen:", barWindow.screen?.name)
|
Logger.d("BarContentWindow", "Bar content window created for screen:", barWindow.screen?.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wayland layer configuration
|
// Wayland layer configuration
|
||||||
|
|||||||
@@ -3,13 +3,12 @@ import Quickshell
|
|||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* BarExclusionZone - Invisible PanelWindow that reserves exclusive space for the bar
|
* BarExclusionZone - Invisible PanelWindow that reserves exclusive space for the bar
|
||||||
*
|
*
|
||||||
* This is a minimal window that works with the compositor to reserve space,
|
* This is a minimal window that works with the compositor to reserve space,
|
||||||
* while the actual bar UI is rendered in MainScreen.
|
* while the actual bar UI is rendered in MainScreen.
|
||||||
*/
|
*/
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -46,11 +45,11 @@ PanelWindow {
|
|||||||
// Vertical bar: reserve bar height + margin on the anchored edge only
|
// Vertical bar: reserve bar height + margin on the anchored edge only
|
||||||
if (barFloating) {
|
if (barFloating) {
|
||||||
// For left bar, reserve left margin; for right bar, reserve right margin
|
// For left bar, reserve left margin; for right bar, reserve right margin
|
||||||
return Style.barHeight + barMarginH
|
return Style.barHeight + barMarginH;
|
||||||
}
|
}
|
||||||
return Style.barHeight
|
return Style.barHeight;
|
||||||
}
|
}
|
||||||
return 0 // Auto-width when left/right anchors are true
|
return 0; // Auto-width when left/right anchors are true
|
||||||
}
|
}
|
||||||
|
|
||||||
implicitHeight: {
|
implicitHeight: {
|
||||||
@@ -58,17 +57,17 @@ PanelWindow {
|
|||||||
// Horizontal bar: reserve bar height + margin on the anchored edge only
|
// Horizontal bar: reserve bar height + margin on the anchored edge only
|
||||||
if (barFloating) {
|
if (barFloating) {
|
||||||
// For top bar, reserve top margin; for bottom bar, reserve bottom margin
|
// For top bar, reserve top margin; for bottom bar, reserve bottom margin
|
||||||
return Style.barHeight + barMarginV
|
return Style.barHeight + barMarginV;
|
||||||
}
|
}
|
||||||
return Style.barHeight
|
return Style.barHeight;
|
||||||
}
|
}
|
||||||
return 0 // Auto-height when top/bottom anchors are true
|
return 0; // Auto-height when top/bottom anchors are true
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.d("BarExclusionZone", "Created for screen:", screen?.name)
|
Logger.d("BarExclusionZone", "Created for screen:", screen?.name);
|
||||||
Logger.d("BarExclusionZone", " Position:", barPosition, "Exclusive:", exclusive, "Floating:", barFloating)
|
Logger.d("BarExclusionZone", " Position:", barPosition, "Exclusive:", exclusive, "Floating:", barFloating);
|
||||||
Logger.d("BarExclusionZone", " Anchors - top:", anchors.top, "bottom:", anchors.bottom, "left:", anchors.left, "right:", anchors.right)
|
Logger.d("BarExclusionZone", " Anchors - top:", anchors.top, "bottom:", anchors.bottom, "left:", anchors.left, "right:", anchors.right);
|
||||||
Logger.d("BarExclusionZone", " Size:", width, "x", height, "implicitWidth:", implicitWidth, "implicitHeight:", implicitHeight)
|
Logger.d("BarExclusionZone", " Size:", width, "x", height, "implicitWidth:", implicitWidth, "implicitHeight:", implicitHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,9 @@ import QtQuick
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
import "Backgrounds" as Backgrounds
|
||||||
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import "Backgrounds" as Backgrounds
|
|
||||||
|
|
||||||
// All panels
|
// All panels
|
||||||
import qs.Modules.Bar
|
import qs.Modules.Bar
|
||||||
@@ -23,11 +22,11 @@ import qs.Modules.Panels.SetupWizard
|
|||||||
import qs.Modules.Panels.Tray
|
import qs.Modules.Panels.Tray
|
||||||
import qs.Modules.Panels.Wallpaper
|
import qs.Modules.Panels.Wallpaper
|
||||||
import qs.Modules.Panels.WiFi
|
import qs.Modules.Panels.WiFi
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MainScreen - Single PanelWindow per screen that manages all panels and the bar
|
* MainScreen - Single PanelWindow per screen that manages all panels and the bar
|
||||||
*/
|
*/
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -62,7 +61,7 @@ PanelWindow {
|
|||||||
readonly property var wifiPanelPlaceholder: wifiPanel.panelPlaceholder
|
readonly property var wifiPanelPlaceholder: wifiPanel.panelPlaceholder
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.d("MainScreen", "Initialized for screen:", screen?.name, "- Dimensions:", screen?.width, "x", screen?.height, "- Position:", screen?.x, ",", screen?.y)
|
Logger.d("MainScreen", "Initialized for screen:", screen?.name, "- Dimensions:", screen?.width, "x", screen?.height, "- Position:", screen?.x, ",", screen?.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wayland
|
// Wayland
|
||||||
@@ -85,9 +84,9 @@ PanelWindow {
|
|||||||
|
|
||||||
color: {
|
color: {
|
||||||
if (dimmerOpacity > 0 && isPanelOpen && !isPanelClosing) {
|
if (dimmerOpacity > 0 && isPanelOpen && !isPanelClosing) {
|
||||||
return Qt.alpha(Color.mShadow, dimmerOpacity)
|
return Qt.alpha(Color.mShadow, dimmerOpacity);
|
||||||
}
|
}
|
||||||
return Color.transparent
|
return Color.transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
@@ -101,15 +100,15 @@ PanelWindow {
|
|||||||
readonly property bool barShouldShow: {
|
readonly property bool barShouldShow: {
|
||||||
// Check global bar visibility
|
// Check global bar visibility
|
||||||
if (!BarService.isVisible)
|
if (!BarService.isVisible)
|
||||||
return false
|
return false;
|
||||||
|
|
||||||
// Check screen-specific configuration
|
// Check screen-specific configuration
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
var screenName = screen?.name || ""
|
var screenName = screen?.name || "";
|
||||||
|
|
||||||
// If no monitors specified, show on all screens
|
// If no monitors specified, show on all screens
|
||||||
// If monitors specified, only show if this screen is in the list
|
// If monitors specified, only show if this screen is in the list
|
||||||
return monitors.length === 0 || monitors.includes(screenName)
|
return monitors.length === 0 || monitors.includes(screenName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make everything click-through except bar
|
// Make everything click-through except bar
|
||||||
@@ -166,8 +165,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "audioPanel-" + (screen?.name || "unknown")
|
objectName = "audioPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(audioPanel)
|
PanelService.registerPanel(audioPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,8 +176,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "batteryPanel-" + (screen?.name || "unknown")
|
objectName = "batteryPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(batteryPanel)
|
PanelService.registerPanel(batteryPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,8 +187,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "bluetoothPanel-" + (screen?.name || "unknown")
|
objectName = "bluetoothPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(bluetoothPanel)
|
PanelService.registerPanel(bluetoothPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,8 +198,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "controlCenterPanel-" + (screen?.name || "unknown")
|
objectName = "controlCenterPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(controlCenterPanel)
|
PanelService.registerPanel(controlCenterPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -210,8 +209,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "calendarPanel-" + (screen?.name || "unknown")
|
objectName = "calendarPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(calendarPanel)
|
PanelService.registerPanel(calendarPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,8 +220,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "launcherPanel-" + (screen?.name || "unknown")
|
objectName = "launcherPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(launcherPanel)
|
PanelService.registerPanel(launcherPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,8 +231,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "notificationHistoryPanel-" + (screen?.name || "unknown")
|
objectName = "notificationHistoryPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(notificationHistoryPanel)
|
PanelService.registerPanel(notificationHistoryPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,8 +242,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "sessionMenuPanel-" + (screen?.name || "unknown")
|
objectName = "sessionMenuPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(sessionMenuPanel)
|
PanelService.registerPanel(sessionMenuPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,8 +253,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "settingsPanel-" + (screen?.name || "unknown")
|
objectName = "settingsPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(settingsPanel)
|
PanelService.registerPanel(settingsPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -265,8 +264,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "setupWizardPanel-" + (screen?.name || "unknown")
|
objectName = "setupWizardPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(setupWizardPanel)
|
PanelService.registerPanel(setupWizardPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,8 +275,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "trayDrawerPanel-" + (screen?.name || "unknown")
|
objectName = "trayDrawerPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(trayDrawerPanel)
|
PanelService.registerPanel(trayDrawerPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,8 +286,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "wallpaperPanel-" + (screen?.name || "unknown")
|
objectName = "wallpaperPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(wallpaperPanel)
|
PanelService.registerPanel(wallpaperPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -298,8 +297,8 @@ PanelWindow {
|
|||||||
z: 50
|
z: 50
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "wifiPanel-" + (screen?.name || "unknown")
|
objectName = "wifiPanel-" + (screen?.name || "unknown");
|
||||||
PanelService.registerPanel(wifiPanel)
|
PanelService.registerPanel(wifiPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,94 +325,93 @@ PanelWindow {
|
|||||||
// Use screen dimensions directly
|
// Use screen dimensions directly
|
||||||
x: {
|
x: {
|
||||||
if (barPosition === "right")
|
if (barPosition === "right")
|
||||||
return screen.width - Style.barHeight - barMarginH - attachmentOverlap // Extend left towards panels
|
return screen.width - Style.barHeight - barMarginH - attachmentOverlap; // Extend left towards panels
|
||||||
return barMarginH
|
return barMarginH;
|
||||||
}
|
}
|
||||||
y: {
|
y: {
|
||||||
if (barPosition === "bottom")
|
if (barPosition === "bottom")
|
||||||
return screen.height - Style.barHeight - barMarginV - attachmentOverlap
|
return screen.height - Style.barHeight - barMarginV - attachmentOverlap;
|
||||||
return barMarginV
|
return barMarginV;
|
||||||
}
|
}
|
||||||
width: {
|
width: {
|
||||||
if (barIsVertical) {
|
if (barIsVertical) {
|
||||||
return Style.barHeight + attachmentOverlap
|
return Style.barHeight + attachmentOverlap;
|
||||||
}
|
}
|
||||||
return screen.width - barMarginH * 2
|
return screen.width - barMarginH * 2;
|
||||||
}
|
}
|
||||||
height: {
|
height: {
|
||||||
if (barIsVertical) {
|
if (barIsVertical) {
|
||||||
return screen.height - barMarginV * 2
|
return screen.height - barMarginV * 2;
|
||||||
}
|
}
|
||||||
return Style.barHeight + attachmentOverlap
|
return Style.barHeight + attachmentOverlap;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Corner states (same as Bar.qml)
|
// Corner states (same as Bar.qml)
|
||||||
readonly property int topLeftCornerState: {
|
readonly property int topLeftCornerState: {
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
if (barPosition === "top")
|
if (barPosition === "top")
|
||||||
return -1
|
return -1;
|
||||||
if (barPosition === "left")
|
if (barPosition === "left")
|
||||||
return -1
|
return -1;
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "right")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "right")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int topRightCornerState: {
|
readonly property int topRightCornerState: {
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
if (barPosition === "top")
|
if (barPosition === "top")
|
||||||
return -1
|
return -1;
|
||||||
if (barPosition === "right")
|
if (barPosition === "right")
|
||||||
return -1
|
return -1;
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "left")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "bottom" || barPosition === "left")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int bottomLeftCornerState: {
|
readonly property int bottomLeftCornerState: {
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
if (barPosition === "bottom")
|
if (barPosition === "bottom")
|
||||||
return -1
|
return -1;
|
||||||
if (barPosition === "left")
|
if (barPosition === "left")
|
||||||
return -1
|
return -1;
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "right")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "right")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int bottomRightCornerState: {
|
readonly property int bottomRightCornerState: {
|
||||||
if (barFloating)
|
if (barFloating)
|
||||||
return 0
|
return 0;
|
||||||
if (barPosition === "bottom")
|
if (barPosition === "bottom")
|
||||||
return -1
|
return -1;
|
||||||
if (barPosition === "right")
|
if (barPosition === "right")
|
||||||
return -1
|
return -1;
|
||||||
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "left")) {
|
if (Settings.data.bar.outerCorners && (barPosition === "top" || barPosition === "left")) {
|
||||||
return barIsVertical ? 1 : 2
|
return barIsVertical ? 1 : 2;
|
||||||
}
|
}
|
||||||
return -1
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
Logger.d("MainScreen", "===== Bar placeholder loaded =====")
|
Logger.d("MainScreen", "===== Bar placeholder loaded =====");
|
||||||
Logger.d("MainScreen", " Screen:", screen?.name, "Size:", screen?.width, "x", screen?.height)
|
Logger.d("MainScreen", " Screen:", screen?.name, "Size:", screen?.width, "x", screen?.height);
|
||||||
Logger.d("MainScreen", " Bar position:", barPosition, "| isVertical:", barIsVertical)
|
Logger.d("MainScreen", " Bar position:", barPosition, "| isVertical:", barIsVertical);
|
||||||
Logger.d("MainScreen", " Bar dimensions: x=" + x, "y=" + y, "width=" + width, "height=" + height)
|
Logger.d("MainScreen", " Bar dimensions: x=" + x, "y=" + y, "width=" + width, "height=" + height);
|
||||||
Logger.d("MainScreen", " Style.barHeight =", Style.barHeight)
|
Logger.d("MainScreen", " Style.barHeight =", Style.barHeight);
|
||||||
Logger.d("MainScreen", " Margins: H=" + barMarginH, "V=" + barMarginV, "| Floating:", barFloating)
|
Logger.d("MainScreen", " Margins: H=" + barMarginH, "V=" + barMarginV, "| Floating:", barFloating);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Screen Corners
|
* Screen Corners
|
||||||
*/
|
*/
|
||||||
ScreenCorners {}
|
ScreenCorners {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,14 +3,13 @@ import Quickshell
|
|||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PanelPlaceholder - Lightweight positioning logic for panel backgrounds
|
* PanelPlaceholder - Lightweight positioning logic for panel backgrounds
|
||||||
*
|
*
|
||||||
* This component stays in MainScreen and provides geometry for PanelBackground rendering.
|
* This component stays in MainScreen and provides geometry for PanelBackground rendering.
|
||||||
* It contains only positioning calculations and animations, no visual content.
|
* It contains only positioning calculations and animations, no visual content.
|
||||||
* The actual panel content lives in a separate SmartPanelWindow.
|
* The actual panel content lives in a separate SmartPanelWindow.
|
||||||
*/
|
*/
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -71,13 +70,13 @@ Item {
|
|||||||
readonly property bool allowAttach: Settings.data.ui.panelsAttachedToBar || root.forceAttachToBar
|
readonly property bool allowAttach: Settings.data.ui.panelsAttachedToBar || root.forceAttachToBar
|
||||||
readonly property bool allowAttachToBar: {
|
readonly property bool allowAttachToBar: {
|
||||||
if (!(Settings.data.ui.panelsAttachedToBar || root.forceAttachToBar) || Settings.data.bar.backgroundOpacity < 1.0) {
|
if (!(Settings.data.ui.panelsAttachedToBar || root.forceAttachToBar) || Settings.data.bar.backgroundOpacity < 1.0) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// A panel can only be attached to a bar if there is a bar on that screen
|
// A panel can only be attached to a bar if there is a bar on that screen
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
var result = monitors.length === 0 || monitors.includes(root.screen?.name || "")
|
var result = monitors.length === 0 || monitors.includes(root.screen?.name || "");
|
||||||
return result
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Effective anchor properties (depend on allowAttach)
|
// Effective anchor properties (depend on allowAttach)
|
||||||
@@ -97,17 +96,17 @@ Item {
|
|||||||
|
|
||||||
function onUiScaleRatioChanged() {
|
function onUiScaleRatioChanged() {
|
||||||
if (root.isPanelVisible) {
|
if (root.isPanelVisible) {
|
||||||
root.setPosition()
|
root.setPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public function to update content size from SmartPanelWindow
|
// Public function to update content size from SmartPanelWindow
|
||||||
function updateContentSize(w, h) {
|
function updateContentSize(w, h) {
|
||||||
contentPreferredWidth = w
|
contentPreferredWidth = w;
|
||||||
contentPreferredHeight = h
|
contentPreferredHeight = h;
|
||||||
if (isPanelVisible) {
|
if (isPanelVisible) {
|
||||||
setPosition()
|
setPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -115,45 +114,45 @@ Item {
|
|||||||
function setPosition() {
|
function setPosition() {
|
||||||
// Don't calculate position if parent dimensions aren't available yet
|
// Don't calculate position if parent dimensions aren't available yet
|
||||||
if (!root.width || !root.height) {
|
if (!root.width || !root.height) {
|
||||||
Logger.d("PanelPlaceholder", "Skipping setPosition - dimensions not ready:", root.width, "x", root.height, panelName)
|
Logger.d("PanelPlaceholder", "Skipping setPosition - dimensions not ready:", root.width, "x", root.height, panelName);
|
||||||
Qt.callLater(setPosition)
|
Qt.callLater(setPosition);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate panel dimensions first (needed for positioning)
|
// Calculate panel dimensions first (needed for positioning)
|
||||||
var w
|
var w;
|
||||||
// Priority 1: Content-driven size (dynamic)
|
// Priority 1: Content-driven size (dynamic)
|
||||||
if (contentPreferredWidth > 0) {
|
if (contentPreferredWidth > 0) {
|
||||||
w = contentPreferredWidth
|
w = contentPreferredWidth;
|
||||||
} // Priority 2: Ratio-based size
|
} // Priority 2: Ratio-based size
|
||||||
else if (root.preferredWidthRatio !== undefined) {
|
else if (root.preferredWidthRatio !== undefined) {
|
||||||
w = Math.round(Math.max(root.width * root.preferredWidthRatio, root.preferredWidth))
|
w = Math.round(Math.max(root.width * root.preferredWidthRatio, root.preferredWidth));
|
||||||
} // Priority 3: Static preferred width
|
} // Priority 3: Static preferred width
|
||||||
else {
|
else {
|
||||||
w = root.preferredWidth
|
w = root.preferredWidth;
|
||||||
}
|
}
|
||||||
var panelWidth = Math.min(w, root.width - Style.marginL * 2)
|
var panelWidth = Math.min(w, root.width - Style.marginL * 2);
|
||||||
|
|
||||||
var h
|
var h;
|
||||||
// Priority 1: Content-driven size (dynamic)
|
// Priority 1: Content-driven size (dynamic)
|
||||||
if (contentPreferredHeight > 0) {
|
if (contentPreferredHeight > 0) {
|
||||||
h = contentPreferredHeight
|
h = contentPreferredHeight;
|
||||||
} // Priority 2: Ratio-based size
|
} // Priority 2: Ratio-based size
|
||||||
else if (root.preferredHeightRatio !== undefined) {
|
else if (root.preferredHeightRatio !== undefined) {
|
||||||
h = Math.round(Math.max(root.height * root.preferredHeightRatio, root.preferredHeight))
|
h = Math.round(Math.max(root.height * root.preferredHeightRatio, root.preferredHeight));
|
||||||
} // Priority 3: Static preferred height
|
} // Priority 3: Static preferred height
|
||||||
else {
|
else {
|
||||||
h = root.preferredHeight
|
h = root.preferredHeight;
|
||||||
}
|
}
|
||||||
var panelHeight = Math.min(h, root.height - Style.barHeight - Style.marginL * 2)
|
var panelHeight = Math.min(h, root.height - Style.barHeight - Style.marginL * 2);
|
||||||
|
|
||||||
// Update panelBackground target size (will be animated)
|
// Update panelBackground target size (will be animated)
|
||||||
panelBackground.targetWidth = panelWidth
|
panelBackground.targetWidth = panelWidth;
|
||||||
panelBackground.targetHeight = panelHeight
|
panelBackground.targetHeight = panelHeight;
|
||||||
|
|
||||||
// Calculate position
|
// Calculate position
|
||||||
var calculatedX
|
var calculatedX;
|
||||||
var calculatedY
|
var calculatedY;
|
||||||
|
|
||||||
// ===== X POSITIONING =====
|
// ===== X POSITIONING =====
|
||||||
if (root.useButtonPosition && root.width > 0 && panelWidth > 0) {
|
if (root.useButtonPosition && root.width > 0 && panelWidth > 0) {
|
||||||
@@ -162,111 +161,111 @@ Item {
|
|||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
// Attached panels: align with bar edge (left or right side)
|
// Attached panels: align with bar edge (left or right side)
|
||||||
if (root.barPosition === "left") {
|
if (root.barPosition === "left") {
|
||||||
var leftBarEdge = root.barMarginH + Style.barHeight
|
var leftBarEdge = root.barMarginH + Style.barHeight;
|
||||||
calculatedX = leftBarEdge
|
calculatedX = leftBarEdge;
|
||||||
} else {
|
} else {
|
||||||
// right
|
// right
|
||||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight
|
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
|
||||||
calculatedX = rightBarEdge - panelWidth
|
calculatedX = rightBarEdge - panelWidth;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Detached panels: center on button X position
|
// Detached panels: center on button X position
|
||||||
var panelX = root.buttonPosition.x + root.buttonWidth / 2 - panelWidth / 2
|
var panelX = root.buttonPosition.x + root.buttonWidth / 2 - panelWidth / 2;
|
||||||
var minX = Style.marginL
|
var minX = Style.marginL;
|
||||||
var maxX = root.width - panelWidth - Style.marginL
|
var maxX = root.width - panelWidth - Style.marginL;
|
||||||
|
|
||||||
// Account for vertical bar taking up space
|
// Account for vertical bar taking up space
|
||||||
if (root.barPosition === "left") {
|
if (root.barPosition === "left") {
|
||||||
minX = root.barMarginH + Style.barHeight + Style.marginL
|
minX = root.barMarginH + Style.barHeight + Style.marginL;
|
||||||
} else if (root.barPosition === "right") {
|
} else if (root.barPosition === "right") {
|
||||||
maxX = root.width - root.barMarginH - Style.barHeight - panelWidth - Style.marginL
|
maxX = root.width - root.barMarginH - Style.barHeight - panelWidth - Style.marginL;
|
||||||
}
|
}
|
||||||
|
|
||||||
panelX = Math.max(minX, Math.min(panelX, maxX))
|
panelX = Math.max(minX, Math.min(panelX, maxX));
|
||||||
calculatedX = panelX
|
calculatedX = panelX;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// For horizontal bars, center panel on button X position
|
// For horizontal bars, center panel on button X position
|
||||||
var panelX = root.buttonPosition.x + root.buttonWidth / 2 - panelWidth / 2
|
var panelX = root.buttonPosition.x + root.buttonWidth / 2 - panelWidth / 2;
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
var cornerInset = root.barFloating ? Style.radiusL * 2 : 0
|
var cornerInset = root.barFloating ? Style.radiusL * 2 : 0;
|
||||||
var barLeftEdge = root.barMarginH + cornerInset
|
var barLeftEdge = root.barMarginH + cornerInset;
|
||||||
var barRightEdge = root.width - root.barMarginH - cornerInset
|
var barRightEdge = root.width - root.barMarginH - cornerInset;
|
||||||
panelX = Math.max(barLeftEdge, Math.min(panelX, barRightEdge - panelWidth))
|
panelX = Math.max(barLeftEdge, Math.min(panelX, barRightEdge - panelWidth));
|
||||||
} else {
|
} else {
|
||||||
panelX = Math.max(Style.marginL, Math.min(panelX, root.width - panelWidth - Style.marginL))
|
panelX = Math.max(Style.marginL, Math.min(panelX, root.width - panelWidth - Style.marginL));
|
||||||
}
|
}
|
||||||
calculatedX = panelX
|
calculatedX = panelX;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Standard anchor positioning
|
// Standard anchor positioning
|
||||||
if (root.panelAnchorHorizontalCenter) {
|
if (root.panelAnchorHorizontalCenter) {
|
||||||
if (root.barIsVertical) {
|
if (root.barIsVertical) {
|
||||||
if (root.barPosition === "left") {
|
if (root.barPosition === "left") {
|
||||||
var availableStart = root.barMarginH + Style.barHeight
|
var availableStart = root.barMarginH + Style.barHeight;
|
||||||
var availableWidth = root.width - availableStart
|
var availableWidth = root.width - availableStart;
|
||||||
calculatedX = availableStart + (availableWidth - panelWidth) / 2
|
calculatedX = availableStart + (availableWidth - panelWidth) / 2;
|
||||||
} else if (root.barPosition === "right") {
|
} else if (root.barPosition === "right") {
|
||||||
var availableWidth = root.width - root.barMarginH - Style.barHeight
|
var availableWidth = root.width - root.barMarginH - Style.barHeight;
|
||||||
calculatedX = (availableWidth - panelWidth) / 2
|
calculatedX = (availableWidth - panelWidth) / 2;
|
||||||
} else {
|
} else {
|
||||||
calculatedX = (root.width - panelWidth) / 2
|
calculatedX = (root.width - panelWidth) / 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
calculatedX = (root.width - panelWidth) / 2
|
calculatedX = (root.width - panelWidth) / 2;
|
||||||
}
|
}
|
||||||
} else if (root.effectivePanelAnchorRight) {
|
} else if (root.effectivePanelAnchorRight) {
|
||||||
if (allowAttach && root.barIsVertical && root.barPosition === "right") {
|
if (allowAttach && root.barIsVertical && root.barPosition === "right") {
|
||||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight
|
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
|
||||||
calculatedX = rightBarEdge - panelWidth
|
calculatedX = rightBarEdge - panelWidth;
|
||||||
} else if (allowAttach) {
|
} else if (allowAttach) {
|
||||||
// Account for corner inset when bar is floating, horizontal, AND panel is on same edge as bar
|
// Account for corner inset when bar is floating, horizontal, AND panel is on same edge as bar
|
||||||
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom)
|
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
|
||||||
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
|
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
|
||||||
var rightCornerInset = Style.radiusL * 2
|
var rightCornerInset = Style.radiusL * 2;
|
||||||
calculatedX = root.width - root.barMarginH - rightCornerInset - panelWidth
|
calculatedX = root.width - root.barMarginH - rightCornerInset - panelWidth;
|
||||||
} else {
|
} else {
|
||||||
calculatedX = root.width - panelWidth
|
calculatedX = root.width - panelWidth;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
calculatedX = root.width - panelWidth - Style.marginL
|
calculatedX = root.width - panelWidth - Style.marginL;
|
||||||
}
|
}
|
||||||
} else if (root.effectivePanelAnchorLeft) {
|
} else if (root.effectivePanelAnchorLeft) {
|
||||||
if (allowAttach && root.barIsVertical && root.barPosition === "left") {
|
if (allowAttach && root.barIsVertical && root.barPosition === "left") {
|
||||||
var leftBarEdge = root.barMarginH + Style.barHeight
|
var leftBarEdge = root.barMarginH + Style.barHeight;
|
||||||
calculatedX = leftBarEdge
|
calculatedX = leftBarEdge;
|
||||||
} else if (allowAttach) {
|
} else if (allowAttach) {
|
||||||
// Account for corner inset when bar is floating, horizontal, AND panel is on same edge as bar
|
// Account for corner inset when bar is floating, horizontal, AND panel is on same edge as bar
|
||||||
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom)
|
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
|
||||||
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
|
if (!root.barIsVertical && root.barFloating && panelOnSameEdgeAsBar) {
|
||||||
var leftCornerInset = Style.radiusL * 2
|
var leftCornerInset = Style.radiusL * 2;
|
||||||
calculatedX = root.barMarginH + leftCornerInset
|
calculatedX = root.barMarginH + leftCornerInset;
|
||||||
} else {
|
} else {
|
||||||
calculatedX = 0
|
calculatedX = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
calculatedX = Style.marginL
|
calculatedX = Style.marginL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// No explicit anchor: default to centering on bar
|
// No explicit anchor: default to centering on bar
|
||||||
if (root.barIsVertical) {
|
if (root.barIsVertical) {
|
||||||
if (root.barPosition === "left") {
|
if (root.barPosition === "left") {
|
||||||
var availableStart = root.barMarginH + Style.barHeight
|
var availableStart = root.barMarginH + Style.barHeight;
|
||||||
var availableWidth = root.width - availableStart - Style.marginL
|
var availableWidth = root.width - availableStart - Style.marginL;
|
||||||
calculatedX = availableStart + (availableWidth - panelWidth) / 2
|
calculatedX = availableStart + (availableWidth - panelWidth) / 2;
|
||||||
} else {
|
} else {
|
||||||
var availableWidth = root.width - root.barMarginH - Style.barHeight - Style.marginL
|
var availableWidth = root.width - root.barMarginH - Style.barHeight - Style.marginL;
|
||||||
calculatedX = Style.marginL + (availableWidth - panelWidth) / 2
|
calculatedX = Style.marginL + (availableWidth - panelWidth) / 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
var cornerInset = Style.radiusL + (root.barFloating ? Style.radiusL : 0)
|
var cornerInset = Style.radiusL + (root.barFloating ? Style.radiusL : 0);
|
||||||
var barLeftEdge = root.barMarginH + cornerInset
|
var barLeftEdge = root.barMarginH + cornerInset;
|
||||||
var barRightEdge = root.width - root.barMarginH - cornerInset
|
var barRightEdge = root.width - root.barMarginH - cornerInset;
|
||||||
var centeredX = (root.width - panelWidth) / 2
|
var centeredX = (root.width - panelWidth) / 2;
|
||||||
calculatedX = Math.max(barLeftEdge, Math.min(centeredX, barRightEdge - panelWidth))
|
calculatedX = Math.max(barLeftEdge, Math.min(centeredX, barRightEdge - panelWidth));
|
||||||
} else {
|
} else {
|
||||||
calculatedX = (root.width - panelWidth) / 2
|
calculatedX = (root.width - panelWidth) / 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -274,76 +273,76 @@ Item {
|
|||||||
|
|
||||||
// Edge snapping for X
|
// Edge snapping for X
|
||||||
if (allowAttach && !root.barFloating && root.width > 0 && panelWidth > 0) {
|
if (allowAttach && !root.barFloating && root.width > 0 && panelWidth > 0) {
|
||||||
var leftEdgePos = root.barMarginH
|
var leftEdgePos = root.barMarginH;
|
||||||
if (root.barPosition === "left") {
|
if (root.barPosition === "left") {
|
||||||
leftEdgePos = root.barMarginH + Style.barHeight
|
leftEdgePos = root.barMarginH + Style.barHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
var rightEdgePos = root.width - root.barMarginH - panelWidth
|
var rightEdgePos = root.width - root.barMarginH - panelWidth;
|
||||||
if (root.barPosition === "right") {
|
if (root.barPosition === "right") {
|
||||||
rightEdgePos = root.width - root.barMarginH - Style.barHeight - panelWidth
|
rightEdgePos = root.width - root.barMarginH - Style.barHeight - panelWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only snap to left edge if panel is actually meant to be at left
|
// Only snap to left edge if panel is actually meant to be at left
|
||||||
var shouldSnapToLeft = root.effectivePanelAnchorLeft || (!root.hasExplicitHorizontalAnchor && root.barPosition === "left")
|
var shouldSnapToLeft = root.effectivePanelAnchorLeft || (!root.hasExplicitHorizontalAnchor && root.barPosition === "left");
|
||||||
// Only snap to right edge if panel is actually meant to be at right
|
// Only snap to right edge if panel is actually meant to be at right
|
||||||
var shouldSnapToRight = root.effectivePanelAnchorRight || (!root.hasExplicitHorizontalAnchor && root.barPosition === "right")
|
var shouldSnapToRight = root.effectivePanelAnchorRight || (!root.hasExplicitHorizontalAnchor && root.barPosition === "right");
|
||||||
|
|
||||||
if (shouldSnapToLeft && Math.abs(calculatedX - leftEdgePos) <= root.edgeSnapDistance) {
|
if (shouldSnapToLeft && Math.abs(calculatedX - leftEdgePos) <= root.edgeSnapDistance) {
|
||||||
calculatedX = leftEdgePos
|
calculatedX = leftEdgePos;
|
||||||
} else if (shouldSnapToRight && Math.abs(calculatedX - rightEdgePos) <= root.edgeSnapDistance) {
|
} else if (shouldSnapToRight && Math.abs(calculatedX - rightEdgePos) <= root.edgeSnapDistance) {
|
||||||
calculatedX = rightEdgePos
|
calculatedX = rightEdgePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Y POSITIONING =====
|
// ===== Y POSITIONING =====
|
||||||
if (root.useButtonPosition && root.height > 0 && panelHeight > 0) {
|
if (root.useButtonPosition && root.height > 0 && panelHeight > 0) {
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
var topBarEdge = root.barMarginV + Style.barHeight
|
var topBarEdge = root.barMarginV + Style.barHeight;
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
calculatedY = topBarEdge
|
calculatedY = topBarEdge;
|
||||||
} else {
|
} else {
|
||||||
calculatedY = topBarEdge + Style.marginM
|
calculatedY = topBarEdge + Style.marginM;
|
||||||
}
|
}
|
||||||
} else if (root.barPosition === "bottom") {
|
} else if (root.barPosition === "bottom") {
|
||||||
var bottomBarEdge = root.height - root.barMarginV - Style.barHeight
|
var bottomBarEdge = root.height - root.barMarginV - Style.barHeight;
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
calculatedY = bottomBarEdge - panelHeight
|
calculatedY = bottomBarEdge - panelHeight;
|
||||||
} else {
|
} else {
|
||||||
calculatedY = bottomBarEdge - panelHeight - Style.marginM
|
calculatedY = bottomBarEdge - panelHeight - Style.marginM;
|
||||||
}
|
}
|
||||||
} else if (root.barIsVertical) {
|
} else if (root.barIsVertical) {
|
||||||
var panelY = root.buttonPosition.y + root.buttonHeight / 2 - panelHeight / 2
|
var panelY = root.buttonPosition.y + root.buttonHeight / 2 - panelHeight / 2;
|
||||||
var extraPadding = (allowAttach && root.barFloating) ? Style.radiusL : 0
|
var extraPadding = (allowAttach && root.barFloating) ? Style.radiusL : 0;
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
var cornerInset = extraPadding + (root.barFloating ? Style.radiusL : 0)
|
var cornerInset = extraPadding + (root.barFloating ? Style.radiusL : 0);
|
||||||
var barTopEdge = root.barMarginV + cornerInset
|
var barTopEdge = root.barMarginV + cornerInset;
|
||||||
var barBottomEdge = root.height - root.barMarginV - cornerInset
|
var barBottomEdge = root.height - root.barMarginV - cornerInset;
|
||||||
panelY = Math.max(barTopEdge, Math.min(panelY, barBottomEdge - panelHeight))
|
panelY = Math.max(barTopEdge, Math.min(panelY, barBottomEdge - panelHeight));
|
||||||
} else {
|
} else {
|
||||||
panelY = Math.max(Style.marginL + extraPadding, Math.min(panelY, root.height - panelHeight - Style.marginL - extraPadding))
|
panelY = Math.max(Style.marginL + extraPadding, Math.min(panelY, root.height - panelHeight - Style.marginL - extraPadding));
|
||||||
}
|
}
|
||||||
calculatedY = panelY
|
calculatedY = panelY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Standard anchor positioning
|
// Standard anchor positioning
|
||||||
var barOffset = 0
|
var barOffset = 0;
|
||||||
if (!allowAttach) {
|
if (!allowAttach) {
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
barOffset = root.barMarginV + Style.barHeight + Style.marginM
|
barOffset = root.barMarginV + Style.barHeight + Style.marginM;
|
||||||
} else if (root.barPosition === "bottom") {
|
} else if (root.barPosition === "bottom") {
|
||||||
barOffset = root.barMarginV + Style.barHeight + Style.marginM
|
barOffset = root.barMarginV + Style.barHeight + Style.marginM;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (root.effectivePanelAnchorTop && root.barPosition === "top") {
|
if (root.effectivePanelAnchorTop && root.barPosition === "top") {
|
||||||
calculatedY = root.barMarginV + Style.barHeight
|
calculatedY = root.barMarginV + Style.barHeight;
|
||||||
} else if (root.effectivePanelAnchorBottom && root.barPosition === "bottom") {
|
} else if (root.effectivePanelAnchorBottom && root.barPosition === "bottom") {
|
||||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight
|
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||||
} else if (!root.hasExplicitVerticalAnchor) {
|
} else if (!root.hasExplicitVerticalAnchor) {
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
calculatedY = root.barMarginV + Style.barHeight
|
calculatedY = root.barMarginV + Style.barHeight;
|
||||||
} else if (root.barPosition === "bottom") {
|
} else if (root.barPosition === "bottom") {
|
||||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight
|
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,57 +351,57 @@ Item {
|
|||||||
if (root.panelAnchorVerticalCenter) {
|
if (root.panelAnchorVerticalCenter) {
|
||||||
if (!root.barIsVertical) {
|
if (!root.barIsVertical) {
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
var availableStart = root.barMarginV + Style.barHeight
|
var availableStart = root.barMarginV + Style.barHeight;
|
||||||
var availableHeight = root.height - availableStart
|
var availableHeight = root.height - availableStart;
|
||||||
calculatedY = availableStart + (availableHeight - panelHeight) / 2
|
calculatedY = availableStart + (availableHeight - panelHeight) / 2;
|
||||||
} else if (root.barPosition === "bottom") {
|
} else if (root.barPosition === "bottom") {
|
||||||
var availableHeight = root.height - root.barMarginV - Style.barHeight
|
var availableHeight = root.height - root.barMarginV - Style.barHeight;
|
||||||
calculatedY = (availableHeight - panelHeight) / 2
|
calculatedY = (availableHeight - panelHeight) / 2;
|
||||||
} else {
|
} else {
|
||||||
calculatedY = (root.height - panelHeight) / 2
|
calculatedY = (root.height - panelHeight) / 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
calculatedY = (root.height - panelHeight) / 2
|
calculatedY = (root.height - panelHeight) / 2;
|
||||||
}
|
}
|
||||||
} else if (root.effectivePanelAnchorTop) {
|
} else if (root.effectivePanelAnchorTop) {
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
calculatedY = 0
|
calculatedY = 0;
|
||||||
} else {
|
} else {
|
||||||
var topBarOffset = (root.barPosition === "top") ? barOffset : 0
|
var topBarOffset = (root.barPosition === "top") ? barOffset : 0;
|
||||||
calculatedY = topBarOffset + Style.marginL
|
calculatedY = topBarOffset + Style.marginL;
|
||||||
}
|
}
|
||||||
} else if (root.effectivePanelAnchorBottom) {
|
} else if (root.effectivePanelAnchorBottom) {
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
calculatedY = root.height - panelHeight
|
calculatedY = root.height - panelHeight;
|
||||||
} else {
|
} else {
|
||||||
var bottomBarOffset = (root.barPosition === "bottom") ? barOffset : 0
|
var bottomBarOffset = (root.barPosition === "bottom") ? barOffset : 0;
|
||||||
calculatedY = root.height - panelHeight - bottomBarOffset - Style.marginL
|
calculatedY = root.height - panelHeight - bottomBarOffset - Style.marginL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (root.barIsVertical) {
|
if (root.barIsVertical) {
|
||||||
if (allowAttach) {
|
if (allowAttach) {
|
||||||
var cornerInset = root.barFloating ? Style.radiusL * 2 : 0
|
var cornerInset = root.barFloating ? Style.radiusL * 2 : 0;
|
||||||
var barTopEdge = root.barMarginV + cornerInset
|
var barTopEdge = root.barMarginV + cornerInset;
|
||||||
var barBottomEdge = root.height - root.barMarginV - cornerInset
|
var barBottomEdge = root.height - root.barMarginV - cornerInset;
|
||||||
var centeredY = (root.height - panelHeight) / 2
|
var centeredY = (root.height - panelHeight) / 2;
|
||||||
calculatedY = Math.max(barTopEdge, Math.min(centeredY, barBottomEdge - panelHeight))
|
calculatedY = Math.max(barTopEdge, Math.min(centeredY, barBottomEdge - panelHeight));
|
||||||
} else {
|
} else {
|
||||||
calculatedY = (root.height - panelHeight) / 2
|
calculatedY = (root.height - panelHeight) / 2;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (allowAttach && !root.barIsVertical) {
|
if (allowAttach && !root.barIsVertical) {
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
calculatedY = root.barMarginV + Style.barHeight
|
calculatedY = root.barMarginV + Style.barHeight;
|
||||||
} else if (root.barPosition === "bottom") {
|
} else if (root.barPosition === "bottom") {
|
||||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight
|
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
calculatedY = barOffset + Style.marginL
|
calculatedY = barOffset + Style.marginL;
|
||||||
} else if (root.barPosition === "bottom") {
|
} else if (root.barPosition === "bottom") {
|
||||||
calculatedY = Style.marginL
|
calculatedY = Style.marginL;
|
||||||
} else {
|
} else {
|
||||||
calculatedY = Style.marginL
|
calculatedY = Style.marginL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -412,34 +411,34 @@ Item {
|
|||||||
|
|
||||||
// Edge snapping for Y
|
// Edge snapping for Y
|
||||||
if (allowAttach && !root.barFloating && root.height > 0 && panelHeight > 0) {
|
if (allowAttach && !root.barFloating && root.height > 0 && panelHeight > 0) {
|
||||||
var topEdgePos = root.barMarginV
|
var topEdgePos = root.barMarginV;
|
||||||
if (root.barPosition === "top") {
|
if (root.barPosition === "top") {
|
||||||
topEdgePos = root.barMarginV + Style.barHeight
|
topEdgePos = root.barMarginV + Style.barHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
var bottomEdgePos = root.height - root.barMarginV - panelHeight
|
var bottomEdgePos = root.height - root.barMarginV - panelHeight;
|
||||||
if (root.barPosition === "bottom") {
|
if (root.barPosition === "bottom") {
|
||||||
bottomEdgePos = root.height - root.barMarginV - Style.barHeight - panelHeight
|
bottomEdgePos = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only snap to top edge if panel is actually meant to be at top
|
// Only snap to top edge if panel is actually meant to be at top
|
||||||
var shouldSnapToTop = root.effectivePanelAnchorTop || (!root.hasExplicitVerticalAnchor && root.barPosition === "top")
|
var shouldSnapToTop = root.effectivePanelAnchorTop || (!root.hasExplicitVerticalAnchor && root.barPosition === "top");
|
||||||
// Only snap to bottom edge if panel is actually meant to be at bottom
|
// Only snap to bottom edge if panel is actually meant to be at bottom
|
||||||
var shouldSnapToBottom = root.effectivePanelAnchorBottom || (!root.hasExplicitVerticalAnchor && root.barPosition === "bottom")
|
var shouldSnapToBottom = root.effectivePanelAnchorBottom || (!root.hasExplicitVerticalAnchor && root.barPosition === "bottom");
|
||||||
|
|
||||||
if (shouldSnapToTop && Math.abs(calculatedY - topEdgePos) <= root.edgeSnapDistance) {
|
if (shouldSnapToTop && Math.abs(calculatedY - topEdgePos) <= root.edgeSnapDistance) {
|
||||||
calculatedY = topEdgePos
|
calculatedY = topEdgePos;
|
||||||
} else if (shouldSnapToBottom && Math.abs(calculatedY - bottomEdgePos) <= root.edgeSnapDistance) {
|
} else if (shouldSnapToBottom && Math.abs(calculatedY - bottomEdgePos) <= root.edgeSnapDistance) {
|
||||||
calculatedY = bottomEdgePos
|
calculatedY = bottomEdgePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply calculated positions (set targets for animation)
|
// Apply calculated positions (set targets for animation)
|
||||||
panelBackground.targetX = calculatedX
|
panelBackground.targetX = calculatedX;
|
||||||
panelBackground.targetY = calculatedY
|
panelBackground.targetY = calculatedY;
|
||||||
|
|
||||||
Logger.d("PanelPlaceholder", "Position calculated:", calculatedX, calculatedY, panelName)
|
Logger.d("PanelPlaceholder", "Position calculated:", calculatedX, calculatedY, panelName);
|
||||||
Logger.d("PanelPlaceholder", " Panel size:", panelWidth, "x", panelHeight)
|
Logger.d("PanelPlaceholder", " Panel size:", panelWidth, "x", panelHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The panel background geometry item
|
// The panel background geometry item
|
||||||
@@ -469,35 +468,35 @@ Item {
|
|||||||
// Animation direction determination (using target position to avoid binding loops)
|
// Animation direction determination (using target position to avoid binding loops)
|
||||||
readonly property bool willTouchTopBar: {
|
readonly property bool willTouchTopBar: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (!allowAttachToBar || root.barPosition !== "top" || root.barIsVertical)
|
if (!allowAttachToBar || root.barPosition !== "top" || root.barIsVertical)
|
||||||
return false
|
return false;
|
||||||
var targetTopBarY = root.barMarginV + Style.barHeight
|
var targetTopBarY = root.barMarginV + Style.barHeight;
|
||||||
return Math.abs(panelBackground.targetY - targetTopBarY) <= 1
|
return Math.abs(panelBackground.targetY - targetTopBarY) <= 1;
|
||||||
}
|
}
|
||||||
readonly property bool willTouchBottomBar: {
|
readonly property bool willTouchBottomBar: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (!allowAttachToBar || root.barPosition !== "bottom" || root.barIsVertical)
|
if (!allowAttachToBar || root.barPosition !== "bottom" || root.barIsVertical)
|
||||||
return false
|
return false;
|
||||||
var targetBottomBarY = root.height - root.barMarginV - Style.barHeight - panelBackground.targetHeight
|
var targetBottomBarY = root.height - root.barMarginV - Style.barHeight - panelBackground.targetHeight;
|
||||||
return Math.abs(panelBackground.targetY - targetBottomBarY) <= 1
|
return Math.abs(panelBackground.targetY - targetBottomBarY) <= 1;
|
||||||
}
|
}
|
||||||
readonly property bool willTouchLeftBar: {
|
readonly property bool willTouchLeftBar: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (!allowAttachToBar || root.barPosition !== "left" || !root.barIsVertical)
|
if (!allowAttachToBar || root.barPosition !== "left" || !root.barIsVertical)
|
||||||
return false
|
return false;
|
||||||
var targetLeftBarX = root.barMarginH + Style.barHeight
|
var targetLeftBarX = root.barMarginH + Style.barHeight;
|
||||||
return Math.abs(panelBackground.targetX - targetLeftBarX) <= 1
|
return Math.abs(panelBackground.targetX - targetLeftBarX) <= 1;
|
||||||
}
|
}
|
||||||
readonly property bool willTouchRightBar: {
|
readonly property bool willTouchRightBar: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (!allowAttachToBar || root.barPosition !== "right" || !root.barIsVertical)
|
if (!allowAttachToBar || root.barPosition !== "right" || !root.barIsVertical)
|
||||||
return false
|
return false;
|
||||||
var targetRightBarX = root.width - root.barMarginH - Style.barHeight - panelBackground.targetWidth
|
var targetRightBarX = root.width - root.barMarginH - Style.barHeight - panelBackground.targetWidth;
|
||||||
return Math.abs(panelBackground.targetX - targetRightBarX) <= 1
|
return Math.abs(panelBackground.targetX - targetRightBarX) <= 1;
|
||||||
}
|
}
|
||||||
readonly property bool willTouchTopEdge: isPanelVisible && allowAttach && panelBackground.targetY <= 1
|
readonly property bool willTouchTopEdge: isPanelVisible && allowAttach && panelBackground.targetY <= 1
|
||||||
readonly property bool willTouchBottomEdge: isPanelVisible && allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1)
|
readonly property bool willTouchBottomEdge: isPanelVisible && allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1)
|
||||||
@@ -506,59 +505,59 @@ Item {
|
|||||||
|
|
||||||
readonly property bool isActuallyAttachedToAnyEdge: {
|
readonly property bool isActuallyAttachedToAnyEdge: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
return willTouchTopBar || willTouchBottomBar || willTouchLeftBar || willTouchRightBar || willTouchTopEdge || willTouchBottomEdge || willTouchLeftEdge || willTouchRightEdge
|
return willTouchTopBar || willTouchBottomBar || willTouchLeftBar || willTouchRightBar || willTouchTopEdge || willTouchBottomEdge || willTouchLeftEdge || willTouchRightEdge;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool animateFromTop: {
|
readonly property bool animateFromTop: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return true
|
return true;
|
||||||
if (willTouchTopBar)
|
if (willTouchTopBar)
|
||||||
return true
|
return true;
|
||||||
if (willTouchTopEdge && !willTouchTopBar && !willTouchBottomBar && !willTouchLeftBar && !willTouchRightBar)
|
if (willTouchTopEdge && !willTouchTopBar && !willTouchBottomBar && !willTouchLeftBar && !willTouchRightBar)
|
||||||
return true
|
return true;
|
||||||
if (!isActuallyAttachedToAnyEdge)
|
if (!isActuallyAttachedToAnyEdge)
|
||||||
return true
|
return true;
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
readonly property bool animateFromBottom: {
|
readonly property bool animateFromBottom: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (willTouchBottomBar)
|
if (willTouchBottomBar)
|
||||||
return true
|
return true;
|
||||||
if (willTouchBottomEdge && !willTouchTopBar && !willTouchBottomBar && !willTouchLeftBar && !willTouchRightBar)
|
if (willTouchBottomEdge && !willTouchTopBar && !willTouchBottomBar && !willTouchLeftBar && !willTouchRightBar)
|
||||||
return true
|
return true;
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
readonly property bool animateFromLeft: {
|
readonly property bool animateFromLeft: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (willTouchTopBar || willTouchBottomBar)
|
if (willTouchTopBar || willTouchBottomBar)
|
||||||
return false
|
return false;
|
||||||
if (willTouchLeftBar)
|
if (willTouchLeftBar)
|
||||||
return true
|
return true;
|
||||||
var touchingTopEdge = isPanelVisible && allowAttach && panelBackground.targetY <= 1
|
var touchingTopEdge = isPanelVisible && allowAttach && panelBackground.targetY <= 1;
|
||||||
var touchingBottomEdge = isPanelVisible && allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1)
|
var touchingBottomEdge = isPanelVisible && allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1);
|
||||||
if (touchingTopEdge || touchingBottomEdge)
|
if (touchingTopEdge || touchingBottomEdge)
|
||||||
return false
|
return false;
|
||||||
if (willTouchLeftEdge && !willTouchLeftBar && !willTouchTopBar && !willTouchBottomBar && !willTouchRightBar)
|
if (willTouchLeftEdge && !willTouchLeftBar && !willTouchTopBar && !willTouchBottomBar && !willTouchRightBar)
|
||||||
return true
|
return true;
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
readonly property bool animateFromRight: {
|
readonly property bool animateFromRight: {
|
||||||
if (!isPanelVisible)
|
if (!isPanelVisible)
|
||||||
return false
|
return false;
|
||||||
if (willTouchTopBar || willTouchBottomBar)
|
if (willTouchTopBar || willTouchBottomBar)
|
||||||
return false
|
return false;
|
||||||
if (willTouchRightBar)
|
if (willTouchRightBar)
|
||||||
return true
|
return true;
|
||||||
var touchingTopEdge = isPanelVisible && allowAttach && panelBackground.targetY <= 1
|
var touchingTopEdge = isPanelVisible && allowAttach && panelBackground.targetY <= 1;
|
||||||
var touchingBottomEdge = isPanelVisible && allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1)
|
var touchingBottomEdge = isPanelVisible && allowAttach && (panelBackground.targetY + panelBackground.targetHeight) >= (root.height - 1);
|
||||||
if (touchingTopEdge || touchingBottomEdge)
|
if (touchingTopEdge || touchingBottomEdge)
|
||||||
return false
|
return false;
|
||||||
if (willTouchRightEdge && !willTouchLeftBar && !willTouchTopBar && !willTouchBottomBar && !willTouchRightBar)
|
if (willTouchRightEdge && !willTouchLeftBar && !willTouchTopBar && !willTouchBottomBar && !willTouchRightBar)
|
||||||
return true
|
return true;
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property bool shouldAnimateWidth: !shouldAnimateHeight && (animateFromLeft || animateFromRight)
|
readonly property bool shouldAnimateWidth: !shouldAnimateHeight && (animateFromLeft || animateFromRight)
|
||||||
@@ -567,17 +566,17 @@ Item {
|
|||||||
// Current animated width/height
|
// Current animated width/height
|
||||||
readonly property real currentWidth: {
|
readonly property real currentWidth: {
|
||||||
if (isClosing && opacityFadeComplete && shouldAnimateWidth)
|
if (isClosing && opacityFadeComplete && shouldAnimateWidth)
|
||||||
return 0
|
return 0;
|
||||||
if (isClosing || isPanelVisible)
|
if (isClosing || isPanelVisible)
|
||||||
return targetWidth
|
return targetWidth;
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
readonly property real currentHeight: {
|
readonly property real currentHeight: {
|
||||||
if (isClosing && opacityFadeComplete && shouldAnimateHeight)
|
if (isClosing && opacityFadeComplete && shouldAnimateHeight)
|
||||||
return 0
|
return 0;
|
||||||
if (isClosing || isPanelVisible)
|
if (isClosing || isPanelVisible)
|
||||||
return targetHeight
|
return targetHeight;
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
width: currentWidth
|
width: currentWidth
|
||||||
@@ -586,28 +585,28 @@ Item {
|
|||||||
x: {
|
x: {
|
||||||
if (animateFromRight) {
|
if (animateFromRight) {
|
||||||
if (isPanelVisible || isClosing) {
|
if (isPanelVisible || isClosing) {
|
||||||
var targetRightEdge = targetX + targetWidth
|
var targetRightEdge = targetX + targetWidth;
|
||||||
return targetRightEdge - width
|
return targetRightEdge - width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return targetX
|
return targetX;
|
||||||
}
|
}
|
||||||
y: {
|
y: {
|
||||||
if (animateFromBottom) {
|
if (animateFromBottom) {
|
||||||
if (isPanelVisible || isClosing) {
|
if (isPanelVisible || isClosing) {
|
||||||
var targetBottomEdge = targetY + targetHeight
|
var targetBottomEdge = targetY + targetHeight;
|
||||||
return targetBottomEdge - height
|
return targetBottomEdge - height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return targetY
|
return targetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on width {
|
Behavior on width {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: {
|
duration: {
|
||||||
if (!panelBackground.shouldAnimateWidth)
|
if (!panelBackground.shouldAnimateWidth)
|
||||||
return 0
|
return 0;
|
||||||
return root.isClosing ? Style.animationFast : Style.animationNormal
|
return root.isClosing ? Style.animationFast : Style.animationNormal;
|
||||||
}
|
}
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: panelBackground.bezierCurve
|
easing.bezierCurve: panelBackground.bezierCurve
|
||||||
@@ -618,8 +617,8 @@ Item {
|
|||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
duration: {
|
duration: {
|
||||||
if (!panelBackground.shouldAnimateHeight)
|
if (!panelBackground.shouldAnimateHeight)
|
||||||
return 0
|
return 0;
|
||||||
return root.isClosing ? Style.animationFast : Style.animationNormal
|
return root.isClosing ? Style.animationFast : Style.animationNormal;
|
||||||
}
|
}
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
easing.bezierCurve: panelBackground.bezierCurve
|
easing.bezierCurve: panelBackground.bezierCurve
|
||||||
@@ -628,75 +627,75 @@ Item {
|
|||||||
|
|
||||||
// Corner states for PanelBackground to read
|
// Corner states for PanelBackground to read
|
||||||
property int topLeftCornerState: {
|
property int topLeftCornerState: {
|
||||||
var barInverted = allowAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft))
|
var barInverted = allowAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft));
|
||||||
var barTouchInverted = touchingTopBar || touchingLeftBar
|
var barTouchInverted = touchingTopBar || touchingLeftBar;
|
||||||
var edgeInverted = allowAttach && (touchingLeftEdge || touchingTopEdge)
|
var edgeInverted = allowAttach && (touchingLeftEdge || touchingTopEdge);
|
||||||
var oppositeEdgeInverted = allowAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top")
|
var oppositeEdgeInverted = allowAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top");
|
||||||
|
|
||||||
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
||||||
if (touchingLeftEdge && touchingTopEdge)
|
if (touchingLeftEdge && touchingTopEdge)
|
||||||
return 0
|
return 0;
|
||||||
if (touchingLeftEdge)
|
if (touchingLeftEdge)
|
||||||
return 2
|
return 2;
|
||||||
if (touchingTopEdge)
|
if (touchingTopEdge)
|
||||||
return 1
|
return 1;
|
||||||
return root.barIsVertical ? 2 : 1
|
return root.barIsVertical ? 2 : 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
property int topRightCornerState: {
|
property int topRightCornerState: {
|
||||||
var barInverted = allowAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight))
|
var barInverted = allowAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight));
|
||||||
var barTouchInverted = touchingTopBar || touchingRightBar
|
var barTouchInverted = touchingTopBar || touchingRightBar;
|
||||||
var edgeInverted = allowAttach && (touchingRightEdge || touchingTopEdge)
|
var edgeInverted = allowAttach && (touchingRightEdge || touchingTopEdge);
|
||||||
var oppositeEdgeInverted = allowAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top")
|
var oppositeEdgeInverted = allowAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top");
|
||||||
|
|
||||||
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
||||||
if (touchingRightEdge && touchingTopEdge)
|
if (touchingRightEdge && touchingTopEdge)
|
||||||
return 0
|
return 0;
|
||||||
if (touchingRightEdge)
|
if (touchingRightEdge)
|
||||||
return 2
|
return 2;
|
||||||
if (touchingTopEdge)
|
if (touchingTopEdge)
|
||||||
return 1
|
return 1;
|
||||||
return root.barIsVertical ? 2 : 1
|
return root.barIsVertical ? 2 : 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
property int bottomLeftCornerState: {
|
property int bottomLeftCornerState: {
|
||||||
var barInverted = allowAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft))
|
var barInverted = allowAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft));
|
||||||
var barTouchInverted = touchingBottomBar || touchingLeftBar
|
var barTouchInverted = touchingBottomBar || touchingLeftBar;
|
||||||
var edgeInverted = allowAttach && (touchingLeftEdge || touchingBottomEdge)
|
var edgeInverted = allowAttach && (touchingLeftEdge || touchingBottomEdge);
|
||||||
var oppositeEdgeInverted = allowAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom")
|
var oppositeEdgeInverted = allowAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom");
|
||||||
|
|
||||||
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
||||||
if (touchingLeftEdge && touchingBottomEdge)
|
if (touchingLeftEdge && touchingBottomEdge)
|
||||||
return 0
|
return 0;
|
||||||
if (touchingLeftEdge)
|
if (touchingLeftEdge)
|
||||||
return 2
|
return 2;
|
||||||
if (touchingBottomEdge)
|
if (touchingBottomEdge)
|
||||||
return 1
|
return 1;
|
||||||
return root.barIsVertical ? 2 : 1
|
return root.barIsVertical ? 2 : 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
property int bottomRightCornerState: {
|
property int bottomRightCornerState: {
|
||||||
var barInverted = allowAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight))
|
var barInverted = allowAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight));
|
||||||
var barTouchInverted = touchingBottomBar || touchingRightBar
|
var barTouchInverted = touchingBottomBar || touchingRightBar;
|
||||||
var edgeInverted = allowAttach && (touchingRightEdge || touchingBottomEdge)
|
var edgeInverted = allowAttach && (touchingRightEdge || touchingBottomEdge);
|
||||||
var oppositeEdgeInverted = allowAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom")
|
var oppositeEdgeInverted = allowAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom");
|
||||||
|
|
||||||
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
if (barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted) {
|
||||||
if (touchingRightEdge && touchingBottomEdge)
|
if (touchingRightEdge && touchingBottomEdge)
|
||||||
return 0
|
return 0;
|
||||||
if (touchingRightEdge)
|
if (touchingRightEdge)
|
||||||
return 2
|
return 2;
|
||||||
if (touchingBottomEdge)
|
if (touchingBottomEdge)
|
||||||
return 1
|
return 1;
|
||||||
return root.barIsVertical ? 2 : 1
|
return root.barIsVertical ? 2 : 1;
|
||||||
}
|
}
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,13 +2,12 @@ import QtQuick
|
|||||||
import QtQuick.Shapes
|
import QtQuick.Shapes
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ScreenCorners - Shape component for rendering screen corners
|
* ScreenCorners - Shape component for rendering screen corners
|
||||||
*
|
*
|
||||||
* Renders concave corners at the screen edges to create a rounded screen effect.
|
* Renders concave corners at the screen edges to create a rounded screen effect.
|
||||||
* Self-contained Shape component (no shadows).
|
* Self-contained Shape component (no shadows).
|
||||||
*/
|
*/
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,14 @@ import Quickshell
|
|||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SmartPanel - Wrapper that creates placeholder + content window
|
* SmartPanel - Wrapper that creates placeholder + content window
|
||||||
*
|
*
|
||||||
* This component is a thin wrapper that maintains backward compatibility
|
* This component is a thin wrapper that maintains backward compatibility
|
||||||
* while splitting panel rendering into:
|
* while splitting panel rendering into:
|
||||||
* 1. PanelPlaceholder (in MainScreen, for background rendering)
|
* 1. PanelPlaceholder (in MainScreen, for background rendering)
|
||||||
* 2. SmartPanelWindow (separate window, for content)
|
* 2. SmartPanelWindow (separate window, for content)
|
||||||
*/
|
*/
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -59,60 +58,74 @@ Item {
|
|||||||
|
|
||||||
// Keyboard event handlers - these can be overridden by panel implementations
|
// Keyboard event handlers - these can be overridden by panel implementations
|
||||||
// Note: SmartPanelWindow directly calls these functions via panelWrapper reference
|
// Note: SmartPanelWindow directly calls these functions via panelWrapper reference
|
||||||
function onEscapePressed() {}
|
function onEscapePressed() {
|
||||||
function onTabPressed() {}
|
}
|
||||||
function onBackTabPressed() {}
|
function onTabPressed() {
|
||||||
function onUpPressed() {}
|
}
|
||||||
function onDownPressed() {}
|
function onBackTabPressed() {
|
||||||
function onLeftPressed() {}
|
}
|
||||||
function onRightPressed() {}
|
function onUpPressed() {
|
||||||
function onReturnPressed() {}
|
}
|
||||||
function onHomePressed() {}
|
function onDownPressed() {
|
||||||
function onEndPressed() {}
|
}
|
||||||
function onPageUpPressed() {}
|
function onLeftPressed() {
|
||||||
function onPageDownPressed() {}
|
}
|
||||||
function onCtrlJPressed() {}
|
function onRightPressed() {
|
||||||
function onCtrlKPressed() {}
|
}
|
||||||
|
function onReturnPressed() {
|
||||||
|
}
|
||||||
|
function onHomePressed() {
|
||||||
|
}
|
||||||
|
function onEndPressed() {
|
||||||
|
}
|
||||||
|
function onPageUpPressed() {
|
||||||
|
}
|
||||||
|
function onPageDownPressed() {
|
||||||
|
}
|
||||||
|
function onCtrlJPressed() {
|
||||||
|
}
|
||||||
|
function onCtrlKPressed() {
|
||||||
|
}
|
||||||
|
|
||||||
// Public control functions
|
// Public control functions
|
||||||
function toggle(buttonItem, buttonName) {
|
function toggle(buttonItem, buttonName) {
|
||||||
// Ensure window is created before toggling
|
// Ensure window is created before toggling
|
||||||
if (!root.windowActive) {
|
if (!root.windowActive) {
|
||||||
root.windowActive = true
|
root.windowActive = true;
|
||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
if (windowLoader.item) {
|
if (windowLoader.item) {
|
||||||
windowLoader.item.toggle(buttonItem, buttonName)
|
windowLoader.item.toggle(buttonItem, buttonName);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} else if (windowLoader.item) {
|
} else if (windowLoader.item) {
|
||||||
windowLoader.item.toggle(buttonItem, buttonName)
|
windowLoader.item.toggle(buttonItem, buttonName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(buttonItem, buttonName) {
|
function open(buttonItem, buttonName) {
|
||||||
// Ensure window is created before opening
|
// Ensure window is created before opening
|
||||||
if (!root.windowActive) {
|
if (!root.windowActive) {
|
||||||
root.windowActive = true
|
root.windowActive = true;
|
||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
if (windowLoader.item) {
|
if (windowLoader.item) {
|
||||||
windowLoader.item.open(buttonItem, buttonName)
|
windowLoader.item.open(buttonItem, buttonName);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
} else if (windowLoader.item) {
|
} else if (windowLoader.item) {
|
||||||
windowLoader.item.open(buttonItem, buttonName)
|
windowLoader.item.open(buttonItem, buttonName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
if (windowLoader.item) {
|
if (windowLoader.item) {
|
||||||
windowLoader.item.close()
|
windowLoader.item.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expose setPosition for panels that need to recalculate on settings changes
|
// Expose setPosition for panels that need to recalculate on settings changes
|
||||||
function setPosition() {
|
function setPosition() {
|
||||||
if (panelPlaceholder) {
|
if (panelPlaceholder) {
|
||||||
panelPlaceholder.setPosition()
|
panelPlaceholder.setPosition();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,11 +170,11 @@ Item {
|
|||||||
// Forward signals
|
// Forward signals
|
||||||
onPanelOpened: root.opened()
|
onPanelOpened: root.opened()
|
||||||
onPanelClosed: {
|
onPanelClosed: {
|
||||||
root.closed()
|
root.closed();
|
||||||
// Destroy the window after close animation completes
|
// Destroy the window after close animation completes
|
||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
root.windowActive = false
|
root.windowActive = false;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -172,9 +185,9 @@ Item {
|
|||||||
// Use Qt.callLater to ensure objectName is set by parent before registering
|
// Use Qt.callLater to ensure objectName is set by parent before registering
|
||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
if (!objectName) {
|
if (!objectName) {
|
||||||
Logger.w("SmartPanel", "Panel created without objectName - PanelService registration may fail")
|
Logger.w("SmartPanel", "Panel created without objectName - PanelService registration may fail");
|
||||||
}
|
}
|
||||||
PanelService.registerPanel(root)
|
PanelService.registerPanel(root);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,12 @@ import qs.Commons
|
|||||||
import qs.Services.Compositor
|
import qs.Services.Compositor
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SmartPanelWindow - Separate window for panel content
|
* SmartPanelWindow - Separate window for panel content
|
||||||
*
|
*
|
||||||
* This component runs in its own window, separate from MainScreen.
|
* This component runs in its own window, separate from MainScreen.
|
||||||
* It follows the PanelPlaceholder for positioning and contains the actual panel content.
|
* It follows the PanelPlaceholder for positioning and contains the actual panel content.
|
||||||
*/
|
*/
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -63,13 +62,13 @@ PanelWindow {
|
|||||||
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
WlrLayershell.exclusionMode: ExclusionMode.Ignore
|
||||||
WlrLayershell.keyboardFocus: {
|
WlrLayershell.keyboardFocus: {
|
||||||
if (!root.isPanelOpen) {
|
if (!root.isPanelOpen) {
|
||||||
return WlrKeyboardFocus.None
|
return WlrKeyboardFocus.None;
|
||||||
}
|
}
|
||||||
if (CompositorService.isHyprland) {
|
if (CompositorService.isHyprland) {
|
||||||
// Exclusive focus on hyprland is too restrictive.
|
// Exclusive focus on hyprland is too restrictive.
|
||||||
return WlrKeyboardFocus.OnDemand
|
return WlrKeyboardFocus.OnDemand;
|
||||||
} else {
|
} else {
|
||||||
return root.exclusiveKeyboard ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.OnDemand
|
return root.exclusiveKeyboard ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.OnDemand;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,95 +90,95 @@ PanelWindow {
|
|||||||
|
|
||||||
// Sync state to placeholder
|
// Sync state to placeholder
|
||||||
onIsPanelVisibleChanged: {
|
onIsPanelVisibleChanged: {
|
||||||
placeholder.isPanelVisible = isPanelVisible
|
placeholder.isPanelVisible = isPanelVisible;
|
||||||
}
|
}
|
||||||
onIsClosingChanged: {
|
onIsClosingChanged: {
|
||||||
placeholder.isClosing = isClosing
|
placeholder.isClosing = isClosing;
|
||||||
}
|
}
|
||||||
onOpacityFadeCompleteChanged: {
|
onOpacityFadeCompleteChanged: {
|
||||||
placeholder.opacityFadeComplete = opacityFadeComplete
|
placeholder.opacityFadeComplete = opacityFadeComplete;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Panel control functions
|
// Panel control functions
|
||||||
function toggle(buttonItem, buttonName) {
|
function toggle(buttonItem, buttonName) {
|
||||||
if (!isPanelOpen) {
|
if (!isPanelOpen) {
|
||||||
open(buttonItem, buttonName)
|
open(buttonItem, buttonName);
|
||||||
} else {
|
} else {
|
||||||
close()
|
close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function open(buttonItem, buttonName) {
|
function open(buttonItem, buttonName) {
|
||||||
if (!buttonItem && buttonName) {
|
if (!buttonItem && buttonName) {
|
||||||
buttonItem = BarService.lookupWidget(buttonName, placeholder.screen.name)
|
buttonItem = BarService.lookupWidget(buttonName, placeholder.screen.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buttonItem) {
|
if (buttonItem) {
|
||||||
placeholder.buttonItem = buttonItem
|
placeholder.buttonItem = buttonItem;
|
||||||
// Map button position to screen coordinates
|
// Map button position to screen coordinates
|
||||||
var buttonPos = buttonItem.mapToItem(null, 0, 0)
|
var buttonPos = buttonItem.mapToItem(null, 0, 0);
|
||||||
placeholder.buttonPosition = Qt.point(buttonPos.x, buttonPos.y)
|
placeholder.buttonPosition = Qt.point(buttonPos.x, buttonPos.y);
|
||||||
placeholder.buttonWidth = buttonItem.width
|
placeholder.buttonWidth = buttonItem.width;
|
||||||
placeholder.buttonHeight = buttonItem.height
|
placeholder.buttonHeight = buttonItem.height;
|
||||||
placeholder.useButtonPosition = true
|
placeholder.useButtonPosition = true;
|
||||||
} else {
|
} else {
|
||||||
// No button provided: reset button position mode
|
// No button provided: reset button position mode
|
||||||
placeholder.buttonItem = null
|
placeholder.buttonItem = null;
|
||||||
placeholder.useButtonPosition = false
|
placeholder.useButtonPosition = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set isPanelOpen to trigger content loading
|
// Set isPanelOpen to trigger content loading
|
||||||
isPanelOpen = true
|
isPanelOpen = true;
|
||||||
|
|
||||||
// Notify PanelService
|
// Notify PanelService
|
||||||
PanelService.willOpenPanel(root)
|
PanelService.willOpenPanel(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
// Start close sequence: fade opacity first
|
// Start close sequence: fade opacity first
|
||||||
isClosing = true
|
isClosing = true;
|
||||||
sizeAnimationComplete = false
|
sizeAnimationComplete = false;
|
||||||
closeFinalized = false
|
closeFinalized = false;
|
||||||
|
|
||||||
// Stop the open animation timer if it's still running
|
// Stop the open animation timer if it's still running
|
||||||
opacityTrigger.stop()
|
opacityTrigger.stop();
|
||||||
openWatchdogActive = false
|
openWatchdogActive = false;
|
||||||
openWatchdogTimer.stop()
|
openWatchdogTimer.stop();
|
||||||
|
|
||||||
// Start close watchdog timer
|
// Start close watchdog timer
|
||||||
closeWatchdogActive = true
|
closeWatchdogActive = true;
|
||||||
closeWatchdogTimer.restart()
|
closeWatchdogTimer.restart();
|
||||||
|
|
||||||
// If opacity is already 0, skip directly to size animation
|
// If opacity is already 0, skip directly to size animation
|
||||||
if (contentWrapper.opacity === 0.0) {
|
if (contentWrapper.opacity === 0.0) {
|
||||||
opacityFadeComplete = true
|
opacityFadeComplete = true;
|
||||||
} else {
|
} else {
|
||||||
opacityFadeComplete = false
|
opacityFadeComplete = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.d("SmartPanelWindow", "Closing panel", placeholder.panelName)
|
Logger.d("SmartPanelWindow", "Closing panel", placeholder.panelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
function finalizeClose() {
|
function finalizeClose() {
|
||||||
// Prevent double-finalization
|
// Prevent double-finalization
|
||||||
if (root.closeFinalized) {
|
if (root.closeFinalized) {
|
||||||
Logger.w("SmartPanelWindow", "finalizeClose called but already finalized - ignoring", placeholder.panelName)
|
Logger.w("SmartPanelWindow", "finalizeClose called but already finalized - ignoring", placeholder.panelName);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete the close sequence after animations finish
|
// Complete the close sequence after animations finish
|
||||||
root.closeFinalized = true
|
root.closeFinalized = true;
|
||||||
root.closeWatchdogActive = false
|
root.closeWatchdogActive = false;
|
||||||
closeWatchdogTimer.stop()
|
closeWatchdogTimer.stop();
|
||||||
|
|
||||||
root.isPanelVisible = false
|
root.isPanelVisible = false;
|
||||||
root.isPanelOpen = false
|
root.isPanelOpen = false;
|
||||||
root.isClosing = false
|
root.isClosing = false;
|
||||||
root.opacityFadeComplete = false
|
root.opacityFadeComplete = false;
|
||||||
PanelService.closedPanel(root)
|
PanelService.closedPanel(root);
|
||||||
panelClosed()
|
panelClosed();
|
||||||
|
|
||||||
Logger.d("SmartPanelWindow", "Panel close finalized", placeholder.panelName)
|
Logger.d("SmartPanelWindow", "Panel close finalized", placeholder.panelName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fullscreen container for click-to-close and content
|
// Fullscreen container for click-to-close and content
|
||||||
@@ -189,59 +188,59 @@ PanelWindow {
|
|||||||
|
|
||||||
// Handle keyboard events directly via Keys handler
|
// Handle keyboard events directly via Keys handler
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
Logger.d("SmartPanelWindow", "Key pressed:", event.key, "for panel:", placeholder.panelName)
|
Logger.d("SmartPanelWindow", "Key pressed:", event.key, "for panel:", placeholder.panelName);
|
||||||
if (event.key === Qt.Key_Escape) {
|
if (event.key === Qt.Key_Escape) {
|
||||||
panelWrapper.onEscapePressed()
|
panelWrapper.onEscapePressed();
|
||||||
if (closeWithEscape) {
|
if (closeWithEscape) {
|
||||||
root.close()
|
root.close();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
} else if (panelWrapper) {
|
} else if (panelWrapper) {
|
||||||
if (event.key === Qt.Key_Up && panelWrapper.onUpPressed) {
|
if (event.key === Qt.Key_Up && panelWrapper.onUpPressed) {
|
||||||
panelWrapper.onUpPressed()
|
panelWrapper.onUpPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Down && panelWrapper.onDownPressed) {
|
} else if (event.key === Qt.Key_Down && panelWrapper.onDownPressed) {
|
||||||
panelWrapper.onDownPressed()
|
panelWrapper.onDownPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Left && panelWrapper.onLeftPressed) {
|
} else if (event.key === Qt.Key_Left && panelWrapper.onLeftPressed) {
|
||||||
panelWrapper.onLeftPressed()
|
panelWrapper.onLeftPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Right && panelWrapper.onRightPressed) {
|
} else if (event.key === Qt.Key_Right && panelWrapper.onRightPressed) {
|
||||||
panelWrapper.onRightPressed()
|
panelWrapper.onRightPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Tab && panelWrapper.onTabPressed) {
|
} else if (event.key === Qt.Key_Tab && panelWrapper.onTabPressed) {
|
||||||
panelWrapper.onTabPressed()
|
panelWrapper.onTabPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Backtab && panelWrapper.onBackTabPressed) {
|
} else if (event.key === Qt.Key_Backtab && panelWrapper.onBackTabPressed) {
|
||||||
panelWrapper.onBackTabPressed()
|
panelWrapper.onBackTabPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && panelWrapper.onReturnPressed) {
|
} else if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && panelWrapper.onReturnPressed) {
|
||||||
panelWrapper.onReturnPressed()
|
panelWrapper.onReturnPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Home && panelWrapper.onHomePressed) {
|
} else if (event.key === Qt.Key_Home && panelWrapper.onHomePressed) {
|
||||||
panelWrapper.onHomePressed()
|
panelWrapper.onHomePressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_End && panelWrapper.onEndPressed) {
|
} else if (event.key === Qt.Key_End && panelWrapper.onEndPressed) {
|
||||||
panelWrapper.onEndPressed()
|
panelWrapper.onEndPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_PageUp && panelWrapper.onPageUpPressed) {
|
} else if (event.key === Qt.Key_PageUp && panelWrapper.onPageUpPressed) {
|
||||||
panelWrapper.onPageUpPressed()
|
panelWrapper.onPageUpPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_PageDown && panelWrapper.onPageDownPressed) {
|
} else if (event.key === Qt.Key_PageDown && panelWrapper.onPageDownPressed) {
|
||||||
panelWrapper.onPageDownPressed()
|
panelWrapper.onPageDownPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_J && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlJPressed) {
|
} else if (event.key === Qt.Key_J && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlJPressed) {
|
||||||
panelWrapper.onCtrlJPressed()
|
panelWrapper.onCtrlJPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_K && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlKPressed) {
|
} else if (event.key === Qt.Key_K && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlKPressed) {
|
||||||
panelWrapper.onCtrlKPressed()
|
panelWrapper.onCtrlKPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_N && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlNPressed) {
|
} else if (event.key === Qt.Key_N && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlNPressed) {
|
||||||
panelWrapper.onCtrlNPressed()
|
panelWrapper.onCtrlNPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_P && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlPPressed) {
|
} else if (event.key === Qt.Key_P && (event.modifiers & Qt.ControlModifier) && panelWrapper.onCtrlPPressed) {
|
||||||
panelWrapper.onCtrlPPressed()
|
panelWrapper.onCtrlPPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -252,8 +251,8 @@ PanelWindow {
|
|||||||
enabled: root.isPanelOpen && !root.isClosing
|
enabled: root.isPanelOpen && !root.isClosing
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
root.close()
|
root.close();
|
||||||
mouse.accepted = true
|
mouse.accepted = true;
|
||||||
}
|
}
|
||||||
z: 0
|
z: 0
|
||||||
}
|
}
|
||||||
@@ -271,10 +270,10 @@ PanelWindow {
|
|||||||
// Opacity animation
|
// Opacity animation
|
||||||
opacity: {
|
opacity: {
|
||||||
if (isClosing)
|
if (isClosing)
|
||||||
return 0.0
|
return 0.0;
|
||||||
if (isPanelVisible && sizeAnimationComplete)
|
if (isPanelVisible && sizeAnimationComplete)
|
||||||
return 1.0
|
return 1.0;
|
||||||
return 0.0
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on opacity {
|
Behavior on opacity {
|
||||||
@@ -287,33 +286,33 @@ PanelWindow {
|
|||||||
// Safety: Zero-duration animation handling
|
// Safety: Zero-duration animation handling
|
||||||
if (!running && duration === 0) {
|
if (!running && duration === 0) {
|
||||||
if (root.isClosing && contentWrapper.opacity === 0.0) {
|
if (root.isClosing && contentWrapper.opacity === 0.0) {
|
||||||
root.opacityFadeComplete = true
|
root.opacityFadeComplete = true;
|
||||||
var shouldFinalizeNow = placeholder.panelItem && !placeholder.panelItem.shouldAnimateWidth && !placeholder.panelItem.shouldAnimateHeight
|
var shouldFinalizeNow = placeholder.panelItem && !placeholder.panelItem.shouldAnimateWidth && !placeholder.panelItem.shouldAnimateHeight;
|
||||||
if (shouldFinalizeNow) {
|
if (shouldFinalizeNow) {
|
||||||
Logger.d("SmartPanelWindow", "Zero-duration opacity + no size animation - finalizing", placeholder.panelName)
|
Logger.d("SmartPanelWindow", "Zero-duration opacity + no size animation - finalizing", placeholder.panelName);
|
||||||
Qt.callLater(root.finalizeClose)
|
Qt.callLater(root.finalizeClose);
|
||||||
}
|
}
|
||||||
} else if (root.isPanelVisible && contentWrapper.opacity === 1.0) {
|
} else if (root.isPanelVisible && contentWrapper.opacity === 1.0) {
|
||||||
root.openWatchdogActive = false
|
root.openWatchdogActive = false;
|
||||||
openWatchdogTimer.stop()
|
openWatchdogTimer.stop();
|
||||||
}
|
}
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// When opacity fade completes during close, trigger size animation
|
// When opacity fade completes during close, trigger size animation
|
||||||
if (!running && root.isClosing && contentWrapper.opacity === 0.0) {
|
if (!running && root.isClosing && contentWrapper.opacity === 0.0) {
|
||||||
root.opacityFadeComplete = true
|
root.opacityFadeComplete = true;
|
||||||
var shouldFinalizeNow = placeholder.panelItem && !placeholder.panelItem.shouldAnimateWidth && !placeholder.panelItem.shouldAnimateHeight
|
var shouldFinalizeNow = placeholder.panelItem && !placeholder.panelItem.shouldAnimateWidth && !placeholder.panelItem.shouldAnimateHeight;
|
||||||
if (shouldFinalizeNow) {
|
if (shouldFinalizeNow) {
|
||||||
Logger.d("SmartPanelWindow", "No animation - finalizing immediately", placeholder.panelName)
|
Logger.d("SmartPanelWindow", "No animation - finalizing immediately", placeholder.panelName);
|
||||||
Qt.callLater(root.finalizeClose)
|
Qt.callLater(root.finalizeClose);
|
||||||
} else {
|
} else {
|
||||||
Logger.d("SmartPanelWindow", "Animation will run - waiting for size animation", placeholder.panelName)
|
Logger.d("SmartPanelWindow", "Animation will run - waiting for size animation", placeholder.panelName);
|
||||||
}
|
}
|
||||||
} // When opacity fade completes during open, stop watchdog
|
} // When opacity fade completes during open, stop watchdog
|
||||||
else if (!running && root.isPanelVisible && contentWrapper.opacity === 1.0) {
|
else if (!running && root.isPanelVisible && contentWrapper.opacity === 1.0) {
|
||||||
root.openWatchdogActive = false
|
root.openWatchdogActive = false;
|
||||||
openWatchdogTimer.stop()
|
openWatchdogTimer.stop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -330,31 +329,31 @@ PanelWindow {
|
|||||||
onLoaded: {
|
onLoaded: {
|
||||||
// Capture initial content-driven size if available
|
// Capture initial content-driven size if available
|
||||||
if (contentLoader.item) {
|
if (contentLoader.item) {
|
||||||
var hasWidthProp = contentLoader.item.hasOwnProperty('contentPreferredWidth')
|
var hasWidthProp = contentLoader.item.hasOwnProperty('contentPreferredWidth');
|
||||||
var hasHeightProp = contentLoader.item.hasOwnProperty('contentPreferredHeight')
|
var hasHeightProp = contentLoader.item.hasOwnProperty('contentPreferredHeight');
|
||||||
|
|
||||||
if (hasWidthProp || hasHeightProp) {
|
if (hasWidthProp || hasHeightProp) {
|
||||||
var initialWidth = hasWidthProp ? contentLoader.item.contentPreferredWidth : 0
|
var initialWidth = hasWidthProp ? contentLoader.item.contentPreferredWidth : 0;
|
||||||
var initialHeight = hasHeightProp ? contentLoader.item.contentPreferredHeight : 0
|
var initialHeight = hasHeightProp ? contentLoader.item.contentPreferredHeight : 0;
|
||||||
placeholder.updateContentSize(initialWidth, initialHeight)
|
placeholder.updateContentSize(initialWidth, initialHeight);
|
||||||
Logger.d("SmartPanelWindow", "Initial content size:", initialWidth, "x", initialHeight, placeholder.panelName)
|
Logger.d("SmartPanelWindow", "Initial content size:", initialWidth, "x", initialHeight, placeholder.panelName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate position in placeholder
|
// Calculate position in placeholder
|
||||||
placeholder.setPosition()
|
placeholder.setPosition();
|
||||||
|
|
||||||
// Make panel visible on the next frame
|
// Make panel visible on the next frame
|
||||||
Qt.callLater(function () {
|
Qt.callLater(function () {
|
||||||
root.isPanelVisible = true
|
root.isPanelVisible = true;
|
||||||
opacityTrigger.start()
|
opacityTrigger.start();
|
||||||
|
|
||||||
// Start open watchdog timer
|
// Start open watchdog timer
|
||||||
root.openWatchdogActive = true
|
root.openWatchdogActive = true;
|
||||||
openWatchdogTimer.start()
|
openWatchdogTimer.start();
|
||||||
|
|
||||||
panelOpened()
|
panelOpened();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -363,7 +362,7 @@ PanelWindow {
|
|||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
mouse.accepted = true // Eat the click to prevent propagation to background
|
mouse.accepted = true; // Eat the click to prevent propagation to background
|
||||||
}
|
}
|
||||||
z: -1 // Behind content but above background click-to-close
|
z: -1 // Behind content but above background click-to-close
|
||||||
}
|
}
|
||||||
@@ -375,13 +374,13 @@ PanelWindow {
|
|||||||
|
|
||||||
function onContentPreferredWidthChanged() {
|
function onContentPreferredWidthChanged() {
|
||||||
if (root.isPanelOpen && root.isPanelVisible && contentLoader.item) {
|
if (root.isPanelOpen && root.isPanelVisible && contentLoader.item) {
|
||||||
placeholder.updateContentSize(contentLoader.item.contentPreferredWidth, placeholder.contentPreferredHeight)
|
placeholder.updateContentSize(contentLoader.item.contentPreferredWidth, placeholder.contentPreferredHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onContentPreferredHeightChanged() {
|
function onContentPreferredHeightChanged() {
|
||||||
if (root.isPanelOpen && root.isPanelVisible && contentLoader.item) {
|
if (root.isPanelOpen && root.isPanelVisible && contentLoader.item) {
|
||||||
placeholder.updateContentSize(placeholder.contentPreferredWidth, contentLoader.item.contentPreferredHeight)
|
placeholder.updateContentSize(placeholder.contentPreferredWidth, contentLoader.item.contentPreferredHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,7 +394,7 @@ PanelWindow {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (root.isPanelVisible) {
|
if (root.isPanelVisible) {
|
||||||
root.sizeAnimationComplete = true
|
root.sizeAnimationComplete = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,11 +406,11 @@ PanelWindow {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (root.openWatchdogActive) {
|
if (root.openWatchdogActive) {
|
||||||
Logger.w("SmartPanelWindow", "Open watchdog timeout - forcing panel visible state", placeholder.panelName)
|
Logger.w("SmartPanelWindow", "Open watchdog timeout - forcing panel visible state", placeholder.panelName);
|
||||||
root.openWatchdogActive = false
|
root.openWatchdogActive = false;
|
||||||
if (root.isPanelOpen && !root.isPanelVisible) {
|
if (root.isPanelOpen && !root.isPanelVisible) {
|
||||||
root.isPanelVisible = true
|
root.isPanelVisible = true;
|
||||||
root.sizeAnimationComplete = true
|
root.sizeAnimationComplete = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,8 +423,8 @@ PanelWindow {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (root.closeWatchdogActive && !root.closeFinalized) {
|
if (root.closeWatchdogActive && !root.closeFinalized) {
|
||||||
Logger.w("SmartPanelWindow", "Close watchdog timeout - forcing panel close", placeholder.panelName)
|
Logger.w("SmartPanelWindow", "Close watchdog timeout - forcing panel close", placeholder.panelName);
|
||||||
Qt.callLater(root.finalizeClose)
|
Qt.callLater(root.finalizeClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -437,14 +436,14 @@ PanelWindow {
|
|||||||
function onWidthChanged() {
|
function onWidthChanged() {
|
||||||
// When width shrinks to 0 during close and we're animating width, finalize
|
// When width shrinks to 0 during close and we're animating width, finalize
|
||||||
if (root.isClosing && placeholder.panelItem.width === 0 && placeholder.panelItem.shouldAnimateWidth) {
|
if (root.isClosing && placeholder.panelItem.width === 0 && placeholder.panelItem.shouldAnimateWidth) {
|
||||||
Qt.callLater(root.finalizeClose)
|
Qt.callLater(root.finalizeClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHeightChanged() {
|
function onHeightChanged() {
|
||||||
// When height shrinks to 0 during close and we're animating height, finalize
|
// When height shrinks to 0 during close and we're animating height, finalize
|
||||||
if (root.isClosing && placeholder.panelItem.height === 0 && placeholder.panelItem.shouldAnimateHeight) {
|
if (root.isClosing && placeholder.panelItem.height === 0 && placeholder.panelItem.shouldAnimateHeight) {
|
||||||
Qt.callLater(root.finalizeClose)
|
Qt.callLater(root.finalizeClose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import QtQuick
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Modules.Bar.Extras
|
import qs.Modules.Bar.Extras
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
// Separate window for TrayMenu context menus
|
// Separate window for TrayMenu context menus
|
||||||
// This is a top-level PanelWindow (sibling to MainScreen, not nested inside it)
|
// This is a top-level PanelWindow (sibling to MainScreen, not nested inside it)
|
||||||
@@ -30,18 +30,18 @@ PanelWindow {
|
|||||||
|
|
||||||
// Register with PanelService so panels can find this window
|
// Register with PanelService so panels can find this window
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
objectName = "trayMenuWindow-" + (screen?.name || "unknown")
|
objectName = "trayMenuWindow-" + (screen?.name || "unknown");
|
||||||
PanelService.registerTrayMenuWindow(screen, root)
|
PanelService.registerTrayMenuWindow(screen, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
function open() {
|
function open() {
|
||||||
visible = true
|
visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function close() {
|
function close() {
|
||||||
visible = false
|
visible = false;
|
||||||
if (trayMenu.item) {
|
if (trayMenu.item) {
|
||||||
trayMenu.item.hideMenu()
|
trayMenu.item.hideMenu();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,7 +56,7 @@ PanelWindow {
|
|||||||
source: Quickshell.shellDir + "/Modules/Bar/Extras/TrayMenu.qml"
|
source: Quickshell.shellDir + "/Modules/Bar/Extras/TrayMenu.qml"
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (item) {
|
if (item) {
|
||||||
item.screen = root.screen
|
item.screen = root.screen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import QtQuick
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Services.Notifications
|
import Quickshell.Services.Notifications
|
||||||
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
@@ -35,7 +35,7 @@ Variants {
|
|||||||
target: notificationModel
|
target: notificationModel
|
||||||
function onCountChanged() {
|
function onCountChanged() {
|
||||||
if (notificationModel.count === 0 && root.active) {
|
if (notificationModel.count === 0 && root.active) {
|
||||||
delayTimer.restart()
|
delayTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,30 +66,30 @@ Variants {
|
|||||||
// Calculate bar offsets for each edge separately
|
// Calculate bar offsets for each edge separately
|
||||||
readonly property int barOffsetTop: {
|
readonly property int barOffsetTop: {
|
||||||
if (barPos !== "top")
|
if (barPos !== "top")
|
||||||
return 0
|
return 0;
|
||||||
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
|
||||||
return Style.barHeight + floatMarginV
|
return Style.barHeight + floatMarginV;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int barOffsetBottom: {
|
readonly property int barOffsetBottom: {
|
||||||
if (barPos !== "bottom")
|
if (barPos !== "bottom")
|
||||||
return 0
|
return 0;
|
||||||
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
|
const floatMarginV = isFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0;
|
||||||
return Style.barHeight + floatMarginV
|
return Style.barHeight + floatMarginV;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int barOffsetLeft: {
|
readonly property int barOffsetLeft: {
|
||||||
if (barPos !== "left")
|
if (barPos !== "left")
|
||||||
return 0
|
return 0;
|
||||||
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
|
||||||
return floatMarginH
|
return floatMarginH;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int barOffsetRight: {
|
readonly property int barOffsetRight: {
|
||||||
if (barPos !== "right")
|
if (barPos !== "right")
|
||||||
return 0
|
return 0;
|
||||||
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
|
const floatMarginH = isFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0;
|
||||||
return floatMarginH
|
return floatMarginH;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Anchoring
|
// Anchoring
|
||||||
@@ -111,31 +111,31 @@ Variants {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
animateConnection = function (notificationId) {
|
animateConnection = function (notificationId) {
|
||||||
var delegate = null
|
var delegate = null;
|
||||||
if (notificationRepeater) {
|
if (notificationRepeater) {
|
||||||
for (var i = 0; i < notificationRepeater.count; i++) {
|
for (var i = 0; i < notificationRepeater.count; i++) {
|
||||||
var item = notificationRepeater.itemAt(i)
|
var item = notificationRepeater.itemAt(i);
|
||||||
if (item?.notificationId === notificationId) {
|
if (item?.notificationId === notificationId) {
|
||||||
delegate = item
|
delegate = item;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delegate?.animateOut) {
|
if (delegate?.animateOut) {
|
||||||
delegate.animateOut()
|
delegate.animateOut();
|
||||||
} else {
|
} else {
|
||||||
NotificationService.dismissActiveNotification(notificationId)
|
NotificationService.dismissActiveNotification(notificationId);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
NotificationService.animateAndRemove.connect(animateConnection)
|
NotificationService.animateAndRemove.connect(animateConnection);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
if (animateConnection) {
|
if (animateConnection) {
|
||||||
NotificationService.animateAndRemove.disconnect(animateConnection)
|
NotificationService.animateAndRemove.disconnect(animateConnection);
|
||||||
animateConnection = null
|
animateConnection = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,8 +223,8 @@ Variants {
|
|||||||
width: parent.availableWidth * model.progress
|
width: parent.availableWidth * model.progress
|
||||||
|
|
||||||
color: {
|
color: {
|
||||||
var baseColor = model.urgency === 2 ? Color.mError : model.urgency === 0 ? Color.mOnSurface : Color.mPrimary
|
var baseColor = model.urgency === 2 ? Color.mError : model.urgency === 0 ? Color.mOnSurface : Color.mPrimary;
|
||||||
return Qt.alpha(baseColor, Settings.data.notifications.backgroundOpacity || 1.0)
|
return Qt.alpha(baseColor, Settings.data.notifications.backgroundOpacity || 1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
antialiasing: true
|
antialiasing: true
|
||||||
@@ -257,10 +257,10 @@ Variants {
|
|||||||
// Hover handling
|
// Hover handling
|
||||||
onHoverCountChanged: {
|
onHoverCountChanged: {
|
||||||
if (hoverCount > 0) {
|
if (hoverCount > 0) {
|
||||||
resumeTimer.stop()
|
resumeTimer.stop();
|
||||||
NotificationService.pauseTimeout(notificationId)
|
NotificationService.pauseTimeout(notificationId);
|
||||||
} else {
|
} else {
|
||||||
resumeTimer.start()
|
resumeTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +270,7 @@ Variants {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (hoverCount === 0) {
|
if (hoverCount === 0) {
|
||||||
NotificationService.resumeTimeout(notificationId)
|
NotificationService.resumeTimeout(notificationId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,30 +284,30 @@ Variants {
|
|||||||
onExited: parent.hoverCount--
|
onExited: parent.hoverCount--
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (mouse.button === Qt.RightButton) {
|
if (mouse.button === Qt.RightButton) {
|
||||||
animateOut()
|
animateOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Animation setup
|
// Animation setup
|
||||||
function triggerEntryAnimation() {
|
function triggerEntryAnimation() {
|
||||||
animInDelayTimer.stop()
|
animInDelayTimer.stop();
|
||||||
removalTimer.stop()
|
removalTimer.stop();
|
||||||
resumeTimer.stop()
|
resumeTimer.stop();
|
||||||
isRemoving = false
|
isRemoving = false;
|
||||||
hoverCount = 0
|
hoverCount = 0;
|
||||||
if (Settings.data.general.animationDisabled) {
|
if (Settings.data.general.animationDisabled) {
|
||||||
slideOffset = 0
|
slideOffset = 0;
|
||||||
scaleValue = 1.0
|
scaleValue = 1.0;
|
||||||
opacityValue = 1.0
|
opacityValue = 1.0;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
slideOffset = slideInOffset
|
slideOffset = slideInOffset;
|
||||||
scaleValue = 0.8
|
scaleValue = 0.8;
|
||||||
opacityValue = 0.0
|
opacityValue = 0.0;
|
||||||
animInDelayTimer.interval = animationDelay
|
animInDelayTimer.interval = animationDelay;
|
||||||
animInDelayTimer.start()
|
animInDelayTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: triggerEntryAnimation()
|
Component.onCompleted: triggerEntryAnimation()
|
||||||
@@ -320,23 +320,23 @@ Variants {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (card.isRemoving)
|
if (card.isRemoving)
|
||||||
return
|
return;
|
||||||
slideOffset = 0
|
slideOffset = 0;
|
||||||
scaleValue = 1.0
|
scaleValue = 1.0;
|
||||||
opacityValue = 1.0
|
opacityValue = 1.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function animateOut() {
|
function animateOut() {
|
||||||
if (isRemoving)
|
if (isRemoving)
|
||||||
return
|
return;
|
||||||
animInDelayTimer.stop()
|
animInDelayTimer.stop();
|
||||||
resumeTimer.stop()
|
resumeTimer.stop();
|
||||||
isRemoving = true
|
isRemoving = true;
|
||||||
if (!Settings.data.general.animationDisabled) {
|
if (!Settings.data.general.animationDisabled) {
|
||||||
slideOffset = slideOutOffset
|
slideOffset = slideOutOffset;
|
||||||
scaleValue = 0.8
|
scaleValue = 0.8;
|
||||||
opacityValue = 0.0
|
opacityValue = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,13 +345,13 @@ Variants {
|
|||||||
interval: Style.animationSlow
|
interval: Style.animationSlow
|
||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
NotificationService.dismissActiveNotification(notificationId)
|
NotificationService.dismissActiveNotification(notificationId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onIsRemovingChanged: {
|
onIsRemovingChanged: {
|
||||||
if (isRemoving) {
|
if (isRemoving) {
|
||||||
removalTimer.start()
|
removalTimer.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -478,9 +478,9 @@ Variants {
|
|||||||
property string parentNotificationId: notificationId
|
property string parentNotificationId: notificationId
|
||||||
property var parsedActions: {
|
property var parsedActions: {
|
||||||
try {
|
try {
|
||||||
return model.actionsJson ? JSON.parse(model.actionsJson) : []
|
return model.actionsJson ? JSON.parse(model.actionsJson) : [];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
visible: parsedActions.length > 0
|
visible: parsedActions.length > 0
|
||||||
@@ -495,11 +495,11 @@ Variants {
|
|||||||
onExited: card.hoverCount--
|
onExited: card.hoverCount--
|
||||||
|
|
||||||
text: {
|
text: {
|
||||||
var actionText = actionData.text || "Open"
|
var actionText = actionData.text || "Open";
|
||||||
if (actionText.includes(",")) {
|
if (actionText.includes(",")) {
|
||||||
return actionText.split(",")[1] || actionText
|
return actionText.split(",")[1] || actionText;
|
||||||
}
|
}
|
||||||
return actionText
|
return actionText;
|
||||||
}
|
}
|
||||||
fontSize: Style.fontSizeS
|
fontSize: Style.fontSizeS
|
||||||
backgroundColor: Color.mPrimary
|
backgroundColor: Color.mPrimary
|
||||||
@@ -508,7 +508,7 @@ Variants {
|
|||||||
outlined: false
|
outlined: false
|
||||||
implicitHeight: 24
|
implicitHeight: 24
|
||||||
onClicked: {
|
onClicked: {
|
||||||
NotificationService.invokeAction(parent.parentNotificationId, actionData.identifier)
|
NotificationService.invokeAction(parent.parentNotificationId, actionData.identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -528,8 +528,8 @@ Variants {
|
|||||||
anchors.rightMargin: Style.marginXL
|
anchors.rightMargin: Style.marginXL
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
NotificationService.removeFromHistory(model.id)
|
NotificationService.removeFromHistory(model.id);
|
||||||
animateOut()
|
animateOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Services.Pipewire
|
import Quickshell.Services.Pipewire
|
||||||
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Services.Hardware
|
import qs.Services.Hardware
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
// Unified OSD component that displays volume, input volume, and brightness changes
|
// Unified OSD component that displays volume, input volume, and brightness changes
|
||||||
Variants {
|
Variants {
|
||||||
@@ -52,54 +52,54 @@ Variants {
|
|||||||
switch (currentOSDType) {
|
switch (currentOSDType) {
|
||||||
case "volume":
|
case "volume":
|
||||||
if (isMuted)
|
if (isMuted)
|
||||||
return "volume-mute"
|
return "volume-mute";
|
||||||
if (currentVolume <= Number.EPSILON)
|
if (currentVolume <= Number.EPSILON)
|
||||||
return "volume-zero"
|
return "volume-zero";
|
||||||
return currentVolume <= 0.5 ? "volume-low" : "volume-high"
|
return currentVolume <= 0.5 ? "volume-low" : "volume-high";
|
||||||
case "inputVolume":
|
case "inputVolume":
|
||||||
return isInputMuted ? "microphone-off" : "microphone"
|
return isInputMuted ? "microphone-off" : "microphone";
|
||||||
case "brightness":
|
case "brightness":
|
||||||
return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high"
|
return currentBrightness <= 0.5 ? "brightness-low" : "brightness-high";
|
||||||
default:
|
default:
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCurrentValue() {
|
function getCurrentValue() {
|
||||||
switch (currentOSDType) {
|
switch (currentOSDType) {
|
||||||
case "volume":
|
case "volume":
|
||||||
return isMuted ? 0 : currentVolume
|
return isMuted ? 0 : currentVolume;
|
||||||
case "inputVolume":
|
case "inputVolume":
|
||||||
return isInputMuted ? 0 : currentInputVolume
|
return isInputMuted ? 0 : currentInputVolume;
|
||||||
case "brightness":
|
case "brightness":
|
||||||
return currentBrightness
|
return currentBrightness;
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMaxValue() {
|
function getMaxValue() {
|
||||||
if (currentOSDType === "volume" || currentOSDType === "inputVolume") {
|
if (currentOSDType === "volume" || currentOSDType === "inputVolume") {
|
||||||
return Settings.data.audio.volumeOverdrive ? 1.5 : 1.0
|
return Settings.data.audio.volumeOverdrive ? 1.5 : 1.0;
|
||||||
}
|
}
|
||||||
return 1.0
|
return 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getDisplayPercentage() {
|
function getDisplayPercentage() {
|
||||||
const value = getCurrentValue()
|
const value = getCurrentValue();
|
||||||
const max = getMaxValue()
|
const max = getMaxValue();
|
||||||
const pct = Math.round(Math.min(max, value) * 100)
|
const pct = Math.round(Math.min(max, value) * 100);
|
||||||
return pct + "%"
|
return pct + "%";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProgressColor() {
|
function getProgressColor() {
|
||||||
const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted)
|
const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted);
|
||||||
return isMutedState ? Color.mError : Color.mPrimary
|
return isMutedState ? Color.mError : Color.mPrimary;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIconColor() {
|
function getIconColor() {
|
||||||
const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted)
|
const isMutedState = (currentOSDType === "volume" && isMuted) || (currentOSDType === "inputVolume" && isInputMuted);
|
||||||
return isMutedState ? Color.mError : Color.mOnSurface
|
return isMutedState ? Color.mError : Color.mOnSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -108,35 +108,35 @@ Variants {
|
|||||||
function initializeAudioValues() {
|
function initializeAudioValues() {
|
||||||
// Initialize output volume
|
// Initialize output volume
|
||||||
if (AudioService.sink?.ready && AudioService.sink?.audio && lastKnownVolume < 0) {
|
if (AudioService.sink?.ready && AudioService.sink?.audio && lastKnownVolume < 0) {
|
||||||
const vol = AudioService.volume
|
const vol = AudioService.volume;
|
||||||
if (vol !== undefined && !isNaN(vol)) {
|
if (vol !== undefined && !isNaN(vol)) {
|
||||||
lastKnownVolume = vol
|
lastKnownVolume = vol;
|
||||||
volumeInitialized = true
|
volumeInitialized = true;
|
||||||
muteInitialized = true
|
muteInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize input volume
|
// Initialize input volume
|
||||||
if (AudioService.hasInput && AudioService.source?.ready && AudioService.source?.audio && lastKnownInputVolume < 0) {
|
if (AudioService.hasInput && AudioService.source?.ready && AudioService.source?.audio && lastKnownInputVolume < 0) {
|
||||||
const inputVol = AudioService.inputVolume
|
const inputVol = AudioService.inputVolume;
|
||||||
if (inputVol !== undefined && !isNaN(inputVol)) {
|
if (inputVol !== undefined && !isNaN(inputVol)) {
|
||||||
lastKnownInputVolume = inputVol
|
lastKnownInputVolume = inputVol;
|
||||||
inputInitialized = true
|
inputInitialized = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetOutputInit() {
|
function resetOutputInit() {
|
||||||
lastKnownVolume = -1
|
lastKnownVolume = -1;
|
||||||
volumeInitialized = false
|
volumeInitialized = false;
|
||||||
muteInitialized = false
|
muteInitialized = false;
|
||||||
Qt.callLater(initializeAudioValues)
|
Qt.callLater(initializeAudioValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetInputInit() {
|
function resetInputInit() {
|
||||||
lastKnownInputVolume = -1
|
lastKnownInputVolume = -1;
|
||||||
inputInitialized = false
|
inputInitialized = false;
|
||||||
Qt.callLater(initializeAudioValues)
|
Qt.callLater(initializeAudioValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
@@ -144,48 +144,48 @@ Variants {
|
|||||||
// ============================================================================
|
// ============================================================================
|
||||||
function connectBrightnessMonitors() {
|
function connectBrightnessMonitors() {
|
||||||
for (var i = 0; i < BrightnessService.monitors.length; i++) {
|
for (var i = 0; i < BrightnessService.monitors.length; i++) {
|
||||||
const monitor = BrightnessService.monitors[i]
|
const monitor = BrightnessService.monitors[i];
|
||||||
monitor.brightnessUpdated.disconnect(onBrightnessChanged)
|
monitor.brightnessUpdated.disconnect(onBrightnessChanged);
|
||||||
monitor.brightnessUpdated.connect(onBrightnessChanged)
|
monitor.brightnessUpdated.connect(onBrightnessChanged);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBrightnessChanged(newBrightness) {
|
function onBrightnessChanged(newBrightness) {
|
||||||
lastUpdatedBrightness = newBrightness
|
lastUpdatedBrightness = newBrightness;
|
||||||
|
|
||||||
if (!brightnessInitialized) {
|
if (!brightnessInitialized) {
|
||||||
brightnessInitialized = true
|
brightnessInitialized = true;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
showOSD("brightness")
|
showOSD("brightness");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
// OSD Display Control
|
// OSD Display Control
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
function showOSD(type) {
|
function showOSD(type) {
|
||||||
currentOSDType = type
|
currentOSDType = type;
|
||||||
|
|
||||||
if (!root.active) {
|
if (!root.active) {
|
||||||
root.active = true
|
root.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root.item) {
|
if (root.item) {
|
||||||
root.item.showOSD()
|
root.item.showOSD();
|
||||||
} else {
|
} else {
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (root.item)
|
if (root.item)
|
||||||
root.item.showOSD()
|
root.item.showOSD();
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideOSD() {
|
function hideOSD() {
|
||||||
if (root.item?.osdItem) {
|
if (root.item?.osdItem) {
|
||||||
root.item.osdItem.hideImmediately()
|
root.item.osdItem.hideImmediately();
|
||||||
} else if (root.active) {
|
} else if (root.active) {
|
||||||
root.active = false
|
root.active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,15 +199,15 @@ Variants {
|
|||||||
|
|
||||||
function onReadyChanged() {
|
function onReadyChanged() {
|
||||||
if (Pipewire.ready)
|
if (Pipewire.ready)
|
||||||
Qt.callLater(initializeAudioValues)
|
Qt.callLater(initializeAudioValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDefaultAudioSinkChanged() {
|
function onDefaultAudioSinkChanged() {
|
||||||
resetOutputInit()
|
resetOutputInit();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDefaultAudioSourceChanged() {
|
function onDefaultAudioSourceChanged() {
|
||||||
resetInputInit()
|
resetInputInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,72 +217,68 @@ Variants {
|
|||||||
|
|
||||||
function onSinkChanged() {
|
function onSinkChanged() {
|
||||||
if (AudioService.sink?.ready && AudioService.sink?.audio) {
|
if (AudioService.sink?.ready && AudioService.sink?.audio) {
|
||||||
resetOutputInit()
|
resetOutputInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSourceChanged() {
|
function onSourceChanged() {
|
||||||
if (AudioService.hasInput && AudioService.source?.ready && AudioService.source?.audio) {
|
if (AudioService.hasInput && AudioService.source?.ready && AudioService.source?.audio) {
|
||||||
resetInputInit()
|
resetInputInit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (lastKnownVolume < 0) {
|
if (lastKnownVolume < 0) {
|
||||||
initializeAudioValues()
|
initializeAudioValues();
|
||||||
if (lastKnownVolume < 0)
|
if (lastKnownVolume < 0)
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!volumeInitialized)
|
if (!volumeInitialized)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (Math.abs(AudioService.volume - lastKnownVolume) > 0.001) {
|
if (Math.abs(AudioService.volume - lastKnownVolume) > 0.001) {
|
||||||
lastKnownVolume = AudioService.volume
|
lastKnownVolume = AudioService.volume;
|
||||||
showOSD("volume")
|
showOSD("volume");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onMutedChanged() {
|
function onMutedChanged() {
|
||||||
if (lastKnownVolume < 0) {
|
if (lastKnownVolume < 0) {
|
||||||
initializeAudioValues()
|
initializeAudioValues();
|
||||||
if (lastKnownVolume < 0)
|
if (lastKnownVolume < 0)
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!muteInitialized)
|
if (!muteInitialized)
|
||||||
return
|
return;
|
||||||
showOSD("volume")
|
showOSD("volume");
|
||||||
}
|
}
|
||||||
|
|
||||||
function onInputVolumeChanged() {
|
function onInputVolumeChanged() {
|
||||||
if (!AudioService.hasInput)
|
if (!AudioService.hasInput)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (lastKnownInputVolume < 0) {
|
if (lastKnownInputVolume < 0) {
|
||||||
initializeAudioValues()
|
initializeAudioValues();
|
||||||
if (lastKnownInputVolume < 0)
|
if (lastKnownInputVolume < 0)
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!inputInitialized)
|
if (!inputInitialized)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (Math.abs(AudioService.inputVolume - lastKnownInputVolume) > 0.001) {
|
if (Math.abs(AudioService.inputVolume - lastKnownInputVolume) > 0.001) {
|
||||||
lastKnownInputVolume = AudioService.inputVolume
|
lastKnownInputVolume = AudioService.inputVolume;
|
||||||
showOSD("inputVolume")
|
showOSD("inputVolume");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onInputMutedChanged() {
|
function onInputMutedChanged() {
|
||||||
if (!AudioService.hasInput)
|
if (!AudioService.hasInput)
|
||||||
return
|
return;
|
||||||
|
|
||||||
if (lastKnownInputVolume < 0) {
|
if (lastKnownInputVolume < 0) {
|
||||||
initializeAudioValues()
|
initializeAudioValues();
|
||||||
if (lastKnownInputVolume < 0)
|
if (lastKnownInputVolume < 0)
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
if (!inputInitialized)
|
if (!inputInitialized)
|
||||||
return
|
return;
|
||||||
showOSD("inputVolume")
|
showOSD("inputVolume");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -290,7 +286,7 @@ Variants {
|
|||||||
Connections {
|
Connections {
|
||||||
target: BrightnessService
|
target: BrightnessService
|
||||||
function onMonitorsChanged() {
|
function onMonitorsChanged() {
|
||||||
connectBrightnessMonitors()
|
connectBrightnessMonitors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -301,9 +297,9 @@ Variants {
|
|||||||
running: true
|
running: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (Pipewire.ready)
|
if (Pipewire.ready)
|
||||||
initializeAudioValues()
|
initializeAudioValues();
|
||||||
muteInitialized = true
|
muteInitialized = true;
|
||||||
connectBrightnessMonitors()
|
connectBrightnessMonitors();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,22 +310,21 @@ Variants {
|
|||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (!Pipewire.ready)
|
if (!Pipewire.ready)
|
||||||
return
|
return;
|
||||||
|
const needsOutputInit = lastKnownVolume < 0;
|
||||||
const needsOutputInit = lastKnownVolume < 0
|
const needsInputInit = AudioService.hasInput && lastKnownInputVolume < 0;
|
||||||
const needsInputInit = AudioService.hasInput && lastKnownInputVolume < 0
|
|
||||||
|
|
||||||
if (needsOutputInit || needsInputInit) {
|
if (needsOutputInit || needsInputInit) {
|
||||||
initializeAudioValues()
|
initializeAudioValues();
|
||||||
|
|
||||||
// Stop timer if both are initialized
|
// Stop timer if both are initialized
|
||||||
const outputDone = lastKnownVolume >= 0
|
const outputDone = lastKnownVolume >= 0;
|
||||||
const inputDone = !AudioService.hasInput || lastKnownInputVolume >= 0
|
const inputDone = !AudioService.hasInput || lastKnownInputVolume >= 0;
|
||||||
if (outputDone && inputDone) {
|
if (outputDone && inputDone) {
|
||||||
running = false
|
running = false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
running = false
|
running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -355,8 +350,8 @@ Variants {
|
|||||||
readonly property int vWidth: Math.round(80 * Style.uiScaleRatio)
|
readonly property int vWidth: Math.round(80 * Style.uiScaleRatio)
|
||||||
readonly property int vHeight: Math.round(280 * Style.uiScaleRatio)
|
readonly property int vHeight: Math.round(280 * Style.uiScaleRatio)
|
||||||
readonly property int barThickness: {
|
readonly property int barThickness: {
|
||||||
const base = Math.max(8, Math.round(8 * Style.uiScaleRatio))
|
const base = Math.max(8, Math.round(8 * Style.uiScaleRatio));
|
||||||
return base % 2 === 0 ? base : base + 1
|
return base % 2 === 0 ? base : base + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.top: isTop
|
anchors.top: isTop
|
||||||
@@ -366,15 +361,15 @@ Variants {
|
|||||||
|
|
||||||
function calculateMargin(isAnchored, position) {
|
function calculateMargin(isAnchored, position) {
|
||||||
if (!isAnchored)
|
if (!isAnchored)
|
||||||
return 0
|
return 0;
|
||||||
|
|
||||||
let base = Style.marginM
|
let base = Style.marginM;
|
||||||
if (Settings.data.bar.position === position) {
|
if (Settings.data.bar.position === position) {
|
||||||
const isVertical = position === "top" || position === "bottom"
|
const isVertical = position === "top" || position === "bottom";
|
||||||
const floatExtra = Settings.data.bar.floating ? (isVertical ? Settings.data.bar.marginVertical : Settings.data.bar.marginHorizontal) * Style.marginXL : 0
|
const floatExtra = Settings.data.bar.floating ? (isVertical ? Settings.data.bar.marginVertical : Settings.data.bar.marginHorizontal) * Style.marginXL : 0;
|
||||||
return Style.barHeight + base + floatExtra
|
return Style.barHeight + base + floatExtra;
|
||||||
}
|
}
|
||||||
return base
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
margins.top: calculateMargin(anchors.top, "top")
|
margins.top: calculateMargin(anchors.top, "top")
|
||||||
@@ -422,9 +417,9 @@ Variants {
|
|||||||
id: visibilityTimer
|
id: visibilityTimer
|
||||||
interval: Style.animationNormal + 50
|
interval: Style.animationNormal + 50
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
osdItem.visible = false
|
osdItem.visible = false;
|
||||||
root.currentOSDType = ""
|
root.currentOSDType = "";
|
||||||
root.active = false
|
root.active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,8 +431,8 @@ Variants {
|
|||||||
color: Qt.alpha(Color.mSurface, Settings.data.osd.backgroundOpacity || 1.0)
|
color: Qt.alpha(Color.mSurface, Settings.data.osd.backgroundOpacity || 1.0)
|
||||||
border.color: Qt.alpha(Color.mOutline, Settings.data.osd.backgroundOpacity || 1.0)
|
border.color: Qt.alpha(Color.mOutline, Settings.data.osd.backgroundOpacity || 1.0)
|
||||||
border.width: {
|
border.width: {
|
||||||
const bw = Math.max(2, Style.borderM)
|
const bw = Math.max(2, Style.borderM);
|
||||||
return bw % 2 === 0 ? bw : bw + 1
|
return bw % 2 === 0 ? bw : bw + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -608,39 +603,39 @@ Variants {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function show() {
|
function show() {
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
visibilityTimer.stop()
|
visibilityTimer.stop();
|
||||||
osdItem.visible = true
|
osdItem.visible = true;
|
||||||
|
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
osdItem.opacity = 1
|
osdItem.opacity = 1;
|
||||||
osdItem.scale = 1.0
|
osdItem.scale = 1.0;
|
||||||
})
|
});
|
||||||
|
|
||||||
hideTimer.start()
|
hideTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide() {
|
function hide() {
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
visibilityTimer.stop()
|
visibilityTimer.stop();
|
||||||
osdItem.opacity = 0
|
osdItem.opacity = 0;
|
||||||
osdItem.scale = 0.85
|
osdItem.scale = 0.85;
|
||||||
visibilityTimer.start()
|
visibilityTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideImmediately() {
|
function hideImmediately() {
|
||||||
hideTimer.stop()
|
hideTimer.stop();
|
||||||
visibilityTimer.stop()
|
visibilityTimer.stop();
|
||||||
osdItem.opacity = 0
|
osdItem.opacity = 0;
|
||||||
osdItem.scale = 0.85
|
osdItem.scale = 0.85;
|
||||||
osdItem.visible = false
|
osdItem.visible = false;
|
||||||
root.currentOSDType = ""
|
root.currentOSDType = "";
|
||||||
root.active = false
|
root.active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showOSD() {
|
function showOSD() {
|
||||||
osdItem.show()
|
osdItem.show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Services.Pipewire
|
import Quickshell.Services.Pipewire
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Modules.MainScreen
|
import qs.Modules.MainScreen
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
SmartPanel {
|
SmartPanel {
|
||||||
id: root
|
id: root
|
||||||
@@ -25,7 +25,7 @@ SmartPanel {
|
|||||||
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
|
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!localOutputVolumeChanging) {
|
if (!localOutputVolumeChanging) {
|
||||||
localOutputVolume = AudioService.volume
|
localOutputVolume = AudioService.volume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,7 +34,7 @@ SmartPanel {
|
|||||||
target: AudioService.source?.audio ? AudioService.source?.audio : null
|
target: AudioService.source?.audio ? AudioService.source?.audio : null
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!localInputVolumeChanging) {
|
if (!localInputVolumeChanging) {
|
||||||
localInputVolume = AudioService.inputVolume
|
localInputVolume = AudioService.inputVolume;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -46,10 +46,10 @@ SmartPanel {
|
|||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (Math.abs(localOutputVolume - AudioService.volume) >= 0.01) {
|
if (Math.abs(localOutputVolume - AudioService.volume) >= 0.01) {
|
||||||
AudioService.setVolume(localOutputVolume)
|
AudioService.setVolume(localOutputVolume);
|
||||||
}
|
}
|
||||||
if (Math.abs(localInputVolume - AudioService.inputVolume) >= 0.01) {
|
if (Math.abs(localInputVolume - AudioService.inputVolume) >= 0.01) {
|
||||||
AudioService.setInputVolume(localInputVolume)
|
AudioService.setInputVolume(localInputVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.output-muted")
|
tooltipText: I18n.tr("tooltips.output-muted")
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
AudioService.setOutputMuted(!AudioService.muted)
|
AudioService.setOutputMuted(!AudioService.muted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +104,7 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.input-muted")
|
tooltipText: I18n.tr("tooltips.input-muted")
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
AudioService.setInputMuted(!AudioService.inputMuted)
|
AudioService.setInputMuted(!AudioService.inputMuted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,7 +113,7 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.close")
|
tooltipText: I18n.tr("tooltips.close")
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,8 +179,8 @@ SmartPanel {
|
|||||||
text: modelData.description
|
text: modelData.description
|
||||||
checked: AudioService.sink?.id === modelData.id
|
checked: AudioService.sink?.id === modelData.id
|
||||||
onClicked: {
|
onClicked: {
|
||||||
AudioService.setAudioSink(modelData)
|
AudioService.setAudioSink(modelData);
|
||||||
localOutputVolume = AudioService.volume
|
localOutputVolume = AudioService.volume;
|
||||||
}
|
}
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.MainScreen
|
||||||
import qs.Services.Hardware
|
import qs.Services.Hardware
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.MainScreen
|
|
||||||
|
|
||||||
SmartPanel {
|
SmartPanel {
|
||||||
id: root
|
id: root
|
||||||
@@ -14,21 +14,25 @@ SmartPanel {
|
|||||||
property var optionsModel: []
|
property var optionsModel: []
|
||||||
|
|
||||||
function updateOptionsModel() {
|
function updateOptionsModel() {
|
||||||
let newOptions = [{
|
let newOptions = [
|
||||||
"id": BatteryService.ChargingMode.Full,
|
{
|
||||||
"label": "battery.panel.full"
|
"id": BatteryService.ChargingMode.Full,
|
||||||
}, {
|
"label": "battery.panel.full"
|
||||||
"id": BatteryService.ChargingMode.Balanced,
|
},
|
||||||
"label": "battery.panel.balanced"
|
{
|
||||||
}, {
|
"id": BatteryService.ChargingMode.Balanced,
|
||||||
"id": BatteryService.ChargingMode.Lifespan,
|
"label": "battery.panel.balanced"
|
||||||
"label": "battery.panel.lifespan"
|
},
|
||||||
}]
|
{
|
||||||
root.optionsModel = newOptions
|
"id": BatteryService.ChargingMode.Lifespan,
|
||||||
|
"label": "battery.panel.lifespan"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
root.optionsModel = newOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
updateOptionsModel()
|
updateOptionsModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
ButtonGroup {
|
ButtonGroup {
|
||||||
@@ -49,7 +53,7 @@ SmartPanel {
|
|||||||
})
|
})
|
||||||
checked: BatteryService.chargingMode === modelData.id
|
checked: BatteryService.chargingMode === modelData.id
|
||||||
onClicked: {
|
onClicked: {
|
||||||
BatteryService.setChargingMode(modelData.id)
|
BatteryService.setChargingMode(modelData.id);
|
||||||
}
|
}
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
@@ -131,7 +135,7 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.close")
|
tooltipText: I18n.tr("tooltips.close")
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Bluetooth
|
import Quickshell.Bluetooth
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
@@ -13,9 +13,7 @@ NBox {
|
|||||||
|
|
||||||
property string label: ""
|
property string label: ""
|
||||||
property string tooltipText: ""
|
property string tooltipText: ""
|
||||||
property var model: {
|
property var model: {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: column.implicitHeight + Style.marginM * 2
|
Layout.preferredHeight: column.implicitHeight + Style.marginM * 2
|
||||||
@@ -52,10 +50,10 @@ NBox {
|
|||||||
|
|
||||||
function getContentColor(defaultColor = Color.mOnSurface) {
|
function getContentColor(defaultColor = Color.mOnSurface) {
|
||||||
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
if (modelData.pairing || modelData.state === BluetoothDeviceState.Connecting)
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
if (modelData.blocked)
|
if (modelData.blocked)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
return defaultColor
|
return defaultColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
@@ -154,33 +152,33 @@ NBox {
|
|||||||
fontWeight: Style.fontWeightMedium
|
fontWeight: Style.fontWeightMedium
|
||||||
backgroundColor: {
|
backgroundColor: {
|
||||||
if (device.canDisconnect && !isBusy) {
|
if (device.canDisconnect && !isBusy) {
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
}
|
}
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
}
|
}
|
||||||
tooltipText: root.tooltipText
|
tooltipText: root.tooltipText
|
||||||
text: {
|
text: {
|
||||||
if (modelData.pairing) {
|
if (modelData.pairing) {
|
||||||
return I18n.tr("bluetooth.panel.pairing")
|
return I18n.tr("bluetooth.panel.pairing");
|
||||||
}
|
}
|
||||||
if (modelData.blocked) {
|
if (modelData.blocked) {
|
||||||
return I18n.tr("bluetooth.panel.blocked")
|
return I18n.tr("bluetooth.panel.blocked");
|
||||||
}
|
}
|
||||||
if (modelData.connected) {
|
if (modelData.connected) {
|
||||||
return I18n.tr("bluetooth.panel.disconnect")
|
return I18n.tr("bluetooth.panel.disconnect");
|
||||||
}
|
}
|
||||||
return I18n.tr("bluetooth.panel.connect")
|
return I18n.tr("bluetooth.panel.connect");
|
||||||
}
|
}
|
||||||
icon: (isBusy ? "busy" : null)
|
icon: (isBusy ? "busy" : null)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (modelData.connected) {
|
if (modelData.connected) {
|
||||||
BluetoothService.disconnectDevice(modelData)
|
BluetoothService.disconnectDevice(modelData);
|
||||||
} else {
|
} else {
|
||||||
BluetoothService.connectDeviceWithTrust(modelData)
|
BluetoothService.connectDeviceWithTrust(modelData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
BluetoothService.forgetDevice(modelData)
|
BluetoothService.forgetDevice(modelData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Bluetooth
|
import Quickshell.Bluetooth
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Services.Networking
|
|
||||||
import qs.Widgets
|
|
||||||
import qs.Modules.MainScreen
|
import qs.Modules.MainScreen
|
||||||
|
import qs.Services.Networking
|
||||||
|
import qs.Services.UI
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
SmartPanel {
|
SmartPanel {
|
||||||
id: root
|
id: root
|
||||||
@@ -65,7 +65,7 @@ SmartPanel {
|
|||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (BluetoothService.adapter) {
|
if (BluetoothService.adapter) {
|
||||||
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +75,7 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.close")
|
tooltipText: I18n.tr("tooltips.close")
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -143,9 +143,9 @@ SmartPanel {
|
|||||||
label: I18n.tr("bluetooth.panel.connected-devices")
|
label: I18n.tr("bluetooth.panel.connected-devices")
|
||||||
property var items: {
|
property var items: {
|
||||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||||
return []
|
return [];
|
||||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && dev.connected)
|
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && dev.connected);
|
||||||
return BluetoothService.sortDevices(filtered)
|
return BluetoothService.sortDevices(filtered);
|
||||||
}
|
}
|
||||||
model: items
|
model: items
|
||||||
visible: items.length > 0
|
visible: items.length > 0
|
||||||
@@ -158,9 +158,9 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.connect-disconnect-devices")
|
tooltipText: I18n.tr("tooltips.connect-disconnect-devices")
|
||||||
property var items: {
|
property var items: {
|
||||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||||
return []
|
return [];
|
||||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.connected && (dev.paired || dev.trusted))
|
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.connected && (dev.paired || dev.trusted));
|
||||||
return BluetoothService.sortDevices(filtered)
|
return BluetoothService.sortDevices(filtered);
|
||||||
}
|
}
|
||||||
model: items
|
model: items
|
||||||
visible: items.length > 0
|
visible: items.length > 0
|
||||||
@@ -172,9 +172,9 @@ SmartPanel {
|
|||||||
label: I18n.tr("bluetooth.panel.available-devices")
|
label: I18n.tr("bluetooth.panel.available-devices")
|
||||||
property var items: {
|
property var items: {
|
||||||
if (!BluetoothService.adapter || !Bluetooth.devices)
|
if (!BluetoothService.adapter || !Bluetooth.devices)
|
||||||
return []
|
return [];
|
||||||
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.paired && !dev.trusted)
|
var filtered = Bluetooth.devices.values.filter(dev => dev && !dev.blocked && !dev.paired && !dev.trusted);
|
||||||
return BluetoothService.sortDevices(filtered)
|
return BluetoothService.sortDevices(filtered);
|
||||||
}
|
}
|
||||||
model: items
|
model: items
|
||||||
visible: items.length > 0
|
visible: items.length > 0
|
||||||
@@ -187,13 +187,13 @@ SmartPanel {
|
|||||||
Layout.preferredHeight: columnScanning.implicitHeight + Style.marginM * 2
|
Layout.preferredHeight: columnScanning.implicitHeight + Style.marginM * 2
|
||||||
visible: {
|
visible: {
|
||||||
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices) {
|
if (!BluetoothService.adapter || !BluetoothService.adapter.discovering || !Bluetooth.devices) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var availableCount = Bluetooth.devices.values.filter(dev => {
|
var availableCount = Bluetooth.devices.values.filter(dev => {
|
||||||
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0)
|
return dev && !dev.paired && !dev.pairing && !dev.blocked && (dev.signalStrength === undefined || dev.signalStrength > 0);
|
||||||
}).length
|
}).length;
|
||||||
return (availableCount === 0)
|
return (availableCount === 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
|
|||||||
@@ -21,22 +21,22 @@ SmartPanel {
|
|||||||
|
|
||||||
// Helper function to calculate ISO week number
|
// Helper function to calculate ISO week number
|
||||||
function getISOWeekNumber(date) {
|
function getISOWeekNumber(date) {
|
||||||
const target = new Date(date.valueOf())
|
const target = new Date(date.valueOf());
|
||||||
const dayNr = (date.getDay() + 6) % 7
|
const dayNr = (date.getDay() + 6) % 7;
|
||||||
target.setDate(target.getDate() - dayNr + 3)
|
target.setDate(target.getDate() - dayNr + 3);
|
||||||
const firstThursday = new Date(target.getFullYear(), 0, 4)
|
const firstThursday = new Date(target.getFullYear(), 0, 4);
|
||||||
const diff = target - firstThursday
|
const diff = target - firstThursday;
|
||||||
const oneWeek = 1000 * 60 * 60 * 24 * 7
|
const oneWeek = 1000 * 60 * 60 * 24 * 7;
|
||||||
const weekNumber = 1 + Math.round(diff / oneWeek)
|
const weekNumber = 1 + Math.round(diff / oneWeek);
|
||||||
return weekNumber
|
return weekNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to check if an event is all-day
|
// Helper function to check if an event is all-day
|
||||||
function isAllDayEvent(event) {
|
function isAllDayEvent(event) {
|
||||||
const duration = event.end - event.start
|
const duration = event.end - event.start;
|
||||||
const startDate = new Date(event.start * 1000)
|
const startDate = new Date(event.start * 1000);
|
||||||
const isAtMidnight = startDate.getHours() === 0 && startDate.getMinutes() === 0
|
const isAtMidnight = startDate.getHours() === 0 && startDate.getMinutes() === 0;
|
||||||
return duration === 86400 && isAtMidnight
|
return duration === 86400 && isAtMidnight;
|
||||||
}
|
}
|
||||||
|
|
||||||
panelContent: Item {
|
panelContent: Item {
|
||||||
@@ -50,12 +50,12 @@ SmartPanel {
|
|||||||
|
|
||||||
property real calendarGridHeight: {
|
property real calendarGridHeight: {
|
||||||
// Calculate number of weeks in the calendar grid
|
// Calculate number of weeks in the calendar grid
|
||||||
const numWeeks = grid.daysModel ? Math.ceil(grid.daysModel.length / 7) : 5
|
const numWeeks = grid.daysModel ? Math.ceil(grid.daysModel.length / 7) : 5;
|
||||||
|
|
||||||
// Calendar grid height (dynamic based on number of weeks)
|
// Calendar grid height (dynamic based on number of weeks)
|
||||||
const rowHeight = Style.baseWidgetSize * 0.9 + Style.marginXXS
|
const rowHeight = Style.baseWidgetSize * 0.9 + Style.marginXXS;
|
||||||
|
|
||||||
return numWeeks * rowHeight
|
return numWeeks * rowHeight;
|
||||||
}
|
}
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: content
|
id: content
|
||||||
@@ -69,17 +69,17 @@ SmartPanel {
|
|||||||
readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null)
|
readonly property bool weatherReady: Settings.data.location.weatherEnabled && (LocationService.data.weather !== null)
|
||||||
|
|
||||||
function checkIsCurrentMonth() {
|
function checkIsCurrentMonth() {
|
||||||
return (now.getMonth() === grid.month) && (now.getFullYear() === grid.year)
|
return (now.getMonth() === grid.month) && (now.getFullYear() === grid.year);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
isCurrentMonth = checkIsCurrentMonth()
|
isCurrentMonth = checkIsCurrentMonth();
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: Time
|
target: Time
|
||||||
function onNowChanged() {
|
function onNowChanged() {
|
||||||
content.isCurrentMonth = content.checkIsCurrentMonth()
|
content.isCurrentMonth = content.checkIsCurrentMonth();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ SmartPanel {
|
|||||||
target: I18n
|
target: I18n
|
||||||
function onLanguageChanged() {
|
function onLanguageChanged() {
|
||||||
// Force update of day names when language changes
|
// Force update of day names when language changes
|
||||||
grid.month = grid.month
|
grid.month = grid.month;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,11 +180,11 @@ SmartPanel {
|
|||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
if (!Settings.data.location.weatherEnabled)
|
if (!Settings.data.location.weatherEnabled)
|
||||||
return ""
|
return "";
|
||||||
if (!content.weatherReady)
|
if (!content.weatherReady)
|
||||||
return I18n.tr("calendar.weather.loading")
|
return I18n.tr("calendar.weather.loading");
|
||||||
const chunks = Settings.data.location.name.split(",")
|
const chunks = Settings.data.location.name.split(",");
|
||||||
return chunks[0]
|
return chunks[0];
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeM
|
pointSize: Style.fontSizeM
|
||||||
font.weight: Style.fontWeightMedium
|
font.weight: Style.fontWeightMedium
|
||||||
@@ -227,11 +227,11 @@ SmartPanel {
|
|||||||
id: calendar
|
id: calendar
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: {
|
Layout.preferredHeight: {
|
||||||
const navigationHeight = Style.baseWidgetSize // Navigation buttons row
|
const navigationHeight = Style.baseWidgetSize; // Navigation buttons row
|
||||||
const dayNamesHeight = Style.baseWidgetSize * 0.6 // Day names header row
|
const dayNamesHeight = Style.baseWidgetSize * 0.6; // Day names header row
|
||||||
const innerMargins = Style.marginM * 2 // Top and bottom margins inside NBox
|
const innerMargins = Style.marginM * 2; // Top and bottom margins inside NBox
|
||||||
const innerSpacing = Style.marginS * 2 // Spacing between nav, dayNames, and grid (2 gaps)
|
const innerSpacing = Style.marginS * 2; // Spacing between nav, dayNames, and grid (2 gaps)
|
||||||
return navigationHeight + dayNamesHeight + calendarGridHeight + innerMargins + innerSpacing
|
return navigationHeight + dayNamesHeight + calendarGridHeight + innerMargins + innerSpacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on Layout.preferredWidth {
|
Behavior on Layout.preferredWidth {
|
||||||
@@ -257,46 +257,46 @@ SmartPanel {
|
|||||||
NIconButton {
|
NIconButton {
|
||||||
icon: "chevron-left"
|
icon: "chevron-left"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
let newDate = new Date(grid.year, grid.month - 1, 1)
|
let newDate = new Date(grid.year, grid.month - 1, 1);
|
||||||
grid.year = newDate.getFullYear()
|
grid.year = newDate.getFullYear();
|
||||||
grid.month = newDate.getMonth()
|
grid.month = newDate.getMonth();
|
||||||
content.isCurrentMonth = content.checkIsCurrentMonth()
|
content.isCurrentMonth = content.checkIsCurrentMonth();
|
||||||
const now = new Date()
|
const now = new Date();
|
||||||
const monthStart = new Date(grid.year, grid.month, 1)
|
const monthStart = new Date(grid.year, grid.month, 1);
|
||||||
const monthEnd = new Date(grid.year, grid.month + 1, 0)
|
const monthEnd = new Date(grid.year, grid.month + 1, 0);
|
||||||
|
|
||||||
const daysBehind = Math.max(0, Math.ceil((now - monthStart) / (24 * 60 * 60 * 1000)))
|
const daysBehind = Math.max(0, Math.ceil((now - monthStart) / (24 * 60 * 60 * 1000)));
|
||||||
const daysAhead = Math.max(0, Math.ceil((monthEnd - now) / (24 * 60 * 60 * 1000)))
|
const daysAhead = Math.max(0, Math.ceil((monthEnd - now) / (24 * 60 * 60 * 1000)));
|
||||||
|
|
||||||
CalendarService.loadEvents(daysAhead + 30, daysBehind + 30)
|
CalendarService.loadEvents(daysAhead + 30, daysBehind + 30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
icon: "calendar"
|
icon: "calendar"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
grid.month = now.getMonth()
|
grid.month = now.getMonth();
|
||||||
grid.year = now.getFullYear()
|
grid.year = now.getFullYear();
|
||||||
content.isCurrentMonth = true
|
content.isCurrentMonth = true;
|
||||||
CalendarService.loadEvents()
|
CalendarService.loadEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NIconButton {
|
NIconButton {
|
||||||
icon: "chevron-right"
|
icon: "chevron-right"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
let newDate = new Date(grid.year, grid.month + 1, 1)
|
let newDate = new Date(grid.year, grid.month + 1, 1);
|
||||||
grid.year = newDate.getFullYear()
|
grid.year = newDate.getFullYear();
|
||||||
grid.month = newDate.getMonth()
|
grid.month = newDate.getMonth();
|
||||||
content.isCurrentMonth = content.checkIsCurrentMonth()
|
content.isCurrentMonth = content.checkIsCurrentMonth();
|
||||||
const now = new Date()
|
const now = new Date();
|
||||||
const monthStart = new Date(grid.year, grid.month, 1)
|
const monthStart = new Date(grid.year, grid.month, 1);
|
||||||
const monthEnd = new Date(grid.year, grid.month + 1, 0)
|
const monthEnd = new Date(grid.year, grid.month + 1, 0);
|
||||||
|
|
||||||
const daysBehind = Math.max(0, Math.ceil((now - monthStart) / (24 * 60 * 60 * 1000)))
|
const daysBehind = Math.max(0, Math.ceil((now - monthStart) / (24 * 60 * 60 * 1000)));
|
||||||
const daysAhead = Math.max(0, Math.ceil((monthEnd - now) / (24 * 60 * 60 * 1000)))
|
const daysAhead = Math.max(0, Math.ceil((monthEnd - now) / (24 * 60 * 60 * 1000)));
|
||||||
|
|
||||||
CalendarService.loadEvents(daysAhead + 30, daysBehind + 30)
|
CalendarService.loadEvents(daysAhead + 30, daysBehind + 30);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,9 +324,9 @@ SmartPanel {
|
|||||||
NText {
|
NText {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: {
|
text: {
|
||||||
let dayIndex = (content.firstDayOfWeek + index) % 7
|
let dayIndex = (content.firstDayOfWeek + index) % 7;
|
||||||
const dayName = I18n.locale.dayName(dayIndex, Locale.ShortFormat)
|
const dayName = I18n.locale.dayName(dayIndex, Locale.ShortFormat);
|
||||||
return dayName.substring(0, 2).toUpperCase()
|
return dayName.substring(0, 2).toUpperCase();
|
||||||
}
|
}
|
||||||
color: Color.mPrimary
|
color: Color.mPrimary
|
||||||
pointSize: Style.fontSizeS
|
pointSize: Style.fontSizeS
|
||||||
@@ -345,55 +345,55 @@ SmartPanel {
|
|||||||
// Helper function to check if a date has events
|
// Helper function to check if a date has events
|
||||||
function hasEventsOnDate(year, month, day) {
|
function hasEventsOnDate(year, month, day) {
|
||||||
if (!CalendarService.available || CalendarService.events.length === 0)
|
if (!CalendarService.available || CalendarService.events.length === 0)
|
||||||
return false
|
return false;
|
||||||
|
|
||||||
const targetDate = new Date(year, month, day)
|
const targetDate = new Date(year, month, day);
|
||||||
const targetStart = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate()).getTime() / 1000
|
const targetStart = new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate()).getTime() / 1000;
|
||||||
const targetEnd = targetStart + 86400 // +24 hours
|
const targetEnd = targetStart + 86400; // +24 hours
|
||||||
|
|
||||||
return CalendarService.events.some(event => {
|
return CalendarService.events.some(event => {
|
||||||
// Check if event starts or overlaps with this day
|
// Check if event starts or overlaps with this day
|
||||||
return (event.start >= targetStart && event.start < targetEnd) || (event.end > targetStart && event.end <= targetEnd) || (event.start < targetStart && event.end > targetEnd)
|
return (event.start >= targetStart && event.start < targetEnd) || (event.end > targetStart && event.end <= targetEnd) || (event.start < targetStart && event.end > targetEnd);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get events for a specific date
|
// Helper function to get events for a specific date
|
||||||
function getEventsForDate(year, month, day) {
|
function getEventsForDate(year, month, day) {
|
||||||
if (!CalendarService.available || CalendarService.events.length === 0)
|
if (!CalendarService.available || CalendarService.events.length === 0)
|
||||||
return []
|
return [];
|
||||||
|
|
||||||
const targetDate = new Date(year, month, day)
|
const targetDate = new Date(year, month, day);
|
||||||
const targetStart = Math.floor(new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate()).getTime() / 1000)
|
const targetStart = Math.floor(new Date(targetDate.getFullYear(), targetDate.getMonth(), targetDate.getDate()).getTime() / 1000);
|
||||||
const targetEnd = targetStart + 86400 // +24 hours
|
const targetEnd = targetStart + 86400; // +24 hours
|
||||||
|
|
||||||
return CalendarService.events.filter(event => {
|
return CalendarService.events.filter(event => {
|
||||||
return (event.start >= targetStart && event.start < targetEnd) || (event.end > targetStart && event.end <= targetEnd) || (event.start < targetStart && event.end > targetEnd)
|
return (event.start >= targetStart && event.start < targetEnd) || (event.end > targetStart && event.end <= targetEnd) || (event.start < targetStart && event.end > targetEnd);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to check if an event is multi-day
|
// Helper function to check if an event is multi-day
|
||||||
function isMultiDayEvent(event) {
|
function isMultiDayEvent(event) {
|
||||||
if (isAllDayEvent(event)) {
|
if (isAllDayEvent(event)) {
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const startDate = new Date(event.start * 1000)
|
const startDate = new Date(event.start * 1000);
|
||||||
const endDate = new Date(event.end * 1000)
|
const endDate = new Date(event.end * 1000);
|
||||||
|
|
||||||
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate())
|
const startDateOnly = new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate());
|
||||||
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate())
|
const endDateOnly = new Date(endDate.getFullYear(), endDate.getMonth(), endDate.getDate());
|
||||||
|
|
||||||
return startDateOnly.getTime() !== endDateOnly.getTime()
|
return startDateOnly.getTime() !== endDateOnly.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to get color for a specific event
|
// Helper function to get color for a specific event
|
||||||
function getEventColor(event, isToday) {
|
function getEventColor(event, isToday) {
|
||||||
if (isMultiDayEvent(event)) {
|
if (isMultiDayEvent(event)) {
|
||||||
return isToday ? Color.mOnSecondary : Color.mTertiary
|
return isToday ? Color.mOnSecondary : Color.mTertiary;
|
||||||
} else if (isAllDayEvent(event)) {
|
} else if (isAllDayEvent(event)) {
|
||||||
return isToday ? Color.mOnSecondary : Color.mSecondary
|
return isToday ? Color.mOnSecondary : Color.mSecondary;
|
||||||
} else {
|
} else {
|
||||||
return isToday ? Color.mOnSecondary : Color.mPrimary
|
return isToday ? Color.mOnSecondary : Color.mPrimary;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,9 +402,9 @@ SmartPanel {
|
|||||||
visible: Settings.data.location.showWeekNumberInCalendar
|
visible: Settings.data.location.showWeekNumberInCalendar
|
||||||
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 : 0
|
Layout.preferredWidth: visible ? Style.baseWidgetSize * 0.7 : 0
|
||||||
Layout.preferredHeight: {
|
Layout.preferredHeight: {
|
||||||
const numWeeks = weekNumbers ? weekNumbers.length : 5
|
const numWeeks = weekNumbers ? weekNumbers.length : 5;
|
||||||
const rowHeight = Style.baseWidgetSize * 0.9 + Style.marginXXS
|
const rowHeight = Style.baseWidgetSize * 0.9 + Style.marginXXS;
|
||||||
return numWeeks * rowHeight
|
return numWeeks * rowHeight;
|
||||||
}
|
}
|
||||||
spacing: Style.marginXXS
|
spacing: Style.marginXXS
|
||||||
|
|
||||||
@@ -417,33 +417,33 @@ SmartPanel {
|
|||||||
|
|
||||||
property var weekNumbers: {
|
property var weekNumbers: {
|
||||||
if (!grid.daysModel || grid.daysModel.length === 0)
|
if (!grid.daysModel || grid.daysModel.length === 0)
|
||||||
return []
|
return [];
|
||||||
|
|
||||||
const weeks = []
|
const weeks = [];
|
||||||
const numWeeks = Math.ceil(grid.daysModel.length / 7)
|
const numWeeks = Math.ceil(grid.daysModel.length / 7);
|
||||||
|
|
||||||
for (var i = 0; i < numWeeks; i++) {
|
for (var i = 0; i < numWeeks; i++) {
|
||||||
const dayIndex = i * 7
|
const dayIndex = i * 7;
|
||||||
if (dayIndex < grid.daysModel.length) {
|
if (dayIndex < grid.daysModel.length) {
|
||||||
const weekDay = grid.daysModel[dayIndex]
|
const weekDay = grid.daysModel[dayIndex];
|
||||||
const date = new Date(weekDay.year, weekDay.month, weekDay.day)
|
const date = new Date(weekDay.year, weekDay.month, weekDay.day);
|
||||||
|
|
||||||
// Get Thursday of this week for ISO week calculation
|
// Get Thursday of this week for ISO week calculation
|
||||||
const firstDayOfWeek = content.firstDayOfWeek
|
const firstDayOfWeek = content.firstDayOfWeek;
|
||||||
let thursday = new Date(date)
|
let thursday = new Date(date);
|
||||||
if (firstDayOfWeek === 0) {
|
if (firstDayOfWeek === 0) {
|
||||||
thursday.setDate(date.getDate() + 4)
|
thursday.setDate(date.getDate() + 4);
|
||||||
} else if (firstDayOfWeek === 1) {
|
} else if (firstDayOfWeek === 1) {
|
||||||
thursday.setDate(date.getDate() + 3)
|
thursday.setDate(date.getDate() + 3);
|
||||||
} else {
|
} else {
|
||||||
let daysToThursday = (4 - firstDayOfWeek + 7) % 7
|
let daysToThursday = (4 - firstDayOfWeek + 7) % 7;
|
||||||
thursday.setDate(date.getDate() + daysToThursday)
|
thursday.setDate(date.getDate() + daysToThursday);
|
||||||
}
|
}
|
||||||
|
|
||||||
weeks.push(root.getISOWeekNumber(thursday))
|
weeks.push(root.getISOWeekNumber(thursday));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return weeks
|
return weeks;
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
@@ -466,9 +466,9 @@ SmartPanel {
|
|||||||
id: grid
|
id: grid
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: {
|
Layout.preferredHeight: {
|
||||||
const numWeeks = daysModel ? Math.ceil(daysModel.length / 7) : 5
|
const numWeeks = daysModel ? Math.ceil(daysModel.length / 7) : 5;
|
||||||
const rowHeight = Style.baseWidgetSize * 0.9 + Style.marginXXS
|
const rowHeight = Style.baseWidgetSize * 0.9 + Style.marginXXS;
|
||||||
return numWeeks * rowHeight
|
return numWeeks * rowHeight;
|
||||||
}
|
}
|
||||||
columns: 7
|
columns: 7
|
||||||
columnSpacing: Style.marginXXS
|
columnSpacing: Style.marginXXS
|
||||||
@@ -486,51 +486,51 @@ SmartPanel {
|
|||||||
|
|
||||||
// Calculate days to display
|
// Calculate days to display
|
||||||
property var daysModel: {
|
property var daysModel: {
|
||||||
const firstOfMonth = new Date(year, month, 1)
|
const firstOfMonth = new Date(year, month, 1);
|
||||||
const lastOfMonth = new Date(year, month + 1, 0)
|
const lastOfMonth = new Date(year, month + 1, 0);
|
||||||
const daysInMonth = lastOfMonth.getDate()
|
const daysInMonth = lastOfMonth.getDate();
|
||||||
|
|
||||||
// Get first day of week (0 = Sunday, 1 = Monday, etc.)
|
// Get first day of week (0 = Sunday, 1 = Monday, etc.)
|
||||||
const firstDayOfWeek = content.firstDayOfWeek
|
const firstDayOfWeek = content.firstDayOfWeek;
|
||||||
const firstOfMonthDayOfWeek = firstOfMonth.getDay()
|
const firstOfMonthDayOfWeek = firstOfMonth.getDay();
|
||||||
|
|
||||||
// Calculate days before first of month
|
// Calculate days before first of month
|
||||||
let daysBefore = (firstOfMonthDayOfWeek - firstDayOfWeek + 7) % 7
|
let daysBefore = (firstOfMonthDayOfWeek - firstDayOfWeek + 7) % 7;
|
||||||
|
|
||||||
// Calculate days after last of month to complete the week
|
// Calculate days after last of month to complete the week
|
||||||
const lastOfMonthDayOfWeek = lastOfMonth.getDay()
|
const lastOfMonthDayOfWeek = lastOfMonth.getDay();
|
||||||
const daysAfter = (firstDayOfWeek - lastOfMonthDayOfWeek - 1 + 7) % 7
|
const daysAfter = (firstDayOfWeek - lastOfMonthDayOfWeek - 1 + 7) % 7;
|
||||||
|
|
||||||
// Build array of day objects
|
// Build array of day objects
|
||||||
const days = []
|
const days = [];
|
||||||
const today = new Date()
|
const today = new Date();
|
||||||
|
|
||||||
// Previous month days
|
// Previous month days
|
||||||
const prevMonth = new Date(year, month, 0)
|
const prevMonth = new Date(year, month, 0);
|
||||||
const prevMonthDays = prevMonth.getDate()
|
const prevMonthDays = prevMonth.getDate();
|
||||||
for (var i = daysBefore - 1; i >= 0; i--) {
|
for (var i = daysBefore - 1; i >= 0; i--) {
|
||||||
const day = prevMonthDays - i
|
const day = prevMonthDays - i;
|
||||||
const date = new Date(year, month - 1, day)
|
const date = new Date(year, month - 1, day);
|
||||||
days.push({
|
days.push({
|
||||||
"day": day,
|
"day": day,
|
||||||
"month": month - 1,
|
"month": month - 1,
|
||||||
"year": month === 0 ? year - 1 : year,
|
"year": month === 0 ? year - 1 : year,
|
||||||
"today": false,
|
"today": false,
|
||||||
"currentMonth": false
|
"currentMonth": false
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Current month days
|
// Current month days
|
||||||
for (var day = 1; day <= daysInMonth; day++) {
|
for (var day = 1; day <= daysInMonth; day++) {
|
||||||
const date = new Date(year, month, day)
|
const date = new Date(year, month, day);
|
||||||
const isToday = date.getFullYear() === today.getFullYear() && date.getMonth() === today.getMonth() && date.getDate() === today.getDate()
|
const isToday = date.getFullYear() === today.getFullYear() && date.getMonth() === today.getMonth() && date.getDate() === today.getDate();
|
||||||
days.push({
|
days.push({
|
||||||
"day": day,
|
"day": day,
|
||||||
"month": month,
|
"month": month,
|
||||||
"year": year,
|
"year": year,
|
||||||
"today": isToday,
|
"today": isToday,
|
||||||
"currentMonth": true
|
"currentMonth": true
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Next month days (only if needed to complete the week)
|
// Next month days (only if needed to complete the week)
|
||||||
@@ -541,10 +541,10 @@ SmartPanel {
|
|||||||
"year": month === 11 ? year + 1 : year,
|
"year": month === 11 ? year + 1 : year,
|
||||||
"today": false,
|
"today": false,
|
||||||
"currentMonth": false
|
"currentMonth": false
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return days
|
return days;
|
||||||
}
|
}
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
@@ -566,10 +566,10 @@ SmartPanel {
|
|||||||
text: modelData.day
|
text: modelData.day
|
||||||
color: {
|
color: {
|
||||||
if (modelData.today)
|
if (modelData.today)
|
||||||
return Color.mOnSecondary
|
return Color.mOnSecondary;
|
||||||
if (modelData.currentMonth)
|
if (modelData.currentMonth)
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
return Color.mOnSurfaceVariant
|
return Color.mOnSurfaceVariant;
|
||||||
}
|
}
|
||||||
opacity: modelData.currentMonth ? 1.0 : 0.4
|
opacity: modelData.currentMonth ? 1.0 : 0.4
|
||||||
pointSize: Style.fontSizeM
|
pointSize: Style.fontSizeM
|
||||||
@@ -602,35 +602,35 @@ SmartPanel {
|
|||||||
enabled: Settings.data.location.showCalendarEvents
|
enabled: Settings.data.location.showCalendarEvents
|
||||||
|
|
||||||
onEntered: {
|
onEntered: {
|
||||||
const events = parent.parent.parent.parent.getEventsForDate(modelData.year, modelData.month, modelData.day)
|
const events = parent.parent.parent.parent.getEventsForDate(modelData.year, modelData.month, modelData.day);
|
||||||
if (events.length > 0) {
|
if (events.length > 0) {
|
||||||
const summaries = events.map(event => {
|
const summaries = events.map(event => {
|
||||||
if (isAllDayEvent(event)) {
|
if (isAllDayEvent(event)) {
|
||||||
return event.summary
|
return event.summary;
|
||||||
} else {
|
} else {
|
||||||
// Always format with '0' padding to ensure proper horizontal alignment
|
// Always format with '0' padding to ensure proper horizontal alignment
|
||||||
const timeFormat = Settings.data.location.use12hourFormat ? "hh:mm AP" : "HH:mm"
|
const timeFormat = Settings.data.location.use12hourFormat ? "hh:mm AP" : "HH:mm";
|
||||||
const start = new Date(event.start * 1000)
|
const start = new Date(event.start * 1000);
|
||||||
const startFormatted = I18n.locale.toString(start, timeFormat)
|
const startFormatted = I18n.locale.toString(start, timeFormat);
|
||||||
const end = new Date(event.end * 1000)
|
const end = new Date(event.end * 1000);
|
||||||
const endFormatted = I18n.locale.toString(end, timeFormat)
|
const endFormatted = I18n.locale.toString(end, timeFormat);
|
||||||
return `${startFormatted}-${endFormatted} ${event.summary}`
|
return `${startFormatted}-${endFormatted} ${event.summary}`;
|
||||||
}
|
}
|
||||||
}).join('\n')
|
}).join('\n');
|
||||||
TooltipService.show(screen, parent, summaries, "auto", Style.tooltipDelay, Settings.data.ui.fontFixed)
|
TooltipService.show(screen, parent, summaries, "auto", Style.tooltipDelay, Settings.data.ui.fontFixed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
const dateWithSlashes = `${(modelData.month + 1).toString().padStart(2, '0')}/${modelData.day.toString().padStart(2, '0')}/${modelData.year.toString().substring(2)}`
|
const dateWithSlashes = `${(modelData.month + 1).toString().padStart(2, '0')}/${modelData.day.toString().padStart(2, '0')}/${modelData.year.toString().substring(2)}`;
|
||||||
if (ProgramCheckerService.gnomeCalendarAvailable) {
|
if (ProgramCheckerService.gnomeCalendarAvailable) {
|
||||||
Quickshell.execDetached(["gnome-calendar", "--date", dateWithSlashes])
|
Quickshell.execDetached(["gnome-calendar", "--date", dateWithSlashes]);
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onExited: {
|
onExited: {
|
||||||
TooltipService.hide()
|
TooltipService.hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ NBox {
|
|||||||
property bool localInputVolumeChanging: false
|
property bool localInputVolumeChanging: false
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
var vol = AudioService.volume
|
var vol = AudioService.volume;
|
||||||
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0
|
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
|
||||||
var inputVol = AudioService.inputVolume
|
var inputVol = AudioService.inputVolume;
|
||||||
localInputVolume = (inputVol !== undefined && !isNaN(inputVol)) ? inputVol : 0
|
localInputVolume = (inputVol !== undefined && !isNaN(inputVol)) ? inputVol : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer to debounce volume changes
|
// Timer to debounce volume changes
|
||||||
@@ -29,10 +29,10 @@ NBox {
|
|||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (Math.abs(localOutputVolume - AudioService.volume) >= 0.01) {
|
if (Math.abs(localOutputVolume - AudioService.volume) >= 0.01) {
|
||||||
AudioService.setVolume(localOutputVolume)
|
AudioService.setVolume(localOutputVolume);
|
||||||
}
|
}
|
||||||
if (Math.abs(localInputVolume - AudioService.inputVolume) >= 0.01) {
|
if (Math.abs(localInputVolume - AudioService.inputVolume) >= 0.01) {
|
||||||
AudioService.setInputVolume(localInputVolume)
|
AudioService.setInputVolume(localInputVolume);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,8 +42,8 @@ NBox {
|
|||||||
target: AudioService
|
target: AudioService
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!localOutputVolumeChanging) {
|
if (!localOutputVolumeChanging) {
|
||||||
var vol = AudioService.volume
|
var vol = AudioService.volume;
|
||||||
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0
|
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -52,8 +52,8 @@ NBox {
|
|||||||
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
|
target: AudioService.sink?.audio ? AudioService.sink?.audio : null
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!localOutputVolumeChanging) {
|
if (!localOutputVolumeChanging) {
|
||||||
var vol = AudioService.volume
|
var vol = AudioService.volume;
|
||||||
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0
|
localOutputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -62,8 +62,8 @@ NBox {
|
|||||||
target: AudioService
|
target: AudioService
|
||||||
function onInputVolumeChanged() {
|
function onInputVolumeChanged() {
|
||||||
if (!localInputVolumeChanging) {
|
if (!localInputVolumeChanging) {
|
||||||
var vol = AudioService.inputVolume
|
var vol = AudioService.inputVolume;
|
||||||
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0
|
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,8 +72,8 @@ NBox {
|
|||||||
target: AudioService.source?.audio ? AudioService.source?.audio : null
|
target: AudioService.source?.audio ? AudioService.source?.audio : null
|
||||||
function onVolumeChanged() {
|
function onVolumeChanged() {
|
||||||
if (!localInputVolumeChanging) {
|
if (!localInputVolumeChanging) {
|
||||||
var vol = AudioService.inputVolume
|
var vol = AudioService.inputVolume;
|
||||||
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0
|
localInputVolume = (vol !== undefined && !isNaN(vol)) ? vol : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -105,7 +105,7 @@ NBox {
|
|||||||
colorFgHover: Color.mOnHover
|
colorFgHover: Color.mOnHover
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (AudioService.sink && AudioService.sink.audio) {
|
if (AudioService.sink && AudioService.sink.audio) {
|
||||||
AudioService.sink.audio.muted = !AudioService.muted
|
AudioService.sink.audio.muted = !AudioService.muted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Services.Media
|
import qs.Services.Media
|
||||||
@@ -22,7 +22,7 @@ NBox {
|
|||||||
target: WallpaperService
|
target: WallpaperService
|
||||||
function onWallpaperChanged(screenName, path) {
|
function onWallpaperChanged(screenName, path) {
|
||||||
if (screenName === screen.name) {
|
if (screenName === screen.name) {
|
||||||
wallpaper = path
|
wallpaper = path;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,8 +48,8 @@ NBox {
|
|||||||
|
|
||||||
// Background image that covers everything
|
// Background image that covers everything
|
||||||
Image {
|
Image {
|
||||||
readonly property int dim: Math.round(256 * Style.uiScaleRatio)
|
|
||||||
id: bgImage
|
id: bgImage
|
||||||
|
readonly property int dim: Math.round(256 * Style.uiScaleRatio)
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
source: MediaService.trackArtUrl || wallpaper
|
source: MediaService.trackArtUrl || wallpaper
|
||||||
sourceSize: Qt.size(dim, dim)
|
sourceSize: Qt.size(dim, dim)
|
||||||
@@ -81,13 +81,13 @@ NBox {
|
|||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
switch (Settings.data.audio.visualizerType) {
|
switch (Settings.data.audio.visualizerType) {
|
||||||
case "linear":
|
case "linear":
|
||||||
return linearComponent
|
return linearComponent;
|
||||||
case "mirrored":
|
case "mirrored":
|
||||||
return mirroredComponent
|
return mirroredComponent;
|
||||||
case "wave":
|
case "wave":
|
||||||
return waveComponent
|
return waveComponent;
|
||||||
default:
|
default:
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,8 +164,8 @@ NBox {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var menuItems = []
|
var menuItems = [];
|
||||||
var players = MediaService.getAvailablePlayers()
|
var players = MediaService.getAvailablePlayers();
|
||||||
for (var i = 0; i < players.length; i++) {
|
for (var i = 0; i < players.length; i++) {
|
||||||
menuItems.push({
|
menuItems.push({
|
||||||
"label": players[i].identity,
|
"label": players[i].identity,
|
||||||
@@ -173,10 +173,10 @@ NBox {
|
|||||||
"icon": "disc",
|
"icon": "disc",
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"visible": true
|
"visible": true
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
playerContextMenu.model = menuItems
|
playerContextMenu.model = menuItems;
|
||||||
playerContextMenu.openAtItem(playerSelectorButton, playerSelectorButton.width - playerContextMenu.width, playerSelectorButton.height)
|
playerContextMenu.openAtItem(playerSelectorButton, playerSelectorButton.width - playerContextMenu.width, playerSelectorButton.height);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,9 +187,9 @@ NBox {
|
|||||||
verticalPolicy: ScrollBar.AlwaysOff
|
verticalPolicy: ScrollBar.AlwaysOff
|
||||||
|
|
||||||
onTriggered: function (action) {
|
onTriggered: function (action) {
|
||||||
var index = parseInt(action)
|
var index = parseInt(action);
|
||||||
if (!isNaN(index)) {
|
if (!isNaN(index)) {
|
||||||
MediaService.switchToPlayer(index)
|
MediaService.switchToPlayer(index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -276,11 +276,11 @@ NBox {
|
|||||||
property real seekEpsilon: 0.01
|
property real seekEpsilon: 0.01
|
||||||
property real progressRatio: {
|
property real progressRatio: {
|
||||||
if (!MediaService.currentPlayer || MediaService.trackLength <= 0)
|
if (!MediaService.currentPlayer || MediaService.trackLength <= 0)
|
||||||
return 0
|
return 0;
|
||||||
const r = MediaService.currentPosition / MediaService.trackLength
|
const r = MediaService.currentPosition / MediaService.trackLength;
|
||||||
if (isNaN(r) || !isFinite(r))
|
if (isNaN(r) || !isFinite(r))
|
||||||
return 0
|
return 0;
|
||||||
return Math.max(0, Math.min(1, r))
|
return Math.max(0, Math.min(1, r));
|
||||||
}
|
}
|
||||||
property real effectiveRatio: (MediaService.isSeeking && localSeekRatio >= 0) ? Math.max(0, Math.min(1, localSeekRatio)) : progressRatio
|
property real effectiveRatio: (MediaService.isSeeking && localSeekRatio >= 0) ? Math.max(0, Math.min(1, localSeekRatio)) : progressRatio
|
||||||
|
|
||||||
@@ -290,10 +290,10 @@ NBox {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (MediaService.isSeeking && progressWrapper.localSeekRatio >= 0) {
|
if (MediaService.isSeeking && progressWrapper.localSeekRatio >= 0) {
|
||||||
const next = Math.max(0, Math.min(1, progressWrapper.localSeekRatio))
|
const next = Math.max(0, Math.min(1, progressWrapper.localSeekRatio));
|
||||||
if (progressWrapper.lastSentSeekRatio < 0 || Math.abs(next - progressWrapper.lastSentSeekRatio) >= progressWrapper.seekEpsilon) {
|
if (progressWrapper.lastSentSeekRatio < 0 || Math.abs(next - progressWrapper.lastSentSeekRatio) >= progressWrapper.seekEpsilon) {
|
||||||
MediaService.seekByRatio(next)
|
MediaService.seekByRatio(next);
|
||||||
progressWrapper.lastSentSeekRatio = next
|
progressWrapper.lastSentSeekRatio = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -310,21 +310,21 @@ NBox {
|
|||||||
heightRatio: 0.6
|
heightRatio: 0.6
|
||||||
|
|
||||||
onMoved: {
|
onMoved: {
|
||||||
progressWrapper.localSeekRatio = value
|
progressWrapper.localSeekRatio = value;
|
||||||
seekDebounce.restart()
|
seekDebounce.restart();
|
||||||
}
|
}
|
||||||
onPressedChanged: {
|
onPressedChanged: {
|
||||||
if (pressed) {
|
if (pressed) {
|
||||||
MediaService.isSeeking = true
|
MediaService.isSeeking = true;
|
||||||
progressWrapper.localSeekRatio = value
|
progressWrapper.localSeekRatio = value;
|
||||||
MediaService.seekByRatio(value)
|
MediaService.seekByRatio(value);
|
||||||
progressWrapper.lastSentSeekRatio = value
|
progressWrapper.lastSentSeekRatio = value;
|
||||||
} else {
|
} else {
|
||||||
seekDebounce.stop()
|
seekDebounce.stop();
|
||||||
MediaService.seekByRatio(value)
|
MediaService.seekByRatio(value);
|
||||||
MediaService.isSeeking = false
|
MediaService.isSeeking = false;
|
||||||
progressWrapper.localSeekRatio = -1
|
progressWrapper.localSeekRatio = -1;
|
||||||
progressWrapper.lastSentSeekRatio = -1
|
progressWrapper.lastSentSeekRatio = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,9 +61,9 @@ NBox {
|
|||||||
icon: "settings"
|
icon: "settings"
|
||||||
tooltipText: I18n.tr("tooltips.open-settings")
|
tooltipText: I18n.tr("tooltips.open-settings")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
var panel = PanelService.getPanel("settingsPanel", screen)
|
var panel = PanelService.getPanel("settingsPanel", screen);
|
||||||
panel.requestedTab = SettingsPanel.Tab.General
|
panel.requestedTab = SettingsPanel.Tab.General;
|
||||||
panel.open()
|
panel.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,8 +71,8 @@ NBox {
|
|||||||
icon: "power"
|
icon: "power"
|
||||||
tooltipText: I18n.tr("tooltips.session-menu")
|
tooltipText: I18n.tr("tooltips.session-menu")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PanelService.getPanel("sessionMenuPanel", screen)?.open()
|
PanelService.getPanel("sessionMenuPanel", screen)?.open();
|
||||||
PanelService.getPanel("controlCenterPanel", screen)?.close()
|
PanelService.getPanel("controlCenterPanel", screen)?.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ NBox {
|
|||||||
icon: "close"
|
icon: "close"
|
||||||
tooltipText: I18n.tr("tooltips.close")
|
tooltipText: I18n.tr("tooltips.close")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
PanelService.getPanel("controlCenterPanel", screen)?.close()
|
PanelService.getPanel("controlCenterPanel", screen)?.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,14 +102,14 @@ NBox {
|
|||||||
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
onStreamFinished: {
|
onStreamFinished: {
|
||||||
var uptimeSeconds = parseFloat(this.text.trim().split(' ')[0])
|
var uptimeSeconds = parseFloat(this.text.trim().split(' ')[0]);
|
||||||
uptimeText = Time.formatVagueHumanReadableDuration(uptimeSeconds)
|
uptimeText = Time.formatVagueHumanReadableDuration(uptimeSeconds);
|
||||||
uptimeProcess.running = false
|
uptimeProcess.running = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateSystemInfo() {
|
function updateSystemInfo() {
|
||||||
uptimeProcess.running = true
|
uptimeProcess.running = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Modules.Panels.ControlCenter
|
import qs.Modules.Panels.ControlCenter
|
||||||
import qs.Modules.Panels.ControlCenter.Cards
|
import qs.Modules.Panels.ControlCenter.Cards
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
|
|||||||
@@ -28,9 +28,11 @@ NBox {
|
|||||||
height: content.widgetHeight
|
height: content.widgetHeight
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
// Highlight color based on thresholds
|
// Highlight color based on thresholds
|
||||||
fillColor: (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor
|
fillColor: (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor || Color.mError) : Color.mError) : (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (
|
||||||
|| Color.mError) : Color.mError) : (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.warningColor
|
Settings.data.systemMonitor.warningColor
|
||||||
|| Color.mTertiary) : Color.mTertiary) : Color.mPrimary
|
|| Color.mTertiary) :
|
||||||
|
Color.mTertiary) :
|
||||||
|
Color.mPrimary
|
||||||
textColor: (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuCriticalThreshold) ? Color.mSurfaceVariant : (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
textColor: (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuCriticalThreshold) ? Color.mSurfaceVariant : (SystemStatService.cpuUsage > Settings.data.systemMonitor.cpuWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
||||||
}
|
}
|
||||||
NCircleStat {
|
NCircleStat {
|
||||||
@@ -42,9 +44,11 @@ NBox {
|
|||||||
height: content.widgetHeight
|
height: content.widgetHeight
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
// Highlight color based on thresholds
|
// Highlight color based on thresholds
|
||||||
fillColor: (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor
|
fillColor: (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor || Color.mError) : Color.mError) : (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (
|
||||||
|| Color.mError) : Color.mError) : (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.warningColor
|
Settings.data.systemMonitor.warningColor
|
||||||
|| Color.mTertiary) : Color.mTertiary) : Color.mPrimary
|
|| Color.mTertiary) :
|
||||||
|
Color.mTertiary) :
|
||||||
|
Color.mPrimary
|
||||||
textColor: (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempCriticalThreshold) ? Color.mSurfaceVariant : (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
textColor: (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempCriticalThreshold) ? Color.mSurfaceVariant : (SystemStatService.cpuTemp > Settings.data.systemMonitor.tempWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
||||||
}
|
}
|
||||||
NCircleStat {
|
NCircleStat {
|
||||||
@@ -55,9 +59,11 @@ NBox {
|
|||||||
height: content.widgetHeight
|
height: content.widgetHeight
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
// Highlight color based on thresholds
|
// Highlight color based on thresholds
|
||||||
fillColor: (SystemStatService.memPercent > Settings.data.systemMonitor.memCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor
|
fillColor: (SystemStatService.memPercent > Settings.data.systemMonitor.memCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor || Color.mError) : Color.mError) : (SystemStatService.memPercent > Settings.data.systemMonitor.memWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (
|
||||||
|| Color.mError) : Color.mError) : (SystemStatService.memPercent > Settings.data.systemMonitor.memWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.warningColor
|
Settings.data.systemMonitor.warningColor
|
||||||
|| Color.mTertiary) : Color.mTertiary) : Color.mPrimary
|
|| Color.mTertiary) :
|
||||||
|
Color.mTertiary) :
|
||||||
|
Color.mPrimary
|
||||||
textColor: (SystemStatService.memPercent > Settings.data.systemMonitor.memCriticalThreshold) ? Color.mSurfaceVariant : (SystemStatService.memPercent > Settings.data.systemMonitor.memWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
textColor: (SystemStatService.memPercent > Settings.data.systemMonitor.memCriticalThreshold) ? Color.mSurfaceVariant : (SystemStatService.memPercent > Settings.data.systemMonitor.memWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
||||||
}
|
}
|
||||||
NCircleStat {
|
NCircleStat {
|
||||||
@@ -68,11 +74,12 @@ NBox {
|
|||||||
height: content.widgetHeight
|
height: content.widgetHeight
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
// Highlight color based on thresholds
|
// Highlight color based on thresholds
|
||||||
fillColor: ((SystemStatService.diskPercents["/"]
|
fillColor: ((SystemStatService.diskPercents["/"] ?? 0) > Settings.data.systemMonitor.diskCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor || Color.mError) : Color.mError) : ((SystemStatService.diskPercents["/"] ?? 0) > Settings.data.systemMonitor.diskWarningThreshold) ? (
|
||||||
?? 0) > Settings.data.systemMonitor.diskCriticalThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.criticalColor
|
Settings.data.systemMonitor.useCustomColors
|
||||||
|| Color.mError) : Color.mError) : ((SystemStatService.diskPercents["/"]
|
? (Settings.data.systemMonitor.warningColor
|
||||||
?? 0) > Settings.data.systemMonitor.diskWarningThreshold) ? (Settings.data.systemMonitor.useCustomColors ? (Settings.data.systemMonitor.warningColor
|
|| Color.mTertiary) :
|
||||||
|| Color.mTertiary) : Color.mTertiary) : Color.mPrimary
|
Color.mTertiary) :
|
||||||
|
Color.mPrimary
|
||||||
textColor: ((SystemStatService.diskPercents["/"] ?? 0) > Settings.data.systemMonitor.diskCriticalThreshold) ? Color.mSurfaceVariant : ((SystemStatService.diskPercents["/"] ?? 0) > Settings.data.systemMonitor.diskWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
textColor: ((SystemStatService.diskPercents["/"] ?? 0) > Settings.data.systemMonitor.diskCriticalThreshold) ? Color.mSurfaceVariant : ((SystemStatService.diskPercents["/"] ?? 0) > Settings.data.systemMonitor.diskWarningThreshold) ? Color.mSurfaceVariant : Color.mOnSurface
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ NBox {
|
|||||||
NText {
|
NText {
|
||||||
text: {
|
text: {
|
||||||
// Ensure the name is not too long if one had to specify the country
|
// Ensure the name is not too long if one had to specify the country
|
||||||
const chunks = Settings.data.location.name.split(",")
|
const chunks = Settings.data.location.name.split(",");
|
||||||
return chunks[0]
|
return chunks[0];
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeL
|
pointSize: Style.fontSizeL
|
||||||
font.weight: Style.fontWeightBold
|
font.weight: Style.fontWeightBold
|
||||||
@@ -56,16 +56,16 @@ NBox {
|
|||||||
visible: weatherReady
|
visible: weatherReady
|
||||||
text: {
|
text: {
|
||||||
if (!weatherReady) {
|
if (!weatherReady) {
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
var temp = LocationService.data.weather.current_weather.temperature
|
var temp = LocationService.data.weather.current_weather.temperature;
|
||||||
var suffix = "C"
|
var suffix = "C";
|
||||||
if (Settings.data.location.useFahrenheit) {
|
if (Settings.data.location.useFahrenheit) {
|
||||||
temp = LocationService.celsiusToFahrenheit(temp)
|
temp = LocationService.celsiusToFahrenheit(temp);
|
||||||
var suffix = "F"
|
var suffix = "F";
|
||||||
}
|
}
|
||||||
temp = Math.round(temp)
|
temp = Math.round(temp);
|
||||||
return `${temp}°${suffix}`
|
return `${temp}°${suffix}`;
|
||||||
}
|
}
|
||||||
pointSize: showLocation ? Style.fontSizeXL : Style.fontSizeXL * 1.6
|
pointSize: showLocation ? Style.fontSizeXL : Style.fontSizeXL * 1.6
|
||||||
font.weight: Style.fontWeightBold
|
font.weight: Style.fontWeightBold
|
||||||
@@ -103,8 +103,8 @@ NBox {
|
|||||||
NText {
|
NText {
|
||||||
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
Layout.alignment: Qt.AlignVCenter | Qt.AlignHCenter
|
||||||
text: {
|
text: {
|
||||||
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"))
|
var weatherDate = new Date(LocationService.data.weather.daily.time[index].replace(/-/g, "/"));
|
||||||
return I18n.locale.toString(weatherDate, "ddd")
|
return I18n.locale.toString(weatherDate, "ddd");
|
||||||
}
|
}
|
||||||
color: Color.mOnSurface
|
color: Color.mOnSurface
|
||||||
}
|
}
|
||||||
@@ -117,15 +117,15 @@ NBox {
|
|||||||
NText {
|
NText {
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
text: {
|
text: {
|
||||||
var max = LocationService.data.weather.daily.temperature_2m_max[index]
|
var max = LocationService.data.weather.daily.temperature_2m_max[index];
|
||||||
var min = LocationService.data.weather.daily.temperature_2m_min[index]
|
var min = LocationService.data.weather.daily.temperature_2m_min[index];
|
||||||
if (Settings.data.location.useFahrenheit) {
|
if (Settings.data.location.useFahrenheit) {
|
||||||
max = LocationService.celsiusToFahrenheit(max)
|
max = LocationService.celsiusToFahrenheit(max);
|
||||||
min = LocationService.celsiusToFahrenheit(min)
|
min = LocationService.celsiusToFahrenheit(min);
|
||||||
}
|
}
|
||||||
max = Math.round(max)
|
max = Math.round(max);
|
||||||
min = Math.round(min)
|
min = Math.round(min);
|
||||||
return `${max}°/${min}°`
|
return `${max}°/${min}°`;
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeXS
|
pointSize: Style.fontSizeXS
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ SmartPanel {
|
|||||||
|
|
||||||
// Check if there's a bar on this screen
|
// Check if there's a bar on this screen
|
||||||
readonly property bool hasBarOnScreen: {
|
readonly property bool hasBarOnScreen: {
|
||||||
var monitors = Settings.data.bar.monitors || []
|
var monitors = Settings.data.bar.monitors || [];
|
||||||
return monitors.length === 0 || monitors.includes(screen?.name)
|
return monitors.length === 0 || monitors.includes(screen?.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
// When position is "close_to_bar_button" but there's no bar, fall back to center
|
// When position is "close_to_bar_button" but there's no bar, fall back to center
|
||||||
@@ -33,39 +33,37 @@ SmartPanel {
|
|||||||
|
|
||||||
preferredWidth: Math.round(460 * Style.uiScaleRatio)
|
preferredWidth: Math.round(460 * Style.uiScaleRatio)
|
||||||
preferredHeight: {
|
preferredHeight: {
|
||||||
var height = 0
|
var height = 0;
|
||||||
var count = 0
|
var count = 0;
|
||||||
for (var i = 0; i < Settings.data.controlCenter.cards.length; i++) {
|
for (var i = 0; i < Settings.data.controlCenter.cards.length; i++) {
|
||||||
const card = Settings.data.controlCenter.cards[i]
|
const card = Settings.data.controlCenter.cards[i];
|
||||||
if (!card.enabled)
|
if (!card.enabled)
|
||||||
continue
|
continue;
|
||||||
|
const contributes = (card.id !== "weather-card" || Settings.data.location.weatherEnabled);
|
||||||
const contributes = (card.id !== "weather-card" || Settings.data.location.weatherEnabled)
|
|
||||||
if (!contributes)
|
if (!contributes)
|
||||||
continue
|
continue;
|
||||||
|
count++;
|
||||||
count++
|
|
||||||
switch (card.id) {
|
switch (card.id) {
|
||||||
case "profile-card":
|
case "profile-card":
|
||||||
height += profileHeight
|
height += profileHeight;
|
||||||
break
|
break;
|
||||||
case "shortcuts-card":
|
case "shortcuts-card":
|
||||||
height += shortcutsHeight
|
height += shortcutsHeight;
|
||||||
break
|
break;
|
||||||
case "audio-card":
|
case "audio-card":
|
||||||
height += audioHeight
|
height += audioHeight;
|
||||||
break
|
break;
|
||||||
case "weather-card":
|
case "weather-card":
|
||||||
height += weatherHeight
|
height += weatherHeight;
|
||||||
break
|
break;
|
||||||
case "media-sysmon-card":
|
case "media-sysmon-card":
|
||||||
height += mediaSysMonHeight
|
height += mediaSysMonHeight;
|
||||||
break
|
break;
|
||||||
default:
|
default:
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return height + (count + 1) * Style.marginL
|
return height + (count + 1) * Style.marginL;
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property int profileHeight: Math.round(64 * Style.uiScaleRatio)
|
readonly property int profileHeight: Math.round(64 * Style.uiScaleRatio)
|
||||||
@@ -77,11 +75,11 @@ SmartPanel {
|
|||||||
property int weatherHeight: Math.round(210 * Style.uiScaleRatio)
|
property int weatherHeight: Math.round(210 * Style.uiScaleRatio)
|
||||||
|
|
||||||
onOpened: {
|
onOpened: {
|
||||||
MediaService.autoSwitchingPaused = true
|
MediaService.autoSwitchingPaused = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosed: {
|
onClosed: {
|
||||||
MediaService.autoSwitchingPaused = false
|
MediaService.autoSwitchingPaused = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
panelContent: Item {
|
panelContent: Item {
|
||||||
@@ -103,31 +101,31 @@ SmartPanel {
|
|||||||
Layout.preferredHeight: {
|
Layout.preferredHeight: {
|
||||||
switch (modelData.id) {
|
switch (modelData.id) {
|
||||||
case "profile-card":
|
case "profile-card":
|
||||||
return profileHeight
|
return profileHeight;
|
||||||
case "shortcuts-card":
|
case "shortcuts-card":
|
||||||
return shortcutsHeight
|
return shortcutsHeight;
|
||||||
case "audio-card":
|
case "audio-card":
|
||||||
return audioHeight
|
return audioHeight;
|
||||||
case "weather-card":
|
case "weather-card":
|
||||||
return weatherHeight
|
return weatherHeight;
|
||||||
case "media-sysmon-card":
|
case "media-sysmon-card":
|
||||||
return mediaSysMonHeight
|
return mediaSysMonHeight;
|
||||||
default:
|
default:
|
||||||
return 0
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
switch (modelData.id) {
|
switch (modelData.id) {
|
||||||
case "profile-card":
|
case "profile-card":
|
||||||
return profileCard
|
return profileCard;
|
||||||
case "shortcuts-card":
|
case "shortcuts-card":
|
||||||
return shortcutsCard
|
return shortcutsCard;
|
||||||
case "audio-card":
|
case "audio-card":
|
||||||
return audioCard
|
return audioCard;
|
||||||
case "weather-card":
|
case "weather-card":
|
||||||
return weatherCard
|
return weatherCard;
|
||||||
case "media-sysmon-card":
|
case "media-sysmon-card":
|
||||||
return mediaSysMonCard
|
return mediaSysMonCard;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,7 +151,7 @@ SmartPanel {
|
|||||||
id: weatherCard
|
id: weatherCard
|
||||||
WeatherCard {
|
WeatherCard {
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
root.weatherHeight = this.height
|
root.weatherHeight = this.height;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Services.UI
|
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Services.UI
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
@@ -18,7 +18,7 @@ Item {
|
|||||||
implicitHeight: getImplicitSize(loader.item, "implicitHeight")
|
implicitHeight: getImplicitSize(loader.item, "implicitHeight")
|
||||||
|
|
||||||
function getImplicitSize(item, prop) {
|
function getImplicitSize(item, prop) {
|
||||||
return (item && item.visible) ? item[prop] : 0
|
return (item && item.visible) ? item[prop] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
@@ -29,36 +29,36 @@ Item {
|
|||||||
|
|
||||||
onLoaded: {
|
onLoaded: {
|
||||||
if (!item)
|
if (!item)
|
||||||
return
|
return;
|
||||||
|
|
||||||
// Apply properties to loaded widget
|
// Apply properties to loaded widget
|
||||||
for (var prop in widgetProps) {
|
for (var prop in widgetProps) {
|
||||||
if (item.hasOwnProperty(prop)) {
|
if (item.hasOwnProperty(prop)) {
|
||||||
item[prop] = widgetProps[prop]
|
item[prop] = widgetProps[prop];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set screen property
|
// Set screen property
|
||||||
if (item.hasOwnProperty("screen")) {
|
if (item.hasOwnProperty("screen")) {
|
||||||
item.screen = widgetScreen
|
item.screen = widgetScreen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call custom onLoaded if it exists
|
// Call custom onLoaded if it exists
|
||||||
if (item.hasOwnProperty("onLoaded")) {
|
if (item.hasOwnProperty("onLoaded")) {
|
||||||
item.onLoaded()
|
item.onLoaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onDestruction: {
|
Component.onDestruction: {
|
||||||
// Explicitly clear references
|
// Explicitly clear references
|
||||||
widgetProps = null
|
widgetProps = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error handling
|
// Error handling
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (!ControlCenterWidgetRegistry.hasWidget(widgetId)) {
|
if (!ControlCenterWidgetRegistry.hasWidget(widgetId)) {
|
||||||
Logger.w("ControlCenterWidgetLoader", "Widget not found in registry:", widgetId)
|
Logger.w("ControlCenterWidgetLoader", "Widget not found in registry:", widgetId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,28 +33,28 @@ Item {
|
|||||||
|
|
||||||
function _updatePropertiesFromSettings() {
|
function _updatePropertiesFromSettings() {
|
||||||
if (!widgetSettings) {
|
if (!widgetSettings) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClickedCommand = widgetSettings.onClicked || ""
|
onClickedCommand = widgetSettings.onClicked || "";
|
||||||
onRightClickedCommand = widgetSettings.onRightClicked || ""
|
onRightClickedCommand = widgetSettings.onRightClicked || "";
|
||||||
onMiddleClickedCommand = widgetSettings.onMiddleClicked || ""
|
onMiddleClickedCommand = widgetSettings.onMiddleClicked || "";
|
||||||
stateChecksJson = widgetSettings.stateChecksJson || "[]" // Populate from widgetSettings
|
stateChecksJson = widgetSettings.stateChecksJson || "[]"; // Populate from widgetSettings
|
||||||
try {
|
try {
|
||||||
_parsedStateChecks = JSON.parse(stateChecksJson)
|
_parsedStateChecks = JSON.parse(stateChecksJson);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("CustomButton: Failed to parse stateChecksJson:", e.message)
|
console.error("CustomButton: Failed to parse stateChecksJson:", e.message);
|
||||||
_parsedStateChecks = []
|
_parsedStateChecks = [];
|
||||||
}
|
}
|
||||||
generalTooltipText = widgetSettings.generalTooltipText || "Custom Button"
|
generalTooltipText = widgetSettings.generalTooltipText || "Custom Button";
|
||||||
enableOnStateLogic = widgetSettings.enableOnStateLogic || false
|
enableOnStateLogic = widgetSettings.enableOnStateLogic || false;
|
||||||
|
|
||||||
updateState()
|
updateState();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onWidgetSettingsChanged() {
|
function onWidgetSettingsChanged() {
|
||||||
if (widgetSettings) {
|
if (widgetSettings) {
|
||||||
_updatePropertiesFromSettings()
|
_updatePropertiesFromSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -64,16 +64,16 @@ Item {
|
|||||||
running: false
|
running: false
|
||||||
command: _currentStateCheckIndex !== -1 && _parsedStateChecks.length > _currentStateCheckIndex ? ["sh", "-c", _parsedStateChecks[_currentStateCheckIndex].command] : []
|
command: _currentStateCheckIndex !== -1 && _parsedStateChecks.length > _currentStateCheckIndex ? ["sh", "-c", _parsedStateChecks[_currentStateCheckIndex].command] : []
|
||||||
onExited: function (exitCode, stdout, stderr) {
|
onExited: function (exitCode, stdout, stderr) {
|
||||||
var currentCheckItem = _parsedStateChecks[_currentStateCheckIndex]
|
var currentCheckItem = _parsedStateChecks[_currentStateCheckIndex];
|
||||||
var currentCommand = currentCheckItem.command
|
var currentCommand = currentCheckItem.command;
|
||||||
if (exitCode === 0) {
|
if (exitCode === 0) {
|
||||||
// Command succeeded, this is the active state
|
// Command succeeded, this is the active state
|
||||||
_isHot = true
|
_isHot = true;
|
||||||
_activeStateIcon = currentCheckItem.icon || widgetSettings.icon || "heart"
|
_activeStateIcon = currentCheckItem.icon || widgetSettings.icon || "heart";
|
||||||
} else {
|
} else {
|
||||||
// Command failed, try next one
|
// Command failed, try next one
|
||||||
_currentStateCheckIndex++
|
_currentStateCheckIndex++;
|
||||||
_checkNextState()
|
_checkNextState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,53 +85,53 @@ Item {
|
|||||||
repeat: false
|
repeat: false
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
if (enableOnStateLogic && _parsedStateChecks.length > 0) {
|
if (enableOnStateLogic && _parsedStateChecks.length > 0) {
|
||||||
_currentStateCheckIndex = 0
|
_currentStateCheckIndex = 0;
|
||||||
_checkNextState()
|
_checkNextState();
|
||||||
} else {
|
} else {
|
||||||
_isHot = false
|
_isHot = false;
|
||||||
_activeStateIcon = widgetSettings.icon || "heart"
|
_activeStateIcon = widgetSettings.icon || "heart";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _checkNextState() {
|
function _checkNextState() {
|
||||||
if (_currentStateCheckIndex < _parsedStateChecks.length) {
|
if (_currentStateCheckIndex < _parsedStateChecks.length) {
|
||||||
var currentCheckItem = _parsedStateChecks[_currentStateCheckIndex]
|
var currentCheckItem = _parsedStateChecks[_currentStateCheckIndex];
|
||||||
if (currentCheckItem && currentCheckItem.command) {
|
if (currentCheckItem && currentCheckItem.command) {
|
||||||
stateCheckProcessExecutor.running = true
|
stateCheckProcessExecutor.running = true;
|
||||||
} else {
|
} else {
|
||||||
_currentStateCheckIndex++
|
_currentStateCheckIndex++;
|
||||||
_checkNextState()
|
_checkNextState();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// All checks failed
|
// All checks failed
|
||||||
_isHot = false
|
_isHot = false;
|
||||||
_activeStateIcon = widgetSettings.icon || "heart"
|
_activeStateIcon = widgetSettings.icon || "heart";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateState() {
|
function updateState() {
|
||||||
if (!enableOnStateLogic || _parsedStateChecks.length === 0) {
|
if (!enableOnStateLogic || _parsedStateChecks.length === 0) {
|
||||||
_isHot = false
|
_isHot = false;
|
||||||
_activeStateIcon = widgetSettings.icon || "heart"
|
_activeStateIcon = widgetSettings.icon || "heart";
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
stateUpdateTimer.restart()
|
stateUpdateTimer.restart();
|
||||||
}
|
}
|
||||||
|
|
||||||
function _buildTooltipText() {
|
function _buildTooltipText() {
|
||||||
let tooltip = generalTooltipText
|
let tooltip = generalTooltipText;
|
||||||
if (onClickedCommand) {
|
if (onClickedCommand) {
|
||||||
tooltip += `\nLeft click: ${onClickedCommand}`
|
tooltip += `\nLeft click: ${onClickedCommand}`;
|
||||||
}
|
}
|
||||||
if (onRightClickedCommand) {
|
if (onRightClickedCommand) {
|
||||||
tooltip += `\nRight click: ${onRightClickedCommand}`
|
tooltip += `\nRight click: ${onRightClickedCommand}`;
|
||||||
}
|
}
|
||||||
if (onMiddleClickedCommand) {
|
if (onMiddleClickedCommand) {
|
||||||
tooltip += `\nMiddle click: ${onMiddleClickedCommand}`
|
tooltip += `\nMiddle click: ${onMiddleClickedCommand}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tooltip
|
return tooltip;
|
||||||
}
|
}
|
||||||
|
|
||||||
NIconButtonHot {
|
NIconButtonHot {
|
||||||
@@ -141,20 +141,20 @@ Item {
|
|||||||
tooltipText: _buildTooltipText()
|
tooltipText: _buildTooltipText()
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (onClickedCommand) {
|
if (onClickedCommand) {
|
||||||
Quickshell.execDetached(["sh", "-c", onClickedCommand])
|
Quickshell.execDetached(["sh", "-c", onClickedCommand]);
|
||||||
updateState()
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
if (onRightClickedCommand) {
|
if (onRightClickedCommand) {
|
||||||
Quickshell.execDetached(["sh", "-c", onRightClickedCommand])
|
Quickshell.execDetached(["sh", "-c", onRightClickedCommand]);
|
||||||
updateState()
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onMiddleClicked: {
|
onMiddleClicked: {
|
||||||
if (onMiddleClickedCommand) {
|
if (onMiddleClickedCommand) {
|
||||||
Quickshell.execDetached(["sh", "-c", onMiddleClickedCommand])
|
Quickshell.execDetached(["sh", "-c", onMiddleClickedCommand]);
|
||||||
updateState()
|
updateState();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,19 +16,19 @@ NIconButtonHot {
|
|||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (!Settings.data.nightLight.enabled) {
|
if (!Settings.data.nightLight.enabled) {
|
||||||
Settings.data.nightLight.enabled = true
|
Settings.data.nightLight.enabled = true;
|
||||||
Settings.data.nightLight.forced = false
|
Settings.data.nightLight.forced = false;
|
||||||
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
|
} else if (Settings.data.nightLight.enabled && !Settings.data.nightLight.forced) {
|
||||||
Settings.data.nightLight.forced = true
|
Settings.data.nightLight.forced = true;
|
||||||
} else {
|
} else {
|
||||||
Settings.data.nightLight.enabled = false
|
Settings.data.nightLight.enabled = false;
|
||||||
Settings.data.nightLight.forced = false
|
Settings.data.nightLight.forced = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRightClicked: {
|
onRightClicked: {
|
||||||
var settingsPanel = PanelService.getPanel("settingsPanel", screen)
|
var settingsPanel = PanelService.getPanel("settingsPanel", screen);
|
||||||
settingsPanel.requestedTab = SettingsPanel.Tab.Display
|
settingsPanel.requestedTab = SettingsPanel.Tab.Display;
|
||||||
settingsPanel.open()
|
settingsPanel.open();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@ NIconButtonHot {
|
|||||||
hot: ScreenRecorderService.isRecording
|
hot: ScreenRecorderService.isRecording
|
||||||
tooltipText: I18n.tr("quickSettings.screenRecorder.tooltip.action")
|
tooltipText: I18n.tr("quickSettings.screenRecorder.tooltip.action")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
ScreenRecorderService.toggleRecording()
|
ScreenRecorderService.toggleRecording();
|
||||||
if (!ScreenRecorderService.isRecording) {
|
if (!ScreenRecorderService.isRecording) {
|
||||||
PanelService.getPanel("controlCenterPanel", screen)?.close
|
PanelService.getPanel("controlCenterPanel", screen)?.close;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,21 +11,21 @@ NIconButtonHot {
|
|||||||
icon: {
|
icon: {
|
||||||
try {
|
try {
|
||||||
if (NetworkService.ethernetConnected) {
|
if (NetworkService.ethernetConnected) {
|
||||||
return NetworkService.internetConnectivity ? "ethernet" : "ethernet-off"
|
return NetworkService.internetConnectivity ? "ethernet" : "ethernet-off";
|
||||||
}
|
}
|
||||||
let connected = false
|
let connected = false;
|
||||||
let signalStrength = 0
|
let signalStrength = 0;
|
||||||
for (const net in NetworkService.networks) {
|
for (const net in NetworkService.networks) {
|
||||||
if (NetworkService.networks[net].connected) {
|
if (NetworkService.networks[net].connected) {
|
||||||
connected = true
|
connected = true;
|
||||||
signalStrength = NetworkService.networks[net].signal
|
signalStrength = NetworkService.networks[net].signal;
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return connected ? NetworkService.signalIcon(signalStrength, true) : "wifi-off"
|
return connected ? NetworkService.signalIcon(signalStrength, true) : "wifi-off";
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
Logger.e("Wi-Fi", "Error getting icon:", error)
|
Logger.e("Wi-Fi", "Error getting icon:", error);
|
||||||
return "wifi-off"
|
return "wifi-off";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
|
|
||||||
|
import "Plugins"
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Modules.MainScreen
|
import qs.Modules.MainScreen
|
||||||
import qs.Services.Keyboard
|
import qs.Services.Keyboard
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
import "Plugins"
|
|
||||||
|
|
||||||
SmartPanel {
|
SmartPanel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -23,12 +23,12 @@ SmartPanel {
|
|||||||
readonly property string panelPosition: {
|
readonly property string panelPosition: {
|
||||||
if (Settings.data.appLauncher.position === "follow_bar") {
|
if (Settings.data.appLauncher.position === "follow_bar") {
|
||||||
if (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") {
|
if (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") {
|
||||||
return `center_${Settings.data.bar.position}`
|
return `center_${Settings.data.bar.position}`;
|
||||||
} else {
|
} else {
|
||||||
return `${Settings.data.bar.position}_center`
|
return `${Settings.data.bar.position}_center`;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Settings.data.appLauncher.position
|
return Settings.data.appLauncher.position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panelAnchorHorizontalCenter: panelPosition === "center" || panelPosition.endsWith("_center")
|
panelAnchorHorizontalCenter: panelPosition === "center" || panelPosition.endsWith("_center")
|
||||||
@@ -55,83 +55,83 @@ SmartPanel {
|
|||||||
// They are not coming from SmartPanelWindow as they are consumed by the search field before reaching the panel.
|
// They are not coming from SmartPanelWindow as they are consumed by the search field before reaching the panel.
|
||||||
// They are instead being forwared from the search field NTextInput below.
|
// They are instead being forwared from the search field NTextInput below.
|
||||||
function onTabPressed() {
|
function onTabPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBackTabPressed() {
|
function onBackTabPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUpPressed() {
|
function onUpPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDownPressed() {
|
function onDownPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReturnPressed() {
|
function onReturnPressed() {
|
||||||
activate()
|
activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHomePressed() {
|
function onHomePressed() {
|
||||||
selectFirst()
|
selectFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndPressed() {
|
function onEndPressed() {
|
||||||
selectLast()
|
selectLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPageUpPressed() {
|
function onPageUpPressed() {
|
||||||
selectPreviousPage()
|
selectPreviousPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onPageDownPressed() {
|
function onPageDownPressed() {
|
||||||
selectNextPage()
|
selectNextPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCtrlJPressed() {
|
function onCtrlJPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCtrlKPressed() {
|
function onCtrlKPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCtrlNPressed() {
|
function onCtrlNPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCtrlPPressed() {
|
function onCtrlPPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public API for plugins
|
// Public API for plugins
|
||||||
function setSearchText(text) {
|
function setSearchText(text) {
|
||||||
searchText = text
|
searchText = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plugin registration
|
// Plugin registration
|
||||||
function registerPlugin(plugin) {
|
function registerPlugin(plugin) {
|
||||||
plugins.push(plugin)
|
plugins.push(plugin);
|
||||||
plugin.launcher = root
|
plugin.launcher = root;
|
||||||
if (plugin.init)
|
if (plugin.init)
|
||||||
plugin.init()
|
plugin.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search handling
|
// Search handling
|
||||||
function updateResults() {
|
function updateResults() {
|
||||||
results = []
|
results = [];
|
||||||
activePlugin = null
|
activePlugin = null;
|
||||||
|
|
||||||
// Check for command mode
|
// Check for command mode
|
||||||
if (searchText.startsWith(">")) {
|
if (searchText.startsWith(">")) {
|
||||||
// Find plugin that handles this command
|
// Find plugin that handles this command
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
if (plugin.handleCommand && plugin.handleCommand(searchText)) {
|
if (plugin.handleCommand && plugin.handleCommand(searchText)) {
|
||||||
activePlugin = plugin
|
activePlugin = plugin;
|
||||||
results = plugin.getResults(searchText)
|
results = plugin.getResults(searchText);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +139,7 @@ SmartPanel {
|
|||||||
if (searchText === ">" && !activePlugin) {
|
if (searchText === ">" && !activePlugin) {
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
if (plugin.commands) {
|
if (plugin.commands) {
|
||||||
results = results.concat(plugin.commands())
|
results = results.concat(plugin.commands());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,43 +147,43 @@ SmartPanel {
|
|||||||
// Regular search - let plugins contribute results
|
// Regular search - let plugins contribute results
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
if (plugin.handleSearch) {
|
if (plugin.handleSearch) {
|
||||||
const pluginResults = plugin.getResults(searchText)
|
const pluginResults = plugin.getResults(searchText);
|
||||||
results = results.concat(pluginResults)
|
results = results.concat(pluginResults);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
onSearchTextChanged: updateResults()
|
onSearchTextChanged: updateResults()
|
||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
onOpened: {
|
onOpened: {
|
||||||
resultsReady = false
|
resultsReady = false;
|
||||||
ignoreMouseHover = true
|
ignoreMouseHover = true;
|
||||||
|
|
||||||
// Notify plugins and update results
|
// Notify plugins and update results
|
||||||
// Use Qt.callLater to ensure plugins are registered (Component.onCompleted runs first)
|
// Use Qt.callLater to ensure plugins are registered (Component.onCompleted runs first)
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
if (plugin.onOpened)
|
if (plugin.onOpened)
|
||||||
plugin.onOpened()
|
plugin.onOpened();
|
||||||
}
|
}
|
||||||
updateResults()
|
updateResults();
|
||||||
resultsReady = true
|
resultsReady = true;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosed: {
|
onClosed: {
|
||||||
// Reset search text
|
// Reset search text
|
||||||
searchText = ""
|
searchText = "";
|
||||||
ignoreMouseHover = true
|
ignoreMouseHover = true;
|
||||||
|
|
||||||
// Notify plugins
|
// Notify plugins
|
||||||
for (let plugin of plugins) {
|
for (let plugin of plugins) {
|
||||||
if (plugin.onClosed)
|
if (plugin.onClosed)
|
||||||
plugin.onClosed()
|
plugin.onClosed();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,16 +191,16 @@ SmartPanel {
|
|||||||
ApplicationsPlugin {
|
ApplicationsPlugin {
|
||||||
id: appsPlugin
|
id: appsPlugin
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
registerPlugin(this)
|
registerPlugin(this);
|
||||||
Logger.d("Launcher", "Registered: ApplicationsPlugin")
|
Logger.d("Launcher", "Registered: ApplicationsPlugin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CalculatorPlugin {
|
CalculatorPlugin {
|
||||||
id: calcPlugin
|
id: calcPlugin
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
registerPlugin(this)
|
registerPlugin(this);
|
||||||
Logger.d("Launcher", "Registered: CalculatorPlugin")
|
Logger.d("Launcher", "Registered: CalculatorPlugin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,8 +208,8 @@ SmartPanel {
|
|||||||
id: clipPlugin
|
id: clipPlugin
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (Settings.data.appLauncher.enableClipboardHistory) {
|
if (Settings.data.appLauncher.enableClipboardHistory) {
|
||||||
registerPlugin(this)
|
registerPlugin(this);
|
||||||
Logger.d("Launcher", "Registered: ClipboardPlugin")
|
Logger.d("Launcher", "Registered: ClipboardPlugin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,47 +217,47 @@ SmartPanel {
|
|||||||
// Navigation functions
|
// Navigation functions
|
||||||
function selectNextWrapped() {
|
function selectNextWrapped() {
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
selectedIndex = (selectedIndex + 1) % results.length
|
selectedIndex = (selectedIndex + 1) % results.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPreviousWrapped() {
|
function selectPreviousWrapped() {
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
selectedIndex = (((selectedIndex - 1) % results.length) + results.length) % results.length
|
selectedIndex = (((selectedIndex - 1) % results.length) + results.length) % results.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectFirst() {
|
function selectFirst() {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLast() {
|
function selectLast() {
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
selectedIndex = results.length - 1
|
selectedIndex = results.length - 1;
|
||||||
} else {
|
} else {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNextPage() {
|
function selectNextPage() {
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
const page = Math.max(1, Math.floor(600 / entryHeight)) // Use approximate height
|
const page = Math.max(1, Math.floor(600 / entryHeight)); // Use approximate height
|
||||||
selectedIndex = Math.min(selectedIndex + page, results.length - 1)
|
selectedIndex = Math.min(selectedIndex + page, results.length - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPreviousPage() {
|
function selectPreviousPage() {
|
||||||
if (results.length > 0) {
|
if (results.length > 0) {
|
||||||
const page = Math.max(1, Math.floor(600 / entryHeight)) // Use approximate height
|
const page = Math.max(1, Math.floor(600 / entryHeight)); // Use approximate height
|
||||||
selectedIndex = Math.max(selectedIndex - page, 0)
|
selectedIndex = Math.max(selectedIndex - page, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function activate() {
|
function activate() {
|
||||||
if (results.length > 0 && results[selectedIndex]) {
|
if (results.length > 0 && results[selectedIndex]) {
|
||||||
const item = results[selectedIndex]
|
const item = results[selectedIndex];
|
||||||
if (item.onActivate) {
|
if (item.onActivate) {
|
||||||
item.onActivate()
|
item.onActivate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -284,19 +284,19 @@ SmartPanel {
|
|||||||
onPositionChanged: mouse => {
|
onPositionChanged: mouse => {
|
||||||
// Store initial position
|
// Store initial position
|
||||||
if (!initialized) {
|
if (!initialized) {
|
||||||
lastX = mouse.x
|
lastX = mouse.x;
|
||||||
lastY = mouse.y
|
lastY = mouse.y;
|
||||||
initialized = true
|
initialized = true;
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if mouse actually moved
|
// Check if mouse actually moved
|
||||||
const deltaX = Math.abs(mouse.x - lastX)
|
const deltaX = Math.abs(mouse.x - lastX);
|
||||||
const deltaY = Math.abs(mouse.y - lastY)
|
const deltaY = Math.abs(mouse.y - lastY);
|
||||||
if (deltaX > 1 || deltaY > 1) {
|
if (deltaX > 1 || deltaY > 1) {
|
||||||
root.ignoreMouseHover = false
|
root.ignoreMouseHover = false;
|
||||||
lastX = mouse.x
|
lastX = mouse.x;
|
||||||
lastY = mouse.y
|
lastY = mouse.y;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,7 +304,7 @@ SmartPanel {
|
|||||||
Connections {
|
Connections {
|
||||||
target: root
|
target: root
|
||||||
function onOpened() {
|
function onOpened() {
|
||||||
mouseMovementDetector.initialized = false
|
mouseMovementDetector.initialized = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -316,9 +316,9 @@ SmartPanel {
|
|||||||
// Delay focus to ensure window has keyboard focus
|
// Delay focus to ensure window has keyboard focus
|
||||||
Qt.callLater(() => {
|
Qt.callLater(() => {
|
||||||
if (searchInput.inputItem) {
|
if (searchInput.inputItem) {
|
||||||
searchInput.inputItem.forceActiveFocus()
|
searchInput.inputItem.forceActiveFocus();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -348,17 +348,17 @@ SmartPanel {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (searchInput.inputItem) {
|
if (searchInput.inputItem) {
|
||||||
searchInput.inputItem.forceActiveFocus()
|
searchInput.inputItem.forceActiveFocus();
|
||||||
// Intercept Tab keys before TextField handles them
|
// Intercept Tab keys before TextField handles them
|
||||||
searchInput.inputItem.Keys.onPressed.connect(function (event) {
|
searchInput.inputItem.Keys.onPressed.connect(function (event) {
|
||||||
if (event.key === Qt.Key_Tab) {
|
if (event.key === Qt.Key_Tab) {
|
||||||
root.onTabPressed()
|
root.onTabPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
} else if (event.key === Qt.Key_Backtab) {
|
} else if (event.key === Qt.Key_Backtab) {
|
||||||
root.onBackTabPressed()
|
root.onBackTabPressed();
|
||||||
event.accepted = true
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -377,14 +377,12 @@ SmartPanel {
|
|||||||
currentIndex: selectedIndex
|
currentIndex: selectedIndex
|
||||||
cacheBuffer: resultsList.height * 2
|
cacheBuffer: resultsList.height * 2
|
||||||
onCurrentIndexChanged: {
|
onCurrentIndexChanged: {
|
||||||
cancelFlick()
|
cancelFlick();
|
||||||
if (currentIndex >= 0) {
|
if (currentIndex >= 0) {
|
||||||
positionViewAtIndex(currentIndex, ListView.Contain)
|
positionViewAtIndex(currentIndex, ListView.Contain);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onModelChanged: {
|
onModelChanged: {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
delegate: Rectangle {
|
||||||
id: entry
|
id: entry
|
||||||
@@ -396,19 +394,19 @@ SmartPanel {
|
|||||||
// Pin helpers
|
// Pin helpers
|
||||||
function togglePin(appId) {
|
function togglePin(appId) {
|
||||||
if (!appId)
|
if (!appId)
|
||||||
return
|
return;
|
||||||
let arr = (Settings.data.dock.pinnedApps || []).slice()
|
let arr = (Settings.data.dock.pinnedApps || []).slice();
|
||||||
const idx = arr.indexOf(appId)
|
const idx = arr.indexOf(appId);
|
||||||
if (idx >= 0)
|
if (idx >= 0)
|
||||||
arr.splice(idx, 1)
|
arr.splice(idx, 1);
|
||||||
else
|
else
|
||||||
arr.push(appId)
|
arr.push(appId);
|
||||||
Settings.data.dock.pinnedApps = arr
|
Settings.data.dock.pinnedApps = arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isPinned(appId) {
|
function isPinned(appId) {
|
||||||
const arr = Settings.data.dock.pinnedApps || []
|
const arr = Settings.data.dock.pinnedApps || [];
|
||||||
return appId && arr.indexOf(appId) >= 0
|
return appId && arr.indexOf(appId) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Property to reliably track the current item's ID.
|
// Property to reliably track the current item's ID.
|
||||||
@@ -419,7 +417,7 @@ SmartPanel {
|
|||||||
onCurrentClipboardIdChanged: {
|
onCurrentClipboardIdChanged: {
|
||||||
// Check if it's a valid ID and if the data isn't already cached.
|
// Check if it's a valid ID and if the data isn't already cached.
|
||||||
if (currentClipboardId && !ClipboardService.getImageData(currentClipboardId)) {
|
if (currentClipboardId && !ClipboardService.getImageData(currentClipboardId)) {
|
||||||
ClipboardService.decodeToDataUrl(currentClipboardId, modelData.mime, null)
|
ClipboardService.decodeToDataUrl(currentClipboardId, modelData.mime, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -466,8 +464,8 @@ SmartPanel {
|
|||||||
// Fetches from the service's cache.
|
// Fetches from the service's cache.
|
||||||
// The dependency on `_rev` ensures this binding is re-evaluated when the cache is updated.
|
// The dependency on `_rev` ensures this binding is re-evaluated when the cache is updated.
|
||||||
imagePath: {
|
imagePath: {
|
||||||
_rev
|
_rev;
|
||||||
return ClipboardService.getImageData(modelData.clipboardId) || ""
|
return ClipboardService.getImageData(modelData.clipboardId) || "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loading indicator
|
// Loading indicator
|
||||||
@@ -487,8 +485,8 @@ SmartPanel {
|
|||||||
// Error fallback
|
// Error fallback
|
||||||
onStatusChanged: status => {
|
onStatusChanged: status => {
|
||||||
if (status === Image.Error) {
|
if (status === Image.Error) {
|
||||||
iconLoader.visible = true
|
iconLoader.visible = true;
|
||||||
imagePreview.visible = false
|
imagePreview.visible = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -538,10 +536,10 @@ SmartPanel {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: {
|
text: {
|
||||||
if (!modelData.isImage)
|
if (!modelData.isImage)
|
||||||
return ""
|
return "";
|
||||||
const desc = modelData.description || ""
|
const desc = modelData.description || "";
|
||||||
const parts = desc.split(" • ")
|
const parts = desc.split(" • ");
|
||||||
return parts[0] || "IMG"
|
return parts[0] || "IMG";
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeXXS
|
pointSize: Style.fontSizeXXS
|
||||||
color: Color.mPrimary
|
color: Color.mPrimary
|
||||||
@@ -592,14 +590,14 @@ SmartPanel {
|
|||||||
cursorShape: Qt.PointingHandCursor
|
cursorShape: Qt.PointingHandCursor
|
||||||
onEntered: {
|
onEntered: {
|
||||||
if (!root.ignoreMouseHover) {
|
if (!root.ignoreMouseHover) {
|
||||||
selectedIndex = index
|
selectedIndex = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onClicked: mouse => {
|
onClicked: mouse => {
|
||||||
if (mouse.button === Qt.LeftButton) {
|
if (mouse.button === Qt.LeftButton) {
|
||||||
selectedIndex = index
|
selectedIndex = index;
|
||||||
root.activate()
|
root.activate();
|
||||||
mouse.accepted = true
|
mouse.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
acceptedButtons: Qt.LeftButton
|
acceptedButtons: Qt.LeftButton
|
||||||
@@ -616,9 +614,9 @@ SmartPanel {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: {
|
text: {
|
||||||
if (results.length === 0)
|
if (results.length === 0)
|
||||||
return searchText ? "No results" : ""
|
return searchText ? "No results" : "";
|
||||||
const prefix = activePlugin?.name ? `${activePlugin.name}: ` : ""
|
const prefix = activePlugin?.name ? `${activePlugin.name}: ` : "";
|
||||||
return prefix + `${results.length} result${results.length !== 1 ? 's' : ''}`
|
return prefix + `${results.length} result${results.length !== 1 ? 's' : ''}`;
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeXS
|
pointSize: Style.fontSizeXS
|
||||||
color: Color.mOnSurfaceVariant
|
color: Color.mOnSurfaceVariant
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import qs.Commons
|
|
||||||
import "../../../../Helpers/FuzzySort.js" as Fuzzysort
|
import "../../../../Helpers/FuzzySort.js" as Fuzzysort
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property var launcher: null
|
property var launcher: null
|
||||||
@@ -29,7 +29,7 @@ Item {
|
|||||||
|
|
||||||
onLoadFailed: function (error) {
|
onLoadFailed: function (error) {
|
||||||
if (error.toString().includes("No such file") || error === 2) {
|
if (error.toString().includes("No such file") || error === 2) {
|
||||||
writeAdapter()
|
writeAdapter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,89 +43,89 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
loadApplications()
|
loadApplications();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onOpened() {
|
function onOpened() {
|
||||||
// Refresh apps when launcher opens
|
// Refresh apps when launcher opens
|
||||||
loadApplications()
|
loadApplications();
|
||||||
}
|
}
|
||||||
|
|
||||||
function loadApplications() {
|
function loadApplications() {
|
||||||
if (typeof DesktopEntries === 'undefined') {
|
if (typeof DesktopEntries === 'undefined') {
|
||||||
Logger.w("ApplicationsPlugin", "DesktopEntries service not available")
|
Logger.w("ApplicationsPlugin", "DesktopEntries service not available");
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const allApps = DesktopEntries.applications.values || []
|
const allApps = DesktopEntries.applications.values || [];
|
||||||
entries = allApps.filter(app => app && !app.noDisplay).map(app => {
|
entries = allApps.filter(app => app && !app.noDisplay).map(app => {
|
||||||
// Add executable name property for search
|
// Add executable name property for search
|
||||||
app.executableName = getExecutableName(app)
|
app.executableName = getExecutableName(app);
|
||||||
return app
|
return app;
|
||||||
})
|
});
|
||||||
Logger.d("ApplicationsPlugin", `Loaded ${entries.length} applications`)
|
Logger.d("ApplicationsPlugin", `Loaded ${entries.length} applications`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getExecutableName(app) {
|
function getExecutableName(app) {
|
||||||
if (!app)
|
if (!app)
|
||||||
return ""
|
return "";
|
||||||
|
|
||||||
// Try to get executable name from command array
|
// Try to get executable name from command array
|
||||||
if (app.command && Array.isArray(app.command) && app.command.length > 0) {
|
if (app.command && Array.isArray(app.command) && app.command.length > 0) {
|
||||||
const cmd = app.command[0]
|
const cmd = app.command[0];
|
||||||
// Extract just the executable name from the full path
|
// Extract just the executable name from the full path
|
||||||
const parts = cmd.split('/')
|
const parts = cmd.split('/');
|
||||||
const executable = parts[parts.length - 1]
|
const executable = parts[parts.length - 1];
|
||||||
// Remove any arguments or parameters
|
// Remove any arguments or parameters
|
||||||
return executable.split(' ')[0]
|
return executable.split(' ')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get from exec property if available
|
// Try to get from exec property if available
|
||||||
if (app.exec) {
|
if (app.exec) {
|
||||||
const parts = app.exec.split('/')
|
const parts = app.exec.split('/');
|
||||||
const executable = parts[parts.length - 1]
|
const executable = parts[parts.length - 1];
|
||||||
return executable.split(' ')[0]
|
return executable.split(' ')[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to app id (desktop file name without .desktop)
|
// Fallback to app id (desktop file name without .desktop)
|
||||||
if (app.id) {
|
if (app.id) {
|
||||||
return app.id.replace('.desktop', '')
|
return app.id.replace('.desktop', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
return ""
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResults(query) {
|
function getResults(query) {
|
||||||
if (!entries || entries.length === 0)
|
if (!entries || entries.length === 0)
|
||||||
return []
|
return [];
|
||||||
|
|
||||||
if (!query || query.trim() === "") {
|
if (!query || query.trim() === "") {
|
||||||
// Return all apps, optionally sorted by usage
|
// Return all apps, optionally sorted by usage
|
||||||
const favoriteApps = Settings.data.appLauncher.favoriteApps || []
|
const favoriteApps = Settings.data.appLauncher.favoriteApps || [];
|
||||||
let sorted
|
let sorted;
|
||||||
if (Settings.data.appLauncher.sortByMostUsed) {
|
if (Settings.data.appLauncher.sortByMostUsed) {
|
||||||
sorted = entries.slice().sort((a, b) => {
|
sorted = entries.slice().sort((a, b) => {
|
||||||
// Favorites first
|
// Favorites first
|
||||||
const aFav = favoriteApps.includes(getAppKey(a))
|
const aFav = favoriteApps.includes(getAppKey(a));
|
||||||
const bFav = favoriteApps.includes(getAppKey(b))
|
const bFav = favoriteApps.includes(getAppKey(b));
|
||||||
if (aFav !== bFav)
|
if (aFav !== bFav)
|
||||||
return aFav ? -1 : 1
|
return aFav ? -1 : 1;
|
||||||
const ua = getUsageCount(a)
|
const ua = getUsageCount(a);
|
||||||
const ub = getUsageCount(b)
|
const ub = getUsageCount(b);
|
||||||
if (ub !== ua)
|
if (ub !== ua)
|
||||||
return ub - ua
|
return ub - ua;
|
||||||
return (a.name || "").toLowerCase().localeCompare((b.name || "").toLowerCase())
|
return (a.name || "").toLowerCase().localeCompare((b.name || "").toLowerCase());
|
||||||
})
|
});
|
||||||
} else {
|
} else {
|
||||||
sorted = entries.slice().sort((a, b) => {
|
sorted = entries.slice().sort((a, b) => {
|
||||||
const aFav = favoriteApps.includes(getAppKey(a))
|
const aFav = favoriteApps.includes(getAppKey(a));
|
||||||
const bFav = favoriteApps.includes(getAppKey(b))
|
const bFav = favoriteApps.includes(getAppKey(b));
|
||||||
if (aFav !== bFav)
|
if (aFav !== bFav)
|
||||||
return aFav ? -1 : 1
|
return aFav ? -1 : 1;
|
||||||
return (a.name || "").toLowerCase().localeCompare((b.name || "").toLowerCase())
|
return (a.name || "").toLowerCase().localeCompare((b.name || "").toLowerCase());
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return sorted.map(app => createResultEntry(app))
|
return sorted.map(app => createResultEntry(app));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use fuzzy search if available, fallback to simple search
|
// Use fuzzy search if available, fallback to simple search
|
||||||
@@ -134,54 +134,54 @@ Item {
|
|||||||
"keys": ["name", "comment", "genericName", "executableName"],
|
"keys": ["name", "comment", "genericName", "executableName"],
|
||||||
"threshold": -1000,
|
"threshold": -1000,
|
||||||
"limit": 20
|
"limit": 20
|
||||||
})
|
});
|
||||||
|
|
||||||
// Sort favorites first within fuzzy results while preserving fuzzysort order otherwise
|
// Sort favorites first within fuzzy results while preserving fuzzysort order otherwise
|
||||||
const favoriteApps = Settings.data.appLauncher.favoriteApps || []
|
const favoriteApps = Settings.data.appLauncher.favoriteApps || [];
|
||||||
const fav = []
|
const fav = [];
|
||||||
const nonFav = []
|
const nonFav = [];
|
||||||
for (const r of fuzzyResults) {
|
for (const r of fuzzyResults) {
|
||||||
const app = r.obj
|
const app = r.obj;
|
||||||
if (favoriteApps.includes(getAppKey(app)))
|
if (favoriteApps.includes(getAppKey(app)))
|
||||||
fav.push(r)
|
fav.push(r);
|
||||||
else
|
else
|
||||||
nonFav.push(r)
|
nonFav.push(r);
|
||||||
}
|
}
|
||||||
return fav.concat(nonFav).map(result => createResultEntry(result.obj))
|
return fav.concat(nonFav).map(result => createResultEntry(result.obj));
|
||||||
} else {
|
} else {
|
||||||
// Fallback to simple search
|
// Fallback to simple search
|
||||||
const searchTerm = query.toLowerCase()
|
const searchTerm = query.toLowerCase();
|
||||||
return entries.filter(app => {
|
return entries.filter(app => {
|
||||||
const name = (app.name || "").toLowerCase()
|
const name = (app.name || "").toLowerCase();
|
||||||
const comment = (app.comment || "").toLowerCase()
|
const comment = (app.comment || "").toLowerCase();
|
||||||
const generic = (app.genericName || "").toLowerCase()
|
const generic = (app.genericName || "").toLowerCase();
|
||||||
const executable = getExecutableName(app).toLowerCase()
|
const executable = getExecutableName(app).toLowerCase();
|
||||||
return name.includes(searchTerm) || comment.includes(searchTerm) || generic.includes(searchTerm) || executable.includes(searchTerm)
|
return name.includes(searchTerm) || comment.includes(searchTerm) || generic.includes(searchTerm) || executable.includes(searchTerm);
|
||||||
}).sort((a, b) => {
|
}).sort((a, b) => {
|
||||||
// Prioritize name matches, then executable matches
|
// Prioritize name matches, then executable matches
|
||||||
const aName = a.name.toLowerCase()
|
const aName = a.name.toLowerCase();
|
||||||
const bName = b.name.toLowerCase()
|
const bName = b.name.toLowerCase();
|
||||||
const aExecutable = getExecutableName(a).toLowerCase()
|
const aExecutable = getExecutableName(a).toLowerCase();
|
||||||
const bExecutable = getExecutableName(b).toLowerCase()
|
const bExecutable = getExecutableName(b).toLowerCase();
|
||||||
const aStarts = aName.startsWith(searchTerm)
|
const aStarts = aName.startsWith(searchTerm);
|
||||||
const bStarts = bName.startsWith(searchTerm)
|
const bStarts = bName.startsWith(searchTerm);
|
||||||
const aExecStarts = aExecutable.startsWith(searchTerm)
|
const aExecStarts = aExecutable.startsWith(searchTerm);
|
||||||
const bExecStarts = bExecutable.startsWith(searchTerm)
|
const bExecStarts = bExecutable.startsWith(searchTerm);
|
||||||
|
|
||||||
// Prioritize name matches first
|
// Prioritize name matches first
|
||||||
if (aStarts && !bStarts)
|
if (aStarts && !bStarts)
|
||||||
return -1
|
return -1;
|
||||||
if (!aStarts && bStarts)
|
if (!aStarts && bStarts)
|
||||||
return 1
|
return 1;
|
||||||
|
|
||||||
// Then prioritize executable matches
|
// Then prioritize executable matches
|
||||||
if (aExecStarts && !bExecStarts)
|
if (aExecStarts && !bExecStarts)
|
||||||
return -1
|
return -1;
|
||||||
if (!aExecStarts && bExecStarts)
|
if (!aExecStarts && bExecStarts)
|
||||||
return 1
|
return 1;
|
||||||
|
|
||||||
return aName.localeCompare(bName)
|
return aName.localeCompare(bName);
|
||||||
}).slice(0, 20).map(app => createResultEntry(app))
|
}).slice(0, 20).map(app => createResultEntry(app));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,75 +195,75 @@ Item {
|
|||||||
"onActivate": function () {
|
"onActivate": function () {
|
||||||
// Close the launcher/SmartPanel immediately without any animations.
|
// Close the launcher/SmartPanel immediately without any animations.
|
||||||
// Ensures we are not preventing the future focusing of the app
|
// Ensures we are not preventing the future focusing of the app
|
||||||
launcher.close()
|
launcher.close();
|
||||||
|
|
||||||
Logger.d("ApplicationsPlugin", `Launching: ${app.name}`)
|
Logger.d("ApplicationsPlugin", `Launching: ${app.name}`);
|
||||||
// Record usage and persist asynchronously
|
// Record usage and persist asynchronously
|
||||||
if (Settings.data.appLauncher.sortByMostUsed)
|
if (Settings.data.appLauncher.sortByMostUsed)
|
||||||
recordUsage(app)
|
recordUsage(app);
|
||||||
if (Settings.data.appLauncher.customLaunchPrefixEnabled && Settings.data.appLauncher.customLaunchPrefix) {
|
if (Settings.data.appLauncher.customLaunchPrefixEnabled && Settings.data.appLauncher.customLaunchPrefix) {
|
||||||
// Use custom launch prefix
|
// Use custom launch prefix
|
||||||
const prefix = Settings.data.appLauncher.customLaunchPrefix.split(" ")
|
const prefix = Settings.data.appLauncher.customLaunchPrefix.split(" ");
|
||||||
|
|
||||||
if (app.runInTerminal) {
|
if (app.runInTerminal) {
|
||||||
const terminal = Settings.data.appLauncher.terminalCommand.split(" ")
|
const terminal = Settings.data.appLauncher.terminalCommand.split(" ");
|
||||||
const command = prefix.concat(terminal.concat(app.command))
|
const command = prefix.concat(terminal.concat(app.command));
|
||||||
Quickshell.execDetached(command)
|
Quickshell.execDetached(command);
|
||||||
} else {
|
} else {
|
||||||
const command = prefix.concat(app.command)
|
const command = prefix.concat(app.command);
|
||||||
Quickshell.execDetached(command)
|
Quickshell.execDetached(command);
|
||||||
}
|
}
|
||||||
} else if (Settings.data.appLauncher.useApp2Unit && app.id) {
|
} else if (Settings.data.appLauncher.useApp2Unit && app.id) {
|
||||||
Logger.d("ApplicationsPlugin", `Using app2unit for: ${app.id}`)
|
Logger.d("ApplicationsPlugin", `Using app2unit for: ${app.id}`);
|
||||||
if (app.runInTerminal)
|
if (app.runInTerminal)
|
||||||
Quickshell.execDetached(["app2unit", "--", app.id + ".desktop"])
|
Quickshell.execDetached(["app2unit", "--", app.id + ".desktop"]);
|
||||||
else
|
else
|
||||||
Quickshell.execDetached(["app2unit", "--"].concat(app.command))
|
Quickshell.execDetached(["app2unit", "--"].concat(app.command));
|
||||||
} else {
|
} else {
|
||||||
// Fallback logic when app2unit is not used
|
// Fallback logic when app2unit is not used
|
||||||
if (app.runInTerminal) {
|
if (app.runInTerminal) {
|
||||||
// If app.execute() fails for terminal apps, we handle it manually.
|
// If app.execute() fails for terminal apps, we handle it manually.
|
||||||
Logger.d("ApplicationsPlugin", "Executing terminal app manually: " + app.name)
|
Logger.d("ApplicationsPlugin", "Executing terminal app manually: " + app.name);
|
||||||
const terminal = Settings.data.appLauncher.terminalCommand.split(" ")
|
const terminal = Settings.data.appLauncher.terminalCommand.split(" ");
|
||||||
const command = terminal.concat(app.command)
|
const command = terminal.concat(app.command);
|
||||||
Quickshell.execDetached(command)
|
Quickshell.execDetached(command);
|
||||||
} else if (app.execute) {
|
} else if (app.execute) {
|
||||||
// Default execution for GUI apps
|
// Default execution for GUI apps
|
||||||
app.execute()
|
app.execute();
|
||||||
} else {
|
} else {
|
||||||
Logger.w("ApplicationsPlugin", `Could not launch: ${app.name}. No valid launch method.`)
|
Logger.w("ApplicationsPlugin", `Could not launch: ${app.name}. No valid launch method.`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------
|
// -------------------------
|
||||||
// Usage tracking helpers
|
// Usage tracking helpers
|
||||||
function getAppKey(app) {
|
function getAppKey(app) {
|
||||||
if (app && app.id)
|
if (app && app.id)
|
||||||
return String(app.id)
|
return String(app.id);
|
||||||
if (app && app.command && app.command.join)
|
if (app && app.command && app.command.join)
|
||||||
return app.command.join(" ")
|
return app.command.join(" ");
|
||||||
return String(app && app.name ? app.name : "unknown")
|
return String(app && app.name ? app.name : "unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
function getUsageCount(app) {
|
function getUsageCount(app) {
|
||||||
const key = getAppKey(app)
|
const key = getAppKey(app);
|
||||||
const m = usageAdapter && usageAdapter.counts ? usageAdapter.counts : null
|
const m = usageAdapter && usageAdapter.counts ? usageAdapter.counts : null;
|
||||||
if (!m)
|
if (!m)
|
||||||
return 0
|
return 0;
|
||||||
const v = m[key]
|
const v = m[key];
|
||||||
return typeof v === 'number' && isFinite(v) ? v : 0
|
return typeof v === 'number' && isFinite(v) ? v : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function recordUsage(app) {
|
function recordUsage(app) {
|
||||||
const key = getAppKey(app)
|
const key = getAppKey(app);
|
||||||
if (!usageAdapter.counts)
|
if (!usageAdapter.counts)
|
||||||
usageAdapter.counts = ({})
|
usageAdapter.counts = ({});
|
||||||
const current = getUsageCount(app)
|
const current = getUsageCount(app);
|
||||||
usageAdapter.counts[key] = current + 1
|
usageAdapter.counts[key] = current + 1;
|
||||||
// Trigger save via debounced timer
|
// Trigger save via debounced timer
|
||||||
saveTimer.restart()
|
saveTimer.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Commons
|
|
||||||
import "../../../../Helpers/AdvancedMath.js" as AdvancedMath
|
import "../../../../Helpers/AdvancedMath.js" as AdvancedMath
|
||||||
|
import qs.Commons
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
property var launcher: null
|
property var launcher: null
|
||||||
@@ -8,98 +8,106 @@ Item {
|
|||||||
|
|
||||||
function handleCommand(query) {
|
function handleCommand(query) {
|
||||||
// Handle >calc command or direct math expressions after >
|
// Handle >calc command or direct math expressions after >
|
||||||
return query.startsWith(">calc") || (query.startsWith(">") && query.length > 1 && isMathExpression(query.substring(1)))
|
return query.startsWith(">calc") || (query.startsWith(">") && query.length > 1 && isMathExpression(query.substring(1)));
|
||||||
}
|
}
|
||||||
|
|
||||||
function commands() {
|
function commands() {
|
||||||
return [{
|
return [
|
||||||
"name": ">calc",
|
{
|
||||||
"description": I18n.tr("plugins.calculator-description"),
|
"name": ">calc",
|
||||||
"icon": "accessories-calculator",
|
"description": I18n.tr("plugins.calculator-description"),
|
||||||
"isImage": false,
|
"icon": "accessories-calculator",
|
||||||
"onActivate": function () {
|
"isImage": false,
|
||||||
launcher.setSearchText(">calc ")
|
"onActivate": function () {
|
||||||
}
|
launcher.setSearchText(">calc ");
|
||||||
}]
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getResults(query) {
|
function getResults(query) {
|
||||||
let expression = ""
|
let expression = "";
|
||||||
|
|
||||||
if (query.startsWith(">calc")) {
|
if (query.startsWith(">calc")) {
|
||||||
expression = query.substring(5).trim()
|
expression = query.substring(5).trim();
|
||||||
} else if (query.startsWith(">")) {
|
} else if (query.startsWith(">")) {
|
||||||
expression = query.substring(1).trim()
|
expression = query.substring(1).trim();
|
||||||
} else {
|
} else {
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!expression) {
|
if (!expression) {
|
||||||
return [{
|
return [
|
||||||
"name": I18n.tr("plugins.calculator-name"),
|
{
|
||||||
"description": I18n.tr("plugins.calculator-enter-expression"),
|
"name": I18n.tr("plugins.calculator-name"),
|
||||||
"icon": "accessories-calculator",
|
"description": I18n.tr("plugins.calculator-enter-expression"),
|
||||||
"isImage": false,
|
"icon": "accessories-calculator",
|
||||||
"onActivate": function () {}
|
"isImage": false,
|
||||||
}]
|
"onActivate": function () {}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let result = AdvancedMath.evaluate(expression.trim())
|
let result = AdvancedMath.evaluate(expression.trim());
|
||||||
|
|
||||||
return [{
|
return [
|
||||||
"name": AdvancedMath.formatResult(result),
|
{
|
||||||
"description": `${expression} = ${result}`,
|
"name": AdvancedMath.formatResult(result),
|
||||||
"icon": "accessories-calculator",
|
"description": `${expression} = ${result}`,
|
||||||
"isImage": false,
|
"icon": "accessories-calculator",
|
||||||
"onActivate": function () {
|
"isImage": false,
|
||||||
// TODO: copy entry to clipboard via ClipHist
|
"onActivate": function () {
|
||||||
launcher.close()
|
// TODO: copy entry to clipboard via ClipHist
|
||||||
}
|
launcher.close();
|
||||||
}]
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return [{
|
return [
|
||||||
"name": I18n.tr("plugins.calculator-error"),
|
{
|
||||||
"description": error.message || "Invalid expression",
|
"name": I18n.tr("plugins.calculator-error"),
|
||||||
"icon": "dialog-error",
|
"description": error.message || "Invalid expression",
|
||||||
"isImage": false,
|
"icon": "dialog-error",
|
||||||
"onActivate": function () {}
|
"isImage": false,
|
||||||
}]
|
"onActivate": function () {}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function evaluateExpression(expr) {
|
function evaluateExpression(expr) {
|
||||||
// Sanitize input - only allow safe characters
|
// Sanitize input - only allow safe characters
|
||||||
const sanitized = expr.replace(/[^0-9\+\-\*\/\(\)\.\s\%]/g, '')
|
const sanitized = expr.replace(/[^0-9\+\-\*\/\(\)\.\s\%]/g, '');
|
||||||
if (sanitized !== expr) {
|
if (sanitized !== expr) {
|
||||||
throw new Error("Invalid characters in expression")
|
throw new Error("Invalid characters in expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow empty expressions
|
// Don't allow empty expressions
|
||||||
if (!sanitized.trim()) {
|
if (!sanitized.trim()) {
|
||||||
throw new Error("Empty expression")
|
throw new Error("Empty expression");
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Use Function constructor for safe evaluation
|
// Use Function constructor for safe evaluation
|
||||||
// This is safer than eval() but still evaluate math
|
// This is safer than eval() but still evaluate math
|
||||||
const result = Function('"use strict"; return (' + sanitized + ')')()
|
const result = Function('"use strict"; return (' + sanitized + ')')();
|
||||||
|
|
||||||
// Check for valid result
|
// Check for valid result
|
||||||
if (!isFinite(result)) {
|
if (!isFinite(result)) {
|
||||||
throw new Error("Result is not a finite number")
|
throw new Error("Result is not a finite number");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Round to reasonable precision to avoid floating point issues
|
// Round to reasonable precision to avoid floating point issues
|
||||||
return Math.round(result * 1000000000) / 1000000000
|
return Math.round(result * 1000000000) / 1000000000;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
throw new Error("Invalid mathematical expression")
|
throw new Error("Invalid mathematical expression");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMathExpression(expr) {
|
function isMathExpression(expr) {
|
||||||
// Check if string looks like a math expression
|
// Check if string looks like a math expression
|
||||||
// Allow digits, operators, parentheses, decimal points, and whitespace
|
// Allow digits, operators, parentheses, decimal points, and whitespace
|
||||||
return /^[\d\s\+\-\*\/\(\)\.\%]+$/.test(expr)
|
return /^[\d\s\+\-\*\/\(\)\.\%]+$/.test(expr);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,14 +25,14 @@ Item {
|
|||||||
if (gotResults && (lastSearchText === searchText)) {
|
if (gotResults && (lastSearchText === searchText)) {
|
||||||
// Do not update results after the first fetch.
|
// Do not update results after the first fetch.
|
||||||
// This will avoid the list resetting every 2seconds when the service updates.
|
// This will avoid the list resetting every 2seconds when the service updates.
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
// Refresh results if we're waiting for data or if clipboard plugin is active
|
// Refresh results if we're waiting for data or if clipboard plugin is active
|
||||||
if (isWaitingForData || (launcher && launcher.searchText.startsWith(">clip"))) {
|
if (isWaitingForData || (launcher && launcher.searchText.startsWith(">clip"))) {
|
||||||
isWaitingForData = false
|
isWaitingForData = false;
|
||||||
gotResults = true
|
gotResults = true;
|
||||||
if (launcher) {
|
if (launcher) {
|
||||||
launcher.updateResults()
|
launcher.updateResults();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -40,142 +40,153 @@ Item {
|
|||||||
|
|
||||||
// Initialize plugin
|
// Initialize plugin
|
||||||
function init() {
|
function init() {
|
||||||
Logger.i("ClipboardPlugin", "Initialized")
|
Logger.i("ClipboardPlugin", "Initialized");
|
||||||
// Pre-load clipboard data if service is active
|
// Pre-load clipboard data if service is active
|
||||||
if (ClipboardService.active) {
|
if (ClipboardService.active) {
|
||||||
ClipboardService.list(100)
|
ClipboardService.list(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when launcher opens
|
// Called when launcher opens
|
||||||
function onOpened() {
|
function onOpened() {
|
||||||
isWaitingForData = true
|
isWaitingForData = true;
|
||||||
gotResults = false
|
gotResults = false;
|
||||||
lastSearchText = ""
|
lastSearchText = "";
|
||||||
|
|
||||||
// Refresh clipboard history when launcher opens
|
// Refresh clipboard history when launcher opens
|
||||||
if (ClipboardService.active) {
|
if (ClipboardService.active) {
|
||||||
ClipboardService.list(100)
|
ClipboardService.list(100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if this plugin handles the command
|
// Check if this plugin handles the command
|
||||||
function handleCommand(searchText) {
|
function handleCommand(searchText) {
|
||||||
return searchText.startsWith(">clip")
|
return searchText.startsWith(">clip");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return available commands when user types ">"
|
// Return available commands when user types ">"
|
||||||
function commands() {
|
function commands() {
|
||||||
return [{
|
return [
|
||||||
"name": ">clip",
|
{
|
||||||
"description": I18n.tr("plugins.clipboard-search-description"),
|
"name": ">clip",
|
||||||
"icon": "text-x-generic",
|
"description": I18n.tr("plugins.clipboard-search-description"),
|
||||||
"isImage": false,
|
"icon": "text-x-generic",
|
||||||
"onActivate": function () {
|
"isImage": false,
|
||||||
launcher.setSearchText(">clip ")
|
"onActivate": function () {
|
||||||
}
|
launcher.setSearchText(">clip ");
|
||||||
}, {
|
}
|
||||||
"name": ">clip clear",
|
},
|
||||||
"description": I18n.tr("plugins.clipboard-clear-description"),
|
{
|
||||||
"icon": "text-x-generic",
|
"name": ">clip clear",
|
||||||
"isImage": false,
|
"description": I18n.tr("plugins.clipboard-clear-description"),
|
||||||
"onActivate": function () {
|
"icon": "text-x-generic",
|
||||||
ClipboardService.wipeAll()
|
"isImage": false,
|
||||||
launcher.close()
|
"onActivate": function () {
|
||||||
}
|
ClipboardService.wipeAll();
|
||||||
}]
|
launcher.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get search results
|
// Get search results
|
||||||
function getResults(searchText) {
|
function getResults(searchText) {
|
||||||
if (!searchText.startsWith(">clip")) {
|
if (!searchText.startsWith(">clip")) {
|
||||||
return []
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
lastSearchText = searchText
|
lastSearchText = searchText;
|
||||||
const results = []
|
const results = [];
|
||||||
const query = searchText.slice(5).trim()
|
const query = searchText.slice(5).trim();
|
||||||
|
|
||||||
// Check if clipboard service is not active
|
// Check if clipboard service is not active
|
||||||
if (!ClipboardService.active) {
|
if (!ClipboardService.active) {
|
||||||
return [{
|
return [
|
||||||
"name": I18n.tr("plugins.clipboard-history-disabled"),
|
{
|
||||||
"description": I18n.tr("plugins.clipboard-history-disabled-description"),
|
"name": I18n.tr("plugins.clipboard-history-disabled"),
|
||||||
"icon": "view-refresh",
|
"description": I18n.tr("plugins.clipboard-history-disabled-description"),
|
||||||
"isImage": false,
|
"icon": "view-refresh",
|
||||||
"onActivate": function () {}
|
"isImage": false,
|
||||||
}]
|
"onActivate": function () {}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Special command: clear
|
// Special command: clear
|
||||||
if (query === "clear") {
|
if (query === "clear") {
|
||||||
return [{
|
return [
|
||||||
"name": I18n.tr("plugins.clipboard-clear-history"),
|
{
|
||||||
"description": I18n.tr("plugins.clipboard-clear-description-full"),
|
"name": I18n.tr("plugins.clipboard-clear-history"),
|
||||||
"icon": "delete_sweep",
|
"description": I18n.tr("plugins.clipboard-clear-description-full"),
|
||||||
"isImage": false,
|
"icon": "delete_sweep",
|
||||||
"onActivate": function () {
|
"isImage": false,
|
||||||
ClipboardService.wipeAll()
|
"onActivate": function () {
|
||||||
launcher.close()
|
ClipboardService.wipeAll();
|
||||||
}
|
launcher.close();
|
||||||
}]
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show loading state if data is being loaded
|
// Show loading state if data is being loaded
|
||||||
if (ClipboardService.loading || isWaitingForData) {
|
if (ClipboardService.loading || isWaitingForData) {
|
||||||
return [{
|
return [
|
||||||
"name": I18n.tr("plugins.clipboard-loading"),
|
{
|
||||||
"description": I18n.tr("plugins.clipboard-loading-description"),
|
"name": I18n.tr("plugins.clipboard-loading"),
|
||||||
"icon": "view-refresh",
|
"description": I18n.tr("plugins.clipboard-loading-description"),
|
||||||
"isImage": false,
|
"icon": "view-refresh",
|
||||||
"onActivate": function () {}
|
"isImage": false,
|
||||||
}]
|
"onActivate": function () {}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get clipboard items
|
// Get clipboard items
|
||||||
const items = ClipboardService.items || []
|
const items = ClipboardService.items || [];
|
||||||
|
|
||||||
// If no items and we haven't tried loading yet, trigger a load
|
// If no items and we haven't tried loading yet, trigger a load
|
||||||
if (items.count === 0 && !ClipboardService.loading) {
|
if (items.count === 0 && !ClipboardService.loading) {
|
||||||
isWaitingForData = true
|
isWaitingForData = true;
|
||||||
ClipboardService.list(100)
|
ClipboardService.list(100);
|
||||||
return [{
|
return [
|
||||||
"name": I18n.tr("plugins.clipboard-loading"),
|
{
|
||||||
"description": I18n.tr("plugins.clipboard-loading-description"),
|
"name": I18n.tr("plugins.clipboard-loading"),
|
||||||
"icon": "view-refresh",
|
"description": I18n.tr("plugins.clipboard-loading-description"),
|
||||||
"isImage": false,
|
"icon": "view-refresh",
|
||||||
"onActivate": function () {}
|
"isImage": false,
|
||||||
}]
|
"onActivate": function () {}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search clipboard items
|
// Search clipboard items
|
||||||
const searchTerm = query.toLowerCase()
|
const searchTerm = query.toLowerCase();
|
||||||
|
|
||||||
// Filter and format results
|
// Filter and format results
|
||||||
items.forEach(function (item) {
|
items.forEach(function (item) {
|
||||||
const preview = (item.preview || "").toLowerCase()
|
const preview = (item.preview || "").toLowerCase();
|
||||||
|
|
||||||
// Skip if search term doesn't match
|
// Skip if search term doesn't match
|
||||||
if (searchTerm && preview.indexOf(searchTerm) === -1) {
|
if (searchTerm && preview.indexOf(searchTerm) === -1) {
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format the result based on type
|
// Format the result based on type
|
||||||
let entry
|
let entry;
|
||||||
if (item.isImage) {
|
if (item.isImage) {
|
||||||
entry = formatImageEntry(item)
|
entry = formatImageEntry(item);
|
||||||
} else {
|
} else {
|
||||||
entry = formatTextEntry(item)
|
entry = formatTextEntry(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add activation handler
|
// Add activation handler
|
||||||
entry.onActivate = function () {
|
entry.onActivate = function () {
|
||||||
ClipboardService.copyToClipboard(item.id)
|
ClipboardService.copyToClipboard(item.id);
|
||||||
launcher.close()
|
launcher.close();
|
||||||
}
|
};
|
||||||
|
|
||||||
results.push(entry)
|
results.push(entry);
|
||||||
})
|
});
|
||||||
|
|
||||||
// Show empty state if no results
|
// Show empty state if no results
|
||||||
if (results.length === 0) {
|
if (results.length === 0) {
|
||||||
@@ -186,16 +197,16 @@ Item {
|
|||||||
"isImage": false,
|
"isImage": false,
|
||||||
"onActivate": function () {// Do nothing
|
"onActivate": function () {// Do nothing
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
//Logger.i("ClipboardPlugin", `Returning ${results.length} results for query: "${query}"`)
|
//Logger.i("ClipboardPlugin", `Returning ${results.length} results for query: "${query}"`)
|
||||||
return results
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: Format image clipboard entry
|
// Helper: Format image clipboard entry
|
||||||
function formatImageEntry(item) {
|
function formatImageEntry(item) {
|
||||||
const meta = parseImageMeta(item.preview)
|
const meta = parseImageMeta(item.preview);
|
||||||
|
|
||||||
// The launcher's delegate will now be responsible for fetching the image data.
|
// The launcher's delegate will now be responsible for fetching the image data.
|
||||||
// This function's role is to provide the necessary metadata for that request.
|
// This function's role is to provide the necessary metadata for that request.
|
||||||
@@ -208,31 +219,31 @@ Item {
|
|||||||
"imageHeight": meta ? meta.h : 0,
|
"imageHeight": meta ? meta.h : 0,
|
||||||
"clipboardId": item.id,
|
"clipboardId": item.id,
|
||||||
"mime": item.mime
|
"mime": item.mime
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: Format text clipboard entry with preview
|
// Helper: Format text clipboard entry with preview
|
||||||
function formatTextEntry(item) {
|
function formatTextEntry(item) {
|
||||||
const preview = (item.preview || "").trim()
|
const preview = (item.preview || "").trim();
|
||||||
const lines = preview.split('\n').filter(l => l.trim())
|
const lines = preview.split('\n').filter(l => l.trim());
|
||||||
|
|
||||||
// Use first line as title, limit length
|
// Use first line as title, limit length
|
||||||
let title = lines[0] || "Empty text"
|
let title = lines[0] || "Empty text";
|
||||||
if (title.length > 60) {
|
if (title.length > 60) {
|
||||||
title = title.substring(0, 57) + "..."
|
title = title.substring(0, 57) + "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use second line or character count as description
|
// Use second line or character count as description
|
||||||
let description = ""
|
let description = "";
|
||||||
if (lines.length > 1) {
|
if (lines.length > 1) {
|
||||||
description = lines[1]
|
description = lines[1];
|
||||||
if (description.length > 80) {
|
if (description.length > 80) {
|
||||||
description = description.substring(0, 77) + "..."
|
description = description.substring(0, 77) + "...";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const chars = preview.length
|
const chars = preview.length;
|
||||||
const words = preview.split(/\s+/).length
|
const words = preview.split(/\s+/).length;
|
||||||
description = `${chars} characters, ${words} word${words !== 1 ? 's' : ''}`
|
description = `${chars} characters, ${words} word${words !== 1 ? 's' : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -240,16 +251,16 @@ Item {
|
|||||||
"description": description,
|
"description": description,
|
||||||
"icon": "text-x-generic",
|
"icon": "text-x-generic",
|
||||||
"isImage": false
|
"isImage": false
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper: Parse image metadata from preview string
|
// Helper: Parse image metadata from preview string
|
||||||
function parseImageMeta(preview) {
|
function parseImageMeta(preview) {
|
||||||
const re = /\[\[\s*binary data\s+([\d\.]+\s*(?:KiB|MiB|GiB|B))\s+(\w+)\s+(\d+)x(\d+)\s*\]\]/i
|
const re = /\[\[\s*binary data\s+([\d\.]+\s*(?:KiB|MiB|GiB|B))\s+(\w+)\s+(\d+)x(\d+)\s*\]\]/i;
|
||||||
const match = (preview || "").match(re)
|
const match = (preview || "").match(re);
|
||||||
|
|
||||||
if (!match) {
|
if (!match) {
|
||||||
return null
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -257,12 +268,12 @@ Item {
|
|||||||
"fmt": (match[2] || "").toUpperCase(),
|
"fmt": (match[2] || "").toUpperCase(),
|
||||||
"w": Number(match[3]),
|
"w": Number(match[3]),
|
||||||
"h": Number(match[4])
|
"h": Number(match[4])
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public method to get image data for a clipboard item
|
// Public method to get image data for a clipboard item
|
||||||
// This can be called by the launcher when rendering
|
// This can be called by the launcher when rendering
|
||||||
function getImageForItem(clipboardId) {
|
function getImageForItem(clipboardId) {
|
||||||
return ClipboardService.getImageData ? ClipboardService.getImageData(clipboardId) : null
|
return ClipboardService.getImageData ? ClipboardService.getImageData(clipboardId) : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
|
||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Wayland
|
|
||||||
import Quickshell.Services.Notifications
|
import Quickshell.Services.Notifications
|
||||||
|
import Quickshell.Wayland
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.MainScreen
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.MainScreen
|
|
||||||
|
|
||||||
// Notification History panel
|
// Notification History panel
|
||||||
SmartPanel {
|
SmartPanel {
|
||||||
@@ -17,7 +17,7 @@ SmartPanel {
|
|||||||
preferredHeight: Math.round(540 * Style.uiScaleRatio)
|
preferredHeight: Math.round(540 * Style.uiScaleRatio)
|
||||||
|
|
||||||
onOpened: function () {
|
onOpened: function () {
|
||||||
NotificationService.updateLastSeenTs()
|
NotificationService.updateLastSeenTs();
|
||||||
}
|
}
|
||||||
|
|
||||||
panelContent: Rectangle {
|
panelContent: Rectangle {
|
||||||
@@ -67,9 +67,9 @@ SmartPanel {
|
|||||||
tooltipText: I18n.tr("tooltips.clear-history")
|
tooltipText: I18n.tr("tooltips.clear-history")
|
||||||
baseSize: Style.baseWidgetSize * 0.8
|
baseSize: Style.baseWidgetSize * 0.8
|
||||||
onClicked: {
|
onClicked: {
|
||||||
NotificationService.clearHistory()
|
NotificationService.clearHistory();
|
||||||
// Close panel as there is nothing more to see.
|
// Close panel as there is nothing more to see.
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,9 +177,9 @@ SmartPanel {
|
|||||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (scrollView.expandedId === notificationId) {
|
if (scrollView.expandedId === notificationId) {
|
||||||
scrollView.expandedId = ""
|
scrollView.expandedId = "";
|
||||||
} else {
|
} else {
|
||||||
scrollView.expandedId = notificationId
|
scrollView.expandedId = notificationId;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -227,11 +227,11 @@ SmartPanel {
|
|||||||
visible: model.urgency !== 1
|
visible: model.urgency !== 1
|
||||||
color: {
|
color: {
|
||||||
if (model.urgency === 2)
|
if (model.urgency === 2)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
else if (model.urgency === 0)
|
else if (model.urgency === 0)
|
||||||
return Color.mOnSurfaceVariant
|
return Color.mOnSurfaceVariant;
|
||||||
else
|
else
|
||||||
return Color.transparent
|
return Color.transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,7 +312,7 @@ SmartPanel {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
onClicked: {
|
onClicked: {
|
||||||
NotificationService.removeFromHistory(notificationId)
|
NotificationService.removeFromHistory(notificationId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,31 +4,31 @@ import QtQuick.Effects
|
|||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Io
|
import Quickshell.Io
|
||||||
import Quickshell.Widgets
|
|
||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
|
import Quickshell.Widgets
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
|
import qs.Modules.MainScreen
|
||||||
import qs.Services.Compositor
|
import qs.Services.Compositor
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
import qs.Modules.MainScreen
|
|
||||||
|
|
||||||
SmartPanel {
|
SmartPanel {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
preferredWidth: Math.round(400 * Style.uiScaleRatio)
|
preferredWidth: Math.round(400 * Style.uiScaleRatio)
|
||||||
preferredHeight: {
|
preferredHeight: {
|
||||||
var headerHeight = Settings.data.sessionMenu.showHeader ? Style.baseWidgetSize * 0.6 : 0
|
var headerHeight = Settings.data.sessionMenu.showHeader ? Style.baseWidgetSize * 0.6 : 0;
|
||||||
|
|
||||||
var dividerHeight = Settings.data.sessionMenu.showHeader ? Style.marginS : 0
|
var dividerHeight = Settings.data.sessionMenu.showHeader ? Style.marginS : 0;
|
||||||
var buttonHeight = Style.baseWidgetSize * 1.3 * Style.uiScaleRatio
|
var buttonHeight = Style.baseWidgetSize * 1.3 * Style.uiScaleRatio;
|
||||||
var buttonSpacing = Style.marginS
|
var buttonSpacing = Style.marginS;
|
||||||
var enabledCount = powerOptions.length
|
var enabledCount = powerOptions.length;
|
||||||
|
|
||||||
var headerSpacing = Settings.data.sessionMenu.showHeader ? (Style.marginL * 2) : 0
|
var headerSpacing = Settings.data.sessionMenu.showHeader ? (Style.marginL * 2) : 0;
|
||||||
var baseHeight = (Style.marginL * 4) + headerHeight + dividerHeight + headerSpacing
|
var baseHeight = (Style.marginL * 4) + headerHeight + dividerHeight + headerSpacing;
|
||||||
var buttonsHeight = enabledCount > 0 ? (buttonHeight * enabledCount) + (buttonSpacing * (enabledCount - 1)) : 0
|
var buttonsHeight = enabledCount > 0 ? (buttonHeight * enabledCount) + (buttonSpacing * (enabledCount - 1)) : 0;
|
||||||
|
|
||||||
return Math.round(baseHeight + buttonsHeight)
|
return Math.round(baseHeight + buttonsHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Positioning
|
// Positioning
|
||||||
@@ -89,216 +89,216 @@ SmartPanel {
|
|||||||
|
|
||||||
// Build powerOptions from settings, filtering enabled ones and adding metadata
|
// Build powerOptions from settings, filtering enabled ones and adding metadata
|
||||||
property var powerOptions: {
|
property var powerOptions: {
|
||||||
var options = []
|
var options = [];
|
||||||
var settingsOptions = Settings.data.sessionMenu.powerOptions || []
|
var settingsOptions = Settings.data.sessionMenu.powerOptions || [];
|
||||||
|
|
||||||
for (var i = 0; i < settingsOptions.length; i++) {
|
for (var i = 0; i < settingsOptions.length; i++) {
|
||||||
var settingOption = settingsOptions[i]
|
var settingOption = settingsOptions[i];
|
||||||
if (settingOption.enabled && actionMetadata[settingOption.action]) {
|
if (settingOption.enabled && actionMetadata[settingOption.action]) {
|
||||||
var metadata = actionMetadata[settingOption.action]
|
var metadata = actionMetadata[settingOption.action];
|
||||||
options.push({
|
options.push({
|
||||||
"action": settingOption.action,
|
"action": settingOption.action,
|
||||||
"icon": metadata.icon,
|
"icon": metadata.icon,
|
||||||
"title": metadata.title,
|
"title": metadata.title,
|
||||||
"isShutdown": metadata.isShutdown,
|
"isShutdown": metadata.isShutdown,
|
||||||
"countdownEnabled": settingOption.countdownEnabled !== undefined ? settingOption.countdownEnabled : true
|
"countdownEnabled": settingOption.countdownEnabled !== undefined ? settingOption.countdownEnabled : true
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return options
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update powerOptions when settings change
|
// Update powerOptions when settings change
|
||||||
Connections {
|
Connections {
|
||||||
target: Settings.data.sessionMenu
|
target: Settings.data.sessionMenu
|
||||||
function onPowerOptionsChanged() {
|
function onPowerOptionsChanged() {
|
||||||
var options = []
|
var options = [];
|
||||||
var settingsOptions = Settings.data.sessionMenu.powerOptions || []
|
var settingsOptions = Settings.data.sessionMenu.powerOptions || [];
|
||||||
|
|
||||||
for (var i = 0; i < settingsOptions.length; i++) {
|
for (var i = 0; i < settingsOptions.length; i++) {
|
||||||
var settingOption = settingsOptions[i]
|
var settingOption = settingsOptions[i];
|
||||||
if (settingOption.enabled && actionMetadata[settingOption.action]) {
|
if (settingOption.enabled && actionMetadata[settingOption.action]) {
|
||||||
var metadata = actionMetadata[settingOption.action]
|
var metadata = actionMetadata[settingOption.action];
|
||||||
options.push({
|
options.push({
|
||||||
"action": settingOption.action,
|
"action": settingOption.action,
|
||||||
"icon": metadata.icon,
|
"icon": metadata.icon,
|
||||||
"title": metadata.title,
|
"title": metadata.title,
|
||||||
"isShutdown": metadata.isShutdown,
|
"isShutdown": metadata.isShutdown,
|
||||||
"countdownEnabled": settingOption.countdownEnabled !== undefined ? settingOption.countdownEnabled : true
|
"countdownEnabled": settingOption.countdownEnabled !== undefined ? settingOption.countdownEnabled : true
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root.powerOptions = options
|
root.powerOptions = options;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lifecycle handlers
|
// Lifecycle handlers
|
||||||
onOpened: {
|
onOpened: {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClosed: {
|
onClosed: {
|
||||||
cancelTimer()
|
cancelTimer();
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Timer management
|
// Timer management
|
||||||
function startTimer(action) {
|
function startTimer(action) {
|
||||||
// Check if global countdown is disabled
|
// Check if global countdown is disabled
|
||||||
if (!Settings.data.sessionMenu.enableCountdown) {
|
if (!Settings.data.sessionMenu.enableCountdown) {
|
||||||
executeAction(action)
|
executeAction(action);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check per-item countdown setting
|
// Check per-item countdown setting
|
||||||
var option = null
|
var option = null;
|
||||||
for (var i = 0; i < powerOptions.length; i++) {
|
for (var i = 0; i < powerOptions.length; i++) {
|
||||||
if (powerOptions[i].action === action) {
|
if (powerOptions[i].action === action) {
|
||||||
option = powerOptions[i]
|
option = powerOptions[i];
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this specific action has countdown disabled, execute immediately
|
// If this specific action has countdown disabled, execute immediately
|
||||||
if (option && option.countdownEnabled === false) {
|
if (option && option.countdownEnabled === false) {
|
||||||
executeAction(action)
|
executeAction(action);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timerActive && pendingAction === action) {
|
if (timerActive && pendingAction === action) {
|
||||||
// Second click - execute immediately
|
// Second click - execute immediately
|
||||||
executeAction(action)
|
executeAction(action);
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingAction = action
|
pendingAction = action;
|
||||||
timeRemaining = timerDuration
|
timeRemaining = timerDuration;
|
||||||
timerActive = true
|
timerActive = true;
|
||||||
countdownTimer.start()
|
countdownTimer.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
function cancelTimer() {
|
function cancelTimer() {
|
||||||
timerActive = false
|
timerActive = false;
|
||||||
pendingAction = ""
|
pendingAction = "";
|
||||||
timeRemaining = 0
|
timeRemaining = 0;
|
||||||
countdownTimer.stop()
|
countdownTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
function executeAction(action) {
|
function executeAction(action) {
|
||||||
// Stop timer but don't reset other properties yet
|
// Stop timer but don't reset other properties yet
|
||||||
countdownTimer.stop()
|
countdownTimer.stop();
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case "lock":
|
case "lock":
|
||||||
// Access lockScreen via PanelService
|
// Access lockScreen via PanelService
|
||||||
if (PanelService.lockScreen && !PanelService.lockScreen.active) {
|
if (PanelService.lockScreen && !PanelService.lockScreen.active) {
|
||||||
PanelService.lockScreen.active = true
|
PanelService.lockScreen.active = true;
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
case "suspend":
|
case "suspend":
|
||||||
// Check if we should lock before suspending
|
// Check if we should lock before suspending
|
||||||
if (Settings.data.general.lockOnSuspend) {
|
if (Settings.data.general.lockOnSuspend) {
|
||||||
CompositorService.lockAndSuspend()
|
CompositorService.lockAndSuspend();
|
||||||
} else {
|
} else {
|
||||||
CompositorService.suspend()
|
CompositorService.suspend();
|
||||||
}
|
}
|
||||||
break
|
break;
|
||||||
case "hibernate":
|
case "hibernate":
|
||||||
CompositorService.hibernate()
|
CompositorService.hibernate();
|
||||||
break
|
break;
|
||||||
case "reboot":
|
case "reboot":
|
||||||
CompositorService.reboot()
|
CompositorService.reboot();
|
||||||
break
|
break;
|
||||||
case "logout":
|
case "logout":
|
||||||
CompositorService.logout()
|
CompositorService.logout();
|
||||||
break
|
break;
|
||||||
case "shutdown":
|
case "shutdown":
|
||||||
CompositorService.shutdown()
|
CompositorService.shutdown();
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset timer state and close panel
|
// Reset timer state and close panel
|
||||||
cancelTimer()
|
cancelTimer();
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Navigation functions
|
// Navigation functions
|
||||||
function selectNextWrapped() {
|
function selectNextWrapped() {
|
||||||
if (powerOptions.length > 0) {
|
if (powerOptions.length > 0) {
|
||||||
selectedIndex = (selectedIndex + 1) % powerOptions.length
|
selectedIndex = (selectedIndex + 1) % powerOptions.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPreviousWrapped() {
|
function selectPreviousWrapped() {
|
||||||
if (powerOptions.length > 0) {
|
if (powerOptions.length > 0) {
|
||||||
selectedIndex = (((selectedIndex - 1) % powerOptions.length) + powerOptions.length) % powerOptions.length
|
selectedIndex = (((selectedIndex - 1) % powerOptions.length) + powerOptions.length) % powerOptions.length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectFirst() {
|
function selectFirst() {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLast() {
|
function selectLast() {
|
||||||
if (powerOptions.length > 0) {
|
if (powerOptions.length > 0) {
|
||||||
selectedIndex = powerOptions.length - 1
|
selectedIndex = powerOptions.length - 1;
|
||||||
} else {
|
} else {
|
||||||
selectedIndex = 0
|
selectedIndex = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function activate() {
|
function activate() {
|
||||||
if (powerOptions.length > 0 && powerOptions[selectedIndex]) {
|
if (powerOptions.length > 0 && powerOptions[selectedIndex]) {
|
||||||
const option = powerOptions[selectedIndex]
|
const option = powerOptions[selectedIndex];
|
||||||
startTimer(option.action)
|
startTimer(option.action);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Override keyboard handlers from SmartPanel
|
// Override keyboard handlers from SmartPanel
|
||||||
function onEscapePressed() {
|
function onEscapePressed() {
|
||||||
if (timerActive) {
|
if (timerActive) {
|
||||||
cancelTimer()
|
cancelTimer();
|
||||||
} else {
|
} else {
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTabPressed() {
|
function onTabPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onBackTabPressed() {
|
function onBackTabPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onUpPressed() {
|
function onUpPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onDownPressed() {
|
function onDownPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onReturnPressed() {
|
function onReturnPressed() {
|
||||||
activate()
|
activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onHomePressed() {
|
function onHomePressed() {
|
||||||
selectFirst()
|
selectFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onEndPressed() {
|
function onEndPressed() {
|
||||||
selectLast()
|
selectLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCtrlJPressed() {
|
function onCtrlJPressed() {
|
||||||
selectNextWrapped()
|
selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function onCtrlKPressed() {
|
function onCtrlKPressed() {
|
||||||
selectPreviousWrapped()
|
selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Countdown timer
|
// Countdown timer
|
||||||
@@ -307,9 +307,9 @@ SmartPanel {
|
|||||||
interval: 100
|
interval: 100
|
||||||
repeat: true
|
repeat: true
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
timeRemaining -= interval
|
timeRemaining -= interval;
|
||||||
if (timeRemaining <= 0) {
|
if (timeRemaining <= 0) {
|
||||||
executeAction(pendingAction)
|
executeAction(pendingAction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -320,23 +320,23 @@ SmartPanel {
|
|||||||
|
|
||||||
// Navigation functions
|
// Navigation functions
|
||||||
function selectFirst() {
|
function selectFirst() {
|
||||||
root.selectFirst()
|
root.selectFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectLast() {
|
function selectLast() {
|
||||||
root.selectLast()
|
root.selectLast();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectNextWrapped() {
|
function selectNextWrapped() {
|
||||||
root.selectNextWrapped()
|
root.selectNextWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function selectPreviousWrapped() {
|
function selectPreviousWrapped() {
|
||||||
root.selectPreviousWrapped()
|
root.selectPreviousWrapped();
|
||||||
}
|
}
|
||||||
|
|
||||||
function activate() {
|
function activate() {
|
||||||
root.activate()
|
root.activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
NBox {
|
NBox {
|
||||||
@@ -379,10 +379,10 @@ SmartPanel {
|
|||||||
colorFg: timerActive ? Color.mError : Color.mOnSurface
|
colorFg: timerActive ? Color.mError : Color.mOnSurface
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (timerActive) {
|
if (timerActive) {
|
||||||
cancelTimer()
|
cancelTimer();
|
||||||
} else {
|
} else {
|
||||||
cancelTimer()
|
cancelTimer();
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -407,8 +407,8 @@ SmartPanel {
|
|||||||
isShutdown: modelData.isShutdown || false
|
isShutdown: modelData.isShutdown || false
|
||||||
isSelected: index === selectedIndex
|
isSelected: index === selectedIndex
|
||||||
onClicked: {
|
onClicked: {
|
||||||
selectedIndex = index
|
selectedIndex = index;
|
||||||
startTimer(modelData.action)
|
startTimer(modelData.action);
|
||||||
}
|
}
|
||||||
pending: timerActive && pendingAction === modelData.action
|
pending: timerActive && pendingAction === modelData.action
|
||||||
}
|
}
|
||||||
@@ -434,12 +434,12 @@ SmartPanel {
|
|||||||
radius: Style.radiusS
|
radius: Style.radiusS
|
||||||
color: {
|
color: {
|
||||||
if (pending) {
|
if (pending) {
|
||||||
return Qt.alpha(Color.mPrimary, 0.08)
|
return Qt.alpha(Color.mPrimary, 0.08);
|
||||||
}
|
}
|
||||||
if (isSelected || mouseArea.containsMouse) {
|
if (isSelected || mouseArea.containsMouse) {
|
||||||
return Color.mHover
|
return Color.mHover;
|
||||||
}
|
}
|
||||||
return Color.transparent
|
return Color.transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
border.width: pending ? Math.max(Style.borderM) : 0
|
border.width: pending ? Math.max(Style.borderM) : 0
|
||||||
@@ -464,12 +464,12 @@ SmartPanel {
|
|||||||
icon: buttonRoot.icon
|
icon: buttonRoot.icon
|
||||||
color: {
|
color: {
|
||||||
if (buttonRoot.pending)
|
if (buttonRoot.pending)
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||||
return Color.mOnHover
|
return Color.mOnHover;
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
}
|
}
|
||||||
pointSize: Style.fontSizeXXL
|
pointSize: Style.fontSizeXXL
|
||||||
width: Style.baseWidgetSize * 0.5
|
width: Style.baseWidgetSize * 0.5
|
||||||
@@ -499,12 +499,12 @@ SmartPanel {
|
|||||||
pointSize: Style.fontSizeM
|
pointSize: Style.fontSizeM
|
||||||
color: {
|
color: {
|
||||||
if (buttonRoot.pending)
|
if (buttonRoot.pending)
|
||||||
return Color.mPrimary
|
return Color.mPrimary;
|
||||||
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
if (buttonRoot.isShutdown && !buttonRoot.isSelected && !mouseArea.containsMouse)
|
||||||
return Color.mError
|
return Color.mError;
|
||||||
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
if (buttonRoot.isSelected || mouseArea.containsMouse)
|
||||||
return Color.mOnHover
|
return Color.mOnHover;
|
||||||
return Color.mOnSurface
|
return Color.mOnSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on color {
|
Behavior on color {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Services.UI
|
import qs.Services.UI
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
// Widget Settings Dialog Component
|
// Widget Settings Dialog Component
|
||||||
Popup {
|
Popup {
|
||||||
@@ -27,7 +27,7 @@ Popup {
|
|||||||
onOpened: {
|
onOpened: {
|
||||||
// Load settings when popup opens with data
|
// Load settings when popup opens with data
|
||||||
if (widgetData && widgetId) {
|
if (widgetData && widgetId) {
|
||||||
loadWidgetSettings()
|
loadWidgetSettings();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,9 +102,9 @@ Popup {
|
|||||||
icon: "check"
|
icon: "check"
|
||||||
onClicked: {
|
onClicked: {
|
||||||
if (settingsLoader.item && settingsLoader.item.saveSettings) {
|
if (settingsLoader.item && settingsLoader.item.saveSettings) {
|
||||||
var newSettings = settingsLoader.item.saveSettings()
|
var newSettings = settingsLoader.item.saveSettings();
|
||||||
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings)
|
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings);
|
||||||
root.close()
|
root.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,13 +112,13 @@ Popup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function loadWidgetSettings() {
|
function loadWidgetSettings() {
|
||||||
const source = BarWidgetRegistry.widgetSettingsMap[widgetId]
|
const source = BarWidgetRegistry.widgetSettingsMap[widgetId];
|
||||||
if (source) {
|
if (source) {
|
||||||
// Use setSource to pass properties at creation time
|
// Use setSource to pass properties at creation time
|
||||||
settingsLoader.setSource(source, {
|
settingsLoader.setSource(source, {
|
||||||
"widgetData": widgetData,
|
"widgetData": widgetData,
|
||||||
"widgetMetadata": BarWidgetRegistry.widgetMetadata[widgetId]
|
"widgetMetadata": BarWidgetRegistry.widgetMetadata[widgetId]
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,35 +22,39 @@ ColumnLayout {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (widgetData && widgetData.hideMode !== undefined) {
|
if (widgetData && widgetData.hideMode !== undefined) {
|
||||||
valueHideMode = widgetData.hideMode
|
valueHideMode = widgetData.hideMode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.hideMode = valueHideMode
|
settings.hideMode = valueHideMode;
|
||||||
settings.showIcon = valueShowIcon
|
settings.showIcon = valueShowIcon;
|
||||||
settings.scrollingMode = valueScrollingMode
|
settings.scrollingMode = valueScrollingMode;
|
||||||
settings.maxWidth = parseInt(widthInput.text) || widgetMetadata.maxWidth
|
settings.maxWidth = parseInt(widthInput.text) || widgetMetadata.maxWidth;
|
||||||
settings.useFixedWidth = valueUseFixedWidth
|
settings.useFixedWidth = valueUseFixedWidth;
|
||||||
settings.colorizeIcons = valueColorizeIcons
|
settings.colorizeIcons = valueColorizeIcons;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NComboBox {
|
NComboBox {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
label: I18n.tr("bar.widget-settings.active-window.hide-mode.label")
|
label: I18n.tr("bar.widget-settings.active-window.hide-mode.label")
|
||||||
description: I18n.tr("bar.widget-settings.active-window.hide-mode.description")
|
description: I18n.tr("bar.widget-settings.active-window.hide-mode.description")
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "visible",
|
"key": "visible",
|
||||||
"name": I18n.tr("options.hide-modes.visible")
|
"name": I18n.tr("options.hide-modes.visible")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "hidden",
|
"key": "hidden",
|
||||||
"name": I18n.tr("options.hide-modes.hidden")
|
"name": I18n.tr("options.hide-modes.hidden")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "transparent",
|
"key": "transparent",
|
||||||
"name": I18n.tr("options.hide-modes.transparent")
|
"name": I18n.tr("options.hide-modes.transparent")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: root.valueHideMode
|
currentKey: root.valueHideMode
|
||||||
onSelected: key => root.valueHideMode = key
|
onSelected: key => root.valueHideMode = key
|
||||||
}
|
}
|
||||||
@@ -91,16 +95,20 @@ ColumnLayout {
|
|||||||
NComboBox {
|
NComboBox {
|
||||||
label: I18n.tr("bar.widget-settings.active-window.scrolling-mode.label")
|
label: I18n.tr("bar.widget-settings.active-window.scrolling-mode.label")
|
||||||
description: I18n.tr("bar.widget-settings.active-window.scrolling-mode.description")
|
description: I18n.tr("bar.widget-settings.active-window.scrolling-mode.description")
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "always",
|
"key": "always",
|
||||||
"name": I18n.tr("options.scrolling-modes.always")
|
"name": I18n.tr("options.scrolling-modes.always")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "hover",
|
"key": "hover",
|
||||||
"name": I18n.tr("options.scrolling-modes.hover")
|
"name": I18n.tr("options.scrolling-modes.hover")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "never",
|
"key": "never",
|
||||||
"name": I18n.tr("options.scrolling-modes.never")
|
"name": I18n.tr("options.scrolling-modes.never")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: valueScrollingMode
|
currentKey: valueScrollingMode
|
||||||
onSelected: key => valueScrollingMode = key
|
onSelected: key => valueScrollingMode = key
|
||||||
minimumWidth: 200
|
minimumWidth: 200
|
||||||
|
|||||||
@@ -17,11 +17,11 @@ ColumnLayout {
|
|||||||
property string valueColorName: widgetData.colorName !== undefined ? widgetData.colorName : widgetMetadata.colorName
|
property string valueColorName: widgetData.colorName !== undefined ? widgetData.colorName : widgetMetadata.colorName
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.width = parseInt(widthInput.text) || widgetMetadata.width
|
settings.width = parseInt(widthInput.text) || widgetMetadata.width;
|
||||||
settings.hideWhenIdle = valueHideWhenIdle
|
settings.hideWhenIdle = valueHideWhenIdle;
|
||||||
settings.colorName = valueColorName
|
settings.colorName = valueColorName;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTextInput {
|
NTextInput {
|
||||||
@@ -37,22 +37,28 @@ ColumnLayout {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
label: I18n.tr("bar.widget-settings.audio-visualizer.color-name.label")
|
label: I18n.tr("bar.widget-settings.audio-visualizer.color-name.label")
|
||||||
description: I18n.tr("bar.widget-settings.audio-visualizer.color-name.description")
|
description: I18n.tr("bar.widget-settings.audio-visualizer.color-name.description")
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "primary",
|
"key": "primary",
|
||||||
"name": I18n.tr("options.colors.primary")
|
"name": I18n.tr("options.colors.primary")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "secondary",
|
"key": "secondary",
|
||||||
"name": I18n.tr("options.colors.secondary")
|
"name": I18n.tr("options.colors.secondary")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "tertiary",
|
"key": "tertiary",
|
||||||
"name": I18n.tr("options.colors.tertiary")
|
"name": I18n.tr("options.colors.tertiary")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "onSurface",
|
"key": "onSurface",
|
||||||
"name": I18n.tr("options.colors.onSurface")
|
"name": I18n.tr("options.colors.onSurface")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "error",
|
"key": "error",
|
||||||
"name": I18n.tr("options.colors.error")
|
"name": I18n.tr("options.colors.error")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: root.valueColorName
|
currentKey: root.valueColorName
|
||||||
onSelected: key => root.valueColorName = key
|
onSelected: key => root.valueColorName = key
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,26 +17,30 @@ ColumnLayout {
|
|||||||
property int valueWarningThreshold: widgetData.warningThreshold !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
|
property int valueWarningThreshold: widgetData.warningThreshold !== undefined ? widgetData.warningThreshold : widgetMetadata.warningThreshold
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.displayMode = valueDisplayMode
|
settings.displayMode = valueDisplayMode;
|
||||||
settings.warningThreshold = valueWarningThreshold
|
settings.warningThreshold = valueWarningThreshold;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NComboBox {
|
NComboBox {
|
||||||
label: I18n.tr("bar.widget-settings.battery.display-mode.label")
|
label: I18n.tr("bar.widget-settings.battery.display-mode.label")
|
||||||
description: I18n.tr("bar.widget-settings.battery.display-mode.description")
|
description: I18n.tr("bar.widget-settings.battery.display-mode.description")
|
||||||
minimumWidth: 134
|
minimumWidth: 134
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "onhover",
|
"key": "onhover",
|
||||||
"name": I18n.tr("options.display-mode.on-hover")
|
"name": I18n.tr("options.display-mode.on-hover")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysShow",
|
"key": "alwaysShow",
|
||||||
"name": I18n.tr("options.display-mode.always-show")
|
"name": I18n.tr("options.display-mode.always-show")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysHide",
|
"key": "alwaysHide",
|
||||||
"name": I18n.tr("options.display-mode.always-hide")
|
"name": I18n.tr("options.display-mode.always-hide")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: root.valueDisplayMode
|
currentKey: root.valueDisplayMode
|
||||||
onSelected: key => root.valueDisplayMode = key
|
onSelected: key => root.valueDisplayMode = key
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,25 +15,29 @@ ColumnLayout {
|
|||||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.displayMode = valueDisplayMode
|
settings.displayMode = valueDisplayMode;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NComboBox {
|
NComboBox {
|
||||||
label: I18n.tr("bar.widget-settings.battery.display-mode.label")
|
label: I18n.tr("bar.widget-settings.battery.display-mode.label")
|
||||||
description: I18n.tr("bar.widget-settings.battery.display-mode.description")
|
description: I18n.tr("bar.widget-settings.battery.display-mode.description")
|
||||||
minimumWidth: 134
|
minimumWidth: 134
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "onhover",
|
"key": "onhover",
|
||||||
"name": I18n.tr("options.display-mode.on-hover")
|
"name": I18n.tr("options.display-mode.on-hover")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysShow",
|
"key": "alwaysShow",
|
||||||
"name": I18n.tr("options.display-mode.always-show")
|
"name": I18n.tr("options.display-mode.always-show")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysHide",
|
"key": "alwaysHide",
|
||||||
"name": I18n.tr("options.display-mode.always-hide")
|
"name": I18n.tr("options.display-mode.always-hide")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: root.valueDisplayMode
|
currentKey: root.valueDisplayMode
|
||||||
onSelected: key => root.valueDisplayMode = key
|
onSelected: key => root.valueDisplayMode = key
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,25 +16,29 @@ ColumnLayout {
|
|||||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.displayMode = valueDisplayMode
|
settings.displayMode = valueDisplayMode;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NComboBox {
|
NComboBox {
|
||||||
label: I18n.tr("bar.widget-settings.brightness.display-mode.label")
|
label: I18n.tr("bar.widget-settings.brightness.display-mode.label")
|
||||||
description: I18n.tr("bar.widget-settings.brightness.display-mode.description")
|
description: I18n.tr("bar.widget-settings.brightness.display-mode.description")
|
||||||
minimumWidth: 134
|
minimumWidth: 134
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "onhover",
|
"key": "onhover",
|
||||||
"name": I18n.tr("options.display-mode.on-hover")
|
"name": I18n.tr("options.display-mode.on-hover")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysShow",
|
"key": "alwaysShow",
|
||||||
"name": I18n.tr("options.display-mode.always-show")
|
"name": I18n.tr("options.display-mode.always-show")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysHide",
|
"key": "alwaysHide",
|
||||||
"name": I18n.tr("options.display-mode.always-hide")
|
"name": I18n.tr("options.display-mode.always-hide")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: valueDisplayMode
|
currentKey: valueDisplayMode
|
||||||
onSelected: key => valueDisplayMode = key
|
onSelected: key => valueDisplayMode = key
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import qs.Commons
|
import qs.Commons
|
||||||
import qs.Widgets
|
|
||||||
import qs.Services.System
|
import qs.Services.System
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
@@ -28,13 +28,13 @@ ColumnLayout {
|
|||||||
readonly property var now: Time.now
|
readonly property var now: Time.now
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.usePrimaryColor = valueUsePrimaryColor
|
settings.usePrimaryColor = valueUsePrimaryColor;
|
||||||
settings.useCustomFont = valueUseCustomFont
|
settings.useCustomFont = valueUseCustomFont;
|
||||||
settings.customFont = valueCustomFont
|
settings.customFont = valueCustomFont;
|
||||||
settings.formatHorizontal = valueFormatHorizontal.trim()
|
settings.formatHorizontal = valueFormatHorizontal.trim();
|
||||||
settings.formatVertical = valueFormatVertical.trim()
|
settings.formatVertical = valueFormatVertical.trim();
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to insert token at cursor position in the focused input
|
// Function to insert token at cursor position in the focused input
|
||||||
@@ -42,25 +42,25 @@ ColumnLayout {
|
|||||||
if (!focusedInput || !focusedInput.inputItem) {
|
if (!focusedInput || !focusedInput.inputItem) {
|
||||||
// If no input is focused, default to horiz
|
// If no input is focused, default to horiz
|
||||||
if (inputHoriz.inputItem) {
|
if (inputHoriz.inputItem) {
|
||||||
inputHoriz.inputItem.focus = true
|
inputHoriz.inputItem.focus = true;
|
||||||
focusedInput = inputHoriz
|
focusedInput = inputHoriz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (focusedInput && focusedInput.inputItem) {
|
if (focusedInput && focusedInput.inputItem) {
|
||||||
var input = focusedInput.inputItem
|
var input = focusedInput.inputItem;
|
||||||
var cursorPos = input.cursorPosition
|
var cursorPos = input.cursorPosition;
|
||||||
var currentText = input.text
|
var currentText = input.text;
|
||||||
|
|
||||||
// Insert token at cursor position
|
// Insert token at cursor position
|
||||||
var newText = currentText.substring(0, cursorPos) + token + currentText.substring(cursorPos)
|
var newText = currentText.substring(0, cursorPos) + token + currentText.substring(cursorPos);
|
||||||
input.text = newText + " "
|
input.text = newText + " ";
|
||||||
|
|
||||||
// Move cursor after the inserted token
|
// Move cursor after the inserted token
|
||||||
input.cursorPosition = cursorPos + token.length + 1
|
input.cursorPosition = cursorPos + token.length + 1;
|
||||||
|
|
||||||
// Ensure the input keeps focus
|
// Ensure the input keeps focus
|
||||||
input.focus = true
|
input.focus = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +92,7 @@ ColumnLayout {
|
|||||||
popupHeight: 420
|
popupHeight: 420
|
||||||
minimumWidth: 300
|
minimumWidth: 300
|
||||||
onSelected: function (key) {
|
onSelected: function (key) {
|
||||||
valueCustomFont = key
|
valueCustomFont = key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,9 +131,9 @@ ColumnLayout {
|
|||||||
if (inputItem) {
|
if (inputItem) {
|
||||||
inputItem.onActiveFocusChanged.connect(function () {
|
inputItem.onActiveFocusChanged.connect(function () {
|
||||||
if (inputItem.activeFocus) {
|
if (inputItem.activeFocus) {
|
||||||
root.focusedInput = inputHoriz
|
root.focusedInput = inputHoriz;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -155,9 +155,9 @@ ColumnLayout {
|
|||||||
if (inputItem) {
|
if (inputItem) {
|
||||||
inputItem.onActiveFocusChanged.connect(function () {
|
inputItem.onActiveFocusChanged.connect(function () {
|
||||||
if (inputItem.activeFocus) {
|
if (inputItem.activeFocus) {
|
||||||
root.focusedInput = inputVert
|
root.focusedInput = inputVert;
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,12 +20,12 @@ ColumnLayout {
|
|||||||
property bool valueColorizeDistroLogo: widgetData.colorizeDistroLogo !== undefined ? widgetData.colorizeDistroLogo : (widgetMetadata.colorizeDistroLogo !== undefined ? widgetMetadata.colorizeDistroLogo : false)
|
property bool valueColorizeDistroLogo: widgetData.colorizeDistroLogo !== undefined ? widgetData.colorizeDistroLogo : (widgetMetadata.colorizeDistroLogo !== undefined ? widgetMetadata.colorizeDistroLogo : false)
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.icon = valueIcon
|
settings.icon = valueIcon;
|
||||||
settings.useDistroLogo = valueUseDistroLogo
|
settings.useDistroLogo = valueUseDistroLogo;
|
||||||
settings.customIconPath = valueCustomIconPath
|
settings.customIconPath = valueCustomIconPath;
|
||||||
settings.colorizeDistroLogo = valueColorizeDistroLogo
|
settings.colorizeDistroLogo = valueColorizeDistroLogo;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NToggle {
|
NToggle {
|
||||||
@@ -33,10 +33,10 @@ ColumnLayout {
|
|||||||
description: I18n.tr("bar.widget-settings.control-center.use-distro-logo.description")
|
description: I18n.tr("bar.widget-settings.control-center.use-distro-logo.description")
|
||||||
checked: valueUseDistroLogo
|
checked: valueUseDistroLogo
|
||||||
onToggled: function (checked) {
|
onToggled: function (checked) {
|
||||||
valueUseDistroLogo = checked
|
valueUseDistroLogo = checked;
|
||||||
if (checked) {
|
if (checked) {
|
||||||
valueCustomIconPath = ""
|
valueCustomIconPath = "";
|
||||||
valueIcon = ""
|
valueIcon = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ ColumnLayout {
|
|||||||
description: I18n.tr("bar.widget-settings.control-center.colorize-distro-logo.description")
|
description: I18n.tr("bar.widget-settings.control-center.colorize-distro-logo.description")
|
||||||
checked: valueColorizeDistroLogo
|
checked: valueColorizeDistroLogo
|
||||||
onToggled: function (checked) {
|
onToggled: function (checked) {
|
||||||
valueColorizeDistroLogo = checked
|
valueColorizeDistroLogo = checked;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,8 +94,8 @@ ColumnLayout {
|
|||||||
id: iconPicker
|
id: iconPicker
|
||||||
initialIcon: valueIcon
|
initialIcon: valueIcon
|
||||||
onIconSelected: iconName => {
|
onIconSelected: iconName => {
|
||||||
valueIcon = iconName
|
valueIcon = iconName;
|
||||||
valueCustomIconPath = ""
|
valueCustomIconPath = "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ ColumnLayout {
|
|||||||
initialPath: Quickshell.env("HOME")
|
initialPath: Quickshell.env("HOME")
|
||||||
onAccepted: paths => {
|
onAccepted: paths => {
|
||||||
if (paths.length > 0) {
|
if (paths.length > 0) {
|
||||||
valueCustomIconPath = paths[0] // Use first selected file
|
valueCustomIconPath = paths[0]; // Use first selected file
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,21 +19,21 @@ ColumnLayout {
|
|||||||
property bool valueHideTextInVerticalBar: widgetData.hideTextInVerticalBar !== undefined ? widgetData.hideTextInVerticalBar : widgetMetadata.hideTextInVerticalBar
|
property bool valueHideTextInVerticalBar: widgetData.hideTextInVerticalBar !== undefined ? widgetData.hideTextInVerticalBar : widgetMetadata.hideTextInVerticalBar
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.icon = valueIcon
|
settings.icon = valueIcon;
|
||||||
settings.leftClickExec = leftClickExecInput.text
|
settings.leftClickExec = leftClickExecInput.text;
|
||||||
settings.leftClickUpdateText = leftClickUpdateText.checked
|
settings.leftClickUpdateText = leftClickUpdateText.checked;
|
||||||
settings.rightClickExec = rightClickExecInput.text
|
settings.rightClickExec = rightClickExecInput.text;
|
||||||
settings.rightClickUpdateText = rightClickUpdateText.checked
|
settings.rightClickUpdateText = rightClickUpdateText.checked;
|
||||||
settings.middleClickExec = middleClickExecInput.text
|
settings.middleClickExec = middleClickExecInput.text;
|
||||||
settings.middleClickUpdateText = middleClickUpdateText.checked
|
settings.middleClickUpdateText = middleClickUpdateText.checked;
|
||||||
settings.textCommand = textCommandInput.text
|
settings.textCommand = textCommandInput.text;
|
||||||
settings.textCollapse = textCollapseInput.text
|
settings.textCollapse = textCollapseInput.text;
|
||||||
settings.textStream = valueTextStream
|
settings.textStream = valueTextStream;
|
||||||
settings.parseJson = valueParseJson
|
settings.parseJson = valueParseJson;
|
||||||
settings.hideTextInVerticalBar = valueHideTextInVerticalBar
|
settings.hideTextInVerticalBar = valueHideTextInVerticalBar;
|
||||||
settings.textIntervalMs = parseInt(textIntervalInput.text || textIntervalInput.placeholderText, 10)
|
settings.textIntervalMs = parseInt(textIntervalInput.text || textIntervalInput.placeholderText, 10);
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
@@ -61,7 +61,7 @@ ColumnLayout {
|
|||||||
id: iconPicker
|
id: iconPicker
|
||||||
initialIcon: valueIcon
|
initialIcon: valueIcon
|
||||||
onIconSelected: function (iconName) {
|
onIconSelected: function (iconName) {
|
||||||
valueIcon = iconName
|
valueIcon = iconName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,25 +16,29 @@ ColumnLayout {
|
|||||||
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
property string valueDisplayMode: widgetData.displayMode !== undefined ? widgetData.displayMode : widgetMetadata.displayMode
|
||||||
|
|
||||||
function saveSettings() {
|
function saveSettings() {
|
||||||
var settings = Object.assign({}, widgetData || {})
|
var settings = Object.assign({}, widgetData || {});
|
||||||
settings.displayMode = valueDisplayMode
|
settings.displayMode = valueDisplayMode;
|
||||||
return settings
|
return settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
NComboBox {
|
NComboBox {
|
||||||
label: I18n.tr("bar.widget-settings.keyboard-layout.display-mode.label")
|
label: I18n.tr("bar.widget-settings.keyboard-layout.display-mode.label")
|
||||||
description: I18n.tr("bar.widget-settings.keyboard-layout.display-mode.description")
|
description: I18n.tr("bar.widget-settings.keyboard-layout.display-mode.description")
|
||||||
minimumWidth: 134
|
minimumWidth: 134
|
||||||
model: [{
|
model: [
|
||||||
|
{
|
||||||
"key": "onhover",
|
"key": "onhover",
|
||||||
"name": I18n.tr("options.display-mode.on-hover")
|
"name": I18n.tr("options.display-mode.on-hover")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "forceOpen",
|
"key": "forceOpen",
|
||||||
"name": I18n.tr("options.display-mode.force-open")
|
"name": I18n.tr("options.display-mode.force-open")
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
"key": "alwaysHide",
|
"key": "alwaysHide",
|
||||||
"name": I18n.tr("options.display-mode.always-hide")
|
"name": I18n.tr("options.display-mode.always-hide")
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
currentKey: valueDisplayMode
|
currentKey: valueDisplayMode
|
||||||
onSelected: key => valueDisplayMode = key
|
onSelected: key => valueDisplayMode = key
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user