diff --git a/dots/.config/hypr/hyprland/general.conf b/dots/.config/hypr/hyprland/general.conf index 2c79a857f..14074b345 100644 --- a/dots/.config/hypr/hyprland/general.conf +++ b/dots/.config/hypr/hyprland/general.conf @@ -6,8 +6,8 @@ monitor=,preferred,auto,1 # monitor=HDMI-A-1,1920x1080@60,1920x0,1,mirror,eDP-1 gesture = 3, swipe, move, +gesture = 3, pinch, float gesture = 4, horizontal, workspace -gesture = 4, pinch, float gesture = 4, up, dispatcher, global, quickshell:overviewToggle gesture = 4, down, dispatcher, global, quickshell:overviewClose gestures { @@ -62,7 +62,7 @@ decoration { brightness = 1 noise = 0.04 contrast = 1 - popups = true + popups = false popups_ignorealpha = 0.6 input_methods = true input_methods_ignorealpha = 0.8 diff --git a/dots/.config/hypr/hyprland/keybinds.conf b/dots/.config/hypr/hyprland/keybinds.conf index 294854d67..fdda9a714 100644 --- a/dots/.config/hypr/hyprland/keybinds.conf +++ b/dots/.config/hypr/hyprland/keybinds.conf @@ -53,6 +53,7 @@ bindd = Ctrl+Super, T, Toggle wallpaper selector, global, quickshell:wallpaperSe bindd = Ctrl+Super+Alt, T, Select random wallpaper, global, quickshell:wallpaperSelectorRandom # Random wallpaper bindd = Ctrl+Super, T, Change wallpaper, exec, qs -c $qsConfig ipc call TEST_ALIVE || ~/.config/quickshell/$qsConfig/scripts/colors/switchwall.sh # [hidden] Change wallpaper (fallback) bind = Ctrl+Super, R, exec, killall ags agsv1 gjs ydotool qs quickshell; qs -c $qsConfig & # Restart widgets +bind = Super+Alt, W, global, quickshell:panelFamilyCycle # Cycle panel family ##! Utilities # Screenshot, Record, OCR, Color picker, Clipboard history diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/README.md b/dots/.config/quickshell/ii/assets/icons/fluent/README.md new file mode 100644 index 000000000..5f4d3eaa2 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/README.md @@ -0,0 +1,5 @@ +The "search" and "task view" icons are from here, with modifications + +https://www.figma.com/community/file/1123040825921884189/windows-11 + +License: CC BY 4.0 diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-0.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-0.svg new file mode 100644 index 000000000..7fe9d7a3d --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-0.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_0_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-1.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-1.svg new file mode 100644 index 000000000..caa369c58 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-1.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_1_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-2.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-2.svg new file mode 100644 index 000000000..b939043ea --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-2.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_2_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-3.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-3.svg new file mode 100644 index 000000000..a504a1ed5 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-3.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_3_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-4.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-4.svg new file mode 100644 index 000000000..6567ddf10 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-4.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_4_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-5.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-5.svg new file mode 100644 index 000000000..1bf4d914f --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-5.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_5_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-6.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-6.svg new file mode 100644 index 000000000..145d9a7de --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-6.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_6_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-7.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-7.svg new file mode 100644 index 000000000..a5197ce94 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-7.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_7_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-8.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-8.svg new file mode 100644 index 000000000..c83bc5fb6 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-8.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_8_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-9.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-9.svg new file mode 100644 index 000000000..7f4937b99 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-9.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_9_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-charge.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-charge.svg new file mode 100644 index 000000000..512a78b1b --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-charge.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_charge_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-full.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-full.svg new file mode 100644 index 000000000..4749fc178 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-full.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_full_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-saver.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-saver.svg new file mode 100644 index 000000000..397061caf --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-saver.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_saver_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/battery-warning.svg b/dots/.config/quickshell/ii/assets/icons/fluent/battery-warning.svg new file mode 100644 index 000000000..7ccade277 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/battery-warning.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_battery_warning_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/bluetooth-connected.svg b/dots/.config/quickshell/ii/assets/icons/fluent/bluetooth-connected.svg new file mode 100644 index 000000000..b491276df --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/bluetooth-connected.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_bluetooth_connected_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/bluetooth-searching.svg b/dots/.config/quickshell/ii/assets/icons/fluent/bluetooth-searching.svg new file mode 100644 index 000000000..e0d9eab70 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/bluetooth-searching.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_bluetooth_searching_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/dismiss.svg b/dots/.config/quickshell/ii/assets/icons/fluent/dismiss.svg new file mode 100644 index 000000000..3cb3656dc --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/dismiss.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/ethernet.svg b/dots/.config/quickshell/ii/assets/icons/fluent/ethernet.svg new file mode 100644 index 000000000..904d9720e --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/ethernet.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_cellular_data_1_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/mic-on.svg b/dots/.config/quickshell/ii/assets/icons/fluent/mic-on.svg new file mode 100644 index 000000000..3f680d2e3 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/mic-on.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_mic_on_48_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/speaker-0.svg b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-0.svg new file mode 100644 index 000000000..0ff116afd --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-0.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_speaker_0_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/speaker-1.svg b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-1.svg new file mode 100644 index 000000000..eff9b6d0c --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-1.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_speaker_1_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/speaker-none.svg b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-none.svg new file mode 100644 index 000000000..364af84cb --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-none.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/speaker-off.svg b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-off.svg new file mode 100644 index 000000000..5fa19e406 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/speaker-off.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/speaker.svg b/dots/.config/quickshell/ii/assets/icons/fluent/speaker.svg new file mode 100644 index 000000000..477b04792 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/speaker.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-dark.svg b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-dark.svg new file mode 100644 index 000000000..2d972a7b4 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-dark.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/system-search-light.svg b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-light.svg new file mode 100644 index 000000000..b22f9c0ca --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/system-search-light.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/task-view-dark.svg b/dots/.config/quickshell/ii/assets/icons/fluent/task-view-dark.svg new file mode 100644 index 000000000..d38c927c8 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/task-view-dark.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/task-view-light.svg b/dots/.config/quickshell/ii/assets/icons/fluent/task-view-light.svg new file mode 100644 index 000000000..1f37c4aa4 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/task-view-light.svg @@ -0,0 +1,104 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/widgets.svg b/dots/.config/quickshell/ii/assets/icons/fluent/widgets.svg new file mode 100644 index 000000000..0989033a7 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/widgets.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wifi-1.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-1.svg new file mode 100644 index 000000000..47662e101 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-1.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_wifi_1_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wifi-2.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-2.svg new file mode 100644 index 000000000..9897c5d70 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-2.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_wifi_2_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wifi-3.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-3.svg new file mode 100644 index 000000000..8a4674bd4 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-3.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_wifi_3_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wifi-4.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-4.svg new file mode 100644 index 000000000..f14828bd8 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-4.svg @@ -0,0 +1,12 @@ + + + + ic_fluent_wifi_4_24_regular + Created with Sketch. + + + + + + + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wifi-off.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-off.svg new file mode 100644 index 000000000..3c247ab12 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-off.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/assets/icons/fluent/wifi-warning.svg b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-warning.svg new file mode 100644 index 000000000..d573ddde0 --- /dev/null +++ b/dots/.config/quickshell/ii/assets/icons/fluent/wifi-warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/dots/.config/quickshell/ii/modules/common/Config.qml b/dots/.config/quickshell/ii/modules/common/Config.qml index b6ac5ebe4..a724c043d 100644 --- a/dots/.config/quickshell/ii/modules/common/Config.qml +++ b/dots/.config/quickshell/ii/modules/common/Config.qml @@ -80,6 +80,7 @@ Singleton { property list enabledPanels: [ "iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector" ] + property string panelFamily: "ii" // "ii", "w" property JsonObject policies: JsonObject { property int ai: 1 // 0: No | 1: Yes | 2: Local @@ -521,6 +522,7 @@ Singleton { // https://doc.qt.io/qt-6/qtime.html#toString property string format: "hh:mm" property string shortDateFormat: "dd/MM" + property string dateWithYearFormat: "dd/MM/yyyy" property string dateFormat: "ddd, dd/MM" property JsonObject pomodoro: JsonObject { property int breakTime: 300 @@ -555,6 +557,13 @@ Singleton { property list linkKeywords: ["hentai", "porn", "sukebei", "hitomi.la", "rule34", "gelbooru", "fanbox", "dlsite"] } } + + property JsonObject waffles: JsonObject { + property JsonObject bar: JsonObject { + property bool bottom: true + property bool leftAlignApps: false + } + } } } } diff --git a/dots/.config/quickshell/ii/modules/common/widgets/PopupToolTip.qml b/dots/.config/quickshell/ii/modules/common/widgets/PopupToolTip.qml index 741b4556c..bc72ee416 100644 --- a/dots/.config/quickshell/ii/modules/common/widgets/PopupToolTip.qml +++ b/dots/.config/quickshell/ii/modules/common/widgets/PopupToolTip.qml @@ -1,3 +1,4 @@ +pragma ComponentBehavior: Bound import qs.modules.common import qs.modules.common.widgets import QtQuick @@ -13,15 +14,24 @@ Item { property real horizontalPadding: 10 property real verticalPadding: 5 + readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition property var anchorEdges: Edges.Top property var anchorGravity: anchorEdges - readonly property bool internalVisibleCondition: (extraVisibleCondition && (parent.hovered === undefined || parent?.hovered)) || alternativeVisibleCondition + property Item contentItem: StyledToolTipContent { + id: contentItem + anchors.centerIn: parent + text: root.text + shown: false + Component.onCompleted: shown = true + horizontalPadding: root.horizontalPadding + verticalPadding: root.verticalPadding + } Loader { id: tooltipLoader anchors.fill: parent - active: internalVisibleCondition + active: root.internalVisibleCondition sourceComponent: PopupWindow { visible: true anchor { @@ -35,18 +45,10 @@ Item { } color: "transparent" - implicitWidth: contentItem.implicitWidth + root.horizontalPadding * 2 - implicitHeight: contentItem.implicitHeight + root.verticalPadding * 2 + implicitWidth: root.contentItem.implicitWidth + root.horizontalPadding * 2 + implicitHeight: root.contentItem.implicitHeight + root.verticalPadding * 2 - StyledToolTipContent { - id: contentItem - anchors.centerIn: parent - text: root.text - shown: false - Component.onCompleted: shown = true - horizontalPadding: root.horizontalPadding - verticalPadding: root.verticalPadding - } + data: [root.contentItem] } } } diff --git a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml index cf8c739e0..c5803b6e2 100644 --- a/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml +++ b/dots/.config/quickshell/ii/modules/ii/background/widgets/clock/ClockWidget.qml @@ -70,7 +70,7 @@ AbstractBackgroundWidget { } ClockText { Layout.topMargin: -5 - text: DateTime.date + text: DateTime.longDate } StyledText { // Somehow gets fucked up if made a ClockText??? diff --git a/dots/.config/quickshell/ii/modules/ii/bar/Bar.qml b/dots/.config/quickshell/ii/modules/ii/bar/Bar.qml index 74f8b5f1b..71a64d76d 100644 --- a/dots/.config/quickshell/ii/modules/ii/bar/Bar.qml +++ b/dots/.config/quickshell/ii/modules/ii/bar/Bar.qml @@ -14,12 +14,14 @@ Scope { Variants { // For each monitor - model: { - const screens = Quickshell.screens; - const list = Config.options.bar.screenList; - if (!list || list.length === 0) - return screens; - return screens.filter(screen => list.includes(screen.name)); + model: ScriptModel { + values: { + const screens = Quickshell.screens; + const list = Config.options.bar.screenList; + if (!list || list.length === 0) + return screens; + return screens.filter(screen => list.includes(screen.name)); + } } LazyLoader { id: barLoader @@ -29,10 +31,6 @@ Scope { id: barRoot screen: barLoader.modelData - property var brightnessMonitor: Brightness.getMonitorForScreen(barLoader.modelData) - property real useShortenedForm: (Appearance.sizes.barHellaShortenScreenWidthThreshold >= screen.width) ? 2 : (Appearance.sizes.barShortenScreenWidthThreshold >= screen.width) ? 1 : 0 - readonly property int centerSideModuleWidth: (useShortenedForm == 2) ? Appearance.sizes.barCenterSideModuleWidthHellaShortened : (useShortenedForm == 1) ? Appearance.sizes.barCenterSideModuleWidthShortened : Appearance.sizes.barCenterSideModuleWidth - Timer { id: showBarTimer interval: (Config?.options.bar.autoHide.showWhenPressingSuper.delay ?? 100) diff --git a/dots/.config/quickshell/ii/modules/ii/bar/ClockWidget.qml b/dots/.config/quickshell/ii/modules/ii/bar/ClockWidget.qml index 895ad9be0..958695a86 100644 --- a/dots/.config/quickshell/ii/modules/ii/bar/ClockWidget.qml +++ b/dots/.config/quickshell/ii/modules/ii/bar/ClockWidget.qml @@ -33,7 +33,7 @@ Item { visible: root.showDate font.pixelSize: Appearance.font.pixelSize.small color: Appearance.colors.colOnLayer1 - text: DateTime.date + text: DateTime.longDate } } diff --git a/dots/.config/quickshell/ii/modules/ii/dock/DockAppButton.qml b/dots/.config/quickshell/ii/modules/ii/dock/DockAppButton.qml index 406eb3f57..41ed8cd07 100644 --- a/dots/.config/quickshell/ii/modules/ii/dock/DockAppButton.qml +++ b/dots/.config/quickshell/ii/modules/ii/dock/DockAppButton.qml @@ -17,8 +17,8 @@ DockButton { property real countDotHeight: 4 property bool appIsActive: appToplevel.toplevels.find(t => (t.activated == true)) !== undefined - property bool isSeparator: appToplevel.appId === "SEPARATOR" - property var desktopEntry: DesktopEntries.heuristicLookup(appToplevel.appId) + readonly property bool isSeparator: appToplevel.appId === "SEPARATOR" + readonly property var desktopEntry: DesktopEntries.heuristicLookup(appToplevel.appId) enabled: !isSeparator implicitWidth: isSeparator ? 1 : implicitHeight - topInset - bottomInset diff --git a/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml b/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml index 2bba6553a..d575b7dd4 100644 --- a/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml +++ b/dots/.config/quickshell/ii/modules/ii/dock/DockApps.qml @@ -1,6 +1,3 @@ -import qs.modules.common -import qs.modules.common.widgets -import qs.modules.common.functions import Qt5Compat.GraphicalEffects import QtQuick import QtQuick.Controls @@ -8,6 +5,10 @@ import QtQuick.Layouts import Quickshell import Quickshell.Widgets import Quickshell.Wayland +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.functions Item { id: root @@ -40,44 +41,7 @@ Item { model: ScriptModel { objectProp: "appId" - values: { - var map = new Map(); - - // Pinned apps - const pinnedApps = Config.options?.dock.pinnedApps ?? []; - for (const appId of pinnedApps) { - if (!map.has(appId.toLowerCase())) map.set(appId.toLowerCase(), ({ - pinned: true, - toplevels: [] - })); - } - - // Separator - if (pinnedApps.length > 0) { - map.set("SEPARATOR", { pinned: false, toplevels: [] }); - } - - // Ignored apps - const ignoredRegexStrings = Config.options?.dock.ignoredAppRegexes ?? []; - const ignoredRegexes = ignoredRegexStrings.map(pattern => new RegExp(pattern, "i")); - // Open windows - for (const toplevel of ToplevelManager.toplevels.values) { - if (ignoredRegexes.some(re => re.test(toplevel.appId))) continue; - if (!map.has(toplevel.appId.toLowerCase())) map.set(toplevel.appId.toLowerCase(), ({ - pinned: false, - toplevels: [] - })); - map.get(toplevel.appId.toLowerCase()).toplevels.push(toplevel); - } - - var values = []; - - for (const [key, value] of map) { - values.push({ appId: key, toplevels: value.toplevels, pinned: value.pinned }); - } - - return values; - } + values: TaskbarApps.apps } delegate: DockAppButton { required property var modelData diff --git a/dots/.config/quickshell/ii/modules/ii/overlay/OverlayBackground.qml b/dots/.config/quickshell/ii/modules/ii/overlay/OverlayBackground.qml index 205307cab..d91e4cbba 100644 --- a/dots/.config/quickshell/ii/modules/ii/overlay/OverlayBackground.qml +++ b/dots/.config/quickshell/ii/modules/ii/overlay/OverlayBackground.qml @@ -4,5 +4,5 @@ import qs.modules.common Rectangle { id: contentItem anchors.fill: parent - color: Appearance.m3colors.m3surfaceContainer + color: Appearance.colors.colSurfaceContainer } diff --git a/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml b/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml index 46d83f7de..5eb409ecb 100644 --- a/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml +++ b/dots/.config/quickshell/ii/modules/ii/sidebarRight/volumeMixer/VolumeDialogContent.qml @@ -44,7 +44,7 @@ ColumnLayout { Layout.fillHeight: false Layout.fillWidth: true Layout.bottomMargin: 6 - model: root.devices.map(node => node.description) + model: root.devices.map(node => (node.nickname || node.description || Translation.tr("Unknown"))) currentIndex: root.devices.findIndex(item => { if (root.isSink) { return item.id === Pipewire.preferredDefaultAudioSink?.id diff --git a/dots/.config/quickshell/ii/modules/waffle/background/WaffleBackground.qml b/dots/.config/quickshell/ii/modules/waffle/background/WaffleBackground.qml new file mode 100644 index 000000000..caaff1707 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/background/WaffleBackground.qml @@ -0,0 +1,46 @@ +pragma ComponentBehavior: Bound + +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.common.widgets.widgetCanvas +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland + +import qs.modules.ii.background.widgets +import qs.modules.ii.background.widgets.clock +import qs.modules.ii.background.widgets.weather + +Variants { + id: root + model: Quickshell.screens + + PanelWindow { + id: panelRoot + required property var modelData + + screen: modelData + exclusionMode: ExclusionMode.Ignore + WlrLayershell.layer: WlrLayer.Bottom + WlrLayershell.namespace: "quickshell:background" + anchors { + top: true + bottom: true + left: true + right: true + } + color: "transparent" + + StyledImage { + anchors.fill: parent + source: Config.options.background.wallpaperPath + fillMode: Image.PreserveAspectCrop + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml new file mode 100644 index 000000000..a35e12a2e --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/AppButton.qml @@ -0,0 +1,86 @@ +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import org.kde.kirigami as Kirigami +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +BarButton { + id: root + + required property string iconName + property bool multiple: false + property bool separateLightDark: false + property alias tryCustomIcon: iconWidget.tryCustomIcon + leftInset: 2 + rightInset: 2 + implicitWidth: height - topInset - bottomInset + leftInset + rightInset + + onDownChanged: { + scaleAnim.duration = root.down ? 150 : 200 + scaleAnim.easing.bezierCurve = root.down ? Looks.transition.easing.bezierCurve.easeIn : Looks.transition.easing.bezierCurve.easeOut + contentItem.scale = root.down ? 5/6 : 1 // If/When we do dragging, the scale is 1.25 + } + + background: Item { + BackgroundAcrylicRectangle { + id: mainBgRect + anchors.fill: parent + layer.enabled: root.multiple + layer.effect: OpacityMask { + invert: true + maskSource: Item { + width: mainBgRect.width + height: mainBgRect.height + Rectangle { + anchors.fill: parent + anchors.rightMargin: 3 + radius: mainBgRect.radius + } + } + } + } + Loader { + anchors.fill: parent + anchors.rightMargin: 5 + active: root.multiple + sourceComponent: BackgroundAcrylicRectangle { + + } + } + } + + contentItem: Item { + id: contentItem + anchors.centerIn: parent + + implicitHeight: iconWidget.implicitHeight + implicitWidth: iconWidget.implicitWidth + + Behavior on scale { + NumberAnimation { + id: scaleAnim + easing.type: Easing.BezierSpline + } + } + + AppIcon { + id: iconWidget + anchors.centerIn: parent + iconName: root.iconName + separateLightDark: root.separateLightDark + } + } + + component BackgroundAcrylicRectangle: AcrylicRectangle { + shiny: ((root.hovered && !root.down) || root.checked) + color: root.colBackground + border.width: 1 + border.color: root.colBackgroundBorder + + Behavior on border.color { + animation: Looks.transition.color.createObject(this) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml b/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml new file mode 100644 index 000000000..f70a80603 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/AppIcon.qml @@ -0,0 +1,19 @@ +import QtQuick +import org.kde.kirigami as Kirigami +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +Kirigami.Icon { + id: root + required property string iconName + property bool separateLightDark: false + property bool tryCustomIcon: true + + property real implicitSize: 26 + implicitWidth: implicitSize + implicitHeight: implicitSize + roundToIconSize: false + fallback: root.iconName + source: tryCustomIcon ? `${Looks.iconsPath}/${root.iconName}${!root.separateLightDark ? "" : Looks.dark ? "-dark" : "-light"}.svg` : fallback +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml new file mode 100644 index 000000000..ce1a4cdc7 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/BarButton.qml @@ -0,0 +1,77 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +Button { + id: root + + signal altAction() + signal middleClickAction() + + property color colBackground + property color colBackgroundBorder + Layout.fillHeight: true + topInset: 4 + bottomInset: 4 + + signal hoverTimedOut() + property bool shouldShowTooltip: false + property Timer hoverTimer: Timer { + id: hoverTimer + running: root.hovered + interval: 400 + onTriggered: { + root.hoverTimedOut() + } + } + onHoverTimedOut: { + root.shouldShowTooltip = true + } + onHoveredChanged: { + if (!root.hovered) { + root.shouldShowTooltip = false + root.hoverTimer.stop() + } + } + + colBackground: { + if (root.down) { + return Looks.colors.bg1Active + } else if ((root.hovered && !root.down) || root.checked) { + return Looks.colors.bg1Hover + } else { + return ColorUtils.transparentize(Looks.colors.bg1) + } + } + colBackgroundBorder: ColorUtils.transparentize(Looks.colors.bg1Border, root.checked ? Looks.contentTransparency : 1) + + MouseArea { + anchors.fill: parent + acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton + onPressed: (event) => { + root.down = true; + } + onReleased: (event) => { + root.down = false; + } + onClicked: (event) => { + if (event.button === Qt.LeftButton) root.clicked(); + if (event.button === Qt.RightButton) root.altAction(); + if (event.button === Qt.MiddleButton) root.middleClickAction(); + } + } + + background: AcrylicRectangle { + shiny: ((root.hovered && !root.down) || root.checked) + color: root.colBackground + border.width: 1 + border.color: root.colBackgroundBorder + + Behavior on border.color { + animation: Looks.transition.color.createObject(this) + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/BarToolTip.qml b/dots/.config/quickshell/ii/modules/waffle/bar/BarToolTip.qml new file mode 100644 index 000000000..d38566fdd --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/BarToolTip.qml @@ -0,0 +1,8 @@ +import QtQuick +import Quickshell +import qs.modules.common +import qs.modules.waffle.looks + +WPopupToolTip { + anchorEdges: Config.options.waffles.bar.bottom ? Edges.Top : Edges.Bottom +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/SearchButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/SearchButton.qml new file mode 100644 index 000000000..a86faaece --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/SearchButton.qml @@ -0,0 +1,24 @@ +import QtQuick +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +AppButton { + id: root + + iconName: "system-search" + separateLightDark: true + + onClicked: { + GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now... + } + + BarToolTip { + id: tooltip + text: Translation.tr("Search") + extraVisibleCondition: root.shouldShowTooltip + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml new file mode 100644 index 000000000..4595802ee --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/StartButton.qml @@ -0,0 +1,24 @@ +import QtQuick +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +AppButton { + id: root + + leftInset: Config.options.waffles.bar.leftAlignApps ? 12 : 0 + iconName: "start-here" + + onClicked: { + GlobalStates.overviewOpen = !GlobalStates.overviewOpen; // For now... + } + + BarToolTip { + id: tooltip + text: Translation.tr("Start") + extraVisibleCondition: root.shouldShowTooltip + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml new file mode 100644 index 000000000..1de9654d5 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/SystemButton.qml @@ -0,0 +1,95 @@ +import QtQuick +import QtQuick.Layouts +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +BarButton { + id: root + + checked: GlobalStates.sidebarRightOpen + onClicked: { + GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; // For now... + } + + contentItem: Item { + anchors.fill: parent + implicitHeight: column.implicitHeight + implicitWidth: column.implicitWidth + Row { + id: column + anchors { + top: parent.top + bottom: parent.bottom + horizontalCenter: parent.horizontalCenter + } + spacing: 4 + + IconHoverArea { + id: internetHoverArea + iconItem: FluentIcon { + anchors.verticalCenter: parent.verticalCenter + icon: WIcons.internetIcon + } + } + + IconHoverArea { + id: volumeHoverArea + iconItem: FluentIcon { + anchors.verticalCenter: parent.verticalCenter + icon: { + const muted = Audio.sink?.audio.muted ?? false; + const volume = Audio.sink?.audio.volume ?? 0; + if (muted) + return volume > 0 ? "speaker-off" : "speaker-none"; + if (volume == 0) + return "speaker-none"; + if (volume < 0.5) + return "speaker-1"; + return "speaker"; + } + } + } + + IconHoverArea { + id: batteryHoverArea + iconItem: FluentIcon { + anchors.verticalCenter: parent.verticalCenter + icon: WIcons.batteryIcon + } + } + } + } + + component IconHoverArea: MouseArea { + id: hoverArea + required property var iconItem + anchors { + top: parent.top + bottom: parent.bottom + } + hoverEnabled: true + implicitHeight: hoverArea.iconItem.implicitHeight + implicitWidth: hoverArea.iconItem.implicitWidth + + onPressed: (event) => event.accepted = false; // Don't consume clicks + + children: [iconItem] + } + + BarToolTip { + extraVisibleCondition: root.shouldShowTooltip && internetHoverArea.containsMouse + text: Translation.tr("%1\nInternet access").arg(Network.ethernet ? Translation.tr("Network") : Network.networkName) + } + BarToolTip { + extraVisibleCondition: root.shouldShowTooltip && volumeHoverArea.containsMouse + text: Translation.tr("Speakers (%1): %2") // + .arg(Audio.sink?.nickname || Audio.sink?.description || Translation.tr("Unknown")) // + .arg(`${Math.round(Audio.sink?.audio.volume * 100) || 0}%`) // + } + BarToolTip { + extraVisibleCondition: root.shouldShowTooltip && batteryHoverArea.containsMouse + text: Translation.tr("Battery: %1").arg(`${Math.round(Battery.percentage * 100) || 0}%`) + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/TaskViewButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/TaskViewButton.qml new file mode 100644 index 000000000..cc35c8b41 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/TaskViewButton.qml @@ -0,0 +1,24 @@ +import QtQuick +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +AppButton { + id: root + + iconName: "task-view" + separateLightDark: true + + checked: GlobalStates.overviewOpen + onClicked: { + GlobalStates.overviewOpen = !GlobalStates.overviewOpen; + } + + BarToolTip { + extraVisibleCondition: root.shouldShowTooltip + text: Translation.tr("Task View") // Should be a preview of workspaces, but we'll have this for now... + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/TimeButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/TimeButton.qml new file mode 100644 index 000000000..bb813c85c --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/TimeButton.qml @@ -0,0 +1,42 @@ +import QtQuick +import QtQuick.Layouts +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +BarButton { + id: root + + rightInset: 12 // For now this is the rightmost button. Desktop peek is useless. (for now) + padding: 12 + + checked: GlobalStates.sidebarRightOpen + onClicked: { + GlobalStates.sidebarRightOpen = !GlobalStates.sidebarRightOpen; + } + + contentItem: Item { + anchors.centerIn: root.background + implicitHeight: column.implicitHeight + implicitWidth: column.implicitWidth + Column { + id: column + anchors.centerIn: parent + WText { + anchors.right: parent.right + text: DateTime.time + } + WText { + anchors.right: parent.right + text: DateTime.date + } + } + } + + BarToolTip { + id: tooltip + extraVisibleCondition: root.shouldShowTooltip + text: `${Qt.locale().toString(DateTime.clock.date, "dddd, MMMM d, yyyy")}\n\n${Qt.locale().toString(DateTime.clock.date, "ddd hh:mm AP")}` + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/WaffleBar.qml b/dots/.config/quickshell/ii/modules/waffle/bar/WaffleBar.qml new file mode 100644 index 000000000..aa5f51f68 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/WaffleBar.qml @@ -0,0 +1,89 @@ +import QtQuick +import Quickshell +import Quickshell.Io +import Quickshell.Wayland +import Quickshell.Hyprland +import qs +import qs.services +import qs.modules.common +import qs.modules.common.widgets + +Scope { + id: bar + property bool showBarBackground: Config.options.bar.showBackground + + LazyLoader { + id: barLoader + active: GlobalStates.barOpen && !GlobalStates.screenLocked + component: Variants { + model: Quickshell.screens + delegate: PanelWindow { // Bar window + id: barRoot + required property var modelData + screen: modelData + exclusionMode: ExclusionMode.Ignore + exclusiveZone: implicitHeight + WlrLayershell.namespace: "quickshell:bar" + + anchors { + left: true + right: true + bottom: Config.options.waffles.bar.bottom + top: !Config.options.waffles.bar.bottom + } + + color: "transparent" + implicitHeight: content.implicitHeight + implicitWidth: content.implicitWidth + + WaffleBarContent { + id: content + anchors.fill: parent + } + } + } + } + + IpcHandler { + target: "bar" + + function toggle(): void { + GlobalStates.barOpen = !GlobalStates.barOpen + } + + function close(): void { + GlobalStates.barOpen = false + } + + function open(): void { + GlobalStates.barOpen = true + } + } + + GlobalShortcut { + name: "barToggle" + description: "Toggles bar on press" + + onPressed: { + GlobalStates.barOpen = !GlobalStates.barOpen; + } + } + + GlobalShortcut { + name: "barOpen" + description: "Opens bar on press" + + onPressed: { + GlobalStates.barOpen = true; + } + } + + GlobalShortcut { + name: "barClose" + description: "Closes bar on press" + + onPressed: { + GlobalStates.barOpen = false; + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/WaffleBarContent.qml b/dots/.config/quickshell/ii/modules/waffle/bar/WaffleBarContent.qml new file mode 100644 index 000000000..aa064118a --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/WaffleBarContent.qml @@ -0,0 +1,80 @@ +import QtQuick +import QtQuick.Layouts +import qs.modules.common +import qs.modules.common.widgets +import qs.modules.waffle.looks +import qs.modules.waffle.bar.tasks + +Rectangle { + id: root + + color: Looks.colors.bg0 + implicitHeight: 48 + + Rectangle { + id: border + anchors { + left: parent.left + right: parent.right + top: Config.options.waffles.bar.bottom ? parent.top : undefined + bottom: Config.options.waffles.bar.bottom ? undefined : parent.bottom + } + color: Looks.colors.bg0Border + implicitHeight: 1 + } + + BarGroupRow { + id: bloatRow + anchors.left: parent.left + opacity: Config.options.waffles.bar.leftAlignApps ? 0 : 1 + visible: opacity > 0 + Behavior on opacity { + animation: Looks.transition.opacity.createObject(this) + } + + WidgetsButton {} + } + + BarGroupRow { + id: appsRow + anchors.left: undefined + anchors.horizontalCenter: parent.horizontalCenter + + states: State { + name: "left" + when: Config.options.waffles.bar.leftAlignApps + AnchorChanges { + target: appsRow + anchors.left: parent.left + anchors.horizontalCenter: undefined + } + } + + transitions: Transition { + animations: Looks.transition.anchor.createObject(this) + } + + StartButton {} + SearchButton {} + TaskViewButton {} + Tasks {} + } + + BarGroupRow { + id: systemRow + anchors.right: parent.right + FadeLoader { + Layout.fillHeight: true + shown: Config.options.waffles.bar.leftAlignApps + sourceComponent: WidgetsButton {} + } + SystemButton {} + TimeButton {} + } + + component BarGroupRow: RowLayout { + anchors.top: parent.top + anchors.bottom: parent.bottom + spacing: 0 + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml new file mode 100644 index 000000000..1c6c11859 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/WidgetsButton.qml @@ -0,0 +1,60 @@ +import QtQuick +import QtQuick.Layouts +import org.kde.kirigami as Kirigami +import qs +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +AppButton { + id: root + + readonly property bool expandedForm: Config.options.waffles.bar.leftAlignApps + leftInset: Config.options.waffles.bar.leftAlignApps ? 0 : 12 + implicitWidth: expandedForm ? 148 : (height - topInset - bottomInset + leftInset + rightInset) + iconName: "widgets" + + checked: GlobalStates.sidebarLeftOpen + onClicked: { + GlobalStates.sidebarLeftOpen = !GlobalStates.sidebarLeftOpen + } + + contentItem: Item { + anchors { + verticalCenter: parent.verticalCenter + left: root.expandedForm ? parent.left : undefined + horizontalCenter: root.expandedForm ? undefined : background.horizontalCenter + } + implicitHeight: row.implicitHeight + implicitWidth: row.implicitWidth + Row { + id: row + anchors { + verticalCenter: parent.verticalCenter + left: root.expandedForm ? parent.left : undefined + horizontalCenter: root.expandedForm ? undefined : parent.horizontalCenter + margins: 8 + } + spacing: 6 + + AppIcon { + id: iconWidget + anchors.verticalCenter: parent.verticalCenter + iconName: root.iconName + } + + Column { + visible: root.expandedForm + anchors.verticalCenter: parent.verticalCenter + WText { + text: Translation.tr("Widgets") + } + } + } + } + + BarToolTip { + extraVisibleCondition: root.shouldShowTooltip + text: Translation.tr("Widgets") + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml new file mode 100644 index 000000000..53b68b82c --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskAppButton.qml @@ -0,0 +1,77 @@ +import QtQuick +import QtQuick.Layouts +import qs.services +import qs.modules.common +import qs.modules.waffle.looks +import qs.modules.waffle.bar +import Quickshell + +AppButton { + id: root + + required property var appEntry + readonly property bool isSeparator: appEntry.appId === "SEPARATOR" + readonly property var desktopEntry: DesktopEntries.heuristicLookup(appEntry.appId) + property bool active: root.appEntry.toplevels.some(t => t.activated) + property bool hasWindows: appEntry.toplevels.length > 0 + + signal hoverPreviewRequested() + + multiple: appEntry.toplevels.length > 1 + checked: active + iconName: AppSearch.guessIcon(appEntry.appId) + tryCustomIcon: false + + onHoverTimedOut: { + root.hoverPreviewRequested() + } + + onClicked: { + root.hoverTimer.stop() // Prevents preview showing up when clicking to focus + if (root.multiple) { + root.hoverPreviewRequested() + } else if (root.appEntry.toplevels.length === 1) { + root.appEntry.toplevels[0].activate() + } else { + root.desktopEntry.execute() + } + } + + onMiddleClickAction: { + if (root.desktopEntry) { + desktopEntry.execute() + } + } + + // Active indicator + Rectangle { + id: activeIndicator + opacity: root.hasWindows ? 1 : 0 + anchors { + horizontalCenter: root.background.horizontalCenter + bottom: root.background.bottom + bottomMargin: 1 + } + + implicitWidth: root.active ? 16 : 6 + implicitHeight: 3 + radius: height / 2 + + color: root.active ? Looks.colors.accent : Looks.colors.accentUnfocused + + Behavior on implicitWidth { + animation: Looks.transition.enter.createObject(this) + } + Behavior on color { + animation: Looks.transition.color.createObject(this) + } + Behavior on opacity { + animation: Looks.transition.opacity.createObject(this) + } + } + + BarToolTip { + extraVisibleCondition: root.shouldShowTooltip && !root.hasWindows + text: desktopEntry ? desktopEntry.name : appEntry.appId + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskPreview.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskPreview.qml new file mode 100644 index 000000000..6d8aeba1a --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/TaskPreview.qml @@ -0,0 +1,128 @@ +import QtQuick +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks +import Quickshell + +PopupWindow { + id: root + + ///////////////////// Properties //////////////////// + required property bool tasksHovered + property var appEntry + property Item anchorItem + + //////////////////// Functions //////////////////// + function close() { + marginBehavior.enabled = false; + root.visible = false; + } + + function open() { + marginBehavior.enabled = true; + root.visible = true; + } + + function show(appEntry: var, button: Item) { + root.appEntry = appEntry; + root.anchorItem = button; + root.anchor.updateAnchor(); + root.open(); + } + + ///////////////////// Internals ///////////////////// + readonly property bool bottom: Config.options.waffles.bar.bottom + property real visualMargin: 12 + property alias ambientShadowWidth: ambientShadow.border.width + + visible: false + color: "transparent" + implicitWidth: contentItem.implicitWidth + ambientShadowWidth + (visualMargin * 2) + implicitHeight: contentItem.implicitHeight + ambientShadowWidth + (visualMargin * 2) + anchor { + adjustment: PopupAdjustment.Slide + item: root.anchorItem + gravity: bottom ? Edges.Top : Edges.Bottom + edges: bottom ? Edges.Top : Edges.Bottom + } + + Timer { + interval: 250 + running: root.visible && !hoverChecker.containsMouse && !root.tasksHovered + onTriggered: { + root.close(); + } + } + + // Content + MouseArea { + id: hoverChecker + anchors.fill: parent + hoverEnabled: true + + // Shadow + Rectangle { + id: ambientShadow + anchors { + fill: contentItem + margins: -border.width + } + border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.shadowTransparency) + border.width: 1 + color: "transparent" + radius: Looks.radius.large + border.width + } + + Rectangle { + id: contentItem + property real sourceEdgeMargin: root.visible ? (root.ambientShadowWidth + root.visualMargin) : -root.implicitHeight + Behavior on sourceEdgeMargin { + id: marginBehavior + animation: Looks.transition.enter.createObject(this) + } + anchors { + left: parent.left + right: parent.right + top: root.bottom ? undefined : parent.top + bottom: root.bottom ? parent.bottom : undefined + margins: root.ambientShadowWidth + root.visualMargin + // Opening anim + bottomMargin: root.bottom ? sourceEdgeMargin : (root.ambientShadowWidth + root.visualMargin) + topMargin: root.bottom ? (root.ambientShadowWidth + root.visualMargin) : sourceEdgeMargin + } + color: Looks.colors.bg1 + radius: Looks.radius.large + + layer.enabled: true + layer.effect: OpacityMask { + maskSource: Rectangle { + width: contentItem.width + height: contentItem.height + radius: contentItem.radius + } + } + + // Testing + implicitHeight: Math.min(158, windowsRow.implicitHeight) + implicitWidth: windowsRow.implicitWidth + + RowLayout { + id: windowsRow + anchors.fill: parent + + Repeater { + model: ScriptModel { + values: root.appEntry?.toplevels ?? [] + } + delegate: WindowPreview { + required property var modelData + toplevel: modelData + } + } + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/Tasks.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/Tasks.qml new file mode 100644 index 000000000..895b1353f --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/Tasks.qml @@ -0,0 +1,49 @@ +import QtQuick +import QtQuick.Layouts +import Quickshell +import qs.services +import qs.modules.common +import qs.modules.waffle.looks + +MouseArea { + id: root + + Layout.fillHeight: true + implicitHeight: row.implicitHeight + implicitWidth: row.implicitWidth + hoverEnabled: true + + function showPreviewPopup(appEntry, button) { + previewPopup.show(appEntry, button); + } + + // Apps row + RowLayout { + id: row + anchors.fill: parent + spacing: 0 + + Repeater { + // TODO: Include only apps (and windows) in current workspace only | wait, does that even make sense in a Hyprland workflow? + model: ScriptModel { + objectProp: "appId" + values: TaskbarApps.apps.filter(app => app.appId !== "SEPARATOR") + } + delegate: TaskAppButton { + required property var modelData + appEntry: modelData + + onHoverPreviewRequested: { + root.showPreviewPopup(appEntry, this) + } + } + } + } + + // Previews popup + TaskPreview { + id: previewPopup + tasksHovered: root.containsMouse + anchor.window: root.QsWindow.window + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml new file mode 100644 index 000000000..2839a6747 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/bar/tasks/WindowPreview.qml @@ -0,0 +1,136 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Qt5Compat.GraphicalEffects +import qs.services +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks +import qs.modules.waffle.bar +import Quickshell +import Quickshell.Wayland + +Button { + id: root + + required property var toplevel + property real previewWidthConstraint: 200 + property real previewHeightConstraint: 110 + padding: 5 + Layout.fillHeight: true + + onClicked: { + root.toplevel.activate(); // TODO: make this work with those who disable focus on activate because telegram is abusive + } + + background: Rectangle { + id: background + radius: Looks.radius.medium + color: root.down ? Looks.colors.bg2Active : (root.hovered ? Looks.colors.bg2Hover : ColorUtils.transparentize(Looks.colors.bg2)) + Behavior on color { + animation: Looks.transition.color.createObject(this) + } + } + + contentItem: ColumnLayout { + id: contentItem + anchors.fill: parent + anchors.margins: root.padding + spacing: 5 + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + spacing: 8 + + AppIcon { + id: appIcon + Layout.leftMargin: Looks.radius.large - root.padding + 2 + Layout.alignment: Qt.AlignVCenter + iconName: AppSearch.guessIcon(root.toplevel.appId) + implicitSize: 16 + } + + Item { + id: appTitleContainer + Layout.fillWidth: true + Layout.fillHeight: true + implicitHeight: closeButton.implicitHeight // Enforce height, because closeButton doesn't contribute when it's invisible + WText { + id: appTitleText + anchors.fill: parent + text: root.toplevel.title + elide: Text.ElideRight + font.pixelSize: Looks.font.pixelSize.large + font.weight: Looks.font.weight.thin + color: Looks.colors.fg1 + } + } + + CloseButton { + id: closeButton + } + } + + Item { + Layout.fillWidth: true + Layout.fillHeight: true + Layout.margins: Looks.radius.large - root.padding + Layout.topMargin: 0 + implicitWidth: Math.max(screencopyView.implicitWidth, 80) + implicitHeight: screencopyView.implicitHeight + + ScreencopyView { + id: screencopyView + anchors.centerIn: parent + captureSource: root.toplevel + live: true + paintCursor: true + constraintSize: Qt.size(root.previewWidthConstraint, root.previewHeightConstraint) + } + } + } + + component CloseButton: Button { + id: reusableCloseButton + visible: root.hovered + Layout.leftMargin: 4 + implicitHeight: 30 + implicitWidth: 30 + onClicked: { + root.toplevel.close(); + } + + Rectangle { + z: 0 + color: "transparent" + anchors.fill: closeButtonBg + anchors.margins: -1 + opacity: closeButtonBg.opacity + border.width: 1 + radius: closeButtonBg.radius + 1 + border.color: Looks.colors.bg2Border + } + + background: Rectangle { + id: closeButtonBg + z: 1 + opacity: reusableCloseButton.hovered ? 1 : 0 + radius: Looks.radius.large - root.padding + color: reusableCloseButton.pressed ? Looks.colors.dangerActive : Looks.colors.danger + Behavior on opacity { + animation: Looks.transition.opacity.createObject(this) + } + Behavior on color { + animation: Looks.transition.color.createObject(this) + } + } + + contentItem: FluentIcon { + z: 2 + anchors.centerIn: parent + icon: "dismiss" + implicitSize: 10 + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml new file mode 100644 index 000000000..3720d6186 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/AcrylicRectangle.qml @@ -0,0 +1,63 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import qs.modules.common +import qs.modules.common.functions +import qs.modules.waffle.looks + +Rectangle { + id: root + + property bool shiny: true // Top border + property color borderColor: ColorUtils.transparentize(Looks.colors.bg1Border, shiny ? Looks.contentTransparency : 1) + color: Looks.colors.bg1Hover + radius: Looks.radius.medium + Behavior on color { + animation: Looks.transition.color.createObject(this) + } + Behavior on borderColor { + animation: Looks.transition.color.createObject(this) + } + onBorderColorChanged: { + borderCanvas.requestPaint(); + } + + // Top 1px border with color + Canvas { + id: borderCanvas + anchors.fill: parent + onPaint: { + var ctx = getContext("2d"); + ctx.clearRect(0, 0, width, height); + + var borderColor = root.borderColor; + + var r = root.radius; + var fadeLength = Math.max(1, r); + var fadeLengthPercent = fadeLength / width; + + // Compute normalized stops + var leftFadeStop = fadeLengthPercent; + var rightFadeStop = 1 - fadeLengthPercent; + + var grad = ctx.createLinearGradient(0, 0, width, 0); + grad.addColorStop(0, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0)); + grad.addColorStop(leftFadeStop, borderColor); + grad.addColorStop(rightFadeStop, borderColor); + grad.addColorStop(1, Qt.rgba(borderColor.r, borderColor.g, borderColor.b, 0)); + + ctx.strokeStyle = grad; + ctx.lineWidth = 1; + + ctx.beginPath(); + ctx.moveTo(r, 0.5); + ctx.lineTo(width - r, 0.5); + // Top-right curve + ctx.arcTo(width, 0.5, width, r + 0.5, r); + // Top-left curve + ctx.moveTo(width - r, 0.5); + ctx.arcTo(0, 0.5, 0, r + 0.5, r); + ctx.stroke(); + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/FluentIcon.qml b/dots/.config/quickshell/ii/modules/waffle/looks/FluentIcon.qml new file mode 100644 index 000000000..81b6ebf08 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/FluentIcon.qml @@ -0,0 +1,21 @@ +import QtQuick +import org.kde.kirigami as Kirigami +import qs.modules.common +import qs.modules.waffle.looks + +Kirigami.Icon { + id: root + required property string icon + // Should be 16, but it appears the icons have some padding, + // Unlike the Windows-only Segoe UI icons, the open source FluentUI ones are hella small + property int implicitSize: 20 + implicitWidth: implicitSize + implicitHeight: implicitSize + + source: `${Looks.iconsPath}/${root.icon}.svg` + fallback: root.icon + roundToIconSize: false + color: Looks.colors.fg + isMask: true + animated: true +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml new file mode 100644 index 000000000..09176830f --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/Looks.qml @@ -0,0 +1,126 @@ +pragma ComponentBehavior: Bound +pragma Singleton + +import QtQuick +import Quickshell +import qs.modules.common +import qs.modules.common.functions + +Singleton { + id: root + property QtObject colors + property QtObject radius + property QtObject font + property QtObject transition + property string iconsPath: `${Directories.assetsPath}/icons/fluent` + property bool dark: Appearance.m3colors.darkmode + + property real backgroundTransparency: 0.17 + property real contentTransparency: 0.25 + property real shadowTransparency: 0.6 + colors: QtObject { + id: colors + property color bg0: root.dark ? "#1C1C1C" : "#EEEEEE" + property color bg0Border: root.dark ? "#404040" : "#BEBEBE" + property color bg1: root.dark ? "#2C2C2C" : "#F7F7F7" + property color bg1Hover: root.dark ? "#292929" : "#F7F7F7" + property color bg1Active: root.dark ? "#252525" : "#F3F3F3" + property color bg1Border: root.dark ? "#333333" : "#E9E9E9" + property color bg2: root.dark ? "#313131" : "#FBFBFB" + property color bg2Hover: root.dark ? "#383838" : "#FDFDFD" + property color bg2Active: root.dark ? "#333333" : "#FDFDFD" + property color bg2Border: root.dark ? "#464646" : "#EEEEEE" + property color fg: root.dark ? "#FFFFFF" : "#000000" + property color fg1: root.dark ? "#D1D1D1" : "#626262" + property color danger: "#C42B1C" + property color dangerActive: "#B62D1F" + // property color accent: root.dark ? "#A5C6D8" : "#5377A3" + property color accent: Appearance.m3colors.m3primary + property color accentUnfocused: root.dark ? "#989898" : "#848484" + } + + radius: QtObject { + id: radius + property int none: 0 + property int small: 2 + property int medium: 4 + property int large: 8 + property int xLarge: 12 + } + + font: QtObject { + id: font + property QtObject family: QtObject { + property string ui: "Noto Sans" + } + property QtObject weight: QtObject { // Noto is not Segoe, so we might use slightly different weights + property int thin: Font.Normal + property int regular: Font.Medium + property int strong: Font.DemiBold + property int stronger: Font.Bold + } + property QtObject pixelSize: QtObject { + property real normal: 11 + property real large: 15 + } + } + + transition: QtObject { + id: transition + property QtObject easing: QtObject { + property QtObject bezierCurve: QtObject { + readonly property list easeInOut: [0.42,0.00,0.58,1.00,1,1] + readonly property list easeIn: [0,1,1,1,1,1] + readonly property list easeOut: [1,0,1,1,1,1] + } + } + + property Component color: Component { + ColorAnimation { + duration: 120 + easing.type: Easing.BezierSpline + easing.bezierCurve: transition.easing.bezierCurve.easeIn + } + } + + property Component opacity: Component { + NumberAnimation{ + duration: 120 + easing.type: Easing.BezierSpline + easing.bezierCurve: transition.easing.bezierCurve.easeIn + } + } + + property Component enter: Component { + NumberAnimation { + duration: 250 + easing.type: Easing.BezierSpline + easing.bezierCurve: transition.easing.bezierCurve.easeIn + } + } + + property Component exit: Component { + NumberAnimation { + duration: 250 + easing.type: Easing.BezierSpline + easing.bezierCurve: transition.easing.bezierCurve.easeOut + } + } + + property Component move: Component { + NumberAnimation { + duration: 170 + easing.type: Easing.BezierSpline + easing.bezierCurve: transition.easing.bezierCurve.easeInOut + } + } + + property Component anchor: Component { + AnchorAnimation { + duration: 160 + easing.type: Easing.BezierSpline + easing.bezierCurve: transition.easing.bezierCurve.easeIn + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml new file mode 100644 index 000000000..813b0a1ce --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WIcons.qml @@ -0,0 +1,31 @@ +pragma Singleton +import QtQuick +import Quickshell +import qs.services + +Singleton { + id: root + + property string internetIcon: { + if (Network.ethernet) return "ethernet"; + if (Network.wifiEnabled) { + const strength = Network.networkStrength; + if (strength > 75) return "wifi-1"; + if (strength > 50) return "wifi-2"; + if (strength > 25) return "wifi-3"; + return "wifi-4"; + } + if (Network.wifiStatus === "connecting") return "wifi-4"; + if (Network.wifiStatus === "disconnected") return "wifi-off"; + if (Network.wifiStatus === "disabled") return "wifi-off"; + return "wifi-warning"; + } + + property string batteryIcon: { + if (Battery.isCharging) return "battery-charge"; + if (Battery.isCriticalAndNotCharging) return "battery-warning"; + if (Battery.percentage >= 0.9) return "battery-full"; + return `battery-${Math.ceil(Battery.percentage * 10)}`; + } + +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WPopupToolTip.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WPopupToolTip.qml new file mode 100644 index 000000000..b35258204 --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WPopupToolTip.qml @@ -0,0 +1,51 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Quickshell +import qs.modules.common +import qs.modules.common.functions +import qs.modules.common.widgets +import qs.modules.waffle.looks + +PopupToolTip { + id: root + + property real padding: 2 + verticalPadding: padding + horizontalPadding: padding + + contentItem: Item { + anchors.centerIn: parent + implicitWidth: realContent.implicitWidth + root.verticalPadding * 2 + implicitHeight: realContent.implicitHeight + root.horizontalPadding * 2 + + Rectangle { + id: ambientShadow + z: 0 + anchors { + fill: realContent + margins: -border.width + } + border.color: ColorUtils.transparentize(Looks.colors.bg0Border, Looks.shadowTransparency) + border.width: 1 + color: "transparent" + radius: realContent.radius + border.width + } + + Rectangle { + id: realContent + z: 1 + anchors.centerIn: parent + implicitWidth: tooltipText.implicitWidth + 10 * 2 + implicitHeight: tooltipText.implicitHeight + 8 * 2 + color: Looks.colors.bg1 + radius: Looks.radius.medium + + WText { + id: tooltipText + text: root.text + anchors.centerIn: parent + } + } + } +} diff --git a/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml b/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml new file mode 100644 index 000000000..240fd63be --- /dev/null +++ b/dots/.config/quickshell/ii/modules/waffle/looks/WText.qml @@ -0,0 +1,15 @@ +import QtQuick + +Text { + id: root + + renderType: Text.NativeRendering + verticalAlignment: Text.AlignVCenter + color: Looks.colors.fg + + font { + family: Looks.font.family.ui + pixelSize: Looks.font.pixelSize.normal + weight: Looks.font.weight.regular + } +} diff --git a/dots/.config/quickshell/ii/services/DateTime.qml b/dots/.config/quickshell/ii/services/DateTime.qml index 62d296dbc..514da212b 100644 --- a/dots/.config/quickshell/ii/services/DateTime.qml +++ b/dots/.config/quickshell/ii/services/DateTime.qml @@ -20,7 +20,8 @@ Singleton { } property string time: Qt.locale().toString(clock.date, Config.options?.time.format ?? "hh:mm") property string shortDate: Qt.locale().toString(clock.date, Config.options?.time.shortDateFormat ?? "dd/MM") - property string date: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM") + property string date: Qt.locale().toString(clock.date, Config.options?.time.dateWithYearFormat ?? "dd/MM/yyyy") + property string longDate: Qt.locale().toString(clock.date, Config.options?.time.dateFormat ?? "dddd, dd/MM") property string collapsedCalendarFormat: Qt.locale().toString(clock.date, "dd MMMM yyyy") property string uptime: "0h, 0m" diff --git a/dots/.config/quickshell/ii/services/TaskbarApps.qml b/dots/.config/quickshell/ii/services/TaskbarApps.qml new file mode 100644 index 000000000..0b5818b71 --- /dev/null +++ b/dots/.config/quickshell/ii/services/TaskbarApps.qml @@ -0,0 +1,60 @@ +pragma Singleton + +import qs.modules.common +import QtQuick +import Quickshell +import Quickshell.Wayland + +Singleton { + id: root + + property list apps: { + var map = new Map(); + + // Pinned apps + const pinnedApps = Config.options?.dock.pinnedApps ?? []; + for (const appId of pinnedApps) { + if (!map.has(appId.toLowerCase())) map.set(appId.toLowerCase(), ({ + pinned: true, + toplevels: [] + })); + } + + // Separator + if (pinnedApps.length > 0) { + map.set("SEPARATOR", { pinned: false, toplevels: [] }); + } + + // Ignored apps + const ignoredRegexStrings = Config.options?.dock.ignoredAppRegexes ?? []; + const ignoredRegexes = ignoredRegexStrings.map(pattern => new RegExp(pattern, "i")); + // Open windows + for (const toplevel of ToplevelManager.toplevels.values) { + if (ignoredRegexes.some(re => re.test(toplevel.appId))) continue; + if (!map.has(toplevel.appId.toLowerCase())) map.set(toplevel.appId.toLowerCase(), ({ + pinned: false, + toplevels: [] + })); + map.get(toplevel.appId.toLowerCase()).toplevels.push(toplevel); + } + + var values = []; + + for (const [key, value] of map) { + values.push(appEntryComp.createObject(null, { appId: key, toplevels: value.toplevels, pinned: value.pinned })); + } + + return values; + } + + component TaskbarAppEntry: QtObject { + id: wrapper + required property string appId + required property list toplevels + required property bool pinned + } + Component { + id: appEntryComp + TaskbarAppEntry {} + } +} diff --git a/dots/.config/quickshell/ii/shell.qml b/dots/.config/quickshell/ii/shell.qml index ee2217bf7..dc0a9509f 100644 --- a/dots/.config/quickshell/ii/shell.qml +++ b/dots/.config/quickshell/ii/shell.qml @@ -28,12 +28,19 @@ import qs.modules.ii.overlay import qs.modules.ii.verticalBar import qs.modules.ii.wallpaperSelector +import qs.modules.waffle.background +import qs.modules.waffle.bar + import QtQuick import QtQuick.Window import Quickshell +import Quickshell.Io +import Quickshell.Hyprland import qs.services ShellRoot { + id: root + // Force initialization of some singletons Component.onCompleted: { MaterialThemeLoader.reapplyTheme() @@ -67,11 +74,41 @@ ShellRoot { PanelLoader { identifier: "iiSidebarRight"; component: SidebarRight {} } PanelLoader { identifier: "iiVerticalBar"; extraCondition: Config.options.bar.vertical; component: VerticalBar {} } PanelLoader { identifier: "iiWallpaperSelector"; component: WallpaperSelector {} } + PanelLoader { identifier: "wBar"; component: WaffleBar {} } + PanelLoader { identifier: "wBackground"; component: WaffleBackground {} } component PanelLoader: LazyLoader { required property string identifier property bool extraCondition: true active: Config.ready && Config.options.enabledPanels.includes(identifier) && extraCondition } + + // Panel families + property list families: ["ii", "waffle"] + property var panelFamilies: ({ + "ii": ["iiBar", "iiBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiVerticalBar", "iiWallpaperSelector"], + "waffle": ["wBar", "wBackground", "iiCheatsheet", "iiDock", "iiLock", "iiMediaControls", "iiNotificationPopup", "iiOnScreenDisplay", "iiOnScreenKeyboard", "iiOverlay", "iiOverview", "iiPolkit", "iiRegionSelector", "iiReloadPopup", "iiScreenCorners", "iiSessionScreen", "iiSidebarLeft", "iiSidebarRight", "iiWallpaperSelector"], + }) + function cyclePanelFamily() { + const currentIndex = families.indexOf(Config.options.panelFamily) + const nextIndex = (currentIndex + 1) % families.length + Config.options.panelFamily = families[nextIndex] + Config.options.enabledPanels = panelFamilies[Config.options.panelFamily] + } + + IpcHandler { + target: "panelFamily" + + function cycle(): void { + root.cyclePanelFamily() + } + } + + GlobalShortcut { + name: "panelFamilyCycle" + description: "Cycles panel family" + + onPressed: root.cyclePanelFamily() + } }