Include a stripped-down version of FLTK in tree and add a USE_INCLUDED_FLTK option to build against it.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4603 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/fltk/src/Fl_Browser.cxx b/common/fltk/src/Fl_Browser.cxx
new file mode 100644
index 0000000..d62b4f4
--- /dev/null
+++ b/common/fltk/src/Fl_Browser.cxx
@@ -0,0 +1,949 @@
+//
+// "$Id: Fl_Browser.cxx 8736 2011-05-24 20:00:56Z AlbrechtS $"
+//
+// Browser widget for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 by Bill Spitzak and others.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+//     http://www.fltk.org/str.php
+//
+
+#include <FL/Fl.H>
+#include <FL/Fl_Browser.H>
+#include <FL/fl_draw.H>
+#include "flstring.h"
+#include <stdlib.h>
+#include <math.h>
+
+#if defined(FL_DLL)	// really needed for c'tors for MS VC++ only
+#include <FL/Fl_Hold_Browser.H>
+#include <FL/Fl_Multi_Browser.H>
+#include <FL/Fl_Select_Browser.H>
+#endif
+
+// I modified this from the original Forms data to use a linked list
+// so that the number of items in the browser and size of those items
+// is unlimited. The only problem is that the old browser used an
+// index number to identify a line, and it is slow to convert from/to
+// a pointer. I use a cache of the last match to try to speed this up.
+
+// Also added the ability to "hide" a line. This sets its height to
+// zero, so the Fl_Browser_ cannot pick it.
+
+#define SELECTED 1
+#define NOTDISPLAYED 2
+
+// WARNING:
+//       Fl_File_Chooser.cxx also has a definition of this structure (FL_BLINE).
+//       Changes to FL_BLINE *must* be reflected in Fl_File_Chooser.cxx as well.
+//       This hack in Fl_File_Chooser should be solved.
+//
+struct FL_BLINE {	// data is in a linked list of these
+  FL_BLINE* prev;
+  FL_BLINE* next;
+  void* data;
+  Fl_Image* icon;
+  short length;		// sizeof(txt)-1, may be longer than string
+  char flags;		// selected, displayed
+  char txt[1];		// start of allocated array
+};
+
+/**
+  Returns the very first item in the list.
+  Example of use:
+  \code
+  // Walk the browser from beginning to end
+  for ( void *i=item_first(); i; i=item_next(i) ) {
+      printf("item label='%s'\n", item_text(i));
+  }
+  \endcode
+  \returns The first item, or NULL if list is empty.
+  \see item_first(), item_last(), item_next(), item_prev()
+*/
+void* Fl_Browser::item_first() const {return first;}
+
+/**
+  Returns the next item after \p item.
+  \param[in] item The 'current' item
+  \returns The next item after \p item, or NULL if there are none after this one.
+  \see item_first(), item_last(), item_next(), item_prev()
+*/
+void* Fl_Browser::item_next(void* item) const {return ((FL_BLINE*)item)->next;}
+
+/**
+  Returns the previous item before \p item.
+  \param[in] item The 'current' item
+  \returns The previous item before \p item, or NULL if there none before this one.
+  \see item_first(), item_last(), item_next(), item_prev()
+*/
+void* Fl_Browser::item_prev(void* item) const {return ((FL_BLINE*)item)->prev;}
+
+/**
+  Returns the very last item in the list.
+  Example of use:
+  \code
+  // Walk the browser in reverse, from end to start
+  for ( void *i=item_last(); i; i=item_prev(i) ) {
+      printf("item label='%s'\n", item_text(i));
+  }
+  \endcode
+  \returns The last item, or NULL if list is empty.
+  \see item_first(), item_last(), item_next(), item_prev()
+*/
+void* Fl_Browser::item_last() const {return last;}
+
+/**
+  See if \p item is selected.
+  \param[in] item The item whose selection state is to be checked.
+  \returns 1 if selected, 0 if not.
+  \see select(), selected(), value(), item_select(), item_selected()
+*/
+int Fl_Browser::item_selected(void* item) const {
+  return ((FL_BLINE*)item)->flags&SELECTED;
+}
+/**
+  Change the selection state of \p item to the value \p val.
+  \param[in] item The item to be changed.
+  \param[in] val The new selection state: 1 selects, 0 de-selects.
+  \see select(), selected(), value(), item_select(), item_selected()
+*/
+void Fl_Browser::item_select(void *item, int val) {
+  if (val) ((FL_BLINE*)item)->flags |= SELECTED;
+  else     ((FL_BLINE*)item)->flags &= ~SELECTED;
+}
+
+/**
+  Returns the label text for \p item.
+  \param[in] item The item whose label text is returned.
+  \returns The item's text string. (Can be NULL)
+*/
+const char *Fl_Browser::item_text(void *item) const { 
+  return ((FL_BLINE*)item)->txt;
+}
+
+/**
+  Returns the item for specified \p line.
+
+  Note: This call is slow. It's fine for e.g. responding to user
+  clicks, but slow if called often, such as in a tight sorting loop.
+  Finding an item 'by line' involves a linear lookup on the internal
+  linked list. The performance hit can be significant if the browser's
+  contents is large, and the method is called often (e.g. during a sort).
+  If you're writing a subclass, use the protected methods item_first(),
+  item_next(), etc. to access the internal linked list more efficiently.
+
+  \param[in] line The line number of the item to return. (1 based)
+  \retval item that was found.
+  \retval NULL if line is out of range.
+  \see item_at(), find_line(), lineno()
+*/
+FL_BLINE* Fl_Browser::find_line(int line) const {
+  int n; FL_BLINE* l;
+  if (line == cacheline) return cache;
+  if (cacheline && line > (cacheline/2) && line < ((cacheline+lines)/2)) {
+    n = cacheline; l = cache;
+  } else if (line <= (lines/2)) {
+    n = 1; l = first;
+  } else {
+    n = lines; l = last;
+  }
+  for (; n < line && l; n++) l = l->next;
+  for (; n > line && l; n--) l = l->prev;
+  ((Fl_Browser*)this)->cacheline = line;
+  ((Fl_Browser*)this)->cache = l;
+  return l;
+}
+
+/**
+  Returns line number corresponding to \p item, or zero if not found.
+  Caveat: See efficiency note in find_line().
+  \param[in] item The item to be found
+  \returns The line number of the item, or 0 if not found.
+  \see item_at(), find_line(), lineno()
+*/
+int Fl_Browser::lineno(void *item) const {
+  FL_BLINE* l = (FL_BLINE*)item;
+  if (!l) return 0;
+  if (l == cache) return cacheline;
+  if (l == first) return 1;
+  if (l == last) return lines;
+  if (!cache) {
+    ((Fl_Browser*)this)->cache = first;
+    ((Fl_Browser*)this)->cacheline = 1;
+  }
+  // assume it is near cache, search both directions:
+  FL_BLINE* b = cache->prev;
+  int bnum = cacheline-1;
+  FL_BLINE* f = cache->next;
+  int fnum = cacheline+1;
+  int n = 0;
+  for (;;) {
+    if (b == l) {n = bnum; break;}
+    if (f == l) {n = fnum; break;}
+    if (b) {b = b->prev; bnum--;}
+    if (f) {f = f->next; fnum++;}
+  }
+  ((Fl_Browser*)this)->cache = l;
+  ((Fl_Browser*)this)->cacheline = n;
+  return n;
+}
+
+/**
+  Removes the item at the specified \p line.
+  Caveat: See efficiency note in find_line().
+  You must call redraw() to make any changes visible.
+  \param[in] line The line number to be removed. (1 based) Must be in range!
+  \returns Pointer to browser item that was removed (and is no longer valid).
+  \see add(), insert(), remove(), swap(int,int), clear()
+*/
+FL_BLINE* Fl_Browser::_remove(int line) {
+  FL_BLINE* ttt = find_line(line);
+  deleting(ttt);
+
+  cacheline = line-1;
+  cache = ttt->prev;
+  lines--;
+  full_height_ -= item_height(ttt);
+  if (ttt->prev) ttt->prev->next = ttt->next;
+  else first = ttt->next;
+  if (ttt->next) ttt->next->prev = ttt->prev;
+  else last = ttt->prev;
+
+  return(ttt);
+}
+
+/**
+  Remove entry for given \p line number, making the browser one line shorter.
+  You must call redraw() to make any changes visible.
+  \param[in] line Line to be removed. (1 based) \n
+                  If \p line is out of range, no action is taken.
+  \see add(), insert(), remove(), swap(int,int), clear()
+*/
+void Fl_Browser::remove(int line) {
+  if (line < 1 || line > lines) return;
+  free(_remove(line));
+}
+
+/**
+  Insert specified \p item above \p line.
+  If \p line > size() then the line is added to the end.
+
+  Caveat: See efficiency note in find_line().
+
+  \param[in] line  The new line will be inserted above this line (1 based).
+  \param[in] item  The item to be added.
+*/
+void Fl_Browser::insert(int line, FL_BLINE* item) {
+  if (!first) {
+    item->prev = item->next = 0;
+    first = last = item;
+  } else if (line <= 1) {
+    inserting(first, item);
+    item->prev = 0;
+    item->next = first;
+    item->next->prev = item;
+    first = item;
+  } else if (line > lines) {
+    item->prev = last;
+    item->prev->next = item;
+    item->next = 0;
+    last = item;
+  } else {
+    FL_BLINE* n = find_line(line);
+    inserting(n, item);
+    item->next = n;
+    item->prev = n->prev;
+    item->prev->next = item;
+    n->prev = item;
+  }
+  cacheline = line;
+  cache = item;
+  lines++;
+  full_height_ += item_height(item);
+  redraw_line(item);
+}
+
+/**
+  Insert a new entry whose label is \p newtext \e above given \p line, optional data \p d.
+
+  Text may contain format characters; see format_char() for details.
+  \p newtext is copied using the strdup() function, and can be NULL to make a blank line.
+
+  The optional void * argument \p d will be the data() of the new item.
+
+  \param[in] line Line position for insert. (1 based) \n
+             If \p line > size(), the entry will be added at the end.
+  \param[in] newtext The label text for the new line.
+  \param[in] d Optional pointer to user data to be associated with the new line.
+*/
+void Fl_Browser::insert(int line, const char* newtext, void* d) {
+  int l = strlen(newtext);
+  FL_BLINE* t = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l);
+  t->length = (short)l;
+  t->flags = 0;
+  strcpy(t->txt, newtext);
+  t->data = d;
+  t->icon = 0;
+  insert(line, t);
+}
+
+/**
+  Line \p from is removed and reinserted at \p to.
+  Note: \p to is calculated \e after line \p from gets removed.
+  \param[in] to Destination line number (calculated \e after line \p from is removed)
+  \param[in] from Line number of item to be moved
+*/
+void Fl_Browser::move(int to, int from) {
+  if (from < 1 || from > lines) return;
+  insert(to, _remove(from));
+}
+
+/**
+  Sets the text for the specified \p line to \p newtext.
+
+  Text may contain format characters; see format_char() for details.
+  \p newtext is copied using the strdup() function, and can be NULL to make a blank line.
+
+  Does nothing if \p line is out of range.
+
+  \param[in] line The line of the item whose text will be changed. (1 based)
+  \param[in] newtext The new string to be assigned to the item.
+*/
+void Fl_Browser::text(int line, const char* newtext) {
+  if (line < 1 || line > lines) return;
+  FL_BLINE* t = find_line(line);
+  int l = strlen(newtext);
+  if (l > t->length) {
+    FL_BLINE* n = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l);
+    replacing(t, n);
+    cache = n;
+    n->data = t->data;
+    n->icon = t->icon;
+    n->length = (short)l;
+    n->flags = t->flags;
+    n->prev = t->prev;
+    if (n->prev) n->prev->next = n; else first = n;
+    n->next = t->next;
+    if (n->next) n->next->prev = n; else last = n;
+    free(t);
+    t = n;
+  }
+  strcpy(t->txt, newtext);
+  redraw_line(t);
+}
+
+/**
+  Sets the user data for specified \p line to \p d.
+  Does nothing if \p line is out of range.
+  \param[in] line The line of the item whose data() is to be changed. (1 based)
+  \param[in] d The new data to be assigned to the item. (can be NULL)
+*/
+void Fl_Browser::data(int line, void* d) {
+  if (line < 1 || line > lines) return;
+  find_line(line)->data = d;
+}
+
+/**
+  Returns height of \p item in pixels.
+  This takes into account embedded \@ codes within the text() label.
+  \param[in] item The item whose height is returned.
+  \returns The height of the item in pixels.
+  \see item_height(), item_width(),\n
+       incr_height(), full_height()
+*/
+int Fl_Browser::item_height(void *item) const {
+  FL_BLINE* l = (FL_BLINE*)item;
+  if (l->flags & NOTDISPLAYED) return 0;
+
+  int hmax = 2; // use 2 to insure we don't return a zero!
+
+  if (!l->txt[0]) {
+    // For blank lines set the height to exactly 1 line!
+    fl_font(textfont(), textsize());
+    int hh = fl_height();
+    if (hh > hmax) hmax = hh;
+  } else {
+    const int* i = column_widths();
+    long int dummy;
+    // do each column separately as they may all set different fonts:
+    for (char* str = l->txt; str && *str; str++) {
+      Fl_Font font = textfont(); // default font
+      int tsize = textsize(); // default size
+      while (*str==format_char()) {
+	str++;
+	switch (*str++) {
+	case 'l': case 'L': tsize = 24; break;
+	case 'm': case 'M': tsize = 18; break;
+	case 's': tsize = 11; break;
+	case 'b': font = (Fl_Font)(font|FL_BOLD); break;
+	case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
+	case 'f': case 't': font = FL_COURIER; break;
+	case 'B':
+	case 'C': dummy = strtol(str, &str, 10); break;// skip a color number
+	case 'F': font = (Fl_Font)strtol(str,&str,10); break;
+	case 'S': tsize = strtol(str,&str,10); break;
+	case 0: case '@': str--;
+	case '.': goto END_FORMAT;
+	}
+      }
+      END_FORMAT:
+      char* ptr = str;
+      if (ptr && *i++) str = strchr(str, column_char());
+      else str = NULL;
+      if((!str && *ptr) || (str && ptr < str)) {
+	fl_font(font, tsize); int hh = fl_height();
+	if (hh > hmax) hmax = hh;
+      }
+      if (!str || !*str) break;
+    }
+  }
+
+  if (l->icon && (l->icon->h()+2)>hmax) {
+    hmax = l->icon->h() + 2;	// leave 2px above/below
+  }
+  return hmax; // previous version returned hmax+2!
+}
+
+/**
+  Returns width of \p item in pixels.
+  This takes into account embedded \@ codes within the text() label.
+  \param[in] item The item whose width is returned.
+  \returns The width of the item in pixels.
+  \see item_height(), item_width(),\n
+       incr_height(), full_height()
+*/
+int Fl_Browser::item_width(void *item) const {
+  FL_BLINE* l=(FL_BLINE*)item;
+  char* str = l->txt;
+  const int* i = column_widths();
+  int ww = 0;
+
+  while (*i) { // add up all tab-separated fields
+    char* e;
+    e = strchr(str, column_char());
+    if (!e) break; // last one occupied by text
+    str = e+1;
+    ww += *i++;
+  }
+
+  // OK, we gotta parse the string and find the string width...
+  int tsize = textsize();
+  Fl_Font font = textfont();
+  int done = 0;
+
+  while (*str == format_char_ && str[1] && str[1] != format_char_) {
+    long int dummy;
+    str ++;
+    switch (*str++) {
+    case 'l': case 'L': tsize = 24; break;
+    case 'm': case 'M': tsize = 18; break;
+    case 's': tsize = 11; break;
+    case 'b': font = (Fl_Font)(font|FL_BOLD); break;
+    case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
+    case 'f': case 't': font = FL_COURIER; break;
+    case 'B':
+    case 'C': dummy = strtol(str, &str, 10); break;// skip a color number
+    case 'F': font = (Fl_Font)strtol(str, &str, 10); break;
+    case 'S': tsize = strtol(str, &str, 10); break;
+    case '.':
+      done = 1;
+      break;
+    case '@':
+      str--;
+      done = 1;
+    }
+
+    if (done)
+      break;
+  }
+
+  if (*str == format_char_ && str[1])
+    str ++;
+
+  if (ww==0 && l->icon) ww = l->icon->w();
+
+  fl_font(font, tsize);
+  return ww + int(fl_width(str)) + 6;
+}
+
+/**
+  The height of the entire list of all visible() items in pixels.
+  This returns the accumulated height of *all* the items in the browser
+  that are not hidden with hide(), including items scrolled off screen.
+  \returns The accumulated size of all the visible items in pixels.
+  \see item_height(), item_width(),\n
+       incr_height(), full_height()
+*/
+int Fl_Browser::full_height() const {
+  return full_height_;
+}
+
+/**
+  The default 'average' item height (including inter-item spacing) in pixels.
+  This currently returns textsize() + 2.
+  \returns The value in pixels.
+  \see item_height(), item_width(),\n
+       incr_height(), full_height()
+*/
+int Fl_Browser::incr_height() const {
+  return textsize()+2;
+}
+
+/**
+  Draws \p item at the position specified by \p X \p Y \p W \p H.
+  The \p W and \p H values are used for clipping.
+  Should only be called within the context of an FLTK draw().
+  \param[in] item The item to be drawn
+  \param[in] X,Y,W,H position and size.
+*/
+void Fl_Browser::item_draw(void* item, int X, int Y, int W, int H) const {
+  FL_BLINE* l = (FL_BLINE*)item;
+  char* str = l->txt;
+  const int* i = column_widths();
+
+  bool first = true;	// for icon
+  while (W > 6) {	// do each tab-separated field
+    int w1 = W;	// width for this field
+    char* e = 0; // pointer to end of field or null if none
+    if (*i) { // find end of field and temporarily replace with 0
+      e = strchr(str, column_char());
+      if (e) {*e = 0; w1 = *i++;}
+    }
+    // Icon drawing code
+    if (first) {
+      first = false;
+      if (l->icon) {
+	l->icon->draw(X+2,Y+1);	// leave 2px left, 1px above
+	int iconw = l->icon->w()+2;
+	X += iconw; W -= iconw; w1 -= iconw;
+      }
+    }
+    int tsize = textsize();
+    Fl_Font font = textfont();
+    Fl_Color lcol = textcolor();
+    Fl_Align talign = FL_ALIGN_LEFT;
+    // check for all the @-lines recognized by XForms:
+    //#if defined(__GNUC__)
+    //#warning FIXME This maybe needs to be more UTF8 aware now...?
+    //#endif /*__GNUC__*/
+    while (*str == format_char() && *++str && *str != format_char()) {
+      long int dummy;
+      switch (*str++) {
+      case 'l': case 'L': tsize = 24; break;
+      case 'm': case 'M': tsize = 18; break;
+      case 's': tsize = 11; break;
+      case 'b': font = (Fl_Font)(font|FL_BOLD); break;
+      case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
+      case 'f': case 't': font = FL_COURIER; break;
+      case 'c': talign = FL_ALIGN_CENTER; break;
+      case 'r': talign = FL_ALIGN_RIGHT; break;
+      case 'B': 
+	if (!(l->flags & SELECTED)) {
+	  fl_color((Fl_Color)strtol(str, &str, 10));
+	  fl_rectf(X, Y, w1, H);
+	} else dummy = strtol(str, &str, 10);
+        break;
+      case 'C':
+	lcol = (Fl_Color)strtol(str, &str, 10);
+	break;
+      case 'F':
+	font = (Fl_Font)strtol(str, &str, 10);
+	break;
+      case 'N':
+	lcol = FL_INACTIVE_COLOR;
+	break;
+      case 'S':
+	tsize = strtol(str, &str, 10);
+	break;
+      case '-':
+	fl_color(FL_DARK3);
+	fl_line(X+3, Y+H/2, X+w1-3, Y+H/2);
+	fl_color(FL_LIGHT3);
+	fl_line(X+3, Y+H/2+1, X+w1-3, Y+H/2+1);
+	break;
+      case 'u':
+      case '_':
+	fl_color(lcol);
+	fl_line(X+3, Y+H-1, X+w1-3, Y+H-1);
+	break;
+      case '.':
+	goto BREAK;
+      case '@':
+	str--; goto BREAK;
+      }
+    }
+  BREAK:
+    fl_font(font, tsize);
+    if (l->flags & SELECTED)
+      lcol = fl_contrast(lcol, selection_color());
+    if (!active_r()) lcol = fl_inactive(lcol);
+    fl_color(lcol);
+    fl_draw(str, X+3, Y, w1-6, H, e ? Fl_Align(talign|FL_ALIGN_CLIP) : talign, 0, 0);
+    if (!e) break; // no more fields...
+    *e = column_char(); // put the separator back
+    X += w1;
+    W -= w1;
+    str = e+1;
+  }
+}
+
+static const int no_columns[1] = {0};
+
+/**
+  The constructor makes an empty browser.
+  \param[in] X,Y,W,H position and size.
+  \param[in] L label string, may be NULL.
+*/
+Fl_Browser::Fl_Browser(int X, int Y, int W, int H, const char *L)
+: Fl_Browser_(X, Y, W, H, L) {
+  column_widths_ = no_columns;
+  lines = 0;
+  full_height_ = 0;
+  cacheline = 0;
+  format_char_ = '@';
+  column_char_ = '\t';
+  first = last = cache = 0;
+}
+
+/**
+  Updates the browser so that \p line is shown at position \p pos.
+  \param[in] line line number. (1 based)
+  \param[in] pos position.
+  \see topline(), middleline(), bottomline()
+*/
+void Fl_Browser::lineposition(int line, Fl_Line_Position pos) {
+  if (line<1) line = 1;
+  if (line>lines) line = lines;
+  int p = 0;
+
+  FL_BLINE* l;
+  for (l=first; l && line>1; l = l->next) {
+    line--; p += item_height(l);
+  }
+  if (l && (pos == BOTTOM)) p += item_height (l);
+
+  int final = p, X, Y, W, H;
+  bbox(X, Y, W, H);
+
+  switch(pos) {
+    case TOP: break;
+    case BOTTOM: final -= H; break;
+    case MIDDLE: final -= H/2; break;
+  }
+  
+  if (final > (full_height() - H)) final = full_height() -H;
+  position(final);
+}
+
+/**
+  Returns the line that is currently visible at the top of the browser.
+  If there is no vertical scrollbar then this will always return 1.
+  \returns The lineno() of the top() of the browser.
+*/
+int Fl_Browser::topline() const {
+  return lineno(top());
+}
+
+/**
+  Removes all the lines in the browser.
+  \see add(), insert(), remove(), swap(int,int), clear()
+*/
+void Fl_Browser::clear() {
+  for (FL_BLINE* l = first; l;) {
+    FL_BLINE* n = l->next;
+    free(l);
+    l = n;
+  }
+  full_height_ = 0;
+  first = 0;
+  last = 0;
+  lines = 0;
+  new_list();
+}
+
+/**
+  Adds a new line to the end of the browser.
+
+  The text string \p newtext may contain format characters; see format_char() for details.
+  \p newtext is copied using the strdup() function, and can be NULL to make a blank line.
+
+  The optional void* argument \p d will be the data() for the new item.
+
+  \param[in] newtext The label text used for the added item
+  \param[in] d Optional user data() for the item (0 if unspecified)
+  \see add(), insert(), remove(), swap(int,int), clear()
+*/
+void Fl_Browser::add(const char* newtext, void* d) {
+  insert(lines+1, newtext, d);
+  //Fl_Browser_::display(last);
+}
+
+/**
+  Returns the label text for the specified \p line.
+  Return value can be NULL if \p line is out of range or unset.
+  The parameter \p line is 1 based.
+  \param[in] line The line number of the item whose text is returned. (1 based)
+  \returns The text string (can be NULL)
+*/
+const char* Fl_Browser::text(int line) const {
+  if (line < 1 || line > lines) return 0;
+  return find_line(line)->txt;
+}
+
+/**
+  Returns the user data() for specified \p line.
+  Return value can be NULL if \p line is out of range or no user data() was defined.
+  The parameter \p line is 1 based (1 will be the first item in the list).
+  \param[in] line The line number of the item whose data() is returned. (1 based)
+  \returns The user data pointer (can be NULL)
+
+*/
+void* Fl_Browser::data(int line) const {
+  if (line < 1 || line > lines) return 0;
+  return find_line(line)->data;
+}
+
+/**
+  Sets the selection state of the item at \p line to the value \p val.
+  If \p val is not specified, the default is 1 (selects the item).
+  \param[in] line The line number of the item to be changed. (1 based)
+  \param[in] val The new selection state (1=select, 0=de-select).
+  \returns 1 if the state changed, 0 if not.
+  \see select(), selected(), value(), item_select(), item_selected()
+*/
+int Fl_Browser::select(int line, int val) {
+  if (line < 1 || line > lines) return 0;
+  return Fl_Browser_::select(find_line(line), val);
+}
+
+/**
+  Returns 1 if specified \p line is selected, 0 if not.
+  \param[in] line The line being checked (1 based)
+  \returns 1 if item selected, 0 if not.
+  \see select(), selected(), value(), item_select(), item_selected()
+  */
+int Fl_Browser::selected(int line) const {
+  if (line < 1 || line > lines) return 0;
+  return find_line(line)->flags & SELECTED;
+}
+
+/**
+  Makes \p line visible, and available for selection by user.
+  Opposite of hide(int).
+  This changes the full_height() if the state was changed.
+  redraw() is called automatically if a change occurred.
+  \param[in] line The line to be shown. (1 based)
+  \see show(int), hide(int), display(), visible(), make_visible()
+*/
+void Fl_Browser::show(int line) {
+  FL_BLINE* t = find_line(line);
+  if (t->flags & NOTDISPLAYED) {
+    t->flags &= ~NOTDISPLAYED;
+    full_height_ += item_height(t);
+    if (Fl_Browser_::displayed(t)) redraw();
+  }
+}
+
+/**
+  Makes \p line invisible, preventing selection by the user.
+  The line can still be selected under program control.
+  This changes the full_height() if the state was changed.
+  When a line is made invisible, lines below it are moved up in the display.
+  redraw() is called automatically if a change occurred.
+  \param[in] line The line to be hidden. (1 based)
+  \see show(int), hide(int), display(), visible(), make_visible()
+*/
+void Fl_Browser::hide(int line) {
+  FL_BLINE* t = find_line(line);
+  if (!(t->flags & NOTDISPLAYED)) {
+    full_height_ -= item_height(t);
+    t->flags |= NOTDISPLAYED;
+    if (Fl_Browser_::displayed(t)) redraw();
+  }
+}
+
+/**
+  For back compatibility.
+  This calls show(line) if \p val is true, and hide(line) otherwise.
+  If \p val is not specified, the default is 1 (makes the line visible).
+  \see show(int), hide(int), display(), visible(), make_visible()
+*/
+void Fl_Browser::display(int line, int val) {
+  if (line < 1 || line > lines) return;
+  if (val) show(line); else hide(line);
+}
+
+/**
+  Returns non-zero if the specified \p line is visible, 0 if hidden.
+  Use show(int), hide(int), or make_visible(int) to change an item's visible state.
+  \param[in] line The line in the browser to be tested. (1 based)
+  \see show(int), hide(int), display(), visible(), make_visible()
+*/
+int Fl_Browser::visible(int line) const {
+  if (line < 1 || line > lines) return 0;
+  return !(find_line(line)->flags&NOTDISPLAYED);
+}
+
+/**
+  Returns the line number of the currently selected line, or 0 if none.
+  \returns The line number of current selection, or 0 if none selected.
+  \see select(), selected(), value(), item_select(), item_selected()
+*/
+int Fl_Browser::value() const {
+  return lineno(selection());
+}
+
+/**
+  Swap the two items \p a and \p b.
+  Uses swapping() to ensure list updates correctly.
+  \param[in] a,b The two items to be swapped.
+  \see swap(int,int), item_swap()
+*/
+void Fl_Browser::swap(FL_BLINE *a, FL_BLINE *b) {
+
+  if ( a == b || !a || !b) return;          // nothing to do
+  swapping(a, b);
+  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;
+  cache = 0;
+}
+
+/**
+  Swaps two browser lines \p a and \p b.
+  You must call redraw() to make any changes visible.
+  \param[in] a,b The two lines to be swapped. (both 1 based)
+  \see swap(int,int), item_swap()
+*/
+void Fl_Browser::swap(int a, int b) {
+  if (a < 1 || a > lines || b < 1 || b > lines) return;
+  FL_BLINE* ai = find_line(a);
+  FL_BLINE* bi = find_line(b);
+  swap(ai,bi);
+}
+
+/**
+  Set the image icon for \p line to the value \p icon.
+  Caller is responsible for keeping the icon allocated.
+  The \p line is automatically redrawn.
+  \param[in] line The line to be modified. If out of range, nothing is done.
+  \param[in] icon The image icon to be assigned to the \p line.
+                  If NULL, any previous icon is removed.
+*/
+void Fl_Browser::icon(int line, Fl_Image* icon) {
+
+  if (line<1 || line > lines) return;
+
+  FL_BLINE* bl = find_line(line);
+
+  int old_h = bl->icon ? bl->icon->h()+2 : 0;	// init with *old* icon height
+  bl->icon = 0;					// remove icon, if any
+  int th = item_height(bl);			// height of text only
+  int new_h = icon ? icon->h()+2 : 0;		// init with *new* icon height
+  if (th > old_h) old_h = th;
+  if (th > new_h) new_h = th;
+  int dh = new_h - old_h;
+  full_height_ += dh;				// do this *always*
+
+  bl->icon = icon;				// set new icon
+  if (dh>0) {
+    redraw();					// icon larger than item? must redraw widget
+  } else {
+    redraw_line(bl);				// icon same or smaller? can redraw just this line
+  }
+  replacing(bl,bl);				// recalc Fl_Browser_::max_width et al
+}
+
+/**
+  Returns the icon currently defined for \p line.
+  If no icon is defined, NULL is returned.
+  \param[in] line The line whose icon is returned.
+  \returns The icon defined, or NULL if none.
+*/
+Fl_Image* Fl_Browser::icon(int line) const {
+  FL_BLINE* l = find_line(line);
+  return(l ? l->icon : NULL);
+}
+
+/**
+  Removes the icon for \p line.
+  It's ok to remove an icon if none has been defined.
+  \param[in] line The line whose icon is to be removed.
+*/
+void Fl_Browser::remove_icon(int line) { 
+  icon(line,0);
+}
+
+/*
+  The following constructors must not be in the header file(s) if we
+  build a shared object (DLL). Instead they are defined here to force
+  the constructor (and default destructor as well) to be defined in
+  the DLL and exported (STR #2632, #2645).
+  
+  Note: if you change any of them, do the same changes in the specific
+  header file as well.  This redundant definition was chosen to enable
+  inline constructors in the header files (for static linking) as well
+  as those here for dynamic linking (Windows DLL).
+*/
+#if defined(FL_DLL)
+
+  Fl_Hold_Browser::Fl_Hold_Browser(int X,int Y,int W,int H,const char *L)
+	: Fl_Browser(X,Y,W,H,L) {type(FL_HOLD_BROWSER);}
+
+  Fl_Multi_Browser::Fl_Multi_Browser(int X,int Y,int W,int H,const char *L)
+	: Fl_Browser(X,Y,W,H,L) {type(FL_MULTI_BROWSER);}
+
+  Fl_Select_Browser::Fl_Select_Browser(int X,int Y,int W,int H,const char *L)
+	: Fl_Browser(X,Y,W,H,L) {type(FL_SELECT_BROWSER);}
+
+#endif // FL_DLL
+
+//
+// End of "$Id: Fl_Browser.cxx 8736 2011-05-24 20:00:56Z AlbrechtS $".
+//