1 #include <cstring>
2 #include <cstdlib>
3 #include <FL/Fl.H>
4 #include <FL/fl_draw.H>
5 
6 #include "combo.h"
7 
8 void popbrwsr_cb (Fl_Widget *v, long d);
9 
Fl_PopBrowser(int X,int Y,int W,int H,retvals R)10 Fl_PopBrowser::Fl_PopBrowser (int X, int Y, int W, int H, retvals R)
11  : Fl_Window (X, Y, W, H, "")
12 {
13 	Rvals = R;
14 	hRow  = H;
15 	wRow  = W;
16 	clear_border();
17 	box(FL_BORDER_BOX);
18 	popbrwsr = new Fl_Select_Browser(0,0,wRow,hRow,0);
19 	popbrwsr->callback ( (Fl_Callback*)popbrwsr_cb);
20 	parent = 0;
21 	end();
22 	set_modal();
23 }
24 
~Fl_PopBrowser()25 Fl_PopBrowser::~Fl_PopBrowser ()
26 {
27 }
28 
handle(int event)29 int Fl_PopBrowser::handle(int event)
30 {
31 	if (!Fl::event_inside( child(0) ) && event == FL_PUSH) {
32 		pophide();
33 		return 1;
34  	}
35 	return Fl_Group::handle(event);
36 }
37 
add(char * s,void * d)38 void Fl_PopBrowser::add(char *s, void *d)
39 {
40 	popbrwsr->add(s,d);
41 }
42 
clear()43 void Fl_PopBrowser::clear()
44 {
45 	popbrwsr->clear();
46 }
47 
sort()48 void Fl_PopBrowser::sort()
49 {
50 	return;
51 }
52 
popshow(int x,int y)53 void Fl_PopBrowser::popshow (int x, int y)
54 {
55 	int nRows = parent->numrows();
56 	int fh = fl_height();
57 	int height = nRows * fh + 4;
58 
59 	if (popbrwsr->size() == 0) return;
60 	if (nRows > parent->lsize()) nRows = parent->lsize();
61 
62 // locate first occurance of Output string value in the list
63 // and display that if found
64 	int i = parent->index();
65 	if (!(i >= 0 && i < parent->listsize)) {
66 		for (i = 0; i < parent->listsize; i++)
67 			if (!strcmp(parent->Output->value(), parent->datalist[i]->s))
68 				break;
69 		if (i == parent->listsize)
70 			i = 0;
71 	}
72 
73 // resize and reposition the popup to insure that it is within the bounds
74 // of the uppermost parent widget
75 // preferred position is just below and at the same x position as the
76 // parent widget
77 
78 	Fl_Widget *gparent = parent;
79 	int	xp = gparent->x(),
80 		yp = gparent->y(),
81 		hp = gparent->h();
82 	while ((gparent = gparent->parent())) {
83 		xp = gparent->x();
84 		yp = gparent->y();
85 		hp = gparent->h();
86 	}
87 
88 	int nu = nRows, nl = nRows;
89 	int hu = nu * fh + 4, hl = nl * fh + 4;
90 	int yu = parent->y() - hu;
91 	int yl = y;
92 
93 	while (nl > 1 && (yl + hl > hp)) { nl--; hl -= fh; }
94 	while (nu > 1 && yu < 0) { nu--; yu += fh; hu -= fh; }
95 
96 	if (nl >= nu) { y = yl; height = hl; }
97 	else { y = yu; height = hu; }
98 
99 	x += xp;
100 	y += yp;
101 
102 	popbrwsr->size (wRow, height);
103 	resize (x, y, wRow, height);
104 
105 	popbrwsr->topline (i);
106 	show();
107 
108 	Fl::grab(this);
109 }
110 
pophide()111 void Fl_PopBrowser::pophide ()
112 {
113 	hide ();
114 	Fl::release();
115 }
116 
popbrwsr_cb_i(Fl_Widget * v,long d)117 void Fl_PopBrowser::popbrwsr_cb_i (Fl_Widget *v, long d)
118 {
119 	Fl_PopBrowser *me = (Fl_PopBrowser *)(v->parent());
120 	Fl_Input *tgt = me->Rvals.Inp;
121 // update the return values
122 	int row = (me->popbrwsr)->value();
123 	if (row == 0) return;
124 	me->popbrwsr->deselect();
125 
126 	if (tgt) {
127 		tgt->value ((me->popbrwsr)->text (row));
128 		me->Rvals.retval = (me->popbrwsr)->data (row);
129 		*(me->Rvals.idx) = row - 1;
130 	}
131 	me->pophide();
132 // user selected an item from the browser list, so execute the
133 // callback if one is registered.
134 	if (me->parent)
135 		(me->parent)->do_callback();
136 	return;
137 }
138 
popbrwsr_cb(Fl_Widget * v,long d)139 void popbrwsr_cb (Fl_Widget *v, long d)
140 {
141 	((Fl_PopBrowser *)(v))->popbrwsr_cb_i (v, d);
142 	return;
143 }
144 
145 
fl_popbrwsr(Fl_Widget * p)146 void Fl_ComboBox::fl_popbrwsr(Fl_Widget *p)
147 {
148 	int xpos = p->x(), ypos = p->h() + p->y();
149 	if (Brwsr == 0) {
150 		Brwsr = new Fl_PopBrowser(xpos, ypos, width, height, R);
151 	}
152 // pass the calling widget to the popup browser so that the
153 // correct callback function can be called when the user selects an item
154 // from the browser list
155 	Brwsr->parent = (Fl_ComboBox *) p;
156 	Brwsr->popshow(xpos, ypos);
157 	return;
158 }
159 
btnComboBox_cb(Fl_Widget * v,void * d)160 void btnComboBox_cb (Fl_Widget *v, void *d)
161 {
162 	Fl_Widget *p = v->parent();
163 	((Fl_ComboBox *)p)->fl_popbrwsr (p);
164 	return;
165 }
166 
167 
Fl_ComboBox(int X,int Y,int W,int H,const char * L)168 Fl_ComboBox::Fl_ComboBox (int X,int Y,int W,int H, const char *L)
169  : Fl_Group (X, Y, W, H, L)
170 {
171 	width = W; height = H - 4;
172 	Btn = new Fl_Button (X + W - 18, Y + 1, 18, H - 2, "@#-32>");
173 	Btn->callback ((Fl_Callback *)btnComboBox_cb, 0);
174 	Output = new Fl_Input (X, Y, W-18, H);
175 
176 	Brwsr = 0;
177 	datalist = new datambr *[FL_COMBO_LIST_INCR];
178 	maxsize = FL_COMBO_LIST_INCR;
179 	for (int i = 0; i < FL_COMBO_LIST_INCR; i++) datalist[i] = 0;
180 	listsize = 0;
181 	listtype = 0;
182 	end();
183 	R.Inp = Output;
184 	R.retval = retdata;
185 	R.idx = &idx;
186 	numrows_ = 8;
187 }
188 
~Fl_ComboBox()189 Fl_ComboBox::~Fl_ComboBox()
190 {
191 	if (Brwsr) delete Brwsr;
192 	for (int i = 0; i < listsize; i++) {
193 		if (datalist[i]) {
194 			if (datalist[i]->s) delete [] datalist[i]->s;
195 			delete datalist[i];
196 		}
197 	}
198 	delete [] datalist;
199 }
200 
type(int t)201 void Fl_ComboBox::type (int t)
202 {
203 	listtype = t;
204 }
205 
readonly()206 void Fl_ComboBox::readonly()
207 {
208 	Output->type(FL_NORMAL_OUTPUT);
209 }
210 
211 // ComboBox value is contained in the Output widget
212 
value(const char * s)213 void Fl_ComboBox::value( const char *s )
214 {
215 	int i;
216 	if ((listtype & FL_COMBO_UNIQUE_NOCASE) == FL_COMBO_UNIQUE_NOCASE) {
217 		for (i = 0; i < listsize; i++) {
218 			if (strcasecmp (s, datalist[i]->s) == 0)
219 				break;
220 		}
221 	} else {
222 		for (i = 0; i < listsize; i++) {
223 			if (strcmp (s, datalist[i]->s) == 0)
224 				break;
225 		}
226 	}
227 	if ( i < listsize)
228 		Output->value(datalist[i]->s);
229 }
230 
put_value(const char * s)231 void Fl_ComboBox::put_value(const char *s)
232 {
233 	value(s);
234 }
235 
index(int i)236 void Fl_ComboBox::index(int i)
237 {
238 	if (i >= 0 && i < listsize)
239 		Output->value( datalist[idx = i]->s);
240 }
241 
242 
value()243 const char *Fl_ComboBox::value()
244 {
245 	return (Output->value ());
246 }
247 
index()248 int Fl_ComboBox::index() {
249 	return idx;
250 }
251 
data()252 void * Fl_ComboBox::data() {
253 	return retdata;
254 }
255 
add(const char * s,void * d)256 void Fl_ComboBox::add( const char *s, void * d)
257 {
258 	if (Brwsr == 0) {
259 		Brwsr = new Fl_PopBrowser(0, 0, width, height, R);
260 	}
261 // test for uniqueness of entry if required
262 	if ((listtype & FL_COMBO_UNIQUE) == FL_COMBO_UNIQUE) {
263 		if ((listtype & FL_COMBO_UNIQUE_NOCASE) == FL_COMBO_UNIQUE_NOCASE) {
264 			for (int i = 0; i < listsize; i++) {
265 				if (strcasecmp (s, datalist[i]->s) == 0)
266 				return;
267 			}
268 		} else {
269 			for (int i = 0; i < listsize; i++) {
270 				if (strcmp (s, datalist[i]->s) == 0)
271 				return;
272 			}
273 		}
274 	}
275 // not unique or not in list, so add this entry
276 	datalist[listsize] = new datambr;
277 	datalist[listsize]->s = new char [strlen(s) + 1];
278 	datalist[listsize]->s[0] = 0;
279 	strcpy (datalist[listsize]->s, s);
280 	datalist[listsize]->d = d;
281 	Brwsr->add(datalist[listsize]->s,d);
282 	listsize++;
283 	if (listsize == maxsize) {
284 		int nusize = maxsize + FL_COMBO_LIST_INCR;
285 		datambr **temparray = new datambr *[nusize];
286 		for (int i = 0; i < listsize; i++)	temparray[i] = datalist[i];
287 		delete [] datalist;
288 		datalist = temparray;
289 		maxsize = nusize;
290 	}
291 }
292 
clear()293 void Fl_ComboBox::clear()
294 {
295 	if (Brwsr == 0)
296 		Brwsr = new Fl_PopBrowser(0, 0, width, height, R);
297 	else
298 		Brwsr->clear();
299 
300 	if (listsize == 0) return;
301 	for (int i = 0; i < listsize; i++) {
302 		delete [] datalist[i]->s;
303 		delete datalist[i];
304 	}
305 	listsize = 0;
306 }
307 
DataCompare(const void * x1,const void * x2)308 int DataCompare( const void *x1, const void *x2 )
309 {
310 	int cmp;
311 	datambr *X1, *X2;
312 	X1 = *(datambr **)(x1);
313 	X2 = *(datambr **)(x2);
314 	cmp = strcasecmp (X1->s, X2->s);
315 	if (cmp < 0)
316 		return -1;
317 	if (cmp > 0)
318 		return 1;
319 	return 0;
320 }
321 
sort()322 void Fl_ComboBox::sort() {
323 	Brwsr->clear ();
324 	qsort (&datalist[0],
325 		 listsize,
326 		 sizeof (datambr *),
327 		 DataCompare);
328 	for (int i = 0; i < listsize; i++)
329 		Brwsr->add (datalist[i]->s, datalist[i]->d);
330 }
331 
textfont(int fnt)332 void Fl_ComboBox::textfont (int fnt)
333 {
334 	Output->textfont (fnt);
335 }
336 
textsize(uchar n)337 void Fl_ComboBox::textsize (uchar n)
338 {
339 	Output->textsize (n);
340 }
341 
textcolor(Fl_Color c)342 void Fl_ComboBox::textcolor( Fl_Color c)
343 {
344 	Output->textcolor (c);
345 }
346 
color(Fl_Color c)347 void Fl_ComboBox::color(Fl_Color c)
348 {
349 	_color = c;
350 	Output->color(c);
351 	if (Brwsr) Brwsr->color(c);
352 }
353 
354 
355 
356