ferroui_controls/presenters/
table_view_cells_presenter.rs1use super::table_view_layout_helper::TableViewLayoutHelper;
2use crate::{ControlImpl, Panel, PanelImpl, TableViewCell, TableViewRow};
3use ferroui_base::input::InputElementImpl;
4use ferroui_base::interactivity::InteractiveImpl;
5use ferroui_base::layout::{LayoutHelper, LayoutableImpl};
6use ferroui_base::{
7 ferro_class, ferro_class_info, ferro_impl_classes, instantiate, FerroObjectImpl, Ref, Size, StyledElement,
8 StyledElementImpl, VisualImpl, WeakRef,
9};
10use std::cell::RefCell;
11
12#[repr(C)]
19pub struct TableViewCellsPresenter {
20 base: Panel,
21 row: RefCell<Option<WeakRef<TableViewRow>>>,
23}
24
25ferro_class!(TableViewCellsPresenter: Panel);
26ferro_class_info!(TableViewCellsPresenter { new: TableViewCellsPresenter::new });
27ferro_impl_classes!(
28 TableViewCellsPresenter: FerroObjectImpl,
29 StyledElementImpl,
30 VisualImpl,
31 InteractiveImpl,
32 InputElementImpl,
33 ControlImpl,
34 PanelImpl
35);
36
37impl LayoutableImpl for TableViewCellsPresenter {
38 fn measure_override(this: &Self, available_size: Size) -> Size {
39 let Some(columns) = this.row().and_then(|row| row.columns()) else { return Size::default() };
40
41 if TableViewLayoutHelper::needs_actual_widths(&columns) {
45 TableViewLayoutHelper::update_actual_widths(
46 &columns,
47 available_size.width,
48 this.use_layout_rounding(),
49 LayoutHelper::get_layout_scale(this),
50 );
51 }
52
53 TableViewLayoutHelper::measure_row(&columns, &this.children(), available_size)
54 }
55
56 fn arrange_override(this: &Self, final_size: Size) -> Size {
57 let Some(columns) = this.row().and_then(|row| row.columns()) else { return final_size };
58
59 if TableViewLayoutHelper::needs_actual_widths(&columns) {
60 TableViewLayoutHelper::update_actual_widths(
61 &columns,
62 final_size.width,
63 this.use_layout_rounding(),
64 LayoutHelper::get_layout_scale(this),
65 );
66 }
67
68 TableViewLayoutHelper::arrange_row(&columns, &this.children(), final_size, 0.0)
69 }
70}
71
72impl TableViewCellsPresenter {
73 pub fn construct() -> Self {
75 Self { base: Panel::construct(), row: RefCell::new(None) }
76 }
77
78 pub fn new() -> Ref<Self> {
79 instantiate(Self::construct())
80 }
81
82 pub(crate) fn row(&self) -> Option<Ref<TableViewRow>> {
83 self.row.borrow().as_ref().and_then(WeakRef::upgrade)
84 }
85
86 pub(crate) fn set_row(&self, value: Option<&Ref<TableViewRow>>) {
87 *self.row.borrow_mut() = value.map(Ref::downgrade);
88 }
89
90 pub(crate) fn clear_cells(&self) {
91 for child in self.children().snapshot().iter() {
92 if let Some(cell) = child.downcast_ref::<TableViewCell>() {
93 cell.set_column(None);
94 }
95 }
96 }
97
98 pub(crate) fn remove_cells(&self) {
99 self.clear_cells();
100 self.children().clear();
101 if let Some(row) = self.row() {
102 StyledElement::logical_children(&row).clear();
103 }
104 }
105
106 pub(crate) fn rebuild_cells(&self) {
107 let row = self.row();
108 let Some((row, columns)) = row.and_then(|row| row.columns().map(|columns| (row, columns))) else {
109 self.remove_cells();
110 return;
111 };
112
113 let children = self.children();
114 let columns = columns.snapshot();
115
116 if columns.len() != children.count() {
117 self.remove_cells();
118
119 for column in columns.iter() {
120 let cell = TableViewCell::new();
121 cell.set_column(Some(column.clone()));
122 children.add(cell);
123 }
124
125 StyledElement::logical_children(&row)
126 .add_range(children.snapshot().iter().map(|child| child.clone().upcast::<StyledElement>()));
127 } else {
128 for (child, column) in children.snapshot().iter().zip(columns.iter()) {
129 Self::cell(child).set_column(Some(column.clone()));
130 }
131 }
132
133 self.invalidate_measure();
134 }
135
136 pub(crate) fn refresh_cell(&self, column_index: usize) {
137 Self::cell(&self.children().get(column_index)).refresh();
138 }
139
140 fn cell(child: &Ref<crate::Control>) -> &TableViewCell {
142 child.downcast_ref::<TableViewCell>().unwrap_or_else(|| {
143 panic!(
144 "Unable to cast object of type '{}' to type '{}'.",
145 child.get_type().name(),
146 <TableViewCell as ferroui_base::StaticType>::TYPE.name()
147 )
148 })
149 }
150}