style_attributes.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582
  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 dioxus_core::{Attribute, VNode};
  25. use dioxus_native_core::PushedDownState;
  26. use crate::{
  27. parse_value,
  28. style::{RinkColor, RinkStyle},
  29. UnitSystem,
  30. };
  31. #[derive(Default, Clone, PartialEq, Debug)]
  32. pub struct StyleModifier {
  33. pub style: RinkStyle,
  34. pub modifier: TuiModifier,
  35. }
  36. impl PushedDownState for StyleModifier {
  37. type Ctx = ();
  38. fn reduce(&mut self, parent: Option<&Self>, vnode: &VNode, _ctx: &mut Self::Ctx) {
  39. *self = StyleModifier::default();
  40. self.style.fg = None;
  41. match vnode {
  42. VNode::Element(el) => {
  43. // handle text modifier elements
  44. if el.namespace.is_none() {
  45. match el.tag {
  46. "b" => apply_style_attributes("font-weight", "bold", self),
  47. "strong" => apply_style_attributes("font-weight", "bold", self),
  48. "u" => apply_style_attributes("text-decoration", "underline", self),
  49. "ins" => apply_style_attributes("text-decoration", "underline", self),
  50. "del" => apply_style_attributes("text-decoration", "line-through", self),
  51. "i" => apply_style_attributes("font-style", "italic", self),
  52. "em" => apply_style_attributes("font-style", "italic", self),
  53. "mark" => apply_style_attributes(
  54. "background-color",
  55. "rgba(241, 231, 64, 50%)",
  56. self,
  57. ),
  58. _ => (),
  59. }
  60. }
  61. // gather up all the styles from the attribute list
  62. for &Attribute { name, value, .. } in el.attributes {
  63. apply_style_attributes(name, value, self);
  64. }
  65. }
  66. _ => (),
  67. }
  68. // keep the text styling from the parent element
  69. if let Some(parent) = parent {
  70. let mut new_style = self.style.merge(parent.style);
  71. new_style.bg = self.style.bg;
  72. self.style = new_style;
  73. }
  74. }
  75. }
  76. #[derive(Default, Clone, PartialEq, Debug)]
  77. pub struct TuiModifier {
  78. pub borders: Borders,
  79. }
  80. #[derive(Default, Clone, PartialEq, Debug)]
  81. pub struct Borders {
  82. pub top: BorderEdge,
  83. pub right: BorderEdge,
  84. pub bottom: BorderEdge,
  85. pub left: BorderEdge,
  86. }
  87. impl Borders {
  88. fn slice(&mut self) -> [&mut BorderEdge; 4] {
  89. [
  90. &mut self.top,
  91. &mut self.right,
  92. &mut self.bottom,
  93. &mut self.left,
  94. ]
  95. }
  96. }
  97. #[derive(Clone, PartialEq, Debug)]
  98. pub struct BorderEdge {
  99. pub color: Option<RinkColor>,
  100. pub style: BorderStyle,
  101. pub width: UnitSystem,
  102. pub radius: UnitSystem,
  103. }
  104. impl Default for BorderEdge {
  105. fn default() -> Self {
  106. Self {
  107. color: None,
  108. style: BorderStyle::NONE,
  109. width: UnitSystem::Point(0.0),
  110. radius: UnitSystem::Point(0.0),
  111. }
  112. }
  113. }
  114. #[derive(Clone, Copy, PartialEq, Debug)]
  115. pub enum BorderStyle {
  116. DOTTED,
  117. DASHED,
  118. SOLID,
  119. DOUBLE,
  120. GROOVE,
  121. RIDGE,
  122. INSET,
  123. OUTSET,
  124. HIDDEN,
  125. NONE,
  126. }
  127. impl BorderStyle {
  128. pub fn symbol_set(&self) -> Option<tui::symbols::line::Set> {
  129. use tui::symbols::line::*;
  130. const DASHED: Set = Set {
  131. horizontal: "╌",
  132. vertical: "╎",
  133. ..NORMAL
  134. };
  135. const DOTTED: Set = Set {
  136. horizontal: "┈",
  137. vertical: "┊",
  138. ..NORMAL
  139. };
  140. match self {
  141. BorderStyle::DOTTED => Some(DOTTED),
  142. BorderStyle::DASHED => Some(DASHED),
  143. BorderStyle::SOLID => Some(NORMAL),
  144. BorderStyle::DOUBLE => Some(DOUBLE),
  145. BorderStyle::GROOVE => Some(NORMAL),
  146. BorderStyle::RIDGE => Some(NORMAL),
  147. BorderStyle::INSET => Some(NORMAL),
  148. BorderStyle::OUTSET => Some(NORMAL),
  149. BorderStyle::HIDDEN => None,
  150. BorderStyle::NONE => None,
  151. }
  152. }
  153. }
  154. /// applies the entire html namespace defined in dioxus-html
  155. pub fn apply_style_attributes(
  156. //
  157. name: &str,
  158. value: &str,
  159. style: &mut StyleModifier,
  160. ) {
  161. match name {
  162. "animation"
  163. | "animation-delay"
  164. | "animation-direction"
  165. | "animation-duration"
  166. | "animation-fill-mode"
  167. | "animation-iteration-count"
  168. | "animation-name"
  169. | "animation-play-state"
  170. | "animation-timing-function" => apply_animation(name, value, style),
  171. "backface-visibility" => {}
  172. "background"
  173. | "background-attachment"
  174. | "background-clip"
  175. | "background-color"
  176. | "background-image"
  177. | "background-origin"
  178. | "background-position"
  179. | "background-repeat"
  180. | "background-size" => apply_background(name, value, style),
  181. "border"
  182. | "border-bottom"
  183. | "border-bottom-color"
  184. | "border-bottom-left-radius"
  185. | "border-bottom-right-radius"
  186. | "border-bottom-style"
  187. | "border-bottom-width"
  188. | "border-collapse"
  189. | "border-color"
  190. | "border-image"
  191. | "border-image-outset"
  192. | "border-image-repeat"
  193. | "border-image-slice"
  194. | "border-image-source"
  195. | "border-image-width"
  196. | "border-left"
  197. | "border-left-color"
  198. | "border-left-style"
  199. | "border-left-width"
  200. | "border-radius"
  201. | "border-right"
  202. | "border-right-color"
  203. | "border-right-style"
  204. | "border-right-width"
  205. | "border-spacing"
  206. | "border-style"
  207. | "border-top"
  208. | "border-top-color"
  209. | "border-top-left-radius"
  210. | "border-top-right-radius"
  211. | "border-top-style"
  212. | "border-top-width"
  213. | "border-width" => apply_border(name, value, style),
  214. "bottom" => {}
  215. "box-shadow" => {}
  216. "box-sizing" => {}
  217. "caption-side" => {}
  218. "clear" => {}
  219. "clip" => {}
  220. "color" => {
  221. if let Ok(c) = value.parse() {
  222. style.style.fg.replace(c);
  223. }
  224. }
  225. "columns" => {}
  226. "content" => {}
  227. "counter-increment" => {}
  228. "counter-reset" => {}
  229. "cursor" => {}
  230. "empty-cells" => {}
  231. "float" => {}
  232. "font" | "font-family" | "font-size" | "font-size-adjust" | "font-stretch"
  233. | "font-style" | "font-variant" | "font-weight" => apply_font(name, value, style),
  234. "letter-spacing" => {}
  235. "line-height" => {}
  236. "list-style" | "list-style-image" | "list-style-position" | "list-style-type" => {}
  237. "opacity" => {}
  238. "order" => {}
  239. "outline" => {}
  240. "outline-color" | "outline-offset" | "outline-style" | "outline-width" => {}
  241. "page-break-after" | "page-break-before" | "page-break-inside" => {}
  242. "perspective" | "perspective-origin" => {}
  243. "pointer-events" => {}
  244. "quotes" => {}
  245. "resize" => {}
  246. "tab-size" => {}
  247. "table-layout" => {}
  248. "text-align"
  249. | "text-align-last"
  250. | "text-decoration"
  251. | "text-decoration-color"
  252. | "text-decoration-line"
  253. | "text-decoration-style"
  254. | "text-indent"
  255. | "text-justify"
  256. | "text-overflow"
  257. | "text-shadow"
  258. | "text-transform" => apply_text(name, value, style),
  259. "transition"
  260. | "transition-delay"
  261. | "transition-duration"
  262. | "transition-property"
  263. | "transition-timing-function" => apply_transition(name, value, style),
  264. "visibility" => {}
  265. "white-space" => {}
  266. _ => {}
  267. }
  268. }
  269. fn apply_background(name: &str, value: &str, style: &mut StyleModifier) {
  270. match name {
  271. "background-color" => {
  272. if let Ok(c) = value.parse() {
  273. style.style.bg.replace(c);
  274. }
  275. }
  276. "background" => {}
  277. "background-attachment" => {}
  278. "background-clip" => {}
  279. "background-image" => {}
  280. "background-origin" => {}
  281. "background-position" => {}
  282. "background-repeat" => {}
  283. "background-size" => {}
  284. _ => {}
  285. }
  286. }
  287. fn apply_border(name: &str, value: &str, style: &mut StyleModifier) {
  288. fn parse_border_style(v: &str) -> BorderStyle {
  289. match v {
  290. "dotted" => BorderStyle::DOTTED,
  291. "dashed" => BorderStyle::DASHED,
  292. "solid" => BorderStyle::SOLID,
  293. "double" => BorderStyle::DOUBLE,
  294. "groove" => BorderStyle::GROOVE,
  295. "ridge" => BorderStyle::RIDGE,
  296. "inset" => BorderStyle::INSET,
  297. "outset" => BorderStyle::OUTSET,
  298. "none" => BorderStyle::NONE,
  299. "hidden" => BorderStyle::HIDDEN,
  300. _ => todo!(),
  301. }
  302. }
  303. match name {
  304. "border" => {}
  305. "border-bottom" => {}
  306. "border-bottom-color" => {
  307. if let Ok(c) = value.parse() {
  308. style.modifier.borders.bottom.color = Some(c);
  309. }
  310. }
  311. "border-bottom-left-radius" => {
  312. if let Some(v) = parse_value(value) {
  313. style.modifier.borders.left.radius = v;
  314. }
  315. }
  316. "border-bottom-right-radius" => {
  317. if let Some(v) = parse_value(value) {
  318. style.modifier.borders.right.radius = v;
  319. }
  320. }
  321. "border-bottom-style" => style.modifier.borders.bottom.style = parse_border_style(value),
  322. "border-bottom-width" => {
  323. if let Some(v) = parse_value(value) {
  324. style.modifier.borders.bottom.width = v;
  325. }
  326. }
  327. "border-collapse" => {}
  328. "border-color" => {
  329. let values: Vec<_> = value.split(' ').collect();
  330. if values.len() == 1 {
  331. if let Ok(c) = values[0].parse() {
  332. style
  333. .modifier
  334. .borders
  335. .slice()
  336. .iter_mut()
  337. .for_each(|b| b.color = Some(c));
  338. }
  339. } else {
  340. for (v, b) in values
  341. .into_iter()
  342. .zip(style.modifier.borders.slice().iter_mut())
  343. {
  344. if let Ok(c) = v.parse() {
  345. b.color = Some(c);
  346. }
  347. }
  348. }
  349. }
  350. "border-image" => {}
  351. "border-image-outset" => {}
  352. "border-image-repeat" => {}
  353. "border-image-slice" => {}
  354. "border-image-source" => {}
  355. "border-image-width" => {}
  356. "border-left" => {}
  357. "border-left-color" => {
  358. if let Ok(c) = value.parse() {
  359. style.modifier.borders.left.color = Some(c);
  360. }
  361. }
  362. "border-left-style" => style.modifier.borders.left.style = parse_border_style(value),
  363. "border-left-width" => {
  364. if let Some(v) = parse_value(value) {
  365. style.modifier.borders.left.width = v;
  366. }
  367. }
  368. "border-radius" => {
  369. let values: Vec<_> = value.split(' ').collect();
  370. if values.len() == 1 {
  371. if let Some(r) = parse_value(values[0]) {
  372. style
  373. .modifier
  374. .borders
  375. .slice()
  376. .iter_mut()
  377. .for_each(|b| b.radius = r);
  378. }
  379. } else {
  380. for (v, b) in values
  381. .into_iter()
  382. .zip(style.modifier.borders.slice().iter_mut())
  383. {
  384. if let Some(r) = parse_value(v) {
  385. b.radius = r;
  386. }
  387. }
  388. }
  389. }
  390. "border-right" => {}
  391. "border-right-color" => {
  392. if let Ok(c) = value.parse() {
  393. style.modifier.borders.right.color = Some(c);
  394. }
  395. }
  396. "border-right-style" => style.modifier.borders.right.style = parse_border_style(value),
  397. "border-right-width" => {
  398. if let Some(v) = parse_value(value) {
  399. style.modifier.borders.right.width = v;
  400. }
  401. }
  402. "border-spacing" => {}
  403. "border-style" => {
  404. let values: Vec<_> = value.split(' ').collect();
  405. if values.len() == 1 {
  406. let border_style = parse_border_style(values[0]);
  407. style
  408. .modifier
  409. .borders
  410. .slice()
  411. .iter_mut()
  412. .for_each(|b| b.style = border_style);
  413. } else {
  414. for (v, b) in values
  415. .into_iter()
  416. .zip(style.modifier.borders.slice().iter_mut())
  417. {
  418. b.style = parse_border_style(v);
  419. }
  420. }
  421. }
  422. "border-top" => {}
  423. "border-top-color" => {
  424. if let Ok(c) = value.parse() {
  425. style.modifier.borders.top.color = Some(c);
  426. }
  427. }
  428. "border-top-left-radius" => {
  429. if let Some(v) = parse_value(value) {
  430. style.modifier.borders.left.radius = v;
  431. }
  432. }
  433. "border-top-right-radius" => {
  434. if let Some(v) = parse_value(value) {
  435. style.modifier.borders.right.radius = v;
  436. }
  437. }
  438. "border-top-style" => style.modifier.borders.top.style = parse_border_style(value),
  439. "border-top-width" => {
  440. if let Some(v) = parse_value(value) {
  441. style.modifier.borders.top.width = v;
  442. }
  443. }
  444. "border-width" => {
  445. let values: Vec<_> = value.split(' ').collect();
  446. if values.len() == 1 {
  447. if let Some(w) = parse_value(values[0]) {
  448. style
  449. .modifier
  450. .borders
  451. .slice()
  452. .iter_mut()
  453. .for_each(|b| b.width = w);
  454. }
  455. } else {
  456. for (v, width) in values
  457. .into_iter()
  458. .zip(style.modifier.borders.slice().iter_mut())
  459. {
  460. if let Some(w) = parse_value(v) {
  461. width.width = w.into();
  462. }
  463. }
  464. }
  465. }
  466. _ => (),
  467. }
  468. }
  469. fn apply_animation(name: &str, _value: &str, _style: &mut StyleModifier) {
  470. match name {
  471. "animation" => {}
  472. "animation-delay" => {}
  473. "animation-direction =>{}" => {}
  474. "animation-duration" => {}
  475. "animation-fill-mode" => {}
  476. "animation-itera =>{}tion-count" => {}
  477. "animation-name" => {}
  478. "animation-play-state" => {}
  479. "animation-timing-function" => {}
  480. _ => {}
  481. }
  482. }
  483. fn apply_font(name: &str, value: &str, style: &mut StyleModifier) {
  484. use tui::style::Modifier;
  485. match name {
  486. "font" => (),
  487. "font-family" => (),
  488. "font-size" => (),
  489. "font-size-adjust" => (),
  490. "font-stretch" => (),
  491. "font-style" => match value {
  492. "italic" => style.style = style.style.add_modifier(Modifier::ITALIC),
  493. "oblique" => style.style = style.style.add_modifier(Modifier::ITALIC),
  494. _ => (),
  495. },
  496. "font-variant" => todo!(),
  497. "font-weight" => match value {
  498. "bold" => style.style = style.style.add_modifier(Modifier::BOLD),
  499. "normal" => style.style = style.style.remove_modifier(Modifier::BOLD),
  500. _ => (),
  501. },
  502. _ => (),
  503. }
  504. }
  505. fn apply_text(name: &str, value: &str, style: &mut StyleModifier) {
  506. use tui::style::Modifier;
  507. match name {
  508. "text-align" => todo!(),
  509. "text-align-last" => todo!(),
  510. "text-decoration" | "text-decoration-line" => {
  511. for v in value.split(' ') {
  512. match v {
  513. "line-through" => style.style = style.style.add_modifier(Modifier::CROSSED_OUT),
  514. "underline" => style.style = style.style.add_modifier(Modifier::UNDERLINED),
  515. _ => (),
  516. }
  517. }
  518. }
  519. "text-decoration-color" => todo!(),
  520. "text-decoration-style" => todo!(),
  521. "text-indent" => todo!(),
  522. "text-justify" => todo!(),
  523. "text-overflow" => todo!(),
  524. "text-shadow" => todo!(),
  525. "text-transform" => todo!(),
  526. _ => todo!(),
  527. }
  528. }
  529. fn apply_transition(_name: &str, _value: &str, _style: &mut StyleModifier) {
  530. todo!()
  531. }