This commit is contained in:
Nathan Sobo 2023-07-26 22:37:59 -06:00
parent c602d98680
commit ab8906551d
3 changed files with 419 additions and 185 deletions

View File

@ -3339,7 +3339,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
self.element_state::<Tag, T>(element_id, T::default())
}
pub fn pixels_per_rem(&self) -> f32 {
pub fn rem_pixels(&self) -> f32 {
16.
}
}

View File

@ -1,5 +1,5 @@
use crate::{
elements::AnyRootElement,
elements::{node::Axis2d, AnyRootElement},
geometry::rect::RectF,
json::ToJson,
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
@ -1248,16 +1248,38 @@ impl Column for Axis {
}
pub trait Vector2FExt {
fn infinity() -> Self;
fn along(self, axis: Axis) -> f32;
fn get(self, axis: Axis2d) -> f32;
fn set(&mut self, axis: Axis2d, value: f32) -> Self;
}
impl Vector2FExt for Vector2F {
fn infinity() -> Self {
Self::new(f32::INFINITY, f32::INFINITY)
}
fn along(self, axis: Axis) -> f32 {
match axis {
Axis::Horizontal => self.x(),
Axis::Vertical => self.y(),
}
}
fn get(self, axis: Axis2d) -> f32 {
match axis {
Axis2d::X => self.x(),
Axis2d::Y => self.y(),
}
}
fn set(&mut self, axis: Axis2d, value: f32) -> Self {
match axis {
Axis2d::X => self.set_x(value),
Axis2d::Y => self.set_y(value),
}
*self
}
}
pub trait RectFExt {
@ -1290,6 +1312,12 @@ impl SizeConstraint {
max: size,
}
}
pub fn loose(max: Vector2F) -> Self {
Self {
min: Vector2F::zero(),
max,
}
}
pub fn strict_along(axis: Axis, max: f32) -> Self {
match axis {

View File

@ -11,17 +11,23 @@ use crate::{
serde_json::Value,
text_layout::{Line, ShapedBoundary},
AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
SizeConstraint, View, ViewContext,
SizeConstraint, Vector2FExt, View, ViewContext,
};
use derive_more::Add;
use length::{Length, Rems};
use log::warn;
use optional_struct::*;
use std::{any::Any, borrow::Cow, f32, ops::Range, sync::Arc};
use std::{
any::Any,
borrow::Cow,
f32,
ops::{Add, Range},
sync::Arc,
};
pub struct Node<V: View> {
style: NodeStyle,
content: Vec<AnyElement<V>>,
children: Vec<AnyElement<V>>,
}
pub fn node<V: View>(child: impl Element<V>) -> Node<V> {
@ -38,7 +44,7 @@ pub fn row<V: View>() -> Node<V> {
axis: Axis3d::X,
..Default::default()
},
content: Default::default(),
children: Default::default(),
}
}
@ -48,7 +54,7 @@ pub fn stack<V: View>() -> Node<V> {
axis: Axis3d::Z,
..Default::default()
},
content: Default::default(),
children: Default::default(),
}
}
@ -56,14 +62,14 @@ impl<V: View> Default for Node<V> {
fn default() -> Self {
Self {
style: Default::default(),
content: Default::default(),
children: Default::default(),
}
}
}
impl<V: View> Node<V> {
pub fn child(mut self, child: impl Element<V>) -> Self {
self.content.push(child.into_any());
self.children.push(child.into_any());
self
}
@ -72,18 +78,18 @@ impl<V: View> Node<V> {
I: IntoIterator<Item = E>,
E: Element<V>,
{
self.content
self.children
.extend(children.into_iter().map(|child| child.into_any()));
self
}
pub fn width(mut self, width: impl Into<Length>) -> Self {
self.style.width = width.into();
self.style.size.width = width.into();
self
}
pub fn height(mut self, height: impl Into<Length>) -> Self {
self.style.height = height.into();
self.style.size.height = height.into();
self
}
@ -104,7 +110,7 @@ impl<V: View> Node<V> {
) -> Self {
let top_bottom = top_bottom.into();
let left_right = left_right.into();
self.style.margin = Edges {
self.style.margins = Edges {
top: top_bottom.top,
bottom: top_bottom.bottom,
left: left_right.left,
@ -114,115 +120,122 @@ impl<V: View> Node<V> {
}
pub fn margin_top(mut self, top: Length) -> Self {
self.style.margin.top = top;
self.style.margins.top = top;
self
}
pub fn margin_bottom(mut self, bottom: Length) -> Self {
self.style.margin.bottom = bottom;
self.style.margins.bottom = bottom;
self
}
pub fn margin_left(mut self, left: impl Into<Length>) -> Self {
self.style.margin.left = left.into();
self.style.margins.left = left.into();
self
}
pub fn margin_right(mut self, right: impl Into<Length>) -> Self {
self.style.margin.right = right.into();
self.style.margins.right = right.into();
self
}
fn layout_2d_children(
fn layout_xy(
&mut self,
axis: Axis2d,
size: Vector2F,
max_size: Vector2F,
rem_length: f32,
computed_margins: &mut Edges<f32>,
computed_padding: &mut Edges<f32>,
view: &mut V,
cx: &mut LayoutContext<V>,
) -> Vector2F {
let mut total_flex: Option<f32> = None;
let mut total_size = 0.0;
let mut cross_axis_max: f32 = 0.0;
*computed_margins = self.style.margins.fixed_pixels(rem_length);
*computed_padding = self.style.padding.fixed_pixels(rem_length);
// First pass: Layout non-flex children only
for child in &mut self.content {
let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
Axis2d::X => style.width.flex(),
Axis2d::Y => style.height.flex(),
});
let padded_max =
max_size - computed_margins.size() - self.style.borders.width - computed_padding.size();
let mut remaining_length = padded_max.get(axis);
if let Some(child_flex) = child_flex {
*total_flex.get_or_insert(0.) += child_flex;
// Pass 1: Total up flex units and layout inflexible children.
//
// Consume the remaining length as we layout inflexible children, so that any
// remaining length can be distributed among flexible children in the next pass.
let mut remaining_flex: f32 = 0.;
let mut cross_axis_max: f32 = 0.;
let cross_axis = axis.rotate();
// Fixed children are unconstrained along the primary axis, and constrained to
// the padded max size along the cross axis.
let mut child_constraint =
SizeConstraint::loose(Vector2F::infinity().set(cross_axis, padded_max.get(cross_axis)));
for child in &mut self.children {
if let Some(child_flex) = child
.metadata::<NodeStyle>()
.and_then(|style| style.flex(axis))
{
remaining_flex += child_flex;
} else {
match axis {
Axis2d::X => {
let child_constraint =
SizeConstraint::new(Vector2F::zero(), vec2f(f32::INFINITY, size.y()));
let child_size = child.layout(child_constraint, view, cx);
cross_axis_max = cross_axis_max.max(child_size.y());
total_size += child_size.x();
}
Axis2d::Y => {
let child_constraint =
SizeConstraint::new(Vector2F::zero(), vec2f(size.x(), f32::INFINITY));
let child_size = child.layout(child_constraint, view, cx);
cross_axis_max = cross_axis_max.max(child_size.x());
total_size += child_size.y();
}
}
let child_size = child.layout(child_constraint, view, cx);
cross_axis_max = cross_axis_max.max(child_size.get(cross_axis));
remaining_length -= child_size.get(axis);
}
}
let remaining_space = match axis {
Axis2d::X => size.x() - total_size,
Axis2d::Y => size.y() - total_size,
};
// Pass 2: Allocate the remaining space among flexible lengths along the primary axis.
if remaining_flex > 0. {
// Add flex pixels from margin and padding.
*computed_margins.start_mut(axis) += self.style.margins.start(axis).flex_pixels(
rem_length,
&mut remaining_flex,
&mut remaining_length,
);
*computed_padding.start_mut(axis) += self.style.padding.start(axis).flex_pixels(
rem_length,
&mut remaining_flex,
&mut remaining_length,
);
// Second pass: Layout flexible children
if let Some(total_flex) = total_flex {
if total_flex > 0. {
let space_per_flex = remaining_space.max(0.) / total_flex;
// Lay out the flexible children
let mut child_max = padded_max;
for child in &mut self.children {
if let Some(child_flex) = child
.metadata::<NodeStyle>()
.and_then(|style| style.flex(axis))
{
child_max.set(axis, child_flex / remaining_flex * remaining_length);
let child_size = child.layout(SizeConstraint::loose(child_max), view, cx);
for child in &mut self.content {
let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
Axis2d::X => style.width.flex(),
Axis2d::Y => style.height.flex(),
});
if let Some(child_flex) = child_flex {
let child_max = space_per_flex * child_flex;
let mut child_constraint = SizeConstraint::new(Vector2F::zero(), size);
match axis {
Axis2d::X => {
child_constraint.min.set_x(0.0);
child_constraint.max.set_x(child_max);
}
Axis2d::Y => {
child_constraint.min.set_y(0.0);
child_constraint.max.set_y(child_max);
}
}
let child_size = child.layout(child_constraint, view, cx);
cross_axis_max = match axis {
Axis2d::X => {
total_size += child_size.x();
cross_axis_max.max(child_size.y())
}
Axis2d::Y => {
total_size += child_size.y();
cross_axis_max.max(child_size.x())
}
};
}
remaining_flex -= child_flex;
remaining_length -= child_size.get(axis);
cross_axis_max = child_size.get(cross_axis).max(cross_axis_max);
}
}
// Add flex pixels from margin and padding.
*computed_margins.end_mut(axis) += self.style.margins.end(axis).flex_pixels(
rem_length,
&mut remaining_flex,
&mut remaining_length,
);
*computed_padding.end_mut(axis) += self.style.padding.end(axis).flex_pixels(
rem_length,
&mut remaining_flex,
&mut remaining_length,
);
}
let size = match axis {
Axis2d::X => vec2f(total_size, cross_axis_max),
Axis2d::Y => vec2f(cross_axis_max, total_size),
let width = match self.style.size.width {
Length::Hug => todo!(),
Length::Fixed(_) => todo!(),
Length::Auto { flex, min, max } => todo!(),
};
size
let length = max_size.get(axis) - remaining_length;
match axis {
Axis2d::X => vec2f(length, cross_axis_max),
Axis2d::Y => vec2f(cross_axis_max, length),
}
}
fn paint_2d_children(
@ -231,7 +244,7 @@ impl<V: View> Node<V> {
axis: Axis2d,
bounds: RectF,
visible_bounds: RectF,
size_of_children: &mut Vector2F,
layout: &mut NodeLayout,
view: &mut V,
cx: &mut ViewContext<V>,
) {
@ -248,13 +261,13 @@ impl<V: View> Node<V> {
align_child(
&mut child_origin,
parent_size,
*size_of_children,
layout.content_size,
self.style.align.0,
align_horizontally,
align_vertically,
);
for child in &mut self.content {
for child in &mut self.children {
// Align each child along the cross axis
align_horizontally = !align_horizontally;
align_vertically = !align_vertically;
@ -295,16 +308,13 @@ impl<V: View> Node<V> {
// }
fn inset_size(&self, rem_size: f32) -> Vector2F {
self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size)
todo!()
// self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size)
}
fn margin_size(&self, rem_size: f32) -> Vector2F {
// We need to account for auto margins
todo!()
// vec2f(
// (self.style.margin.left + self.style.margin.right).to_pixels(rem_size),
// (self.style.margin.top + self.style.margin.bottom).to_pixels(rem_size),
// )
//
fn margin_fixed_size(&self, rem_size: f32) -> Vector2F {
self.style.margins.fixed().to_pixels(rem_size)
}
fn padding_size(&self, rem_size: f32) -> Vector2F {
@ -318,19 +328,19 @@ impl<V: View> Node<V> {
fn border_size(&self) -> Vector2F {
let mut x = 0.0;
if self.style.border.left {
x += self.style.border.width;
if self.style.borders.left {
x += self.style.borders.width;
}
if self.style.border.right {
x += self.style.border.width;
if self.style.borders.right {
x += self.style.borders.width;
}
let mut y = 0.0;
if self.style.border.top {
y += self.style.border.width;
if self.style.borders.top {
y += self.style.borders.width;
}
if self.style.border.bottom {
y += self.style.border.width;
if self.style.borders.bottom {
y += self.style.borders.width;
}
vec2f(x, y)
@ -338,7 +348,7 @@ impl<V: View> Node<V> {
}
impl<V: View> Element<V> for Node<V> {
type LayoutState = Vector2F; // Content size
type LayoutState = NodeLayout;
type PaintState = ();
fn layout(
@ -347,48 +357,23 @@ impl<V: View> Element<V> for Node<V> {
view: &mut V,
cx: &mut LayoutContext<V>,
) -> (Vector2F, Self::LayoutState) {
let mut size = Vector2F::zero();
let rem_size = cx.pixels_per_rem();
let margin_size = self.margin_size(rem_size);
match self.style.width {
Length::Hug => size.set_x(f32::INFINITY),
Length::Fixed(width) => size.set_x(width.to_pixels(rem_size) + margin_size.x()),
Length::Auto { min, max, .. } => size.set_x(constraint.max.x().max(min).min(max)),
}
match self.style.height {
Length::Hug => size.set_y(f32::INFINITY),
Length::Fixed(height) => size.set_y(height.to_pixels(rem_size) + margin_size.y()),
Length::Auto { min, max, .. } => size.set_y(constraint.max.y().max(min).min(max)),
}
let mut layout = NodeLayout::default();
// Impose horizontal constraints
if constraint.min.x().is_finite() {
size.set_x(size.x().max(constraint.min.x()));
}
size.set_x(size.x().min(constraint.max.x()));
// Impose vertical constraints
if constraint.min.y().is_finite() {
size.set_y(size.y().max(constraint.min.y()));
}
size.set_y(size.y().min(constraint.max.y()));
let inset_size = self.inset_size(rem_size);
let inner_size = size - inset_size;
let size_of_children = match self.style.axis {
Axis3d::X => self.layout_2d_children(Axis2d::X, inner_size, view, cx),
Axis3d::Y => self.layout_2d_children(Axis2d::Y, inner_size, view, cx),
Axis3d::Z => todo!(), // self.layout_stacked_children(inner_constraint, view, cx),
let size = if let Some(axis) = self.style.axis.to_2d() {
self.layout_xy(
axis,
constraint.max,
cx.rem_pixels(),
&mut layout.margins,
&mut layout.padding,
view,
cx,
)
} else {
todo!()
};
if matches!(self.style.width, Length::Hug) {
size.set_x(size_of_children.x() + inset_size.x());
}
if matches!(self.style.height, Length::Hug) {
size.set_y(size_of_children.y() + inset_size.y());
}
(size, size_of_children)
(size, layout);
}
fn paint(
@ -396,15 +381,39 @@ impl<V: View> Element<V> for Node<V> {
scene: &mut SceneBuilder,
bounds: RectF,
visible_bounds: RectF,
size_of_children: &mut Vector2F,
layout: &mut NodeLayout,
view: &mut V,
cx: &mut PaintContext<V>,
) -> Self::PaintState {
let rem_size = cx.pixels_per_rem();
let margin: Edges<f32> = todo!(); // &self.style.margin.to_pixels(rem_size);
let rem_pixels = cx.rem_pixels();
// let margin: Edges<f32> = todo!(); // &self.style.margin.to_pixels(rem_size);
//
let size = bounds.size();
let mut remaining_flex = layout.flex_size;
let mut fixed_size = layout.fixed_size;
// let margin_left = self.style.margin.left.to_pixels(rem_pixels, size.x() - fixed_size.x() / layout.);
// fixed_size +=
// let mut origin = bounds.origin();
// origin.set_x(
// origin.x()
// ,
// Length::Hug => 0.,
// Length::Fixed(rems) => rems.to_pixels(rem_pixels),
// Length::Auto { flex, min, max } => {
// flex * (size.x() - fixed_size.x()) / layout.flex_size.x()
// }
// },
// );
let mut low_right = bounds.lower_right();
let mut remaining_fixed = bounds.size() - layout.fixed_size;
let mut remaining_flex = layout.flex_size;
// Account for margins
let content_bounds = RectF::from_points(
let margin_bounds = RectF::from_points(
bounds.origin() + vec2f(margin.left, margin.top),
bounds.lower_right() - vec2f(margin.right, margin.bottom),
);
@ -412,7 +421,7 @@ impl<V: View> Element<V> for Node<V> {
// Paint drop shadow
for shadow in &self.style.shadows {
scene.push_shadow(scene::Shadow {
bounds: content_bounds + shadow.offset,
bounds: margin_bounds + shadow.offset,
corner_radius: self.style.corner_radius,
sigma: shadow.blur,
color: shadow.color,
@ -432,29 +441,29 @@ impl<V: View> Element<V> for Node<V> {
// Render the background and/or the border (if it not an overlay border).
let Fill::Color(fill_color) = self.style.fill;
let is_fill_visible = !fill_color.is_fully_transparent();
if is_fill_visible || self.style.border.is_visible() {
if is_fill_visible || self.style.borders.is_visible() {
scene.push_quad(Quad {
bounds: content_bounds,
bounds: margin_bounds,
background: is_fill_visible.then_some(fill_color),
border: scene::Border {
width: self.style.border.width,
color: self.style.border.color,
width: self.style.borders.width,
color: self.style.borders.color,
overlay: false,
top: self.style.border.top,
right: self.style.border.right,
bottom: self.style.border.bottom,
left: self.style.border.left,
top: self.style.borders.top,
right: self.style.borders.right,
bottom: self.style.borders.bottom,
left: self.style.borders.left,
},
corner_radius: self.style.corner_radius,
});
}
if !self.content.is_empty() {
if !self.children.is_empty() {
// Account for padding first.
let padding: Edges<f32> = todo!(); // &self.style.padding.to_pixels(rem_size);
let padded_bounds = RectF::from_points(
content_bounds.origin() + vec2f(padding.left, padding.top),
content_bounds.lower_right() - vec2f(padding.right, padding.top),
margin_bounds.origin() + vec2f(padding.left, padding.top),
margin_bounds.lower_right() - vec2f(padding.right, padding.top),
);
match self.style.axis {
@ -463,7 +472,7 @@ impl<V: View> Element<V> for Node<V> {
Axis2d::X,
padded_bounds,
visible_bounds,
size_of_children,
layout,
view,
cx,
),
@ -472,7 +481,7 @@ impl<V: View> Element<V> for Node<V> {
Axis2d::Y,
padded_bounds,
visible_bounds,
size_of_children,
layout,
view,
cx,
),
@ -491,7 +500,7 @@ impl<V: View> Element<V> for Node<V> {
view: &V,
cx: &ViewContext<V>,
) -> Option<RectF> {
self.content
self.children
.iter()
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
}
@ -598,18 +607,40 @@ pub struct NodeStyle {
gap_x: Gap,
gap_y: Gap,
width: Length,
height: Length,
margin: Edges<Length>,
size: Size<Length>,
margins: Edges<Length>,
padding: Edges<Length>,
text: OptionalTextStyle,
opacity: f32,
fill: Fill,
border: Border,
borders: Border,
corner_radius: f32, // corner radius matches swift!
shadows: Vec<Shadow>,
}
impl NodeStyle {
fn flex(&self, axis: Axis2d) -> Option<f32> {
let mut sum = None;
match axis {
Axis2d::X => {
sum = optional_add(sum, self.margins.left.flex());
sum = optional_add(sum, self.padding.left.flex());
sum = optional_add(sum, self.size.width.flex());
sum = optional_add(sum, self.padding.right.flex());
sum = optional_add(sum, self.margins.right.flex());
}
Axis2d::Y => {
sum = optional_add(sum, self.margins.top.flex());
sum = optional_add(sum, self.padding.top.flex());
sum = optional_add(sum, self.size.height.flex());
sum = optional_add(sum, self.padding.bottom.flex());
sum = optional_add(sum, self.margins.bottom.flex());
}
}
sum
}
}
#[optional_struct]
struct TextStyle {
size: Rems,
@ -618,12 +649,44 @@ struct TextStyle {
style: FontStyle,
}
#[derive(Add)]
#[derive(Add, Default, Clone)]
struct Size<T> {
width: T,
height: T,
}
impl<T: Add<Output = T>> Size<Option<T>> {
fn add_assign_optional(&mut self, rhs: Size<Option<T>>) {
self.width = optional_add(self.width, rhs.width);
self.height = optional_add(self.height, rhs.height);
}
}
impl Size<Length> {
pub fn fixed(&self) -> Size<Rems> {
Size {
width: self.width.fixed().unwrap_or_default(),
height: self.height.fixed().unwrap_or_default(),
}
}
pub fn flex(&self) -> Vector2F {
vec2f(
self.width.flex().unwrap_or(0.),
self.height.flex().unwrap_or(0.),
)
}
}
impl Size<Rems> {
pub fn to_pixels(&self, rem_size: f32) -> Vector2F {
vec2f(
self.width.to_pixels(rem_size),
self.height.to_pixels(rem_size),
)
}
}
// Sides?
#[derive(Clone, Default)]
struct Edges<T> {
@ -633,6 +696,89 @@ struct Edges<T> {
right: T,
}
impl<T> Edges<T> {
fn start(&self, axis: Axis2d) -> &T {
match axis {
Axis2d::X => &self.left,
Axis2d::Y => &self.top,
}
}
fn start_mut(&mut self, axis: Axis2d) -> &mut T {
match axis {
Axis2d::X => &mut self.left,
Axis2d::Y => &mut self.top,
}
}
fn end(&self, axis: Axis2d) -> &T {
match axis {
Axis2d::X => &self.right,
Axis2d::Y => &self.bottom,
}
}
fn end_mut(&mut self, axis: Axis2d) -> &mut T {
match axis {
Axis2d::X => &mut self.right,
Axis2d::Y => &mut self.bottom,
}
}
}
impl Edges<f32> {
fn size(&self) -> Vector2F {
vec2f(self.left + self.right, self.top + self.bottom)
}
}
impl Edges<Length> {
fn fixed_pixels(&self, rem_length: f32) -> Edges<f32> {
Edges {
top: self.top.fixed_pixels(rem_length),
bottom: self.bottom.fixed_pixels(rem_length),
left: self.left.fixed_pixels(rem_length),
right: self.right.fixed_pixels(rem_length),
}
}
fn flex_pixels(
&self,
rem_length: f32,
remaining_flex: &mut f32,
remaining_length: &mut f32,
) -> Edges<f32> {
Edges {
top: self
.top
.flex_pixels(rem_length, remaining_flex, remaining_length),
bottom: self
.bottom
.flex_pixels(rem_length, remaining_flex, remaining_length),
left: self
.left
.flex_pixels(rem_length, remaining_flex, remaining_length),
right: self
.right
.flex_pixels(rem_length, remaining_flex, remaining_length),
}
}
// pub fn fixed(&self) -> Size<Rems> {
// let mut size = Size::default();
// size.width += self.left.fixed().unwrap_or_default();
// size.width += self.right.fixed().unwrap_or_default();
// size
// }
pub fn flex(&self) -> Vector2F {
vec2f(
self.left.flex().unwrap_or(0.) + self.right.flex().unwrap_or(0.),
self.top.flex().unwrap_or(0.) + self.bottom.flex().unwrap_or(0.),
)
}
}
impl Edges<Rems> {
pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
Edges {
@ -688,9 +834,9 @@ impl Border {
}
pub mod length {
use derive_more::{Add, Into};
use derive_more::{Add, AddAssign, Into};
#[derive(Add, Into, Clone, Copy, Default, Debug, PartialEq)]
#[derive(Add, AddAssign, Into, Clone, Copy, Default, Debug, PartialEq)]
pub struct Rems(f32);
pub fn rems(rems: f32) -> Rems {
@ -698,8 +844,8 @@ pub mod length {
}
impl Rems {
pub fn to_pixels(&self, root_font_size: f32) -> f32 {
self.0 * root_font_size
pub fn to_pixels(&self, rem_length: f32) -> f32 {
self.0 * rem_length
}
}
@ -710,8 +856,8 @@ pub mod length {
Fixed(Rems),
Auto {
flex: f32,
min: f32,
max: f32,
min: Rems,
max: Rems,
},
}
@ -728,26 +874,59 @@ pub mod length {
pub fn flex(flex: f32) -> Length {
Length::Auto {
flex,
min: 0.,
max: f32::INFINITY,
min: Default::default(),
max: rems(f32::INFINITY),
}
}
pub fn constrained(flex: f32, min: Option<f32>, max: Option<f32>) -> Length {
pub fn constrained(flex: f32, min: Option<Rems>, max: Option<Rems>) -> Length {
Length::Auto {
flex,
min: min.unwrap_or(0.),
max: max.unwrap_or(f32::INFINITY),
min: min.unwrap_or(Default::default()),
max: max.unwrap_or(rems(f32::INFINITY)),
}
}
impl Length {
pub fn flex_pixels(
&self,
rem_length: f32,
remaining_flex: &mut f32,
remaining_length: &mut f32,
) -> f32 {
match self {
Length::Auto { flex, min, max } => {
let flex_length = *remaining_length / *remaining_flex;
let length = (flex * flex_length)
.clamp(min.to_pixels(rem_length), max.to_pixels(rem_length));
*remaining_flex -= flex;
*remaining_length -= length;
length
}
_ => 0.,
}
}
pub fn fixed_pixels(&self, rem: f32) -> f32 {
match self {
Length::Fixed(rems) => rems.to_pixels(rem),
_ => 0.,
}
}
pub fn flex(&self) -> Option<f32> {
match self {
Length::Auto { flex, .. } => Some(*flex),
_ => None,
}
}
pub fn fixed(&self) -> Option<Rems> {
match self {
Length::Fixed(rems) => Some(*rems),
_ => None,
}
}
}
}
@ -779,12 +958,21 @@ impl Axis3d {
}
#[derive(Clone, Copy, Default)]
enum Axis2d {
pub enum Axis2d {
X,
#[default]
Y,
}
impl Axis2d {
fn rotate(self) -> Self {
match self {
Axis2d::X => Axis2d::Y,
Axis2d::Y => Axis2d::X,
}
}
}
#[derive(Clone, Copy, Default)]
enum Overflow {
#[default]
@ -853,6 +1041,13 @@ pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
})
}
#[derive(Default)]
struct NodeLayout {
content_size: Vector2F,
margins: Edges<f32>,
padding: Edges<f32>,
}
impl<V: View> Element<V> for Text {
type LayoutState = TextLayout;
type PaintState = ();
@ -864,7 +1059,6 @@ impl<V: View> Element<V> for Text {
cx: &mut LayoutContext<V>,
) -> (Vector2F, Self::LayoutState) {
// Convert the string and highlight ranges into an iterator of highlighted chunks.
let mut offset = 0;
let mut highlight_ranges = self
.highlights
@ -1127,3 +1321,15 @@ pub struct TextLayout {
wrap_boundaries: Vec<Vec<ShapedBoundary>>,
line_height: f32,
}
fn optional_add<T>(a: Option<T>, b: Option<T>) -> Option<T::Output>
where
T: Add<Output = T>,
{
match (a, b) {
(Some(a), Some(b)) => Some(a + b),
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(None, None) => None,
}
}