- Pass all tags to the super-constructor. Now Listviews can have
[AROS.git] / workbench / libs / muimaster / classes / listview.c
blobc1a141d7f2f851ddc2fd3a2ca81725db40bb3123
1 /*
2 Copyright © 2002-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <aros/debug.h>
8 #include <graphics/gfx.h>
9 #include <graphics/view.h>
10 #include <devices/rawkeycodes.h>
11 #include <clib/alib_protos.h>
12 #include <proto/exec.h>
13 #include <proto/graphics.h>
14 #include <proto/utility.h>
15 #include <proto/intuition.h>
16 #include <proto/muimaster.h>
18 #include "mui.h"
19 #include "muimaster_intern.h"
20 #include "support.h"
21 #include "window.h"
22 #include "list.h"
23 #include "prefs.h"
25 extern struct Library *MUIMasterBase;
27 struct MUI_ListviewData
29 Object *list, *group, *vert;
30 struct Hook hook;
31 struct Hook selfnotify_hook;
32 BOOL noforward;
33 BOOL read_only;
34 BOOL select_change;
35 IPTR multiselect;
36 IPTR scroller_pos;
37 struct MUI_EventHandlerNode ehn;
39 int mouse_click; /* see below if mouse is held down */
41 /* double click */
42 ULONG last_secs;
43 ULONG last_mics;
44 ULONG last_active;
45 BOOL doubleclick;
47 /* clicked column */
48 LONG click_column;
49 LONG def_click_column;
51 /* user prefs */
52 ListviewMulti prefs_multi;
55 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
56 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
58 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely);
60 #define PROP_VERT_FIRST 1
61 #define LIST_VERT_FIRST 4
62 #define LIST_VERT_VISIBLE 5
63 #define LIST_VERT_ENTRIES 6
65 ULONG Listview_Function(struct Hook *hook, APTR dummyobj, void **msg)
67 struct MUI_ListviewData *data = (struct MUI_ListviewData *)hook->h_Data;
68 SIPTR type = (SIPTR) msg[0];
69 SIPTR val = (SIPTR) msg[1];
71 D(bug("[ListView] List 0x%p, Event %d, value %ld\n", data->list, type,
72 val));
74 switch (type)
76 case PROP_VERT_FIRST:
77 get(data->vert, MUIA_Prop_First, &val);
78 nnset(data->list, MUIA_List_VertProp_First, val);
79 break;
81 case LIST_VERT_FIRST:
82 nnset(data->vert, MUIA_Prop_First, val);
83 break;
84 case LIST_VERT_VISIBLE:
85 nnset(data->vert, MUIA_Prop_Visible, val);
86 break;
87 case LIST_VERT_ENTRIES:
88 nnset(data->vert, MUIA_Prop_Entries, val);
89 break;
91 return 0;
94 ULONG SelfNotify_Function(struct Hook *hook, APTR obj, void **msg)
96 struct MUI_ListviewData *data = (struct MUI_ListviewData *)hook->h_Data;
97 SIPTR attribute = (SIPTR) msg[0];
98 SIPTR value = (SIPTR) msg[1];
100 /* This allows avoiding notify loops */
101 data->noforward = TRUE;
102 SetAttrs(obj, MUIA_Group_Forward, FALSE, attribute, value, TAG_DONE);
103 data->noforward = FALSE;
105 return 0;
108 /**************************************************************************
109 OM_NEW
110 **************************************************************************/
111 IPTR Listview__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
113 struct MUI_ListviewData *data;
114 struct TagItem *tag, *tags;
115 Object *group, *vert;
116 Object *list =
117 (Object *) GetTagData(MUIA_Listview_List, (IPTR) NULL,
118 msg->ops_AttrList);
119 LONG entries = 0, first = 0, visible = 0;
121 if (!list)
122 return (IPTR) NULL;
124 vert = ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
126 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
127 MUIA_Group_Horiz, FALSE,
128 MUIA_InnerLeft, 0,
129 MUIA_InnerRight, 0,
130 Child, (IPTR) (group = HGroup,
131 MUIA_InnerLeft, 0,
132 MUIA_InnerRight, 0,
133 MUIA_Group_Spacing, 0,
134 End),
135 TAG_MORE, msg->ops_AttrList);
137 if (!obj)
138 return (IPTR) NULL;
140 data = INST_DATA(cl, obj);
141 data->list = list;
142 data->vert = vert;
143 data->group = group;
145 data->hook.h_Entry = HookEntry;
146 data->hook.h_SubEntry = (HOOKFUNC) Listview_Function;
147 data->hook.h_Data = data;
149 data->selfnotify_hook.h_Entry = HookEntry;
150 data->selfnotify_hook.h_SubEntry = (HOOKFUNC) SelfNotify_Function;
151 data->selfnotify_hook.h_Data = data;
152 data->noforward = FALSE;
154 data->last_active = -1;
156 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
157 data->ehn.ehn_Priority = 0;
158 data->ehn.ehn_Flags = 0;
159 data->ehn.ehn_Object = obj;
160 data->ehn.ehn_Class = cl;
162 /* parse initial taglist */
163 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
165 switch (tag->ti_Tag)
167 case MUIA_Listview_DoubleClick:
168 data->doubleclick = tag->ti_Data != 0;
169 break;
170 case MUIA_Listview_Input:
171 data->read_only = !tag->ti_Data;
172 break;
173 case MUIA_Listview_MultiSelect:
174 data->multiselect = tag->ti_Data;
175 break;
176 case MUIA_Listview_ScrollerPos:
177 data->scroller_pos = tag->ti_Data;
178 break;
182 /* Add list and/or scroller */
183 switch (data->scroller_pos)
185 case MUIV_Listview_ScrollerPos_None:
186 DoMethod(group, OM_ADDMEMBER, list);
187 break;
188 case MUIV_Listview_ScrollerPos_Left:
189 DoMethod(group, OM_ADDMEMBER, vert);
190 DoMethod(group, OM_ADDMEMBER, list);
191 break;
192 default:
193 DoMethod(group, OM_ADDMEMBER, list);
194 DoMethod(group, OM_ADDMEMBER, vert);
195 break;
198 get(list, MUIA_List_VertProp_First, &first);
199 get(list, MUIA_List_VertProp_Visible, &visible);
200 get(list, MUIA_List_VertProp_Entries, &entries);
202 D(bug
203 ("[ListView 0x%p] List 0x%p, First %ld, Visible %ld, Entries %ld\n",
204 obj, list, first, visible, entries));
206 SetAttrs(data->vert,
207 MUIA_Prop_First, first,
208 MUIA_Prop_Visible, visible, MUIA_Prop_Entries, entries, TAG_DONE);
210 DoMethod(vert, MUIM_Notify, MUIA_Prop_First, MUIV_EveryTime, (IPTR) obj,
211 4, MUIM_CallHook, (IPTR) &data->hook, PROP_VERT_FIRST,
212 MUIV_TriggerValue);
213 DoMethod(list, MUIM_Notify, MUIA_List_VertProp_First, MUIV_EveryTime,
214 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook, LIST_VERT_FIRST,
215 MUIV_TriggerValue);
216 DoMethod(list, MUIM_Notify, MUIA_List_VertProp_Visible, MUIV_EveryTime,
217 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook,
218 LIST_VERT_VISIBLE, MUIV_TriggerValue);
219 DoMethod(list, MUIM_Notify, MUIA_List_VertProp_Entries, MUIV_EveryTime,
220 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook,
221 LIST_VERT_ENTRIES, MUIV_TriggerValue);
222 DoMethod(list, MUIM_Notify, MUIA_List_Active, MUIV_EveryTime,
223 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->selfnotify_hook,
224 MUIA_List_Active, MUIV_TriggerValue);
226 return (IPTR) obj;
229 /**************************************************************************
230 OM_DISPOSE
231 **************************************************************************/
232 IPTR Listview__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
234 return DoSuperMethodA(cl, obj, msg);
237 /**************************************************************************
238 OM_SET
239 **************************************************************************/
240 IPTR Listview__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
242 struct TagItem *tag, *tags;
243 IPTR no_notify = GetTagData(MUIA_NoNotify, FALSE, msg->ops_AttrList);
244 struct MUI_ListviewData *data = INST_DATA(cl, obj);
246 if (data->noforward)
248 return DoSuperMethodA(cl, obj, (Msg) msg);
251 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
253 switch (tag->ti_Tag)
255 case MUIA_List_CompareHook:
256 case MUIA_List_ConstructHook:
257 case MUIA_List_DestructHook:
258 case MUIA_List_DisplayHook:
259 case MUIA_List_VertProp_First:
260 case MUIA_List_Format:
261 case MUIA_List_VertProp_Entries:
262 case MUIA_List_VertProp_Visible:
263 case MUIA_List_Active:
264 case MUIA_List_First:
265 case MUIA_List_Visible:
266 case MUIA_List_Entries:
267 case MUIA_List_Quiet:
268 SetAttrs(data->list, MUIA_NoNotify, no_notify, tag->ti_Tag,
269 tag->ti_Data, TAG_DONE);
270 break;
271 case MUIA_Listview_DoubleClick:
272 data->doubleclick = tag->ti_Data != 0;
273 break;
274 case MUIA_Listview_SelectChange:
275 data->select_change = tag->ti_Data != 0;
276 break;
277 case MUIA_Disabled:
278 if (_flags(obj) & MADF_SETUP)
280 /* Stop listening for events we only listen to when mouse
281 button is down: we will not be informed of the button
282 being released */
283 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
284 (IPTR) &data->ehn);
285 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
286 | IDCMP_INACTIVEWINDOW);
287 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
288 (IPTR) &data->ehn);
290 break;
294 return DoSuperMethodA(cl, obj, (Msg) msg);
297 /**************************************************************************
298 OM_GET
299 **************************************************************************/
300 IPTR Listview__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
302 /* small macro to simplify return value storage */
303 #define STORE *(msg->opg_Storage)
304 struct MUI_ListviewData *data = INST_DATA(cl, obj);
306 switch (msg->opg_AttrID)
308 case MUIA_List_CompareHook:
309 case MUIA_List_ConstructHook:
310 case MUIA_List_DestructHook:
311 case MUIA_List_DisplayHook:
312 case MUIA_List_VertProp_First:
313 case MUIA_List_Format:
314 case MUIA_List_VertProp_Entries:
315 case MUIA_List_VertProp_Visible:
316 case MUIA_List_Active:
317 case MUIA_List_First:
318 case MUIA_List_Visible:
319 case MUIA_List_Entries:
320 case MUIA_List_Quiet:
321 return GetAttr(msg->opg_AttrID, data->list, msg->opg_Storage);
322 case MUIA_Listview_DoubleClick:
323 STORE = data->doubleclick;
324 return 1;
325 case MUIA_Listview_ClickColumn:
326 STORE = data->click_column;
327 return 1;
328 case MUIA_Listview_List:
329 STORE = (IPTR) data->list;
330 return 1;
331 case MUIA_Listview_SelectChange:
332 STORE = data->select_change;
333 return 1;
336 return DoSuperMethodA(cl, obj, (Msg) msg);
337 #undef STORE
340 /**************************************************************************
341 MUIM_Setup
342 **************************************************************************/
343 IPTR Listview__MUIM_Setup(struct IClass *cl, Object *obj,
344 struct MUIP_Setup *msg)
346 struct MUI_ListviewData *data = INST_DATA(cl, obj);
348 if (!DoSuperMethodA(cl, obj, (Msg) msg))
349 return 0;
351 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
352 if (data->multiselect == MUIV_Listview_MultiSelect_Default)
354 if (data->prefs_multi == LISTVIEW_MULTI_SHIFTED)
355 data->multiselect = MUIV_Listview_MultiSelect_Shifted;
356 else
357 data->multiselect = MUIV_Listview_MultiSelect_Always;
360 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) &data->ehn);
362 return 1;
365 /**************************************************************************
366 MUIM_Cleanup
367 **************************************************************************/
368 IPTR Listview__MUIM_Cleanup(struct IClass *cl, Object *obj,
369 struct MUIP_Cleanup *msg)
371 struct MUI_ListviewData *data = INST_DATA(cl, obj);
373 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) &data->ehn);
374 data->mouse_click = 0;
376 return DoSuperMethodA(cl, obj, (Msg) msg);
379 /**************************************************************************
380 MUIM_HandleEvent
381 **************************************************************************/
382 IPTR Listview__MUIM_HandleEvent(struct IClass *cl, Object *obj,
383 struct MUIP_HandleEvent *msg)
385 struct MUI_ListviewData *data = INST_DATA(cl, obj);
386 Object *list = data->list;
387 struct MUI_List_TestPos_Result pos;
388 LONG seltype, old_active, new_active, visible, first, last, i;
389 IPTR result = 0;
390 BOOL select = FALSE, clear = FALSE, range_select = FALSE, changing;
391 WORD delta;
392 typeof(msg->muikey) muikey = msg->muikey;
394 new_active = old_active = XGET(list, MUIA_List_Active);
395 visible = XGET(list, MUIA_List_Visible);
397 if (muikey != MUIKEY_NONE)
399 result = MUI_EventHandlerRC_Eat;
401 /* Make keys behave differently in read-only mode */
402 if (data->read_only)
404 switch (muikey)
406 case MUIKEY_TOP:
407 muikey = MUIKEY_LINESTART;
408 break;
410 case MUIKEY_BOTTOM:
411 muikey = MUIKEY_LINEEND;
412 break;
414 case MUIKEY_UP:
415 muikey = MUIKEY_LEFT;
416 break;
418 case MUIKEY_DOWN:
419 case MUIKEY_PRESS:
420 muikey = MUIKEY_RIGHT;
421 break;
425 switch (muikey)
427 case MUIKEY_TOGGLE:
428 if (data->multiselect != MUIV_Listview_MultiSelect_None
429 && !data->read_only)
431 select = TRUE;
432 data->click_column = data->def_click_column;
433 new_active = MUIV_List_Active_Down;
435 else
437 DoMethod(list, MUIM_List_Jump, 0);
438 muikey = MUIKEY_NONE;
440 break;
442 case MUIKEY_TOP:
443 new_active = MUIV_List_Active_Top;
444 break;
446 case MUIKEY_BOTTOM:
447 new_active = MUIV_List_Active_Bottom;
448 break;
450 case MUIKEY_LEFT:
451 case MUIKEY_WORDLEFT:
452 DoMethod(list, MUIM_List_Jump, MUIV_List_Jump_Up);
453 break;
455 case MUIKEY_RIGHT:
456 case MUIKEY_WORDRIGHT:
457 DoMethod(list, MUIM_List_Jump, MUIV_List_Jump_Down);
458 break;
460 case MUIKEY_LINESTART:
461 DoMethod(list, MUIM_List_Jump, MUIV_List_Jump_Top);
462 break;
464 case MUIKEY_LINEEND:
465 DoMethod(list, MUIM_List_Jump, MUIV_List_Jump_Bottom);
466 break;
468 case MUIKEY_UP:
469 new_active = MUIV_List_Active_Up;
470 break;
472 case MUIKEY_DOWN:
473 new_active = MUIV_List_Active_Down;
474 break;
476 case MUIKEY_PAGEUP:
477 if (data->read_only)
478 DoWheelMove(cl, obj, -visible);
479 else
480 new_active = MUIV_List_Active_PageUp;
481 break;
483 case MUIKEY_PAGEDOWN:
484 if (data->read_only)
485 DoWheelMove(cl, obj, visible);
486 else
487 new_active = MUIV_List_Active_PageDown;
488 break;
490 default:
491 result = 0;
494 else if (msg->imsg)
496 DoMethod(list, MUIM_List_TestPos, msg->imsg->MouseX,
497 msg->imsg->MouseY, (IPTR) &pos);
499 switch (msg->imsg->Class)
501 case IDCMP_MOUSEBUTTONS:
502 if (msg->imsg->Code == SELECTDOWN)
504 if (_isinobject(list, msg->imsg->MouseX, msg->imsg->MouseY))
506 data->mouse_click = MOUSE_CLICK_ENTRY;
508 if (!data->read_only && pos.entry != -1)
510 new_active = pos.entry;
512 clear = (data->multiselect
513 == MUIV_Listview_MultiSelect_Shifted
514 && (msg->imsg->Qualifier
515 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0);
516 seltype = clear ?
517 MUIV_List_Select_On: MUIV_List_Select_Toggle;
518 select = data->multiselect
519 != MUIV_Listview_MultiSelect_None;
521 /* Handle MUIA_Listview_ClickColumn */
522 data->click_column = pos.column;
523 superset(cl, obj, MUIA_Listview_ClickColumn,
524 data->click_column);
526 /* Handle double clicking */
527 if (data->last_active == pos.entry
528 && DoubleClick(data->last_secs, data->last_mics,
529 msg->imsg->Seconds, msg->imsg->Micros))
531 set(obj, MUIA_Listview_DoubleClick, TRUE);
532 data->last_active = -1;
533 data->last_secs = data->last_mics = 0;
535 else
537 data->last_active = pos.entry;
538 data->last_secs = msg->imsg->Seconds;
539 data->last_mics = msg->imsg->Micros;
542 /* Look out for mouse movement, timer and
543 inactive-window events while mouse button is
544 down */
545 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
546 (IPTR) &data->ehn);
547 data->ehn.ehn_Events |= (IDCMP_MOUSEMOVE
548 | IDCMP_INTUITICKS |IDCMP_INACTIVEWINDOW);
549 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
550 (IPTR) &data->ehn);
554 else
556 /* Activate object */
557 if (msg->imsg->Code == SELECTUP && data->mouse_click)
559 set(_win(obj), MUIA_Window_ActiveObject, (IPTR)obj);
560 data->mouse_click = 0;
563 /* Restore normal event mask */
564 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
565 (IPTR) &data->ehn);
566 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
567 | IDCMP_INACTIVEWINDOW);
568 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
569 (IPTR) &data->ehn);
571 break;
573 case IDCMP_MOUSEMOVE:
574 case IDCMP_INTUITICKS:
575 if (pos.flags & MUI_LPR_ABOVE)
576 new_active = MUIV_List_Active_Up;
577 else if (pos.flags & MUI_LPR_BELOW)
578 new_active = MUIV_List_Active_Down;
579 else
580 new_active = pos.entry;
582 select = new_active != old_active
583 && data->multiselect != MUIV_Listview_MultiSelect_None;
584 if (select)
586 DoMethod(list, MUIM_List_Select, MUIV_List_Select_Active,
587 MUIV_List_Select_Ask, &seltype);
588 range_select = new_active >= 0;
591 break;
593 case IDCMP_INACTIVEWINDOW:
594 /* Stop listening for events we only listen to when mouse button is
595 down: we will not be informed of the button being released */
596 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
597 (IPTR) &data->ehn);
598 data->ehn.ehn_Events &=
599 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS | IDCMP_INACTIVEWINDOW);
600 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
601 (IPTR) &data->ehn);
602 break;
604 case IDCMP_RAWKEY:
605 /* Scroll wheel */
606 if (_isinobject(data->vert, msg->imsg->MouseX, msg->imsg->MouseY))
607 delta = 1;
608 else if (_isinobject(list, msg->imsg->MouseX, msg->imsg->MouseY))
609 delta = 4;
610 else
611 delta = 0;
613 if (delta != 0)
615 switch (msg->imsg->Code)
617 case RAWKEY_NM_WHEEL_UP:
618 DoWheelMove(cl, obj, -delta);
619 break;
621 case RAWKEY_NM_WHEEL_DOWN:
622 DoWheelMove(cl, obj, delta);
623 break;
625 result = MUI_EventHandlerRC_Eat;
627 break;
631 /* Decide in advance if any selections may change */
632 changing = clear || muikey == MUIKEY_TOGGLE || select;
634 /* Change selected and active entries */
635 if (changing)
636 set(obj, MUIA_Listview_SelectChange, TRUE);
638 if (clear)
640 DoMethod(list, MUIM_List_Select, MUIV_List_Select_All,
641 MUIV_List_Select_Off, NULL);
644 if (muikey == MUIKEY_TOGGLE)
646 DoMethod(list, MUIM_List_Select,
647 MUIV_List_Select_Active,
648 MUIV_List_Select_Toggle, NULL);
649 select = FALSE;
652 if (new_active != old_active)
653 set(list, MUIA_List_Active, new_active);
655 if (select)
657 if (range_select)
659 if (old_active < new_active)
660 first = old_active + 1, last = new_active;
661 else
662 first = new_active, last = old_active - 1;
663 for (i = first; i <= last; i++)
664 DoMethod(list, MUIM_List_Select, i, seltype, NULL);
666 else
667 DoMethod(list, MUIM_List_Select, MUIV_List_Select_Active, seltype,
668 NULL);
671 if (changing)
672 set(obj, MUIA_Listview_SelectChange, FALSE);
674 return result;
677 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely)
679 struct MUI_ListviewData *data = INST_DATA(cl, obj);
680 LONG new, first, entries, visible;
682 new = first = XGET(data->list, MUIA_List_First);
683 entries = XGET(data->list, MUIA_List_Entries);
684 visible = XGET(data->list, MUIA_List_Visible);
686 new += wheely;
688 if (new > entries - visible)
690 new = entries - visible;
693 if (new < 0)
695 new = 0;
698 if (new != first)
700 set(data->list, MUIA_List_First, new);
704 BOOPSI_DISPATCHER(IPTR, Listview_Dispatcher, cl, obj, msg)
706 switch (msg->MethodID)
708 case OM_SET:
709 return Listview__OM_SET(cl, obj, (struct opSet *)msg);
710 case OM_GET:
711 return Listview__OM_GET(cl, obj, (struct opGet *)msg);
712 case OM_NEW:
713 return Listview__OM_NEW(cl, obj, (struct opSet *)msg);
714 case OM_DISPOSE:
715 return Listview__OM_DISPOSE(cl, obj, msg);
716 case MUIM_Setup:
717 return Listview__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
718 case MUIM_Cleanup:
719 return Listview__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
720 case MUIM_HandleEvent:
721 return Listview__MUIM_HandleEvent(cl, obj,
722 (struct MUIP_HandleEvent *)msg);
723 case MUIM_List_Clear:
724 case MUIM_List_CreateImage:
725 case MUIM_List_DeleteImage:
726 case MUIM_List_Exchange:
727 case MUIM_List_GetEntry:
728 case MUIM_List_Insert:
729 case MUIM_List_InsertSingle:
730 case MUIM_List_Jump:
731 case MUIM_List_NextSelected:
732 case MUIM_List_Redraw:
733 case MUIM_List_Remove:
734 case MUIM_List_Select:
735 case MUIM_List_Sort:
736 case MUIM_List_TestPos:
738 struct MUI_ListviewData *data = INST_DATA(cl, obj);
740 return DoMethodA(data->list, msg);
745 return DoSuperMethodA(cl, obj, msg);
747 BOOPSI_DISPATCHER_END
750 * Class descriptor.
752 const struct __MUIBuiltinClass _MUI_Listview_desc =
754 MUIC_Listview,
755 MUIC_Group,
756 sizeof(struct MUI_ListviewData),
757 (void *) Listview_Dispatcher