123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380 |
- use std::sync::{Arc, Mutex};
- use dioxus_native_core::exports::shipyard::Component;
- use dioxus_native_core::layout_attributes::{
- apply_layout_attributes_cfg, BorderWidths, LayoutConfigeration,
- };
- use dioxus_native_core::node::OwnedAttributeView;
- use dioxus_native_core::node_ref::{AttributeMaskBuilder, NodeMaskBuilder, NodeView};
- use dioxus_native_core::prelude::*;
- use dioxus_native_core_macro::partial_derive_state;
- use taffy::prelude::*;
- use crate::{screen_to_layout_space, unit_to_layout_space};
- #[derive(Debug, Clone, Copy, PartialEq)]
- pub(crate) enum PossiblyUninitalized<T> {
- Uninitalized,
- Initialized(T),
- }
- impl<T> PossiblyUninitalized<T> {
- pub fn unwrap(self) -> T {
- match self {
- Self::Initialized(i) => i,
- _ => panic!("uninitalized"),
- }
- }
- }
- impl<T> Default for PossiblyUninitalized<T> {
- fn default() -> Self {
- Self::Uninitalized
- }
- }
- #[derive(Clone, PartialEq, Default, Debug, Component)]
- pub(crate) struct TaffyLayout {
- pub style: Style,
- pub node: PossiblyUninitalized<Node>,
- }
- #[partial_derive_state]
- impl State for TaffyLayout {
- type ChildDependencies = (Self,);
- type ParentDependencies = ();
- type NodeDependencies = ();
- const NODE_MASK: NodeMaskBuilder<'static> = NodeMaskBuilder::new()
- .with_attrs(AttributeMaskBuilder::Some(SORTED_LAYOUT_ATTRS))
- .with_text();
- // The layout state should be effected by the shadow dom
- const TRAVERSE_SHADOW_DOM: bool = true;
- fn update<'a>(
- &mut self,
- node_view: NodeView,
- _: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
- _: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
- children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
- ctx: &SendAnyMap,
- ) -> bool {
- let mut changed = false;
- let taffy: &Arc<Mutex<Taffy>> = ctx.get().unwrap();
- let mut taffy = taffy.lock().expect("poisoned taffy");
- let mut style = Style::default();
- if let Some(text) = node_view.text() {
- let char_len = text.chars().count();
- style = Style {
- size: Size {
- // characters are 1 point tall
- height: Dimension::Points(screen_to_layout_space(1)),
- // text is as long as it is declared
- width: Dimension::Points(screen_to_layout_space(char_len as u16)),
- },
- ..Default::default()
- };
- if let PossiblyUninitalized::Initialized(n) = self.node {
- if self.style != style {
- taffy.set_style(n, style.clone()).unwrap();
- }
- } else {
- self.node =
- PossiblyUninitalized::Initialized(taffy.new_leaf(style.clone()).unwrap());
- changed = true;
- }
- } else {
- // gather up all the styles from the attribute list
- if let Some(attributes) = node_view.attributes() {
- for OwnedAttributeView {
- attribute, value, ..
- } in attributes
- {
- if value.as_custom().is_none() {
- apply_layout_attributes_cfg(
- &attribute.name,
- &value.to_string(),
- &mut style,
- &LayoutConfigeration {
- border_widths: BorderWidths {
- thin: 1.0,
- medium: 1.0,
- thick: 1.0,
- },
- },
- );
- }
- }
- }
- // Set all direct nodes as our children
- let mut child_layout = vec![];
- for (l,) in children {
- child_layout.push(l.node.unwrap());
- }
- fn scale_dimension(d: Dimension) -> Dimension {
- match d {
- Dimension::Points(p) => Dimension::Points(unit_to_layout_space(p)),
- Dimension::Percent(p) => Dimension::Percent(p),
- Dimension::Auto => Dimension::Auto,
- }
- }
- fn scale_length_percentage_auto(d: LengthPercentageAuto) -> LengthPercentageAuto {
- match d {
- LengthPercentageAuto::Points(p) => {
- LengthPercentageAuto::Points(unit_to_layout_space(p))
- }
- LengthPercentageAuto::Percent(p) => LengthPercentageAuto::Percent(p),
- LengthPercentageAuto::Auto => LengthPercentageAuto::Auto,
- }
- }
- fn scale_length_percentage(d: LengthPercentage) -> LengthPercentage {
- match d {
- LengthPercentage::Points(p) => {
- LengthPercentage::Points(unit_to_layout_space(p))
- }
- LengthPercentage::Percent(p) => LengthPercentage::Percent(p),
- }
- }
- let scaled_style = Style {
- inset: Rect {
- left: scale_length_percentage_auto(style.inset.left),
- right: scale_length_percentage_auto(style.inset.right),
- top: scale_length_percentage_auto(style.inset.top),
- bottom: scale_length_percentage_auto(style.inset.bottom),
- },
- margin: Rect {
- left: scale_length_percentage_auto(style.margin.left),
- right: scale_length_percentage_auto(style.margin.right),
- top: scale_length_percentage_auto(style.margin.top),
- bottom: scale_length_percentage_auto(style.margin.bottom),
- },
- padding: Rect {
- left: scale_length_percentage(style.padding.left),
- right: scale_length_percentage(style.padding.right),
- top: scale_length_percentage(style.padding.top),
- bottom: scale_length_percentage(style.padding.bottom),
- },
- border: Rect {
- left: scale_length_percentage(style.border.left),
- right: scale_length_percentage(style.border.right),
- top: scale_length_percentage(style.border.top),
- bottom: scale_length_percentage(style.border.bottom),
- },
- gap: Size {
- width: scale_length_percentage(style.gap.width),
- height: scale_length_percentage(style.gap.height),
- },
- flex_basis: scale_dimension(style.flex_basis),
- size: Size {
- width: scale_dimension(style.size.width),
- height: scale_dimension(style.size.height),
- },
- min_size: Size {
- width: scale_dimension(style.min_size.width),
- height: scale_dimension(style.min_size.height),
- },
- max_size: Size {
- width: scale_dimension(style.max_size.width),
- height: scale_dimension(style.max_size.height),
- },
- ..style.clone()
- };
- if let PossiblyUninitalized::Initialized(n) = self.node {
- if self.style != style {
- taffy.set_style(n, scaled_style).unwrap();
- }
- if taffy.children(n).unwrap() != child_layout {
- taffy.set_children(n, &child_layout).unwrap();
- }
- } else {
- self.node = PossiblyUninitalized::Initialized(
- taffy
- .new_with_children(scaled_style, &child_layout)
- .unwrap(),
- );
- changed = true;
- }
- }
- if self.style != style {
- changed = true;
- self.style = style;
- }
- changed
- }
- fn create<'a>(
- node_view: NodeView<()>,
- node: <Self::NodeDependencies as Dependancy>::ElementBorrowed<'a>,
- parent: Option<<Self::ParentDependencies as Dependancy>::ElementBorrowed<'a>>,
- children: Vec<<Self::ChildDependencies as Dependancy>::ElementBorrowed<'a>>,
- context: &SendAnyMap,
- ) -> Self {
- let mut myself = Self::default();
- myself.update(node_view, node, parent, children, context);
- myself
- }
- }
- // these are the attributes in layout_attiributes in native-core
- const SORTED_LAYOUT_ATTRS: &[&str] = &[
- "align-content",
- "align-items",
- "align-self",
- "animation",
- "animation-delay",
- "animation-direction",
- "animation-duration",
- "animation-fill-mode",
- "animation-iteration-count",
- "animation-name",
- "animation-play-state",
- "animation-timing-function",
- "backface-visibility",
- "border",
- "border-bottom",
- "border-bottom-color",
- "border-bottom-left-radius",
- "border-bottom-right-radius",
- "border-bottom-style",
- "border-bottom-width",
- "border-collapse",
- "border-color",
- "border-image",
- "border-image-outset",
- "border-image-repeat",
- "border-image-slice",
- "border-image-source",
- "border-image-width",
- "border-left",
- "border-left-color",
- "border-left-style",
- "border-left-width",
- "border-radius",
- "border-right",
- "border-right-color",
- "border-right-style",
- "border-right-width",
- "border-spacing",
- "border-style",
- "border-top",
- "border-top-color",
- "border-top-left-radius",
- "border-top-right-radius",
- "border-top-style",
- "border-top-width",
- "border-width",
- "bottom",
- "box-shadow",
- "box-sizing",
- "caption-side",
- "clear",
- "clip",
- "column-count",
- "column-fill",
- "column-gap",
- "column-rule",
- "column-rule-color",
- "column-rule-style",
- "column-rule-width",
- "column-span",
- "column-width",
- "columns",
- "content",
- "counter-increment",
- "counter-reset",
- "cursor",
- "direction",
- "ltr",
- "rtl",
- "display",
- "empty-cells",
- "flex",
- "flex-basis",
- "flex-direction",
- "flex-flow",
- "flex-grow",
- "flex-shrink",
- "flex-wrap",
- "float",
- "height",
- "justify-content",
- "flex-start",
- "flex-end",
- "center",
- "space-between",
- "space-around",
- "space-evenly",
- "left",
- "letter-spacing",
- "line-height",
- "list-style",
- "list-style-image",
- "list-style-position",
- "list-style-type",
- "margin",
- "margin-bottom",
- "margin-left",
- "margin-right",
- "margin-top",
- "max-height",
- "max-width",
- "min-height",
- "min-width",
- "opacity",
- "order",
- "outline",
- "outline-color",
- "outline-offset",
- "outline-style",
- "outline-width",
- "overflow",
- "overflow-x",
- "overflow-y",
- "padding",
- "padding-bottom",
- "padding-left",
- "padding-right",
- "padding-top",
- "page-break-after",
- "page-break-before",
- "page-break-inside",
- "perspective",
- "perspective-origin",
- "position",
- "static",
- "relative",
- "fixed",
- "absolute",
- "sticky",
- "pointer-events",
- "quotes",
- "resize",
- "right",
- "tab-size",
- "table-layout",
- "top",
- "transform",
- "transform-origin",
- "transform-style",
- "transition",
- "transition-delay",
- "transition-duration",
- "transition-property",
- "transition-timing-function",
- "vertical-align",
- "visibility",
- "white-space",
- "width",
- "word-break",
- "word-spacing",
- "word-wrap",
- "z-index",
- ];
|