query.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. use std::{
  2. cell::{Ref, RefCell},
  3. rc::Rc,
  4. sync::{Arc, Mutex, MutexGuard},
  5. };
  6. use dioxus_native_core::{real_dom::NodeImmutable, NodeId, RealDom};
  7. use taffy::{
  8. geometry::Point,
  9. prelude::{Layout, Size},
  10. Taffy,
  11. };
  12. use crate::{layout::TaffyLayout, layout_to_screen_space};
  13. /// Allows querying the layout of nodes after rendering. It will only provide a correct value after a node is rendered.
  14. /// Provided as a root context for all tui applictions.
  15. /// # Example
  16. /// ```rust, ignore
  17. /// use dioxus::prelude::*;
  18. /// use dioxus_tui::query::Query;
  19. /// use dioxus_tui::Size;
  20. ///
  21. /// fn main() {
  22. /// dioxus_tui::launch(app);
  23. /// }
  24. ///
  25. /// fn app(cx: Scope) -> Element {
  26. /// let hue = use_state(cx, || 0.0);
  27. /// let brightness = use_state(cx, || 0.0);
  28. /// let tui_query: Query = cx.consume_context().unwrap();
  29. /// cx.render(rsx! {
  30. /// div{
  31. /// width: "100%",
  32. /// background_color: "hsl({hue}, 70%, {brightness}%)",
  33. /// onmousemove: move |evt| {
  34. /// let node = tui_query.get(cx.root_node().mounted_id());
  35. /// let Size{width, height} = node.size().unwrap();
  36. /// hue.set((evt.data.offset_x as f32/width as f32)*255.0);
  37. /// brightness.set((evt.data.offset_y as f32/height as f32)*100.0);
  38. /// },
  39. /// "hsl({hue}, 70%, {brightness}%)",
  40. /// }
  41. /// })
  42. /// }
  43. /// ```
  44. #[derive(Clone)]
  45. pub struct Query {
  46. pub(crate) rdom: Rc<RefCell<RealDom>>,
  47. pub(crate) stretch: Arc<Mutex<Taffy>>,
  48. }
  49. impl Query {
  50. pub fn get(&self, id: NodeId) -> ElementRef {
  51. ElementRef::new(
  52. self.rdom.borrow(),
  53. self.stretch.lock().expect("taffy lock poisoned"),
  54. id,
  55. )
  56. }
  57. }
  58. pub struct ElementRef<'a> {
  59. inner: Ref<'a, RealDom>,
  60. stretch: MutexGuard<'a, Taffy>,
  61. id: NodeId,
  62. }
  63. impl<'a> ElementRef<'a> {
  64. fn new(inner: Ref<'a, RealDom>, stretch: MutexGuard<'a, Taffy>, id: NodeId) -> Self {
  65. Self { inner, stretch, id }
  66. }
  67. pub fn size(&self) -> Option<Size<u32>> {
  68. self.layout().map(|l| l.size.map(|v| v.round() as u32))
  69. }
  70. pub fn pos(&self) -> Option<Point<u32>> {
  71. self.layout().map(|l| Point {
  72. x: l.location.x.round() as u32,
  73. y: l.location.y.round() as u32,
  74. })
  75. }
  76. pub fn layout(&self) -> Option<Layout> {
  77. let layout = self
  78. .stretch
  79. .layout(
  80. self.inner
  81. .get(self.id)
  82. .unwrap()
  83. .get::<TaffyLayout>()
  84. .unwrap()
  85. .node
  86. .ok()?,
  87. )
  88. .ok();
  89. layout.map(|layout| Layout {
  90. order: layout.order,
  91. size: layout.size.map(layout_to_screen_space),
  92. location: Point {
  93. x: layout_to_screen_space(layout.location.x),
  94. y: layout_to_screen_space(layout.location.y),
  95. },
  96. })
  97. }
  98. }