1use super::{
2 MultiPage, MultiPageImpl, NavigatedFromEventArgs, NavigatedToEventArgs, NavigationType, Page, PageImpl,
3 PageSelectionChangedEventArgs,
4};
5use crate::primitives::TemplatedControlImpl;
6use crate::ControlImpl;
7use ferroui_base::input::InputElementImpl;
8use ferroui_base::interactivity::{
9 Interactive, InteractiveImpl, RoutedEvent, RoutedEventHandlerToken, RoutingStrategies,
10};
11use ferroui_base::layout::LayoutableImpl;
12use ferroui_base::{
13 ferro_class, ferro_class_info, ferro_impl_classes, ferro_properties, ferro_routed_event, DirectProperty,
14 FerroObjectImpl, FerroProperty, Ref, StyledElementImpl, VisualImpl,
15};
16use std::cell::{Cell, RefCell};
17
18#[repr(C)]
22pub struct SelectingMultiPage {
23 base: MultiPage,
24 selected_index: Cell<i32>,
25 selected_page: RefCell<Option<Ref<Page>>>,
26}
27
28ferro_class! {
29 SelectingMultiPage: MultiPage, virtuals SelectingMultiPageImpl: MultiPageImpl {
30 fn apply_selected_index(this, index: i32);
32 }
33}
34
35ferro_class_info!(SelectingMultiPage {});
36
37ferro_impl_classes!(
38 SelectingMultiPage: FerroObjectImpl,
39 StyledElementImpl,
40 VisualImpl,
41 LayoutableImpl,
42 InteractiveImpl,
43 InputElementImpl,
44 ControlImpl,
45 TemplatedControlImpl,
46 PageImpl,
47 MultiPageImpl
48);
49
50impl SelectingMultiPageImpl for SelectingMultiPage {
51 fn apply_selected_index(_this: &Self, _index: i32) {
52 panic!("SelectingMultiPage is abstract.")
53 }
54}
55
56ferro_properties! {
57 impl SelectingMultiPage {
58 pub fn selected_index_property() -> DirectProperty<SelectingMultiPage, i32> {
60 FerroProperty::register_direct::<SelectingMultiPage, _>(
61 "SelectedIndex",
62 |o| o.selected_index(),
63 Some(|o, v| o.set_selected_index(v)),
64 0,
65 )
66 }
67
68 pub fn selected_page_property() -> DirectProperty<SelectingMultiPage, Option<Ref<Page>>> {
70 FerroProperty::register_direct::<SelectingMultiPage, _>("SelectedPage", |o| o.selected_page(), None, None)
71 }
72 }
73}
74
75impl SelectingMultiPage {
76 ferro_routed_event!(
77 pub fn selection_changed_event() -> RoutedEvent<PageSelectionChangedEventArgs> {
79 RoutedEvent::register::<SelectingMultiPage, _>("SelectionChanged", RoutingStrategies::BUBBLE)
80 }
81 );
82
83 pub fn construct() -> Self {
85 Self { base: MultiPage::construct(), selected_index: Cell::new(-1), selected_page: RefCell::new(None) }
86 }
87
88 pub fn selected_index(&self) -> i32 {
90 self.selected_index.get()
91 }
92
93 pub fn set_selected_index(&self, value: i32) {
94 self.apply_selected_index(value)
95 }
96
97 pub fn selected_page(&self) -> Option<Ref<Page>> {
99 self.selected_page.borrow().clone()
100 }
101
102 pub fn selection_changed(
104 &self,
105 handler: impl Fn(&Interactive, &PageSelectionChangedEventArgs) + 'static,
106 ) -> RoutedEventHandlerToken {
107 self.add_handler(Self::selection_changed_event(), handler)
108 }
109
110 pub fn commit_selection(&self, new_index: i32, new_page: Option<Ref<Page>>, navigation_type: NavigationType) {
118 let previous_page = self.selected_page();
119 self.set_and_raise_cell(Self::selected_index_property(), &self.selected_index, new_index);
120 self.set_and_raise(Self::selected_page_property(), &self.selected_page, new_page.clone());
121 self.set_current_value(Page::current_page_property(), new_page.clone());
122 if !same_page(&previous_page, &new_page) {
123 self.raise_event(&PageSelectionChangedEventArgs::new(
124 Some(Self::selection_changed_event()),
125 previous_page.clone(),
126 new_page.clone(),
127 ));
128
129 if let Some(previous_page) = &previous_page {
130 previous_page.send_navigated_from(&NavigatedFromEventArgs::new(new_page.clone(), navigation_type));
131 }
132
133 if let Some(new_page) = &new_page {
134 new_page.send_navigated_to(&NavigatedToEventArgs::new(previous_page, navigation_type));
135 }
136 }
137 }
138
139 pub fn store_selected_index(&self, index: i32) {
141 self.set_and_raise_cell(Self::selected_index_property(), &self.selected_index, index);
142 }
143
144 pub fn resolve_page_at_index(&self, index: i32) -> Option<Ref<Page>> {
147 let pages = self.pages()?;
148 if index < 0 {
149 return None;
150 }
151 pages.try_get(index as usize)
152 }
153}
154
155pub(crate) fn same_page(a: &Option<Ref<Page>>, b: &Option<Ref<Page>>) -> bool {
157 match (a, b) {
158 (None, None) => true,
159 (Some(a), Some(b)) => a.ptr_eq(b),
160 _ => false,
161 }
162}