WIP
This commit is contained in:
parent
c602d98680
commit
ab8906551d
3 changed files with 419 additions and 185 deletions
|
@ -3339,7 +3339,7 @@ impl<'a, 'b, V: View> ViewContext<'a, 'b, V> {
|
||||||
self.element_state::<Tag, T>(element_id, T::default())
|
self.element_state::<Tag, T>(element_id, T::default())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pixels_per_rem(&self) -> f32 {
|
pub fn rem_pixels(&self) -> f32 {
|
||||||
16.
|
16.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
elements::AnyRootElement,
|
elements::{node::Axis2d, AnyRootElement},
|
||||||
geometry::rect::RectF,
|
geometry::rect::RectF,
|
||||||
json::ToJson,
|
json::ToJson,
|
||||||
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
|
keymap_matcher::{Binding, KeymapContext, Keystroke, MatchResult},
|
||||||
|
@ -1248,16 +1248,38 @@ impl Column for Axis {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Vector2FExt {
|
pub trait Vector2FExt {
|
||||||
|
fn infinity() -> Self;
|
||||||
fn along(self, axis: Axis) -> f32;
|
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 {
|
impl Vector2FExt for Vector2F {
|
||||||
|
fn infinity() -> Self {
|
||||||
|
Self::new(f32::INFINITY, f32::INFINITY)
|
||||||
|
}
|
||||||
|
|
||||||
fn along(self, axis: Axis) -> f32 {
|
fn along(self, axis: Axis) -> f32 {
|
||||||
match axis {
|
match axis {
|
||||||
Axis::Horizontal => self.x(),
|
Axis::Horizontal => self.x(),
|
||||||
Axis::Vertical => self.y(),
|
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 {
|
pub trait RectFExt {
|
||||||
|
@ -1290,6 +1312,12 @@ impl SizeConstraint {
|
||||||
max: size,
|
max: size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn loose(max: Vector2F) -> Self {
|
||||||
|
Self {
|
||||||
|
min: Vector2F::zero(),
|
||||||
|
max,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn strict_along(axis: Axis, max: f32) -> Self {
|
pub fn strict_along(axis: Axis, max: f32) -> Self {
|
||||||
match axis {
|
match axis {
|
||||||
|
|
|
@ -11,17 +11,23 @@ use crate::{
|
||||||
serde_json::Value,
|
serde_json::Value,
|
||||||
text_layout::{Line, ShapedBoundary},
|
text_layout::{Line, ShapedBoundary},
|
||||||
AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
|
AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
|
||||||
SizeConstraint, View, ViewContext,
|
SizeConstraint, Vector2FExt, View, ViewContext,
|
||||||
};
|
};
|
||||||
use derive_more::Add;
|
use derive_more::Add;
|
||||||
use length::{Length, Rems};
|
use length::{Length, Rems};
|
||||||
use log::warn;
|
use log::warn;
|
||||||
use optional_struct::*;
|
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> {
|
pub struct Node<V: View> {
|
||||||
style: NodeStyle,
|
style: NodeStyle,
|
||||||
content: Vec<AnyElement<V>>,
|
children: Vec<AnyElement<V>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn node<V: View>(child: impl Element<V>) -> Node<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,
|
axis: Axis3d::X,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
content: Default::default(),
|
children: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +54,7 @@ pub fn stack<V: View>() -> Node<V> {
|
||||||
axis: Axis3d::Z,
|
axis: Axis3d::Z,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
content: Default::default(),
|
children: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,14 +62,14 @@ impl<V: View> Default for Node<V> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
style: Default::default(),
|
style: Default::default(),
|
||||||
content: Default::default(),
|
children: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View> Node<V> {
|
impl<V: View> Node<V> {
|
||||||
pub fn child(mut self, child: impl Element<V>) -> Self {
|
pub fn child(mut self, child: impl Element<V>) -> Self {
|
||||||
self.content.push(child.into_any());
|
self.children.push(child.into_any());
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,18 +78,18 @@ impl<V: View> Node<V> {
|
||||||
I: IntoIterator<Item = E>,
|
I: IntoIterator<Item = E>,
|
||||||
E: Element<V>,
|
E: Element<V>,
|
||||||
{
|
{
|
||||||
self.content
|
self.children
|
||||||
.extend(children.into_iter().map(|child| child.into_any()));
|
.extend(children.into_iter().map(|child| child.into_any()));
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn width(mut self, width: impl Into<Length>) -> Self {
|
pub fn width(mut self, width: impl Into<Length>) -> Self {
|
||||||
self.style.width = width.into();
|
self.style.size.width = width.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn height(mut self, height: impl Into<Length>) -> Self {
|
pub fn height(mut self, height: impl Into<Length>) -> Self {
|
||||||
self.style.height = height.into();
|
self.style.size.height = height.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,7 +110,7 @@ impl<V: View> Node<V> {
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let top_bottom = top_bottom.into();
|
let top_bottom = top_bottom.into();
|
||||||
let left_right = left_right.into();
|
let left_right = left_right.into();
|
||||||
self.style.margin = Edges {
|
self.style.margins = Edges {
|
||||||
top: top_bottom.top,
|
top: top_bottom.top,
|
||||||
bottom: top_bottom.bottom,
|
bottom: top_bottom.bottom,
|
||||||
left: left_right.left,
|
left: left_right.left,
|
||||||
|
@ -114,115 +120,122 @@ impl<V: View> Node<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn margin_top(mut self, top: Length) -> Self {
|
pub fn margin_top(mut self, top: Length) -> Self {
|
||||||
self.style.margin.top = top;
|
self.style.margins.top = top;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn margin_bottom(mut self, bottom: Length) -> Self {
|
pub fn margin_bottom(mut self, bottom: Length) -> Self {
|
||||||
self.style.margin.bottom = bottom;
|
self.style.margins.bottom = bottom;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn margin_left(mut self, left: impl Into<Length>) -> 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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn margin_right(mut self, right: impl Into<Length>) -> 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
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout_2d_children(
|
fn layout_xy(
|
||||||
&mut self,
|
&mut self,
|
||||||
axis: Axis2d,
|
axis: Axis2d,
|
||||||
size: Vector2F,
|
max_size: Vector2F,
|
||||||
|
rem_length: f32,
|
||||||
|
computed_margins: &mut Edges<f32>,
|
||||||
|
computed_padding: &mut Edges<f32>,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut LayoutContext<V>,
|
cx: &mut LayoutContext<V>,
|
||||||
) -> Vector2F {
|
) -> Vector2F {
|
||||||
let mut total_flex: Option<f32> = None;
|
*computed_margins = self.style.margins.fixed_pixels(rem_length);
|
||||||
let mut total_size = 0.0;
|
*computed_padding = self.style.padding.fixed_pixels(rem_length);
|
||||||
let mut cross_axis_max: f32 = 0.0;
|
|
||||||
|
|
||||||
// First pass: Layout non-flex children only
|
let padded_max =
|
||||||
for child in &mut self.content {
|
max_size - computed_margins.size() - self.style.borders.width - computed_padding.size();
|
||||||
let child_flex = child.metadata::<NodeStyle>().and_then(|style| match axis {
|
let mut remaining_length = padded_max.get(axis);
|
||||||
Axis2d::X => style.width.flex(),
|
|
||||||
Axis2d::Y => style.height.flex(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if let Some(child_flex) = child_flex {
|
// Pass 1: Total up flex units and layout inflexible children.
|
||||||
*total_flex.get_or_insert(0.) += child_flex;
|
//
|
||||||
|
// 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 {
|
} else {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
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 width = match self.style.size.width {
|
||||||
|
Length::Hug => todo!(),
|
||||||
|
Length::Fixed(_) => todo!(),
|
||||||
|
Length::Auto { flex, min, max } => todo!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let length = max_size.get(axis) - remaining_length;
|
||||||
match axis {
|
match axis {
|
||||||
Axis2d::X => {
|
Axis2d::X => vec2f(length, cross_axis_max),
|
||||||
let child_constraint =
|
Axis2d::Y => vec2f(cross_axis_max, length),
|
||||||
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 remaining_space = match axis {
|
|
||||||
Axis2d::X => size.x() - total_size,
|
|
||||||
Axis2d::Y => size.y() - total_size,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
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())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let size = match axis {
|
|
||||||
Axis2d::X => vec2f(total_size, cross_axis_max),
|
|
||||||
Axis2d::Y => vec2f(cross_axis_max, total_size),
|
|
||||||
};
|
|
||||||
size
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint_2d_children(
|
fn paint_2d_children(
|
||||||
|
@ -231,7 +244,7 @@ impl<V: View> Node<V> {
|
||||||
axis: Axis2d,
|
axis: Axis2d,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
visible_bounds: RectF,
|
visible_bounds: RectF,
|
||||||
size_of_children: &mut Vector2F,
|
layout: &mut NodeLayout,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut ViewContext<V>,
|
cx: &mut ViewContext<V>,
|
||||||
) {
|
) {
|
||||||
|
@ -248,13 +261,13 @@ impl<V: View> Node<V> {
|
||||||
align_child(
|
align_child(
|
||||||
&mut child_origin,
|
&mut child_origin,
|
||||||
parent_size,
|
parent_size,
|
||||||
*size_of_children,
|
layout.content_size,
|
||||||
self.style.align.0,
|
self.style.align.0,
|
||||||
align_horizontally,
|
align_horizontally,
|
||||||
align_vertically,
|
align_vertically,
|
||||||
);
|
);
|
||||||
|
|
||||||
for child in &mut self.content {
|
for child in &mut self.children {
|
||||||
// Align each child along the cross axis
|
// Align each child along the cross axis
|
||||||
align_horizontally = !align_horizontally;
|
align_horizontally = !align_horizontally;
|
||||||
align_vertically = !align_vertically;
|
align_vertically = !align_vertically;
|
||||||
|
@ -295,16 +308,13 @@ impl<V: View> Node<V> {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
fn inset_size(&self, rem_size: f32) -> Vector2F {
|
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
|
fn margin_fixed_size(&self, rem_size: f32) -> Vector2F {
|
||||||
todo!()
|
self.style.margins.fixed().to_pixels(rem_size)
|
||||||
// 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 padding_size(&self, rem_size: f32) -> Vector2F {
|
fn padding_size(&self, rem_size: f32) -> Vector2F {
|
||||||
|
@ -318,19 +328,19 @@ impl<V: View> Node<V> {
|
||||||
|
|
||||||
fn border_size(&self) -> Vector2F {
|
fn border_size(&self) -> Vector2F {
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
if self.style.border.left {
|
if self.style.borders.left {
|
||||||
x += self.style.border.width;
|
x += self.style.borders.width;
|
||||||
}
|
}
|
||||||
if self.style.border.right {
|
if self.style.borders.right {
|
||||||
x += self.style.border.width;
|
x += self.style.borders.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut y = 0.0;
|
let mut y = 0.0;
|
||||||
if self.style.border.top {
|
if self.style.borders.top {
|
||||||
y += self.style.border.width;
|
y += self.style.borders.width;
|
||||||
}
|
}
|
||||||
if self.style.border.bottom {
|
if self.style.borders.bottom {
|
||||||
y += self.style.border.width;
|
y += self.style.borders.width;
|
||||||
}
|
}
|
||||||
|
|
||||||
vec2f(x, y)
|
vec2f(x, y)
|
||||||
|
@ -338,7 +348,7 @@ impl<V: View> Node<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: View> Element<V> for Node<V> {
|
impl<V: View> Element<V> for Node<V> {
|
||||||
type LayoutState = Vector2F; // Content size
|
type LayoutState = NodeLayout;
|
||||||
type PaintState = ();
|
type PaintState = ();
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
|
@ -347,48 +357,23 @@ impl<V: View> Element<V> for Node<V> {
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut LayoutContext<V>,
|
cx: &mut LayoutContext<V>,
|
||||||
) -> (Vector2F, Self::LayoutState) {
|
) -> (Vector2F, Self::LayoutState) {
|
||||||
let mut size = Vector2F::zero();
|
let mut layout = NodeLayout::default();
|
||||||
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)),
|
|
||||||
}
|
|
||||||
|
|
||||||
// Impose horizontal constraints
|
let size = if let Some(axis) = self.style.axis.to_2d() {
|
||||||
if constraint.min.x().is_finite() {
|
self.layout_xy(
|
||||||
size.set_x(size.x().max(constraint.min.x()));
|
axis,
|
||||||
}
|
constraint.max,
|
||||||
size.set_x(size.x().min(constraint.max.x()));
|
cx.rem_pixels(),
|
||||||
|
&mut layout.margins,
|
||||||
// Impose vertical constraints
|
&mut layout.padding,
|
||||||
if constraint.min.y().is_finite() {
|
view,
|
||||||
size.set_y(size.y().max(constraint.min.y()));
|
cx,
|
||||||
}
|
)
|
||||||
size.set_y(size.y().min(constraint.max.y()));
|
} else {
|
||||||
|
todo!()
|
||||||
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),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if matches!(self.style.width, Length::Hug) {
|
(size, layout);
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(
|
fn paint(
|
||||||
|
@ -396,15 +381,39 @@ impl<V: View> Element<V> for Node<V> {
|
||||||
scene: &mut SceneBuilder,
|
scene: &mut SceneBuilder,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
visible_bounds: RectF,
|
visible_bounds: RectF,
|
||||||
size_of_children: &mut Vector2F,
|
layout: &mut NodeLayout,
|
||||||
view: &mut V,
|
view: &mut V,
|
||||||
cx: &mut PaintContext<V>,
|
cx: &mut PaintContext<V>,
|
||||||
) -> Self::PaintState {
|
) -> Self::PaintState {
|
||||||
let rem_size = cx.pixels_per_rem();
|
let rem_pixels = cx.rem_pixels();
|
||||||
let margin: Edges<f32> = todo!(); // &self.style.margin.to_pixels(rem_size);
|
// 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
|
// Account for margins
|
||||||
let content_bounds = RectF::from_points(
|
let margin_bounds = RectF::from_points(
|
||||||
bounds.origin() + vec2f(margin.left, margin.top),
|
bounds.origin() + vec2f(margin.left, margin.top),
|
||||||
bounds.lower_right() - vec2f(margin.right, margin.bottom),
|
bounds.lower_right() - vec2f(margin.right, margin.bottom),
|
||||||
);
|
);
|
||||||
|
@ -412,7 +421,7 @@ impl<V: View> Element<V> for Node<V> {
|
||||||
// Paint drop shadow
|
// Paint drop shadow
|
||||||
for shadow in &self.style.shadows {
|
for shadow in &self.style.shadows {
|
||||||
scene.push_shadow(scene::Shadow {
|
scene.push_shadow(scene::Shadow {
|
||||||
bounds: content_bounds + shadow.offset,
|
bounds: margin_bounds + shadow.offset,
|
||||||
corner_radius: self.style.corner_radius,
|
corner_radius: self.style.corner_radius,
|
||||||
sigma: shadow.blur,
|
sigma: shadow.blur,
|
||||||
color: shadow.color,
|
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).
|
// Render the background and/or the border (if it not an overlay border).
|
||||||
let Fill::Color(fill_color) = self.style.fill;
|
let Fill::Color(fill_color) = self.style.fill;
|
||||||
let is_fill_visible = !fill_color.is_fully_transparent();
|
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 {
|
scene.push_quad(Quad {
|
||||||
bounds: content_bounds,
|
bounds: margin_bounds,
|
||||||
background: is_fill_visible.then_some(fill_color),
|
background: is_fill_visible.then_some(fill_color),
|
||||||
border: scene::Border {
|
border: scene::Border {
|
||||||
width: self.style.border.width,
|
width: self.style.borders.width,
|
||||||
color: self.style.border.color,
|
color: self.style.borders.color,
|
||||||
overlay: false,
|
overlay: false,
|
||||||
top: self.style.border.top,
|
top: self.style.borders.top,
|
||||||
right: self.style.border.right,
|
right: self.style.borders.right,
|
||||||
bottom: self.style.border.bottom,
|
bottom: self.style.borders.bottom,
|
||||||
left: self.style.border.left,
|
left: self.style.borders.left,
|
||||||
},
|
},
|
||||||
corner_radius: self.style.corner_radius,
|
corner_radius: self.style.corner_radius,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.content.is_empty() {
|
if !self.children.is_empty() {
|
||||||
// Account for padding first.
|
// Account for padding first.
|
||||||
let padding: Edges<f32> = todo!(); // &self.style.padding.to_pixels(rem_size);
|
let padding: Edges<f32> = todo!(); // &self.style.padding.to_pixels(rem_size);
|
||||||
let padded_bounds = RectF::from_points(
|
let padded_bounds = RectF::from_points(
|
||||||
content_bounds.origin() + vec2f(padding.left, padding.top),
|
margin_bounds.origin() + vec2f(padding.left, padding.top),
|
||||||
content_bounds.lower_right() - vec2f(padding.right, padding.top),
|
margin_bounds.lower_right() - vec2f(padding.right, padding.top),
|
||||||
);
|
);
|
||||||
|
|
||||||
match self.style.axis {
|
match self.style.axis {
|
||||||
|
@ -463,7 +472,7 @@ impl<V: View> Element<V> for Node<V> {
|
||||||
Axis2d::X,
|
Axis2d::X,
|
||||||
padded_bounds,
|
padded_bounds,
|
||||||
visible_bounds,
|
visible_bounds,
|
||||||
size_of_children,
|
layout,
|
||||||
view,
|
view,
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
|
@ -472,7 +481,7 @@ impl<V: View> Element<V> for Node<V> {
|
||||||
Axis2d::Y,
|
Axis2d::Y,
|
||||||
padded_bounds,
|
padded_bounds,
|
||||||
visible_bounds,
|
visible_bounds,
|
||||||
size_of_children,
|
layout,
|
||||||
view,
|
view,
|
||||||
cx,
|
cx,
|
||||||
),
|
),
|
||||||
|
@ -491,7 +500,7 @@ impl<V: View> Element<V> for Node<V> {
|
||||||
view: &V,
|
view: &V,
|
||||||
cx: &ViewContext<V>,
|
cx: &ViewContext<V>,
|
||||||
) -> Option<RectF> {
|
) -> Option<RectF> {
|
||||||
self.content
|
self.children
|
||||||
.iter()
|
.iter()
|
||||||
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
|
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
|
||||||
}
|
}
|
||||||
|
@ -598,18 +607,40 @@ pub struct NodeStyle {
|
||||||
gap_x: Gap,
|
gap_x: Gap,
|
||||||
gap_y: Gap,
|
gap_y: Gap,
|
||||||
|
|
||||||
width: Length,
|
size: Size<Length>,
|
||||||
height: Length,
|
margins: Edges<Length>,
|
||||||
margin: Edges<Length>,
|
|
||||||
padding: Edges<Length>,
|
padding: Edges<Length>,
|
||||||
text: OptionalTextStyle,
|
text: OptionalTextStyle,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
fill: Fill,
|
fill: Fill,
|
||||||
border: Border,
|
borders: Border,
|
||||||
corner_radius: f32, // corner radius matches swift!
|
corner_radius: f32, // corner radius matches swift!
|
||||||
shadows: Vec<Shadow>,
|
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]
|
#[optional_struct]
|
||||||
struct TextStyle {
|
struct TextStyle {
|
||||||
size: Rems,
|
size: Rems,
|
||||||
|
@ -618,12 +649,44 @@ struct TextStyle {
|
||||||
style: FontStyle,
|
style: FontStyle,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Add)]
|
#[derive(Add, Default, Clone)]
|
||||||
struct Size<T> {
|
struct Size<T> {
|
||||||
width: T,
|
width: T,
|
||||||
height: 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?
|
// Sides?
|
||||||
#[derive(Clone, Default)]
|
#[derive(Clone, Default)]
|
||||||
struct Edges<T> {
|
struct Edges<T> {
|
||||||
|
@ -633,6 +696,89 @@ struct Edges<T> {
|
||||||
right: 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> {
|
impl Edges<Rems> {
|
||||||
pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
|
pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
|
||||||
Edges {
|
Edges {
|
||||||
|
@ -688,9 +834,9 @@ impl Border {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod length {
|
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 struct Rems(f32);
|
||||||
|
|
||||||
pub fn rems(rems: f32) -> Rems {
|
pub fn rems(rems: f32) -> Rems {
|
||||||
|
@ -698,8 +844,8 @@ pub mod length {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Rems {
|
impl Rems {
|
||||||
pub fn to_pixels(&self, root_font_size: f32) -> f32 {
|
pub fn to_pixels(&self, rem_length: f32) -> f32 {
|
||||||
self.0 * root_font_size
|
self.0 * rem_length
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -710,8 +856,8 @@ pub mod length {
|
||||||
Fixed(Rems),
|
Fixed(Rems),
|
||||||
Auto {
|
Auto {
|
||||||
flex: f32,
|
flex: f32,
|
||||||
min: f32,
|
min: Rems,
|
||||||
max: f32,
|
max: Rems,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -728,26 +874,59 @@ pub mod length {
|
||||||
pub fn flex(flex: f32) -> Length {
|
pub fn flex(flex: f32) -> Length {
|
||||||
Length::Auto {
|
Length::Auto {
|
||||||
flex,
|
flex,
|
||||||
min: 0.,
|
min: Default::default(),
|
||||||
max: f32::INFINITY,
|
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 {
|
Length::Auto {
|
||||||
flex,
|
flex,
|
||||||
min: min.unwrap_or(0.),
|
min: min.unwrap_or(Default::default()),
|
||||||
max: max.unwrap_or(f32::INFINITY),
|
max: max.unwrap_or(rems(f32::INFINITY)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Length {
|
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> {
|
pub fn flex(&self) -> Option<f32> {
|
||||||
match self {
|
match self {
|
||||||
Length::Auto { flex, .. } => Some(*flex),
|
Length::Auto { flex, .. } => Some(*flex),
|
||||||
_ => None,
|
_ => 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)]
|
#[derive(Clone, Copy, Default)]
|
||||||
enum Axis2d {
|
pub enum Axis2d {
|
||||||
X,
|
X,
|
||||||
#[default]
|
#[default]
|
||||||
Y,
|
Y,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Axis2d {
|
||||||
|
fn rotate(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Axis2d::X => Axis2d::Y,
|
||||||
|
Axis2d::Y => Axis2d::X,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
enum Overflow {
|
enum Overflow {
|
||||||
#[default]
|
#[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 {
|
impl<V: View> Element<V> for Text {
|
||||||
type LayoutState = TextLayout;
|
type LayoutState = TextLayout;
|
||||||
type PaintState = ();
|
type PaintState = ();
|
||||||
|
@ -864,7 +1059,6 @@ impl<V: View> Element<V> for Text {
|
||||||
cx: &mut LayoutContext<V>,
|
cx: &mut LayoutContext<V>,
|
||||||
) -> (Vector2F, Self::LayoutState) {
|
) -> (Vector2F, Self::LayoutState) {
|
||||||
// Convert the string and highlight ranges into an iterator of highlighted chunks.
|
// Convert the string and highlight ranges into an iterator of highlighted chunks.
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let mut highlight_ranges = self
|
let mut highlight_ranges = self
|
||||||
.highlights
|
.highlights
|
||||||
|
@ -1127,3 +1321,15 @@ pub struct TextLayout {
|
||||||
wrap_boundaries: Vec<Vec<ShapedBoundary>>,
|
wrap_boundaries: Vec<Vec<ShapedBoundary>>,
|
||||||
line_height: f32,
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue