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