blockworx/panels/
notices.rs1use crate::grid::GRID_SIZE;
15pub use crate::kernel::{Acknowledged, Notice};
16use crate::panels::chrome::Panel;
17
18const MAX_WIDTH: f32 = 0.4;
20
21pub fn draw(
25 ui: &mut egui::Ui,
26 viewport: egui::Rect,
27 above: egui::Rect,
28 notices: &[Notice],
29) -> Option<Acknowledged> {
30 if notices.is_empty() {
31 return None;
32 }
33 let top = if above.is_positive() {
34 above.bottom() + GRID_SIZE
35 } else {
36 viewport.top() + GRID_SIZE
37 };
38 let strip = egui::Rect::from_min_max(
39 egui::pos2(viewport.left() + GRID_SIZE, top),
40 viewport.right_bottom(),
41 );
42 let mut child = ui.new_child(
43 Panel::DocumentNotices
44 .ui_builder()
45 .max_rect(strip)
46 .layout(egui::Layout::top_down(egui::Align::Min)),
47 );
48 let mut acknowledged = None;
49 let drawn = egui::Frame::popup(child.style()).show(&mut child, |ui| {
50 ui.set_max_width(viewport.width() * MAX_WIDTH);
51 let mut failures = 0;
52 for notice in notices {
53 match notice {
54 Notice::Standing(text) => {
55 ui.label(egui::RichText::new(text).small());
56 }
57 Notice::Failure(text) => {
58 let failure = failures;
59 failures += 1;
60 ui.horizontal(|ui| {
61 ui.add(egui::Label::new(egui::RichText::new(text).small()).wrap());
65 if ui
66 .small_button(DISMISS)
67 .on_hover_text("Done with this message")
68 .clicked()
69 {
70 acknowledged = Some(Acknowledged(failure));
71 }
72 });
73 }
74 }
75 }
76 });
77 let pass = ui.ctx().cumulative_pass_nr();
78 ui.ctx().data_mut(|d| {
79 d.insert_temp(
80 Panel::DocumentNotices.measurement("rect"),
81 (pass, drawn.response.rect),
82 );
83 });
84 acknowledged
85}
86
87pub(crate) fn strip_rect(ctx: &egui::Context) -> Option<egui::Rect> {
90 let (pass, rect) =
91 ctx.data(|d| d.get_temp::<(u64, egui::Rect)>(Panel::DocumentNotices.measurement("rect")))?;
92 (pass + 1 == ctx.cumulative_pass_nr()).then_some(rect)
93}
94
95pub(crate) const DISMISS: &str = "Dismiss";
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::canvas::convert::{IntoEgui as _, IntoGeom as _};
103 use crate::panels::painted::Chrome;
104 use egui::{Rect, pos2, vec2};
105
106 fn viewport() -> Rect {
107 Rect::from_min_size(pos2(0.0, 0.0), vec2(1000.0, 800.0))
108 }
109
110 fn toolbar() -> Rect {
113 Rect::from_min_size(pos2(380.0, 8.0), vec2(240.0, 40.0))
114 }
115
116 #[test]
119 fn the_strip_never_covers_the_chrome_above_it() {
120 let long = "Read-only \u{2014} the log does not verify at record 41 of 128, whose \
121 stamp names a fold this build does not produce";
122 let mut chrome = Chrome::new(viewport().geom());
123 chrome.settle(|ui| {
124 let notices = [
125 Notice::Standing(long.to_owned()),
126 Notice::Failure(long.to_owned()),
127 ];
128 let _ = draw(ui, viewport(), toolbar(), ¬ices);
129 });
130 assert!(
131 chrome.shows(DISMISS),
132 "the failure carries no acknowledgement: {:?}",
133 chrome.texts(),
134 );
135 let drawn = chrome
136 .rect(long)
137 .expect("the notices drew their text")
138 .union(chrome.rect(DISMISS).expect("and the dismiss button"));
139 assert!(
140 drawn.top() > toolbar().bottom(),
141 "the notices at {drawn:?} sit over the toolbar at {:?}",
142 toolbar(),
143 );
144 assert!(
145 viewport().contains_rect(drawn.egui()),
146 "the notices at {drawn:?} left the canvas",
147 );
148 }
149
150 #[test]
153 fn dismissing_names_the_failure_it_dismissed() {
154 let mut chrome = Chrome::new(viewport().geom());
155 let mut acknowledged = None;
156 let notices = || {
157 [
158 Notice::Failure("first".to_owned()),
159 Notice::Standing("Read-only \u{2014} another blockworx has it".to_owned()),
160 Notice::Failure("second".to_owned()),
161 ]
162 };
163 chrome.settle(|ui| {
164 let _ = draw(ui, viewport(), toolbar(), ¬ices());
165 });
166 let second = chrome.rect("second").expect("the second failure drew");
169 let dismiss = chrome
170 .rects(DISMISS)
171 .into_iter()
172 .find(|rect| (rect.center().y - second.center().y).abs() < 4.0)
173 .expect("the second failure carries a dismiss button");
174 assert_eq!(chrome.rects(DISMISS).len(), 2, "a standing notice grew one");
175 chrome.click_at(dismiss.center(), |ui| {
176 if let Some(hit) = draw(ui, viewport(), toolbar(), ¬ices()) {
177 acknowledged = Some(hit.0);
178 }
179 });
180 assert_eq!(acknowledged, Some(1));
181 }
182}