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