rich_sdl2_rust/video/window/
builder.rs1#![allow(clippy::unnecessary_cast)]
2
3use bitflags::bitflags;
4use std::ffi::CString;
5use std::ptr::NonNull;
6use typed_builder::TypedBuilder;
7
8use super::{Window, WindowContextKind, WindowFormat};
9use crate::{bind, Sdl, Video};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub struct WindowCoord {
14 coord: i32,
15}
16
17impl WindowCoord {
18 #[must_use]
24 pub fn coord(coord: i32) -> Self {
25 const MAX: i32 = 16384;
26 assert!((-MAX..=MAX).contains(&coord));
27 Self { coord }
28 }
29 #[must_use]
31 pub const fn undefined() -> Self {
32 Self {
33 coord: 0x1FFF0000, }
35 }
36 #[must_use]
38 pub const fn centered() -> Self {
39 Self {
40 coord: 0x2FFF0000, }
42 }
43 pub(super) fn into_arg(self) -> std::os::raw::c_int {
44 self.coord
45 }
46}
47
48#[derive(Debug, TypedBuilder)]
50pub struct WindowBuilder {
51 #[builder(default = "Untitled".into(), setter(into))]
52 title: String,
53 #[builder(default = WindowCoord::centered())]
54 x: WindowCoord,
55 #[builder(default = WindowCoord::centered())]
56 y: WindowCoord,
57 #[builder(default = 640)]
58 width: u32,
59 #[builder(default = 480)]
60 height: u32,
61 #[builder(default = WindowFormat::Normal)]
62 format: WindowFormat,
63 #[builder(default = WindowContextKind::Software)]
64 context_kind: WindowContextKind,
65 #[builder(default)]
66 hidden: bool,
67 #[builder(default)]
68 allow_high_dpi: bool,
69 #[builder(default)]
70 borderless: bool,
71 #[builder(default)]
72 resizable: bool,
73}
74
75impl WindowBuilder {
76 #[must_use]
78 pub fn new_window<'video>(self, video: &'video Video) -> Window<'video> {
79 if self.context_kind == WindowContextKind::Vulkan {
80 let ret = unsafe { bind::SDL_Vulkan_LoadLibrary(std::ptr::null()) };
81 if ret == -1 {
82 Sdl::error_then_panic("loading vulkan library from SDL_VULKAN_LIBRARY");
83 }
84 }
85
86 let flags = self.calc_flags();
87
88 use std::os::raw::c_int;
89 let cstr = CString::new(self.title).unwrap_or_default();
90 let raw = unsafe {
91 bind::SDL_CreateWindow(
92 cstr.as_ptr(),
93 self.x.into_arg(),
94 self.y.into_arg(),
95 self.width as c_int,
96 self.height as c_int,
97 flags,
98 )
99 };
100 NonNull::new(raw).map_or_else(
101 || Sdl::error_then_panic("Sdl window"),
102 move |window| Window { window, video },
103 )
104 }
105
106 fn calc_flags(&self) -> u32 {
107 let mut flags = WindowFlags::empty();
108 flags |= match self.format {
109 WindowFormat::Normal => WindowFlags::empty(),
110 WindowFormat::Maximized => WindowFlags::MAXIMIZED,
111 WindowFormat::Minimized => WindowFlags::MINIMIZED,
112 WindowFormat::FullScreen => WindowFlags::FULLSCREEN,
113 WindowFormat::FullScreenWithCurrentDesktop => WindowFlags::FULLSCREEN_DESKTOP,
114 };
115 flags |= match self.context_kind {
116 WindowContextKind::Software => WindowFlags::empty(),
117 WindowContextKind::OpenGl => WindowFlags::OPENGL,
118 WindowContextKind::Vulkan => WindowFlags::VULKAN,
119 WindowContextKind::Metal => WindowFlags::METAL,
120 };
121 if self.hidden {
122 flags |= WindowFlags::HIDDEN;
123 }
124 if self.allow_high_dpi {
125 flags |= WindowFlags::ALLOW_HIGHDPI;
126 }
127 if self.borderless {
128 flags |= WindowFlags::BORDERLESS;
129 }
130 if self.resizable {
131 flags |= WindowFlags::RESIZABLE;
132 }
133 flags.bits()
134 }
135}
136
137bitflags! {
138 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
140 pub(super) struct WindowFlags: u32 {
141 const FULLSCREEN = bind::SDL_WINDOW_FULLSCREEN as u32;
142 const FULLSCREEN_DESKTOP = bind::SDL_WINDOW_FULLSCREEN_DESKTOP as u32;
143 const OPENGL = bind::SDL_WINDOW_OPENGL as u32;
144 const VULKAN = bind::SDL_WINDOW_VULKAN as u32;
145 const METAL = bind::SDL_WINDOW_METAL as u32;
146 const SHOWN = bind::SDL_WINDOW_SHOWN as u32;
147 const HIDDEN = bind::SDL_WINDOW_HIDDEN as u32;
148 const BORDERLESS = bind::SDL_WINDOW_BORDERLESS as u32;
149 const RESIZABLE = bind::SDL_WINDOW_RESIZABLE as u32;
150 const MINIMIZED = bind::SDL_WINDOW_MINIMIZED as u32;
151 const MAXIMIZED = bind::SDL_WINDOW_MAXIMIZED as u32;
152 const INPUT_GRABBED = bind::SDL_WINDOW_INPUT_GRABBED as u32;
153 const INPUT_FOCUS = bind::SDL_WINDOW_INPUT_FOCUS as u32;
154 const MOUSE_FOCUS = bind::SDL_WINDOW_MOUSE_FOCUS as u32;
155 const FOREIGN = bind::SDL_WINDOW_FOREIGN as u32;
156 const ALLOW_HIGHDPI = bind::SDL_WINDOW_ALLOW_HIGHDPI as u32;
157 const MOUSE_CAPTURE = bind::SDL_WINDOW_MOUSE_CAPTURE as u32;
158 }
159}