1mod cache;
3pub mod component;
4mod renderer;
5pub mod widget;
6
7pub use cache::{Font, FontId, RawFont, load_font};
8pub use graphic::{Id, Rotation};
9pub use iced::Event;
10pub use iced_winit::conversion::window_event;
11pub use renderer::{IcedRenderer, style};
12
13use super::{
14 graphic::{self, Graphic},
15 scale::{Scale, ScaleMode},
16};
17use crate::{
18 error::Error,
19 render::{Renderer, UiDrawer},
20 window::Window,
21};
22use common::slowjob::SlowJobPool;
23use common_base::span;
24use iced::{Cache, Size, UserInterface, mouse};
25use iced_winit::Clipboard;
26use vek::*;
27
28pub type Element<'a, M> = iced::Element<'a, M, IcedRenderer>;
29
30pub struct IcedUi {
31 renderer: IcedRenderer,
32 cache: Option<Cache>,
33 events: Vec<Event>,
34 cursor_position: Vec2<f32>,
35 scale: Scale,
37 scale_changed: bool,
38}
39impl IcedUi {
40 pub fn new(
41 window: &mut Window,
42 default_font: Font,
43 scale_mode: ScaleMode,
44 ) -> Result<Self, Error> {
45 let scale_factor = window.scale_factor();
46 let renderer = window.renderer_mut();
47 let physical_resolution = renderer.resolution();
48 let scale = Scale::new(physical_resolution, scale_factor, scale_mode, 1.2);
49
50 let scaled_resolution = scale.scaled_resolution().map(|e| e as f32);
51
52 Ok(Self {
54 renderer: IcedRenderer::new(
55 renderer,
56 scaled_resolution,
57 physical_resolution,
58 default_font,
59 )?,
60 cache: Some(Cache::new()),
61 events: Vec::new(),
62 cursor_position: Vec2::zero(),
64 scale,
65 scale_changed: false,
66 })
67 }
68
69 pub fn add_font(&mut self, font: RawFont) -> FontId { self.renderer.add_font(font) }
71
72 pub fn clear_fonts(&mut self, default_font: Font) { self.renderer.clear_fonts(default_font); }
74
75 pub fn add_graphic(&mut self, graphic: Graphic) -> Id { self.renderer.add_graphic(graphic) }
77
78 pub fn replace_graphic(&mut self, id: Id, graphic: Graphic) {
79 self.renderer.replace_graphic(id, graphic);
80 }
81
82 pub fn scale(&self) -> Scale { self.scale }
83
84 pub fn set_scaling_mode(&mut self, mode: ScaleMode) {
85 self.scale_changed |= self.scale.set_scaling_mode(mode);
87 }
88
89 pub fn scale_factor_changed(&mut self, scale_factor: f64) {
92 self.scale_changed |= self.scale.scale_factor_changed(scale_factor);
93 }
94
95 pub fn handle_event(&mut self, event: Event) {
96 use iced::window;
97 match event {
98 Event::Window(window::Event::Resized { .. }) => {},
102 Event::Mouse(mouse::Event::CursorMoved { position }) => {
106 let scale = self.scale.scale_factor_logical() as f32;
108 let x = position.x / scale;
109 let y = position.y / scale;
110 self.cursor_position = Vec2::new(x, y);
114 self.events.push(Event::Mouse(mouse::Event::CursorMoved {
115 position: iced::Point::new(x, y),
116 }));
117 },
118 Event::Mouse(mouse::Event::WheelScrolled {
120 delta: mouse::ScrollDelta::Pixels { x, y },
121 }) => {
122 let scale = self.scale.scale_factor_logical() as f32;
124 self.events.push(Event::Mouse(mouse::Event::WheelScrolled {
125 delta: mouse::ScrollDelta::Pixels {
126 x: x / scale,
127 y: y / scale,
128 },
129 }));
130 },
131 event => self.events.push(event),
132 }
133 }
134
135 pub fn maintain<'a, M, E: Into<Element<'a, M>>>(
139 &mut self,
140 root: E,
141 renderer: &mut Renderer,
142 pool: Option<&SlowJobPool>,
143 clipboard: &mut Clipboard,
144 ) -> (Vec<M>, mouse::Interaction) {
145 span!(_guard, "maintain", "IcedUi::maintain");
146 let resolution_changed = self.scale.surface_resized(renderer.resolution());
150
151 if self.scale_changed || resolution_changed {
153 self.scale_changed = false;
154
155 let scaled_resolution = self.scale.scaled_resolution().map(|e| e as f32);
156 self.events
157 .push(Event::Window(iced::window::Event::Resized {
158 width: scaled_resolution.x as u32,
159 height: scaled_resolution.y as u32,
160 }));
161 let physical_resolution = renderer.resolution();
165 if physical_resolution.map(|e| e > 0).reduce_and() {
166 self.renderer
167 .resize(scaled_resolution, physical_resolution, renderer);
168 }
169 }
170
171 let cursor_position = iced::Point {
172 x: self.cursor_position.x,
173 y: self.cursor_position.y,
174 };
175
176 let window_size = self.scale.scaled_resolution().map(|e| e as f32);
178
179 span!(guard, "build user_interface");
180 let mut user_interface = UserInterface::build(
181 root,
182 Size::new(window_size.x, window_size.y),
183 self.cache.take().unwrap(),
184 &mut self.renderer,
185 );
186 drop(guard);
187
188 let messages = {
189 span!(_guard, "update user_interface");
190 let mut messages = Vec::new();
191 let _event_status_list = user_interface.update(
192 &self.events,
193 cursor_position,
194 &self.renderer,
195 clipboard,
196 &mut messages,
197 );
198 messages
199 };
200 self.events.clear();
202
203 span!(guard, "draw user_interface");
204 let (primitive, mouse_interaction) =
205 user_interface.draw(&mut self.renderer, cursor_position);
206 drop(guard);
207
208 self.cache = Some(user_interface.into_cache());
209
210 self.renderer.draw(primitive, renderer, pool);
211
212 (messages, mouse_interaction)
213 }
214
215 pub fn render<'a>(&'a self, drawer: &mut UiDrawer<'_, 'a>) { self.renderer.render(drawer); }
216}