egui-data-table 0.10.0

A generic data table widget implmentation for egui
Documentation
use tap::prelude::Pipe;

macro_rules! int_ty {
(
    $(#[$meta:meta])*
    struct $name:ident ($($ty:ty),+); $($rest:tt)*) => {
    #[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
    $(#[$meta])*
    pub(crate) struct $name($(pub(in crate::draw) $ty),+);

    int_ty!($($rest)*);
};
() => {}
}

int_ty!(
    struct VisLinearIdx(usize);
    struct VisSelection(VisLinearIdx, VisLinearIdx);
    struct RowSlabIndex(usize);

    struct RowIdx(usize);
    struct VisRowPos(usize);
    struct VisRowOffset(usize);
    struct VisColumnPos(usize);

    #[cfg_attr(feature = "persistency", derive(serde::Serialize, serde::Deserialize))]
    struct IsAscending(bool);
    #[cfg_attr(feature = "persistency", derive(serde::Serialize, serde::Deserialize))]
    struct ColumnIdx(usize);
);

impl VisSelection {
    pub fn contains(&self, ncol: usize, row: VisRowPos, col: VisColumnPos) -> bool {
        let (top, left) = self.0.row_col(ncol);
        let (bottom, right) = self.1.row_col(ncol);

        row.0 >= top.0 && row.0 <= bottom.0 && col.0 >= left.0 && col.0 <= right.0
    }

    pub fn contains_rect(&self, ncol: usize, other: Self) -> bool {
        let (top, left) = self.0.row_col(ncol);
        let (bottom, right) = self.1.row_col(ncol);

        let (other_top, other_left) = other.0.row_col(ncol);
        let (other_bottom, other_right) = other.1.row_col(ncol);

        other_top.0 >= top.0
            && other_bottom.0 <= bottom.0
            && other_left.0 >= left.0
            && other_right.0 <= right.0
    }

    pub fn from_points(ncol: usize, a: VisLinearIdx, b: VisLinearIdx) -> Self {
        let (a_r, a_c) = a.row_col(ncol);
        let (b_r, b_c) = b.row_col(ncol);

        let top = a_r.0.min(b_r.0);
        let bottom = a_r.0.max(b_r.0);
        let left = a_c.0.min(b_c.0);
        let right = a_c.0.max(b_c.0);

        Self(
            VisLinearIdx(top * ncol + left),
            VisLinearIdx(bottom * ncol + right),
        )
    }

    pub fn is_point(&self) -> bool {
        self.0 == self.1
    }

    pub fn union(&self, ncol: usize, other: Self) -> Self {
        let (top, left) = self.0.row_col(ncol);
        let (bottom, right) = self.1.row_col(ncol);

        let (other_top, other_left) = other.0.row_col(ncol);
        let (other_bottom, other_right) = other.1.row_col(ncol);

        let top = top.0.min(other_top.0);
        let left = left.0.min(other_left.0);
        let bottom = bottom.0.max(other_bottom.0);
        let right = right.0.max(other_right.0);

        Self(
            VisLinearIdx(top * ncol + left),
            VisLinearIdx(bottom * ncol + right),
        )
    }

    pub fn _from_row_col(ncol: usize, r: VisRowPos, c: VisColumnPos) -> Self {
        r.linear_index(ncol, c).pipe(|idx| Self(idx, idx))
    }
}

impl From<VisLinearIdx> for VisSelection {
    fn from(value: VisLinearIdx) -> Self {
        Self(value, value)
    }
}

impl VisLinearIdx {
    pub fn row_col(&self, ncol: usize) -> (VisRowPos, VisColumnPos) {
        let (row, col) = (self.0 / ncol, self.0 % ncol);
        (VisRowPos(row), VisColumnPos(col))
    }
}

impl VisRowPos {
    pub fn linear_index(&self, ncol: usize, col: VisColumnPos) -> VisLinearIdx {
        VisLinearIdx(self.0 * ncol + col.0)
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum SelectionModifier {
    None,
    Toggle,
    Extend,
}