ofxDatGui: A New User Interface for OF


#1

Hey guys,

I’ve been a fan of the Google DataArt team’s datgui project for a while now and it’s pretty much my goto UI kit for JavaScript projects. As I’ve been doing quite a bit of prototyping in OF over the last few months I thought I’d have a go at porting their awesome project over to OF.

So without further ado I offer you ofxDatGui :blush:

It’s still very much a work in progress and I’ll be adding more components & features over the next few weeks, however in the interim I’d love some feedback once you guys have had a chance to play around with it.

Cheers,
Stephen


Need a gui solution that works with 0.8.4
#2

Hi, looks nice, but i tried to build it in OF0.8.4 and had no luck. Can you add some manual for compiling?


#3

Hi, thanks for checking it out!

I’m using std::function & std::bind to handle event callbacks which require c++11 which AFAIK is a little shaky in 0.8.4. You can try futzing with your project build settings to enable c++11 support but you may run into the dreaded tr1/memory issue that [I believe was fixed in 0.9.0.][1]

If you get it working in 0.8.4 please LMK otherwise for now you have to build it against 0.9.0.
[1]: https://github.com/openframeworks/openFrameworks/issues/2335


#4

Hello,

I’m made a ton of updates since my last post and feel that I’m rapidly approaching a v1 release.

If you have a minute I would really appreciate help testing this on different platforms and any general feedback you may have regarding performance and which features I should prioritize next.

Here’s a quick video showing ofxDatGui in action.
The example in the video is called Oscillating Polygon and is included in the repository.

Also if you have any questions about its capabilities, usage or anything in the readme please LMK.

Many many thanks for your time in advance!

Stephen


#5

cloning and starting to test, you give you feedback when I can.
Seems very nice!


#6

hello,

looks really promising ! great job !
reminds me ofxUI a lot.

Does it work with ofParamter ?

will test it and give my feedback

thanks


#7

Hi, I haven’t added support for ofParameter. To be honest I’m not exactly sure what ofParameter does or why it even exists. I’m guessing the intention behind it is some form of data binding?

If that’s the case I’m working on adding data binding to ofxDatGui which currently looks like this:

// draw a circle with a radius of 150px and position it in the middle of the screen //
    circle = new Circle(150);
    circle->x = ofGetWidth()/2;
    circle->y = ofGetHeight()/2;
    
// instantiate a gui and a couple of range sliders //
    gui = new ofxDatGui( ofxDatGuiAnchor::TOP_RIGHT );
    ofxDatGuiSlider* sx = gui->addSlider("CIRCLE X", 0, 100);
    ofxDatGuiSlider* sy = gui->addSlider("CIRCLE Y", 0, 100);
    
// bind the circle's x & y movement to the gui sliders //
    sx->bind(&circle->x, 0, ofGetWidth());
    sy->bind(&circle->y, 0, ofGetHeight());

I just added this example to the repository and here’s a video of what it looks like.


#8

HI, I’ve only just started learning about ofParameter myself and haven’t found much in the way of a comprehensive tutorial or documentation about it. From what I understand it’s basically a standardised means sharing data between classes, with support for event listeners when the data changes and setting things like label name, initial value, min value and max value. One of the big advantages of using it in a gui is that it makes it a lot easier to swap out different guis, because you just set up the ofParameterGroups in your various classes and then assign them all to the gui in one place. This means you don’t have gui-specific code throughout your project, so it makes it a lot easier to swap out different guis. The stock ofxGui makes use of these, so if other guis also use them it makes it easier to prototype with ofxGui and then change over to something nicer later in the development process.

Here are a couple of vids that explain the basics of ofParameterGroup with ofxGui:


It seems they also link in well with reading and writing xml files (including functions for flagging as serialisable).

But as I say I don’t fully know what I’m talking about with this stuff, others can probably explain it better and correct any mistakes I’ve made above!

btw ofxDatGui looks really nice!


#9

