]>
Commit | Line | Data |
---|---|---|
1 | /* This goofed-up box whacked into shape by Elliot Lee <sopwith@cuc.edu> | |
2 | (from the original listbox by Erik Troan <ewt@redhat.com>) | |
3 | and contributed to newt for use under the LGPL license. | |
4 | Copyright (C) 1996, 1997 Elliot Lee */ | |
5 | ||
6 | #include <slang.h> | |
7 | #include <stdio.h> | |
8 | #include <stdlib.h> | |
9 | #include <string.h> | |
10 | #include <ctype.h> | |
11 | ||
12 | #include "newt.h" | |
13 | #include "newt_pr.h" | |
14 | ||
15 | ||
16 | /* Linked list of items in the listbox */ | |
17 | struct items { | |
18 | char * text; | |
19 | const void *data; | |
20 | unsigned char isSelected; | |
21 | struct items *next; | |
22 | }; | |
23 | ||
24 | /* Holds all the relevant information for this listbox */ | |
25 | struct listbox { | |
26 | newtComponent sb; /* Scrollbar on right side of listbox */ | |
27 | int curWidth; /* size of text w/o scrollbar or border*/ | |
28 | int curHeight; /* size of text w/o border */ | |
29 | int sbAdjust; | |
30 | int bdxAdjust, bdyAdjust; | |
31 | int numItems, numSelected; | |
32 | int userHasSetWidth; | |
33 | int currItem, startShowItem; /* startShowItem is the first item displayed | |
34 | on the screen */ | |
35 | int isActive; /* If we handle key events all the time, it seems | |
36 | to do things even when they are supposed to be for | |
37 | another button/whatever */ | |
38 | struct items *boxItems; | |
39 | int grow; | |
40 | int flags; /* flags for this listbox, right now just | |
41 | NEWT_FLAG_RETURNEXIT */ | |
42 | }; | |
43 | ||
44 | static void listboxDraw(newtComponent co); | |
45 | static void listboxDestroy(newtComponent co); | |
46 | static struct eventResult listboxEvent(newtComponent co, struct event ev); | |
47 | static void newtListboxRealSetCurrent(newtComponent co); | |
48 | static void listboxPlace(newtComponent co, int newLeft, int newTop); | |
49 | static inline void updateWidth(newtComponent co, struct listbox * li, | |
50 | int maxField); | |
51 | static void listboxMapped(newtComponent co, int isMapped); | |
52 | ||
53 | static struct componentOps listboxOps = { | |
54 | listboxDraw, | |
55 | listboxEvent, | |
56 | listboxDestroy, | |
57 | listboxPlace, | |
58 | listboxMapped, | |
59 | }; | |
60 | ||
61 | static void listboxMapped(newtComponent co, int isMapped) { | |
62 | struct listbox * li = co->data; | |
63 | ||
64 | co->isMapped = isMapped; | |
65 | if (li->sb) | |
66 | li->sb->ops->mapped(li->sb, isMapped); | |
67 | } | |
68 | ||
69 | static void listboxPlace(newtComponent co, int newLeft, int newTop) { | |
70 | struct listbox * li = co->data; | |
71 | ||
72 | co->top = newTop; | |
73 | co->left = newLeft; | |
74 | ||
75 | if (li->sb) | |
76 | li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1, | |
77 | co->top); | |
78 | } | |
79 | ||
80 | newtComponent newtListbox(int left, int top, int height, int flags) { | |
81 | newtComponent co, sb; | |
82 | struct listbox * li; | |
83 | ||
84 | if (!(co = malloc(sizeof(*co)))) | |
85 | return NULL; | |
86 | ||
87 | if (!(li = malloc(sizeof(struct listbox)))) { | |
88 | free(co); | |
89 | return NULL; | |
90 | } | |
91 | ||
92 | li->boxItems = NULL; | |
93 | li->numItems = 0; | |
94 | li->currItem = 0; | |
95 | li->numSelected = 0; | |
96 | li->isActive = 0; | |
97 | li->userHasSetWidth = 0; | |
98 | li->startShowItem = 0; | |
99 | li->sbAdjust = 0; | |
100 | li->bdxAdjust = 0; | |
101 | li->bdyAdjust = 0; | |
102 | li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER | | |
103 | NEWT_FLAG_MULTIPLE); | |
104 | ||
105 | if (li->flags & NEWT_FLAG_BORDER) { | |
106 | li->bdxAdjust = 2; | |
107 | li->bdyAdjust = 1; | |
108 | } | |
109 | ||
110 | co->height = height; | |
111 | li->curHeight = co->height - (2 * li->bdyAdjust); | |
112 | ||
113 | if (height) { | |
114 | li->grow = 0; | |
115 | if (flags & NEWT_FLAG_SCROLL) { | |
116 | sb = newtVerticalScrollbar(left, top + li->bdyAdjust, | |
117 | li->curHeight, | |
118 | COLORSET_LISTBOX, COLORSET_ACTLISTBOX); | |
119 | li->sbAdjust = 3; | |
120 | } else { | |
121 | sb = NULL; | |
122 | } | |
123 | } else { | |
124 | li->grow = 1; | |
125 | sb = NULL; | |
126 | } | |
127 | ||
128 | li->sb = sb; | |
129 | co->data = li; | |
130 | co->isMapped = 0; | |
131 | co->left = left; | |
132 | co->top = top; | |
133 | co->ops = &listboxOps; | |
134 | co->takesFocus = 1; | |
135 | co->callback = NULL; | |
136 | ||
137 | updateWidth(co, li, 5); | |
138 | ||
139 | return co; | |
140 | } | |
141 | ||
142 | static inline void updateWidth(newtComponent co, struct listbox * li, | |
143 | int maxField) { | |
144 | li->curWidth = maxField; | |
145 | co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust; | |
146 | ||
147 | if (li->sb) | |
148 | li->sb->left = co->left + co->width - li->bdxAdjust - 1; | |
149 | } | |
150 | ||
151 | void newtListboxSetCurrentByKey(newtComponent co, void * key) { | |
152 | struct listbox * li = co->data; | |
153 | struct items * item; | |
154 | int i; | |
155 | ||
156 | item = li->boxItems, i = 0; | |
157 | while (item && item->data != key) | |
158 | item = item->next, i++; | |
159 | ||
160 | if (item) | |
161 | newtListboxSetCurrent(co, i); | |
162 | } | |
163 | ||
164 | void newtListboxSetCurrent(newtComponent co, int num) | |
165 | { | |
166 | struct listbox * li = co->data; | |
167 | ||
168 | if (num >= li->numItems) | |
169 | li->currItem = li->numItems - 1; | |
170 | else if (num < 0) | |
171 | li->currItem = 0; | |
172 | else | |
173 | li->currItem = num; | |
174 | ||
175 | if (li->currItem < li->startShowItem) | |
176 | li->startShowItem = li->currItem; | |
177 | else if (li->currItem - li->startShowItem > co->height - 1) | |
178 | li->startShowItem = li->currItem - co->height + 1; | |
179 | if (li->startShowItem + co->height > li->numItems) | |
180 | li->startShowItem = li->numItems - co->height; | |
181 | if(li->startShowItem < 0) | |
182 | li->startShowItem = 0; | |
183 | ||
184 | newtListboxRealSetCurrent(co); | |
185 | } | |
186 | ||
187 | static void newtListboxRealSetCurrent(newtComponent co) | |
188 | { | |
189 | struct listbox * li = co->data; | |
190 | ||
191 | if(li->sb) | |
192 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
193 | listboxDraw(co); | |
194 | if(co->callback) co->callback(co, co->callbackData); | |
195 | } | |
196 | ||
197 | void newtListboxSetWidth(newtComponent co, int width) { | |
198 | struct listbox * li = co->data; | |
199 | ||
200 | co->width = width; | |
201 | li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust; | |
202 | li->userHasSetWidth = 1; | |
203 | if (li->sb) li->sb->left = co->width + co->left - 1; | |
204 | listboxDraw(co); | |
205 | } | |
206 | ||
207 | void * newtListboxGetCurrent(newtComponent co) { | |
208 | struct listbox * li = co->data; | |
209 | int i; | |
210 | struct items *item; | |
211 | ||
212 | for(i = 0, item = li->boxItems; item != NULL && i < li->currItem; | |
213 | i++, item = item->next); | |
214 | ||
215 | if (item) | |
216 | return (void *)item->data; | |
217 | else | |
218 | return NULL; | |
219 | } | |
220 | ||
221 | void newtListboxSelectItem(newtComponent co, const void * key, | |
222 | enum newtFlagsSense sense) | |
223 | { | |
224 | struct listbox * li = co->data; | |
225 | int i; | |
226 | struct items * item; | |
227 | ||
228 | item = li->boxItems, i = 0; | |
229 | while (item && item->data != key) | |
230 | item = item->next, i++; | |
231 | ||
232 | if (!item) return; | |
233 | ||
234 | if (item->isSelected) | |
235 | li->numSelected--; | |
236 | ||
237 | switch(sense) { | |
238 | case NEWT_FLAGS_RESET: | |
239 | item->isSelected = 0; break; | |
240 | case NEWT_FLAGS_SET: | |
241 | item->isSelected = 1; break; | |
242 | case NEWT_FLAGS_TOGGLE: | |
243 | item->isSelected = !item->isSelected; | |
244 | } | |
245 | ||
246 | if (item->isSelected) | |
247 | li->numSelected++; | |
248 | ||
249 | listboxDraw(co); | |
250 | } | |
251 | ||
252 | void newtListboxClearSelection(newtComponent co) | |
253 | { | |
254 | struct items *item; | |
255 | struct listbox * li = co->data; | |
256 | ||
257 | for(item = li->boxItems; item != NULL; | |
258 | item = item->next) | |
259 | item->isSelected = 0; | |
260 | li->numSelected = 0; | |
261 | listboxDraw(co); | |
262 | } | |
263 | ||
264 | /* Free the returned array after use, but NOT the values in the array */ | |
265 | void ** newtListboxGetSelection(newtComponent co, int *numitems) | |
266 | { | |
267 | struct listbox * li; | |
268 | int i; | |
269 | void **retval; | |
270 | struct items *item; | |
271 | ||
272 | if(!co || !numitems) return NULL; | |
273 | ||
274 | li = co->data; | |
275 | if(!li || !li->numSelected) return NULL; | |
276 | ||
277 | retval = malloc(li->numSelected * sizeof(void *)); | |
278 | for(i = 0, item = li->boxItems; item != NULL; | |
279 | item = item->next) | |
280 | if(item->isSelected) | |
281 | retval[i++] = (void *)item->data; | |
282 | *numitems = li->numSelected; | |
283 | return retval; | |
284 | } | |
285 | ||
286 | void newtListboxSetEntry(newtComponent co, int num, const char * text) { | |
287 | struct listbox * li = co->data; | |
288 | int i; | |
289 | struct items *item; | |
290 | ||
291 | for(i = 0, item = li->boxItems; item != NULL && i < num; | |
292 | i++, item = item->next); | |
293 | ||
294 | if(!item) | |
295 | return; | |
296 | else { | |
297 | free(item->text); | |
298 | item->text = strdup(text); | |
299 | } | |
300 | if (li->userHasSetWidth == 0 && strlen(text) > li->curWidth) { | |
301 | updateWidth(co, li, strlen(text)); | |
302 | } | |
303 | ||
304 | if (num >= li->startShowItem && num <= li->startShowItem + co->height) | |
305 | listboxDraw(co); | |
306 | } | |
307 | ||
308 | void newtListboxSetData(newtComponent co, int num, void * data) { | |
309 | struct listbox * li = co->data; | |
310 | int i; | |
311 | struct items *item; | |
312 | ||
313 | for(i = 0, item = li->boxItems; item != NULL && i < num; | |
314 | i++, item = item->next); | |
315 | ||
316 | item->data = data; | |
317 | } | |
318 | ||
319 | int newtListboxAppendEntry(newtComponent co, const char * text, | |
320 | const void * data) { | |
321 | struct listbox * li = co->data; | |
322 | struct items *item; | |
323 | ||
324 | if(li->boxItems) { | |
325 | for (item = li->boxItems; item->next != NULL; item = item->next); | |
326 | ||
327 | item = item->next = malloc(sizeof(struct items)); | |
328 | } else { | |
329 | item = li->boxItems = malloc(sizeof(struct items)); | |
330 | } | |
331 | ||
332 | if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth)) | |
333 | updateWidth(co, li, strlen(text)); | |
334 | ||
335 | item->text = strdup(text); item->data = data; item->next = NULL; | |
336 | item->isSelected = 0; | |
337 | ||
338 | if (li->grow) | |
339 | co->height++, li->curHeight++; | |
340 | li->numItems++; | |
341 | ||
342 | return 0; | |
343 | } | |
344 | ||
345 | int newtListboxInsertEntry(newtComponent co, const char * text, | |
346 | const void * data, void * key) { | |
347 | struct listbox * li = co->data; | |
348 | struct items *item, *t; | |
349 | ||
350 | if (li->boxItems) { | |
351 | if (key) { | |
352 | item = li->boxItems; | |
353 | while (item && item->data != key) item = item->next; | |
354 | ||
355 | if (!item) return 1; | |
356 | ||
357 | t = item->next; | |
358 | item = item->next = malloc(sizeof(struct items)); | |
359 | item->next = t; | |
360 | } else { | |
361 | t = li->boxItems; | |
362 | item = li->boxItems = malloc(sizeof(struct items)); | |
363 | item->next = t; | |
364 | } | |
365 | } else if (key) { | |
366 | return 1; | |
367 | } else { | |
368 | item = li->boxItems = malloc(sizeof(struct items)); | |
369 | item->next = NULL; | |
370 | } | |
371 | ||
372 | if (!li->userHasSetWidth && text && (strlen(text) > li->curWidth)) | |
373 | updateWidth(co, li, strlen(text)); | |
374 | ||
375 | item->text = strdup(text?text:"(null)"); item->data = data; | |
376 | item->isSelected = 0; | |
377 | ||
378 | if (li->sb) | |
379 | li->sb->left = co->left + co->width - li->bdxAdjust - 1; | |
380 | li->numItems++; | |
381 | ||
382 | listboxDraw(co); | |
383 | ||
384 | return 0; | |
385 | } | |
386 | ||
387 | int newtListboxDeleteEntry(newtComponent co, void * key) { | |
388 | struct listbox * li = co->data; | |
389 | int widest = 0, t; | |
390 | struct items *item, *item2 = NULL; | |
391 | int num; | |
392 | ||
393 | if (li->boxItems == NULL || li->numItems <= 0) | |
394 | return 0; | |
395 | ||
396 | num = 0; | |
397 | ||
398 | item2 = NULL, item = li->boxItems; | |
399 | while (item && item->data != key) { | |
400 | item2 = item; | |
401 | item = item->next; | |
402 | num++; | |
403 | } | |
404 | ||
405 | if (!item) | |
406 | return -1; | |
407 | ||
408 | if (item2) | |
409 | item2->next = item->next; | |
410 | else | |
411 | li->boxItems = item->next; | |
412 | ||
413 | free(item->text); | |
414 | free(item); | |
415 | li->numItems--; | |
416 | ||
417 | if (!li->userHasSetWidth) { | |
418 | widest = 0; | |
419 | for (item = li->boxItems; item != NULL; item = item->next) | |
420 | if ((t = strlen(item->text)) > widest) widest = t; | |
421 | } | |
422 | ||
423 | if (li->currItem >= num) | |
424 | li->currItem--; | |
425 | ||
426 | if (!li->userHasSetWidth) { | |
427 | updateWidth(co, li, widest); | |
428 | } | |
429 | ||
430 | listboxDraw(co); | |
431 | ||
432 | return 0; | |
433 | } | |
434 | ||
435 | void newtListboxClear(newtComponent co) | |
436 | { | |
437 | struct listbox * li; | |
438 | struct items *anitem, *nextitem; | |
439 | if(co == NULL || (li = co->data) == NULL) | |
440 | return; | |
441 | for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) { | |
442 | nextitem = anitem->next; | |
443 | free(anitem->text); | |
444 | free(anitem); | |
445 | } | |
446 | li->numItems = li->numSelected = li->currItem = li->startShowItem = 0; | |
447 | li->boxItems = NULL; | |
448 | if (!li->userHasSetWidth) | |
449 | updateWidth(co, li, 5); | |
450 | } | |
451 | ||
452 | /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same | |
453 | goes for the data. */ | |
454 | void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) { | |
455 | struct listbox * li = co->data; | |
456 | int i; | |
457 | struct items *item; | |
458 | ||
459 | if (!li->boxItems || num >= li->numItems) { | |
460 | if(text) | |
461 | *text = NULL; | |
462 | if(data) | |
463 | *data = NULL; | |
464 | return; | |
465 | } | |
466 | ||
467 | i = 0; | |
468 | item = li->boxItems; | |
469 | while (item && i < num) { | |
470 | i++, item = item->next; | |
471 | } | |
472 | ||
473 | if (item) { | |
474 | if (text) | |
475 | *text = item->text; | |
476 | if (data) | |
477 | *data = (void *)item->data; | |
478 | } | |
479 | } | |
480 | ||
481 | static void listboxDraw(newtComponent co) | |
482 | { | |
483 | struct listbox * li = co->data; | |
484 | struct items *item; | |
485 | int i, j; | |
486 | ||
487 | if (!co->isMapped) return ; | |
488 | ||
489 | if(li->flags & NEWT_FLAG_BORDER) { | |
490 | if(li->isActive) | |
491 | SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); | |
492 | else | |
493 | SLsmg_set_color(NEWT_COLORSET_LISTBOX); | |
494 | ||
495 | newtDrawBox(co->left, co->top, co->width, co->height, 0); | |
496 | } | |
497 | ||
498 | if(li->sb) | |
499 | li->sb->ops->draw(li->sb); | |
500 | ||
501 | SLsmg_set_color(NEWT_COLORSET_LISTBOX); | |
502 | ||
503 | for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem; | |
504 | i++, item = item->next); | |
505 | ||
506 | j = i; | |
507 | ||
508 | for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) { | |
509 | if (!item->text) continue; | |
510 | ||
511 | newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust); | |
512 | if(j + i == li->currItem) { | |
513 | if(item->isSelected) | |
514 | SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX); | |
515 | else | |
516 | SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); | |
517 | } else if(item->isSelected) | |
518 | SLsmg_set_color(NEWT_COLORSET_SELLISTBOX); | |
519 | else | |
520 | SLsmg_set_color(NEWT_COLORSET_LISTBOX); | |
521 | ||
522 | SLsmg_write_nstring(item->text, li->curWidth); | |
523 | ||
524 | } | |
525 | newtGotorc(co->top + (li->currItem - li->startShowItem), co->left); | |
526 | } | |
527 | ||
528 | static struct eventResult listboxEvent(newtComponent co, struct event ev) { | |
529 | struct eventResult er; | |
530 | struct listbox * li = co->data; | |
531 | struct items *item; | |
532 | int i; | |
533 | ||
534 | er.result = ER_IGNORED; | |
535 | ||
536 | if(ev.when == EV_EARLY || ev.when == EV_LATE) { | |
537 | return er; | |
538 | } | |
539 | ||
540 | switch(ev.event) { | |
541 | case EV_KEYPRESS: | |
542 | if (!li->isActive) break; | |
543 | ||
544 | switch(ev.u.key) { | |
545 | case ' ': | |
546 | if(!(li->flags & NEWT_FLAG_MULTIPLE)) break; | |
547 | newtListboxSelectItem(co, li->boxItems[li->currItem].data, | |
548 | NEWT_FLAGS_TOGGLE); | |
549 | er.result = ER_SWALLOWED; | |
550 | /* We don't break here, because it is cool to be able to | |
551 | hold space to select a bunch of items in a list at once */ | |
552 | ||
553 | case NEWT_KEY_DOWN: | |
554 | if(li->numItems <= 0) break; | |
555 | if(li->currItem < li->numItems - 1) { | |
556 | li->currItem++; | |
557 | if(li->currItem > (li->startShowItem + li->curHeight - 1)) { | |
558 | li->startShowItem = li->currItem - li->curHeight + 1; | |
559 | if(li->startShowItem + li->curHeight > li->numItems) | |
560 | li->startShowItem = li->numItems - li->curHeight; | |
561 | } | |
562 | if(li->sb) | |
563 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
564 | listboxDraw(co); | |
565 | } | |
566 | if(co->callback) co->callback(co, co->callbackData); | |
567 | er.result = ER_SWALLOWED; | |
568 | break; | |
569 | ||
570 | case NEWT_KEY_ENTER: | |
571 | if(li->numItems <= 0) break; | |
572 | if(li->flags & NEWT_FLAG_RETURNEXIT) | |
573 | er.result = ER_EXITFORM; | |
574 | break; | |
575 | ||
576 | case NEWT_KEY_UP: | |
577 | if(li->numItems <= 0) break; | |
578 | if(li->currItem > 0) { | |
579 | li->currItem--; | |
580 | if(li->currItem < li->startShowItem) | |
581 | li->startShowItem = li->currItem; | |
582 | if(li->sb) | |
583 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
584 | listboxDraw(co); | |
585 | } | |
586 | if(co->callback) co->callback(co, co->callbackData); | |
587 | er.result = ER_SWALLOWED; | |
588 | break; | |
589 | ||
590 | case NEWT_KEY_PGUP: | |
591 | if(li->numItems <= 0) break; | |
592 | li->startShowItem -= li->curHeight - 1; | |
593 | if(li->startShowItem < 0) | |
594 | li->startShowItem = 0; | |
595 | li->currItem -= li->curHeight - 1; | |
596 | if(li->currItem < 0) | |
597 | li->currItem = 0; | |
598 | newtListboxRealSetCurrent(co); | |
599 | er.result = ER_SWALLOWED; | |
600 | break; | |
601 | ||
602 | case NEWT_KEY_PGDN: | |
603 | if(li->numItems <= 0) break; | |
604 | li->startShowItem += li->curHeight; | |
605 | if(li->startShowItem > (li->numItems - li->curHeight)) { | |
606 | li->startShowItem = li->numItems - li->curHeight; | |
607 | } | |
608 | li->currItem += li->curHeight; | |
609 | if(li->currItem >= li->numItems) { | |
610 | li->currItem = li->numItems - 1; | |
611 | } | |
612 | newtListboxRealSetCurrent(co); | |
613 | er.result = ER_SWALLOWED; | |
614 | break; | |
615 | ||
616 | case NEWT_KEY_HOME: | |
617 | if(li->numItems <= 0) break; | |
618 | newtListboxSetCurrent(co, 0); | |
619 | er.result = ER_SWALLOWED; | |
620 | break; | |
621 | ||
622 | case NEWT_KEY_END: | |
623 | if(li->numItems <= 0) break; | |
624 | li->startShowItem = li->numItems - li->curHeight; | |
625 | if(li->startShowItem < 0) | |
626 | li->startShowItem = 0; | |
627 | li->currItem = li->numItems - 1; | |
628 | newtListboxRealSetCurrent(co); | |
629 | er.result = ER_SWALLOWED; | |
630 | break; | |
631 | default: | |
632 | if (isalpha(ev.u.key)) { | |
633 | ||
634 | for(i = 0, item = li->boxItems; item != NULL && | |
635 | i < li->currItem; i++, item = item->next); | |
636 | ||
637 | if (item->text && (toupper(*item->text) == toupper(ev.u.key))) { | |
638 | item = item->next; | |
639 | i++; | |
640 | } else { | |
641 | item = li->boxItems; | |
642 | i = 0; | |
643 | } | |
644 | while (item && item->text && | |
645 | toupper(*item->text) != toupper(ev.u.key)) { | |
646 | item = item->next; | |
647 | i++; | |
648 | } | |
649 | if (item) { | |
650 | li->currItem = i; | |
651 | if(li->currItem < li->startShowItem || | |
652 | li->currItem > li->startShowItem) | |
653 | li->startShowItem = | |
654 | li->currItem > li->numItems - li->curHeight ? | |
655 | li->startShowItem = li->numItems - li->curHeight : | |
656 | li->currItem; | |
657 | if(li->sb) | |
658 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
659 | newtListboxRealSetCurrent(co); | |
660 | er.result = ER_SWALLOWED; | |
661 | } | |
662 | } | |
663 | } | |
664 | break; | |
665 | ||
666 | case EV_FOCUS: | |
667 | li->isActive = 1; | |
668 | listboxDraw(co); | |
669 | er.result = ER_SWALLOWED; | |
670 | break; | |
671 | ||
672 | case EV_UNFOCUS: | |
673 | li->isActive = 0; | |
674 | listboxDraw(co); | |
675 | er.result = ER_SWALLOWED; | |
676 | break; | |
677 | ||
678 | case EV_MOUSE: | |
679 | /* if this mouse click was within the listbox, make the current | |
680 | item the item clicked on. */ | |
681 | /* Up scroll arrow */ | |
682 | if (li->sb && | |
683 | ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 && | |
684 | ev.u.mouse.y == co->top + li->bdyAdjust) { | |
685 | if(li->numItems <= 0) break; | |
686 | if(li->currItem > 0) { | |
687 | li->currItem--; | |
688 | if(li->currItem < li->startShowItem) | |
689 | li->startShowItem = li->currItem; | |
690 | if(li->sb) | |
691 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
692 | listboxDraw(co); | |
693 | } | |
694 | if(co->callback) co->callback(co, co->callbackData); | |
695 | er.result = ER_SWALLOWED; | |
696 | break; | |
697 | } | |
698 | /* Down scroll arrow */ | |
699 | if (li->sb && | |
700 | ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 && | |
701 | ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) { | |
702 | if(li->numItems <= 0) break; | |
703 | if(li->currItem < li->numItems - 1) { | |
704 | li->currItem++; | |
705 | if(li->currItem > (li->startShowItem + li->curHeight - 1)) { | |
706 | li->startShowItem = li->currItem - li->curHeight + 1; | |
707 | if(li->startShowItem + li->curHeight > li->numItems) | |
708 | li->startShowItem = li->numItems - li->curHeight; | |
709 | } | |
710 | if(li->sb) | |
711 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
712 | listboxDraw(co); | |
713 | } | |
714 | if(co->callback) co->callback(co, co->callbackData); | |
715 | er.result = ER_SWALLOWED; | |
716 | break; | |
717 | } | |
718 | if ((ev.u.mouse.y >= co->top + li->bdyAdjust) && | |
719 | (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) && | |
720 | (ev.u.mouse.x >= co->left + li->bdxAdjust) && | |
721 | (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) { | |
722 | li->currItem = li->startShowItem + | |
723 | (ev.u.mouse.y - li->bdyAdjust - co->top); | |
724 | newtListboxRealSetCurrent(co); | |
725 | listboxDraw(co); | |
726 | if(co->callback) co->callback(co, co->callbackData); | |
727 | er.result = ER_SWALLOWED; | |
728 | break; | |
729 | } | |
730 | } | |
731 | ||
732 | return er; | |
733 | } | |
734 | ||
735 | static void listboxDestroy(newtComponent co) { | |
736 | struct listbox * li = co->data; | |
737 | struct items * item, * nextitem; | |
738 | ||
739 | nextitem = item = li->boxItems; | |
740 | ||
741 | while (item != NULL) { | |
742 | nextitem = item->next; | |
743 | free(item->text); | |
744 | free(item); | |
745 | item = nextitem; | |
746 | } | |
747 | ||
748 | free(li); | |
749 | free(co); | |
750 | } |