blob: d62b4f4db28f16dc41602437c5015e032aa3cf00 [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: Fl_Browser.cxx 8736 2011-05-24 20:00:56Z AlbrechtS $"
3//
4// Browser widget for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2010 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28#include <FL/Fl.H>
29#include <FL/Fl_Browser.H>
30#include <FL/fl_draw.H>
31#include "flstring.h"
32#include <stdlib.h>
33#include <math.h>
34
35#if defined(FL_DLL) // really needed for c'tors for MS VC++ only
36#include <FL/Fl_Hold_Browser.H>
37#include <FL/Fl_Multi_Browser.H>
38#include <FL/Fl_Select_Browser.H>
39#endif
40
41// I modified this from the original Forms data to use a linked list
42// so that the number of items in the browser and size of those items
43// is unlimited. The only problem is that the old browser used an
44// index number to identify a line, and it is slow to convert from/to
45// a pointer. I use a cache of the last match to try to speed this up.
46
47// Also added the ability to "hide" a line. This sets its height to
48// zero, so the Fl_Browser_ cannot pick it.
49
50#define SELECTED 1
51#define NOTDISPLAYED 2
52
53// WARNING:
54// Fl_File_Chooser.cxx also has a definition of this structure (FL_BLINE).
55// Changes to FL_BLINE *must* be reflected in Fl_File_Chooser.cxx as well.
56// This hack in Fl_File_Chooser should be solved.
57//
58struct FL_BLINE { // data is in a linked list of these
59 FL_BLINE* prev;
60 FL_BLINE* next;
61 void* data;
62 Fl_Image* icon;
63 short length; // sizeof(txt)-1, may be longer than string
64 char flags; // selected, displayed
65 char txt[1]; // start of allocated array
66};
67
68/**
69 Returns the very first item in the list.
70 Example of use:
71 \code
72 // Walk the browser from beginning to end
73 for ( void *i=item_first(); i; i=item_next(i) ) {
74 printf("item label='%s'\n", item_text(i));
75 }
76 \endcode
77 \returns The first item, or NULL if list is empty.
78 \see item_first(), item_last(), item_next(), item_prev()
79*/
80void* Fl_Browser::item_first() const {return first;}
81
82/**
83 Returns the next item after \p item.
84 \param[in] item The 'current' item
85 \returns The next item after \p item, or NULL if there are none after this one.
86 \see item_first(), item_last(), item_next(), item_prev()
87*/
88void* Fl_Browser::item_next(void* item) const {return ((FL_BLINE*)item)->next;}
89
90/**
91 Returns the previous item before \p item.
92 \param[in] item The 'current' item
93 \returns The previous item before \p item, or NULL if there none before this one.
94 \see item_first(), item_last(), item_next(), item_prev()
95*/
96void* Fl_Browser::item_prev(void* item) const {return ((FL_BLINE*)item)->prev;}
97
98/**
99 Returns the very last item in the list.
100 Example of use:
101 \code
102 // Walk the browser in reverse, from end to start
103 for ( void *i=item_last(); i; i=item_prev(i) ) {
104 printf("item label='%s'\n", item_text(i));
105 }
106 \endcode
107 \returns The last item, or NULL if list is empty.
108 \see item_first(), item_last(), item_next(), item_prev()
109*/
110void* Fl_Browser::item_last() const {return last;}
111
112/**
113 See if \p item is selected.
114 \param[in] item The item whose selection state is to be checked.
115 \returns 1 if selected, 0 if not.
116 \see select(), selected(), value(), item_select(), item_selected()
117*/
118int Fl_Browser::item_selected(void* item) const {
119 return ((FL_BLINE*)item)->flags&SELECTED;
120}
121/**
122 Change the selection state of \p item to the value \p val.
123 \param[in] item The item to be changed.
124 \param[in] val The new selection state: 1 selects, 0 de-selects.
125 \see select(), selected(), value(), item_select(), item_selected()
126*/
127void Fl_Browser::item_select(void *item, int val) {
128 if (val) ((FL_BLINE*)item)->flags |= SELECTED;
129 else ((FL_BLINE*)item)->flags &= ~SELECTED;
130}
131
132/**
133 Returns the label text for \p item.
134 \param[in] item The item whose label text is returned.
135 \returns The item's text string. (Can be NULL)
136*/
137const char *Fl_Browser::item_text(void *item) const {
138 return ((FL_BLINE*)item)->txt;
139}
140
141/**
142 Returns the item for specified \p line.
143
144 Note: This call is slow. It's fine for e.g. responding to user
145 clicks, but slow if called often, such as in a tight sorting loop.
146 Finding an item 'by line' involves a linear lookup on the internal
147 linked list. The performance hit can be significant if the browser's
148 contents is large, and the method is called often (e.g. during a sort).
149 If you're writing a subclass, use the protected methods item_first(),
150 item_next(), etc. to access the internal linked list more efficiently.
151
152 \param[in] line The line number of the item to return. (1 based)
153 \retval item that was found.
154 \retval NULL if line is out of range.
155 \see item_at(), find_line(), lineno()
156*/
157FL_BLINE* Fl_Browser::find_line(int line) const {
158 int n; FL_BLINE* l;
159 if (line == cacheline) return cache;
160 if (cacheline && line > (cacheline/2) && line < ((cacheline+lines)/2)) {
161 n = cacheline; l = cache;
162 } else if (line <= (lines/2)) {
163 n = 1; l = first;
164 } else {
165 n = lines; l = last;
166 }
167 for (; n < line && l; n++) l = l->next;
168 for (; n > line && l; n--) l = l->prev;
169 ((Fl_Browser*)this)->cacheline = line;
170 ((Fl_Browser*)this)->cache = l;
171 return l;
172}
173
174/**
175 Returns line number corresponding to \p item, or zero if not found.
176 Caveat: See efficiency note in find_line().
177 \param[in] item The item to be found
178 \returns The line number of the item, or 0 if not found.
179 \see item_at(), find_line(), lineno()
180*/
181int Fl_Browser::lineno(void *item) const {
182 FL_BLINE* l = (FL_BLINE*)item;
183 if (!l) return 0;
184 if (l == cache) return cacheline;
185 if (l == first) return 1;
186 if (l == last) return lines;
187 if (!cache) {
188 ((Fl_Browser*)this)->cache = first;
189 ((Fl_Browser*)this)->cacheline = 1;
190 }
191 // assume it is near cache, search both directions:
192 FL_BLINE* b = cache->prev;
193 int bnum = cacheline-1;
194 FL_BLINE* f = cache->next;
195 int fnum = cacheline+1;
196 int n = 0;
197 for (;;) {
198 if (b == l) {n = bnum; break;}
199 if (f == l) {n = fnum; break;}
200 if (b) {b = b->prev; bnum--;}
201 if (f) {f = f->next; fnum++;}
202 }
203 ((Fl_Browser*)this)->cache = l;
204 ((Fl_Browser*)this)->cacheline = n;
205 return n;
206}
207
208/**
209 Removes the item at the specified \p line.
210 Caveat: See efficiency note in find_line().
211 You must call redraw() to make any changes visible.
212 \param[in] line The line number to be removed. (1 based) Must be in range!
213 \returns Pointer to browser item that was removed (and is no longer valid).
214 \see add(), insert(), remove(), swap(int,int), clear()
215*/
216FL_BLINE* Fl_Browser::_remove(int line) {
217 FL_BLINE* ttt = find_line(line);
218 deleting(ttt);
219
220 cacheline = line-1;
221 cache = ttt->prev;
222 lines--;
223 full_height_ -= item_height(ttt);
224 if (ttt->prev) ttt->prev->next = ttt->next;
225 else first = ttt->next;
226 if (ttt->next) ttt->next->prev = ttt->prev;
227 else last = ttt->prev;
228
229 return(ttt);
230}
231
232/**
233 Remove entry for given \p line number, making the browser one line shorter.
234 You must call redraw() to make any changes visible.
235 \param[in] line Line to be removed. (1 based) \n
236 If \p line is out of range, no action is taken.
237 \see add(), insert(), remove(), swap(int,int), clear()
238*/
239void Fl_Browser::remove(int line) {
240 if (line < 1 || line > lines) return;
241 free(_remove(line));
242}
243
244/**
245 Insert specified \p item above \p line.
246 If \p line > size() then the line is added to the end.
247
248 Caveat: See efficiency note in find_line().
249
250 \param[in] line The new line will be inserted above this line (1 based).
251 \param[in] item The item to be added.
252*/
253void Fl_Browser::insert(int line, FL_BLINE* item) {
254 if (!first) {
255 item->prev = item->next = 0;
256 first = last = item;
257 } else if (line <= 1) {
258 inserting(first, item);
259 item->prev = 0;
260 item->next = first;
261 item->next->prev = item;
262 first = item;
263 } else if (line > lines) {
264 item->prev = last;
265 item->prev->next = item;
266 item->next = 0;
267 last = item;
268 } else {
269 FL_BLINE* n = find_line(line);
270 inserting(n, item);
271 item->next = n;
272 item->prev = n->prev;
273 item->prev->next = item;
274 n->prev = item;
275 }
276 cacheline = line;
277 cache = item;
278 lines++;
279 full_height_ += item_height(item);
280 redraw_line(item);
281}
282
283/**
284 Insert a new entry whose label is \p newtext \e above given \p line, optional data \p d.
285
286 Text may contain format characters; see format_char() for details.
287 \p newtext is copied using the strdup() function, and can be NULL to make a blank line.
288
289 The optional void * argument \p d will be the data() of the new item.
290
291 \param[in] line Line position for insert. (1 based) \n
292 If \p line > size(), the entry will be added at the end.
293 \param[in] newtext The label text for the new line.
294 \param[in] d Optional pointer to user data to be associated with the new line.
295*/
296void Fl_Browser::insert(int line, const char* newtext, void* d) {
297 int l = strlen(newtext);
298 FL_BLINE* t = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l);
299 t->length = (short)l;
300 t->flags = 0;
301 strcpy(t->txt, newtext);
302 t->data = d;
303 t->icon = 0;
304 insert(line, t);
305}
306
307/**
308 Line \p from is removed and reinserted at \p to.
309 Note: \p to is calculated \e after line \p from gets removed.
310 \param[in] to Destination line number (calculated \e after line \p from is removed)
311 \param[in] from Line number of item to be moved
312*/
313void Fl_Browser::move(int to, int from) {
314 if (from < 1 || from > lines) return;
315 insert(to, _remove(from));
316}
317
318/**
319 Sets the text for the specified \p line to \p newtext.
320
321 Text may contain format characters; see format_char() for details.
322 \p newtext is copied using the strdup() function, and can be NULL to make a blank line.
323
324 Does nothing if \p line is out of range.
325
326 \param[in] line The line of the item whose text will be changed. (1 based)
327 \param[in] newtext The new string to be assigned to the item.
328*/
329void Fl_Browser::text(int line, const char* newtext) {
330 if (line < 1 || line > lines) return;
331 FL_BLINE* t = find_line(line);
332 int l = strlen(newtext);
333 if (l > t->length) {
334 FL_BLINE* n = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l);
335 replacing(t, n);
336 cache = n;
337 n->data = t->data;
338 n->icon = t->icon;
339 n->length = (short)l;
340 n->flags = t->flags;
341 n->prev = t->prev;
342 if (n->prev) n->prev->next = n; else first = n;
343 n->next = t->next;
344 if (n->next) n->next->prev = n; else last = n;
345 free(t);
346 t = n;
347 }
348 strcpy(t->txt, newtext);
349 redraw_line(t);
350}
351
352/**
353 Sets the user data for specified \p line to \p d.
354 Does nothing if \p line is out of range.
355 \param[in] line The line of the item whose data() is to be changed. (1 based)
356 \param[in] d The new data to be assigned to the item. (can be NULL)
357*/
358void Fl_Browser::data(int line, void* d) {
359 if (line < 1 || line > lines) return;
360 find_line(line)->data = d;
361}
362
363/**
364 Returns height of \p item in pixels.
365 This takes into account embedded \@ codes within the text() label.
366 \param[in] item The item whose height is returned.
367 \returns The height of the item in pixels.
368 \see item_height(), item_width(),\n
369 incr_height(), full_height()
370*/
371int Fl_Browser::item_height(void *item) const {
372 FL_BLINE* l = (FL_BLINE*)item;
373 if (l->flags & NOTDISPLAYED) return 0;
374
375 int hmax = 2; // use 2 to insure we don't return a zero!
376
377 if (!l->txt[0]) {
378 // For blank lines set the height to exactly 1 line!
379 fl_font(textfont(), textsize());
380 int hh = fl_height();
381 if (hh > hmax) hmax = hh;
382 } else {
383 const int* i = column_widths();
384 long int dummy;
385 // do each column separately as they may all set different fonts:
386 for (char* str = l->txt; str && *str; str++) {
387 Fl_Font font = textfont(); // default font
388 int tsize = textsize(); // default size
389 while (*str==format_char()) {
390 str++;
391 switch (*str++) {
392 case 'l': case 'L': tsize = 24; break;
393 case 'm': case 'M': tsize = 18; break;
394 case 's': tsize = 11; break;
395 case 'b': font = (Fl_Font)(font|FL_BOLD); break;
396 case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
397 case 'f': case 't': font = FL_COURIER; break;
398 case 'B':
399 case 'C': dummy = strtol(str, &str, 10); break;// skip a color number
400 case 'F': font = (Fl_Font)strtol(str,&str,10); break;
401 case 'S': tsize = strtol(str,&str,10); break;
402 case 0: case '@': str--;
403 case '.': goto END_FORMAT;
404 }
405 }
406 END_FORMAT:
407 char* ptr = str;
408 if (ptr && *i++) str = strchr(str, column_char());
409 else str = NULL;
410 if((!str && *ptr) || (str && ptr < str)) {
411 fl_font(font, tsize); int hh = fl_height();
412 if (hh > hmax) hmax = hh;
413 }
414 if (!str || !*str) break;
415 }
416 }
417
418 if (l->icon && (l->icon->h()+2)>hmax) {
419 hmax = l->icon->h() + 2; // leave 2px above/below
420 }
421 return hmax; // previous version returned hmax+2!
422}
423
424/**
425 Returns width of \p item in pixels.
426 This takes into account embedded \@ codes within the text() label.
427 \param[in] item The item whose width is returned.
428 \returns The width of the item in pixels.
429 \see item_height(), item_width(),\n
430 incr_height(), full_height()
431*/
432int Fl_Browser::item_width(void *item) const {
433 FL_BLINE* l=(FL_BLINE*)item;
434 char* str = l->txt;
435 const int* i = column_widths();
436 int ww = 0;
437
438 while (*i) { // add up all tab-separated fields
439 char* e;
440 e = strchr(str, column_char());
441 if (!e) break; // last one occupied by text
442 str = e+1;
443 ww += *i++;
444 }
445
446 // OK, we gotta parse the string and find the string width...
447 int tsize = textsize();
448 Fl_Font font = textfont();
449 int done = 0;
450
451 while (*str == format_char_ && str[1] && str[1] != format_char_) {
452 long int dummy;
453 str ++;
454 switch (*str++) {
455 case 'l': case 'L': tsize = 24; break;
456 case 'm': case 'M': tsize = 18; break;
457 case 's': tsize = 11; break;
458 case 'b': font = (Fl_Font)(font|FL_BOLD); break;
459 case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
460 case 'f': case 't': font = FL_COURIER; break;
461 case 'B':
462 case 'C': dummy = strtol(str, &str, 10); break;// skip a color number
463 case 'F': font = (Fl_Font)strtol(str, &str, 10); break;
464 case 'S': tsize = strtol(str, &str, 10); break;
465 case '.':
466 done = 1;
467 break;
468 case '@':
469 str--;
470 done = 1;
471 }
472
473 if (done)
474 break;
475 }
476
477 if (*str == format_char_ && str[1])
478 str ++;
479
480 if (ww==0 && l->icon) ww = l->icon->w();
481
482 fl_font(font, tsize);
483 return ww + int(fl_width(str)) + 6;
484}
485
486/**
487 The height of the entire list of all visible() items in pixels.
488 This returns the accumulated height of *all* the items in the browser
489 that are not hidden with hide(), including items scrolled off screen.
490 \returns The accumulated size of all the visible items in pixels.
491 \see item_height(), item_width(),\n
492 incr_height(), full_height()
493*/
494int Fl_Browser::full_height() const {
495 return full_height_;
496}
497
498/**
499 The default 'average' item height (including inter-item spacing) in pixels.
500 This currently returns textsize() + 2.
501 \returns The value in pixels.
502 \see item_height(), item_width(),\n
503 incr_height(), full_height()
504*/
505int Fl_Browser::incr_height() const {
506 return textsize()+2;
507}
508
509/**
510 Draws \p item at the position specified by \p X \p Y \p W \p H.
511 The \p W and \p H values are used for clipping.
512 Should only be called within the context of an FLTK draw().
513 \param[in] item The item to be drawn
514 \param[in] X,Y,W,H position and size.
515*/
516void Fl_Browser::item_draw(void* item, int X, int Y, int W, int H) const {
517 FL_BLINE* l = (FL_BLINE*)item;
518 char* str = l->txt;
519 const int* i = column_widths();
520
521 bool first = true; // for icon
522 while (W > 6) { // do each tab-separated field
523 int w1 = W; // width for this field
524 char* e = 0; // pointer to end of field or null if none
525 if (*i) { // find end of field and temporarily replace with 0
526 e = strchr(str, column_char());
527 if (e) {*e = 0; w1 = *i++;}
528 }
529 // Icon drawing code
530 if (first) {
531 first = false;
532 if (l->icon) {
533 l->icon->draw(X+2,Y+1); // leave 2px left, 1px above
534 int iconw = l->icon->w()+2;
535 X += iconw; W -= iconw; w1 -= iconw;
536 }
537 }
538 int tsize = textsize();
539 Fl_Font font = textfont();
540 Fl_Color lcol = textcolor();
541 Fl_Align talign = FL_ALIGN_LEFT;
542 // check for all the @-lines recognized by XForms:
543 //#if defined(__GNUC__)
544 //#warning FIXME This maybe needs to be more UTF8 aware now...?
545 //#endif /*__GNUC__*/
546 while (*str == format_char() && *++str && *str != format_char()) {
547 long int dummy;
548 switch (*str++) {
549 case 'l': case 'L': tsize = 24; break;
550 case 'm': case 'M': tsize = 18; break;
551 case 's': tsize = 11; break;
552 case 'b': font = (Fl_Font)(font|FL_BOLD); break;
553 case 'i': font = (Fl_Font)(font|FL_ITALIC); break;
554 case 'f': case 't': font = FL_COURIER; break;
555 case 'c': talign = FL_ALIGN_CENTER; break;
556 case 'r': talign = FL_ALIGN_RIGHT; break;
557 case 'B':
558 if (!(l->flags & SELECTED)) {
559 fl_color((Fl_Color)strtol(str, &str, 10));
560 fl_rectf(X, Y, w1, H);
561 } else dummy = strtol(str, &str, 10);
562 break;
563 case 'C':
564 lcol = (Fl_Color)strtol(str, &str, 10);
565 break;
566 case 'F':
567 font = (Fl_Font)strtol(str, &str, 10);
568 break;
569 case 'N':
570 lcol = FL_INACTIVE_COLOR;
571 break;
572 case 'S':
573 tsize = strtol(str, &str, 10);
574 break;
575 case '-':
576 fl_color(FL_DARK3);
577 fl_line(X+3, Y+H/2, X+w1-3, Y+H/2);
578 fl_color(FL_LIGHT3);
579 fl_line(X+3, Y+H/2+1, X+w1-3, Y+H/2+1);
580 break;
581 case 'u':
582 case '_':
583 fl_color(lcol);
584 fl_line(X+3, Y+H-1, X+w1-3, Y+H-1);
585 break;
586 case '.':
587 goto BREAK;
588 case '@':
589 str--; goto BREAK;
590 }
591 }
592 BREAK:
593 fl_font(font, tsize);
594 if (l->flags & SELECTED)
595 lcol = fl_contrast(lcol, selection_color());
596 if (!active_r()) lcol = fl_inactive(lcol);
597 fl_color(lcol);
598 fl_draw(str, X+3, Y, w1-6, H, e ? Fl_Align(talign|FL_ALIGN_CLIP) : talign, 0, 0);
599 if (!e) break; // no more fields...
600 *e = column_char(); // put the separator back
601 X += w1;
602 W -= w1;
603 str = e+1;
604 }
605}
606
607static const int no_columns[1] = {0};
608
609/**
610 The constructor makes an empty browser.
611 \param[in] X,Y,W,H position and size.
612 \param[in] L label string, may be NULL.
613*/
614Fl_Browser::Fl_Browser(int X, int Y, int W, int H, const char *L)
615: Fl_Browser_(X, Y, W, H, L) {
616 column_widths_ = no_columns;
617 lines = 0;
618 full_height_ = 0;
619 cacheline = 0;
620 format_char_ = '@';
621 column_char_ = '\t';
622 first = last = cache = 0;
623}
624
625/**
626 Updates the browser so that \p line is shown at position \p pos.
627 \param[in] line line number. (1 based)
628 \param[in] pos position.
629 \see topline(), middleline(), bottomline()
630*/
631void Fl_Browser::lineposition(int line, Fl_Line_Position pos) {
632 if (line<1) line = 1;
633 if (line>lines) line = lines;
634 int p = 0;
635
636 FL_BLINE* l;
637 for (l=first; l && line>1; l = l->next) {
638 line--; p += item_height(l);
639 }
640 if (l && (pos == BOTTOM)) p += item_height (l);
641
642 int final = p, X, Y, W, H;
643 bbox(X, Y, W, H);
644
645 switch(pos) {
646 case TOP: break;
647 case BOTTOM: final -= H; break;
648 case MIDDLE: final -= H/2; break;
649 }
650
651 if (final > (full_height() - H)) final = full_height() -H;
652 position(final);
653}
654
655/**
656 Returns the line that is currently visible at the top of the browser.
657 If there is no vertical scrollbar then this will always return 1.
658 \returns The lineno() of the top() of the browser.
659*/
660int Fl_Browser::topline() const {
661 return lineno(top());
662}
663
664/**
665 Removes all the lines in the browser.
666 \see add(), insert(), remove(), swap(int,int), clear()
667*/
668void Fl_Browser::clear() {
669 for (FL_BLINE* l = first; l;) {
670 FL_BLINE* n = l->next;
671 free(l);
672 l = n;
673 }
674 full_height_ = 0;
675 first = 0;
676 last = 0;
677 lines = 0;
678 new_list();
679}
680
681/**
682 Adds a new line to the end of the browser.
683
684 The text string \p newtext may contain format characters; see format_char() for details.
685 \p newtext is copied using the strdup() function, and can be NULL to make a blank line.
686
687 The optional void* argument \p d will be the data() for the new item.
688
689 \param[in] newtext The label text used for the added item
690 \param[in] d Optional user data() for the item (0 if unspecified)
691 \see add(), insert(), remove(), swap(int,int), clear()
692*/
693void Fl_Browser::add(const char* newtext, void* d) {
694 insert(lines+1, newtext, d);
695 //Fl_Browser_::display(last);
696}
697
698/**
699 Returns the label text for the specified \p line.
700 Return value can be NULL if \p line is out of range or unset.
701 The parameter \p line is 1 based.
702 \param[in] line The line number of the item whose text is returned. (1 based)
703 \returns The text string (can be NULL)
704*/
705const char* Fl_Browser::text(int line) const {
706 if (line < 1 || line > lines) return 0;
707 return find_line(line)->txt;
708}
709
710/**
711 Returns the user data() for specified \p line.
712 Return value can be NULL if \p line is out of range or no user data() was defined.
713 The parameter \p line is 1 based (1 will be the first item in the list).
714 \param[in] line The line number of the item whose data() is returned. (1 based)
715 \returns The user data pointer (can be NULL)
716
717*/
718void* Fl_Browser::data(int line) const {
719 if (line < 1 || line > lines) return 0;
720 return find_line(line)->data;
721}
722
723/**
724 Sets the selection state of the item at \p line to the value \p val.
725 If \p val is not specified, the default is 1 (selects the item).
726 \param[in] line The line number of the item to be changed. (1 based)
727 \param[in] val The new selection state (1=select, 0=de-select).
728 \returns 1 if the state changed, 0 if not.
729 \see select(), selected(), value(), item_select(), item_selected()
730*/
731int Fl_Browser::select(int line, int val) {
732 if (line < 1 || line > lines) return 0;
733 return Fl_Browser_::select(find_line(line), val);
734}
735
736/**
737 Returns 1 if specified \p line is selected, 0 if not.
738 \param[in] line The line being checked (1 based)
739 \returns 1 if item selected, 0 if not.
740 \see select(), selected(), value(), item_select(), item_selected()
741 */
742int Fl_Browser::selected(int line) const {
743 if (line < 1 || line > lines) return 0;
744 return find_line(line)->flags & SELECTED;
745}
746
747/**
748 Makes \p line visible, and available for selection by user.
749 Opposite of hide(int).
750 This changes the full_height() if the state was changed.
751 redraw() is called automatically if a change occurred.
752 \param[in] line The line to be shown. (1 based)
753 \see show(int), hide(int), display(), visible(), make_visible()
754*/
755void Fl_Browser::show(int line) {
756 FL_BLINE* t = find_line(line);
757 if (t->flags & NOTDISPLAYED) {
758 t->flags &= ~NOTDISPLAYED;
759 full_height_ += item_height(t);
760 if (Fl_Browser_::displayed(t)) redraw();
761 }
762}
763
764/**
765 Makes \p line invisible, preventing selection by the user.
766 The line can still be selected under program control.
767 This changes the full_height() if the state was changed.
768 When a line is made invisible, lines below it are moved up in the display.
769 redraw() is called automatically if a change occurred.
770 \param[in] line The line to be hidden. (1 based)
771 \see show(int), hide(int), display(), visible(), make_visible()
772*/
773void Fl_Browser::hide(int line) {
774 FL_BLINE* t = find_line(line);
775 if (!(t->flags & NOTDISPLAYED)) {
776 full_height_ -= item_height(t);
777 t->flags |= NOTDISPLAYED;
778 if (Fl_Browser_::displayed(t)) redraw();
779 }
780}
781
782/**
783 For back compatibility.
784 This calls show(line) if \p val is true, and hide(line) otherwise.
785 If \p val is not specified, the default is 1 (makes the line visible).
786 \see show(int), hide(int), display(), visible(), make_visible()
787*/
788void Fl_Browser::display(int line, int val) {
789 if (line < 1 || line > lines) return;
790 if (val) show(line); else hide(line);
791}
792
793/**
794 Returns non-zero if the specified \p line is visible, 0 if hidden.
795 Use show(int), hide(int), or make_visible(int) to change an item's visible state.
796 \param[in] line The line in the browser to be tested. (1 based)
797 \see show(int), hide(int), display(), visible(), make_visible()
798*/
799int Fl_Browser::visible(int line) const {
800 if (line < 1 || line > lines) return 0;
801 return !(find_line(line)->flags&NOTDISPLAYED);
802}
803
804/**
805 Returns the line number of the currently selected line, or 0 if none.
806 \returns The line number of current selection, or 0 if none selected.
807 \see select(), selected(), value(), item_select(), item_selected()
808*/
809int Fl_Browser::value() const {
810 return lineno(selection());
811}
812
813/**
814 Swap the two items \p a and \p b.
815 Uses swapping() to ensure list updates correctly.
816 \param[in] a,b The two items to be swapped.
817 \see swap(int,int), item_swap()
818*/
819void Fl_Browser::swap(FL_BLINE *a, FL_BLINE *b) {
820
821 if ( a == b || !a || !b) return; // nothing to do
822 swapping(a, b);
823 FL_BLINE *aprev = a->prev;
824 FL_BLINE *anext = a->next;
825 FL_BLINE *bprev = b->prev;
826 FL_BLINE *bnext = b->next;
827 if ( b->prev == a ) { // A ADJACENT TO B
828 if ( aprev ) aprev->next = b; else first = b;
829 b->next = a;
830 a->next = bnext;
831 b->prev = aprev;
832 a->prev = b;
833 if ( bnext ) bnext->prev = a; else last = a;
834 } else if ( a->prev == b ) { // B ADJACENT TO A
835 if ( bprev ) bprev->next = a; else first = a;
836 a->next = b;
837 b->next = anext;
838 a->prev = bprev;
839 b->prev = a;
840 if ( anext ) anext->prev = b; else last = b;
841 } else { // A AND B NOT ADJACENT
842 // handle prev's
843 b->prev = aprev;
844 if ( anext ) anext->prev = b; else last = b;
845 a->prev = bprev;
846 if ( bnext ) bnext->prev = a; else last = a;
847 // handle next's
848 if ( aprev ) aprev->next = b; else first = b;
849 b->next = anext;
850 if ( bprev ) bprev->next = a; else first = a;
851 a->next = bnext;
852 }
853 // Disable cache -- we played around with positions
854 cacheline = 0;
855 cache = 0;
856}
857
858/**
859 Swaps two browser lines \p a and \p b.
860 You must call redraw() to make any changes visible.
861 \param[in] a,b The two lines to be swapped. (both 1 based)
862 \see swap(int,int), item_swap()
863*/
864void Fl_Browser::swap(int a, int b) {
865 if (a < 1 || a > lines || b < 1 || b > lines) return;
866 FL_BLINE* ai = find_line(a);
867 FL_BLINE* bi = find_line(b);
868 swap(ai,bi);
869}
870
871/**
872 Set the image icon for \p line to the value \p icon.
873 Caller is responsible for keeping the icon allocated.
874 The \p line is automatically redrawn.
875 \param[in] line The line to be modified. If out of range, nothing is done.
876 \param[in] icon The image icon to be assigned to the \p line.
877 If NULL, any previous icon is removed.
878*/
879void Fl_Browser::icon(int line, Fl_Image* icon) {
880
881 if (line<1 || line > lines) return;
882
883 FL_BLINE* bl = find_line(line);
884
885 int old_h = bl->icon ? bl->icon->h()+2 : 0; // init with *old* icon height
886 bl->icon = 0; // remove icon, if any
887 int th = item_height(bl); // height of text only
888 int new_h = icon ? icon->h()+2 : 0; // init with *new* icon height
889 if (th > old_h) old_h = th;
890 if (th > new_h) new_h = th;
891 int dh = new_h - old_h;
892 full_height_ += dh; // do this *always*
893
894 bl->icon = icon; // set new icon
895 if (dh>0) {
896 redraw(); // icon larger than item? must redraw widget
897 } else {
898 redraw_line(bl); // icon same or smaller? can redraw just this line
899 }
900 replacing(bl,bl); // recalc Fl_Browser_::max_width et al
901}
902
903/**
904 Returns the icon currently defined for \p line.
905 If no icon is defined, NULL is returned.
906 \param[in] line The line whose icon is returned.
907 \returns The icon defined, or NULL if none.
908*/
909Fl_Image* Fl_Browser::icon(int line) const {
910 FL_BLINE* l = find_line(line);
911 return(l ? l->icon : NULL);
912}
913
914/**
915 Removes the icon for \p line.
916 It's ok to remove an icon if none has been defined.
917 \param[in] line The line whose icon is to be removed.
918*/
919void Fl_Browser::remove_icon(int line) {
920 icon(line,0);
921}
922
923/*
924 The following constructors must not be in the header file(s) if we
925 build a shared object (DLL). Instead they are defined here to force
926 the constructor (and default destructor as well) to be defined in
927 the DLL and exported (STR #2632, #2645).
928
929 Note: if you change any of them, do the same changes in the specific
930 header file as well. This redundant definition was chosen to enable
931 inline constructors in the header files (for static linking) as well
932 as those here for dynamic linking (Windows DLL).
933*/
934#if defined(FL_DLL)
935
936 Fl_Hold_Browser::Fl_Hold_Browser(int X,int Y,int W,int H,const char *L)
937 : Fl_Browser(X,Y,W,H,L) {type(FL_HOLD_BROWSER);}
938
939 Fl_Multi_Browser::Fl_Multi_Browser(int X,int Y,int W,int H,const char *L)
940 : Fl_Browser(X,Y,W,H,L) {type(FL_MULTI_BROWSER);}
941
942 Fl_Select_Browser::Fl_Select_Browser(int X,int Y,int W,int H,const char *L)
943 : Fl_Browser(X,Y,W,H,L) {type(FL_SELECT_BROWSER);}
944
945#endif // FL_DLL
946
947//
948// End of "$Id: Fl_Browser.cxx 8736 2011-05-24 20:00:56Z AlbrechtS $".
949//