duat_base/widgets/
which_key.rs1use duat_core::{
2 context::{self, Handle},
3 data::Pass,
4 hook::{self, FocusChanged, KeyTyped},
5 mode::{self, Description, MouseEvent, MouseEventKind},
6 text::{Spacer, Text, txt},
7 ui::{DynSpawnSpecs, Widget},
8};
9
10pub struct WhichKey {
14 text: Text,
15}
16
17impl WhichKey {
18 #[allow(clippy::type_complexity)] pub fn open(
23 pa: &mut Pass,
24 mut fmt: Option<Box<dyn FnMut(Description) -> Option<Text>>>,
25 mut specs: DynSpawnSpecs,
26 ) {
27 let mut builder = Text::builder();
28
29 for desc in mode::current_seq_descriptions(pa) {
30 if let Some(fmt) = fmt.as_mut() {
31 if let Some(text) = fmt(desc) {
32 builder.push(text);
33 }
34 } else if let Some(text) = desc.text
35 && !text.is_empty()
36 {
37 builder.push(txt!("{}{Spacer}{text}\n", desc.keys.into_text()));
38 }
39 }
40
41 let wk = WhichKey { text: builder.build_no_double_nl() };
42
43 let handles: Vec<_> = context::windows().handles_of::<WhichKey>(pa).collect();
44 for handle in handles {
45 let _ = handle.close(pa);
46 }
47
48 if let Some(height) = specs.height.as_mut() {
49 *height = wk.text().len().line().min(*height as usize) as f32;
50 }
51
52 let handle = context::current_buffer(pa)
53 .clone()
54 .spawn_widget(pa, wk, specs)
55 .unwrap();
56
57 let (wk, area) = handle.write_with_area(pa);
58 if let Ok(width) = area.width_of_text(wk.get_print_opts(), wk.text()) {
59 area.set_width(width + 3.0).unwrap();
60 }
61
62 hook::add::<KeyTyped>({
63 let handle = handle.clone();
64 move |pa, _| Ok(_ = handle.close(pa))
65 })
66 .once();
67 hook::add::<FocusChanged>(move |pa, _| Ok(_ = handle.close(pa))).once();
68 }
69}
70
71impl Widget for WhichKey {
72 fn update(_: &mut Pass, _: &Handle<Self>) {}
73
74 fn needs_update(&self, _: &Pass) -> bool {
75 false
76 }
77
78 fn text(&self) -> &Text {
79 &self.text
80 }
81
82 fn text_mut(&mut self) -> &mut Text {
83 &mut self.text
84 }
85
86 fn on_mouse_event(pa: &mut Pass, handle: &Handle<Self>, event: MouseEvent) {
87 match event.kind {
88 MouseEventKind::ScrollDown | MouseEventKind::ScrollUp => {
89 let (wk, area) = handle.write_with_area(pa);
90 let scroll = if let MouseEventKind::ScrollDown = event.kind {
91 3
92 } else {
93 -3
94 };
95 area.scroll_ver(&wk.text, scroll, wk.get_print_opts());
96 }
97 _ => {}
98 }
99 }
100}