1#![doc(html_root_url = "https://docs.rs/egui-dataframe/0.3.3")]
2use eframe::{self, egui::*};
6use egui_grid::GridBuilder;
7use egui_extras::{Size, TableBuilder, Column};
8use polars::prelude::{DataFrame, Schema}; #[derive(Debug, Clone)]
12pub struct Decorator {
13 pub sz: Vec2,
15 pub sense: Sense,
17 pub cols: Vec<Option<Color32>>,
19 pub align: Align2,
21 pub ofs: Vec2,
23 pub fontid: FontId
25}
26
27impl Decorator {
29 pub fn opt(v: &[Color32]) -> Vec<Option<Color32>> {
31 v.iter().map(|c| Some(*c)).collect::<Vec<_>>()
32 }
33
34 pub fn new(sz: Vec2, sense: Sense, cols: Vec<Option<Color32>>,
36 align: Align2, ofs: Vec2, fontid: FontId) -> Self {
37 Decorator{sz, sense, cols, align, ofs, fontid}
38 }
39
40 pub fn disp(&self, ui: &mut Ui, txt: &str) -> Option<(Response, Painter)> {
45 let (bgr, bgc, fgc) = (self.cols[0], self.cols[1], self.cols[2]);
46 if let Some(fgc) = fgc {
47 let (resp, painter) = ui.allocate_painter(self.sz, self.sense);
48 let rc = resp.rect;
49 if let Some(bgr) = bgr {
51 if let Some(bgc) = bgc {
52 painter.rect(rc, 0.0, bgc, Stroke{width: 1.0, color: bgr});
53 }
54 }
55 painter.text(rc.min + self.ofs, self.align, txt,
56 self.fontid.clone(), fgc);
57 Some((resp, painter))
58 }else{
59 ui.label(RichText::new(txt)
60 .size(self.fontid.size).family(self.fontid.family.clone()));
61 None
62 }
63 }
64}
65
66pub type DecoFunc<'a> = &'a mut dyn FnMut(&Decorator, &mut Ui, &str,
68 usize, usize) -> bool;
69
70pub struct DecoFs<'a> {
72 pub fncs: (DecoFunc<'a>, DecoFunc<'a>)
74}
75
76impl<'a> DecoFs<'a> {
78 pub fn default(d: &Decorator, ui: &mut Ui, tx: &str,
80 _ri: usize, _ci: usize) -> bool {
81 let _resp_painter = d.disp(ui, tx);
82 true
83 }
84}
85
86#[derive(Debug, Clone)]
88pub struct DFDesc {
89 pub default_deco: (Decorator, Decorator),
91 pub deco: Vec<(Option<Decorator>, Option<Decorator>)>,
93 pub schema: Schema
95}
96
97impl DFDesc {
99 pub fn new(default_deco: (Decorator, Decorator), schema: Schema) -> Self {
101 let n = schema.len();
102 DFDesc{default_deco,
103 deco: Vec::<(Option<Decorator>, Option<Decorator>)>::with_capacity(n),
104 schema}
105 }
106
107 pub fn all_from(mut self,
109 deco: Vec<(Option<Decorator>, Option<Decorator>)>) -> Self {
110 self.deco = deco; self
112 }
113
114 pub fn all_default(mut self) -> Self {
116 for _i in 0..self.schema.len() { self.push((None, None)) }
117 self
118 }
119
120 pub fn push(&mut self, deco: (Option<Decorator>, Option<Decorator>)) {
122 self.deco.push(deco);
123 }
124
125 pub fn disp<'a>(&'a self, ui: &'a mut Ui, f: &mut DecoFs, df: &DataFrame,
127 height_head: f32, height_body: f32, resizable: bool, striped: bool,
128 vscroll: bool) {
129 let (nrows, ncols) = (df.height(), df.width());
130 let cols = df.get_column_names();
131 TableBuilder::new(ui).columns(Column::auto().resizable(resizable), ncols)
132 .resizable(resizable)
133 .striped(striped)
134 .vscroll(vscroll)
135 .header(height_head, |mut header| {
136 for (i, head) in cols.iter().enumerate() {
137 header.col(|ui| {
138 let tx = format!("{}", head);
139 let d = if self.deco.len() == 0 { &self.default_deco.0 } else {
140 match &self.deco[i] {
141 (None, _) => &self.default_deco.0,
142 (Some(deco_head), _) => deco_head
143 }
144 };
145 f.fncs.0(d, ui, &tx, 0, i);
146 });
148 }
149 })
150 .body(|body| {
151 body.rows(height_body, nrows, |ri, mut row| {
152 for (i, col) in cols.iter().enumerate() {
153 row.col(|ui| {
154 if let Ok(column) = &df.column(col) {
155let value = column.get(ri);
157 let tx = format!("{}", value);
158 let d = if self.deco.len() == 0 { &self.default_deco.1 } else {
159 match &self.deco[i] {
160 (_, None) => &self.default_deco.1,
161 (_, Some(deco_body)) => deco_body
162 }
163 };
164 f.fncs.1(d, ui, &tx, ri, i);
165 }
168 });
169 }
170 });
171 });
172 }
173
174 pub fn grid<'a>(&'a self, ui: &'a mut Ui, f: &mut DecoFs, df: &DataFrame,
177 width: f32, height: f32, ts: &TextStyle,
178 sp: &(f32, f32), ma: &style::Margin) {
179 let (nrows, ncols) = (df.height(), df.width());
180 ui.style_mut().override_text_style = Some(ts.clone());
181 let mut gb = GridBuilder::new().spacing(sp.0, sp.1).clip(true);
182 gb = (0..nrows).into_iter().fold(gb, |gb, _i|
183 (0..ncols).into_iter().fold(gb.new_row(Size::exact(height)), |gb, _j|
184 gb.cell(Size::exact(width)).with_margin(ma.clone())
185 )
187 );
188 gb.show(ui, |mut grid| {
189 let cols = df.get_column_names();
190 for j in 0..nrows {
191 for (i, col) in cols.iter().enumerate() {
192 grid.cell(|ui| {
194 if let Ok(column) = &df.column(col) {
195let value = column.get(j);
197 let tx = format!("{}", value);
198 let d = if self.deco.len() == 0 { &self.default_deco.1 } else {
199 match &self.deco[i] {
200 (_, None) => &self.default_deco.1,
201 (_, Some(deco_body)) => deco_body
202 }
203 };
204 f.fncs.1(d, ui, &tx, j, i);
205 }
208 });
209 }
210 }
211 });
212 }
213}
214
215#[cfg(test)]
217mod tests {
218 use super::*;
219
220 #[test]
230 fn test_dataframe() {
231 assert_eq!(Decorator::opt(&[Color32::RED, Color32::GREEN]),
232 [Some(Color32::RED), Some(Color32::GREEN)]);
233 }
234}