summaryrefslogtreecommitdiff
path: root/src/layout.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout.zig')
-rw-r--r--src/layout.zig77
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.