magma_windowing 0.1.0-alpha.3

Part of the Magma-API, which is the API of the Magma3D game engine. This is responsable for handling windows.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
use std::num::NonZero;

use magma_app::entities::Entity;
use magma_math::{IVec2, UVec2};

/// The Window Component
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
pub struct Window {
    title: String,
    name: Option<String>,
    position: WindowPosition,
    resolution: WindowResolution,
    resizable: bool,
    resize_limit: WindowResizeLimit,
    mode: WindowMode,
    cursor_mode: CursorMode,
    cursor_visible: bool,
    decorations: bool,
    titlebar_buttons: TitlebarButtons,
    present_mode: PresentMode, // wgpu
    alpha_mode: AlphaMode,     // wgpu
    transparent: bool,
    focused: bool,
    default_event_handling: bool, // internal
    window_theme: WindowTheme,
    desired_maximum_frame_latency: Option<NonZero<u32>>, // wgpu::SurfaceConfiguration::desired_maximum_frame_latency

    /// True if the backend has created a window for this component.
    pub has_window: bool,
    /// True if this component was modified in the current update. This does not include changes that the backend makesto sync windows.
    pub changed_attr: bool,
}

impl Default for Window {
    fn default() -> Self {
        Self {
            title: "Magma Window".to_owned(),
            name: None,
            position: Default::default(),
            resolution: Default::default(),
            resizable: true,
            resize_limit: Default::default(),
            mode: Default::default(),
            cursor_mode: Default::default(),
            cursor_visible: true,
            decorations: true,
            titlebar_buttons: Default::default(),
            present_mode: Default::default(),
            alpha_mode: Default::default(),
            transparent: false,
            focused: true,
            default_event_handling: true,
            window_theme: Default::default(),
            desired_maximum_frame_latency: NonZero::new(2_u32),
            has_window: false,
            changed_attr: false,
        }
    }
}

impl Window {
    pub fn new() -> Self {
        Self::default()
    }

    /// Create the window with a custom title.
    pub fn with_title(mut self, title: &str) -> Self {
        self.title = title.to_owned();
        self
    }

    /// Get the window's display title.
    pub fn title(&self) -> String {
        self.title.to_owned()
    }

    /// Set the window's display title.
    pub fn set_title(&mut self, title: &str) {
        self.title = title.to_owned();
        self.changed_attr = true;
    }

    /// Create the window with a custom (optional) name.
    pub fn with_name(mut self, name: &str) -> Self {
        self.name = Some(name.to_owned());
        self
    }

    /// Get the window's name.
    pub fn name(&self) -> Option<String> {
        self.name.to_owned()
    }

    /// Set the window's optional name. This can only be set after first creating the window.
    pub fn set_name(&mut self, name: &str) {
        self.name = Some(name.to_owned());
        self.changed_attr = true;
    }

    /// Create the window with specified [`WindowPosition`].
    pub fn with_position(mut self, position: WindowPosition) -> Self {
        self.position = position;
        self
    }

    /// Get the current [`WindowPosition`].
    pub fn position(&self) -> WindowPosition {
        self.position
    }

    /// Set the [`WindowPosition`].
    pub fn set_position(&mut self, position: WindowPosition) {
        self.position = position;
        self.changed_attr = true;
    }

    /// Create the window with specified [`WindowResolution`].
    pub fn with_resolution(mut self, resolution: WindowResolution) -> Self {
        self.resolution = resolution;
        self
    }

    /// Get the current [`WindowResolution`].
    pub fn resolution(&self) -> WindowResolution {
        self.resolution
    }

    /// Set the [`WindowResolution`].
    pub fn set_resolution(&mut self, resolution: WindowResolution) {
        self.resolution = resolution;
        self.changed_attr = true;
    }

    /// Set if the window should be resizable on creation.
    pub fn with_resizable(mut self, resizable: bool) -> Self {
        self.resizable = resizable;
        self
    }

