Custom buttons: WIP implementing custom properties

This commit is contained in:
LemmyCook 2025-09-03 19:09:36 -04:00
parent 3ba6899e69
commit 7f34ca4122
7 changed files with 154 additions and 33 deletions

View file

@ -100,6 +100,31 @@ Singleton {
Logger.log("Settings", "Settings loaded successfully") Logger.log("Settings", "Settings loaded successfully")
isLoaded = true isLoaded = true
for (var i = 0; i < adapter.bar.widgets.left.length; i++) {
var obj = adapter.bar.widgets.left[i]
if (typeof obj === "string") {
adapter.bar.widgets.left[i] = {
"id": obj
}
}
}
for (var i = 0; i < adapter.bar.widgets.center.length; i++) {
var obj = adapter.bar.widgets.center[i]
if (typeof obj === "string") {
adapter.bar.widgets.center[i] = {
"id": obj
}
}
}
for (var i = 0; i < adapter.bar.widgets.right.length; i++) {
var obj = adapter.bar.widgets.right[i]
if (typeof obj === "string") {
adapter.bar.widgets.right[i] = {
"id": obj
}
}
}
// Emit the signal // Emit the signal
root.settingsLoaded() root.settingsLoaded()
@ -126,6 +151,8 @@ Singleton {
JsonAdapter { JsonAdapter {
id: adapter id: adapter
property int settingsVersion: 1
// bar // bar
property JsonObject bar: JsonObject { property JsonObject bar: JsonObject {
property string position: "top" // Possible values: "top", "bottom" property string position: "top" // Possible values: "top", "bottom"
@ -140,9 +167,39 @@ Singleton {
// Widget configuration for modular bar system // Widget configuration for modular bar system
property JsonObject widgets property JsonObject widgets
widgets: JsonObject { widgets: JsonObject {
property list<string> left: ["SystemMonitor", "ActiveWindow", "MediaMini"] property list<var> left: [{
property list<string> center: ["Workspace"] "id": "SystemMonitor"
property list<string> right: ["ScreenRecorderIndicator", "Tray", "NotificationHistory", "WiFi", "Bluetooth", "Battery", "Volume", "Brightness", "NightLight", "Clock", "SidePanelToggle"] }, {
"id": "ActiveWindow"
}, {
"id": "MediaMini"
}]
property list<var> center: [{
"id": "Workspace"
}]
property list<var> right: [{
"id": "ScreenRecorderIndicator"
}, {
"id": "Tray"
}, {
"id": "NotificationHistory"
}, {
"id": "WiFi"
}, {
"id": "Bluetooth"
}, {
"id": "Battery"
}, {
"id": "Volume"
}, {
"id": "Brightness"
}, {
"id": "NightLight"
}, {
"id": "Clock"
}, {
"id": "SidePanelToggle"
}]
} }
} }

View file

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

View file

@ -0,0 +1,26 @@
import Quickshell
import qs.Commons
import qs.Widgets
import qs.Services
NIconButton {
id: root
property ShellScreen screen
property real scaling: 1.0
property bool allowUserSettings: true
icon: "favorite"
tooltipText: "Hello world"
sizeRatio: 0.8
colorBg: Color.mSurfaceVariant
colorFg: Color.mOnSurface
colorBorder: Color.transparent
colorBorderHover: Color.transparent
anchors.verticalCenter: parent.verticalCenter
onClicked: {
}
}

View file

@ -162,7 +162,7 @@ ColumnLayout {
sectionId: "left" sectionId: "left"
widgetModel: Settings.data.bar.widgets.left widgetModel: Settings.data.bar.widgets.left
availableWidgets: availableWidgets availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
} }
@ -173,7 +173,7 @@ ColumnLayout {
sectionId: "center" sectionId: "center"
widgetModel: Settings.data.bar.widgets.center widgetModel: Settings.data.bar.widgets.center
availableWidgets: availableWidgets availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
} }
@ -184,7 +184,7 @@ ColumnLayout {
sectionId: "right" sectionId: "right"
widgetModel: Settings.data.bar.widgets.right widgetModel: Settings.data.bar.widgets.right
availableWidgets: availableWidgets availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section) onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index) onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex) onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
} }
@ -198,14 +198,16 @@ ColumnLayout {
} }
// Helper functions // Helper functions
function addWidgetToSection(widgetName, section) { function addWidgetToSection(widgetId, section) {
//Logger.log("BarTab", "Adding widget", widgetName, "to section", section) //Logger.log("BarTab", "Adding widget", widgetId, "to section", section)
var sectionArray = Settings.data.bar.widgets[section] var sectionArray = Settings.data.bar.widgets[section]
if (sectionArray) { if (sectionArray) {
// Create a new array to avoid modifying the original // Create a new array to avoid modifying the original
var newArray = sectionArray.slice() var newArray = sectionArray.slice()
newArray.push(widgetName) newArray.push({
"id": widgetId
})
//Logger.log("BarTab", "Widget added. New array:", JSON.stringify(newArray)) //Logger.log("BarTab", "Widget added. New array:", JSON.stringify(newArray))
// Assign the new array // Assign the new array

View file

@ -16,6 +16,7 @@ Singleton {
"Bluetooth": bluetoothComponent, "Bluetooth": bluetoothComponent,
"Brightness": brightnessComponent, "Brightness": brightnessComponent,
"Clock": clockComponent, "Clock": clockComponent,
"CustomButton": customButtonComponent,
"DarkModeToggle": darkModeToggle, "DarkModeToggle": darkModeToggle,
"KeyboardLayout": keyboardLayoutComponent, "KeyboardLayout": keyboardLayoutComponent,
"MediaMini": mediaMiniComponent, "MediaMini": mediaMiniComponent,
@ -33,6 +34,15 @@ Singleton {
"Workspace": workspaceComponent "Workspace": workspaceComponent
}) })
property var widgetMetadata: ({
"CustomButton": {
allowUserSettings: true,
icon: "favorite",
execute: ""
},
})
// Component definitions - these are loaded once at startup // Component definitions - these are loaded once at startup
property Component activeWindowComponent: Component { property Component activeWindowComponent: Component {
ActiveWindow {} ActiveWindow {}
@ -52,6 +62,9 @@ Singleton {
property Component clockComponent: Component { property Component clockComponent: Component {
Clock {} Clock {}
} }
property Component customButtonComponent: Component {
CustomButton {}
}
property Component darkModeToggle: Component { property Component darkModeToggle: Component {
DarkModeToggle {} DarkModeToggle {}
} }
@ -100,20 +113,25 @@ Singleton {
// ------------------------------ // ------------------------------
// Helper function to get widget component by name // Helper function to get widget component by name
function getWidget(name) { function getWidget(id) {
return widgets[name] || null return widgets[id] || null
} }
// Helper function to check if widget exists // Helper function to check if widget exists
function hasWidget(name) { function hasWidget(id) {
return name in widgets return id in widgets
} }
// Get list of available widget names // Get list of available widget id
function getAvailableWidgets() { function getAvailableWidgets() {
return Object.keys(widgets) return Object.keys(widgets)
} }
// Helper function to check if widget has user settings
function widgetHasUserSettings(id) {
return (widgetMetadata[id] !== undefined) && (widgetMetadata[id].allowUserSettings === true)
}
function getNPillDirection(widget) { function getNPillDirection(widget) {
try { try {
if (widget.barSection === "leftSection") { if (widget.barSection === "leftSection") {

View file

@ -3,6 +3,7 @@ import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import qs.Commons import qs.Commons
import qs.Widgets import qs.Widgets
import qs.Services
NBox { NBox {
id: root id: root
@ -12,7 +13,7 @@ NBox {
property var widgetModel: [] property var widgetModel: []
property var availableWidgets: [] property var availableWidgets: []
signal addWidget(string widgetName, string section) signal addWidget(string widgetId, string section)
signal removeWidget(string section, int index) signal removeWidget(string section, int index)
signal reorderWidget(string section, int fromIndex, int toIndex) signal reorderWidget(string section, int fromIndex, int toIndex)
@ -32,8 +33,8 @@ NBox {
} }
// Generate widget color from name checksum // Generate widget color from name checksum
function getWidgetColor(name) { function getWidgetColor(widgetId) {
const totalSum = name.split('').reduce((acc, character) => { const totalSum = widgetId.split('').reduce((acc, character) => {
return acc + character.charCodeAt(0) return acc + character.charCodeAt(0)
}, 0) }, 0)
switch (totalSum % 5) { switch (totalSum % 5) {
@ -110,17 +111,18 @@ NBox {
spacing: Style.marginS * scaling spacing: Style.marginS * scaling
flow: Flow.LeftToRight flow: Flow.LeftToRight
Repeater { Repeater {
model: widgetModel model: widgetModel
delegate: Rectangle { delegate: Rectangle {
id: widgetItem id: widgetItem
required property int index required property int index
required property string modelData required property var modelData
width: widgetContent.implicitWidth + Style.marginL * scaling width: widgetContent.implicitWidth + Style.marginL * scaling
height: 40 * scaling height: 40 * scaling
radius: Style.radiusL * scaling radius: Style.radiusL * scaling
color: root.getWidgetColor(modelData) color: root.getWidgetColor(modelData.id)
border.color: Color.mOutline border.color: Color.mOutline
border.width: Math.max(1, Style.borderS * scaling) border.width: Math.max(1, Style.borderS * scaling)
@ -151,7 +153,7 @@ NBox {
spacing: Style.marginXS * scaling spacing: Style.marginXS * scaling
NText { NText {
text: modelData text: modelData.id
font.pointSize: Style.fontSizeS * scaling font.pointSize: Style.fontSizeS * scaling
color: Color.mOnPrimary color: Color.mOnPrimary
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
@ -159,6 +161,23 @@ NBox {
Layout.preferredWidth: 80 * scaling Layout.preferredWidth: 80 * scaling
} }
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: {
// TODO open settings
}
}
}
NIconButton { NIconButton {
icon: "close" icon: "close"
sizeRatio: 0.6 sizeRatio: 0.6
@ -193,13 +212,13 @@ NBox {
return return
} }
//Logger.log("NSectionEditor", `Started dragging widget: ${modelData} at index ${index}`) //Logger.log("NSectionEditor", `Started dragging widget: ${modelData.id} at index ${index}`)
// Bring to front when starting drag // Bring to front when starting drag
widgetItem.z = 1000 widgetItem.z = 1000
} }
onReleased: { onReleased: {
//Logger.log("NSectionEditor", `Released widget: ${modelData} at index ${index}`) //Logger.log("NSectionEditor", `Released widget: ${modelData.id} at index ${index}`)
// Reset z-index when drag ends // Reset z-index when drag ends
widgetItem.z = 0 widgetItem.z = 0

View file

@ -6,7 +6,7 @@ import qs.Commons
Item { Item {
id: root id: root
property string widgetName: "" property string widgetId: ""
property var widgetProps: ({}) property var widgetProps: ({})
property bool enabled: true property bool enabled: true
@ -27,12 +27,12 @@ Item {
id: loader id: loader
anchors.fill: parent anchors.fill: parent
active: Settings.isLoaded && enabled && widgetName !== "" active: Settings.isLoaded && enabled && widgetId !== ""
sourceComponent: { sourceComponent: {
if (!active) { if (!active) {
return null return null
} }
return BarWidgetRegistry.getWidget(widgetName) return BarWidgetRegistry.getWidget(widgetId)
} }
onLoaded: { onLoaded: {
@ -49,14 +49,14 @@ Item {
item.onLoaded() item.onLoaded()
} }
//Logger.log("NWidgetLoader", "Loaded", widgetName, "on screen", item.screen.name) //Logger.log("NWidgetLoader", "Loaded", widgetId, "on screen", item.screen.name)
} }
} }
// Error handling // Error handling
onWidgetNameChanged: { onWidgetIdChanged: {
if (widgetName && !BarWidgetRegistry.hasWidget(widgetName)) { if (widgetId && !BarWidgetRegistry.hasWidget(widgetId)) {
Logger.warn("WidgetLoader", "Widget not found in registry:", widgetName) Logger.warn("WidgetLoader", "Widget not found in registry:", widgetId)
} }
} }
} }