]>
Commit | Line | Data |
---|---|---|
0b38669d | 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. | |
ad792351 | 4 | Copyright (C) 1996, 1997 Elliot Lee */ |
a61e44cc | 5 | |
139f06bc | 6 | #include <slang.h> |
4a93351d | 7 | #include <stdio.h> |
962b92a5 | 8 | #include <stdlib.h> |
9 | #include <string.h> | |
d63d1c70 | 10 | #include <ctype.h> |
962b92a5 | 11 | |
12 | #include "newt.h" | |
13 | #include "newt_pr.h" | |
63231242 | 14 | |
a61e44cc | 15 | |
16 | /* Linked list of items in the listbox */ | |
17 | struct items { | |
a507b3ec | 18 | char * text; |
d4109c37 | 19 | const void *data; |
2dbc072e | 20 | unsigned char isSelected; |
a61e44cc | 21 | struct items *next; |
22 | }; | |
23 | ||
24 | /* Holds all the relevant information for this listbox */ | |
962b92a5 | 25 | struct listbox { |
e948278c | 26 | newtComponent sb; /* Scrollbar on right side of listbox */ |
6f481af2 | 27 | int curWidth; /* size of text w/o scrollbar or border*/ |
28 | int curHeight; /* size of text w/o border */ | |
e948278c | 29 | int sbAdjust; |
913d0524 | 30 | int bdxAdjust, bdyAdjust; |
45f6c4fd | 31 | int numItems, numSelected; |
babcb349 | 32 | int userHasSetWidth; |
a61e44cc | 33 | int currItem, startShowItem; /* startShowItem is the first item displayed |
6f481af2 | 34 | on the screen */ |
a61e44cc | 35 | int isActive; /* If we handle key events all the time, it seems |
6f481af2 | 36 | to do things even when they are supposed to be for |
37 | another button/whatever */ | |
a61e44cc | 38 | struct items *boxItems; |
0bf47501 | 39 | int grow; |
a61e44cc | 40 | int flags; /* flags for this listbox, right now just |
6f481af2 | 41 | NEWT_FLAG_RETURNEXIT */ |
962b92a5 | 42 | }; |
43 | ||
44 | static void listboxDraw(newtComponent co); | |
45 | static void listboxDestroy(newtComponent co); | |
46 | static struct eventResult listboxEvent(newtComponent co, struct event ev); | |
4e9c4bb9 | 47 | static void newtListboxRealSetCurrent(newtComponent co); |
8f52cd47 | 48 | static void listboxPlace(newtComponent co, int newLeft, int newTop); |
45f6c4fd | 49 | static inline void updateWidth(newtComponent co, struct listbox * li, |
6f481af2 | 50 | int maxField); |
8f52cd47 | 51 | static void listboxMapped(newtComponent co, int isMapped); |
962b92a5 | 52 | |
53 | static struct componentOps listboxOps = { | |
54 | listboxDraw, | |
55 | listboxEvent, | |
56 | listboxDestroy, | |
e948278c | 57 | listboxPlace, |
8f52cd47 | 58 | listboxMapped, |
a61e44cc | 59 | }; |
962b92a5 | 60 | |
8f52cd47 | 61 | static void listboxMapped(newtComponent co, int isMapped) { |
e948278c | 62 | struct listbox * li = co->data; |
63 | ||
8f52cd47 | 64 | co->isMapped = isMapped; |
65 | if (li->sb) | |
6f481af2 | 66 | li->sb->ops->mapped(li->sb, isMapped); |
8f52cd47 | 67 | } |
68 | ||
69 | static void listboxPlace(newtComponent co, int newLeft, int newTop) { | |
70 | struct listbox * li = co->data; | |
71 | ||
72 | co->top = newTop; | |
73 | co->left = newLeft; | |
74 | ||
75 | if (li->sb) | |
6f481af2 | 76 | li->sb->ops->place(li->sb, co->left + co->width - li->bdxAdjust - 1, |
4014bc65 | 77 | co->top + li->bdyAdjust); |
e948278c | 78 | } |
79 | ||
962b92a5 | 80 | newtComponent newtListbox(int left, int top, int height, int flags) { |
b9523497 | 81 | newtComponent co, sb; |
962b92a5 | 82 | struct listbox * li; |
83 | ||
a61e44cc | 84 | if (!(co = malloc(sizeof(*co)))) |
6f481af2 | 85 | return NULL; |
962b92a5 | 86 | |
a61e44cc | 87 | if (!(li = malloc(sizeof(struct listbox)))) { |
6f481af2 | 88 | free(co); |
89 | return NULL; | |
a61e44cc | 90 | } |
91 | ||
92 | li->boxItems = NULL; | |
93 | li->numItems = 0; | |
94 | li->currItem = 0; | |
2dbc072e | 95 | li->numSelected = 0; |
a61e44cc | 96 | li->isActive = 0; |
babcb349 | 97 | li->userHasSetWidth = 0; |
a61e44cc | 98 | li->startShowItem = 0; |
dc3ac6cf | 99 | li->sbAdjust = 0; |
913d0524 | 100 | li->bdxAdjust = 0; |
101 | li->bdyAdjust = 0; | |
45f6c4fd | 102 | li->flags = flags & (NEWT_FLAG_RETURNEXIT | NEWT_FLAG_BORDER | |
6f481af2 | 103 | NEWT_FLAG_MULTIPLE | NEWT_FLAG_SHOWCURSOR); |
913d0524 | 104 | |
dd2f0e88 | 105 | if (li->flags & NEWT_FLAG_BORDER) { |
6f481af2 | 106 | li->bdxAdjust = 2; |
107 | li->bdyAdjust = 1; | |
913d0524 | 108 | } |
962b92a5 | 109 | |
aa564c1d | 110 | co->height = height; |
111 | li->curHeight = co->height - (2 * li->bdyAdjust); | |
112 | ||
0bf47501 | 113 | if (height) { |
6f481af2 | 114 | li->grow = 0; |
115 | if (flags & NEWT_FLAG_SCROLL) { | |
116 | sb = newtVerticalScrollbar(left, top + li->bdyAdjust, | |
117 | li->curHeight, | |
118 | COLORSET_LISTBOX, COLORSET_ACTLISTBOX); | |
119 | li->sbAdjust = 3; | |
120 | } else { | |
121 | sb = NULL; | |
122 | } | |
0bf47501 | 123 | } else { |
6f481af2 | 124 | li->grow = 1; |
125 | sb = NULL; | |
0bf47501 | 126 | } |
962b92a5 | 127 | |
a61e44cc | 128 | li->sb = sb; |
962b92a5 | 129 | co->data = li; |
913d0524 | 130 | co->isMapped = 0; |
962b92a5 | 131 | co->left = left; |
132 | co->top = top; | |
962b92a5 | 133 | co->ops = &listboxOps; |
134 | co->takesFocus = 1; | |
f37450e9 | 135 | co->callback = NULL; |
c101e99e | 136 | co->destroyCallback = NULL; |
962b92a5 | 137 | |
913d0524 | 138 | updateWidth(co, li, 5); |
913d0524 | 139 | |
962b92a5 | 140 | return co; |
141 | } | |
142 | ||
45f6c4fd | 143 | static inline void updateWidth(newtComponent co, struct listbox * li, |
6f481af2 | 144 | int maxField) { |
913d0524 | 145 | li->curWidth = maxField; |
146 | co->width = li->curWidth + li->sbAdjust + 2 * li->bdxAdjust; | |
147 | ||
148 | if (li->sb) | |
6f481af2 | 149 | li->sb->left = co->left + co->width - li->bdxAdjust - 1; |
913d0524 | 150 | } |
151 | ||
d5878365 | 152 | void newtListboxSetCurrentByKey(newtComponent co, void * key) { |
153 | struct listbox * li = co->data; | |
154 | struct items * item; | |
155 | int i; | |
156 | ||
157 | item = li->boxItems, i = 0; | |
158 | while (item && item->data != key) | |
6f481af2 | 159 | item = item->next, i++; |
d5878365 | 160 | |
161 | if (item) | |
6f481af2 | 162 | newtListboxSetCurrent(co, i); |
d5878365 | 163 | } |
164 | ||
4e9c4bb9 | 165 | void newtListboxSetCurrent(newtComponent co, int num) |
166 | { | |
7ea3dccd | 167 | struct listbox * li = co->data; |
d5878365 | 168 | |
a61e44cc | 169 | if (num >= li->numItems) |
6f481af2 | 170 | li->currItem = li->numItems - 1; |
a61e44cc | 171 | else if (num < 0) |
6f481af2 | 172 | li->currItem = 0; |
a61e44cc | 173 | else |
6f481af2 | 174 | li->currItem = num; |
a61e44cc | 175 | |
176 | if (li->currItem < li->startShowItem) | |
6f481af2 | 177 | li->startShowItem = li->currItem; |
dc598586 | 178 | else if (li->currItem - li->startShowItem > li->curHeight - 1) |
6f481af2 | 179 | li->startShowItem = li->currItem - li->curHeight + 1; |
dc598586 | 180 | if (li->startShowItem + li->curHeight > li->numItems) |
6f481af2 | 181 | li->startShowItem = li->numItems - li->curHeight; |
3a779f2f | 182 | if(li->startShowItem < 0) |
6f481af2 | 183 | li->startShowItem = 0; |
d5878365 | 184 | |
4e9c4bb9 | 185 | newtListboxRealSetCurrent(co); |
186 | } | |
187 | ||
d5878365 | 188 | static void newtListboxRealSetCurrent(newtComponent co) |
4e9c4bb9 | 189 | { |
190 | struct listbox * li = co->data; | |
d5878365 | 191 | |
0bf47501 | 192 | if(li->sb) |
6f481af2 | 193 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); |
913d0524 | 194 | listboxDraw(co); |
f37450e9 | 195 | if(co->callback) co->callback(co, co->callbackData); |
7ea3dccd | 196 | } |
197 | ||
913d0524 | 198 | void newtListboxSetWidth(newtComponent co, int width) { |
babcb349 | 199 | struct listbox * li = co->data; |
45f6c4fd | 200 | |
e948278c | 201 | co->width = width; |
913d0524 | 202 | li->curWidth = co->width - li->sbAdjust - 2 * li->bdxAdjust; |
babcb349 | 203 | li->userHasSetWidth = 1; |
4014bc65 | 204 | if (li->sb) |
205 | li->sb->left = co->left + co->width - li->bdxAdjust - 1; | |
913d0524 | 206 | listboxDraw(co); |
babcb349 | 207 | } |
208 | ||
2287215a | 209 | void * newtListboxGetCurrent(newtComponent co) { |
210 | struct listbox * li = co->data; | |
2287215a | 211 | int i; |
a61e44cc | 212 | struct items *item; |
2287215a | 213 | |
a61e44cc | 214 | for(i = 0, item = li->boxItems; item != NULL && i < li->currItem; |
6f481af2 | 215 | i++, item = item->next); |
2287215a | 216 | |
a61e44cc | 217 | if (item) |
6f481af2 | 218 | return (void *)item->data; |
2287215a | 219 | else |
6f481af2 | 220 | return NULL; |
2287215a | 221 | } |
222 | ||
dd2f0e88 | 223 | void newtListboxSelectItem(newtComponent co, const void * key, |
6f481af2 | 224 | enum newtFlagsSense sense) |
46263d9e | 225 | { |
226 | struct listbox * li = co->data; | |
227 | int i; | |
dd2f0e88 | 228 | struct items * item; |
45f6c4fd | 229 | |
dd2f0e88 | 230 | item = li->boxItems, i = 0; |
231 | while (item && item->data != key) | |
6f481af2 | 232 | item = item->next, i++; |
dd2f0e88 | 233 | |
234 | if (!item) return; | |
235 | ||
236 | if (item->isSelected) | |
6f481af2 | 237 | li->numSelected--; |
dd2f0e88 | 238 | |
239 | switch(sense) { | |
6f481af2 | 240 | case NEWT_FLAGS_RESET: |
241 | item->isSelected = 0; break; | |
242 | case NEWT_FLAGS_SET: | |
243 | item->isSelected = 1; break; | |
244 | case NEWT_FLAGS_TOGGLE: | |
245 | item->isSelected = !item->isSelected; | |
46263d9e | 246 | } |
dd2f0e88 | 247 | |
248 | if (item->isSelected) | |
6f481af2 | 249 | li->numSelected++; |
dd2f0e88 | 250 | |
913d0524 | 251 | listboxDraw(co); |
46263d9e | 252 | } |
253 | ||
254 | void newtListboxClearSelection(newtComponent co) | |
255 | { | |
256 | struct items *item; | |
257 | struct listbox * li = co->data; | |
258 | ||
259 | for(item = li->boxItems; item != NULL; | |
6f481af2 | 260 | item = item->next) |
261 | item->isSelected = 0; | |
69bf2308 | 262 | li->numSelected = 0; |
913d0524 | 263 | listboxDraw(co); |
46263d9e | 264 | } |
265 | ||
2dbc072e | 266 | /* Free the returned array after use, but NOT the values in the array */ |
cb586ef6 | 267 | void ** newtListboxGetSelection(newtComponent co, int *numitems) |
2dbc072e | 268 | { |
269 | struct listbox * li; | |
270 | int i; | |
271 | void **retval; | |
272 | struct items *item; | |
273 | ||
cb586ef6 | 274 | if(!co || !numitems) return NULL; |
2dbc072e | 275 | |
276 | li = co->data; | |
277 | if(!li || !li->numSelected) return NULL; | |
278 | ||
cb586ef6 | 279 | retval = malloc(li->numSelected * sizeof(void *)); |
2dbc072e | 280 | for(i = 0, item = li->boxItems; item != NULL; |
6f481af2 | 281 | item = item->next) |
282 | if(item->isSelected) | |
283 | retval[i++] = (void *)item->data; | |
cb586ef6 | 284 | *numitems = li->numSelected; |
2dbc072e | 285 | return retval; |
286 | } | |
287 | ||
dd2f0e88 | 288 | void newtListboxSetEntry(newtComponent co, int num, const char * text) { |
a61e44cc | 289 | struct listbox * li = co->data; |
63231242 | 290 | int i; |
a61e44cc | 291 | struct items *item; |
292 | ||
293 | for(i = 0, item = li->boxItems; item != NULL && i < num; | |
6f481af2 | 294 | i++, item = item->next); |
a61e44cc | 295 | |
296 | if(!item) | |
6f481af2 | 297 | return; |
3a779f2f | 298 | else { |
6f481af2 | 299 | free(item->text); |
300 | item->text = strdup(text); | |
3a779f2f | 301 | } |
349586bb | 302 | if (li->userHasSetWidth == 0 && wstrlen(text,-1) > li->curWidth) { |
6f481af2 | 303 | updateWidth(co, li, wstrlen(text,-1)); |
a61e44cc | 304 | } |
305 | ||
306 | if (num >= li->startShowItem && num <= li->startShowItem + co->height) | |
6f481af2 | 307 | listboxDraw(co); |
a61e44cc | 308 | } |
309 | ||
a61e44cc | 310 | void newtListboxSetData(newtComponent co, int num, void * data) { |
2287215a | 311 | struct listbox * li = co->data; |
a61e44cc | 312 | int i; |
313 | struct items *item; | |
2287215a | 314 | |
a61e44cc | 315 | for(i = 0, item = li->boxItems; item != NULL && i < num; |
6f481af2 | 316 | i++, item = item->next); |
2287215a | 317 | |
3341bdc5 ML |
318 | if (item) |
319 | item->data = data; | |
2287215a | 320 | } |
321 | ||
dd2f0e88 | 322 | int newtListboxAppendEntry(newtComponent co, const char * text, |
6f481af2 | 323 | const void * data) { |
962b92a5 | 324 | struct listbox * li = co->data; |
a61e44cc | 325 | struct items *item; |
326 | ||
327 | if(li->boxItems) { | |
6f481af2 | 328 | for (item = li->boxItems; item->next != NULL; item = item->next); |
962b92a5 | 329 | |
6f481af2 | 330 | item = item->next = malloc(sizeof(struct items)); |
a61e44cc | 331 | } else { |
6f481af2 | 332 | item = li->boxItems = malloc(sizeof(struct items)); |
962b92a5 | 333 | } |
334 | ||
349586bb | 335 | if (!li->userHasSetWidth && text && (wstrlen(text,-1) > li->curWidth)) |
6f481af2 | 336 | updateWidth(co, li, wstrlen(text,-1)); |
a61e44cc | 337 | |
a507b3ec | 338 | item->text = strdup(text); item->data = data; item->next = NULL; |
46263d9e | 339 | item->isSelected = 0; |
45f6c4fd | 340 | |
0bf47501 | 341 | if (li->grow) |
6f481af2 | 342 | co->height++, li->curHeight++; |
962b92a5 | 343 | li->numItems++; |
a61e44cc | 344 | |
a507b3ec | 345 | return 0; |
a61e44cc | 346 | } |
347 | ||
d4109c37 | 348 | int newtListboxInsertEntry(newtComponent co, const char * text, |
6f481af2 | 349 | const void * data, void * key) { |
a61e44cc | 350 | struct listbox * li = co->data; |
351 | struct items *item, *t; | |
962b92a5 | 352 | |
a61e44cc | 353 | if (li->boxItems) { |
6f481af2 | 354 | if (key) { |
355 | item = li->boxItems; | |
356 | while (item && item->data != key) item = item->next; | |
357 | ||
358 | if (!item) return 1; | |
359 | ||
360 | t = item->next; | |
361 | item = item->next = malloc(sizeof(struct items)); | |
362 | item->next = t; | |
363 | } else { | |
364 | t = li->boxItems; | |
365 | item = li->boxItems = malloc(sizeof(struct items)); | |
366 | item->next = t; | |
367 | } | |
a507b3ec | 368 | } else if (key) { |
6f481af2 | 369 | return 1; |
a61e44cc | 370 | } else { |
6f481af2 | 371 | item = li->boxItems = malloc(sizeof(struct items)); |
372 | item->next = NULL; | |
a61e44cc | 373 | } |
374 | ||
349586bb | 375 | if (!li->userHasSetWidth && text && (wstrlen(text,-1) > li->curWidth)) |
6f481af2 | 376 | updateWidth(co, li, wstrlen(text,-1)); |
a61e44cc | 377 | |
a507b3ec | 378 | item->text = strdup(text?text:"(null)"); item->data = data; |
46263d9e | 379 | item->isSelected = 0; |
45f6c4fd | 380 | |
b9523497 | 381 | if (li->sb) |
6f481af2 | 382 | li->sb->left = co->left + co->width - li->bdxAdjust - 1; |
a61e44cc | 383 | li->numItems++; |
46263d9e | 384 | |
913d0524 | 385 | listboxDraw(co); |
a61e44cc | 386 | |
a507b3ec | 387 | return 0; |
962b92a5 | 388 | } |
389 | ||
a507b3ec | 390 | int newtListboxDeleteEntry(newtComponent co, void * key) { |
962b92a5 | 391 | struct listbox * li = co->data; |
a507b3ec | 392 | int widest = 0, t; |
a880525e | 393 | struct items *item, *item2 = NULL; |
a507b3ec | 394 | int num; |
aed35dda | 395 | |
4a93351d | 396 | if (li->boxItems == NULL || li->numItems <= 0) |
6f481af2 | 397 | return 0; |
a61e44cc | 398 | |
a507b3ec | 399 | num = 0; |
a61e44cc | 400 | |
a507b3ec | 401 | item2 = NULL, item = li->boxItems; |
402 | while (item && item->data != key) { | |
6f481af2 | 403 | item2 = item; |
404 | item = item->next; | |
405 | num++; | |
a507b3ec | 406 | } |
a61e44cc | 407 | |
a507b3ec | 408 | if (!item) |
6f481af2 | 409 | return -1; |
a61e44cc | 410 | |
a507b3ec | 411 | if (item2) |
6f481af2 | 412 | item2->next = item->next; |
a507b3ec | 413 | else |
6f481af2 | 414 | li->boxItems = item->next; |
a507b3ec | 415 | |
416 | free(item->text); | |
a61e44cc | 417 | free(item); |
418 | li->numItems--; | |
a507b3ec | 419 | |
420 | if (!li->userHasSetWidth) { | |
6f481af2 | 421 | widest = 0; |
422 | for (item = li->boxItems; item != NULL; item = item->next) | |
423 | if ((t = wstrlen(item->text,-1)) > widest) widest = t; | |
a507b3ec | 424 | } |
425 | ||
426 | if (li->currItem >= num) | |
6f481af2 | 427 | li->currItem--; |
a61e44cc | 428 | |
913d0524 | 429 | if (!li->userHasSetWidth) { |
6f481af2 | 430 | updateWidth(co, li, widest); |
babcb349 | 431 | } |
a61e44cc | 432 | |
913d0524 | 433 | listboxDraw(co); |
962b92a5 | 434 | |
a507b3ec | 435 | return 0; |
962b92a5 | 436 | } |
437 | ||
49a541f2 | 438 | void newtListboxClear(newtComponent co) |
439 | { | |
440 | struct listbox * li; | |
441 | struct items *anitem, *nextitem; | |
442 | if(co == NULL || (li = co->data) == NULL) | |
6f481af2 | 443 | return; |
49a541f2 | 444 | for(anitem = li->boxItems; anitem != NULL; anitem = nextitem) { |
6f481af2 | 445 | nextitem = anitem->next; |
446 | free(anitem->text); | |
447 | free(anitem); | |
49a541f2 | 448 | } |
449 | li->numItems = li->numSelected = li->currItem = li->startShowItem = 0; | |
450 | li->boxItems = NULL; | |
45f6c4fd | 451 | if (!li->userHasSetWidth) |
6f481af2 | 452 | updateWidth(co, li, 5); |
49a541f2 | 453 | } |
454 | ||
1dcea57f | 455 | int newtListboxItemCount(newtComponent co) |
456 | { | |
457 | struct listbox *li = co->data; | |
458 | return li->numItems; | |
459 | } | |
460 | ||
a61e44cc | 461 | /* If you don't want to get back the text, pass in NULL for the ptr-ptr. Same |
462 | goes for the data. */ | |
463 | void newtListboxGetEntry(newtComponent co, int num, char **text, void **data) { | |
962b92a5 | 464 | struct listbox * li = co->data; |
a61e44cc | 465 | int i; |
466 | struct items *item; | |
467 | ||
468 | if (!li->boxItems || num >= li->numItems) { | |
6f481af2 | 469 | if(text) |
470 | *text = NULL; | |
471 | if(data) | |
472 | *data = NULL; | |
473 | return; | |
a61e44cc | 474 | } |
475 | ||
476 | i = 0; | |
45f6c4fd | 477 | item = li->boxItems; |
a61e44cc | 478 | while (item && i < num) { |
6f481af2 | 479 | i++, item = item->next; |
a61e44cc | 480 | } |
481 | ||
482 | if (item) { | |
6f481af2 | 483 | if (text) |
484 | *text = item->text; | |
485 | if (data) | |
486 | *data = (void *)item->data; | |
a61e44cc | 487 | } |
488 | } | |
489 | ||
490 | static void listboxDraw(newtComponent co) | |
491 | { | |
492 | struct listbox * li = co->data; | |
493 | struct items *item; | |
494 | int i, j; | |
495 | ||
913d0524 | 496 | if (!co->isMapped) return ; |
c6e478c2 | 497 | |
7ff5fd71 | 498 | newtTrashScreen(); |
499 | ||
dd2f0e88 | 500 | if(li->flags & NEWT_FLAG_BORDER) { |
69f73704 | 501 | if(li->isActive) |
6f481af2 | 502 | SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); |
69f73704 | 503 | else |
504 | SLsmg_set_color(NEWT_COLORSET_LISTBOX); | |
505 | ||
913d0524 | 506 | newtDrawBox(co->left, co->top, co->width, co->height, 0); |
69f73704 | 507 | } |
0b38669d | 508 | |
aa564c1d | 509 | if(li->sb) |
6f481af2 | 510 | li->sb->ops->draw(li->sb); |
aa564c1d | 511 | |
69f73704 | 512 | SLsmg_set_color(NEWT_COLORSET_LISTBOX); |
45f6c4fd | 513 | |
a61e44cc | 514 | for(i = 0, item = li->boxItems; item != NULL && i < li->startShowItem; |
6f481af2 | 515 | i++, item = item->next); |
a61e44cc | 516 | |
517 | j = i; | |
a61e44cc | 518 | |
913d0524 | 519 | for (i = 0; item != NULL && i < li->curHeight; i++, item = item->next) { |
6f481af2 | 520 | if (!item->text) continue; |
a61e44cc | 521 | |
6f481af2 | 522 | newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust); |
523 | if(j + i == li->currItem) { | |
9fc6a6b0 | 524 | if(li->isActive) |
6f481af2 | 525 | SLsmg_set_color(NEWT_COLORSET_ACTSELLISTBOX); |
526 | else | |
527 | SLsmg_set_color(NEWT_COLORSET_ACTLISTBOX); | |
528 | } else if(item->isSelected) | |
529 | SLsmg_set_color(NEWT_COLORSET_SELLISTBOX); | |
530 | else | |
531 | SLsmg_set_color(NEWT_COLORSET_LISTBOX); | |
45f6c4fd | 532 | |
8e0e899c | 533 | SLsmg_write_nstring(item->text, li->curWidth); |
a61e44cc | 534 | |
9fc6a6b0 | 535 | if (li->flags & NEWT_FLAG_MULTIPLE) { |
536 | newtGotorc(co->top + i + li->bdyAdjust, co->left + li->bdxAdjust); | |
537 | SLsmg_set_color(item->isSelected ? | |
538 | NEWT_COLORSET_SELLISTBOX : NEWT_COLORSET_LISTBOX); | |
539 | SLsmg_write_nstring(item->text, 1); | |
540 | } | |
a61e44cc | 541 | } |
f4f5c676 | 542 | newtGotorc(co->top + (li->currItem - li->startShowItem) + li->bdyAdjust, |
543 | co->left + li->bdxAdjust); | |
a61e44cc | 544 | } |
545 | ||
546 | static struct eventResult listboxEvent(newtComponent co, struct event ev) { | |
2287215a | 547 | struct eventResult er; |
a61e44cc | 548 | struct listbox * li = co->data; |
d63d1c70 | 549 | struct items *item; |
550 | int i; | |
551 | ||
a61e44cc | 552 | er.result = ER_IGNORED; |
45f6c4fd | 553 | |
0b38669d | 554 | if(ev.when == EV_EARLY || ev.when == EV_LATE) { |
6f481af2 | 555 | return er; |
0b38669d | 556 | } |
45f6c4fd | 557 | |
a61e44cc | 558 | switch(ev.event) { |
559 | case EV_KEYPRESS: | |
6f481af2 | 560 | if (!li->isActive) break; |
561 | ||
562 | switch(ev.u.key) { | |
563 | case ' ': | |
564 | if(!(li->flags & NEWT_FLAG_MULTIPLE)) break; | |
565 | newtListboxSelectItem(co, newtListboxGetCurrent(co), | |
566 | NEWT_FLAGS_TOGGLE); | |
567 | er.result = ER_SWALLOWED; | |
568 | /* We don't break here, because it is cool to be able to | |
569 | hold space to select a bunch of items in a list at once */ | |
570 | ||
571 | case NEWT_KEY_DOWN: | |
572 | if(li->numItems <= 0) break; | |
573 | if(li->currItem < li->numItems - 1) { | |
574 | li->currItem++; | |
575 | if(li->currItem > (li->startShowItem + li->curHeight - 1)) { | |
576 | li->startShowItem = li->currItem - li->curHeight + 1; | |
577 | if(li->startShowItem + li->curHeight > li->numItems) | |
578 | li->startShowItem = li->numItems - li->curHeight; | |
579 | } | |
580 | if(li->sb) | |
581 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
582 | listboxDraw(co); | |
583 | } | |
584 | if(co->callback) co->callback(co, co->callbackData); | |
585 | er.result = ER_SWALLOWED; | |
586 | break; | |
587 | ||
588 | case NEWT_KEY_ENTER: | |
589 | if(li->numItems <= 0) break; | |
590 | if(li->flags & NEWT_FLAG_RETURNEXIT) | |
591 | er.result = ER_EXITFORM; | |
592 | break; | |
593 | ||
594 | case NEWT_KEY_UP: | |
595 | if(li->numItems <= 0) break; | |
596 | if(li->currItem > 0) { | |
597 | li->currItem--; | |
598 | if(li->currItem < li->startShowItem) | |
599 | li->startShowItem = li->currItem; | |
600 | if(li->sb) | |
601 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
602 | listboxDraw(co); | |
603 | } | |
604 | if(co->callback) co->callback(co, co->callbackData); | |
605 | er.result = ER_SWALLOWED; | |
606 | break; | |
607 | ||
608 | case NEWT_KEY_PGUP: | |
609 | if(li->numItems <= 0) break; | |
610 | li->startShowItem -= li->curHeight - 1; | |
611 | if(li->startShowItem < 0) | |
612 | li->startShowItem = 0; | |
613 | li->currItem -= li->curHeight - 1; | |
614 | if(li->currItem < 0) | |
615 | li->currItem = 0; | |
616 | newtListboxRealSetCurrent(co); | |
617 | er.result = ER_SWALLOWED; | |
618 | break; | |
619 | ||
620 | case NEWT_KEY_PGDN: | |
621 | if(li->numItems <= 0) break; | |
622 | li->startShowItem += li->curHeight; | |
623 | if(li->startShowItem > (li->numItems - li->curHeight)) { | |
624 | li->startShowItem = li->numItems - li->curHeight; | |
625 | } | |
626 | li->currItem += li->curHeight; | |
627 | if(li->currItem >= li->numItems) { | |
628 | li->currItem = li->numItems - 1; | |
629 | } | |
630 | newtListboxRealSetCurrent(co); | |
631 | er.result = ER_SWALLOWED; | |
632 | break; | |
633 | ||
634 | case NEWT_KEY_HOME: | |
635 | if(li->numItems <= 0) break; | |
636 | newtListboxSetCurrent(co, 0); | |
637 | er.result = ER_SWALLOWED; | |
638 | break; | |
639 | ||
640 | case NEWT_KEY_END: | |
641 | if(li->numItems <= 0) break; | |
642 | li->startShowItem = li->numItems - li->curHeight; | |
643 | if(li->startShowItem < 0) | |
644 | li->startShowItem = 0; | |
645 | li->currItem = li->numItems - 1; | |
646 | newtListboxRealSetCurrent(co); | |
647 | er.result = ER_SWALLOWED; | |
648 | break; | |
649 | default: | |
650 | if (li->numItems <= 0) break; | |
f3de1284 | 651 | if (ev.u.key < NEWT_KEY_EXTRA_BASE && isalpha(ev.u.key)) { |
6f481af2 | 652 | for(i = 0, item = li->boxItems; item != NULL && |
653 | i < li->currItem; i++, item = item->next); | |
654 | ||
655 | if (item && item->text && (toupper(*item->text) == toupper(ev.u.key))) { | |
656 | item = item->next; | |
657 | i++; | |
658 | } else { | |
659 | item = li->boxItems; | |
660 | i = 0; | |
661 | } | |
662 | while (item && item->text && | |
663 | toupper(*item->text) != toupper(ev.u.key)) { | |
664 | item = item->next; | |
665 | i++; | |
666 | } | |
667 | if (item) { | |
668 | li->currItem = i; | |
669 | if(li->currItem < li->startShowItem || | |
670 | li->currItem > li->startShowItem) | |
671 | li->startShowItem = | |
672 | li->currItem > li->numItems - li->curHeight ? | |
3341bdc5 | 673 | li->numItems - li->curHeight : |
6f481af2 | 674 | li->currItem; |
675 | if(li->sb) | |
676 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
677 | newtListboxRealSetCurrent(co); | |
678 | er.result = ER_SWALLOWED; | |
679 | } | |
680 | } | |
681 | } | |
682 | break; | |
45f6c4fd | 683 | |
a61e44cc | 684 | case EV_FOCUS: |
6f481af2 | 685 | li->isActive = 1; |
686 | listboxDraw(co); | |
687 | if(li->flags & NEWT_FLAG_SHOWCURSOR) | |
688 | newtCursorOn(); | |
689 | er.result = ER_SWALLOWED; | |
690 | break; | |
a61e44cc | 691 | |
692 | case EV_UNFOCUS: | |
6f481af2 | 693 | li->isActive = 0; |
694 | listboxDraw(co); | |
695 | if(li->flags & NEWT_FLAG_SHOWCURSOR) | |
696 | newtCursorOff(); | |
697 | er.result = ER_SWALLOWED; | |
698 | break; | |
45f6c4fd | 699 | |
700 | case EV_MOUSE: | |
6f481af2 | 701 | /* if this mouse click was within the listbox, make the current |
702 | item the item clicked on. */ | |
703 | /* Up scroll arrow */ | |
704 | if (li->sb && | |
705 | ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 && | |
706 | ev.u.mouse.y == co->top + li->bdyAdjust) { | |
707 | if(li->numItems <= 0) break; | |
708 | if(li->currItem > 0) { | |
709 | li->currItem--; | |
710 | if(li->currItem < li->startShowItem) | |
711 | li->startShowItem = li->currItem; | |
712 | if(li->sb) | |
713 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
714 | listboxDraw(co); | |
715 | } | |
716 | if(co->callback) co->callback(co, co->callbackData); | |
717 | er.result = ER_SWALLOWED; | |
718 | break; | |
719 | } | |
720 | /* Down scroll arrow */ | |
721 | if (li->sb && | |
722 | ev.u.mouse.x == co->left + co->width - li->bdxAdjust - 1 && | |
723 | ev.u.mouse.y == co->top + co->height - li->bdyAdjust - 1) { | |
724 | if(li->numItems <= 0) break; | |
725 | if(li->currItem < li->numItems - 1) { | |
726 | li->currItem++; | |
727 | if(li->currItem > (li->startShowItem + li->curHeight - 1)) { | |
728 | li->startShowItem = li->currItem - li->curHeight + 1; | |
729 | if(li->startShowItem + li->curHeight > li->numItems) | |
730 | li->startShowItem = li->numItems - li->curHeight; | |
731 | } | |
732 | if(li->sb) | |
733 | newtScrollbarSet(li->sb, li->currItem + 1, li->numItems); | |
734 | listboxDraw(co); | |
735 | } | |
736 | if(co->callback) co->callback(co, co->callbackData); | |
737 | er.result = ER_SWALLOWED; | |
738 | break; | |
739 | } | |
740 | if ((ev.u.mouse.y >= co->top + li->bdyAdjust) && | |
741 | (ev.u.mouse.y <= co->top + co->height - (li->bdyAdjust * 2)) && | |
742 | (ev.u.mouse.x >= co->left + li->bdxAdjust) && | |
743 | (ev.u.mouse.x <= co->left + co->width + (li->bdxAdjust * 2))) { | |
744 | li->currItem = li->startShowItem + | |
745 | (ev.u.mouse.y - li->bdyAdjust - co->top); | |
746 | newtListboxRealSetCurrent(co); | |
747 | listboxDraw(co); | |
748 | if(co->callback) co->callback(co, co->callbackData); | |
749 | er.result = ER_SWALLOWED; | |
750 | break; | |
751 | } | |
2287215a | 752 | } |
962b92a5 | 753 | |
a61e44cc | 754 | return er; |
962b92a5 | 755 | } |
756 | ||
757 | static void listboxDestroy(newtComponent co) { | |
758 | struct listbox * li = co->data; | |
a61e44cc | 759 | struct items * item, * nextitem; |
760 | ||
638f672c | 761 | item = li->boxItems; |
a61e44cc | 762 | |
763 | while (item != NULL) { | |
6f481af2 | 764 | nextitem = item->next; |
765 | free(item->text); | |
766 | free(item); | |
767 | item = nextitem; | |
a61e44cc | 768 | } |
962b92a5 | 769 | |
a50f10e7 | 770 | if (li->sb) li->sb->ops->destroy(li->sb); |
771 | ||
962b92a5 | 772 | free(li); |
773 | free(co); | |
774 | } |