- More code for multiple selection in WMList.
[wmaker-crm.git] / WINGs / wlist.c
blob46747d3b0f4ca8aa9244154a152f4abd9d4d93aa
5 #include "WINGsP.h"
7 char *WMListDidScrollNotification = "WMListDidScrollNotification";
8 char *WMListSelectionDidChangeNotification = "WMListSelectionDidChangeNotification";
10 typedef struct W_List {
11 W_Class widgetClass;
12 W_View *view;
14 WMArray *items; /* list of WMListItem */
15 WMArray *selectedItems; /* list of selected WMListItems */
17 //short selectedItem;
19 short itemHeight;
21 short topItem; /* index of first visible item */
23 short fullFitLines; /* no of lines that fit entirely */
25 void *clientData;
26 WMAction *action;
27 void *doubleClientData;
28 WMAction *doubleAction;
30 WMListDrawProc *draw;
32 WMHandlerID *idleID; /* for updating the scroller after adding elements */
34 WMScroller *vScroller;
36 struct {
37 unsigned int allowMultipleSelection:1;
38 unsigned int allowEmptySelection:1;
39 unsigned int userDrawn:1;
40 unsigned int userItemHeight:1;
41 unsigned int dontFitAll:1; /* 1 = last item won't be fully visible */
42 unsigned int redrawPending:1;
43 unsigned int buttonPressed:1;
44 unsigned int buttonWasPressed:1;
45 } flags;
46 } List;
50 #define DEFAULT_WIDTH 150
51 #define DEFAULT_HEIGHT 150
54 static void destroyList(List *lPtr);
55 static void paintList(List *lPtr);
58 static void handleEvents(XEvent *event, void *data);
59 static void handleActionEvents(XEvent *event, void *data);
60 static void updateScroller(List *lPtr);
62 static void vScrollCallBack(WMWidget *scroller, void *self);
64 static void updateGeometry(WMList *lPtr);
65 static void didResizeList();
68 W_ViewDelegate _ListViewDelegate = {
69 NULL,
70 NULL,
71 didResizeList,
72 NULL,
73 NULL
77 static void
78 releaseItem(void *data)
80 WMListItem *item = (WMListItem*)data;
82 if (item->text)
83 wfree(item->text);
84 wfree(item);
88 WMList*
89 WMCreateList(WMWidget *parent)
91 List *lPtr;
92 W_Screen *scrPtr = W_VIEW(parent)->screen;
94 lPtr = wmalloc(sizeof(List));
95 memset(lPtr, 0, sizeof(List));
97 lPtr->widgetClass = WC_List;
99 lPtr->view = W_CreateView(W_VIEW(parent));
100 if (!lPtr->view) {
101 wfree(lPtr);
102 return NULL;
104 lPtr->view->self = lPtr;
106 lPtr->view->delegate = &_ListViewDelegate;
108 WMCreateEventHandler(lPtr->view, ExposureMask|StructureNotifyMask
109 |ClientMessageMask, handleEvents, lPtr);
111 WMCreateEventHandler(lPtr->view, ButtonPressMask|ButtonReleaseMask
112 |EnterWindowMask|LeaveWindowMask|ButtonMotionMask,
113 handleActionEvents, lPtr);
115 lPtr->itemHeight = WMFontHeight(scrPtr->normalFont) + 1;
117 lPtr->items = WMCreateArrayWithDestructor(4, releaseItem);
118 lPtr->selectedItems = WMCreateArray(4);
120 /* create the vertical scroller */
121 lPtr->vScroller = WMCreateScroller(lPtr);
122 WMMoveWidget(lPtr->vScroller, 1, 1);
123 WMSetScrollerArrowsPosition(lPtr->vScroller, WSAMaxEnd);
125 WMSetScrollerAction(lPtr->vScroller, vScrollCallBack, lPtr);
127 /* make the scroller map itself when it's realized */
128 WMMapWidget(lPtr->vScroller);
130 W_ResizeView(lPtr->view, DEFAULT_WIDTH, DEFAULT_HEIGHT);
132 //lPtr->selectedItem = -1;
134 return lPtr;
138 void
139 WMSetListAllowMultipleSelection(WMList *lPtr, Bool flag)
141 lPtr->flags.allowMultipleSelection = flag ? 1 : 0;
146 void
147 WMSetListAllowEmptySelection(WMList *lPtr, Bool flag)
149 lPtr->flags.allowEmptySelection = flag ? 1 : 0;
153 static int
154 comparator(const void *a, const void *b)
156 return (strcmp((*(WMListItem**)a)->text, (*(WMListItem**)b)->text));
160 void
161 WMSortListItems(WMList *lPtr)
163 WMSortArray(lPtr->items, comparator);
165 paintList(lPtr);
170 void
171 WMSortListItemsWithComparer(WMList *lPtr, WMCompareDataProc *func)
173 WMSortArray(lPtr->items, func);
175 paintList(lPtr);
180 WMListItem*
181 WMInsertListItem(WMList *lPtr, int row, char *text)
183 WMListItem *item;
185 CHECK_CLASS(lPtr, WC_List);
187 item = wmalloc(sizeof(WMListItem));
188 memset(item, 0, sizeof(WMListItem));
189 item->text = wstrdup(text);
192 //if (lPtr->selectedItem >= row && lPtr->selectedItem >= 0
193 // && row >= 0)
194 // lPtr->selectedItem++;
196 row = WMIN(row, WMGetArrayItemCount(lPtr->items));
198 if (row < 0)
199 WMAddToArray(lPtr->items, item);
200 else
201 WMInsertInArray(lPtr->items, row, item);
203 /* update the scroller when idle, so that we don't waste time
204 * updating it when another item is going to be added later */
205 if (!lPtr->idleID) {
206 lPtr->idleID = WMAddIdleHandler((WMCallback*)updateScroller, lPtr);
209 return item;
214 WMRemoveListItem(WMList *lPtr, int row)
216 WMListItem *item;
217 int topItem = lPtr->topItem;
218 int selNotify = 0;
220 CHECK_CLASS(lPtr, WC_List);
222 if (row < 0 || row >= WMGetArrayItemCount(lPtr->items))
223 return 0;
225 item = WMGetFromArray(lPtr->items, row);
226 if (item->selected) {
227 WMRemoveFromArray(lPtr->selectedItems, item);
228 //WMUnselectListItem(lPtr, row);
229 selNotify = 1;
232 //if (lPtr->selectedItem == row) {
233 // lPtr->selectedItem = -1;
234 // selNotify = 1;
235 //} else if (lPtr->selectedItem > row) {
236 // lPtr->selectedItem--;
239 if (row <= lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll)
240 lPtr->topItem--;
241 if (lPtr->topItem < 0)
242 lPtr->topItem = 0;
244 WMDeleteFromArray(lPtr->items, row);
246 if (!lPtr->idleID) {
247 lPtr->idleID = WMAddIdleHandler((WMCallback*)updateScroller, lPtr);
249 if (lPtr->topItem != topItem) {
250 WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
252 if (selNotify) {
253 WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
256 return 1;
260 WMListItem*
261 WMGetListItem(WMList *lPtr, int row)
263 return WMGetFromArray(lPtr->items, row);
267 WMArray*
268 WMGetListItems(WMList *lPtr)
270 return lPtr->items;
274 void
275 WMSetListUserDrawProc(WMList *lPtr, WMListDrawProc *proc)
277 lPtr->flags.userDrawn = 1;
278 lPtr->draw = proc;
282 void
283 WMSetListUserDrawItemHeight(WMList *lPtr, unsigned short height)
285 assert(height > 0);
287 lPtr->flags.userItemHeight = 1;
288 lPtr->itemHeight = height;
290 updateGeometry(lPtr);
294 void
295 WMClearList(WMList *lPtr)
297 int selNo = WMGetArrayItemCount(lPtr->selectedItems);
299 WMEmptyArray(lPtr->selectedItems);
300 WMEmptyArray(lPtr->items);
302 lPtr->topItem = 0;
303 //lPtr->selectedItem = -1;
305 if (!lPtr->idleID) {
306 WMDeleteIdleHandler(lPtr->idleID);
307 lPtr->idleID = NULL;
309 if (lPtr->view->flags.realized) {
310 updateScroller(lPtr);
312 if (selNo > 0) {
313 WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
318 void
319 WMSetListAction(WMList *lPtr, WMAction *action, void *clientData)
321 lPtr->action = action;
322 lPtr->clientData = clientData;
326 void
327 WMSetListDoubleAction(WMList *lPtr, WMAction *action, void *clientData)
329 lPtr->doubleAction = action;
330 lPtr->doubleClientData = clientData;
334 WMArray*
335 WMGetListSelectedItems(WMList *lPtr)
337 return lPtr->selectedItems;
341 WMListItem*
342 WMGetListSelectedItem(WMList *lPtr)
344 return WMGetFromArray(lPtr->selectedItems, 0);
349 WMGetListSelectedItemRow(WMList *lPtr)
351 WMListItem *item = WMGetFromArray(lPtr->selectedItems, 0);
353 return (item!=NULL ? WMGetFirstInArray(lPtr->items, item) : WLNotFound);
358 WMGetListItemHeight(WMList *lPtr)
360 return lPtr->itemHeight;
364 void
365 WMSetListPosition(WMList *lPtr, int row)
367 lPtr->topItem = row;
368 if (lPtr->topItem + lPtr->fullFitLines > WMGetArrayItemCount(lPtr->items))
369 lPtr->topItem = WMGetArrayItemCount(lPtr->items) - lPtr->fullFitLines;
371 if (lPtr->topItem < 0)
372 lPtr->topItem = 0;
374 if (lPtr->view->flags.realized)
375 updateScroller(lPtr);
379 void
380 WMSetListBottomPosition(WMList *lPtr, int row)
382 if (WMGetArrayItemCount(lPtr->items) > lPtr->fullFitLines) {
383 lPtr->topItem = row - lPtr->fullFitLines;
384 if (lPtr->topItem < 0)
385 lPtr->topItem = 0;
386 if (lPtr->view->flags.realized)
387 updateScroller(lPtr);
393 WMGetListNumberOfRows(WMList *lPtr)
395 return WMGetArrayItemCount(lPtr->items);
400 WMGetListPosition(WMList *lPtr)
402 return lPtr->topItem;
406 Bool
407 WMListAllowsMultipleSelection(WMList *lPtr)
409 return lPtr->flags.allowMultipleSelection;
413 Bool
414 WMListAllowsEmptySelection(WMList *lPtr)
416 return lPtr->flags.allowEmptySelection;
420 static void
421 scrollByAmount(WMList *lPtr, int amount)
423 int itemCount = WMGetArrayItemCount(lPtr->items);
425 if ((amount < 0 && lPtr->topItem > 0) ||
426 (amount > 0 && (lPtr->topItem + lPtr->fullFitLines < itemCount))) {
428 lPtr->topItem += amount;
429 if (lPtr->topItem < 0)
430 lPtr->topItem = 0;
431 if (lPtr->topItem + lPtr->fullFitLines > itemCount)
432 lPtr->topItem = itemCount - lPtr->fullFitLines;
434 updateScroller(lPtr);
439 static void
440 vScrollCallBack(WMWidget *scroller, void *self)
442 WMList *lPtr = (WMList*)self;
443 int height;
444 int oldTopItem = lPtr->topItem;
445 int itemCount = WMGetArrayItemCount(lPtr->items);
447 height = lPtr->view->size.height - 4;
449 switch (WMGetScrollerHitPart((WMScroller*)scroller)) {
450 case WSDecrementLine:
451 //if (lPtr->topItem > 0) {
452 // lPtr->topItem--;
454 // updateScroller(lPtr);
456 scrollByAmount(lPtr, -1);
457 break;
459 case WSIncrementLine:
460 //if (lPtr->topItem + lPtr->fullFitLines < itemCount) {
461 // lPtr->topItem++;
463 // updateScroller(lPtr);
465 scrollByAmount(lPtr, 1);
466 break;
468 case WSDecrementPage:
469 //if (lPtr->topItem > 0) {
470 // lPtr->topItem -= lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
471 // if (lPtr->topItem < 0)
472 // lPtr->topItem = 0;
474 // updateScroller(lPtr);
476 scrollByAmount(lPtr, -lPtr->fullFitLines+(1-lPtr->flags.dontFitAll)+1);
477 break;
479 case WSIncrementPage:
480 //if (lPtr->topItem + lPtr->fullFitLines < itemCount) {
481 // lPtr->topItem += lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
483 // if (lPtr->topItem + lPtr->fullFitLines > itemCount)
484 // lPtr->topItem = itemCount - lPtr->fullFitLines;
486 // updateScroller(lPtr);
488 scrollByAmount(lPtr, lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1);
489 break;
491 case WSKnob:
492 lPtr->topItem = WMGetScrollerValue(lPtr->vScroller) *
493 (float)(itemCount - lPtr->fullFitLines);
495 if (oldTopItem != lPtr->topItem)
496 paintList(lPtr); // use updateScroller(lPtr) here?
497 break;
499 case WSKnobSlot:
500 case WSNoPart:
501 default:
502 /* do nothing */
503 break;
506 if (lPtr->topItem != oldTopItem)
507 WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
511 static void
512 paintItem(List *lPtr, int index)
514 WMView *view = lPtr->view;
515 W_Screen *scr = view->screen;
516 int width, height, x, y;
517 WMListItem *itemPtr;
519 itemPtr = WMGetFromArray(lPtr->items, index);
521 width = lPtr->view->size.width - 2 - 19;
522 height = lPtr->itemHeight;
523 x = 19;
524 y = 2 + (index-lPtr->topItem) * lPtr->itemHeight + 1;
526 if (lPtr->flags.userDrawn) {
527 WMRect rect;
528 int flags;
530 rect.size.width = width;
531 rect.size.height = height;
532 rect.pos.x = x;
533 rect.pos.y = y;
535 flags = itemPtr->uflags;
536 if (itemPtr->disabled)
537 flags |= WLDSDisabled;
538 if (itemPtr->selected)
539 flags |= WLDSSelected;
540 if (itemPtr->isBranch)
541 flags |= WLDSIsBranch;
543 if (lPtr->draw)
544 (*lPtr->draw)(lPtr, index, view->window, itemPtr->text, flags,
545 &rect);
546 } else {
547 if (itemPtr->selected) {
548 XFillRectangle(scr->display, view->window, WMColorGC(scr->white),
549 x, y, width, height);
550 } else {
551 XClearArea(scr->display, view->window, x, y, width, height, False);
554 W_PaintText(view, view->window, scr->normalFont, x+4, y, width,
555 WALeft, WMColorGC(scr->black), False,
556 itemPtr->text, strlen(itemPtr->text));
562 static void
563 paintList(List *lPtr)
565 W_Screen *scrPtr = lPtr->view->screen;
566 int i, lim;
568 if (!lPtr->view->flags.mapped)
569 return;
571 if (WMGetArrayItemCount(lPtr->items) > 0) {
572 if (lPtr->topItem+lPtr->fullFitLines+lPtr->flags.dontFitAll
573 > WMGetArrayItemCount(lPtr->items)) {
575 lim = WMGetArrayItemCount(lPtr->items) - lPtr->topItem;
576 XClearArea(scrPtr->display, lPtr->view->window, 19,
577 2+lim*lPtr->itemHeight, lPtr->view->size.width-21,
578 lPtr->view->size.height-lim*lPtr->itemHeight-3, False);
579 } else {
580 lim = lPtr->fullFitLines + lPtr->flags.dontFitAll;
582 for (i = lPtr->topItem; i < lPtr->topItem + lim; i++) {
583 paintItem(lPtr, i);
585 } else {
586 XClearWindow(scrPtr->display, lPtr->view->window);
588 W_DrawRelief(scrPtr, lPtr->view->window, 0, 0, lPtr->view->size.width,
589 lPtr->view->size.height, WRSunken);
592 #if 0
593 static void
594 scrollTo(List *lPtr, int newTop)
598 #endif
600 static void
601 updateScroller(List *lPtr)
603 float knobProportion, floatValue, tmp;
604 int count = WMGetArrayItemCount(lPtr->items);
606 if (lPtr->idleID)
607 WMDeleteIdleHandler(lPtr->idleID);
608 lPtr->idleID = NULL;
610 paintList(lPtr);
612 if (count == 0 || count <= lPtr->fullFitLines)
613 WMSetScrollerParameters(lPtr->vScroller, 0, 1);
614 else {
615 tmp = lPtr->fullFitLines;
616 knobProportion = tmp/(float)count;
618 floatValue = (float)lPtr->topItem/(float)(count - lPtr->fullFitLines);
620 WMSetScrollerParameters(lPtr->vScroller, floatValue, knobProportion);
625 static void
626 handleEvents(XEvent *event, void *data)
628 List *lPtr = (List*)data;
630 CHECK_CLASS(data, WC_List);
633 switch (event->type) {
634 case Expose:
635 if (event->xexpose.count!=0)
636 break;
637 paintList(lPtr);
638 break;
640 case DestroyNotify:
641 destroyList(lPtr);
642 break;
648 static int
649 matchTitle(void *item, void *title)
651 return (strcmp(((WMListItem*)item)->text, (char*)title)==0 ? 1 : 0);
656 WMFindRowOfListItemWithTitle(WMList *lPtr, char *title)
658 return WMFindInArray(lPtr->items, matchTitle, title);
662 void
663 WMSelectListItem(WMList *lPtr, int row)
665 WMListItem *item, *oldSelected;
667 if (row >= WMGetArrayItemCount(lPtr->items))
668 return;
669 if (row < 0) {
670 /* Should row = -1 deselect all or just do nothing ?. Check it. -Dan */
671 if (!lPtr->flags.allowMultipleSelection) {
672 WMUnselectAllListItems(lPtr);
674 return;
677 item = WMGetFromArray(lPtr->items, row);
678 if (item->selected)
679 return; /* Return if already selected */
681 oldSelected = WMGetFromArray(lPtr->selectedItems, 0);
683 /* unselect previous selected item if case */
684 if (!lPtr->flags.allowMultipleSelection && oldSelected) {
685 int oldSelectedRow = WMGetListSelectedItemRow(lPtr);
687 // better call WMUnselectAllListItems() here? -Dan
688 oldSelected->selected = 0;
689 WMDeleteFromArray(lPtr->selectedItems, 0);
690 // This is faster and have the same effect in the single selected case
691 // but may leave xxx->selected flags set after a multi->single selected
692 // switch
693 //WMEmptyArray(lPtr->selectedItems);
695 if (lPtr->view->flags.mapped && oldSelectedRow>=lPtr->topItem
696 && oldSelectedRow<=lPtr->topItem+lPtr->fullFitLines) {
697 paintItem(lPtr, oldSelectedRow);
701 /* select item */
702 item->selected = 1;
703 WMAddToArray(lPtr->selectedItems, item);
705 if (lPtr->view->flags.mapped) {
706 paintItem(lPtr, row);
708 if ((row-lPtr->topItem+lPtr->fullFitLines)*lPtr->itemHeight
709 > lPtr->view->size.height-2)
710 W_DrawRelief(lPtr->view->screen, lPtr->view->window, 0, 0,
711 lPtr->view->size.width, lPtr->view->size.height,
712 WRSunken);
714 //lPtr->selectedItem = row;
716 WMPostNotificationName(WMListSelectionDidChangeNotification, lPtr, NULL);
720 static int
721 getItemIndexAt(List *lPtr, int clickY)
723 int index;
725 index = (clickY - 2) / lPtr->itemHeight + lPtr->topItem;
727 if (index < 0 || index >= WMGetArrayItemCount(lPtr->items))
728 return -1;
730 return index;
734 static void
735 handleActionEvents(XEvent *event, void *data)
737 List *lPtr = (List*)data;
738 int tmp;
739 int topItem = lPtr->topItem;
741 CHECK_CLASS(data, WC_List);
743 switch (event->type) {
744 case ButtonRelease:
745 #define CHECK_WHEEL_PATCH
746 #ifdef CHECK_WHEEL_PATCH
747 /* Ignore mouse wheel events, they're not "real" button events */
748 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp ||
749 event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
750 break;
752 #endif
754 lPtr->flags.buttonPressed = 0;
755 tmp = getItemIndexAt(lPtr, event->xbutton.y);
757 if (tmp == lPtr->selectedItem && tmp >= 0) {
758 if (lPtr->action)
759 (*lPtr->action)(lPtr, lPtr->clientData);
761 break;
763 case EnterNotify:
764 lPtr->flags.buttonPressed = lPtr->flags.buttonWasPressed;
765 lPtr->flags.buttonWasPressed = 0;
766 break;
768 case LeaveNotify:
769 lPtr->flags.buttonWasPressed = lPtr->flags.buttonPressed;
770 lPtr->flags.buttonPressed = 0;
771 break;
773 case ButtonPress:
774 if (event->xbutton.x > WMWidgetWidth(lPtr->vScroller)) {
775 #ifdef CHECK_WHEEL_PATCH
776 int amount = 0;
778 // join them
779 if (event->xbutton.button == WINGsConfiguration.mouseWheelDown) {
780 /* Wheel down */
781 /*int itemCount = WMGetArrayItemCount(lPtr->items);
782 if (lPtr->topItem + lPtr->fullFitLines < itemCount) {
783 int incr = lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
784 lPtr->topItem += incr;
786 if (lPtr->topItem + lPtr->fullFitLines > itemCount)
787 lPtr->topItem = itemCount - lPtr->fullFitLines;
789 updateScroller(lPtr);
791 if (event->xbutton.state & ShiftMask) {
792 amount = lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
793 } else if (event->xbutton.state & ControlMask) {
794 amount = 1;
795 } else {
796 amount = lPtr->fullFitLines / 3;
797 if (amount == 0)
798 amount++;
801 scrollByAmount(lPtr, amount);
802 break;
805 if (event->xbutton.button == WINGsConfiguration.mouseWheelUp) {
806 /* Wheel up */
807 /*if (lPtr->topItem > 0) {
808 int decr = lPtr->fullFitLines-(1-lPtr->flags.dontFitAll)-1;
809 lPtr->topItem -= decr;
811 if (lPtr->topItem < 0)
812 lPtr->topItem = 0;
814 updateScroller(lPtr);
816 if (event->xbutton.state & ShiftMask) {
817 amount = -lPtr->fullFitLines+(1-lPtr->flags.dontFitAll)+1;
818 } else if (event->xbutton.state & ControlMask) {
819 amount = -1;
820 } else {
821 amount = -(lPtr->fullFitLines / 3);
822 if (amount == 0)
823 amount--;
826 scrollByAmount(lPtr, amount);
827 break;
829 #endif
831 tmp = getItemIndexAt(lPtr, event->xbutton.y);
832 lPtr->flags.buttonPressed = 1;
834 if (tmp >= 0) {
835 if (tmp == lPtr->selectedItem && WMIsDoubleClick(event)) {
836 WMSelectListItem(lPtr, tmp);
837 if (lPtr->doubleAction)
838 (*lPtr->doubleAction)(lPtr, lPtr->doubleClientData);
839 } else {
840 WMSelectListItem(lPtr, tmp);
844 break;
846 case MotionNotify:
847 if (lPtr->flags.buttonPressed) {
848 tmp = getItemIndexAt(lPtr, event->xmotion.y);
849 if (tmp>=0 && tmp != lPtr->selectedItem) {
850 WMSelectListItem(lPtr, tmp);
853 break;
855 if (lPtr->topItem != topItem)
856 WMPostNotificationName(WMListDidScrollNotification, lPtr, NULL);
860 static void
861 updateGeometry(WMList *lPtr)
863 lPtr->fullFitLines = (lPtr->view->size.height - 4) / lPtr->itemHeight;
864 if (lPtr->fullFitLines * lPtr->itemHeight < lPtr->view->size.height - 4) {
865 lPtr->flags.dontFitAll = 1;
866 } else {
867 lPtr->flags.dontFitAll = 0;
870 if (WMGetArrayItemCount(lPtr->items) - lPtr->topItem <= lPtr->fullFitLines) {
871 lPtr->topItem = WMGetArrayItemCount(lPtr->items) - lPtr->fullFitLines;
872 if (lPtr->topItem < 0)
873 lPtr->topItem = 0;
876 updateScroller(lPtr);
880 static void
881 didResizeList(W_ViewDelegate *self, WMView *view)
883 WMList *lPtr = (WMList*)view->self;
885 WMResizeWidget(lPtr->vScroller, 1, view->size.height-2);
887 updateGeometry(lPtr);
891 static void
892 destroyList(List *lPtr)
894 if (lPtr->idleID)
895 WMDeleteIdleHandler(lPtr->idleID);
896 lPtr->idleID = NULL;
898 WMFreeArray(lPtr->items);
900 wfree(lPtr);