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