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
//! GTK rasteriser for [`crate::SplitTree`].
//!
//! Painting moved to the shared
//! [`crate::primitives::split_tree::native_surface_paint::paint`] (#863,
//! `PaintSurface` Phase 2d slice 6/9, child of #811) — see that fn's
//! module doc for why the three per-backend copies were found to be
//! already identical (no divergence). This module now carries
//! [`gtk_split_tree_layout`]; the deprecated `draw_split_tree`
//! compatibility shim over the shared [`super::surface::CairoSurface`]
//! adapter was removed in issue #1109 (zero uses in coord-tui's `main`
//! and vimcode's `develop`).
use crate::event::Rect;
use crate::primitives::layout_metrics::pixel_split_tree_layout;
use crate::primitives::split_tree::{SplitTree, SplitTreeLayout};
/// Compute the GTK pixel-unit layout for a [`SplitTree`] without
/// painting. Shares its divider thickness with `mac_split_tree_layout` /
/// `win_split_tree_layout` via [`pixel_split_tree_layout`] (issue #1079).
pub fn gtk_split_tree_layout(tree: &SplitTree, x: f64, y: f64, w: f64, h: f64) -> SplitTreeLayout {
let bounds = Rect::new(x as f32, y as f32, w as f32, h as f32);
pixel_split_tree_layout(tree, bounds)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::event::Point;
use crate::primitives::split_tree::SplitDirection;
use crate::types::WidgetId;
fn wid(s: &str) -> WidgetId {
WidgetId::new(s)
}
/// `split_tree_layout` is documented **ABSOLUTE** (issue #505):
/// leaf/divider bounds are shifted by the origin, so `(x, y) = (0, 0)`
/// is exactly the case where a LOCAL/ABSOLUTE mixup is invisible.
fn round_trip_at(x: f64, y: f64) {
let tree = SplitTree::split(
SplitDirection::Horizontal,
0.5,
SplitTree::leaf(wid("a")),
SplitTree::leaf(wid("b")),
);
let layout = gtk_split_tree_layout(&tree, x, y, 100.0, 40.0);
assert_eq!(
layout.leaves[0].1.x as f64, x,
"first leaf must start at the split's own x"
);
assert_eq!(
layout.leaves[0].1.y as f64, y,
"first leaf must start at the split's own y"
);
let d = &layout.dividers[0];
let cross_mid = y as f32 + 20.0;
assert_eq!(
layout.hit_test_divider(
Point {
x: d.position,
y: cross_mid
},
1.0
),
Some(d.split_index)
);
assert_eq!(
layout.hit_test_leaf(Point {
x: x as f32 + 1.0,
y: cross_mid
}),
Some(&wid("a"))
);
assert_eq!(
layout.hit_test_leaf(Point {
x: d.position + 10.0,
y: cross_mid
}),
Some(&wid("b"))
);
}
#[test]
fn paint_and_click_round_trip() {
round_trip_at(0.0, 0.0);
}
/// Non-zero-origin regression guard (issue #505 / LESSONS.md).
#[test]
fn paint_and_click_round_trip_at_nonzero_origin() {
round_trip_at(7.0, 13.0);
}
#[test]
fn layout_matches_split_layout_semantics() {
let tree = SplitTree::split(
SplitDirection::Horizontal,
0.5,
SplitTree::leaf(wid("a")),
SplitTree::leaf(wid("b")),
);
let layout = gtk_split_tree_layout(&tree, 0.0, 0.0, 100.0, 50.0);
assert_eq!(layout.leaves.len(), 2);
assert_eq!(layout.dividers.len(), 1);
assert_eq!(
layout.dividers[0].thickness,
crate::primitives::layout_metrics::pixel::DIVIDER
);
// available = 96, 0.5*96 = 48.
assert!((layout.dividers[0].position - 48.0).abs() < 0.001);
}
#[test]
fn nested_tree_produces_all_dividers() {
let tree = SplitTree::split(
SplitDirection::Horizontal,
0.5,
SplitTree::split(
SplitDirection::Vertical,
0.5,
SplitTree::leaf(wid("a")),
SplitTree::leaf(wid("c")),
),
SplitTree::leaf(wid("b")),
);
let layout = gtk_split_tree_layout(&tree, 0.0, 0.0, 400.0, 300.0);
assert_eq!(layout.leaves.len(), 3);
assert_eq!(layout.dividers.len(), 2);
assert_eq!(layout.dividers[0].split_index, 0);
assert_eq!(layout.dividers[1].split_index, 1);
}
}