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 */
16 /* Linked list of items in the listbox */
20 unsigned char isSelected
;
24 /* Holds all the relevant information for this 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 */
30 int bdxAdjust
, bdyAdjust
;
31 int numItems
, numSelected
;
33 int currItem
, startShowItem
; /* startShowItem is the first item displayed
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
;
40 int flags
; /* flags for this listbox, right now just
41 NEWT_FLAG_RETURNEXIT */
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
,
51 static void listboxMapped(newtComponent co
, int isMapped
);
53 static struct componentOps listboxOps
= {
61 static void listboxMapped(newtComponent co
, int isMapped
) {
62 struct listbox
* li
= co
->data
;
64 co
->isMapped
= isMapped
;
66 li
->sb
->ops
->mapped(li
->sb
, isMapped
);
69 static void listboxPlace(newtComponent co
, int newLeft
, int newTop
) {
70 struct listbox
* li
= co
->data
;
76 li
->sb
->ops
->place(li
->sb
, co
->left
+ co
->width
- li
->bdxAdjust
- 1,
80 newtComponent
newtListbox(int left
, int top
, int height
, int flags
) {
84 if (!(co
= malloc(sizeof(*co
))))
87 if (!(li
= malloc(sizeof(struct listbox
)))) {
97 li
->userHasSetWidth
= 0;
98 li
->startShowItem
= 0;
102 li
->flags
= flags
& (NEWT_FLAG_RETURNEXIT
| NEWT_FLAG_BORDER
|
105 if (li
->flags
& NEWT_FLAG_BORDER
) {
111 li
->curHeight
= co
->height
- (2 * li
->bdyAdjust
);
115 if (flags
& NEWT_FLAG_SCROLL
) {
116 sb
= newtVerticalScrollbar(left
, top
+ li
->bdyAdjust
,
118 COLORSET_LISTBOX
, COLORSET_ACTLISTBOX
);
133 co
->ops
= &listboxOps
;
137 updateWidth(co
, li
, 5);
142 static inline void updateWidth(newtComponent co
, struct listbox
* li
,
144 li
->curWidth
= maxField
;
145 co
->width
= li
->curWidth
+ li
->sbAdjust
+ 2 * li
->bdxAdjust
;
148 li
->sb
->left
= co
->left
+ co
->width
- li
->bdxAdjust
- 1;
151 void newtListboxSetCurrentByKey(newtComponent co
, void * key
) {
152 struct listbox
* li
= co
->data
;
156 item
= li
->boxItems
, i
= 0;
157 while (item
&& item
->data
!= key
)
158 item
= item
->next
, i
++;
161 newtListboxSetCurrent(co
, i
);
164 void newtListboxSetCurrent(newtComponent co
, int num
)
166 struct listbox
* li
= co
->data
;
168 if (num
>= li
->numItems
)
169 li
->currItem
= li
->numItems
- 1;
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;
184 newtListboxRealSetCurrent(co
);
187 static void newtListboxRealSetCurrent(newtComponent co
)
189 struct listbox
* li
= co
->data
;
192 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
194 if(co
->callback
) co
->callback(co
, co
->callbackData
);
197 void newtListboxSetWidth(newtComponent co
, int width
) {
198 struct listbox
* li
= co
->data
;
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;
207 void * newtListboxGetCurrent(newtComponent co
) {
208 struct listbox
* li
= co
->data
;
212 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->currItem
;
213 i
++, item
= item
->next
);
216 return (void *)item
->data
;
221 void newtListboxSelectItem(newtComponent co
, const void * key
,
222 enum newtFlagsSense sense
)
224 struct listbox
* li
= co
->data
;
228 item
= li
->boxItems
, i
= 0;
229 while (item
&& item
->data
!= key
)
230 item
= item
->next
, i
++;
234 if (item
->isSelected
)
238 case NEWT_FLAGS_RESET
:
239 item
->isSelected
= 0; break;
241 item
->isSelected
= 1; break;
242 case NEWT_FLAGS_TOGGLE
:
243 item
->isSelected
= !item
->isSelected
;
246 if (item
->isSelected
)
252 void newtListboxClearSelection(newtComponent co
)
255 struct listbox
* li
= co
->data
;
257 for(item
= li
->boxItems
; item
!= NULL
;
259 item
->isSelected
= 0;
264 /* Free the returned array after use, but NOT the values in the array */
265 void ** newtListboxGetSelection(newtComponent co
, int *numitems
)
272 if(!co
|| !numitems
) return NULL
;
275 if(!li
|| !li
->numSelected
) return NULL
;
277 retval
= malloc(li
->numSelected
* sizeof(void *));
278 for(i
= 0, item
= li
->boxItems
; item
!= NULL
;
281 retval
[i
++] = (void *)item
->data
;
282 *numitems
= li
->numSelected
;
286 void newtListboxSetEntry(newtComponent co
, int num
, const char * text
) {
287 struct listbox
* li
= co
->data
;
291 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
292 i
++, item
= item
->next
);
298 item
->text
= strdup(text
);
300 if (li
->userHasSetWidth
== 0 && strlen(text
) > li
->curWidth
) {
301 updateWidth(co
, li
, strlen(text
));
304 if (num
>= li
->startShowItem
&& num
<= li
->startShowItem
+ co
->height
)
308 void newtListboxSetData(newtComponent co
, int num
, void * data
) {
309 struct listbox
* li
= co
->data
;
313 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
314 i
++, item
= item
->next
);
319 int newtListboxAppendEntry(newtComponent co
, const char * text
,
321 struct listbox
* li
= co
->data
;
325 for (item
= li
->boxItems
; item
->next
!= NULL
; item
= item
->next
);
327 item
= item
->next
= malloc(sizeof(struct items
));
329 item
= li
->boxItems
= malloc(sizeof(struct items
));
332 if (!li
->userHasSetWidth
&& text
&& (strlen(text
) > li
->curWidth
))
333 updateWidth(co
, li
, strlen(text
));
335 item
->text
= strdup(text
); item
->data
= data
; item
->next
= NULL
;
336 item
->isSelected
= 0;
339 co
->height
++, li
->curHeight
++;
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
;
353 while (item
&& item
->data
!= key
) item
= item
->next
;
358 item
= item
->next
= malloc(sizeof(struct items
));
362 item
= li
->boxItems
= malloc(sizeof(struct items
));
368 item
= li
->boxItems
= malloc(sizeof(struct items
));
372 if (!li
->userHasSetWidth
&& text
&& (strlen(text
) > li
->curWidth
))
373 updateWidth(co
, li
, strlen(text
));
375 item
->text
= strdup(text
?text
:"(null)"); item
->data
= data
;
376 item
->isSelected
= 0;
379 li
->sb
->left
= co
->left
+ co
->width
- li
->bdxAdjust
- 1;
387 int newtListboxDeleteEntry(newtComponent co
, void * key
) {
388 struct listbox
* li
= co
->data
;
390 struct items
*item
, *item2
= NULL
;
393 if (li
->boxItems
== NULL
|| li
->numItems
<= 0)
398 item2
= NULL
, item
= li
->boxItems
;
399 while (item
&& item
->data
!= key
) {
409 item2
->next
= item
->next
;
411 li
->boxItems
= item
->next
;
417 if (!li
->userHasSetWidth
) {
419 for (item
= li
->boxItems
; item
!= NULL
; item
= item
->next
)
420 if ((t
= strlen(item
->text
)) > widest
) widest
= t
;
423 if (li
->currItem
>= num
)
426 if (!li
->userHasSetWidth
) {
427 updateWidth(co
, li
, widest
);
435 void newtListboxClear(newtComponent co
)
438 struct items
*anitem
, *nextitem
;
439 if(co
== NULL
|| (li
= co
->data
) == NULL
)
441 for(anitem
= li
->boxItems
; anitem
!= NULL
; anitem
= nextitem
) {
442 nextitem
= anitem
->next
;
446 li
->numItems
= li
->numSelected
= li
->currItem
= li
->startShowItem
= 0;
448 if (!li
->userHasSetWidth
)
449 updateWidth(co
, li
, 5);
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
;
459 if (!li
->boxItems
|| num
>= li
->numItems
) {
469 while (item
&& i
< num
) {
470 i
++, item
= item
->next
;
477 *data
= (void *)item
->data
;
481 static void listboxDraw(newtComponent co
)
483 struct listbox
* li
= co
->data
;
487 if (!co
->isMapped
) return ;
489 if(li
->flags
& NEWT_FLAG_BORDER
) {
491 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
493 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
495 newtDrawBox(co
->left
, co
->top
, co
->width
, co
->height
, 0);
499 li
->sb
->ops
->draw(li
->sb
);
501 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
503 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->startShowItem
;
504 i
++, item
= item
->next
);
508 for (i
= 0; item
!= NULL
&& i
< li
->curHeight
; i
++, item
= item
->next
) {
509 if (!item
->text
) continue;
511 newtGotorc(co
->top
+ i
+ li
->bdyAdjust
, co
->left
+ li
->bdxAdjust
);
512 if(j
+ i
== li
->currItem
) {
514 SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX
);
516 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
517 } else if(item
->isSelected
)
518 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
520 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
522 SLsmg_write_nstring(item
->text
, li
->curWidth
);
525 newtGotorc(co
->top
+ (li
->currItem
- li
->startShowItem
), co
->left
);
528 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
) {
529 struct eventResult er
;
530 struct listbox
* li
= co
->data
;
534 er
.result
= ER_IGNORED
;
536 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
542 if (!li
->isActive
) break;
546 if(!(li
->flags
& NEWT_FLAG_MULTIPLE
)) break;
547 newtListboxSelectItem(co
, li
->boxItems
[li
->currItem
].data
,
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 */
554 if(li
->numItems
<= 0) break;
555 if(li
->currItem
< li
->numItems
- 1) {
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
;
563 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
566 if(co
->callback
) co
->callback(co
, co
->callbackData
);
567 er
.result
= ER_SWALLOWED
;
571 if(li
->numItems
<= 0) break;
572 if(li
->flags
& NEWT_FLAG_RETURNEXIT
)
573 er
.result
= ER_EXITFORM
;
577 if(li
->numItems
<= 0) break;
578 if(li
->currItem
> 0) {
580 if(li
->currItem
< li
->startShowItem
)
581 li
->startShowItem
= li
->currItem
;
583 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
586 if(co
->callback
) co
->callback(co
, co
->callbackData
);
587 er
.result
= ER_SWALLOWED
;
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;
598 newtListboxRealSetCurrent(co
);
599 er
.result
= ER_SWALLOWED
;
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
;
608 li
->currItem
+= li
->curHeight
;
609 if(li
->currItem
>= li
->numItems
) {
610 li
->currItem
= li
->numItems
- 1;
612 newtListboxRealSetCurrent(co
);
613 er
.result
= ER_SWALLOWED
;
617 if(li
->numItems
<= 0) break;
618 newtListboxSetCurrent(co
, 0);
619 er
.result
= ER_SWALLOWED
;
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
;
632 if (ev
.u
.key
< NEWT_KEY_EXTRA_BASE
&& isalpha(ev
.u
.key
)) {
633 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&&
634 i
< li
->currItem
; i
++, item
= item
->next
);
636 if (item
->text
&& (toupper(*item
->text
) == toupper(ev
.u
.key
))) {
643 while (item
&& item
->text
&&
644 toupper(*item
->text
) != toupper(ev
.u
.key
)) {
650 if(li
->currItem
< li
->startShowItem
||
651 li
->currItem
> li
->startShowItem
)
653 li
->currItem
> li
->numItems
- li
->curHeight
?
654 li
->startShowItem
= li
->numItems
- li
->curHeight
:
657 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
658 newtListboxRealSetCurrent(co
);
659 er
.result
= ER_SWALLOWED
;
668 er
.result
= ER_SWALLOWED
;
674 er
.result
= ER_SWALLOWED
;
678 /* if this mouse click was within the listbox, make the current
679 item the item clicked on. */
680 /* Up scroll arrow */
682 ev
.u
.mouse
.x
== co
->left
+ co
->width
- li
->bdxAdjust
- 1 &&
683 ev
.u
.mouse
.y
== co
->top
+ li
->bdyAdjust
) {
684 if(li
->numItems
<= 0) break;
685 if(li
->currItem
> 0) {
687 if(li
->currItem
< li
->startShowItem
)
688 li
->startShowItem
= li
->currItem
;
690 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
693 if(co
->callback
) co
->callback(co
, co
->callbackData
);
694 er
.result
= ER_SWALLOWED
;
697 /* Down scroll arrow */
699 ev
.u
.mouse
.x
== co
->left
+ co
->width
- li
->bdxAdjust
- 1 &&
700 ev
.u
.mouse
.y
== co
->top
+ co
->height
- li
->bdyAdjust
- 1) {
701 if(li
->numItems
<= 0) break;
702 if(li
->currItem
< li
->numItems
- 1) {
704 if(li
->currItem
> (li
->startShowItem
+ li
->curHeight
- 1)) {
705 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
706 if(li
->startShowItem
+ li
->curHeight
> li
->numItems
)
707 li
->startShowItem
= li
->numItems
- li
->curHeight
;
710 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
713 if(co
->callback
) co
->callback(co
, co
->callbackData
);
714 er
.result
= ER_SWALLOWED
;
717 if ((ev
.u
.mouse
.y
>= co
->top
+ li
->bdyAdjust
) &&
718 (ev
.u
.mouse
.y
<= co
->top
+ co
->height
- (li
->bdyAdjust
* 2)) &&
719 (ev
.u
.mouse
.x
>= co
->left
+ li
->bdxAdjust
) &&
720 (ev
.u
.mouse
.x
<= co
->left
+ co
->width
+ (li
->bdxAdjust
* 2))) {
721 li
->currItem
= li
->startShowItem
+
722 (ev
.u
.mouse
.y
- li
->bdyAdjust
- co
->top
);
723 newtListboxRealSetCurrent(co
);
725 if(co
->callback
) co
->callback(co
, co
->callbackData
);
726 er
.result
= ER_SWALLOWED
;
734 static void listboxDestroy(newtComponent co
) {
735 struct listbox
* li
= co
->data
;
736 struct items
* item
, * nextitem
;
738 nextitem
= item
= li
->boxItems
;
740 while (item
!= NULL
) {
741 nextitem
= item
->next
;
747 if (li
->sb
) li
->sb
->ops
->destroy(li
->sb
);