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