Skip to content

Commit da3d646

Browse files
authored
Merge pull request #29 from lambda-sh/ahlawat/winit-refactor
Dicussion : Refactor the `winit` crate module
2 parents f08f445 + 5adf29d commit da3d646

5 files changed

Lines changed: 246 additions & 72 deletions

File tree

crates/lambda-platform/src/winit/mod.rs

Lines changed: 119 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,13 @@ use winit::{
1919

2020
/// Embedded module for exporting data/types from winit as minimally/controlled
2121
/// as possible. The exports from this module are not guaranteed to be stable.
22+
// TODO(ahlawat) = Remove all these except WindowEvent since we're abstracting them already? Double check
2223
pub mod winit_exports {
2324
pub use winit::{
2425
event::{
26+
ElementState,
2527
Event,
28+
VirtualKeyCode,
2629
WindowEvent,
2730
},
2831
event_loop::{
@@ -34,24 +37,33 @@ pub mod winit_exports {
3437
};
3538
}
3639

40+
/// LoopBuilder - Putting this here for consistency.
41+
pub struct LoopBuilder;
42+
43+
impl LoopBuilder {
44+
pub fn new() -> Self {
45+
return Self;
46+
}
47+
48+
pub fn build<Events: 'static + std::fmt::Debug>(self) -> Loop<Events> {
49+
let event_loop = EventLoop::<Events>::with_user_event();
50+
return Loop { event_loop };
51+
}
52+
}
53+
3754
/// Loop wrapping for the winit event loop.
3855
pub struct Loop<E: 'static + std::fmt::Debug> {
3956
event_loop: EventLoop<E>,
4057
}
4158

42-
pub fn create_event_loop<Events: 'static + std::fmt::Debug>() -> Loop<Events> {
43-
let event_loop = EventLoop::<Events>::with_user_event();
44-
return Loop { event_loop };
45-
}
46-
4759
/// Structure that contains properties needed for building a window.
4860
pub struct WindowProperties {
4961
pub name: String,
5062
pub dimensions: (u32, u32),
5163
pub monitor_handle: MonitorHandle,
5264
}
5365

54-
/// Metadata for Lambda window sizing that supports Copy and move operations.
66+
/// Metadata for Lambda window sizing that supports Copy and Move operations.
5567
#[derive(Clone, Copy)]
5668
pub struct WindowSize {
5769
pub width: u32,
@@ -66,6 +78,92 @@ pub struct WindowHandle {
6678
pub monitor_handle: MonitorHandle,
6779
}
6880

81+
// Should we take the loop as a field right here? Probably a ref or something? IDK
82+
pub struct WindowHandleBuilder {
83+
window_handle: Option<Window>,
84+
size: WindowSize,
85+
monitor_handle: Option<MonitorHandle>,
86+
}
87+
88+
impl WindowHandleBuilder {
89+
/// Instantiate an empty builder
90+
pub fn new() -> Self {
91+
// Initialize the window size with some default values.
92+
let logical: LogicalSize<u32> = [0, 0].into();
93+
let physical = logical.to_physical(1.0);
94+
let size = WindowSize {
95+
width: 0,
96+
height: 0,
97+
logical,
98+
physical,
99+
};
100+
101+
return Self {
102+
window_handle: None,
103+
size,
104+
monitor_handle: None,
105+
};
106+
}
107+
108+
/// Set the window size for the WindowHandle
109+
fn with_window_size(
110+
mut self,
111+
window_size: (u32, u32),
112+
scale_factor: f64,
113+
) -> Self {
114+
let logical: LogicalSize<u32> = window_size.into();
115+
let physical: PhysicalSize<u32> = logical.to_physical(scale_factor);
116+
let (width, height) = window_size;
117+
118+
let window_size = WindowSize {
119+
width,
120+
height,
121+
logical,
122+
physical,
123+
};
124+
125+
self.size = window_size;
126+
return self;
127+
}
128+
129+
/// Probably the function that'll be used the most
130+
pub fn with_window_properties<E: 'static + std::fmt::Debug>(
131+
mut self,
132+
window_properties: WindowProperties,
133+
lambda_loop: &Loop<E>,
134+
) -> Self {
135+
let WindowProperties {
136+
name,
137+
dimensions,
138+
monitor_handle,
139+
} = window_properties;
140+
141+
// TODO(ahlawat) = Find out if there's a better way to do this. Looks kinda ugly.
142+
self = self.with_window_size(dimensions, monitor_handle.scale_factor());
143+
144+
let window_handle = WindowBuilder::new()
145+
.with_title(name)
146+
.with_inner_size(self.size.logical)
147+
.build(&lambda_loop.event_loop)
148+
.expect("Failed creation of window handle");
149+
150+
self.monitor_handle = Some(monitor_handle);
151+
self.window_handle = Some(window_handle);
152+
return self;
153+
}
154+
155+
/// Build the WindowHandle
156+
pub fn build(self) -> WindowHandle {
157+
return WindowHandle {
158+
monitor_handle: self
159+
.monitor_handle
160+
.expect("Unable to find a MonitorHandle."),
161+
size: self.size,
162+
window_handle: self.window_handle.expect("Unable to find WindowHandle."),
163+
};
164+
}
165+
}
166+
69167
/// Construct WindowSize metdata from the window dimensions and scale factor of
70168
/// the monitor being rendered to.
71169
#[inline]
@@ -85,19 +183,20 @@ fn construct_window_size(
85183
};
86184
}
87185

