1 //
2 // "$Id$"
3 //
4 // Fl_Check_Browser header file for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file.  If this
10 // file is missing or damaged, see the license at:
11 //
12 //     http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 //     http://www.fltk.org/str.php
17 //
18 
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include "flstring.h"
22 #include <FL/fl_draw.H>
23 #include <FL/Fl_Check_Browser.H>
24 
25 /* This uses a cache for faster access when you're scanning the list
26 either forwards or backwards. */
27 
find_item(int n) const28 Fl_Check_Browser::cb_item *Fl_Check_Browser::find_item(int n) const {
29 	int i = n;
30 	cb_item *p = first;
31 
32 	if (n <= 0 || n > nitems_ || p == 0) {
33 		return 0;
34 	}
35 
36 	if (n == cached_item) {
37 		p = cache;
38 		n = 1;
39 	} else if (n == cached_item + 1) {
40 		p = cache->next;
41 		n = 1;
42 	} else if (n == cached_item - 1) {
43 		p = cache->prev;
44 		n = 1;
45 	}
46 
47 	while (--n) {
48 		p = p->next;
49 	}
50 
51 	/* Cast to not const and cache it. */
52 
53 	((Fl_Check_Browser *)this)->cache = p;
54 	((Fl_Check_Browser *)this)->cached_item = i;
55 
56 	return p;
57 }
58 
lineno(cb_item * p0) const59 int Fl_Check_Browser::lineno(cb_item *p0) const {
60 	cb_item *p = first;
61 
62 	if (p == 0) {
63 		return 0;
64 	}
65 
66 	int i = 1;
67 	while (p) {
68 		if (p == p0) {
69 			return i;
70 		}
71 		i++;
72 		p = p->next;
73 	}
74 
75 	return 0;
76 }
77 
Fl_Check_Browser(int X,int Y,int W,int H,const char * l)78 Fl_Check_Browser::Fl_Check_Browser(int X, int Y, int W, int H, const char *l)
79 /**  The constructor makes an empty browser.*/
80 : Fl_Browser_(X, Y, W, H, l) {
81 	type(FL_SELECT_BROWSER);
82 	when(FL_WHEN_NEVER);
83 	first = last = 0;
84 	nitems_ = nchecked_ = 0;
85 	cached_item = -1;
86 }
87 
item_first() const88 void *Fl_Check_Browser::item_first() const {
89 	return first;
90 }
91 
item_next(void * l) const92 void *Fl_Check_Browser::item_next(void *l) const {
93 	return ((cb_item *)l)->next;
94 }
95 
item_prev(void * l) const96 void *Fl_Check_Browser::item_prev(void *l) const {
97 	return ((cb_item *)l)->prev;
98 }
99 
item_height(void *) const100 int Fl_Check_Browser::item_height(void *) const {
101 	return textsize() + 2;
102 }
103 
104 #define CHECK_SIZE (textsize()-2)
105 
item_width(void * v) const106 int Fl_Check_Browser::item_width(void *v) const {
107 	fl_font(textfont(), textsize());
108 	return int(fl_width(((cb_item *)v)->text)) + CHECK_SIZE + 8;
109 }
110 
item_draw(void * v,int X,int Y,int,int) const111 void Fl_Check_Browser::item_draw(void *v, int X, int Y, int, int) const {
112 	cb_item *i = (cb_item *)v;
113 	char *s = i->text;
114 	int tsize = textsize();
115 	Fl_Color col = active_r() ? textcolor() : fl_inactive(textcolor());
116 	int cy = Y + (tsize + 1 - CHECK_SIZE) / 2;
117 	X += 2;
118 
119 	fl_color(active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR));
120 	fl_loop(X, cy, X, cy + CHECK_SIZE,
121 	        X + CHECK_SIZE, cy + CHECK_SIZE, X + CHECK_SIZE, cy);
122 	if (i->checked) {
123 	  int tx = X + 3;
124 	  int tw = CHECK_SIZE - 4;
125 	  int d1 = tw/3;
126 	  int d2 = tw-d1;
127 	  int ty = cy + (CHECK_SIZE+d2)/2-d1-2;
128 	  for (int n = 0; n < 3; n++, ty++) {
129 	    fl_line(tx, ty, tx+d1, ty+d1);
130 	    fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1);
131 	  }
132 	}
133 	fl_font(textfont(), tsize);
134 	if (i->selected) {
135 		col = fl_contrast(col, selection_color());
136 	}
137 	fl_color(col);
138 	fl_draw(s, X + CHECK_SIZE + 8, Y + tsize - 1);
139 }
140 
item_select(void * v,int state)141 void Fl_Check_Browser::item_select(void *v, int state) {
142 	cb_item *i = (cb_item *)v;
143 
144 	if (state) {
145 		if (i->checked) {
146 			i->checked = 0;
147 			nchecked_--;
148 		} else {
149 			i->checked = 1;
150 			nchecked_++;
151 		}
152 	}
153 }
154 
item_selected(void * v) const155 int Fl_Check_Browser::item_selected(void *v) const {
156 	cb_item *i = (cb_item *)v;
157 	return i->selected;
158 }
159 /**
160  Add a new unchecked line to the end of the browser.
161  \see add(char *s, int b)
162 */
add(char * s)163 int Fl_Check_Browser::add(char *s) {
164 	return (add(s, 0));
165 }
166 
167 /**
168  Add a new line to the end of the browser.  The text is copied
169  using the strdup() function.  It may also be NULL to make
170  a blank line.  It can set the item checked if \p b is not 0.
171  */
add(char * s,int b)172 int Fl_Check_Browser::add(char *s, int b) {
173 	cb_item *p = (cb_item *)malloc(sizeof(cb_item));
174 	p->next = 0;
175 	p->prev = 0;
176 	p->checked = b;
177 	p->selected = 0;
178 	p->text = strdup(s);
179 
180 	if (b) {
181 		nchecked_++;
182 	}
183 
184 	if (last == 0) {
185 		first = last = p;
186 	} else {
187 		last->next = p;
188 		p->prev = last;
189 		last = p;
190 	}
191 	nitems_++;
192 
193 	return (nitems_);
194 }
195 
196 /**
197   Remove line n and make the browser one line shorter. Returns the
198   number of lines left in the browser.
199 */
remove(int item)200 int Fl_Check_Browser::remove(int item) {
201   cb_item *p = find_item(item);
202 
203   // line at item exists
204   if(p) {
205     // tell the Browser_ what we will do
206     deleting(p);
207 
208     // fix checked count
209     if(p->checked)
210       --nchecked_;
211 
212     // remove the node
213     if (p->prev)
214       p->prev->next = p->next;
215     else
216       first = p->next;
217     if (p->next)
218       p->next->prev = p->prev;
219     else
220       last = p->prev;
221 
222     free(p->text);
223     free(p);
224 
225     --nitems_;
226     cached_item = -1;
227   }
228 
229   return (nitems_);
230 }
231 
232 /**  Remove every item from the browser.*/
clear()233 void Fl_Check_Browser::clear() {
234 	cb_item *p = first;
235 	cb_item *next;
236 
237 	if (p == 0) {
238 		return;
239 	}
240 
241 	new_list();
242 	do {
243 		next = p->next;
244 		free(p->text);
245 		free(p);
246 		p = next;
247 	} while (p);
248 
249 	first = last = 0;
250 	nitems_ = nchecked_ = 0;
251 	cached_item = -1;
252 }
253 
254 /** Gets the current status of item item. */
checked(int i) const255 int Fl_Check_Browser::checked(int i) const {
256 	cb_item *p = find_item(i);
257 
258 	if (p) return p->checked;
259 	return 0;
260 }
261 
262 /** Sets the check status of item item to b. */
checked(int i,int b)263 void Fl_Check_Browser::checked(int i, int b) {
264 	cb_item *p = find_item(i);
265 
266 	if (p && (p->checked ^ b)) {
267 		p->checked = b;
268 		if (b) {
269 			nchecked_++;
270 		} else {
271 			nchecked_--;
272 		}
273 		redraw();
274 	}
275 }
276 
277 /**  Returns the index of the currently selected item.*/
value() const278 int Fl_Check_Browser::value() const {
279 	return lineno((cb_item *)selection());
280 }
281 
282 /**  Return a pointer to an internal buffer holding item item's text.*/
text(int i) const283 char *Fl_Check_Browser::text(int i) const {
284 	cb_item *p = find_item(i);
285 
286 	if (p) return p->text;
287 	return 0;
288 }
289 
290 /**  Sets all the items checked.*/
check_all()291 void Fl_Check_Browser::check_all() {
292 	cb_item *p;
293 
294 	nchecked_ = nitems_;
295 	for (p = first; p; p = p->next) {
296 		p->checked = 1;
297 	}
298 	redraw();
299 }
300 
301 /**  Sets all the items unchecked.*/
check_none()302 void Fl_Check_Browser::check_none() {
303 	cb_item *p;
304 
305 	nchecked_ = 0;
306 	for (p = first; p; p = p->next) {
307 		p->checked = 0;
308 	}
309 	redraw();
310 }
311 
handle(int event)312 int Fl_Check_Browser::handle(int event) {
313   if (event==FL_PUSH)
314     deselect();
315   return Fl_Browser_::handle(event);
316 }
317 
318 //
319 // End of "$Id$".
320 //
321