NPanel now can properly be positioned relative to their opener (button)

This commit is contained in:
LemmyCook 2025-08-26 08:55:29 -04:00
parent 3c39ea192b
commit f3ae0101d7
6 changed files with 66 additions and 31 deletions

View file

@ -66,7 +66,7 @@ NIconButton {
if (ArchUpdaterService.updatePackages.length > 0) { if (ArchUpdaterService.updatePackages.length > 0) {
// Show confirmation dialog for updates // Show confirmation dialog for updates
PanelService.getPanel("archUpdaterPanel").toggle(screen) PanelService.getPanel("archUpdaterPanel").toggle(screen, this)
} else { } else {
// Just refresh if no updates available // Just refresh if no updates available
ArchUpdaterService.doPoll() ArchUpdaterService.doPoll()

View file

@ -31,5 +31,5 @@ NIconButton {
} }
} }
tooltipText: "Bluetooth Devices" tooltipText: "Bluetooth Devices"
onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen) onClicked: PanelService.getPanel("bluetoothPanel")?.toggle(screen, this)
} }

View file

@ -38,7 +38,7 @@ Rectangle {
} }
onClicked: { onClicked: {
tooltip.hide() tooltip.hide()
PanelService.getPanel("calendarPanel")?.toggle(screen) PanelService.getPanel("calendarPanel")?.toggle(screen, this)
} }
} }
} }

View file

@ -20,5 +20,5 @@ NIconButton {
colorFg: Color.mOnSurface colorFg: Color.mOnSurface
colorBorder: Color.transparent colorBorder: Color.transparent
colorBorderHover: Color.transparent colorBorderHover: Color.transparent
onClicked: PanelService.getPanel("notificationHistoryPanel")?.toggle(screen) onClicked: PanelService.getPanel("notificationHistoryPanel")?.toggle(screen, this)
} }

View file

