EguiStruct
EguiStruct is a rust derive macro that creates egui UI's from arbitrary structs and enums. This is useful for generating data bindings that can be modified and displayed in an egui ui.
Crate idea is similar to crates enum2egui, egui_inspect and egui-controls, but there are some important differences:
EguiStruct vs similar crates
| EguiStruct | enum2egui | egui_inspect | egui-controls | |
|---|---|---|---|---|
| egui version | 0.23 | 0.23 | 0.20 | N/A |
| Layout* | Grid | Group/nested | Nested | Grid |
| i18n support | ✅ (rust-i18n**) | ❌ | ❌ | ❌ |
| Field description | ✅ on hover hint (from attribute) | ❌ | ❌ | ✅ third column (from doc comment) |
| Rename field/variant | ✅ | ✅/❌ (enum only) | ❌ | ❌ |
| Mass name case conversion | ✅ | ❌ | ❌ | ❌ |
| Callback on-change | ✅ | ❌ | ❌ | ❌ |
| Reset button | ✅ | ❌ | ❌ | ❌ |
| Skip field | ✅ | ✅ | ✅ | ❌ |
| Numerics & strings support | ✅ | ✅ | ✅ | ✅ |
| Vec support | ✅/❌ (does not support adding/removing elements) | ✅ | ✅ | ❌ |
| Other support | ✅ bool, Option, [T;N] | ✅ bool, Option | ✅ bool, [T;N] | ❌ |
| HashMap/Set support | ✅ std, indexmap | ✅ std, hashbrown | ❌ | ❌ |
| Map field/override impl | ✅ | ❌ | ✅ | ❌ |
| Struct derive | ✅ | ✅ | ✅ | ✅ |
| Enum derive | ✅ | ✅ | ❌ | ❌ |
| Custom types in derive | ✅ | ✅ | ✅ | ❌ |
| Configuration numerics | ✅ Slider(min,max), Slider(min,max,step), DragValue(min,max), DragValue, List | ❌ | ✅ Slider(min,max), DragValue | ❌ |
| Configuration string | ✅ multi/singleline, List | ❌ | ✅ multi/singleline | ❌ |
| Configuration user types | ✅ | ❌ | ❌ | ❌ |
| List/Combobox wrapper | ✅ *** | ❌ | ❌ | ❌ |
* Everything is put inside scroll&grid layout (with collapsable rows)
- Gui is less chaotic,
- all values are aligned,
- Gui is comact in width
** integrated/with i18n in mind (with rust-i18n crate (or if using extractor modified rust-i18n))
*** Wrap T: Clone + ToString + PartialEq type into Combobox<T> and pass through config attribute iterator with all possible values → field will be shown as combobox
Usage
Basic description
Add this to your Cargo.toml:
= { = "https://github.com/PingPongun/egui_struct.git", = "master" }
Add derive macro EguiStruct to struct you want to show (and all nested types):
;
then to show data, you only need to call show_top(..) on top level struct:
default.show;
Detailed description
Crate consists of 4 traits (EguiStructImut -> EguiStructEq+EguiStructClone -> EguiStruct) and one derive macro (EguiStruct).
EguiStructImut:- for end user ofers one function
show_top_imut(..), which displays struct inside scroll area. - when implementing (most of bellow has some default impl):
show_primitive_imut(..)- ui elements shown in the same line as labelshow_childs_imut(..)- ui elements related to nested data, that is show inside collapsible rowshas_childs_imut(..)&&has_primitive_imut(..)- indicates if data has at the moment childs/primitive sectionconst SIMPLE_IMUT- flag that indicates that data can be shown in the same line as parent (set to true if data is shown as single&simple widget)type ConfigTypeImut- type that will pass some data to cutomise how data is shown, in most cases this will be ()show_collapsing_imut(..)- do not overide this method, use it when implementingshow_childs_imut(..)to display single nested element
- for end user ofers one function
EguiStructEq/EguiStructCloneare similar to stdPartialEq/Clonetraits, but they respecteguis(skip). They are necessary to implementEguiStruct(if type is Clone/PartialEq can be implemented throughimpl_eclone!{ty}/impl_eeq!{ty}/impl_eeqclone!{ty}).EguiStructis mutable equivalent ofEguiStructImut.
Macro EguiStruct can be used on structs&enums to derive all traits ( EguiStructImut & EguiStruct & EguiStructEq & EguiStructClone).
Macro supports attribute eguis on either enum/struct, field or variant level:
-
enum/struct level:
rename_all = "str"- renames all fields/variants to selected case (recognized values:"Upper","Lower","Title","Toggle","Camel","Pascal","UpperCamel","Snake","UpperSnake","ScreamingSnake","Kebab","Cobol","UpperKebab","Train","Flat","UpperFlat","Alternating","Sentence")prefix = "str"- add this prefix when generatingrust-i18nkeysno_imut- do not generateEguiStructImutimplementationno_mut- do not generateEguiStructimplementationno_eclone- do not generateEguiStructCloneimplementationno_eeq- do not generateEguiStructEqimplementationresetable = "val"ORresetable(with_expr = Expr)- all fields/variants will be resetable according to provieded value (val:"not_resetable","field_default","struct_default","follow_arg"(use value passed on runtime through reset2 arg))
-
variant level:
rename ="str"- Name of the field to be displayed on UI labels or variantName in i18n keyskip- Don't generate code for the given varianthint ="str"- add on hover hintimut- variant will be shown as immutablei18n ="i18n_key"- normally i18n keys are in format "prefix.enumName.variantName", override this with "i18n_key"resetable- overides enum/struct level resetable
-
field level
rename,skip,hint,imut,i18n- see variant levelresetable- overides enum/struct & variant level resetableon_change = "expr"- Use function (expr: closure surounded by()OR function path) callback (when value has been changed; signature:fn(&mut field_type))on_change_struct = "expr"- Similar toon_changebut takes whole struct: signature:fn(&mut self)imconfig- pass format/config object to customise how field is displayedconfig- same as imconfig but for mutable displaymap_pre- Expression (closure surounded by()OR function path) called to map field to another type before displaying- this allows displaying fields that does not implement EguiStruct or overiding how field is shown
- function shall take
& field_typeor&mut field_typeAND return either mutable reference or owned value of selected type - ! beware, becouse (if
map_pre_refis not set) this will make field work only with resetable values: {NonResetable, WithExpr, FieldDefault} - defaults to
map_pre_ref(so if&mutis not needed for map, can be left unused)
map_pre_ref- similar tomap_pre, but takes immutable reference (signature:fn(&field_type)->mapped),- used for EguiStructImut, converting default/reset2 and inside eguis_eq (if eeq not specified)
map_post- Expression (closure surounded by()OR function path) called to map mapped field back to field_type after displaying- only used if
map_preis set AND not for EguiStructImut - signature:
fn(&mut field_type, &mapped)(withmappedtype matching return frommap_pre) - expresion should assign new value to
&mut field_type
- only used if
eeq- overrideeguis_eqfunction for field (signature fn(&field_type, &field_type))- if either
field_type : EguiStructEqORmap_pre_refis specified can be unused
- if either
eclone- overrideeguis_eclonefunction for field (signature fn(&mut field_type, &field_type))- if
field_type : EguiStructClonecan be unused
- if
Example
See ./demo
TODO
- elegant error/invalid input handling & helpful messages (macro)
- add bounds
- tests
- code cleanup & simplify
- support adding/removing elements for Vec&Hashmap's
- (requires specialization) EguiStructEq/EguiStructClone default impl