Old Fltk Stuff


Fltk has grown a bit since I started these pages, so anything that became obsolete by such changed have been relegated to this page.



Fl_Browser: Adding a swap(a,b) method


    ***   NOTE: Fl_Browser now has a swap() method as of Fltk 1.1.5,   ***
    ***         making the following modifications unnecessary.        ***
    ***         These mods would only be needed for older versions.    ***
    

I find myself needing to be able to sort browsers while they already contain data. The supported ::move() method works, but is very slow, because it does both an insert() and remove(). By adding a swap() method, sorting is greatly improved.

These code modifications work with fltk 1.0.9:

Efficient Browser Sorting With qsort() Using swap()

    ** ADD THE FOLLOWING METHOD TO FL/Fl_Browser.H **
    ** I added it below the move() declaration.    **

FL_EXPORT void swap(FL_BLINE *a, FL_BLINE *b);
FL_EXPORT void swap(int a, int b);

    ** ADD THE FOLLOWING METHOD TO src/Fl_Browser.cxx    **
    ** I added it directly below the move() definition.  **
    ** This can probably be cleaner. -erco 05/07/01      **

// SWAP TWO LINES
void Fl_Browser::swap(FL_BLINE *a, FL_BLINE *b) {

  if ( a == b) return;          // nothing to do

  FL_BLINE *aprev  = a->prev;
  FL_BLINE *anext  = a->next;
  FL_BLINE *bprev  = b->prev;
  FL_BLINE *bnext  = b->next;

  if ( b->prev == a ) { 		// A ADJACENT TO B
     if ( aprev ) aprev->next = b; else first = b;
     b->next = a;
     a->next = bnext;
     b->prev = aprev;
     a->prev = b;
     if ( bnext ) bnext->prev = a; else last = a;
  } else if ( a->prev == b ) {		// B ADJACENT TO A
     if ( bprev ) bprev->next = a; else first = a;
     a->next = b;
     b->next = anext;
     a->prev = bprev;
     b->prev = a;
     if ( anext ) anext->prev = b; else last = b;
  } else {				// A AND B NOT ADJACENT
     // handle prev's
     b->prev = aprev;
     if ( anext ) anext->prev = b; else last = b;
     a->prev = bprev;
     if ( bnext ) bnext->prev = a; else last = a;
     // handle next's
     if ( aprev ) aprev->next = b; else first = b;
     b->next = anext;
     if ( bprev ) bprev->next = a; else first = a;
     a->next = bnext;
  }

  // Disable cache -- we played around with positions
  cacheline = 0;

  // REDRAW THE TWO MODIFIED LINES
  redraw_line(a);
  redraw_line(b);
}

void Fl_Browser::swap(int ai, int bi) {
  if (ai < 1 || ai > lines || bi < 1 || bi > lines) return;

  FL_BLINE* a = find_line(ai);
  FL_BLINE* b = find_line(bi);
  swap(a,b);
}

Implementing item_pathname() For Old releases of Fltk


    ***   NOTE: Fl_Menu has an item_pathname() method as of Fltk 1.1.6, ***
    ***         making the following unnecessary.                       ***
    ***         These mods would only be needed for older versions.     ***
    

(Old Version) Accessing Menu Items Without Using Callback Data

// menubar-example.cxx
//    An example program showing how to use an Fl_Menu_Bar w/out callbacks or userdata.
//
//    Absolute menubar 'pathnames' are generated on the fly to determine which
//    menu item was picked.
//
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Menu_Bar.H>

// Return the full 'menu item pathname' for a given menuitem* (eg. "File/Quit").
//    NOTE: This method is now built into FLTK 1.1.6 and up as Fl_Menu_Bar::item_pathname()
//
const char *ItemPathname(const Fl_Menu_Bar *menubar, const Fl_Menu_Item *item)
{
    static char menupath[1024];
    menupath[0] = '\0';
    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());
	}
	else
	{
	    if ( m->label() == NULL )
	    {
		// END OF SUBMENU?
	        char *ss = strrchr(menupath, '/');
		if ( ss ) *ss = 0;		// "File/Edit" -> "File"
		else menupath[0] = '\0';	// "File" -> ""
		continue;
	    }
	    else
	    {
		// MENU ITEM?
		if ( m == item )
		{
		    strcat(menupath, "/");
		    strcat(menupath, m->label());
		    return(menupath);
		}
	    }
	}
    }
    return(NULL);
}

// Callback for all menu items
static void Menu_CB(Fl_Widget*w, void*)
{   
    const Fl_Menu_Bar *menubar = (Fl_Menu_Bar*)w;
    const Fl_Menu_Item *item = menubar->mvalue();

    const char *shortname = menubar->text();                 // eg. "Quit"
    const char *fullname  = ItemPathname(menubar, item);  // eg. "File/Quit"

    fprintf(stderr, "\nMenu_CB: shortname='%s'\tfullname='%s'\n", 
		    shortname, (fullname?fullname:"(?)"));

         if ( strcmp(fullname, "File/Open" ) == 0 ) { printf("File's 'Open' was selected.\n"); }
    else if ( strcmp(fullname, "File/Save" ) == 0 ) { printf("File's 'Save' was selected.\n"); }
    else if ( strcmp(fullname, "File/Help" ) == 0 ) { printf("File's 'Help' was selected.\n"); }
    else if ( strcmp(fullname, "File/Quit" ) == 0 ) { printf("File's 'Quit' was selected.\n"); }
    else if ( strcmp(fullname, "Edit/Copy" ) == 0 ) { printf("Edit's 'Copy' was selected.\n"); }
    else if ( strcmp(fullname, "Edit/Help" ) == 0 ) { printf("Edit's 'Help' was selected.\n"); }
}

int main()
{
    Fl_Window win(720,486);
    Fl_Menu_Bar menubar(0,0,720,28);
    menubar.add("File/Open", 0, Menu_CB);
    menubar.add("File/Save", 0, Menu_CB);
    menubar.add("File/Help", 0, Menu_CB);
    menubar.add("File/Quit", 0, Menu_CB);
    menubar.add("Edit/Copy", 0, Menu_CB);
    menubar.add("Edit/Help", 0, Menu_CB);
    win.end();
    win.show();
    return(Fl::run());
}