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
|
103 NEWT_FLAG_MULTIPLE
| NEWT_FLAG_SHOWCURSOR
);
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
> li
->curHeight
- 1)
178 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
179 if (li
->startShowItem
+ li
->curHeight
> li
->numItems
)
180 li
->startShowItem
= li
->numItems
- li
->curHeight
;
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 && wstrlen(text
,-1) > li
->curWidth
) {
301 updateWidth(co
, li
, wstrlen(text
,-1));
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
&& (wstrlen(text
,-1) > li
->curWidth
))
333 updateWidth(co
, li
, wstrlen(text
,-1));
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
&& (wstrlen(text
,-1) > li
->curWidth
))
373 updateWidth(co
, li
, wstrlen(text
,-1));
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
= wstrlen(item
->text
,-1)) > 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 int newtListboxItemCount(newtComponent co
)
454 struct listbox
*li
= co
->data
;
458 /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
459 goes for the data. */
460 void newtListboxGetEntry(newtComponent co
, int num
, char **text
, void **data
) {
461 struct listbox
* li
= co
->data
;
465 if (!li
->boxItems
|| num
>= li
->numItems
) {
475 while (item
&& i
< num
) {
476 i
++, item
= item
->next
;
483 *data
= (void *)item
->data
;
487 static void listboxDraw(newtComponent co
)
489 struct listbox
* li
= co
->data
;
493 if (!co
->isMapped
) return ;
497 if(li
->flags
& NEWT_FLAG_BORDER
) {
499 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
501 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
503 newtDrawBox(co
->left
, co
->top
, co
->width
, co
->height
, 0);
507 li
->sb
->ops
->draw(li
->sb
);
509 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
511 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->startShowItem
;
512 i
++, item
= item
->next
);
516 for (i
= 0; item
!= NULL
&& i
< li
->curHeight
; i
++, item
= item
->next
) {
517 if (!item
->text
) continue;
519 newtGotorc(co
->top
+ i
+ li
->bdyAdjust
, co
->left
+ li
->bdxAdjust
);
520 if(j
+ i
== li
->currItem
) {
522 SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX
);
524 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
525 } else if(item
->isSelected
)
526 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
528 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
530 SLsmg_write_nstring(item
->text
, li
->curWidth
);
533 newtGotorc(co
->top
+ (li
->currItem
- li
->startShowItem
) + li
->bdyAdjust
,
534 co
->left
+ li
->bdxAdjust
);
537 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
) {
538 struct eventResult er
;
539 struct listbox
* li
= co
->data
;
543 er
.result
= ER_IGNORED
;
545 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
551 if (!li
->isActive
) break;
555 if(!(li
->flags
& NEWT_FLAG_MULTIPLE
)) break;
556 newtListboxSelectItem(co
, newtListboxGetCurrent(co
),
558 er
.result
= ER_SWALLOWED
;
559 /* We don't break here, because it is cool to be able to
560 hold space to select a bunch of items in a list at once */
563 if(li
->numItems
<= 0) break;
564 if(li
->currItem
< li
->numItems
- 1) {
566 if(li
->currItem
> (li
->startShowItem
+ li
->curHeight
- 1)) {
567 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
568 if(li
->startShowItem
+ li
->curHeight
> li
->numItems
)
569 li
->startShowItem
= li
->numItems
- li
->curHeight
;
572 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
575 if(co
->callback
) co
->callback(co
, co
->callbackData
);
576 er
.result
= ER_SWALLOWED
;
580 if(li
->numItems
<= 0) break;
581 if(li
->flags
& NEWT_FLAG_RETURNEXIT
)
582 er
.result
= ER_EXITFORM
;
586 if(li
->numItems
<= 0) break;
587 if(li
->currItem
> 0) {
589 if(li
->currItem
< li
->startShowItem
)
590 li
->startShowItem
= li
->currItem
;
592 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
595 if(co
->callback
) co
->callback(co
, co
->callbackData
);
596 er
.result
= ER_SWALLOWED
;
600 if(li
->numItems
<= 0) break;
601 li
->startShowItem
-= li
->curHeight
- 1;
602 if(li
->startShowItem
< 0)
603 li
->startShowItem
= 0;
604 li
->currItem
-= li
->curHeight
- 1;
607 newtListboxRealSetCurrent(co
);
608 er
.result
= ER_SWALLOWED
;
612 if(li
->numItems
<= 0) break;
613 li
->startShowItem
+= li
->curHeight
;
614 if(li
->startShowItem
> (li
->numItems
- li
->curHeight
)) {
615 li
->startShowItem
= li
->numItems
- li
->curHeight
;
617 li
->currItem
+= li
->curHeight
;
618 if(li
->currItem
>= li
->numItems
) {
619 li
->currItem
= li
->numItems
- 1;
621 newtListboxRealSetCurrent(co
);
622 er
.result
= ER_SWALLOWED
;
626 if(li
->numItems
<= 0) break;
627 newtListboxSetCurrent(co
, 0);
628 er
.result
= ER_SWALLOWED
;
632 if(li
->numItems
<= 0) break;
633 li
->startShowItem
= li
->numItems
- li
->curHeight
;
634 if(li
->startShowItem
< 0)
635 li
->startShowItem
= 0;
636 li
->currItem
= li
->numItems
- 1;
637 newtListboxRealSetCurrent(co
);
638 er
.result
= ER_SWALLOWED
;
641 if (li
->numItems
<= 0) break;
642 if (ev
.u
.key
< NEWT_KEY_EXTRA_BASE
&& isalpha(ev
.u
.key
)) {
643 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&&
644 i
< li
->currItem
; i
++, item
= item
->next
);
646 if (item
&& item
->text
&& (toupper(*item
->text
) == toupper(ev
.u
.key
))) {
653 while (item
&& item
->text
&&
654 toupper(*item
->text
) != toupper(ev
.u
.key
)) {
660 if(li
->currItem
< li
->startShowItem
||
661 li
->currItem
> li
->startShowItem
)
663 li
->currItem
> li
->numItems
- li
->curHeight
?
664 li
->startShowItem
= li
->numItems
- li
->curHeight
:
667 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
668 newtListboxRealSetCurrent(co
);
669 er
.result
= ER_SWALLOWED
;
678 if(li
->flags
& NEWT_FLAG_SHOWCURSOR
)
680 er
.result
= ER_SWALLOWED
;
686 if(li
->flags
& NEWT_FLAG_SHOWCURSOR
)
688 er
.result
= ER_SWALLOWED
;
692 /* if this mouse click was within the listbox, make the current
693 item the item clicked on. */
694 /* Up scroll arrow */
696 ev
.u
.mouse
.x
== co
->left
+ co
->width
- li
->bdxAdjust
- 1 &&
697 ev
.u
.mouse
.y
== co
->top
+ li
->bdyAdjust
) {
698 if(li
->numItems
<= 0) break;
699 if(li
->currItem
> 0) {
701 if(li
->currItem
< li
->startShowItem
)
702 li
->startShowItem
= li
->currItem
;
704 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
707 if(co
->callback
) co
->callback(co
, co
->callbackData
);
708 er
.result
= ER_SWALLOWED
;
711 /* Down scroll arrow */
713 ev
.u
.mouse
.x
== co
->left
+ co
->width
- li
->bdxAdjust
- 1 &&
714 ev
.u
.mouse
.y
== co
->top
+ co
->height
- li
->bdyAdjust
- 1) {
715 if(li
->numItems
<= 0) break;
716 if(li
->currItem
< li
->numItems
- 1) {
718 if(li
->currItem
> (li
->startShowItem
+ li
->curHeight
- 1)) {
719 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
720 if(li
->startShowItem
+ li
->curHeight
> li
->numItems
)
721 li
->startShowItem
= li
->numItems
- li
->curHeight
;
724 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
727 if(co
->callback
) co
->callback(co
, co
->callbackData
);
728 er
.result
= ER_SWALLOWED
;
731 if ((ev
.u
.mouse
.y
>= co
->top
+ li
->bdyAdjust
) &&
732 (ev
.u
.mouse
.y
<= co
->top
+ co
->height
- (li
->bdyAdjust
* 2)) &&
733 (ev
.u
.mouse
.x
>= co
->left
+ li
->bdxAdjust
) &&
734 (ev
.u
.mouse
.x
<= co
->left
+ co
->width
+ (li
->bdxAdjust
* 2))) {
735 li
->currItem
= li
->startShowItem
+
736 (ev
.u
.mouse
.y
- li
->bdyAdjust
- co
->top
);
737 newtListboxRealSetCurrent(co
);
739 if(co
->callback
) co
->callback(co
, co
->callbackData
);
740 er
.result
= ER_SWALLOWED
;
748 static void listboxDestroy(newtComponent co
) {
749 struct listbox
* li
= co
->data
;
750 struct items
* item
, * nextitem
;
752 nextitem
= item
= li
->boxItems
;
754 while (item
!= NULL
) {
755 nextitem
= item
->next
;
761 if (li
->sb
) li
->sb
->ops
->destroy(li
->sb
);