node.rs

   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}