iced_winit/program/
state.rs
1use crate::conversion;
2use crate::core::{Color, Size};
3use crate::core::{mouse, theme, window};
4use crate::graphics::Viewport;
5use crate::program::Program;
6
7use winit::event::{Touch, WindowEvent};
8use winit::window::Window;
9
10use std::fmt::{Debug, Formatter};
11
12pub struct State<P: Program>
14where
15 P::Theme: theme::Base,
16{
17 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 style: theme::Style,
25}
26
27impl<P: Program> Debug for State<P>
28where
29 P::Theme: theme::Base,
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("style", &self.style)
39 .finish()
40 }
41}
42
43impl<P: Program> State<P>
44where
45 P::Theme: theme::Base,
46{
47 pub fn new(
49 application: &P,
50 window_id: window::Id,
51 window: &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 style = application.style(&theme);
57
58 let viewport = {
59 let physical_size = window.inner_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 style,
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 cursor(&self) -> mouse::Cursor {
108 self.cursor_position
109 .map(|cursor_position| {
110 conversion::cursor_position(
111 cursor_position,
112 self.viewport.scale_factor(),
113 )
114 })
115 .map(mouse::Cursor::Available)
116 .unwrap_or(mouse::Cursor::Unavailable)
117 }
118
119 pub fn modifiers(&self) -> winit::keyboard::ModifiersState {
121 self.modifiers
122 }
123
124 pub fn theme(&self) -> &P::Theme {
126 &self.theme
127 }
128
129 pub fn background_color(&self) -> Color {
131 self.style.background_color
132 }
133
134 pub fn text_color(&self) -> Color {
136 self.style.text_color
137 }
138
139 pub fn update(
141 &mut self,
142 window: &Window,
143 event: &WindowEvent,
144 _debug: &mut crate::runtime::Debug,
145 ) {
146 match event {
147 WindowEvent::Resized(new_size) => {
148 let size = Size::new(new_size.width, new_size.height);
149
150 self.viewport = Viewport::with_physical_size(
151 size,
152 window.scale_factor() * self.scale_factor,
153 );
154
155 self.viewport_version = self.viewport_version.wrapping_add(1);
156 }
157 WindowEvent::ScaleFactorChanged {
158 scale_factor: new_scale_factor,
159 ..
160 } => {
161 let size = self.viewport.physical_size();
162
163 self.viewport = Viewport::with_physical_size(
164 size,
165 new_scale_factor * self.scale_factor,
166 );
167
168 self.viewport_version = self.viewport_version.wrapping_add(1);
169 }
170 WindowEvent::CursorMoved { position, .. }
171 | WindowEvent::Touch(Touch {
172 location: position, ..
173 }) => {
174 self.cursor_position = Some(*position);
175 }
176 WindowEvent::CursorLeft { .. } => {
177 self.cursor_position = None;
178 }
179 WindowEvent::ModifiersChanged(new_modifiers) => {
180 self.modifiers = new_modifiers.state();
181 }
182 #[cfg(feature = "debug")]
183 WindowEvent::KeyboardInput {
184 event:
185 winit::event::KeyEvent {
186 logical_key:
187 winit::keyboard::Key::Named(
188 winit::keyboard::NamedKey::F12,
189 ),
190 state: winit::event::ElementState::Pressed,
191 ..
192 },
193 ..
194 } => {
195 _debug.toggle();
196 window.request_redraw();
197 }
198 _ => {}
199 }
200 }
201
202 pub fn synchronize(
208 &mut self,
209 application: &P,
210 window_id: window::Id,
211 window: &Window,
212 ) {
213 let new_title = application.title(window_id);
215
216 if self.title != new_title {
217 window.set_title(&new_title);
218 self.title = new_title;
219 }
220
221 let new_scale_factor = application.scale_factor(window_id);
223 let new_size = window.inner_size();
224 let current_size = self.viewport.physical_size();
225
226 if self.scale_factor != new_scale_factor
227 || (current_size.width, current_size.height)
228 != (new_size.width, new_size.height)
229 {
230 self.viewport = Viewport::with_physical_size(
231 Size::new(new_size.width, new_size.height),
232 window.scale_factor() * new_scale_factor,
233 );
234 self.viewport_version = self.viewport_version.wrapping_add(1);
235
236 self.scale_factor = new_scale_factor;
237 }
238
239 self.theme = application.theme(window_id);
241 self.style = application.style(&self.theme);
242 }
243}