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")
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
root.settingsLoaded()
@ -126,6 +151,8 @@ Singleton {
JsonAdapter {
id: adapter
property int settingsVersion: 1
// bar
property JsonObject bar: JsonObject {
property string position: "top" // Possible values: "top", "bottom"
@ -140,9 +167,39 @@ Singleton {
// Widget configuration for modular bar system
property JsonObject widgets
widgets: JsonObject {
property list<string> left: ["SystemMonitor", "ActiveWindow", "MediaMini"]
property list<string> center: ["Workspace"]
property list<string> right: ["ScreenRecorderIndicator", "Tray", "NotificationHistory", "WiFi", "Bluetooth", "Battery", "Volume", "Brightness", "NightLight", "Clock", "SidePanelToggle"]
property list<var> left: [{
"id": "SystemMonitor"
}, {
"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 {
model: Settings.data.bar.widgets.left
delegate: NWidgetLoader {
widgetName: modelData
widgetId: 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
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
widgetProps: {
"screen": root.modelData || null,
"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"
widgetModel: Settings.data.bar.widgets.left
availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
}
@ -173,7 +173,7 @@ ColumnLayout {
sectionId: "center"
widgetModel: Settings.data.bar.widgets.center
availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
}
@ -184,7 +184,7 @@ ColumnLayout {
sectionId: "right"
widgetModel: Settings.data.bar.widgets.right
availableWidgets: availableWidgets
onAddWidget: (widgetName, section) => addWidgetToSection(widgetName, section)
onAddWidget: (widgetId, section) => addWidgetToSection(widgetId, section)
onRemoveWidget: (section, index) => removeWidgetFromSection(section, index)
onReorderWidget: (section, fromIndex, toIndex) => reorderWidgetInSection(section, fromIndex, toIndex)
}
@ -198,14 +198,16 @@ ColumnLayout {
}
// Helper functions
function addWidgetToSection(widgetName, section) {
//Logger.log("BarTab", "Adding widget", widgetName, "to section", section)
function addWidgetToSection(widgetId, section) {
//Logger.log("BarTab", "Adding widget", widgetId, "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)
newArray.push({
"id": widgetId
})
//Logger.log("BarTab", "Widget added. New array:", JSON.stringify(newArray))
// Assign the new array

View file

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

View file

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

View file

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