    /// Is the window resizable?
    pub fn resizable(&self) -> bool {
        self.resizable
    }

    /// Set if the window should be resizable.
    pub fn set_resizable(&mut self, resizable: bool) {
        self.resizable = resizable;
        self.changed_attr = true;
    }

    /// Create the window with specified [`WindowResizeLimit`].
    pub fn with_resize_limit(mut self, resize_limit: WindowResizeLimit) -> Self {
        self.resize_limit = resize_limit;
        self
    }

    /// Get the current [`WindowResizeLimit`].
    pub fn resize_limit(&self) -> WindowResizeLimit {
        self.resize_limit
    }

    /// Set the [`WindowResizeLimit`].
    pub fn set_resize_limit(&mut self, resize_limit: WindowResizeLimit) {
        self.resize_limit = resize_limit;
        self.changed_attr = true;
    }

    /// Create the window with specified [`WindowMode`].
    pub fn with_mode(mut self, mode: WindowMode) -> Self {
        self.mode = mode;
        self
    }

    /// Get the current [`WindowMode`]
    pub fn mode(&self) -> WindowMode {
        self.mode
    }

    /// Set the [`WindowMode`].
    pub fn set_mode(&mut self, mode: WindowMode) {
        self.mode = mode;
        self.changed_attr = true;
    }

    /// Create the window with specified [`CursorMode`].
    pub fn with_cursor_mode(mut self, cursor_mode: CursorMode) -> Self {
        self.cursor_mode = cursor_mode;
        self
    }

    /// Get the current [`CursorMode`].
    pub fn cursor_mode(&self) -> CursorMode {
        self.cursor_mode
    }

    /// Set the [`CursorMode`].
    pub fn set_cursor_mode(&mut self, cursor_mode: CursorMode) {
        self.cursor_mode = cursor_mode;
        self.changed_attr = true;
    }

    /// Set if the cursor should be visible at window creation.
    pub fn with_cursor_visible(mut self, cursor_visible: bool) -> Self {
        self.cursor_visible = cursor_visible;
        self
    }

    /// Is the cursor visible?
    pub fn cursor_visible(&self) -> bool {
        self.cursor_visible
    }

    /// Set if the cursor should be visible.
    pub fn set_cursor_visible(&mut self, cursor_visible: bool) {
        self.cursor_visible = cursor_visible;
        self.changed_attr = true;
    }

    /// Set if window decorations should be enabled at window creation.
    pub fn with_decorations(mut self, decorations: bool) -> Self {
        self.decorations = decorations;
        self
    }

    /// Are window decorations enabled?
    pub fn decorations(&self) -> bool {
        self.decorations
    }

    /// Set if window decorations should be enabled.
    pub fn set_decorations(&mut self, decorations: bool) {
        self.decorations = decorations;
        self.changed_attr = true;
    }

    /// Set which [`TitlebarButtons`] should be enabled at window creation.
    pub fn with_titlebar_buttons(mut self, titlebar_buttons: TitlebarButtons) -> Self {
        self.titlebar_buttons = titlebar_buttons;
        self
    }

    /// Get enabled [`TitlebarButtons`].
    pub fn titlebar_buttons(&self) -> TitlebarButtons {
        self.titlebar_buttons
    }

    /// Set which [`TitlebarButtons`] should be enabled.
    pub fn set_titlebar_buttons(&mut self, titlebar_buttons: TitlebarButtons) {
        self.titlebar_buttons = titlebar_buttons;
        self.changed_attr = true;
    }

    /// Create the window with specified [`PresentMode`].
    pub fn with_present_mode(mut self, present_mode: PresentMode) -> Self {
        self.present_mode = present_mode;
        self
    }

    /// Get the current [`PresentMode`].
    pub fn present_mode(&self) -> PresentMode {
        self.present_mode
    }

    /// Set the [`PresentMode`].
    pub fn set_present_mode(&mut self, present_mode: PresentMode) {
        self.present_mode = present_mode;
        self.changed_attr = true;
    }

