egui_tabular 0.1.0

Customizable egui table viewer and editor
Documentation
use rvariant::Variant;

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CellKind {
    /// Column is stored and processed by backend in a defined data structure.
    /// Renaming, changing type and removing is not permitted.
    Static(StaticCellKind),
    /// Type, name, description and other parameters are stored globally and can be reused.
    /// Global parameter's name and type can be changed through other tool, but not from TableViewer's.
    /// Can be removed.
    Global,
    /// Column exists only in the context of a particular table, even if it's name is the same.
    /// Name and type can be freely changed. Can be removed.
    Adhoc,
    // needed?
    // Calculated with an expression from other cells around
}

impl CellKind {
    pub const GLOBAL_DOC: &'static str = "Global parameter, can be used everywhere, same type is enforced\nand you can add short names and other metadata";
    pub const ADHOC_DOC: &'static str =
        "Adhoc parameter, can be removed or edited without any side-effects";
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum StaticCellKind {
    /// Column's cells simply store data with a specified type.
    Plain,
    /// Changing cell value will cause some other cells to change as well.
    /// e.g. kind column that chooses what parameters are available or not.
    /// Must be soft-committed? in online mode even if local edit mode is enabled, in order to receive
    /// updated cells types / values.
    CausesSideEffects,
    /// Cells values are auto generated by backend, thus they are also read only.
    AutoGenerated,
}

impl StaticCellKind {
    pub const PLAIN_DOC: &'static str =
        "Parameter stored in a proper data structure and processed by the system";
    pub const CAUSES_SIDE_EFFECTS_DOC: &'static str =
        "Changing this parameter will cause others to recalculate\nor cause other side effects";
    pub const AUTO_GENERATED_DOC: &'static str =
        "This columns is not actually stored, but calculated from other local or global data";
}

/// row, col
#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct CellCoord(pub u32, pub u32);

pub enum TableCellRef<'a> {
    Never,
    Empty,
    Available {
        value: &'a Variant,
        /// true if cell contains uncommitted data
        is_dirty: bool,
        /// Cell was modified locally and then remotely as well
        in_conflict: bool,
    },
}

impl<'a> TableCellRef<'a> {
    pub fn get_ref(&self) -> Option<&Variant> {
        if let TableCellRef::Available { value, .. } = self {
            Some(value)
        } else {
            None
        }
    }

    pub fn get_if_str(&self) -> Option<&str> {
        if let TableCellRef::Available { value, .. } = self {
            if let Variant::Str(s) = value {
                Some(s.as_str())
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn get_if_string(&self) -> Option<String> {
        if let TableCellRef::Available { value, .. } = self {
            if let Variant::Str(s) = value {
                Some(s.clone())
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn get_if_u32(&self) -> Option<u32> {
        if let TableCellRef::Available { value, .. } = self {
            if let Variant::U32(x) = value {
                Some(*x)
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn get_if_enum(&self, enum_uid: u32) -> Option<u32> {
        if let TableCellRef::Available { value, .. } = self {
            if let Variant::Enum {
                enum_uid: uid,
                discriminant,
            } = value
            {
                if *uid == enum_uid {
                    Some(*discriminant)
                } else {
                    None
                }
            } else {
                None
            }
        } else {
            None
        }
    }

    pub fn is_empty(&self) -> bool {
        matches!(self, TableCellRef::Empty)
    }
}

pub enum TableCell {
    Never,
    Available {
        value: Variant,
        /// true if cell contains uncommitted data
        is_dirty: bool,
        /// Cell was modified locally and then remotely as well
        in_conflict: bool,
    },
}

impl TableCell {
    pub fn new(value: Variant) -> Self {
        TableCell::Available {
            value,
            is_dirty: false,
            in_conflict: false,
        }
    }

    pub fn as_ref(&self) -> TableCellRef {
        match self {
            TableCell::Never => TableCellRef::Never,
            TableCell::Available {
                value,
                is_dirty,
                in_conflict,
            } => TableCellRef::Available {
                value: &value,
                is_dirty: *is_dirty,
                in_conflict: *in_conflict,
            },
        }
    }
}