ferroui_controls/presentation_source/
presentation_source_layout.rs1use super::PresentationSource;
2use ferroui_base::layout::{ILayoutManager, ILayoutRoot, LayoutManager, Layoutable};
3use ferroui_base::reactive::IDisposable;
4use ferroui_base::rendering::{RendererDebugOverlays, RendererDiagnostics};
5use ferroui_base::Ref;
6use std::cell::{Cell, RefCell};
7use std::rc::{Rc, Weak};
8
9impl PresentationSource {
10 pub fn layout_scaling(&self) -> f64 {
12 self.render_scaling()
13 }
14
15 pub fn layout_manager(&self) -> &Rc<LayoutManager> {
17 &self.layout_manager
18 }
19
20 pub(super) fn create_layout_manager(owner: Weak<dyn ILayoutRoot>) -> Rc<LayoutManager> {
21 LayoutManager::new(owner)
22 }
23
24 pub(super) fn create_layout_diagnostic_bridge(&self) {
29 let bridge = LayoutDiagnosticBridge::new(self.typed_renderer().diagnostics(), &self.layout_manager);
30 bridge.setup_bridge();
31 *self.layout_diagnostic_bridge.borrow_mut() = Some(bridge);
32 }
33}
34
35impl ILayoutRoot for PresentationSource {
36 fn layout_scaling(&self) -> f64 {
37 PresentationSource::layout_scaling(self)
38 }
39
40 fn layout_manager(&self) -> Rc<dyn ILayoutManager> {
41 self.layout_manager.clone()
42 }
43
44 fn root_visual(&self) -> Ref<Layoutable> {
45 self.root_element().upcast()
46 }
47}
48
49pub(super) struct LayoutDiagnosticBridge {
52 state: Rc<BridgeState>,
53 property_changed_subscription: RefCell<Option<Rc<dyn IDisposable>>>,
54}
55
56struct BridgeState {
57 diagnostics: Rc<RendererDiagnostics>,
58 layout_manager: Weak<LayoutManager>,
59 is_handling: Cell<bool>,
60}
61
62impl LayoutDiagnosticBridge {
63 pub fn new(diagnostics: Rc<RendererDiagnostics>, layout_manager: &Rc<LayoutManager>) -> Self {
64 let state = Rc::new(BridgeState {
65 diagnostics: diagnostics.clone(),
66 layout_manager: Rc::downgrade(layout_manager),
67 is_handling: Cell::new(false),
68 });
69
70 let weak = Rc::downgrade(&state);
71 let subscription = diagnostics.property_changed(move |_, property_name| {
72 if let Some(state) = weak.upgrade() {
73 state.on_diagnostics_property_changed(property_name);
74 }
75 });
76
77 Self { state, property_changed_subscription: RefCell::new(Some(subscription)) }
78 }
79
80 pub fn setup_bridge(&self) {
81 self.state.setup_bridge();
82 }
83
84 pub fn dispose(&self) {
85 if let Some(subscription) = self.property_changed_subscription.borrow_mut().take() {
86 subscription.dispose();
87 }
88 if let Some(layout_manager) = self.state.layout_manager.upgrade() {
89 layout_manager.set_layout_pass_timed(None);
90 }
91 }
92}
93
94impl BridgeState {
95 fn setup_bridge(&self) {
96 let needs_handling = self.diagnostics.debug_overlays().contains(RendererDebugOverlays::LAYOUT_TIME_GRAPH);
97 if needs_handling != self.is_handling.get() {
98 self.is_handling.set(needs_handling);
99 let Some(layout_manager) = self.layout_manager.upgrade() else { return };
100 layout_manager.set_layout_pass_timed(if needs_handling {
101 let diagnostics = Rc::downgrade(&self.diagnostics);
102 Some(Rc::new(move |timing| {
103 if let Some(diagnostics) = diagnostics.upgrade() {
104 diagnostics.set_last_layout_pass_timing(timing);
105 }
106 }))
107 } else {
108 None
109 });
110 }
111 }
112
113 fn on_diagnostics_property_changed(&self, property_name: &str) {
114 if property_name == RendererDiagnostics::DEBUG_OVERLAYS_PROPERTY_NAME {
115 self.setup_bridge();
116 }
117 }
118}