Files
noctalia-shell/Modules/Panels/Settings/Bar/MonitorWidgetsConfig.qml
T
2026-02-20 21:11:06 -05:00

231 lines
8.9 KiB
QML

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import Quickshell
import "../../../../Helpers/QtObj2JS.js" as QtObj2JS
import qs.Commons
import qs.Services.Noctalia
import qs.Services.UI
import qs.Widgets
// Monitor Widgets Configuration (inline)
NBox {
id: root
required property var screen
readonly property string screenName: screen?.name || ""
// determine bar orientation
readonly property string barPosition: Settings.getBarPositionForScreen(screenName)
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
color: Color.mSurfaceVariant
Layout.fillWidth: true
implicitHeight: content.implicitHeight + Style.margin2L
// Helper to get widgets for this screen (ensures override exists)
function _getWidgetsContainer() {
if (!Settings.hasScreenOverride(screenName, "widgets")) {
var currentWidgets = Settings.getBarWidgetsForScreen(screenName);
var widgetsCopy = QtObj2JS.qtObjectToPlainObject(currentWidgets);
Settings.setScreenOverride(screenName, "widgets", widgetsCopy);
}
var entry = Settings.getScreenOverrideEntry(screenName);
return entry ? entry.widgets : Settings.data.bar.widgets;
}
// Persist widget changes by reassigning the override (triggers change detection)
function _saveWidgets(widgets) {
Settings.setScreenOverride(screenName, "widgets", widgets);
}
// Widget manipulation functions
function _addWidgetToSection(widgetId, section) {
var newWidget = {
"id": widgetId
};
if (BarWidgetRegistry.widgetHasUserSettings(widgetId)) {
var metadata = BarWidgetRegistry.widgetMetadata[widgetId];
if (metadata) {
Object.keys(metadata).forEach(function (key) {
newWidget[key] = metadata[key];
});
}
}
var widgets = _getWidgetsContainer();
widgets[section].push(newWidget);
_saveWidgets(widgets);
BarService.widgetsRevision++;
}
function _removeWidgetFromSection(section, index) {
var widgets = _getWidgetsContainer();
if (index >= 0 && index < widgets[section].length) {
var newArray = widgets[section].slice();
var removedWidgets = newArray.splice(index, 1);
widgets[section] = newArray;
_saveWidgets(widgets);
BarService.widgetsRevision++;
if (removedWidgets[0].id === "ControlCenter" && BarService.lookupWidget("ControlCenter") === undefined) {
ToastService.showWarning(I18n.tr("toast.missing-control-center.label"), I18n.tr("toast.missing-control-center.description"), 12000);
}
}
}
function _reorderWidgetInSection(section, fromIndex, toIndex) {
var widgets = _getWidgetsContainer();
if (fromIndex >= 0 && fromIndex < widgets[section].length && toIndex >= 0 && toIndex < widgets[section].length) {
var newArray = widgets[section].slice();
var item = newArray[fromIndex];
newArray.splice(fromIndex, 1);
newArray.splice(toIndex, 0, item);
widgets[section] = newArray;
_saveWidgets(widgets);
BarService.widgetsRevision++;
}
}
// Note: _updateWidgetSettingsInSection does NOT increment revision
// because it only changes settings, not widget structure
function _updateWidgetSettingsInSection(section, index, settings) {
var widgets = _getWidgetsContainer();
widgets[section][index] = settings;
_saveWidgets(widgets);
}
function _moveWidgetBetweenSections(fromSection, index, toSection) {
var widgets = _getWidgetsContainer();
if (index >= 0 && index < widgets[fromSection].length) {
var widget = widgets[fromSection][index];
var sourceArray = widgets[fromSection].slice();
sourceArray.splice(index, 1);
widgets[fromSection] = sourceArray;
var targetArray = widgets[toSection].slice();
targetArray.push(widget);
widgets[toSection] = targetArray;
_saveWidgets(widgets);
BarService.widgetsRevision++;
}
}
// Available widgets ListModel
function updateAvailableWidgetsModel() {
availableWidgetsModel.clear();
var widgetIds = BarWidgetRegistry.getAvailableWidgets();
if (!widgetIds)
return;
for (var i = 0; i < widgetIds.length; i++) {
var id = widgetIds[i];
var displayName = id;
const badges = [];
if (BarWidgetRegistry.isPluginWidget(id)) {
var pluginId = id.replace("plugin:", "");
var manifest = PluginRegistry.getPluginManifest(pluginId);
if (manifest && manifest.name) {
displayName = manifest.name;
} else {
displayName = pluginId;
}
badges.push({
"icon": "plugin",
"color": Color.mSecondary
});
}
if (BarWidgetRegistry.isCpuIntensive(id)) {
badges.push({
"icon": "cpu-intensive",
"color": Color.mSecondary
});
}
availableWidgetsModel.append({
"key": id,
"name": displayName,
"badges": badges
});
}
}
Component.onCompleted: updateAvailableWidgetsModel()
ListModel {
id: availableWidgetsModel
}
// Get effective widgets for this screen
readonly property var effectiveWidgets: Settings.getBarWidgetsForScreen(screenName)
ColumnLayout {
id: content
anchors.fill: parent
anchors.margins: Style.marginL
spacing: Style.marginM
NText {
text: I18n.tr("panels.bar.widgets-desc")
wrapMode: Text.WordWrap
Layout.fillWidth: true
}
// Left Section
NSectionEditor {
sectionName: root.barIsVertical ? I18n.tr("positions.top") : I18n.tr("positions.left")
sectionId: "left"
barIsVertical: root.barIsVertical
screen: root.screen
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml")
widgetRegistry: BarWidgetRegistry
widgetModel: root.effectiveWidgets.left
availableWidgets: availableWidgetsModel
onAddWidget: (widgetId, section) => root._addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => root._removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => root._reorderWidgetInSection(section, fromIndex, toIndex)
onUpdateWidgetSettings: (section, index, settings) => root._updateWidgetSettingsInSection(section, index, settings)
onMoveWidget: (fromSection, index, toSection) => root._moveWidgetBetweenSections(fromSection, index, toSection)
onOpenPluginSettingsRequested: manifest => pluginSettingsDialog.openPluginSettings(manifest)
}
// Center Section
NSectionEditor {
sectionName: I18n.tr("positions.center")
sectionId: "center"
barIsVertical: root.barIsVertical
screen: root.screen
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml")
widgetRegistry: BarWidgetRegistry
widgetModel: root.effectiveWidgets.center
availableWidgets: availableWidgetsModel
onAddWidget: (widgetId, section) => root._addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => root._removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => root._reorderWidgetInSection(section, fromIndex, toIndex)
onUpdateWidgetSettings: (section, index, settings) => root._updateWidgetSettingsInSection(section, index, settings)
onMoveWidget: (fromSection, index, toSection) => root._moveWidgetBetweenSections(fromSection, index, toSection)
onOpenPluginSettingsRequested: manifest => pluginSettingsDialog.openPluginSettings(manifest)
}
// Right Section
NSectionEditor {
sectionName: root.barIsVertical ? I18n.tr("positions.bottom") : I18n.tr("positions.right")
sectionId: "right"
barIsVertical: root.barIsVertical
screen: root.screen
settingsDialogComponent: Qt.resolvedUrl(Quickshell.shellDir + "/Modules/Panels/Settings/Bar/BarWidgetSettingsDialog.qml")
widgetRegistry: BarWidgetRegistry
widgetModel: root.effectiveWidgets.right
availableWidgets: availableWidgetsModel
onAddWidget: (widgetId, section) => root._addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => root._removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => root._reorderWidgetInSection(section, fromIndex, toIndex)
onUpdateWidgetSettings: (section, index, settings) => root._updateWidgetSettingsInSection(section, index, settings)
onMoveWidget: (fromSection, index, toSection) => root._moveWidgetBetweenSections(fromSection, index, toSection)
onOpenPluginSettingsRequested: manifest => pluginSettingsDialog.openPluginSettings(manifest)
}
}
// Plugin settings dialog
NPluginSettingsPopup {
id: pluginSettingsDialog
parent: Overlay.overlay
showToastOnSave: false
}
}