ferroui_diagnostics/diagnostics/views/
control_details_view.rs1use crate::diagnostics::view_models::{ControlDetailsViewModel, SetterViewModelRef};
8use ferroui_base::data::core::ValueTypes;
9use ferroui_base::input::{InputElementImpl, PointerPressedEventArgs, TappedEventArgs};
10use ferroui_base::interactivity::{IRoutedEventArgs, InteractiveImpl};
11use ferroui_base::layout::LayoutableImpl;
12use ferroui_base::StyledElementImplExt;
13use ferroui_base::{
14 ferro_class, ferro_class_info, ferro_impl_classes, instantiate, BoxedValue, FerroObjectImpl, Ref,
15 StyledElementImpl, VisualImpl,
16};
17use ferroui_controls::primitives::TemplatedControlImpl;
18use ferroui_controls::{ContentControlImpl, Control, ControlImpl, UserControl};
19use ferroui_controls_treedatagrid::TreeDataGrid;
20use std::rc::Rc;
21
22#[repr(C)]
25pub struct ControlDetailsView {
26 base: UserControl,
27}
28
29ferro_class!(ControlDetailsView: UserControl);
30ferro_impl_classes!(
31 ControlDetailsView: FerroObjectImpl,
32 VisualImpl,
33 LayoutableImpl,
34 InteractiveImpl,
35 InputElementImpl,
36 ControlImpl,
37 TemplatedControlImpl,
38 ContentControlImpl
39);
40impl StyledElementImpl for ControlDetailsView {
41 fn on_data_context_changed(this: &Self) {
42 Self::parent_on_data_context_changed(this);
43
44 if let Some(scroll) = this.find_control::<TreeDataGrid>("DataGrid").and_then(|grid| grid.scroll()) {
48 scroll.set_offset(ferroui_base::Vector::default());
49 }
50 }
51}
52
53ferro_class_info!(ControlDetailsView {
54 new: ControlDetailsView::new,
55 markup: {
56 methods: [
57 fn PropertiesGrid_OnDoubleTapped(Option<BoxedValue>, Rc<dyn IRoutedEventArgs>) =>
58 |this: &Ref<ControlDetailsView>, sender: Option<BoxedValue>, e: Rc<dyn IRoutedEventArgs>| {
59 if let Some(e) = e.downcast_ref::<TappedEventArgs>() {
60 this.properties_grid_on_double_tapped(&sender, e)
61 }
62 },
63 fn PropertyNamePressed(Option<BoxedValue>, Rc<dyn IRoutedEventArgs>) =>
64 |this: &Ref<ControlDetailsView>, sender: Option<BoxedValue>, e: Rc<dyn IRoutedEventArgs>| {
65 if let Some(e) = e.downcast_ref::<PointerPressedEventArgs>() {
66 this.property_name_pressed(&sender, e)
67 }
68 },
69 ],
70 },
71});
72
73fn details_of(value: Option<&BoxedValue>) -> Option<Rc<ControlDetailsViewModel>> {
75 let value = value?;
76 if let Some(details) = value.downcast_ref::<Rc<ControlDetailsViewModel>>() {
77 return Some(details.clone());
78 }
79 let any: Rc<dyn std::any::Any> = value.clone();
80 any.downcast::<ControlDetailsViewModel>().ok()
81}
82
83impl ControlDetailsView {
84 pub const DOCUMENT_URI: &'static str = "ferres://FerroUI.Diagnostics/diagnostics/views/ControlDetailsView.xaml";
86
87 pub fn construct() -> Self {
88 Self { base: UserControl::construct() }
89 }
90
91 pub fn new() -> Ref<Self> {
95 let this = instantiate(Self::construct());
96 Self::initialize_component(&this);
97
98 let _ = this.data_grid();
101
102 this
103 }
104
105 fn initialize_component(this: &Ref<Self>) {
106 crate::register_types();
107 if let Err(error) = crate::compiled_diagnostics_views_control_details_view::populate(None, this) {
108 panic!("{}: {error}", Self::DOCUMENT_URI);
109 }
110 }
111
112 fn data_grid(&self) -> Ref<TreeDataGrid> {
114 self.get_control::<TreeDataGrid>("DataGrid")
115 }
116
117 fn properties_grid_on_double_tapped(&self, sender: &Option<BoxedValue>, _e: &TappedEventArgs) {
118 let grid = sender
119 .as_ref()
120 .and_then(|sender| ValueTypes::as_object(&**sender))
121 .and_then(|sender| sender.cast::<TreeDataGrid>());
122 if let Some(grid) = grid {
123 if let Some(control_details) = details_of(grid.data_context().as_ref()) {
124 control_details.navigate_to_selected_property();
125 }
126 }
127 }
128
129 pub fn property_name_pressed(&self, sender: &Option<BoxedValue>, _e: &PointerPressedEventArgs) {
130 let Some(main_vm) = details_of(self.data_context().as_ref()) else {
131 return;
132 };
133
134 let control = sender
135 .as_ref()
136 .and_then(|sender| ValueTypes::as_object(&**sender))
137 .and_then(|sender| sender.cast::<Control>());
138 let setter_vm = control
139 .and_then(|control| control.data_context())
140 .and_then(|data_context| SetterViewModelRef::from_boxed(&data_context));
141
142 if let Some(setter_vm) = setter_vm {
143 main_vm.select_property(setter_vm.property());
144
145 if let Some(selected_property) = main_vm.selected_property() {
146 let row_index = main_vm
149 .properties_view()
150 .map(|properties_view| properties_view.row_index_of(&selected_property))
151 .unwrap_or(-1);
152 if row_index >= 0 {
153 if let Some(rows_presenter) = self.data_grid().rows_presenter() {
154 rows_presenter.bring_into_view(row_index, None);
155 }
156 }
157 }
158 }
159 }
160}