#egui #table #widgets #undo-redo #clipboard #row #ui

egui-data-table

A generic data table widget implmentation for egui

8 unstable releases (3 breaking)

new 0.4.0 Nov 21, 2024
0.3.0 Aug 6, 2024
0.2.2 May 11, 2024
0.2.0 Apr 7, 2024
0.1.3 Mar 25, 2024

#153 in GUI

Custom license

110KB
2K SLoC

Latest version Documentation

Data table UI implementation for egui

MSRV is 1.75, with RPITIT

Demo Web Page

Features

  • Undo/Redo for every editions
  • Show/Hide/Reorder columns
  • Row duplication / removal
  • Keyboard navigation
  • Internal clipboard support
  • System clipboard support
  • Tutorials documentation
  • Tidy light mode visuals

Usage

In Cargo.toml, add egui-data-table to your dependencies section

[dependencies]
egui-data-table = "0.1"

Minimal example:

// Use same version of `egui` with this crate!
use egui_data_table::egui;

// Don't need to implement any trait on row data itself.
struct MyRowData(i32, String, bool);

// Every logic is defined in `Viewer`
struct MyRowViewer;

// There are several methods that MUST be implemented to make the viewer work correctly.
impl egui_data_table::RowViewer<MyRowData> for MyRowViewer {
    fn num_columns(&mut self) -> usize {
        3
    }
    
    fn show_cell_view(&mut self, ui: &mut egui::Ui, row: &MyRowData, column: usize) {
        let _ = match column {
            0 => ui.label(format!("{}", row.0)),
            1 => ui.label(&row.1),
            2 => ui.checkbox(&mut { row.2 }, ""),
            _ => unreachable!()
        };
    }
    
    fn show_cell_editor(
        &mut self,
        ui: &mut egui::Ui,
        row: &mut MyRowData,
        column: usize,
    ) -> Option<egui::Response> {
        match column {
            0 => ui.add(egui::DragValue::new(&mut row.0).speed(1.0)),
            1 => {
                egui::TextEdit::multiline(&mut row.1)
                    .desired_rows(1)
                    .code_editor()
                    .show(ui)
                    .response
            }
            2 => ui.checkbox(&mut row.2, ""),
            _ => unreachable!()
        }
        .into() // To make focusing work correctly, valid response must be returned.
    }
    
    fn set_cell_value(&mut self, src: &MyRowData, dst: &mut MyRowData, column: usize) {
        match column {
            0 => dst.0 = src.0,
            1 => dst.1 = src.1.clone(),
            2 => dst.2 = src.2,
            _ => unreachable!()
        }
    }
    
    fn new_empty_row(&mut self) -> MyRowData {
        // Instead of requiring `Default` trait for row data types, the viewer is
        // responsible of providing default creation method.
        MyRowData(0, Default::default(), false)
    }
    
    // fn clone_row(&mut self, src: &MyRowData) -> MyRowData 
    // ^^ Overriding this method is optional. In default, it'll utilize `set_cell_value` which 
    //    would be less performant during huge duplication of lines.
}

fn show(ui: &mut egui::Ui, table: &mut egui_data_table::DataTable<MyRowData>) {
    ui.add(egui_data_table::Renderer::new(
        table,
        &mut { MyRowViewer },
    ));
}

For more details / advanced usage, see demo

Dependencies

~5–11MB
~120K SLoC