pix_engine/state/settings.rs
1//! Settings methods for the [`Engine`].
2//!
3//! Methods for reading and setting various engine configuration values.
4//!
5//! Provided types:
6//!
7//! - [`DrawMode`]: Determines how `(x, y)` coordinates are used for rendering.
8//! - [`RectMode`]: Alias for `DrawMode`.
9//! - [`EllipseMode`]: Alias for `DrawMode`.
10//! - [`ImageMode`]: Alias for `DrawMode`.
11//! - [`ArcMode`]: Determines how arcs are rendered.
12//! - [`BlendMode`]: Determines how images and textures are blended.
13//! - [`AngleMode`]: Determines how angles are interpreted.
14//! - [`FontStyle`]: Determines how text is rendered.
15//!
16//! Provided [`PixState`] methods:
17//!
18//! - [`PixState::background`]: Sets the [Color] used by [`PixState::clear`] to clear the canvas.
19//! - [`PixState::fill`]: Sets the [Color] used to fill shapes.
20//! - [`PixState::stroke`]: Sets the [Color] used to stroke shapes and text.
21//! - [`PixState::stroke_weight`]: Sets the stroke line thickness for lines and text.
22//! - [`PixState::text_shadow`]: Sets the shadow distance for drawing text.
23//! - [`PixState::smooth`]: Enables the anti-alias smoothing option for drawing shapes.
24//! - [`PixState::bezier_detail`]: Set the resolution at which Bezier curves are dispalyed.
25//! - [`PixState::wrap`]: Sets the wrap width for rendering text.
26//! - [`PixState::clip`]: Sets a clip rectangle for rendering.
27//! - [`PixState::fullscreen`]: Sets fullscreen mode to enabled or disabled.
28//! - [`PixState::toggle_fullscreen`]: Toggles fullscreen.
29//! - [`PixState::vsync`]: Sets vertical sync mode to enabled or disabled.
30//! - [`PixState::toggle_vsync`]: Toggles vertical sync.
31//! - [`PixState::cursor`]: Set a custom window cursor or hide the cursor.
32//! - [`PixState::disable`]: Disable UI elements from being interactive.
33//! - [`PixState::running`]: Whether the render loop is running (calling [`PixEngine::on_update`]).
34//! - [`PixState::run`]: Enable or disable the render loop.
35//! - [`PixState::show_frame_rate`]: Display the average frame rate in the title bar.
36//! - [`PixState::target_frame_rate`]: Return the current targeted frame rate.
37//! - [`PixState::frame_rate`]: Set or clear a targeted frame rate.
38//! - [`PixState::scale`]: Set the rendering scale of the current canvas.
39//! - [`PixState::rect_mode`]: Change the [`RectMode`] for rendering rectangles.
40//! - [`PixState::ellipse_mode`]: Change the [`EllipseMode`] for rendering ellipses.
41//! - [`PixState::image_mode`]: Change the [`ImageMode`] for rendering images.
42//! - [`PixState::image_tint`]: Set or clear a [Color] used to tint [Image]s.
43//! - [`PixState::arc_mode`]: Change the [`ArcMode`] for rendering arcs.
44//! - [`PixState::angle_mode`]: Change the [`AngleMode`] for angle interpretation.
45//! - [`PixState::blend_mode`]: Change the [`BlendMode`] for rendering images and textures.
46//! - [`PixState::push`]: Push a copy of all the current settings to a stack.
47//! - [`PixState::pop`]: Pop the previously pushed settings off the stack, restoring them.
48
49use crate::{
50 prelude::*,
51 renderer::{Rendering, WindowRenderer},
52};
53use bitflags::bitflags;
54#[cfg(feature = "serde")]
55use serde::{Deserialize, Serialize};
56use std::time::Duration;
57
58/// Drawing mode which changes how `(x, y)` coordinates are interpreted.
59#[non_exhaustive]
60#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
61#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
62pub enum DrawMode {
63 /// Use `(x, y)` as the top-left corner. Default.
64 Corner,
65 /// Use `(x, y)` as the center.
66 Center,
67}
68
69/// Drawing mode which determines how `(x, y)` coordinates are interpreted when drawing [Rect]s.
70pub type RectMode = DrawMode;
71
72/// Drawing mode which determines how `(x, y)` coordinates are interpreted when drawing [Ellipse]s.
73pub type EllipseMode = DrawMode;
74
75/// Drawing mode which determines how `(x, y)` coordinates are interpreted when drawing [Image]s.
76pub type ImageMode = DrawMode;
77
78/// Drawing mode which determines how arcs are drawn.
79#[non_exhaustive]
80#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
81#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
82pub enum ArcMode {
83 /// Draws arc as an open, unfilled pie segment using `stroke` color.
84 Default,
85 /// Draws arc as a closed pie segment using `stroke` and `fill` colors.
86 Pie,
87}
88
89/// Drawing mode which determines how textures are blended together.
90#[non_exhaustive]
91#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
92#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
93pub enum BlendMode {
94 /// Disable blending.
95 None,
96 /// Alpha blending.
97 Blend,
98 /// Additive blending.
99 Add,
100 /// Color modulate.
101 Mod,
102}
103
104/// Determines how angles are interpreted.
105#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
106#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
107pub enum AngleMode {
108 /// Radians.
109 Radians,
110 /// Degrees.
111 Degrees,
112}
113
114bitflags! {
115 /// Font style for drawing text.
116 #[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
117 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
118 #[cfg_attr(feature = "serde", serde(transparent))]
119 pub struct FontStyle: i32 {
120 /// Normal.
121 const NORMAL = 0x00;
122 /// Bold.
123 const BOLD = 0x01;
124 /// Italic.
125 const ITALIC = 0x02;
126 /// Underline
127 const UNDERLINE = 0x04;
128 /// Strike-through
129 const STRIKETHROUGH = 0x08;
130 }
131}
132
133/// Several settings used to change various functionality of the engine.
134#[derive(Debug, Clone)]
135#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136pub(crate) struct Settings {
137 pub(crate) background: Color,
138 pub(crate) fill: Option<Color>,
139 pub(crate) stroke: Option<Color>,
140 pub(crate) stroke_weight: u16,
141 pub(crate) font_size: u32,
142 pub(crate) font_style: FontStyle,
143 #[cfg_attr(feature = "serde", serde(skip))]
144 pub(crate) font_family: Font,
145 pub(crate) text_shadow: Option<u16>,
146 pub(crate) smooth: bool,
147 pub(crate) bezier_detail: i32,
148 pub(crate) wrap_width: Option<u32>,
149 pub(crate) clip: Option<Rect<i32>>,
150 pub(crate) running: bool,
151 pub(crate) show_frame_rate: bool,
152 pub(crate) target_frame_rate: Option<usize>,
153 pub(crate) target_delta_time: Option<Duration>,
154 pub(crate) scale_x: f32,
155 pub(crate) scale_y: f32,
156 pub(crate) rect_mode: RectMode,
157 pub(crate) ellipse_mode: EllipseMode,
158 pub(crate) image_mode: ImageMode,
159 pub(crate) image_tint: Option<Color>,
160 pub(crate) arc_mode: ArcMode,
161 pub(crate) angle_mode: AngleMode,
162 pub(crate) blend_mode: BlendMode,
163 pub(crate) cursor: Option<Cursor>,
164 pub(crate) disabled: bool,
165}
166
167impl Default for Settings {
168 fn default() -> Self {
169 Self {
170 background: Color::BLACK,
171 fill: Some(Color::WHITE),
172 stroke: None,
173 stroke_weight: 1,
174 font_size: 14,
175 font_style: FontStyle::NORMAL,
176 font_family: Font::default(),
177 text_shadow: None,
178 smooth: true,
179 bezier_detail: 20,
180 wrap_width: None,
181 clip: None,
182 running: true,
183 show_frame_rate: false,
184 target_frame_rate: None,
185 target_delta_time: None,
186 scale_x: 1.0,
187 scale_y: 1.0,
188 rect_mode: RectMode::Corner,
189 ellipse_mode: EllipseMode::Center,
190 image_mode: ImageMode::Corner,
191 image_tint: None,
192 arc_mode: ArcMode::Default,
193 angle_mode: AngleMode::Radians,
194 blend_mode: BlendMode::None,
195 cursor: Some(Cursor::default()),
196 disabled: false,
197 }
198 }
199}
200
201impl PixState {
202 /// Sets the [Color] value used to clear the canvas.
203 ///
204 /// # Example
205 ///
206 /// ```
207 /// # use pix_engine::prelude::*;
208 /// # struct App;
209 /// # impl PixEngine for App {
210 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
211 /// s.background(Color::ALICE_BLUE);
212 /// s.clear();
213 /// Ok(())
214 /// }
215 /// # }
216 /// ```
217 #[inline]
218 pub fn background<C>(&mut self, color: C)
219 where
220 C: Into<Color>,
221 {
222 self.settings.background = color.into();
223 let _result = self.clear(); // If this errors, something is very wrong
224 }
225
226 /// Sets the [Color] value used to fill shapes drawn on the canvas. `None` disables fill
227 /// entirely.
228 ///
229 /// # Example
230 ///
231 /// ```
232 /// # use pix_engine::prelude::*;
233 /// # struct App;
234 /// # impl PixEngine for App {
235 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
236 /// s.fill(Color::ALICE_BLUE);
237 /// s.rect([0, 0, 100, 100])?;
238 /// s.fill((None));
239 /// s.rect([25, 25, 75, 75])?;
240 /// Ok(())
241 /// }
242 /// # }
243 /// ```
244 #[inline]
245 pub fn fill<C>(&mut self, color: C)
246 where
247 C: Into<Option<Color>>,
248 {
249 self.settings.fill = color.into();
250 }
251
252 /// Sets the [Color] value used to outline shapes drawn on the canvas. `None` disables stroke
253 /// entirely.
254 ///
255 /// # Example
256 ///
257 /// ```
258 /// # use pix_engine::prelude::*;
259 /// # struct App;
260 /// # impl PixEngine for App {
261 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
262 /// s.stroke(Color::BLACK);
263 /// s.rect([0, 0, 100, 100])?;
264 /// s.stroke((None));
265 /// s.rect([25, 25, 75, 75])?;
266 /// Ok(())
267 /// }
268 /// # }
269 /// ```
270 #[inline]
271 pub fn stroke<C>(&mut self, color: C)
272 where
273 C: Into<Option<Color>>,
274 {
275 self.settings.stroke = color.into();
276 }
277
278 /// Sets the width used to draw lines on the canvas.
279 ///
280 /// # Example
281 ///
282 /// ```
283 /// # use pix_engine::prelude::*;
284 /// # struct App;
285 /// # impl PixEngine for App {
286 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
287 /// s.stroke(Color::BLUE);
288 /// s.stroke_weight(2);
289 /// // Draws a 2-pixel wide diagonal line
290 /// s.line(line_![0, 0, 100, 100])?;
291 /// Ok(())
292 /// }
293 /// # }
294 /// ```
295 #[inline]
296 pub fn stroke_weight(&mut self, weight: u16) {
297 self.settings.stroke_weight = weight;
298 }
299
300 /// Set the font size for drawing to the current canvas.
301 ///
302 /// # Errors
303 ///
304 /// If the renderer fails to load the given font size from the currently loaded font data, then
305 /// an error is returned.
306 ///
307 /// # Example
308 ///
309 /// ```
310 /// # use pix_engine::prelude::*;
311 /// # struct App;
312 /// # impl PixEngine for App {
313 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
314 /// s.font_size(22);
315 /// s.text("Some big text")?;
316 /// Ok(())
317 /// }
318 /// # }
319 /// ```
320 #[inline]
321 pub fn font_size(&mut self, size: u32) -> PixResult<()> {
322 self.settings.font_size = size;
323 self.theme.font_size = size;
324 self.renderer.font_size(size)
325 }
326
327 /// Set the font style for drawing to the current canvas.
328 ///
329 /// # Errors
330 ///
331 /// If the renderer fails to load the current font, then an error is returned.
332 ///
333 /// # Example
334 ///
335 /// ```
336 /// # use pix_engine::prelude::*;
337 /// # struct App;
338 /// # impl PixEngine for App {
339 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
340 /// s.font_style(FontStyle::BOLD);
341 /// s.text("Some bold text")?;
342 /// Ok(())
343 /// }
344 /// # }
345 /// ```
346 #[inline]
347 pub fn font_style(&mut self, style: FontStyle) {
348 self.settings.font_style = style;
349 self.renderer.font_style(style);
350 }
351
352 /// Set the font family for drawing to the current canvas.
353 ///
354 /// # Errors
355 ///
356 /// If the renderer fails to load the given font size from the currently loaded font data, then
357 /// an error is returned.
358 ///
359 /// # Example
360 ///
361 /// ```
362 /// # use pix_engine::prelude::*;
363 /// # struct App;
364 /// # impl PixEngine for App {
365 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
366 /// s.font_family(Font::NOTO)?;
367 /// s.text("Some NOTO family text")?;
368 /// s.font_family(Font::from_file("Custom font", "./custom_font.ttf"))?;
369 /// s.text("Some custom family text")?;
370 /// Ok(())
371 /// }
372 /// # }
373 /// ```
374 #[inline]
375 pub fn font_family(&mut self, font: Font) -> PixResult<()> {
376 self.settings.font_family = font;
377 self.renderer.font_family(&self.settings.font_family)
378 }
379
380 /// Sets the text shadow distance used to draw text on the canvas.
381 ///
382 /// # Example
383 ///
384 /// ```
385 /// # use pix_engine::prelude::*;
386 /// # struct App;
387 /// # impl PixEngine for App {
388 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
389 /// s.text_shadow(2);
390 /// // Draws a 2-pixel offset shhadow
391 /// s.text("Shadowed")?;
392 /// Ok(())
393 /// }
394 /// # }
395 /// ```
396 #[inline]
397 pub fn text_shadow<D>(&mut self, distance: D)
398 where
399 D: Into<Option<u16>>,
400 {
401 self.settings.text_shadow = distance.into();
402 }
403
404 /// Enable or disable the anti-alias option used for drawing shapes on the canvas. `smooth` is
405 /// enabled by default.
406 ///
407 /// # Example
408 ///
409 /// ```
410 /// # use pix_engine::prelude::*;
411 /// # struct App;
412 /// # impl PixEngine for App {
413 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
414 /// // Draws a anti-aliased diagonal line
415 /// s.smooth(true);
416 /// s.line(line_![0, 0, 100, 100])?;
417 /// // Disables anti-aliasing
418 /// s.smooth(false);
419 /// s.line(line_![0, 0, 100, 100])?;
420 /// Ok(())
421 /// }
422 /// # }
423 /// ```
424 #[inline]
425 pub fn smooth(&mut self, val: bool) {
426 self.settings.smooth = val;
427 }
428
429 /// Set the resolution at which [`PixState::bezier`] curves are displayed. The default is `20`.
430 ///
431 /// # Example
432 ///
433 /// ```
434 /// # use pix_engine::prelude::*;
435 /// # struct App;
436 /// # impl PixEngine for App {
437 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
438 /// s.bezier_detail(5);
439 /// s.stroke(Color::RED);
440 /// s.bezier([[85, 20], [10, 10], [90, 90], [15, 80]])?;
441 /// Ok(())
442 /// }
443 /// # }
444 /// ```
445 #[inline]
446 pub fn bezier_detail(&mut self, detail: i32) {
447 self.settings.bezier_detail = detail;
448 }
449
450 /// Sets the wrap width used to draw text on the canvas. `None` disables text wrap.
451 ///
452 /// # Example
453 ///
454 /// ```
455 /// # use pix_engine::prelude::*;
456 /// # struct App;
457 /// # impl PixEngine for App {
458 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
459 /// // Renders as (depending on font width):
460 /// //
461 /// // Lorem ipsum
462 /// // dollor sit amet,
463 /// // consetetur
464 /// // sadipscing
465 /// // elitr, sed diam
466 /// s.wrap(100);
467 /// s.text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam")?;
468 ///
469 /// // Disable wrapping
470 /// s.wrap((None));
471 /// s.text("Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam")?;
472 /// Ok(())
473 /// }
474 /// # }
475 /// ```
476 #[inline]
477 pub fn wrap<W>(&mut self, width: W)
478 where
479 W: Into<Option<u32>>,
480 {
481 self.settings.wrap_width = width.into();
482 }
483
484 /// Sets the clip [Rect] used by the renderer to draw to the current canvas. `None` disables
485 /// clipping.
486 ///
487 /// # Errors
488 ///
489 /// If the current render target is closed or dropped, then an error is returned.
490 ///
491 /// # Example
492 ///
493 /// ```
494 /// # use pix_engine::prelude::*;
495 /// # struct App;
496 /// # impl PixEngine for App {
497 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
498 /// s.clip(rect![0, 0, 100, 100])?;
499 /// // Renders a quarter pie-slice with radius 100
500 /// s.circle([100, 100, 200, 200])?;
501 /// Ok(())
502 /// }
503 /// # }
504 /// ```
505 #[inline]
506 pub fn clip<R>(&mut self, rect: R) -> PixResult<()>
507 where
508 R: Into<Option<Rect<i32>>>,
509 {
510 self.settings.clip = rect.into();
511 self.renderer.clip(self.settings.clip)
512 }
513
514 /// Set the application to fullscreen or not.
515 ///
516 /// # Errors
517 ///
518 /// If the current render target is closed or dropped or the renderer fails to set
519 /// fullscreen, then an error is returned.
520 ///
521 /// # Example
522 ///
523 /// ```
524 /// # use pix_engine::prelude::*;
525 /// # struct App;
526 /// # impl PixEngine for App {
527 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
528 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
529 /// if let Key::Return = event.key {
530 /// s.fullscreen(true)?;
531 /// return Ok(true);
532 /// }
533 /// Ok(false)
534 /// }
535 /// # }
536 /// ```
537 #[inline]
538 pub fn fullscreen(&mut self, val: bool) -> PixResult<()> {
539 self.renderer.set_fullscreen(val)
540 }
541
542 /// Toggle fullscreen.
543 ///
544 /// # Errors
545 ///
546 /// If the current render target is closed or dropped or the renderer fails to toggle
547 /// fullscreen, then an error is returned.
548 ///
549 /// # Example
550 ///
551 /// ```
552 /// # use pix_engine::prelude::*;
553 /// # struct App;
554 /// # impl PixEngine for App {
555 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
556 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
557 /// if let Key::Return = event.key {
558 /// s.toggle_fullscreen()?;
559 /// return Ok(true);
560 /// }
561 /// Ok(false)
562 /// }
563 /// # }
564 /// ```
565 #[inline]
566 pub fn toggle_fullscreen(&mut self) -> PixResult<()> {
567 let is_fullscreen = self.renderer.fullscreen()?;
568 self.renderer.set_fullscreen(!is_fullscreen)
569 }
570
571 /// Set the window to synchronize frame rate to the screens refresh rate ([`VSync`]).
572 ///
573 /// # Note
574 ///
575 /// Due to the current limitation with changing `VSync` at runtime, this method creates a new
576 /// window using the properties of the current window and returns the new `WindowId`.
577 ///
578 /// If you are storing and interacting with this window using the `WindowId`, make sure to
579 /// use the newly returned `WindowId`.
580 ///
581 /// [`VSync`]: https://en.wikipedia.org/wiki/Screen_tearing#Vertical_synchronization
582 ///
583 /// # Errors
584 ///
585 /// If the current render target is closed or dropped or the renderer fails to set
586 /// vsync, then an error is returned.
587 ///
588 /// # Example
589 ///
590 /// ```
591 /// # use pix_engine::prelude::*;
592 /// # struct App;
593 /// # impl PixEngine for App {
594 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
595 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
596 /// if let Key::Return = event.key {
597 /// s.vsync(true)?;
598 /// return Ok(true);
599 /// }
600 /// Ok(false)
601 /// }
602 /// # }
603 /// ```
604 #[inline]
605 pub fn vsync(&mut self, val: bool) -> PixResult<WindowId> {
606 self.renderer.set_vsync(val)
607 }
608
609 /// Toggle synchronizing frame rate to the screens refresh rate ([`VSync`]).
610 ///
611 /// # Note
612 ///
613 /// Due to the current limitation with changing `VSync` at runtime, this method creates a new
614 /// window using the properties of the current window and returns the new `WindowId`.
615 ///
616 /// If you are storing and interacting with this window using the `WindowId`, make sure to
617 /// use the newly returned `WindowId`.
618 ///
619 /// [`VSync`]: https://en.wikipedia.org/wiki/Screen_tearing#Vertical_synchronization
620 ///
621 /// # Errors
622 ///
623 /// If the current render target is closed or dropped or the renderer fails to toggle
624 /// vsync, then an error is returned.
625 ///
626 /// # Example
627 ///
628 /// ```
629 /// # use pix_engine::prelude::*;
630 /// # struct App;
631 /// # impl PixEngine for App {
632 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
633 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
634 /// if let Key::Return = event.key {
635 /// s.toggle_vsync()?;
636 /// return Ok(true);
637 /// }
638 /// Ok(false)
639 /// }
640 /// # }
641 /// ```
642 #[inline]
643 pub fn toggle_vsync(&mut self) -> PixResult<WindowId> {
644 let vsync_enabled = self.renderer.vsync();
645 self.renderer.set_vsync(vsync_enabled)
646 }
647
648 /// Set the mouse cursor to a predefined symbol or image. `None` hides the cursor.
649 ///
650 /// # Errors
651 ///
652 /// If the renderer fails to set the cursor or load it from an image file, then an error is
653 /// returned.
654 ///
655 /// # Example
656 ///
657 /// ```
658 /// # use pix_engine::prelude::*;
659 /// # struct App;
660 /// # impl PixEngine for App {
661 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
662 /// s.text("Hover me")?;
663 /// if s.hovered() {
664 /// s.cursor(Cursor::hand())?;
665 /// } else {
666 /// s.cursor(Cursor::arrow())?;
667 /// }
668 /// Ok(())
669 /// }
670 /// # }
671 /// ```
672 #[inline]
673 pub fn cursor<C>(&mut self, cursor: C) -> PixResult<()>
674 where
675 C: Into<Option<Cursor>>,
676 {
677 self.settings.cursor = cursor.into();
678 self.renderer.cursor(self.settings.cursor.as_ref())
679 }
680
681 /// Disables any UI elements drawn after this is called, preventing them from being interacted
682 /// with.
683 ///
684 /// # Example
685 ///
686 /// ```
687 /// # use pix_engine::prelude::*;
688 /// # struct App { checkbox: bool };
689 /// # impl PixEngine for App {
690 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
691 /// if s.button("Disable UI")? {
692 /// s.disable(true);
693 /// }
694 /// s.checkbox("Disabled checkbox", &mut self.checkbox)?;
695 /// Ok(())
696 /// }
697 /// # }
698 /// ```
699 pub fn disable(&mut self, disabled: bool) {
700 self.settings.disabled = disabled;
701 self.ui.disabled = disabled;
702 }
703
704 /// Whether the render loop is running or not.
705 ///
706 /// # Example
707 ///
708 /// ```
709 /// # use pix_engine::prelude::*;
710 /// # struct App;
711 /// # impl PixEngine for App {
712 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
713 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
714 /// if let Key::Return = event.key {
715 /// // Toggle pausing rendering
716 /// let running = s.running();
717 /// s.run(!running);
718 /// return Ok(true);
719 /// }
720 /// Ok(false)
721 /// }
722 /// # }
723 /// ```
724 #[inline]
725 #[must_use]
726 pub fn running(&mut self) -> bool {
727 self.settings.running
728 }
729
730 /// Pause or resume the render loop called by [`PixEngine::on_update`].
731 ///
732 /// # Example
733 ///
734 /// ```
735 /// # use pix_engine::prelude::*;
736 /// # struct App;
737 /// # impl PixEngine for App {
738 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
739 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
740 /// if let Key::Return = event.key {
741 /// // Toggle rendering
742 /// let running = s.running();
743 /// s.run(running);
744 /// return Ok(true);
745 /// }
746 /// Ok(false)
747 /// }
748 /// # }
749 /// ```
750 #[inline]
751 pub fn run(&mut self, val: bool) {
752 self.settings.running = val;
753 }
754
755 /// Set whether to show the current frame rate per second in the title or not.
756 ///
757 /// # Example
758 ///
759 /// ```
760 /// # use pix_engine::prelude::*;
761 /// # struct App;
762 /// # impl PixEngine for App {
763 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
764 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
765 /// if let Key::Return = event.key {
766 /// s.show_frame_rate(true);
767 /// return Ok(true);
768 /// }
769 /// Ok(false)
770 /// }
771 /// # }
772 /// ```
773 #[inline]
774 pub fn show_frame_rate(&mut self, show: bool) {
775 self.settings.show_frame_rate = show;
776 }
777
778 /// Get the target frame rate to render at.
779 ///
780 /// # Example
781 ///
782 /// ```
783 /// # use pix_engine::prelude::*;
784 /// # struct App;
785 /// # impl PixEngine for App {
786 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
787 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
788 /// if let Key::Down = event.key {
789 /// let target = s.target_frame_rate().unwrap_or(60);
790 /// s.frame_rate(target - 10);
791 /// return Ok(true);
792 /// }
793 /// Ok(false)
794 /// }
795 /// # }
796 /// ```
797 #[inline]
798 #[must_use]
799 pub fn target_frame_rate(&mut self) -> Option<usize> {
800 self.settings.target_frame_rate
801 }
802
803 /// Set a target frame rate to render at, controls how often [`PixEngine::on_update`] is
804 /// called. `None` clears the target frame rate.
805 ///
806 /// # Example
807 ///
808 /// ```
809 /// # use pix_engine::prelude::*;
810 /// # struct App;
811 /// # impl PixEngine for App {
812 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
813 /// fn on_start(&mut self, s: &mut PixState) -> PixResult<()> {
814 /// // Target a lower FPS than natively possible
815 /// s.frame_rate(30);
816 /// Ok(())
817 /// }
818 /// # }
819 /// ```
820 #[inline]
821 pub fn frame_rate<R>(&mut self, frame_rate: R)
822 where
823 R: Into<Option<usize>>,
824 {
825 let frame_rate = frame_rate.into();
826 self.settings.target_frame_rate = frame_rate;
827 self.settings.target_delta_time =
828 frame_rate.map(|frame_rate| Duration::from_secs(1) / frame_rate as u32);
829 }
830
831 /// Set the rendering scale of the current canvas. Drawing coordinates are scaled by x/y
832 /// factors before being drawn to the canvas.
833 ///
834 /// # Errors
835 ///
836 /// If the current render target is closed or dropped, or `(x, y`) contain invalid values,
837 /// then an error is returned.
838 ///
839 /// # Example
840 ///
841 /// ```
842 /// # use pix_engine::prelude::*;
843 /// # struct App;
844 /// # impl PixEngine for App {
845 /// # fn on_update(&mut self, s: &mut PixState) -> PixResult<()> { Ok(()) }
846 /// fn on_key_pressed(&mut self, s: &mut PixState, event: KeyEvent) -> PixResult<bool> {
847 /// if let Key::Plus = event.key {
848 /// s.scale(2.0, 2.0)?;
849 /// return Ok(true);
850 /// }
851 /// Ok(false)
852 /// }
853 /// # }
854 /// ```
855 #[inline]
856 pub fn scale(&mut self, x: f32, y: f32) -> PixResult<()> {
857 let s = &mut self.settings;
858 s.scale_x = x;
859 s.scale_y = y;
860 self.renderer.scale(s.scale_x, s.scale_y)
861 }
862
863 /// Change the way parameters are interpreted for drawing [Square](Rect)s and
864 /// [Rectangle](Rect)s.
865 ///
866 /// # Example
867 ///
868 /// ```
869 /// # use pix_engine::prelude::*;
870 /// # struct App;
871 /// # impl PixEngine for App {
872 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
873 /// s.rect_mode(RectMode::Center);
874 /// // Draw rect with center at `(100, 100)`
875 /// s.rect([100, 100, 50, 50])?;
876 /// Ok(())
877 /// }
878 /// # }
879 /// ```
880 #[inline]
881 pub fn rect_mode(&mut self, mode: RectMode) {
882 self.settings.rect_mode = mode;
883 }
884
885 /// Change the way parameters are interpreted for drawing [Ellipse]s.
886 ///
887 /// # Example
888 ///
889 /// ```
890 /// # use pix_engine::prelude::*;
891 /// # struct App;
892 /// # impl PixEngine for App {
893 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
894 /// s.ellipse_mode(EllipseMode::Center);
895 /// // Draw ellipse with center at `(100, 100)`
896 /// s.ellipse([100, 100, 50, 50])?;
897 /// Ok(())
898 /// }
899 /// # }
900 /// ```
901 #[inline]
902 pub fn ellipse_mode(&mut self, mode: EllipseMode) {
903 self.settings.ellipse_mode = mode;
904 }
905
906 /// Change the way parameters are interpreted for drawing [Image]s.
907 ///
908 /// # Example
909 ///
910 /// ```
911 /// # use pix_engine::prelude::*;
912 /// # struct App;
913 /// # impl PixEngine for App {
914 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
915 /// s.image_mode(ImageMode::Center);
916 /// // Draw image with center at `(100, 100)`
917 /// s.image(&Image::from_file("./some_image.png")?, [100, 100])?;
918 /// Ok(())
919 /// }
920 /// # }
921 /// ```
922 #[inline]
923 pub fn image_mode(&mut self, mode: ImageMode) {
924 self.settings.image_mode = mode;
925 }
926
927 /// Add a color tint to [Image]s when drawing.
928 ///
929 /// # Example
930 ///
931 /// ```
932 /// # use pix_engine::prelude::*;
933 /// # struct App;
934 /// # impl PixEngine for App {
935 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
936 /// s.image_tint(Color::RED);
937 /// // Draw image tinted red
938 /// s.image(&Image::from_file("./some_image.png")?, [0, 0])?;
939 /// Ok(())
940 /// }
941 /// # }
942 /// ```
943 #[inline]
944 pub fn image_tint<C>(&mut self, tint: C)
945 where
946 C: Into<Option<Color>>,
947 {
948 self.settings.image_tint = tint.into();
949 }
950
951 /// Change the way arcs are drawn.
952 ///
953 /// # Example
954 ///
955 /// ```
956 /// # use pix_engine::prelude::*;
957 /// # struct App;
958 /// # impl PixEngine for App {
959 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
960 /// // Draw arc as a open, unfilled pie segment using only the `stroke` (The default)
961 /// s.arc_mode(ArcMode::Default);
962 /// s.arc([100, 100], 20, 0, 180)?;
963 /// s.arc_mode(ArcMode::Pie);
964 /// // Draw arc as a closed pie segment using both `fill` and `stroke`
965 /// s.arc([200, 200], 20, 0, 180)?;
966 /// Ok(())
967 /// }
968 /// # }
969 /// ```
970 #[inline]
971 pub fn arc_mode(&mut self, mode: ArcMode) {
972 self.settings.arc_mode = mode;
973 }
974
975 /// Change the way angles are interpreted for rotation and matrix transformations.
976 ///
977 /// # Example
978 ///
979 /// ```
980 /// # use pix_engine::prelude::*;
981 /// # struct App;
982 /// # impl PixEngine for App {
983 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
984 /// s.angle_mode(AngleMode::Degrees);
985 /// let angle = 10.0;
986 /// let center = point!(10, 10);
987 /// s.text_transformed("Rotated text", angle, center, None)?;
988 /// Ok(())
989 /// }
990 /// # }
991 /// ```
992 #[inline]
993 pub fn angle_mode(&mut self, mode: AngleMode) {
994 self.settings.angle_mode = mode;
995 }
996
997 /// Change the way textures are blended together.
998 ///
999 /// # Example
1000 ///
1001 /// ```
1002 /// # use pix_engine::prelude::*;
1003 /// # struct App;
1004 /// # impl PixEngine for App {
1005 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
1006 /// s.blend_mode(BlendMode::Blend);
1007 /// // Draw image with alpha blended with background
1008 /// s.image(&Image::from_file("./some_image.png")?, [0, 0])?;
1009 /// Ok(())
1010 /// }
1011 /// # }
1012 /// ```
1013 #[inline]
1014 pub fn blend_mode(&mut self, mode: BlendMode) {
1015 self.settings.blend_mode = mode;
1016 self.renderer.blend_mode(mode);
1017 }
1018
1019 /// Saves the current draw settings and transforms.
1020 ///
1021 /// # Example
1022 ///
1023 /// ```
1024 /// # use pix_engine::prelude::*;
1025 /// # struct App;
1026 /// # impl PixEngine for App {
1027 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
1028 /// s.fill(Color::BLUE);
1029 /// s.stroke(Color::WHITE);
1030 ///
1031 /// s.push(); // Save settings
1032 ///
1033 /// s.fill(Color::RED);
1034 /// s.stroke(Color::BLACK);
1035 /// s.rect([0, 0, 100, 100])?;
1036 ///
1037 /// s.pop(); // Restore settings
1038 ///
1039 /// // Rectangle is blue with a white outline
1040 /// s.rect([0, 0, 100, 100])?;
1041 /// Ok(())
1042 /// }
1043 /// # }
1044 #[inline]
1045 pub fn push(&mut self) {
1046 self.setting_stack.push(self.settings.clone());
1047 }
1048
1049 /// Restores the previous draw settings and transforms, if present. If the settings stack is
1050 /// empty, the settings will remain unchanged.
1051 ///
1052 /// # Example
1053 ///
1054 /// ```
1055 /// # use pix_engine::prelude::*;
1056 /// # struct App;
1057 /// # impl PixEngine for App {
1058 /// fn on_update(&mut self, s: &mut PixState) -> PixResult<()> {
1059 /// s.fill(Color::BLUE);
1060 /// s.stroke(Color::WHITE);
1061 ///
1062 /// s.push(); // Save settings
1063 ///
1064 /// s.fill(Color::RED);
1065 /// s.stroke(Color::BLACK);
1066 /// s.rect([0, 0, 100, 100])?;
1067 ///
1068 /// s.pop(); // Restore settings
1069 ///
1070 /// // Rectangle is blue with a white outline
1071 /// s.rect([0, 0, 100, 100])?;
1072 /// Ok(())
1073 /// }
1074 /// # }
1075 #[inline]
1076 pub fn pop(&mut self) {
1077 if let Some(settings) = self.setting_stack.pop() {
1078 self.settings = settings;
1079 self.ui.disabled = self.settings.disabled;
1080 }
1081 let s = &self.settings;
1082 // All of these settings should be valid since they were set prior to `pop()` being
1083 // called.
1084 let _ = self.renderer.clip(s.clip);
1085 // Excluding restoring cursor - as it's used for mouse hover.
1086 let _ = self.renderer.font_size(s.font_size);
1087 self.renderer.font_style(s.font_style);
1088 let _ = self.renderer.font_family(&s.font_family);
1089 self.renderer.blend_mode(s.blend_mode);
1090 }
1091}
1092
1093impl PixState {
1094 /// Set the mouse cursor to a predefined symbol or image for a single frame.
1095 ///
1096 /// Cursor will get reset to the current setting next frame.
1097 #[inline]
1098 pub(crate) fn frame_cursor(&mut self, cursor: &Cursor) -> PixResult<()> {
1099 self.renderer.cursor(Some(cursor))
1100 }
1101
1102 /// Get the target delta time between frames.
1103 #[inline]
1104 pub(crate) fn target_delta_time(&self) -> Option<Duration> {
1105 self.settings.target_delta_time
1106 }
1107
1108 /// Get whether `VSync` is enabled.
1109 #[inline]
1110 pub(crate) fn vsync_enabled(&self) -> bool {
1111 self.renderer.vsync()
1112 }
1113}