1use sfml::{
2 graphics::{
3 Color, Font, Rect, RectangleShape, RenderTarget, RenderWindow, Shape, Text, Transformable,
4 },
5 system::Vector2,
6 window::{mouse, ContextSettings, Cursor, CursorType, Event, Style},
7 SfResult,
8};
9
10include!("../example_common.rs");
11
12const DRAW_AREA_TOPLEFT: (u16, u16) = (300, 64);
13const DRAW_GRID_WH: u8 = 16;
14const DRAW_CELL_WH: u8 = 26;
15
16fn gridindex(
17 grid: &mut [bool; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize],
18 x: usize,
19 y: usize,
20) -> Option<&mut bool> {
21 grid.get_mut(y * DRAW_GRID_WH as usize + x)
22}
23
24fn mouse_over(rect: &Rect<i32>, mouse_x: i32, mouse_y: i32) -> bool {
25 rect.contains(Vector2::new(mouse_x, mouse_y))
26}
27
28enum ButtonStyle {
29 Normal,
30 Highlighted,
31 Selected,
32 Error,
33}
34
35fn draw_button(
36 rect: &Rect<i32>,
37 shape: &mut RectangleShape,
38 text: &mut Text,
39 string: &str,
40 render_window: &mut RenderWindow,
41 style: ButtonStyle,
42) {
43 shape.set_position((rect.left as f32, rect.top as f32));
44 shape.set_size((rect.width as f32, rect.height as f32));
45 let (rect_fill, rect_outline, text_fill) = match style {
46 ButtonStyle::Normal => (Color::TRANSPARENT, Color::WHITE, Color::WHITE),
47 ButtonStyle::Highlighted => (Color::WHITE, Color::WHITE, Color::BLACK),
48 ButtonStyle::Selected => (Color::GREEN, Color::GREEN, Color::BLACK),
49 ButtonStyle::Error => (Color::RED, Color::BLACK, Color::BLACK),
50 };
51 shape.set_outline_color(rect_outline);
52 shape.set_fill_color(rect_fill);
53 text.set_position((rect.left as f32 + 12.0, rect.top as f32 + 8.0));
54 text.set_fill_color(text_fill);
55 text.set_string(string);
56 render_window.draw(shape);
57 render_window.draw(text);
58}
59
60fn bstyle(highlighted: bool, selected: bool, error: bool) -> ButtonStyle {
61 if error {
62 ButtonStyle::Error
63 } else if highlighted {
64 ButtonStyle::Highlighted
65 } else if selected {
66 ButtonStyle::Selected
67 } else {
68 ButtonStyle::Normal
69 }
70}
71
72fn main() -> SfResult<()> {
73 example_ensure_right_working_dir();
74
75 let mut cursor = Cursor::from_system(CursorType::Arrow)?;
76 let mut rw = RenderWindow::new(
77 (800, 800),
78 "SFML cursor example",
79 Style::CLOSE,
80 &ContextSettings::default(),
81 )?;
82 rw.set_vertical_sync_enabled(true);
83 let font = Font::from_file("sansation.ttf")?;
84 let mut failed_index = usize::MAX;
85 let mut selected_index = usize::MAX;
86 let set_button = Rect::new(348, 500, 100, 32);
87 let hotspot_button = Rect::new(458, 500, 100, 32);
88 let clear_button = Rect::new(568, 500, 100, 32);
89 let mut pixel_grid = [false; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize];
90 let mut hotspot_selection = false;
91 let mut hotspot_selected = false;
92 let mut hotspot = Vector2::new(8, 8);
93 let mut modif = false;
94
95 let mut buttons = Vec::new();
96 let cursor_types = [
97 CursorType::Arrow,
98 CursorType::ArrowWait,
99 CursorType::Wait,
100 CursorType::Text,
101 CursorType::Hand,
102 CursorType::SizeHorizontal,
103 CursorType::SizeVertical,
104 CursorType::SizeTopLeftBottomRight,
105 CursorType::SizeBottomLeftTopRight,
106 CursorType::SizeLeft,
107 CursorType::SizeRight,
108 CursorType::SizeTop,
109 CursorType::SizeBottom,
110 CursorType::SizeTopLeft,
111 CursorType::SizeBottomRight,
112 CursorType::SizeBottomLeft,
113 CursorType::SizeTopRight,
114 CursorType::SizeAll,
115 CursorType::Cross,
116 CursorType::Help,
117 CursorType::NotAllowed,
118 ];
119 for i in 0..cursor_types.len() {
120 buttons.push(Rect::new(16, 16 + i as i32 * 36, 250, 32));
121 }
122
123 while rw.is_open() {
124 while let Some(ev) = rw.poll_event() {
125 match ev {
126 Event::Closed => rw.close(),
127 Event::MouseButtonPressed {
128 button: mouse::Button::Left,
129 x,
130 y,
131 } => {
132 for (i, b) in buttons.iter().enumerate() {
133 if mouse_over(b, x, y) {
134 match cursor.load_from_system(cursor_types[i]) {
135 Ok(()) => {
136 unsafe {
137 rw.set_mouse_cursor(&cursor);
138 }
139 selected_index = i;
140 }
141 Err(e) => {
142 eprintln!("{e}");
143 failed_index = i;
144 }
145 }
146 }
147 }
148 if mouse_over(&set_button, x, y) {
149 let mut pixels = [0; DRAW_GRID_WH as usize * DRAW_GRID_WH as usize * 4];
150 for (i, px) in pixel_grid.iter().enumerate() {
151 let offset = i * 4;
152 if *px {
153 pixels[offset] = 255;
154 pixels[offset + 1] = 255;
155 pixels[offset + 2] = 255;
156 pixels[offset + 3] = 255;
157 }
158 }
159 unsafe {
160 match cursor.load_from_pixels(
161 &pixels,
162 Vector2::new(DRAW_GRID_WH as u32, DRAW_GRID_WH as u32),
163 hotspot,
164 ) {
165 Ok(()) => {
166 rw.set_mouse_cursor(&cursor);
167 }
168 Err(e) => {
169 eprintln!("{e}");
170 }
171 }
172 }
173 modif = false;
174 }
175 if mouse_over(&clear_button, x, y) {
176 for px in pixel_grid.iter_mut() {
177 *px = false;
178 }
179 modif = true;
180 }
181 if mouse_over(&hotspot_button, x, y) {
182 hotspot_selection = true;
183 }
184 }
185 Event::MouseButtonReleased {
186 button: mouse::Button::Left,
187 ..
188 } => {
189 if hotspot_selected {
190 hotspot_selection = false;
191 hotspot_selected = false;
192 }
193 }
194 _ => {}
195 }
196 }
197 let mut set_button_highlighted = false;
198 let mut hotspot_button_highlighted = false;
199 let mut clear_button_highlighted = false;
200 let mp = rw.mouse_position();
202 let mut highlight_index = usize::MAX;
203 for (i, b) in buttons.iter().enumerate() {
204 if mouse_over(b, mp.x, mp.y) {
205 highlight_index = i;
206 }
207 }
208 if mouse_over(&set_button, mp.x, mp.y) {
209 set_button_highlighted = true;
210 }
211 if mouse_over(&hotspot_button, mp.x, mp.y) {
212 hotspot_button_highlighted = true;
213 }
214 if mouse_over(&clear_button, mp.x, mp.y) {
215 clear_button_highlighted = true;
216 }
217 let rela_x = mp.x - DRAW_AREA_TOPLEFT.0 as i32;
219 let rela_y = mp.y - DRAW_AREA_TOPLEFT.1 as i32;
220 let (gx, gy) = (rela_x / DRAW_CELL_WH as i32, rela_y / DRAW_CELL_WH as i32);
221 if gx >= 0 && gy >= 0 {
222 if let Some(cell) = gridindex(&mut pixel_grid, gx as usize, gy as usize) {
223 if hotspot_selection {
224 hotspot_selected = true;
225 hotspot = Vector2::new(gx as u32, gy as u32);
226 modif = true;
227 } else if mouse::Button::Left.is_pressed() {
228 *cell = true;
229 modif = true;
230 } else if mouse::Button::Right.is_pressed() {
231 *cell = false;
232 modif = true;
233 }
234 }
235 }
236 rw.clear(Color::BLACK);
237 let mut shape = RectangleShape::default();
239 let mut text = Text::new("", &font, 14);
240 shape.set_outline_thickness(-1.0);
241 shape.set_outline_color(Color::WHITE);
242 for (i, b) in buttons.iter().enumerate() {
243 let types = [
244 "ARROW",
245 "ARROW_WAIT",
246 "WAIT",
247 "TEXT",
248 "HAND",
249 "SIZE_HORIZONTAL",
250 "SIZE_VERTICAL",
251 "SIZE_TOP_LEFT_BOTTOM_RIGHT",
252 "SIZE_BOTTOM_LEFT_TOP_RIGHT",
253 "SIZE_LEFT",
254 "SIZE_RIGHT",
255 "SIZE_TOP",
256 "SIZE_BOTTOM",
257 "SIZE_TOP_LEFT",
258 "SIZE_BOTTOM_RIGHT",
259 "SIZE_BOTTOM_LEFT",
260 "SIZE_TOP_RIGHT",
261 "SIZE_ALL",
262 "CROSS",
263 "HELP",
264 "NOT_ALLOWED",
265 ];
266 draw_button(
267 b,
268 &mut shape,
269 &mut text,
270 types[i],
271 &mut rw,
272 bstyle(highlight_index == i, selected_index == i, failed_index == i),
273 );
274 }
275 shape.set_fill_color(Color::TRANSPARENT);
277 for y in 0..DRAW_GRID_WH {
278 for x in 0..DRAW_GRID_WH {
279 if hotspot.x == x as u32 && hotspot.y == y as u32 {
280 shape.set_outline_color(Color::RED);
281 } else {
282 shape.set_outline_color(Color::rgb(180, 180, 180));
283 }
284 if gridindex(&mut pixel_grid, x as usize, y as usize).is_some_and(|bool| *bool) {
285 shape.set_fill_color(Color::WHITE);
286 } else {
287 shape.set_fill_color(Color::TRANSPARENT);
288 }
289 shape.set_size((DRAW_CELL_WH as f32, DRAW_CELL_WH as f32));
290 shape.set_position((
291 DRAW_AREA_TOPLEFT.0 as f32 + (x as f32 * DRAW_CELL_WH as f32),
292 DRAW_AREA_TOPLEFT.1 as f32 + (y as f32 * DRAW_CELL_WH as f32),
293 ));
294 rw.draw(&shape);
295 }
296 }
297 draw_button(
298 &set_button,
299 &mut shape,
300 &mut text,
301 if modif { "Set*" } else { "Set" },
302 &mut rw,
303 bstyle(set_button_highlighted, false, false),
304 );
305 draw_button(
306 &hotspot_button,
307 &mut shape,
308 &mut text,
309 "Hotspot",
310 &mut rw,
311 bstyle(hotspot_button_highlighted, hotspot_selection, false),
312 );
313 draw_button(
314 &clear_button,
315 &mut shape,
316 &mut text,
317 "Clear",
318 &mut rw,
319 bstyle(clear_button_highlighted, false, false),
320 );
321 rw.display();
322 }
323 Ok(())
324}