iced_winit/program/
state.rs
1use crate::conversion;
2use crate::core::{mouse, window};
3use crate::core::{Color, Size};
4use crate::graphics::Viewport;
5use crate::program::{self, Program};
6use std::fmt::{Debug, Formatter};
7
8use winit::dpi::LogicalPosition;
9use winit::event::{Touch, WindowEvent};
10use winit::window::Window;
11
12pub struct State<P: Program>
14where
15 P::Theme: program::DefaultStyle,
16{
17 pub(crate) title: String,
18 scale_factor: f64,
19 viewport: Viewport,
20 viewport_version: u64,
21 cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
22 modifiers: winit::keyboard::ModifiersState,
23 theme: P::Theme,
24 appearance: program::Appearance,
25}
26
27impl<P: Program> Debug for State<P>
28where
29 P::Theme: program::DefaultStyle,
30{
31 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
32 f.debug_struct("multi_window::State")
33 .field("title", &self.title)
34 .field("scale_factor", &self.scale_factor)
35 .field("viewport", &self.viewport)
36 .field("viewport_version", &self.viewport_version)
37 .field("cursor_position", &self.cursor_position)
38 .field("appearance", &self.appearance)
39 .finish()
40 }
41}
42
43impl<P: Program> State<P>
44where
45 P::Theme: program::DefaultStyle,
46{
47 pub fn new(
49 application: &P,
50 window_id: window::Id,
51 window: &dyn Window,
52 ) -> Self {
53 let title = application.title(window_id);
54 let scale_factor = application.scale_factor(window_id);
55 let theme = application.theme(window_id);
56 let appearance = application.style(&theme);
57
58 let viewport = {
59 let physical_size = window.surface_size();
60
61 Viewport::with_physical_size(
62 Size::new(physical_size.width, physical_size.height),
63 window.scale_factor() * scale_factor,
64 )
65 };
66
67 Self {
68 title,
69 scale_factor,
70 viewport,
71 viewport_version: 0,
72 cursor_position: None,
73 modifiers: winit::keyboard::ModifiersState::default(),
74 theme,
75 appearance,
76 }
77 }
78
79 pub fn viewport(&self) -> &Viewport {
81 &self.viewport
82 }
83
84 pub fn viewport_version(&self) -> u64 {
88 self.viewport_version
89 }
90
91 pub fn physical_size(&self) -> Size<u32> {
93 self.viewport.physical_size()
94 }
95
96 pub fn logical_size(&self) -> Size<f32> {
98 self.viewport.logical_size()
99 }
100
101 pub fn scale_factor(&self) -> f64 {
103 self.viewport.scale_factor()
104 }
105
106 pub fn set_logical_cursor_pos(&mut self, pos: LogicalPosition<f64>) {
107 let physical = pos.to_physical(self.scale_factor());
108 self.cursor_position = Some(physical);
109 }
110
111 pub fn cursor(&self) -> mouse::Cursor {
113 self.cursor_position
114 .map(|cursor_position| {
115 conversion::cursor_position(
116 cursor_position,
117 self.viewport.scale_factor(),
118 )
119 })
120 .map(mouse::Cursor::Available)
121 .unwrap_or(mouse::Cursor::Unavailable)
122 }
123
124 pub fn modifiers(&self) -> winit::keyboard::ModifiersState {
126 self.modifiers
127 }
128
129 pub fn theme(&self) -> &P::Theme {
131 &self.theme
132 }
133
134 pub fn background_color(&self) -> Color {
136 self.appearance.background_color
137 }
138
139 pub fn text_color(&self) -> Color {
141 self.appearance.text_color
142 }
143
144 pub fn icon_color(&self) -> Color {
146 self.appearance.icon_color
147 }
148
149 pub(crate) fn update_scale_factor(&mut self, new_scale_factor: f64) {
151 let size = self.viewport.physical_size();
152
153 self.viewport = Viewport::with_physical_size(
154 size,
155 new_scale_factor * self.scale_factor,
156 );
157
158 self.viewport_version = self.viewport_version.wrapping_add(1);
159 }
160
161 pub fn update(
163 &mut self,
164 window: &dyn Window,
165 event: &WindowEvent,
166 _debug: &mut crate::runtime::Debug,
167 ) {
168 match event {
169 WindowEvent::SurfaceResized(new_size) => {
170 let size = Size::new(new_size.width, new_size.height);
171
172 self.viewport = Viewport::with_physical_size(
173 size,
174 window.scale_factor() * self.scale_factor,
175 );
176
177 self.viewport_version = self.viewport_version.wrapping_add(1);
178 }
179 WindowEvent::ScaleFactorChanged {
180 scale_factor: new_scale_factor,
181 ..
182 } => {
183 self.update_scale_factor(*new_scale_factor);
184 }
185 WindowEvent::CursorMoved { position, .. }
186 | WindowEvent::Touch(Touch {
187 location: position, ..
188 }) => {
189 self.cursor_position = Some(*position);
190 }
191 WindowEvent::CursorLeft { .. } => {
192 self.cursor_position = None;
193 }
194 WindowEvent::ModifiersChanged(new_modifiers) => {
195 self.modifiers = new_modifiers.state();
196 }
197 #[cfg(feature = "debug")]
198 WindowEvent::KeyboardInput {
199 event:
200 winit::event::KeyEvent {
201 logical_key:
202 winit::keyboard::Key::Named(
203 winit::keyboard::NamedKey::F12,
204 ),
205 state: winit::event::ElementState::Pressed,
206 ..
207 },
208 ..
209 } => _debug.toggle(),
210 _ => {}
211 }
212 }
213
214 pub fn synchronize(
220 &mut self,
221 application: &P,
222 window_id: window::Id,
223 window: &dyn Window,
224 ) {
225 let new_title = application.title(window_id);
227
228 if self.title != new_title {
229 window.set_title(&new_title);
230 self.title = new_title;
231 }
232
233 let new_scale_factor = application.scale_factor(window_id);
235 let mut new_size = window.surface_size();
236 let current_size = self.viewport.physical_size();
237 if self.scale_factor != new_scale_factor
238 || (current_size.width, current_size.height)
239 != (new_size.width, new_size.height)
240 && !(new_size.width == 0 && new_size.height == 0)
241 {
242 if new_size.width == 0 {
243 new_size.width = current_size.width;
244 }
245 if new_size.height == 0 {
246 new_size.height = current_size.height;
247 }
248 self.viewport = Viewport::with_physical_size(
249 Size::new(new_size.width, new_size.height),
250 window.scale_factor() * new_scale_factor,
251 );
252 self.viewport_version = self.viewport_version.wrapping_add(1);
253
254 self.scale_factor = new_scale_factor;
255 }
256
257 self.theme = application.theme(window_id);
259 self.appearance = application.style(&self.theme);
260 }
261}