aurora6a3e480
aurora: bar layout (horizontal/vertical) and floating pill settings, net and bt as separate blocks
+185 −90
13 files changed
- M .config/quickshell/aurora/Bar.qml +86 −47
- M .config/quickshell/aurora/BarPill.qml +19 −12
- M .config/quickshell/aurora/CalPopup.qml +9 −4
- M .config/quickshell/aurora/ControlPanel.qml +1 −1
- M .config/quickshell/aurora/Desktop.qml +4 −3
- M .config/quickshell/aurora/NotifPopups.qml +1 −1
- M .config/quickshell/aurora/Overview.qml +2 −1
- M .config/quickshell/aurora/SetAppearance.qml +17 −2
- M .config/quickshell/aurora/SetIndex.qml +1 −1
- M .config/quickshell/aurora/Settings.qml +7 −1
- M .config/quickshell/aurora/Theme.qml +9 −2
- M .config/quickshell/aurora/Tray.qml +10 −6
- M .config/quickshell/aurora/Workspaces.qml +19 −9
| @@ -6,11 +6,14 @@ import Quickshell.Hyprland | |||
| 6 | 6 | import Quickshell.Services.Pipewire | |
| 7 | 7 | import Quickshell.Services.UPower | |
| 8 | 8 | ||
| 9 | − | // The bar: a strip docked at the top of every monitor. | |
| 10 | − | // Left: the mark (a dotted ring: click = runner; its centre turns the live colour while something records or listens, | |
| 9 | + | // The bar: a strip docked at the top of every monitor, or at the left edge (Settings.barLayout "vertical", like | |
| 10 | + | // glyph-rice's; the groups are Grids that turn from rows into columns). Settings.barFloat: a rounded pill held off the | |
| 11 | + | // screen edges (glyph's look) instead of a strip along the edge. | |
| 12 | + | // Left / top: the mark (a dotted ring: click = runner; its centre turns the live colour while something records or listens, | |
| 11 | 13 | // the ring lights up in a wave on a new notification), this monitor's workspaces as dots, the cat. | |
| 12 | − | // Centre: time · day (click = calendar). Right: tray, recording, privacy, caffeine/airplane, headset, volume, | |
| 13 | − | // net + bt, battery. Clicks open the same panel tabs as always. | |
| 14 | + | // Centre: time · day, or Doto hours over minutes over the day when vertical (click = calendar). | |
| 15 | + | // Right / bottom: tray, recording, privacy, caffeine/airplane, headset, volume, net, bt, battery. | |
| 16 | + | // Clicks open the same panel tabs as always. | |
| 14 | 17 | // After glyph-rice (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), bar/Bar.qml. | |
| 15 | 18 | PanelWindow { | |
| 16 | 19 | id: bar | |
| @@ -19,8 +22,10 @@ PanelWindow { | |||
| 19 | 22 | signal togglePanel(string name, var scr) | |
| 20 | 23 | signal toggleOverlay(string name, var scr) | |
| 21 | 24 | ||
| 22 | − | anchors { top: true; left: true; right: true } | |
| 23 | − | implicitHeight: Theme.barHeight | |
| 25 | + | readonly property bool vertical: Theme.barVertical | |
| 26 | + | anchors { top: true; left: true; right: !vertical; bottom: vertical } | |
| 27 | + | implicitHeight: vertical ? 0 : Theme.barSpan | |
| 28 | + | implicitWidth: vertical ? Theme.barSpan : 0 | |
| 24 | 29 | color: "transparent" | |
| 25 | 30 | WlrLayershell.namespace: "aurora-bar" | |
| 26 | 31 | ||
| @@ -78,29 +83,39 @@ PanelWindow { | |||
| 78 | 83 | ||
| 79 | 84 | Rectangle { | |
| 80 | 85 | id: pill | |
| 81 | − | anchors.fill: parent | |
| 86 | + | // floating: barGap off the screen edges, barInner (+ Hyprland's gaps_out) to the windows | |
| 87 | + | x: Theme.barGap | |
| 88 | + | y: Theme.barGap | |
| 89 | + | width: bar.vertical ? Theme.barSize : parent.width - 2 * Theme.barGap | |
| 90 | + | height: bar.vertical ? parent.height - 2 * Theme.barGap : Theme.barSize | |
| 91 | + | radius: Theme.barFloat ? Theme.barSize / 2 : 0 | |
| 82 | 92 | color: Theme.fade(Theme.s1, Theme.barAlpha) | |
| 83 | − | Rectangle { // hairline along the bottom | |
| 84 | − | anchors.left: parent.left | |
| 85 | − | anchors.right: parent.right | |
| 86 | − | anchors.bottom: parent.bottom | |
| 87 | − | height: 1 | |
| 93 | + | border.width: Theme.barFloat ? 1 : 0 | |
| 94 | + | border.color: Theme.s2 | |
| 95 | + | Rectangle { // hairline along the bottom, or the right edge when vertical (the pill has a border instead) | |
| 96 | + | visible: !Theme.barFloat | |
| 97 | + | x: bar.vertical ? parent.width - 1 : 0 | |
| 98 | + | y: bar.vertical ? 0 : parent.height - 1 | |
| 99 | + | width: bar.vertical ? 1 : parent.width | |
| 100 | + | height: bar.vertical ? parent.height : 1 | |
| 88 | 101 | color: Theme.s2 | |
| 89 | 102 | } | |
| 90 | 103 | ||
| 91 | − | // ---------------- left ---------------- | |
| 92 | − | Row { | |
| 93 | − | anchors.left: parent.left | |
| 94 | − | anchors.leftMargin: Math.round(Theme.barSize * 0.25) | |
| 95 | − | height: parent.height | |
| 104 | + | // ---------------- left / top ---------------- | |
| 105 | + | Grid { | |
| 106 | + | x: bar.vertical ? (parent.width - width) / 2 : Math.round(Theme.barSize * 0.25) | |
| 107 | + | y: bar.vertical ? Math.round(Theme.barSize * 0.25) : 0 | |
| 108 | + | height: bar.vertical ? implicitHeight : parent.height | |
| 109 | + | columns: bar.vertical ? 1 : 3 // only columns flips, see BarPill | |
| 96 | 110 | spacing: 14 | |
| 111 | + | horizontalItemAlignment: Grid.AlignHCenter | |
| 112 | + | verticalItemAlignment: Grid.AlignVCenter | |
| 97 | 113 | ||
| 98 | 114 | Item { | |
| 99 | 115 | id: mark | |
| 100 | 116 | readonly property real size: Math.round(Theme.barSize * 0.55) | |
| 101 | 117 | width: size | |
| 102 | 118 | height: size | |
| 103 | − | anchors.verticalCenter: parent.verticalCenter | |
| 104 | 119 | Ring { | |
| 105 | 120 | anchors.fill: parent | |
| 106 | 121 | anchors.margins: 1.5 | |
| @@ -123,31 +138,52 @@ PanelWindow { | |||
| 123 | 138 | onClicked: bar.toggleOverlay("runner", bar.modelData) | |
| 124 | 139 | } | |
| 125 | 140 | } | |
| 126 | − | Workspaces { height: parent.height; monitor: bar.hmon } | |
| 127 | − | CatLoop { height: parent.height } | |
| 141 | + | Workspaces { monitor: bar.hmon } | |
| 142 | + | CatLoop { height: bar.vertical ? 24 : Theme.barSize } | |
| 128 | 143 | } | |
| 129 | 144 | ||
| 130 | 145 | // ---------------- center: time · day, one line (click = calendar) ---------------- | |
| 131 | 146 | BarPill { | |
| 147 | + | visible: !bar.vertical | |
| 132 | 148 | anchors.centerIn: parent | |
| 133 | − | height: parent.height | |
| 134 | 149 | text: Theme.hh(clock.date) + ":" + Qt.formatDateTime(clock.date, "mm") + " · " + Qt.locale("en_US").toString(clock.date, "ddd d") | |
| 135 | 150 | onActivated: bar.toggleOverlay("cal", bar.modelData) | |
| 136 | 151 | } | |
| 152 | + | // vertical: hours over minutes in Doto, the day under them | |
| 153 | + | BarPill { | |
| 154 | + | visible: bar.vertical | |
| 155 | + | anchors.centerIn: parent | |
| 156 | + | onActivated: bar.toggleOverlay("cal", bar.modelData) | |
| 157 | + | Column { | |
| 158 | + | readonly property int px: Math.max(26, Math.round(Theme.barSize * 0.5)) | |
| 159 | + | Num { anchors.horizontalCenter: parent.horizontalCenter; text: Theme.hh(clock.date); font.pixelSize: parent.px } | |
| 160 | + | Num { anchors.horizontalCenter: parent.horizontalCenter; text: Qt.formatDateTime(clock.date, "mm"); font.pixelSize: parent.px } | |
| 161 | + | Lb { | |
| 162 | + | anchors.horizontalCenter: parent.horizontalCenter | |
| 163 | + | topPadding: 6 | |
| 164 | + | text: Qt.locale("en_US").toString(clock.date, "ddd d") | |
| 165 | + | px: 10 | |
| 166 | + | } | |
| 167 | + | } | |
| 168 | + | } | |
| 137 | 169 | ||
| 138 | − | // ---------------- right ---------------- | |
| 139 | − | Row { | |
| 140 | − | anchors.right: parent.right | |
| 141 | − | anchors.rightMargin: 6 | |
| 142 | − | height: parent.height | |
| 143 | − | spacing: 0 | |
| 170 | + | // ---------------- right / bottom ---------------- | |
| 171 | + | Grid { | |
| 172 | + | x: bar.vertical ? 0 : parent.width - width - (Theme.barFloat ? 10 : 6) | |
| 173 | + | y: bar.vertical ? parent.height - height - (Theme.barFloat ? 12 : 8) : 0 | |
| 174 | + | width: bar.vertical ? parent.width : implicitWidth | |
| 175 | + | height: bar.vertical ? implicitHeight : parent.height | |
| 176 | + | columns: bar.vertical ? 1 : Math.max(1, visibleChildren.length) // see BarPill | |
| 177 | + | spacing: bar.vertical ? 2 : 0 | |
| 178 | + | horizontalItemAlignment: Grid.AlignHCenter | |
| 179 | + | verticalItemAlignment: Grid.AlignVCenter | |
| 144 | 180 | ||
| 145 | 181 | Tray { show: bar.monFocused } | |
| 146 | 182 | ||
| 147 | 183 | BarPill { // click to stop recording / cancel the area selection | |
| 148 | 184 | visible: Rec.busy | |
| 149 | 185 | icon: Theme.iStop | |
| 150 | − | text: Rec.running ? "rec " + Theme.fmtClock(Rec.elapsed) : "select area" | |
| 186 | + | text: Rec.running ? (bar.vertical ? "" : "rec ") + Theme.fmtClock(Rec.elapsed) : (bar.vertical ? "" : "select area") | |
| 151 | 187 | tint: Theme.live | |
| 152 | 188 | onActivated: Rec.stop() | |
| 153 | 189 | } | |
| @@ -156,28 +192,29 @@ PanelWindow { | |||
| 156 | 192 | BarPill { | |
| 157 | 193 | visible: bar.monFocused && Privacy.mic | |
| 158 | 194 | icon: bar.mic && bar.mic.muted ? Theme.iMicOff : Theme.iMic | |
| 159 | − | text: Privacy.micApps.join(", ") | |
| 195 | + | text: bar.vertical ? "" : Privacy.micApps.join(", ") | |
| 160 | 196 | tint: bar.mic && bar.mic.muted ? Theme.grey : Theme.live | |
| 161 | 197 | onActivated: if (bar.mic) bar.mic.muted = !bar.mic.muted | |
| 162 | 198 | } | |
| 163 | 199 | BarPill { | |
| 164 | 200 | visible: bar.monFocused && Privacy.cam | |
| 165 | 201 | icon: Theme.iWebcam | |
| 166 | − | text: Privacy.camApps.join(", ") | |
| 202 | + | text: bar.vertical ? "" : Privacy.camApps.join(", ") | |
| 167 | 203 | tint: Theme.live | |
| 168 | 204 | } | |
| 169 | 205 | BarPill { | |
| 170 | 206 | visible: bar.monFocused && Privacy.screen | |
| 171 | 207 | icon: Theme.iCast | |
| 172 | − | text: Privacy.shareApps.join(", ") | |
| 208 | + | text: bar.vertical ? "" : Privacy.shareApps.join(", ") | |
| 173 | 209 | tint: Theme.live | |
| 174 | 210 | } | |
| 175 | 211 | ||
| 176 | 212 | BarPill { | |
| 177 | 213 | visible: Toggles.caffeine || Toggles.airplane | |
| 178 | − | icon: (Toggles.caffeine ? Theme.iCoffee : "") + (Toggles.caffeine && Toggles.airplane ? " " : "") | |
| 179 | − | + (Toggles.airplane ? Theme.iPlane : "") | |
| 214 | + | icon: Toggles.caffeine ? Theme.iCoffee : Theme.iPlane | |
| 215 | + | icon2: Toggles.caffeine && Toggles.airplane ? Theme.iPlane : "" | |
| 180 | 216 | onActivated: bar.togglePanel("home", bar.modelData) | |
| 217 | + | onActivated2: bar.togglePanel("home", bar.modelData) | |
| 181 | 218 | } | |
| 182 | 219 | ||
| 183 | 220 | BarPill { | |
| @@ -205,18 +242,21 @@ PanelWindow { | |||
| 205 | 242 | } | |
| 206 | 243 | } | |
| 207 | 244 | ||
| 208 | − | // net + bt share one block: click the left icon for the net tab, the right one for bt | |
| 209 | 245 | BarPill { | |
| 210 | 246 | icon: Net.wired && !(Net.wifiEnabled && Net.connected !== "") ? Net.wiredIcon | |
| 211 | 247 | : (Net.wifiEnabled ? Theme.wifiIcon(Net.connected !== "" ? Net.activeSignal : 0) : Theme.iWifiOff) | |
| 212 | 248 | tint: Net.portal ? Theme.live : ((Net.wired || (Net.wifiEnabled && Net.connected !== "")) ? Theme.fg : Theme.grey) | |
| 213 | − | icon2: bar.adapter === null ? "" : (!bar.btOn ? Theme.iBtOff : (bar.btLink ? Theme.iBtConn : Theme.iBt)) | |
| 214 | − | tint2: bar.btLink ? Theme.fg : Theme.grey | |
| 215 | 249 | onActivated: bar.togglePanel("net", bar.modelData) | |
| 216 | − | onActivated2: bar.togglePanel("bt", bar.modelData) | |
| 250 | + | } | |
| 251 | + | BarPill { | |
| 252 | + | visible: bar.adapter !== null | |
| 253 | + | icon: !bar.btOn ? Theme.iBtOff : (bar.btLink ? Theme.iBtConn : Theme.iBt) | |
| 254 | + | tint: bar.btLink ? Theme.fg : Theme.grey | |
| 255 | + | onActivated: bar.togglePanel("bt", bar.modelData) | |
| 217 | 256 | } | |
| 218 | 257 | ||
| 219 | − | // battery: a capsule that fills up, the error colour when low, a bolt + breathing fill while charging | |
| 258 | + | // battery: a capsule that fills up (standing, from the bottom, when vertical), the error colour when low, | |
| 259 | + | // a bolt + breathing fill while charging | |
| 220 | 260 | BarPill { | |
| 221 | 261 | id: batt | |
| 222 | 262 | visible: bar.hasBat | |
| @@ -233,25 +273,24 @@ PanelWindow { | |||
| 233 | 273 | onRunningChanged: batt.phase = 0 | |
| 234 | 274 | } | |
| 235 | 275 | Rectangle { | |
| 236 | − | anchors.verticalCenter: parent.verticalCenter | |
| 237 | − | width: 26 | |
| 238 | − | height: 13 | |
| 239 | − | radius: height / 2 | |
| 276 | + | width: bar.vertical ? 13 : 26 | |
| 277 | + | height: bar.vertical ? 26 : 13 | |
| 278 | + | radius: Math.min(width, height) / 2 | |
| 240 | 279 | color: "transparent" | |
| 241 | 280 | border.width: 1.5 | |
| 242 | 281 | border.color: bar.batLow ? Theme.err : Theme.grey | |
| 243 | 282 | Rectangle { | |
| 283 | + | readonly property real fill: Math.max(3, ((bar.vertical ? parent.height : parent.width) - 6) * bar.batPct) | |
| 244 | 284 | x: 3 | |
| 245 | − | anchors.verticalCenter: parent.verticalCenter | |
| 246 | − | width: Math.max(3, (parent.width - 6) * bar.batPct) | |
| 247 | − | height: parent.height - 6 | |
| 248 | − | radius: height / 2 | |
| 285 | + | y: bar.vertical ? parent.height - 3 - height : 3 | |
| 286 | + | width: bar.vertical ? parent.width - 6 : fill | |
| 287 | + | height: bar.vertical ? fill : parent.height - 6 | |
| 288 | + | radius: Math.min(width, height) / 2 | |
| 249 | 289 | color: bar.batLow ? Theme.err : Theme.fill | |
| 250 | 290 | opacity: batt.pulse | |
| 251 | 291 | } | |
| 252 | 292 | } | |
| 253 | 293 | Lb { | |
| 254 | − | anchors.verticalCenter: parent.verticalCenter | |
| 255 | 294 | text: Math.round(bar.batPct * 100) | |
| 256 | 295 | px: 11 | |
| 257 | 296 | color: bar.batLow ? Theme.err : Theme.fg | |
| @@ -1,7 +1,8 @@ | |||
| 1 | 1 | import QtQuick | |
| 2 | 2 | ||
| 3 | 3 | // One block of the bar: icon, caps label, optional second icon with its own click (activated2), anything else declared | |
| 4 | − | // inside goes after them (the battery capsule, the clock). Hover = a rounded highlight. | |
| 4 | + | // inside goes after them (the battery capsule, the clock). Side by side in the top bar, stacked in the vertical one. | |
| 5 | + | // Hover = a rounded highlight. | |
| 5 | 6 | Item { | |
| 6 | 7 | id: p | |
| 7 | 8 | property string icon: "" | |
| @@ -10,35 +11,41 @@ Item { | |||
| 10 | 11 | property color underline: "transparent" // old style, unused | |
| 11 | 12 | property string icon2: "" | |
| 12 | 13 | property color tint2: Theme.fg | |
| 14 | + | property bool vertical: Theme.barVertical | |
| 13 | 15 | default property alias extra: row.data | |
| 14 | 16 | signal activated(int button) | |
| 15 | 17 | signal activated2(int button) | |
| 16 | 18 | signal scrolled(int dir) | |
| 17 | 19 | ||
| 18 | − | implicitWidth: row.implicitWidth + 22 | |
| 19 | − | implicitHeight: parent ? parent.height : Theme.barSize | |
| 20 | + | implicitWidth: vertical ? Theme.barSize : row.implicitWidth + 22 | |
| 21 | + | implicitHeight: vertical ? row.implicitHeight + 16 : Theme.barSize | |
| 20 | 22 | ||
| 21 | 23 | Rectangle { | |
| 22 | 24 | anchors.fill: parent | |
| 23 | − | anchors.topMargin: 5 | |
| 24 | − | anchors.bottomMargin: 5 | |
| 25 | − | radius: height / 2 | |
| 25 | + | anchors.topMargin: p.vertical ? 0 : 5 | |
| 26 | + | anchors.bottomMargin: p.vertical ? 0 : 5 | |
| 27 | + | anchors.leftMargin: p.vertical ? 5 : 0 | |
| 28 | + | anchors.rightMargin: p.vertical ? 5 : 0 | |
| 29 | + | radius: Math.min(width, height) / 2 | |
| 26 | 30 | color: m.containsMouse ? Theme.s2 : "transparent" | |
| 27 | 31 | } | |
| 28 | − | Row { | |
| 32 | + | // a row, or a column in the vertical bar. Only `columns` flips (rows and columns both changing pass through 1x1 and | |
| 33 | + | // warn), and it must match the shown items exactly: Grid leaves a gap for every empty column. | |
| 34 | + | Grid { | |
| 29 | 35 | id: row | |
| 30 | 36 | anchors.centerIn: parent | |
| 31 | − | spacing: 7 | |
| 37 | + | columns: p.vertical ? 1 : Math.max(1, visibleChildren.length) | |
| 38 | + | spacing: p.vertical ? 5 : 7 | |
| 39 | + | horizontalItemAlignment: Grid.AlignHCenter | |
| 40 | + | verticalItemAlignment: Grid.AlignVCenter | |
| 32 | 41 | Icon { | |
| 33 | 42 | visible: p.icon !== "" | |
| 34 | − | anchors.verticalCenter: parent.verticalCenter | |
| 35 | 43 | text: p.icon | |
| 36 | 44 | font.pixelSize: 16 | |
| 37 | 45 | color: p.tint | |
| 38 | 46 | } | |
| 39 | 47 | Lb { | |
| 40 | 48 | visible: p.text !== "" | |
| 41 | − | anchors.verticalCenter: parent.verticalCenter | |
| 42 | 49 | text: p.text | |
| 43 | 50 | px: 11 | |
| 44 | 51 | color: p.tint | |
| @@ -46,7 +53,6 @@ Item { | |||
| 46 | 53 | Icon { | |
| 47 | 54 | id: second | |
| 48 | 55 | visible: p.icon2 !== "" | |
| 49 | − | anchors.verticalCenter: parent.verticalCenter | |
| 50 | 56 | text: p.icon2 | |
| 51 | 57 | font.pixelSize: 16 | |
| 52 | 58 | color: p.tint2 | |
| @@ -60,7 +66,8 @@ Item { | |||
| 60 | 66 | acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton | |
| 61 | 67 | onClicked: mouse => { | |
| 62 | 68 | // split at the middle of the gap before the second icon | |
| 63 | − | if (second.visible && mouse.x >= row.x + second.x - row.spacing / 2) p.activated2(mouse.button) | |
| 69 | + | var at = p.vertical ? mouse.y - row.y - second.y : mouse.x - row.x - second.x | |
| 70 | + | if (second.visible && at >= -row.spacing / 2) p.activated2(mouse.button) | |
| 64 | 71 | else p.activated(mouse.button) | |
| 65 | 72 | } | |
| 66 | 73 | onWheel: w => p.scrolled(w.angleDelta.y > 0 ? 1 : -1) | |
| @@ -18,10 +18,14 @@ PanelWindow { | |||
| 18 | 18 | Behavior on t { NumberAnimation { duration: Theme.t; easing.type: Easing.BezierSpline; easing.bezierCurve: Theme.glide } } | |
| 19 | 19 | ||
| 20 | 20 | visible: t > 0 | |
| 21 | − | anchors.top: true | |
| 21 | + | // under the clock: top centre, or next to it (left edge, centred) when the bar is vertical | |
| 22 | + | readonly property bool side: Theme.barVertical | |
| 23 | + | anchors.top: !side | |
| 24 | + | anchors.left: side | |
| 22 | 25 | margins.top: 6 | |
| 23 | − | implicitWidth: card.width | |
| 24 | − | implicitHeight: card.height + 20 // room for the slide | |
| 26 | + | margins.left: 8 | |
| 27 | + | implicitWidth: card.width + (side ? 20 : 0) // room for the slide | |
| 28 | + | implicitHeight: card.height + (side ? 0 : 20) | |
| 25 | 29 | exclusiveZone: 0 | |
| 26 | 30 | color: "transparent" | |
| 27 | 31 | mask: Region { item: card } | |
| @@ -88,7 +92,8 @@ PanelWindow { | |||
| 88 | 92 | ||
| 89 | 93 | Rectangle { | |
| 90 | 94 | id: card | |
| 91 | − | y: -16 * (1 - win.t) | |
| 95 | + | x: win.side ? -16 * (1 - win.t) : 0 | |
| 96 | + | y: win.side ? 0 : -16 * (1 - win.t) | |
| 92 | 97 | opacity: win.t | |
| 93 | 98 | width: row.width + 52 | |
| 94 | 99 | height: row.height + 48 | |
| @@ -22,7 +22,7 @@ PanelWindow { | |||
| 22 | 22 | ||
| 23 | 23 | visible: t > 0 | |
| 24 | 24 | anchors { top: true; right: true; bottom: true } | |
| 25 | − | margins { top: 6; right: 8; bottom: 8 } // sits just under the bar (bar's exclusive zone is respected) | |
| 25 | + | margins { top: Theme.barTop ? 6 : 8; right: 8; bottom: 8 } // sits just under the bar (bar's exclusive zone is respected) | |
| 26 | 26 | implicitWidth: card.width + 24 // room for the slide | |
| 27 | 27 | exclusiveZone: 0 | |
| 28 | 28 | color: "transparent" | |
| @@ -33,8 +33,8 @@ PanelWindow { | |||
| 33 | 33 | ||
| 34 | 34 | Column { | |
| 35 | 35 | visible: win.showClock | |
| 36 | − | x: 56 | |
| 37 | − | y: Theme.barHeight + 48 | |
| 36 | + | x: Theme.barLeft + 56 | |
| 37 | + | y: Theme.barTop + 48 | |
| 38 | 38 | spacing: 2 | |
| 39 | 39 | ||
| 40 | 40 | Row { | |
| @@ -87,9 +87,10 @@ PanelWindow { | |||
| 87 | 87 | anchors.bottom: parent.bottom | |
| 88 | 88 | anchors.bottomMargin: 18 | |
| 89 | 89 | anchors.horizontalCenter: parent.horizontalCenter | |
| 90 | + | anchors.horizontalCenterOffset: Theme.barLeft / 2 // not under a vertical bar | |
| 90 | 91 | readonly property int rows: 14 | |
| 91 | 92 | readonly property real d: 6 | |
| 92 | − | readonly property real gap: Math.max(2, (win.width - 72) / Cava.bars - d) | |
| 93 | + | readonly property real gap: Math.max(2, (win.width - Theme.barLeft - 72) / Cava.bars - d) | |
| 93 | 94 | spacing: gap | |
| 94 | 95 | Repeater { | |
| 95 | 96 | model: Cava.bars | |
| @@ -15,7 +15,7 @@ PanelWindow { | |||
| 15 | 15 | ||
| 16 | 16 | visible: stack.count > 0 && !suppressed | |
| 17 | 17 | anchors.top: true | |
| 18 | − | margins.top: 6 | |
| 18 | + | margins.top: Theme.barTop ? 6 : 8 | |
| 19 | 19 | implicitWidth: cardW | |
| 20 | 20 | implicitHeight: 4 * 160 + 20 // fixed; only the cards take input (mask) | |
| 21 | 21 | exclusiveZone: 0 | |
| @@ -80,7 +80,8 @@ PanelWindow { | |||
| 80 | 80 | ColumnLayout { | |
| 81 | 81 | anchors.fill: parent | |
| 82 | 82 | anchors.margins: 40 | |
| 83 | − | anchors.topMargin: Theme.barHeight + 24 | |
| 83 | + | anchors.topMargin: Math.max(40, Theme.barTop + 24) | |
| 84 | + | anchors.leftMargin: Math.max(40, Theme.barLeft + 24) | |
| 84 | 85 | spacing: 16 | |
| 85 | 86 | ||
| 86 | 87 | RowLayout { | |
| @@ -119,8 +119,23 @@ Flickable { | |||
| 119 | 119 | } | |
| 120 | 120 | Knob { label: "contrast"; keywords: "colours colors"; from: -1; to: 1; decimals: 2; value: Settings.matuContrast; onMoved: v => Settings.matuContrast = v } | |
| 121 | 121 | ||
| 122 | − | SectionLabel { text: "sizes" } | |
| 123 | − | Knob { label: "bar height"; keywords: "top bar size"; from: 32; to: 56; value: Settings.barSize; onMoved: v => Settings.barSize = v } | |
| 122 | + | SectionLabel { text: "bar"; keywords: "status bar sizes" } | |
| 123 | + | Choice { | |
| 124 | + | label: "bar layout" | |
| 125 | + | keywords: "vertical horizontal orientation side left top position" | |
| 126 | + | options: [{ value: "horizontal", label: "horizontal" }, { value: "vertical", label: "vertical" }] | |
| 127 | + | value: Settings.barLayout | |
| 128 | + | onPicked: v => Settings.barLayout = v | |
| 129 | + | } | |
| 130 | + | Choice { | |
| 131 | + | label: "bar shape" | |
| 132 | + | keywords: "floating pill attached edge strip rounded" | |
| 133 | + | options: [{ value: false, label: "attached" }, { value: true, label: "floating pill" }] | |
| 134 | + | value: Settings.barFloat | |
| 135 | + | onPicked: v => Settings.barFloat = v | |
| 136 | + | } | |
| 137 | + | Knob { visible: !Theme.barVertical; label: "bar height"; keywords: "top bar size"; from: 32; to: 56; value: Settings.barSize; onMoved: v => Settings.barSize = v } | |
| 138 | + | Knob { visible: Theme.barVertical; label: "bar width"; keywords: "vertical side bar size"; from: 48; to: 80; value: Settings.barWidth; onMoved: v => Settings.barWidth = v } | |
| 124 | 139 | ||
| 125 | 140 | SectionLabel { text: "transparency"; keywords: "transparent opacity alpha translucent" } | |
| 126 | 141 | Knob { label: "bar opacity"; keywords: "transparent"; from: 0.3; to: 1; decimals: 2; value: Settings.barAlpha; onMoved: v => Settings.barAlpha = v } | |
| @@ -18,7 +18,7 @@ Singleton { | |||
| 18 | 18 | { id: "bluetooth", word: "bluetooth", caption: "bluetooth · devices, pairing", files: ["BtPage.qml"], keywords: "bt" }, | |
| 19 | 19 | { id: "sound", word: "sound", caption: "sound · levels, devices, apps", files: ["AudioPage.qml"], | |
| 20 | 20 | keywords: "audio volume speakers microphone" }, | |
| 21 | − | { id: "appearance", word: "look", caption: "look · wallpaper, home screen, colours, sizes", files: ["SetAppearance.qml"], | |
| 21 | + | { id: "appearance", word: "look", caption: "look · wallpaper, home screen, colours, bar", files: ["SetAppearance.qml"], | |
| 22 | 22 | keywords: "appearance theme style" }, | |
| 23 | 23 | { id: "shell", word: "shell", caption: "shell · home screen, dock, osd, notifications", files: ["SetShell.qml"], | |
| 24 | 24 | keywords: "aurora" }, | |
| @@ -18,7 +18,7 @@ Singleton { | |||
| 18 | 18 | idleDim: 150, idleOff: 330, idleLock: 600, idleSuspend: 0, charTone: 0, portalAutoOpen: true, | |
| 19 | 19 | chargeMode: "off", batLow: 15, batCritical: 5, batCriticalAction: "none", | |
| 20 | 20 | privacyIndicators: true, powerAuto: false, powerAc: "balanced", powerBat: "saver", | |
| 21 | − | motion: true, clock24: true, appIcons: "dots", barSize: 40, | |
| 21 | + | motion: true, clock24: true, appIcons: "dots", barSize: 40, barLayout: "horizontal", barWidth: 56, barFloat: false, | |
| 22 | 22 | wallLook: "dots", wallPitch: 10, wallBright: 85, dotGrid: true, | |
| 23 | 23 | blink: true, weatherLoc: "" | |
| 24 | 24 | }) | |
| @@ -54,6 +54,9 @@ Singleton { | |||
| 54 | 54 | property alias clock24: a.clock24 | |
| 55 | 55 | property alias appIcons: a.appIcons | |
| 56 | 56 | property alias barSize: a.barSize | |
| 57 | + | property alias barLayout: a.barLayout | |
| 58 | + | property alias barWidth: a.barWidth | |
| 59 | + | property alias barFloat: a.barFloat | |
| 57 | 60 | property alias wallLook: a.wallLook | |
| 58 | 61 | property alias wallPitch: a.wallPitch | |
| 59 | 62 | property alias wallBright: a.wallBright | |
| @@ -115,6 +118,9 @@ Singleton { | |||
| 115 | 118 | property bool clock24: true | |
| 116 | 119 | property string appIcons: "dots" // dots | mono | colour: how app icons are drawn | |
| 117 | 120 | property int barSize: 40 // height of the bar (Doto clock from 40 up) | |
| 121 | + | property string barLayout: "horizontal" // horizontal (top edge) | vertical (left edge) | |
| 122 | + | property int barWidth: 56 // width of the vertical bar | |
| 123 | + | property bool barFloat: false // a rounded pill held off the screen edges (glyph-rice) instead of a strip | |
| 118 | 124 | property string wallLook: "dots" // dots | colour | photo: how aurora draws the wallpaper (WallView) | |
| 119 | 125 | property int wallPitch: 10 // dot step, px | |
| 120 | 126 | property int wallBright: 85 // %, from the background to the full image | |
| @@ -16,8 +16,15 @@ Singleton { | |||
| 16 | 16 | ||
| 17 | 17 | // ---- knobs (persisted in ~/.config/aurora/settings.json, edited in the settings app) ---- | |
| 18 | 18 | readonly property real panelAlpha: Settings.panelAlpha | |
| 19 | − | readonly property int barSize: Math.max(32, Settings.barSize) // the bar's height (docked at the top) | |
| 20 | − | readonly property int barHeight: barSize // what the bar reserves at the top | |
| 19 | + | readonly property bool barVertical: Settings.barLayout === "vertical" // docked at the left edge instead of the top | |
| 20 | + | readonly property int barSize: barVertical ? Math.max(48, Settings.barWidth) : Math.max(32, Settings.barSize) // its thickness | |
| 21 | + | readonly property bool barFloat: Settings.barFloat // a floating pill instead of a strip along the edge | |
| 22 | + | readonly property int barGap: barFloat ? 14 : 0 // the pill's distance from the screen edges (glyph-rice) | |
| 23 | + | // ... and from the windows: glyph's 14 too, there it is Hyprland's gaps_out; here only the part gaps_out doesn't cover | |
| 24 | + | readonly property int barInner: barFloat ? Math.max(0, barGap - (HyprConf.values["general:gaps_out"] || 0)) : 0 | |
| 25 | + | readonly property int barSpan: barSize + barGap + barInner // the bar window, across the bar | |
| 26 | + | readonly property int barTop: barVertical ? 0 : barSpan // what the bar reserves at the top | |
| 27 | + | readonly property int barLeft: barVertical ? barSpan : 0 // ... and at the left | |
| 21 | 28 | readonly property real barAlpha: Settings.barAlpha | |
| 22 | 29 | ||
| 23 | 30 | // ---- motion: ease-out-quart without overshoot (glyph's "glide"); Settings.motion off = instant ---- | |
| @@ -3,29 +3,33 @@ import QtQuick.Effects | |||
| 3 | 3 | import Quickshell | |
| 4 | 4 | import Quickshell.Services.SystemTray | |
| 5 | 5 | ||
| 6 | − | // Tray icons in the bar; monochrome unless Settings.appIcons is "colour" (dots are too coarse at this size). | |
| 6 | + | // Tray icons in the bar (a row, or a column in the vertical bar); monochrome unless Settings.appIcons is "colour" | |
| 7 | + | // (dots are too coarse at this size). | |
| 7 | 8 | Item { | |
| 8 | 9 | id: tray | |
| 9 | 10 | property bool show: true | |
| 11 | + | property bool vertical: Theme.barVertical | |
| 10 | 12 | visible: show && SystemTray.items.values.length > 0 | |
| 11 | − | implicitWidth: row.implicitWidth + 22 | |
| 12 | − | implicitHeight: parent ? parent.height : Theme.barSize | |
| 13 | + | implicitWidth: vertical ? Theme.barSize : row.implicitWidth + 22 | |
| 14 | + | implicitHeight: vertical ? row.implicitHeight + 22 : Theme.barSize | |
| 13 | 15 | ||
| 14 | − | Row { | |
| 16 | + | Grid { | |
| 15 | 17 | id: row | |
| 16 | 18 | anchors.centerIn: parent | |
| 19 | + | columns: tray.vertical ? 1 : Math.max(1, rep.count) // only columns flips, see BarPill | |
| 17 | 20 | spacing: 12 | |
| 18 | 21 | Repeater { | |
| 22 | + | id: rep | |
| 19 | 23 | model: SystemTray.items | |
| 20 | 24 | delegate: Item { | |
| 21 | 25 | id: it | |
| 22 | 26 | required property var modelData | |
| 23 | 27 | width: 16 | |
| 24 | 28 | height: 16 | |
| 25 | − | anchors.verticalCenter: parent.verticalCenter | |
| 26 | 29 | ||
| 30 | + | // under the icon, or beside it in the vertical bar | |
| 27 | 31 | function openMenu() { | |
| 28 | − | var p = it.mapToItem(null, 0, it.height + 10) | |
| 32 | + | var p = tray.vertical ? it.mapToItem(null, it.width + 14, 0) : it.mapToItem(null, 0, it.height + 10) | |
| 29 | 33 | modelData.display(QsWindow.window, p.x, p.y) | |
| 30 | 34 | } | |
| 31 | 35 | Image { | |
| @@ -3,14 +3,18 @@ import Quickshell.Hyprland | |||
| 3 | 3 | ||
| 4 | 4 | // This monitor's 10 workspaces as dots (split-monitor-workspaces: monitor 1 owns 1-10, monitor 2 11-20, ...; the block | |
| 5 | 5 | // comes from the monitor's own active workspace, so it works without the plugin too). | |
| 6 | − | // Active = a wide pill (primary on the focused monitor, grey on the others), occupied = grey dot, empty = dim dot, | |
| 6 | + | // A row, or a column in the vertical bar. Active = a long pill (primary on the focused monitor, grey on the others), | |
| 7 | + | // occupied = grey dot, empty = dim dot, | |
| 7 | 8 | // urgent = the live colour. Click = go there, wheel = the next / previous occupied one. | |
| 8 | 9 | // After glyph-rice (github.com/Nebelung-cloud/glyph-rice, GPL-3.0), bar/Bar.qml. | |
| 9 | − | Row { | |
| 10 | + | Grid { | |
| 10 | 11 | id: ws | |
| 11 | 12 | spacing: 6 | |
| 13 | + | columns: vertical ? 1 : list.length // only columns flips, see BarPill | |
| 12 | 14 | ||
| 13 | 15 | property var monitor: null // HyprlandMonitor of the bar this sits in | |
| 16 | + | property bool vertical: Theme.barVertical | |
| 17 | + | property real thick: Theme.barSize // each dot's cell across the bar (its click area) | |
| 14 | 18 | ||
| 15 | 19 | readonly property var activeWs: monitor ? monitor.activeWorkspace : null | |
| 16 | 20 | readonly property int offset: activeWs && activeWs.id > 0 ? Math.floor((activeWs.id - 1) / 10) * 10 : 0 | |
| @@ -42,14 +46,14 @@ Row { | |||
| 42 | 46 | readonly property bool occupied: obj !== null && obj.toplevels.values.length > 0 | |
| 43 | 47 | readonly property bool urgent: obj !== null && obj.urgent | |
| 44 | 48 | ||
| 45 | − | width: dot.width | |
| 46 | − | height: ws.height | |
| 49 | + | width: ws.vertical ? ws.thick : dot.width | |
| 50 | + | height: ws.vertical ? dot.height : ws.thick | |
| 47 | 51 | ||
| 48 | 52 | Rectangle { | |
| 49 | 53 | id: dot | |
| 50 | − | anchors.verticalCenter: parent.verticalCenter | |
| 51 | − | width: b.active ? 26 : 8 | |
| 52 | − | height: 8 | |
| 54 | + | anchors.centerIn: parent | |
| 55 | + | width: b.active && !ws.vertical ? 26 : 8 | |
| 56 | + | height: b.active && ws.vertical ? 26 : 8 | |
| 53 | 57 | radius: 4 | |
| 54 | 58 | color: b.urgent && !b.active ? Theme.live | |
| 55 | 59 | : b.active ? (ws.monFocused ? Theme.fill : Theme.grey) | |
| @@ -59,13 +63,19 @@ Row { | |||
| 59 | 63 | enabled: Theme.motion | |
| 60 | 64 | NumberAnimation { duration: Theme.t; easing.type: Easing.BezierSpline; easing.bezierCurve: Theme.glide } | |
| 61 | 65 | } | |
| 66 | + | Behavior on height { | |
| 67 | + | enabled: Theme.motion | |
| 68 | + | NumberAnimation { duration: Theme.t; easing.type: Easing.BezierSpline; easing.bezierCurve: Theme.glide } | |
| 69 | + | } | |
| 62 | 70 | Behavior on color { enabled: Theme.motion; ColorAnimation { duration: Theme.t } } | |
| 63 | 71 | } | |
| 64 | 72 | MouseArea { | |
| 65 | 73 | id: m | |
| 66 | 74 | anchors.fill: parent | |
| 67 | − | anchors.leftMargin: -3 | |
| 68 | − | anchors.rightMargin: -3 | |
| 75 | + | anchors.leftMargin: ws.vertical ? 0 : -3 | |
| 76 | + | anchors.rightMargin: ws.vertical ? 0 : -3 | |
| 77 | + | anchors.topMargin: ws.vertical ? -3 : 0 | |
| 78 | + | anchors.bottomMargin: ws.vertical ? -3 : 0 | |
| 69 | 79 | hoverEnabled: true | |
| 70 | 80 | cursorShape: Qt.PointingHandCursor | |
| 71 | 81 | onClicked: Hypr.workspace(b.modelData) | |