diff options
Diffstat (limited to 'src/layout.zig')
| -rw-r--r-- | src/layout.zig | 77 |
1 files changed, 62 insertions, 15 deletions
diff --git a/src/layout.zig b/src/layout.zig index cbf0fd96..09cf23b3 100644 --- a/src/layout.zig +++ b/src/layout.zig @@ -416,10 +416,71 @@ pub fn acmePlace(p: *Pardes, c: usize, origin: ?usize, id: usize) void { /// its tag (acme's minht keeps one). pub const min_body_rows = 2; -fn minRows(p: *Pardes, id: usize) u16 { +/// The rows a placement, and a `size`, leave a pane: its tag at its width +/// and `min_body_rows`. The one minimum both ask. +pub fn minRows(p: *Pardes, id: usize) u16 { return p.wantedTagRows(id) + min_body_rows; } +/// Whether every column has the rows for each of its unfolded panes' +/// `minRows` (a folded one its tag row): the panes' own minima, not how +/// the weights happen to share the rows, so a size that fits keeps fitting +/// when it grows. One pane alone in its column always fits. +pub fn minimaFit(p: *Pardes) bool { + compute(p); + const avail = p.screen_h -| (p.topBarHeight() + p.columnBarHeight()); + for (0..p.ncol) |c| { + if (p.col_n[c] < 2) continue; + var need: u32 = 0; + for (p.col_panes[c][0..p.col_n[c]]) |k| { + const pane = p.panes[k] orelse continue; + need += if (pane.collapsed) BOX_H else minRows(p, k); + } + if (need > avail) return false; + } + return true; +} + +/// After a resize the minima fit: each unfolded pane the resize took below +/// its `minRows` (it had them in `before`) gets them back, a row at a time +/// from whichever pane of its column has the most above its own. A pane +/// dragged short before keeps what it had. +pub fn restoreMinima(p: *Pardes, before: *const [MAX_PANES]Rect) void { + compute(p); + for (0..p.ncol) |c| { + const n = p.col_n[c]; + if (n < 2) continue; + var hs: [MAX_PANES]u16 = undefined; + var mins: [MAX_PANES]u16 = undefined; + var short = false; + for (p.col_panes[c][0..n], 0..) |k, i| { + const pane = p.panes[k] orelse return; + if (pane.collapsed) break; + hs[i] = p.rects[k].h; + mins[i] = minRows(p, k); + if (hs[i] < mins[i] and before[k].h >= mins[i]) short = true; + } else { + if (!short) continue; + for (p.col_panes[c][0..n], 0..) |k, i| { + if (hs[i] >= mins[i] or before[k].h < mins[i]) continue; + while (hs[i] < mins[i]) { + var giver: ?usize = null; + var spare: u16 = 0; + for (0..n) |j| if (j != i and hs[j] -| mins[j] > spare) { + spare = hs[j] - mins[j]; + giver = j; + }; + const g = giver orelse break; + hs[g] -= 1; + hs[i] += 1; + } + } + for (p.col_panes[c][0..n], 0..) |k, i| p.panes[k].?.vweight = @floatFromInt(@max(1, hs[i])); + } + } + compute(p); +} + /// After placing `id`: whether it, and every pane of its column that the /// placement shrank, still has its tag and `min_body_rows` (from `before`, /// the rects as they were). A pane alone in its column always has room: the @@ -437,20 +498,6 @@ pub fn placedRoomy(p: *Pardes, id: usize, before: *const [MAX_PANES]Rect) bool { return true; } -/// Whether every unfolded pane sharing its column has its tag and -/// `min_body_rows` (one alone in its column always fits). -pub fn everyPaneRoomy(p: *Pardes) bool { - compute(p); - for (0..p.ncol) |c| { - if (p.col_n[c] < 2) continue; - for (p.col_panes[c][0..p.col_n[c]]) |k| { - const pane = p.panes[k] orelse continue; - if (!pane.collapsed and p.rects[k].h < minRows(p, k)) return false; - } - } - return true; -} - /// Places `id` last in column `c`, where acme's coladd puts a new window, /// with half the rows of the column's tallest unfolded pane, when that /// leaves both their rows; false, and `id` in no column, when not. |