    /// Create the Window with specified [`AlphaMode`].
    pub fn with_alpha_mode(mut self, alpha_mode: AlphaMode) -> Self {
        self.alpha_mode = alpha_mode;
        self
    }

    /// Get the current [`AlphaMode`].
    pub fn alpha_mode(&self) -> AlphaMode {
        self.alpha_mode
    }

    /// Set the [`AlphaMode`].
    pub fn set_alpha_mode(&mut self, alpha_mode: AlphaMode) {
        self.alpha_mode = alpha_mode;
        self.changed_attr = true;
    }

    /// Set if the window should be transparent at window creation.
    pub fn with_transparent(mut self, transparent: bool) -> Self {
        self.transparent = transparent;
        self
    }

    /// Is the window transparent?
    pub fn transparent(&self) -> bool {
        self.transparent
    }

    /// Set if the window should be transparent.
    pub fn set_transparent(&mut self, transparent: bool) {
        self.transparent = transparent;
        self.changed_attr = true;
    }

    /// Create the window with specified focus.
    pub fn with_focused(mut self, focused: bool) -> Self {
        self.focused = focused;
        self
    }

    /// Is the window focused?
    pub fn focused(&self) -> bool {
        self.focused
    }

    /// Set if the window should be focused.
    pub fn set_focused(&mut self, focused: bool) {
        self.focused = focused;
        self.changed_attr = true;
    }

    /// Set if default event handling should be enabled at window creation.
    pub fn with_default_event_handling(mut self, default_event_handling: bool) -> Self {
        self.default_event_handling = default_event_handling;
        self
    }

    /// Is default event handling enabled for this window?
    pub fn default_event_handling(&self) -> bool {
        self.default_event_handling
    }

    /// Set if default event handling should be enabled.
    pub fn set_default_event_handling(&mut self, default_event_handling: bool) {
        self.default_event_handling = default_event_handling;
        self.changed_attr = true;
    }

    /// Create the window with specified [`WindowTheme`].
    pub fn with_window_theme(mut self, window_theme: WindowTheme) -> Self {
        self.window_theme = window_theme;
        self
    }

    /// Get the current [`WindowTheme`].
    pub fn window_theme(&self) -> WindowTheme {
        self.window_theme
    }

    /// Set the [`WindowTheme`].
    pub fn set_window_theme(&mut self, window_theme: WindowTheme) {
        self.window_theme = window_theme;
        self.changed_attr = true;
    }

    /// Create the window disired maximum frame latency.
    pub fn with_desired_maximum_frame_latency(
        mut self,
        desired_maximum_frame_latency: Option<NonZero<u32>>,
    ) -> Self {
        self.desired_maximum_frame_latency = desired_maximum_frame_latency;
        self
    }

    /// Get the desired maximum frame latency (see [`wgpu::SurfaceConfiguration::desired_maximum_frame_latency`](https://docs.rs/wgpu/latest/wgpu/type.SurfaceConfiguration.html#structfield.desired_maximum_frame_latency)).
    pub fn desired_maximum_frame_latency(&self) -> Option<NonZero<u32>> {
        self.desired_maximum_frame_latency
    }

    /// Set the disired maximum frame latency.
    pub fn set_desired_maximum_frame_latency(
        &mut self,
        desired_maximum_frame_latency: Option<NonZero<u32>>,
    ) {
        self.desired_maximum_frame_latency = desired_maximum_frame_latency;
        self.changed_attr = true;
    }
}

/// Marks a window that has been requested to close
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub struct ClosingWindow;

/// Position of a window
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
pub enum WindowPosition {
    /// Automatically set an initial position for the [`Window`]. This will be converted into [`WindowPosition::Pos`] once the window has been created.
    #[default]
    Auto,
    /// Center the [`Window`] on the screen. This will be converted to [`WindowPosition::Pos`] once the window has been created.
    Center,
    /// Physical position of a window starting from the top left corner of the screen.
    Pos(IVec2),
}

