ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
60.9k stars 10.29k forks source link

How would you implement communication between ImGui widgets and user data source? #7119

Open sairus7 opened 10 months ago

sairus7 commented 10 months ago

I have a GUI to work with data files with a lot of plot widgets, statistics tables and others "views" on data, and a bunch of interaction functionality: navigate through data, make edits, view changed data.

So I've made a bunch of reusable widgets with their own state stored into a hashmap accessed by global ID or widget ID stack. Some actions (like open file) lead to state initialization. I can do this in two ways:

Another actions in GUI lead to changes in user data, that should recursively update any of its affected states (or invalidate cached "views"). For example, when I change some GUI control (like, plot x-axis range), I want to cache another piece of data. I can do this the following way:

All of these options lead to hard coupling of UI code with data source logic. How can I decouple those? I think I need some communication mechanics. Are there any examples of how to combine ImGui widgets with:

Please point me where to look. Thank you!

jonbarnettk commented 10 months ago

Maybe you could use something like zeromq such as inproc pair.

I have never used for this particular situation and am not entirely sure your use case, but it sounds like all you need are messages, although zmq might add more complexity than some other lib that may exist, perhaps it can fit your use case.

ocornut commented 10 months ago

The key design principle of dear imgui is that widget states should avoid duplicating or synching with user data. It is unclear to me why you are designing a system that goes the opposite of our core principle. There may be a good reason, but we can’t help you until we understand better why you are doing so.

sairus7 commented 10 months ago

Well, there is always some state involved. For imgui it is just a global one state in user code that is accessed directly from different places, so no syncronization is needed.

Hhere are a couple of reasons to do so:

  1. Separate process for visualization and process for individual time-consuming operations or streaming data processing. E.g. open file or batch processing for big data chunk doesn't freeze GUI. Or streaming audio FFT spectrum calculated in background, and a separate rendering process that just takes results to show, so it doesn't throttle.
  2. Split imgui prototype from datasource code, so it can be potentially wrapped into a "data server" without full rewrite, and GUI code that can be switched to another.
ocornut commented 10 months ago

Well, there is always some state involved

Yes but with a few exception imgui only holds on UI related state and users hold on the actual editable data.

Reason 1) seems like a one-way update rather than a back and forth update. You’d probably want to multithread parts of your app if you can’t easily make your algorithm faster or work in step, with eg a multi buffer approach where UI visualize the last ready data while main processing is outputting to a temp copy.

I am not sure I understand what you mean by 2).

emoon commented 10 months ago
  1. I use handles for this. This includes images loading, data processing, etc as I can load images directly from the web I can't stall on anything so I just have my own threading system for it. On the UI side it would look something like this (simplified example)

ImageHandle image = ImageLoader::load_async("https://myurl.com/cool_image.png");

loop {
   // Regular imgui/window update goes here
   // ....

   if (ImageLoader::has_loaded_image(image))
      ImGui::ShowImage(image);
   else
      ImGui::ShomImage(place_holder_image);
}