| // |
| // "$Id: Fl_Check_Browser.cxx 8354 2011-02-01 15:41:04Z manolo $" |
| // |
| // Fl_Check_Browser header file 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 <stdio.h> |
| #include <stdlib.h> |
| #include "flstring.h" |
| #include <FL/fl_draw.H> |
| #include <FL/Fl_Check_Browser.H> |
| |
| /* This uses a cache for faster access when you're scanning the list |
| either forwards or backwards. */ |
| |
| Fl_Check_Browser::cb_item *Fl_Check_Browser::find_item(int n) const { |
| int i = n; |
| cb_item *p = first; |
| |
| if (n <= 0 || n > nitems_ || p == 0) { |
| return 0; |
| } |
| |
| if (n == cached_item) { |
| p = cache; |
| n = 1; |
| } else if (n == cached_item + 1) { |
| p = cache->next; |
| n = 1; |
| } else if (n == cached_item - 1) { |
| p = cache->prev; |
| n = 1; |
| } |
| |
| while (--n) { |
| p = p->next; |
| } |
| |
| /* Cast to not const and cache it. */ |
| |
| ((Fl_Check_Browser *)this)->cache = p; |
| ((Fl_Check_Browser *)this)->cached_item = i; |
| |
| return p; |
| } |
| |
| int Fl_Check_Browser::lineno(cb_item *p0) const { |
| cb_item *p = first; |
| |
| if (p == 0) { |
| return 0; |
| } |
| |
| int i = 1; |
| while (p) { |
| if (p == p0) { |
| return i; |
| } |
| i++; |
| p = p->next; |
| } |
| |
| return 0; |
| } |
| |
| Fl_Check_Browser::Fl_Check_Browser(int X, int Y, int W, int H, const char *l) |
| /** The constructor makes an empty browser.*/ |
| : Fl_Browser_(X, Y, W, H, l) { |
| type(FL_SELECT_BROWSER); |
| when(FL_WHEN_NEVER); |
| first = last = 0; |
| nitems_ = nchecked_ = 0; |
| cached_item = -1; |
| } |
| |
| void *Fl_Check_Browser::item_first() const { |
| return first; |
| } |
| |
| void *Fl_Check_Browser::item_next(void *l) const { |
| return ((cb_item *)l)->next; |
| } |
| |
| void *Fl_Check_Browser::item_prev(void *l) const { |
| return ((cb_item *)l)->prev; |
| } |
| |
| int Fl_Check_Browser::item_height(void *) const { |
| return textsize() + 2; |
| } |
| |
| #define CHECK_SIZE (textsize()-2) |
| |
| int Fl_Check_Browser::item_width(void *v) const { |
| fl_font(textfont(), textsize()); |
| return int(fl_width(((cb_item *)v)->text)) + CHECK_SIZE + 8; |
| } |
| |
| void Fl_Check_Browser::item_draw(void *v, int X, int Y, int, int) const { |
| cb_item *i = (cb_item *)v; |
| char *s = i->text; |
| int tsize = textsize(); |
| Fl_Color col = active_r() ? textcolor() : fl_inactive(textcolor()); |
| int cy = Y + (tsize + 1 - CHECK_SIZE) / 2; |
| X += 2; |
| |
| fl_color(active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR)); |
| fl_loop(X, cy, X, cy + CHECK_SIZE, |
| X + CHECK_SIZE, cy + CHECK_SIZE, X + CHECK_SIZE, cy); |
| if (i->checked) { |
| int tx = X + 3; |
| int tw = CHECK_SIZE - 4; |
| int d1 = tw/3; |
| int d2 = tw-d1; |
| int ty = cy + (CHECK_SIZE+d2)/2-d1-2; |
| for (int n = 0; n < 3; n++, ty++) { |
| fl_line(tx, ty, tx+d1, ty+d1); |
| fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1); |
| } |
| } |
| fl_font(textfont(), tsize); |
| if (i->selected) { |
| col = fl_contrast(col, selection_color()); |
| } |
| fl_color(col); |
| fl_draw(s, X + CHECK_SIZE + 8, Y + tsize - 1); |
| } |
| |
| void Fl_Check_Browser::item_select(void *v, int state) { |
| cb_item *i = (cb_item *)v; |
| |
| if (state) { |
| if (i->checked) { |
| i->checked = 0; |
| nchecked_--; |
| } else { |
| i->checked = 1; |
| nchecked_++; |
| } |
| } |
| } |
| |
| int Fl_Check_Browser::item_selected(void *v) const { |
| cb_item *i = (cb_item *)v; |
| return i->selected; |
| } |
| /** |
| Add a new unchecked line to the end of the browser. |
| \see add(char *s, int b) |
| */ |
| int Fl_Check_Browser::add(char *s) { |
| return (add(s, 0)); |
| } |
| |
| /** |
| Add a new line to the end of the browser. The text is copied |
| using the strdup() function. It may also be NULL to make |
| a blank line. It can set the item checked if \p b is not 0. |
| */ |
| int Fl_Check_Browser::add(char *s, int b) { |
| cb_item *p = (cb_item *)malloc(sizeof(cb_item)); |
| p->next = 0; |
| p->prev = 0; |
| p->checked = b; |
| p->selected = 0; |
| p->text = strdup(s); |
| |
| if (b) { |
| nchecked_++; |
| } |
| |
| if (last == 0) { |
| first = last = p; |
| } else { |
| last->next = p; |
| p->prev = last; |
| last = p; |
| } |
| nitems_++; |
| |
| return (nitems_); |
| } |
| |
| /** |
| Remove line n and make the browser one line shorter. Returns the |
| number of lines left in the browser. |
| */ |
| int Fl_Check_Browser::remove(int item) { |
| cb_item *p = find_item(item); |
| |
| // line at item exists |
| if(p) { |
| // tell the Browser_ what we will do |
| deleting(p); |
| |
| // fix checked count |
| if(p->checked) |
| --nchecked_; |
| |
| // remove the node |
| if (p->prev) |
| p->prev->next = p->next; |
| else |
| first = p->next; |
| if (p->next) |
| p->next->prev = p->prev; |
| else |
| last = p->prev; |
| |
| free(p->text); |
| free(p); |
| |
| --nitems_; |
| cached_item = -1; |
| } |
| |
| return (nitems_); |
| } |
| |
| /** Remove every item from the browser.*/ |
| void Fl_Check_Browser::clear() { |
| cb_item *p = first; |
| cb_item *next; |
| |
| if (p == 0) { |
| return; |
| } |
| |
| new_list(); |
| do { |
| next = p->next; |
| free(p->text); |
| free(p); |
| p = next; |
| } while (p); |
| |
| first = last = 0; |
| nitems_ = nchecked_ = 0; |
| cached_item = -1; |
| } |
| |
| /** Gets the current status of item item. */ |
| int Fl_Check_Browser::checked(int i) const { |
| cb_item *p = find_item(i); |
| |
| if (p) return p->checked; |
| return 0; |
| } |
| |
| /** Sets the check status of item item to b. */ |
| void Fl_Check_Browser::checked(int i, int b) { |
| cb_item *p = find_item(i); |
| |
| if (p && (p->checked ^ b)) { |
| p->checked = b; |
| if (b) { |
| nchecked_++; |
| } else { |
| nchecked_--; |
| } |
| redraw(); |
| } |
| } |
| |
| /** Returns the index of the currently selected item.*/ |
| int Fl_Check_Browser::value() const { |
| return lineno((cb_item *)selection()); |
| } |
| |
| /** Return a pointer to an internal buffer holding item item's text.*/ |
| char *Fl_Check_Browser::text(int i) const { |
| cb_item *p = find_item(i); |
| |
| if (p) return p->text; |
| return 0; |
| } |
| |
| /** Sets all the items checked.*/ |
| void Fl_Check_Browser::check_all() { |
| cb_item *p; |
| |
| nchecked_ = nitems_; |
| for (p = first; p; p = p->next) { |
| p->checked = 1; |
| } |
| redraw(); |
| } |
| |
| /** Sets all the items unchecked.*/ |
| void Fl_Check_Browser::check_none() { |
| cb_item *p; |
| |
| nchecked_ = 0; |
| for (p = first; p; p = p->next) { |
| p->checked = 0; |
| } |
| redraw(); |
| } |
| |
| int Fl_Check_Browser::handle(int event) { |
| if (event==FL_PUSH) |
| deselect(); |
| return Fl_Browser_::handle(event); |
| } |
| |
| // |
| // End of "$Id: Fl_Check_Browser.cxx 8354 2011-02-01 15:41:04Z manolo $". |
| // |