ferroui_controls/primitives/
headered_content_control.rs1use crate::utils::debug_display::append_optional_boxed_value;
2use super::TemplatedControlImpl;
3use crate::metadata::TemplatePartAttribute;
4use crate::presenters::ContentPresenter;
5use crate::templates::IDataTemplate;
6use crate::{ContentControl, ContentControlImpl, ContentControlImplExt, Control, ControlImpl};
7use ferroui_base::input::InputElementImpl;
8use ferroui_base::interactivity::InteractiveImpl;
9use ferroui_base::layout::LayoutableImpl;
10use ferroui_base::{
11 ferro_class, ferro_impl_classes, ferro_property, instantiate, BoxedValue, FerroObjectImpl,
12 FerroProperty, FerroPropertyChangedEventArgs, Ref, StaticType, StyledElement, StyledElementImpl, StyledProperty,
13 VisualImpl,
14};
15use std::cell::RefCell;
16use std::rc::Rc;
17
18#[repr(C)]
20pub struct HeaderedContentControl {
21 base: ContentControl,
22 header_presenter: RefCell<Option<Ref<ContentPresenter>>>,
23}
24
25ferro_class!(HeaderedContentControl: ContentControl);
26ferroui_base::ferro_class_info!(HeaderedContentControl { new: HeaderedContentControl::new });
27ferro_impl_classes!(
28 HeaderedContentControl: StyledElementImpl,
29 VisualImpl,
30 LayoutableImpl,
31 InteractiveImpl,
32 InputElementImpl,
33 ControlImpl,
34 TemplatedControlImpl
35);
36
37ferroui_base::ferro_impl_classes!(HeaderedContentControl: FerroObjectImpl);
38
39impl ContentControlImpl for HeaderedContentControl {
40 fn register_content_presenter(this: &Self, presenter: &ContentPresenter) -> bool {
41 let mut result = Self::parent_register_content_presenter(this, presenter);
42
43 if presenter.name().as_deref() == Some("PART_HeaderPresenter") {
44 *this.header_presenter.borrow_mut() = Some(presenter.to_ref());
45 result = true;
46 }
47
48 result
49 }
50}
51
52impl HeaderedContentControl {
53 pub const TEMPLATE_PARTS: &'static [TemplatePartAttribute] =
56 &[TemplatePartAttribute::new("PART_HeaderPresenter", <ContentPresenter as StaticType>::TYPE)];
57}
58
59ferroui_base::ferro_properties! { impl HeaderedContentControl {
60 ferro_property!(
61 pub fn header_property() -> StyledProperty<Option<BoxedValue>> {
63 FerroProperty::register::<HeaderedContentControl, _>("Header", None)
64 }
65 );
66
67 ferro_property!(
68 pub fn header_template_property() -> StyledProperty<Option<Rc<dyn IDataTemplate>>> {
70 FerroProperty::register::<HeaderedContentControl, _>("HeaderTemplate", None)
71 }
72 );
73} }
74
75impl HeaderedContentControl {
76 fn static_constructor() {
77 Self::header_property().changed().add_class_handler::<HeaderedContentControl>(|x, e| x.header_changed(e));
78 crate::i_headered::register_headered::<HeaderedContentControl>();
79 }
80
81 pub fn construct() -> Self {
83 Self { base: ContentControl::construct(), header_presenter: RefCell::new(None) }
84 }
85
86 pub fn new() -> Ref<Self> {
87 instantiate(Self::construct())
88 }
89
90 pub fn header(&self) -> Option<BoxedValue> {
92 self.get_value(Self::header_property())
93 }
94
95 pub fn set_header(&self, value: Option<BoxedValue>) {
96 self.set_value(Self::header_property(), value)
97 }
98
99 pub fn header_presenter(&self) -> Option<Ref<ContentPresenter>> {
101 self.header_presenter.borrow().clone()
102 }
103
104 pub fn header_template(&self) -> Option<Rc<dyn IDataTemplate>> {
106 self.get_value(Self::header_template_property())
107 }
108
109 pub fn set_header_template(&self, value: Option<Rc<dyn IDataTemplate>>) {
110 self.set_value(Self::header_template_property(), value)
111 }
112
113 fn header_changed(&self, e: &FerroPropertyChangedEventArgs<'_>) {
114 let (old_value, new_value) = e.get_old_and_new_value::<Option<BoxedValue>>();
115
116 if let Some(old_child) = old_value.as_ref().and_then(Control::logical_from_boxed) {
117 StyledElement::logical_children(self).remove(&old_child);
118 }
119
120 if let Some(new_child) = new_value.as_ref().and_then(Control::logical_from_boxed) {
121 StyledElement::logical_children(self).add(new_child);
122 }
123 }
124}
125
126impl crate::i_headered::IHeadered for HeaderedContentControl {
127 fn header(&self) -> Option<BoxedValue> {
128 HeaderedContentControl::header(self)
129 }
130
131 fn set_header(&self, value: Option<BoxedValue>) {
132 HeaderedContentControl::set_header(self, value)
133 }
134}
135
136impl HeaderedContentControl {
137 pub(crate) fn build_debug_display(&self, builder: &mut String, include_content: bool) {
140 let base: &ContentControl = self;
141 base.build_debug_display(builder, include_content);
142
143 if include_content {
144 append_optional_boxed_value(builder, "Header", self.header().as_ref(), true);
145 }
146 }
147}