ofxImGui and ofParameter


#1

I would really like to clean my code when using ImGUI. So far, every single widget takes me a lot of code and I end up with a huge file with a lot of redundancy…

Here is an example of my current code:
one single slider and using ofParameterSync used to synchronize two applications:

ofApp.h:
	int				imageFrameRate;
	ofParameterGroup	sharedSettings;

ofApp.cpp:
	// Check if client has changed framerate
	if (sharedSettings.imageFrameRate != imageFrameRate)
	{
		ofLogNotice() << "Client cahnged imageFrameRate";
		bool result = setFramerate(sharedSettings.imageFrameRate);
		if (result) imageFrameRate = sharedSettings.imageFrameRate;
	}
	// Draw slider and check user interaction
	ImGui::Text("Image Framerate");
	ImGui::PushID("Image Framerate");
	{
		ImGui::SliderInt("##v", &imageFrameRate, 1, 1000, "");
		if (ImGui::IsItemActive() || ImGui::IsItemHovered()) {
			ImGui::SetTooltip(" %i", imageFrameRate);
		}
	}
	ImGui::PopID();
	// if user interaction send changes to Client
	if (sharedSettings.imageFrameRate != imageFrameRate) {
		bool result = setFramerate(imageFrameRate);
		if (result) {
			sharedSettings.imageFrameRate = imageFrameRate;
		}
	}

So, I would like to know where to start in order to create an abstract class to bind ofParameters to ImGUI. Using a similar pattern as in ofxGuiGroup. I would like to do something like:

gui.add(sharedSettings.imageFrameRate);
sharedSettings.imageFrameRate.addListener(this, &ofApp::framerateChanged);

Is the current ofParameter able to handle different GUIs? Any Ideas What piftalls would I encounter?
Thank you for any advice.

ping the gurus @jvcleave, @arturo


#2

I played around with the concept with this:

However I don’t really like it - I just stuff all my GUI code into a separate class/file (usually something like ControlPanel.h) that mostly helps with the clutter.

With ofxImGui I am really just trying to make it more easily integrate with OF and the platforms it supports. Anything else I try let ImGui/the user handle.


#3

Thank you very much for your fast reply!
I will have a look at your code.

In fact I would really like to see ImGui as one of the available GUIs for OF. It would be great to have it as an intermediate step between ofxGUI and Qt.
Thanks for the great addon!


#4

I did something similar with GTK and ended up wrapping each gtk element to a typed ofParameter. https://github.com/underdoeg/ofxGtk/blob/master/src/ofxGtkParameters.h But I also use them mainly with my implemented of an ofParameterServer and control the app via OSC. Rather hacky approach here: https://github.com/underdoeg/ofxParamServer/tree/master/src


#5

i haven’t really used im gui but have read a little about the idea and in my opinion this is the main problem i see with the immediate gui approach, it’s a nice idea if you want to do something quick (which is what you want a lot of the time in the tipical OF application) but it completely violates the separation data/logic/presentation principle which ofParameter aimed to make easier to implement.

if you want a dynamic, nice looking gui and your project won’t require much mantainance over time i think is an ideal solution since it seems really easy to use and allows to do things like adding/removing controls from the gui in the update loop without much hassle.

the main disadvantage i think is that you’ll end up with your gui code mixed with the logic of the application or with a class that needs to know about the internals of every other class.

i guess you could do something that parsed an ofParameterGroup and did the immediate mode calls to create the gui from that but then, it seems to me, you wouldn’t be using it as immediate mode any more.


#6

Thank you very much @underdoeg I will look at ofxGtk. And thank you for your comments @arturo. It is true that immediate gui is by force a messy coding style… I’m still trying to figure out how to keep it somehow clean.

One last question about this.
As far as I understand immediate gui needs all objects available during certain step on the main loop. Forcing us so do all draw calls at once. and as @arturo says going pretty much against OOP.

I was playing around with lambdas lately and as far as I understand one can pass the current scope to a function so that all objects are available from within that function. Isn’t that exactly the main restriction of immediate gui to be solved? I haven’t tried anything yet. Just wondering how that sounds to you guys…

Thanks again for the comments!


#7

Yes you can use lambdas as a quick solution. I did that to connect ofParameter with Gtkmm events: https://github.com/underdoeg/ofxGtk/blob/master/src/ofxGtkWidgets.h#L53


#8

Hello,

ImGui author here (I don’t know much about ofx).

I’m finding it hard to understand why the code is made to be that complex. It feels you are fighting against against the grain and against what the library is trying to do.

The entirety of your snippet code above could be replaced by something like:

if (ImGui::SliderInt("Image Framerate", sharedSettings.imageFrameRate, 1, 1000))
    setFramerate(sharedSettings.imageFrameRate);

or

ImGui::Text("Image Framerate");
if (ImGui::SliderInt("##Image Framerate", sharedSettings.imageFrameRate, 1, 1000))
    setFramerate(sharedSettings.imageFrameRate);

Or perhaps an extra line to read if you can’t access your field directly.
For a single simple parameter, any more seems like madness to me (I’d personally try to avoid a system where a getter/setter needs to be called).

If you really want the odd layout/behavior/tooltip exhibited in your example then you can wrap it in a function that takes a pointer to float and a string, create similar code and return a boolean so you can call a function like setFramerate() if it is required by the underlying code.

ImGui arguably needs more option for widget layouts but I have little resources to updates are taking time.


#9

Adding my blunt two cents here. It feels like lots of the pain (here and in many many places where people uses C++) stems from the assumption that OOP is a good thing at all and people are trying too hard to protect that dogma at all cost, making their own life harder. May I bluntly suggest that is a bunch of BS and you are making your harder than in needs to be. OOP often means building your own trap and trying to justify its existence by fighting back anything that doesn’t play as well with over-engineered code. Sit back, take a deep breath and relax:

#define private public

Done :slight_smile:

That said, I am also strongly the spreading misconception that imgui are for “something quick” and don’t scale. I’ve been working with enormous projects and they scale much better than anything I’ve seen. Plus they tend to be portable, and they tend to enable more team members to actually create decent tools faster which is key as collective programmer brain time is the bottleneck of every project.

" it completely violates the separation data/logic/presentation "

I would that that this idea completely violates your right to be productive :wink:


#10

yeah i wasn’t talking about OOP in particular but i still think that for projects that require certain mantainance over time having some separation of concerns makes things easier on the long term.

that said i also think that in most OF applications or projects like video games… that’s really not the case since there’s usually not much mantainance compared with other kinds of projects so in principle the immediate gui paradigm could be a good solution.

i guess what i was trying to say, is that if you are using imgui probably you want to forget about trying to mix it with ofParameter and just embrace it’s paradigm completely, since ofParameter tries to solve more or less the same things as the immedaite mode gui paradigm in a different way so trying to mix them is probably going to make things more complex than using any of them separately.


#11

Thank you very much @underdoeg and @ocornut for your code samples. Its great to learn from you. Thank you everybody for the interesting discussion. In my opinion a good coding paradigm is the one that fits your current project :slight_smile: So, with this thread i did not want to start a discussion on what is best, but rather how to use each paradigm at its best.

So thanks again for your contributions. Its great to learn by example.