Skip to main content

pixels_graphics_lib/
lib.rs

1//! Rust Graphics Lib
2//!
3//! This is a simple pixel graphics and GUI library, it provides basic shape, image and text rendering.
4//!
5//! This boilerplate code is needed to use it:
6//!
7//! ```
8//! # use std::error::Error;
9//! # use pixels_graphics_lib::prelude::*;
10//! # use buffer_graphics_lib::Graphics;
11//! # use simple_game_utils::prelude::Timing;
12//!
13//! struct Example {
14//! }
15//!
16//! impl System for Example {
17//!   fn update(&mut self, timing: &Timing, _: &Window) {
18//!
19//!   }
20//!
21//!   fn render(&mut self, graphics: &mut Graphics) {
22//!
23//!   }
24//! }
25//!
26//! fn main() -> Result<(), Box<dyn Error>> {
27//! let system = Example {};
28//!   run(240, 160, "Doc Example", Box::new(system), Options::default())?;
29//!   Ok(())
30//! }
31//!```
32
33pub mod dialogs;
34mod integration;
35#[cfg(feature = "scenes")]
36pub mod scenes;
37pub mod ui;
38pub mod utilities;
39#[cfg(feature = "window_prefs")]
40pub mod window_prefs;
41
42use crate::prelude::{winit, Coord, ALL_KEYS};
43use crate::ui::styles::UiStyle;
44#[cfg(feature = "window_prefs")]
45use crate::window_prefs::WindowPreferences;
46pub use buffer_graphics_lib;
47use buffer_graphics_lib::Graphics;
48use rustc_hash::FxHashMap;
49#[cfg(feature = "serde")]
50use serde::{Deserialize, Serialize};
51use simple_game_utils::prelude::*;
52use thiserror::Error;
53use winit::event::MouseButton;
54pub use winit::event_loop::ControlFlow;
55use winit::keyboard::KeyCode;
56use winit::window::Window;
57
58pub mod prelude {
59    pub use crate::dialogs::*;
60    pub use crate::integration::softbuffer_winit::run;
61    #[cfg(feature = "scenes")]
62    pub use crate::scenes::*;
63    pub use crate::utilities::virtual_key_codes::*;
64    #[cfg(feature = "window_prefs")]
65    pub use crate::window_prefs::*;
66    pub use crate::GraphicsError;
67    pub use crate::MouseData;
68    pub use crate::Options;
69    pub use crate::System;
70    pub use crate::WindowScaling;
71    pub use buffer_graphics_lib::prelude::*;
72    pub use rustc_hash::FxHashSet;
73    pub use simple_game_utils::prelude::*;
74    pub use winit;
75    pub use winit::event::MouseButton;
76    pub use winit::keyboard::KeyCode;
77    pub use winit::window::Window;
78}
79
80#[derive(Error, Debug)]
81pub enum GraphicsError {
82    #[error("Creating a window: {0}")]
83    WindowInit(String),
84    #[error("Saving window pref: {0}")]
85    SavingWindowPref(String),
86    #[cfg(feature = "window_prefs")]
87    #[error("Loading window pref: {0}")]
88    LoadingWindowPref(String),
89    #[error("Invalid pixel array length, expected: {0}, found: {1}")]
90    ImageInitSize(usize, usize),
91    #[error("Both images must be the same size, expected: {0}x{1}, found: {2}x{3}")]
92    ImageBlendSize(usize, usize, usize, usize),
93    #[cfg(feature = "controller")]
94    #[error("Unable to init controller: {0}")]
95    ControllerInit(String),
96    #[error("Initialing Winit: {0}")]
97    WinitInit(#[source] winit::error::EventLoopError),
98}
99
100#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
101#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
102pub enum WindowScaling {
103    /// Use system DPI
104    Native,
105    /// Use system DPI + 1
106    Double,
107    /// Use system DPI + 3
108    Quad,
109}
110
111#[allow(unused_variables)]
112pub trait System {
113    /// List of keys that your app uses
114    fn keys_used(&self) -> &[KeyCode] {
115        &ALL_KEYS
116    }
117    #[cfg(feature = "window_prefs")]
118    fn window_prefs(&mut self) -> Option<WindowPreferences> {
119        None
120    }
121    fn update(&mut self, timing: &Timing, window: &Window);
122    fn render(&mut self, graphics: &mut Graphics);
123    fn on_mouse_move(&mut self, mouse: &MouseData) {}
124    fn on_mouse_down(&mut self, mouse: &MouseData, button: MouseButton) {}
125    fn on_mouse_up(&mut self, mouse: &MouseData, button: MouseButton) {}
126    fn on_scroll(&mut self, mouse: &MouseData, x_diff: isize, y_diff: isize) {}
127    fn on_key_down(&mut self, keys: Vec<KeyCode>) {}
128    fn on_key_up(&mut self, keys: Vec<KeyCode>) {}
129    fn on_window_closed(&mut self) {}
130    fn on_visibility_changed(&mut self, visible: bool) {}
131    fn on_focus_changed(&mut self, focused: bool) {}
132    fn should_exit(&mut self) -> bool {
133        false
134    }
135}
136
137/// Options for program windows
138#[derive(Debug, PartialEq)]
139pub struct Options {
140    /// Target and max number of times [Scene::update] can be called per second
141    /// Default is 240
142    pub ups: usize,
143    /// How the window should be scaled
144    /// Default is [Double][WindowScaling::Double]
145    pub scaling: WindowScaling,
146    /// If vsync should be enabled
147    /// Default is true
148    pub vsync: bool,
149    /// If OS mouse cursor should be hidden
150    /// (you'll have to draw your own if this is true, this is often called software cursor in games)
151    /// Default is false
152    pub hide_cursor: bool,
153    /// If the mouse cursor should be locked to within this window while it's in the foreground
154    /// Default is false
155    pub confine_cursor: bool,
156    /// Style data for [UiElement]
157    pub style: UiStyle,
158    /// Control how the program loops, see [Winit ControlFlow](https://docs.rs/winit/latest/winit/event_loop/enum.ControlFlow.html)
159    pub control_flow: ControlFlow,
160}
161
162impl Options {
163    pub fn new(
164        ups: usize,
165        scaling: WindowScaling,
166        vsync: bool,
167        hide_cursor: bool,
168        confine_cursor: bool,
169        style: UiStyle,
170        control_flow: ControlFlow,
171    ) -> Self {
172        Self {
173            ups,
174            scaling,
175            vsync,
176            hide_cursor,
177            confine_cursor,
178            style,
179            control_flow,
180        }
181    }
182}
183
184impl Default for Options {
185    fn default() -> Self {
186        Self {
187            ups: 240,
188            scaling: WindowScaling::Double,
189            vsync: true,
190            hide_cursor: false,
191            confine_cursor: false,
192            style: UiStyle::default(),
193            control_flow: ControlFlow::Poll,
194        }
195    }
196}
197
198#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
199#[derive(Debug, Clone, Eq, PartialEq, Default)]
200pub struct MouseData {
201    pub xy: Coord,
202    buttons: FxHashMap<MouseButton, Coord>,
203}
204
205impl MouseData {
206    pub fn any_held(&self) -> bool {
207        !self.buttons.is_empty()
208    }
209
210    /// Returns the press location if the mouse button is currently held down
211    pub fn is_down(&self, button: MouseButton) -> Option<Coord> {
212        self.buttons.get(&button).cloned()
213    }
214
215    pub(crate) fn add_up(&mut self, button: MouseButton) {
216        self.buttons.remove(&button);
217    }
218
219    pub(crate) fn add_down(&mut self, xy: Coord, button: MouseButton) {
220        self.buttons.insert(button, xy);
221    }
222}