pushrod_widgets/system_widgets/
toggle_button_widget.rs1use sdl2::render::{Canvas, Texture};
17use sdl2::video::Window;
18
19use crate::caches::TextureCache;
20use crate::event::PushrodEvent;
21use crate::event::PushrodEvent::{
22 DrawFrame, MouseButton, WidgetMouseEntered, WidgetMouseExited, WidgetSelected,
23};
24use crate::primitives::draw_base;
25use crate::properties::{
26 WidgetProperties, PROPERTY_BORDER_WIDTH, PROPERTY_ID, PROPERTY_TEXT_JUSTIFICATION,
27 PROPERTY_TOGGLED, TEXT_JUSTIFY_CENTER, TEXT_JUSTIFY_LEFT, TEXT_JUSTIFY_RIGHT,
28};
29use crate::texture_store::TextureStore;
30use crate::widget::Widget;
31use sdl2::pixels::Color;
32use sdl2::rect::Rect;
33
34const PROPERTY_BUTTON_ACTIVE: u32 = 20000;
36
37const PROPERTY_BUTTON_IN_BOUNDS: u32 = 20001;
39
40const PROPERTY_BUTTON_ORIGINATED: u32 = 20002;
42
43const PROPERTY_BUTTON_HOVERED: u32 = 20003;
46
47#[derive(Default)]
49pub struct ToggleButtonWidget {
50 texture_store: TextureStore,
51 properties: WidgetProperties,
52}
53
54impl ToggleButtonWidget {
56 fn set_hovered(&mut self) {
58 self.properties.set_bool(PROPERTY_BUTTON_HOVERED);
59 self.invalidate();
60 }
61
62 fn set_unhovered(&mut self) {
64 self.properties.delete(PROPERTY_BUTTON_HOVERED);
65 self.invalidate();
66 }
67
68 fn toggle_selected(&mut self) {
70 if self.properties.get_bool(PROPERTY_TOGGLED) {
71 self.properties.delete(PROPERTY_TOGGLED);
72 } else {
73 self.properties.set_bool(PROPERTY_TOGGLED);
74 }
75 }
76
77 fn is_selected(&self) -> bool {
79 self.properties.get_bool(PROPERTY_TOGGLED)
80 }
81}
82
83impl Widget for ToggleButtonWidget {
85 widget_default_impl!("ToggleButtonWidget");
86
87 fn draw(&mut self, c: &mut Canvas<Window>, t: &mut TextureCache) -> Option<&Texture> {
104 if self.invalidated() {
106 let bounds = self.properties.get_bounds();
107 let text_color = if self.properties.get_bool(PROPERTY_BUTTON_HOVERED) {
108 if self.is_selected() {
109 Some(Color::BLACK)
110 } else {
111 Some(Color::WHITE)
112 }
113 } else if self.is_selected() {
114 Some(Color::WHITE)
115 } else {
116 None
117 };
118 let (font_texture, width, height) = t.render_text(c, &mut self.properties, text_color);
119 let text_justification = self.properties.get_value(PROPERTY_TEXT_JUSTIFICATION);
120 let border_width = self.properties.get_value(PROPERTY_BORDER_WIDTH);
121 let widget_w = bounds.0;
122 let texture_x: i32 = match text_justification {
123 TEXT_JUSTIFY_LEFT => 0,
124 TEXT_JUSTIFY_CENTER => (widget_w - width) as i32 / 2,
125 TEXT_JUSTIFY_RIGHT => (widget_w - width) as i32,
126 _ => 0,
127 };
128
129 self.texture_store
130 .create_or_resize_texture(c, bounds.0, bounds.1);
131
132 let cloned_properties = self.properties.clone();
133 let back_color = if self.properties.get_bool(PROPERTY_BUTTON_HOVERED) {
134 if self.is_selected() {
135 Some(Color::WHITE)
136 } else {
137 Some(Color::BLACK)
138 }
139 } else if self.is_selected() {
140 Some(Color::BLACK)
141 } else {
142 None
143 };
144
145 c.with_texture_canvas(self.texture_store.get_mut_ref(), |texture| {
146 draw_base(texture, &cloned_properties, back_color);
147
148 texture
149 .copy(
150 &font_texture,
151 None,
152 Rect::new(
153 texture_x + border_width,
154 ((bounds.1 / 2) - (height / 2) - (border_width / 2) as u32) as i32,
155 width,
156 height,
157 ),
158 )
159 .unwrap();
160 })
161 .unwrap();
162 }
163
164 self.texture_store.get_optional_ref()
165 }
166
167 fn handle_event(&mut self, event: PushrodEvent) -> Option<PushrodEvent> {
170 match event {
171 WidgetMouseEntered { .. } => {
172 if self.properties.get_bool(PROPERTY_BUTTON_ACTIVE) {
173 self.set_hovered();
174 }
175
176 self.properties.set_bool(PROPERTY_BUTTON_IN_BOUNDS);
177 }
178 WidgetMouseExited { .. } => {
179 if self.properties.get_bool(PROPERTY_BUTTON_ACTIVE) {
180 self.set_unhovered();
181 }
182
183 self.properties.delete(PROPERTY_BUTTON_IN_BOUNDS);
184 }
185 MouseButton {
186 widget_id,
187 button,
188 state,
189 } => {
190 let current_widget_id = self.properties.get_value(PROPERTY_ID);
191
192 if button == 1 {
193 if state {
194 self.set_hovered();
195 self.properties.set_bool(PROPERTY_BUTTON_ACTIVE);
196 self.properties.set_bool(PROPERTY_BUTTON_ORIGINATED);
197 } else {
198 let had_bounds = self.properties.get_bool(PROPERTY_BUTTON_ACTIVE);
199
200 self.set_unhovered();
201 self.properties.delete(PROPERTY_BUTTON_ACTIVE);
202
203 if self.properties.get_bool(PROPERTY_BUTTON_IN_BOUNDS)
204 && had_bounds
205 && self.properties.get_bool(PROPERTY_BUTTON_ORIGINATED)
206 && current_widget_id as u32 == widget_id
207 {
208 self.properties.delete(PROPERTY_BUTTON_ORIGINATED);
209
210 self.toggle_selected();
211
212 return Some(WidgetSelected {
213 widget_id: current_widget_id as u32,
214 state: self.is_selected(),
215 });
216 }
217
218 self.properties.delete(PROPERTY_BUTTON_ORIGINATED);
219 }
220 }
221 }
222 DrawFrame { .. } => {}
223 _ => eprintln!("ButtonWidget Event: {:?}", event),
224 }
225
226 None
227 }
228}