egui_data_table/lib.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
#![doc = include_str!("../README.md")]
pub mod draw;
pub mod viewer;
pub use draw::Renderer;
pub use viewer::{RowViewer, UiAction};
/// You may want to sync egui version with this crate.
pub extern crate egui;
/* ---------------------------------------------------------------------------------------------- */
/* CORE CLASS */
/* ---------------------------------------------------------------------------------------------- */
/// Prevents direct modification of `Vec`
pub struct DataTable<R> {
/// Efficient row data storage
///
/// XXX: If we use `VecDeque` here, it'd be more efficient when inserting new element
/// at the beginning of the list. However, it does not support `splice` method like
/// `Vec`, which results in extremely inefficient when there's multiple insertions.
///
/// The efficiency order of general operations are only twice as slow when using
/// `Vec`, we're just ignoring it for now. Maybe we can utilize `IndexMap` for this
/// purpose, however, there are many trade-offs to consider, for now, we're just
/// using `Vec` for simplicity.
rows: Vec<R>,
/// Is Dirty?
dirty_flag: bool,
/// Ui
ui: Option<Box<draw::state::UiState<R>>>,
}
impl<R: std::fmt::Debug> std::fmt::Debug for DataTable<R> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Spreadsheet")
.field("rows", &self.rows)
.finish()
}
}
impl<R> Default for DataTable<R> {
fn default() -> Self {
Self {
rows: Default::default(),
ui: Default::default(),
dirty_flag: false,
}
}
}
impl<R> FromIterator<R> for DataTable<R> {
fn from_iter<T: IntoIterator<Item = R>>(iter: T) -> Self {
Self {
rows: iter.into_iter().collect(),
..Default::default()
}
}
}
impl<R> DataTable<R> {
pub fn new() -> Self {
Default::default()
}
pub fn len(&self) -> usize {
self.rows.len()
}
pub fn is_empty(&self) -> bool {
self.rows.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &R> {
self.rows.iter()
}
pub fn take(&mut self) -> Vec<R> {
self.ui = None;
std::mem::take(&mut self.rows)
}
pub fn replace(&mut self, new: Vec<R>) -> Vec<R> {
self.ui = None;
std::mem::replace(&mut self.rows, new)
}
pub fn retain(&mut self, mut f: impl FnMut(&R) -> bool) {
let mut removed_any = false;
self.rows.retain(|row| {
let retain = f(row);
removed_any |= !retain;
retain
});
if removed_any {
self.ui = None;
}
}
pub fn clear_dirty_flag(&mut self) {
self.dirty_flag = false;
}
pub fn is_dirty(&self) -> bool {
self.dirty_flag
}
pub fn has_user_modification(&self) -> bool {
self.dirty_flag
}
pub fn clear_user_modification_flag(&mut self) {
self.dirty_flag = false;
}
}
impl<R> Extend<R> for DataTable<R> {
/// Programmatic extend operation will invalidate the index table cache.
fn extend<T: IntoIterator<Item = R>>(&mut self, iter: T) {
// Invalidate the cache
self.ui = None;
self.rows.extend(iter);
}
}
fn default<T: Default>() -> T {
T::default()
}