Expand description
Frame builder and other types.
Frame rendering means building a display list and updating all widget transforms, no actual pixel rendering happens during the render pass, the built display list is send to the view-process where it is actually rendered.
Widgets render is centered around UiNode::render
and UiNode::render_update
using the FrameBuilder
and FrameUpdate
types. Render builds a display list, updates widget transforms and hit-test shapes, during
render some values in the display list can be bound to a FrameValueKey
, this key can be used during render_update
to replace the value in the last display list instead of rebuilding it.
Note that even without render-updates all widgets that do not request render and are not ancestor to one are reused. Reused widgets only include a range of display items to copy from the previous display list. A normal release built window can easily achieve 60FPS rendering even without render-updates, but reusable components should try to achieve best performance.
use zng::prelude_wgt::*;
/// Fills the available space with a centered circle of the color.
///
/// This node disables inline layout for the widget.
pub fn color_circle(color: impl IntoVar<Rgba>) -> impl UiNode {
let color = color.into_var();
let mut area = PxRect::zero();
// key to the color in a rendered frame,
// can be used to update the frame without rebuilding the display list
let color_key = FrameValueKey::new_unique();
match_node_leaf(move |op| match op {
UiNodeOp::Init => {
// request a frame update when the color changes
WIDGET.sub_var_render_update(&color);
}
UiNodeOp::Measure { wm, desired_size } => {
wm.disable_inline(); // is inline-block
*desired_size = LAYOUT.constraints().fill_size();
}
UiNodeOp::Layout { final_size, .. } => {
*final_size = LAYOUT.constraints().fill_size();
// centered square
let mut a = PxRect::from_size(*final_size);
if a.size.width < a.size.height {
a.origin.y = (a.size.height - a.size.width) / Px(2);
a.size.height = a.size.width;
} else {
a.origin.x = (a.size.width - a.size.height) / Px(2);
a.size.width = a.size.height;
}
if a != area {
area = a;
// request a full render because are is not keyed for updates
WIDGET.render();
}
}
UiNodeOp::Render { frame } => {
// clip a circle at the area
frame.push_clip_rounded_rect(area, PxCornerRadius::new_all(area.size), false, false, |frame| {
// fill the are with color, bind the color_key to the color
frame.push_color(area, color_key.bind_var(&color, |&c| c.into()));
});
}
UiNodeOp::RenderUpdate { update } => {
// update the color in the existing frame, this is an optimization
update.update_color_opt(color_key.update_var(&color, |&c| c.into()));
}
_ => {}
})
}
The example above declares a simple node that draws a colored circle, the circle color is keyed for render updates.
let color = var(colors::RED);
let mut i = 0u8;
Container! {
child = color_circle(color.easing_with(1.secs(), easing::linear, color::rgba_sampler));
gesture::on_click = hn!(|_| {
color.set(match i {
0 => colors::YELLOW,
1 => colors::GREEN,
2 => colors::RED,
_ => unreachable!(),
});
i += 1;
if i == 3 {
i = 0;
}
});
}
§Full API
See zng_app::render
for the full API.
Structs§
- Builder for a chain of render and hit-test clips.
- Configure if a synthetic font is generated for fonts that do not implement bold or oblique variants.
- A full frame builder.
- Identifier of a frame or frame update.
- A frame quick update.
- Unique key of an updatable value in the view-process frame.
- Represents an update targeting a previously setup
FrameValue
. - Builder for the hit-testable shape of the inner-bounds of a widget.
- Builder for a chain of hit-test clips.
- Represents an unique key for a spatial reference frame that is recreated in multiple frames.
- Represents a display list reuse range.
- Unique ID of a reference frame.
Enums§
- Represents a frame value that may be updated.
- Image scaling algorithm in the renderer.
- Nine-patch border repeat mode.