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,
77 co
->top
+ li
->bdyAdjust
);
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;
204 li
->sb
->left
= co
->left
+ co
->width
- li
->bdxAdjust
- 1;
208 void * newtListboxGetCurrent(newtComponent co
) {
209 struct listbox
* li
= co
->data
;
213 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->currItem
;
214 i
++, item
= item
->next
);
217 return (void *)item
->data
;
222 void newtListboxSelectItem(newtComponent co
, const void * key
,
223 enum newtFlagsSense sense
)
225 struct listbox
* li
= co
->data
;
229 item
= li
->boxItems
, i
= 0;
230 while (item
&& item
->data
!= key
)
231 item
= item
->next
, i
++;
235 if (item
->isSelected
)
239 case NEWT_FLAGS_RESET
:
240 item
->isSelected
= 0; break;
242 item
->isSelected
= 1; break;
243 case NEWT_FLAGS_TOGGLE
:
244 item
->isSelected
= !item
->isSelected
;
247 if (item
->isSelected
)
253 void newtListboxClearSelection(newtComponent co
)
256 struct listbox
* li
= co
->data
;
258 for(item
= li
->boxItems
; item
!= NULL
;
260 item
->isSelected
= 0;
265 /* Free the returned array after use, but NOT the values in the array */
266 void ** newtListboxGetSelection(newtComponent co
, int *numitems
)
273 if(!co
|| !numitems
) return NULL
;
276 if(!li
|| !li
->numSelected
) return NULL
;
278 retval
= malloc(li
->numSelected
* sizeof(void *));
279 for(i
= 0, item
= li
->boxItems
; item
!= NULL
;
282 retval
[i
++] = (void *)item
->data
;
283 *numitems
= li
->numSelected
;
287 void newtListboxSetEntry(newtComponent co
, int num
, const char * text
) {
288 struct listbox
* li
= co
->data
;
292 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
293 i
++, item
= item
->next
);
299 item
->text
= strdup(text
);
301 if (li
->userHasSetWidth
== 0 && wstrlen(text
,-1) > li
->curWidth
) {
302 updateWidth(co
, li
, wstrlen(text
,-1));
305 if (num
>= li
->startShowItem
&& num
<= li
->startShowItem
+ co
->height
)
309 void newtListboxSetData(newtComponent co
, int num
, void * data
) {
310 struct listbox
* li
= co
->data
;
314 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
315 i
++, item
= item
->next
);
320 int newtListboxAppendEntry(newtComponent co
, const char * text
,
322 struct listbox
* li
= co
->data
;
326 for (item
= li
->boxItems
; item
->next
!= NULL
; item
= item
->next
);
328 item
= item
->next
= malloc(sizeof(struct items
));
330 item
= li
->boxItems
= malloc(sizeof(struct items
));
333 if (!li
->userHasSetWidth
&& text
&& (wstrlen(text
,-1) > li
->curWidth
))
334 updateWidth(co
, li
, wstrlen(text
,-1));
336 item
->text
= strdup(text
); item
->data
= data
; item
->next
= NULL
;
337 item
->isSelected
= 0;
340 co
->height
++, li
->curHeight
++;
346 int newtListboxInsertEntry(newtComponent co
, const char * text
,
347 const void * data
, void * key
) {
348 struct listbox
* li
= co
->data
;
349 struct items
*item
, *t
;
354 while (item
&& item
->data
!= key
) item
= item
->next
;
359 item
= item
->next
= malloc(sizeof(struct items
));
363 item
= li
->boxItems
= malloc(sizeof(struct items
));
369 item
= li
->boxItems
= malloc(sizeof(struct items
));
373 if (!li
->userHasSetWidth
&& text
&& (wstrlen(text
,-1) > li
->curWidth
))
374 updateWidth(co
, li
, wstrlen(text
,-1));
376 item
->text
= strdup(text
?text
:"(null)"); item
->data
= data
;
377 item
->isSelected
= 0;
380 li
->sb
->left
= co
->left
+ co
->width
- li
->bdxAdjust
- 1;
388 int newtListboxDeleteEntry(newtComponent co
, void * key
) {
389 struct listbox
* li
= co
->data
;
391 struct items
*item
, *item2
= NULL
;
394 if (li
->boxItems
== NULL
|| li
->numItems
<= 0)
399 item2
= NULL
, item
= li
->boxItems
;
400 while (item
&& item
->data
!= key
) {
410 item2
->next
= item
->next
;
412 li
->boxItems
= item
->next
;
418 if (!li
->userHasSetWidth
) {
420 for (item
= li
->boxItems
; item
!= NULL
; item
= item
->next
)
421 if ((t
= wstrlen(item
->text
,-1)) > widest
) widest
= t
;
424 if (li
->currItem
>= num
)
427 if (!li
->userHasSetWidth
) {
428 updateWidth(co
, li
, widest
);
436 void newtListboxClear(newtComponent co
)
439 struct items
*anitem
, *nextitem
;
440 if(co
== NULL
|| (li
= co
->data
) == NULL
)
442 for(anitem
= li
->boxItems
; anitem
!= NULL
; anitem
= nextitem
) {
443 nextitem
= anitem
->next
;
447 li
->numItems
= li
->numSelected
= li
->currItem
= li
->startShowItem
= 0;
449 if (!li
->userHasSetWidth
)
450 updateWidth(co
, li
, 5);
453 int newtListboxItemCount(newtComponent co
)
455 struct listbox
*li
= co
->data
;
459 /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
460 goes for the data. */
461 void newtListboxGetEntry(newtComponent co
, int num
, char **text
, void **data
) {
462 struct listbox
* li
= co
->data
;
466 if (!li
->boxItems
|| num
>= li
->numItems
) {
476 while (item
&& i
< num
) {
477 i
++, item
= item
->next
;
484 *data
= (void *)item
->data
;
488 static void listboxDraw(newtComponent co
)
490 struct listbox
* li
= co
->data
;
494 if (!co
->isMapped
) return ;
498 if(li
->flags
& NEWT_FLAG_BORDER
) {
500 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
502 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
504 newtDrawBox(co
->left
, co
->top
, co
->width
, co
->height
, 0);
508 li
->sb
->ops
->draw(li
->sb
);
510 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
512 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->startShowItem
;
513 i
++, item
= item
->next
);
517 for (i
= 0; item
!= NULL
&& i
< li
->curHeight
; i
++, item
= item
->next
) {
518 if (!item
->text
) continue;
520 newtGotorc(co
->top
+ i
+ li
->bdyAdjust
, co
->left
+ li
->bdxAdjust
);
521 if(j
+ i
== li
->currItem
) {
523 SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX
);
525 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
526 } else if(item
->isSelected
)
527 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
529 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
531 SLsmg_write_nstring(NULL
, li
->curWidth
);
532 newtGotorc(co
->top
+ i
+ li
->bdyAdjust
, co
->left
+ li
->bdxAdjust
);
533 if (wstrlen(item
->text
, -1) > li
->curWidth
) {
535 tmp
= strdup(item
->text
);
536 trim_string(tmp
, li
->curWidth
);
537 SLsmg_write_string(tmp
);
540 SLsmg_write_string(item
->text
);
542 if (li
->flags
& NEWT_FLAG_MULTIPLE
) {
543 newtGotorc(co
->top
+ i
+ li
->bdyAdjust
, co
->left
+ li
->bdxAdjust
);
544 SLsmg_set_color(item
->isSelected
?
545 NEWT_COLORSET_SELLISTBOX
: NEWT_COLORSET_LISTBOX
);
546 SLsmg_write_nstring(item
->text
, 1);
549 newtGotorc(co
->top
+ (li
->currItem
- li
->startShowItem
) + li
->bdyAdjust
,
550 co
->left
+ li
->bdxAdjust
);
553 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
) {
554 struct eventResult er
;
555 struct listbox
* li
= co
->data
;
559 er
.result
= ER_IGNORED
;
561 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
567 if (!li
->isActive
) break;
571 if(!(li
->flags
& NEWT_FLAG_MULTIPLE
)) break;
572 newtListboxSelectItem(co
, newtListboxGetCurrent(co
),
574 er
.result
= ER_SWALLOWED
;
575 /* We don't break here, because it is cool to be able to
576 hold space to select a bunch of items in a list at once */
579 if(li
->numItems
<= 0) break;
580 if(li
->currItem
< li
->numItems
- 1) {
582 if(li
->currItem
> (li
->startShowItem
+ li
->curHeight
- 1)) {
583 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
584 if(li
->startShowItem
+ li
->curHeight
> li
->numItems
)
585 li
->startShowItem
= li
->numItems
- li
->curHeight
;
588 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
591 if(co
->callback
) co
->callback(co
, co
->callbackData
);
592 er
.result
= ER_SWALLOWED
;
596 if(li
->numItems
<= 0) break;
597 if(li
->flags
& NEWT_FLAG_RETURNEXIT
)
598 er
.result
= ER_EXITFORM
;
602 if(li
->numItems
<= 0) break;
603 if(li
->currItem
> 0) {
605 if(li
->currItem
< li
->startShowItem
)
606 li
->startShowItem
= li
->currItem
;
608 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
611 if(co
->callback
) co
->callback(co
, co
->callbackData
);
612 er
.result
= ER_SWALLOWED
;
616 if(li
->numItems
<= 0) break;
617 li
->startShowItem
-= li
->curHeight
- 1;
618 if(li
->startShowItem
< 0)
619 li
->startShowItem
= 0;
620 li
->currItem
-= li
->curHeight
- 1;
623 newtListboxRealSetCurrent(co
);
624 er
.result
= ER_SWALLOWED
;
628 if(li
->numItems
<= 0) break;
629 li
->startShowItem
+= li
->curHeight
;
630 if(li
->startShowItem
> (li
->numItems
- li
->curHeight
)) {
631 li
->startShowItem
= li
->numItems
- li
->curHeight
;
633 li
->currItem
+= li
->curHeight
;
634 if(li
->currItem
>= li
->numItems
) {
635 li
->currItem
= li
->numItems
- 1;
637 newtListboxRealSetCurrent(co
);
638 er
.result
= ER_SWALLOWED
;
642 if(li
->numItems
<= 0) break;
643 newtListboxSetCurrent(co
, 0);
644 er
.result
= ER_SWALLOWED
;
648 if(li
->numItems
<= 0) break;
649 li
->startShowItem
= li
->numItems
- li
->curHeight
;
650 if(li
->startShowItem
< 0)
651 li
->startShowItem
= 0;
652 li
->currItem
= li
->numItems
- 1;
653 newtListboxRealSetCurrent(co
);
654 er
.result
= ER_SWALLOWED
;
657 if (li
->numItems
<= 0) break;
658 if (ev
.u
.key
< NEWT_KEY_EXTRA_BASE
&& isalpha(ev
.u
.key
)) {
659 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&&
660 i
< li
->currItem
; i
++, item
= item
->next
);
662 if (item
&& item
->text
&& (toupper(*item
->text
) == toupper(ev
.u
.key
))) {
669 while (item
&& item
->text
&&
670 toupper(*item
->text
) != toupper(ev
.u
.key
)) {
676 if(li
->currItem
< li
->startShowItem
||
677 li
->currItem
> li
->startShowItem
)
679 li
->currItem
> li
->numItems
- li
->curHeight
?
680 li
->startShowItem
= li
->numItems
- li
->curHeight
:
683 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
684 newtListboxRealSetCurrent(co
);
685 er
.result
= ER_SWALLOWED
;
694 if(li
->flags
& NEWT_FLAG_SHOWCURSOR
)
696 er
.result
= ER_SWALLOWED
;
702 if(li
->flags
& NEWT_FLAG_SHOWCURSOR
)
704 er
.result
= ER_SWALLOWED
;
708 /* if this mouse click was within the listbox, make the current
709 item the item clicked on. */
710 /* Up scroll arrow */
712 ev
.u
.mouse
.x
== co
->left
+ co
->width
- li
->bdxAdjust
- 1 &&
713 ev
.u
.mouse
.y
== co
->top
+ li
->bdyAdjust
) {
714 if(li
->numItems
<= 0) break;
715 if(li
->currItem
> 0) {
717 if(li
->currItem
< li
->startShowItem
)
718 li
->startShowItem
= li
->currItem
;
720 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
723 if(co
->callback
) co
->callback(co
, co
->callbackData
);
724 er
.result
= ER_SWALLOWED
;
727 /* Down scroll arrow */
729 ev
.u
.mouse
.x
== co
->left
+ co
->width
- li
->bdxAdjust
- 1 &&
730 ev
.u
.mouse
.y
== co
->top
+ co
->height
- li
->bdyAdjust
- 1) {
731 if(li
->numItems
<= 0) break;
732 if(li
->currItem
< li
->numItems
- 1) {
734 if(li
->currItem
> (li
->startShowItem
+ li
->curHeight
- 1)) {
735 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
736 if(li
->startShowItem
+ li
->curHeight
> li
->numItems
)
737 li
->startShowItem
= li
->numItems
- li
->curHeight
;
740 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
743 if(co
->callback
) co
->callback(co
, co
->callbackData
);
744 er
.result
= ER_SWALLOWED
;
747 if ((ev
.u
.mouse
.y
>= co
->top
+ li
->bdyAdjust
) &&
748 (ev
.u
.mouse
.y
<= co
->top
+ co
->height
- (li
->bdyAdjust
* 2)) &&
749 (ev
.u
.mouse
.x
>= co
->left
+ li
->bdxAdjust
) &&
750 (ev
.u
.mouse
.x
<= co
->left
+ co
->width
+ (li
->bdxAdjust
* 2))) {
751 li
->currItem
= li
->startShowItem
+
752 (ev
.u
.mouse
.y
- li
->bdyAdjust
- co
->top
);
753 newtListboxRealSetCurrent(co
);
755 if(co
->callback
) co
->callback(co
, co
->callbackData
);
756 er
.result
= ER_SWALLOWED
;
764 static void listboxDestroy(newtComponent co
) {
765 struct listbox
* li
= co
->data
;
766 struct items
* item
, * nextitem
;
768 nextitem
= item
= li
->boxItems
;
770 while (item
!= NULL
) {
771 nextitem
= item
->next
;
777 if (li
->sb
) li
->sb
->ops
->destroy(li
->sb
);