1 #![allow(dead_code)]
2 use std::io;
3
4 use std::fmt;
5
6 #[cfg(not(feature = "glfw"))]
7 #[path = "dummy.rs"]
8 pub mod backend;
9
10 #[cfg(feature = "glfw")]
11 #[path = "glfw.rs"]
12 pub mod backend;
13
14 /// Initialize the platform.
init( title: &str, w: u32, h: u32, hints: &[WindowHint], context: GraphicsContext, ) -> io::Result<(backend::Window, backend::Events)>15 pub fn init(
16 title: &str,
17 w: u32,
18 h: u32,
19 hints: &[WindowHint],
20 context: GraphicsContext,
21 ) -> io::Result<(backend::Window, backend::Events)> {
22 backend::init(title, w, h, hints, context)
23 }
24
25 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
26 pub enum GraphicsContext {
27 None,
28 Gl,
29 }
30
31 #[derive(Debug, Copy, Clone)]
32 pub enum WindowHint {
33 Resizable(bool),
34 Visible(bool),
35 }
36
37 /// Describes an event from a `Window`.
38 #[derive(Clone, Debug, PartialEq)]
39 pub enum WindowEvent {
40 /// The size of the window has changed. Contains the client area's new dimensions.
41 Resized(LogicalSize),
42
43 /// The position of the window has changed. Contains the window's new position.
44 Moved(LogicalPosition),
45
46 /// The window was minimized.
47 Minimized,
48
49 /// The window was restored after having been minimized.
50 Restored,
51
52 /// The window has been requested to close.
53 CloseRequested,
54
55 /// The window has been destroyed.
56 Destroyed,
57
58 /// The window received a unicode character.
59 ReceivedCharacter(char),
60
61 /// The window gained or lost focus.
62 Focused(bool),
63
64 /// An event from the keyboard has been received.
65 KeyboardInput(KeyboardInput),
66
67 /// The cursor has moved on the window.
68 CursorMoved {
69 /// Coords in pixels relative to the top-left corner of the window.
70 position: LogicalPosition,
71 },
72
73 /// The cursor has entered the window.
74 CursorEntered,
75
76 /// The cursor has left the window.
77 CursorLeft,
78
79 /// A mouse button press has been received.
80 MouseInput {
81 state: InputState,
82 button: MouseButton,
83 modifiers: ModifiersState,
84 },
85
86 /// The mouse wheel has been used.
87 MouseWheel { delta: LogicalDelta },
88
89 /// The OS or application has requested that the window be redrawn.
90 RedrawRequested,
91
92 /// There are no more inputs to process, the application can do work.
93 Ready,
94
95 /// The content scale factor of the window has changed. For example,
96 /// the window was moved to a higher DPI screen.
97 ScaleFactorChanged(f64),
98
99 /// No-op event, for events we don't handle.
100 Noop,
101 }
102
103 impl WindowEvent {
104 /// Events that are triggered by user input.
is_input(&self) -> bool105 pub fn is_input(&self) -> bool {
106 match self {
107 Self::Resized(_)
108 | Self::Moved(_)
109 | Self::Minimized
110 | Self::Restored
111 | Self::CloseRequested
112 | Self::Destroyed
113 | Self::ReceivedCharacter(_)
114 | Self::Focused(_)
115 | Self::KeyboardInput(_)
116 | Self::CursorMoved { .. }
117 | Self::CursorEntered
118 | Self::CursorLeft
119 | Self::MouseInput { .. }
120 | Self::ScaleFactorChanged(_) => true,
121 _ => false,
122 }
123 }
124 }
125
126 /// Describes a keyboard input event.
127 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
128 pub struct KeyboardInput {
129 pub state: InputState,
130 pub key: Option<Key>,
131 pub modifiers: ModifiersState,
132 }
133
134 /// Describes the input state of a key.
135 #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
136 pub enum InputState {
137 Pressed,
138 Released,
139 Repeated,
140 }
141
142 /// Describes a mouse button.
143 #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
144 pub enum MouseButton {
145 Left,
146 Right,
147 Middle,
148 Other(u8),
149 }
150
151 /// Symbolic name for a keyboard key.
152 #[derive(Debug, Hash, Ord, PartialOrd, PartialEq, Eq, Clone, Copy)]
153 #[repr(u32)]
154 #[rustfmt::skip]
155 pub enum Key {
156 // Number keys.
157 Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9, Num0,
158
159 // Alpha keys.
160 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
161
162 // Arrow keys.
163 Left, Up, Right, Down,
164
165 // Control characters.
166 Backspace, Return, Space, Tab,
167 Escape, Insert, Home, Delete, End, PageDown, PageUp,
168
169 // Punctuation.
170 Apostrophe, Grave, Caret, Comma, Period, Colon, Semicolon,
171 LBracket, RBracket,
172 Slash, Backslash,
173
174 // Modifiers.
175 Alt, Control, Shift,
176
177 // Math keys.
178 Equal, Minus,
179
180 // Key is unknown/unsupported.
181 Unknown,
182 }
183
184 impl From<char> for Key {
185 #[rustfmt::skip]
from(c: char) -> Self186 fn from(c: char) -> Self {
187 match c {
188 '0' => Key::Num0, '1' => Key::Num1, '2' => Key::Num2,
189 '3' => Key::Num3, '4' => Key::Num4, '5' => Key::Num5,
190 '6' => Key::Num6, '7' => Key::Num7, '8' => Key::Num8,
191 '9' => Key::Num9,
192
193 'a' => Key::A, 'b' => Key::B, 'c' => Key::C, 'd' => Key::D,
194 'e' => Key::E, 'f' => Key::F, 'g' => Key::G, 'h' => Key::H,
195 'i' => Key::I, 'j' => Key::J, 'k' => Key::K, 'l' => Key::L,
196 'm' => Key::M, 'n' => Key::N, 'o' => Key::O, 'p' => Key::P,
197 'q' => Key::Q, 'r' => Key::R, 's' => Key::S, 't' => Key::T,
198 'u' => Key::U, 'v' => Key::V, 'w' => Key::W, 'x' => Key::X,
199 'y' => Key::Y, 'z' => Key::Z,
200
201 '/' => Key::Slash, '[' => Key::LBracket, ']' => Key::RBracket,
202 '`' => Key::Grave, ',' => Key::Comma, '.' => Key::Period,
203 '=' => Key::Equal, '-' => Key::Minus, '\'' => Key::Apostrophe,
204 ';' => Key::Semicolon, ':' => Key::Colon, ' ' => Key::Space,
205 '\\' => Key::Backslash,
206 _ => Key::Unknown,
207 }
208 }
209 }
210
211 impl fmt::Display for Key {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 match self {
214 Key::A => "a".fmt(f),
215 Key::B => "b".fmt(f),
216 Key::C => "c".fmt(f),
217 Key::D => "d".fmt(f),
218 Key::E => "e".fmt(f),
219 Key::F => "f".fmt(f),
220 Key::G => "g".fmt(f),
221 Key::H => "h".fmt(f),
222 Key::I => "i".fmt(f),
223 Key::J => "j".fmt(f),
224 Key::K => "k".fmt(f),
225 Key::L => "l".fmt(f),
226 Key::M => "m".fmt(f),
227 Key::N => "n".fmt(f),
228 Key::O => "o".fmt(f),
229 Key::P => "p".fmt(f),
230 Key::Q => "q".fmt(f),
231 Key::R => "r".fmt(f),
232 Key::S => "s".fmt(f),
233 Key::T => "t".fmt(f),
234 Key::U => "u".fmt(f),
235 Key::V => "v".fmt(f),
236 Key::W => "w".fmt(f),
237 Key::X => "x".fmt(f),
238 Key::Y => "y".fmt(f),
239 Key::Z => "z".fmt(f),
240 Key::Num0 => "0".fmt(f),
241 Key::Num1 => "1".fmt(f),
242 Key::Num2 => "2".fmt(f),
243 Key::Num3 => "3".fmt(f),
244 Key::Num4 => "4".fmt(f),
245 Key::Num5 => "5".fmt(f),
246 Key::Num6 => "6".fmt(f),
247 Key::Num7 => "7".fmt(f),
248 Key::Num8 => "8".fmt(f),
249 Key::Num9 => "9".fmt(f),
250 Key::LBracket => "[".fmt(f),
251 Key::RBracket => "]".fmt(f),
252 Key::Comma => ",".fmt(f),
253 Key::Period => ".".fmt(f),
254 Key::Slash => "/".fmt(f),
255 Key::Backslash => "\\".fmt(f),
256 Key::Apostrophe => "'".fmt(f),
257 Key::Control => "<ctrl>".fmt(f),
258 Key::Shift => "<shift>".fmt(f),
259 Key::Alt => "<alt>".fmt(f),
260 Key::Up => "<up>".fmt(f),
261 Key::Down => "<down>".fmt(f),
262 Key::Left => "<left>".fmt(f),
263 Key::Right => "<right>".fmt(f),
264 Key::Return => "<return>".fmt(f),
265 Key::Backspace => "<backspace>".fmt(f),
266 Key::Space => "<space>".fmt(f),
267 Key::Tab => "<tab>".fmt(f),
268 Key::Escape => "<esc>".fmt(f),
269 Key::Insert => "<insert>".fmt(f),
270 Key::Delete => "<delete>".fmt(f),
271 Key::Home => "<home>".fmt(f),
272 Key::PageUp => "<pgup>".fmt(f),
273 Key::PageDown => "<pgdown>".fmt(f),
274 Key::Grave => "`".fmt(f),
275 Key::Caret => "^".fmt(f),
276 Key::End => "<end>".fmt(f),
277 Key::Colon => ":".fmt(f),
278 Key::Semicolon => ";".fmt(f),
279 Key::Equal => "=".fmt(f),
280 Key::Minus => "-".fmt(f),
281 _ => "???".fmt(f),
282 }
283 }
284 }
285
286 impl Key {
287 pub fn is_modifier(&self) -> bool {
288 match self {
289 Key::Alt | Key::Control | Key::Shift => true,
290 _ => false,
291 }
292 }
293 }
294
295 /// Represents the current state of the keyboard modifiers
296 #[derive(Default, Debug, Hash, PartialEq, Eq, Clone, Copy)]
297 pub struct ModifiersState {
298 /// The "shift" key
299 pub shift: bool,
300 /// The "control" key
301 pub ctrl: bool,
302 /// The "alt" key
303 pub alt: bool,
304 /// The "meta" key. This is the "windows" key on PC and "command" key on Mac.
305 pub meta: bool,
306 }
307
308 impl fmt::Display for ModifiersState {
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 let mut s = String::new();
311 if self.ctrl {
312 s.push_str("<ctrl>");
313 }
314 if self.alt {
315 s.push_str("<alt>");
316 }
317 if self.meta {
318 s.push_str("<meta>");
319 }
320 if self.shift {
321 s.push_str("<shift>");
322 }
323 s.fmt(f)
324 }
325 }
326
327 /// A delta represented in logical pixels.
328 #[derive(Debug, Copy, Clone, PartialEq)]
329 pub struct LogicalDelta {
330 pub x: f64,
331 pub y: f64,
332 }
333
334 /// A position represented in logical pixels.
335 #[derive(Debug, Copy, Clone, PartialEq)]
336 pub struct LogicalPosition {
337 pub x: f64,
338 pub y: f64,
339 }
340
341 impl LogicalPosition {
342 pub fn new(x: f64, y: f64) -> Self {
343 LogicalPosition { x, y }
344 }
345
346 pub fn from_physical<T: Into<PhysicalPosition>>(physical: T, scale_factor: f64) -> Self {
347 physical.into().to_logical(self::pixel_ratio(scale_factor))
348 }
349
350 pub fn to_physical(&self, scale_factor: f64) -> PhysicalPosition {
351 let x = self.x * self::pixel_ratio(scale_factor);
352 let y = self.y * self::pixel_ratio(scale_factor);
353 PhysicalPosition::new(x, y)
354 }
355 }
356
357 /// A position represented in physical pixels.
358 #[derive(Debug, Copy, Clone, PartialEq)]
359 pub struct PhysicalPosition {
360 pub x: f64,
361 pub y: f64,
362 }
363
364 impl PhysicalPosition {
365 pub fn new(x: f64, y: f64) -> Self {
366 PhysicalPosition { x, y }
367 }
368
369 pub fn from_logical<T: Into<LogicalPosition>>(logical: T, scale_factor: f64) -> Self {
370 logical.into().to_physical(self::pixel_ratio(scale_factor))
371 }
372
373 pub fn to_logical(&self, scale_factor: f64) -> LogicalPosition {
374 let x = self.x / self::pixel_ratio(scale_factor);
375 let y = self.y / self::pixel_ratio(scale_factor);
376 LogicalPosition::new(x, y)
377 }
378 }
379
380 /// A size represented in logical pixels.
381 #[derive(Debug, Copy, Clone, PartialEq)]
382 pub struct LogicalSize {
383 pub width: f64,
384 pub height: f64,
385 }
386
387 impl LogicalSize {
388 pub const fn new(width: f64, height: f64) -> Self {
389 LogicalSize { width, height }
390 }
391
392 pub fn from_physical<T: Into<PhysicalSize>>(physical: T, scale_factor: f64) -> Self {
393 physical.into().to_logical(self::pixel_ratio(scale_factor))
394 }
395
396 pub fn to_physical(&self, scale_factor: f64) -> PhysicalSize {
397 let width = self.width * self::pixel_ratio(scale_factor);
398 let height = self.height * self::pixel_ratio(scale_factor);
399 PhysicalSize::new(width, height)
400 }
401
402 pub fn is_zero(&self) -> bool {
403 self.width < 1. || self.height < 1.
404 }
405 }
406
407 impl From<(u32, u32)> for LogicalSize {
408 fn from((width, height): (u32, u32)) -> Self {
409 Self::new(width as f64, height as f64)
410 }
411 }
412
413 impl Into<(u32, u32)> for LogicalSize {
414 /// Note that this rounds instead of truncating.
415 fn into(self) -> (u32, u32) {
416 (self.width.round() as _, self.height.round() as _)
417 }
418 }
419
420 /// A size represented in physical pixels.
421 #[derive(Debug, Copy, Clone, PartialEq)]
422 pub struct PhysicalSize {
423 pub width: f64,
424 pub height: f64,
425 }
426
427 impl PhysicalSize {
428 pub fn new(width: f64, height: f64) -> Self {
429 PhysicalSize { width, height }
430 }
431
432 pub fn from_logical<T: Into<LogicalSize>>(logical: T, scale_factor: f64) -> Self {
433 logical.into().to_physical(self::pixel_ratio(scale_factor))
434 }
435
436 pub fn to_logical(&self, scale_factor: f64) -> LogicalSize {
437 let width = self.width / self::pixel_ratio(scale_factor);
438 let height = self.height / self::pixel_ratio(scale_factor);
439 LogicalSize::new(width, height)
440 }
441 }
442
443 impl From<(u32, u32)> for PhysicalSize {
444 fn from((width, height): (u32, u32)) -> Self {
445 Self::new(width as f64, height as f64)
446 }
447 }
448
449 impl Into<(u32, u32)> for PhysicalSize {
450 /// Note that this rounds instead of truncating.
451 fn into(self) -> (u32, u32) {
452 (self.width.round() as _, self.height.round() as _)
453 }
454 }
455
456 /// The ratio between screen coordinates and pixels, given the
457 /// content scale.
458 /// On macOS, screen coordinates don't map 1:1 with pixels. Hence,
459 /// our ratio between screen coordinates and pixels is whatever
460 /// the scaling factor is, which is always `2.0` on modern hardware.
461 #[cfg(target_os = "macos")]
462 pub fn pixel_ratio(scale_factor: f64) -> f64 {
463 scale_factor
464 }
465
466 /// The ratio between screen coordinates and pixels, given the
467 /// content scale.
468 /// On Linux and Windows, screen coordinates always map 1:1 with pixels.
469 /// No matter the DPI settings and display, we always want to map a screen
470 /// coordinate with a single pixel.
471 #[cfg(not(target_os = "macos"))]
472 pub fn pixel_ratio(_scale_factor: f64) -> f64 {
473 1.0
474 }
475