@@ -1574,6 +1574,12 @@ dependencies = [
"theme",
]
+[[package]]
+name = "convert_case"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
+
[[package]]
name = "copilot"
version = "0.1.0"
@@ -2105,6 +2111,19 @@ dependencies = [
"byteorder",
]
+[[package]]
+name = "derive_more"
+version = "0.99.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321"
+dependencies = [
+ "convert_case",
+ "proc-macro2",
+ "quote",
+ "rustc_version 0.4.0",
+ "syn 1.0.109",
+]
+
[[package]]
name = "dhat"
version = "0.3.2"
@@ -3050,6 +3069,7 @@ dependencies = [
"core-graphics",
"core-text",
"ctor",
+ "derive_more",
"dhat",
"env_logger 0.9.3",
"etagere",
@@ -3065,6 +3085,7 @@ dependencies = [
"metal",
"num_cpus",
"objc",
+ "optional_struct",
"ordered-float",
"parking",
"parking_lot 0.11.2",
@@ -4627,9 +4648,9 @@ dependencies = [
[[package]]
name = "num-traits"
-version = "0.2.15"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
+checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg 1.1.0",
"libm",
@@ -4809,6 +4830,34 @@ dependencies = [
"vcpkg",
]
+[[package]]
+name = "optional_struct"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e60da57c6a9d057c07f1a90ca7abed9d104fca0d0db1a7d7e3304e4567d977fd"
+dependencies = [
+ "optional_struct_internal",
+ "optional_struct_macro_impl",
+]
+
+[[package]]
+name = "optional_struct_internal"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "64e389cec0df3c934737dadc7b927a8e05b8c8ef792cd1af06a524bd129e9f4d"
+
+[[package]]
+name = "optional_struct_macro_impl"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "286db11c92049709d5fbbe89eecaa2febc0efe6c18d94d9ebf942e592ac80f9f"
+dependencies = [
+ "optional_struct_internal",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "ordered-float"
version = "2.10.0"
@@ -4990,7 +5039,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39fe46acc5503595e5949c17b818714d26fdf9b4920eacf3b2947f0199f4a6ff"
dependencies = [
- "rustc_version",
+ "rustc_version 0.3.3",
]
[[package]]
@@ -6165,7 +6214,16 @@ version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
dependencies = [
- "semver",
+ "semver 0.11.0",
+]
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver 1.0.18",
]
[[package]]
@@ -6548,6 +6606,12 @@ dependencies = [
"semver-parser",
]
+[[package]]
+name = "semver"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
+
[[package]]
name = "semver-parser"
version = "0.10.2"
@@ -1,5 +1,4 @@
-use log::warn;
-
+use super::layout_highlighted_chunks;
use crate::{
color::Color,
fonts::HighlightStyle,
@@ -11,15 +10,14 @@ use crate::{
scene,
serde_json::Value,
text_layout::{Line, ShapedBoundary},
- AnyElement, AppContext, Element, LayoutContext, Quad, SceneBuilder, SizeConstraint, View,
- ViewContext,
+ AnyElement, AppContext, Element, LayoutContext, PaintContext, Quad, SceneBuilder,
+ SizeConstraint, View, ViewContext,
};
-
-use std::{any::Any, borrow::Cow, f32, ops::Range};
-
-use self::length::Length;
-
-use super::layout_highlighted_chunks;
+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};
pub struct Node<V: View> {
style: NodeStyle,
@@ -90,13 +88,44 @@ impl<V: View> Node<V> {
self
}
- pub fn row(mut self) -> Self {
- self.style.axis = Axis3d::X;
+ pub fn text_size(mut self, text_size: Rems) -> Self {
+ self.style.text.size = Some(text_size);
+ self
+ }
+
+ pub fn margins(
+ mut self,
+ top_bottom: impl Into<TopBottom>,
+ left_right: impl Into<LeftRight>,
+ ) -> Self {
+ let top_bottom = top_bottom.into();
+ let left_right = left_right.into();
+ self.style.margin = Edges {
+ top: top_bottom.top,
+ bottom: top_bottom.bottom,
+ left: left_right.left,
+ right: left_right.right,
+ };
+ self
+ }
+
+ pub fn margin_top(mut self, top: Length) -> Self {
+ self.style.margin.top = top;
self
}
- pub fn stack(mut self) -> Self {
- self.style.axis = Axis3d::Z;
+ pub fn margin_bottom(mut self, bottom: Length) -> Self {
+ self.style.margin.bottom = bottom;
+ self
+ }
+
+ pub fn margin_left(mut self, left: Length) -> Self {
+ self.style.margin.left = left;
+ self
+ }
+
+ pub fn margin_right(mut self, right: Length) -> Self {
+ self.style.margin.right = right;
self
}
@@ -261,22 +290,26 @@ impl<V: View> Node<V> {
// size
// }
- fn inset_size(&self) -> Vector2F {
- self.padding_size() + self.border_size() + self.margin_size()
+ fn inset_size(&self, rem_size: f32) -> Vector2F {
+ self.padding_size(rem_size) + self.border_size() + self.margin_size(rem_size)
}
- fn margin_size(&self) -> Vector2F {
- vec2f(
- self.style.margin.left + self.style.margin.right,
- self.style.margin.top + self.style.margin.bottom,
- )
+ 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 padding_size(&self) -> Vector2F {
- vec2f(
- self.style.padding.left + self.style.padding.right,
- self.style.padding.top + self.style.padding.bottom,
- )
+ fn padding_size(&self, rem_size: f32) -> Vector2F {
+ // We need to account for auto padding
+ todo!()
+ // vec2f(
+ // (self.style.padding.left + self.style.padding.right).to_pixels(rem_size),
+ // (self.style.padding.top + self.style.padding.bottom).to_pixels(rem_size),
+ // )
}
fn border_size(&self) -> Vector2F {
@@ -310,18 +343,17 @@ impl<V: View> Element<V> for Node<V> {
view: &mut V,
cx: &mut LayoutContext<V>,
) -> (Vector2F, Self::LayoutState) {
- dbg!(constraint.max);
-
let mut size = Vector2F::zero();
- let margin_size = self.margin_size();
+ 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 + margin_size.x()),
+ 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 + margin_size.y()),
+ 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)),
}
@@ -337,7 +369,7 @@ impl<V: View> Element<V> for Node<V> {
}
size.set_y(size.y().min(constraint.max.y()));
- let inset_size = self.inset_size();
+ 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),
@@ -362,9 +394,10 @@ impl<V: View> Element<V> for Node<V> {
visible_bounds: RectF,
size_of_children: &mut Vector2F,
view: &mut V,
- cx: &mut ViewContext<V>,
+ cx: &mut PaintContext<V>,
) -> Self::PaintState {
- let margin = &self.style.margin;
+ let rem_size = cx.pixels_per_rem();
+ let margin: Edges<f32> = todo!(); // &self.style.margin.to_pixels(rem_size);
// Account for margins
let content_bounds = RectF::from_points(
@@ -414,7 +447,7 @@ impl<V: View> Element<V> for Node<V> {
if !self.content.is_empty() {
// Account for padding first.
- let padding = &self.style.padding;
+ 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),
@@ -480,6 +513,49 @@ impl<V: View> Element<V> for Node<V> {
}
}
+pub struct TopBottom {
+ top: Length,
+ bottom: Length,
+}
+
+impl<T: Into<Length>> From<(T, T)> for TopBottom {
+ fn from((top, bottom): (T, T)) -> Self {
+ Self {
+ top: top.into(),
+ bottom: bottom.into(),
+ }
+ }
+}
+
+impl<T: Copy + Into<Length>> From<T> for TopBottom {
+ fn from(both: T) -> Self {
+ Self {
+ top: both.into(),
+ bottom: both.into(),
+ }
+ }
+}
+
+pub struct LeftRight {
+ left: Length,
+ right: Length,
+}
+
+impl From<(Length, Length)> for LeftRight {
+ fn from((left, right): (Length, Length)) -> Self {
+ Self { left, right }
+ }
+}
+
+impl From<Length> for LeftRight {
+ fn from(both: Length) -> Self {
+ Self {
+ left: both,
+ right: both,
+ }
+ }
+}
+
fn align_child(
child_origin: &mut Vector2F,
parent_size: Vector2F,
@@ -520,14 +596,9 @@ pub struct NodeStyle {
width: Length,
height: Length,
- margin: Edges<f32>,
- padding: Edges<f32>,
-
- text_color: Option<Color>,
- font_size: Option<f32>,
- font_style: Option<FontStyle>,
- font_weight: Option<FontWeight>,
-
+ margin: Edges<Length>,
+ padding: Edges<Length>,
+ text: OptionalTextStyle,
opacity: f32,
fill: Fill,
border: Border,
@@ -535,6 +606,20 @@ pub struct NodeStyle {
shadows: Vec<Shadow>,
}
+#[optional_struct]
+struct TextStyle {
+ size: Rems,
+ font_family: Arc<str>,
+ weight: FontWeight,
+ style: FontStyle,
+}
+
+#[derive(Add)]
+struct Size<T> {
+ width: T,
+ height: T,
+}
+
// Sides?
#[derive(Clone, Default)]
struct Edges<T> {
@@ -544,6 +629,17 @@ struct Edges<T> {
right: T,
}
+impl Edges<Rems> {
+ pub fn to_pixels(&self, rem_size: f32) -> Edges<f32> {
+ Edges {
+ top: self.top.to_pixels(rem_size),
+ bottom: self.bottom.to_pixels(rem_size),
+ left: self.left.to_pixels(rem_size),
+ right: self.right.to_pixels(rem_size),
+ }
+ }
+}
+
#[derive(Clone, Default)]
struct CornerRadii {
top_left: f32,
@@ -588,11 +684,26 @@ impl Border {
}
pub mod length {
- #[derive(Clone, Copy, Default)]
+ use derive_more::{Add, Into};
+
+ #[derive(Add, Into, Clone, Copy, Default, Debug, PartialEq)]
+ pub struct Rems(f32);
+
+ pub fn rems(rems: f32) -> Rems {
+ Rems(rems)
+ }
+
+ impl Rems {
+ pub fn to_pixels(&self, root_font_size: f32) -> f32 {
+ self.0 * root_font_size
+ }
+ }
+
+ #[derive(Clone, Copy, Default, Debug)]
pub enum Length {
#[default]
Hug,
- Fixed(f32),
+ Fixed(Rems),
Auto {
flex: f32,
min: f32,
@@ -600,8 +711,8 @@ pub mod length {
},
}
- impl From<f32> for Length {
- fn from(value: f32) -> Self {
+ impl From<Rems> for Length {
+ fn from(value: Rems) -> Self {
Length::Fixed(value)
}
}
@@ -699,7 +810,7 @@ struct Shadow {
color: Color,
}
-#[derive(Clone, Copy, Default)]
+#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
enum FontStyle {
#[default]
Normal,
@@ -707,7 +818,7 @@ enum FontStyle {
Oblique,
}
-#[derive(Clone, Copy, Default)]
+#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
enum FontWeight {
Thin,
ExtraLight,
@@ -721,6 +832,7 @@ enum FontWeight {
Black,
}
+#[derive(Default)]
pub struct Text {
text: Cow<'static, str>,
highlights: Option<Box<[(Range<usize>, HighlightStyle)]>>,
@@ -730,10 +842,11 @@ pub struct Text {
)>,
}
-pub struct TextLayout {
- shaped_lines: Vec<Line>,
- wrap_boundaries: Vec<Vec<ShapedBoundary>>,
- line_height: f32,
+pub fn text<V: View>(text: impl Into<Cow<'static, str>>) -> Node<V> {
+ row().child(Text {
+ text: text.into(),
+ ..Default::default()
+ })
}
impl<V: View> Element<V> for Text {
@@ -839,7 +952,7 @@ impl<V: View> Element<V> for Text {
visible_bounds: RectF,
layout: &mut Self::LayoutState,
_: &mut V,
- cx: &mut ViewContext<V>,
+ cx: &mut PaintContext<V>,
) -> Self::PaintState {
let mut origin = bounds.origin();
let empty = Vec::new();
@@ -1004,3 +1117,9 @@ impl<V: View> Element<V> for Text {
})
}
}
+
+pub struct TextLayout {
+ shaped_lines: Vec<Line>,
+ wrap_boundaries: Vec<Vec<ShapedBoundary>>,
+ line_height: f32,
+}
@@ -69,6 +69,19 @@ pub struct TextStyle {
#[schemars(with = "PropertiesDef")]
pub font_properties: Properties,
pub underline: Underline,
+ pub soft_wrap: bool,
+}
+
+#[derive(Clone, Debug)]
+pub struct TextStyleRefinement {
+ pub color: Option<Color>,
+ pub font_family_name: Option<Arc<str>>,
+ pub font_family_id: Option<FamilyId>,
+ pub font_id: Option<FontId>,
+ pub font_size: Option<f32>,
+ pub font_properties: Option<Properties>,
+ pub underline: Option<Underline>,
+ pub soft_wrap: Option<bool>,
}
impl TextStyle {
@@ -83,20 +96,11 @@ impl TextStyle {
font_size: refinement.font_size.unwrap_or(self.font_size),
font_properties: refinement.font_properties.unwrap_or(self.font_properties),
underline: refinement.underline.unwrap_or(self.underline),
+ soft_wrap: refinement.soft_wrap.unwrap_or(self.soft_wrap),
}
}
}
-pub struct TextStyleRefinement {
- pub color: Option<Color>,
- pub font_family_name: Option<Arc<str>>,
- pub font_family_id: Option<FamilyId>,
- pub font_id: Option<FontId>,
- pub font_size: Option<f32>,
- pub font_properties: Option<Properties>,
- pub underline: Option<Underline>,
-}
-
#[derive(JsonSchema)]
#[serde(remote = "Properties")]
pub struct PropertiesDef {
@@ -215,6 +219,7 @@ impl TextStyle {
font_size,
font_properties,
underline,
+ soft_wrap: false,
})
}
@@ -355,13 +360,14 @@ impl Default for TextStyle {
.expect("we loaded this family from the font cache, so this should work");
Self {
- color: Default::default(),
+ color: Color::default(),
font_family_name,
font_family_id,
font_id,
font_size: 14.,
font_properties: Default::default(),
underline: Default::default(),
+ soft_wrap: true,
}
})
}