88-
#[derive(Clone, Debug)]
89-
pub struct EventLoopPublisher<E: 'static + std::fmt::Debug> {
186+
/// Event loop publisher wrapper for pushing events into a winit event loop.
187+
pub struct LoopPublisher<E: 'static> {
90188
winit_proxy: EventLoopProxy<E>,
91189
}
92190

93-
impl<E: 'static + std::fmt::Debug> EventLoopPublisher<E> {
94-
/// Instantiate a new EventLoopPublisher from an event loop proxy.
191+
impl<E: 'static + std::fmt::Debug> LoopPublisher<E> {
192+
/// New LoopPublishers are created from a lambda_loop directly and don't need
95193
#[inline]
96-
pub fn new(winit_proxy: EventLoopProxy<E>) -> Self {
97-
return EventLoopPublisher { winit_proxy };
194+
pub fn new(lambda_loop: &Loop<E>) -> Self {
195+
let winit_proxy = lambda_loop.event_loop.create_proxy();
196+
return LoopPublisher { winit_proxy };
98197
}
99198

100-
/// Send an event
199+
/// Publishes an event into the event loop that created this publisher.
101200
#[inline]
102201
pub fn publish_event(&self, event: E) {
103202
self
@@ -108,9 +207,9 @@ impl<E: 'static + std::fmt::Debug> EventLoopPublisher<E> {
108207
}
109208

110209
impl<E: 'static + std::fmt::Debug> Loop<E> {
111-
pub fn create_publisher(&mut self) -> EventLoopPublisher<E> {
112-
let proxy = self.event_loop.create_proxy();
113-
return EventLoopPublisher::new(proxy);
210+
/// Create an event publisher for this Loop.
211+
pub fn create_event_publisher(&mut self) -> LoopPublisher<E> {
212+
return LoopPublisher::new(&self);
114213
}
115214

116215
/// Returns the primary monitor for the current OS if detectable.
@@ -123,43 +222,17 @@ impl<E: 'static + std::fmt::Debug> Loop<E> {
123222
return self.event_loop.available_monitors();
124223
}
125224

126-
pub fn get_any_available_monitors(&self) -> MonitorHandle {
127-
// TODO(vmarcella): Remove the panic from this in favor of returning a result or an error.
128-
match self.event_loop.available_monitors().next() {
129-
Some(monitor) => monitor,
130-
None => panic!("No available monitors found."),
131-
}
225+
/// Gets the first available monitor or panics.
226+
pub fn get_any_available_monitors(&self) -> Option<MonitorHandle> {
227+
return self.event_loop.available_monitors().next();
132228
}
133229

134-
/// Uses the winit event loop to run forever.
230+
/// Uses the winit event loop to run forever
135231
pub fn run_forever<Callback>(self, callback: Callback)
136232
where
137233
Callback: 'static
138234
+ FnMut(Event<E>, &EventLoopWindowTarget<E>, &mut ControlFlow) -> (),
139235
{
140236
self.event_loop.run(callback);
141237
}
142-
143-
pub fn create_window_handle(
144-
&mut self,
145-
window_properties: WindowProperties,
146-
) -> WindowHandle {
147-
let name = window_properties.name;
148-
let dimensions = window_properties.dimensions;
149-
let monitor_handle = window_properties.monitor_handle;
150-
151-
let size = construct_window_size(dimensions, monitor_handle.scale_factor());
152-
153-
let window_handle = WindowBuilder::new()
154-
.with_title(name)
155-
.with_inner_size(size.logical)
156-
.build(&self.event_loop)
157-
.expect("Failed to create a winit handle.");
158-
159-
return WindowHandle {
160-
window_handle,
161-
size,
162-
monitor_handle,
163-
};
164-
}
165238
}

lambda/src/core/events.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,49 @@
11
use std::time::Instant;
22

33
/// events generated by kernel interactions with the component.
4-
#[derive(Debug)]
4+
#[derive(Debug, Clone)]
55
pub enum ComponentEvent {
66
Attached { name: String },
77
Detached { name: String },
8-
Update { delta: Instant },
98
}
109

1110
/// Window events are generated in response to window events coming from
1211
/// the windowing system.
13-
#[derive(Debug)]
12+
#[derive(Debug, Clone)]
1413
pub enum WindowEvent {
1514
Close,
1615
Resize { width: u32, height: u32 },
1716
}
1817

1918
/// Kernel events are generated by the kernel itself
20-
#[derive(Debug)]
19+
#[derive(Debug, Clone)]
2120
pub enum RuntimeEvent {
2221
Initialized,
2322
Shutdown,
2423
}
2524

25+
/// Exports the winit virtual key codes to this namespace for convenience.
26+
pub use lambda_platform::winit::winit_exports::VirtualKeyCode as VirtualKey;
27+
28+
#[derive(Debug, Clone)]
29+
pub enum KeyEvent {
30+
KeyPressed {
31+
scan_code: u32,
32+
virtual_key: VirtualKey,
33+
},
34+
KeyReleased {
35+
scan_code: u32,
36+
virtual_key: VirtualKey,
37+
},
38+
ModifierPressed {
39+
modifier: u32,
40+
virtual_key: VirtualKey,
41+
},
42+
}
43+
2644
/// Generic Event Enum which encapsulates all possible events that will be
2745
/// emitted by the LambdaKernel
28-
#[derive(Debug)]
46+
#[derive(Debug, Clone)]
2947
pub enum Events {
3048
Component {
3149
event: ComponentEvent,
@@ -39,4 +57,8 @@ pub enum Events {
3957
event: RuntimeEvent,
4058
issued_at: Instant,
4159
},
60+
Keyboard {
61+
event: KeyEvent,
62+
issued_at: Instant,
63+
},
4264
}

lambda/src/core/render/window.rs

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use lambda_platform::winit::{
22
Loop,
33
WindowHandle,
4+
WindowHandleBuilder,
45
WindowProperties,
56
};
67

@@ -12,21 +13,24 @@ pub struct WindowBuilder {
1213
}
1314

1415
impl WindowBuilder {
15-
/// Construct a new window window builder.
16+
/// A new window builder will be 480x360 by default and have the name
17+
/// "Window". After customizing the window with whatever properties your
18+
/// application needs, you can supply it an event loop to process the
19+
/// events that will be generated by the window.
1620
pub fn new() -> Self {
1721
return Self {
18-
name: "Window".to_string(),
22+
name: String::from("Window"),
1923
dimensions: (480, 360),
2024
};
2125
}
2226

23-
/// The name of the window (Will also appear as the title of the window/application)
27+
/// The name to be displayed in the title bar of the window.
2428
pub fn with_name(mut self, name: &str) -> Self {
2529
self.name = name.to_string();
2630
return self;
2731
}
2832

29-
/// Specify the dimensions for the window (Defaults to 480 x 360)
33+
/// Specify the dimensions for the window (Defaults to 480 x 360).
3034
pub fn with_dimensions(mut self, width: u32, height: u32) -> Self {
3135
self.dimensions = (width, height);
3236
return self;
@@ -49,23 +53,29 @@ impl Window {
4953
dimensions: (u32, u32),
5054
event_loop: &mut Loop<Events>,
5155
) -> Self {
52-
let monitor_handle = event_loop
53-
.get_primary_monitor()
54-
.unwrap_or(event_loop.get_any_available_monitors());
56+
// Attempt to get the primary monitor first and then falls back to the first
57+
// available monitor if that isn't found.
58+
let monitor_handle = event_loop.get_primary_monitor().unwrap_or(
59+
event_loop
60+
.get_any_available_monitors()
61+
.expect("No monitors available"),
62+
);
5563

5664
let window_properties = WindowProperties {
5765
name: name.to_string(),
5866
dimensions,
5967
monitor_handle,
6068
};
6169

62-
let window_handle = event_loop.create_window_handle(window_properties);
70+
let window_handle = WindowHandleBuilder::new()
71+
.with_window_properties(window_properties, event_loop)
72+
.build();
6373

6474
return Self { window_handle };
6575
}
6676

6777
/// Redraws the window.
68-
pub fn redraw(&mut self) {
78+
pub fn redraw(&self) {
6979
self.window_handle.window_handle.request_redraw();
7080
}
7181

@@ -74,7 +84,7 @@ impl Window {
7484
return &self.window_handle;
7585
}
7686

77-
/// Returns the dimensions of the current window.
87+
/// Returns the dimensions of the current window. (width, height)
7888
pub fn dimensions(&self) -> (u32, u32) {
7989
return (
8090
self.window_handle.size.width,

0 commit comments

Comments
 (0)