1use derive_more::Add;
2use gpui::elements::layout_highlighted_chunks;
3use gpui::{
4 color::Color,
5 fonts::HighlightStyle,
6 geometry::{
7 rect::RectF,
8 vector::{vec2f, Vector2F},
9 },
10 json::{json, ToJson},
11 scene,
12 serde_json::Value,
13 text_layout::{Line, ShapedBoundary},
14 AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
15 SizeConstraint, View, ViewContext,
16};
17use length::{Length, Rems};
18use log::warn;
19use optional_struct::*;
20use std::{any::Any, borrow::Cow, f32, ops::Range, sync::Arc};
21
22pub struct Node<V: View> {
23 style: NodeStyle,
24 children: Vec<AnyElement<V>>,
25 id: Option<Cow<'static, str>>,
26}
27
28pub fn node<V: View>(child: impl Element<V>) -> Node<V> {
29 Node::default().child(child)
30}
31
32pub fn column<V: View>() -> Node<V> {
33 Node::default()
34}
35
36pub fn row<V: View>() -> Node<V> {
37 Node {
38 style: NodeStyle {
39 axis: Axis3d::X,
40 ..Default::default()
41 },
42 ..Default::default()
43 }
44}
45
46pub fn stack<V: View>() -> Node<V> {
47 Node {
48 style: NodeStyle {
49 axis: Axis3d::Z,
50 ..Default::default()
51 },
52 ..Default::default()
53 }
54}
55
56impl<V: View> Default for Node<V> {
57 fn default() -> Self {
58 Self {
59 style: Default::default(),
60 children: Default::default(),
61 id: None,
62 }
63 }
64}
65
66impl<V: View> Element<V> for Node<V> {
67 type LayoutState = NodeLayout;
68 type PaintState = ();
69
70 fn layout(
71 &mut self,
72 constraint: SizeConstraint,
73 view: &mut V,
74 cx: &mut LayoutContext<V>,
75 ) -> (Vector2F, Self::LayoutState) {
76 let layout = if let Some(axis) = self.style.axis.to_2d() {
77 self.layout_xy(axis, constraint, cx.rem_pixels(), view, cx)
78 } else {
79 todo!()
80 };
81
82 (layout.size.max(constraint.min), layout)
83 }
84
85 fn paint(
86 &mut self,
87 scene: &mut SceneBuilder,
88 bounds: RectF,
89 visible_bounds: RectF,
90 layout: &mut NodeLayout,
91 view: &mut V,
92 cx: &mut PaintContext<V>,
93 ) -> Self::PaintState {
94 let margined_bounds = RectF::from_points(
95 bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
96 bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
97 );
98
99 // Paint drop shadow
100 for shadow in &self.style.shadows {
101 scene.push_shadow(scene::Shadow {
102 bounds: margined_bounds + shadow.offset,
103 corner_radius: self.style.corner_radius,
104 sigma: shadow.blur,
105 color: shadow.color,
106 });
107 }
108
109 // // Paint cursor style
110 // if let Some(hit_bounds) = content_bounds.intersection(visible_bounds) {
111 // if let Some(style) = self.style.cursor {
112 // scene.push_cursor_region(CursorRegion {
113 // bounds: hit_bounds,
114 // style,
115 // });
116 // }
117 // }
118
119 // Render the background and/or the border.
120 let Fill::Color(fill_color) = self.style.fill;
121 let is_fill_visible = !fill_color.is_fully_transparent();
122 if is_fill_visible || self.style.borders.is_visible() {
123 eprintln!(
124 "{}: paint background: {:?}",
125 self.id.as_deref().unwrap_or(""),
126 margined_bounds
127 );
128
129 scene.push_quad(Quad {
130 bounds: margined_bounds,
131 background: is_fill_visible.then_some(fill_color),
132 border: scene::Border {
133 width: self.style.borders.width,
134 color: self.style.borders.color,
135 overlay: false,
136 top: self.style.borders.top,
137 right: self.style.borders.right,
138 bottom: self.style.borders.bottom,
139 left: self.style.borders.left,
140 },
141 corner_radius: self.style.corner_radius,
142 });
143 }
144
145 if !self.children.is_empty() {
146 // Account for padding first.
147 let borders = &self.style.borders;
148 let padded_bounds = RectF::from_points(
149 margined_bounds.origin()
150 + vec2f(
151 borders.left_width() + layout.padding.left,
152 borders.top_width() + layout.padding.top,
153 ),
154 margined_bounds.lower_right()
155 - vec2f(
156 layout.padding.right + borders.right_width(),
157 layout.padding.bottom + borders.bottom_width(),
158 ),
159 );
160
161 if let Some(axis) = self.style.axis.to_2d() {
162 // let parent_size = padded_bounds.size();
163 let mut child_origin = padded_bounds.origin();
164
165 // Align all children together along the primary axis
166 // let mut align_horizontally = false;
167 // let mut align_vertically = false;
168 // match axis {
169 // Axis2d::X => align_horizontally = true,
170 // Axis2d::Y => align_vertically = true,
171 // }
172 // align_child(
173 // &mut child_origin,
174 // parent_size,
175 // layout.content_size,
176 // self.style.align.0,
177 // align_horizontally,
178 // align_vertically,
179 // );
180
181 for child in &mut self.children {
182 // Align each child along the cross axis
183 // align_horizontally = !align_horizontally;
184 // align_vertically = !align_vertically;
185 // align_child(
186 // &mut child_origin,
187 // parent_size,
188 // child.size(),
189 // self.style.align.0,
190 // align_horizontally,
191 // align_vertically,
192 // );
193 //
194 child.paint(scene, child_origin, visible_bounds, view, cx);
195
196 // Advance along the primary axis by the size of this child
197 child_origin.set(axis, child_origin.get(axis) + child.size().get(axis));
198 }
199 } else {
200 todo!();
201 }
202 }
203 }
204
205 fn rect_for_text_range(
206 &self,
207 range_utf16: Range<usize>,
208 _: RectF,
209 _: RectF,
210 _: &Self::LayoutState,
211 _: &Self::PaintState,
212 view: &V,
213 cx: &ViewContext<V>,
214 ) -> Option<RectF> {
215 self.children
216 .iter()
217 .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
218 }
219
220 fn debug(
221 &self,
222 bounds: RectF,
223 _: &Self::LayoutState,
224 _: &Self::PaintState,
225 view: &V,
226 cx: &ViewContext<V>,
227 ) -> Value {
228 json!({
229 "type": "Node",
230 "bounds": bounds.to_json(),
231 // TODO!
232 // "children": self.content.iter().map(|child| child.debug(view, cx)).collect::<Vec<Value>>()
233 })
234 }
235
236 fn metadata(&self) -> Option<&dyn Any> {
237 Some(&self.style)
238 }
239}
240
241impl<V: View> Node<V> {
242 pub fn id(mut self, id: impl Into<Cow<'static, str>>) -> Self {
243 self.id = Some(id.into());
244 self
245 }
246
247 pub fn child(mut self, child: impl Element<V>) -> Self {
248 self.children.push(child.into_any());
249 self
250 }
251
252 pub fn children<I, E>(mut self, children: I) -> Self
253 where
254 I: IntoIterator<Item = E>,
255 E: Element<V>,
256 {
257 self.children
258 .extend(children.into_iter().map(|child| child.into_any()));
259 self
260 }
261
262 pub fn width(mut self, width: impl Into<Length>) -> Self {
263 self.style.size.width = width.into();
264 self
265 }
266
267 pub fn height(mut self, height: impl Into<Length>) -> Self {
268 self.style.size.height = height.into();
269 self
270 }
271
272 pub fn fill(mut self, fill: impl Into<Fill>) -> Self {
273 self.style.fill = fill.into();
274 self
275 }
276
277 pub fn text_size(mut self, text_size: Rems) -> Self {
278 self.style.text.size = Some(text_size);
279 self
280 }
281
282 pub fn margins(mut self, margins: impl Into<Edges<Length>>) -> Self {
283 self.style.margins = margins.into();
284 self
285 }
286
287 pub fn margin_top(mut self, top: Length) -> Self {
288 self.style.margins.top = top;
289 self
290 }
291
292 pub fn margin_bottom(mut self, bottom: Length) -> Self {
293 self.style.margins.bottom = bottom;
294 self
295 }
296
297 pub fn margin_left(mut self, left: impl Into<Length>) -> Self {
298 self.style.margins.left = left.into();
299 self
300 }
301
302 pub fn margin_right(mut self, right: impl Into<Length>) -> Self {
303 self.style.margins.right = right.into();
304 self
305 }
306
307 fn id_string(&self) -> String {
308 self.id.as_deref().unwrap_or("<anonymous>").to_string()
309 }
310
311 fn layout_xy(
312 &mut self,
313 primary_axis: Axis2d,
314 constraint: SizeConstraint,
315 rem_pixels: f32,
316 view: &mut V,
317 cx: &mut LayoutContext<V>,
318 ) -> NodeLayout {
319 let cross_axis = primary_axis.rotate();
320 let total_flex = self.style.flex();
321 let mut layout = NodeLayout {
322 size: Default::default(),
323 padding: self.style.padding.fixed_pixels(rem_pixels),
324 margins: self.style.margins.fixed_pixels(rem_pixels),
325 borders: self.style.borders.edges(),
326 };
327 let fixed_padding_size = layout.padding.size();
328 let fixed_margin_size = layout.margins.size();
329 let borders_size = layout.borders.size();
330 let fixed_constraint = constraint - fixed_margin_size - borders_size - fixed_padding_size;
331
332 // Determine the child constraints in each dimension based on the styled size
333 let mut child_constraint = SizeConstraint::default();
334 for axis in [Axis2d::X, Axis2d::Y] {
335 let length = self.style.size.get(axis);
336 let content_length = match length {
337 Length::Hug => {
338 // Tell the children not to expand
339 0.
340 }
341 Length::Fixed(fixed_length) => {
342 // Tell the children to expand up to the fixed length minus the padding.
343 fixed_length.to_pixels(rem_pixels) - fixed_padding_size.get(axis)
344 }
345 Length::Auto { .. } => {
346 // Tell the children to expand to fill their share of the flex space in this node.
347 length.flex_pixels(
348 rem_pixels,
349 &mut total_flex.get(axis),
350 &mut fixed_constraint.max.get(axis),
351 )
352 }
353 };
354 child_constraint.max.set(axis, content_length);
355 if axis == cross_axis {
356 child_constraint.min.set(axis, content_length);
357 }
358 }
359
360 // Lay out inflexible children. Total up flex of flexible children for
361 // use in a second pass.
362 let mut remaining_length = child_constraint.max.get(primary_axis);
363 let mut remaining_flex = 0.;
364 let mut total_length = 0.;
365 let mut cross_axis_max: f32 = 0.;
366
367 for child in &mut self.children {
368 if let Some(child_flex) = child
369 .metadata::<NodeStyle>()
370 .map(|style| style.flex().get(primary_axis))
371 {
372 if child_flex > 0. {
373 remaining_flex += child_flex;
374 continue;
375 }
376 }
377
378 let child_size = child.layout(child_constraint, view, cx);
379 let child_length = child_size.get(primary_axis);
380 remaining_length -= child_length;
381 total_length += child_length;
382 cross_axis_max = cross_axis_max.max(child_size.get(cross_axis));
383 }
384
385 // Distribute the remaining length among the flexible children.
386 for child in &mut self.children {
387 if let Some(child_flex) = child
388 .metadata::<NodeStyle>()
389 .map(|style| style.flex().get(primary_axis))
390 {
391 if child_flex > 0. {
392 let max_child_length = (child_flex / remaining_flex) * remaining_length;
393 child_constraint.max.set(primary_axis, max_child_length);
394
395 let child_size = child.layout(child_constraint, view, cx);
396 let child_length = child_size.get(primary_axis);
397 total_length += child_length;
398 remaining_length -= child_length;
399 remaining_flex -= child_flex;
400 cross_axis_max = cross_axis_max.max(child_size.get(cross_axis));
401 }
402 }
403 }
404
405 let content_size = match primary_axis {
406 Axis2d::X => vec2f(total_length, cross_axis_max),
407 Axis2d::Y => vec2f(cross_axis_max, total_length),
408 };
409
410 // Distribute remaining space to flexible padding and margins.
411 for axis in [Axis2d::X, Axis2d::Y] {
412 let length = self.style.size.get(axis);
413 match length {
414 Length::Hug => {
415 let mut remaining_flex = total_flex.get(axis);
416 let mut remaining_length =
417 fixed_constraint.min.get(axis) - content_size.get(axis);
418
419 layout.padding.compute_flex_edges(
420 &self.style.padding,
421 axis,
422 &mut remaining_flex,
423 &mut remaining_length,
424 rem_pixels,
425 );
426 layout.margins.compute_flex_edges(
427 &self.style.margins,
428 axis,
429 &mut remaining_flex,
430 &mut remaining_length,
431 rem_pixels,
432 );
433 layout.size.set(
434 axis,
435 content_size.get(axis)
436 + layout.padding.size().get(axis)
437 + layout.borders.size().get(axis)
438 + layout.margins.size().get(axis),
439 );
440 }
441 Length::Fixed(fixed_length) => {
442 let fixed_length = fixed_length.to_pixels(rem_pixels);
443
444 // With a fixed length, we can only distribute the space in the fixed-length container
445 // not consumed by the content.
446 let mut padding_flex = self.style.padding.flex().get(axis);
447 let mut max_padding_length = (fixed_length - content_size.get(axis)).max(0.);
448 layout.padding.compute_flex_edges(
449 &self.style.padding,
450 axis,
451 &mut padding_flex,
452 &mut max_padding_length,
453 rem_pixels,
454 );
455
456 // Similarly, distribute the available space for margins so we preserve the fixed length
457 // of the container.
458 let mut margin_flex = self.style.margins.flex().get(axis);
459 let mut max_margin_length = constraint.max.get(axis) - fixed_length;
460 layout.margins.compute_flex_edges(
461 &self.style.padding,
462 axis,
463 &mut margin_flex,
464 &mut max_margin_length,
465 rem_pixels,
466 );
467
468 layout
469 .size
470 .set(axis, fixed_length + layout.margins.size().get(axis))
471 }
472 Length::Auto { .. } => {
473 let mut remaining_flex = total_flex.get(axis);
474 let mut remaining_length = fixed_constraint.max.get(axis);
475 let flex_length =
476 length.flex_pixels(rem_pixels, &mut remaining_flex, &mut remaining_length);
477
478 layout.padding.compute_flex_edges(
479 &self.style.padding,
480 axis,
481 &mut remaining_flex,
482 &mut remaining_length,
483 rem_pixels,
484 );
485
486 layout.margins.compute_flex_edges(
487 &self.style.margins,
488 axis,
489 &mut remaining_flex,
490 &mut remaining_length,
491 rem_pixels,
492 );
493
494 layout.size.set(
495 axis,
496 flex_length
497 + layout.padding.size().get(axis)
498 + layout.borders.size().get(axis)
499 + layout.margins.size().get(axis),
500 )
501 }
502 }
503 }
504
505 layout
506 }
507}
508
509pub struct TopBottom {
510 top: Length,
511 bottom: Length,
512}
513
514impl<T: Into<Length>> From<(T, T)> for TopBottom {
515 fn from((top, bottom): (T, T)) -> Self {
516 Self {
517 top: top.into(),
518 bottom: bottom.into(),
519 }
520 }
521}
522
523impl<T: Copy + Into<Length>> From<T> for TopBottom {
524 fn from(both: T) -> Self {
525 Self {
526 top: both.into(),
527 bottom: both.into(),
528 }
529 }
530}
531
532pub struct LeftRight {
533 left: Length,
534 right: Length,
535}
536
537impl From<(Length, Length)> for LeftRight {
538 fn from((left, right): (Length, Length)) -> Self {
539 Self { left, right }
540 }
541}
542
543impl From<Length> for LeftRight {
544 fn from(both: Length) -> Self {
545 Self {
546 left: both,
547 right: both,
548 }
549 }
550}
551
552fn align_child(
553 child_origin: &mut Vector2F,
554 parent_size: Vector2F,
555 child_size: Vector2F,
556 alignment: Vector2F,
557 horizontal: bool,
558 vertical: bool,
559) {
560 let parent_center = parent_size / 2.;
561 let parent_target = parent_center + parent_center * alignment;
562 let child_center = child_size / 2.;
563 let child_target = child_center + child_center * alignment;
564
565 if horizontal {
566 child_origin.set_x(child_origin.x() + parent_target.x() - child_target.x())
567 }
568 if vertical {
569 child_origin.set_y(child_origin.y() + parent_target.y() - child_target.y());
570 }
571}
572
573struct Interactive<Style> {
574 default: Style,
575 hovered: Style,
576 active: Style,
577 disabled: Style,
578}
579
580#[derive(Clone, Default)]
581pub struct NodeStyle {
582 axis: Axis3d,
583 wrap: bool,
584 align: Align,
585 overflow_x: Overflow,
586 overflow_y: Overflow,
587 gap_x: Gap,
588 gap_y: Gap,
589
590 size: Size<Length>,
591 margins: Edges<Length>,
592 padding: Edges<Length>,
593 text: OptionalTextStyle,
594 opacity: f32,
595 fill: Fill,
596 borders: Borders,
597 corner_radius: f32,
598 shadows: Vec<Shadow>,
599}
600
601impl NodeStyle {
602 fn flex(&self) -> Vector2F {
603 self.size.flex() + self.padding.flex() + self.margins.flex()
604 }
605}
606
607#[optional_struct]
608struct TextStyle {
609 size: Rems,
610 font_family: Arc<str>,
611 weight: FontWeight,
612 style: FontStyle,
613}
614
615#[derive(Add, Default, Clone)]
616struct Size<T> {
617 width: T,
618 height: T,
619}
620
621impl<T: Copy> Size<T> {
622 fn get(&self, axis: Axis2d) -> T {
623 match axis {
624 Axis2d::X => self.width,
625 Axis2d::Y => self.height,
626 }
627 }
628}
629
630impl Size<Length> {
631 fn fixed_pixels(&self, rem_pixels: f32) -> Size<f32> {
632 Size {
633 width: self.width.fixed_pixels(rem_pixels),
634 height: self.height.fixed_pixels(rem_pixels),
635 }
636 }
637
638 pub fn fixed(&self) -> Size<Rems> {
639 Size {
640 width: self.width.fixed().unwrap_or_default(),
641 height: self.height.fixed().unwrap_or_default(),
642 }
643 }
644
645 pub fn flex(&self) -> Vector2F {
646 vec2f(
647 self.width.flex().unwrap_or(0.),
648 self.height.flex().unwrap_or(0.),
649 )
650 }
651}
652
653impl Size<Rems> {
654 pub fn to_pixels(&self, rem_size: f32) -> Vector2F {
655 vec2f(
656 self.width.to_pixels(rem_size),
657 self.height.to_pixels(rem_size),
658 )
659 }
660}
661
662#[derive(Clone, Default, Debug)]
663struct Edges<T> {
664 top: T,
665 bottom: T,
666 left: T,
667 right: T,
668}
669
670impl<T> Edges<T> {
671 fn start(&self, axis: Axis2d) -> &T {
672 match axis {
673 Axis2d::X => &self.left,
674 Axis2d::Y => &self.top,
675 }
676 }
677
678 fn start_mut(&mut self, axis: Axis2d) -> &mut T {
679 match axis {
680 Axis2d::X => &mut self.left,
681 Axis2d::Y => &mut self.top,
682 }
683 }
684
685 fn end(&self, axis: Axis2d) -> &T {
686 match axis {
687 Axis2d::X => &self.right,
688 Axis2d::Y => &self.bottom,
689 }
690 }
691
692 fn end_mut(&mut self, axis: Axis2d) -> &mut T {
693 match axis {
694 Axis2d::X => &mut self.right,
695 Axis2d::Y => &mut self.bottom,
696 }
697 }
698}
699
700impl Edges<f32> {
701 fn size(&self) -> Vector2F {
702 vec2f(self.left + self.right, self.top + self.bottom)
703 }
704
705 fn compute_flex_edges(
706 &mut self,
707 style_edges: &Edges<Length>,
708 axis: Axis2d,
709 remaining_flex: &mut f32,
710 remaining_length: &mut f32,
711 rem_pixels: f32,
712 ) {
713 *self.start_mut(axis) +=
714 style_edges
715 .start(axis)
716 .flex_pixels(rem_pixels, remaining_flex, remaining_length);
717 *self.end_mut(axis) +=
718 style_edges
719 .end(axis)
720 .flex_pixels(rem_pixels, remaining_flex, remaining_length);
721 }
722}
723
724impl Edges<Length> {
725 fn fixed_pixels(&self, rem_pixels: f32) -> Edges<f32> {
726 Edges {
727 top: self.top.fixed_pixels(rem_pixels),
728 bottom: self.bottom.fixed_pixels(rem_pixels),
729 left: self.left.fixed_pixels(rem_pixels),
730 right: self.right.fixed_pixels(rem_pixels),
731 }
732 }
733
734 fn flex_pixels(
735 &self,
736 rem_pixels: f32,
737 remaining_flex: &mut f32,
738 remaining_length: &mut f32,
739 ) -> Edges<f32> {
740 Edges {
741 top: self
742 .top
743 .flex_pixels(rem_pixels, remaining_flex, remaining_length),
744 bottom: self
745 .bottom
746 .flex_pixels(rem_pixels, remaining_flex, remaining_length),
747 left: self
748 .left
749 .flex_pixels(rem_pixels, remaining_flex, remaining_length),
750 right: self
751 .right
752 .flex_pixels(rem_pixels, remaining_flex, remaining_length),
753 }
754 }
755
756 // pub fn fixed(&self) -> Size<Rems> {
757 // let mut size = Size::default();
758 // size.width += self.left.fixed().unwrap_or_default();
759 // size.width += self.right.fixed().unwrap_or_default();
760 // size
761 // }
762
763 pub fn flex(&self) -> Vector2F {
764 vec2f(
765 self.left.flex().unwrap_or(0.) + self.right.flex().unwrap_or(0.),
766 self.top.flex().unwrap_or(0.) + self.bottom.flex().unwrap_or(0.),
767 )
768 }
769}
770
771impl Edges<Rems> {
772 pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
773 Edges {
774 top: self.top.to_pixels(rem_size),
775 bottom: self.bottom.to_pixels(rem_size),
776 left: self.left.to_pixels(rem_size),
777 right: self.right.to_pixels(rem_size),
778 }
779 }
780}
781
782impl<L> From<L> for Edges<Length>
783where
784 L: Into<Length>,
785{
786 fn from(uniform: L) -> Self {
787 let uniform = uniform.into();
788 Edges {
789 top: uniform,
790 bottom: uniform,
791 left: uniform,
792 right: uniform,
793 }
794 }
795}
796
797impl<Vertical, Horizontal> From<(Vertical, Horizontal)> for Edges<Length>
798where
799 Vertical: Into<Length>,
800 Horizontal: Into<Length>,
801{
802 fn from((vertical, horizontal): (Vertical, Horizontal)) -> Self {
803 let vertical = vertical.into();
804 let horizontal = horizontal.into();
805 Edges {
806 top: vertical,
807 bottom: vertical,
808 left: horizontal,
809 right: horizontal,
810 }
811 }
812}
813
814impl<Top, Bottom, Left, Right> From<(Top, Bottom, Left, Right)> for Edges<Length>
815where
816 Top: Into<Length>,
817 Bottom: Into<Length>,
818 Left: Into<Length>,
819 Right: Into<Length>,
820{
821 fn from((top, bottom, left, right): (Top, Bottom, Left, Right)) -> Self {
822 Edges {
823 top: top.into(),
824 bottom: bottom.into(),
825 left: left.into(),
826 right: right.into(),
827 }
828 }
829}
830
831#[derive(Clone, Default)]
832struct CornerRadii {
833 top_left: f32,
834 top_right: f32,
835 bottom_right: f32,
836 bottom_left: f32,
837}
838
839#[derive(Clone)]
840pub enum Fill {
841 Color(Color),
842}
843
844impl From<Color> for Fill {
845 fn from(value: Color) -> Self {
846 Fill::Color(value)
847 }
848}
849
850impl Default for Fill {
851 fn default() -> Self {
852 Fill::Color(Color::default())
853 }
854}
855
856#[derive(Clone, Default)]
857struct Borders {
858 color: Color,
859 width: f32,
860 top: bool,
861 bottom: bool,
862 left: bool,
863 right: bool,
864}
865
866impl Borders {
867 fn is_visible(&self) -> bool {
868 self.width > 0.
869 && !self.color.is_fully_transparent()
870 && (self.top || self.bottom || self.left || self.right)
871 }
872
873 fn top_width(&self) -> f32 {
874 if self.top {
875 self.width
876 } else {
877 0.
878 }
879 }
880
881 fn bottom_width(&self) -> f32 {
882 if self.bottom {
883 self.width
884 } else {
885 0.
886 }
887 }
888
889 fn left_width(&self) -> f32 {
890 if self.left {
891 self.width
892 } else {
893 0.
894 }
895 }
896
897 fn right_width(&self) -> f32 {
898 if self.right {
899 self.width
900 } else {
901 0.
902 }
903 }
904
905 fn edges(&self) -> Edges<f32> {
906 let mut edges = Edges::default();
907 if self.width > 0. {
908 if self.top {
909 edges.top = self.width;
910 }
911 if self.bottom {
912 edges.bottom = self.width;
913 }
914 if self.left {
915 edges.left = self.width;
916 }
917 if self.right {
918 edges.right = self.width;
919 }
920 }
921 edges
922 }
923
924 fn size(&self) -> Vector2F {
925 let width =
926 if self.left { self.width } else { 0. } + if self.right { self.width } else { 0. };
927 let height =
928 if self.top { self.width } else { 0. } + if self.bottom { self.width } else { 0. };
929
930 vec2f(width, height)
931 }
932}
933
934pub mod length {
935 use derive_more::{Add, AddAssign, Into};
936
937 #[derive(Add, AddAssign, Into, Clone, Copy, Default, Debug, PartialEq)]
938 pub struct Rems(f32);
939
940 pub fn rems(rems: f32) -> Rems {
941 Rems(rems)
942 }
943
944 impl Rems {
945 pub fn to_pixels(&self, rem_pixels: f32) -> f32 {
946 self.0 * rem_pixels
947 }
948 }
949
950 #[derive(Clone, Copy, Default, Debug)]
951 pub enum Length {
952 #[default]
953 Hug,
954 Fixed(Rems),
955 Auto {
956 flex: f32,
957 min: Rems,
958 max: Rems,
959 },
960 }
961
962 impl From<Rems> for Length {
963 fn from(value: Rems) -> Self {
964 Length::Fixed(value)
965 }
966 }
967
968 pub fn auto() -> Length {
969 flex(1.)
970 }
971
972 pub fn flex(flex: f32) -> Length {
973 Length::Auto {
974 flex,
975 min: Default::default(),
976 max: rems(f32::INFINITY),
977 }
978 }
979
980 pub fn constrained(flex: f32, min: Option<Rems>, max: Option<Rems>) -> Length {
981 Length::Auto {
982 flex,
983 min: min.unwrap_or(Default::default()),
984 max: max.unwrap_or(rems(f32::INFINITY)),
985 }
986 }
987
988 impl Length {
989 pub fn flex_pixels(
990 &self,
991 rem_pixels: f32,
992 remaining_flex: &mut f32,
993 remaining_length: &mut f32,
994 ) -> f32 {
995 match self {
996 Length::Auto { flex, min, max } => {
997 let flex_length = *remaining_length / *remaining_flex;
998 let length = (flex * flex_length)
999 .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels));
1000 *remaining_flex -= flex;
1001 *remaining_length -= length;
1002 length
1003 }
1004 _ => 0.,
1005 }
1006 }
1007
1008 pub fn fixed_pixels(&self, rem: f32) -> f32 {
1009 match self {
1010 Length::Fixed(rems) => rems.to_pixels(rem),
1011 _ => 0.,
1012 }
1013 }
1014
1015 pub fn flex(&self) -> Option<f32> {
1016 match self {
1017 Length::Auto { flex, .. } => Some(*flex),
1018 _ => None,
1019 }
1020 }
1021
1022 pub fn fixed(&self) -> Option<Rems> {
1023 match self {
1024 Length::Fixed(rems) => Some(*rems),
1025 _ => None,
1026 }
1027 }
1028 }
1029}
1030
1031#[derive(Clone)]
1032struct Align(Vector2F);
1033
1034impl Default for Align {
1035 fn default() -> Self {
1036 Self(vec2f(-1., -1.))
1037 }
1038}
1039
1040#[derive(Clone, Copy, Default)]
1041enum Axis3d {
1042 X,
1043 #[default]
1044 Y,
1045 Z,
1046}
1047
1048impl Axis3d {
1049 fn to_2d(self) -> Option<Axis2d> {
1050 match self {
1051 Axis3d::X => Some(Axis2d::X),
1052 Axis3d::Y => Some(Axis2d::Y),
1053 Axis3d::Z => None,
1054 }
1055 }
1056}
1057
1058#[derive(Clone, Copy, Default, PartialEq, Eq, Debug)]
1059pub enum Axis2d {
1060 X,
1061 #[default]
1062 Y,
1063}
1064
1065impl Axis2d {
1066 fn rotate(self) -> Self {
1067 match self {
1068 Axis2d::X => Axis2d::Y,
1069 Axis2d::Y => Axis2d::X,
1070 }
1071 }
1072}
1073
1074#[derive(Clone, Copy, Default)]
1075enum Overflow {
1076 #[default]
1077 Visible,
1078 Hidden,
1079 Auto,
1080}
1081
1082#[derive(Clone, Copy)]
1083enum Gap {
1084 Fixed(f32),
1085 Around,
1086 Between,
1087 Even,
1088}
1089
1090impl Default for Gap {
1091 fn default() -> Self {
1092 Gap::Fixed(0.)
1093 }
1094}
1095
1096#[derive(Clone, Copy, Default)]
1097struct Shadow {
1098 offset: Vector2F,
1099 blur: f32,
1100 color: Color,
1101}
1102
1103#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
1104enum FontStyle {
1105 #[default]
1106 Normal,
1107 Italic,
1108 Oblique,
1109}
1110
1111#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
1112enum FontWeight {
1113 Thin,
1114 ExtraLight,
1115 Light,
1116 #[default]
1117 Normal,
1118 Medium,
1119 Semibold,
1120 Bold,
1121 ExtraBold,
1122 Black,
1123}
1124
1125#[derive(Default)]
1126pub struct Text {
1127 text: Cow<'static, str>,
1128 highlights: Option<Box<[(Range<usize>, HighlightStyle)]>>,
1129 custom_runs: Option<(
1130 Box<[Range<usize>]>,
1131 Box<dyn FnMut(usize, RectF, &mut SceneBuilder, &mut AppContext)>,
1132 )>,
1133}
1134
1135pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
1136 row().child(Text {
1137 text: text.into(),
1138 ..Default::default()
1139 })
1140}
1141
1142#[derive(Default, Debug)]
1143pub struct NodeLayout {
1144 size: Vector2F,
1145 padding: Edges<f32>,
1146 borders: Edges<f32>,
1147 margins: Edges<f32>,
1148}
1149
1150impl<V: View> Element<V> for Text {
1151 type LayoutState = TextLayout;
1152 type PaintState = ();
1153
1154 fn layout(
1155 &mut self,
1156 constraint: SizeConstraint,
1157 _: &mut V,
1158 cx: &mut LayoutContext<V>,
1159 ) -> (Vector2F, Self::LayoutState) {
1160 // Convert the string and highlight ranges into an iterator of highlighted chunks.
1161 let mut offset = 0;
1162 let mut highlight_ranges = self
1163 .highlights
1164 .as_ref()
1165 .map_or(Default::default(), AsRef::as_ref)
1166 .iter()
1167 .peekable();
1168 let chunks = std::iter::from_fn(|| {
1169 let result;
1170 if let Some((range, highlight_style)) = highlight_ranges.peek() {
1171 if offset < range.start {
1172 result = Some((&self.text[offset..range.start], None));
1173 offset = range.start;
1174 } else if range.end <= self.text.len() {
1175 result = Some((&self.text[range.clone()], Some(*highlight_style)));
1176 highlight_ranges.next();
1177 offset = range.end;
1178 } else {
1179 warn!(
1180 "Highlight out of text range. Text len: {}, Highlight range: {}..{}",
1181 self.text.len(),
1182 range.start,
1183 range.end
1184 );
1185 result = None;
1186 }
1187 } else if offset < self.text.len() {
1188 result = Some((&self.text[offset..], None));
1189 offset = self.text.len();
1190 } else {
1191 result = None;
1192 }
1193 result
1194 });
1195
1196 let style = cx.text_style();
1197
1198 // Perform shaping on these highlighted chunks
1199 let shaped_lines = layout_highlighted_chunks(
1200 chunks,
1201 &style,
1202 cx.text_layout_cache(),
1203 &cx.font_cache,
1204 usize::MAX,
1205 self.text.matches('\n').count() + 1,
1206 );
1207
1208 // If line wrapping is enabled, wrap each of the shaped lines.
1209 let font_id = style.font_id;
1210 let mut line_count = 0;
1211 let mut max_line_width = 0_f32;
1212 let mut wrap_boundaries = Vec::new();
1213 let mut wrapper = cx.font_cache.line_wrapper(font_id, style.font_size);
1214 for (line, shaped_line) in self.text.split('\n').zip(&shaped_lines) {
1215 if style.soft_wrap {
1216 let boundaries = wrapper
1217 .wrap_shaped_line(line, shaped_line, constraint.max.x())
1218 .collect::<Vec<_>>();
1219 line_count += boundaries.len() + 1;
1220 wrap_boundaries.push(boundaries);
1221 } else {
1222 line_count += 1;
1223 }
1224 max_line_width = max_line_width.max(shaped_line.width());
1225 }
1226
1227 let line_height = cx.font_cache.line_height(style.font_size);
1228 let size = vec2f(
1229 max_line_width
1230 .ceil()
1231 .max(constraint.min.x())
1232 .min(constraint.max.x()),
1233 (line_height * line_count as f32).ceil(),
1234 );
1235 (
1236 size,
1237 TextLayout {
1238 shaped_lines,
1239 wrap_boundaries,
1240 line_height,
1241 },
1242 )
1243 }
1244
1245 fn paint(
1246 &mut self,
1247 scene: &mut SceneBuilder,
1248 bounds: RectF,
1249 visible_bounds: RectF,
1250 layout: &mut Self::LayoutState,
1251 _: &mut V,
1252 cx: &mut PaintContext<V>,
1253 ) -> Self::PaintState {
1254 dbg!(bounds);
1255
1256 let mut origin = bounds.origin();
1257 let empty = Vec::new();
1258 let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
1259
1260 let mouse_runs;
1261 let custom_run_callback;
1262 if let Some((runs, build_region)) = &mut self.custom_runs {
1263 mouse_runs = runs.iter();
1264 custom_run_callback = build_region.as_mut();
1265 } else {
1266 mouse_runs = [].iter();
1267 custom_run_callback = &mut callback;
1268 }
1269 let mut custom_runs = mouse_runs.enumerate().peekable();
1270
1271 let mut offset = 0;
1272 for (ix, line) in layout.shaped_lines.iter().enumerate() {
1273 let wrap_boundaries = layout.wrap_boundaries.get(ix).unwrap_or(&empty);
1274 let boundaries = RectF::new(
1275 origin,
1276 vec2f(
1277 bounds.width(),
1278 (wrap_boundaries.len() + 1) as f32 * layout.line_height,
1279 ),
1280 );
1281
1282 let style = cx.text_style();
1283 if boundaries.intersects(visible_bounds) {
1284 if style.soft_wrap {
1285 line.paint_wrapped(
1286 scene,
1287 origin,
1288 visible_bounds,
1289 layout.line_height,
1290 wrap_boundaries,
1291 cx,
1292 );
1293 } else {
1294 line.paint(scene, origin, visible_bounds, layout.line_height, cx);
1295 }
1296 }
1297
1298 // Paint any custom runs that intersect this line.
1299 let end_offset = offset + line.len();
1300 if let Some((custom_run_ix, custom_run_range)) = custom_runs.peek().cloned() {
1301 if custom_run_range.start < end_offset {
1302 let mut current_custom_run = None;
1303 if custom_run_range.start <= offset {
1304 current_custom_run = Some((custom_run_ix, custom_run_range.end, origin));
1305 }
1306
1307 let mut glyph_origin = origin;
1308 let mut prev_position = 0.;
1309 let mut wrap_boundaries = wrap_boundaries.iter().copied().peekable();
1310 for (run_ix, glyph_ix, glyph) in
1311 line.runs().iter().enumerate().flat_map(|(run_ix, run)| {
1312 run.glyphs()
1313 .iter()
1314 .enumerate()
1315 .map(move |(ix, glyph)| (run_ix, ix, glyph))
1316 })
1317 {
1318 glyph_origin.set_x(glyph_origin.x() + glyph.position.x() - prev_position);
1319 prev_position = glyph.position.x();
1320
1321 // If we've reached a soft wrap position, move down one line. If there
1322 // is a custom run in-progress, paint it.
1323 if wrap_boundaries
1324 .peek()
1325 .map_or(false, |b| b.run_ix == run_ix && b.glyph_ix == glyph_ix)
1326 {
1327 if let Some((run_ix, _, run_origin)) = &mut current_custom_run {
1328 let bounds = RectF::from_points(
1329 *run_origin,
1330 glyph_origin + vec2f(0., layout.line_height),
1331 );
1332 custom_run_callback(*run_ix, bounds, scene, cx);
1333 *run_origin =
1334 vec2f(origin.x(), glyph_origin.y() + layout.line_height);
1335 }
1336 wrap_boundaries.next();
1337 glyph_origin = vec2f(origin.x(), glyph_origin.y() + layout.line_height);
1338 }
1339
1340 // If we've reached the end of the current custom run, paint it.
1341 if let Some((run_ix, run_end_offset, run_origin)) = current_custom_run {
1342 if offset + glyph.index == run_end_offset {
1343 current_custom_run.take();
1344 let bounds = RectF::from_points(
1345 run_origin,
1346 glyph_origin + vec2f(0., layout.line_height),
1347 );
1348 custom_run_callback(run_ix, bounds, scene, cx);
1349 custom_runs.next();
1350 }
1351
1352 if let Some((_, run_range)) = custom_runs.peek() {
1353 if run_range.start >= end_offset {
1354 break;
1355 }
1356 if run_range.start == offset + glyph.index {
1357 current_custom_run =
1358 Some((run_ix, run_range.end, glyph_origin));
1359 }
1360 }
1361 }
1362
1363 // If we've reached the start of a new custom run, start tracking it.
1364 if let Some((run_ix, run_range)) = custom_runs.peek() {
1365 if offset + glyph.index == run_range.start {
1366 current_custom_run = Some((*run_ix, run_range.end, glyph_origin));
1367 }
1368 }
1369 }
1370
1371 // If a custom run extends beyond the end of the line, paint it.
1372 if let Some((run_ix, run_end_offset, run_origin)) = current_custom_run {
1373 let line_end = glyph_origin + vec2f(line.width() - prev_position, 0.);
1374 let bounds = RectF::from_points(
1375 run_origin,
1376 line_end + vec2f(0., layout.line_height),
1377 );
1378 custom_run_callback(run_ix, bounds, scene, cx);
1379 if end_offset == run_end_offset {
1380 custom_runs.next();
1381 }
1382 }
1383 }
1384 }
1385
1386 offset = end_offset + 1;
1387 origin.set_y(boundaries.max_y());
1388 }
1389 }
1390
1391 fn rect_for_text_range(
1392 &self,
1393 _: Range<usize>,
1394 _: RectF,
1395 _: RectF,
1396 _: &Self::LayoutState,
1397 _: &Self::PaintState,
1398 _: &V,
1399 _: &ViewContext<V>,
1400 ) -> Option<RectF> {
1401 None
1402 }
1403
1404 fn debug(
1405 &self,
1406 bounds: RectF,
1407 _: &Self::LayoutState,
1408 _: &Self::PaintState,
1409 _: &V,
1410 _: &ViewContext<V>,
1411 ) -> Value {
1412 json!({
1413 "type": "Text",
1414 "bounds": bounds.to_json(),
1415 "text": &self.text,
1416 })
1417 }
1418}
1419
1420pub struct TextLayout {
1421 shaped_lines: Vec<Line>,
1422 wrap_boundaries: Vec<Vec<ShapedBoundary>>,
1423 line_height: f32,
1424}
1425
1426trait Vector2FExt {
1427 fn infinity() -> Self;
1428 fn get(self, axis: Axis2d) -> f32;
1429 fn set(&mut self, axis: Axis2d, value: f32);
1430 fn increment_x(&mut self, delta: f32) -> f32;
1431 fn increment_y(&mut self, delta: f32) -> f32;
1432}
1433
1434impl Vector2FExt for Vector2F {
1435 fn infinity() -> Self {
1436 vec2f(f32::INFINITY, f32::INFINITY)
1437 }
1438
1439 fn get(self, axis: Axis2d) -> f32 {
1440 match axis {
1441 Axis2d::X => self.x(),
1442 Axis2d::Y => self.y(),
1443 }
1444 }
1445
1446 fn set(&mut self, axis: Axis2d, value: f32) {
1447 match axis {
1448 Axis2d::X => self.set_x(value),
1449 Axis2d::Y => self.set_y(value),
1450 }
1451 }
1452
1453 fn increment_x(&mut self, delta: f32) -> f32 {
1454 self.set_x(self.x() + delta);
1455 self.x()
1456 }
1457
1458 fn increment_y(&mut self, delta: f32) -> f32 {
1459 self.set_y(self.y() + delta);
1460 self.y()
1461 }
1462}
1463
1464trait ElementExt<V: View> {
1465 fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
1466 where
1467 Self: Element<V> + Sized,
1468 {
1469 node(self).margin_left(margin_left)
1470 }
1471}
1472
1473impl<V, E> ElementExt<V> for E
1474where
1475 V: View,
1476 E: Element<V>,
1477{
1478 fn margin_left(self, margin_left: impl Into<Length>) -> Node<V>
1479 where
1480 Self: Sized,
1481 {
1482 node(self).margin_left(margin_left)
1483 }
1484}