node.rs

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