mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
46a3c7e2d4
This reverts commit 2fcd219c34.
276 lines
8.1 KiB
QML
276 lines
8.1 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Effects
|
|
import QtQuick.Layouts
|
|
import Quickshell
|
|
import qs.Commons
|
|
import qs.Services.Noctalia
|
|
import qs.Services.UI
|
|
import qs.Widgets
|
|
|
|
Popup {
|
|
id: root
|
|
|
|
property int widgetIndex: -1
|
|
property var widgetData: null
|
|
property string widgetId: ""
|
|
property string sectionId: "" // Not used for desktop widgets, but required by NSectionEditor
|
|
property var screen: null
|
|
property var settingsCache: ({})
|
|
|
|
readonly property real maxHeight: (screen ? screen.height : (parent ? parent.height : 800)) * 0.8
|
|
|
|
signal updateWidgetSettings(string section, int index, var settings)
|
|
|
|
width: Math.max(content.implicitWidth + padding * 2, 500)
|
|
height: Math.min(content.implicitHeight + padding * 2, maxHeight)
|
|
padding: Style.marginXL
|
|
modal: true
|
|
dim: false
|
|
|
|
// Center in parent
|
|
x: Math.round((parent.width - width) / 2)
|
|
y: Math.round((parent.height - height) / 2)
|
|
|
|
onOpened: {
|
|
if (widgetData && widgetId) {
|
|
loadWidgetSettings();
|
|
}
|
|
forceActiveFocus();
|
|
}
|
|
|
|
background: Rectangle {
|
|
id: bgRect
|
|
color: Color.mSurface
|
|
radius: Style.radiusL
|
|
border.color: Color.mPrimary
|
|
border.width: Style.borderM
|
|
}
|
|
|
|
contentItem: FocusScope {
|
|
id: focusScope
|
|
focus: true
|
|
|
|
ColumnLayout {
|
|
id: content
|
|
anchors.fill: parent
|
|
spacing: Style.marginM
|
|
|
|
RowLayout {
|
|
id: titleRow
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: implicitHeight
|
|
|
|
NText {
|
|
text: I18n.tr("system.widget-settings-title", {
|
|
"widget": DesktopWidgetRegistry.getWidgetDisplayName(root.widgetId)
|
|
})
|
|
pointSize: Style.fontSizeL
|
|
font.weight: Style.fontWeightBold
|
|
color: Color.mPrimary
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
NIconButton {
|
|
icon: "close"
|
|
tooltipText: I18n.tr("common.close")
|
|
onClicked: saveAndClose()
|
|
}
|
|
}
|
|
|
|
Rectangle {
|
|
id: separator
|
|
Layout.fillWidth: true
|
|
Layout.preferredHeight: 1
|
|
color: Color.mOutline
|
|
}
|
|
|
|
// Scrollable settings area
|
|
NScrollView {
|
|
id: scrollView
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
Layout.minimumHeight: 100
|
|
gradientColor: Color.mSurface
|
|
|
|
ColumnLayout {
|
|
width: scrollView.availableWidth
|
|
spacing: Style.marginM
|
|
|
|
Loader {
|
|
id: settingsLoader
|
|
Layout.fillWidth: true
|
|
onLoaded: {
|
|
if (item) {
|
|
Qt.callLater(() => {
|
|
var firstInput = findFirstFocusable(item);
|
|
if (firstInput) {
|
|
firstInput.forceActiveFocus();
|
|
} else {
|
|
focusScope.forceActiveFocus();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
function findFirstFocusable(item) {
|
|
if (!item)
|
|
return null;
|
|
if (item.focus !== undefined && item.focus === true)
|
|
return item;
|
|
if (item.children) {
|
|
for (var i = 0; i < item.children.length; i++) {
|
|
var child = item.children[i];
|
|
if (child && child.focus !== undefined && child.focus === true)
|
|
return child;
|
|
var found = findFirstFocusable(child);
|
|
if (found)
|
|
return found;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mouse area for a draggable popup
|
|
MouseArea {
|
|
x: titleRow.x
|
|
y: titleRow.y
|
|
width: titleRow.width
|
|
height: titleRow.height
|
|
z: -1
|
|
|
|
cursorShape: Qt.OpenHandCursor
|
|
|
|
property real pressX: 0
|
|
property real pressY: 0
|
|
|
|
onPressed: mouse => {
|
|
pressX = mouse.x;
|
|
pressY = mouse.y;
|
|
cursorShape = Qt.ClosedHandCursor;
|
|
}
|
|
|
|
onReleased: {
|
|
cursorShape = Qt.OpenHandCursor;
|
|
}
|
|
|
|
onPositionChanged: mouse => {
|
|
if (pressed) {
|
|
var deltaX = mouse.x - pressX;
|
|
var deltaY = mouse.y - pressY;
|
|
|
|
root.x += deltaX;
|
|
root.y += deltaY;
|
|
}
|
|
}
|
|
}
|
|
|
|
Timer {
|
|
id: saveTimer
|
|
running: false
|
|
interval: 150
|
|
onTriggered: {
|
|
root.updateWidgetSettings(root.sectionId, root.widgetIndex, root.settingsCache);
|
|
}
|
|
}
|
|
|
|
Connections {
|
|
target: settingsLoader.item
|
|
ignoreUnknownSignals: true
|
|
function onSettingsChanged(newSettings) {
|
|
if (newSettings) {
|
|
root.settingsCache = newSettings;
|
|
saveTimer.start();
|
|
}
|
|
}
|
|
|
|
function onSettingsSaved(newSettings) {
|
|
if (newSettings) {
|
|
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings);
|
|
}
|
|
}
|
|
}
|
|
|
|
function saveAndClose() {
|
|
if (settingsLoader.item && typeof settingsLoader.item.saveSettings === 'function') {
|
|
var newSettings = settingsLoader.item.saveSettings();
|
|
if (newSettings) {
|
|
root.updateWidgetSettings(root.sectionId, root.widgetIndex, newSettings);
|
|
}
|
|
}
|
|
root.close();
|
|
}
|
|
|
|
function loadWidgetSettings() {
|
|
// Handle plugin widgets
|
|
if (DesktopWidgetRegistry.isPluginWidget(widgetId)) {
|
|
var pluginId = widgetId.replace("plugin:", "");
|
|
var manifest = PluginRegistry.getPluginManifest(pluginId);
|
|
|
|
var pluginDir = PluginRegistry.getPluginDir(pluginId);
|
|
var loadVersion = PluginRegistry.pluginLoadVersions[pluginId] || 0;
|
|
var api = PluginService.getPluginAPI(pluginId);
|
|
|
|
var settingsPath;
|
|
if (manifest && manifest.entryPoints && manifest.entryPoints.desktopWidgetSettings) {
|
|
settingsPath = "file://" + pluginDir + "/" + manifest.entryPoints.desktopWidgetSettings;
|
|
|
|
var widgetSettings = {};
|
|
widgetSettings.data = widgetData || {};
|
|
widgetSettings.metadata = DesktopWidgetRegistry.widgetMetadata[widgetId] || {};
|
|
widgetSettings.save = function () {
|
|
var newSettings = Object.assign({}, widgetSettings.data);
|
|
root.settingsCache = newSettings;
|
|
saveTimer.start();
|
|
};
|
|
|
|
settingsLoader.setSource(settingsPath + "?v=" + loadVersion, {
|
|
"pluginApi": api,
|
|
"widgetSettings": widgetSettings
|
|
});
|
|
} else {
|
|
Logger.w("DesktopWidgetSettingsDialog", "Plugin does not have desktop widget settings:", pluginId);
|
|
|
|
// Fallback to the plugin settings
|
|
if (manifest && manifest.entryPoints && manifest.entryPoints.settings) {
|
|
settingsPath = "file://" + pluginDir + "/" + manifest.entryPoints.settings;
|
|
|
|
settingsLoader.setSource(settingsPath + "?v=" + loadVersion, {
|
|
"pluginApi": api
|
|
});
|
|
} else {
|
|
Logger.w("DesktopWidgetSettingsDialog", "Plugin does not have settings:", pluginId);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Handle core widgets
|
|
const source = DesktopWidgetRegistry.widgetSettingsMap[widgetId];
|
|
if (source) {
|
|
var currentWidgetData = widgetData;
|
|
var monitorWidgets = Settings.data.desktopWidgets.monitorWidgets || [];
|
|
for (var i = 0; i < monitorWidgets.length; i++) {
|
|
if (monitorWidgets[i].name === sectionId) {
|
|
var widgets = monitorWidgets[i].widgets || [];
|
|
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
|
currentWidgetData = widgets[widgetIndex];
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
var fullPath = Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/DesktopWidgets/" + source);
|
|
settingsLoader.setSource(fullPath, {
|
|
"widgetData": currentWidgetData,
|
|
"widgetMetadata": DesktopWidgetRegistry.widgetMetadata[widgetId]
|
|
});
|
|
}
|
|
}
|
|
}
|