mirror of
https://github.com/noctalia-dev/noctalia-shell.git
synced 2026-05-11 17:08:27 +08:00
Bar: Improve centering by computing pixel perfect coordinates. All basic widgets + workspace.
This commit is contained in:
+6
-1
@@ -90,7 +90,7 @@ Singleton {
|
||||
let h;
|
||||
switch (Settings.data.bar.density) {
|
||||
case "mini":
|
||||
h = (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 22 : 20;
|
||||
h = (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 23 : 21;
|
||||
break;
|
||||
case "compact":
|
||||
h = (Settings.data.bar.position === "left" || Settings.data.bar.position === "right") ? 27 : 25;
|
||||
@@ -136,4 +136,9 @@ Singleton {
|
||||
function toOdd(n) {
|
||||
return Math.floor(n / 2) * 2 + 1;
|
||||
}
|
||||
|
||||
// Ensures a number is always even (rounds down to nearest even)
|
||||
function toEven(n) {
|
||||
return Math.floor(n / 2) * 2;
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -211,7 +211,7 @@ Item {
|
||||
|
||||
// Top section (left widgets)
|
||||
ColumnLayout {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Style.marginM
|
||||
spacing: Style.marginS
|
||||
@@ -238,7 +238,7 @@ Item {
|
||||
|
||||
// Center section (center widgets)
|
||||
ColumnLayout {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Style.marginS
|
||||
|
||||
@@ -264,7 +264,7 @@ Item {
|
||||
|
||||
// Bottom section (right widgets)
|
||||
ColumnLayout {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: Style.marginM
|
||||
spacing: Style.marginS
|
||||
@@ -304,7 +304,7 @@ Item {
|
||||
objectName: "leftSection"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Style.marginS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
spacing: Style.marginS
|
||||
|
||||
Repeater {
|
||||
@@ -332,7 +332,7 @@ Item {
|
||||
id: centerSection
|
||||
objectName: "centerSection"
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
spacing: Style.marginS
|
||||
|
||||
Repeater {
|
||||
@@ -361,7 +361,7 @@ Item {
|
||||
objectName: "rightSection"
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Style.marginS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
spacing: Style.marginS
|
||||
|
||||
Repeater {
|
||||
|
||||
@@ -58,7 +58,7 @@ Item {
|
||||
readonly property real groupedBorderOpacity: (widgetSettings.groupedBorderOpacity !== undefined) ? widgetSettings.groupedBorderOpacity : widgetMetadata.groupedBorderOpacity
|
||||
readonly property bool enableScrollWheel: (widgetSettings.enableScrollWheel !== undefined) ? widgetSettings.enableScrollWheel : widgetMetadata.enableScrollWheel
|
||||
|
||||
readonly property int itemSize: Math.round(Style.capsuleHeight * 0.8)
|
||||
readonly property int itemSize: Style.toOdd(Style.capsuleHeight * 0.8)
|
||||
|
||||
// Context menu state for grouped mode - store IDs instead of object references to avoid stale references
|
||||
property string selectedWindowId: ""
|
||||
@@ -123,13 +123,13 @@ Item {
|
||||
|
||||
const textWidth = displayText.length * (d * 0.4); // Approximate width per character
|
||||
const padding = d * 0.6;
|
||||
return Math.round(Math.max(d * factor, textWidth + padding));
|
||||
return Style.toOdd(Math.max(d * factor, textWidth + padding));
|
||||
}
|
||||
|
||||
function getWorkspaceHeight(ws) {
|
||||
const d = Math.round(Style.capsuleHeight * root.baseDimensionRatio);
|
||||
const factor = ws.isActive ? 2.2 : 1;
|
||||
return Math.round(d * factor);
|
||||
return Style.toOdd(d * factor);
|
||||
}
|
||||
|
||||
function computeWidth() {
|
||||
@@ -140,7 +140,7 @@ Item {
|
||||
}
|
||||
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills;
|
||||
total += horizontalPadding * 2;
|
||||
return Math.round(total);
|
||||
return Style.toOdd(total);
|
||||
}
|
||||
|
||||
function computeHeight() {
|
||||
@@ -151,7 +151,7 @@ Item {
|
||||
}
|
||||
total += Math.max(localWorkspaces.count - 1, 0) * spacingBetweenPills;
|
||||
total += horizontalPadding * 2;
|
||||
return Math.round(total);
|
||||
return Style.toOdd(total);
|
||||
}
|
||||
|
||||
function getFocusedLocalIndex() {
|
||||
@@ -410,8 +410,8 @@ Item {
|
||||
border.color: Style.capsuleBorderColor
|
||||
border.width: Style.capsuleBorderWidth
|
||||
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
x: isVertical ? Style.pixelAlignCenter(parent.width, width) : 0
|
||||
y: isVertical ? 0 : Style.pixelAlignCenter(parent.height, height)
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
@@ -473,8 +473,8 @@ Item {
|
||||
Row {
|
||||
id: pillRow
|
||||
spacing: spacingBetweenPills
|
||||
anchors.verticalCenter: workspaceBackground.verticalCenter
|
||||
x: horizontalPadding
|
||||
y: workspaceBackground.y + Style.pixelAlignCenter(workspaceBackground.height, height)
|
||||
visible: !isVertical && !showApplications
|
||||
|
||||
Repeater {
|
||||
@@ -483,7 +483,7 @@ Item {
|
||||
Item {
|
||||
id: workspacePillContainer
|
||||
width: root.getWorkspaceWidth(model)
|
||||
height: Style.capsuleHeight * root.baseDimensionRatio
|
||||
height: Style.toOdd(Style.capsuleHeight * root.baseDimensionRatio)
|
||||
|
||||
Rectangle {
|
||||
id: pill
|
||||
@@ -493,8 +493,8 @@ Item {
|
||||
active: (labelMode !== "none") && (!root.showLabelsOnlyWhenOccupied || model.isOccupied || model.isFocused)
|
||||
sourceComponent: Component {
|
||||
NText {
|
||||
x: (pill.width - width) / 2
|
||||
y: (pill.height - height) / 2 + (height - contentHeight) / 2
|
||||
x: Style.pixelAlignCenter(pill.width, width)
|
||||
y: Style.pixelAlignCenter(pill.height, height)
|
||||
text: {
|
||||
if (model.name && model.name.length > 0) {
|
||||
if (root.labelMode === "name") {
|
||||
@@ -621,7 +621,7 @@ Item {
|
||||
Column {
|
||||
id: pillColumn
|
||||
spacing: spacingBetweenPills
|
||||
anchors.horizontalCenter: workspaceBackground.horizontalCenter
|
||||
x: workspaceBackground.x + Style.pixelAlignCenter(workspaceBackground.width, width)
|
||||
y: horizontalPadding
|
||||
visible: isVertical && !showApplications
|
||||
|
||||
@@ -630,7 +630,7 @@ Item {
|
||||
model: localWorkspaces
|
||||
Item {
|
||||
id: workspacePillContainerVertical
|
||||
width: Style.capsuleHeight * root.baseDimensionRatio
|
||||
width: Style.toOdd(Style.capsuleHeight * root.baseDimensionRatio)
|
||||
height: root.getWorkspaceHeight(model)
|
||||
|
||||
Rectangle {
|
||||
@@ -641,8 +641,8 @@ Item {
|
||||
active: (labelMode !== "none") && (!root.showLabelsOnlyWhenOccupied || model.isOccupied || model.isFocused)
|
||||
sourceComponent: Component {
|
||||
NText {
|
||||
x: (pillVertical.width - width) / 2
|
||||
y: (pillVertical.height - height) / 2 + (height - contentHeight) / 2
|
||||
x: Style.pixelAlignCenter(pillVertical.width, width)
|
||||
y: Style.pixelAlignCenter(pillVertical.height, height)
|
||||
text: {
|
||||
if (model.name && model.name.length > 0) {
|
||||
if (root.labelMode === "name") {
|
||||
@@ -779,8 +779,8 @@ Item {
|
||||
property var workspaceModel: model
|
||||
property bool hasWindows: (workspaceModel?.windows?.count ?? 0) > 0
|
||||
|
||||
width: (hasWindows ? groupedIconsFlow.implicitWidth : root.itemSize) + (root.isVertical ? Style.marginXS : Style.marginXL)
|
||||
height: (hasWindows ? groupedIconsFlow.implicitHeight : root.itemSize) + (root.isVertical ? Style.marginL : Style.marginXS)
|
||||
width: Style.toOdd((hasWindows ? groupedIconsFlow.implicitWidth : root.itemSize) + (root.isVertical ? Style.marginXS : Style.marginXL))
|
||||
height: Style.toOdd((hasWindows ? groupedIconsFlow.implicitHeight : root.itemSize) + (root.isVertical ? Style.marginL : Style.marginXS))
|
||||
color: Style.capsuleColor
|
||||
radius: Style.radiusS
|
||||
border.color: Settings.data.bar.showOutline ? Style.capsuleBorderColor : Qt.alpha((workspaceModel.isFocused ? Color.mPrimary : Color.mOutline), root.groupedBorderOpacity)
|
||||
@@ -812,7 +812,8 @@ Item {
|
||||
Flow {
|
||||
id: groupedIconsFlow
|
||||
|
||||
anchors.centerIn: parent
|
||||
x: Style.pixelAlignCenter(parent.width, width)
|
||||
y: Style.pixelAlignCenter(parent.height, height)
|
||||
spacing: 4
|
||||
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
|
||||
@@ -1019,15 +1020,11 @@ Item {
|
||||
id: groupedGrid
|
||||
visible: showApplications
|
||||
|
||||
anchors.verticalCenter: isVertical ? undefined : parent.verticalCenter
|
||||
anchors.left: isVertical ? undefined : parent.left
|
||||
anchors.leftMargin: isVertical ? 0 : Style.marginM
|
||||
anchors.horizontalCenter: isVertical ? parent.horizontalCenter : undefined
|
||||
anchors.top: isVertical ? parent.top : undefined
|
||||
anchors.topMargin: isVertical ? Style.marginM : 0
|
||||
x: root.isVertical ? Style.pixelAlignCenter(parent.width, width) : Style.marginM
|
||||
y: root.isVertical ? Style.marginM : Style.pixelAlignCenter(parent.height, height)
|
||||
|
||||
spacing: Style.marginS
|
||||
flow: isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
|
||||
Repeater {
|
||||
model: showApplications ? localWorkspaces : null
|
||||
|
||||
@@ -294,25 +294,24 @@ PanelWindow {
|
||||
readonly property string barPosition: Settings.data.bar.position || "top"
|
||||
readonly property bool barIsVertical: barPosition === "left" || barPosition === "right"
|
||||
readonly property bool barFloating: Settings.data.bar.floating || false
|
||||
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
|
||||
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0
|
||||
readonly property real attachmentOverlap: 1 // Attachment overlap to fix hairline gap with fractional scaling
|
||||
readonly property real barMarginH: barFloating ? Math.floor(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
|
||||
readonly property real barMarginV: barFloating ? Math.floor(Settings.data.bar.marginVertical * Style.marginXL) : 0
|
||||
|
||||
// Expose bar dimensions directly on this Item for BarBackground
|
||||
// Use screen dimensions directly
|
||||
x: {
|
||||
if (barPosition === "right")
|
||||
return screen.width - Style.barHeight - barMarginH - attachmentOverlap; // Extend left towards panels
|
||||
return screen.width - Style.barHeight - barMarginH;
|
||||
return barMarginH;
|
||||
}
|
||||
y: {
|
||||
if (barPosition === "bottom")
|
||||
return screen.height - Style.barHeight - barMarginV - attachmentOverlap;
|
||||
return screen.height - Style.barHeight - barMarginV;
|
||||
return barMarginV;
|
||||
}
|
||||
width: {
|
||||
if (barIsVertical) {
|
||||
return Style.barHeight + attachmentOverlap;
|
||||
return Style.barHeight;
|
||||
}
|
||||
return screen.width - barMarginH * 2;
|
||||
}
|
||||
@@ -320,7 +319,7 @@ PanelWindow {
|
||||
if (barIsVertical) {
|
||||
return screen.height - barMarginV * 2;
|
||||
}
|
||||
return Style.barHeight + attachmentOverlap;
|
||||
return Style.barHeight;
|
||||
}
|
||||
|
||||
// Corner states (same as Bar.qml)
|
||||
|
||||
@@ -93,6 +93,7 @@ Item {
|
||||
readonly property bool barFloating: Settings.data.bar.floating
|
||||
readonly property real barMarginH: barFloating ? Math.ceil(Settings.data.bar.marginHorizontal * Style.marginXL) : 0
|
||||
readonly property real barMarginV: barFloating ? Math.ceil(Settings.data.bar.marginVertical * Style.marginXL) : 0
|
||||
readonly property real attachmentOverlap: 1 // Panel extends 1px into bar area to fix hairline gap with fractional scaling
|
||||
|
||||
// Check if bar should be visible on this screen
|
||||
readonly property bool barShouldShow: {
|
||||
@@ -306,12 +307,13 @@ Item {
|
||||
// For vertical bars
|
||||
if (panelContent.allowAttach) {
|
||||
// Attached panels: align with bar edge (left or right side)
|
||||
// Subtract attachmentOverlap to extend panel 1px into bar area
|
||||
if (root.barPosition === "left") {
|
||||
var leftBarEdge = root.barMarginH + Style.barHeight;
|
||||
var leftBarEdge = root.barMarginH + Style.barHeight - root.attachmentOverlap;
|
||||
calculatedX = leftBarEdge;
|
||||
} else {
|
||||
// right
|
||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
|
||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight + root.attachmentOverlap;
|
||||
calculatedX = rightBarEdge - panelWidth;
|
||||
}
|
||||
} else {
|
||||
@@ -365,7 +367,8 @@ Item {
|
||||
if (root.effectivePanelAnchorRight) {
|
||||
// Attached: snap to edge/bar
|
||||
if (root.barIsVertical && root.barPosition === "right") {
|
||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
|
||||
// Add attachmentOverlap to extend panel 1px into bar area
|
||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight + root.attachmentOverlap;
|
||||
calculatedX = rightBarEdge - panelWidth;
|
||||
} else {
|
||||
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
|
||||
@@ -385,7 +388,8 @@ Item {
|
||||
if (root.effectivePanelAnchorLeft) {
|
||||
// Attached: snap to edge/bar
|
||||
if (root.barIsVertical && root.barPosition === "left") {
|
||||
var leftBarEdge = root.barMarginH + Style.barHeight;
|
||||
// Subtract attachmentOverlap to extend panel 1px into bar area
|
||||
var leftBarEdge = root.barMarginH + Style.barHeight - root.attachmentOverlap;
|
||||
calculatedX = leftBarEdge;
|
||||
} else {
|
||||
var panelOnSameEdgeAsBar = (root.barPosition === "top" && root.effectivePanelAnchorTop) || (root.barPosition === "bottom" && root.effectivePanelAnchorBottom);
|
||||
@@ -404,12 +408,12 @@ Item {
|
||||
// No explicit anchor: attach to bar if allowAttach, otherwise center
|
||||
if (root.barIsVertical) {
|
||||
if (panelContent.allowAttach) {
|
||||
// Attach to the bar edge
|
||||
// Attach to the bar edge (with overlap into bar area)
|
||||
if (root.barPosition === "left") {
|
||||
var leftBarEdge = root.barMarginH + Style.barHeight;
|
||||
var leftBarEdge = root.barMarginH + Style.barHeight - root.attachmentOverlap;
|
||||
calculatedX = leftBarEdge;
|
||||
} else {
|
||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight;
|
||||
var rightBarEdge = root.width - root.barMarginH - Style.barHeight + root.attachmentOverlap;
|
||||
calculatedX = rightBarEdge - panelWidth;
|
||||
}
|
||||
} else {
|
||||
@@ -466,14 +470,16 @@ Item {
|
||||
if (root.barPosition === "top") {
|
||||
var topBarEdge = root.barMarginV + Style.barHeight;
|
||||
if (panelContent.allowAttach) {
|
||||
calculatedY = topBarEdge;
|
||||
// Subtract attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = topBarEdge - root.attachmentOverlap;
|
||||
} else {
|
||||
calculatedY = topBarEdge + Style.marginM;
|
||||
}
|
||||
} else if (root.barPosition === "bottom") {
|
||||
var bottomBarEdge = root.height - root.barMarginV - Style.barHeight;
|
||||
if (panelContent.allowAttach) {
|
||||
calculatedY = bottomBarEdge - panelHeight;
|
||||
// Add attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = bottomBarEdge - panelHeight + root.attachmentOverlap;
|
||||
} else {
|
||||
calculatedY = bottomBarEdge - panelHeight - Style.marginM;
|
||||
}
|
||||
@@ -501,14 +507,18 @@ Item {
|
||||
}
|
||||
} else {
|
||||
if (root.effectivePanelAnchorTop && root.barPosition === "top") {
|
||||
calculatedY = root.barMarginV + Style.barHeight;
|
||||
// Subtract attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = root.barMarginV + Style.barHeight - root.attachmentOverlap;
|
||||
} else if (root.effectivePanelAnchorBottom && root.barPosition === "bottom") {
|
||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||
// Add attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight + root.attachmentOverlap;
|
||||
} else if (!root.hasExplicitVerticalAnchor) {
|
||||
if (root.barPosition === "top") {
|
||||
calculatedY = root.barMarginV + Style.barHeight;
|
||||
// Subtract attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = root.barMarginV + Style.barHeight - root.attachmentOverlap;
|
||||
} else if (root.barPosition === "bottom") {
|
||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||
// Add attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight + root.attachmentOverlap;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -532,8 +542,8 @@ Item {
|
||||
} else if (root.panelAnchorTop) {
|
||||
// Use raw panelAnchorTop for positioning decision
|
||||
if (root.effectivePanelAnchorTop) {
|
||||
// Attached: snap to edge/bar
|
||||
calculatedY = root.barPosition === "top" ? root.barMarginV + Style.barHeight : 0;
|
||||
// Attached: snap to edge/bar (with overlap into bar area)
|
||||
calculatedY = root.barPosition === "top" ? root.barMarginV + Style.barHeight - root.attachmentOverlap : 0;
|
||||
} else {
|
||||
// Not attached: position at top with margin
|
||||
var topBarOffset = (root.barPosition === "top") ? barOffset : 0;
|
||||
@@ -542,8 +552,8 @@ Item {
|
||||
} else if (root.panelAnchorBottom) {
|
||||
// Use raw panelAnchorBottom for positioning decision
|
||||
if (root.effectivePanelAnchorBottom) {
|
||||
// Attached: snap to edge/bar
|
||||
calculatedY = root.barPosition === "bottom" ? root.height - root.barMarginV - Style.barHeight - panelHeight : root.height - panelHeight;
|
||||
// Attached: snap to edge/bar (with overlap into bar area)
|
||||
calculatedY = root.barPosition === "bottom" ? root.height - root.barMarginV - Style.barHeight - panelHeight + root.attachmentOverlap : root.height - panelHeight;
|
||||
} else {
|
||||
// Not attached: position at bottom with margin
|
||||
var bottomBarOffset = (root.barPosition === "bottom") ? barOffset : 0;
|
||||
@@ -563,9 +573,11 @@ Item {
|
||||
} else {
|
||||
if (panelContent.allowAttach && !root.barIsVertical) {
|
||||
if (root.barPosition === "top") {
|
||||
calculatedY = root.barMarginV + Style.barHeight;
|
||||
// Subtract attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = root.barMarginV + Style.barHeight - root.attachmentOverlap;
|
||||
} else if (root.barPosition === "bottom") {
|
||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight;
|
||||
// Add attachmentOverlap to extend panel 1px into bar area
|
||||
calculatedY = root.height - root.barMarginV - Style.barHeight - panelHeight + root.attachmentOverlap;
|
||||
}
|
||||
} else {
|
||||
if (root.barPosition === "top") {
|
||||
|
||||
Reference in New Issue
Block a user