emilk / egui

egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
https://www.egui.rs/
Apache License 2.0
20.88k stars 1.51k forks source link

Introduce a new Operation<T> enum for widgets with from_get_set #4390

Open murl-digital opened 2 months ago

murl-digital commented 2 months ago

Is your feature request related to a problem? Please describe. When integrating egui in a project, you may not have direct access to the data you want to represent. The solution egui has right now (a closure which takes an option and returns a value) is great, but when encountering it for the first time, it feels obtuse.

Describe the solution you'd like I'd like to introduce a new enum type, Operation<T>, which would be a drop-in replacement for the Options that closures already take. Operation would look something like this:

pub enum Operation<T> {
   Get,
   Set(T)
}

The reason I'm opting for generics here is so that people writing their own widget implementations can use the same thing with types that would be more idiomatic for their use case.

I feel this change would be mildly intrusive, and would ultimately make for more readable code. I'm using this pattern with my own widget library and like it quite a lot, but figured I should give the chance to see if this is even a good idea before I run off making a PR.

emilk commented 2 months ago

I have no idea what you are referring to. Please explain, perhaps referring to existing code and/or adding some code example.

murl-digital commented 2 months ago

Sorry, I should've clarified. What I'm referring to is the from_get_set method that sliders and drag values have:

docs.rs

Doing a quick search, I realized that expanding this to other widgets may also be a good idea. The main thing this benefits is audio plugins. When you're doing the editor UI, you don't have a direct mutable reference you can use. Here's an example from nih_plug:

ui.add(
    egui::widgets::Slider::from_get_set(-30.0..=30.0, |new_value| {
        match new_value {
            Some(new_value_db) => {
                let new_value = util::gain_to_db(new_value_db as f32);

                setter.begin_set_parameter(&params.gain);
                setter.set_parameter(&params.gain, new_value);
                setter.end_set_parameter(&params.gain);

                new_value_db
            }
            None => util::gain_to_db(params.gain.value()) as f64,
        }
    })
    .suffix(" dB"),
);

When reading this for the first time, the Option in the closure doesn't immediately make sense.