feat(bar): horizontal top bar — Phase A geometry (NoSignal layout)

Convert the bar from a vertical left-edge strip to a horizontal top bar. The
shell had no orientation abstraction, so this flips the geometry across the bar
and the drawer/region/interaction layer:

- Bar.qml: ColumnLayout -> RowLayout; hit-testing (checkPopout/handleWheel),
  scroll halves and popout-center anchoring all keyed off x instead of y;
  first/last padding -> left/right margins.
- BarWrapper.qml: the bar's "thickness" is now its height (clampedHeight/
  contentHeight/implicitHeight); content anchors left/right/top.
- drawers: Exclusions (exclusive zone moved left->top), Panels (content inset
  topMargin = bar height), Regions + ContentWindow (panel->window coordinate
  mapping and the thick border flip left->top), Interactions (bar-region check
  y<barHeight, panel Y-origin uses bar height, scroll passes x, bar drag-reveal
  is vertical).
- widgets: Clock (Row, HH:MM with a colon), StatusIcons (Row), Workspaces +
  Workspace (Row), Tray (Row, expand chevron at the right) — each sizes to the
  bar height instead of width.

Verified live in the dev VM: top bar renders with centered-clock entries, the
exclusion zone keeps windows below the bar, and the dashboard drops down
correctly. Popout fly-outs still anchor sideways (Phase B).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
28allday 2026-06-13 23:26:55 +01:00
parent 152923f5d8
commit b1e2bb3bc6
12 changed files with 131 additions and 117 deletions

View file

