zng/render.rs
1//! Frame builder and other types.
2//!
3//! Frame rendering means building a display list and updating all widget transforms, no actual pixel rendering happens
4//! during the render pass, the built display list is send to the view-process where it is actually rendered.
5//!
6//! Widgets render is centered around [`UiNode::render`] and [`UiNode::render_update`] using the [`FrameBuilder`]
7//! and [`FrameUpdate`] types. Render builds a display list, updates widget transforms and hit-test shapes, during
8//! render some values in the display list can be bound to a [`FrameValueKey`], this key can be used during `render_update`
9//! to replace the value in the last display list instead of rebuilding it.
10//!
11//! Note that even without render-updates all widgets that do not request render and are not ancestor to one are reused.
12//! Reused widgets only include a range of display items to copy from the previous display list. A normal release built window
13//! can easily achieve 60FPS rendering even without render-updates, but reusable components should try to achieve best performance.
14//!
15//! ```
16//! use zng::prelude_wgt::*;
17//!
18//! /// Fills the available space with a centered circle of the color.
19//! ///
20//! /// This node disables inline layout for the widget.
21//! pub fn color_circle(color: impl IntoVar<Rgba>) -> impl UiNode {
22//! let color = color.into_var();
23//! let mut area = PxRect::zero();
24//!
25//! // key to the color in a rendered frame,
26//! // can be used to update the frame without rebuilding the display list
27//! let color_key = FrameValueKey::new_unique();
28//!
29//! match_node_leaf(move |op| match op {
30//! UiNodeOp::Init => {
31//! // request a frame update when the color changes
32//! WIDGET.sub_var_render_update(&color);
33//! }
34//! UiNodeOp::Measure { wm, desired_size } => {
35//! wm.disable_inline(); // is inline-block
36//! *desired_size = LAYOUT.constraints().fill_size();
37//! }
38//! UiNodeOp::Layout { final_size, .. } => {
39//! *final_size = LAYOUT.constraints().fill_size();
40//!
41//! // centered square
42//! let mut a = PxRect::from_size(*final_size);
43//! if a.size.width < a.size.height {
44//! a.origin.y = (a.size.height - a.size.width) / Px(2);
45//! a.size.height = a.size.width;
46//! } else {
47//! a.origin.x = (a.size.width - a.size.height) / Px(2);
48//! a.size.width = a.size.height;
49//! }
50//!
51//! if a != area {
52//! area = a;
53//! // request a full render because are is not keyed for updates
54//! WIDGET.render();
55//! }
56//! }
57//! UiNodeOp::Render { frame } => {
58//! // clip a circle at the area
59//! frame.push_clip_rounded_rect(area, PxCornerRadius::new_all(area.size), false, false, |frame| {
60//! // fill the are with color, bind the color_key to the color
61//! frame.push_color(area, color_key.bind_var(&color, |&c| c.into()));
62//! });
63//! }
64//! UiNodeOp::RenderUpdate { update } => {
65//! // update the color in the existing frame, this is an optimization
66//! update.update_color_opt(color_key.update_var(&color, |&c| c.into()));
67//! }
68//! _ => {}
69//! })
70//! }
71//! ```
72//!
73//! The example above declares a simple node that draws a colored circle, the circle color is keyed for render updates.
74//!
75//! ```
76//! # use zng::prelude::*;
77//! # let _scope = APP.defaults();
78//! # fn color_circle(_color: impl IntoVar<zng::color::Rgba>) -> impl UiNode { widget::node::FillUiNode }
79//! let color = var(colors::RED);
80//! let mut i = 0u8;
81//! # let _ =
82//! Container! {
83//! child = color_circle(color.easing_with(1.secs(), easing::linear, color::rgba_sampler));
84//! gesture::on_click = hn!(|_| {
85//! color.set(match i {
86//! 0 => colors::YELLOW,
87//! 1 => colors::GREEN,
88//! 2 => colors::RED,
89//! _ => unreachable!(),
90//! });
91//! i += 1;
92//! if i == 3 {
93//! i = 0;
94//! }
95//! });
96//! }
97//! # ;
98//! ```
99//!
100//! [`UiNode::render`]: crate::widget::node::UiNode::render
101//! [`UiNode::render_update`]: crate::widget::node::UiNode::render_update
102//!
103//! # Full API
104//!
105//! See [`zng_app::render`] for the full API.
106
107pub use zng_app::render::{
108 ClipBuilder, FontSynthesis, FrameBuilder, FrameUpdate, FrameValue, FrameValueKey, FrameValueUpdate, HitTestBuilder, HitTestClipBuilder,
109 ImageRendering, ReferenceFrameId, ReuseRange, SpatialFrameId,
110};
111pub use zng_view_api::window::FrameId;