layout_attributes.rs 19 KB

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