7 char *WMListDidScrollNotification
= "WMListDidScrollNotification";
8 char *WMListSelectionDidChangeNotification
= "WMListSelectionDidChangeNotification";
10 typedef struct W_List
{
14 WMArray
*items
; /* list of WMListItem */
15 WMArray
*selectedItems
; /* list of selected WMListItems */
19 short topItem
; /* index of first visible item */
21 short fullFitLines
; /* no of lines that fit entirely */
25 void *doubleClientData
;
26 WMAction
*doubleAction
;
30 WMHandlerID
*idleID
; /* for updating the scroller after adding elements */
32 WMScroller
*vScroller
;
35 unsigned int allowMultipleSelection
:1;
36 unsigned int allowEmptySelection
:1;
37 unsigned int userDrawn
:1;
38 unsigned int userItemHeight
:1;
39 unsigned int dontFitAll
:1; /* 1 = last item won't be fully visible */
40 unsigned int redrawPending
:1;
41 unsigned int buttonPressed
:1;
42 unsigned int buttonWasPressed
:1;
48 #define DEFAULT_WIDTH 150
49 #define DEFAULT_HEIGHT 150
52 static void destroyList(List
*lPtr
);
53 static void paintList(List
*lPtr
);
56 static void handleEvents(XEvent
*event
, void *data
);
57 static void handleActionEvents(XEvent
*event
, void *data
);
58 static void updateScroller(List
*lPtr
);
60 static void vScrollCallBack(WMWidget
*scroller
, void *self
);
62 static void updateGeometry(WMList
*lPtr
);
63 static void didResizeList();
66 W_ViewDelegate _ListViewDelegate
= {
76 releaseItem(void *data
)
78 WMListItem
*item
= (WMListItem
*)data
;
87 WMCreateList(WMWidget
*parent
)
90 W_Screen
*scrPtr
= W_VIEW(parent
)->screen
;
92 lPtr
= wmalloc(sizeof(List
));
93 memset(lPtr
, 0, sizeof(List
));
95 lPtr
->widgetClass
= WC_List
;
97 lPtr
->view
= W_CreateView(W_VIEW(parent
));
102 lPtr
->view
->self
= lPtr
;
104 lPtr
->view
->delegate
= &_ListViewDelegate
;
106 WMCreateEventHandler(lPtr
->view
, ExposureMask
|StructureNotifyMask
107 |ClientMessageMask
, handleEvents
, lPtr
);
109 WMCreateEventHandler(lPtr
->view
, ButtonPressMask
|ButtonReleaseMask
110 |EnterWindowMask
|LeaveWindowMask
|ButtonMotionMask
,
111 handleActionEvents
, lPtr
);
113 lPtr
->itemHeight
= WMFontHeight(scrPtr
->normalFont
) + 1;
115 lPtr
->items
= WMCreateArrayWithDestructor(4, releaseItem
);
116 lPtr
->selectedItems
= WMCreateArray(4);
118 /* create the vertical scroller */
119 lPtr
->vScroller
= WMCreateScroller(lPtr
);
120 WMMoveWidget(lPtr
->vScroller
, 1, 1);
121 WMSetScrollerArrowsPosition(lPtr
->vScroller
, WSAMaxEnd
);
123 WMSetScrollerAction(lPtr
->vScroller
, vScrollCallBack
, lPtr
);
125 /* make the scroller map itself when it's realized */
126 WMMapWidget(lPtr
->vScroller
);
128 W_ResizeView(lPtr
->view
, DEFAULT_WIDTH
, DEFAULT_HEIGHT
);
135 WMSetListAllowMultipleSelection(WMList
*lPtr
, Bool flag
)
137 lPtr
->flags
.allowMultipleSelection
= flag
? 1 : 0;
142 WMSetListAllowEmptySelection(WMList
*lPtr
, Bool flag
)
144 lPtr
->flags
.allowEmptySelection
= flag
? 1 : 0;
149 comparator(const void *a
, const void *b
)
151 return (strcmp((*(WMListItem
**)a
)->text
, (*(WMListItem
**)b
)->text
));
156 WMSortListItems(WMList
*lPtr
)
158 WMSortArray(lPtr
->items
, comparator
);
166 WMSortListItemsWithComparer(WMList
*lPtr
, WMCompareDataProc
*func
)
168 WMSortArray(lPtr
->items
, func
);
176 WMInsertListItem(WMList
*lPtr
, int row
, char *text
)
180 CHECK_CLASS(lPtr
, WC_List
);
182 item
= wmalloc(sizeof(WMListItem
));
183 memset(item
, 0, sizeof(WMListItem
));
184 item
->text
= wstrdup(text
);
186 row
= WMIN(row
, WMGetArrayItemCount(lPtr
->items
));
189 WMAddToArray(lPtr
->items
, item
);
191 WMInsertInArray(lPtr
->items
, row
, item
);
193 /* update the scroller when idle, so that we don't waste time
194 * updating it when another item is going to be added later */
196 lPtr
->idleID
= WMAddIdleHandler((WMCallback
*)updateScroller
, lPtr
);
204 WMRemoveListItem(WMList
*lPtr
, int row
)
207 int topItem
= lPtr
->topItem
;
210 CHECK_CLASS(lPtr
, WC_List
);
212 /*wassertr(row>=0 && row<WMGetArrayItemCount(lPtr->items));*/
213 if (row
<0 || row
>=WMGetArrayItemCount(lPtr
->items
))
216 item
= WMGetFromArray(lPtr
->items
, row
);
217 if (item
->selected
) {
218 WMRemoveFromArray(lPtr
->selectedItems
, item
);
222 if (row
<= lPtr
->topItem
+lPtr
->fullFitLines
+lPtr
->flags
.dontFitAll
)
224 if (lPtr
->topItem
< 0)
227 WMDeleteFromArray(lPtr
->items
, row
);
230 lPtr
->idleID
= WMAddIdleHandler((WMCallback
*)updateScroller
, lPtr
);
232 if (lPtr
->topItem
!= topItem
) {
233 WMPostNotificationName(WMListDidScrollNotification
, lPtr
, NULL
);
236 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
242 WMGetListItem(WMList
*lPtr
, int row
)
244 return WMGetFromArray(lPtr
->items
, row
);
249 WMGetListItems(WMList
*lPtr
)
256 WMSetListUserDrawProc(WMList
*lPtr
, WMListDrawProc
*proc
)
258 lPtr
->flags
.userDrawn
= 1;
264 WMSetListUserDrawItemHeight(WMList
*lPtr
, unsigned short height
)
268 lPtr
->flags
.userItemHeight
= 1;
269 lPtr
->itemHeight
= height
;
271 updateGeometry(lPtr
);
276 WMClearList(WMList
*lPtr
)
278 int selNo
= WMGetArrayItemCount(lPtr
->selectedItems
);
280 WMEmptyArray(lPtr
->selectedItems
);
281 WMEmptyArray(lPtr
->items
);
286 WMDeleteIdleHandler(lPtr
->idleID
);
289 if (lPtr
->view
->flags
.realized
) {
290 updateScroller(lPtr
);
293 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
299 WMSetListAction(WMList
*lPtr
, WMAction
*action
, void *clientData
)
301 lPtr
->action
= action
;
302 lPtr
->clientData
= clientData
;
307 WMSetListDoubleAction(WMList
*lPtr
, WMAction
*action
, void *clientData
)
309 lPtr
->doubleAction
= action
;
310 lPtr
->doubleClientData
= clientData
;
315 WMGetListSelectedItems(WMList
*lPtr
)
317 return lPtr
->selectedItems
;
322 WMGetListSelectedItem(WMList
*lPtr
)
324 return WMGetFromArray(lPtr
->selectedItems
, 0);
329 WMGetListSelectedItemRow(WMList
*lPtr
)
331 WMListItem
*item
= WMGetFromArray(lPtr
->selectedItems
, 0);
333 return (item
!=NULL
? WMGetFirstInArray(lPtr
->items
, item
) : WLNotFound
);
338 WMGetListItemHeight(WMList
*lPtr
)
340 return lPtr
->itemHeight
;
345 WMSetListPosition(WMList
*lPtr
, int row
)
348 if (lPtr
->topItem
+ lPtr
->fullFitLines
> WMGetArrayItemCount(lPtr
->items
))
349 lPtr
->topItem
= WMGetArrayItemCount(lPtr
->items
) - lPtr
->fullFitLines
;
351 if (lPtr
->topItem
< 0)
354 if (lPtr
->view
->flags
.realized
)
355 updateScroller(lPtr
);
360 WMSetListBottomPosition(WMList
*lPtr
, int row
)
362 if (WMGetArrayItemCount(lPtr
->items
) > lPtr
->fullFitLines
) {
363 lPtr
->topItem
= row
- lPtr
->fullFitLines
;
364 if (lPtr
->topItem
< 0)
366 if (lPtr
->view
->flags
.realized
)
367 updateScroller(lPtr
);
373 WMGetListNumberOfRows(WMList
*lPtr
)
375 return WMGetArrayItemCount(lPtr
->items
);
380 WMGetListPosition(WMList
*lPtr
)
382 return lPtr
->topItem
;
387 WMListAllowsMultipleSelection(WMList
*lPtr
)
389 return lPtr
->flags
.allowMultipleSelection
;
394 WMListAllowsEmptySelection(WMList
*lPtr
)
396 return lPtr
->flags
.allowEmptySelection
;
401 scrollByAmount(WMList
*lPtr
, int amount
)
403 int itemCount
= WMGetArrayItemCount(lPtr
->items
);
405 if ((amount
< 0 && lPtr
->topItem
> 0) ||
406 (amount
> 0 && (lPtr
->topItem
+ lPtr
->fullFitLines
< itemCount
))) {
408 lPtr
->topItem
+= amount
;
409 if (lPtr
->topItem
< 0)
411 if (lPtr
->topItem
+ lPtr
->fullFitLines
> itemCount
)
412 lPtr
->topItem
= itemCount
- lPtr
->fullFitLines
;
414 updateScroller(lPtr
);
420 vScrollCallBack(WMWidget
*scroller
, void *self
)
422 WMList
*lPtr
= (WMList
*)self
;
424 int oldTopItem
= lPtr
->topItem
;
425 int itemCount
= WMGetArrayItemCount(lPtr
->items
);
427 height
= lPtr
->view
->size
.height
- 4;
429 switch (WMGetScrollerHitPart((WMScroller
*)scroller
)) {
430 case WSDecrementLine
:
431 scrollByAmount(lPtr
, -1);
434 case WSIncrementLine
:
435 scrollByAmount(lPtr
, 1);
438 case WSDecrementPage
:
439 scrollByAmount(lPtr
, -lPtr
->fullFitLines
+(1-lPtr
->flags
.dontFitAll
)+1);
442 case WSIncrementPage
:
443 scrollByAmount(lPtr
, lPtr
->fullFitLines
-(1-lPtr
->flags
.dontFitAll
)-1);
446 case WSDecrementWheel
:
447 scrollByAmount(lPtr
, -lPtr
->fullFitLines
/ 3);
450 case WSIncrementWheel
:
451 scrollByAmount(lPtr
, lPtr
->fullFitLines
/ 3);
455 lPtr
->topItem
= WMGetScrollerValue(lPtr
->vScroller
) *
456 (float)(itemCount
- lPtr
->fullFitLines
);
458 if (oldTopItem
!= lPtr
->topItem
)
459 paintList(lPtr
); // use updateScroller(lPtr) here?
469 if (lPtr
->topItem
!= oldTopItem
)
470 WMPostNotificationName(WMListDidScrollNotification
, lPtr
, NULL
);
475 paintItem(List
*lPtr
, int index
)
477 WMView
*view
= lPtr
->view
;
478 W_Screen
*scr
= view
->screen
;
479 int width
, height
, x
, y
;
482 itemPtr
= WMGetFromArray(lPtr
->items
, index
);
484 width
= lPtr
->view
->size
.width
- 2 - 19;
485 height
= lPtr
->itemHeight
;
487 y
= 2 + (index
-lPtr
->topItem
) * lPtr
->itemHeight
+ 1;
489 if (lPtr
->flags
.userDrawn
) {
493 rect
.size
.width
= width
;
494 rect
.size
.height
= height
;
498 flags
= itemPtr
->uflags
;
499 if (itemPtr
->disabled
)
500 flags
|= WLDSDisabled
;
501 if (itemPtr
->selected
)
502 flags
|= WLDSSelected
;
503 if (itemPtr
->isBranch
)
504 flags
|= WLDSIsBranch
;
507 (*lPtr
->draw
)(lPtr
, index
, view
->window
, itemPtr
->text
, flags
,
510 if (itemPtr
->selected
) {
511 XFillRectangle(scr
->display
, view
->window
, WMColorGC(scr
->white
),
512 x
, y
, width
, height
);
514 XClearArea(scr
->display
, view
->window
, x
, y
, width
, height
, False
);
517 W_PaintText(view
, view
->window
, scr
->normalFont
, x
+4, y
, width
,
518 WALeft
, WMColorGC(scr
->black
), False
,
519 itemPtr
->text
, strlen(itemPtr
->text
));
522 if ((index
-lPtr
->topItem
+lPtr
->fullFitLines
)*lPtr
->itemHeight
>
523 lPtr
->view
->size
.height
-2) {
524 W_DrawRelief(lPtr
->view
->screen
, lPtr
->view
->window
, 0, 0,
525 lPtr
->view
->size
.width
, lPtr
->view
->size
.height
,
533 paintList(List
*lPtr
)
535 W_Screen
*scrPtr
= lPtr
->view
->screen
;
538 if (!lPtr
->view
->flags
.mapped
)
541 if (WMGetArrayItemCount(lPtr
->items
) > 0) {
542 if (lPtr
->topItem
+lPtr
->fullFitLines
+lPtr
->flags
.dontFitAll
543 > WMGetArrayItemCount(lPtr
->items
)) {
545 lim
= WMGetArrayItemCount(lPtr
->items
) - lPtr
->topItem
;
546 XClearArea(scrPtr
->display
, lPtr
->view
->window
, 19,
547 2+lim
*lPtr
->itemHeight
, lPtr
->view
->size
.width
-21,
548 lPtr
->view
->size
.height
-lim
*lPtr
->itemHeight
-3, False
);
550 lim
= lPtr
->fullFitLines
+ lPtr
->flags
.dontFitAll
;
552 for (i
= lPtr
->topItem
; i
< lPtr
->topItem
+ lim
; i
++) {
556 XClearWindow(scrPtr
->display
, lPtr
->view
->window
);
558 W_DrawRelief(scrPtr
, lPtr
->view
->window
, 0, 0, lPtr
->view
->size
.width
,
559 lPtr
->view
->size
.height
, WRSunken
);
564 scrollTo(List
*lPtr
, int newTop
)
571 updateScroller(List
*lPtr
)
573 float knobProportion
, floatValue
, tmp
;
574 int count
= WMGetArrayItemCount(lPtr
->items
);
577 WMDeleteIdleHandler(lPtr
->idleID
);
582 if (count
== 0 || count
<= lPtr
->fullFitLines
)
583 WMSetScrollerParameters(lPtr
->vScroller
, 0, 1);
585 tmp
= lPtr
->fullFitLines
;
586 knobProportion
= tmp
/(float)count
;
588 floatValue
= (float)lPtr
->topItem
/(float)(count
- lPtr
->fullFitLines
);
590 WMSetScrollerParameters(lPtr
->vScroller
, floatValue
, knobProportion
);
596 handleEvents(XEvent
*event
, void *data
)
598 List
*lPtr
= (List
*)data
;
600 CHECK_CLASS(data
, WC_List
);
603 switch (event
->type
) {
605 if (event
->xexpose
.count
!=0)
619 matchTitle(void *item
, void *title
)
621 return (strcmp(((WMListItem
*)item
)->text
, (char*)title
)==0 ? 1 : 0);
626 WMFindRowOfListItemWithTitle(WMList
*lPtr
, char *title
)
628 return WMFindInArray(lPtr
->items
, matchTitle
, title
);
633 WMSelectListItem(WMList
*lPtr
, int row
)
637 if (row
>= WMGetArrayItemCount(lPtr
->items
))
641 /* row = -1 will deselects all for backward compatibility.
642 * will be removed later. -Dan */
643 WMUnselectAllListItems(lPtr
);
647 item
= WMGetFromArray(lPtr
->items
, row
);
649 return; /* Return if already selected */
651 if (!lPtr
->flags
.allowMultipleSelection
) {
652 /* unselect previous selected items */
653 int foo
= lPtr
->flags
.allowEmptySelection
;
655 lPtr
->flags
.allowEmptySelection
= 1;
656 WMUnselectAllListItems(lPtr
);
657 lPtr
->flags
.allowEmptySelection
= foo
;
662 WMAddToArray(lPtr
->selectedItems
, item
);
664 if (lPtr
->view
->flags
.mapped
&& row
>=lPtr
->topItem
665 && row
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
666 paintItem(lPtr
, row
);
669 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
674 WMUnselectListItem(WMList
*lPtr
, int row
)
676 WMListItem
*item
= WMGetFromArray(lPtr
->items
, row
);
678 if (!item
|| !item
->selected
)
681 if (!lPtr
->flags
.allowEmptySelection
&&
682 WMGetArrayItemCount(lPtr
->selectedItems
) <= 1) {
687 WMRemoveFromArray(lPtr
->selectedItems
, item
);
689 if (lPtr
->view
->flags
.mapped
&& row
>=lPtr
->topItem
690 && row
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
691 paintItem(lPtr
, row
);
694 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
699 WMSelectListItemsInRange(WMList
*lPtr
, WMRange range
)
702 int position
= range
.position
, k
= 1, notify
= 0;
703 int total
= WMGetArrayItemCount(lPtr
->items
);
705 if (!lPtr
->flags
.allowMultipleSelection
)
708 return; /* Nothing to select */
710 if (range
.count
< 0) {
711 range
.count
= -range
.count
;
715 for (; range
.count
>0 && position
>=0 && position
<total
; range
.count
--) {
716 item
= WMGetFromArray(lPtr
->items
, position
);
717 if (!item
->selected
) {
719 WMAddToArray(lPtr
->selectedItems
, item
);
720 if (lPtr
->view
->flags
.mapped
&& position
>=lPtr
->topItem
721 && position
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
722 paintItem(lPtr
, position
);
730 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
736 WMSetListSelectionToRange(WMList
*lPtr
, WMRange range
)
739 int mark1
, mark2
, i
, k
;
740 int position
= range
.position
, notify
= 0;
741 int total
= WMGetArrayItemCount(lPtr
->items
);
743 if (!lPtr
->flags
.allowMultipleSelection
)
746 if (range
.count
==0) {
747 WMUnselectAllListItems(lPtr
);
751 if (range
.count
< 0) {
752 mark1
= range
.position
+ range
.count
+ 1;
753 mark2
= range
.position
+ 1;
754 range
.count
= -range
.count
;
757 mark1
= range
.position
;
758 mark2
= range
.position
+ range
.count
;
766 WMEmptyArray(lPtr
->selectedItems
);
768 for (i
=0; i
<mark1
; i
++) {
769 item
= WMGetFromArray(lPtr
->items
, i
);
770 if (item
->selected
) {
772 if (lPtr
->view
->flags
.mapped
&& i
>=lPtr
->topItem
773 && i
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
779 for (; range
.count
>0 && position
>=0 && position
<total
; range
.count
--) {
780 item
= WMGetFromArray(lPtr
->items
, position
);
781 if (!item
->selected
) {
783 if (lPtr
->view
->flags
.mapped
&& position
>=lPtr
->topItem
784 && position
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
785 paintItem(lPtr
, position
);
789 WMAddToArray(lPtr
->selectedItems
, item
);
792 for (i
=mark2
; i
<total
; i
++) {
793 item
= WMGetFromArray(lPtr
->items
, i
);
794 if (item
->selected
) {
796 if (lPtr
->view
->flags
.mapped
&& i
>=lPtr
->topItem
797 && i
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
805 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
811 WMSelectAllListItems(WMList
*lPtr
)
816 if (!lPtr
->flags
.allowMultipleSelection
)
819 if (WMGetArrayItemCount(lPtr
->items
) ==
820 WMGetArrayItemCount(lPtr
->selectedItems
)) {
821 return; /* All items are selected already */
824 WMFreeArray(lPtr
->selectedItems
);
825 lPtr
->selectedItems
= WMCreateArrayWithArray(lPtr
->items
);
827 for (i
=0; i
<WMGetArrayItemCount(lPtr
->items
); i
++) {
828 item
= WMGetFromArray(lPtr
->items
, i
);
829 if (!item
->selected
) {
831 if (lPtr
->view
->flags
.mapped
&& i
>=lPtr
->topItem
832 && i
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
838 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
843 WMUnselectAllListItems(WMList
*lPtr
)
846 WMListItem
*item
, *keepItem
;
848 keep
= lPtr
->flags
.allowEmptySelection
? 0 : 1;
850 if (WMGetArrayItemCount(lPtr
->selectedItems
) == keep
)
853 keepItem
= (keep
==1 ? WMGetFromArray(lPtr
->selectedItems
, 0) : NULL
);
855 for (i
=0; i
<WMGetArrayItemCount(lPtr
->items
); i
++) {
856 item
= WMGetFromArray(lPtr
->items
, i
);
857 if (item
!=keepItem
&& item
->selected
) {
859 if (lPtr
->view
->flags
.mapped
&& i
>=lPtr
->topItem
860 && i
<=lPtr
->topItem
+lPtr
->fullFitLines
) {
866 WMEmptyArray(lPtr
->selectedItems
);
868 WMAddToArray(lPtr
->selectedItems
, keepItem
);
870 WMPostNotificationName(WMListSelectionDidChangeNotification
, lPtr
, NULL
);
875 getItemIndexAt(List
*lPtr
, int clickY
)
879 index
= (clickY
- 2) / lPtr
->itemHeight
+ lPtr
->topItem
;
881 if (index
< 0 || index
>= WMGetArrayItemCount(lPtr
->items
))
889 toggleItemSelection(WMList
*lPtr
, int index
)
891 WMListItem
*item
= WMGetFromArray(lPtr
->items
, index
);
893 if (item
&& item
->selected
) {
894 WMUnselectListItem(lPtr
, index
);
896 WMSelectListItem(lPtr
, index
);
902 handleActionEvents(XEvent
*event
, void *data
)
904 List
*lPtr
= (List
*)data
;
906 int topItem
= lPtr
->topItem
;
907 static int lastClicked
= -1, prevItem
= -1;
909 CHECK_CLASS(data
, WC_List
);
911 switch (event
->type
) {
913 /* Ignore mouse wheel events, they're not "real" button events */
914 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
||
915 event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
) {
919 lPtr
->flags
.buttonPressed
= 0;
920 tmp
= getItemIndexAt(lPtr
, event
->xbutton
.y
);
924 (*lPtr
->action
)(lPtr
, lPtr
->clientData
);
927 if (!(event
->xbutton
.state
& ShiftMask
))
928 lastClicked
= prevItem
= tmp
;
933 lPtr
->flags
.buttonPressed
= lPtr
->flags
.buttonWasPressed
;
934 lPtr
->flags
.buttonWasPressed
= 0;
938 lPtr
->flags
.buttonWasPressed
= lPtr
->flags
.buttonPressed
;
939 lPtr
->flags
.buttonPressed
= 0;
943 if (event
->xbutton
.x
<= WMWidgetWidth(lPtr
->vScroller
))
945 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelDown
||
946 event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
) {
949 if (event
->xbutton
.state
& ControlMask
) {
950 amount
= lPtr
->fullFitLines
-(1-lPtr
->flags
.dontFitAll
)-1;
951 } else if (event
->xbutton
.state
& ShiftMask
) {
954 amount
= lPtr
->fullFitLines
/ 3;
958 if (event
->xbutton
.button
== WINGsConfiguration
.mouseWheelUp
)
961 scrollByAmount(lPtr
, amount
);
965 tmp
= getItemIndexAt(lPtr
, event
->xbutton
.y
);
966 lPtr
->flags
.buttonPressed
= 1;
969 if (tmp
== lastClicked
&& WMIsDoubleClick(event
)) {
970 WMSelectListItem(lPtr
, tmp
);
971 if (lPtr
->doubleAction
)
972 (*lPtr
->doubleAction
)(lPtr
, lPtr
->doubleClientData
);
974 if (!lPtr
->flags
.allowMultipleSelection
) {
975 if (event
->xbutton
.state
& ControlMask
) {
976 toggleItemSelection(lPtr
, tmp
);
978 WMSelectListItem(lPtr
, tmp
);
984 if (event
->xbutton
.state
& ControlMask
) {
985 toggleItemSelection(lPtr
, tmp
);
986 } else if (event
->xbutton
.state
& ShiftMask
) {
987 if (WMGetArrayItemCount(lPtr
->selectedItems
) == 0) {
988 WMSelectListItem(lPtr
, tmp
);
990 lastSel
= WMGetFromArray(lPtr
->items
, lastClicked
);
991 range
.position
= WMGetFirstInArray(lPtr
->items
,
993 if (tmp
>= range
.position
)
994 range
.count
= tmp
- range
.position
+ 1;
996 range
.count
= tmp
- range
.position
- 1;
998 WMSetListSelectionToRange(lPtr
, range
);
1001 range
.position
= tmp
;
1003 WMSetListSelectionToRange(lPtr
, range
);
1009 if (!(event
->xbutton
.state
& ShiftMask
))
1010 lastClicked
= prevItem
= tmp
;
1015 if (lPtr
->flags
.buttonPressed
) {
1016 tmp
= getItemIndexAt(lPtr
, event
->xmotion
.y
);
1017 if (tmp
>=0 && tmp
!=prevItem
) {
1018 if (lPtr
->flags
.allowMultipleSelection
) {
1021 range
.position
= lastClicked
;
1022 if (tmp
>= lastClicked
)
1023 range
.count
= tmp
- lastClicked
+ 1;
1025 range
.count
= tmp
- lastClicked
- 1;
1026 WMSetListSelectionToRange(lPtr
, range
);
1028 WMSelectListItem(lPtr
, tmp
);
1035 if (lPtr
->topItem
!= topItem
)
1036 WMPostNotificationName(WMListDidScrollNotification
, lPtr
, NULL
);
1041 updateGeometry(WMList
*lPtr
)
1043 lPtr
->fullFitLines
= (lPtr
->view
->size
.height
- 4) / lPtr
->itemHeight
;
1044 if (lPtr
->fullFitLines
* lPtr
->itemHeight
< lPtr
->view
->size
.height
- 4) {
1045 lPtr
->flags
.dontFitAll
= 1;
1047 lPtr
->flags
.dontFitAll
= 0;
1050 if (WMGetArrayItemCount(lPtr
->items
) - lPtr
->topItem
<= lPtr
->fullFitLines
) {
1051 lPtr
->topItem
= WMGetArrayItemCount(lPtr
->items
) - lPtr
->fullFitLines
;
1052 if (lPtr
->topItem
< 0)
1056 updateScroller(lPtr
);
1061 didResizeList(W_ViewDelegate
*self
, WMView
*view
)
1063 WMList
*lPtr
= (WMList
*)view
->self
;
1065 WMResizeWidget(lPtr
->vScroller
, 1, view
->size
.height
-2);
1067 updateGeometry(lPtr
);
1072 destroyList(List
*lPtr
)
1075 WMDeleteIdleHandler(lPtr
->idleID
);
1076 lPtr
->idleID
= NULL
;
1078 WMFreeArray(lPtr
->items
);