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 */
6 #include <slang/slang.h>
15 /* Linked list of items in the listbox */
19 unsigned char isSelected
;
23 /* Holds all the relevant information for this listbox */
25 newtComponent sb
; /* Scrollbar on right side of listbox */
26 int curWidth
; /* size of text w/o scrollbar or border*/
27 int curHeight
; /* size of text w/o border */
29 int bdxAdjust
, bdyAdjust
;
30 int numItems
, numSelected
;
32 int currItem
, startShowItem
; /* startShowItem is the first item displayed
34 int isActive
; /* If we handle key events all the time, it seems
35 to do things even when they are supposed to be for
36 another button/whatever */
37 struct items
*boxItems
;
39 int flags
; /* flags for this listbox, right now just
40 NEWT_FLAG_RETURNEXIT */
43 static void listboxDraw(newtComponent co
);
44 static void listboxDestroy(newtComponent co
);
45 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
);
46 static void newtListboxRealSetCurrent(newtComponent co
);
47 static void listboxPlace(newtComponent co
);
48 static inline void updateWidth(newtComponent co
, struct listbox
* li
,
51 static struct componentOps listboxOps
= {
58 static void listboxPlace(newtComponent co
) {
59 struct listbox
* li
= co
->data
;
62 li
->sb
->top
= co
->top
;
63 li
->sb
->left
= co
->left
+ co
->width
- 1;
64 if (li
->sb
->ops
->place
) li
->sb
->ops
->place(li
->sb
);
68 newtComponent
newtListbox(int left
, int top
, int height
, int flags
) {
72 if (!(co
= malloc(sizeof(*co
))))
75 if (!(li
= malloc(sizeof(struct listbox
)))) {
85 li
->userHasSetWidth
= 0;
86 li
->startShowItem
= 0;
90 li
->flags
= flags
& (NEWT_FLAG_RETURNEXIT
| NEWT_FLAG_DOBORDER
|
93 if (li
->flags
& NEWT_FLAG_DOBORDER
) {
100 if (flags
& NEWT_FLAG_NOSCROLL
) {
103 sb
= newtVerticalScrollbar(left
, top
, height
, COLORSET_LISTBOX
,
104 COLORSET_ACTLISTBOX
);
111 co
->height
= 2 * li
->bdyAdjust
;
119 co
->ops
= &listboxOps
;
123 updateWidth(co
, li
, 5);
124 li
->curHeight
= co
->height
- (2 * li
->bdyAdjust
);
129 static inline void updateWidth(newtComponent co
, struct listbox
* li
,
131 li
->curWidth
= maxField
;
132 co
->width
= li
->curWidth
+ li
->sbAdjust
+ 2 * li
->bdxAdjust
;
135 li
->sb
->left
= co
->left
+ co
->width
- 1;
138 void newtListboxSetCurrent(newtComponent co
, int num
)
140 struct listbox
* li
= co
->data
;
141 if (num
>= li
->numItems
)
142 li
->currItem
= li
->numItems
- 1;
148 if (li
->currItem
< li
->startShowItem
)
149 li
->startShowItem
= li
->currItem
;
150 else if (li
->currItem
- li
->startShowItem
> co
->height
- 1)
151 li
->startShowItem
= li
->currItem
- co
->height
+ 1;
152 if (li
->startShowItem
+ co
->height
> li
->numItems
)
153 li
->startShowItem
= li
->numItems
- co
->height
;
154 if(li
->startShowItem
< 0)
155 li
->startShowItem
= 0;
156 newtListboxRealSetCurrent(co
);
160 newtListboxRealSetCurrent(newtComponent co
)
162 struct listbox
* li
= co
->data
;
164 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
166 if(co
->callback
) co
->callback(co
, co
->callbackData
);
169 void newtListboxSetWidth(newtComponent co
, int width
) {
170 struct listbox
* li
= co
->data
;
173 li
->curWidth
= co
->width
- li
->sbAdjust
- 2 * li
->bdxAdjust
;
174 li
->userHasSetWidth
= 1;
175 if (li
->sb
) li
->sb
->left
= co
->width
+ co
->left
- 1;
179 void * newtListboxGetCurrent(newtComponent co
) {
180 struct listbox
* li
= co
->data
;
184 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->currItem
;
185 i
++, item
= item
->next
);
188 return (void *)item
->data
;
193 void newtListboxSelectItem(newtComponent co
, int item
,
194 enum newtFlagsSense sense
)
196 struct listbox
* li
= co
->data
;
200 for(i
= 0, iitem
= li
->boxItems
; iitem
!= NULL
&& i
< item
;
201 i
++, iitem
= iitem
->next
);
204 if(iitem
->isSelected
&& sense
!= NEWT_FLAGS_SET
)
206 else if(!iitem
->isSelected
&& sense
!= NEWT_FLAGS_RESET
)
209 case NEWT_FLAGS_RESET
:
210 iitem
->isSelected
= 0; break;
212 iitem
->isSelected
= 1; break;
213 case NEWT_FLAGS_TOGGLE
:
214 iitem
->isSelected
= !iitem
->isSelected
;
220 void newtListboxClearSelection(newtComponent co
)
223 struct listbox
* li
= co
->data
;
225 for(item
= li
->boxItems
; item
!= NULL
;
227 item
->isSelected
= 0;
232 /* Free the returned array after use, but NOT the values in the array */
233 void ** newtListboxGetSelection(newtComponent co
, int *numitems
)
240 if(!co
|| !numitems
) return NULL
;
243 if(!li
|| !li
->numSelected
) return NULL
;
245 retval
= malloc(li
->numSelected
* sizeof(void *));
246 for(i
= 0, item
= li
->boxItems
; item
!= NULL
;
249 retval
[i
++] = (void *)item
->data
;
250 *numitems
= li
->numSelected
;
254 void newtListboxSetText(newtComponent co
, int num
, const char * text
) {
255 struct listbox
* li
= co
->data
;
259 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
260 i
++, item
= item
->next
);
266 item
->key
= strdup(text
);
268 if (li
->userHasSetWidth
== 0 && strlen(text
) > li
->curWidth
) {
269 updateWidth(co
, li
, strlen(text
));
272 if (num
>= li
->startShowItem
&& num
<= li
->startShowItem
+ co
->height
)
276 void newtListboxSetEntry(newtComponent co
, int num
, const char * text
) {
277 newtListboxSetText(co
, num
, text
);
280 void newtListboxSetData(newtComponent co
, int num
, void * data
) {
281 struct listbox
* li
= co
->data
;
285 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
286 i
++, item
= item
->next
);
291 int newtListboxAddEntry(newtComponent co
, const char * text
,
293 struct listbox
* li
= co
->data
;
297 for (item
= li
->boxItems
; item
->next
!= NULL
; item
= item
->next
);
299 item
= item
->next
= malloc(sizeof(struct items
));
301 item
= li
->boxItems
= malloc(sizeof(struct items
));
304 if (!li
->userHasSetWidth
&& text
&& (strlen(text
) > li
->curWidth
))
305 updateWidth(co
, li
, strlen(text
));
307 item
->key
= strdup(text
); item
->data
= data
; item
->next
= NULL
;
308 item
->isSelected
= 0;
311 co
->height
++, li
->curHeight
++;
318 int newtListboxInsertEntry(newtComponent co
, const char * text
,
319 const void * data
, int num
) {
320 struct listbox
* li
= co
->data
;
321 struct items
*item
, *t
;
323 if(num
> li
->numItems
)
328 for(i
= 0, item
= li
->boxItems
; item
->next
!= NULL
&& i
< num
- 1;
329 item
= item
->next
, i
++);
331 item
= item
->next
= malloc(sizeof(struct items
));
335 item
= li
->boxItems
= malloc(sizeof(struct items
));
339 item
= li
->boxItems
= malloc(sizeof(struct items
));
343 if (!li
->userHasSetWidth
&& text
&& (strlen(text
) > li
->curWidth
))
344 updateWidth(co
, li
, strlen(text
));
346 item
->key
= strdup(text
?text
:"(null)"); item
->data
= data
;
347 item
->isSelected
= 0;
350 li
->sb
->left
= co
->left
+ co
->width
- 1;
358 int newtListboxDeleteEntry(newtComponent co
, int num
) {
359 struct listbox
* li
= co
->data
;
360 int i
, widest
= 0, t
;
361 struct items
*item
, *item2
= NULL
;
363 if(num
> li
->numItems
)
366 if (li
->boxItems
== NULL
|| li
->numItems
<= 0)
371 li
->boxItems
= item
->next
;
373 /* Fix things up for the width-finding loop near the bottom */
374 item2
= li
->boxItems
;
375 widest
= strlen(item2
?item2
->key
:"");
377 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
- 1;
378 i
++, item
= item
->next
) {
379 if((t
= strlen(item
->key
)) > widest
) widest
= t
;
386 item2
->next
= item
->next
;
391 if(li
->currItem
>= num
)
393 for (item
= item2
?item2
->next
:item2
; item
!= NULL
; item
= item
->next
)
394 if((t
= strlen(item
->key
)) > widest
) widest
= t
;
396 /* Adjust the listbox width */
397 if (!li
->userHasSetWidth
) {
398 updateWidth(co
, li
, widest
);
406 void newtListboxClear(newtComponent co
)
409 struct items
*anitem
, *nextitem
;
410 if(co
== NULL
|| (li
= co
->data
) == NULL
)
412 for(anitem
= li
->boxItems
; anitem
!= NULL
; anitem
= nextitem
) {
413 nextitem
= anitem
->next
;
417 li
->numItems
= li
->numSelected
= li
->currItem
= li
->startShowItem
= 0;
419 if (!li
->userHasSetWidth
)
420 updateWidth(co
, li
, 5);
423 /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
424 goes for the data. */
425 void newtListboxGetEntry(newtComponent co
, int num
, char **text
, void **data
) {
426 struct listbox
* li
= co
->data
;
430 if (!li
->boxItems
|| num
>= li
->numItems
) {
440 while (item
&& i
< num
) {
441 i
++, item
= item
->next
;
448 *data
= (void *)item
->data
;
452 static void listboxDraw(newtComponent co
)
454 struct listbox
* li
= co
->data
;
458 if (!co
->isMapped
) return ;
461 li
->sb
->ops
->draw(li
->sb
);
463 if(li
->flags
& NEWT_FLAG_DOBORDER
) {
465 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
467 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
469 newtDrawBox(co
->left
, co
->top
, co
->width
, co
->height
, 0);
472 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
474 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->startShowItem
;
475 i
++, item
= item
->next
);
479 for (i
= 0; item
!= NULL
&& i
< li
->curHeight
; i
++, item
= item
->next
) {
480 if (!item
->key
) continue;
482 newtGotorc(co
->top
+ i
+ li
->bdyAdjust
, co
->left
+ li
->bdxAdjust
);
483 if(j
+ i
== li
->currItem
) {
485 SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX
);
487 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
488 } else if(item
->isSelected
)
489 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
491 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
493 SLsmg_write_nstring(item
->key
, li
->curWidth
);
496 newtGotorc(co
->top
+ (li
->currItem
- li
->startShowItem
), co
->left
);
499 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
) {
500 struct eventResult er
;
501 struct listbox
* li
= co
->data
;
503 er
.result
= ER_IGNORED
;
505 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
511 if (!li
->isActive
) break;
515 if(!(li
->flags
& NEWT_FLAG_MULTIPLE
)) break;
516 newtListboxSelectItem(co
, li
->currItem
, NEWT_FLAGS_TOGGLE
);
517 er
.result
= ER_SWALLOWED
;
518 /* We don't break here, because it is cool to be able to
519 hold space to select a bunch of items in a list at once */
522 if(li
->numItems
<= 0) break;
523 if(li
->currItem
< li
->numItems
- 1) {
525 if(li
->currItem
> (li
->startShowItem
+ li
->curHeight
- 1)) {
526 li
->startShowItem
= li
->currItem
- li
->curHeight
+ 1;
527 if(li
->startShowItem
+ li
->curHeight
> li
->numItems
)
528 li
->startShowItem
= li
->numItems
- li
->curHeight
;
531 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
534 if(co
->callback
) co
->callback(co
, co
->callbackData
);
535 er
.result
= ER_SWALLOWED
;
539 if(li
->numItems
<= 0) break;
540 if(li
->flags
& NEWT_FLAG_RETURNEXIT
)
541 er
.result
= ER_EXITFORM
;
545 if(li
->numItems
<= 0) break;
546 if(li
->currItem
> 0) {
548 if(li
->currItem
< li
->startShowItem
)
549 li
->startShowItem
= li
->currItem
;
551 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
554 if(co
->callback
) co
->callback(co
, co
->callbackData
);
555 er
.result
= ER_SWALLOWED
;
559 if(li
->numItems
<= 0) break;
560 li
->startShowItem
-= li
->curHeight
- 1;
561 if(li
->startShowItem
< 0)
562 li
->startShowItem
= 0;
563 li
->currItem
-= li
->curHeight
- 1;
566 newtListboxRealSetCurrent(co
);
567 er
.result
= ER_SWALLOWED
;
571 if(li
->numItems
<= 0) break;
572 li
->startShowItem
+= li
->curHeight
;
573 if(li
->startShowItem
> (li
->numItems
- li
->curHeight
)) {
574 li
->startShowItem
= li
->numItems
- li
->curHeight
;
576 li
->currItem
+= li
->curHeight
;
577 if(li
->currItem
> li
->numItems
) {
578 li
->currItem
= li
->numItems
- 1;
580 newtListboxRealSetCurrent(co
);
581 er
.result
= ER_SWALLOWED
;
585 if(li
->numItems
<= 0) break;
586 newtListboxSetCurrent(co
, 0);
587 er
.result
= ER_SWALLOWED
;
591 if(li
->numItems
<= 0) break;
592 li
->startShowItem
= li
->numItems
- li
->curHeight
- 1;
593 if(li
->startShowItem
< 0)
594 li
->startShowItem
= 0;
595 newtListboxRealSetCurrent(co
, li
->numItems
- 1);
596 er
.result
= ER_SWALLOWED
;
599 /* keeps gcc quiet */
606 er
.result
= ER_SWALLOWED
;
612 er
.result
= ER_SWALLOWED
;
619 static void listboxDestroy(newtComponent co
) {
620 struct listbox
* li
= co
->data
;
621 struct items
* item
, * nextitem
;
623 nextitem
= item
= li
->boxItems
;
625 while (item
!= NULL
) {
626 nextitem
= item
->next
;