aboutsummaryrefslogtreecommitdiffstats
path: root/config/quickshell/qs-hyprview-trixie/layouts/MasonryLayout.qml
blob: 73192f17247fb26d2f2f66436ba7ca4b526564da (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
pragma Singleton
import Quickshell

Singleton {
    id: root

    function doLayout(windowList, outerWidth, outerHeight) {
        var N = windowList.length
        if (N === 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))

        // Safe Area (90%)
        // Define the bounding box for the content.
        var contentScale = 0.90
        var useW = outerWidth * contentScale
        var useH = outerHeight * contentScale

        // Find Best Column Count
        // Standard logic: try to fit content in 1 col, then 2, etc.
        var bestCols = N

        for (var cols = 1; cols <= N; cols++) {
            var tryColWidth = (useW - (cols - 1) * gap) / cols
            var tryColHeights = new Array(cols).fill(0)

            for (var i = 0; i < N; i++) {
                var item = windowList[i]
                var minH = Math.min.apply(null, tryColHeights)
                var colIdx = tryColHeights.indexOf(minH)

                var w0 = (item.width && item.width > 0) ? item.width : 100
                var h0 = (item.height && item.height > 0) ? item.height : 100
                var scale = tryColWidth / w0

                tryColHeights[colIdx] += (h0 * scale) + gap
            }

            var currentMaxH = Math.max.apply(null, tryColHeights)
            if (currentMaxH > 0) currentMaxH -= gap

            // If it fits vertically, we stop.
            if (currentMaxH <= useH) {
                bestCols = cols
                break
            }
        }

        // Rigorous clamping
        // We have chosen 'bestCols'. Now we calculate the theoretical column width.
        // BUT, if N is small (e.g. 1), this width might produce a height > useH.
        // We must calculate a "Global Downscale Factor" to ensure NO item exceeds useH.

        var rawColWidth = (useW - (bestCols - 1) * gap) / bestCols
        var maxOverflowRatio = 1.0 // 1.0 means "fits perfectly"

        // Simulate again to find the worst offender (tallest item/column relative to screen)
        // Note: In masonry, we care about the total column height, not just single item.
        var clampHeights = new Array(bestCols).fill(0)

        for (var j = 0; j < N; j++) {
            var it = windowList[j]

            // Standard masonry placement logic
            var mH = Math.min.apply(null, clampHeights)
            var cId = clampHeights.indexOf(mH)

            var wRaw = (it.width && it.width > 0) ? it.width : 100
            var hRaw = (it.height && it.height > 0) ? it.height : 100
            var sc = rawColWidth / wRaw

            clampHeights[cId] += (hRaw * sc) + gap
        }

        // Find the tallest column produced by the raw width
        var tallestCol = Math.max.apply(null, clampHeights)
        if (tallestCol > 0) tallestCol -= gap

        // If the tallest column is taller than Safe Area, calculate reduction factor
        if (tallestCol > useH) {
            maxOverflowRatio = useH / tallestCol
        }

        // Apply the reduction factor to the column width.
        var finalColWidth = rawColWidth * maxOverflowRatio

        // Re-centering x
        var finalGridW = (finalColWidth * bestCols) + (gap * (bestCols - 1))
        var finalOffX = (outerWidth - finalGridW) / 2


        // Final rendering
        var colHeights = new Array(bestCols).fill(0)
        var result = []

        for (var k = 0; k < N; k++) {
            var itemK = windowList[k]

            // 1. Find shortest column
            var minH = Math.min.apply(null, colHeights)
            var cIdx = colHeights.indexOf(minH)

            // 2. Dimensions
            var wOrig = (itemK.width && itemK.width > 0) ? itemK.width : 100
            var hOrig = (itemK.height && itemK.height > 0) ? itemK.height : 100
            var s = finalColWidth / wOrig
            var tH = hOrig * s

            // 3. Position (using Recalculated OffX)
            var xPos = finalOffX + cIdx * (finalColWidth + gap)
            var yPos = colHeights[cIdx]

            result.push({
                win: itemK.win,
                x: xPos,
                y: yPos,
                width: finalColWidth,
                height: tH,
                colIndex: cIdx
            })

            colHeights[cIdx] += tH + gap
        }

        // Vertical centering
        var realGridH = Math.max.apply(null, colHeights)
        if (realGridH > 0) realGridH -= gap

        var finalOffY = (outerHeight - realGridH) / 2

        for (var m = 0; m < result.length; m++) {
            result[m].y += finalOffY
        }

        return result
    }
}
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage