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 */
18 unsigned char isSelected
;
22 /* Holds all the relevant information for this listbox */
24 newtComponent sb
; /* Scrollbar on right side of listbox */
25 int numItems
, curWidth
, numSelected
;
27 int currItem
, startShowItem
; /* startShowItem is the first item displayed
29 int isActive
; /* If we handle key events all the time, it seems
30 to do things even when they are supposed to be for
31 another button/whatever */
32 struct items
*boxItems
;
34 int flags
; /* flags for this listbox, right now just
35 NEWT_FLAG_RETURNEXIT */
38 static void listboxDraw(newtComponent co
);
39 static void listboxDestroy(newtComponent co
);
40 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
);
41 static void newtListboxRealSetCurrent(newtComponent co
);
43 static struct componentOps listboxOps
= {
49 newtComponent
newtListbox(int left
, int top
, int height
, int flags
) {
53 if (!(co
= malloc(sizeof(*co
))))
56 if (!(li
= malloc(sizeof(struct listbox
)))) {
66 li
->userHasSetWidth
= 0;
67 li
->startShowItem
= 0;
68 li
->flags
= flags
& (NEWT_FLAG_RETURNEXIT
|NEWT_FLAG_DOBORDER
|NEWT_FLAG_MULTIPLE
);
72 if (flags
& NEWT_FLAG_NOSCROLL
)
75 sb
= newtVerticalScrollbar(left
, top
, height
, COLORSET_LISTBOX
,
88 co
->ops
= &listboxOps
;
95 void newtListboxSetCurrent(newtComponent co
, int num
)
97 struct listbox
* li
= co
->data
;
98 if (num
>= li
->numItems
)
99 li
->currItem
= li
->numItems
- 1;
105 if (li
->currItem
< li
->startShowItem
)
106 li
->startShowItem
= li
->currItem
;
107 else if (li
->currItem
- li
->startShowItem
> co
->height
- 1)
108 li
->startShowItem
= li
->currItem
- co
->height
+ 1;
109 if (li
->startShowItem
+ co
->height
> li
->numItems
)
110 li
->startShowItem
= li
->numItems
- co
->height
;
111 if(li
->startShowItem
< 0)
112 li
->startShowItem
= 0;
113 newtListboxRealSetCurrent(co
);
117 newtListboxRealSetCurrent(newtComponent co
)
119 struct listbox
* li
= co
->data
;
121 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
123 if(co
->callback
) co
->callback(co
, co
->callbackData
);
126 void newtListboxSetWidth(newtComponent co
, int width
) {
127 struct listbox
* li
= co
->data
;
129 li
->curWidth
= co
->width
= width
;
130 li
->userHasSetWidth
= 1;
131 li
->sb
->left
= width
+ co
->left
+ 2;
135 void * newtListboxGetCurrent(newtComponent co
) {
136 struct listbox
* li
= co
->data
;
140 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->currItem
;
141 i
++, item
= item
->next
);
149 void newtListboxSelectItem(newtComponent co
, int item
)
151 struct listbox
* li
= co
->data
;
155 for(i
= 0, iitem
= li
->boxItems
; iitem
!= NULL
&& i
< item
;
156 i
++, iitem
= iitem
->next
);
159 if(iitem
->isSelected
)
163 iitem
->isSelected
= !iitem
->isSelected
;
168 void newtListboxClearSelection(newtComponent co
)
171 struct listbox
* li
= co
->data
;
173 for(item
= li
->boxItems
; item
!= NULL
;
175 item
->isSelected
= 0;
180 /* Free the returned array after use, but NOT the values in the array */
181 void ** newtListboxGetSelection(newtComponent co
)
191 if(!li
|| !li
->numSelected
) return NULL
;
193 retval
= malloc((li
->numSelected
+ 1) * sizeof(void *));
194 for(i
= 0, item
= li
->boxItems
; item
!= NULL
;
197 retval
[i
++] = item
->data
;
202 void newtListboxSetText(newtComponent co
, int num
, char * text
) {
203 struct listbox
* li
= co
->data
;
207 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
208 i
++, item
= item
->next
);
214 item
->key
= strdup(text
);
216 if (li
->userHasSetWidth
== 0
217 && strlen(text
) > li
->curWidth
) {
218 co
->width
= li
->curWidth
= strlen(text
);
220 li
->sb
->left
= co
->left
+ co
->width
+ 2;
223 if (num
>= li
->startShowItem
&& num
<= li
->startShowItem
+ co
->height
)
227 void newtListboxSetEntry(newtComponent co
, int num
, char * text
) {
228 newtListboxSetText(co
, num
, text
);
231 void newtListboxSetData(newtComponent co
, int num
, void * data
) {
232 struct listbox
* li
= co
->data
;
236 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
;
237 i
++, item
= item
->next
);
242 int newtListboxAddEntry(newtComponent co
, char * text
, void * data
) {
243 struct listbox
* li
= co
->data
;
247 for (item
= li
->boxItems
; item
->next
!= NULL
; item
= item
->next
);
249 item
= item
->next
= malloc(sizeof(struct items
));
251 item
= li
->boxItems
= malloc(sizeof(struct items
));
254 if (li
->userHasSetWidth
== 0
255 && text
&& (strlen(text
) > li
->curWidth
))
256 li
->curWidth
= strlen(text
) ;
258 item
->key
= strdup(text
); item
->data
= data
; item
->next
= NULL
;
259 item
->isSelected
= 0;
262 li
->sb
->left
= co
->left
+ li
->curWidth
+ 2;
266 if(li
->userHasSetWidth
== 0)
267 co
->width
= li
->curWidth
;
276 int newtListboxInsertEntry(newtComponent co
, char * text
, void * data
,
278 struct listbox
* li
= co
->data
;
279 struct items
*item
, *t
;
281 if(num
> li
->numItems
)
286 for(i
= 0, item
= li
->boxItems
; item
->next
!= NULL
&& i
< num
- 1;
287 item
= item
->next
, i
++);
289 item
= item
->next
= malloc(sizeof(struct items
));
293 item
= li
->boxItems
= malloc(sizeof(struct items
));
297 item
= li
->boxItems
= malloc(sizeof(struct items
));
301 if (li
->userHasSetWidth
== 0
302 && text
&& (strlen(text
) > li
->curWidth
))
303 li
->curWidth
= strlen(text
);
305 item
->key
= strdup(text
?text
:"(null)"); item
->data
= data
;
306 item
->isSelected
= 0;
309 li
->sb
->left
= co
->left
+ li
->curWidth
+ 2;
310 if (li
->userHasSetWidth
== 0)
311 co
->width
= li
->curWidth
;
319 int newtListboxDeleteEntry(newtComponent co
, int num
) {
320 struct listbox
* li
= co
->data
;
321 int i
, widest
= 0, t
;
322 struct items
*item
, *item2
;
324 if(num
> li
->numItems
)
327 if (li
->boxItems
== NULL
|| li
->numItems
<= 0)
332 li
->boxItems
= item
->next
;
334 /* Fix things up for the width-finding loop near the bottom */
335 item2
= li
->boxItems
;
336 widest
= strlen(item2
?item2
->key
:"");
338 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< num
- 1;
339 i
++, item
= item
->next
) {
340 if((t
= strlen(item
->key
)) > widest
) widest
= t
;
347 item2
->next
= item
->next
;
352 if(li
->currItem
>= num
)
354 for (item
= item2
?item2
->next
:item2
; item
!= NULL
; item
= item
->next
)
355 if((t
= strlen(item
->key
)) > widest
) widest
= t
;
357 /* Adjust the listbox width */
358 if (li
->userHasSetWidth
== 0) {
359 co
->width
= li
->curWidth
= widest
;
361 li
->sb
->left
= co
->left
+ widest
+ 2;
369 void newtListboxClear(newtComponent co
)
372 struct items
*anitem
, *nextitem
;
373 if(co
== NULL
|| (li
= co
->data
) == NULL
)
375 for(anitem
= li
->boxItems
; anitem
!= NULL
; anitem
= nextitem
) {
376 nextitem
= anitem
->next
;
380 li
->numItems
= li
->numSelected
= li
->currItem
= li
->startShowItem
= 0;
382 if(li
->userHasSetWidth
== 0)
386 /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same
387 goes for the data. */
388 void newtListboxGetEntry(newtComponent co
, int num
, char **text
, void **data
) {
389 struct listbox
* li
= co
->data
;
393 if (!li
->boxItems
|| num
>= li
->numItems
) {
403 while (item
&& i
< num
) {
404 i
++, item
= item
->next
;
415 static void listboxDraw(newtComponent co
)
417 struct listbox
* li
= co
->data
;
422 li
->sb
->ops
->draw(li
->sb
);
424 if(li
->flags
& NEWT_FLAG_DOBORDER
) {
426 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
428 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
430 newtDrawBox(co
->left
-1, co
->top
-1, co
->width
+5, co
->height
+2, 0);
433 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
435 for(i
= 0, item
= li
->boxItems
; item
!= NULL
&& i
< li
->startShowItem
;
436 i
++, item
= item
->next
);
440 for (i
= 0; item
!= NULL
&& i
< co
->height
; i
++, item
= item
->next
) {
441 if (!item
->key
) continue;
443 newtGotorc(co
->top
+ i
, co
->left
+ 1);
444 if(j
+ i
== li
->currItem
) {
446 SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX
);
448 SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX
);
449 } else if(item
->isSelected
)
450 SLsmg_set_color(NEWT_COLORSET_SELLISTBOX
);
452 SLsmg_set_color(NEWT_COLORSET_LISTBOX
);
454 SLsmg_write_nstring(item
->key
, li
->curWidth
);
457 newtGotorc(co
->top
+ (li
->currItem
- li
->startShowItem
), co
->left
);
460 static struct eventResult
listboxEvent(newtComponent co
, struct event ev
) {
461 struct eventResult er
;
462 struct listbox
* li
= co
->data
;
464 er
.result
= ER_IGNORED
;
466 if(ev
.when
== EV_EARLY
|| ev
.when
== EV_LATE
) {
472 if (!li
->isActive
) break;
476 if(!(li
->flags
& NEWT_FLAG_MULTIPLE
)) break;
477 newtListboxSelectItem(co
, li
->currItem
);
478 er
.result
= ER_SWALLOWED
;
482 if(li
->numItems
<= 0) break;
483 if(li
->flags
& NEWT_FLAG_RETURNEXIT
)
484 er
.result
= ER_EXITFORM
;
488 if(li
->numItems
<= 0) break;
489 if(li
->currItem
> 0) {
491 if(li
->currItem
< li
->startShowItem
)
492 li
->startShowItem
= li
->currItem
;
494 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
497 if(co
->callback
) co
->callback(co
, co
->callbackData
);
498 er
.result
= ER_SWALLOWED
;
502 if(li
->numItems
<= 0) break;
503 if(li
->currItem
< li
->numItems
- 1) {
505 if(li
->currItem
> (li
->startShowItem
+ co
->height
- 1)) {
506 li
->startShowItem
= li
->currItem
- co
->height
+ 1;
507 if(li
->startShowItem
+ co
->height
> li
->numItems
)
508 li
->startShowItem
= li
->numItems
- co
->height
;
511 newtScrollbarSet(li
->sb
, li
->currItem
+ 1, li
->numItems
);
514 if(co
->callback
) co
->callback(co
, co
->callbackData
);
515 er
.result
= ER_SWALLOWED
;
519 if(li
->numItems
<= 0) break;
520 li
->startShowItem
-= co
->height
- 1;
521 if(li
->startShowItem
< 0)
522 li
->startShowItem
= 0;
523 li
->currItem
-= co
->height
- 1;
526 newtListboxRealSetCurrent(co
);
527 er
.result
= ER_SWALLOWED
;
531 if(li
->numItems
<= 0) break;
532 li
->startShowItem
+= co
->height
;
533 if(li
->startShowItem
> (li
->numItems
- co
->height
)) {
534 li
->startShowItem
= li
->numItems
- co
->height
;
536 li
->currItem
+= co
->height
;
537 if(li
->currItem
> li
->numItems
) {
538 li
->currItem
= li
->numItems
- 1;
540 newtListboxRealSetCurrent(co
);
541 er
.result
= ER_SWALLOWED
;
545 if(li
->numItems
<= 0) break;
546 newtListboxSetCurrent(co
, 0);
547 er
.result
= ER_SWALLOWED
;
551 if(li
->numItems
<= 0) break;
552 newtListboxSetCurrent(co
, li
->numItems
- 1);
553 er
.result
= ER_SWALLOWED
;
556 /* keeps gcc quiet */
563 er
.result
= ER_SWALLOWED
;
569 er
.result
= ER_SWALLOWED
;
576 static void listboxDestroy(newtComponent co
) {
577 struct listbox
* li
= co
->data
;
578 struct items
* item
, * nextitem
;
580 nextitem
= item
= li
->boxItems
;
582 while (item
!= NULL
) {
583 nextitem
= item
->next
;