1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
//! 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.
//!
//! ```
//! # use zng::prelude::*;
//! # let _scope = APP.defaults();
//! # fn color_circle(_color: impl IntoVar<zng::color::Rgba>) -> impl UiNode { widget::node::FillUiNode }
//! let color = var(colors::RED);
//! let mut i = 0u8;
//! # let _ =
//! 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;
//! }
//! });
//! }
//! # ;
//! ```
//!
//! [`UiNode::render`]: crate::widget::node::UiNode::render
//! [`UiNode::render_update`]: crate::widget::node::UiNode::render_update
//!
//! # Full API
//!
//! See [`zng_app::render`] for the full API.
pub use zng_app::render::{
ClipBuilder, FontSynthesis, FrameBuilder, FrameUpdate, FrameValue, FrameValueKey, FrameValueUpdate, HitTestBuilder, HitTestClipBuilder,
ImageRendering, ReferenceFrameId, RepeatMode, ReuseRange, SpatialFrameId,
};
pub use zng_view_api::window::FrameId;