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()
}