/// Window resolution in physical pixels.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct WindowResolution {
    width: u32,
    height: u32,
}

impl Default for WindowResolution {
    fn default() -> Self {
        Self {
            width: 1280,
            height: 720,
        }
    }
}

impl WindowResolution {
    /// Returns a [`WindowResolution`] with specified physical width and height.
    pub const fn new(width: u32, height: u32) -> Self {
        Self { width, height }
    }

    /// Get the [`WindowResolution`]'s physical width.
    pub const fn width(&self) -> u32 {
        self.width
    }

    /// Get the [`WindowResolution`]'s physical height.
    pub const fn height(&self) -> u32 {
        self.height
    }

    /// Get the [`WindowResolution`]'s physical size as a [`UVec2`].
    pub const fn size(&self) -> UVec2 {
        UVec2::new(self.width, self.height)
    }
}

/// Resize limit of a window.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct WindowResizeLimit {
    min_width: u32,
    min_height: u32,
    max_width: u32,
    max_height: u32,
}

impl Default for WindowResizeLimit {
    fn default() -> Self {
        Self {
            min_width: 144,
            min_height: 256,
            max_width: u32::MAX,
            max_height: u32::MAX,
        }
    }
}

impl WindowResizeLimit {
    /// Returns a [`WindowResizeLimit`] with specified constraints.
    pub const fn new(min_width: u32, min_height: u32, max_width: u32, max_height: u32) -> Self {
        Self {
            min_width,
            min_height,
            max_width,
            max_height,
        }
    }

    /// Get the minimum width.
    pub const fn min_width(&self) -> u32 {
        self.min_width
    }

    /// Get the minimum height.
    pub const fn min_height(&self) -> u32 {
        self.min_height
    }

    /// Get the maximum width.
    pub const fn max_width(&self) -> u32 {
        self.max_width
    }

    /// Get the maximum height.
    pub const fn max_height(&self) -> u32 {
        self.max_height
    }

    /// Get the minimum size as a [`UVec2`].
    pub const fn min_size(&self) -> UVec2 {
        UVec2::new(self.min_width, self.min_height)
    }

    /// Get the maximum size as a [`UVec2`].
    pub const fn max_size(&self) -> UVec2 {
        UVec2::new(self.max_width, self.max_height)
    }
}

/// The windowing mode of the window.
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Default)]
pub enum WindowMode {
    /// The window should be the size of it's resolution.
    #[default]
    Windowed,
    /// The window along with its resolution gets upscaled to fit the screen.
    BorderlessFullscreen(MonitorSelection),
    /// True fullscreen mode. The window occupies the whole screen, its resolution is not modified.
    Fullscreen(MonitorSelection, VideoModeSelection),
}

/// The theme variant to use
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub enum WindowTheme {
    /// The window will use the system's global theme variant.
    #[default]
    Auto,
    /// Use the light theme variant.
    Light,
    /// Use the dark theme variant.
    Dark,
}

/// The monitor to use for a window.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub enum MonitorSelection {
    /// Use the currently focused monitor.
    #[default]
    Current,
    /// Use the system's primary monitor.
    Primary,
    /// Specify monitor by it's entity.
    Entity(Entity),
}

/// Specifies the window's video mode.
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default)]
pub enum VideoModeSelection {
    /// Use the current monitor's viodeo mode
    #[default]
    Current,
    /// Specify a video mode to use.
    Specific {
        size: UVec2,
        bit_depth: u16,
        refresh_rate_millihertz: u32,
    },
}

/// The window's curosr mode.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub enum CursorMode {
    /// The cursor can freely move in and outside the window.
    #[default]
    Free,
    /**
    The cursor will be confined to the window.

    # Support

    MacOS doesn't support this mode, therfore on MacOS this will be converted to locked cursor mode.
    */
    Confined,
    /**
    The cursor will be locked in one place.

    # Support

    Windows doesn't support the mode, therefore on Windows this will be converted to confined cursor mode.
    */
    Locked,
}