@ -32,8 +32,9 @@ NIconButton {
icon: { icon: {
try { try {
if (NetworkService.ethernet) if (NetworkService.ethernet) {
return "lan" return "lan"
}
let connected = false let connected = false
let signalStrength = 0 let signalStrength = 0
for (const net in NetworkService.networks) { for (const net in NetworkService.networks) {
@ -50,12 +51,5 @@ NIconButton {
} }
} }
tooltipText: "Network / WiFi" tooltipText: "Network / WiFi"
onClicked: { onClicked: PanelService.getPanel("wifiPanel")?.toggle(screen, this)
try {
Logger.log("WiFi", "Button clicked, toggling panel")
PanelService.getPanel("wifiPanel")?.toggle(screen)
} catch (error) {
Logger.error("WiFi", "Error toggling panel:", error)
}
}
} }

View file

@ -10,8 +10,8 @@ Loader {
active: false active: false
asynchronous: true asynchronous: true
readonly property real scaling: ScalingService.scale(screen)
property ShellScreen screen property ShellScreen screen
readonly property real scaling: ScalingService.scale(screen)
property Component panelContent: null property Component panelContent: null
property int panelWidth: 1500 property int panelWidth: 1500
@ -20,6 +20,12 @@ Loader {
property bool panelAnchorLeft: false property bool panelAnchorLeft: false
property bool panelAnchorRight: false property bool panelAnchorRight: false
// Properties to support positioning relative to the opener (button)
property bool useButtonPosition: false
property point buttonPosition: Qt.point(0, 0)
property int buttonWidth: 0
property int buttonHeight: 0
// Animation properties // Animation properties
readonly property real originalScale: 0.7 readonly property real originalScale: 0.7
readonly property real originalOpacity: 0.0 readonly property real originalOpacity: 0.0
@ -27,6 +33,8 @@ Loader {
property real opacityValue: originalOpacity property real opacityValue: originalOpacity
property alias isClosing: hideTimer.running property alias isClosing: hideTimer.running
readonly property real barHeight: Style.barHeight * scaling
readonly property bool barAtBottom: Settings.data.bar.position === "bottom"
signal opened signal opened
signal closed signal closed
@ -36,20 +44,32 @@ Loader {
} }
// ----------------------------------------- // -----------------------------------------
function toggle(aScreen) { function toggle(aScreen, buttonItem) {
if (!active || isClosing) { if (!active || isClosing) {
open(aScreen) open(aScreen, buttonItem)
} else { } else {
close() close()
} }
} }
// ----------------------------------------- // -----------------------------------------
function open(aScreen) { function open(aScreen, buttonItem) {
if (aScreen !== null) { if (aScreen !== null) {
screen = aScreen screen = aScreen
} }
// Get t button position if provided
if (buttonItem !== undefined && buttonItem !== null) {
useButtonPosition = true
var itemPos = buttonItem.mapToItem(null, 0, 0)
buttonPosition = Qt.point(itemPos.x, itemPos.y)
buttonWidth = buttonItem.width
buttonHeight = buttonItem.height
} else {
useButtonPosition = false
}
// Special case if currently closing/animating // Special case if currently closing/animating
if (isClosing) { if (isClosing) {
hideTimer.stop() // in case we were closing hideTimer.stop() // in case we were closing
@ -74,6 +94,7 @@ Loader {
function closeCompleted() { function closeCompleted() {
root.closed() root.closed()
active = false active = false
useButtonPosition = false // Reset button position usage
} }
// ----------------------------------------- // -----------------------------------------
@ -113,8 +134,8 @@ Loader {
anchors.left: true anchors.left: true
anchors.right: true anchors.right: true
anchors.bottom: true anchors.bottom: true
margins.top: Settings.data.bar.position === "top" ? Style.barHeight * scaling : 0 margins.top: !barAtBottom ? barHeight : 0
margins.bottom: Settings.data.bar.position === "bottom" ? Style.barHeight * scaling : 0 margins.bottom: barAtBottom ? barHeight : 0
// Close any panel with Esc without requiring focus // Close any panel with Esc without requiring focus
Shortcut { Shortcut {
@ -140,21 +161,41 @@ Loader {
width: panelWidth width: panelWidth
height: panelHeight height: panelHeight
anchors { property int calculatedX: {
centerIn: panelAnchorCentered ? parent : null if (root.useButtonPosition) {
left: !panelAnchorCentered && panelAnchorLeft ? parent.left : parent.center // Position panel relative to button
right: !panelAnchorCentered && panelAnchorRight ? parent.right : parent.center var targetX = root.buttonPosition.x + (root.buttonWidth / 2) - (panelWidth / 2)
top: !panelAnchorCentered && (Settings.data.bar.position === "top") ? parent.top : undefined
bottom: !panelAnchorCentered && (Settings.data.bar.position === "bottom") ? parent.bottom : undefined
// margins // Keep panel within screen bounds
topMargin: !panelAnchorCentered var maxX = panelWindow.width - panelWidth - (Style.marginS * scaling)
&& (Settings.data.bar.position === "top") ? Style.marginS * scaling : undefined var minX = Style.marginS * scaling
bottomMargin: !panelAnchorCentered
&& (Settings.data.bar.position === "bottom") ? Style.marginS * scaling : undefined return Math.max(minX, Math.min(targetX, maxX))
rightMargin: !panelAnchorCentered && panelAnchorRight ? Style.marginS * scaling : undefined } else if (!panelAnchorCentered && panelAnchorLeft) {
return Style.marginS * scaling
} else if (!panelAnchorCentered && panelAnchorRight) {
return panelWindow.width - panelWidth - (Style.marginS * scaling)
} else {
return (panelWindow.width - panelWidth) / 2
}
} }
property int calculatedY: {
// Position panel below or above the bar
if (!panelAnchorCentered) {
if (!barAtBottom) {
return Style.marginS * scaling
} else {
return panelWindow.height - panelHeight - (Style.marginS * scaling)
}
} else {
return (panelWindow.height - panelHeight) / 2
}
}
x: calculatedX
y: calculatedY
scale: root.scaleValue scale: root.scaleValue
opacity: root.opacityValue opacity: root.opacityValue