Hi, is there any way to have lowercase and uppercase text instead of uppercase only?


#10

@gmol Check this out> github repo


#11

It looks really nice! Thanks @braitsch and go ahead with it! :smile:

I used to work with ofxUI and I have seen now is deprecated. I started to work with ofParamater and ofxGui and it seems comfortable. This two videos above are really nice to see how it works.

I am thinking to switch my main project from ofxUI to this ofxDataGui, and I will must remake lot of the code sections… I am not an expert but I understand that the use ofParameter to “communicate between classes” and to isolate GUI sections seems really nice IMO…


#12

@superartificial Thanks, your post and those videos do a nice job of contextualizing ofxParameter. I just took a closer look at the class and how it’s integrated with ofxGui and imagine it wouldn’t take me long to add support for it, however I do have quite a few tasks I want to get to first (particularly improved iOS support).

I’m curious how many of you guys would use ofxDatGui if it supported ofParameter? If there’s enough interest here I’ll prioritize it.

Stephen


#13

That’s exactly what I was looking for, thanks.


#14

Also I just restructured the docs and added a gallery page.

If you are working with ofxDatGui and need help open an issue or pm me off list and I’ll get you sorted out. When your project’s ready for primetime I’d love to feature it on the site.

Stephen


#15

There’s a good chance I’d use it at some stage even without ofParameter support, but if it did have that I’d be more likely to use it on some stuff I’m working on at the moment which uses ofxGui


#16

@braitsch @superartificial

Here is a concept I have been playing with. It essentially allows you to use a normal variable with ofParameter but have it’s changes tracked.

The idea is that you want to use features like ofxOscParameterSync or have a GUI that doesn’t know about ofParameter/just wants a value to track.

It does copy in order to work but may be fast enough.


#17

Interesting, thanks Jason. I’ve been thinking a lot about how to integrate ofParameter into ofxDatGui lately as it’s the #1 feature people have been asking for.

One of issues though that I see with its design is that it doesn’t look like the payload passed to the an event handler function carries any information about the parameter object itself that dispatched the event.

For example, looking at the guiFromParametersExample

circleResolution.addListener(this, &ofApp::circleResolutionChanged);
void ofApp::circleResolutionChanged(int & circleResolution){
    ofSetCircleResolution(circleResolution);
}

The circleResolutionChanged event handler just receives a reference to the integer that the circleResolution parameter wraps. So if I understand the design correctly every ofParameter requires its own unique event handler to listen for when its underlying value has changed?

It seems to me that this could get unwieldy very quickly say if I had a Gui with 20 sliders in it as each slider would require its own unique event handler method to detect when its value had changed?

Or am I totally missing something here?

The way ofxDatGui currently handles variable binding is you create say a slider component by passing in a label (which every component requires) and then a min, max, and optional initial value (which can be a reference to a variable).

float myNumber = 50.0f;
ofxDatGui* gui = new ofxDatGui();
gui->addSlider("slider 1", 0, 100, &myNumber);
// listen for interactions // 
gui->onSliderEvent(this, &ofApp::onSliderEvent);

Alternatively you can bind a variable to a component after it’s been constructed.

ofxDatGuiSlider* mySlider = gui->addSlider("slider 1", 0, 100);
mySlider->bind(&myNumber, minValue, maxValue);

The onSliderEvent event handler receives an ofxDatGuiSliderEvent object that contains not only a reference to the underlying float variable but also a pointer to the slider itself that dispatched the event. The advantage of this is that you only need one slider event handler on your entire gui because you can easily inspect the incoming event object to find out which slider dispatched the event.