@ -10,14 +10,18 @@ import Caelestia.Config
import qs.components
import qs.services
ColumnLayout {
// NoSignal: horizontal top bar. The widgets flow left->right in a RowLayout and
// the bar's "thickness" is its HEIGHT; hit-testing / scroll / popout anchoring all
// key off the x-axis (the position along the bar). Upstream caelestia is a
// vertical left-edge bar this is the NoSignal layout fork (Phase 3).
RowLayout {
id: root
required property ShellScreen screen
required property DrawerVisibilities visibilities
required property BarPopouts.Wrapper popouts
required property bool fullscreen
readonly property int vPadding: Tokens.padding.large
readonly property int hPadding: Tokens.padding.large
function closeTray(): void {
if (!Config.bar.tray.compact)
@ -31,8 +35,8 @@ ColumnLayout {
}
}
function checkPopout(y: real): void {
const ch = childAt(width / 2, y) as WrappedLoader;
function checkPopout(x: real): void {
const ch = childAt(x, height / 2) as WrappedLoader;
if (ch?.id !== "tray")
closeTray();
@ -43,24 +47,24 @@ ColumnLayout {
}
const id = ch.id;
const top = ch.y;
const left = ch.x;
if (id === "statusIcons" && Config.bar.popouts.statusIcons) {
const items = (ch.item as StatusIcons).items;
const icon = items.childAt(items.width / 2, mapToItem(items, 0, y).y);
const icon = items.childAt(mapToItem(items, x, 0).x, items.height / 2);
if (icon) {
popouts.currentName = icon.name;
popouts.currentCenter = Qt.binding(() => icon.mapToItem(root, 0, icon.implicitHeight / 2).y);
popouts.currentCenter = Qt.binding(() => icon.mapToItem(root, icon.implicitWidth / 2, 0).x);
popouts.hasCurrent = true;
}
} else if (id === "tray" && Config.bar.popouts.tray) {
const tray = ch.item as Tray;
if (!Config.bar.tray.compact || (tray.expanded && !tray.expandIcon.contains(mapToItem(tray.expandIcon, tray.implicitWidth / 2, y)))) {
const index = Math.floor(((y - top - tray.padding * 2 + tray.spacing) / tray.layout.implicitHeight) * tray.items.count);
if (!Config.bar.tray.compact || (tray.expanded && !tray.expandIcon.contains(mapToItem(tray.expandIcon, x, tray.implicitHeight / 2)))) {
const index = Math.floor(((x - left - tray.padding * 2 + tray.spacing) / tray.layout.implicitWidth) * tray.items.count);
const trayItem = tray.items.itemAt(index);
if (trayItem) {
popouts.currentName = `traymenu${index}`;
popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, 0, trayItem.implicitHeight / 2).y);
popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, trayItem.implicitWidth / 2, 0).x);
popouts.hasCurrent = true;
} else {
popouts.hasCurrent = false;
@ -71,13 +75,13 @@ ColumnLayout {
}
} else if (id === "activeWindow" && Config.bar.popouts.activeWindow && Config.bar.activeWindow.showOnHover) {
popouts.currentName = id.toLowerCase();
popouts.currentCenter = (ch.item as Item).mapToItem(root, 0, (ch.item as Item).implicitHeight / 2).y ?? 0;
popouts.currentCenter = (ch.item as Item).mapToItem(root, (ch.item as Item).implicitWidth / 2, 0).x ?? 0;
popouts.hasCurrent = true;
}
}
function handleWheel(y: real, angleDelta: point): void {
const ch = childAt(width / 2, y) as WrappedLoader;
function handleWheel(x: real, angleDelta: point): void {
const ch = childAt(x, height / 2) as WrappedLoader;
if (ch?.id === "workspaces" && Config.bar.scrollActions.workspaces) {
// Workspace scroll
const mon = (GlobalConfig.bar.workspaces.perMonitorWorkspaces ? Hypr.monitorFor(screen) : Hypr.focusedMonitor);
@ -86,14 +90,14 @@ ColumnLayout {
Hypr.dispatch(`togglespecialworkspace ${specialWs.slice(8)}`);
else if (angleDelta.y < 0 || (GlobalConfig.bar.workspaces.perMonitorWorkspaces ? mon.activeWorkspace?.id : Hypr.activeWsId) > 1)
Hypr.dispatch(`workspace r${angleDelta.y > 0 ? "-" : "+"}1`);
} else if (y < screen.height / 2 && Config.bar.scrollActions.volume) {
// Volume scroll on top half
} else if (x < screen.width / 2 && Config.bar.scrollActions.volume) {
// Volume scroll on left half
if (angleDelta.y > 0)
Audio.incrementVolume();
else if (angleDelta.y < 0)
Audio.decrementVolume();
} else if (Config.bar.scrollActions.brightness) {
// Brightness scroll on bottom half
// Brightness scroll on right half
const monitor = Brightness.getMonitorForScreen(screen);
if (angleDelta.y > 0)
monitor.setBrightness(monitor.brightness + GlobalConfig.services.brightnessIncrement);
@ -115,7 +119,7 @@ ColumnLayout {
DelegateChoice {
roleValue: "spacer"
delegate: WrappedLoader {
Layout.fillHeight: enabled
Layout.fillWidth: enabled
}
}
DelegateChoice {
@ -201,11 +205,11 @@ ColumnLayout {
}
asynchronous: true
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
// Cursed ahh thing to add padding to first and last enabled components
Layout.topMargin: findFirstEnabled() === this ? root.vPadding : 0
Layout.bottomMargin: findLastEnabled() === this ? root.vPadding : 0
Layout.leftMargin: findFirstEnabled() === this ? root.hPadding : 0
Layout.rightMargin: findLastEnabled() === this ? root.hPadding : 0
visible: enabled
active: enabled

View file

@ -17,10 +17,13 @@ Item {
readonly property bool disabled: Strings.testRegexList(Config.bar.excludedScreens, screen.name)
readonly property int clampedWidth: Math.max(Config.border.minThickness, implicitWidth)
// NoSignal horizontal top bar: the bar's "thickness" is its HEIGHT (was width
// for the upstream vertical left-edge bar). clampedHeight/contentHeight and
// implicitHeight carry the thickness; the wrapper fills the screen width.
readonly property int clampedHeight: Math.max(Config.border.minThickness, implicitHeight)
readonly property int padding: Math.max(Tokens.padding.small, Config.border.thickness)
readonly property int contentWidth: Tokens.sizes.bar.innerWidth + padding * 2
readonly property int exclusiveZone: !disabled && (Config.bar.persistent || visibilities.bar) ? contentWidth : Config.border.thickness
readonly property int contentHeight: Tokens.sizes.bar.innerWidth + padding * 2
readonly property int exclusiveZone: !disabled && (Config.bar.persistent || visibilities.bar) ? contentHeight : Config.border.thickness
readonly property bool shouldBeVisible: !fullscreen && !disabled && (Config.bar.persistent || visibilities.bar || isHovered)
property bool isHovered
@ -28,24 +31,24 @@ Item {
(content.item as Bar)?.closeTray();
}
function checkPopout(y: real): void {
(content.item as Bar)?.checkPopout(y);
function checkPopout(x: real): void {
(content.item as Bar)?.checkPopout(x);
}
function handleWheel(y: real, angleDelta: point): void {
(content.item as Bar)?.handleWheel(y, angleDelta);
function handleWheel(x: real, angleDelta: point): void {
(content.item as Bar)?.handleWheel(x, angleDelta);
}
clip: true
visible: width > Config.border.thickness
implicitWidth: fullscreen ? 0 : Config.border.thickness
visible: height > Config.border.thickness
implicitHeight: fullscreen ? 0 : Config.border.thickness
states: State {
name: "visible"
when: root.shouldBeVisible
PropertyChanges {
root.implicitWidth: root.contentWidth
root.implicitHeight: root.contentHeight
}
}
@ -56,7 +59,7 @@ Item {
Anim {
target: root
property: "implicitWidth"
property: "implicitHeight"
}
},
Transition {
@ -65,7 +68,7 @@ Item {
Anim {
target: root
property: "implicitWidth"
property: "implicitHeight"
type: Anim.Emphasized
}
}
@ -74,14 +77,14 @@ Item {
Loader {
id: content
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
active: root.shouldBeVisible
sourceComponent: Bar {
width: root.contentWidth
height: root.contentHeight
screen: root.screen
visibilities: root.visibilities
popouts: root.popouts // qmllint disable incompatible-type

View file

@ -13,20 +13,20 @@ StyledRect {
readonly property int padding: Config.bar.clock.background ? Tokens.padding.medium : Tokens.padding.extraSmall
readonly property var font: Tokens.font.body.builders.small.scale(1.1)
implicitWidth: Tokens.sizes.bar.innerWidth
implicitHeight: layout.implicitHeight + root.padding * 2
implicitHeight: Tokens.sizes.bar.innerWidth
implicitWidth: layout.implicitWidth + root.padding * 2
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, Config.bar.clock.background ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Tokens.rounding.full
ColumnLayout {
RowLayout {
id: layout
anchors.centerIn: parent
spacing: Tokens.spacing.small
Loader {
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
asynchronous: true
active: Config.bar.clock.showIcon
visible: active
@ -38,24 +38,26 @@ StyledRect {
}
StyledText {
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
visible: Config.bar.clock.showDate
horizontalAlignment: StyledText.AlignHCenter
text: Time.format("ddd\nd")
text: Time.format("ddd d")
font: Tokens.font.body.small
color: root.colour
}
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.topMargin: root.padding
Layout.bottomMargin: root.padding
visible: Config.bar.clock.showDate
implicitHeight: 1
implicitWidth: 1
color: Colours.palette.m3outlineVariant
}
StyledText {
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
text: Time.hourStr
font: {
const scale = text === "11" ? 1.15 : Math.min(1.05, Math.max(hourMetrics.width, minMetrics.width) / hourMetrics.width);
@ -72,8 +74,14 @@ StyledRect {
}
StyledText {
Layout.topMargin: -parent.spacing - 4
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
text: ":"
font: root.font.build()
color: root.colour
}
StyledText {
Layout.alignment: Qt.AlignVCenter
text: Time.minuteStr
font: {
const scale = text === "11" ? 1.15 : Math.min(1.05, Math.max(hourMetrics.width, minMetrics.width) / minMetrics.width);
@ -90,8 +98,7 @@ StyledRect {
}
Loader {
Layout.topMargin: -parent.spacing - 4
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
asynchronous: true
active: GlobalConfig.services.useTwelveHourClock
visible: active

View file

@ -20,16 +20,13 @@ StyledRect {
radius: Tokens.rounding.full
clip: true
implicitWidth: Tokens.sizes.bar.innerWidth
implicitHeight: iconColumn.implicitHeight + Tokens.padding.medium * 2 - (Config.bar.status.showLockStatus && !Hypr.capsLock && !Hypr.numLock ? iconColumn.spacing : 0)
implicitHeight: Tokens.sizes.bar.innerWidth
implicitWidth: iconColumn.implicitWidth + Tokens.padding.medium * 2 - (Config.bar.status.showLockStatus && !Hypr.capsLock && !Hypr.numLock ? iconColumn.spacing : 0)
ColumnLayout {
RowLayout {
id: iconColumn
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
anchors.bottomMargin: Tokens.padding.medium
anchors.centerIn: parent
spacing: Tokens.spacing.medium / 2
@ -261,7 +258,7 @@ StyledRect {
required property string name
asynchronous: true
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
visible: active
}
}

View file

@ -19,27 +19,27 @@ StyledRect {
property bool expanded
readonly property real nonAnimHeight: {
readonly property real nonAnimWidth: {
if (!Config.bar.tray.compact)
return layout.implicitHeight + padding * 2;
return (expanded ? expandIcon.implicitHeight + layout.implicitHeight + spacing : expandIcon.implicitHeight) + padding * 2;
return layout.implicitWidth + padding * 2;
return (expanded ? expandIcon.implicitWidth + layout.implicitWidth + spacing : expandIcon.implicitWidth) + padding * 2;
}
clip: true
visible: height > 0
visible: width > 0
implicitWidth: Tokens.sizes.bar.innerWidth
implicitHeight: nonAnimHeight
implicitHeight: Tokens.sizes.bar.innerWidth
implicitWidth: nonAnimWidth
color: Qt.alpha(Colours.tPalette.m3surfaceContainer, (Config.bar.tray.background && items.count > 0) ? Colours.tPalette.m3surfaceContainer.a : 0)
radius: Tokens.rounding.full
Column {
Row {
id: layout
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: root.padding
anchors.verticalCenter: parent.verticalCenter
anchors.left: parent.left
anchors.leftMargin: root.padding
spacing: Tokens.spacing.small
opacity: root.expanded || !Config.bar.tray.compact ? 1 : 0
@ -86,37 +86,37 @@ StyledRect {
asynchronous: true
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
active: Config.bar.tray.compact && items.count > 0
sourceComponent: Item {
implicitWidth: expandIconInner.implicitWidth
implicitHeight: expandIconInner.implicitHeight - Tokens.padding.small
implicitHeight: expandIconInner.implicitHeight
implicitWidth: expandIconInner.implicitWidth - Tokens.padding.small
MaterialIcon {
id: expandIconInner
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: parent.bottom
anchors.bottomMargin: Config.bar.tray.background ? Tokens.padding.extraSmall : -Tokens.padding.extraSmall
anchors.verticalCenter: parent.verticalCenter
anchors.right: parent.right
anchors.rightMargin: Config.bar.tray.background ? Tokens.padding.extraSmall : -Tokens.padding.extraSmall
text: "expand_less"
fontStyle: Tokens.font.icon.large
rotation: root.expanded ? 180 : 0
rotation: root.expanded ? 270 : 90
Behavior on rotation {
Anim {}
}
Behavior on anchors.bottomMargin {
Behavior on anchors.rightMargin {
Anim {}
}
}
}
}
Behavior on implicitHeight {
Behavior on implicitWidth {
Anim {}
}
}

View file

@ -24,7 +24,7 @@ ColumnLayout {
readonly property bool isOccupied: occupied[ws] ?? false
readonly property bool hasWindows: isOccupied && Config.bar.workspaces.showWindows
Layout.alignment: Qt.AlignHCenter
Layout.alignment: Qt.AlignVCenter
Layout.preferredHeight: size
spacing: 0

View file

@ -27,8 +27,8 @@ StyledClippingRect {
property real blur: onSpecial ? 1 : 0
implicitWidth: Tokens.sizes.bar.innerWidth
implicitHeight: layout.implicitHeight + Tokens.padding.small
implicitHeight: Tokens.sizes.bar.innerWidth
implicitWidth: layout.implicitWidth + Tokens.padding.small
color: Colours.tPalette.m3surfaceContainer
radius: Tokens.rounding.full
@ -60,7 +60,7 @@ StyledClippingRect {
}
}
ColumnLayout {
RowLayout {
id: layout
anchors.centerIn: parent
@ -81,7 +81,7 @@ StyledClippingRect {
Loader {
asynchronous: true
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
active: Config.bar.workspaces.activeIndicator
sourceComponent: ActiveIndicator {

View file

@ -85,14 +85,14 @@ StyledWindow {
Region {
id: emptyRegion
x: panels.notifications.x + bar.implicitWidth
y: panels.notifications.y + root.borderThickness
x: panels.notifications.x + root.borderThickness
y: panels.notifications.y + bar.implicitHeight
width: panels.notifications.width
height: panels.notifications.height
Region {
x: root.width - width
y: panels.osdWrapper.y + root.borderThickness
y: panels.osdWrapper.y + bar.implicitHeight
width: panels.osdWrapper.width * (1 - panels.osd.offsetScale) + root.borderThickness
height: panels.osd.height
}
@ -155,9 +155,9 @@ StyledWindow {
anchors.margins: -50 // Make border thicker to smooth out bulge from closed drawers
group: blobGroup
radius: root.borderRounding
borderLeft: bar.implicitWidth - anchors.margins - root.sdfBorderOffset
borderLeft: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderRight: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderTop: root.borderThickness - anchors.margins - root.sdfBorderOffset
borderTop: bar.implicitHeight - anchors.margins - root.sdfBorderOffset
borderBottom: root.borderThickness - anchors.margins - root.sdfBorderOffset
}
@ -180,7 +180,7 @@ StyledWindow {
panel: panels.sessionWrapper
deformAmount: 0.2
x: panels.sessionWrapper.x + panels.session.x + bar.implicitWidth
x: panels.sessionWrapper.x + panels.session.x + root.borderThickness
implicitWidth: panels.session.width
}
@ -199,7 +199,7 @@ StyledWindow {
panel: panels.osdWrapper
deformAmount: 0.25
x: panels.osdWrapper.x + panels.osd.x + bar.implicitWidth
x: panels.osdWrapper.x + panels.osd.x + root.borderThickness
implicitWidth: panels.osd.width
}
@ -226,7 +226,7 @@ StyledWindow {
panel: panels.popoutsWrapper
deformAmount: panels.popouts.isDetached ? 0.05 : panels.popouts.hasCurrent ? 0.15 : 0.1
x: panels.popoutsWrapper.x + panels.popouts.x + bar.implicitWidth - panels.popouts.width * extraWidth
x: panels.popoutsWrapper.x + panels.popouts.x + root.borderThickness - panels.popouts.width * extraWidth
implicitWidth: panels.popouts.width * (1 + extraWidth)
Behavior on extraWidth {
@ -292,8 +292,9 @@ StyledWindow {
BarWrapper {
id: bar
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
screen: root.screen
visibilities: visibilities
@ -310,8 +311,8 @@ StyledWindow {
property real deformAmount: 0.15
group: blobGroup
x: panel.x + bar.implicitWidth
y: panel.y + root.borderThickness
x: panel.x + root.borderThickness
y: panel.y + bar.implicitHeight
implicitWidth: panel.width
implicitHeight: panel.height
radius: Tokens.rounding.extraLarge

View file

@ -14,11 +14,11 @@ Scope {
ExclusionZone {
anchors.left: true
exclusiveZone: root.bar.exclusiveZone
}
ExclusionZone {
anchors.top: true
exclusiveZone: root.bar.exclusiveZone
}
ExclusionZone {

View file

@ -23,27 +23,29 @@ CustomMouseArea {
property bool osdShortcutActive
property bool utilitiesShortcutActive
// NoSignal top bar: the bar's thickness now insets the TOP, so panel Y-origins
// are offset by bar.implicitHeight; the left inset is just the border thickness.
function withinPanelHeight(panel: Item, x: real, y: real): bool {
const panelY = root.borderThickness + panel.y;
const panelY = root.bar.implicitHeight + panel.y;
return y >= panelY - Config.border.rounding && y <= panelY + panel.height + Config.border.rounding;
}
function withinPanelWidth(panel: Item, x: real, y: real): bool {
const panelX = bar.implicitWidth + panel.x;
const panelX = root.borderThickness + panel.x;
return x >= panelX - Config.border.rounding && x <= panelX + panel.width + Config.border.rounding;
}
function inLeftPanel(panel: Item, x: real, y: real): bool {
return x < bar.implicitWidth + panel.x + panel.width && withinPanelHeight(panel, x, y);
return x < root.borderThickness + panel.x + panel.width && withinPanelHeight(panel, x, y);
}
function inRightPanel(panel: Item, x: real, y: real): bool {
return x > Math.min(width - Config.border.minThickness, bar.implicitWidth + panel.x) && withinPanelHeight(panel, x, y);
return x > Math.min(width - Config.border.minThickness, root.borderThickness + panel.x) && withinPanelHeight(panel, x, y);
}
function inTopPanel(panel: Item, x: real, y: real): bool {
const panelHeight = panel.height * (1 - (panel.offsetScale ?? 0)); // qmllint disable missing-property
return y < Math.max(Config.border.minThickness, Config.border.thickness + panelHeight) && withinPanelWidth(panel, x, y);
return y < Math.max(Config.border.minThickness, root.bar.implicitHeight + panelHeight) && withinPanelWidth(panel, x, y);
}
function inBottomPanel(panel: Item, x: real, y: real, isCorner = false): bool {
@ -54,8 +56,8 @@ CustomMouseArea {
function onWheel(event: WheelEvent): void {
if (fullscreen)
return;
if (event.x < bar.implicitWidth) {
bar.handleWheel(event.y, event.angleDelta);
if (event.y < bar.implicitHeight) {
bar.handleWheel(event.x, event.angleDelta);
}
}
@ -102,15 +104,15 @@ CustomMouseArea {
return;
}
// Show bar in non-exclusive mode on hover
if (!visibilities.bar && Config.bar.showOnHover && x < bar.clampedWidth)
// Show bar in non-exclusive mode on hover (top edge)
if (!visibilities.bar && Config.bar.showOnHover && y < bar.clampedHeight)
bar.isHovered = true;
// Show/hide bar on drag
if (pressed && dragStart.x < bar.clampedWidth) {
if (dragX > Config.bar.dragThreshold)
// Show/hide bar on drag (vertical, from the top edge)
if (pressed && dragStart.y < bar.clampedHeight) {
if (dragY > Config.bar.dragThreshold)
visibilities.bar = true;
else if (dragX < -Config.bar.dragThreshold)
else if (dragY < -Config.bar.dragThreshold)
visibilities.bar = false;
}
@ -128,7 +130,7 @@ CustomMouseArea {
root.panels.osd.hovered = true;
}
const showSidebar = pressed && dragStart.x > Math.min(width - Config.border.minThickness, bar.implicitWidth + panels.sidebar.x);
const showSidebar = pressed && dragStart.x > Math.min(width - Config.border.minThickness, root.borderThickness + panels.sidebar.x);
// Show/hide session on drag
if (pressed && inRightPanel(panels.sessionWrapper, dragStart.x, dragStart.y) && withinPanelHeight(panels.sessionWrapper, x, y)) {
@ -213,9 +215,9 @@ CustomMouseArea {
utilitiesShortcutActive = false;
}
// Show popouts on hover
if (x < bar.implicitWidth) {
bar.checkPopout(y);
// Show popouts on hover (top bar)
if (y < bar.implicitHeight) {
bar.checkPopout(x);
} else if ((!popouts.currentName.startsWith("traymenu") || ((popouts.current as StackView)?.depth ?? 0) <= 1) && !inLeftPanel(panels.popoutsWrapper, x, y)) {
popouts.hasCurrent = false;
bar.closeTray();

View file

@ -36,7 +36,7 @@ Item {
anchors.fill: parent
anchors.margins: borderThickness
anchors.leftMargin: bar.implicitWidth
anchors.topMargin: bar.implicitHeight
Item {
id: osdWrapper

View file

@ -15,10 +15,10 @@ Region {
readonly property real borderThickness: win.contentItem.Config.border.thickness
readonly property real clampedThickness: win.contentItem.Config.border.clampedThickness
x: bar.clampedWidth + win.dragMaskPadding
y: clampedThickness + win.dragMaskPadding
width: win.width - bar.clampedWidth - clampedThickness - win.dragMaskPadding * 2
height: win.height - clampedThickness * 2 - win.dragMaskPadding * 2
x: clampedThickness + win.dragMaskPadding
y: bar.clampedHeight + win.dragMaskPadding
width: win.width - clampedThickness * 2 - win.dragMaskPadding * 2
height: win.height - bar.clampedHeight - clampedThickness - win.dragMaskPadding * 2
intersection: Intersection.Xor
R {
@ -75,8 +75,8 @@ Region {
component R: Region {
required property Item panel
x: panel.x + root.bar.implicitWidth
y: panel.y + root.borderThickness
x: panel.x + root.borderThickness
y: panel.y + root.bar.implicitHeight
width: panel.width
height: panel.height
intersection: Intersection.Subtract