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

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