Merge branch 'custom-buttons'

This commit is contained in:
LemmyCook 2025-09-04 08:40:00 -04:00
commit 902cdc39e0
15 changed files with 835 additions and 398 deletions

View file

@ -73,7 +73,7 @@ Variants {
Repeater {
model: Settings.data.bar.widgets.left
delegate: NWidgetLoader {
widgetName: modelData
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
@ -100,8 +100,7 @@ Variants {
Repeater {
model: Settings.data.bar.widgets.center
delegate: NWidgetLoader {
widgetName: modelData
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),
@ -129,7 +128,7 @@ Variants {
Repeater {
model: Settings.data.bar.widgets.right
delegate: NWidgetLoader {
widgetName: modelData
widgetId: (modelData.id !== undefined ? modelData.id : "")
widgetProps: {
"screen": root.modelData || null,
"scaling": ScalingService.getScreenScale(screen),

View file

@ -0,0 +1,87 @@
import QtQuick
import QtQuick.Layouts
import Quickshell
import qs.Commons
import qs.Services
import qs.Widgets
import qs.Modules.SettingsPanel
NIconButton {
id: root
// Widget properties passed from Bar.qml
property var screen
property real scaling: 1.0
property string barSection: ""
property int sectionWidgetIndex: -1
property int sectionWidgetsCount: 0
// Get user settings from Settings data
property var widgetSettings: {
var section = barSection.replace("Section", "").toLowerCase()
if (section && sectionWidgetIndex >= 0) {
var widgets = Settings.data.bar.widgets[section]
if (widgets && sectionWidgetIndex < widgets.length) {
return widgets[sectionWidgetIndex]
}
}
return {}
}
// Use settings or defaults from BarWidgetRegistry
readonly property string userIcon: widgetSettings.icon || BarWidgetRegistry.widgetMetadata["CustomButton"].icon
readonly property string userLeftClickExec: widgetSettings.leftClickExec
|| BarWidgetRegistry.widgetMetadata["CustomButton"].leftClickExec
readonly property string userRightClickExec: widgetSettings.rightClickExec
|| BarWidgetRegistry.widgetMetadata["CustomButton"].rightClickExec
readonly property string userMiddleClickExec: widgetSettings.middleClickExec
|| BarWidgetRegistry.widgetMetadata["CustomButton"].middleClickExec
readonly property bool hasExec: (userLeftClickExec || userRightClickExec || userMiddleClickExec)
icon: userIcon
tooltipText: {
if (!hasExec) {
return "Custom Button - Configure in settings"
} else {
var lines = []
if (userLeftClickExec !== "") {
lines.push(`Left click: <i>${userLeftClickExec}</i>`)
}
if (userRightClickExec !== "") {
lines.push(`Right click: <i>${userRightClickExec}</i>`)
}
if (userLeftClickExec !== "") {
lines.push(`Middle click: <i>${userMiddleClickExec}</i>`)
}
return lines.join("<br/>")
}
}
opacity: hasExec ? Style.opacityFull : Style.opacityMedium
onClicked: {
if (userLeftClickExec) {
Quickshell.execDetached(userLeftClickExec.split(" "))
Logger.log("CustomButton", `Executing command: ${userLeftClickExec}`)
} else if (!hasExec) {
// No script was defined, open settings
var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.Bar
settingsPanel.open(screen)
}
}
onRightClicked: {
if (userRightClickExec) {
Quickshell.execDetached(userRightClickExec.split(" "))
Logger.log("CustomButton", `Executing command: ${userRightClickExec}`)
}
}
onMiddleClicked: {
if (userMiddleClickExec) {
Quickshell.execDetached(userMiddleClickExec.split(" "))
Logger.log("CustomButton", `Executing command: ${userMiddleClickExec}`)
}
}
}

View file

@ -93,7 +93,7 @@ Item {
}
onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.AudioService
settingsPanel.requestedTab = SettingsPanel.Tab.Audio
settingsPanel.open(screen)
}
onRightClicked: {

View file

@ -78,7 +78,7 @@ Item {
}
onClicked: {
var settingsPanel = PanelService.getPanel("settingsPanel")
settingsPanel.requestedTab = SettingsPanel.Tab.AudioService
settingsPanel.requestedTab = SettingsPanel.Tab.Audio
settingsPanel.open(screen)
}
onRightClicked: {

View file

@ -0,0 +1,432 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
import qs.Services
NBox {
id: root
property string sectionName: ""
property string sectionId: ""
property var widgetModel: []
property var availableWidgets: []
signal addWidget(string widgetId, string section)
signal removeWidget(string section, int index)
signal reorderWidget(string section, int fromIndex, int toIndex)
signal updateWidgetSettings(string section, int index, var settings)
color: Color.mSurface
Layout.fillWidth: true
Layout.minimumHeight: {
var widgetCount = widgetModel.length
if (widgetCount === 0)
return 140 * scaling
var availableWidth = parent.width
var avgWidgetWidth = 150 * scaling
var widgetsPerRow = Math.max(1, Math.floor(availableWidth / avgWidgetWidth))
var rows = Math.ceil(widgetCount / widgetsPerRow)
return (50 + 20 + (rows * 48) + ((rows - 1) * Style.marginS) + 20) * scaling
}
// Generate widget color from name checksum
function getWidgetColor(widget) {
const totalSum = JSON.stringify(widget).split('').reduce((acc, character) => {
return acc + character.charCodeAt(0)
}, 0)
switch (totalSum % 10) {
case 0:
return Color.mPrimary
case 1:
return Color.mSecondary
case 2:
return Color.mTertiary
case 3:
return Color.mError
case 4:
return Color.mOnSurface
case 5:
return Qt.darker(Color.mPrimary, 1.3)
case 6:
return Qt.darker(Color.mSecondary, 1.3)
case 7:
return Qt.darker(Color.mTertiary, 1.3)
case 8:
return Qt.darker(Color.mError, 1.3)
case 9:
return Qt.darker(Color.mOnSurface, 1.3)
}
}
ColumnLayout {
anchors.fill: parent
anchors.margins: Style.marginL * scaling
spacing: Style.marginM * scaling
RowLayout {
Layout.fillWidth: true
NText {
text: sectionName + " Section"
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mSecondary
Layout.alignment: Qt.AlignVCenter
}
Item {
Layout.fillWidth: true
}
NComboBox {
id: comboBox
model: availableWidgets
label: ""
description: ""
placeholder: "Select a widget to add..."
onSelected: key => comboBox.currentKey = key
popupHeight: 240 * scaling
Layout.alignment: Qt.AlignVCenter
}
NIconButton {
icon: "add"
colorBg: Color.mPrimary
colorFg: Color.mOnPrimary
colorBgHover: Color.mSecondary
colorFgHover: Color.mOnSecondary
enabled: comboBox.currentKey !== ""
tooltipText: "Add widget to section"
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: Style.marginS * scaling
onClicked: {
if (comboBox.currentKey !== "") {
addWidget(comboBox.currentKey, sectionId)
comboBox.currentKey = ""
}
}
}
}
// Drag and Drop Widget Area
// Replace your Flow section with this:
// Drag and Drop Widget Area - use Item container
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 65 * scaling
Flow {
id: widgetFlow
anchors.fill: parent
spacing: Style.marginS * scaling
flow: Flow.LeftToRight
Repeater {
model: widgetModel
delegate: Rectangle {
id: widgetItem
required property int index
required property var modelData
width: widgetContent.implicitWidth + Style.marginL * scaling
height: Style.baseWidgetSize * 1.15 * scaling
radius: Style.radiusL * scaling
color: root.getWidgetColor(modelData)
border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling)
// Store the widget index for drag operations
property int widgetIndex: index
readonly property int buttonsWidth: Math.round(20 * scaling)
readonly property int buttonsCount: 1 + BarWidgetRegistry.widgetHasUserSettings(modelData.id)
// Visual feedback during drag
states: State {
when: flowDragArea.draggedIndex === index
PropertyChanges {
target: widgetItem
scale: 1.1
opacity: 0.9
z: 1000
}
}
RowLayout {
id: widgetContent
anchors.centerIn: parent
spacing: Style.marginXXS * scaling
NText {
text: modelData.id
font.pointSize: Style.fontSizeS * scaling
color: Color.mOnPrimary
horizontalAlignment: Text.AlignHCenter
elide: Text.ElideRight
Layout.preferredWidth: 80 * scaling
}
RowLayout {
spacing: 0
Layout.preferredWidth: buttonsCount * buttonsWidth
Loader {
active: BarWidgetRegistry.widgetHasUserSettings(modelData.id)
sourceComponent: NIconButton {
icon: "settings"
sizeRatio: 0.6
colorBorder: Color.applyOpacity(Color.mOutline, "40")
colorBg: Color.mOnSurface
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
onClicked: {
var dialog = Qt.createComponent("BarWidgetSettingsDialog.qml").createObject(root, {
"widgetIndex": index,
"widgetData": modelData,
"widgetId": modelData.id,
"parent": Overlay.overlay
})
dialog.open()
}
}
}
NIconButton {
icon: "close"
sizeRatio: 0.6
colorBorder: Color.applyOpacity(Color.mOutline, "40")
colorBg: Color.mOnSurface
colorFg: Color.mOnPrimary
colorBgHover: Color.applyOpacity(Color.mOnPrimary, "40")
colorFgHover: Color.mOnPrimary
onClicked: {
removeWidget(sectionId, index)
}
}
}
}
}
}
}
// MouseArea outside Flow, covering the same area
MouseArea {
id: flowDragArea
anchors.fill: parent
z: 999 // Above all widgets to ensure it gets events first
// Critical properties for proper event handling
acceptedButtons: Qt.LeftButton
preventStealing: false // Prevent child items from stealing events
propagateComposedEvents: draggedIndex != -1 // Don't propagate to children during drag
hoverEnabled: draggedIndex != -1
property point startPos: Qt.point(0, 0)
property bool dragStarted: false
property int draggedIndex: -1
property real dragThreshold: 15 * scaling
property Item draggedWidget: null
property point clickOffsetInWidget: Qt.point(0, 0)
property point originalWidgetPos: Qt.point(0, 0) // ADD THIS: Store original position
onPressed: mouse => {
startPos = Qt.point(mouse.x, mouse.y)
dragStarted = false
draggedIndex = -1
draggedWidget = null
// Find which widget was clicked
for (var i = 0; i < widgetModel.length; i++) {
const widget = widgetFlow.children[i]
if (widget && widget.widgetIndex !== undefined) {
if (mouse.x >= widget.x && mouse.x <= widget.x + widget.width && mouse.y >= widget.y
&& mouse.y <= widget.y + widget.height) {
const localX = mouse.x - widget.x
const buttonsStartX = widget.width - (widget.buttonsCount * widget.buttonsWidth)
if (localX < buttonsStartX) {
draggedIndex = widget.widgetIndex
draggedWidget = widget
// Calculate and store where within the widget the user clicked
const clickOffsetX = mouse.x - widget.x
const clickOffsetY = mouse.y - widget.y
clickOffsetInWidget = Qt.point(clickOffsetX, clickOffsetY)
// STORE ORIGINAL POSITION
originalWidgetPos = Qt.point(widget.x, widget.y)
// Immediately set prevent stealing to true when drag candidate is found
preventStealing = true
break
} else {
// Click was on buttons - allow event propagation
mouse.accepted = false
return
}
}
}
}
}
onPositionChanged: mouse => {
if (draggedIndex !== -1) {
const deltaX = mouse.x - startPos.x
const deltaY = mouse.y - startPos.y
const distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
if (!dragStarted && distance > dragThreshold) {
dragStarted = true
//Logger.log("BarSectionEditor", "Drag started")
// Enable visual feedback
if (draggedWidget) {
draggedWidget.z = 1000
}
}
if (dragStarted && draggedWidget) {
// Adjust position to account for where within the widget the user clicked
draggedWidget.x = mouse.x - clickOffsetInWidget.x
draggedWidget.y = mouse.y - clickOffsetInWidget.y
}
}
}
onReleased: mouse => {
if (dragStarted && draggedWidget) {
// Find drop target using improved logic
let targetIndex = -1
let minDistance = Infinity
const mouseX = mouse.x
const mouseY = mouse.y
// Check if we should insert at the beginning
let insertAtBeginning = true
let insertAtEnd = true
// Check if the dragged item is already the last item
let isLastItem = true
for (var k = 0; k < widgetModel.length; k++) {
if (k !== draggedIndex && k > draggedIndex) {
isLastItem = false
break
}
}
for (var i = 0; i < widgetModel.length; i++) {
if (i !== draggedIndex) {
const widget = widgetFlow.children[i]
if (widget && widget.widgetIndex !== undefined) {
const centerX = widget.x + widget.width / 2
const centerY = widget.y + widget.height / 2
const distance = Math.sqrt(Math.pow(mouseX - centerX, 2) + Math.pow(mouseY - centerY, 2))
// Check if mouse is to the right of this widget
if (mouseX > widget.x + widget.width / 2) {
insertAtBeginning = false
}
// Check if mouse is to the left of this widget
if (mouseX < widget.x + widget.width / 2) {
insertAtEnd = false
}
if (distance < minDistance) {
minDistance = distance
targetIndex = widget.widgetIndex
}
}
}
}
// If dragging the last item to the right, don't reorder
if (isLastItem && insertAtEnd) {
insertAtEnd = false
targetIndex = -1
//Logger.log("BarSectionEditor", "Last item dropped to right - no reordering needed")
}
// Determine final target index based on position
let finalTargetIndex = targetIndex
if (insertAtBeginning && widgetModel.length > 1) {
// Insert at the very beginning (position 0)
finalTargetIndex = 0
//Logger.log("BarSectionEditor", "Inserting at beginning")
} else if (insertAtEnd && widgetModel.length > 1) {
// Insert at the very end
let maxIndex = -1
for (var j = 0; j < widgetModel.length; j++) {
if (j !== draggedIndex) {
maxIndex = Math.max(maxIndex, j)
}
}
finalTargetIndex = maxIndex
//Logger.log("BarSectionEditor", "Inserting at end, target:", finalTargetIndex)
} else if (targetIndex !== -1) {
// Normal case - determine if we should insert before or after the target
const targetWidget = widgetFlow.children[targetIndex]
if (targetWidget) {
const targetCenterX = targetWidget.x + targetWidget.width / 2
if (mouseX > targetCenterX) {
// Mouse is to the right of target center, insert after
//Logger.log("BarSectionEditor", "Inserting after widget at index:", targetIndex)
} else {
// Mouse is to the left of target center, insert before
finalTargetIndex = targetIndex
//Logger.log("BarSectionEditor", "Inserting before widget at index:", targetIndex)
}
}
}
//Logger.log("BarSectionEditor", "Final drop target index:", finalTargetIndex)
// Check if reordering is needed
if (finalTargetIndex !== -1 && finalTargetIndex !== draggedIndex) {
// Reordering will happen - reset position for the Flow to handle
draggedWidget.x = 0
draggedWidget.y = 0
draggedWidget.z = 0
reorderWidget(sectionId, draggedIndex, finalTargetIndex)
} else {
// No reordering - restore original position
draggedWidget.x = originalWidgetPos.x
draggedWidget.y = originalWidgetPos.y
draggedWidget.z = 0
//Logger.log("BarSectionEditor", "No reordering - restoring original position")
}
} else if (draggedIndex !== -1 && !dragStarted) {
// This was a click without drag - could add click handling here if needed
}
// Reset everything
dragStarted = false
draggedIndex = -1
draggedWidget = null
preventStealing = false // Allow normal event propagation again
originalWidgetPos = Qt.point(0, 0) // Reset stored position
}
// Handle case where mouse leaves the area during drag
onExited: {
if (dragStarted && draggedWidget) {
// Restore original position when mouse leaves area
draggedWidget.x = originalWidgetPos.x
draggedWidget.y = originalWidgetPos.y
draggedWidget.z = 0
}
}
}
}
}
}

View file

@ -0,0 +1,160 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Layouts
import qs.Commons
import qs.Widgets
import qs.Services
// Widget Settings Dialog Component
Popup {
id: settingsPopup
property int widgetIndex: -1
property var widgetData: null
property string widgetId: ""
// Center popup in parent
x: (parent.width - width) * 0.5
y: (parent.height - height) * 0.5
width: 420 * scaling
height: content.implicitHeight + padding * 2
padding: Style.marginXL * scaling
modal: true
background: Rectangle {
id: bgRect
color: Color.mSurface
radius: Style.radiusL * scaling
border.color: Color.mPrimary
border.width: Style.borderM * scaling
}
ColumnLayout {
id: content
width: parent.width
spacing: Style.marginM * scaling
// Title
RowLayout {
Layout.fillWidth: true
NText {
text: "Widget Settings: " + settingsPopup.widgetId
font.pointSize: Style.fontSizeL * scaling
font.weight: Style.fontWeightBold
color: Color.mPrimary
Layout.fillWidth: true
}
NIconButton {
icon: "close"
onClicked: settingsPopup.close()
}
}
// Separator
Rectangle {
Layout.fillWidth: true
Layout.preferredHeight: 1
color: Color.mOutline
}
// Settings based on widget type
Loader {
id: settingsLoader
Layout.fillWidth: true
sourceComponent: {
if (settingsPopup.widgetId === "CustomButton") {
return customButtonSettings
}
// Add more widget settings components here as needed
return null
}
}
// Action buttons
RowLayout {
Layout.fillWidth: true
Layout.topMargin: Style.marginM * scaling
Item {
Layout.fillWidth: true
}
NButton {
text: "Cancel"
outlined: true
onClicked: settingsPopup.close()
}
NButton {
text: "Save"
onClicked: {
if (settingsLoader.item && settingsLoader.item.saveSettings) {
var newSettings = settingsLoader.item.saveSettings()
root.updateWidgetSettings(sectionId, settingsPopup.widgetIndex, newSettings)
settingsPopup.close()
}
}
}
}
}
// CustomButton settings component
Component {
id: customButtonSettings
ColumnLayout {
spacing: Style.marginM * scaling
function saveSettings() {
var settings = Object.assign({}, settingsPopup.widgetData)
settings.icon = iconInput.text
settings.leftClickExec = leftClickExecInput.text
settings.rightClickExec = rightClickExecInput.text
settings.middleClickExec = middleClickExecInput.text
return settings
}
// Icon setting
NTextInput {
id: iconInput
Layout.fillWidth: true
Layout.bottomMargin: Style.marginXL * scaling
label: "Icon Name"
description: "Use Material Icon names from the icon set."
text: settingsPopup.widgetData.icon || ""
placeholderText: "Enter icon name (e.g., favorite, home, settings)"
}
NTextInput {
id: leftClickExecInput
Layout.fillWidth: true
label: "Left Click Command"
description: "Command or application to run when left clicked."
text: settingsPopup.widgetData.leftClickExec || ""
placeholderText: "Enter command to execute (app or custom script)"
}
NTextInput {
id: rightClickExecInput
Layout.fillWidth: true
label: "Right Click Command"
description: "Command or application to run when right clicked."
text: settingsPopup.widgetData.rightClickExec || ""
placeholderText: "Enter command to execute (app or custom script)"
}
NTextInput {
id: middleClickExecInput
Layout.fillWidth: true
label: "Middle Click Command"
description: "Command or application to run when middle clicked."
text: settingsPopup.widgetData.middleClickExec || ""
placeholderText: "Enter command to execute (app or custom script)"
}
}
}
}

View file

@ -24,13 +24,12 @@ NPanel {
panelAnchorHorizontalCenter: true
panelAnchorVerticalCenter: true
// Enable keyboard focus for settings panel
panelKeyboardFocus: true
// Tabs enumeration, order is NOT relevant
enum Tab {
About,
AudioService,
Audio,
Bar,
Launcher,
Brightness,
@ -131,7 +130,7 @@ NPanel {
"icon": "apps",
"source": launcherTab
}, {
"id": SettingsPanel.Tab.AudioService,
"id": SettingsPanel.Tab.Audio,
"label": "Audio",
"icon": "volume_up",
"source": audioTab

View file

@ -4,6 +4,7 @@ import QtQuick.Layouts
import qs.Commons
import qs.Services
import qs.Widgets
import qs.Modules.SettingsPanel.Extras
ColumnLayout {
id: root
@ -157,36 +158,39 @@ ColumnLayout {
spacing: Style.marginM * scaling
// Left Section
NSectionEditor {
BarSectionEditor {
sectionName: "Left"
sectionId: "left"
widgetModel: Settings.data.bar.widgets.left
availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
}
// Center Section
NSectionEditor {
BarSectionEditor {
sectionName: "Center"
sectionId: "center"
widgetModel: Settings.data.bar.widgets.center
availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
}
// Right Section
NSectionEditor {
BarSectionEditor {
sectionName: "Right"
sectionId: "right"
widgetModel: Settings.data.bar.widgets.right
availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
onAddWidget: (widgetId, section) => _addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => _removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => _reorderWidgetInSection(section, fromIndex, toIndex)
onUpdateWidgetSettings: (section, index, settings) => _updateWidgetSettingsInSection(section, index, settings)
}
}
}
@ -197,60 +201,55 @@ ColumnLayout {
Layout.bottomMargin: Style.marginXL * scaling
}
// Helper functions
function addWidgetToSection(widgetName, section) {
//Logger.log("BarTab", "Adding widget", widgetName, "to section", section)
var sectionArray = Settings.data.bar.widgets[section]
if (sectionArray) {
// Create a new array to avoid modifying the original
var newArray = sectionArray.slice()
newArray.push(widgetName)
//Logger.log("BarTab", "Widget added. New array:", JSON.stringify(newArray))
// Assign the new array
Settings.data.bar.widgets[section] = newArray
// ---------------------------------
// Signal 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) {
if (key !== "allowUserSettings") {
newWidget[key] = metadata[key]
}
})
}
}
Settings.data.bar.widgets[section].push(newWidget)
}
function removeWidgetFromSection(section, index) {
// Logger.log("BarTab", "Removing widget from section", section, "at index", index)
var sectionArray = Settings.data.bar.widgets[section]
//Logger.log("BarTab", "Current section array:", JSON.stringify(sectionArray))
if (sectionArray && index >= 0 && index < sectionArray.length) {
// Create a new array to avoid modifying the original
var newArray = sectionArray.slice()
function _removeWidgetFromSection(section, index) {
if (index >= 0 && index < Settings.data.bar.widgets[section].length) {
var newArray = Settings.data.bar.widgets[section].slice()
newArray.splice(index, 1)
//Logger.log("BarTab", "Widget removed. New array:", JSON.stringify(newArray))
// Assign the new array
Settings.data.bar.widgets[section] = newArray
} else {
//Logger.log("BarTab", "Invalid section or index:", section, index, "array length:",
// sectionArray ? sectionArray.length : "null")
}
}
function reorderWidgetInSection(section, fromIndex, toIndex) {
//Logger.log("BarTab", "Reordering widget in section", section, "from", fromIndex, "to", toIndex)
var sectionArray = Settings.data.bar.widgets[section]
if (sectionArray && fromIndex >= 0 && fromIndex < sectionArray.length && toIndex >= 0
&& toIndex < sectionArray.length) {
function _reorderWidgetInSection(section, fromIndex, toIndex) {
if (fromIndex >= 0 && fromIndex < Settings.data.bar.widgets[section].length && toIndex >= 0
&& toIndex < Settings.data.bar.widgets[section].length) {
// Create a new array to avoid modifying the original
var newArray = sectionArray.slice()
var newArray = Settings.data.bar.widgets[section].slice()
var item = newArray[fromIndex]
newArray.splice(fromIndex, 1)
newArray.splice(toIndex, 0, item)
Logger.log("BarTab", "Widget reordered. New array:", JSON.stringify(newArray))
// Assign the new array
Settings.data.bar.widgets[section] = newArray
//Logger.log("BarTab", "Widget reordered. New array:", JSON.stringify(newArray))
}
}
function _updateWidgetSettingsInSection(section, index, settings) {
// Update the widget settings in the Settings data
Settings.data.bar.widgets[section][index] = settings
//Logger.log("BarTab", `Updated widget settings for ${settings.id} in ${section} section`)
}
// Base list model for all combo boxes
ListModel {
id: availableWidgets

View file

@ -8,7 +8,7 @@ import qs.Services
import qs.Widgets
NPanel {
id: panel
id: root
panelWidth: 460 * scaling
panelHeight: 708 * scaling