1#![doc = include_str!("../README.md")]
2#![deny(missing_docs)]
3
4use std::ops::{Deref, DerefMut};
5use std::sync::Arc;
6use std::task::Waker;
7
8use node::GenericNode;
9use widget::Context;
10
11use crate::component::Component;
12use crate::draw::DrawList;
13use crate::event::Event;
14use crate::layout::Rectangle;
15use crate::node::component_node::ComponentNode;
16use crate::style::tree::Query;
17use crate::style::Style;
18use crate::tracker::ManagedState;
19
20mod atlas;
21pub mod backend;
23mod bitset;
24pub mod cache;
26pub mod component;
28pub mod draw;
30pub mod event;
32pub mod graphics;
34pub mod layout;
36mod macros;
37pub mod node;
39pub mod prelude;
41#[cfg(feature = "winit")]
43#[cfg(feature = "wgpu")]
44pub mod sandbox;
45pub mod style;
47pub mod text;
49pub mod tracker;
51pub mod widget;
53
54pub struct Ui<M: 'static + Component> {
72 root_node: ComponentNode<'static, M>,
73 _state: ManagedState,
74 viewport: Rectangle,
75 redraw: bool,
76 cursor: (f32, f32),
77 style: Arc<Style>,
78 hidpi_scale: f32,
79}
80
81impl<C: 'static + Component> Ui<C> {
82 pub fn new<S, E>(root: C, viewport: Rectangle, hidpi_scale: f32, style: S) -> anyhow::Result<Self>
84 where
85 S: TryInto<Style, Error = E>,
86 anyhow::Error: From<E>,
87 {
88 let mut state = ManagedState::default();
89 let mut root_node = ComponentNode::new(root);
90 root_node.acquire_state(&mut unsafe { (&mut state as *mut ManagedState).as_mut() }.unwrap().tracker());
91
92 let style = Arc::new(style.try_into()?);
93 root_node.set_dirty();
94 root_node.style(&mut Query::from_style(style.clone()), (0, 1));
95
96 Ok(Self {
97 root_node,
98 _state: state,
99 viewport: Rectangle {
100 left: viewport.left / hidpi_scale,
101 top: viewport.top / hidpi_scale,
102 right: viewport.right / hidpi_scale,
103 bottom: viewport.bottom / hidpi_scale,
104 },
105 redraw: true,
106 cursor: (0.0, 0.0),
107 style,
108 hidpi_scale,
109 })
110 }
111
112 pub fn update_and_poll(&mut self, message: C::Message, waker: Waker) -> Vec<C::Output> {
119 let mut context = Context::new(self.needs_redraw(), self.cursor, waker);
120
121 self.root_node.update(message, &mut context);
122 while self.root_node.needs_poll() {
123 self.root_node.poll(&mut context);
124 }
125
126 self.redraw = context.redraw_requested();
127 context.into_vec()
128 }
129
130 pub fn handle_event_and_poll(&mut self, mut event: Event, waker: Waker) -> Vec<C::Output> {
137 if let Event::Cursor(x, y) = event {
138 event = Event::Cursor(x / self.hidpi_scale, y / self.hidpi_scale);
139 self.cursor = (x / self.hidpi_scale, y / self.hidpi_scale);
140 }
141
142 let mut context = Context::new(self.needs_redraw(), self.cursor, waker.clone());
143
144 {
145 let mut view = self.root_node.view();
146 let (w, h) = view.size();
147 let layout = Rectangle::from_wh(
148 w.resolve(self.viewport.width(), w.parts()),
149 h.resolve(self.viewport.height(), h.parts()),
150 );
151 view.event(layout, self.viewport, event, &mut context);
152 }
153
154 self.redraw = context.redraw_requested();
155
156 let mut outer_context = Context::new(self.needs_redraw(), self.cursor, waker);
157
158 for message in context {
159 self.root_node.update(message, &mut outer_context);
160 }
161 while self.root_node.needs_poll() {
162 self.root_node.poll(&mut outer_context);
163 }
164
165 self.redraw = outer_context.redraw_requested();
166 outer_context.into_vec()
167 }
168
169 pub fn poll(&mut self, waker: Waker) -> Vec<C::Output> {
174 let mut context = Context::new(self.needs_redraw(), self.cursor, waker);
175 loop {
176 self.root_node.poll(&mut context);
177 self.redraw = context.redraw_requested();
178
179 if self.root_node.needs_poll() {
180 continue;
181 } else {
182 break;
183 }
184 }
185 context.into_vec()
186 }
187
188 pub fn resize(&mut self, viewport: Rectangle) {
191 self.root_node.set_dirty();
192 self.redraw = true;
193 self.viewport = Rectangle {
194 left: viewport.left / self.hidpi_scale,
195 top: viewport.top / self.hidpi_scale,
196 right: viewport.right / self.hidpi_scale,
197 bottom: viewport.bottom / self.hidpi_scale,
198 };
199 }
200
201 pub fn needs_redraw(&self) -> bool {
204 self.redraw || self.root_node.dirty()
205 }
206
207 pub fn draw(&mut self) -> DrawList {
209 use self::draw::*;
210
211 let viewport = self.viewport;
212 let primitives = {
213 let mut view = self.root_node.view();
214 let (w, h) = view.size();
215 let layout = Rectangle::from_wh(
216 w.resolve(viewport.width(), w.parts()),
217 h.resolve(viewport.height(), h.parts()),
218 );
219 view.draw(layout, viewport)
220 };
221 self.redraw = false;
222
223 struct Layer {
224 vtx: Vec<Vertex>,
225 cmd: Vec<Command>,
226 }
227
228 impl Layer {
229 fn append(&mut self, command: Command) {
230 if let Some(next) = self.cmd.last_mut().unwrap().append(command) {
231 self.cmd.push(next);
232 }
233 }
234 }
235
236 let mut layers = vec![Layer {
237 vtx: Vec::new(),
238 cmd: vec![Command::Nop],
239 }];
240 let mut layer: usize = 0;
241
242 let mut scissors = vec![viewport];
243
244 let scale = self.hidpi_scale;
245 let validate_clip = move |clip: Rectangle| {
246 let v = Rectangle {
247 left: clip.left.max(0.0).min(viewport.right) * scale,
248 top: clip.top.max(0.0).min(viewport.bottom) * scale,
249 right: clip.right.max(0.0).min(viewport.right) * scale,
250 bottom: clip.bottom.max(0.0).min(viewport.bottom) * scale,
251 };
252 if v.right as u32 - v.left as u32 > 0 && v.bottom as u32 - v.top as u32 > 0 {
253 Some(v)
254 } else {
255 None
256 }
257 };
258
259 let mut draw_enabled = true;
260
261 for primitive in primitives.into_iter() {
262 match primitive {
263 Primitive::PushClip(scissor) => {
264 scissors.push(scissor);
265
266 draw_enabled = validate_clip(scissor).map_or(false, |s| {
267 layers[layer].append(Command::Clip { scissor: s });
268 true
269 });
270 }
271
272 Primitive::PopClip => {
273 scissors.pop();
274 let scissor = scissors[scissors.len() - 1];
275
276 draw_enabled = validate_clip(scissor).map_or(false, |s| {
277 layers[layer].append(Command::Clip { scissor: s });
278 true
279 });
280 }
281
282 Primitive::LayerUp => {
283 layer += 1;
284 while layer >= layers.len() {
285 layers.push(Layer {
286 vtx: Vec::new(),
287 cmd: vec![Command::Nop],
288 });
289 }
290 }
291
292 Primitive::LayerDown => {
293 layer -= 1;
294 }
295
296 Primitive::DrawRect(r, color) => {
297 if draw_enabled {
298 let r = r.to_device_coordinates(viewport);
299 let color = [color.r, color.g, color.b, color.a];
300 let mode = 1.0;
301 let offset = layers[layer].vtx.len();
302 layers[layer].vtx.push(Vertex {
303 pos: [r.left, r.top],
304 uv: [0.0; 2],
305 color,
306 mode,
307 });
308 layers[layer].vtx.push(Vertex {
309 pos: [r.right, r.top],
310 uv: [0.0; 2],
311 color,
312 mode,
313 });
314 layers[layer].vtx.push(Vertex {
315 pos: [r.right, r.bottom],
316 uv: [0.0; 2],
317 color,
318 mode,
319 });
320 layers[layer].vtx.push(Vertex {
321 pos: [r.left, r.top],
322 uv: [0.0; 2],
323 color,
324 mode,
325 });
326 layers[layer].vtx.push(Vertex {
327 pos: [r.right, r.bottom],
328 uv: [0.0; 2],
329 color,
330 mode,
331 });
332 layers[layer].vtx.push(Vertex {
333 pos: [r.left, r.bottom],
334 uv: [0.0; 2],
335 color,
336 mode,
337 });
338 layers[layer].append(Command::Colored { offset, count: 6 });
339 }
340 }
341
342 Primitive::DrawText(text, rect) => {
343 if draw_enabled {
344 let color = [text.color.r, text.color.g, text.color.b, text.color.a];
345 let mode = 0.0;
346 let offset = layers[layer].vtx.len();
347
348 self.style.cache().lock().unwrap().draw_text(&text, rect, |uv, pos| {
349 let rc = Rectangle {
350 left: pos.left,
351 top: pos.top,
352 right: pos.right,
353 bottom: pos.bottom,
354 }
355 .to_device_coordinates(viewport);
356
357 layers[layer].vtx.push(Vertex {
358 pos: [rc.left, rc.top],
359 uv: uv.pt(0.0, 0.0),
360 color,
361 mode,
362 });
363 layers[layer].vtx.push(Vertex {
364 pos: [rc.right, rc.top],
365 uv: uv.pt(1.0, 0.0),
366 color,
367 mode,
368 });
369 layers[layer].vtx.push(Vertex {
370 pos: [rc.right, rc.bottom],
371 uv: uv.pt(1.0, 1.0),
372 color,
373 mode,
374 });
375 layers[layer].vtx.push(Vertex {
376 pos: [rc.left, rc.top],
377 uv: uv.pt(0.0, 0.0),
378 color,
379 mode,
380 });
381 layers[layer].vtx.push(Vertex {
382 pos: [rc.right, rc.bottom],
383 uv: uv.pt(1.0, 1.0),
384 color,
385 mode,
386 });
387 layers[layer].vtx.push(Vertex {
388 pos: [rc.left, rc.bottom],
389 uv: uv.pt(0.0, 1.0),
390 color,
391 mode,
392 });
393 });
394
395 let count = layers[layer].vtx.len() - offset;
396 layers[layer].append(Command::Textured {
397 texture: text.font.tex_slot,
398 offset,
399 count,
400 });
401 }
402 }
403
404 Primitive::Draw9(patch, rect, color) => {
405 if draw_enabled {
406 let uv = patch.image.texcoords;
407 let color = [color.r, color.g, color.b, color.a];
408 let mode = 0.0;
409 let offset = layers[layer].vtx.len();
410
411 patch.iterate_sections(false, rect.width(), |x, u| {
412 patch.iterate_sections(true, rect.height(), |y, v| {
413 let rc = Rectangle {
414 left: x.0 + rect.left,
415 right: x.1 + rect.left,
416 top: y.0 + rect.top,
417 bottom: y.1 + rect.top,
418 }
419 .to_device_coordinates(viewport);
420
421 layers[layer].vtx.push(Vertex {
422 pos: [rc.left, rc.top],
423 uv: uv.pt(u.0, v.0),
424 color,
425 mode,
426 });
427 layers[layer].vtx.push(Vertex {
428 pos: [rc.right, rc.top],
429 uv: uv.pt(u.1, v.0),
430 color,
431 mode,
432 });
433 layers[layer].vtx.push(Vertex {
434 pos: [rc.right, rc.bottom],
435 uv: uv.pt(u.1, v.1),
436 color,
437 mode,
438 });
439 layers[layer].vtx.push(Vertex {
440 pos: [rc.left, rc.top],
441 uv: uv.pt(u.0, v.0),
442 color,
443 mode,
444 });
445 layers[layer].vtx.push(Vertex {
446 pos: [rc.right, rc.bottom],
447 uv: uv.pt(u.1, v.1),
448 color,
449 mode,
450 });
451 layers[layer].vtx.push(Vertex {
452 pos: [rc.left, rc.bottom],
453 uv: uv.pt(u.0, v.1),
454 color,
455 mode,
456 });
457 });
458 });
459
460 let count = layers[layer].vtx.len() - offset;
461 layers[layer].append(Command::Textured {
462 texture: patch.image.texture,
463 offset,
464 count,
465 });
466 }
467 }
468
469 Primitive::DrawImage(image, r, color) => {
470 if draw_enabled {
471 let r = r.to_device_coordinates(viewport);
472 let uv = image.texcoords;
473 let color = [color.r, color.g, color.b, color.a];
474 let mode = 0.0;
475 let offset = layers[layer].vtx.len();
476
477 layers[layer].vtx.push(Vertex {
478 pos: [r.left, r.top],
479 uv: [uv.left, uv.top],
480 color,
481 mode,
482 });
483 layers[layer].vtx.push(Vertex {
484 pos: [r.right, r.top],
485 uv: [uv.right, uv.top],
486 color,
487 mode,
488 });
489 layers[layer].vtx.push(Vertex {
490 pos: [r.right, r.bottom],
491 uv: [uv.right, uv.bottom],
492 color,
493 mode,
494 });
495 layers[layer].vtx.push(Vertex {
496 pos: [r.left, r.top],
497 uv: [uv.left, uv.top],
498 color,
499 mode,
500 });
501 layers[layer].vtx.push(Vertex {
502 pos: [r.right, r.bottom],
503 uv: [uv.right, uv.bottom],
504 color,
505 mode,
506 });
507 layers[layer].vtx.push(Vertex {
508 pos: [r.left, r.bottom],
509 uv: [uv.left, uv.bottom],
510 color,
511 mode,
512 });
513
514 layers[layer].append(Command::Textured {
515 texture: image.texture,
516 offset,
517 count: 6,
518 });
519 }
520 }
521 }
522 }
523
524 let (vertices, commands) =
525 layers
526 .into_iter()
527 .fold((Vec::new(), Vec::new()), |(mut vtx, mut cmd), mut layer| {
528 let layer_offset = vtx.len();
529 vtx.append(&mut layer.vtx);
530 cmd.extend(layer.cmd.into_iter().map(|command| match command {
531 Command::Textured { texture, offset, count } => Command::Textured {
532 texture,
533 offset: offset + layer_offset,
534 count,
535 },
536 Command::Colored { offset, count } => Command::Colored {
537 offset: offset + layer_offset,
538 count,
539 },
540 other => other,
541 }));
542 (vtx, cmd)
543 });
544
545 DrawList {
546 updates: self.style.cache().lock().unwrap().take_updates(),
547 vertices,
548 commands,
549 }
550 }
551}
552
553impl<C: Component> Deref for Ui<C> {
554 type Target = C;
555
556 fn deref(&self) -> &Self::Target {
557 self.root_node.props()
558 }
559}
560
561impl<C: Component> DerefMut for Ui<C> {
562 fn deref_mut(&mut self) -> &mut Self::Target {
563 self.root_node.props_mut()
564 }
565}