/// The window's present mode
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub enum PresentMode {
    /// Chooses [`RelaxedFifo`](Self::RelaxedFifo) -> [`Fifo`](Self::Fifo) however available.
    Vsync,
    /// Chooses [`Immediate`](Self::Immediate) -> [`Mailbox`](Self::Mailbox) however available.
    NoVsync,
    /**
    Presentation frames are kept in a First-In-First-Out queue approximately 3 frames
    long. Every vertical blanking period, the presentation engine will pop a frame
    off the queue to display. If there is no frame to display, it will present the same
    frame again until the next vblank.

    - When a present command is executed on the gpu, the presented image is added on the queue.
    - no tearing
    - traditionally "VSync"
    */
    #[default]
    Fifo,
    /**
    Presentation frames are kept in a First-In-First-Out queue approximately 3 frames
    long. Every vertical blanking period, the presentation engine will pop a frame
    off the queue to display. If there is no frame to display, it will present the
    same frame until there is a frame in the queue. The moment there is a frame in the
    queue, it will immediately pop the frame off the queue.

    - When a present command is executed on the gpu, the presented image is added on the queue.
    - Tearing, if frames last more than one vblank as the front buffer.
    - supported on AMD + Vulkan
    - traditionally "Adaptive Vsync"
    */
    RelaxedFifo,
    /**
    Presentation frames are kept in a single-frame queue. Every vertical blanking period,
    the presentation engine will pop a frame from the queue. If there is no frame to display,
    it will present the same frame again until the next vblank.

    When a present command is executed on the gpu, the frame will be put into the queue.
    If there was already a frame in the queue, the new frame will _replace_ the old frame
    on the queue.

    - no tearing
    - supported on DX11/12 + Windows 10, NVidia + Vulkan and Wayland + Vulkan.
    - traditionally "Fast Vsync"
    */
    Mailbox,
    /**
    Presentation frames are not queued at all. The moment a present command
    is executed on the GPU, the presented image is swapped onto the front buffer
    immediately.

    - tearing
    - supported on most platforms except older DX12 + Wayland.
    - traditionally "Vsync Off".
    */
    Immediate,
}

/// The window's alpha mode
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Default)]
pub enum AlphaMode {
    /// Automatically determine alpha mode.
    #[default]
    Auto,
    /// The window will always be opaque.
    Opaque,
    /// The alpha channel of textures is respected when compositing.
    /// The non-alpha channels should already be multiplied by the alpha channel.
    PreMultiplied,
    /// The alpha channel of textures is respected when compositing.
    /// The non-alpha channels should _not_ already be multiplied by the alpha channel.
    PostMultiplied,
    /// The alpha channel of textures is unknown for compositing.
    Inherit,
}

/// Used for specifying which titlebar buttons should be enabled on a window.
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
pub struct TitlebarButtons {
    minimize: bool,
    maximize: bool,
    close: bool,
}

impl Default for TitlebarButtons {
    fn default() -> Self {
        Self {
            minimize: true,
            maximize: true,
            close: true,
        }
    }
}

impl TitlebarButtons {
    /// Get [`TitlebarButtons`] with specified buttons activated.
    pub const fn new(minimize: bool, maximize: bool, close: bool) -> Self {
        Self {
            minimize,
            maximize,
            close,
        }
    }

    /// Get [`TitlebarButtons`] with all buttons enabled.
    pub const fn all_enabled() -> Self {
        Self {
            minimize: true,
            maximize: true,
            close: true,
        }
    }

    /// Is teh minimize button enabled?
    pub const fn minimize(&self) -> bool {
        self.minimize
    }

    /// Is the maximize button enabled?
    pub const fn maximize(&self) -> bool {
        self.maximize
    }

    /// Is the close button enabled?
    pub const fn close(&self) -> bool {
        self.close
    }
}