FLUID The Fast Light User Interface Designer, or FLUID, is a graphical editor that is used to produce FLTK source code Creates C++ code Compile .fl file into .cxx and .h Located in fltk-source/fluid/fluidd.exe We will create the CustomWidget using fluid Timers • • Not 100% accurate (don't measure time with them) Single shot timeouts • void add_timeout(double t, Fl_Timeout_Handler, void* d) o call a function in t seconds void remove_timeout(Fl_Timeout_Handler, void* d) o cancels a timeout (harmless if timer already triggered) void repeat_timeout(double t, Fl_Timeout_Handler, void* d) o call a function t seconds after the last timeout triggered o can only be called from within a timer callback • • Simple Timer Print "TICK" every second void callback(void*) { printf(“TICK\n"); Fl::repeat_timeout(1.0, callback); } int main() { …… Fl::add_timeout(1.0, callback); return Fl::run() } Add Timer to Move CustomWidget Goal: Have slider slide back and forth • Use globals for all variables and widgets o Make customWidget global o Add variable to control direction • Callback o Setup repeat timer o Move widget in specified direction o Check if we have reached max or min and change direction • Main o Set initial direction o Initial timer call int increasing; CustomWidget *customWidget; void timer(void*) { Fl::repeat_timeout(0.02, timer); if ( increasing ) { customWidget->value(customWidget->value() + 1); if ( customWidget->value() >= customWidget->maximum() ) increasing = 0; } else { customWidget->value(customWidget->value() - 1); if ( customWidget->value() <= customWidget->minimum() ) increasing = 1; } } Idle • • Similar to GLUT add_idle(void (*cb)(void*), void *) o function to call whenever nothing else is happening o can have multiple callbacks • remove_timout(void (*cb)(void*), void *) o removes callback function if it exists OpenGL in FLTK OpenGL Widget Create a subclass of Fl_Gl_Window o #include <FL/Fl_Gl_Window.H> o #include <FL/gl.h> Will include <GL/gl.h> • Need to implement draw function in subclass o Setup view port valid() will return false if needed o Actual drawing • OpenGL Widget class OpenGLWindow : public Fl_Gl_Window { private: void draw() { if ( !valid() ) { // initialization } // draw }; public: OpenGLWindow(int x, int y, int w, int h, const char* l = 0) : Fl_Gl_Window(x, y, w, h, l) { }; }; 3D Gasket in FLTK Put all code into subclass of Fl_Gl_Window Copy triangle, tetra, and divide_tetra functions o Move colors into tetra and v into draw • All reference to width are height need to be replaced with w() and h() • Hard code number of sub divisions • Create a window and place OpenGL widget in it • • Widget to Control Sub Divisions • OpenGL draw() now get value from slider widget divide_tetra(v[0], v[1], v[2], v[3], divisions->value()); • Add a slider (and label) for number of sub divisions divisions = new Fl_Slider(100, 480, 540,20); divisions->type(FL_HORIZONTAL); divisions->range(1, 20); divisions->step(1); • Need to tell FLTK/OpenGL Widget to update o call widget's redraw() • Need to redraw when we change slider (callback) void update(Fl_Widget*, void*) { glwindow->redraw(); } // when creating slider divisions->callback(update); Assignment 1 Part 3 in FLTK • • Will use toggle button instead of mouse clicks Timer instead of idle • Create toggle button and start timer spinning = new Fl_Button(545, 485, 90, 20, "Spinning"); spinning->type(FL_TOGGLE_BUTTON); Fl::add_timeout(1, timer, 0); spin = 0.0f; Update spin and redraw if necessary void timer(void*) { Fl::repeat_timeout(0.02, timer); if ( spinning->value() ) { spin += 1.0f; if ( spin > 360.0f ) spin -= 360.0f; glwindow->redraw(); } } • Events Implement int handle(int event) o event is mouse click & drag, mouse wheel, keyboard presses & release, system events • Return 1 if event is used o Event consumed • Return 0 is unused o Event will continue to be passed around • Additional helper functions o Mouse: event_button() event_x() o Keyboard: event_key() • Spin Triangle with Mouse • • Goal: mouse drags will rotate object Filter out only used event o Pass rest to default handler • No previous mouse position with drag event (only current) • Initial click will seed last position • Need to hold current state Spin Triangle with Mouse • Header: int oldX, oldY; float vRotation, hRotation; int handle(int event); • Constructor: vRotation = hRotation = 0.0f; • Draw: glRotatef(hRotation, 0.0f, 1.0f, 0.0f); glRotatef(vRotation, 1.0f, 0.0f, 0.0f); • Handle switch ( event ) { case FL_DRAG: hRotation += Fl::event_x() - oldX; vRotation += Fl::event_y() - oldY; redraw(); case FL_PUSH: oldX = Fl::event_x(); oldY = Fl::event_y(); return 1; default: return Fl_Gl_Window::handle(event); } Assignment 1 Part 3 in FLUID Keep class OpenGLWindow In fluidd.exe Add New->Code->class, set the name of the class ‘UI’ Highlight class UI, New->Code->function/Method, add the constructor UI(), set it public Highlight UI(), New->group->Window, under C++ tab, name it mainWindow Highlight mainWindow, New->valuator->Slider. Change its label. Under tab C++, set it horizontal. Add extra code divisions->range(0, 5); divisions->step(1); Add callback glWindow->setDivision(divisions->value()); glWindow->redraw(); Highlight mainWindow New->Buttons->button. Change its label. Under tab C++, set it a toggle button, and set its name spinning. New->others->box to add OpenGLWindow widget. Under tab C++, add extra code: #include"OpenGLWindow.h“ and name it glWindow. Highlight class UI New->Code->declaration, add a variable ‘float spin’