1use egui::accesskit::ActionRequest;
2use egui::mutex::Mutex;
3use egui::{Modifiers, PointerButton, Pos2, accesskit};
4use kittest::{AccessKitNode, NodeT, debug_fmt_node};
5use std::fmt::{Debug, Formatter};
6
7pub(crate) enum EventType {
8 Event(egui::Event),
9 Modifiers(Modifiers),
10}
11
12pub(crate) type EventQueue = Mutex<Vec<EventType>>;
13
14#[derive(Clone, Copy)]
15pub struct Node<'tree> {
16 pub(crate) accesskit_node: AccessKitNode<'tree>,
17 pub(crate) queue: &'tree EventQueue,
18}
19
20impl Debug for Node<'_> {
21 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
22 debug_fmt_node(self, f)
23 }
24}
25
26impl<'tree> NodeT<'tree> for Node<'tree> {
27 fn accesskit_node(&self) -> AccessKitNode<'tree> {
28 self.accesskit_node
29 }
30
31 fn new_related(&self, child_node: AccessKitNode<'tree>) -> Self {
32 Self {
33 queue: self.queue,
34 accesskit_node: child_node,
35 }
36 }
37}
38
39impl Node<'_> {
40 fn event(&self, event: egui::Event) {
41 self.queue.lock().push(EventType::Event(event));
42 }
43
44 fn modifiers(&self, modifiers: Modifiers) {
45 self.queue.lock().push(EventType::Modifiers(modifiers));
46 }
47
48 pub fn hover(&self) {
49 self.event(egui::Event::PointerMoved(self.rect().center()));
50 }
51
52 pub fn click(&self) {
54 self.click_button(PointerButton::Primary);
55 }
56
57 #[deprecated = "Use `click()` instead."]
58 pub fn simulate_click(&self) {
59 self.click();
60 }
61
62 pub fn click_secondary(&self) {
63 self.click_button(PointerButton::Secondary);
64 }
65
66 pub fn click_button(&self, button: PointerButton) {
67 self.hover();
68 for pressed in [true, false] {
69 self.event(egui::Event::PointerButton {
70 pos: self.rect().center(),
71 button,
72 pressed,
73 modifiers: Modifiers::default(),
74 });
75 }
76 }
77
78 pub fn click_modifiers(&self, modifiers: Modifiers) {
79 self.click_button_modifiers(PointerButton::Primary, modifiers);
80 }
81
82 pub fn click_button_modifiers(&self, button: PointerButton, modifiers: Modifiers) {
83 self.hover();
84 self.modifiers(modifiers);
85 for pressed in [true, false] {
86 self.event(egui::Event::PointerButton {
87 pos: self.rect().center(),
88 button,
89 pressed,
90 modifiers,
91 });
92 }
93 self.modifiers(Modifiers::default());
94 }
95
96 pub fn click_accesskit(&self) {
101 self.event(egui::Event::AccessKitActionRequest(
102 accesskit::ActionRequest {
103 target: self.accesskit_node.id(),
104 action: accesskit::Action::Click,
105 data: None,
106 },
107 ));
108 }
109
110 pub fn rect(&self) -> egui::Rect {
111 let rect = self
112 .accesskit_node
113 .bounding_box()
114 .expect("Every egui node should have a rect");
115 egui::Rect {
116 min: Pos2::new(rect.x0 as f32, rect.y0 as f32),
117 max: Pos2::new(rect.x1 as f32, rect.y1 as f32),
118 }
119 }
120
121 pub fn focus(&self) {
122 self.event(egui::Event::AccessKitActionRequest(ActionRequest {
123 action: accesskit::Action::Focus,
124 target: self.accesskit_node.id(),
125 data: None,
126 }));
127 }
128
129 #[deprecated = "Use `Harness::key_down` instead."]
130 pub fn key_down(&self, key: egui::Key) {
131 self.event(egui::Event::Key {
132 key,
133 pressed: true,
134 modifiers: Modifiers::default(),
135 repeat: false,
136 physical_key: None,
137 });
138 }
139
140 #[deprecated = "Use `Harness::key_up` instead."]
141 pub fn key_up(&self, key: egui::Key) {
142 self.event(egui::Event::Key {
143 key,
144 pressed: false,
145 modifiers: Modifiers::default(),
146 repeat: false,
147 physical_key: None,
148 });
149 }
150
151 pub fn type_text(&self, text: &str) {
152 self.event(egui::Event::Text(text.to_owned()));
153 }
154
155 pub fn value(&self) -> Option<String> {
156 self.accesskit_node.value()
157 }
158
159 pub fn is_focused(&self) -> bool {
160 self.accesskit_node.is_focused()
161 }
162
163 pub fn scroll_to_me(&self) {
165 self.event(egui::Event::AccessKitActionRequest(ActionRequest {
166 action: accesskit::Action::ScrollIntoView,
167 target: self.accesskit_node.id(),
168 data: None,
169 }));
170 }
171
172 pub fn scroll_down(&self) {
174 self.event(egui::Event::AccessKitActionRequest(ActionRequest {
175 action: accesskit::Action::ScrollDown,
176 target: self.accesskit_node.id(),
177 data: None,
178 }));
179 }
180
181 pub fn scroll_up(&self) {
183 self.event(egui::Event::AccessKitActionRequest(ActionRequest {
184 action: accesskit::Action::ScrollUp,
185 target: self.accesskit_node.id(),
186 data: None,
187 }));
188 }
189
190 pub fn scroll_left(&self) {
192 self.event(egui::Event::AccessKitActionRequest(ActionRequest {
193 action: accesskit::Action::ScrollLeft,
194 target: self.accesskit_node.id(),
195 data: None,
196 }));
197 }
198
199 pub fn scroll_right(&self) {
201 self.event(egui::Event::AccessKitActionRequest(ActionRequest {
202 action: accesskit::Action::ScrollRight,
203 target: self.accesskit_node.id(),
204 data: None,
205 }));
206 }
207}