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