layout_attributes.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. /*
  2. - [ ] pub display: Display,
  3. - [x] pub position_type: PositionType, --> kinda, stretch doesnt support everything
  4. - [ ] pub direction: Direction,
  5. - [x] pub flex_direction: FlexDirection,
  6. - [x] pub flex_wrap: FlexWrap,
  7. - [x] pub flex_grow: f32,
  8. - [x] pub flex_shrink: f32,
  9. - [x] pub flex_basis: Dimension,
  10. - [x] pub overflow: Overflow, ---> kinda implemented... stretch doesnt have support for directional overflow
  11. - [x] pub align_items: AlignItems,
  12. - [x] pub align_self: AlignSelf,
  13. - [x] pub align_content: AlignContent,
  14. - [x] pub margin: Rect<Dimension>,
  15. - [x] pub padding: Rect<Dimension>,
  16. - [x] pub justify_content: JustifyContent,
  17. - [ ] pub position: Rect<Dimension>,
  18. - [x] pub border: Rect<Dimension>,
  19. - [ ] pub size: Size<Dimension>, ----> ??? seems to only be relevant for input?
  20. - [ ] pub min_size: Size<Dimension>,
  21. - [ ] pub max_size: Size<Dimension>,
  22. - [ ] pub aspect_ratio: Number,
  23. */
  24. use stretch2::{prelude::*, style::PositionType};
  25. /// applies the entire html namespace defined in dioxus-html
  26. pub fn apply_layout_attributes(
  27. //
  28. name: &str,
  29. value: &str,
  30. style: &mut Style,
  31. ) {
  32. match name {
  33. "align-content"
  34. | "align-items"
  35. | "align-self" => apply_align(name, value, style),
  36. "animation"
  37. | "animation-delay"
  38. | "animation-direction"
  39. | "animation-duration"
  40. | "animation-fill-mode"
  41. | "animation-iteration-count"
  42. | "animation-name"
  43. | "animation-play-state"
  44. | "animation-timing-function" => apply_animation(name, value, style),
  45. "backface-visibility" => {}
  46. "border"
  47. | "border-bottom"
  48. | "border-bottom-color"
  49. | "border-bottom-left-radius"
  50. | "border-bottom-right-radius"
  51. | "border-bottom-style"
  52. | "border-bottom-width"
  53. | "border-collapse"
  54. | "border-color"
  55. | "border-image"
  56. | "border-image-outset"
  57. | "border-image-repeat"
  58. | "border-image-slice"
  59. | "border-image-source"
  60. | "border-image-width"
  61. | "border-left"
  62. | "border-left-color"
  63. | "border-left-style"
  64. | "border-left-width"
  65. | "border-radius"
  66. | "border-right"
  67. | "border-right-color"
  68. | "border-right-style"
  69. | "border-right-width"
  70. | "border-spacing"
  71. | "border-style"
  72. | "border-top"
  73. | "border-top-color"
  74. | "border-top-left-radius"
  75. | "border-top-right-radius"
  76. | "border-top-style"
  77. | "border-top-width"
  78. | "border-width" => apply_border(name, value, style),
  79. "bottom" => {}
  80. "box-shadow" => {}
  81. "box-sizing" => {}
  82. "caption-side" => {}
  83. "clear" => {}
  84. "clip" => {}
  85. "column-count"
  86. | "column-fill"
  87. | "column-gap"
  88. | "column-rule"
  89. | "column-rule-color"
  90. | "column-rule-style"
  91. | "column-rule-width"
  92. | "column-span"
  93. // add column-width
  94. | "column-width" => apply_column(name, value, style),
  95. "columns" => {}
  96. "content" => {}
  97. "counter-increment" => {}
  98. "counter-reset" => {}
  99. "cursor" => {}
  100. "direction" => {
  101. match value {
  102. "ltr" => style.direction = Direction::LTR,
  103. "rtl" => style.direction = Direction::RTL,
  104. _ => {}
  105. }
  106. }
  107. "display" => apply_display(name, value, style),
  108. "empty-cells" => {}
  109. "flex"
  110. | "flex-basis"
  111. | "flex-direction"
  112. | "flex-flow"
  113. | "flex-grow"
  114. | "flex-shrink"
  115. | "flex-wrap" => apply_flex(name, value, style),
  116. "float" => {}
  117. "height" => {
  118. if let Some(v) = parse_value(value){
  119. style.size.height = match v {
  120. UnitSystem::Percent(v)=> Dimension::Percent(v/100.0),
  121. UnitSystem::Point(v)=> Dimension::Points(v),
  122. };
  123. }
  124. }
  125. "justify-content" => {
  126. use JustifyContent::*;
  127. style.justify_content = match value {
  128. "flex-start" => FlexStart,
  129. "flex-end" => FlexEnd,
  130. "center" => Center,
  131. "space-between" => SpaceBetween,
  132. "space-around" => SpaceAround,
  133. "space-evenly" => SpaceEvenly,
  134. _ => FlexStart,
  135. };
  136. }
  137. "left" => {}
  138. "letter-spacing" => {}
  139. "line-height" => {}
  140. "list-style"
  141. | "list-style-image"
  142. | "list-style-position"
  143. | "list-style-type" => {}
  144. "margin"
  145. | "margin-bottom"
  146. | "margin-left"
  147. | "margin-right"
  148. | "margin-top" => apply_margin(name, value, style),
  149. "max-height" => {}
  150. "max-width" => {}
  151. "min-height" => {}
  152. "min-width" => {}
  153. "opacity" => {}
  154. "order" => {}
  155. "outline" => {}
  156. "outline-color"
  157. | "outline-offset"
  158. | "outline-style"
  159. | "outline-width" => {}
  160. "overflow"
  161. | "overflow-x"
  162. | "overflow-y" => apply_overflow(name, value, style),
  163. "padding"
  164. | "padding-bottom"
  165. | "padding-left"
  166. | "padding-right"
  167. | "padding-top" => apply_padding(name, value, style),
  168. "page-break-after"
  169. | "page-break-before"
  170. | "page-break-inside" => {}
  171. "perspective"
  172. | "perspective-origin" => {}
  173. "position" => {
  174. match value {
  175. "static" => {}
  176. "relative" => style.position_type = PositionType::Relative,
  177. "fixed" => {}
  178. "absolute" => style.position_type = PositionType::Absolute,
  179. "sticky" => {}
  180. _ => {}
  181. }
  182. }
  183. "pointer-events" => {}
  184. "quotes" => {}
  185. "resize" => {}
  186. "right" => {}
  187. "tab-size" => {}
  188. "table-layout" => {}
  189. "top" => {}
  190. "transform"
  191. | "transform-origin"
  192. | "transform-style" => apply_transform(name, value, style),
  193. "transition"
  194. | "transition-delay"
  195. | "transition-duration"
  196. | "transition-property"
  197. | "transition-timing-function" => apply_transition(name, value, style),
  198. "vertical-align" => {}
  199. "visibility" => {}
  200. "white-space" => {}
  201. "width" => {
  202. if let Some(v) = parse_value(value){
  203. style.size.width = match v {
  204. UnitSystem::Percent(v)=> Dimension::Percent(v/100.0),
  205. UnitSystem::Point(v)=> Dimension::Points(v),
  206. };
  207. }
  208. }
  209. "word-break" => {}
  210. "word-spacing" => {}
  211. "word-wrap" => {}
  212. "z-index" => {}
  213. _ => {}
  214. }
  215. }
  216. #[derive(Clone, Copy, PartialEq, Debug)]
  217. pub enum UnitSystem {
  218. Percent(f32),
  219. Point(f32),
  220. }
  221. impl Into<Dimension> for UnitSystem {
  222. fn into(self) -> Dimension {
  223. match self {
  224. Self::Percent(v) => Dimension::Percent(v),
  225. Self::Point(v) => Dimension::Points(v),
  226. }
  227. }
  228. }
  229. pub fn parse_value(value: &str) -> Option<UnitSystem> {
  230. if value.ends_with("px") {
  231. if let Ok(px) = value.trim_end_matches("px").parse::<f32>() {
  232. Some(UnitSystem::Point(px))
  233. } else {
  234. None
  235. }
  236. } else if value.ends_with('%') {
  237. if let Ok(pct) = value.trim_end_matches('%').parse::<f32>() {
  238. Some(UnitSystem::Percent(pct))
  239. } else {
  240. None
  241. }
  242. } else {
  243. None
  244. }
  245. }
  246. fn apply_overflow(name: &str, value: &str, style: &mut Style) {
  247. match name {
  248. // todo: add more overflow support to stretch2
  249. "overflow" | "overflow-x" | "overflow-y" => {
  250. style.overflow = match value {
  251. "auto" => Overflow::Visible,
  252. "hidden" => Overflow::Hidden,
  253. "scroll" => Overflow::Scroll,
  254. "visible" => Overflow::Visible,
  255. _ => Overflow::Visible,
  256. };
  257. }
  258. _ => {}
  259. }
  260. }
  261. fn apply_display(_name: &str, value: &str, style: &mut Style) {
  262. style.display = match value {
  263. "flex" => Display::Flex,
  264. "block" => Display::None,
  265. _ => Display::Flex,
  266. }
  267. // TODO: there are way more variants
  268. // stretch needs to be updated to handle them
  269. //
  270. // "block" => Display::Block,
  271. // "inline" => Display::Inline,
  272. // "inline-block" => Display::InlineBlock,
  273. // "inline-table" => Display::InlineTable,
  274. // "list-item" => Display::ListItem,
  275. // "run-in" => Display::RunIn,
  276. // "table" => Display::Table,
  277. // "table-caption" => Display::TableCaption,
  278. // "table-cell" => Display::TableCell,
  279. // "table-column" => Display::TableColumn,
  280. // "table-column-group" => Display::TableColumnGroup,
  281. // "table-footer-group" => Display::TableFooterGroup,
  282. // "table-header-group" => Display::TableHeaderGroup,
  283. // "table-row" => Display::TableRow,
  284. // "table-row-group" => Display::TableRowGroup,
  285. // "none" => Display::None,
  286. // _ => Display::Inline,
  287. }
  288. fn apply_border(name: &str, value: &str, style: &mut Style) {
  289. match name {
  290. "border" => {}
  291. "border-bottom" => {}
  292. "border-bottom-color" => {}
  293. "border-bottom-left-radius" => {}
  294. "border-bottom-right-radius" => {}
  295. "border-bottom-style" => {
  296. if style.border.bottom == Dimension::default() {
  297. let v = Dimension::Points(1.0);
  298. style.border.bottom = v;
  299. }
  300. }
  301. "border-bottom-width" => {
  302. if let Some(v) = parse_value(value) {
  303. style.border.bottom = v.into();
  304. }
  305. }
  306. "border-collapse" => {}
  307. "border-color" => {}
  308. "border-image" => {}
  309. "border-image-outset" => {}
  310. "border-image-repeat" => {}
  311. "border-image-slice" => {}
  312. "border-image-source" => {}
  313. "border-image-width" => {}
  314. "border-left" => {}
  315. "border-left-color" => {}
  316. "border-left-style" => {
  317. if style.border.start == Dimension::default() {
  318. let v = Dimension::Points(1.0);
  319. style.border.start = v;
  320. }
  321. }
  322. "border-left-width" => {
  323. if let Some(v) = parse_value(value) {
  324. style.border.start = v.into();
  325. }
  326. }
  327. "border-radius" => {}
  328. "border-right" => {}
  329. "border-right-color" => {}
  330. "border-right-style" => {
  331. let v = Dimension::Points(1.0);
  332. style.border.end = v;
  333. }
  334. "border-right-width" => {
  335. if let Some(v) = parse_value(value) {
  336. style.border.end = v.into();
  337. }
  338. }
  339. "border-spacing" => {}
  340. "border-style" => {
  341. if style.border.top == Dimension::default() {
  342. let v = Dimension::Points(1.0);
  343. style.border.top = v;
  344. }
  345. if style.border.bottom == Dimension::default() {
  346. let v = Dimension::Points(1.0);
  347. style.border.bottom = v;
  348. }
  349. if style.border.start == Dimension::default() {
  350. let v = Dimension::Points(1.0);
  351. style.border.start = v;
  352. }
  353. if style.border.end == Dimension::default() {
  354. let v = Dimension::Points(1.0);
  355. style.border.end = v;
  356. }
  357. }
  358. "border-top" => {}
  359. "border-top-color" => {}
  360. "border-top-left-radius" => {}
  361. "border-top-right-radius" => {}
  362. "border-top-style" => {
  363. if style.border.top == Dimension::default() {
  364. let v = Dimension::Points(1.0);
  365. style.border.top = v;
  366. }
  367. }
  368. "border-top-width" => {
  369. if let Some(v) = parse_value(value) {
  370. style.border.top = v.into();
  371. }
  372. }
  373. "border-width" => {
  374. let values: Vec<_> = value.split(' ').collect();
  375. if values.len() == 1 {
  376. if let Some(w) = parse_value(values[0]) {
  377. style.border.top = w.into();
  378. style.border.bottom = w.into();
  379. style.border.start = w.into();
  380. style.border.end = w.into();
  381. }
  382. } else {
  383. let border_widths = [
  384. &mut style.border.top,
  385. &mut style.border.bottom,
  386. &mut style.border.start,
  387. &mut style.border.end,
  388. ];
  389. for (v, width) in values.into_iter().zip(border_widths) {
  390. if let Some(w) = parse_value(v) {
  391. *width = w.into();
  392. }
  393. }
  394. }
  395. }
  396. _ => (),
  397. }
  398. }
  399. fn apply_animation(name: &str, _value: &str, _style: &mut Style) {
  400. match name {
  401. "animation" => {}
  402. "animation-delay" => {}
  403. "animation-direction =>{}" => {}
  404. "animation-duration" => {}
  405. "animation-fill-mode" => {}
  406. "animation-itera =>{}tion-count" => {}
  407. "animation-name" => {}
  408. "animation-play-state" => {}
  409. "animation-timing-function" => {}
  410. _ => {}
  411. }
  412. }
  413. fn apply_column(name: &str, _value: &str, _style: &mut Style) {
  414. match name {
  415. "column-count" => {}
  416. "column-fill" => {}
  417. "column-gap" => {}
  418. "column-rule" => {}
  419. "column-rule-color" => {}
  420. "column-rule-style" => {}
  421. "column-rule-width" => {}
  422. "column-span" => {}
  423. "column-width" => {}
  424. _ => {}
  425. }
  426. }
  427. fn apply_flex(name: &str, value: &str, style: &mut Style) {
  428. // - [x] pub flex_direction: FlexDirection,
  429. // - [x] pub flex_wrap: FlexWrap,
  430. // - [x] pub flex_grow: f32,
  431. // - [x] pub flex_shrink: f32,
  432. // - [x] pub flex_basis: Dimension,
  433. match name {
  434. "flex" => {}
  435. "flex-direction" => {
  436. use FlexDirection::*;
  437. style.flex_direction = match value {
  438. "row" => Row,
  439. "row-reverse" => RowReverse,
  440. "column" => Column,
  441. "column-reverse" => ColumnReverse,
  442. _ => Row,
  443. };
  444. }
  445. "flex-basis" => {
  446. if let Some(v) = parse_value(value) {
  447. style.flex_basis = match v {
  448. UnitSystem::Percent(v) => Dimension::Percent(v / 100.0),
  449. UnitSystem::Point(v) => Dimension::Points(v),
  450. };
  451. }
  452. }
  453. "flex-flow" => {}
  454. "flex-grow" => {
  455. if let Ok(val) = value.parse::<f32>() {
  456. style.flex_grow = val;
  457. }
  458. }
  459. "flex-shrink" => {
  460. if let Ok(px) = value.parse::<f32>() {
  461. style.flex_shrink = px;
  462. }
  463. }
  464. "flex-wrap" => {
  465. use FlexWrap::*;
  466. style.flex_wrap = match value {
  467. "nowrap" => NoWrap,
  468. "wrap" => Wrap,
  469. "wrap-reverse" => WrapReverse,
  470. _ => NoWrap,
  471. };
  472. }
  473. _ => {}
  474. }
  475. }
  476. fn apply_padding(name: &str, value: &str, style: &mut Style) {
  477. match parse_value(value) {
  478. Some(UnitSystem::Percent(v)) => match name {
  479. "padding" => {
  480. let v = Dimension::Percent(v / 100.0);
  481. style.padding.top = v;
  482. style.padding.bottom = v;
  483. style.padding.start = v;
  484. style.padding.end = v;
  485. }
  486. "padding-bottom" => style.padding.bottom = Dimension::Percent(v / 100.0),
  487. "padding-left" => style.padding.start = Dimension::Percent(v / 100.0),
  488. "padding-right" => style.padding.end = Dimension::Percent(v / 100.0),
  489. "padding-top" => style.padding.top = Dimension::Percent(v / 100.0),
  490. _ => {}
  491. },
  492. Some(UnitSystem::Point(v)) => match name {
  493. "padding" => {
  494. style.padding.top = Dimension::Points(v);
  495. style.padding.bottom = Dimension::Points(v);
  496. style.padding.start = Dimension::Points(v);
  497. style.padding.end = Dimension::Points(v);
  498. }
  499. "padding-bottom" => style.padding.bottom = Dimension::Points(v),
  500. "padding-left" => style.padding.start = Dimension::Points(v),
  501. "padding-right" => style.padding.end = Dimension::Points(v),
  502. "padding-top" => style.padding.top = Dimension::Points(v),
  503. _ => {}
  504. },
  505. None => {}
  506. }
  507. }
  508. fn apply_transform(_name: &str, _value: &str, _style: &mut Style) {
  509. todo!()
  510. }
  511. fn apply_transition(_name: &str, _value: &str, _style: &mut Style) {
  512. todo!()
  513. }
  514. fn apply_align(name: &str, value: &str, style: &mut Style) {
  515. match name {
  516. "align-items" => {
  517. use AlignItems::*;
  518. style.align_items = match value {
  519. "flex-start" => FlexStart,
  520. "flex-end" => FlexEnd,
  521. "center" => Center,
  522. "baseline" => Baseline,
  523. "stretch" => Stretch,
  524. _ => FlexStart,
  525. };
  526. }
  527. "align-content" => {
  528. use AlignContent::*;
  529. style.align_content = match value {
  530. "flex-start" => FlexStart,
  531. "flex-end" => FlexEnd,
  532. "center" => Center,
  533. "space-between" => SpaceBetween,
  534. "space-around" => SpaceAround,
  535. _ => FlexStart,
  536. };
  537. }
  538. "align-self" => {
  539. use AlignSelf::*;
  540. style.align_self = match value {
  541. "auto" => Auto,
  542. "flex-start" => FlexStart,
  543. "flex-end" => FlexEnd,
  544. "center" => Center,
  545. "baseline" => Baseline,
  546. "stretch" => Stretch,
  547. _ => Auto,
  548. };
  549. }
  550. _ => {}
  551. }
  552. }
  553. pub fn apply_size(_name: &str, _value: &str, _style: &mut Style) {
  554. //
  555. }
  556. pub fn apply_margin(name: &str, value: &str, style: &mut Style) {
  557. match parse_value(value) {
  558. Some(UnitSystem::Percent(v)) => match name {
  559. "margin" => {
  560. let v = Dimension::Percent(v / 100.0);
  561. style.margin.top = v;
  562. style.margin.bottom = v;
  563. style.margin.start = v;
  564. style.margin.end = v;
  565. }
  566. "margin-top" => style.margin.top = Dimension::Percent(v / 100.0),
  567. "margin-bottom" => style.margin.bottom = Dimension::Percent(v / 100.0),
  568. "margin-left" => style.margin.start = Dimension::Percent(v / 100.0),
  569. "margin-right" => style.margin.end = Dimension::Percent(v / 100.0),
  570. _ => {}
  571. },
  572. Some(UnitSystem::Point(v)) => match name {
  573. "margin" => {
  574. style.margin.top = Dimension::Points(v);
  575. style.margin.bottom = Dimension::Points(v);
  576. style.margin.start = Dimension::Points(v);
  577. style.margin.end = Dimension::Points(v);
  578. }
  579. "margin-top" => style.margin.top = Dimension::Points(v),
  580. "margin-bottom" => style.margin.bottom = Dimension::Points(v),
  581. "margin-left" => style.margin.start = Dimension::Points(v),
  582. "margin-right" => style.margin.end = Dimension::Points(v),
  583. _ => {}
  584. },
  585. None => {}
  586. }
  587. }