ofxDatGui is a simple to use, fully customizable, high-resolution graphical user interface for OpenFrameworks inspired by the popular JavaScript datgui interface.
Once you've downloaded openFrameworks, clone or download this repository into your openFrameworks/addons directory.
Create a new project using the project generator and include ofxDatGui by selecting the addons
button in the generator.
Copy the ofxbraitsch
directory in the root of this repository to your project's bin/data directory. This directory contains the fonts & icons used by ofxDatGui.
Add ofxDatGui to your project by adding #include "ofxDatGui.h"
to the top of your ofApp.h
file and you're ready to go!
There are two ways to work with ofxDatGui. You can either instantiate each component on its own or consolidate them into a gui panel that you can drag around. The individual component examples included in this repository demonstrate how to use each on its own.
To create an ofxDatGui panel that groups components together simply pass in the X and Y coordinates where you would like it to live or use one of the convenient pre-defined anchors.
ofxDatGui* gui = new ofxDatGui( 100, 100 ); ofxDatGui* gui = new ofxDatGui( ofxDatGuiAnchor::TOP_LEFT ); ofxDatGui* gui = new ofxDatGui( ofxDatGuiAnchor::TOP_RIGHT ); ofxDatGui* gui = new ofxDatGui( ofxDatGuiAnchor::BOTTOM_LEFT ); ofxDatGui* gui = new ofxDatGui( ofxDatGuiAnchor::BOTTOM_RIGHT );
Adding components to ofxDatGui is as simple as:
gui->addButton("Click!");
This generates a Basic Button with the label "Click!"
Most components can be grouped together into an ofxDatGui panel via the gui->add*
method.
Click on any component's name to view its full documentation.
gui->addButton(string label);
gui->addToggle(string label, bool enabled = true);
gui->addLabel(string label);
gui->addTextInput(string label, string value = "");
gui->addSlider(string label, float min, float max);
gui->addColorPicker(string label, ofColor color = ofColor::black);
vector<string> options = {"ONE", "TWO", "THREE", "FOUR"}; gui->addDropdown(options);
gui->addFolder("My White Folder", ofColor::white);
gui->addValuePlotter(string label, float min, float max);
gui->addWaveMonitor(string label, float frequency, float amplitude);
gui->addMatrix(string label, int numButtons)
gui->add2dPad(string label, ofRectangle bounds);
gui->addFRM();
You can easily space components apart by placing padded breaks between them.
gui->addLabel("Above"); gui->addBreak()->setHeight(10.0f); gui->addLabel("Stuck in the Middle"); gui->addBreak()->setHeight(10.0f); gui->addLabel("Below");
ofxDatGui also provides an optional header and footer that allows you to title your gui, drag it around and conveniently collapse and expand it. The AllComponentsGui
example offers a nice demonstration of their use.
Header
gui->addHeader(":: Drag Me To Reposition ::");
You can change the header's label just like any other component by calling:
gui->getHeader()->setLabel("PANEL 1");
Adding a header to your gui will allow you to drag it around, however you can easily disable this via:
gui->getHeader()->setDraggable(false);
Or by passing in false
as the second argument to the constructor.
gui->addHeader(":: My Stationary Panel ::", false);
Footer
gui->addFooter();
Footers have two labels that each map to the gui's expanded and collapsed states.
By default these labels are "Collapse Controls" and "Expand Controls" although you can override these defaults via:
gui->getFooter()->setLabelWhenExpanded("CLOSE PANEL 1"); gui->getFooter()->setLabelWhenCollapsed("EXPAND PANEL 1");
If your gui has a footer you can programmatically open & close it.
// expand the gui // gui->expand(); // collapse the gui // gui->collapse(); // toggle the gui open & closed // gui->toggle();
If your gui doesn't have a footer simply call setVisible
to show or hide it.
// hide the gui // gui->setVisible(false);
ofxDatGuiEvents are designed to be as simple and convenient to work with as possible.
To listen for an event simply register a callback (or assign a lambda) to be executed when an event you care about is fired:
Assigning a callback
gui->onButtonEvent(this, &ofApp::onButtonEvent); void onButtonEvent(ofxDatGuiButtonEvent e) { cout << "A button was clicked!" << endl; }
Assigning a lambda (anonymous function)
gui->onButtonEvent([&](ofxDatGuiButtonEvent e) { cout << "A button was clicked!" << endl; }
Every event handler will receive an event object that contains a pointer (called target) to the object that dispatched the event.
gui->addButton("My Button"); gui->onButtonEvent(this, &ofApp::onButtonEvent); void onButtonEvent(ofxDatGuiButtonEvent e) { cout << e.target->getLabel() << endl; // prints "My Button" }
If you saved the pointer returned by gui->add*
in a variable you can compare it to the event target to decide how to handle the event.
ofxDatGuiButton* b1 = gui->addButton("Button 1"); ofxDatGuiButton* b2 = gui->addButton("Button 2"); gui->onButtonEvent(this, &ofApp::onButtonEvent); void onButtonEvent(ofxDatGuiButtonEvent e) { if (e.target == b1){ cout << "Button 1 was clicked" << endl; } else if (e.target == b2){ // button 2 was clicked, do something else // } }
However a more convenient way of determining which component dispatched the event is by using the built in is
operator.
gui->addButton("Button 1"); gui->addButton("Button 2"); void onButtonEvent(ofxDatGuiButtonEvent e) { if (e.target->is("button 1")){ cout << "Button 1 was clicked" << endl; } else if (e.target->is("button 2")){ // button 2 was clicked, do something else // } }
This performs a case-insensitive search against the component's name which by default is the same as its label.
Interactive components dispatch event objects that have properties unique to that type of component.
All ofxDatGuiEvents and their properties are covered in more detail in the Component API.
If you're lazy and don't feel like storing your components in variables you can easily retrieve them by name which by default is the same as whatever you set its label to.
ofxDatGuiButton* gui->getButton("My Button"); // button name ofxDatGuiSlider* gui->getSlider("My Slider"); // slider name
Note: gui->getComponent
performs a case-insensitive lookup against the component's name so the following works fine as well.
ofxDatGuiButton* gui->getButton("my bUTTon"); // button name ofxDatGuiSlider* gui->getSlider("mY sLiDEr"); // slider name
To change a component's label or name simply:
gui->getButton("My Button")->setName("b1"); gui->getButton("b1")->setLabel("Your Button");
If you have multiple components with the same name nested in separate folders just specify the folder to search.
ofxDatGuiButton* gui->getButton("Reset Button", "Folder 1"); ofxDatGuiButton* gui->getButton("Reset Button", "Folder 2");
Otherwise the function will return the first component whose name & type match the query.
ofxDatGui sliders & coordinate pads can also be bound to object variables. Just pass a reference to the variable to the component and set a range by which to limit its movement.
For example the following snippet binds a circle's position to a range slider and limits its movement to the width & height of the screen.
// draw a circle with a radius of 100px // and position it in the middle of the screen // circle = new Circle(100); 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, ofGetWidth()); ofxDatGuiSlider* sy = gui->addSlider("CIRCLE Y", 0, ofGetHeight()); // bind the circle's x & y movement to the sliders // sx->bind(circle->x); sy->bind(circle->y);
Here's a video of the sketch generated by the snippet above.
ofxDatGui v1.1 introduces limited support for ofParameter (currently sliders only)
To bind an ofParameter to an ofxDatGuiSlider simply pass it into the slider's constructor.
// setup three ofParameters // ofParameter<int> p1; ofParameter<float> p2; ofParameter<int> p3; p1.set("position X", 75, 0, 120); p2.set("position Y", 200.0f, -40.0f, 240.0f); p3.set("position Z", -40, -80, 120); // and bind them to slider's by passing them into the constructors // gui = new ofxDatGui(); gui->addLabel("gui from of_parameters"); gui->addSlider(p1); gui->addSlider(p2); gui->addSlider(p3); gui->onSliderEvent(this, &ofApp::onSliderEvent);
Take a look at the ofParameter example for more details.
ofxDatGui automatically updates and draws itself on top of your application so there is no need to call update
or draw
on it. However you can easily disable this if you like via:
gui->setAutoDraw(false);
ofxDatGui will softly warn you if you forget to attach an event listener to a component you've created or if you attempt to perform an action on a component that does not exist.
[ERROR] :: Component Not Found : GHOST BUTTON [WARNING] :: Event Handler Not Set : MY BUTTON
However you can easily suppress these warnings by calling:
ofxDatGuiLog::quiet();
The ability to save and load settings from an external file is currently in development.
Check out the project roadmap for more information.