add noctalia and fuzzel
This commit is contained in:
+332
@@ -0,0 +1,332 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import Quickshell
|
||||
import qs.Commons
|
||||
import qs.Services.Compositor
|
||||
import qs.Services.Noctalia
|
||||
import qs.Services.UI
|
||||
import qs.Widgets
|
||||
|
||||
ColumnLayout {
|
||||
id: root
|
||||
|
||||
spacing: Style.marginL
|
||||
|
||||
// Available widgets model - declared early so Repeater delegates can access it
|
||||
property alias availableWidgetsModel: availableWidgets
|
||||
ListModel {
|
||||
id: availableWidgets
|
||||
}
|
||||
|
||||
// Listen for plugin widget registration/unregistration
|
||||
Connections {
|
||||
target: DesktopWidgetRegistry
|
||||
function onPluginWidgetRegistryUpdated() {
|
||||
updateAvailableWidgetsModel();
|
||||
}
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
label: I18n.tr("panels.desktop-widgets.enabled-label")
|
||||
description: I18n.tr("panels.desktop-widgets.enabled-description")
|
||||
checked: Settings.data.desktopWidgets.enabled
|
||||
defaultValue: Settings.getDefaultValue("desktopWidgets.enabled")
|
||||
onToggled: checked => Settings.data.desktopWidgets.enabled = checked
|
||||
}
|
||||
|
||||
NToggle {
|
||||
Layout.fillWidth: true
|
||||
enabled: Settings.data.desktopWidgets.enabled
|
||||
label: I18n.tr("panels.desktop-widgets.overview-enabled-label")
|
||||
description: I18n.tr("panels.desktop-widgets.overview-enabled-description")
|
||||
checked: Settings.data.desktopWidgets.overviewEnabled
|
||||
defaultValue: Settings.getDefaultValue("desktopWidgets.overviewEnabled")
|
||||
onToggled: checked => Settings.data.desktopWidgets.overviewEnabled = checked
|
||||
}
|
||||
|
||||
ColumnLayout {
|
||||
enabled: Settings.data.desktopWidgets.enabled
|
||||
|
||||
NLabel {
|
||||
description: I18n.tr("panels.desktop-widgets.cpu-intensive-note")
|
||||
}
|
||||
|
||||
NButton {
|
||||
Layout.fillWidth: true
|
||||
Layout.topMargin: Style.marginM
|
||||
Layout.bottomMargin: Style.marginM
|
||||
text: DesktopWidgetRegistry.editMode ? I18n.tr("panels.desktop-widgets.edit-mode-exit-button") : I18n.tr("panels.desktop-widgets.edit-mode-button-label")
|
||||
icon: "edit"
|
||||
onClicked: {
|
||||
DesktopWidgetRegistry.editMode = !DesktopWidgetRegistry.editMode;
|
||||
if (DesktopWidgetRegistry.editMode && Settings.data.ui.settingsPanelMode !== "window") {
|
||||
var item = root.parent;
|
||||
while (item) {
|
||||
if (item.closeRequested !== undefined) {
|
||||
item.closeRequested();
|
||||
break;
|
||||
}
|
||||
item = item.parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// One NSectionEditor per monitor
|
||||
Repeater {
|
||||
model: Quickshell.screens
|
||||
|
||||
NSectionEditor {
|
||||
required property var modelData
|
||||
readonly property real compositorScale: {
|
||||
const info = CompositorService.displayScales[modelData.name];
|
||||
return (info && info.scale) ? info.scale : 1.0;
|
||||
}
|
||||
|
||||
Layout.fillWidth: true
|
||||
sectionName: modelData.name
|
||||
sectionSubtitle: {
|
||||
// Format scale to 2 decimal places to prevent overly long text
|
||||
var formattedScale = compositorScale.toFixed(2);
|
||||
return "(" + modelData.width + "x" + modelData.height + " @ " + formattedScale + "x)";
|
||||
}
|
||||
|
||||
sectionId: modelData.name
|
||||
screen: modelData
|
||||
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/DesktopWidgets/DesktopWidgetSettingsDialog.qml")
|
||||
widgetRegistry: DesktopWidgetRegistry
|
||||
widgetModel: getWidgetsForMonitor(modelData.name)
|
||||
availableWidgets: root.availableWidgetsModel
|
||||
availableSections: root.getScreenNames()
|
||||
sectionLabels: root.getScreenLabels()
|
||||
sectionIcons: root.getScreenIcons()
|
||||
draggable: false // Desktop widgets are positioned by X,Y, not list order
|
||||
crossSectionDraggable: true
|
||||
maxWidgets: -1
|
||||
onAddWidget: (widgetId, section) => _addWidgetToMonitor(modelData.name, widgetId)
|
||||
onRemoveWidget: (section, index) => _removeWidgetFromMonitor(modelData.name, index)
|
||||
onMoveWidget: (fromSection, index, toSection) => _moveWidgetToMonitor(fromSection, index, toSection)
|
||||
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsForMonitor(modelData.name, index, settings)
|
||||
pluginSettingsEntryPoints: ["desktopWidgetSettings", "settings"]
|
||||
onOpenPluginSettingsRequested: (manifest, entryPoint) => pluginSettingsDialog.openPluginSettings(manifest, entryPoint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Shared Plugin Settings Popup
|
||||
NPluginSettingsPopup {
|
||||
id: pluginSettingsDialog
|
||||
parent: Overlay.overlay
|
||||
showToastOnSave: false
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
// Use Qt.callLater to ensure DesktopWidgetRegistry is ready
|
||||
Qt.callLater(updateAvailableWidgetsModel);
|
||||
}
|
||||
|
||||
// Helper to get screen names array
|
||||
function getScreenNames() {
|
||||
var names = [];
|
||||
for (var i = 0; i < Quickshell.screens.length; i++) {
|
||||
names.push(Quickshell.screens[i].name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
// Helper to get screen labels map (just screen names, NSectionEditor adds "Move to" prefix)
|
||||
function getScreenLabels() {
|
||||
var labels = {};
|
||||
for (var i = 0; i < Quickshell.screens.length; i++) {
|
||||
var screen = Quickshell.screens[i];
|
||||
labels[screen.name] = screen.name;
|
||||
}
|
||||
return labels;
|
||||
}
|
||||
|
||||
// Helper to get screen icons map
|
||||
function getScreenIcons() {
|
||||
var icons = {};
|
||||
for (var i = 0; i < Quickshell.screens.length; i++) {
|
||||
icons[Quickshell.screens[i].name] = "device-desktop";
|
||||
}
|
||||
return icons;
|
||||
}
|
||||
|
||||
function updateAvailableWidgetsModel() {
|
||||
availableWidgets.clear();
|
||||
try {
|
||||
if (typeof DesktopWidgetRegistry === "undefined" || !DesktopWidgetRegistry) {
|
||||
Logger.e("DesktopWidgetsTab", "DesktopWidgetRegistry is not available");
|
||||
// Retry after a short delay
|
||||
Qt.callLater(function () {
|
||||
if (typeof DesktopWidgetRegistry !== "undefined" && DesktopWidgetRegistry) {
|
||||
updateAvailableWidgetsModel();
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
var widgetIds = DesktopWidgetRegistry.getAvailableWidgets();
|
||||
Logger.d("DesktopWidgetsTab", "Found widgets:", widgetIds, "count:", widgetIds ? widgetIds.length : 0);
|
||||
if (!widgetIds || widgetIds.length === 0) {
|
||||
Logger.w("DesktopWidgetsTab", "No widgets found in registry");
|
||||
return;
|
||||
}
|
||||
for (var i = 0; i < widgetIds.length; i++) {
|
||||
var widgetId = widgetIds[i];
|
||||
var displayName = widgetId;
|
||||
|
||||
// Get plugin name for plugin widgets
|
||||
var isPlugin = false;
|
||||
if (DesktopWidgetRegistry.isPluginWidget(widgetId)) {
|
||||
isPlugin = true;
|
||||
var pluginId = widgetId.replace("plugin:", "");
|
||||
var manifest = PluginRegistry.getPluginManifest(pluginId);
|
||||
if (manifest && manifest.name) {
|
||||
displayName = manifest.name;
|
||||
}
|
||||
}
|
||||
|
||||
// Add plugin badge first (with custom color)
|
||||
const badges = [];
|
||||
if (isPlugin) {
|
||||
badges.push({
|
||||
"icon": "plugin",
|
||||
"color": Color.mSecondary
|
||||
});
|
||||
}
|
||||
if (DesktopWidgetRegistry.isCpuIntensive(widgetId)) {
|
||||
badges.push({
|
||||
"icon": "cpu-intensive",
|
||||
"color": Color.mSecondary
|
||||
});
|
||||
}
|
||||
|
||||
availableWidgets.append({
|
||||
"key": widgetId,
|
||||
"name": displayName,
|
||||
"badges": badges
|
||||
});
|
||||
}
|
||||
Logger.d("DesktopWidgetsTab", "Available widgets model count:", availableWidgets.count);
|
||||
} catch (e) {
|
||||
Logger.e("DesktopWidgetsTab", "Error updating available widgets:", e, e.stack);
|
||||
}
|
||||
}
|
||||
|
||||
// Get widgets for a specific monitor
|
||||
function getWidgetsForMonitor(monitorName) {
|
||||
var monitorWidgets = Settings.data.desktopWidgets.monitorWidgets || [];
|
||||
for (var i = 0; i < monitorWidgets.length; i++) {
|
||||
if (monitorWidgets[i].name === monitorName) {
|
||||
return monitorWidgets[i].widgets || [];
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
// Set widgets for a specific monitor
|
||||
function setWidgetsForMonitor(monitorName, widgets) {
|
||||
var monitorWidgets = Settings.data.desktopWidgets.monitorWidgets || [];
|
||||
var newMonitorWidgets = monitorWidgets.slice();
|
||||
var found = false;
|
||||
for (var i = 0; i < newMonitorWidgets.length; i++) {
|
||||
if (newMonitorWidgets[i].name === monitorName) {
|
||||
newMonitorWidgets[i] = {
|
||||
"name": monitorName,
|
||||
"widgets": widgets
|
||||
};
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
newMonitorWidgets.push({
|
||||
"name": monitorName,
|
||||
"widgets": widgets
|
||||
});
|
||||
}
|
||||
Settings.data.desktopWidgets.monitorWidgets = newMonitorWidgets;
|
||||
}
|
||||
|
||||
function _addWidgetToMonitor(monitorName, widgetId) {
|
||||
var newWidget = {
|
||||
"id": widgetId
|
||||
};
|
||||
if (DesktopWidgetRegistry.widgetHasUserSettings(widgetId)) {
|
||||
var metadata = DesktopWidgetRegistry.widgetMetadata[widgetId];
|
||||
if (metadata) {
|
||||
Object.keys(metadata).forEach(function (key) {
|
||||
newWidget[key] = metadata[key];
|
||||
});
|
||||
}
|
||||
}
|
||||
// Set default positions
|
||||
if (widgetId === "Clock") {
|
||||
newWidget.x = 50;
|
||||
newWidget.y = 50;
|
||||
} else if (widgetId === "MediaPlayer") {
|
||||
newWidget.x = 100;
|
||||
newWidget.y = 200;
|
||||
} else if (widgetId === "AudioVisualizer") {
|
||||
newWidget.x = 120;
|
||||
newWidget.y = 280;
|
||||
} else if (widgetId === "Weather") {
|
||||
newWidget.x = 100;
|
||||
newWidget.y = 300;
|
||||
} else {
|
||||
// Default position for plugin widgets
|
||||
newWidget.x = 150;
|
||||
newWidget.y = 150;
|
||||
}
|
||||
var widgets = getWidgetsForMonitor(monitorName).slice();
|
||||
widgets.push(newWidget);
|
||||
setWidgetsForMonitor(monitorName, widgets);
|
||||
}
|
||||
|
||||
function _removeWidgetFromMonitor(monitorName, index) {
|
||||
var widgets = getWidgetsForMonitor(monitorName);
|
||||
if (index >= 0 && index < widgets.length) {
|
||||
var newArray = widgets.slice();
|
||||
newArray.splice(index, 1);
|
||||
setWidgetsForMonitor(monitorName, newArray);
|
||||
}
|
||||
}
|
||||
|
||||
function _updateWidgetSettingsForMonitor(monitorName, index, settings) {
|
||||
var widgets = getWidgetsForMonitor(monitorName);
|
||||
if (index >= 0 && index < widgets.length) {
|
||||
var newArray = widgets.slice();
|
||||
newArray[index] = Object.assign({}, newArray[index], settings);
|
||||
setWidgetsForMonitor(monitorName, newArray);
|
||||
}
|
||||
}
|
||||
|
||||
function _moveWidgetToMonitor(fromMonitor, index, toMonitor) {
|
||||
Logger.i("DesktopWidgetsTab", "Moving widget from", fromMonitor, "index", index, "to", toMonitor);
|
||||
var sourceWidgets = getWidgetsForMonitor(fromMonitor);
|
||||
if (index < 0 || index >= sourceWidgets.length) {
|
||||
Logger.e("DesktopWidgetsTab", "Invalid index", index, "for monitor", fromMonitor);
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the widget to move
|
||||
var newSourceWidgets = sourceWidgets.slice();
|
||||
var widget = Object.assign({}, newSourceWidgets.splice(index, 1)[0]);
|
||||
|
||||
// Reset position and scale to ensure widget is accessible on new screen
|
||||
widget.x = 100;
|
||||
widget.y = 100;
|
||||
widget.scale = 1.0;
|
||||
|
||||
// Add to destination monitor
|
||||
var destWidgets = getWidgetsForMonitor(toMonitor).slice();
|
||||
destWidgets.push(widget);
|
||||
|
||||
// Update both monitors
|
||||
setWidgetsForMonitor(fromMonitor, newSourceWidgets);
|
||||
setWidgetsForMonitor(toMonitor, destWidgets);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user