polyhorn_ios/components/
view.rs1use polyhorn_core::{use_channel, CommandBuffer as _};
2use polyhorn_ios_sys::coregraphics::CGRect;
3use polyhorn_ios_sys::polykit::{PLYCallback, PLYLayoutEvent, PLYView};
4use polyhorn_ui::geometry::Size;
5
6use crate::handles::ViewHandle;
7use crate::prelude::*;
8use crate::raw::{Apply, Builtin, Container, ContainerID, OpaqueContainer};
9use crate::{Key, Platform, Reference};
10
11pub enum Message {
12 PointerDown,
13 PointerCancel,
14 PointerUp,
15 Layout(CGRect),
16}
17
18impl Container for PLYView {
19 fn mount(&mut self, child: &mut OpaqueContainer) {
20 if let Some(view) = child.container().to_view() {
21 self.add_subview(&view)
22 } else if let Some(view_controller) = child.container().to_view_controller() {
23 self.window()
24 .unwrap()
25 .root_view_controller()
26 .present_view_controller(&view_controller, true, None);
27 }
28 }
29
30 fn unmount(&mut self) {
31 self.remove_from_superview();
32 }
33
34 fn to_view(&self) -> Option<PLYView> {
35 Some(self.clone())
36 }
37}
38
39pub type View = polyhorn_ui::components::View<Platform, ViewHandle>;
42
43impl Component for View {
44 fn render(&self, manager: &mut Manager) -> Element {
45 let view_ref: Reference<Option<ContainerID>> = use_reference!(manager, None);
46 let style = self.style;
47
48 if let Some(reference) = self.reference.as_ref() {
49 reference.replace(Some(ViewHandle {
50 compositor: manager.compositor().clone(),
51 container_id: view_ref.weak(manager),
52 }));
53 }
54
55 let on_pointer_cancel_ref = use_reference!(manager, self.on_pointer_cancel.clone());
56 on_pointer_cancel_ref.replace(manager, self.on_pointer_cancel.clone());
57 let on_pointer_cancel_ref = on_pointer_cancel_ref.weak(manager);
58
59 let on_pointer_down_ref = use_reference!(manager, self.on_pointer_down.clone());
60 on_pointer_down_ref.replace(manager, self.on_pointer_down.clone());
61 let on_pointer_down_ref = on_pointer_down_ref.weak(manager);
62
63 let on_pointer_up_ref = use_reference!(manager, self.on_pointer_up.clone());
64 on_pointer_up_ref.replace(manager, self.on_pointer_up.clone());
65 let on_pointer_up_ref = on_pointer_up_ref.weak(manager);
66
67 let on_layout_ref = use_reference!(manager, self.on_layout.clone());
68 on_layout_ref.replace(manager, self.on_layout.clone());
69 let on_layout_ref = on_layout_ref.weak(manager);
70
71 let tx = use_channel!(manager, move |mut rx| {
72 async move {
73 while let Some(message) = rx.next().await {
74 match message {
75 Message::PointerCancel => {
76 on_pointer_cancel_ref.apply(|listener| listener.emit(()));
77 }
78 Message::PointerDown => {
79 on_pointer_down_ref.apply(|listener| listener.emit(()));
80 }
81 Message::PointerUp => {
82 on_pointer_up_ref.apply(|listener| listener.emit(()));
83 }
84 Message::Layout(frame) => {
85 on_layout_ref.apply(|listener| {
86 listener.emit(Size {
87 width: frame.size.width as _,
88 height: frame.size.height as _,
89 })
90 });
91 }
92 }
93 }
94 }
95 });
96
97 use_layout_effect!(manager, move |link, buffer| {
98 let id = match view_ref.apply(link, |view| view.to_owned()) {
99 Some(id) => id,
100 None => return,
101 };
102
103 buffer.mutate(&[id], move |containers, _| {
104 let container = &mut containers[0];
105
106 let layout = match container.layout() {
107 Some(layout) => layout.clone(),
108 None => return,
109 };
110
111 if let Some(view) = container.downcast_mut::<PLYView>() {
112 style.apply(view);
113
114 view.set_layout(move || {
115 let current = layout.current();
116
117 CGRect::new(
118 current.origin.x as _,
119 current.origin.y as _,
120 current.size.width as _,
121 current.size.height as _,
122 )
123 });
124
125 {
126 let mut tx = tx.clone();
127
128 view.set_on_pointer_cancel(PLYCallback::new(move |_| {
129 let _ = tx.try_send(Message::PointerCancel);
130 }));
131 }
132
133 {
134 let mut tx = tx.clone();
135
136 view.set_on_pointer_down(PLYCallback::new(move |_| {
137 let _ = tx.try_send(Message::PointerDown);
138 }));
139 }
140
141 {
142 let mut tx = tx.clone();
143
144 view.set_on_pointer_up(PLYCallback::new(move |_| {
145 let _ = tx.try_send(Message::PointerUp);
146 }));
147 }
148
149 {
150 let mut tx = tx.clone();
151
152 view.set_on_layout(PLYCallback::new(move |event: PLYLayoutEvent| {
153 let _ = tx.try_send(Message::Layout(event.frame()));
154 }));
155 }
156 }
157 });
158 });
159
160 Element::builtin(
161 Key::new(()),
162 Builtin::View(self.style),
163 manager.children(),
164 Some(view_ref.weak(manager)),
165 )
166 }
167}