Support for optional/unset values in controls
I'm just trying egui for the first time and I'm very impressed, but I've immediately run into something that appears unsupported.
I'm prototying an entity inspector for Bevy, and I want to be able to support editing of multiple simultaneously selected entities. Here's a Unity screenshot as an example of the common way of handling this.

Here I have two objects selected. Their rotations are identical, so those fields display normally. Their positions and scales differ, so no single value can be displayed for both, so the fields display in this unset state. These are still functional and active fields - if I type in them, or drag over them, a single value is entered and set for both of the selected objects.
I can't see a way to implement this functionality using egui without reimplementing all of the basic controls. It would be very nice if controls all had an unset state like this.
I think this makes sense. I guess interacting with the control would then set the value for all selected entities.
This requires some design work. A slider can just be empty and when interacted with, it can calculate a value from the range. But a DragValue needs a base value when interacting with it.
I guess we could implement it using something like .show_value(false) on DragValue and Slider.
The .show_value(false) idea makes sense, the only slight catch would be smooth change detection.
- Code sets
value = 0,show_value = false - User interacts with the control, and
show_value = truehappens automatically .changed()istrue, even ifvaluehasn't changed. i.e.(value = 0, show_value = false)->(value = 0, show_value = true)is treated as a change
Given that there's some semantic meaning and logic involved, I would probably give it a name that reflects that. I personally lean towards "conflicted" or "mixed".
My ideal version of this API would actually look a little different:
enum MaybeMixed<T> {
Unmixed(/*value:*/ T),
Mixed(/*default:*/ T)
}
// Usage
let mut val = MaybeMixed::Mixed(0);
if ui.add(egui::DragValue::new_maybe_mixed(&mut val)).changed() {
// on change logic
// As .changed() == true, val is now guaranteed to be MaybeMixed::Unmixed
} else {
// As .changed() == false, val is guaranteed to be unchanged
}
This way it's actually part of the value, which I think semantically and ergonomically makes sense.
The tricky thing is that, in order to be useful for my use case, this pattern would have to be implemented for almost all controls. I'm prototyping an entity inspector design where users commonly write custom inspectors that need to handle this pattern of maybe having multiple conflicted values selected at once. If I put that expectation on users, they need to be able to do so easily using the UI tools.
I should stress that this is early stage protototyping. This could easily never become a finished and implemented Bevy feature, and if it does, Bevy could easily not end up using egui. I don't want to give the impression that a large project would definitely make use of this feature, but I expect that somebody else would find it useful if Bevy doesn't.
for people coming across this issue with the same need with a DragValue , here is a hacky work around I came up with until this has library support.
fn optional_drag<T: Numeric>(ui: &mut Ui, opt: &mut Option<T>) {
let mut placeholder = 0u32;
if let Some(ref mut val) = opt {
ui.add(egui_winit::egui::DragValue::new(val));
} else {
ui.add(
egui_winit::egui::DragValue::new(&mut placeholder).custom_formatter(|_, _| "—".into()),
);
}
if placeholder != 0 && opt.is_none() {
*opt = Some(T::from_f64(0.0));
}
}