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_children_xy(
 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(axis, constraint.max, cx.rem_pixels(), &mut layout, view, cx)
 399        } else {
 400            todo!()
 401        };
 402
 403        (size, layout)
 404    }
 405
 406    fn paint(
 407        &mut self,
 408        scene: &mut SceneBuilder,
 409        bounds: RectF,
 410        visible_bounds: RectF,
 411        layout: &mut NodeLayout,
 412        view: &mut V,
 413        cx: &mut PaintContext<V>,
 414    ) -> Self::PaintState {
 415        let rem_pixels = cx.rem_pixels();
 416        let margined_bounds = RectF::from_points(
 417            bounds.origin() + vec2f(layout.margins.left, layout.margins.top),
 418            bounds.lower_right() - vec2f(layout.margins.right, layout.margins.bottom),
 419        );
 420
 421        // Paint drop shadow
 422        for shadow in &self.style.shadows {
 423            scene.push_shadow(scene::Shadow {
 424                bounds: margined_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.
 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: margined_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 borders = &self.style.borders;
 464            let padded_bounds = RectF::from_points(
 465                margined_bounds.origin()
 466                    + vec2f(
 467                        borders.left_width() + layout.padding.left,
 468                        borders.top_width() + layout.padding.top,
 469                    ),
 470                margined_bounds.lower_right()
 471                    - vec2f(
 472                        layout.padding.right + borders.right_width(),
 473                        layout.padding.bottom + borders.bottom_width(),
 474                    ),
 475            );
 476
 477            if let Some(axis) = self.style.axis.to_2d() {
 478                self.paint_children_xy(scene, axis, padded_bounds, visible_bounds, layout, view, cx)
 479            } else {
 480                todo!();
 481            }
 482        }
 483    }
 484
 485    fn rect_for_text_range(
 486        &self,
 487        range_utf16: Range<usize>,
 488        _: RectF,
 489        _: RectF,
 490        _: &Self::LayoutState,
 491        _: &Self::PaintState,
 492        view: &V,
 493        cx: &ViewContext<V>,
 494    ) -> Option<RectF> {
 495        self.children
 496            .iter()
 497            .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
 498    }
 499
 500    fn debug(
 501        &self,
 502        bounds: RectF,
 503        _: &Self::LayoutState,
 504        _: &Self::PaintState,
 505        view: &V,
 506        cx: &ViewContext<V>,
 507    ) -> Value {
 508        json!({
 509            "type": "Node",
 510            "bounds": bounds.to_json(),
 511            // TODO!
 512            // "children": self.content.iter().map(|child| child.debug(view, cx)).collect::<Vec<Value>>()
 513        })
 514    }
 515
 516    fn metadata(&self) -> Option<&dyn Any> {
 517        Some(&self.style)
 518    }
 519}
 520
 521pub struct TopBottom {
 522    top: Length,
 523    bottom: Length,
 524}
 525
 526impl<T: Into<Length>> From<(T, T)> for TopBottom {
 527    fn from((top, bottom): (T, T)) -> Self {
 528        Self {
 529            top: top.into(),
 530            bottom: bottom.into(),
 531        }
 532    }
 533}
 534
 535impl<T: Copy + Into<Length>> From<T> for TopBottom {
 536    fn from(both: T) -> Self {
 537        Self {
 538            top: both.into(),
 539            bottom: both.into(),
 540        }
 541    }
 542}
 543
 544pub struct LeftRight {
 545    left: Length,
 546    right: Length,
 547}
 548
 549impl From<(Length, Length)> for LeftRight {
 550    fn from((left, right): (Length, Length)) -> Self {
 551        Self { left, right }
 552    }
 553}
 554
 555impl From<Length> for LeftRight {
 556    fn from(both: Length) -> Self {
 557        Self {
 558            left: both,
 559            right: both,
 560        }
 561    }
 562}
 563
 564fn align_child(
 565    child_origin: &mut Vector2F,
 566    parent_size: Vector2F,
 567    child_size: Vector2F,
 568    alignment: Vector2F,
 569    horizontal: bool,
 570    vertical: bool,
 571) {
 572    let parent_center = parent_size / 2.;
 573    let parent_target = parent_center + parent_center * alignment;
 574    let child_center = child_size / 2.;
 575    let child_target = child_center + child_center * alignment;
 576
 577    if horizontal {
 578        child_origin.set_x(child_origin.x() + parent_target.x() - child_target.x())
 579    }
 580    if vertical {
 581        child_origin.set_y(child_origin.y() + parent_target.y() - child_target.y());
 582    }
 583}
 584
 585struct Interactive<Style> {
 586    default: Style,
 587    hovered: Style,
 588    active: Style,
 589    disabled: Style,
 590}
 591
 592#[derive(Clone, Default)]
 593pub struct NodeStyle {
 594    axis: Axis3d,
 595    wrap: bool,
 596    align: Align,
 597    overflow_x: Overflow,
 598    overflow_y: Overflow,
 599    gap_x: Gap,
 600    gap_y: Gap,
 601
 602    size: Size<Length>,
 603    margins: Edges<Length>,
 604    padding: Edges<Length>,
 605    text: OptionalTextStyle,
 606    opacity: f32,
 607    fill: Fill,
 608    borders: Borders,
 609    corner_radius: f32,
 610    shadows: Vec<Shadow>,
 611}
 612
 613impl NodeStyle {
 614    fn flex(&self, axis: Axis2d) -> Option<f32> {
 615        let mut sum = None;
 616        match axis {
 617            Axis2d::X => {
 618                sum = optional_add(sum, self.margins.left.flex());
 619                sum = optional_add(sum, self.padding.left.flex());
 620                sum = optional_add(sum, self.size.width.flex());
 621                sum = optional_add(sum, self.padding.right.flex());
 622                sum = optional_add(sum, self.margins.right.flex());
 623            }
 624            Axis2d::Y => {
 625                sum = optional_add(sum, self.margins.top.flex());
 626                sum = optional_add(sum, self.padding.top.flex());
 627                sum = optional_add(sum, self.size.height.flex());
 628                sum = optional_add(sum, self.padding.bottom.flex());
 629                sum = optional_add(sum, self.margins.bottom.flex());
 630            }
 631        }
 632        sum
 633    }
 634}
 635
 636#[optional_struct]
 637struct TextStyle {
 638    size: Rems,
 639    font_family: Arc<str>,
 640    weight: FontWeight,
 641    style: FontStyle,
 642}
 643
 644#[derive(Add, Default, Clone)]
 645struct Size<T> {
 646    width: T,
 647    height: T,
 648}
 649
 650impl<T: Copy> Size<T> {
 651    fn get(&self, axis: Axis2d) -> T {
 652        match axis {
 653            Axis2d::X => self.width,
 654            Axis2d::Y => self.height,
 655        }
 656    }
 657}
 658
 659impl<T: Copy + Add<Output = T>> Size<Option<T>> {
 660    fn add_assign_optional(&mut self, rhs: Size<Option<T>>) {
 661        self.width = optional_add(self.width, rhs.width);
 662        self.height = optional_add(self.height, rhs.height);
 663    }
 664}
 665
 666impl Size<Length> {
 667    pub fn fixed(&self) -> Size<Rems> {
 668        Size {
 669            width: self.width.fixed().unwrap_or_default(),
 670            height: self.height.fixed().unwrap_or_default(),
 671        }
 672    }
 673
 674    pub fn flex(&self) -> Vector2F {
 675        vec2f(
 676            self.width.flex().unwrap_or(0.),
 677            self.height.flex().unwrap_or(0.),
 678        )
 679    }
 680}
 681
 682impl Size<Rems> {
 683    pub fn to_pixels(&self, rem_size: f32) -> Vector2F {
 684        vec2f(
 685            self.width.to_pixels(rem_size),
 686            self.height.to_pixels(rem_size),
 687        )
 688    }
 689}
 690
 691// Sides?
 692#[derive(Clone, Default)]
 693struct Edges<T> {
 694    top: T,
 695    bottom: T,
 696    left: T,
 697    right: T,
 698}
 699
 700impl<T> Edges<T> {
 701    fn start(&self, axis: Axis2d) -> &T {
 702        match axis {
 703            Axis2d::X => &self.left,
 704            Axis2d::Y => &self.top,
 705        }
 706    }
 707
 708    fn start_mut(&mut self, axis: Axis2d) -> &mut T {
 709        match axis {
 710            Axis2d::X => &mut self.left,
 711            Axis2d::Y => &mut self.top,
 712        }
 713    }
 714
 715    fn end(&self, axis: Axis2d) -> &T {
 716        match axis {
 717            Axis2d::X => &self.right,
 718            Axis2d::Y => &self.bottom,
 719        }
 720    }
 721
 722    fn end_mut(&mut self, axis: Axis2d) -> &mut T {
 723        match axis {
 724            Axis2d::X => &mut self.right,
 725            Axis2d::Y => &mut self.bottom,
 726        }
 727    }
 728}
 729
 730impl Edges<f32> {
 731    fn size(&self) -> Vector2F {
 732        vec2f(self.left + self.right, self.top + self.bottom)
 733    }
 734}
 735
 736impl Edges<Length> {
 737    fn fixed_pixels(&self, rem_pixels: f32) -> Edges<f32> {
 738        Edges {
 739            top: self.top.fixed_pixels(rem_pixels),
 740            bottom: self.bottom.fixed_pixels(rem_pixels),
 741            left: self.left.fixed_pixels(rem_pixels),
 742            right: self.right.fixed_pixels(rem_pixels),
 743        }
 744    }
 745
 746    fn flex_pixels(
 747        &self,
 748        rem_pixels: f32,
 749        remaining_flex: &mut f32,
 750        remaining_length: &mut f32,
 751    ) -> Edges<f32> {
 752        Edges {
 753            top: self
 754                .top
 755                .flex_pixels(rem_pixels, remaining_flex, remaining_length),
 756            bottom: self
 757                .bottom
 758                .flex_pixels(rem_pixels, remaining_flex, remaining_length),
 759            left: self
 760                .left
 761                .flex_pixels(rem_pixels, remaining_flex, remaining_length),
 762            right: self
 763                .right
 764                .flex_pixels(rem_pixels, remaining_flex, remaining_length),
 765        }
 766    }
 767
 768    // pub fn fixed(&self) -> Size<Rems> {
 769    //     let mut size = Size::default();
 770    //     size.width += self.left.fixed().unwrap_or_default();
 771    //     size.width += self.right.fixed().unwrap_or_default();
 772    //     size
 773    // }
 774
 775    pub fn flex(&self) -> Vector2F {
 776        vec2f(
 777            self.left.flex().unwrap_or(0.) + self.right.flex().unwrap_or(0.),
 778            self.top.flex().unwrap_or(0.) + self.bottom.flex().unwrap_or(0.),
 779        )
 780    }
 781}
 782
 783impl Edges<Rems> {
 784    pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
 785        Edges {
 786            top: self.top.to_pixels(rem_size),
 787            bottom: self.bottom.to_pixels(rem_size),
 788            left: self.left.to_pixels(rem_size),
 789            right: self.right.to_pixels(rem_size),
 790        }
 791    }
 792}
 793
 794#[derive(Clone, Default)]
 795struct CornerRadii {
 796    top_left: f32,
 797    top_right: f32,
 798    bottom_right: f32,
 799    bottom_left: f32,
 800}
 801
 802#[derive(Clone)]
 803pub enum Fill {
 804    Color(Color),
 805}
 806
 807impl From<Color> for Fill {
 808    fn from(value: Color) -> Self {
 809        Fill::Color(value)
 810    }
 811}
 812
 813impl Default for Fill {
 814    fn default() -> Self {
 815        Fill::Color(Color::default())
 816    }
 817}
 818
 819#[derive(Clone, Default)]
 820struct Borders {
 821    color: Color,
 822    width: f32,
 823    top: bool,
 824    bottom: bool,
 825    left: bool,
 826    right: bool,
 827}
 828
 829impl Borders {
 830    fn is_visible(&self) -> bool {
 831        self.width > 0.
 832            && !self.color.is_fully_transparent()
 833            && (self.top || self.bottom || self.left || self.right)
 834    }
 835
 836    fn top_width(&self) -> f32 {
 837        if self.top {
 838            self.width
 839        } else {
 840            0.
 841        }
 842    }
 843
 844    fn bottom_width(&self) -> f32 {
 845        if self.bottom {
 846            self.width
 847        } else {
 848            0.
 849        }
 850    }
 851
 852    fn left_width(&self) -> f32 {
 853        if self.left {
 854            self.width
 855        } else {
 856            0.
 857        }
 858    }
 859
 860    fn right_width(&self) -> f32 {
 861        if self.right {
 862            self.width
 863        } else {
 864            0.
 865        }
 866    }
 867
 868    fn size(&self) -> Vector2F {
 869        let width =
 870            if self.left { self.width } else { 0. } + if self.right { self.width } else { 0. };
 871        let height =
 872            if self.top { self.width } else { 0. } + if self.bottom { self.width } else { 0. };
 873
 874        vec2f(width, height)
 875    }
 876}
 877
 878pub mod length {
 879    use derive_more::{Add, AddAssign, Into};
 880
 881    #[derive(Add, AddAssign, Into, Clone, Copy, Default, Debug, PartialEq)]
 882    pub struct Rems(f32);
 883
 884    pub fn rems(rems: f32) -> Rems {
 885        Rems(rems)
 886    }
 887
 888    impl Rems {
 889        pub fn to_pixels(&self, rem_pixels: f32) -> f32 {
 890            self.0 * rem_pixels
 891        }
 892    }
 893
 894    #[derive(Clone, Copy, Default, Debug)]
 895    pub enum Length {
 896        #[default]
 897        Hug,
 898        Fixed(Rems),
 899        Auto {
 900            flex: f32,
 901            min: Rems,
 902            max: Rems,
 903        },
 904    }
 905
 906    impl From<Rems> for Length {
 907        fn from(value: Rems) -> Self {
 908            Length::Fixed(value)
 909        }
 910    }
 911
 912    pub fn auto() -> Length {
 913        flex(1.)
 914    }
 915
 916    pub fn flex(flex: f32) -> Length {
 917        Length::Auto {
 918            flex,
 919            min: Default::default(),
 920            max: rems(f32::INFINITY),
 921        }
 922    }
 923
 924    pub fn constrained(flex: f32, min: Option<Rems>, max: Option<Rems>) -> Length {
 925        Length::Auto {
 926            flex,
 927            min: min.unwrap_or(Default::default()),
 928            max: max.unwrap_or(rems(f32::INFINITY)),
 929        }
 930    }
 931
 932    impl Length {
 933        pub fn flex_pixels(
 934            &self,
 935            rem_pixels: f32,
 936            remaining_flex: &mut f32,
 937            remaining_length: &mut f32,
 938        ) -> f32 {
 939            match self {
 940                Length::Auto { flex, min, max } => {
 941                    let flex_length = *remaining_length / *remaining_flex;
 942                    let length = (flex * flex_length)
 943                        .clamp(min.to_pixels(rem_pixels), max.to_pixels(rem_pixels));
 944                    *remaining_flex -= flex;
 945                    *remaining_length -= length;
 946                    length
 947                }
 948                _ => 0.,
 949            }
 950        }
 951
 952        pub fn fixed_pixels(&self, rem: f32) -> f32 {
 953            match self {
 954                Length::Fixed(rems) => rems.to_pixels(rem),
 955                _ => 0.,
 956            }
 957        }
 958
 959        pub fn flex(&self) -> Option<f32> {
 960            match self {
 961                Length::Auto { flex, .. } => Some(*flex),
 962                _ => None,
 963            }
 964        }
 965
 966        pub fn fixed(&self) -> Option<Rems> {
 967            match self {
 968                Length::Fixed(rems) => Some(*rems),
 969                _ => None,
 970            }
 971        }
 972    }
 973}
 974
 975#[derive(Clone)]
 976struct Align(Vector2F);
 977
 978impl Default for Align {
 979    fn default() -> Self {
 980        Self(vec2f(-1., -1.))
 981    }
 982}
 983
 984#[derive(Clone, Copy, Default)]
 985enum Axis3d {
 986    X,
 987    #[default]
 988    Y,
 989    Z,
 990}
 991
 992impl Axis3d {
 993    fn to_2d(self) -> Option<Axis2d> {
 994        match self {
 995            Axis3d::X => Some(Axis2d::X),
 996            Axis3d::Y => Some(Axis2d::Y),
 997            Axis3d::Z => None,
 998        }
 999    }
1000}
1001
1002#[derive(Clone, Copy, Default)]
1003pub enum Axis2d {
1004    X,
1005    #[default]
1006    Y,
1007}
1008
1009impl Axis2d {
1010    fn rotate(self) -> Self {
1011        match self {
1012            Axis2d::X => Axis2d::Y,
1013            Axis2d::Y => Axis2d::X,
1014        }
1015    }
1016}
1017
1018#[derive(Clone, Copy, Default)]
1019enum Overflow {
1020    #[default]
1021    Visible,
1022    Hidden,
1023    Auto,
1024}
1025
1026#[derive(Clone, Copy)]
1027enum Gap {
1028    Fixed(f32),
1029    Around,
1030    Between,
1031    Even,
1032}
1033
1034impl Default for Gap {
1035    fn default() -> Self {
1036        Gap::Fixed(0.)
1037    }
1038}
1039
1040#[derive(Clone, Copy, Default)]
1041struct Shadow {
1042    offset: Vector2F,
1043    blur: f32,
1044    color: Color,
1045}
1046
1047#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
1048enum FontStyle {
1049    #[default]
1050    Normal,
1051    Italic,
1052    Oblique,
1053}
1054
1055#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
1056enum FontWeight {
1057    Thin,
1058    ExtraLight,
1059    Light,
1060    #[default]
1061    Normal,
1062    Medium,
1063    Semibold,
1064    Bold,
1065    ExtraBold,
1066    Black,
1067}
1068
1069#[derive(Default)]
1070pub struct Text {
1071    text: Cow<'static, str>,
1072    highlights: Option<Box<[(Range<usize>, HighlightStyle)]>>,
1073    custom_runs: Option<(
1074        Box<[Range<usize>]>,
1075        Box<dyn FnMut(usize, RectF, &mut SceneBuilder, &mut AppContext)>,
1076    )>,
1077}
1078
1079pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
1080    row().child(Text {
1081        text: text.into(),
1082        ..Default::default()
1083    })
1084}
1085
1086#[derive(Default)]
1087pub struct NodeLayout {
1088    content_size: Vector2F,
1089    margins: Edges<f32>,
1090    padding: Edges<f32>,
1091}
1092
1093impl<V: View> Element<V> for Text {
1094    type LayoutState = TextLayout;
1095    type PaintState = ();
1096
1097    fn layout(
1098        &mut self,
1099        constraint: SizeConstraint,
1100        _: &mut V,
1101        cx: &mut LayoutContext<V>,
1102    ) -> (Vector2F, Self::LayoutState) {
1103        // Convert the string and highlight ranges into an iterator of highlighted chunks.
1104        let mut offset = 0;
1105        let mut highlight_ranges = self
1106            .highlights
1107            .as_ref()
1108            .map_or(Default::default(), AsRef::as_ref)
1109            .iter()
1110            .peekable();
1111        let chunks = std::iter::from_fn(|| {
1112            let result;
1113            if let Some((range, highlight_style)) = highlight_ranges.peek() {
1114                if offset < range.start {
1115                    result = Some((&self.text[offset..range.start], None));
1116                    offset = range.start;
1117                } else if range.end <= self.text.len() {
1118                    result = Some((&self.text[range.clone()], Some(*highlight_style)));
1119                    highlight_ranges.next();
1120                    offset = range.end;
1121                } else {
1122                    warn!(
1123                        "Highlight out of text range. Text len: {}, Highlight range: {}..{}",
1124                        self.text.len(),
1125                        range.start,
1126                        range.end
1127                    );
1128                    result = None;
1129                }
1130            } else if offset < self.text.len() {
1131                result = Some((&self.text[offset..], None));
1132                offset = self.text.len();
1133            } else {
1134                result = None;
1135            }
1136            result
1137        });
1138
1139        let style = cx.text_style();
1140
1141        // Perform shaping on these highlighted chunks
1142        let shaped_lines = layout_highlighted_chunks(
1143            chunks,
1144            &style,
1145            cx.text_layout_cache(),
1146            &cx.font_cache,
1147            usize::MAX,
1148            self.text.matches('\n').count() + 1,
1149        );
1150
1151        // If line wrapping is enabled, wrap each of the shaped lines.
1152        let font_id = style.font_id;
1153        let mut line_count = 0;
1154        let mut max_line_width = 0_f32;
1155        let mut wrap_boundaries = Vec::new();
1156        let mut wrapper = cx.font_cache.line_wrapper(font_id, style.font_size);
1157        for (line, shaped_line) in self.text.split('\n').zip(&shaped_lines) {
1158            if style.soft_wrap {
1159                let boundaries = wrapper
1160                    .wrap_shaped_line(line, shaped_line, constraint.max.x())
1161                    .collect::<Vec<_>>();
1162                line_count += boundaries.len() + 1;
1163                wrap_boundaries.push(boundaries);
1164            } else {
1165                line_count += 1;
1166            }
1167            max_line_width = max_line_width.max(shaped_line.width());
1168        }
1169
1170        let line_height = cx.font_cache.line_height(style.font_size);
1171        let size = vec2f(
1172            max_line_width
1173                .ceil()
1174                .max(constraint.min.x())
1175                .min(constraint.max.x()),
1176            (line_height * line_count as f32).ceil(),
1177        );
1178        (
1179            size,
1180            TextLayout {
1181                shaped_lines,
1182                wrap_boundaries,
1183                line_height,
1184            },
1185        )
1186    }
1187
1188    fn paint(
1189        &mut self,
1190        scene: &mut SceneBuilder,
1191        bounds: RectF,
1192        visible_bounds: RectF,
1193        layout: &mut Self::LayoutState,
1194        _: &mut V,
1195        cx: &mut PaintContext<V>,
1196    ) -> Self::PaintState {
1197        let mut origin = bounds.origin();
1198        let empty = Vec::new();
1199        let mut callback = |_, _, _: &mut SceneBuilder, _: &mut AppContext| {};
1200
1201        let mouse_runs;
1202        let custom_run_callback;
1203        if let Some((runs, build_region)) = &mut self.custom_runs {
1204            mouse_runs = runs.iter();
1205            custom_run_callback = build_region.as_mut();
1206        } else {
1207            mouse_runs = [].iter();
1208            custom_run_callback = &mut callback;
1209        }
1210        let mut custom_runs = mouse_runs.enumerate().peekable();
1211
1212        let mut offset = 0;
1213        for (ix, line) in layout.shaped_lines.iter().enumerate() {
1214            let wrap_boundaries = layout.wrap_boundaries.get(ix).unwrap_or(&empty);
1215            let boundaries = RectF::new(
1216                origin,
1217                vec2f(
1218                    bounds.width(),
1219                    (wrap_boundaries.len() + 1) as f32 * layout.line_height,
1220                ),
1221            );
1222
1223            let style = cx.text_style();
1224            if boundaries.intersects(visible_bounds) {
1225                if style.soft_wrap {
1226                    line.paint_wrapped(
1227                        scene,
1228                        origin,
1229                        visible_bounds,
1230                        layout.line_height,
1231                        wrap_boundaries,
1232                        cx,
1233                    );
1234                } else {
1235                    line.paint(scene, origin, visible_bounds, layout.line_height, cx);
1236                }
1237            }
1238
1239            // Paint any custom runs that intersect this line.
1240            let end_offset = offset + line.len();
1241            if let Some((custom_run_ix, custom_run_range)) = custom_runs.peek().cloned() {
1242                if custom_run_range.start < end_offset {
1243                    let mut current_custom_run = None;
1244                    if custom_run_range.start <= offset {
1245                        current_custom_run = Some((custom_run_ix, custom_run_range.end, origin));
1246                    }
1247
1248                    let mut glyph_origin = origin;
1249                    let mut prev_position = 0.;
1250                    let mut wrap_boundaries = wrap_boundaries.iter().copied().peekable();
1251                    for (run_ix, glyph_ix, glyph) in
1252                        line.runs().iter().enumerate().flat_map(|(run_ix, run)| {
1253                            run.glyphs()
1254                                .iter()
1255                                .enumerate()
1256                                .map(move |(ix, glyph)| (run_ix, ix, glyph))
1257                        })
1258                    {
1259                        glyph_origin.set_x(glyph_origin.x() + glyph.position.x() - prev_position);
1260                        prev_position = glyph.position.x();
1261
1262                        // If we've reached a soft wrap position, move down one line. If there
1263                        // is a custom run in-progress, paint it.
1264                        if wrap_boundaries
1265                            .peek()
1266                            .map_or(false, |b| b.run_ix == run_ix && b.glyph_ix == glyph_ix)
1267                        {
1268                            if let Some((run_ix, _, run_origin)) = &mut current_custom_run {
1269                                let bounds = RectF::from_points(
1270                                    *run_origin,
1271                                    glyph_origin + vec2f(0., layout.line_height),
1272                                );
1273                                custom_run_callback(*run_ix, bounds, scene, cx);
1274                                *run_origin =
1275                                    vec2f(origin.x(), glyph_origin.y() + layout.line_height);
1276                            }
1277                            wrap_boundaries.next();
1278                            glyph_origin = vec2f(origin.x(), glyph_origin.y() + layout.line_height);
1279                        }
1280
1281                        // If we've reached the end of the current custom run, paint it.
1282                        if let Some((run_ix, run_end_offset, run_origin)) = current_custom_run {
1283                            if offset + glyph.index == run_end_offset {
1284                                current_custom_run.take();
1285                                let bounds = RectF::from_points(
1286                                    run_origin,
1287                                    glyph_origin + vec2f(0., layout.line_height),
1288                                );
1289                                custom_run_callback(run_ix, bounds, scene, cx);
1290                                custom_runs.next();
1291                            }
1292
1293                            if let Some((_, run_range)) = custom_runs.peek() {
1294                                if run_range.start >= end_offset {
1295                                    break;
1296                                }
1297                                if run_range.start == offset + glyph.index {
1298                                    current_custom_run =
1299                                        Some((run_ix, run_range.end, glyph_origin));
1300                                }
1301                            }
1302                        }
1303
1304                        // If we've reached the start of a new custom run, start tracking it.
1305                        if let Some((run_ix, run_range)) = custom_runs.peek() {
1306                            if offset + glyph.index == run_range.start {
1307                                current_custom_run = Some((*run_ix, run_range.end, glyph_origin));
1308                            }
1309                        }
1310                    }
1311
1312                    // If a custom run extends beyond the end of the line, paint it.
1313                    if let Some((run_ix, run_end_offset, run_origin)) = current_custom_run {
1314                        let line_end = glyph_origin + vec2f(line.width() - prev_position, 0.);
1315                        let bounds = RectF::from_points(
1316                            run_origin,
1317                            line_end + vec2f(0., layout.line_height),
1318                        );
1319                        custom_run_callback(run_ix, bounds, scene, cx);
1320                        if end_offset == run_end_offset {
1321                            custom_runs.next();
1322                        }
1323                    }
1324                }
1325            }
1326
1327            offset = end_offset + 1;
1328            origin.set_y(boundaries.max_y());
1329        }
1330    }
1331
1332    fn rect_for_text_range(
1333        &self,
1334        _: Range<usize>,
1335        _: RectF,
1336        _: RectF,
1337        _: &Self::LayoutState,
1338        _: &Self::PaintState,
1339        _: &V,
1340        _: &ViewContext<V>,
1341    ) -> Option<RectF> {
1342        None
1343    }
1344
1345    fn debug(
1346        &self,
1347        bounds: RectF,
1348        _: &Self::LayoutState,
1349        _: &Self::PaintState,
1350        _: &V,
1351        _: &ViewContext<V>,
1352    ) -> Value {
1353        json!({
1354            "type": "Text",
1355            "bounds": bounds.to_json(),
1356            "text": &self.text,
1357        })
1358    }
1359}
1360
1361pub struct TextLayout {
1362    shaped_lines: Vec<Line>,
1363    wrap_boundaries: Vec<Vec<ShapedBoundary>>,
1364    line_height: f32,
1365}
1366
1367fn optional_add<T>(a: Option<T>, b: Option<T>) -> Option<T::Output>
1368where
1369    T: Add<Output = T>,
1370{
1371    match (a, b) {
1372        (Some(a), Some(b)) => Some(a + b),
1373        (Some(a), None) => Some(a),
1374        (None, Some(b)) => Some(b),
1375        (None, None) => None,
1376    }
1377}