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