pub struct TableColumn {
pub header: String,
pub width: ColumnWidth,
pub sortable: bool,
pub align: TextAlign,
}Expand description
A column definition for a table.
Fields§
§header: StringHeader text for this column.
width: ColumnWidthWidth specification.
sortable: boolWhether this column is sortable.
align: TextAlignText alignment for this column.
Implementations§
Source§impl TableColumn
impl TableColumn
Sourcepub fn new(header: impl Into<String>) -> Self
pub fn new(header: impl Into<String>) -> Self
Create a new table column with the given header.
Examples found in repository?
examples/17_table.rs (line 167)
21 fn render(&self, cx: Scope) -> View {
22 let show_help = state!(cx, || false);
23
24 // F1 toggles help
25 cx.use_command(
26 KeyBinding::key(KeyCode::F(1)),
27 with!(show_help => move || show_help.update(|v| *v = !*v)),
28 );
29
30 // Track selected row
31 let selected = state!(cx, || 0usize);
32
33 // Track sort state (column index, ascending)
34 let sort_state = state!(cx, || None::<(usize, bool)>);
35
36 // Sample pod data (like k9s)
37 let base_data = vec![
38 vec![
39 "nginx-pod".to_string(),
40 "Running".to_string(),
41 "12%".to_string(),
42 "256Mi".to_string(),
43 "2h".to_string(),
44 ],
45 vec![
46 "redis-cache".to_string(),
47 "Running".to_string(),
48 "8%".to_string(),
49 "128Mi".to_string(),
50 "5d".to_string(),
51 ],
52 vec![
53 "api-server".to_string(),
54 "Running".to_string(),
55 "45%".to_string(),
56 "512Mi".to_string(),
57 "1h".to_string(),
58 ],
59 vec![
60 "db-postgres".to_string(),
61 "Running".to_string(),
62 "23%".to_string(),
63 "1Gi".to_string(),
64 "3d".to_string(),
65 ],
66 vec![
67 "worker-1".to_string(),
68 "Pending".to_string(),
69 "0%".to_string(),
70 "0Mi".to_string(),
71 "5m".to_string(),
72 ],
73 vec![
74 "worker-2".to_string(),
75 "Running".to_string(),
76 "67%".to_string(),
77 "384Mi".to_string(),
78 "45m".to_string(),
79 ],
80 vec![
81 "frontend".to_string(),
82 "Running".to_string(),
83 "5%".to_string(),
84 "64Mi".to_string(),
85 "12h".to_string(),
86 ],
87 vec![
88 "metrics".to_string(),
89 "CrashLoop".to_string(),
90 "0%".to_string(),
91 "32Mi".to_string(),
92 "2m".to_string(),
93 ],
94 ];
95
96 // Sort data based on current sort state
97 let mut rows = base_data.clone();
98 if let Some((col, ascending)) = sort_state.get() {
99 rows.sort_by(|a, b| {
100 let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101 let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102 if ascending {
103 a_val.cmp(b_val)
104 } else {
105 b_val.cmp(a_val)
106 }
107 });
108 }
109
110 let on_select = with!(selected => move |idx: usize| {
111 selected.set(idx);
112 });
113
114 let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115 sort_state.set(Some((col, asc)));
116 });
117
118 let on_activate = with!(selected => move |idx: usize| {
119 // In a real app, this might open a details view
120 selected.set(idx);
121 });
122
123 let selected_name = rows
124 .get(selected.get())
125 .and_then(|r| r.first())
126 .map(|s| s.as_str())
127 .unwrap_or("None");
128
129 let sort_info = match sort_state.get() {
130 Some((col, asc)) => {
131 let col_name = match col {
132 0 => "NAME",
133 1 => "STATUS",
134 2 => "CPU",
135 3 => "MEMORY",
136 4 => "AGE",
137 _ => "?",
138 };
139 format!(
140 "Sorted by {} ({})",
141 col_name,
142 if asc { "asc" } else { "desc" }
143 )
144 }
145 None => "Unsorted".to_string(),
146 };
147
148 View::vstack()
149 .child(
150 View::styled_text("Pod Dashboard")
151 .color(Color::Cyan)
152 .bold()
153 .build(),
154 )
155 .child(
156 View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157 .dim()
158 .build(),
159 )
160 .child(
161 View::boxed()
162 .flex(1)
163 .border(true)
164 .child(
165 View::table()
166 .column("NAME")
167 .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168 .column_with(
169 TableColumn::new("CPU")
170 .width(ColumnWidth::Fixed(8))
171 .align(TextAlign::Right),
172 )
173 .column_with(
174 TableColumn::new("MEMORY")
175 .width(ColumnWidth::Fixed(10))
176 .align(TextAlign::Right),
177 )
178 .column_with(
179 TableColumn::new("AGE")
180 .width(ColumnWidth::Fixed(8))
181 .align(TextAlign::Right),
182 )
183 .rows(rows)
184 .selected(selected.get())
185 .sort(sort_state.get())
186 .on_select(on_select)
187 .on_sort(on_sort)
188 .on_activate(on_activate)
189 .build(),
190 )
191 .build(),
192 )
193 .child(
194 View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195 .dim()
196 .build(),
197 )
198 .child(
199 View::modal()
200 .visible(show_help.get())
201 .title("Example 17: Table")
202 .on_dismiss(with!(show_help => move || show_help.set(false)))
203 .child(
204 View::vstack()
205 .child(View::styled_text("What you're seeing").bold().build())
206 .child(View::text("• Data table with sortable columns"))
207 .child(View::text("• Row selection and activation"))
208 .child(View::text("• Fixed and flexible column widths"))
209 .child(View::gap(1))
210 .child(View::styled_text("Key concepts").bold().build())
211 .child(View::text("• View::table() for tabular data"))
212 .child(View::text("• TableColumn for column config"))
213 .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214 .child(View::text("• on_sort callback for sorting"))
215 .child(View::gap(1))
216 .child(View::styled_text("Try this").bold().build())
217 .child(View::text("• Navigate rows with arrow keys"))
218 .child(View::text("• Press Enter to activate a row"))
219 .child(View::text("• Sorting is managed via on_sort"))
220 .child(View::gap(1))
221 .child(View::styled_text("Next up").bold().build())
222 .child(View::text("→ 18_progress_bar: progress indicators"))
223 .child(View::gap(1))
224 .child(View::styled_text("Press Escape to close").dim().build())
225 .build(),
226 )
227 .build(),
228 )
229 .build()
230 }Sourcepub fn width(self, width: ColumnWidth) -> Self
pub fn width(self, width: ColumnWidth) -> Self
Set the width of this column.
Examples found in repository?
examples/17_table.rs (line 167)
21 fn render(&self, cx: Scope) -> View {
22 let show_help = state!(cx, || false);
23
24 // F1 toggles help
25 cx.use_command(
26 KeyBinding::key(KeyCode::F(1)),
27 with!(show_help => move || show_help.update(|v| *v = !*v)),
28 );
29
30 // Track selected row
31 let selected = state!(cx, || 0usize);
32
33 // Track sort state (column index, ascending)
34 let sort_state = state!(cx, || None::<(usize, bool)>);
35
36 // Sample pod data (like k9s)
37 let base_data = vec![
38 vec![
39 "nginx-pod".to_string(),
40 "Running".to_string(),
41 "12%".to_string(),
42 "256Mi".to_string(),
43 "2h".to_string(),
44 ],
45 vec![
46 "redis-cache".to_string(),
47 "Running".to_string(),
48 "8%".to_string(),
49 "128Mi".to_string(),
50 "5d".to_string(),
51 ],
52 vec![
53 "api-server".to_string(),
54 "Running".to_string(),
55 "45%".to_string(),
56 "512Mi".to_string(),
57 "1h".to_string(),
58 ],
59 vec![
60 "db-postgres".to_string(),
61 "Running".to_string(),
62 "23%".to_string(),
63 "1Gi".to_string(),
64 "3d".to_string(),
65 ],
66 vec![
67 "worker-1".to_string(),
68 "Pending".to_string(),
69 "0%".to_string(),
70 "0Mi".to_string(),
71 "5m".to_string(),
72 ],
73 vec![
74 "worker-2".to_string(),
75 "Running".to_string(),
76 "67%".to_string(),
77 "384Mi".to_string(),
78 "45m".to_string(),
79 ],
80 vec![
81 "frontend".to_string(),
82 "Running".to_string(),
83 "5%".to_string(),
84 "64Mi".to_string(),
85 "12h".to_string(),
86 ],
87 vec![
88 "metrics".to_string(),
89 "CrashLoop".to_string(),
90 "0%".to_string(),
91 "32Mi".to_string(),
92 "2m".to_string(),
93 ],
94 ];
95
96 // Sort data based on current sort state
97 let mut rows = base_data.clone();
98 if let Some((col, ascending)) = sort_state.get() {
99 rows.sort_by(|a, b| {
100 let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101 let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102 if ascending {
103 a_val.cmp(b_val)
104 } else {
105 b_val.cmp(a_val)
106 }
107 });
108 }
109
110 let on_select = with!(selected => move |idx: usize| {
111 selected.set(idx);
112 });
113
114 let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115 sort_state.set(Some((col, asc)));
116 });
117
118 let on_activate = with!(selected => move |idx: usize| {
119 // In a real app, this might open a details view
120 selected.set(idx);
121 });
122
123 let selected_name = rows
124 .get(selected.get())
125 .and_then(|r| r.first())
126 .map(|s| s.as_str())
127 .unwrap_or("None");
128
129 let sort_info = match sort_state.get() {
130 Some((col, asc)) => {
131 let col_name = match col {
132 0 => "NAME",
133 1 => "STATUS",
134 2 => "CPU",
135 3 => "MEMORY",
136 4 => "AGE",
137 _ => "?",
138 };
139 format!(
140 "Sorted by {} ({})",
141 col_name,
142 if asc { "asc" } else { "desc" }
143 )
144 }
145 None => "Unsorted".to_string(),
146 };
147
148 View::vstack()
149 .child(
150 View::styled_text("Pod Dashboard")
151 .color(Color::Cyan)
152 .bold()
153 .build(),
154 )
155 .child(
156 View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157 .dim()
158 .build(),
159 )
160 .child(
161 View::boxed()
162 .flex(1)
163 .border(true)
164 .child(
165 View::table()
166 .column("NAME")
167 .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168 .column_with(
169 TableColumn::new("CPU")
170 .width(ColumnWidth::Fixed(8))
171 .align(TextAlign::Right),
172 )
173 .column_with(
174 TableColumn::new("MEMORY")
175 .width(ColumnWidth::Fixed(10))
176 .align(TextAlign::Right),
177 )
178 .column_with(
179 TableColumn::new("AGE")
180 .width(ColumnWidth::Fixed(8))
181 .align(TextAlign::Right),
182 )
183 .rows(rows)
184 .selected(selected.get())
185 .sort(sort_state.get())
186 .on_select(on_select)
187 .on_sort(on_sort)
188 .on_activate(on_activate)
189 .build(),
190 )
191 .build(),
192 )
193 .child(
194 View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195 .dim()
196 .build(),
197 )
198 .child(
199 View::modal()
200 .visible(show_help.get())
201 .title("Example 17: Table")
202 .on_dismiss(with!(show_help => move || show_help.set(false)))
203 .child(
204 View::vstack()
205 .child(View::styled_text("What you're seeing").bold().build())
206 .child(View::text("• Data table with sortable columns"))
207 .child(View::text("• Row selection and activation"))
208 .child(View::text("• Fixed and flexible column widths"))
209 .child(View::gap(1))
210 .child(View::styled_text("Key concepts").bold().build())
211 .child(View::text("• View::table() for tabular data"))
212 .child(View::text("• TableColumn for column config"))
213 .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214 .child(View::text("• on_sort callback for sorting"))
215 .child(View::gap(1))
216 .child(View::styled_text("Try this").bold().build())
217 .child(View::text("• Navigate rows with arrow keys"))
218 .child(View::text("• Press Enter to activate a row"))
219 .child(View::text("• Sorting is managed via on_sort"))
220 .child(View::gap(1))
221 .child(View::styled_text("Next up").bold().build())
222 .child(View::text("→ 18_progress_bar: progress indicators"))
223 .child(View::gap(1))
224 .child(View::styled_text("Press Escape to close").dim().build())
225 .build(),
226 )
227 .build(),
228 )
229 .build()
230 }Sourcepub fn align(self, align: TextAlign) -> Self
pub fn align(self, align: TextAlign) -> Self
Set the text alignment for this column.
Examples found in repository?
examples/17_table.rs (line 171)
21 fn render(&self, cx: Scope) -> View {
22 let show_help = state!(cx, || false);
23
24 // F1 toggles help
25 cx.use_command(
26 KeyBinding::key(KeyCode::F(1)),
27 with!(show_help => move || show_help.update(|v| *v = !*v)),
28 );
29
30 // Track selected row
31 let selected = state!(cx, || 0usize);
32
33 // Track sort state (column index, ascending)
34 let sort_state = state!(cx, || None::<(usize, bool)>);
35
36 // Sample pod data (like k9s)
37 let base_data = vec![
38 vec![
39 "nginx-pod".to_string(),
40 "Running".to_string(),
41 "12%".to_string(),
42 "256Mi".to_string(),
43 "2h".to_string(),
44 ],
45 vec![
46 "redis-cache".to_string(),
47 "Running".to_string(),
48 "8%".to_string(),
49 "128Mi".to_string(),
50 "5d".to_string(),
51 ],
52 vec![
53 "api-server".to_string(),
54 "Running".to_string(),
55 "45%".to_string(),
56 "512Mi".to_string(),
57 "1h".to_string(),
58 ],
59 vec![
60 "db-postgres".to_string(),
61 "Running".to_string(),
62 "23%".to_string(),
63 "1Gi".to_string(),
64 "3d".to_string(),
65 ],
66 vec![
67 "worker-1".to_string(),
68 "Pending".to_string(),
69 "0%".to_string(),
70 "0Mi".to_string(),
71 "5m".to_string(),
72 ],
73 vec![
74 "worker-2".to_string(),
75 "Running".to_string(),
76 "67%".to_string(),
77 "384Mi".to_string(),
78 "45m".to_string(),
79 ],
80 vec![
81 "frontend".to_string(),
82 "Running".to_string(),
83 "5%".to_string(),
84 "64Mi".to_string(),
85 "12h".to_string(),
86 ],
87 vec![
88 "metrics".to_string(),
89 "CrashLoop".to_string(),
90 "0%".to_string(),
91 "32Mi".to_string(),
92 "2m".to_string(),
93 ],
94 ];
95
96 // Sort data based on current sort state
97 let mut rows = base_data.clone();
98 if let Some((col, ascending)) = sort_state.get() {
99 rows.sort_by(|a, b| {
100 let a_val = a.get(col).map(|s| s.as_str()).unwrap_or("");
101 let b_val = b.get(col).map(|s| s.as_str()).unwrap_or("");
102 if ascending {
103 a_val.cmp(b_val)
104 } else {
105 b_val.cmp(a_val)
106 }
107 });
108 }
109
110 let on_select = with!(selected => move |idx: usize| {
111 selected.set(idx);
112 });
113
114 let on_sort = with!(sort_state => move |col: usize, asc: bool| {
115 sort_state.set(Some((col, asc)));
116 });
117
118 let on_activate = with!(selected => move |idx: usize| {
119 // In a real app, this might open a details view
120 selected.set(idx);
121 });
122
123 let selected_name = rows
124 .get(selected.get())
125 .and_then(|r| r.first())
126 .map(|s| s.as_str())
127 .unwrap_or("None");
128
129 let sort_info = match sort_state.get() {
130 Some((col, asc)) => {
131 let col_name = match col {
132 0 => "NAME",
133 1 => "STATUS",
134 2 => "CPU",
135 3 => "MEMORY",
136 4 => "AGE",
137 _ => "?",
138 };
139 format!(
140 "Sorted by {} ({})",
141 col_name,
142 if asc { "asc" } else { "desc" }
143 )
144 }
145 None => "Unsorted".to_string(),
146 };
147
148 View::vstack()
149 .child(
150 View::styled_text("Pod Dashboard")
151 .color(Color::Cyan)
152 .bold()
153 .build(),
154 )
155 .child(
156 View::styled_text(format!("Selected: {} | {}", selected_name, sort_info))
157 .dim()
158 .build(),
159 )
160 .child(
161 View::boxed()
162 .flex(1)
163 .border(true)
164 .child(
165 View::table()
166 .column("NAME")
167 .column_with(TableColumn::new("STATUS").width(ColumnWidth::Fixed(12)))
168 .column_with(
169 TableColumn::new("CPU")
170 .width(ColumnWidth::Fixed(8))
171 .align(TextAlign::Right),
172 )
173 .column_with(
174 TableColumn::new("MEMORY")
175 .width(ColumnWidth::Fixed(10))
176 .align(TextAlign::Right),
177 )
178 .column_with(
179 TableColumn::new("AGE")
180 .width(ColumnWidth::Fixed(8))
181 .align(TextAlign::Right),
182 )
183 .rows(rows)
184 .selected(selected.get())
185 .sort(sort_state.get())
186 .on_select(on_select)
187 .on_sort(on_sort)
188 .on_activate(on_activate)
189 .build(),
190 )
191 .build(),
192 )
193 .child(
194 View::styled_text("↑↓/jk: navigate | Enter: activate | F1 help | Ctrl+Q: quit")
195 .dim()
196 .build(),
197 )
198 .child(
199 View::modal()
200 .visible(show_help.get())
201 .title("Example 17: Table")
202 .on_dismiss(with!(show_help => move || show_help.set(false)))
203 .child(
204 View::vstack()
205 .child(View::styled_text("What you're seeing").bold().build())
206 .child(View::text("• Data table with sortable columns"))
207 .child(View::text("• Row selection and activation"))
208 .child(View::text("• Fixed and flexible column widths"))
209 .child(View::gap(1))
210 .child(View::styled_text("Key concepts").bold().build())
211 .child(View::text("• View::table() for tabular data"))
212 .child(View::text("• TableColumn for column config"))
213 .child(View::text("• ColumnWidth::Fixed or ColumnWidth::Flex"))
214 .child(View::text("• on_sort callback for sorting"))
215 .child(View::gap(1))
216 .child(View::styled_text("Try this").bold().build())
217 .child(View::text("• Navigate rows with arrow keys"))
218 .child(View::text("• Press Enter to activate a row"))
219 .child(View::text("• Sorting is managed via on_sort"))
220 .child(View::gap(1))
221 .child(View::styled_text("Next up").bold().build())
222 .child(View::text("→ 18_progress_bar: progress indicators"))
223 .child(View::gap(1))
224 .child(View::styled_text("Press Escape to close").dim().build())
225 .build(),
226 )
227 .build(),
228 )
229 .build()
230 }Trait Implementations§
Source§impl Clone for TableColumn
impl Clone for TableColumn
Source§fn clone(&self) -> TableColumn
fn clone(&self) -> TableColumn
Returns a duplicate of the value. Read more
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
Performs copy-assignment from
source. Read moreAuto Trait Implementations§
impl Freeze for TableColumn
impl RefUnwindSafe for TableColumn
impl Send for TableColumn
impl Sync for TableColumn
impl Unpin for TableColumn
impl UnwindSafe for TableColumn
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Convert
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Convert
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
Convert
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
Convert
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.