void ofApp::onSliderEvent(ofxDatGuiSliderEvent e){
    if(e.target == mySlider) // pointer comparison
// or
    if(e.target.is("slider 1")) // name comparison
// do something with e.value (current value of the slider)
// do something with e.scale (current position of the value between min & max)

Not having to write an event handler for every variable I want to watch seems like the simpler solution to me but someone please correct me if I’m missing a feature of ofParameter that negates this need.

Regardless I do plan on adding ofParameter support to ofxDatGui soon, likely in a way that is similar to how it works with ofxGui via gui.add methods to keep it consistent for people.

I just want to make sure I fully understand ofParameter’s design and what folks really like about it so that I can support it in ofxDatGui in the best way possible.


#18

Also I meant to announce on the forum yesterday that ofxDatGui v1.0 just launched with an updated API (and supporting documentation) and includes a pack of extensible themes that you can easily customize and apply to both individual components & guis.

Cheers,
Stephen


#19

Yeah - for ofxImGui it just wants raw variables and is pretty much why I started the SynchedParameter stuff

My thought is that ofxImGui shouldn’t have to know about ofParameter. It just needs to deal with the data.

So in your case

float myNumber = 50.0f;
ofxDatGui* gui = new ofxDatGui();
gui->addSlider("slider 1", 0, 100, &myNumber);
// listen for interactions // 
gui->onSliderEvent(this, &ofApp::onSliderEvent);

would be like this

SynchedParameter<float> floatParam;
floatParam.set("floatParam", 50.0);
ofxDatGui* gui = new ofxDatGui();
gui->addSlider("slider 1", 0, 100, &floatParam.value);
floatParam.startUpdating();
// listen for interactions // 
gui->onSliderEvent(this, &ofApp::onSliderEvent);

Then if someone wants to listen for the change event they can

floatParam.parameter.addListener(this, &ofApp::onFloatParamUpdate);

Or tweak the value manually if they want
floatParam.value = 10000.0f;

It’s kinda becoming an ofxSynchedParameter addon at the moment. I will publish it as soon as I get a few demos going


#20

ofParameter is thought to be a way to separate data from presentation in the code which gives independence from the different gui systems in OF, if everyone uses it people will be able to easily switch from one system to another if lets say a gui becomes unmantained or another has a feature that they need…

@braitsch you can always add a sender parameter to your event like:

void listenerFunc(void * sender, float & value)

since sender is the ofParameter instead of the gui element itself then you can do:

void listenerFunc(void * sender, float & value){
   auto * param =  (ofAbstractParameter *) sender;
   sender->getName();
  ....
}

There’s already a PR to refactor events to be able to use lambda functions which will automatically work for ofParameter so you’ll be able to do:

//.h
ofParameter<float> amplitude{"amplitude", 10, 0, 100};

//.cpp
amplitude.addListener{[](float & amp){
    // do something with the amplitude
})

which pretty much removes the need for someway of iding the sender since creating listener functions is way less verbose but we could add other ways of identifying the sender like an extra id parameter in the event or whatever we can think might make it easier to use

There’s also some other advantages of using ofParameter over a raw pointer to a variable, for example this:

class MyClass{
    void setup(){
        slider.bind(&x)
    }
    ofxSomeSlider slider;
    int x
}

...

//ofApp::setup
MyClass obj;
obj.setup();
myvector.push_back(obj);

will crash since the pointer to x will be invalidated when the variable is pushed into the vector, ofParameter solves that problem and that same pattern will still work even when the parameter moves in memory.

Or for example the possibility of initializing parameters and groups in headers like:

ofParameter<float> amplitude{"amplitude", 10, 0, 100};
ofParameter<float> frequency{"frequency", 440, 20, 20000};
ofParameterGroup{
   "audio parameters",
   amplitude,
   frequency,
};

which makes it really easy to understand the data for an specific class, it’s ranges…

@jvcleave what’s the difference between SynchedParameter and ofParmater? seems to be the same idea no?

if there’s other needed features that seem missing from ofParameter please open an issue in github or we can discuss it here in the forum but it would be really nice to have a common mvc backend for all the guis. so people can switch from one to another without having to refactor all their code whch is one of the main reasons why ofParameter exists.


ofParameter listeners