egui_charts/drawings/services/
z_order.rs1use crate::drawings::domain::Drawing;
7
8pub struct ZOrderService;
10
11impl ZOrderService {
12 pub fn bring_to_front(drawings: &mut [Drawing], id: usize) {
14 let max_z = drawings.iter().map(|d| d.z_order()).max().unwrap_or(0);
15 if let Some(drawing) = drawings.iter_mut().find(|d| d.id == id) {
16 drawing.set_z_order(max_z.saturating_add(1));
17 }
18 }
19
20 pub fn send_to_back(drawings: &mut [Drawing], id: usize) {
22 let min_z = drawings.iter().map(|d| d.z_order()).min().unwrap_or(0);
23 if let Some(drawing) = drawings.iter_mut().find(|d| d.id == id) {
24 drawing.set_z_order(min_z.saturating_sub(1));
25 }
26 }
27
28 pub fn bring_forward(drawings: &mut [Drawing], id: usize) {
32 let target_idx = match drawings.iter().position(|d| d.id == id) {
33 Some(i) => i,
34 None => return,
35 };
36 let current_z = drawings[target_idx].z_order();
37
38 let swap_idx = drawings
40 .iter()
41 .enumerate()
42 .filter(|(i, d)| *i != target_idx && d.z_order() > current_z)
43 .min_by_key(|(_, d)| d.z_order())
44 .map(|(i, _)| i);
45
46 match swap_idx {
47 Some(si) => {
48 let above_z = drawings[si].z_order();
49 drawings[target_idx].set_z_order(above_z);
50 drawings[si].set_z_order(current_z);
51 }
52 None => {
53 drawings[target_idx].set_z_order(current_z.saturating_add(1));
55 }
56 }
57 }
58
59 pub fn send_backward(drawings: &mut [Drawing], id: usize) {
63 let target_idx = match drawings.iter().position(|d| d.id == id) {
64 Some(i) => i,
65 None => return,
66 };
67 let current_z = drawings[target_idx].z_order();
68
69 let swap_idx = drawings
71 .iter()
72 .enumerate()
73 .filter(|(i, d)| *i != target_idx && d.z_order() < current_z)
74 .max_by_key(|(_, d)| d.z_order())
75 .map(|(i, _)| i);
76
77 match swap_idx {
78 Some(si) => {
79 let below_z = drawings[si].z_order();
80 drawings[target_idx].set_z_order(below_z);
81 drawings[si].set_z_order(current_z);
82 }
83 None => {
84 drawings[target_idx].set_z_order(current_z.saturating_sub(1));
86 }
87 }
88 }
89
90 pub fn sort_by_z_order(drawings: &mut [Drawing]) {
92 drawings.sort_by_key(|d| d.z_order());
93 }
94}
95
96pub(crate) fn in_z_order(drawings: &[Drawing]) -> Vec<&Drawing> {
99 let mut ordered: Vec<_> = drawings.iter().collect();
100 ordered.sort_by_key(|d| d.z_order());
101 ordered
102}
103
104#[cfg(test)]
105mod tests {
106 use super::*;
107 use crate::drawings::domain::DrawingToolType;
108
109 fn make_drawing(id: usize, z: i32) -> Drawing {
110 let mut d = Drawing::new(id, DrawingToolType::TrendLine);
111 d.set_z_order(z);
112 d
113 }
114
115 #[test]
116 fn ordering_operations_preserve_drawing_identity() {
117 let cases = [
118 (
119 "front",
120 ZOrderService::bring_to_front as fn(&mut [Drawing], usize),
121 1,
122 [(1, 6), (2, 5), (3, 3)],
123 ),
124 (
125 "back",
126 ZOrderService::send_to_back,
127 2,
128 [(1, 0), (2, -1), (3, 3)],
129 ),
130 (
131 "forward",
132 ZOrderService::bring_forward,
133 3,
134 [(1, 0), (2, 3), (3, 5)],
135 ),
136 (
137 "backward",
138 ZOrderService::send_backward,
139 3,
140 [(1, 3), (2, 5), (3, 0)],
141 ),
142 (
143 "sort",
144 |drawings: &mut [Drawing], _| ZOrderService::sort_by_z_order(drawings),
145 0,
146 [(1, 0), (3, 3), (2, 5)],
147 ),
148 ];
149 for (name, operation, id, expected) in cases {
150 let mut drawings = [make_drawing(1, 0), make_drawing(2, 5), make_drawing(3, 3)];
151 operation(&mut drawings, id);
152 assert_eq!(drawings.map(|d| (d.id, d.z_order())), expected, "{name}");
153 }
154 }
155}