gardesk/tarmac / b9e6405

Browse files

Stack: drop the Slack-peek offset, all members share the tile rect

The reveal-offset path had a long-standing dead-code bug: the depth
counter never decremented past the active member because the active
case continued before the saturating_sub line could run, so windows
iterated after the active accumulated progressively larger origin
offsets and visibly drifted out of the tile.

The peek itself was a stylistic flourish; the user's report 'windows
in the stack are not sized and positioned as members of the stack'
matches removing it entirely. All stack members now occupy the full
padded tile; non-active windows sit fully behind the active in
z-order. Replaces the two reveal-direction tests with a single test
asserting all members share the tile rect across active positions.
Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
b9e64055fa6fe82626f9072b1a0331ba66da1a9f
Parents
73e39c1
Tree
5192158

1 changed file

StatusFile+-
M tarmac/src/core/tree.rs 61 69
tarmac/src/core/tree.rsmodified
@@ -61,9 +61,6 @@ impl Rect {
6161
     }
6262
 }
6363
 
64
-const STACK_REVEAL_OFFSET_X: f64 = 4.0;
65
-const STACK_REVEAL_OFFSET_Y: f64 = 4.0;
66
-
6764
 #[derive(Debug, Clone, PartialEq)]
6865
 pub enum Node {
6966
     Internal {
@@ -89,12 +86,6 @@ impl Default for Node {
8986
 }
9087
 
9188
 impl Node {
92
-    fn stack_reveal_direction(windows_len: usize, active: usize) -> f64 {
93
-        let left_count = active;
94
-        let right_count = windows_len.saturating_sub(active + 1);
95
-        if left_count > right_count { -1.0 } else { 1.0 }
96
-    }
97
-
9889
     pub fn empty() -> Self {
9990
         Node::Leaf { window: None }
10091
     }
@@ -317,35 +308,17 @@ impl Node {
317308
         match self {
318309
             Node::Leaf { window: Some(w) } => vec![(*w, padded)],
319310
             Node::Leaf { window: None } => vec![],
320
-            Node::Stack {
321
-                windows, active, ..
322
-            } => {
323
-                let active_window = windows.get(*active).copied();
324
-                let x_direction = Self::stack_reveal_direction(windows.len(), *active);
325
-                let mut geoms = Vec::with_capacity(windows.len());
326
-                let mut depth = 0usize;
327
-                for (idx, wid) in windows.iter().enumerate() {
328
-                    if Some(*wid) == active_window {
329
-                        continue;
330
-                    }
331
-                    depth += 1;
332
-                    geoms.push((
333
-                        *wid,
334
-                        Rect::new(
335
-                            padded.x + x_direction * STACK_REVEAL_OFFSET_X * depth as f64,
336
-                            padded.y + STACK_REVEAL_OFFSET_Y * depth as f64,
337
-                            padded.width,
338
-                            padded.height,
339
-                        ),
340
-                    ));
341
-                    if idx == *active {
342
-                        depth = depth.saturating_sub(1);
343
-                    }
344
-                }
345
-                if let Some(wid) = active_window {
346
-                    geoms.push((wid, padded));
347
-                }
348
-                geoms
311
+            Node::Stack { windows, .. } => {
312
+                // All stack members share the tile's full rect. Non-active
313
+                // windows sit fully behind the active in z-order. The
314
+                // previous "Slack-style reveal" offset (origin += depth *
315
+                // STACK_REVEAL_OFFSET) leaked: the depth counter never
316
+                // reset past the active member, so windows iterated after
317
+                // the active in insertion order accumulated progressively
318
+                // larger offsets and visibly drifted away from the tile
319
+                // (user-reported as "the windows are not sized and
320
+                // positioned as if they are members of the stack").
321
+                windows.iter().map(|wid| (*wid, padded)).collect()
349322
             }
350323
             Node::Internal {
351324
                 split,
@@ -840,6 +813,35 @@ impl Node {
840813
         self.make_stack_for_window_impl(window)
841814
     }
842815
 
816
+    /// Replace the entire tree with a single root-level Stack containing
817
+    /// every window currently in the tree. Used as overflow remediation
818
+    /// during initial discovery: if even one window can't fit its tile in
819
+    /// the BSP layout we'd otherwise produce, just stack everything into
820
+    /// one tile so the user gets a clean, navigable layout instead of a
821
+    /// staircase with a partial stack at the bottom.
822
+    pub fn collapse_to_root_stack(&mut self, active_window: WindowId) -> bool {
823
+        match self {
824
+            Node::Internal { .. } => {
825
+                let previous = self.clone();
826
+                let windows = self.windows();
827
+                if windows.is_empty() {
828
+                    return false;
829
+                }
830
+                let active = windows
831
+                    .iter()
832
+                    .position(|wid| *wid == active_window)
833
+                    .unwrap_or(0);
834
+                *self = Node::Stack {
835
+                    windows,
836
+                    active,
837
+                    previous: Box::new(previous),
838
+                };
839
+                true
840
+            }
841
+            _ => false,
842
+        }
843
+    }
844
+
843845
     fn make_stack_for_window_impl(&mut self, window: WindowId) -> bool {
844846
         match self {
845847
             Node::Internal { left, right, .. } => {
@@ -1488,37 +1490,27 @@ mod tests {
14881490
     }
14891491
 
14901492
     #[test]
1491
-    fn stacked_render_geometries_reveal_background_windows_to_the_right_when_right_biased() {
1492
-        let tree = Node::Stack {
1493
-            windows: vec![1, 2, 3],
1494
-            active: 0,
1495
-            previous: Box::new(Node::Leaf { window: Some(1) }),
1496
-        };
1497
-        let geoms = tree.calculate_geometries(SCREEN);
1498
-        let g1 = geoms.iter().find(|(wid, _)| *wid == 1).unwrap().1;
1499
-        let g2 = geoms.iter().find(|(wid, _)| *wid == 2).unwrap().1;
1500
-
1501
-        assert!(g2.x > g1.x);
1502
-        assert!(g2.y > g1.y);
1503
-        assert_eq!(g2.width, g1.width);
1504
-        assert_eq!(g2.height, g1.height);
1505
-    }
1506
-
1507
-    #[test]
1508
-    fn stacked_render_geometries_reveal_background_windows_to_the_left_when_left_biased() {
1509
-        let tree = Node::Stack {
1510
-            windows: vec![1, 2, 3],
1511
-            active: 2,
1512
-            previous: Box::new(Node::Leaf { window: Some(3) }),
1513
-        };
1514
-        let geoms = tree.calculate_geometries(SCREEN);
1515
-        let g2 = geoms.iter().find(|(wid, _)| *wid == 2).unwrap().1;
1516
-        let g3 = geoms.iter().find(|(wid, _)| *wid == 3).unwrap().1;
1517
-
1518
-        assert!(g2.x < g3.x);
1519
-        assert!(g2.y > g3.y);
1520
-        assert_eq!(g2.width, g3.width);
1521
-        assert_eq!(g2.height, g3.height);
1493
+    fn stacked_render_geometries_share_the_tile_rect() {
1494
+        // All stack members occupy the full tile rect, regardless of
1495
+        // which is active. Non-active windows sit fully behind the
1496
+        // active in z-order — no Slack-style peek offset (removed:
1497
+        // its depth counter accumulated past the active position
1498
+        // and produced visibly drifting non-active windows).
1499
+        for active in 0..3 {
1500
+            let tree = Node::Stack {
1501
+                windows: vec![1, 2, 3],
1502
+                active,
1503
+                previous: Box::new(Node::Leaf { window: Some(1) }),
1504
+            };
1505
+            let geoms = tree.calculate_geometries(SCREEN);
1506
+            assert_eq!(geoms.len(), 3);
1507
+            for (_, rect) in &geoms {
1508
+                assert_eq!(rect.x, SCREEN.x);
1509
+                assert_eq!(rect.y, SCREEN.y);
1510
+                assert_eq!(rect.width, SCREEN.width);
1511
+                assert_eq!(rect.height, SCREEN.height);
1512
+            }
1513
+        }
15221514
     }
15231515
 
15241516
     #[test]