diff options
Diffstat (limited to 'raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml')
| -rw-r--r-- | raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml | 1091 |
1 files changed, 1091 insertions, 0 deletions
diff --git a/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml new file mode 100644 index 0000000..4cdd979 --- /dev/null +++ b/raveos-theme/hyprland/theme-data/DankMaterialShell/quickshell/Modules/ControlCenter/Components/DragDropGrid.qml @@ -0,0 +1,1091 @@ +import QtQuick +import qs.Common +import qs.Services +import qs.Modules.ControlCenter.Widgets +import qs.Modules.ControlCenter.Components +import "../utils/layout.js" as LayoutUtils + +Column { + id: root + + property bool editMode: false + property string expandedSection: "" + property int expandedWidgetIndex: -1 + property var model: null + property var expandedWidgetData: null + property var bluetoothCodecSelector: null + property bool darkModeTransitionPending: false + property string screenName: "" + property string screenModel: "" + property var parentScreen: null + + signal expandClicked(var widgetData, int globalIndex) + signal removeWidget(int index) + signal moveWidget(int fromIndex, int toIndex) + signal toggleWidgetSize(int index) + signal collapseRequested + + function requestCollapse() { + collapseRequested(); + } + + spacing: editMode ? Theme.spacingL : Theme.spacingS + + property real maxPopoutHeight: 9999 + property var currentRowWidgets: [] + property real currentRowWidth: 0 + property int expandedRowIndex: -1 + property var colorPickerModal: null + + readonly property real _maxDetailHeight: { + const rows = layoutResult.rows; + let totalRowHeight = 0; + for (let i = 0; i < rows.length; i++) { + const sliderOnly = rows[i].every(w => { + const id = w.id || ""; + return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"; + }); + totalRowHeight += sliderOnly ? 36 : 60; + } + const rowSpacing = Math.max(0, rows.length - 1) * spacing; + return Math.max(100, maxPopoutHeight - totalRowHeight - rowSpacing); + } + + function calculateRowsAndWidgets() { + return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex); + } + + property var layoutResult: { + const dummy = [expandedSection, expandedWidgetIndex, model?.controlCenterWidgets]; + return calculateRowsAndWidgets(); + } + + onLayoutResultChanged: { + expandedRowIndex = layoutResult.expandedRowIndex; + } + + function moveToTop(item) { + const children = root.children; + for (var i = 0; i < children.length; i++) { + if (children[i] === item) + continue; + if (children[i].z) + children[i].z = Math.min(children[i].z, 999); + } + item.z = 1000; + } + + Repeater { + model: root.layoutResult.rows + + Column { + width: root.width + spacing: 0 + property int rowIndex: index + property var rowWidgets: modelData + property bool isSliderOnlyRow: { + const widgets = rowWidgets || []; + if (widgets.length === 0) + return false; + return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider"); + } + topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0 + bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0 + + Flow { + width: parent.width + spacing: Theme.spacingS + + Repeater { + model: rowWidgets || [] + + DragDropWidgetWrapper { + widgetData: modelData + property int globalWidgetIndex: { + const widgets = SettingsData.controlCenterWidgets || []; + for (var i = 0; i < widgets.length; i++) { + if (widgets[i].id === modelData.id) { + if (modelData.id === "diskUsage" || modelData.id === "brightnessSlider") { + if (widgets[i].instanceId === modelData.instanceId) { + return i; + } + } else { + return i; + } + } + } + return -1; + } + property int widgetWidth: modelData.width || 50 + width: { + const baseWidth = root.width; + const spacing = Theme.spacingS; + if (widgetWidth <= 25) { + return (baseWidth - spacing * 3) / 4; + } else if (widgetWidth <= 50) { + return (baseWidth - spacing) / 2; + } else if (widgetWidth <= 75) { + return (baseWidth - spacing * 2) * 0.75; + } else { + return baseWidth; + } + } + height: isSliderOnlyRow ? 48 : 60 + + editMode: root.editMode + widgetIndex: globalWidgetIndex + gridCellWidth: width + gridCellHeight: height + gridColumns: 4 + gridLayout: root + isSlider: { + const id = modelData.id || ""; + return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"; + } + + widgetComponent: { + const id = modelData.id || ""; + if (id.startsWith("builtin_")) { + return builtinPluginWidgetComponent; + } else if (id.startsWith("plugin_")) { + return pluginWidgetComponent; + } else if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") { + return compoundPillComponent; + } else if (id === "volumeSlider") { + return audioSliderComponent; + } else if (id === "brightnessSlider") { + return brightnessSliderComponent; + } else if (id === "inputVolumeSlider") { + return inputAudioSliderComponent; + } else if (id === "battery") { + return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent; + } else if (id === "diskUsage") { + return widgetWidth <= 25 ? smallDiskUsageComponent : diskUsagePillComponent; + } else if (id === "colorPicker") { + return colorPickerPillComponent; + } else { + return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent; + } + } + + onWidgetMoved: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex) + onRemoveWidget: index => root.removeWidget(index) + onToggleWidgetSize: index => root.toggleWidgetSize(index) + } + } + } + + DetailHost { + id: detailHost + width: parent.width + maxAvailableHeight: root._maxDetailHeight + height: active ? (getDetailHeight(root.expandedSection) + Theme.spacingS) : 0 + property bool active: { + if (root.expandedSection === "") + return false; + + if (root.expandedSection.startsWith("diskUsage_") && root.expandedWidgetData) { + const expandedInstanceId = root.expandedWidgetData.instanceId; + return rowWidgets.some(w => w.id === "diskUsage" && w.instanceId === expandedInstanceId); + } + + if (root.expandedSection.startsWith("brightnessSlider_") && root.expandedWidgetData) { + const expandedInstanceId = root.expandedWidgetData.instanceId; + return rowWidgets.some(w => w.id === "brightnessSlider" && w.instanceId === expandedInstanceId); + } + + return rowIndex === root.expandedRowIndex; + } + visible: active + expandedSection: root.expandedSection + expandedWidgetData: root.expandedWidgetData + bluetoothCodecSelector: root.bluetoothCodecSelector + widgetModel: root.model + collapseCallback: root.requestCollapse + screenName: root.screenName + screenModel: root.screenModel + } + } + } + + Component { + id: errorPillComponent + ErrorPill { + property var widgetData: parent.widgetData || {} + width: parent.width + height: 60 + primaryMessage: { + if (!DMSService.dmsAvailable) { + return I18n.tr("DMS_SOCKET not available"); + } + return I18n.tr("NM not supported"); + } + secondaryMessage: I18n.tr("update dms for NM integration.") + } + } + + Component { + id: compoundPillComponent + CompoundPill { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") + width: parent.width + height: 60 + iconName: { + switch (widgetData.id || "") { + case "wifi": + { + if (NetworkService.wifiToggling) + return "sync"; + + const status = NetworkService.networkStatus; + if (status === "ethernet") + return "settings_ethernet"; + if (status === "vpn") + return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon; + if (status === "wifi") + return NetworkService.wifiSignalIcon; + if (NetworkService.wifiEnabled) + return "wifi_off"; + return "wifi_off"; + } + case "bluetooth": + { + if (!BluetoothService.available) + return "bluetooth_disabled"; + if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) + return "bluetooth_disabled"; + return "bluetooth"; + } + case "audioOutput": + { + if (!AudioService.sink) + return "volume_off"; + let volume = AudioService.sink.audio.volume; + let muted = AudioService.sink.audio.muted; + if (muted) + return "volume_off"; + if (volume === 0.0) + return "volume_mute"; + if (volume <= 0.33) + return "volume_down"; + if (volume <= 0.66) + return "volume_up"; + return "volume_up"; + } + case "audioInput": + { + if (!AudioService.source) + return "mic_off"; + let muted = AudioService.source.audio.muted; + return muted ? "mic_off" : "mic"; + } + default: + return widgetDef?.icon || "help"; + } + } + primaryText: { + switch (widgetData.id || "") { + case "wifi": + { + if (NetworkService.wifiToggling) + return NetworkService.wifiEnabled ? I18n.tr("Disabling WiFi...", "network status") : I18n.tr("Enabling WiFi...", "network status"); + + const status = NetworkService.networkStatus; + if (status === "ethernet") + return I18n.tr("Ethernet", "network status"); + if (status === "vpn") { + if (NetworkService.ethernetConnected) + return I18n.tr("Ethernet", "network status"); + if (NetworkService.wifiConnected && NetworkService.currentWifiSSID) + return NetworkService.currentWifiSSID; + } + if (status === "wifi" && NetworkService.currentWifiSSID) + return NetworkService.currentWifiSSID; + if (NetworkService.wifiEnabled) + return I18n.tr("Not connected", "network status"); + return I18n.tr("WiFi off", "network status"); + } + case "bluetooth": + { + if (!BluetoothService.available) + return I18n.tr("Bluetooth", "bluetooth status"); + if (!BluetoothService.adapter) + return I18n.tr("No adapter", "bluetooth status"); + if (!BluetoothService.adapter.enabled) + return I18n.tr("Disabled", "bluetooth status"); + return I18n.tr("Enabled", "bluetooth status"); + } + case "audioOutput": + return AudioService.sink?.description || I18n.tr("No output device", "audio status"); + case "audioInput": + return AudioService.source?.description || I18n.tr("No input device", "audio status"); + default: + return widgetDef?.text || I18n.tr("Unknown", "widget status"); + } + } + secondaryText: { + switch (widgetData.id || "") { + case "wifi": + { + if (NetworkService.wifiToggling) + return I18n.tr("Please wait...", "network status"); + + const status = NetworkService.networkStatus; + if (status === "ethernet") + return I18n.tr("Connected", "network status"); + if (status === "vpn") { + if (NetworkService.ethernetConnected) + return I18n.tr("Connected", "network status"); + if (NetworkService.wifiConnected) + return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : I18n.tr("Connected", "network status"); + } + if (status === "wifi") + return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : I18n.tr("Connected", "network status"); + if (NetworkService.wifiEnabled) + return I18n.tr("Select network", "network status"); + return ""; + } + case "bluetooth": + { + if (!BluetoothService.available) + return I18n.tr("No adapters", "bluetooth status"); + if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) + return I18n.tr("Off", "bluetooth status"); + const primaryDevice = (() => { + if (!BluetoothService.adapter || !BluetoothService.adapter.devices) + return null; + let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]; + for (let device of devices) { + if (device && device.connected) + return device; + } + return null; + })(); + if (primaryDevice) + return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || I18n.tr("Connected Device", "bluetooth status"); + return I18n.tr("No devices", "bluetooth status"); + } + case "audioOutput": + { + if (!AudioService.sink) + return I18n.tr("Select device", "audio status"); + if (AudioService.sink.audio.muted) + return I18n.tr("Muted", "audio status"); + const volume = AudioService.sink.audio.volume; + if (typeof volume !== "number" || isNaN(volume)) + return "0%"; + return Math.round(volume * 100) + "%"; + } + case "audioInput": + { + if (!AudioService.source) + return I18n.tr("Select device", "audio status"); + if (AudioService.source.audio.muted) + return I18n.tr("Muted", "audio status"); + const volume = AudioService.source.audio.volume; + if (typeof volume !== "number" || isNaN(volume)) + return "0%"; + return Math.round(volume * 100) + "%"; + } + default: + return widgetDef?.description || ""; + } + } + isActive: { + switch (widgetData.id || "") { + case "wifi": + { + if (NetworkService.wifiToggling) + return false; + + const status = NetworkService.networkStatus; + if (status === "ethernet") + return true; + if (status === "vpn") + return NetworkService.ethernetConnected || NetworkService.wifiConnected; + if (status === "wifi") + return true; + return NetworkService.wifiEnabled; + } + case "bluetooth": + return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled); + case "audioOutput": + return !!(AudioService.sink && !AudioService.sink.audio.muted); + case "audioInput": + return !!(AudioService.source && !AudioService.source.audio.muted); + default: + return false; + } + } + enabled: widgetDef?.enabled ?? true + onToggled: { + if (root.editMode) + return; + switch (widgetData.id || "") { + case "wifi": + { + if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) { + NetworkService.toggleWifiRadio(); + } + break; + } + case "bluetooth": + { + if (BluetoothService.available && BluetoothService.adapter) { + BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled; + } + break; + } + case "audioOutput": + { + if (AudioService.sink && AudioService.sink.audio) { + AudioService.sink.audio.muted = !AudioService.sink.audio.muted; + } + break; + } + case "audioInput": + { + if (AudioService.source && AudioService.source.audio) { + AudioService.source.audio.muted = !AudioService.source.audio.muted; + } + break; + } + } + } + onExpandClicked: { + if (root.editMode) + return; + root.expandClicked(widgetData, widgetIndex); + } + onWheelEvent: function (wheelEvent) { + if (root.editMode) + return; + const id = widgetData.id || ""; + if (id === "audioOutput") { + if (!AudioService.sink || !AudioService.sink.audio) + return; + let delta = wheelEvent.angleDelta.y; + let maxVol = AudioService.sinkMaxVolume; + let currentVolume = AudioService.sink.audio.volume * 100; + let newVolume; + if (delta > 0) + newVolume = Math.min(maxVol, currentVolume + 5); + else + newVolume = Math.max(0, currentVolume - 5); + AudioService.sink.audio.muted = false; + AudioService.sink.audio.volume = newVolume / 100; + wheelEvent.accepted = true; + } else if (id === "audioInput") { + if (!AudioService.source || !AudioService.source.audio) + return; + let delta = wheelEvent.angleDelta.y; + let currentVolume = AudioService.source.audio.volume * 100; + let newVolume; + if (delta > 0) + newVolume = Math.min(100, currentVolume + 5); + else + newVolume = Math.max(0, currentVolume - 5); + AudioService.source.audio.muted = false; + AudioService.source.audio.volume = newVolume / 100; + wheelEvent.accepted = true; + } + } + } + } + + Component { + id: audioSliderComponent + Item { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 16 + + AudioSliderRow { + anchors.centerIn: parent + width: parent.width + height: 14 + property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + } + } + } + + Component { + id: brightnessSliderComponent + Item { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 16 + + BrightnessSliderRow { + id: brightnessSliderRow + anchors.centerIn: parent + width: parent.width + height: 14 + deviceName: widgetData.deviceName || "" + instanceId: widgetData.instanceId || "" + screenName: root.screenName + parentScreen: root.parentScreen + property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + + onIconClicked: { + if (!root.editMode && DisplayService.devices && DisplayService.devices.length > 1) { + root.expandClicked(widgetData, widgetIndex); + } + } + } + } + } + + Component { + id: inputAudioSliderComponent + Item { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 16 + + InputAudioSliderRow { + anchors.centerIn: parent + width: parent.width + height: 14 + property color sliderTrackColor: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency) + } + } + } + + Component { + id: batteryPillComponent + BatteryPill { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 60 + + onExpandClicked: { + if (!root.editMode) { + root.expandClicked(widgetData, widgetIndex); + } + } + } + } + + Component { + id: smallBatteryComponent + SmallBatteryButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 48 + + onClicked: { + if (!root.editMode) { + root.expandClicked(widgetData, widgetIndex); + } + } + } + } + + Component { + id: toggleButtonComponent + ToggleButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 60 + + iconName: { + switch (widgetData.id || "") { + case "nightMode": + return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"; + case "darkMode": + return "contrast"; + case "doNotDisturb": + return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"; + case "idleInhibitor": + return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"; + default: + return "help"; + } + } + + text: { + switch (widgetData.id || "") { + case "nightMode": + return I18n.tr("Night Mode"); + case "darkMode": + return I18n.tr("Dark Mode"); + case "doNotDisturb": + return I18n.tr("Do Not Disturb"); + case "idleInhibitor": + return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake"); + default: + return I18n.tr("Unknown", "widget status"); + } + } + + iconRotation: { + if (widgetData.id !== "darkMode") + return 0; + if (darkModeTransitionPending) { + return SessionData.isLightMode ? 180 : 0; + } + return SessionData.isLightMode ? 180 : 0; + } + + isActive: { + switch (widgetData.id || "") { + case "nightMode": + return DisplayService.nightModeEnabled || false; + case "darkMode": + return !SessionData.isLightMode; + case "doNotDisturb": + return SessionData.doNotDisturb || false; + case "idleInhibitor": + return SessionService.idleInhibited || false; + default: + return false; + } + } + + enabled: !root.editMode + + onClicked: { + if (root.editMode) + return; + switch (widgetData.id || "") { + case "nightMode": + { + if (DisplayService.automationAvailable) + DisplayService.toggleNightMode(); + break; + } + case "darkMode": + { + const newMode = !SessionData.isLightMode; + Theme.screenTransition(); + Theme.setLightMode(newMode); + break; + } + case "doNotDisturb": + { + SessionData.setDoNotDisturb(!SessionData.doNotDisturb); + break; + } + case "idleInhibitor": + { + SessionService.toggleIdleInhibit(); + break; + } + } + } + } + } + + Component { + id: smallToggleComponent + SmallToggleButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 48 + + iconName: { + switch (widgetData.id || "") { + case "nightMode": + return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"; + case "darkMode": + return "contrast"; + case "doNotDisturb": + return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"; + case "idleInhibitor": + return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"; + default: + return "help"; + } + } + + iconRotation: { + if (widgetData.id !== "darkMode") + return 0; + if (darkModeTransitionPending) { + return SessionData.isLightMode ? 180 : 0; + } + return SessionData.isLightMode ? 180 : 0; + } + + isActive: { + switch (widgetData.id || "") { + case "nightMode": + return DisplayService.nightModeEnabled || false; + case "darkMode": + return !SessionData.isLightMode; + case "doNotDisturb": + return SessionData.doNotDisturb || false; + case "idleInhibitor": + return SessionService.idleInhibited || false; + default: + return false; + } + } + + enabled: !root.editMode + + onClicked: { + if (root.editMode) + return; + switch (widgetData.id || "") { + case "nightMode": + { + if (DisplayService.automationAvailable) + DisplayService.toggleNightMode(); + break; + } + case "darkMode": + { + const newMode = !SessionData.isLightMode; + Theme.screenTransition(); + Theme.setLightMode(newMode); + break; + } + case "doNotDisturb": + { + SessionData.setDoNotDisturb(!SessionData.doNotDisturb); + break; + } + case "idleInhibitor": + { + SessionService.toggleIdleInhibit(); + break; + } + } + } + } + } + + Component { + id: diskUsagePillComponent + DiskUsagePill { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 60 + + mountPath: widgetData.mountPath || "/" + instanceId: widgetData.instanceId || "" + + onExpandClicked: { + if (!root.editMode) { + root.expandClicked(widgetData, widgetIndex); + } + } + } + } + + Component { + id: smallDiskUsageComponent + SmallDiskUsageButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 48 + + mountPath: widgetData.mountPath || "/" + instanceId: widgetData.instanceId || "" + + onClicked: { + if (!root.editMode) { + root.expandClicked(widgetData, widgetIndex); + } + } + } + } + + Component { + id: colorPickerPillComponent + ColorPickerPill { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + width: parent.width + height: 60 + + colorPickerModal: root.colorPickerModal + } + } + + Component { + id: builtinPluginWidgetComponent + Loader { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property int widgetWidth: widgetData.width || 50 + width: parent.width + height: 60 + + property var builtinInstance: null + + Component.onCompleted: { + const id = widgetData.id || ""; + if (id === "builtin_vpn") { + if (root.model?.vpnLoader) { + root.model.vpnLoader.active = true; + } + builtinInstance = Qt.binding(() => root.model?.vpnBuiltinInstance); + } + if (id === "builtin_cups") { + if (root.model?.cupsLoader) { + root.model.cupsLoader.active = true; + } + builtinInstance = Qt.binding(() => root.model?.cupsBuiltinInstance); + } + } + + sourceComponent: { + if (!builtinInstance) + return null; + + const hasDetail = builtinInstance.ccDetailContent !== null; + + if (widgetWidth <= 25) { + return builtinSmallToggleComponent; + } else if (hasDetail) { + return builtinCompoundPillComponent; + } else { + return builtinToggleComponent; + } + } + } + } + + Component { + id: builtinCompoundPillComponent + CompoundPill { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var builtinInstance: parent.builtinInstance + + iconName: builtinInstance?.ccWidgetIcon || "extension" + primaryText: builtinInstance?.ccWidgetPrimaryText || "Built-in" + secondaryText: builtinInstance?.ccWidgetSecondaryText || "" + isActive: builtinInstance?.ccWidgetIsActive || false + + onToggled: { + if (root.editMode) + return; + if (builtinInstance) { + builtinInstance.ccWidgetToggled(); + } + } + + onExpandClicked: { + if (root.editMode) + return; + if (builtinInstance) { + builtinInstance.ccWidgetExpanded(); + } + root.expandClicked(widgetData, widgetIndex); + } + } + } + + Component { + id: builtinToggleComponent + ToggleButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var builtinInstance: parent.builtinInstance + + iconName: builtinInstance?.ccWidgetIcon || "extension" + text: builtinInstance?.ccWidgetPrimaryText || "Built-in" + isActive: builtinInstance?.ccWidgetIsActive || false + enabled: !root.editMode + + onClicked: { + if (root.editMode) + return; + if (builtinInstance) { + builtinInstance.ccWidgetToggled(); + } + } + } + } + + Component { + id: builtinSmallToggleComponent + SmallToggleButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var builtinInstance: parent.builtinInstance + + iconName: builtinInstance?.ccWidgetIcon || "extension" + isActive: builtinInstance?.ccWidgetIsActive || false + enabled: !root.editMode + + onClicked: { + if (root.editMode) + return; + if (builtinInstance) { + builtinInstance.ccWidgetToggled(); + } + } + } + } + + Component { + id: pluginWidgetComponent + Loader { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property int widgetWidth: widgetData.width || 50 + width: parent.width + height: 60 + + property var pluginInstance: null + property string pluginId: widgetData.id?.replace("plugin_", "") || "" + + sourceComponent: { + if (!pluginInstance) + return null; + + const hasDetail = pluginInstance.ccDetailContent !== null; + + if (widgetWidth <= 25) { + return pluginSmallToggleComponent; + } else if (hasDetail) { + return pluginCompoundPillComponent; + } else { + return pluginToggleComponent; + } + } + + function tryCreatePluginInstance() { + const pluginComponent = PluginService.pluginWidgetComponents[pluginId]; + if (!pluginComponent) + return false; + try { + const instance = pluginComponent.createObject(null, { + "pluginId": pluginId, + "pluginService": PluginService, + "visible": false, + "width": 0, + "height": 0 + }); + if (instance) { + pluginInstance = instance; + return true; + } + } catch (e) { + console.warn("DragDropGrid: stale plugin component for", pluginId, "- reloading"); + PluginService.reloadPlugin(pluginId); + } + return false; + } + + Component.onCompleted: { + Qt.callLater(() => tryCreatePluginInstance()); + } + + Connections { + target: PluginService + function onPluginDataChanged(changedPluginId) { + if (changedPluginId === pluginId && pluginInstance) { + pluginInstance.loadPluginData(); + } + } + function onPluginLoaded(loadedPluginId) { + if (loadedPluginId !== pluginId || pluginInstance) + return; + Qt.callLater(() => tryCreatePluginInstance()); + } + } + + Component.onDestruction: { + if (pluginInstance) { + pluginInstance.destroy(); + } + } + } + } + + Component { + id: pluginCompoundPillComponent + CompoundPill { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var pluginInstance: parent.pluginInstance + + iconName: pluginInstance?.ccWidgetIcon || "extension" + primaryText: pluginInstance?.ccWidgetPrimaryText || "Plugin" + secondaryText: pluginInstance?.ccWidgetSecondaryText || "" + isActive: pluginInstance?.ccWidgetIsActive || false + + onToggled: { + if (root.editMode) + return; + if (pluginInstance) { + pluginInstance.ccWidgetToggled(); + } + } + + onExpandClicked: { + if (root.editMode) + return; + if (pluginInstance) { + pluginInstance.ccWidgetExpanded(); + } + root.expandClicked(widgetData, widgetIndex); + } + } + } + + Component { + id: pluginToggleComponent + ToggleButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var pluginInstance: parent.pluginInstance + property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") + + iconName: pluginInstance?.ccWidgetIcon || widgetDef?.icon || "extension" + text: pluginInstance?.ccWidgetPrimaryText || widgetDef?.text || "Plugin" + secondaryText: pluginInstance?.ccWidgetSecondaryText || "" + isActive: pluginInstance?.ccWidgetIsActive || false + enabled: !root.editMode + + onClicked: { + if (root.editMode) + return; + if (pluginInstance) { + pluginInstance.ccWidgetToggled(); + } + } + } + } + + Component { + id: pluginSmallToggleComponent + SmallToggleButton { + property var widgetData: parent.widgetData || {} + property int widgetIndex: parent.widgetIndex || 0 + property var pluginInstance: parent.pluginInstance + property var widgetDef: root.model?.getWidgetForId(widgetData.id || "") + + iconName: pluginInstance?.ccWidgetIcon || widgetDef?.icon || "extension" + isActive: pluginInstance?.ccWidgetIsActive || false + enabled: !root.editMode + + onClicked: { + if (root.editMode) + return; + if (pluginInstance && pluginInstance.ccDetailContent) { + root.expandClicked(widgetData, widgetIndex); + } else if (pluginInstance) { + pluginInstance.ccWidgetToggled(); + } + } + } + } +} |