Files
z-bar-qt/Modules/Bar/Bar.qml
T
zach c5608dc9b9
C++ / fmt (pull_request) Failing after 5s
C++ / build (pull_request) Failing after 10s
C++ / clang-tidy (pull_request) Failing after 10s
JS/TS / fmt (pull_request) Successful in 9s
JS/TS / lint (pull_request) Successful in 25s
Python / static (pull_request) Successful in 34s
Rust / build (pull_request) Successful in 51s
Python / verify (pull_request) Failing after 1m25s
Rust / fmt (pull_request) Successful in 39s
Rust / clippy (pull_request) Successful in 59s
fix: blobs now allow to be drawn in device pixels to stay sharp
2026-10-30 01:52:33 +01:00

296 lines
7.1 KiB
QML

pragma ComponentBehavior: Bound
import Quickshell
import QtQuick
import QtQuick.Layouts
import ZShell.Config
import ZShell.Components
import qs.Components
import qs.Modules.Bar.Components
import qs.Modules.Bar.Popouts
import ZShell
SnapLayout {
id: root
required property bool fullscreen
required property bool horizontal
required property bool isHovered
required property Wrapper popouts
required property ClipWrapper popoutsWrapper
required property ShellScreen screen
required property ScreenState screenState
readonly property int vPadding: 6
function axisCenterOf(item: Item): real {
const c = item.mapToItem(root, item.implicitWidth / 2, item.implicitHeight / 2);
return horizontal ? ZUtils.snap(c.x, item) : ZUtils.snap(c.y, item);
}
function checkPopout(pos: real): void {
const ch = (horizontal ? childAt(pos, height / 2) : childAt(width / 2, pos)) as EntryWrapper;
const id = ch?.entryId;
if (!ch || id === undefined) {
if (!popouts.currentName.startsWith("traymenu") || Config.bar.tray.showOnHover)
popouts.hasCurrent = false;
return;
}
if (screenState.sidebar || screenState.dashboard || screenState.resources || screenState.settings)
return;
if (id === "statusIcons" && Config.bar.popouts.statusIcons) {
const items = (ch.item as StatusIcons).items;
const icon = horizontal ? items.childAt(mapToItem(items, pos, 0).x, items.height / 2) : items.childAt(items.width / 2, mapToItem(items, 0, pos).y);
if (icon) {
popouts.currentName = icon.name;
popouts.currentCenter = Qt.binding(() => axisCenterOf(icon));
popouts.hasCurrent = true;
}
} else if (id === "tray" && Config.bar.popouts.tray && Config.bar.tray.showOnHover) {
const tray = ch.item as TrayIcons;
const layout = tray.layout;
const trayItem = horizontal ? layout.childAt(mapToItem(layout, pos, 0).x, layout.height / 2) : layout.childAt(tray.width / 2, mapToItem(layout, 0, pos).y);
if (trayItem) {
const idx = trayItem.index;
popouts.currentName = `traymenu${idx}`;
popouts.currentCenter = Qt.binding(() => axisCenterOf(trayItem));
popouts.hasCurrent = true;
}
if (!popouts.currentName.startsWith("traymenu"))
popouts.hasCurrent = false;
}
if (id === "updates") {
popouts.currentName = "updates";
popouts.currentCenter = Qt.binding(() => axisCenterOf(ch.item as Item));
popouts.hasCurrent = true;
}
}
function entryAt(pos: real): string {
const ch = (horizontal ? childAt(pos, height / 2) : childAt(width / 2, pos)) as EntryWrapper;
return ch?.entryId ?? "";
}
readonly property var sectionRects: {
const count = repeater.count; // dependency: re-run when items are added/removed
const names = ["start", "middle", "end"]; // constant ids by position
const bounds = [null];
let spacers = 0;
for (let i = 0; i < count; i++) {
const it = repeater.itemAt(i) as EntryWrapper;
if (!it)
continue;
if (it.entryId === "spacer") {
bounds.push(null);
spacers++;
continue;
}
const l = it.x, t = it.y, r = it.x + it.width, b = it.y + it.height;
const cur = bounds[spacers];
bounds[spacers] = cur ? {
l: Math.min(cur.l, l),
t: Math.min(cur.t, t),
r: Math.max(cur.r, r),
b: Math.max(cur.b, b)
} : {
l,
t,
r,
b
};
}
return bounds.map((c, n) => ({
id: names[n] ?? `section${n}`,
rect: c ? Qt.rect(c.l, c.t, c.r - c.l, c.b - c.t) : Qt.rect(0, 0, 0, 0)
}));
}
spacing: Tokens.spacing.small
orientation: horizontal ? Qt.Horizontal : Qt.Vertical
Repeater {
id: repeater
model: ScriptModel {
values: Config.bar.entries.values.filter(e => e.enabled)
}
DelegateChooser {
role: "id"
DelegateChoice {
roleValue: "nightlight"
delegate: EntryWrapper {
NightlightWidget {
horizontal: root.horizontal
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "spacer"
delegate: EntryWrapper {
Layout.fillHeight: !root.horizontal
Layout.fillWidth: root.horizontal
}
}
DelegateChoice {
roleValue: "workspaces"
delegate: EntryWrapper {
Workspaces {
horizontal: root.horizontal
screen: root.screen
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "tray"
delegate: EntryWrapper {
TrayIcons {
horizontal: root.horizontal
loader: root
popouts: root.popouts
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "statusIcons"
delegate: EntryWrapper {
StatusIcons {
horizontal: root.horizontal
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "resources"
delegate: EntryWrapper {
Resources {
horizontal: root.horizontal
screenState: root.screenState
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "updates"
delegate: EntryWrapper {
UpdatesWidget {
horizontal: root.horizontal
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "notifBell"
delegate: EntryWrapper {
NotifBell {
horizontal: root.horizontal
popouts: root.popouts
screenState: root.screenState
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "clock"
delegate: EntryWrapper {
Clock {
horizontal: root.horizontal
loader: root
popouts: root.popouts
screenState: root.screenState
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "activeWindow"
delegate: EntryWrapper {
WindowTitle {
bar: root
horizontal: root.horizontal
visible: !root.fullscreen || root.isHovered
}
}
}
DelegateChoice {
roleValue: "network"
delegate: EntryWrapper {
NetworkWidget {}
}
}
DelegateChoice {
roleValue: "media"
delegate: EntryWrapper {
MediaWidget {
horizontal: root.horizontal
visible: !root.fullscreen || root.isHovered
}
}
}
}
}
component EntryWrapper: Item {
readonly property int section: {
let n = 0;
for (let i = 0; i < index; i++) {
if (repeater.model.values[i].id === "spacer")
n++;
}
return n;
}
readonly property string entryId: modelData.id
required property int index
required property var modelData
default property Item item
Layout.alignment: root.horizontal ? Qt.AlignVCenter : Qt.AlignHCenter
Layout.bottomMargin: !root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.leftMargin: root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0
Layout.rightMargin: root.horizontal && index === repeater.count - 1 ? root.vPadding : 0
Layout.topMargin: !root.horizontal && index === 0 ? root.vPadding : (entryId === "statusIcons" && !root.horizontal) ? -root.spacing + Tokens.spacing.extraSmall : 0
children: item
implicitHeight: item?.implicitHeight ?? 0
implicitWidth: item?.implicitWidth ?? 0
}
}