bar: allow hiding items and reordering (#379)
* feat: reorder bar, no popout yet * chore: cleanup * refactor: use DelegateChooser * feat: popouts * chore: cleanup * better popout check + fix async stuff + bar interaction + a bunch of other fixes * fix activewindow and bar vertical padding * readme: add config opt * bar: fix top/bottom padding * bar: better wheel behaviour --------- Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com>
This commit is contained in:
parent
e34953f595
commit
3710df29f5
11 changed files with 381 additions and 320 deletions
38
README.md
38
README.md
|
|
@ -198,6 +198,44 @@ All configuration options are in `~/.config/caelestia/shell.json`.
|
||||||
},
|
},
|
||||||
"bar": {
|
"bar": {
|
||||||
"dragThreshold": 20,
|
"dragThreshold": 20,
|
||||||
|
"entries": [
|
||||||
|
{
|
||||||
|
"id": "logo",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "workspaces",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "spacer",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "activeWindow",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "spacer",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "tray",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "clock",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "statusIcons",
|
||||||
|
"enabled": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "power",
|
||||||
|
"enabled": true
|
||||||
|
}
|
||||||
|
],
|
||||||
"persistent": true,
|
"persistent": true,
|
||||||
"showOnHover": true,
|
"showOnHover": true,
|
||||||
"status": {
|
"status": {
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,45 @@ JsonObject {
|
||||||
property Status status: Status {}
|
property Status status: Status {}
|
||||||
property Sizes sizes: Sizes {}
|
property Sizes sizes: Sizes {}
|
||||||
|
|
||||||
|
property list<var> entries: [
|
||||||
|
{
|
||||||
|
id: "logo",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "workspaces",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "spacer",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "activeWindow",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "spacer",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "tray",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "clock",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "statusIcons",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "power",
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
component Workspaces: JsonObject {
|
component Workspaces: JsonObject {
|
||||||
property int shown: 5
|
property int shown: 5
|
||||||
property bool rounded: true
|
property bool rounded: true
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import qs.components
|
pragma ComponentBehavior: Bound
|
||||||
import qs.components.controls
|
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
import "popouts" as BarPopouts
|
import "popouts" as BarPopouts
|
||||||
|
|
@ -7,170 +7,176 @@ import "components"
|
||||||
import "components/workspaces"
|
import "components/workspaces"
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import QtQuick
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
ColumnLayout {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property ShellScreen screen
|
required property ShellScreen screen
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
required property BarPopouts.Wrapper popouts
|
required property BarPopouts.Wrapper popouts
|
||||||
|
readonly property int padding: Math.max(Appearance.padding.smaller, Config.border.thickness)
|
||||||
|
readonly property int vPadding: Appearance.padding.large
|
||||||
|
|
||||||
function checkPopout(y: real): void {
|
function checkPopout(y: real): void {
|
||||||
const spacing = Appearance.spacing.small;
|
const ch = childAt(width / 2, y) as WrappedLoader;
|
||||||
const aw = activeWindow.child;
|
if (!ch) {
|
||||||
const awy = activeWindow.y + aw.y;
|
|
||||||
|
|
||||||
const ty = tray.y;
|
|
||||||
const th = tray.implicitHeight;
|
|
||||||
const trayItems = tray.items;
|
|
||||||
|
|
||||||
// Check status icons hover areas
|
|
||||||
let statusIconFound = false;
|
|
||||||
for (const area of statusIconsInner.hoverAreas) {
|
|
||||||
if (!area.enabled)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const item = area.item;
|
|
||||||
const itemY = statusIcons.y + statusIconsInner.y + item.y - spacing / 2;
|
|
||||||
const itemHeight = item.implicitHeight + spacing;
|
|
||||||
|
|
||||||
if (y >= itemY && y <= itemY + itemHeight) {
|
|
||||||
popouts.currentName = area.name;
|
|
||||||
popouts.currentCenter = Qt.binding(() => statusIcons.y + statusIconsInner.y + item.y + item.implicitHeight / 2);
|
|
||||||
popouts.hasCurrent = true;
|
|
||||||
statusIconFound = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (y >= awy && y <= awy + aw.implicitHeight) {
|
|
||||||
popouts.currentName = "activewindow";
|
|
||||||
popouts.currentCenter = Qt.binding(() => activeWindow.y + aw.y + aw.implicitHeight / 2);
|
|
||||||
popouts.hasCurrent = true;
|
|
||||||
} else if (y > ty && y < ty + th) {
|
|
||||||
const index = Math.floor(((y - ty) / th) * trayItems.count);
|
|
||||||
const item = trayItems.itemAt(index);
|
|
||||||
|
|
||||||
popouts.currentName = `traymenu${index}`;
|
|
||||||
popouts.currentCenter = Qt.binding(() => tray.y + item.y + item.implicitHeight / 2);
|
|
||||||
popouts.hasCurrent = true;
|
|
||||||
} else if (!statusIconFound) {
|
|
||||||
popouts.hasCurrent = false;
|
popouts.hasCurrent = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const id = ch.id;
|
||||||
|
const top = ch.y;
|
||||||
|
const item = ch.item;
|
||||||
|
const itemHeight = item.implicitHeight;
|
||||||
|
|
||||||
|
if (id === "statusIcons") {
|
||||||
|
const items = item.items;
|
||||||
|
const icon = items.childAt(items.width / 2, mapToItem(items, 0, y).y);
|
||||||
|
if (icon) {
|
||||||
|
popouts.currentName = icon.name;
|
||||||
|
popouts.currentCenter = Qt.binding(() => icon.mapToItem(root, 0, icon.implicitHeight / 2).y);
|
||||||
|
popouts.hasCurrent = true;
|
||||||
|
}
|
||||||
|
} else if (id === "tray") {
|
||||||
|
const index = Math.floor(((y - top) / itemHeight) * item.items.count);
|
||||||
|
const trayItem = item.items.itemAt(index);
|
||||||
|
if (trayItem) {
|
||||||
|
popouts.currentName = `traymenu${index}`;
|
||||||
|
popouts.currentCenter = Qt.binding(() => trayItem.mapToItem(root, 0, trayItem.implicitHeight / 2).y);
|
||||||
|
popouts.hasCurrent = true;
|
||||||
|
}
|
||||||
|
} else if (id === "activeWindow") {
|
||||||
|
popouts.currentName = id.toLowerCase();
|
||||||
|
popouts.currentCenter = item.mapToItem(root, 0, itemHeight / 2).y;
|
||||||
|
popouts.hasCurrent = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
anchors.top: parent.top
|
function handleWheel(y: real, angleDelta: point): void {
|
||||||
anchors.bottom: parent.bottom
|
const ch = childAt(width / 2, y) as WrappedLoader;
|
||||||
anchors.left: parent.left
|
if (ch?.id === "workspaces") {
|
||||||
|
// Workspace scroll
|
||||||
implicitWidth: child.implicitWidth + Math.max(Appearance.padding.smaller, Config.border.thickness) * 2
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: child
|
|
||||||
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
implicitWidth: Math.max(osIcon.implicitWidth, workspaces.implicitWidth, activeWindow.implicitWidth, tray.implicitWidth, clock.implicitWidth, statusIcons.implicitWidth, power.implicitWidth)
|
|
||||||
|
|
||||||
OsIcon {
|
|
||||||
id: osIcon
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.topMargin: Appearance.padding.large
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
id: workspaces
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.top: osIcon.bottom
|
|
||||||
anchors.topMargin: Appearance.spacing.normal
|
|
||||||
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
|
|
||||||
implicitWidth: workspacesInner.implicitWidth + Appearance.padding.small * 2
|
|
||||||
implicitHeight: workspacesInner.implicitHeight + Appearance.padding.small * 2
|
|
||||||
|
|
||||||
CustomMouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.leftMargin: -Math.max(Appearance.padding.smaller, Config.border.thickness)
|
|
||||||
anchors.rightMargin: -Math.max(Appearance.padding.smaller, Config.border.thickness)
|
|
||||||
|
|
||||||
function onWheel(event: WheelEvent): void {
|
|
||||||
const activeWs = Hyprland.activeToplevel?.workspace?.name;
|
const activeWs = Hyprland.activeToplevel?.workspace?.name;
|
||||||
if (activeWs?.startsWith("special:"))
|
if (activeWs?.startsWith("special:"))
|
||||||
Hyprland.dispatch(`togglespecialworkspace ${activeWs.slice(8)}`);
|
Hyprland.dispatch(`togglespecialworkspace ${activeWs.slice(8)}`);
|
||||||
else if (event.angleDelta.y < 0 || Hyprland.activeWsId > 1)
|
else if (angleDelta.y < 0 || Hyprland.activeWsId > 1)
|
||||||
Hyprland.dispatch(`workspace r${event.angleDelta.y > 0 ? "-" : "+"}1`);
|
Hyprland.dispatch(`workspace r${angleDelta.y > 0 ? "-" : "+"}1`);
|
||||||
|
} else if (y < screen.height / 2) {
|
||||||
|
// Volume scroll on top half
|
||||||
|
if (angleDelta.y > 0)
|
||||||
|
Audio.incrementVolume();
|
||||||
|
else if (angleDelta.y < 0)
|
||||||
|
Audio.decrementVolume();
|
||||||
|
} else {
|
||||||
|
// Brightness scroll on bottom half
|
||||||
|
const monitor = Brightness.getMonitorForScreen(screen);
|
||||||
|
if (angleDelta.y > 0)
|
||||||
|
monitor.setBrightness(monitor.brightness + 0.1);
|
||||||
|
else if (angleDelta.y < 0)
|
||||||
|
monitor.setBrightness(monitor.brightness - 0.1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Workspaces {
|
spacing: Appearance.spacing.normal
|
||||||
id: workspacesInner
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
Repeater {
|
||||||
|
id: repeater
|
||||||
|
|
||||||
|
model: Config.bar.entries
|
||||||
|
|
||||||
|
DelegateChooser {
|
||||||
|
role: "id"
|
||||||
|
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "spacer"
|
||||||
|
delegate: WrappedLoader {
|
||||||
|
Layout.fillHeight: enabled
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DelegateChoice {
|
||||||
ActiveWindow {
|
roleValue: "logo"
|
||||||
id: activeWindow
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: OsIcon {}
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
}
|
||||||
anchors.top: workspaces.bottom
|
}
|
||||||
anchors.bottom: tray.top
|
DelegateChoice {
|
||||||
anchors.margins: Appearance.spacing.large
|
roleValue: "workspaces"
|
||||||
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: Workspaces {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "activeWindow"
|
||||||
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: ActiveWindow {
|
||||||
|
bar: root
|
||||||
monitor: Brightness.getMonitorForScreen(root.screen)
|
monitor: Brightness.getMonitorForScreen(root.screen)
|
||||||
}
|
}
|
||||||
|
|
||||||
Tray {
|
|
||||||
id: tray
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.bottom: clock.top
|
|
||||||
anchors.bottomMargin: Appearance.spacing.larger
|
|
||||||
}
|
|
||||||
|
|
||||||
Clock {
|
|
||||||
id: clock
|
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
anchors.bottom: statusIcons.top
|
|
||||||
anchors.bottomMargin: Appearance.spacing.normal
|
|
||||||
}
|
|
||||||
|
|
||||||
StyledRect {
|
|
||||||
id: statusIcons
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: power.top
|
|
||||||
anchors.bottomMargin: Appearance.spacing.normal
|
|
||||||
|
|
||||||
radius: Appearance.rounding.full
|
|
||||||
color: Colours.tPalette.m3surfaceContainer
|
|
||||||
|
|
||||||
implicitHeight: statusIconsInner.implicitHeight + Appearance.padding.normal * 2
|
|
||||||
|
|
||||||
StatusIcons {
|
|
||||||
id: statusIconsInner
|
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DelegateChoice {
|
||||||
Power {
|
roleValue: "tray"
|
||||||
id: power
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: Tray {}
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
}
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
anchors.bottomMargin: Appearance.padding.large
|
DelegateChoice {
|
||||||
|
roleValue: "clock"
|
||||||
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: Clock {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "statusIcons"
|
||||||
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: StatusIcons {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DelegateChoice {
|
||||||
|
roleValue: "power"
|
||||||
|
delegate: WrappedLoader {
|
||||||
|
sourceComponent: Power {
|
||||||
visibilities: root.visibilities
|
visibilities: root.visibilities
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
component WrappedLoader: Loader {
|
||||||
|
required property bool enabled
|
||||||
|
required property string id
|
||||||
|
required property int index
|
||||||
|
|
||||||
|
function findFirstEnabled(): Item {
|
||||||
|
const count = repeater.count;
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
|
const item = repeater.itemAt(i);
|
||||||
|
if (item?.enabled)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findLastEnabled(): Item {
|
||||||
|
for (let i = repeater.count - 1; i >= 0; i--) {
|
||||||
|
const item = repeater.itemAt(i);
|
||||||
|
if (item?.enabled)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.leftMargin: root.padding
|
||||||
|
Layout.rightMargin: root.padding
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
visible: enabled
|
||||||
|
active: enabled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,19 +14,24 @@ Item {
|
||||||
required property BarPopouts.Wrapper popouts
|
required property BarPopouts.Wrapper popouts
|
||||||
|
|
||||||
readonly property int exclusiveZone: Config.bar.persistent || visibilities.bar ? content.implicitWidth : Config.border.thickness
|
readonly property int exclusiveZone: Config.bar.persistent || visibilities.bar ? content.implicitWidth : Config.border.thickness
|
||||||
|
readonly property bool shouldBeVisible: Config.bar.persistent || visibilities.bar || isHovered
|
||||||
property bool isHovered
|
property bool isHovered
|
||||||
|
|
||||||
function checkPopout(y: real): void {
|
function checkPopout(y: real): void {
|
||||||
content.item?.checkPopout(y);
|
content.item?.checkPopout(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleWheel(y: real, angleDelta: point): void {
|
||||||
|
content.item?.handleWheel(y, angleDelta);
|
||||||
|
}
|
||||||
|
|
||||||
visible: width > Config.border.thickness
|
visible: width > Config.border.thickness
|
||||||
implicitWidth: Config.border.thickness
|
implicitWidth: Config.border.thickness
|
||||||
implicitHeight: content.implicitHeight
|
implicitHeight: content.implicitHeight
|
||||||
|
|
||||||
states: State {
|
states: State {
|
||||||
name: "visible"
|
name: "visible"
|
||||||
when: Config.bar.persistent || root.visibilities.bar || root.isHovered
|
when: root.shouldBeVisible
|
||||||
|
|
||||||
PropertyChanges {
|
PropertyChanges {
|
||||||
root.implicitWidth: content.implicitWidth
|
root.implicitWidth: content.implicitWidth
|
||||||
|
|
@ -63,7 +68,7 @@ Item {
|
||||||
Loader {
|
Loader {
|
||||||
id: content
|
id: content
|
||||||
|
|
||||||
Component.onCompleted: active = Qt.binding(() => Config.bar.persistent || root.visibilities.bar || root.isHovered || root.visible)
|
Component.onCompleted: active = Qt.binding(() => root.shouldBeVisible || root.visible)
|
||||||
|
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
|
||||||
|
|
@ -9,19 +9,17 @@ import QtQuick
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
|
required property var bar
|
||||||
required property Brightness.Monitor monitor
|
required property Brightness.Monitor monitor
|
||||||
property color colour: Colours.palette.m3primary
|
property color colour: Colours.palette.m3primary
|
||||||
readonly property Item child: child
|
|
||||||
|
|
||||||
implicitWidth: child.implicitWidth
|
readonly property int maxHeight: {
|
||||||
implicitHeight: child.implicitHeight
|
const otherModules = bar.children.filter(c => c.id && c.item !== this && c.id !== "spacer");
|
||||||
|
const otherHeight = otherModules.reduce((acc, curr) => acc + curr.height, 0);
|
||||||
Item {
|
// Length - 2 cause repeater counts as a child
|
||||||
id: child
|
return bar.height - otherHeight - bar.spacing * (bar.children.length - 1) - bar.vPadding * 2;
|
||||||
|
}
|
||||||
property Item current: text1
|
property Title current: text1
|
||||||
|
|
||||||
anchors.centerIn: parent
|
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
implicitWidth: Math.max(icon.implicitWidth, current.implicitHeight)
|
implicitWidth: Math.max(icon.implicitWidth, current.implicitHeight)
|
||||||
|
|
@ -30,11 +28,11 @@ Item {
|
||||||
MaterialIcon {
|
MaterialIcon {
|
||||||
id: icon
|
id: icon
|
||||||
|
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
animate: true
|
animate: true
|
||||||
text: Icons.getAppCategoryIcon(Hyprland.activeToplevel?.lastIpcObject.class, "desktop_windows")
|
text: Icons.getAppCategoryIcon(Hyprland.activeToplevel?.lastIpcObject.class, "desktop_windows")
|
||||||
color: root.colour
|
color: root.colour
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Title {
|
Title {
|
||||||
|
|
@ -52,22 +50,14 @@ Item {
|
||||||
font.pointSize: Appearance.font.size.smaller
|
font.pointSize: Appearance.font.size.smaller
|
||||||
font.family: Appearance.font.family.mono
|
font.family: Appearance.font.family.mono
|
||||||
elide: Qt.ElideRight
|
elide: Qt.ElideRight
|
||||||
elideWidth: root.height - icon.height
|
elideWidth: root.maxHeight - icon.height
|
||||||
|
|
||||||
onTextChanged: {
|
onTextChanged: {
|
||||||
const next = child.current === text1 ? text2 : text1;
|
const next = root.current === text1 ? text2 : text1;
|
||||||
next.text = elidedText;
|
next.text = elidedText;
|
||||||
child.current = next;
|
root.current = next;
|
||||||
}
|
|
||||||
onElideWidthChanged: child.current.text = elidedText
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on implicitWidth {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Appearance.anim.durations.normal
|
|
||||||
easing.type: Easing.BezierSpline
|
|
||||||
easing.bezierCurve: Appearance.anim.curves.emphasized
|
|
||||||
}
|
}
|
||||||
|
onElideWidthChanged: root.current.text = elidedText
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on implicitHeight {
|
Behavior on implicitHeight {
|
||||||
|
|
@ -77,7 +67,6 @@ Item {
|
||||||
easing.bezierCurve: Appearance.anim.curves.emphasized
|
easing.bezierCurve: Appearance.anim.curves.emphasized
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
component Title: StyledText {
|
component Title: StyledText {
|
||||||
id: text
|
id: text
|
||||||
|
|
@ -89,7 +78,7 @@ Item {
|
||||||
font.pointSize: metrics.font.pointSize
|
font.pointSize: metrics.font.pointSize
|
||||||
font.family: metrics.font.family
|
font.family: metrics.font.family
|
||||||
color: root.colour
|
color: root.colour
|
||||||
opacity: child.current === this ? 1 : 0
|
opacity: root.current === this ? 1 : 0
|
||||||
|
|
||||||
transform: Rotation {
|
transform: Rotation {
|
||||||
angle: 90
|
angle: 90
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,22 @@ import qs.components
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
import Quickshell
|
import Quickshell
|
||||||
|
import QtQuick
|
||||||
|
|
||||||
MaterialIcon {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
required property PersistentProperties visibilities
|
required property PersistentProperties visibilities
|
||||||
|
|
||||||
text: "power_settings_new"
|
implicitWidth: icon.implicitHeight + Appearance.padding.small * 2
|
||||||
color: Colours.palette.m3error
|
implicitHeight: icon.implicitHeight
|
||||||
font.bold: true
|
|
||||||
font.pointSize: Appearance.font.size.normal
|
|
||||||
|
|
||||||
StateLayer {
|
StateLayer {
|
||||||
|
// Cursed workaround to make the height larger than the parent
|
||||||
anchors.fill: undefined
|
anchors.fill: undefined
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
anchors.horizontalCenterOffset: 1
|
implicitWidth: implicitHeight
|
||||||
|
implicitHeight: icon.implicitHeight + Appearance.padding.small * 2
|
||||||
implicitWidth: parent.implicitHeight + Appearance.padding.small * 2
|
|
||||||
implicitHeight: implicitWidth
|
|
||||||
|
|
||||||
radius: Appearance.rounding.full
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
|
@ -27,4 +25,16 @@ MaterialIcon {
|
||||||
root.visibilities.session = !root.visibilities.session;
|
root.visibilities.session = !root.visibilities.session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
anchors.horizontalCenterOffset: -1
|
||||||
|
|
||||||
|
text: "power_settings_new"
|
||||||
|
color: Colours.palette.m3error
|
||||||
|
font.bold: true
|
||||||
|
font.pointSize: Appearance.font.size.normal
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,51 +10,29 @@ import Quickshell.Services.UPower
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
StyledRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
property color colour: Colours.palette.m3secondary
|
property color colour: Colours.palette.m3secondary
|
||||||
|
readonly property alias items: iconColumn
|
||||||
|
|
||||||
readonly property list<var> hoverAreas: [
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
{
|
radius: Appearance.rounding.full
|
||||||
name: "audio",
|
|
||||||
item: audioIcon,
|
|
||||||
enabled: Config.bar.status.showAudio
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "network",
|
|
||||||
item: networkIcon,
|
|
||||||
enabled: Config.bar.status.showNetwork
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bluetooth",
|
|
||||||
item: bluetoothGroup,
|
|
||||||
enabled: Config.bar.status.showBluetooth
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "battery",
|
|
||||||
item: batteryIcon,
|
|
||||||
enabled: Config.bar.status.showBattery
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
implicitWidth: iconColumn.implicitWidth
|
implicitWidth: iconColumn.implicitWidth + Appearance.padding.normal * 2
|
||||||
implicitHeight: iconColumn.implicitHeight
|
implicitHeight: iconColumn.implicitHeight + Appearance.padding.normal * 2
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: iconColumn
|
id: iconColumn
|
||||||
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.centerIn: parent
|
||||||
spacing: Appearance.spacing.smaller / 2
|
spacing: Appearance.spacing.smaller / 2
|
||||||
|
|
||||||
// Audio icon
|
// Audio icon
|
||||||
Loader {
|
WrappedLoader {
|
||||||
id: audioIcon
|
name: "audio"
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
active: Config.bar.status.showAudio
|
active: Config.bar.status.showAudio
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: MaterialIcon {
|
sourceComponent: MaterialIcon {
|
||||||
animate: true
|
animate: true
|
||||||
|
|
@ -65,8 +43,6 @@ Item {
|
||||||
|
|
||||||
// Keyboard layout icon
|
// Keyboard layout icon
|
||||||
Loader {
|
Loader {
|
||||||
id: kbLayout
|
|
||||||
|
|
||||||
Layout.alignment: Qt.AlignHCenter
|
Layout.alignment: Qt.AlignHCenter
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
active: Config.bar.status.showKbLayout
|
active: Config.bar.status.showKbLayout
|
||||||
|
|
@ -81,12 +57,9 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network icon
|
// Network icon
|
||||||
Loader {
|
WrappedLoader {
|
||||||
id: networkIcon
|
name: "network"
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
active: Config.bar.status.showNetwork
|
active: Config.bar.status.showNetwork
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: MaterialIcon {
|
sourceComponent: MaterialIcon {
|
||||||
animate: true
|
animate: true
|
||||||
|
|
@ -95,13 +68,10 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bluetooth section (grouped for hover area)
|
// Bluetooth section
|
||||||
Loader {
|
WrappedLoader {
|
||||||
id: bluetoothGroup
|
name: "bluetooth"
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
active: Config.bar.status.showBluetooth
|
active: Config.bar.status.showBluetooth
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: ColumnLayout {
|
sourceComponent: ColumnLayout {
|
||||||
spacing: Appearance.spacing.smaller / 2
|
spacing: Appearance.spacing.smaller / 2
|
||||||
|
|
@ -157,12 +127,9 @@ Item {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Battery icon
|
// Battery icon
|
||||||
Loader {
|
WrappedLoader {
|
||||||
id: batteryIcon
|
name: "battery"
|
||||||
|
|
||||||
asynchronous: true
|
|
||||||
active: Config.bar.status.showBattery
|
active: Config.bar.status.showBattery
|
||||||
visible: active
|
|
||||||
|
|
||||||
sourceComponent: MaterialIcon {
|
sourceComponent: MaterialIcon {
|
||||||
animate: true
|
animate: true
|
||||||
|
|
@ -194,6 +161,14 @@ Item {
|
||||||
Anim {}
|
Anim {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
component WrappedLoader: Loader {
|
||||||
|
required property string name
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
asynchronous: true
|
||||||
|
visible: active
|
||||||
|
}
|
||||||
|
|
||||||
component Anim: NumberAnimation {
|
component Anim: NumberAnimation {
|
||||||
duration: Appearance.anim.durations.large
|
duration: Appearance.anim.durations.large
|
||||||
easing.type: Easing.BezierSpline
|
easing.type: Easing.BezierSpline
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,11 @@ pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import qs.services
|
import qs.services
|
||||||
import qs.config
|
import qs.config
|
||||||
|
import qs.components
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
|
|
||||||
Item {
|
StyledRect {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
readonly property list<Workspace> workspaces: layout.children.filter(c => c.isWorkspace).sort((w1, w2) => w1.ws - w2.ws)
|
readonly property list<Workspace> workspaces: layout.children.filter(c => c.isWorkspace).sort((w1, w2) => w1.ws - w2.ws)
|
||||||
|
|
@ -15,8 +16,16 @@ Item {
|
||||||
}, {})
|
}, {})
|
||||||
readonly property int groupOffset: Math.floor((Hyprland.activeWsId - 1) / Config.bar.workspaces.shown) * Config.bar.workspaces.shown
|
readonly property int groupOffset: Math.floor((Hyprland.activeWsId - 1) / Config.bar.workspaces.shown) * Config.bar.workspaces.shown
|
||||||
|
|
||||||
implicitWidth: layout.implicitWidth
|
implicitWidth: layout.implicitWidth + Appearance.padding.small * 2
|
||||||
implicitHeight: layout.implicitHeight
|
implicitHeight: layout.implicitHeight + Appearance.padding.small * 2
|
||||||
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
radius: Appearance.rounding.full
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: inner
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Appearance.padding.small
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
id: layout
|
id: layout
|
||||||
|
|
@ -56,8 +65,8 @@ Item {
|
||||||
sourceComponent: ActiveIndicator {
|
sourceComponent: ActiveIndicator {
|
||||||
workspaces: root.workspaces
|
workspaces: root.workspaces
|
||||||
mask: layout
|
mask: layout
|
||||||
maskWidth: root.width
|
maskWidth: inner.width
|
||||||
maskHeight: root.height
|
maskHeight: inner.height
|
||||||
groupOffset: root.groupOffset
|
groupOffset: root.groupOffset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -71,4 +80,5 @@ Item {
|
||||||
Hyprland.dispatch(`workspace ${ws}`);
|
Hyprland.dispatch(`workspace ${ws}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,6 @@ Variants {
|
||||||
visibilities: visibilities
|
visibilities: visibilities
|
||||||
bar: bar
|
bar: bar
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
BarWrapper {
|
BarWrapper {
|
||||||
id: bar
|
id: bar
|
||||||
|
|
@ -147,4 +146,5 @@ Variants {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,18 +45,7 @@ CustomMouseArea {
|
||||||
|
|
||||||
function onWheel(event: WheelEvent): void {
|
function onWheel(event: WheelEvent): void {
|
||||||
if (event.x < bar.implicitWidth) {
|
if (event.x < bar.implicitWidth) {
|
||||||
if (event.y < screen.height / 2) {
|
bar.handleWheel(event.y, event.angleDelta);
|
||||||
if (event.angleDelta.y > 0)
|
|
||||||
Audio.incrementVolume();
|
|
||||||
else if (event.angleDelta.y < 0)
|
|
||||||
Audio.decrementVolume();
|
|
||||||
} else {
|
|
||||||
const monitor = Brightness.getMonitorForScreen(screen);
|
|
||||||
if (event.angleDelta.y > 0)
|
|
||||||
monitor.setBrightness(monitor.brightness + 0.1);
|
|
||||||
else if (event.angleDelta.y < 0)
|
|
||||||
monitor.setBrightness(monitor.brightness - 0.1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ Item {
|
||||||
const diff = root.height - Math.floor(off + nonAnimHeight);
|
const diff = root.height - Math.floor(off + nonAnimHeight);
|
||||||
if (diff < 0)
|
if (diff < 0)
|
||||||
return off + diff;
|
return off + diff;
|
||||||
return off;
|
return Math.max(off, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue