Erco's FLTK Cheat Page |
These are some common FLTK code snippets I often find hard to remember how to do when looking at the docs. Besides, I like having working code examples handy that I can cut + paste from to get started with right away. I often start with these mini-programs and turn them into working programs.This is always a work in progress; I add examples as I encounter the need for them.
Table Of Contents Fl_Browser Tricks for using a browser Fl_Text_Display Simple example of Fl_Text_Display Fl_Text_Display with colors Simple example of Fl_Text_Display with color styles Fl_Multiline_Output Simple example of Fl_Multiline_Output Fl_Menu_Bar: Changing Labels Shows how to access and change menu item labels at runtime Fl_Menu_Bar callbacks One callback for all menu items, w/out userdata! Fl_Menu_Bar: Miscellaneous Miscellaneous techniques to manipulate Fl_Menu_Bar/Fl_Menu's Fl_Radio_Button How to handle radio buttons Fl_JPG_Image Simple example to display a JPEG image Fl_Image How to walk pixels of an Fl_Image Fl_Wizard How to make a 'wizard' using Fl_Wizard Animate Image How to animate images in FLTK Animate Line Drawing How to animate line drawing in FLTK Fltk Event Names How to print FLTK event names from within your program (for debugging) popen() + add_fd() How to use popen() with add_fd() Fltk + Fifos How to use fifos to control a console program from fltk, showing output in Fl_Browser Slider+Input How to tie an Fl_Slider to an Fl_Int_Input Slider+Tooltip An Fl_Slider with a floating 'tooltip' to show the current value Fltk-tty Shows how to fork() child processes and display their real-time output Draw An X Simple FLTK custom widget to draw an 'X' Scrollable Canvas Shows how to make a scrollable custom canvas Custom Bar Graph Shows how to draw a customized 'trigger' shaped bar graph Table Of Widgets Shows how to make a resizable 'table' of widgets, using Fl_Scroll and Fl_Tile Draggable Boxes Simple app shows user can drag boxes on scrollable 'desk' Popup Menu Shows how to make a popup menu appear Popup Text Window Shows how to make a borderless text window pop up Draw Coordinates How to draw mouse coordinates w/out redrawing screen Progress Bar Demo How to update a progress bar in fltk Scrollable Widget Browser Demonstrates a scrollable browser of widgets that are resizable. Scrollable Image Viewer How to display an image in a scrollable viewer Disable Symbols How to disable '@' symbols throughout your FLTK application OpenGL Simple Example Simple OpenGL example showing how to draw an 'X' OpenGL App with FLTK Widgets Simple OpenGL app with FLTK widget controls OpenGL Shape Interpolation Shows how to animate simple shape interpolation in opengl OpenGL Sphere With Light Simple OpenGL Shaded Sphere with Light Fl_File_Chooser example Shows how to use Fl_File_Chooser (simple, and full test) Clicks on Scrollable Box How to get the coordinates for mouse clicks on scrollable box Fl_Browser with Columns How to use the Fl_Browser methods column_widths() and column_char() Fl_Browser Sorting How to sort an Fl_Browser Strike Through Text Demonstrate how to draw strike through text Fl_Gl_Window + Cursor Demonstrate how to change the mouse cursor for an Fl_Gl_Window Fl_Resize_Browser How to extend Fl_Browser to have interactively resizable columns Fl_Tile (4) Port Fl_Gl_Window How to make a 4 port proportionally resizable openGL window using Fl_Tile OpenGL with Dynamic Popup Menu How to make a dynamic popup menu for an openGL window Drop Shadow Box Example How to make text with a drop shadow effect OpenGL Text on 3D Object How to make text appear on a spinning OpenGL object Simple Fl_Tabs Example Simple demo of how to use the Fl_Tabs widget Making a Mac "Bundle" (.app) How to turn a Mac FLTK application into an ".app bundle" Making icons for Mac "Bundles" How to make icons for your Mac application Touch Pad How to make a pop-up numeric keypad for touch screens Drawing into overlay planes Two examples on drawing into the overlay planes Thumbnails In Scroller How to show a scroller of thumbnail images with labels Drag And Drop How to use Drag+Drop fl_draw_image() How to draw into a pixel buffer, and display it using fl_draw_image() FLTK/WIN32 File Chooser How to open a WIN32 File Chooser directly from FLTK Fl_Group Event vs. Draw Clipping Fl_Group xywh clips children of events, but not graphics Vertical Tabs How to use Fl_Browser to implement a 'vertical tab' dialog Fl_Chart How to use Fl_Chart Also, some of my other fltk related stuff:
- Fltk Videos -- Video tutorials on how to use fltk
- Fl_Table -- A flexible table widget
- Fl_Input_Choice -- A combo of Fl_Input and Fl_Choice (to be in fltk-1.1.7)
- Fl_Native_File_Chooser -- A widget for accessing native OS file browsers
- Fl_Gel_Tabs -- A 'Mac OSX' style tab widget
- Fl_Matte_Button -- A 'matte finish' button widget
- Fl_Fixed_Group -- A fixed sized group whose edges can be attached to a parent
- nixieclock -- A Nixietube Clock (application and widget)
- flruler -- A desktop ruler (GUI debugging tool)
| Fl_Browser |
One thing I use is browsers. Browsers are a composite of several other widgets, and often involves remembering certain programming techniques to manipulate them.
Fl_Browser "How To" Code Snippets Fl_Browser browser(0,0,500,500); // CLEAR BROWSER browser.clear(); // ADD LINES TO BROWSER browser.add("One"); // fltk does strdup() internally browser.add("Two"); browser.add("Three"); // FORMAT CHARACTERS: CHANGING TEXT COLORS IN LINES // Warning: format chars are returned to you via ::text() // @C# - text color @b - bold // @B# - background color @i - italic // @F# - set font number @f - fixed pitch font // @S# - set point size @u - underline // @. - terminate '@' parser @- - strikeout // browser.add("Black @C1Red @C2Green @C3Yellow"); // DISABLING FORMAT CHARACTERS browser.format_char(0); // ACCESS ALL SELECTED ITEMS IN BROWSER for ( int t=1; t<=browser->size(); t++ ) { if ( browser->selected(t) ) { printf("%d) '%s'\n", t, browser->text(t)); } } // PRE-SELECT ALL LINES IN BROWSER // Note: index numbers are 1 based..! // for ( int t=1; t<=browser->size(); t++ ) { browser->select(t); } // DE-SELECT ALL LINES IN BROWSER browser->deselect(); // GET SINGLE SELECTED ITEM FROM BROWSER int index = browser->value(); // USING INDEX NUMBER, RETURN TEXT // Note: index numbers are 1 based..! // if ( index > 0 ) { const char *s = browser->text(index); .. }Here's an older example that shows how to add a swap() method to Fl_Browser for versions of Fltk older than Fltk 1.1.5.
| Fl_Multiline_Output |
Making windows that display multiple lines of text is another common thing I find myself doing.
Displaying Multiple Lines Of Text Fl_Multiline_Output output(0,0,500,500); // CLEAR OUTPUT output->value(""); // SET OUTPUT output->value("one\ntwo"); // fltk does strdup() internally // APPENDING OUTPUT // Would be nice if this were an add() method in fltk ;) // char *news = "Add this text"; char *cat = (char*)malloc(strlen(output->value()) + strlen(news) + 1); strcpy(cat, output->value()); strcat(cat, news); output->value(cat); free(cat);
| Fl_Menu_Bar: Changing Menu Item's Labels At Runtime |
Shows how to access and change menu items at run time.
Access and Change Menu Item's Labels #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Menu_Bar.H> #include <stdlib.h> // // Show how to change submenu names and menu item names // Click on Edit -> Change to change the contents of the Edit menu. // void Change_CB(Fl_Widget *w, void *) { Fl_Menu_Bar *menu = (Fl_Menu_Bar*)w; Fl_Menu_Item *p; // Change submenu name p = (Fl_Menu_Item*)menu->find_item("Edit/Submenu"); if ( p ) p->label("New Submenu Name"); // Change item name p = (Fl_Menu_Item*)menu->find_item("Edit/New Submenu Name/Aaa"); if ( p ) p->label("New Aaa Name"); } void Quit_CB(Fl_Widget *, void *) { exit(0); } int main() { Fl_Window *win = new Fl_Window(400,400); Fl_Menu_Bar *menu = new Fl_Menu_Bar(0,0,400,25); menu->add("File/Quit", FL_CTRL+'q', Quit_CB); menu->add("Edit/Change", FL_CTRL+'c', Change_CB); menu->add("Edit/Submenu/Aaa"); menu->add("Edit/Submenu/Bbb"); win->end(); win->show(); return(Fl::run()); }
| Fl_Menu_Bar Single Callback Example |
Here's an example program showing a neat trick that lets the menubar's callback determine the full menu item's 'pathname' (eg. "File/Quit") without using any userdata.
Accessing Menu Items Without Using Callback Data // Show the use of item_pathname() in a custom class. #include <stdio.h> #include <string.h> #include <stdlib.h> #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Menu_Bar.H> class MyApp { Fl_Window *win; Fl_Menu_Bar *menubar; // Static menu callback static void Menu_CB(Fl_Widget*w, void*data) { MyApp *o = (MyApp*)data; o->Menu_CB2(); } // Callback method with class access void Menu_CB2() { char picked[80]; menubar->item_pathname(picked, sizeof(picked)-1); printf("CALLBACK: You picked '%s'\n", picked); // How to handle callbacks.. if ( strcmp(picked, "File/Quit") == 0 ) exit(0); if ( strcmp(picked, "Help/Help") == 0 ) printf("Help goes here\n"); } public: MyApp() { // Make the app window and menu bar w/callbacks win = new Fl_Window(720, 486); menubar = new Fl_Menu_Bar(0, 0, win->w(), 25); menubar->add("File/Open", 0, Menu_CB, (void*)this); // userdata is always 'this' menubar->add("File/Quit", 0, Menu_CB, (void*)this); menubar->add("Help/Help", 0, Menu_CB, (void*)this); win->end(); win->show(); } }; // MAIN int main() { MyApp app; return(Fl::run()); }Here's an older example that works with fltk 1.1.5 and back that doesn't have item_pathname() built in.
| Fl_Menu_Bar |
Dynamically creating/clearing submenus in the main menu bar is something I often need to do. Since it's not well documented how this is done, this is what I've figured out.WARNING: when creating or modifying menus using add(), beware that if you name items in fluid, the pointers may become invalid, since dynamic manipulation of the menus can cause the array to be realloc()ed, causing menu item pointers to become STALE. The submenus and all their contents in the menu bar are really all part of a single linear internal array to the Fl_Menu_Bar class, and are accessed as:
Accessing Menu Items In Fl_Menu_Bar for ( int t=0; t < menubar->size(); t++ ) { Fl_Menu_Item *m = (Fl_Menu_Item*)&(menubar->menu()[t]); : : }Given the above on how the menus are arranged in the array, here are some guides for how to write routines to work with FLTK menus dynamically.
Dynamic Manipulation Of Menus in FLTK // FIND MENU ITEM INDEX, GIVEN MENU PATHNAME // eg. "Edit/Copy" // Will also return submenus, eg. "Edit" // Returns -1 if not found. // int GetIndexByName(Fl_Menu_Bar* menubar, const char *findname) { char menupath[1024] = ""; // File/Export for ( int t=0; t < menubar->size(); t++ ) { Fl_Menu_Item *m = (Fl_Menu_Item*)&(menubar->menu()[t]); if ( m->submenu() ) { // Submenu? if ( menupath[0] ) strcat(menupath, "/"); strcat(menupath, m->label()); if ( strcmp(menupath, findname) == 0 ) return(t); } else { if ( m->label() == NULL ) { // End of submenu? Pop back one level. char *ss = strrchr(menupath, '/'); if ( ss ) *ss = 0; else menupath[0] = '\0'; continue; } // Menu item? char itempath[1024]; // eg. Edit/Copy strcpy(itempath, menupath); if ( itempath[0] ) strcat(itempath, "/"); strcat(itempath, m->label()); if ( strcmp(itempath, findname) == 0 ) { return(t); } } } return(-1); } // FIND A MENU ITEM BY MENU PATHNAME // eg. "Edit/Copy" // Will also return submenus, eg. "Edit" // Returns NULL if not found. // Fl_Menu_Item *GetMenuItemByName(Fl_Menu_Bar* menubar, const char *findname) { int index = GetIndexByName(menubar, findname); if ( index == -1 ) return(NULL); Fl_Menu_Item *m = (Fl_Menu_Item*)&(menubar->menu()[index]); return(m); } // TURN ON RADIO BUTTON GIVEN MENU PATHNAME // eg. SetRadioByName(menubar, "File/Radio-1") // void SetRadioByName(Fl_Menu_Bar *menubar, const char *menuname) { Fl_Menu_Item *m = GetMenuItemByName(menubar, menuname); if ( m == NULL ) return; m->setonly(); } // SET TOGGLE BUTTON ON OR OFF, GIVEN MENU PATHNAME // eg. SetToggleByName("File/Toggle-1", "on") // void SetToggleByName(Fl_Menu_Bar *menubar, const char *menuname, int val ) { Fl_Menu_Item *m = GetMenuItemByName(menubar, menuname); if ( m == NULL ) return; if ( val ) m->set(); else m->clear(); } // ACTIVATE MENU ITEM, GIVEN MENU ITEM PATHNAME // eg. SetActivateByName("File/Radio-1") // void SetActivateByName(Fl_Menu_Bar *menubar, const char *menuname, int val) { Fl_Menu_Item *m = GetMenuItemByName(menubar, menuname); if ( m == NULL ) return; if ( val ) m->activate(); else m->deactivate(); } // GET TOGGLE BUTTON STATE, GIVEN MENU PATHNAME // eg. GetToggleByName("Edit/Preferences/Toggle-1") // int GetToggleValueByName(Fl_Menu_Bar *menubar, const char *menuname) { Fl_Menu_Item *m = GetMenuItemByName(menubar, menuname); if ( m == NULL ) return; return(m->value()); } // CLEAR ALL ITEMS IN SUBMENU BELOW THE NAMED ITEM // eg. ClearItemsBelow("File/Save As"); // where menu looks like: // // File..New // Open // Save // Save As // ------- __ // /usr/tmp/foo.st |__ Clear all these so they // /usr/tmp/bar.st | can be recreated later. // /usr/tmp/bla.st __| // __ // Edit..Cut | // Copy | These are unaffected. // Paste __| // static void ClearItemsBelow(Fl_Menu_Bar *menubar, const char *menuname) { int index = GetIndexByName(menubar, menuname); if ( index == -1 ) return; int level = 0; ++index; // skip the item itself, so we delete stuff _below_ it while ( index <= menubar->size() ) { Fl_Menu_Item *m = (Fl_Menu_Item*)&(menubar->menu()[index]); if ( m->label() == NULL ) { // Pop out of submenu, keep track of level if ( --level < 0 ) return; } else { // Descending into a submenu? Keep track of leveL if ( m->submenu() ) ++level; } // Remove all menu items *and* submenus menubar->remove(index); } }
| Fl_Radio_Button |
Dealing with radio buttons in menus is fairly easy, using the Fl_Menu_Bar routines described above. I guess fltk groups radio buttons together based on dividers and submenus.
Using Radio Buttons In Menus int index = GetIndexByName(menubar, "Edit/Preferences/Radio 1"); Fl_Menu_Item *m = menubar->menu(); m[index]->setonly(); // set radio on, turns other(s) off int onoff = m[index]->value(); // get radio button's state
| Fl_Text_Display |
A simple example of how to use Fl_Text_Display, a read only viewer.If you want to make it an editor, change all instances of the string "Fl_Text_Display" to "Fl_Text_Editor".
Simple Example of How To Use Fl_Text_Display // Fl_Text_Display example. -erco #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Text_Display.H> int main() { Fl_Window *win = new Fl_Window(640, 480); Fl_Text_Buffer *buff = new Fl_Text_Buffer(); Fl_Text_Display *disp = new Fl_Text_Display(20, 20, 640-40, 480-40, "Display"); disp->buffer(buff); win->resizable(*disp); win->show(); buff->text("line 0\nline 1\nline 2\n" "line 3\nline 4\nline 5\n" "line 6\nline 7\nline 8\n" "line 9\nline 10\nline 11\n" "line 12\nline 13\nline 14\n" "line 15\nline 16\nline 17\n" "line 18\nline 19\nline 20\n" "line 21\nline 22\nline 23\n"); return(Fl::run()); }
| Fl_Text_Display with colors |
A simple example of how to use Fl_Text_Display with colors.This example shows how to add text with different colors by creating a 'style buffer', where each character in the style buffer corresponds to a character in the text buffer, and the contents of the style buffer specifies characters (A, B, C.. ) that correspond to entries in your pre-defined 'style table', that defines the actual attributes of each character.
This scheme is similar to a 'color map' in images, where the image data is not an RGB color, but an index into a color table.
Simple Example of Fl_Text_Display with colors // Fl_Text_Display example with color styles . -erco #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Text_Display.H> int main() { // Style table Fl_Text_Display::Style_Table_Entry stable[] = { // FONT COLOR FONT FACE FONT SIZE // --------------- ----------- -------------- { FL_RED, FL_COURIER, 18 }, // A - Red { FL_DARK_YELLOW, FL_COURIER, 18 }, // B - Yellow { FL_DARK_GREEN, FL_COURIER, 18 }, // C - Green { FL_BLUE, FL_COURIER, 18 }, // D - Blue }; Fl_Window *win = new Fl_Window(640, 480); Fl_Text_Display *disp = new Fl_Text_Display(20, 20, 640-40, 480-40, "Display"); Fl_Text_Buffer *tbuff = new Fl_Text_Buffer(); // text buffer Fl_Text_Buffer *sbuff = new Fl_Text_Buffer(); // style buffer disp->buffer(tbuff); int stable_size = sizeof(stable)/sizeof(stable[0]); disp->highlight_data(sbuff, stable, stable_size, 'A', 0, 0); // Text tbuff->text("Red Line 1\nYel Line 2\nGrn Line 3\nBlu Line 4\n" "Red Line 5\nYel Line 6\nGrn Line 7\nBlu Line 8\n"); // Style for text sbuff->text("AAAAAAAAAA\nBBBBBBBBBB\nCCCCCCCCCC\nDDDDDDDDDD\n" "AAAAAAAAAA\nBBBBBBBBBB\nCCCCCCCCCC\nDDDDDDDDDD\n"); win->resizable(*disp); win->show(); return(Fl::run()); }
| Fl_JPG_Image: A simple example |
A simple example of how to load and display a JPEG image.For PNG's, just substitute all occurances of "JPEG" with "PNG". Same for GIFs, and other supported image formats.
Simple example to display a JPEG image #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Shared_Image.H> #include <FL/Fl_JPEG_Image.H> #include <FL/Fl_Box.H> int main() { fl_register_images(); // initialize image lib Fl_Window win(720,486); // make a window Fl_Box box(10,10,720-20,486-20); // widget that will contain image Fl_JPEG_Image jpg("/var/tmp/foo.jpg"); // load jpeg image into ram box.image(jpg); // attach jpg image to box win.show(); return(Fl::run()); }
| Fl_Image |
An example of how to walk the r/g/b pixel data of an Fl_BMP_Image image.NOTE: There are faster ways of coding this to avoid recalculating 'index' at every pixel. This is just to make a clear example of how pixel indexes should be calculated, eg. for random access. Optimization is left as an exercise to the reader.
Accessing Raw RGB Data from Fl_Image #include <stdio.h> #include <FL/Fl_BMP_Image.H> int main() { Fl_BMP_Image *img = new Fl_BMP_Image("tiny.bmp"); if ( img->d() == 0 ) { perror("tiny.bmp"); exit(1); } char r,g,b; for ( int y=0; y<img->h(); y++ ) { // X loop for ( int x=0; x<img->w(); x++ ) { // Y loop long index = (y * img->w() * img->d()) + (x * img->d()); // X/Y -> buf index switch ( img->count() ) { case 1: { // bitmap const char *buf = img->data()[0]; switch ( img->d() ) { case 1: { // 8bit r = g = b = *(buf+index); break; } case 3: // 24bit r = *(buf+index+0); g = *(buf+index+1); b = *(buf+index+2); break; default: // ?? printf("Not supported: chans=%d\n", img->d()); exit(1); } break; } default: // ?? pixmap, bit vals printf("Not supported: count=%d\n", img->count()); exit(1); } printf("%2x %2x %2x\n", // hex dump r/g/b (unsigned char)r, (unsigned char)g, (unsigned char)b); } } }
| Fl_Wizard Example |
A simple 3 screen 'wizard' using Fl_Wizard, showing how groups can be used to move through the 'pages' of the wizard.
FLTK's Wizard #include <stdlib.h> #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Group.H> #include <FL/Fl_Wizard.H> #include <FL/Fl_Button.H> #include <FL/Fl_Multiline_Output.H> // Simple 'wizard' using fltk's new Fl_Wizard widget Fl_Window *G_win = 0; Fl_Wizard *G_wiz = 0; void back_cb(Fl_Widget*,void*) { G_wiz->prev(); } void next_cb(Fl_Widget*,void*) { G_wiz->next(); } void done_cb(Fl_Widget*,void*) { exit(0); } int main(int argc, char **argv) { G_win = new Fl_Window(400,300,"Example Wizard"); G_wiz = new Fl_Wizard(0,0,400,300); // Wizard: page 1 { Fl_Group *g = new Fl_Group(0,0,400,300); Fl_Button *next = new Fl_Button(290,265,100,25,"Next"); next->callback(next_cb); Fl_Multiline_Output *out = new Fl_Multiline_Output(10,30,400-20,300-80,"Welcome"); out->labelsize(20); out->align(FL_ALIGN_TOP|FL_ALIGN_LEFT); out->value("This is First page"); g->end(); } // Wizard: page 2 { Fl_Group *g = new Fl_Group(0,0,400,300); Fl_Button *next = new Fl_Button(290,265,100,25,"Next"); next->callback(next_cb); Fl_Button *back = new Fl_Button(180,265,100,25,"Back"); back->callback(back_cb); Fl_Multiline_Output *out = new Fl_Multiline_Output(10,30,400-20,300-80,"Terms And Conditions"); out->labelsize(20); out->align(FL_ALIGN_TOP|FL_ALIGN_LEFT); out->value("This is the Second page"); g->end(); } // Wizard: page 3 { Fl_Group *g = new Fl_Group(0,0,400,300); Fl_Button *done = new Fl_Button(290,265,100,25,"Finish"); done->callback(done_cb); Fl_Button *back = new Fl_Button(180,265,100,25,"Back"); back->callback(back_cb); Fl_Multiline_Output *out = new Fl_Multiline_Output(10,30,400-20,300-80,"Finish"); out->labelsize(20); out->align(FL_ALIGN_TOP|FL_ALIGN_LEFT); out->value("This is the Last page"); g->end(); } G_wiz->end(); G_win->end(); G_win->show(argc, argv); return Fl::run(); }
| Image Animation Example |
Shows how to animate some JPG files. Here are some jpgs you can use for playback.
Animating Images in FLTK #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Shared_Image.H> #include <FL/Fl_JPEG_Image.H> #include <FL/Fl_Box.H> // animate.cxx -- Animate playback of three jpg images (0001.jpg, 0002.jpg..) // Hold each image for RATE seconds // #define RATE 0.1 // how long to hold each image #define TOTAL 3 // total images: /var/tmp/000{1,2,3}.jpg Fl_Window *win = 0; // main window Fl_JPEG_Image *jpgs[TOTAL]; // loaded images Fl_Group *grp = 0; // group in which images are displayed // SHOW NEXT IMAGE // Slaps next image up on screen, resets frame timer. // void ShowNextImage_CB(void*) { static int x = 0; grp->image(jpgs[x++ % TOTAL]); win->redraw(); // Fl::repeat_timeout(RATE, ShowNextImage_CB); // steady rate Fl::repeat_timeout(((x%TOTAL)==0)?2.0:RATE, ShowNextImage_CB); // eye blink: hold 0003.jpg for 2 secs } // LOAD ALL IMAGES INTO MEMORY int LoadImages() { for ( int t=0; t<TOTAL; t++ ) { char filename[80]; sprintf(filename, "%04d.jpg", t+1); // 0001.jpg, 0002.jpg.. jpgs[t] = new Fl_JPEG_Image(filename); if ( jpgs[t]->w() == 0 ) { perror(filename); return(1); } } return(0); } // MAIN -- OPEN DOUBLE BUFFERED WINDOW, LOAD IMAGES, START PLAYBACK int main() { fl_register_images(); // initialize image lib win = new Fl_Double_Window(720,486); // make a window grp = new Fl_Group(0,0,win->w(),win->h()); grp->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); win->show(); if ( LoadImages() ) return(1); Fl::add_timeout(RATE, ShowNextImage_CB); return(Fl::run()); }
| Line Drawing Animation Example |
Shows how to animate line drawing, showing a simple timer application that animates the 'second hand'.
Animating Line Drawing in FLTK // // FLTK drawing example showing simple line drawing animation // erco 03/22/07 // #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Box.H> #include <FL/fl_draw.h> #include <math.h> #include <stdio.h> #include <time.h> #define BG_COLOR 45 #define TICK_COLOR 50 #define CIRC_COLOR 0 class MyTimer : public Fl_Box { void draw() { // COMPUTE NEW COORDS OF LINE static long start = time(NULL); long tick = time(NULL) - start; char secs[80]; sprintf(secs, "%02ld:%02ld", tick/60, tick%60); float pi = 3.14 - (((tick % 60) / 60.0) * 6.28); int radius = h() / 2; int x1 = (int)(x() + w()/2), y1 = (int)(y() + h()/2), x2 = (int)(x1 + (sin(pi) * radius)), y2 = (int)(y1 + (cos(pi) * radius)); // TELL BASE WIDGET TO DRAW ITS BACKGROUND Fl_Box::draw(); // DRAW 'SECOND HAND' OVER WIDGET'S BACKGROUND fl_color(TICK_COLOR); fl_line(x1, y1, x2, y2); fl_color(CIRC_COLOR); fl_pie(x1-10, y1-10, 20, 20, 0.0, 360.0); // DRAW TIMER TEXT STRING fl_color(TICK_COLOR); fl_font(FL_HELVETICA,16); fl_draw(secs, x()+4, y()+h()-4); } static void Timer_CB(void *userdata) { MyTimer *o = (MyTimer*)userdata; o->redraw(); Fl::repeat_timeout(0.25, Timer_CB, userdata); } public: // CONSTRUCTOR MyTimer(int X,int Y,int W,int H,const char*L=0) : Fl_Box(X,Y,W,H,L) { box(FL_FLAT_BOX); color(BG_COLOR); Fl::add_timeout(0.25, Timer_CB, (void*)this); } }; // MAIN int main() { Fl_Double_Window win(220, 220); MyTimer tim(10, 10, win.w()-20, win.h()-20); win.show(); return(Fl::run()); }
| Printing FLTK Event Names |
Here is an eventnames.h file that you can include in your FLTK programs to make it easy to print FLTK event names from within your program, useful for debugging.Example use:
Printing FLTK Event Names #include "eventnames.h" : class YourClass : public Fl_Window { int handle(int e) { : fprintf(stderr, "YOURCLASS EVENT: %s(%d)\n", eventnames[e], e); : } };
| Using popen() and Fl::add_fd() |
The following code shows how to use popen() with Fl::add_fd().You can highlight text and scroll while output is coming in, showing that the FLTK interface is 'alive' while the command is running.
The add_fd() technique works well under unix, but may not work under Windows.
Example: Using popen() and Fl::add_fd() // demo use of popen() and Fl::add_fd() - erco 10/04/04 #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Multi_Browser.H> #include <stdio.h> #ifdef _WIN32 #include <windows.h> #define PING_CMD "ping -n 9999 localhost" // 'slow command' under windows #define popen _popen #define pclose _pclose #else #include <unistd.h> #define PING_CMD "ping localhost" // 'slow command' under unix #endif FILE *G_fp = NULL; void HandleFD(int fd, void *data) { Fl_Multi_Browser *brow = (Fl_Multi_Browser*)data; char s[1024]; if ( fgets(s, 1023, G_fp) == NULL ) { Fl::remove_fd(fileno(G_fp)); pclose(G_fp); return; } brow->add(s); } int main() { Fl_Window win(600,600); Fl_Multi_Browser brow(10,10,580,580); if ( ( G_fp = popen(PING_CMD, "r") ) == NULL ) { perror("popen failed"); return(1); } Fl::add_fd(fileno(G_fp), HandleFD, (void*)&brow); win.resizable(brow); win.show(); return(Fl::run()); }
| Fltk + Fifos |
The following shows how to use fifos to control a console oriented menu program from fltk, showing its output in Fl_Browser. Unix only.This demo uses a bourne shell script [menu.sh] to be the 'menu program' to be controlled by the fltk program [demo-fifo.cxx].
Example: Using FLTK with named pipes and popen() [menu.sh]
#!/bin/bash while [ 1 ]; do echo "" echo "Menu Options" echo " a) Do an ls -la" echo " b) netstat" echo " c) date/uptime/w" echo " q) quit" echo "" echo "Your choice?" read choice if [ ! $? ]; then echo 'Parent closed'; exit 1; fi case $choice in a) ls -la ;; b) netstat ;; c) date; uptime; w ;; q) exit 0 ;; esac done [demo-fifo.cxx]
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> // mkfifo #include <sys/stat.h> // mkfifo #include <fcntl.h> // open #include <signal.h> // killpg #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Multi_Browser.H> #include <FL/Fl_Button.H> // // Demonstrate how to use fltk with named pipes // erco 1.00 09/21/2005 // // Globals FILE *G_in = NULL; // how we read the child int G_out = 0; // how we write to the child // Close all descriptors, remove fifo void CleanExit_CB(Fl_Widget*, void *data) { unlink("tomenu.fifo"); killpg(getpid(), SIGKILL); _exit(0); } // Read output from child, append to browser void HandleInput_CB(int, void *data) { Fl_Multi_Browser *brow = (Fl_Multi_Browser*)data; static int x = 0; static char s[1024]; char c = fgetc(G_in); // read one char at a time if ( c == '\n' || x == (sizeof(s)-1) ) { s[x] = 0; brow->add(s); x = 0; } else { s[x++] = c; } } // Handle sending commands to child when button pressed void HandleButton_CB(Fl_Widget*, void *data) { write(G_out, data, strlen((char*)data)); // 'data' is a string, eg. "a\n" } int main() { // Process group leader (for killpg()) setsid(); // Make fifo unlink("tomenu.fifo"); if ( mkfifo("tomenu.fifo", 0666) < 0 ) { perror("mkfifo(tomenu.fifo)"); exit(1); } // Popen child for reading, set child to read fifo if ( ( G_in = popen("./menu.sh < tomenu.fifo", "r") ) == NULL ) { perror("popen failed"); exit(1); } setbuf(G_in, NULL); // disable buffering // Now open fifo if ( ( G_out = open("tomenu.fifo", O_WRONLY) ) < 0 ) { perror("open(tomenu.fifo) for write failed"); unlink("tomenu.fifo"); exit(1); } // Fltk stuff Fl_Window win(600,600); win.callback(CleanExit_CB); Fl_Button a(10, 10, 20, 20, "A"); a.callback(HandleButton_CB, (void*)"a\n"); Fl_Button b(30, 10, 20, 20, "B"); b.callback(HandleButton_CB, (void*)"b\n"); Fl_Button c(50, 10, 20, 20, "C"); c.callback(HandleButton_CB, (void*)"c\n"); Fl_Button q(70, 10, 20, 20, "q"); q.callback(CleanExit_CB, (void*)"q\n"); Fl_Multi_Browser brow(10,30,580,560); brow.textfont(FL_COURIER); Fl::add_fd(fileno(G_in), HandleInput_CB, (void*)&brow); win.resizable(brow); win.show(); return(Fl::run()); }
| Tying an Fl_Slider and Fl_Int_Input Together |
The following code shows how to tie Fl_Int_Input and Fl_Slider widgets together, making a new 'composite' widget called 'SliderInput'. The widget is derived from an Fl_Group, so that the two widgets can exist together.Dragging the slider changes the input widget, and changing the input widget repositions the slider. eg:
SliderInput - Tie Fl_Slider and Fl_Int_Input together #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Int_Input.H> #include <FL/Fl_Slider.H> #include <stdio.h> // sliderinput -- simple example of tying an fltk slider and input widget together // 1.00 erco 10/17/04 class SliderInput : public Fl_Group { Fl_Int_Input *input; Fl_Slider *slider; // CALLBACK HANDLERS // These 'attach' the input and slider's values together. // void Slider_CB2() { static int recurse = 0; if ( recurse ) { return; } else { recurse = 1; char s[80]; sprintf(s, "%d", (int)(slider->value() + .5)); // fprintf(stderr, "SPRINTF(%d) -> '%s'\n", (int)slider->value(), s); input->value(s); // pass slider's value to input recurse = 0; } } static void Slider_CB(Fl_Widget *w, void *data) { ((SliderInput*)data)-> Slider_CB2(); } void Input_CB2() { static int recurse = 0; if ( recurse ) { return; } else { recurse = 1; int val = 0; if ( sscanf(input->value(), "%d", &val) != 1 ) { val = 0; } // fprintf(stderr, "SCANF('%s') -> %d\n", input->value(), val); slider->value(val); // pass input's value to slider recurse = 0; } } static void Input_CB(Fl_Widget *w, void *data) { ((SliderInput*)data)-> Input_CB2(); } public: // CTOR SliderInput(int x, int y, int w, int h, const char *l=0) : Fl_Group(x,y,w,h,l) { int in_w = 40; int in_h = 25; input = new Fl_Int_Input(x+10, y+10, in_w, in_h); input->callback(Input_CB, (void*)this); input->when(FL_WHEN_ENTER_KEY|FL_WHEN_NOT_CHANGED); slider = new Fl_Slider(x+10+in_w, y+10, w - 20 - in_w, in_h); slider->type(1); slider->callback(Slider_CB, (void*)this); bounds(1, 10); // some usable default value(5); // some usable default end(); // close the group } // MINIMAL ACCESSORS -- Add your own as needed int value() { return((int)(slider->value() + 0.5)); } void value(int val) { slider->value(val); Slider_CB2(); } void minumum(int val) { slider->minimum(val); } int minumum() { return((int)slider->minimum()); } void maximum(int val) { slider->maximum(val); } int maximum() { return((int)slider->maximum()); } void bounds(int low, int high) { slider->bounds(low, high); } }; int main() { Fl_Window win(240,90); SliderInput *si = new SliderInput(20,20,200,50,"Slider Input"); si->color(44); si->box(FL_FLAT_BOX); si->bounds(1,100); si->value(50); win.show(); return(Fl::run()); }
| Fl_Slider with a floating tooltip to show current value |
The following code shows how to get a floating tooltip to show the current value of the slider while it's being moved. Not well tested. 'It works under linux'. Example:
Fl_Slider with a floating tooltip to show current value // Demonstrate a slider with tooltip that tracks the mouse - erco 11/18/04 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <FL/fl_draw.H> #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Group.H> #include <FL/Fl_Slider.H> #include <FL/Fl_Menu_Window.H> #include <FL/Fl_Tooltip.H> // FLOATING TIP WINDOW class TipWin : public Fl_Menu_Window { char tip[40]; public: TipWin():Fl_Menu_Window(1,1) { // will autosize strcpy(tip, "X.XX"); set_override(); end(); } void draw() { draw_box(FL_BORDER_BOX, 0, 0, w(), h(), Fl_Color(175)); fl_color(FL_BLACK); fl_font(labelfont(), labelsize()); fl_draw(tip, 3, 3, w()-6, h()-6, Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_WRAP)); } void value(float f) { sprintf(tip, "%.2f", f); // Recalc size of window fl_font(labelfont(), labelsize()); int W = w(), H = h(); fl_measure(tip, W, H, 0); W += 8; size(W, H); redraw(); } }; // VALUE SLIDER WITH FLOATING TIP WINDOW class MyValueSlider : public Fl_Slider { TipWin *tipwin; void value_cb2() { tipwin->value(value()); tipwin->position(Fl::event_x_root(), Fl::event_y_root()+20); } static void value_cb(Fl_Widget*, void*data) { MyValueSlider *val = (MyValueSlider*)data; val->value_cb2(); } public: MyValueSlider(int x,int y,int w,int h,const char*l=0):Fl_Slider(x,y,w,h,l) { type(FL_HOR_SLIDER); callback(value_cb, (void*)this); Fl_Group *save = Fl_Group::current(); // save current widget.. tipwin = new TipWin(); // ..because this trashes it tipwin->hide(); Fl_Group::current(save); // ..then back to previous. } int handle(int e) { switch(e) { case FL_PUSH: // XXX: if offscreen, move tip ABOVE mouse instead tipwin->position(Fl::event_x_root(), Fl::event_y_root()+20); tipwin->value(value()); tipwin->show(); break; case FL_HIDE: // valuator goes away case FL_RELEASE: // release mouse case FL_LEAVE: // leave focus // Make sure tipwin closes when app closes tipwin->hide(); break; } return(Fl_Slider::handle(e)); } }; int main() { Fl_Double_Window *win = new Fl_Double_Window(640, 100); MyValueSlider *val1 = new MyValueSlider(20,20,200,30); MyValueSlider *val2 = new MyValueSlider(20,50,200,30); win->show(); return(Fl::run()); }
| Show Real-Time Output of Child Processes in Fl_Text_Display |
The following is a unix example that starts three child processes, showing their real-time output in separate FLTK Fl_Text_Display widgets. Also demonstrates how to use Fl::add_fd(), Fl::remove_fd(), and the unix calls waitpid(), fork(), execlp() and pipe() all together in one example. When the window is closed, any child processes that were running are killed first.
The design is this:
- Open three Fl_Text_Display widgets [see main()]
- Start three external processes that generate text on stdout [see start_child()], and configure FLTK to invoke a callback [data_ready()] whenever output from these processes is generated, so the data is appended to the appropriate Fl_Text_Display widget in real-time
- Set up FLTK to invoke a callback [close_cb()] if the app is closed, so child processes are first killed, before the app exits (preventing orphaned processes).
As the processes run, FLTK's event loop invokes callbacks whenever data is generated by the child processes, thanks to FLTK's add_fd() mechanism. The FLTK event loop also handles all FLTK events, such as when the user moves the scrollbars, highlights text, etc.
This is unix specific code. (Won't work on Windows)
Fltk-Tty example #include <sys/types.h> #include <sys/wait.h> #include <errno.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Text_Display.H> // // fltk-ttys - Open several processes, display their output in fltk widgets // Greg Ercolano 02/21/2005 1.00 // // Globals Fl_Text_Display *G_disp[3]; // one display per child Fl_Text_Buffer *G_buff[3]; // one buffer per child int G_outfd[3]; // read pipe for child's stderr, one per child pid_t G_pids[3]; // pid for each child // Start child process, makes a read pipe to its stderr void start_child(int t) { int out[2]; pipe(out); switch ( ( G_pids[t] = fork() ) ) { case -1: // Error close(out[0]); close(out[1]); perror("fork()"); exit(1); case 0: // Child close(out[0]); dup2(out[1], 2); close(out[1]); switch (t) { case 0: execlp("/bin/sh", "sh", "-c", "ps auxww 1>&2",0); perror("execlp(ps)"); exit(1); case 1: execlp("/bin/sh", "sh", "-c", "perl -e 'for($t=0; sleep(1); $t++)" "{print STDERR rand().\"\\n\"; if ($t>5) {kill(9,$$);}}' 1>&2", 0); perror("execlp(perl)"); exit(1); case 2: execlp("/bin/sh", "sh", "-c", "(ls -la; ping -c 8 localhost) 1>&2", 0); perror("execlp(ls/ping)"); exit(1); default: exit(1); } default: // Parent G_outfd[t] = out[0]; close(out[1]); return; } } // Data ready interrupt void data_ready(int fd, void *data) { int t = (int)data; char s[4096]; int bytes = read(fd, s, 4096-1); // fprintf(stderr, "Data ready for %d) pid=%ld fd=%d bytes=%d\n", t, (long)G_pids[t], fd, bytes); if ( bytes == -1 ) { // ERROR perror("read()"); } else if ( bytes == 0 ) { // EOF G_buff[t]->append("\n\n*** EOF ***\n"); int status; if ( waitpid(G_pids[t], &status, WNOHANG) < 0 ) { sprintf(s, "waitpid(): %s\n", strerror(errno)); } else { if ( WIFEXITED(status) ) { sprintf(s, "Exit=%d\n", WEXITSTATUS(status)); close(fd); Fl::remove_fd(fd); G_pids[t] = -1; } else if ( WIFSIGNALED(status) ) { sprintf(s, "Killed with %d\n", WTERMSIG(status)); close(fd); Fl::remove_fd(fd); G_pids[t] = -1; } else if ( WIFSTOPPED(status) ) { sprintf(s, "Stopped with %d\n", WSTOPSIG(status)); } } G_buff[t]->append(s); } else { // DATA s[bytes] = 0; G_buff[t]->append(s); } } // Clean up if someone closes the window void close_cb(Fl_Widget*, void*) { printf("Killing child processes..\n"); for ( int t=0; t<3; t++ ) { if ( G_pids[t] == -1 ) continue; kill(G_pids[t], 9); } printf("Done.\n"); exit(0); } int main() { Fl_Double_Window win(620,520,"fltk-tty"); win.callback(close_cb); // kill children if window closed // Start children, one tty for each for ( int t=0; t<3; t++ ) { start_child(t); G_buff[t] = new Fl_Text_Buffer(); G_disp[t] = new Fl_Text_Display(10+t*200, 10, 200, 500); G_disp[t]->buffer(G_buff[t]); G_disp[t]->textfont(FL_COURIER); G_disp[t]->textsize(12); Fl::add_fd(G_outfd[t], data_ready, (void*)t); } win.resizable(win); win.show(); return(Fl::run()); }
| Show how to draw a simple 'X' in FLTK |
Here's how to make your own FLTK widget that just draws a simple 'X' to the four corners of the widget. A good starting point for anyone that wants to make a custom widget that uses custom drawing code.
This example uses FLTK's own drawing code, so it has no dependence on OpenGL libraries. If you want an OpenGL example, click here.
Example: Draw 'X' // DEMONSTRATE HOW TO DRAW AN 'X' IN FLTK #include <FL/Fl.H> #include <FL/fl_draw.H> #include <FL/Fl_Double_Window.H> // SIMPLE BOX WIDGET THAT DRAWS AN 'X' class DrawX : public Fl_Widget { public: DrawX(int X, int Y, int W, int H, const char*L=0) : Fl_Widget(X,Y,W,H,L) { } void draw() { // DRAW BLACK 'X' fl_color(FL_BLACK); fl_line(x(), y(), x()+w()-1, y()+h()-1); fl_line(x(), y()+h()-1, x()+w()-1, y()); } }; int main() { Fl_Double_Window win(200,200); DrawX draw_x(0, 0, win.w(), win.h()); win.resizable(draw_x); win.show(); return(Fl::run()); }
| How to make a Scrollable 'Canvas' |

A scrollable version of the simple FLTK widget that just draws an 'X'. Scrollers let you pan around to look at the "canvas" drawing of the 'X'.
Example: A Scrollable Custom Widget "Canvas" // DEMONSTRATE HOW TO MAKE A SCROLLABLE "CANVAS" DRAWING OF AN 'X' #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Scroll.H> #include <FL/fl_draw.H> // SCROLLABLE CANVAS EXAMPLE -- JUST DRAWS AN 'X' class MyCanvas : public Fl_Widget { public: MyCanvas(int X,int Y,int W,int H,const char*L=0) : Fl_Widget(X,Y,W,H,L) { } void draw() { // DRAW BG fl_color(color()); fl_rectf(x(),y(),w(),h()); // DRAW 'X' OVER BG // Do your graphics here.. // int x1=x(), y1=y(); // Fl_Scroll works by changing our widget's x() and y(), int x2=x()+w()-1, y2=y()+h()-1; // so take these into account for our drawing coordinates fl_color(FL_BLACK); fl_line(x1,y1,x2,y2); fl_line(x1,y2,x2,y1); } }; int main() { Fl_Double_Window win(200,200); Fl_Scroll scroll(0,0,200,200); MyCanvas canvas(0,0,350,350); // purposely make drawing area larger than scroll scroll.end(); win.end(); win.resizable(canvas); win.show(); return(Fl::run()); }
| Show how to draw a custom bar graph |
----------- --------- -------- ------ ----- ---- --- -The following is an example I posted to the newsgroup, in response to a request for a very specific 'trigger shaped' bar graph to appear in the left corner of an eliptical LCD screen.
Example: Custom 'Trigger Shaped' Bar Graph // DEMONSTRATE HOW TO DRAW A TRIGGER SHAPED BAR GRAPH #include <stdlib.h> #include <math.h> #include <FL/Fl.H> #include <FL/fl_draw.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Group.H> // LED DISPLAY CLASS class MyDisplay : public Fl_Group { int _value; // 0 - 100 public: MyDisplay(int X, int Y, int W, int H, const char*L=0) : Fl_Group(X,Y,W,H,L) { _value = 0; } void value(int val) { _value = val; redraw(); } void draw() { Fl_Group::draw(); // TRIGGER GRAPHIC DRAWING CODE fl_color(42); int w = 1; for ( int t=0; t<_value; t+=2) { float f = ( t / 100.0 ); // f = 0.0 ~ 1.0 float f2 = ( abs(t-50) / 100.0 ); // f = .5 ~ 0 ~ .5 int xoff = (int)( f2 * f2 * 100 + .5); w += 1; int x1 = x() + 10 + xoff; int x2 = x() + 10 + w + xoff; int y1 = y() + h() - 10 - t; fl_line(x1, y1, x2, y1); } } }; // // TEST THE CLASS -- Send a sine wave to the class off a timer // MyDisplay *disp = 0; void Timer_CB(void *) { static float f = 6.28/4; f += .1; float v = ( sin(f) + 1.0 ) * .5; // sine wave: 0 ~ 1 v = v * 100; // sine wave: 0 ~ 100 disp->value((int)(v + .5)); Fl::repeat_timeout(0.03, Timer_CB); } int main() { Fl_Double_Window win(240,240); disp = new MyDisplay(20,20,240-40,240-40); disp->box(FL_BORDER_BOX); disp->value(100); Fl::add_timeout(1.0, Timer_CB); win.show(); return(Fl::run()); }
| Cell Table |
A table of Fl_Box, Fl_Input and Fl_Float_Input widgets.
You can change both the size of the window, and interactively
resize the individual cell rows and columns.An example showing how one can create a table of cells using simple FLTK widgets, without needing an Fl_Table.
Example: Table of Cells #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Scroll.H> #include <FL/Fl_Tile.H> #include <FL/Fl_Box.H> #include <FL/Fl_Input.H> #include <FL/Fl_Float_Input.H> #define COLS 9 #define ROWS 20 class RateTable : public Fl_Scroll { void *w[ROWS][COLS]; // widget pointers public: RateTable(int X, int Y, int W, int H, const char*L=0) : Fl_Scroll(X,Y,W,H,L) { static char *header[COLS] = { "Time", "In Rate", "Out Rate", "Coeff A", "Coeff B", "Coeff C", "Std Dev", "Pkg In", "Pkg Out" }; int cellw = 80; int cellh = 25; int xx = X, yy = Y; Fl_Tile *tile = new Fl_Tile(X,Y,cellw*COLS,cellh*ROWS); // Create widgets for ( int r=0; r<ROWS; r++ ) { for ( int c=0; c<COLS; c++ ) { if ( r==0 ) { Fl_Box *box = new Fl_Box(xx,yy,cellw,cellh,header[c]); box->box(FL_BORDER_BOX); w[r][c] = (void*)box; } else if ( c==0 ) { Fl_Input *in = new Fl_Input(xx,yy,cellw,cellh); in->box(FL_BORDER_BOX); in->value(""); w[r][c] = (void*)in; } else { Fl_Float_Input *in = new Fl_Float_Input(xx,yy,cellw,cellh); in->box(FL_BORDER_BOX); in->value("0.00"); w[r][c] = (void*)in; } xx += cellw; } xx = X; yy += cellh; } tile->end(); end(); } }; int main() { Fl_Double_Window win(720,486); RateTable rate(10,10,720-20,486-20); win.resizable(win); win.show(); return(Fl::run()); }
| Draggable Boxes on Scrollable Desk |
A scrollable 'desk' containing boxes the user can drag around.Demonstrates how to make boxes (containing images) that the user can drag around on a scrollable desktop.
Just click and drag the cat boxes around.. note that when you drag a box off the edge of the 'desktop', scrollbars appear, so you can scroll around the desktop to view all the boxes.
All of the work is done by FLTK.. only a few lines of custom code are needed to manage making the boxes 'draggable'
Example: Draggable Boxes on a Scrollable Desk #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Scroll.H> #include <FL/Fl_Box.H> #include <FL/Fl_Pixmap.H> #include <stdio.h> // // Demonstrate user-movable boxes in a scroll region // erco@netcom.com 08/06/02 // erco@3dsite.com 01/06/05 -- added call to Fl_Box::handle() // static char *cat_xpm[] = { // XPM "50 34 4 1", " c black", "o c #ff9900", "@ c #ffffff", "# c None", "##################################################", "### ############################## ####", "### ooooo ########################### ooooo ####", "### oo oo ######################### oo oo ####", "### oo oo ####################### oo oo ####", "### oo oo ##################### oo oo ####", "### oo oo ################### oo oo ####", "### oo oo oo oo ####", "### oo oo ooooooooooooooo oo oo ####", "### oo ooooooooooooooooooooo oo ####", "### oo ooooooooooooooooooooooooooo ooo ####", "#### oo ooooooo ooooooooooooo ooooooo oo #####", "#### oo oooooooo ooooooooooooo oooooooo oo #####", "##### oo oooooooo ooooooooooooo oooooooo oo ######", "##### o ooooooooooooooooooooooooooooooo o ######", "###### ooooooooooooooooooooooooooooooooooo #######", "##### ooooooooo ooooooooo ooooooooo ######", "##### oooooooo @@@ ooooooo @@@ oooooooo ######", "##### oooooooo @@@@@ ooooooo @@@@@ oooooooo ######", "##### oooooooo @@@@@ ooooooo @@@@@ oooooooo ######", "##### oooooooo @@@ ooooooo @@@ oooooooo ######", "##### ooooooooo ooooooooo ooooooooo ######", "###### oooooooooooooo oooooooooooooo #######", "###### oooooooo@@@@@@@ @@@@@@@oooooooo #######", "###### ooooooo@@@@@@@@@ @@@@@@@@@ooooooo #######", "####### ooooo@@@@@@@@@@@ @@@@@@@@@@@ooooo ########", "######### oo@@@@@@@@@@@@ @@@@@@@@@@@@oo ##########", "########## o@@@@@@ @@@@@ @@@@@ @@@@@@o ###########", "########### @@@@@@@ @ @@@@@@@ ############", "############ @@@@@@@@@@@@@@@@@@@@@ #############", "############## @@@@@@@@@@@@@@@@@ ###############", "################ @@@@@@@@@ #################", "#################### #####################", "##################################################", }; Fl_Double_Window *G_win = NULL; Fl_Scroll *G_scroll = NULL; static Fl_Pixmap G_cat(cat_xpm); #define BOXWIDTH 80 #define BOXHEIGHT 50 // A 'MOVABLE' BOX class Box : public Fl_Box { protected: int handle(int e) { static int offset[2] = { 0, 0 }; int ret = Fl_Box::handle(e); switch ( e ) { case FL_PUSH: offset[0] = x() - Fl::event_x(); // save where user clicked for dragging offset[1] = y() - Fl::event_y(); return(1); case FL_RELEASE: return(1); case FL_DRAG: position(offset[0]+Fl::event_x(), offset[1]+Fl::event_y()); // handle dragging G_win->redraw(); return(1); } return(ret); } public: Box(int X, int Y, int W, int H, const char *L=0) : Fl_Box(X,Y,W,H,L) { image(G_cat); box(FL_UP_BOX); color(FL_GRAY); } Box(int X, int Y) : Fl_Box(X,Y,BOXWIDTH,BOXHEIGHT,0) { image(G_cat); box(FL_UP_BOX); color(FL_GRAY); } }; /// MAIN int main() { G_win = new Fl_Double_Window(420,300); G_scroll = new Fl_Scroll(10,10,420-20,300-20); G_scroll->box(FL_FLAT_BOX); G_scroll->color(Fl_Color(46)); G_scroll->begin(); { // CREATE NEW BOXES ON THE SCROLLABLE 'DESK' for ( int x=20; x<=G_scroll->w()-BOXWIDTH; x+= BOXWIDTH+20) for ( int y=20; y<=G_scroll->h()-BOXHEIGHT; y+= BOXHEIGHT+20) new Box(x,y); } G_scroll->end(); G_win->resizable(G_win); G_win->show(); return(Fl::run()); }
| Popup Menu Example |
Demonstrates how to make a popup menu appear, so the user can choose an item, and cause a callback and return the menuitem.
Example: Popup Menu #include <FL/Fl.H> #include <FL/fl_ask.H> #include <FL/Fl_Window.H> #include <FL/Fl_Button.H> #include <FL/Fl_Menu.H> #include <stdio.h> void handle_menu(Fl_Widget *w, void *v) { if(!w || !v) return; switch((int)v) { case 1: fl_choice("Thing 1 happened", "OK", NULL, NULL); break; case 2: fl_choice("Thing 2 happened", "OK", NULL, NULL); break; case 3: fl_choice("Thing 3 happened", "OK", NULL, NULL); break; } } void push_cb(Fl_Widget *w, void*) { Fl_Menu_Item rclick_menu[] = { { "Do Thing 1", 0, handle_menu, (void*)1 }, { "Do Thing 2", 0, handle_menu, (void*)2 }, { "Do Thing 3", 0, handle_menu, (void*)3 }, { 0 } }; const Fl_Menu_Item *m = rclick_menu->popup(Fl::event_x(), Fl::event_y(), 0, 0, 0); if ( m ) m->do_callback(w, m->user_data()); return; } int main() { Fl_Window win(140,45,"Test"); Fl_Button butt(10,10,120,25,"Push For Menu"); butt.callback(push_cb); win.show(); return(Fl::run()); }
| Popup Text Window |
Demonstrates how to popup a borderless text message window when user clicks anywhere in the window.
Example: Popup Text Window #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Box.H> #include <FL/Fl_Menu_Window.H> #include <FL/fl_draw.H> #include <stdio.h> // // Demonstrate how to popup a simple window of information // erco 1.1 01/04/06 // class PopupWindow : public Fl_Menu_Window { Fl_Box *output; // Size window to just fit output's label text void SizeToText() { int W=0, H=0; fl_font(output->labelfont(), output->labelsize()); fl_measure(output->label(), W, H, 0); resize(x(), y(), W+10, H+10); // +10: leaves +5 margin on all sides output->resize(0, 0, W+10, H+10); } public: PopupWindow() : Fl_Menu_Window(10,10) { output = new Fl_Box(0, 0, w(), h()); // box will have the text of user's msg output->box(FL_UP_BOX); // popup window will have an 'Up Box' border end(); hide(); border(0); // popup will be borderless output->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); // text should be left aligned output->label("No text defined"); // (default msg if none defined) SizeToText(); } // Change text in box void text(const char*s) { output->label(s); // set message text SizeToText(); // resize window to size of text } // Pop up window at current mouse position void popup() { position(Fl::event_x_root(), Fl::event_y_root()); // position window at cursor show(); } }; // A window where mouse events pops open text messages class MyWindow : public Fl_Window { PopupWindow *popup; int handle(int e) { int ret = Fl_Window::handle(e); switch (e) { case FL_PUSH: popup->popup(); return(1); case FL_RELEASE: popup->hide(); return(1); } return(ret); } public: MyWindow(int w,int h) : Fl_Window(w,h) { popup = new PopupWindow(); popup->text("This is a test\nSo is this, a much longer line of text."); end(); } }; int main(int argc, char** argv) { MyWindow win(300,300); win.show(); return(Fl::run()); }
| Draw Mouse Coordinates Example |
|
| Screen shows x/y coords of mouse in upper left, while large font shows the full screen's redraw count to show that the entire screen is not being redrawn as the mouse is moved. |
Demonstrates how to draw the coordinates of a mouse into a window without causing the entire screen to redraw, without using overlay planes, separate widgets or windows for the coordinates.
I liked Hartmut's idea of only drawing the coords over the graphic, avoiding overlays and complete redraws, while still updating the coords IN the screen area, and doing it fast.
Here's a cute technique abusing damage(FL_DAMAGE_USER1), to avoid the whole problem of keeping a separate 'flag'. This works in the knowledge that setting the damage flag also causes a redraw, and the flag gets ORed with other bits if other kinds of damage occur.
Note that the main screen graphic counts the redraws, so you can see whenever the entire screen is redrawn. While moving around the mouse, /only/ the coords will change, showing entire redraws are being avoided.
To get the screen to fully redraw, you can resize the screen, or on some window managers, overlaying then revealing again will count it up.
Example: Drawing Mouse Coordinates Without Redrawing Entire Screen #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Group.H> #include <FL/fl_draw.H> #include <stdio.h> // Demonstrate drawing mouse coords: // o w/out redrawing entire screen // o w/out using overlay planes or windows // o w/out using XOR mode class MyDesk : public Fl_Group { protected: int handle(int e) { int ret = Fl_Group::handle(e); switch ( e ) { case FL_ENTER: ret = 1; // FL_ENTER: must return(1) to receive FL_MOVE break; case FL_MOVE: // FL_MOVE: mouse movement causes 'user damage' and redraw.. damage(FL_DAMAGE_USER1); ret = 1; break; } return(ret); } // Draw mouse coords in small black rectangle void draw_coords() { // Coordinates as a string char s[80]; sprintf(s, "x=%d y=%d", (int)Fl::event_x(), (int)Fl::event_y()); // Black rect fl_color(FL_BLACK); fl_rectf(10,10,200,25); // White text fl_color(FL_WHITE); fl_font(FL_HELVETICA, 18); fl_draw(s, 15, 25); } void draw() { // User damage ONLY? just draw coords and done if ( damage() == FL_DAMAGE_USER1 ) { draw_coords(); return; } // Let group draw itself Fl_Group::draw(); { // Show redraw count, so we can tell when full redraws occur. static int redraws = 0; char s[80]; sprintf(s, "redraw #%d", ++redraws); fl_color(FL_BLACK); fl_font(FL_COURIER, 80); fl_draw(s, 50, h()/2); } // Draw coords last draw_coords(); } public: MyDesk(int X, int Y, int W, int H, const char *L=0) : Fl_Group(X,Y,W,H,L) { color(48); } }; /// MAIN int main() { Fl_Window win(720,486); MyDesk desk(10,10,700,466); win.resizable(win); win.show(); return(Fl::run()); }
| Progress Bar Example |
Demonstrates how to update a progress bar within a cpu intensive operation.
Example: Progress Bar Demonstration #include <stdio.h> #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Button.H> #include <FL/Fl_Progress.H> // Demonstrate progress bar in app window (windows|linux) // erco 05/02/05 #ifdef _WIN32 // WINDOWS #include <windows.h> #define usleep(v) Sleep(v/1000) #else // UNIX #include <unistd.h> // usleep #endif // Button callback void butt_cb(Fl_Widget *butt, void *data) { // Deactivate the button butt->deactivate(); // prevent button from being pressed again Fl::check(); // give fltk some cpu to gray out button // Make the progress bar Fl_Window *w = (Fl_Window*)data; // access parent window w->begin(); // add progress bar to it.. Fl_Progress *progress = new Fl_Progress(10,50,200,30); progress->minimum(0); // set progress bar attribs.. progress->maximum(1); w->end(); // end of adding to window // Computation loop.. for ( int t=1; t<=500; t++ ) { progress->value(t/500.0); // update progress bar Fl::check(); // give fltk some cpu to update the screen usleep(1000); // 'your stuff' that's compute intensive } // Cleanup w->remove(progress); // remove progress bar from window delete(progress); // deallocate it butt->activate(); // reactivate button w->redraw(); // tell window to redraw now that progress removed } // Main int main() { Fl_Window win(220,90); Fl_Button butt(10,10,100,25,"Press"); butt.callback(butt_cb, &win); win.resizable(win); win.show(); return(Fl::run()); }
| Scrollable Image Viewer |
Demonstrates how to display an image in a scrollable window.
Example: Scrollable Image Viewer #include <stdlio.h> #include <stdlib.h> #include <FL/Fl.H> #include <FL/Fl_Shared_Image.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Scroll.H> #include <FL/Fl_JPEG_Image.H> #include <FL/Fl_Box.H> #define JPGFILE "/var/tmp/foo.jpg" // Show a jpg image in a scrolled window - erco 05/07/2005 int main() { fl_register_images(); Fl_Double_Window win(720,486); Fl_Scroll scr(0,0,720,486); Fl_JPEG_Image jpg(JPGFILE); if ( jpg.h() == 0 ) { perror(JPGFILE); exit(1); } // error check Fl_Box box(0,0,jpg.w(),jpg.h()); box.image(jpg); win.resizable(win); win.show(); return(Fl::run()); }
| Scrollable Widget Browser |
Demonstrates how to make a scrollable browser of widgets where children of the scroll follow a change in size of the scroller.
Example: Scrollable widget 'browser' #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Group.H> #include <FL/Fl_Scroll.H> #include <FL/Fl_Button.H> #include <FL/Fl_Box.H> // demonstrate a scrollable browser of widgets where children follow size // erco 05/20/05 // // dialog // ------------------------------------------- // | scroll | // | ------------------------------------- | // | | fixed | stretch | ^| | // | |_________|________________________|--| | // | | fixed | stretch | | | // | |_________|________________________| | | // | | fixed | stretch | | | // | |_________|________________________| | | // | | fixed | stretch | | | // | |_________|________________________|__| | // | |__________________________________| v| | // | -- | // | _______ | // | | ADD | | // | ------- | // |___________________________________________| // const int fixedWidth = 50; const int defaultHeight = 25; // Combo widget to appear in the scroll, two boxes: one fixed, the other stretches class ScrollItem : public Fl_Group { Fl_Box *fixedBox; Fl_Box *stretchBox; public: ScrollItem(int X, int Y, int W, int H, const char* L=0) : Fl_Group(X,Y,W,H,L) { begin(); // Fixed width box fixedBox = new Fl_Box(X,Y,fixedWidth,defaultHeight,"Fixed"); fixedBox->box(FL_UP_BOX); // Stretchy box stretchBox = new Fl_Box(X+fixedWidth,Y,W-fixedWidth,defaultHeight, "Stretch"); stretchBox->box(FL_UP_BOX); resizable(stretchBox); end(); } }; // Custom scroll that tells children to follow scroll's width when resized class MyScroll : public Fl_Scroll { int nchild; public: MyScroll(int X, int Y, int W, int H, const char* L=0) : Fl_Scroll(X,Y,W,H,L) { nchild = 0; } void resize(int X, int Y, int W, int H) { // Tell children to resize to our new width for ( int t=0; t<nchild; t++ ) { Fl_Widget *w = child(t); w->resize(w->x(), w->y(), W-20, w->h()); // W-20: leave room for scrollbar } // Tell scroll children changed in size init_sizes(); Fl_Scroll::resize(X,Y,W,H); } // Append new scrollitem to bottom // Note: An Fl_Pack would be a good way to do this, too // void AddItem() { int X = x() + 1, Y = y() - yposition() + (nchild*defaultHeight) + 1, W = w() - 20, // -20: compensate for vscroll bar H = defaultHeight; add(new ScrollItem(X,Y,W,H)); redraw(); nchild++; } }; // Callback to add new item to scroll void add_cb(Fl_Widget*, void *data) { MyScroll *scroll = (MyScroll*)data; scroll->AddItem(); } // Main int main() { Fl_Double_Window *win = new Fl_Double_Window(300,300); MyScroll *scroll = new MyScroll(10,10,win->w()-20,win->h()-60); scroll->box(FL_BORDER_BOX); scroll->end(); Fl_Button *add_butt = new Fl_Button(win->w()-150, win->h()-40, 100, 25, "Add"); add_butt->callback(add_cb, (void*)scroll); // Create a few widgets to start with for ( int t=0; t<4; t++ ) { scroll->AddItem(); } win->resizable(scroll); win->show(); return(Fl::run()); }
| How To Globally Disable @ Symbols |
Demonstrates how to globally disable fltk's '@' symbols throughout your app. Also shows how to define your own global label drawing code.
Example: Disable Symbols // // Example showing how to disable FLTK symbols globally // erco 05/31/2005 // #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Choice.H> #include <FL/Fl_Button.H> #include <FL/fl_draw.H> static int G_usesymbols = 1; // Global FLTK callback for drawing all label text void MyDraw(const Fl_Label *o, int X, int Y, int W, int H, Fl_Align a) { fl_font(o->font, o->size); fl_color((Fl_Color)o->color); fl_draw(o->value, X, Y, W, H, a, o->image, G_usesymbols); } // Global FLTK callback for measuring all labels void MyMeasure(const Fl_Label *o, int &W, int &H) { fl_font(o->font, o->size); fl_measure(o->value, W, H, G_usesymbols); } // Turn symbols on or off void FltkUseSymbols(int onoff) { G_usesymbols = onoff; Fl::set_labeltype(FL_NORMAL_LABEL, MyDraw, MyMeasure); // real action here } // Button callback to toggle symbols on/off void Button_CB(Fl_Widget*,void*data) { FltkUseSymbols(G_usesymbols ? 0 : 1); Fl_Window *win = (Fl_Window*)data; win->redraw(); } int main() { Fl_Double_Window win(0,0,400,200); Fl_Choice choice(100,10,120,25,"Email@3Dsite"); choice.add("abc@->"); choice.add("ABC@<-"); choice.value(0); Fl_Button butt(100,45,120,25,"Toggle Symbols"); butt.callback(Button_CB, (void*)&win); win.resizable(win); win.show(); return(Fl::run()); }
| OpenGL Simple Example |
Demonstrates simplest OpenGL example in Fltk, simply drawing an 'X'.
Example: OpenGL Simple Example #include <FL/Fl.H> #include <FL/Fl_Gl_Window.H> #include <FL/gl.h> // // Simple resizable 2D GL window // erco 10/08/05 // class MyGlWindow : public Fl_Gl_Window { // DRAW METHOD // OpenGL window: (w,h) is upper right, (-w,-h) is lower left, (0,0) is center // void draw() { // First time? init viewport, etc. if (!valid()) { valid(1); glLoadIdentity(); glViewport(0,0,w(),h()); glOrtho(-w(),w(),-h(),h(),-1,1); } // Clear screen glClear(GL_COLOR_BUFFER_BIT); // Draw white 'X' glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINE_STRIP); glVertex2f(w(), h()); glVertex2f(-w(),-h()); glEnd(); glBegin(GL_LINE_STRIP); glVertex2f(w(),-h()); glVertex2f(-w(), h()); glEnd(); } // HANDLE WINDOW RESIZING // If window reshaped, need to readjust viewport/ortho // void resize(int X,int Y,int W,int H) { Fl_Gl_Window::resize(X,Y,W,H); glLoadIdentity(); glViewport(0,0,W,H); glOrtho(-W,W,-H,H,-1,1); redraw(); } public: // CONSTRUCTOR MyGlWindow(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) { } }; // MAIN int main() { Fl_Window win(500, 300); MyGlWindow mygl(10, 10, win.w()-20, win.h()-20); win.end(); win.resizable(mygl); win.show(); return(Fl::run()); }
| OpenGL Example with Widgets |
Demonstrates a simple OpenGL application that includes FLTK widgets to control the brightness of the OpenGL's contents (an 'X').
Example: OpenGL Application With Widgets #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Value_Slider.H> #include <FL/Fl_Gl_Window.H> #include <FL/gl.h> // // OpenGL App With FLTK Widgets // erco 11/08/06 // // OPENGL WINDOW CLASS class MyGlWindow : public Fl_Gl_Window { double fg; // foreground brightness double bg; // background brightness // FIX OPENGL VIEWPORT // Do this on init or when window's size is changed void FixViewport(int W,int H) { glLoadIdentity(); glViewport(0,0,W,H); glOrtho(-W,W,-H,H,-1,1); } // DRAW METHOD void draw() { if (!valid()) { valid(1); FixViewport(w(), h()); } // first time? init // Clear screen to bg color glClearColor(bg, bg, bg, 0.0); glClear(GL_COLOR_BUFFER_BIT); // Draw 'X' in fg color glColor3f(fg, fg, fg); glBegin(GL_LINE_STRIP); glVertex2f(w(), h()); glVertex2f(-w(),-h()); glEnd(); glBegin(GL_LINE_STRIP); glVertex2f(w(),-h()); glVertex2f(-w(), h()); glEnd(); } // HANDLE WINDOW RESIZING void resize(int X,int Y,int W,int H) { Fl_Gl_Window::resize(X,Y,W,H); FixViewport(W,H); redraw(); } public: // OPENGL WINDOW CONSTRUCTOR MyGlWindow(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) { fg = 1.0; bg = 0.0; end(); } void SetBrightness(double new_fg, double new_bg) { fg = new_fg; bg = new_bg; redraw(); } }; // APP WINDOW CLASS class MyAppWindow : public Fl_Window { MyGlWindow *mygl; // opengl window Fl_Value_Slider *fg_brightness; // fg brightness slider Fl_Value_Slider *bg_brightness; // bg brightness slider private: // Someone changed one of the sliders void ValueChanged_CB2() { mygl->SetBrightness(fg_brightness->value(), bg_brightness->value()); } static void ValueChanged_CB(Fl_Widget*, void*userdata) { MyAppWindow *appwin = (MyAppWindow*)userdata; appwin->ValueChanged_CB2(); } public: // APP WINDOW CONSTRUCTOR MyAppWindow(int W,int H,const char*L=0) : Fl_Window(W,H,L) { // OpenGL window mygl = new MyGlWindow(10, 10, w()-20, h()-80); // Foreground slider fg_brightness = new Fl_Value_Slider(120, h()-60, w()/2, 20, "FG Bright"); fg_brightness->align(FL_ALIGN_LEFT); fg_brightness->type(FL_HOR_SLIDER); fg_brightness->bounds(0.0, 1.0); fg_brightness->value(1.0); fg_brightness->callback(ValueChanged_CB, (void*)this); // Background slider bg_brightness = new Fl_Value_Slider(120, h()-30, w()/2, 20, "BG Bright"); bg_brightness->align(FL_ALIGN_LEFT); bg_brightness->type(FL_HOR_SLIDER); bg_brightness->bounds(0.0, 1.0); bg_brightness->value(0.0); bg_brightness->callback(ValueChanged_CB, (void*)this); end(); } }; // MAIN int main() { MyAppWindow win(500, 300, "OpenGL Test App"); win.resizable(win); win.show(); return(Fl::run()); }
| OpenGL Shape Interpolation |
Demonstrates how to animate simple shape interpolation in opengl, using a 24fps timer to run the animation smoothly. (Image above shows only a few frames to give a rough idea of the demo)
Example: Simple OpenGL Shape Interpolation #include <FL/Fl.H> #include <FL/Fl_Gl_Window.H> #include <FL/gl.h> #include <math.h> // // Demonstrate interpolating shapes // erco 06/10/05 // class Playback : public Fl_Gl_Window { int frame; // Linear interpolation between two values based on 'frac' (0.0=a, 1.0=b) float Linterp(float frac, float a, float b) { return( a + ( frac * (b - a) )); } // Sinusoidal easein/easeout interpolation between two values based on 'frac' (0.0=a, 1.0=b) float SinInterp(float frac, float a, float b) { float pi = 3.14159; frac = (sin(pi/2 + frac*pi ) + 1.0 ) / 2.0; // 0 ~ 1 -> 0 ~ 1 return(Linterp(frac,a,b)); } // DRAW SIMPLE SHAPE INTERPOLATION // Interpolation is based on the current frame number // void DrawShape(int frame) { // Calculate a fraction that represents the frame# being shown float frac = ( frame % 48 ) / 48.0 * 2; if ( frac > 1.0 ) frac = 2.0-frac; // saw tooth wave: "/\/\/\" static float a_xy[9][2] = { { -.5, -1. }, { 0.0, -.5 }, { -.5, -1. }, { 0.0, -.5 }, { 0.0, 0.0 }, { 0.0, -.5 }, { +.5, -1. }, { 0.0, -.5 }, { +.5, -1. }, }; static float b_xy[9][2] = { { -.25, -1. }, { -.50, -.75 }, { -.75, -1.0 }, { -.50, -.75 }, { 0.0, 0.0 }, { +.50, -.75 }, { +.75, -1.0 }, { +.50, -.75 }, { +.25, -1.0 } }; // Linterp a and b to form new shape c float c_xy[9][2]; for ( int i=0; i<9; i++ ) for ( int xy=0; xy<2; xy++ ) c_xy[i][xy] = SinInterp(frac, a_xy[i][xy], b_xy[i][xy]); // Draw shape glColor3f(1.0, 1.0, 1.0); glBegin(GL_LINE_STRIP); for ( int i=0; i<9; i++ ) glVertex2f(c_xy[i][0], c_xy[i][1]); glEnd(); } // DRAW THE WIDGET // Each time we're called, assume // void draw() { if (!valid()) { valid(1); glLoadIdentity(); glViewport(0,0,w(),h()); } glClear(GL_COLOR_BUFFER_BIT); // Draw shape 4x, rotated at 90 degree positions glPushMatrix(); DrawShape(frame); glRotatef(90.0, 0, 0, 1); DrawShape(frame); glRotatef(90.0, 0, 0, 1); DrawShape(frame); glRotatef(90.0, 0, 0, 1); DrawShape(frame); glPopMatrix(); // Advance frame counter ++frame; } // 24 FPS TIMER CALLBACK // Called 24x per second to redraw the widget // static void Timer_CB(void *userdata) { Playback *pb = (Playback*)userdata; pb->redraw(); Fl::repeat_timeout(1.0/24.0, Timer_CB, userdata); } public: // Constructor Playback(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) { frame = 0; Fl::add_timeout(1.0/24.0, Timer_CB, (void*)this); // 24fps timer end(); } }; int main() { Fl_Window win(500, 500); Playback playback(10, 10, win.w()-20, win.h()-20); win.resizable(&playback); win.show(); return(Fl::run()); }
| OpenGL Sphere With Light |
Example of an opengl sphere with a light and materials.
Uses glut only for creating the sphere.
OpenGL Sphere With Light #ifdef _WIN32 #include <windows.h> #endif #include <math.h> #include <FL/Fl.h> #include <FL/Fl_Window.h> #include <FL/Fl_Gl_Window.h> #include <FL/gl.h> #include <FL/glut.h> // // Render a simple opengl shaded sphere with a single side light -- erco 11/28/08 // NOTE: Glut needed *only* for glutSolidSphere() // class MyGlWindow : public Fl_Gl_Window { public: // RESHAPE THE VIEWPORT void Reshape(GLfloat W, GLfloat H) { // (REFERENCE: SGI light.c DEMO) GLfloat ratio = W / H; glViewport(0, 0, (GLsizei)W, (GLsizei)H); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.5*ratio, 1.5*ratio, -1.5, 1.5, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void draw() { if (!valid()) { valid(1); Reshape(w(), h()); // (REFERENCE: SGI 'light.c' EXAMPLE) GLfloat mat_ambient[] = { 1.0, 1.0, 1.0, 1.0 }; // RGBA GLfloat mat_diffuse[] = { 1.0, 1.0, 1.0, 1.0 }; // RGBA GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 }; // RGBA GLfloat light_position[] = { 5.0, 5.0, 0.0, 0.0 }; // XYZ glClearColor(0.0, 0.0, 0.4, 0.0); // bg color glShadeModel(GL_SMOOTH); // glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular); glMaterialf(GL_FRONT, GL_SHININESS, 20.0); glLightfv(GL_LIGHT0, GL_POSITION, light_position); // glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); } glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glColor3f(0.5, 0.5, 0.5); glutSolidSphere(0.5, 30, 30); glPopMatrix(); } // CTOR MyGlWindow(int X,int Y,int W,int H,const char*L=0) : Fl_Gl_Window(X,Y,W,H,L) { } }; int main() { Fl_Window win(640, 480, "sphere"); MyGlWindow mygl(10, 10, win.w()-20, win.h()-20); win.resizable(&mygl); win.show(); return(Fl::run()); }
| Fl_File_Chooser Example |
What follows is a simple example of how to use Fl_File_Chooser. Or, you can look at this more thorough example.
Example: Fl_File_Chooser Example Usage #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Menu_Bar.H> #include <FL/Fl_File_Chooser.H> // // Demonstrate how to use Fl_File_Chooser // erco 08/04/2005 // // Callback: when use picks 'File | Open' from main menu void open_cb(Fl_Widget*, void*) { // Create the file chooser, and show it Fl_File_Chooser chooser(".", // directory "*", // filter Fl_File_Chooser::MULTI, // chooser type "Title Of Chooser"); // title chooser.show(); // Block until user picks something. // (The other way to do this is to use a callback()) // while(chooser.shown()) { Fl::wait(); } // User hit cancel? if ( chooser.value() == NULL ) { fprintf(stderr, "(User hit 'Cancel')\n"); return; } // Print what the user picked fprintf(stderr, "--------------------\n"); fprintf(stderr, "DIRECTORY: '%s'\n", chooser.directory()); fprintf(stderr, " VALUE: '%s'\n", chooser.value()); fprintf(stderr, " COUNT: %d files selected\n", chooser.count()); // Multiple files? Show all of them if ( chooser.count() > 1 ) { for ( int t=1; t<=chooser.count(); t++ ) { fprintf(stderr, " VALUE[%d]: '%s'\n", t, chooser.value(t)); } } } // Callback: when user picks 'Quit' void quit_cb(Fl_Widget*, void*) { exit(0); } int main() { Fl_Window win(300, 180, "Simple Example of Fl_File_Chooser"); Fl_Menu_Bar menubar(0,0,300,25); menubar.add("File/Open", 0, open_cb); menubar.add("File/Quit", 0, quit_cb); win.show(); return(Fl::run()); }
| Get coordinates for mouse clicks on scrollable box |
This example shows how to get the coordinates for mouse click events on a scrollable box, the coordinates being relative to the corners of the box.
This can be usful, for instance, in an application that shows large images inside a scroll; allowing the user to click on the image, so as to read back and display pixel data and x/y pixel coordinates on the image, taking into account the scroll positions of the image.
Shows how to use the mouse events (which are relative to the corner of the fltk window) and the offset of the scrollbars to calculate where in the box (or image) the user clicked.
Example: Getting Mouse Clicks on a Scrollable Box #include <stdio.h> #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Scroll.H> #include <FL/Fl_Box.H> // // Demonstrate getting mouse click coords on a scrollable box // erco 08/14/2005 // class ScrollBox : public Fl_Box { Fl_Scroll *scroll; public: int handle(int e) { if ( e == FL_PUSH ) { fprintf(stderr, "event_x,event_y: %d,%d, Hit on box: %d,%d\n", Fl::event_x(), Fl::event_y(), Fl::event_x() - scroll->x() + scroll->hscrollbar.value(), Fl::event_y() - scroll->y() + scroll->scrollbar.value()); } return(Fl_Box::handle(e)); } void SetScroll(Fl_Scroll *val) { scroll = val; } ScrollBox(int x,int y,int w,int h,const char*l=0) : Fl_Box(x,y,w,h,l) { color(FL_BLUE); box(FL_FLAT_BOX); } }; int main() { Fl_Double_Window win(400, 400); Fl_Scroll scroll(0,0,400,400); ScrollBox box(0,0,1000,1000); // box is bigger than scroll box.SetScroll(&scroll); scroll.end(); win.resizable(win); win.show(); return(Fl::run()); }
| Using Fl_Browser with columns |
This example shows how to use the Fl_Browser column_widths() and column_char() methods for presenting data in columns (even in non-fixed-width fonts).
Example: Using Fl_Browser with columns #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Browser.H> // // Demonstrate Fl_Browser with columns // erco 09/16/05 // int main() { Fl_Window *w = new Fl_Window(900,300); Fl_Browser *b = new Fl_Browser(10,10,w->w()-20,w->h()-20); int widths[] = { 50, 50, 50, 70, 70, 40, 40, 70, 70, 50, 0 }; // widths for each column b->column_widths(widths); b->column_char('\t'); // tabs as column delimiters b->type(FL_MULTI_BROWSER); b->add("USER\tPID\t%CPU\t%MEM\tVSZ\tRSS\tTTY\tSTAT\tSTART\tTIME\tCOMMAND"); // lines of tab delimited data b->add("root\t2888\t0.0\t0.0\t1352\t0\ttty3\tSW\tAug15\t0:00\t@b@f/sbin/mingetty tty3"); b->add("erco\t2889\t0.0\t13.0\t221352\t0\ttty3\tR\tAug15\t1:34\t@b@f/usr/local/bin/render a35 0004"); b->add("uucp\t2892\t0.0\t0.0\t1352\t0\tttyS0\tSW\tAug15\t0:00\t@b@f/sbin/agetty -h 19200 ttyS0 vt100"); b->add("root\t13115\t0.0\t0.0\t1352\t0\ttty2\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty2"); b->add("root\t13464\t0.0\t0.0\t1352\t0\ttty1\tSW\tAug30\t0:00\t@b@f/sbin/mingetty tty1 --noclear"); w->resizable(b); w->end(); w->show(); return(Fl::run()); }
| Fl_Browser Sorting |
This example shows how to sort the lines in an Fl_Browser.
Example: Sorting an Fl_Browser #include <string.h> #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Button.H> #include <FL/Fl_Browser.H> // // Demo sorting an Fl_Browser with bubble sort // erco 09/02/2005 // void ForwardSort(Fl_Browser *b) { for ( int t=1; t<=b->size(); t++ ) { for ( int r=t+1; r<=b->size(); r++ ) { if ( strcmp(b->text(t), b->text(r)) > 0 ) { b->swap(t,r); } } } } void ReverseSort(Fl_Browser *b) { for ( int t=1; t<=b->size(); t++ ) { for ( int r=t+1; r<=b->size(); r++ ) { if ( strcmp(b->text(t), b->text(r)) < 0 ) { b->swap(t,r); } } } } void togglesort_cb(Fl_Widget *w, void*data) { Fl_Browser *b = (Fl_Browser*)data; if ( strcmp(w->label(), "Do Fwd Sort") == 0 ) { ForwardSort(b); w->label("Do Rev Sort"); // toggle } else { ReverseSort(b); w->label("Do Fwd Sort"); // toggle } } int main() { Fl_Window *win = new Fl_Window(300,500,"Sort Example"); Fl_Browser *b = new Fl_Browser(10,40,win->w()-20, win->h()-50); b->type(FL_MULTI_BROWSER); b->add("Papa"); b->add("Delta"); b->add("Hotel"); b->add("Charlie"); b->add("Echo"); b->add("Foxtrot"); b->add("Golf"); b->add("Lima"); b->add("Victor"); b->add("Alpha"); b->add("Xray"); b->add("Yankee"); b->add("Oscar"); b->add("India"); b->add("Juliet"); b->add("Kilo"); b->add("Mike"); b->add("Sierra"); b->add("November"); b->add("Tango"); b->add("Quebec"); b->add("Bravo"); b->add("Romeo"); b->add("Uniform"); b->add("Whisky"); b->add("Zulu"); Fl_Button *butt = new Fl_Button(10,10,100,28,"Do Fwd Sort"); butt->callback(togglesort_cb, (void*)b); win->show(); return(Fl::run()); }
| Strike Through Text |
Demonstrates how to draw 'strikethrough' text.
A slider is included to show how font size changes look with the strikethrough line.You can uncomment the 'DRAW UNDERLINE' code to do underlining as well.
Example: Drawing Strikethrough Text #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Box.H> #include <FL/Fl_Value_Slider.H> #include <FL/fl_draw.H> // // Demonstrate strikethrough text // erco 10/09/05 // class MyBox : public Fl_Box { void draw() { if ( label() ) { Fl_Box::draw_box(); // DRAW LABEL IN CENTER OF WIDGET int label_x, label_y, label_w, label_h; fl_font(labelfont(), labelsize()); fl_measure(label(), label_w, label_h, 1); fl_color(labelcolor()); label_x = x() + (w() / 2) - label_w / 2; // always center text label_y = y() + (h() / 2) - label_h / 2; fl_draw(label(), label_x, label_y+labelsize()); // DRAW STRIKETHROUGH fl_line_style(FL_SOLID); fl_line(label_x, label_y+(labelsize()/3*2), label_x+label_w, label_y+(labelsize()/3*2)); //// // DRAW UNDERLINE //// fl_line_style(FL_SOLID); //// fl_line(label_x, label_y+labelsize(), label_x+label_w, label_y+labelsize()+1); } } public: // CONSTRUCTOR MyBox(int X,int Y,int W,int H,const char*L=0) : Fl_Box(X,Y,W,H,L) { } }; // HANDLE SLIDER CHANGING FONT SIZE void ChangeFontsize_CB(Fl_Widget *w,void *data) { Fl_Value_Slider *slider = (Fl_Value_Slider*)w; Fl_Box *box = (Fl_Box*)data; int newsize = (int)slider->value(); box->labelsize(newsize); box->redraw(); } int main() { Fl_Window win(200, 100); MyBox box(10, 40, win.w()-20, win.h()-50, "Testing"); box.labelsize(24); box.box(FL_FLAT_BOX); box.color(50); Fl_Value_Slider fontsize(10,10,200-20,20); fontsize.callback(ChangeFontsize_CB, (void*)&box); fontsize.type(FL_HOR_SLIDER); fontsize.range(8,40); fontsize.value(box.labelsize()); win.show(); return(Fl::run()); }
| Changing the mouse cursor for an Fl_GL_Window |
Demonstrates how to change the cursor for an Fl_Gl_Window.
Fl_Gl_Window is a special case on Win32 with Fltk versions 1.1.6 and older, because there was a bug where just setting the cursor wasn't enough, you had to set the cursor for the parent Fl_Window.
The following code should work for all platforms and all versions of 1.1.x.
Changing the mouse cursor for an Fl_GL_Window #include <FL/Fl.H> #include <FL/Fl_Window.H> #include <FL/Fl_Gl_Window.H> #include <FL/gl.h> // // Test 'cross' cursor when mouse in GL window // erco 11/03/05 // class MyGlWindow : public Fl_Gl_Window { int handle(int e) { int ret = Fl_Gl_Window::handle(e); switch ( e ) { case FL_ENTER: window()->cursor(FL_CURSOR_CROSS); // 'window()->cursor()' needed on WIN32 for 1.1.6 and older. return(1); // 1.1.7 and up can probably just use fl_cursor(..) case FL_LEAVE: window()->cursor(FL_CURSOR_DEFAULT); return(1); } return(ret); } void draw() { if (!valid()) { valid(1); glViewport(0,0,w(),h()); } glClear(GL_COLOR_BUFFER_BIT); } public: MyGlWindow(int x,int y,int w,int h,const char*l=0) : Fl_Gl_Window(x,y,w,h,l) { } }; int main() { Fl_Window win(500, 500); MyGlWindow glwin(10,10,500-20,500-20); win.show(); return(Fl::run()); }
| Extend Fl_Browser to have interactively resizable columns |
An interactively resizable Fl_BrowserDemonstrates how to extend the functionality of the standard Fl_Browser to support interactively resizable columns.
The following code tested on Fltk 1.1.6
An Interactively Resizable Fl_Browser #include <FL/Fl.H> #include <FL/Fl_Double_Window.H> #include <FL/Fl_Browser.H> #include <FL/fl_draw.H> // // Demonstrate how to derive a class extending Fl_Browser with interactively resizable columns // erco 1.10 12/09/2005 // class ColResizeBrowser : public Fl_Browser { Fl_Color _colsepcolor; // color of column separator lines int _showcolsep; // flag to enable drawing column separators Fl_Cursor _last_cursor; // saved cursor state info int _dragging; // 1=user dragging a column int _dragcol; // col# user is currently dragging int *_widths; // pointer to user's width[] array int _nowidths[1]; // default width array (non-const) // CHANGE CURSOR // Does nothing if cursor already set to value specified. // void change_cursor(Fl_Cursor newcursor) { if ( newcursor != _last_cursor ) { fl_cursor(newcursor, FL_BLACK, FL_WHITE); _last_cursor = newcursor; } } // RETURN THE COLUMN MOUSE IS 'NEAR' // Returns -1 if none. // int which_col_near_mouse() { int X,Y,W,H; Fl_Browser::bbox(X,Y,W,H); // area inside browser's box() // EVENT NOT INSIDE BROWSER AREA? (eg. on a scrollbar) if ( ! Fl::event_inside(X,Y,W,H) ) { return(-1); } int mousex = Fl::event_x() + hposition(); int colx = this->x(); for ( int t=0; _widths[t]; t++ ) { colx += _widths[t]; int diff = mousex - colx; // MOUSE 'NEAR' A COLUMN? // Return column # // if ( diff >= -4 && diff <= 4 ) { return(t); } } return(-1); } protected: // MANAGE EVENTS TO HANDLE COLUMN RESIZING int handle(int e) { // Not showing column separators? Use default Fl_Browser::handle() logic if ( ! showcolsep() ) return(Fl_Browser::handle(e)); // Handle column resizing int ret = 0; switch ( e ) { case FL_ENTER: { ret = 1; break; } case FL_MOVE: { if ( which_col_near_mouse() >= 0 ) { change_cursor(FL_CURSOR_WE); } else { change_cursor(FL_CURSOR_DEFAULT); } ret = 1; break; } case FL_PUSH: { int whichcol = which_col_near_mouse(); if ( whichcol >= 0 ) { // CLICKED ON RESIZER? START DRAGGING ret = 1; _dragging = 1; _dragcol = whichcol; change_cursor(FL_CURSOR_DEFAULT); } break; } case FL_DRAG: { if ( _dragging ) { ret = 1; // Sum up column widths to determine position int mousex = Fl::event_x() + hposition(); int newwidth = mousex - x(); for ( int t=0; _widths[t] && t<_dragcol; t++ ) { newwidth -= _widths[t]; } if ( newwidth > 0 ) { // Apply new width, redraw interface _widths[_dragcol] = newwidth;