lgui_core/core/view/declarative/
primitives.rs1use super::element::{location_hash, stable_hash};
2use super::*;
3
4pub fn group(rect: UiRect) -> Element {
5 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| {
6 UiElement::group(cx.id, rect).children(cx.children)
7 })
8}
9
10pub fn compositing_layer(rect: UiRect, spec: CompositingLayerSpec) -> Element {
11 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| {
12 UiElement::compositing_layer(cx.id, rect, spec).children(cx.children)
13 })
14}
15
16#[track_caller]
19pub fn animated_compositing_layer<T>(
20 rect: UiRect,
21 configure: impl FnOnce(&mut T) + 'static,
22) -> Element
23where
24 T: CompositingLayerAnimation,
25{
26 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| {
27 let (_, spec, wants_frame) = cx
28 .context
29 .compositing_layer_animation_mut(&cx.id, configure);
30 if wants_frame {
31 cx.context.hook_updates().request_frame();
32 }
33 UiElement::compositing_layer(cx.id, rect, spec).children(cx.children)
34 })
35}
36
37pub fn text(
38 rect: UiRect,
39 value: impl Into<std::borrow::Cow<'static, str>>,
40 style: TextStyle,
41) -> Element {
42 let value = value.into();
43 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| UiElement::text(cx.id, rect, value, style))
44}
45
46pub fn content_text(value: impl Into<Cow<'static, str>>) -> Element {
47 let value = value.into();
48 let height = 18;
49 let width = (value.chars().count() as i32 * 9).max(1);
50 let rect = UiRect::new(0.0, 0.0, width as f32, height as f32);
51 text(rect, value, TextStyle::new(Color::WHITE, 16.0, 400))
52 .with_layout(LayoutSpec::Fixed(Size::new(width as f32, height as f32)))
53}
54
55pub fn fragment(content: impl IntoElementContent) -> Fragment {
56 let mut children = Vec::new();
57 content.append_to(&mut children);
58 Fragment { children }
59}
60
61#[track_caller]
67pub fn context_provider<T>(value: T, content: impl IntoElementContent + 'static) -> Element
68where
69 T: Clone + PartialEq + 'static,
70{
71 let mut children = Vec::new();
72 content.append_to(&mut children);
73 component(value, move |_cx, value| {
74 let value = value.clone();
75 Element::new(move |mut cx: ElementRenderCx<'_, '_, '_>| {
76 let _provider =
77 cx.context
78 .contexts()
79 .provide(cx.component_id, value, cx.context.component_tree());
80 let children = cx.compile_deferred_children();
81 let bounds = children
82 .iter()
83 .map(ui_element_paint_bounds)
84 .reduce(UiRect::union)
85 .unwrap_or_else(|| UiRect::new(0.0, 0.0, 0.0, 0.0));
86 UiElement::group(cx.id, cx.context.viewport())
87 .paint_bounds(bounds)
88 .children(children)
89 })
90 .defer_children_compile()
91 .children(children)
92 })
93}
94
95fn ui_element_paint_bounds(element: &UiElement) -> UiRect {
96 element
97 .children_ref()
98 .iter()
99 .map(ui_element_paint_bounds)
100 .fold(element.node().paint_bounds, UiRect::union)
101}
102
103pub fn ellipse(rect: UiRect, style: VisualStyle) -> Element {
104 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| UiElement::ellipse(cx.id, rect, style))
105}
106
107pub fn glow(rect: UiRect, color: Color, alpha: u8) -> Element {
108 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| UiElement::glow(cx.id, rect, color, alpha))
109}
110
111pub fn line(rect: UiRect, style: VisualStyle) -> Element {
112 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| UiElement::line(cx.id, rect, style))
113}
114
115pub fn overlay(rect: UiRect, style: OverlayStyle) -> Element {
116 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| UiElement::overlay(cx.id, rect, style))
117}
118
119pub fn clip(rect: UiRect, offset_x: f32, offset_y: f32) -> Element {
120 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| {
121 UiElement::clip(cx.id, rect, offset_x, offset_y).children(cx.children)
122 })
123}
124
125pub fn clip_path(rect: UiRect, path: UiPath) -> Element {
126 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| {
127 UiElement::clip_path(cx.id, rect, path).children(cx.children)
128 })
129}
130
131pub fn path(rect: UiRect, path: UiPath, style: PathStyle) -> Element {
132 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| UiElement::path(cx.id, rect, path, style))
133}
134
135pub fn precompiled(element: UiElement) -> Element {
136 Element::new(move |_| element)
137}
138
139#[track_caller]
142pub fn component<P, F>(props: P, render: F) -> Element
143where
144 P: PartialEq + 'static,
145 F: for<'a, 'ctx> FnOnce(&mut RenderCx<'a, 'ctx>, &P) -> Element + 'static,
146{
147 let location = Location::caller();
148 let callsite = location_hash(location);
149 Element::new(move |cx: ElementRenderCx<'_, '_, '_>| {
150 let identity = stable_hash(cx.id.as_str());
151 let component_id = cx.context.component_tree().keyed_child(
152 cx.component_id,
153 callsite,
154 identity,
155 type_name::<F>(),
156 );
157 if cx.force_components {
158 cx.context.component_tree().mark_dirty(component_id);
159 }
160 if cx.context.component_tree().can_reuse(component_id, &props) {
161 cx.context.preserve_component_state_scope(cx.scope);
162 return cx
163 .context
164 .component_tree()
165 .reuse_output(component_id)
166 .into_retained_boundary(component_id);
167 }
168
169 cx.context.contexts().begin_component(component_id);
170 let force_children = cx
171 .context
172 .component_tree()
173 .begin_component_execution(component_id);
174 let mut render_cx =
175 RenderCx::for_component(cx.scope, cx.context, component_id, force_children);
176 let _current_context = cx.context.contexts().enter_current(component_id);
177 let view = render(&mut render_cx, &props);
178 let output = render_cx
179 .compile(view)
180 .claim_component_owner(component_id)
181 .component_boundary(component_id);
182 cx.context
183 .component_tree()
184 .commit_output(component_id, props, output.clone());
185 output
186 })
187}