Bar widgets: modular loading refactoring via BarWidgetRegistry+NWidgetLoader

- Hot reload is working again.
- Should also be more memory efficient on multi monitors.
This commit is contained in:
LemmyCook 2025-08-24 23:50:09 -04:00
parent a110a0d636
commit a10d55e7f5
36 changed files with 514 additions and 446 deletions

View file

@ -31,6 +31,12 @@ Loader {
signal opened
signal closed
Component.onCompleted: {
// console.log("Oh Yeah")
// console.log(objectName)
PanelService.registerPanel(root)
}
// -----------------------------------------
function toggle(aScreen) {
if (!active || isClosing) {
@ -53,7 +59,7 @@ Loader {
opacityValue = 1.0
}
PanelService.registerOpen(root)
PanelService.willOpenPanel(root)
active = true
root.opened()

View file

@ -16,10 +16,11 @@ Item {
property color collapsedIconColor: Color.mOnSurface
property real sizeMultiplier: 0.8
property bool autoHide: false
// When true, keep the pill expanded regardless of hover state
property bool forceShown: false
property bool forceOpen: false
property bool disableOpen: false
// Effective shown state (true if hovered/animated open or forced)
readonly property bool effectiveShown: forceShown || showPill
readonly property bool effectiveShown: forceOpen || showPill
signal shown
signal hidden
@ -85,7 +86,7 @@ Item {
height: iconSize
radius: width * 0.5
// When forced shown, match pill background; otherwise use accent when hovered
color: forceShown ? pillColor : (showPill ? iconCircleColor : Color.mSurfaceVariant)
color: forceOpen ? pillColor : (showPill ? iconCircleColor : Color.mSurfaceVariant)
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
@ -100,7 +101,7 @@ Item {
text: root.icon
font.pointSize: Style.fontSizeM * scaling
// When forced shown, use pill text color; otherwise accent color when hovered
color: forceShown ? textColor : (showPill ? iconTextColor : Color.mOnSurface)
color: forceOpen ? textColor : (showPill ? iconTextColor : Color.mOnSurface)
anchors.centerIn: parent
}
}
@ -194,18 +195,21 @@ Item {
anchors.fill: parent
hoverEnabled: true
onEntered: {
if (!forceShown) {
root.entered()
tooltip.show()
if (disableOpen) {
return
}
if (!forceOpen) {
showDelayed()
}
tooltip.show()
root.entered()
}
onExited: {
if (!forceShown) {
root.exited()
if (!forceOpen) {
hide()
}
tooltip.hide()
root.exited()
}
onClicked: {
root.clicked()
@ -226,7 +230,7 @@ Item {
}
function hide() {
if (forceShown) {
if (forceOpen) {
return
}
if (showPill) {
@ -245,8 +249,8 @@ Item {
}
}
onForceShownChanged: {
if (forceShown) {
onForceOpenChanged: {
if (forceOpen) {
// Immediately lock open without animations
showAnim.stop()
hideAnim.stop()

View file

@ -90,6 +90,7 @@ NBox {
colorFgHover: Color.mOnSecondary
enabled: comboBox.selectedKey !== ""
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: Style.marginS * scaling
onClicked: {
if (comboBox.currentKey !== "") {
addWidget(comboBox.currentKey, sectionName.toLowerCase())
@ -174,27 +175,27 @@ NBox {
anchors.fill: parent
drag.target: parent
onPressed: {
// Check if the click is on the close button area
const closeButtonX = widgetContent.x + widgetContent.width - 20 * scaling
const closeButtonY = widgetContent.y
const closeButtonWidth = 20 * scaling
const closeButtonHeight = 20 * scaling
onPressed: mouse => {
// Check if the click is on the close button area
const closeButtonX = widgetContent.x + widgetContent.width - 20 * scaling
const closeButtonY = widgetContent.y
const closeButtonWidth = 20 * scaling
const closeButtonHeight = 20 * scaling
if (mouseX >= closeButtonX && mouseX <= closeButtonX + closeButtonWidth && mouseY >= closeButtonY
&& mouseY <= closeButtonY + closeButtonHeight) {
// Click is on the close button, don't start drag
mouse.accepted = false
return
}
if (mouseX >= closeButtonX && mouseX <= closeButtonX + closeButtonWidth
&& mouseY >= closeButtonY && mouseY <= closeButtonY + closeButtonHeight) {
// Click is on the close button, don't start drag
mouse.accepted = false
return
}
Logger.log("NWidgetCard", `Started dragging widget: ${modelData} at index ${index}`)
// Bring to front when starting drag
widgetItem.z = 1000
}
Logger.log("NSectionEditor", `Started dragging widget: ${modelData} at index ${index}`)
// Bring to front when starting drag
widgetItem.z = 1000
}
onReleased: {
Logger.log("NWidgetCard", `Released widget: ${modelData} at index ${index}`)
Logger.log("NSectionEditor", `Released widget: ${modelData} at index ${index}`)
// Reset z-index when drag ends
widgetItem.z = 0
@ -232,12 +233,12 @@ NBox {
const fromIndex = index
const toIndex = targetIndex
Logger.log(
"NWidgetCard",
"NSectionEditor",
`Dropped widget from index ${fromIndex} to position ${toIndex} (distance: ${minDistance.toFixed(
2)})`)
reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex)
} else {
Logger.log("NWidgetCard", `No valid drop target found for widget at index ${index}`)
Logger.log("NSectionEditor", `No valid drop target found for widget at index ${index}`)
}
}
}
@ -264,16 +265,16 @@ NBox {
}
onEntered: function (drag) {
Logger.log("NWidgetCard", "Entered start drop zone")
Logger.log("NSectionEditor", "Entered start drop zone")
}
onDropped: function (drop) {
Logger.log("NWidgetCard", "Dropped on start zone")
Logger.log("NSectionEditor", "Dropped on start zone")
if (drop.source && drop.source.widgetIndex !== undefined) {
const fromIndex = drop.source.widgetIndex
const toIndex = 0 // Insert at the beginning
if (fromIndex !== toIndex) {
Logger.log("NWidgetCard", `Dropped widget from index ${fromIndex} to beginning`)
Logger.log("NSectionEditor", `Dropped widget from index ${fromIndex} to beginning`)
reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex)
}
}
@ -299,16 +300,16 @@ NBox {
}
onEntered: function (drag) {
Logger.log("NWidgetCard", "Entered end drop zone")
Logger.log("NSectionEditor", "Entered end drop zone")
}
onDropped: function (drop) {
Logger.log("NWidgetCard", "Dropped on end zone")
Logger.log("NSectionEditor", "Dropped on end zone")
if (drop.source && drop.source.widgetIndex !== undefined) {
const fromIndex = drop.source.widgetIndex
const toIndex = widgetModel.length // Insert at the end
if (fromIndex !== toIndex) {
Logger.log("NWidgetCard", `Dropped widget from index ${fromIndex} to end`)
Logger.log("NSectionEditor", `Dropped widget from index ${fromIndex} to end`)
reorderWidget(sectionName.toLowerCase(), fromIndex, toIndex)
}
}

46
Widgets/NWidgetLoader.qml Normal file
View file

@ -0,0 +1,46 @@
import QtQuick
import Quickshell
import qs.Services
Item {
id: root
property string widgetName: ""
property var widgetProps: ({})
property bool enabled: true
// Don't reserve space unless the loaded widget is really visible
implicitWidth: loader.item ? loader.item.visible ? loader.item.implicitWidth : 0 : 0
implicitHeight: loader.item ? loader.item.visible ? loader.item.implicitHeight : 0 : 0
Loader {
id: loader
anchors.fill: parent
active: enabled && widgetName !== ""
sourceComponent: {
if (!active) {
return null
}
return BarWidgetRegistry.getWidget(widgetName)
}
onLoaded: {
if (item && widgetProps) {
// Apply properties to loaded widget
for (var prop in widgetProps) {
if (item.hasOwnProperty(prop)) {
item[prop] = widgetProps[prop]
}
}
}
}
}
// Error handling
onWidgetNameChanged: {
if (widgetName && !BarWidgetRegistry.hasWidget(widgetName)) {
Logger.warn("WidgetLoader", "Widget not found in registry:", widgetName)
}
}
}