aboutsummaryrefslogtreecommitdiffstats
path: root/config/quickshell/qs-hyprview/layouts/HeroLayout.qml
diff options
context:
space:
mode:
authorDon Williams <Don.e.williams@gmail.com>2026-07-11 04:31:59 -0400
committerPinapelz <yukais@pinapelz.com>2026-08-29 21:40:34 -0700
commit1ee78be8453f86ef366fe7a73e4e8cf245d2d336 (patch)
tree72fbbfa17e61299f3eb400b6fd5a27ec52f9b291 /config/quickshell/qs-hyprview/layouts/HeroLayout.qml
parent4d39fc9670d5cb0b3e0624ead386d30db3b8110f (diff)
Added qs-hyprview as alternative overview
Signed-off-by: Don Williams <Don.e.williams@gmail.com> On branch development Your branch is up to date with 'origin/development'. Changes to be committed: deleted: ./ new file: LICENSE new file: README.md new file: common/Appearance.qml new file: layouts/BandsLayout.qml new file: layouts/ColumnarLayout.qml new file: layouts/HeroLayout.qml new file: layouts/JustifiedLayout.qml new file: layouts/LayoutsManager.qml new file: layouts/MasonryLayout.qml new file: layouts/SatelliteLayout.qml new file: layouts/SmartGridLayout.qml new file: layouts/SpiralLayout.qml new file: layouts/StarggeredLayout.qml new file: layouts/VortexLayout.qml new file: layouts/qmldir new file: modules/Hyprview.qml new file: modules/SearchBox.qml new file: modules/WindowThumbnail.qml new file: modules/qmldir new file: qs-hyprview-template.qml new file: screenshots/bands.jpeg new file: screenshots/hero.jpeg new file: screenshots/masonry.jpeg new file: screenshots/satellite.jpeg new file: screenshots/smartgrid.jpeg new file: screenshots/spiral.jpeg new file: screenshots/staggered.jpeg new file: screenshots/vortex.jpeg new file: shell.qml
Diffstat (limited to 'config/quickshell/qs-hyprview/layouts/HeroLayout.qml')
-rw-r--r--config/quickshell/qs-hyprview/layouts/HeroLayout.qml144
1 files changed, 144 insertions, 0 deletions
diff --git a/config/quickshell/qs-hyprview/layouts/HeroLayout.qml b/config/quickshell/qs-hyprview/layouts/HeroLayout.qml
new file mode 100644
index 00000000..e45ecf2c
--- /dev/null
+++ b/config/quickshell/qs-hyprview/layouts/HeroLayout.qml
@@ -0,0 +1,144 @@
+pragma Singleton
+import Quickshell
+import Quickshell.Hyprland
+
+Singleton {
+ id: root
+
+ function doLayout(windowList, outerWidth, outerHeight) {
+ if (windowList.length === 0) return []
+
+ // Gap: 0.8% of screen, clamped between 12px and 32px
+ var rawGap = Math.min(outerWidth * 0.08, outerHeight * 0.08)
+ var gap = Math.max(12, Math.min(32, rawGap))
+
+ // Move active window to the head of windowList
+ var activeAddr = Hyprland.activeToplevel?.lastIpcObject?.address
+ if (activeAddr) {
+ var activeIdx = windowList.findIndex(it => it.lastIpcObject.address === activeAddr)
+ if (activeIdx !== -1) {
+ windowList = [windowList[activeIdx], ...windowList.filter(it => it !== windowList[activeIdx])]
+ }
+ }
+
+ // Safe area definition (90%)
+ var contentScale = 0.90
+ var useW = outerWidth * contentScale
+ var useH = outerHeight * contentScale
+
+ // Global offset - center Safe area
+ var offX = (outerWidth - useW) / 2
+ var offY = (outerHeight - useH) / 2
+
+ var result = []
+
+ // Screen zones (Hero/Stack)
+ var heroRatio = 0.40 // 40% Hero
+ var heroAreaW = useW * heroRatio
+ var stackAreaW = useW - heroAreaW - gap // 60% Stack
+
+ var heroItem = windowList[0]
+
+ // Aspect Fit
+ var hScale = Math.min(heroAreaW / heroItem.width, useH / heroItem.height)
+ var hW = heroItem.width * hScale
+ var hH = heroItem.height * hScale
+
+ result.push({
+ win: heroItem.win,
+ x: offX + (heroAreaW - hW) / 2,
+ y: offY + (useH - hH) / 2,
+ width: hW,
+ height: hH,
+ isHero: true
+ })
+
+ var others = windowList.slice(1)
+ var N = others.length
+
+ if (N > 0) {
+ var stackStartX = offX + heroAreaW + gap
+
+ // Evaluate col number
+ var bestCols = 1
+ var bestRows = N
+
+ // Windows height on a single column
+ var oneColH = (useH - (gap * (N - 1))) / N
+
+ // TOLERANCE THRESHOLD (0.15 = 15% of screen height)
+ // If the windows are at least 15% of the screen height, we stay on 1 column.
+ // With 4 windows we are at ~25% -> OK (1 Column)
+ // With 7 windows we are at ~14% -> NO (Go to grid calculation)
+ var useSingleCol = oneColH > (useH * 0.15)
+
+ if (!useSingleCol) {
+ // If space is limited, we look for the optimal grid starting with 2 columns.
+ var bestScale = 0
+ var TARGET_ASPECT = 16.0 / 9.0
+
+ for (var cols = 2; cols <= N; cols++) {
+ var rows = Math.ceil(N / cols)
+ var availW = stackAreaW - (gap * (cols - 1))
+ var availH = useH - (gap * (rows - 1))
+
+ if (availW <= 0 || availH <= 0) continue
+
+ var cellW = availW / cols
+ var cellH = availH / rows
+
+ // Size score
+ var sW = cellW / TARGET_ASPECT
+ var sH = cellH / 1.0
+ var currentScale = Math.min(sW, sH)
+
+ if (currentScale > bestScale) {
+ bestScale = currentScale
+ bestCols = cols
+ bestRows = rows
+ }
+ }
+ }
+
+ // Evaluation of the final dimensions of the selected grid
+ var finalAvailW = stackAreaW - (gap * (bestCols - 1))
+ var finalAvailH = useH - (gap * (bestRows - 1))
+
+ var finalCellW = finalAvailW / bestCols
+ var finalCellH = finalAvailH / bestRows
+
+ // Vertical centering of the total stack
+ var totalGridH = bestRows * finalCellH + (bestRows - 1) * gap
+ var stackStartY = offY + (useH - totalGridH) / 2
+
+ // Items positioning
+ for (var i = 0; i < N; ++i) {
+ var item = others[i]
+
+ var row = Math.floor(i / bestCols)
+ var col = i % bestCols
+
+ // Cell coords (Standard Grid Alignment)
+ // No “rowOffsetX”, cell 0 always starts on the left
+ var cellAbsX = stackStartX + col * (finalCellW + gap)
+ var cellAbsY = stackStartY + row * (finalCellH + gap)
+
+ // Thumb aspect Fit
+ var sc = Math.min(finalCellW / item.width, finalCellH / item.height)
+ var w = item.width * sc
+ var h = item.height * sc
+
+ result.push({
+ win: item.win,
+ x: cellAbsX + (finalCellW - w) / 2,
+ y: cellAbsY + (finalCellH - h) / 2,
+ width: w,
+ height: h,
+ isHero: false
+ })
+ }
+ }
+
+ return result
+ }
+}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage