layout_attributes.rs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. //! Utility functions for applying layout attributes to taffy layout
  2. /*
  3. - [ ] pub display: Display, ----> taffy doesnt support all display types
  4. - [x] pub position: Position, --> taffy doesnt support everything
  5. - [x] pub direction: Direction,
  6. - [x] pub flex_direction: FlexDirection,
  7. - [x] pub flex_wrap: FlexWrap,
  8. - [x] pub flex_grow: f32,
  9. - [x] pub flex_shrink: f32,
  10. - [x] pub flex_basis: Dimension,
  11. - [x]pub grid_auto_flow: GridAutoFlow,
  12. - [x]pub grid_template_rows: GridTrackVec<TrackSizingFunction>,
  13. - [x]pub grid_template_columns: GridTrackVec<TrackSizingFunction>,
  14. - [x]pub grid_auto_rows: GridTrackVec<NonRepeatedTrackSizingFunction>,
  15. - [x]pub grid_auto_columns: GridTrackVec<NonRepeatedTrackSizingFunction>,
  16. - [x]pub grid_row: Line<GridPlacement>,
  17. - [x]pub grid_column: Line<GridPlacement>,
  18. - [x] pub overflow: Overflow, ---> taffy doesnt have support for directional overflow
  19. - [x] pub align_items: AlignItems,
  20. - [x] pub align_self: AlignSelf,
  21. - [x] pub align_content: AlignContent,
  22. - [x] pub margin: Rect<Dimension>,
  23. - [x] pub padding: Rect<Dimension>,
  24. - [x] pub justify_content: JustifyContent,
  25. - [x] pub inset: Rect<Dimension>,
  26. - [x] pub border: Rect<Dimension>,
  27. - [ ] pub size: Size<Dimension>, ----> seems to only be relevant for input?
  28. - [ ] pub min_size: Size<Dimension>,
  29. - [ ] pub max_size: Size<Dimension>,
  30. - [x] pub aspect_ratio: Number,
  31. */
  32. use lightningcss::properties::border::LineStyle;
  33. use lightningcss::properties::grid::{TrackBreadth, TrackSizing};
  34. use lightningcss::properties::{align, border, display, flex, grid, position, size};
  35. use lightningcss::values::percentage::Percentage;
  36. use lightningcss::{
  37. properties::{Property, PropertyId},
  38. stylesheet::ParserOptions,
  39. traits::Parse,
  40. values::{
  41. length::{Length, LengthPercentageOrAuto, LengthValue},
  42. percentage::DimensionPercentage,
  43. ratio::Ratio,
  44. },
  45. };
  46. use taffy::{
  47. prelude::*,
  48. style::{FlexDirection, Position},
  49. };
  50. /// Default values for layout attributes
  51. #[derive(Default)]
  52. pub struct LayoutConfigeration {
  53. /// the default border widths to use
  54. pub border_widths: BorderWidths,
  55. }
  56. /// Default border widths
  57. pub struct BorderWidths {
  58. /// the default border width to use for thin borders
  59. pub thin: f32,
  60. /// the default border width to use for medium borders
  61. pub medium: f32,
  62. /// the default border width to use for thick borders
  63. pub thick: f32,
  64. }
  65. impl Default for BorderWidths {
  66. fn default() -> Self {
  67. Self {
  68. thin: 1.0,
  69. medium: 3.0,
  70. thick: 5.0,
  71. }
  72. }
  73. }
  74. /// applies the entire html namespace defined in dioxus-html
  75. pub fn apply_layout_attributes(name: &str, value: &str, style: &mut Style) {
  76. apply_layout_attributes_cfg(name, value, style, &LayoutConfigeration::default())
  77. }
  78. /// applies the entire html namespace defined in dioxus-html with the specified configeration
  79. pub fn apply_layout_attributes_cfg(
  80. name: &str,
  81. value: &str,
  82. style: &mut Style,
  83. config: &LayoutConfigeration,
  84. ) {
  85. if let Ok(property) =
  86. Property::parse_string(PropertyId::from(name), value, ParserOptions::default())
  87. {
  88. match property {
  89. Property::Display(display) => match display {
  90. display::Display::Keyword(display::DisplayKeyword::None) => {
  91. style.display = Display::None
  92. }
  93. display::Display::Pair(pair) => match pair.inside {
  94. display::DisplayInside::Flex(_) => {
  95. style.display = Display::Flex;
  96. }
  97. display::DisplayInside::Grid => {
  98. style.display = Display::Grid;
  99. }
  100. _ => {}
  101. },
  102. _ => {}
  103. },
  104. Property::Position(position) => {
  105. style.position = match position {
  106. position::Position::Relative => Position::Relative,
  107. position::Position::Absolute => Position::Absolute,
  108. _ => return,
  109. }
  110. }
  111. Property::Top(top) => style.inset.top = convert_length_percentage_or_auto(top),
  112. Property::Bottom(bottom) => {
  113. style.inset.bottom = convert_length_percentage_or_auto(bottom)
  114. }
  115. Property::Left(left) => style.inset.left = convert_length_percentage_or_auto(left),
  116. Property::Right(right) => style.inset.right = convert_length_percentage_or_auto(right),
  117. Property::Inset(inset) => {
  118. style.inset.top = convert_length_percentage_or_auto(inset.top);
  119. style.inset.bottom = convert_length_percentage_or_auto(inset.bottom);
  120. style.inset.left = convert_length_percentage_or_auto(inset.left);
  121. style.inset.right = convert_length_percentage_or_auto(inset.right);
  122. }
  123. Property::BorderTopWidth(width) => {
  124. style.border.top = convert_border_side_width(width, &config.border_widths);
  125. }
  126. Property::BorderBottomWidth(width) => {
  127. style.border.bottom = convert_border_side_width(width, &config.border_widths);
  128. }
  129. Property::BorderLeftWidth(width) => {
  130. style.border.left = convert_border_side_width(width, &config.border_widths);
  131. }
  132. Property::BorderRightWidth(width) => {
  133. style.border.right = convert_border_side_width(width, &config.border_widths);
  134. }
  135. Property::BorderWidth(width) => {
  136. style.border.top = convert_border_side_width(width.top, &config.border_widths);
  137. style.border.bottom =
  138. convert_border_side_width(width.bottom, &config.border_widths);
  139. style.border.left = convert_border_side_width(width.left, &config.border_widths);
  140. style.border.right = convert_border_side_width(width.right, &config.border_widths);
  141. }
  142. Property::Border(border) => {
  143. let width = convert_border_side_width(border.width, &config.border_widths);
  144. style.border.top = width;
  145. style.border.bottom = width;
  146. style.border.left = width;
  147. style.border.right = width;
  148. }
  149. Property::BorderTop(top) => {
  150. style.border.top = convert_border_side_width(top.width, &config.border_widths);
  151. }
  152. Property::BorderBottom(bottom) => {
  153. style.border.bottom =
  154. convert_border_side_width(bottom.width, &config.border_widths);
  155. }
  156. Property::BorderLeft(left) => {
  157. style.border.left = convert_border_side_width(left.width, &config.border_widths);
  158. }
  159. Property::BorderRight(right) => {
  160. style.border.right = convert_border_side_width(right.width, &config.border_widths);
  161. }
  162. Property::BorderTopStyle(line_style) => {
  163. if line_style != LineStyle::None {
  164. style.border.top = convert_border_side_width(
  165. border::BorderSideWidth::Medium,
  166. &config.border_widths,
  167. );
  168. }
  169. }
  170. Property::BorderBottomStyle(line_style) => {
  171. if line_style != LineStyle::None {
  172. style.border.bottom = convert_border_side_width(
  173. border::BorderSideWidth::Medium,
  174. &config.border_widths,
  175. );
  176. }
  177. }
  178. Property::BorderLeftStyle(line_style) => {
  179. if line_style != LineStyle::None {
  180. style.border.left = convert_border_side_width(
  181. border::BorderSideWidth::Medium,
  182. &config.border_widths,
  183. );
  184. }
  185. }
  186. Property::BorderRightStyle(line_style) => {
  187. if line_style != LineStyle::None {
  188. style.border.right = convert_border_side_width(
  189. border::BorderSideWidth::Medium,
  190. &config.border_widths,
  191. );
  192. }
  193. }
  194. Property::BorderStyle(styles) => {
  195. if styles.top != LineStyle::None {
  196. style.border.top = convert_border_side_width(
  197. border::BorderSideWidth::Medium,
  198. &config.border_widths,
  199. );
  200. }
  201. if styles.bottom != LineStyle::None {
  202. style.border.bottom = convert_border_side_width(
  203. border::BorderSideWidth::Medium,
  204. &config.border_widths,
  205. );
  206. }
  207. if styles.left != LineStyle::None {
  208. style.border.left = convert_border_side_width(
  209. border::BorderSideWidth::Medium,
  210. &config.border_widths,
  211. );
  212. }
  213. if styles.right != LineStyle::None {
  214. style.border.right = convert_border_side_width(
  215. border::BorderSideWidth::Medium,
  216. &config.border_widths,
  217. );
  218. }
  219. }
  220. // Flexbox properties
  221. Property::FlexDirection(flex_direction, _) => {
  222. use FlexDirection::*;
  223. style.flex_direction = match flex_direction {
  224. flex::FlexDirection::Row => Row,
  225. flex::FlexDirection::RowReverse => RowReverse,
  226. flex::FlexDirection::Column => Column,
  227. flex::FlexDirection::ColumnReverse => ColumnReverse,
  228. }
  229. }
  230. Property::FlexWrap(wrap, _) => {
  231. use FlexWrap::*;
  232. style.flex_wrap = match wrap {
  233. flex::FlexWrap::NoWrap => NoWrap,
  234. flex::FlexWrap::Wrap => Wrap,
  235. flex::FlexWrap::WrapReverse => WrapReverse,
  236. }
  237. }
  238. Property::FlexGrow(grow, _) => {
  239. style.flex_grow = grow;
  240. }
  241. Property::FlexShrink(shrink, _) => {
  242. style.flex_shrink = shrink;
  243. }
  244. Property::FlexBasis(basis, _) => {
  245. style.flex_basis = convert_length_percentage_or_auto(basis).into();
  246. }
  247. Property::Flex(flex, _) => {
  248. style.flex_grow = flex.grow;
  249. style.flex_shrink = flex.shrink;
  250. style.flex_basis = convert_length_percentage_or_auto(flex.basis).into();
  251. }
  252. // Grid properties
  253. Property::GridAutoFlow(grid_auto_flow) => {
  254. let is_row = grid_auto_flow.contains(grid::GridAutoFlow::Row);
  255. let is_dense = grid_auto_flow.contains(grid::GridAutoFlow::Dense);
  256. style.grid_auto_flow = match (is_row, is_dense) {
  257. (true, false) => GridAutoFlow::Row,
  258. (false, false) => GridAutoFlow::Column,
  259. (true, true) => GridAutoFlow::RowDense,
  260. (false, true) => GridAutoFlow::ColumnDense,
  261. };
  262. }
  263. Property::GridTemplateColumns(TrackSizing::TrackList(track_list)) => {
  264. style.grid_template_columns = track_list
  265. .items
  266. .into_iter()
  267. .map(convert_grid_track_item)
  268. .collect();
  269. }
  270. Property::GridTemplateRows(TrackSizing::TrackList(track_list)) => {
  271. style.grid_template_rows = track_list
  272. .items
  273. .into_iter()
  274. .map(convert_grid_track_item)
  275. .collect();
  276. }
  277. Property::GridAutoColumns(grid::TrackSizeList(track_size_list)) => {
  278. style.grid_auto_columns = track_size_list
  279. .into_iter()
  280. .map(convert_grid_track_size)
  281. .collect();
  282. }
  283. Property::GridAutoRows(grid::TrackSizeList(track_size_list)) => {
  284. style.grid_auto_rows = track_size_list
  285. .into_iter()
  286. .map(convert_grid_track_size)
  287. .collect();
  288. }
  289. Property::GridRow(grid_row) => {
  290. style.grid_row = Line {
  291. start: convert_grid_placement(grid_row.start),
  292. end: convert_grid_placement(grid_row.end),
  293. };
  294. }
  295. Property::GridColumn(grid_column) => {
  296. style.grid_column = Line {
  297. start: convert_grid_placement(grid_column.start),
  298. end: convert_grid_placement(grid_column.end),
  299. };
  300. }
  301. // Alignment properties
  302. Property::AlignContent(align, _) => {
  303. use AlignContent::*;
  304. style.align_content = match align {
  305. align::AlignContent::ContentDistribution(distribution) => match distribution {
  306. align::ContentDistribution::SpaceBetween => Some(SpaceBetween),
  307. align::ContentDistribution::SpaceAround => Some(SpaceAround),
  308. align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly),
  309. align::ContentDistribution::Stretch => Some(Stretch),
  310. },
  311. align::AlignContent::ContentPosition {
  312. value: position, ..
  313. } => match position {
  314. align::ContentPosition::Center => Some(Center),
  315. align::ContentPosition::Start => Some(Start),
  316. align::ContentPosition::FlexStart => Some(FlexStart),
  317. align::ContentPosition::End => Some(End),
  318. align::ContentPosition::FlexEnd => Some(FlexEnd),
  319. },
  320. _ => return,
  321. };
  322. }
  323. Property::JustifyContent(justify, _) => {
  324. use AlignContent::*;
  325. style.justify_content = match justify {
  326. align::JustifyContent::ContentDistribution(distribution) => {
  327. match distribution {
  328. align::ContentDistribution::SpaceBetween => Some(SpaceBetween),
  329. align::ContentDistribution::SpaceAround => Some(SpaceAround),
  330. align::ContentDistribution::SpaceEvenly => Some(SpaceEvenly),
  331. _ => return,
  332. }
  333. }
  334. align::JustifyContent::ContentPosition {
  335. value: position, ..
  336. } => match position {
  337. align::ContentPosition::Center => Some(Center),
  338. align::ContentPosition::Start => Some(Start),
  339. align::ContentPosition::FlexStart => Some(FlexStart),
  340. align::ContentPosition::End => Some(End),
  341. align::ContentPosition::FlexEnd => Some(FlexEnd),
  342. },
  343. _ => return,
  344. };
  345. }
  346. Property::AlignSelf(align, _) => {
  347. use AlignItems::*;
  348. style.align_self = match align {
  349. align::AlignSelf::Auto => None,
  350. align::AlignSelf::Stretch => Some(Stretch),
  351. align::AlignSelf::BaselinePosition(_) => Some(Baseline),
  352. align::AlignSelf::SelfPosition {
  353. value: position, ..
  354. } => match position {
  355. align::SelfPosition::Center => Some(Center),
  356. align::SelfPosition::Start | align::SelfPosition::SelfStart => Some(Start),
  357. align::SelfPosition::FlexStart => Some(FlexStart),
  358. align::SelfPosition::End | align::SelfPosition::SelfEnd => Some(End),
  359. align::SelfPosition::FlexEnd => Some(FlexEnd),
  360. },
  361. _ => return,
  362. };
  363. }
  364. Property::AlignItems(align, _) => {
  365. use AlignItems::*;
  366. style.align_items = match align {
  367. align::AlignItems::BaselinePosition(_) => Some(Baseline),
  368. align::AlignItems::Stretch => Some(Stretch),
  369. align::AlignItems::SelfPosition {
  370. value: position, ..
  371. } => match position {
  372. align::SelfPosition::Center => Some(Center),
  373. align::SelfPosition::FlexStart => Some(FlexStart),
  374. align::SelfPosition::FlexEnd => Some(FlexEnd),
  375. align::SelfPosition::Start | align::SelfPosition::SelfStart => {
  376. Some(FlexEnd)
  377. }
  378. align::SelfPosition::End | align::SelfPosition::SelfEnd => Some(FlexEnd),
  379. },
  380. _ => return,
  381. };
  382. }
  383. Property::RowGap(row_gap) => {
  384. style.gap.width = convert_gap_value(row_gap);
  385. }
  386. Property::ColumnGap(column_gap) => {
  387. style.gap.height = convert_gap_value(column_gap);
  388. }
  389. Property::Gap(gap) => {
  390. style.gap = Size {
  391. width: convert_gap_value(gap.row),
  392. height: convert_gap_value(gap.column),
  393. };
  394. }
  395. Property::MarginTop(margin) => {
  396. style.margin.top = convert_length_percentage_or_auto(margin);
  397. }
  398. Property::MarginBottom(margin) => {
  399. style.margin.bottom = convert_length_percentage_or_auto(margin);
  400. }
  401. Property::MarginLeft(margin) => {
  402. style.margin.left = convert_length_percentage_or_auto(margin);
  403. }
  404. Property::MarginRight(margin) => {
  405. style.margin.right = convert_length_percentage_or_auto(margin);
  406. }
  407. Property::Margin(margin) => {
  408. style.margin = Rect {
  409. top: convert_length_percentage_or_auto(margin.top),
  410. bottom: convert_length_percentage_or_auto(margin.bottom),
  411. left: convert_length_percentage_or_auto(margin.left),
  412. right: convert_length_percentage_or_auto(margin.right),
  413. };
  414. }
  415. Property::PaddingTop(padding) => {
  416. style.padding.top = convert_padding(padding);
  417. }
  418. Property::PaddingBottom(padding) => {
  419. style.padding.bottom = convert_padding(padding);
  420. }
  421. Property::PaddingLeft(padding) => {
  422. style.padding.left = convert_padding(padding);
  423. }
  424. Property::PaddingRight(padding) => {
  425. style.padding.right = convert_padding(padding);
  426. }
  427. Property::Padding(padding) => {
  428. style.padding = Rect {
  429. top: convert_padding(padding.top),
  430. bottom: convert_padding(padding.bottom),
  431. left: convert_padding(padding.left),
  432. right: convert_padding(padding.right),
  433. };
  434. }
  435. Property::Width(width) => {
  436. style.size.width = convert_size(width);
  437. }
  438. Property::Height(height) => {
  439. style.size.height = convert_size(height);
  440. }
  441. _ => (),
  442. }
  443. // currently not implemented in lightningcss
  444. if name == "aspect-ratio" {
  445. if let Ok(ratio) = Ratio::parse_string(value) {
  446. style.aspect_ratio = Some(ratio.0 / ratio.1);
  447. }
  448. }
  449. }
  450. }
  451. fn extract_px_value(length_value: LengthValue) -> f32 {
  452. match length_value {
  453. LengthValue::Px(value) => value,
  454. _ => todo!("Only px values are supported"),
  455. }
  456. }
  457. fn convert_length_percentage(
  458. dimension_percentage: DimensionPercentage<LengthValue>,
  459. ) -> LengthPercentage {
  460. match dimension_percentage {
  461. DimensionPercentage::Dimension(value) => LengthPercentage::Points(extract_px_value(value)),
  462. DimensionPercentage::Percentage(percentage) => LengthPercentage::Percent(percentage.0),
  463. DimensionPercentage::Calc(_) => todo!("Calc is not supported yet"),
  464. }
  465. }
  466. fn convert_padding(dimension_percentage: LengthPercentageOrAuto) -> LengthPercentage {
  467. match dimension_percentage {
  468. LengthPercentageOrAuto::Auto => unimplemented!(),
  469. LengthPercentageOrAuto::LengthPercentage(lp) => match lp {
  470. DimensionPercentage::Dimension(value) => {
  471. LengthPercentage::Points(extract_px_value(value))
  472. }
  473. DimensionPercentage::Percentage(percentage) => LengthPercentage::Percent(percentage.0),
  474. DimensionPercentage::Calc(_) => unimplemented!("Calc is not supported yet"),
  475. },
  476. }
  477. }
  478. fn convert_length_percentage_or_auto(
  479. dimension_percentage: LengthPercentageOrAuto,
  480. ) -> LengthPercentageAuto {
  481. match dimension_percentage {
  482. LengthPercentageOrAuto::Auto => LengthPercentageAuto::Auto,
  483. LengthPercentageOrAuto::LengthPercentage(lp) => match lp {
  484. DimensionPercentage::Dimension(value) => {
  485. LengthPercentageAuto::Points(extract_px_value(value))
  486. }
  487. DimensionPercentage::Percentage(percentage) => {
  488. LengthPercentageAuto::Percent(percentage.0)
  489. }
  490. DimensionPercentage::Calc(_) => todo!("Calc is not supported yet"),
  491. },
  492. }
  493. }
  494. fn convert_dimension(dimension_percentage: DimensionPercentage<LengthValue>) -> Dimension {
  495. match dimension_percentage {
  496. DimensionPercentage::Dimension(value) => Dimension::Points(extract_px_value(value)),
  497. DimensionPercentage::Percentage(percentage) => Dimension::Percent(percentage.0),
  498. DimensionPercentage::Calc(_) => todo!("Calc is not supported yet"),
  499. }
  500. }
  501. fn convert_border_side_width(
  502. border_side_width: border::BorderSideWidth,
  503. border_width_config: &BorderWidths,
  504. ) -> LengthPercentage {
  505. match border_side_width {
  506. border::BorderSideWidth::Length(Length::Value(value)) => {
  507. LengthPercentage::Points(extract_px_value(value))
  508. }
  509. border::BorderSideWidth::Thick => LengthPercentage::Points(border_width_config.thick),
  510. border::BorderSideWidth::Medium => LengthPercentage::Points(border_width_config.medium),
  511. border::BorderSideWidth::Thin => LengthPercentage::Points(border_width_config.thin),
  512. border::BorderSideWidth::Length(_) => todo!("Only Length::Value is supported"),
  513. }
  514. }
  515. fn convert_gap_value(gap_value: align::GapValue) -> LengthPercentage {
  516. match gap_value {
  517. align::GapValue::LengthPercentage(dim) => convert_length_percentage(dim),
  518. align::GapValue::Normal => LengthPercentage::Points(0.0),
  519. }
  520. }
  521. fn convert_size(size: size::Size) -> Dimension {
  522. match size {
  523. size::Size::Auto => Dimension::Auto,
  524. size::Size::LengthPercentage(length) => convert_dimension(length),
  525. size::Size::MinContent(_) => Dimension::Auto, // Unimplemented, so default auto
  526. size::Size::MaxContent(_) => Dimension::Auto, // Unimplemented, so default auto
  527. size::Size::FitContent(_) => Dimension::Auto, // Unimplemented, so default auto
  528. size::Size::FitContentFunction(_) => Dimension::Auto, // Unimplemented, so default auto
  529. size::Size::Stretch(_) => Dimension::Auto, // Unimplemented, so default auto
  530. size::Size::Contain => Dimension::Auto, // Unimplemented, so default auto
  531. }
  532. }
  533. fn convert_grid_placement(input: grid::GridLine) -> GridPlacement {
  534. match input {
  535. grid::GridLine::Auto => GridPlacement::Auto,
  536. grid::GridLine::Line { index, .. } => line(index as i16),
  537. grid::GridLine::Span { index, .. } => span(index as u16),
  538. grid::GridLine::Area { .. } => unimplemented!(),
  539. }
  540. }
  541. fn convert_grid_track_item(input: grid::TrackListItem) -> TrackSizingFunction {
  542. match input {
  543. grid::TrackListItem::TrackSize(size) => {
  544. TrackSizingFunction::Single(convert_grid_track_size(size))
  545. }
  546. grid::TrackListItem::TrackRepeat(_) => todo!("requires TrackRepeat fields to be public!"),
  547. }
  548. }
  549. fn convert_grid_track_size(input: grid::TrackSize) -> NonRepeatedTrackSizingFunction {
  550. match input {
  551. grid::TrackSize::TrackBreadth(breadth) => minmax(
  552. convert_track_breadth_min(&breadth),
  553. convert_track_breadth_max(&breadth),
  554. ),
  555. grid::TrackSize::MinMax { min, max } => minmax(
  556. convert_track_breadth_min(&min),
  557. convert_track_breadth_max(&max),
  558. ),
  559. grid::TrackSize::FitContent(limit) => match limit {
  560. DimensionPercentage::Dimension(LengthValue::Px(len)) => minmax(auto(), points(len)),
  561. DimensionPercentage::Percentage(Percentage(pct)) => minmax(auto(), percent(pct)),
  562. _ => unimplemented!(),
  563. },
  564. }
  565. }
  566. fn convert_track_breadth_max(breadth: &TrackBreadth) -> MaxTrackSizingFunction {
  567. match breadth {
  568. grid::TrackBreadth::Length(length_percentage) => match length_percentage {
  569. DimensionPercentage::Dimension(LengthValue::Px(len)) => points(*len),
  570. DimensionPercentage::Percentage(Percentage(pct)) => percent(*pct),
  571. _ => unimplemented!(),
  572. },
  573. grid::TrackBreadth::Flex(fraction) => fr(*fraction),
  574. grid::TrackBreadth::MinContent => MaxTrackSizingFunction::MinContent,
  575. grid::TrackBreadth::MaxContent => MaxTrackSizingFunction::MaxContent,
  576. grid::TrackBreadth::Auto => MaxTrackSizingFunction::Auto,
  577. }
  578. }
  579. fn convert_track_breadth_min(breadth: &TrackBreadth) -> MinTrackSizingFunction {
  580. match breadth {
  581. grid::TrackBreadth::Length(length_percentage) => match length_percentage {
  582. DimensionPercentage::Dimension(LengthValue::Px(len)) => points(*len),
  583. DimensionPercentage::Percentage(Percentage(pct)) => percent(*pct),
  584. _ => unimplemented!(),
  585. },
  586. grid::TrackBreadth::MinContent => MinTrackSizingFunction::MinContent,
  587. grid::TrackBreadth::MaxContent => MinTrackSizingFunction::MaxContent,
  588. grid::TrackBreadth::Auto => MinTrackSizingFunction::Auto,
  589. grid::TrackBreadth::Flex(_) => MinTrackSizingFunction::Auto,
  590. }
  591. }
  592. /// parse relative or absolute value
  593. pub fn parse_value(value: &str) -> Option<Dimension> {
  594. if value.ends_with("px") {
  595. if let Ok(px) = value.trim_end_matches("px").parse::<f32>() {
  596. Some(Dimension::Points(px))
  597. } else {
  598. None
  599. }
  600. } else if value.ends_with('%') {
  601. if let Ok(pct) = value.trim_end_matches('%').parse::<f32>() {
  602. Some(Dimension::Percent(pct / 100.0))
  603. } else {
  604. None
  605. }
  606. } else {
  607. None
  608. }
  609. }