Bar/NPanels Improvements

- Fix potential hairline gap with fractional scaling
- Apply auto-snap rules even to centered anchored panels
- Improving animations and sizing
This commit is contained in:
Sébastien Atoch
2025-11-03 23:42:14 -05:00
parent c911756f5e
commit 057693fae3
5 changed files with 82 additions and 35 deletions
+1
View File
@@ -58,6 +58,7 @@ NPanel {
// Use implicitHeight from content + margins to avoid binding loops
property real contentPreferredHeight: mainColumn.implicitHeight + Style.marginL * 2
// property real contentPreferredHeight: Math.min(screen.height * 0.42, mainColumn.implicitHeight) + Style.marginL * 2
ColumnLayout {
id: mainColumn
+28 -4
View File
@@ -27,6 +27,9 @@ Item {
readonly property real barMarginH: barFloating ? Settings.data.bar.marginHorizontal * Style.marginXL : 0
readonly property real barMarginV: barFloating ? Settings.data.bar.marginVertical * Style.marginXL : 0
// Attachment overlap to fix hairline gap with fractional scaling
readonly property real attachmentOverlap: 1
// Fill the parent (the Loader)
anchors.fill: parent
@@ -54,10 +57,31 @@ Item {
id: bar
// Position and size the bar based on orientation and floating margins
x: (root.barPosition === "right") ? (parent.width - Style.barHeight - root.barMarginH) : root.barMarginH
y: (root.barPosition === "bottom") ? (parent.height - Style.barHeight - root.barMarginV) : root.barMarginV
width: root.barIsVertical ? Style.barHeight : (parent.width - root.barMarginH * 2)
height: root.barIsVertical ? (parent.height - root.barMarginV * 2) : Style.barHeight
// Extend the bar by attachmentOverlap to eliminate hairline gap
x: {
var baseX = (root.barPosition === "right") ? (parent.width - Style.barHeight - root.barMarginH) : root.barMarginH
if (root.barPosition === "right")
return baseX + root.attachmentOverlap
return baseX
}
y: {
var baseY = (root.barPosition === "bottom") ? (parent.height - Style.barHeight - root.barMarginV) : root.barMarginV
if (root.barPosition === "bottom")
return baseY + root.attachmentOverlap
return baseY
}
width: {
var baseWidth = root.barIsVertical ? Style.barHeight : (parent.width - root.barMarginH * 2)
if (!root.barIsVertical)
return baseWidth // Horizontal bars extend via height, not width
return baseWidth + root.attachmentOverlap
}
height: {
var baseHeight = root.barIsVertical ? (parent.height - root.barMarginV * 2) : Style.barHeight
if (!root.barIsVertical)
return baseHeight + root.attachmentOverlap
return baseHeight // Vertical bars extend via width, not height
}
backgroundColor: Qt.alpha(Color.mSurface, Settings.data.bar.backgroundOpacity)
+3 -1
View File
@@ -12,7 +12,7 @@ NPanel {
id: root
preferredWidth: 820 * Style.uiScaleRatio
preferredHeight: 940 * Style.uiScaleRatio
preferredHeight: 900 * Style.uiScaleRatio
panelAnchorHorizontalCenter: true
panelAnchorVerticalCenter: true
@@ -335,6 +335,8 @@ NPanel {
// Sidebar
Rectangle {
id: sidebar
clip: true
Layout.preferredWidth: 220 * Style.uiScaleRatio
Layout.fillHeight: true
Layout.alignment: Qt.AlignTop
+1 -1
View File
@@ -424,7 +424,7 @@ NPanel {
model: filteredWallpapers
property int columns: 5
property int columns: (screen.width > 1920) ? 5 : 4
property int itemSize: cellWidth
cellWidth: Math.floor((width - leftMargin - rightMargin) / columns)
+49 -29
View File
@@ -237,6 +237,21 @@ Item {
if (!isAttachedToNonFloating)
return "none"
// Priority: If panel is touching the bar (but not touching any screen edge), slide from the bar direction
// This handles cases where centered panels snap to the bar due to height constraints
// If touching screen edges, fall through to the distance-based calculation below
// var touchingAnyScreenEdge = touchingLeftEdge || touchingRightEdge || touchingTopEdge || touchingBottomEdge
// if (!touchingAnyScreenEdge) {
if (touchingTopBar && root.barPosition === "top")
return "top"
if (touchingBottomBar && root.barPosition === "bottom")
return "bottom"
if (touchingLeftBar && root.barPosition === "left")
return "left"
if (touchingRightBar && root.barPosition === "right")
return "right"
//}
// Use panel's center point (barycenter) as reference
var centerX = x + width / 2
var centerY = y + height / 2
@@ -278,7 +293,7 @@ Item {
}
// Animation properties
opacity: root.animationProgress
opacity: isAttachedToNonFloating ? Math.min(1, root.animationProgress * 5) : root.animationProgress
scale: {
if (isAttachedToNonFloating)
return 1 // No scale for full slide animation
@@ -341,31 +356,36 @@ Item {
topLeftInverted: {
// Bar attachment: only attach to bar if bar opacity >= 1.0 (no color clash)
var barInverted = root.couldAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft))
// Also detect when panel touches bar edge (e.g., centered panel that's too tall)
var barTouchInverted = touchingTopBar || touchingLeftBar
// Screen edge contact: can attach to screen edges even if bar opacity < 1.0
// For horizontal bars: invert when touching left/right edges
// For vertical bars: invert when touching top/bottom edges
var edgeInverted = root.couldAttach && ((touchingLeftEdge && !root.barIsVertical) || (touchingTopEdge && root.barIsVertical))
// Also invert when touching screen edge opposite to bar (e.g., bottom edge when bar is at top)
var oppositeEdgeInverted = root.couldAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top")
return barInverted || edgeInverted || oppositeEdgeInverted
return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted
}
topRightInverted: {
var barInverted = root.couldAttachToBar && ((root.barPosition === "top" && !root.barIsVertical && root.effectivePanelAnchorTop) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight))
var barTouchInverted = touchingTopBar || touchingRightBar
var edgeInverted = root.couldAttach && ((touchingRightEdge && !root.barIsVertical) || (touchingTopEdge && root.barIsVertical))
var oppositeEdgeInverted = root.couldAttach && (touchingTopEdge && !root.barIsVertical && root.barPosition !== "top")
return barInverted || edgeInverted || oppositeEdgeInverted
return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted
}
bottomLeftInverted: {
var barInverted = root.couldAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "left" && root.barIsVertical && root.effectivePanelAnchorLeft))
var barTouchInverted = touchingBottomBar || touchingLeftBar
var edgeInverted = root.couldAttach && ((touchingLeftEdge && !root.barIsVertical) || (touchingBottomEdge && root.barIsVertical))
var oppositeEdgeInverted = root.couldAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom")
return barInverted || edgeInverted || oppositeEdgeInverted
return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted
}
bottomRightInverted: {
var barInverted = root.couldAttachToBar && ((root.barPosition === "bottom" && !root.barIsVertical && root.effectivePanelAnchorBottom) || (root.barPosition === "right" && root.barIsVertical && root.effectivePanelAnchorRight))
var barTouchInverted = touchingBottomBar || touchingRightBar
var edgeInverted = root.couldAttach && ((touchingRightEdge && !root.barIsVertical) || (touchingBottomEdge && root.barIsVertical))
var oppositeEdgeInverted = root.couldAttach && (touchingBottomEdge && !root.barIsVertical && root.barPosition !== "bottom")
return barInverted || edgeInverted || oppositeEdgeInverted
return barInverted || barTouchInverted || edgeInverted || oppositeEdgeInverted
}
// Set inverted corner direction based on which edge touches
@@ -435,6 +455,12 @@ Item {
readonly property bool touchingTopEdge: root.couldAttach && y <= 1
readonly property bool touchingBottomEdge: root.couldAttach && (y + height) >= (parent.height - 1)
// Detect if panel is touching bar edges (for cases where centered panels snap to bar due to height constraints)
readonly property bool touchingTopBar: root.couldAttachToBar && root.barPosition === "top" && !root.barIsVertical && Math.abs(y - (root.barMarginV + Style.barHeight)) <= 1
readonly property bool touchingBottomBar: root.couldAttachToBar && root.barPosition === "bottom" && !root.barIsVertical && Math.abs((y + height) - (parent.height - root.barMarginV - Style.barHeight)) <= 1
readonly property bool touchingLeftBar: root.couldAttachToBar && root.barPosition === "left" && root.barIsVertical && Math.abs(x - (root.barMarginH + Style.barHeight)) <= 1
readonly property bool touchingRightBar: root.couldAttachToBar && root.barPosition === "right" && root.barIsVertical && Math.abs((x + width) - (parent.width - root.barMarginH - Style.barHeight)) <= 1
// Position the panel using explicit x/y coordinates (no anchors)
// This makes coordinates clearer for the click-through mask system
x: {
@@ -451,16 +477,14 @@ Item {
if (root.barPosition === "left") {
// Panel to the right of left bar
var leftBarEdge = root.barMarginH + Style.barHeight
// Panel sits right at bar edge (inverted corners curve up/down)
// Shift left by 1px to eliminate any gap between bar and panel
calculatedX = leftBarEdge - 1
// Panel sits right at bar edge (inverted corners align perfectly)
calculatedX = leftBarEdge
} else {
// right
// Panel to the left of right bar
var rightBarEdge = parent.width - root.barMarginH - Style.barHeight
// Panel sits right at bar edge (inverted corners curve up/down)
// Shift right by 1px to eliminate any gap between bar and panel
calculatedX = rightBarEdge - width + 1
// Panel sits right at bar edge (inverted corners align perfectly)
calculatedX = rightBarEdge - width
}
} else {
// Detached panels: center on button X position
@@ -526,7 +550,7 @@ Item {
// When attached to right vertical bar, position next to bar (like useButtonPosition does)
if (root.couldAttach && root.barIsVertical && root.barPosition === "right") {
var rightBarEdge = parent.width - root.barMarginH - Style.barHeight
calculatedX = rightBarEdge - width + 1 // +1 to eliminate gap
calculatedX = rightBarEdge - width
} else if (root.couldAttach) {
// Attach to right screen edge
calculatedX = parent.width - width
@@ -539,7 +563,7 @@ Item {
// When attached to left vertical bar, position next to bar (like useButtonPosition does)
if (root.couldAttach && root.barIsVertical && root.barPosition === "left") {
var leftBarEdge = root.barMarginH + Style.barHeight
calculatedX = leftBarEdge - 1 // -1 to eliminate gap
calculatedX = leftBarEdge
} else if (root.couldAttach) {
// Attach to left screen edge
calculatedX = 0
@@ -619,9 +643,8 @@ Item {
// Panel below top bar
var topBarEdge = root.barMarginV + Style.barHeight
if (root.couldAttach) {
// Panel sits right at bar edge (inverted corners curve to the sides)
// Shift up by 1px to eliminate any gap between bar and panel
calculatedY = topBarEdge - 1
// Panel sits right at bar edge (inverted corners align perfectly)
calculatedY = topBarEdge
} else {
calculatedY = topBarEdge + Style.marginM
}
@@ -629,9 +652,8 @@ Item {
// Panel above bottom bar
var bottomBarEdge = parent.height - root.barMarginV - Style.barHeight
if (root.couldAttach) {
// Panel sits right at bar edge (inverted corners curve to the sides)
// Shift down by 1px to eliminate any gap between bar and panel
calculatedY = bottomBarEdge - height + 1
// Panel sits right at bar edge (inverted corners align perfectly)
calculatedY = bottomBarEdge - height
} else {
calculatedY = bottomBarEdge - height - Style.marginM
}
@@ -668,21 +690,19 @@ Item {
} else {
// For attached panels with explicit anchors
if (root.effectivePanelAnchorTop && root.barPosition === "top") {
// When attached to top bar: position right at bar edge (like useButtonPosition does)
// Shift up by 1px to eliminate gap between bar and panel
calculatedY = root.barMarginV + Style.barHeight - 1
// When attached to top bar: position right at bar edge (inverted corners align perfectly)
calculatedY = root.barMarginV + Style.barHeight
} else if (root.effectivePanelAnchorBottom && root.barPosition === "bottom") {
// When attached to bottom bar: position right at bar edge
// Shift down by 1px to eliminate gap between bar and panel
calculatedY = parent.height - root.barMarginV - Style.barHeight - height + 1
// When attached to bottom bar: position right at bar edge (inverted corners align perfectly)
calculatedY = parent.height - root.barMarginV - Style.barHeight - height
} else if (!root.hasExplicitVerticalAnchor) {
// No explicit vertical anchor AND attached: default to attaching to bar edge
if (root.barPosition === "top") {
// Attach to top bar
calculatedY = root.barMarginV + Style.barHeight - 1
calculatedY = root.barMarginV + Style.barHeight
} else if (root.barPosition === "bottom") {
// Attach to bottom bar
calculatedY = parent.height - root.barMarginV - Style.barHeight - height + 1
calculatedY = parent.height - root.barMarginV - Style.barHeight - height
}
// For vertical bars with no explicit anchor: fall through to center vertically on bar
}
@@ -745,9 +765,9 @@ Item {
// For horizontal bars: attach to bar edge by default
if (root.couldAttach && !root.barIsVertical) {
if (root.barPosition === "top") {
calculatedY = root.barMarginV + Style.barHeight - 1
calculatedY = root.barMarginV + Style.barHeight
} else if (root.barPosition === "bottom") {
calculatedY = parent.height - root.barMarginV - Style.barHeight - height + 1
calculatedY = parent.height - root.barMarginV - Style.barHeight - height
}
} else {
// Detached or no bar position: use default positioning