Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / libs / muimaster / classes / list.c
blob8d1797084eab19a9c1dbe8c3ea15eb4ee13ff6d8
1 /*
2 Copyright © 2002-2016, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <string.h>
7 #include <stdlib.h>
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <devices/rawkeycodes.h>
14 #include <clib/alib_protos.h>
15 #include <proto/exec.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
20 #include <proto/muimaster.h>
22 /* #define MYDEBUG 1 */
23 #include "debug.h"
24 #include "mui.h"
25 #include "muimaster_intern.h"
26 #include "support.h"
27 #include "imspec.h"
28 #include "textengine.h"
29 #include "listimage.h"
30 #include "prefs.h"
32 extern struct Library *MUIMasterBase;
34 #define ENTRY_TITLE (-1)
36 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
37 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
39 #define BAR_WIDTH 2
41 enum
43 ARG_DELTA,
44 ARG_PREPARSE,
45 ARG_WEIGHT,
46 ARG_MINWIDTH,
47 ARG_MAXWIDTH,
48 ARG_COL,
49 ARG_BAR,
50 ARG_CNT
54 struct ListEntry
56 APTR data;
57 LONG width; /* Line width */
58 LONG height; /* Line height */
59 WORD flags; /* see below */
60 LONG widths[]; /* Widths of the columns */
63 #define ENTRY_SELECTED (1<<0)
66 struct ColumnInfo
68 int colno; /* Column number */
69 int user_width; /* user set width; -1 if entry width */
70 int min_width; /* min width percentage */
71 int max_width; /* min width percentage */
72 int weight;
73 int delta; /* ignored for the first and last column, defaults to 4 */
74 int bar;
75 STRPTR preparse;
76 int entries_width; /* width of the entries (maximum of all widths) */
79 struct MUI_ImageSpec_intern;
81 struct MUI_ListData
83 /* bool attrs */
84 ULONG flags;
86 APTR intern_pool; /* The internal pool which the class has allocated */
87 LONG intern_puddle_size;
88 LONG intern_thresh_size;
89 APTR pool; /* the pool which is used to allocate list entries */
91 struct Hook *construct_hook;
92 struct Hook *compare_hook;
93 struct Hook *destruct_hook;
94 struct Hook *display_hook;
95 struct Hook *multi_test_hook;
97 struct Hook default_compare_hook;
99 /* List management, currently we use a simple flat array, which is not
100 * good if many entries are inserted/deleted */
101 LONG entries_num; /* Number of Entries in the list */
102 LONG entries_allocated;
103 struct ListEntry **entries;
105 LONG entries_first; /* first visible entry */
106 LONG entries_visible; /* number of visible entries,
107 * determined at MUIM_Layout */
108 LONG entries_active;
109 LONG insert_position; /* pos of the last insertion */
111 LONG entry_maxheight; /* Maximum height of an entry */
112 ULONG entry_minheight; /* from MUIA_List_MinLineHeight */
114 LONG entries_totalheight;
115 LONG entries_maxwidth;
117 LONG vertprop_entries;
118 LONG vertprop_visible;
119 LONG vertprop_first;
121 LONG confirm_entries_num; /* These are the correct entries num, used
122 * so you cannot set MUIA_List_Entries to
123 * wrong values */
125 LONG entries_top_pixel; /* Where the entries start */
127 /* Column managment, is allocated by ParseListFormat() and freed
128 * by CleanListFormat() */
129 STRPTR format;
130 LONG columns; /* Number of columns the list has */
131 struct ColumnInfo *ci;
132 STRPTR *preparses;
133 STRPTR *strings_mem; /* safe pointer to allocated memory for strings[] */
134 STRPTR *strings; /* the strings for the display function, one
135 * more than needed (for the entry position) */
137 /* Titlestuff */
138 int title_height; /* The complete height of the title */
139 STRPTR title; /* On single column lists this is the title,
140 * otherwise 1. NULL for no title(s) */
142 /* Cursor images */
143 struct MUI_ImageSpec_intern *list_cursor;
144 struct MUI_ImageSpec_intern *list_select;
145 struct MUI_ImageSpec_intern *list_selcur;
147 /* Render optimization */
148 int update; /* 1 - update everything, 2 - redraw entry at update_pos,
149 * 3 - scroll to current entries_first (old value is in
150 * update_pos) */
151 int update_pos;
153 LONG drop_mark_y;
155 /* list images */
156 struct MinList images;
158 /* user prefs */
159 ListviewRefresh prefs_refresh;
160 UWORD prefs_linespacing;
161 BOOL prefs_smoothed;
162 UWORD prefs_smoothval;
164 /* render space handling */
165 Object *area;
166 BOOL area_replaced;
167 BOOL area_connected;
169 /***************************/
170 /* Former Listview members */
171 /***************************/
173 Object *vert;
174 BOOL vert_connected;
175 IPTR scroller_pos;
176 BOOL read_only;
177 IPTR multiselect;
179 /* clicked column */
180 LONG click_column;
181 LONG def_click_column;
183 LONG mouse_click; /* see below if mouse is held down */
185 /* double click */
186 ULONG last_secs;
187 ULONG last_mics;
188 ULONG last_active;
190 struct MUI_EventHandlerNode ehn;
192 /* user prefs */
193 ListviewMulti prefs_multi;
195 BOOL select_change;
196 BOOL doubleclick;
198 struct Hook hook;
201 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
202 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
204 #define LIST_ADJUSTWIDTH (1<<0)
205 #define LIST_ADJUSTHEIGHT (1<<1)
206 #define LIST_AUTOVISIBLE (1<<2)
207 #define LIST_DRAGSORTABLE (1<<3)
208 #define LIST_SHOWDROPMARKS (1<<4)
209 #define LIST_QUIET (1<<5)
212 /****** List.mui/MUIA_List_Active ********************************************
214 * NAME
215 * MUIA_List_Active -- (V4) [ISG], LONG
217 * FUNCTION
218 * The index of the active entry. There can be at most one active entry
219 * in a list. The active entry is highlighted visibly, except for
220 * read-only lists (those whose Listview has MUIA_Listview_Input set to
221 * FALSE). Selecting an entry with the mouse, or moving through the list
222 * with keyboard controls will also change the active entry (again
223 * excepting read-only lists).
225 * When set programmatically through this attribute, some special values
226 * can be used:
228 * MUIV_List_Active_Off
229 * MUIV_List_Active_Top
230 * MUIV_List_Active_Bottom
231 * MUIV_List_Active_Up
232 * MUIV_List_Active_Down
233 * MUIV_List_Active_PageUp
234 * MUIV_List_Active_PageDown
236 * When this attribute is read, either the index of the active entry or
237 * the special value MUIV_List_Active_Off will be returned.
239 * Setting this attribute to a new value will additionally have the same
240 * effect as calling the MUIM_List_Jump method with the specified or
241 * implied index.
243 * NOTES
244 * The concept of an active entry must not be confused with that of a
245 * selected entry.
247 * SEE ALSO
248 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
250 ******************************************************************************
254 /****** List.mui/MUIA_List_CompareHook ***************************************
256 * NAME
257 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
259 * FUNCTION
260 * The provided hook indicates the sort ordering of two list entries.
261 * The hook receives list-entry data pointers as its second and third
262 * arguments. The hook should return a negative value if the first entry
263 * should be placed before the second entry, a positive value if the
264 * first entry should be placed after the second entry, and zero if the
265 * entries are equal.
267 * In addition to being used internally for sorting operations, this hook
268 * will be called when MUIM_List_Compare is externally invoked.
270 * If this attribute is not specified or is set to NULL, all list entries
271 * must be strings.
273 ******************************************************************************
277 /****** List.mui/MUIA_List_First *********************************************
279 * NAME
280 * MUIA_List_First -- (V4) [..G], LONG
282 * FUNCTION
283 * The index of the first entry that can be seen (assuming nothing
284 * obscures the list) This value of this attribute is -1 when the
285 * list's window is not open.
287 * NOTES
288 * Notification does not occur on this attribute in MUI.
290 * SEE ALSO
291 * MUIA_List_First, MUIA_List_Entries
293 ******************************************************************************
297 /****** List.mui/MUIA_List_MultiTestHook *************************************
299 * NAME
300 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
302 * FUNCTION
303 * The provided hook indicates whether a particular list entry
304 * may be multiselected. The hook receives the list-entry data pointer as
305 * its third argument, and returns a Boolean value. If this attribute is
306 * not specified or is set to NULL, all list entries are considered
307 * multi-selectable.
309 * Whenever an entry is about to be selected, this hook is called if
310 * there are other entries already selected. If the hook returns TRUE,
311 * the entry may be multi-selected; if the hook returns FALSE, the entry
312 * remains unselected.
314 * Additionally, if a non-multi-selectable entry has been selected (as
315 * the only selected entry in the list), any attempt to select an
316 * additional entry will fail.
318 ******************************************************************************
322 /****** List.mui/MUIA_List_Title *********************************************
324 * NAME
325 * MUIA_List_Title -- (V6) [ISG], char *
327 * FUNCTION
328 * A heading for the list, placed above list entries. A value of NULL
329 * means no title is used. A value of TRUE means that the custom
330 * display hook provides a separate title for each column; the hook
331 * must then provide column titles instead of normal column data when
332 * the entry pointer provided is NULL.
334 * NOTES
335 * If a string is set for this attribute, it is not cached within the
336 * object.
338 * SEE ALSO
339 * MUIA_List_DisplayHook
341 ******************************************************************************
345 /****** List.mui/MUIA_List_Visible *******************************************
347 * NAME
348 * MUIA_List_Visible -- (V4) [..G], LONG
350 * FUNCTION
351 * The number of entries that can be seen at once with the list's
352 * current dimensions. This value of this attribute is -1 when the
353 * list's window is not open.
355 * NOTES
356 * Notification does not occur on this attribute in MUI.
358 * SEE ALSO
359 * MUIA_List_First, MUIA_List_Entries
361 ******************************************************************************
365 /**************************************************************************
366 Allocate a single list entry, does not initialize it (except the pointer)
367 **************************************************************************/
368 static struct ListEntry *AllocListEntry(struct MUI_ListData *data)
370 struct ListEntry *le;
371 /* what happens, if data->columns is later increased by MUIA_List_Format? */
372 IPTR size = sizeof(struct ListEntry) + sizeof(LONG) * (data->columns + 1);
374 le = (struct ListEntry *) AllocVecPooled(data->pool, size);
375 D(bug("List AllocListEntry %p, %ld bytes\n", le, size));
376 if(le)
378 /* possible, that we have an external pool, which does not have
379 MEMF_CLEAR set.. */
380 memset(le, 0, size);
382 return le;
385 /**************************************************************************
386 Deallocate a single list entry, does not deinitialize it
387 **************************************************************************/
388 static void FreeListEntry(struct MUI_ListData *data,
389 struct ListEntry *entry)
391 D(bug("FreeListEntry %p\n", entry));
392 FreeVecPooled(data->pool, entry);
395 /**************************************************************************
396 Ensures that there can be at least the given amount of entries within
397 the list. Returns 0 if not. It also allocates the space for the title.
398 It can be accessed with data->entries[ENTRY_TITLE]
399 **************************************************************************/
400 static int SetListSize(struct MUI_ListData *data, LONG size)
402 struct ListEntry **new_entries;
403 int new_entries_allocated;
405 if (size + 1 <= data->entries_allocated)
406 return 1;
408 new_entries_allocated = data->entries_allocated * 2 + 4;
409 if (new_entries_allocated < size + 1)
410 new_entries_allocated = size + 1 + 10; /* 10 is just random */
412 D(bug("List %p : SetListSize allocating %ld bytes\n", data,
413 new_entries_allocated * sizeof(struct ListEntry *)));
414 new_entries =
415 AllocVec(new_entries_allocated * sizeof(struct ListEntry *), 0);
416 if (NULL == new_entries)
417 return 0;
418 if (data->entries)
420 CopyMem(data->entries - 1, new_entries,
421 (data->entries_num + 1) * sizeof(struct ListEntry *));
422 FreeVec(data->entries - 1);
424 data->entries = new_entries + 1;
425 data->entries_allocated = new_entries_allocated;
426 return 1;
429 /**************************************************************************
430 Prepares the insertion of count entries at pos.
431 This function doesn't care if there is enough space in the datastructure.
432 SetListSize() must be used first.
433 With current implementation, this call will never fail
434 **************************************************************************/
435 static int PrepareInsertListEntries(struct MUI_ListData *data, int pos,
436 int count)
438 memmove(&data->entries[pos + count], &data->entries[pos],
439 (data->entries_num - pos) * sizeof(struct ListEntry *));
440 return 1;
443 /**************************************************************************
444 Removes count (already deinitalized) list entries starting az pos.
445 **************************************************************************/
446 static void RemoveListEntries(struct MUI_ListData *data, int pos, int count)
448 // FIXME: segfault if entries_num = pos = count = 1
449 memmove(&data->entries[pos], &data->entries[pos + count],
450 (data->entries_num - (pos + count)) * sizeof(struct ListEntry *));
453 /**************************************************************************
454 Frees all memory allocated by ParseListFormat()
455 **************************************************************************/
456 static void FreeListFormat(struct MUI_ListData *data)
458 int i;
460 if (data->ci)
462 for (i = 0; i < data->columns; i++)
464 FreeVec(data->ci[i].preparse);
465 data->ci[i].preparse = NULL;
467 FreeVec(data->ci);
468 data->ci = NULL;
470 FreeVec(data->preparses);
471 data->preparses = NULL;
472 if (data->strings_mem)
474 FreeVec(data->strings_mem);
475 data->strings_mem = NULL;
476 data->strings = NULL;
478 data->columns = 0;
481 /**************************************************************************
482 Parses the given format string (also frees a previously parsed format).
483 Return 0 on failure.
484 **************************************************************************/
485 static int ParseListFormat(struct MUI_ListData *data, STRPTR format)
487 int new_columns, i;
488 STRPTR ptr;
489 STRPTR format_sep;
490 char c;
492 IPTR args[ARG_CNT];
493 struct RDArgs *rdargs;
495 if (!format)
496 format = (STRPTR) "";
498 ptr = format;
500 FreeListFormat(data);
502 new_columns = 1;
504 /* Count the number of columns first */
505 while ((c = *ptr++))
506 if (c == ',')
507 new_columns++;
509 if (!(data->preparses =
510 AllocVec((new_columns + 10) * sizeof(STRPTR), 0)))
511 return 0;
513 if (!(data->strings_mem = AllocVec((new_columns + 1 + 10)
514 * sizeof(STRPTR), 0))) /* hold enough space also for the entry pos,
515 * used by orginal MUI and also some
516 * security space */
517 return 0;
518 data->strings=data->strings_mem;
520 if (!(data->ci = AllocVec(new_columns * sizeof(struct ColumnInfo), 0)))
521 return 0;
523 // set defaults
524 for (i = 0; i < new_columns; i++)
526 data->ci[i].colno = -1; // -1 means: use unassigned column
527 data->ci[i].weight = 100;
528 data->ci[i].delta = 4;
529 data->ci[i].min_width = -1;
530 data->ci[i].max_width = -1;
531 data->ci[i].user_width = -1;
532 data->ci[i].bar = FALSE;
533 data->ci[i].preparse = NULL;
536 if ((format_sep = StrDup(format)) != 0)
538 for (i = 0; format_sep[i] != '\0'; i++)
540 if (format_sep[i] == ',')
541 format_sep[i] = '\0';
544 if ((rdargs = AllocDosObject(DOS_RDARGS, NULL)) != 0)
546 ptr = format_sep;
547 i = 0;
550 rdargs->RDA_Source.CS_Buffer = ptr;
551 rdargs->RDA_Source.CS_Length = strlen(ptr);
552 rdargs->RDA_Source.CS_CurChr = 0;
553 rdargs->RDA_DAList = 0;
554 rdargs->RDA_Buffer = NULL;
555 rdargs->RDA_BufSiz = 0;
556 rdargs->RDA_ExtHelp = NULL;
557 rdargs->RDA_Flags = 0;
559 memset(args, 0, sizeof args);
560 if (ReadArgs(FORMAT_TEMPLATE, args, rdargs))
562 if (args[ARG_COL])
563 data->ci[i].colno = *(LONG *) args[ARG_COL];
564 if (args[ARG_WEIGHT])
565 data->ci[i].weight = *(LONG *) args[ARG_WEIGHT];
566 if (args[ARG_DELTA])
567 data->ci[i].delta = *(LONG *) args[ARG_DELTA];
568 if (args[ARG_MINWIDTH])
569 data->ci[i].min_width =
570 *(LONG *) args[ARG_MINWIDTH];
571 if (args[ARG_MAXWIDTH])
572 data->ci[i].max_width =
573 *(LONG *) args[ARG_MAXWIDTH];
574 data->ci[i].bar = args[ARG_BAR];
575 if (args[ARG_PREPARSE])
576 data->ci[i].preparse =
577 StrDup((STRPTR) args[ARG_PREPARSE]);
579 FreeArgs(rdargs);
581 ptr += strlen(ptr) + 1;
582 i++;
584 while (i < new_columns);
585 FreeDosObject(DOS_RDARGS, rdargs);
587 FreeVec(format_sep);
590 for (i = 0; i < new_columns; i++)
592 D(bug("colno %d weight %d delta %d preparse %s\n",
593 data->ci[i].colno, data->ci[i].weight, data->ci[i].delta,
594 data->ci[i].preparse));
597 data->columns = new_columns;
598 data->strings++; /* Skip entry pos */
600 return 1;
603 /**************************************************************************
604 Call the MUIM_List_Display for the given entry. It fills out
605 data->string and data->preparses
606 **************************************************************************/
607 static void DisplayEntry(struct IClass *cl, Object *obj, int entry_pos)
609 struct MUI_ListData *data = INST_DATA(cl, obj);
610 APTR entry_data;
611 int col;
613 for (col = 0; col < data->columns; col++)
614 data->preparses[col] = data->ci[col].preparse;
616 if (entry_pos == ENTRY_TITLE)
618 if ((data->columns == 1) && (data->title != (STRPTR) 1))
620 *data->strings = data->title;
621 return;
623 entry_data = NULL; /* it's a title request */
625 else
626 entry_data = data->entries[entry_pos]->data;
628 /* Get the display formation */
629 DoMethod(obj, MUIM_List_Display, (IPTR) entry_data,
630 (IPTR) data->strings, entry_pos, (IPTR) data->preparses);
633 /**************************************************************************
634 Determine the dims of a single entry and adapt the columninfo according
635 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
636 be redrawn after this operation, 1 if all entries need to be redrawn.
637 **************************************************************************/
638 static int CalcDimsOfEntry(struct IClass *cl, Object *obj, int pos)
640 struct MUI_ListData *data = INST_DATA(cl, obj);
641 struct ListEntry *entry = data->entries[pos];
642 int j;
643 int ret = 0;
645 if (!entry)
646 return ret;
648 if (!(_flags(obj) & MADF_SETUP))
649 return ret;
651 DisplayEntry(cl, obj, pos);
653 /* Set height to at least minheight */
654 if (data->entries[pos]->height < data->entry_minheight)
655 data->entries[pos]->height = data->entry_minheight;
657 for (j = 0; j < data->columns; j++)
659 ZText *text =
660 zune_text_new(data->preparses[j], data->strings[j],
661 ZTEXT_ARG_NONE, 0);
662 if (text != NULL)
664 zune_text_get_bounds(text, obj);
666 if (text->height > data->entries[pos]->height)
668 data->entries[pos]->height = text->height;
669 /* entry height changed, redraw all entries later */
670 ret = 1;
672 data->entries[pos]->widths[j] = text->width;
674 if (text->width > data->ci[j].entries_width)
676 /* This entry has a greater width for this column than any
677 * other entry, so we store this value
679 data->ci[j].entries_width = text->width;
680 /* column width changed, redraw all entries later */
681 ret = 1;
684 zune_text_destroy(text);
687 if (data->entries[pos]->height > data->entry_maxheight)
689 data->entry_maxheight = data->entries[pos]->height;
690 /* maximum entry height changed, redraw all entries later */
691 ret = 1;
694 return ret;
697 /**************************************************************************
698 Determine the widths of the entries
699 **************************************************************************/
700 static void CalcWidths(struct IClass *cl, Object *obj)
702 int i, j;
703 struct MUI_ListData *data = INST_DATA(cl, obj);
705 if (!(_flags(obj) & MADF_SETUP))
706 return;
708 for (j = 0; j < data->columns; j++)
709 data->ci[j].entries_width = 0;
711 data->entry_maxheight = 0;
712 data->entries_totalheight = 0;
713 data->entries_maxwidth = 0;
715 for (i = (data->title ? ENTRY_TITLE : 0); i < data->entries_num; i++)
717 CalcDimsOfEntry(cl, obj, i);
718 data->entries_totalheight += data->entries[i]->height;
721 for (j = 0; j < data->columns; j++)
722 data->entries_maxwidth += data->ci[j].entries_width;
724 if (!data->entry_maxheight)
725 data->entry_maxheight = 1;
728 /**************************************************************************
729 Calculates the number of visible entry lines. Returns 1 if it has
730 changed
731 **************************************************************************/
732 static int CalcVertVisible(struct IClass *cl, Object *obj)
734 struct MUI_ListData *data = INST_DATA(cl, obj);
735 int old_entries_visible = data->entries_visible;
736 int old_entries_top_pixel = data->entries_top_pixel;
738 data->vertprop_visible = data->entries_visible =
739 (_mheight(data->area) - data->title_height)
740 / (data->entry_maxheight /* + data->prefs_linespacing */ );
742 /* Distribute extra vertical space evenly between top and bottom of
743 * list */
745 data->entries_top_pixel = _mtop(data->area) + data->title_height
746 + (_mheight(data->area) - data->title_height
748 data->entries_visible *
749 (data->entry_maxheight /* + data->prefs_linespacing */ )) / 2;
751 if (data->entries_visible != old_entries_visible)
753 superset(cl, obj, MUIA_List_Visible, data->entries_visible);
754 superset(cl, obj, MUIA_List_VertProp_Visible, data->entries_visible);
757 return (old_entries_visible != data->entries_visible)
758 || (old_entries_top_pixel != data->entries_top_pixel);
761 /**************************************************************************
762 Default hook to compare two list entries. Works for strings only.
763 **************************************************************************/
764 AROS_UFH3S(int, default_compare_func,
765 AROS_UFHA(struct Hook *, h, A0),
766 AROS_UFHA(char *, s2, A2),
767 AROS_UFHA(char *, s1, A1))
769 AROS_USERFUNC_INIT
771 return Stricmp(s1, s2);
773 AROS_USERFUNC_EXIT
776 #define PROP_VERT_FIRST 1
778 static ULONG List_Function(struct Hook *hook, Object * obj, void **msg)
780 struct MUI_ListData *data = (struct MUI_ListData *)hook->h_Data;
781 SIPTR type = (SIPTR) msg[0];
782 SIPTR val = (SIPTR) msg[1];
784 switch (type)
786 case PROP_VERT_FIRST:
787 get(data->vert, MUIA_Prop_First, &val);
788 nnset(obj, MUIA_List_VertProp_First, val);
789 break;
791 return 0;
794 /* At entry to this function, data->area is always set, but data->vert may
795 * or may not be set */
796 static void List_HandleScrollerPos(struct IClass *cl, Object *obj)
798 struct MUI_ListData *data = INST_DATA(cl, obj);
799 BOOL vert_not_used = FALSE;
801 /* Disallow any changes after setup. This function should basically be
802 * creation-time only */
803 if (_flags(obj) & MADF_SETUP)
804 return;
806 /* Remove both objects */
807 if (data->area_connected)
808 DoMethod(obj, OM_REMMEMBER, data->area);
809 if (data->vert_connected)
810 DoMethod(obj, OM_REMMEMBER, data->vert);
812 /* Add list and/or scroller */
813 switch (data->scroller_pos)
815 case MUIV_Listview_ScrollerPos_None:
816 vert_not_used = TRUE;
817 DoMethod(obj, OM_ADDMEMBER, data->area);
818 break;
819 case MUIV_Listview_ScrollerPos_Left:
820 if (!data->vert)
821 data->vert =ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
822 DoMethod(obj, OM_ADDMEMBER, data->vert);
823 DoMethod(obj, OM_ADDMEMBER, data->area);
824 break;
825 default:
826 if (!data->vert)
827 data->vert = ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
828 DoMethod(obj, OM_ADDMEMBER, data->area);
829 DoMethod(obj, OM_ADDMEMBER, data->vert);
830 break;
833 data->area_connected = TRUE;
835 /* Handle case where it was decided that vert will not be used */
836 if (vert_not_used)
838 if (data->vert)
840 if (data->vert_connected)
842 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_First,
843 (IPTR) data->vert);
844 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_Visible,
845 (IPTR) data->vert);
846 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_Entries,
847 (IPTR) data->vert);
848 data->vert_connected = FALSE;
851 MUI_DisposeObject(data->vert);
852 data->vert = NULL;
856 /* If at this point data->vert is not null, it means vert is to be
857 * connected */
858 if (data->vert && !data->vert_connected)
860 LONG entries = 0, first = 0, visible = 0;
862 get(obj, MUIA_List_VertProp_First, &first);
863 get(obj, MUIA_List_VertProp_Visible, &visible);
864 get(obj, MUIA_List_VertProp_Entries, &entries);
866 SetAttrs(data->vert, MUIA_Prop_First, first,
867 MUIA_Prop_Visible, visible, MUIA_Prop_Entries, entries, TAG_DONE);
869 DoMethod(data->vert, MUIM_Notify, MUIA_Prop_First, MUIV_EveryTime,
870 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook, PROP_VERT_FIRST,
871 MUIV_TriggerValue);
873 /* Pass prop object as DestObj (based on code in NList) */
874 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_First, MUIV_EveryTime,
875 (IPTR) data->vert, 3, MUIM_NoNotifySet,
876 MUIA_Prop_First, MUIV_TriggerValue);
877 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_Visible, MUIV_EveryTime,
878 (IPTR) data->vert, 3, MUIM_NoNotifySet,
879 MUIA_Prop_Visible, MUIV_TriggerValue);
880 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_Entries, MUIV_EveryTime,
881 (IPTR) data->vert, 3, MUIM_NoNotifySet,
882 MUIA_Prop_Entries, MUIV_TriggerValue);
884 data->vert_connected = TRUE;
888 /**************************************************************************
889 OM_NEW
890 **************************************************************************/
891 IPTR List__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
893 struct MUI_ListData *data;
894 struct TagItem *tag;
895 struct TagItem *tags;
896 APTR *array = NULL;
897 LONG new_entries_active = MUIV_List_Active_Off;
898 struct TagItem rectattrs[2] =
899 {{TAG_IGNORE, TAG_IGNORE }, {TAG_DONE, TAG_DONE}};
900 Object *area;
902 /* search for MUIA_Frame as it has to be passed to rectangle object */
903 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
905 if (tag->ti_Tag == MUIA_Frame)
907 rectattrs[0].ti_Tag = MUIA_Frame;
908 rectattrs[0].ti_Data = tag->ti_Data;
909 tag->ti_Tag = TAG_IGNORE;
910 break;
914 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
915 MUIA_Group_Horiz, TRUE,
916 MUIA_InnerLeft, 0,
917 MUIA_InnerRight, 0,
918 MUIA_Group_Spacing, 0,
919 MUIA_Font, MUIV_Font_List,
920 MUIA_ShowSelState, FALSE,
921 MUIA_InputMode, MUIV_InputMode_RelVerify,
922 MUIA_Background, MUII_ListBack,
923 TAG_MORE, (IPTR) msg->ops_AttrList,
924 TAG_DONE);
926 if (!obj)
927 return FALSE;
929 data = INST_DATA(cl, obj);
931 data->columns = 1;
932 data->entries_active = MUIV_List_Active_Off;
933 data->intern_puddle_size = 2008;
934 data->intern_thresh_size = 1024;
935 data->default_compare_hook.h_Entry = (HOOKFUNC) default_compare_func;
936 data->default_compare_hook.h_SubEntry = 0;
937 data->compare_hook = &(data->default_compare_hook);
938 data->flags = LIST_SHOWDROPMARKS;
939 data->area_replaced = FALSE;
940 data->area_connected = FALSE;
941 data->vert_connected = FALSE;
943 data->entries_visible = data->vertprop_visible = -1;
944 data->last_active = -1;
946 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
947 data->ehn.ehn_Priority = 0;
948 data->ehn.ehn_Flags = 0;
949 data->ehn.ehn_Object = obj;
950 data->ehn.ehn_Class = cl;
952 /* HACK:
953 * List is a group where part of area is rendered and part is filled
954 * with other objects (inside of List dimensions). One such object is
955 * up/down arrow. This object depends on RelVerify mode to control
956 * behaviour. List also has the RelVerify mode. Area super class in case
957 * of both of those objects adds an event handler node with the same
958 * priority. Depending on the sort order, the event handler node of
959 * "list" can eat a click event and up/down arrows stop working. The
960 * hack is to decrease the priority of Area event handler for list to
961 * always favor up/down arrow. There are other hacky ways of solving
962 * this, but this seems least evil approach, as this hack is
963 * encapsulated in the List class itself.
965 muiAreaData(obj)->mad_ehn.ehn_Priority--;
967 data->hook.h_Entry = HookEntry;
968 data->hook.h_SubEntry = (HOOKFUNC) List_Function;
969 data->hook.h_Data = data;
971 area = (Object *)GetTagData(MUIA_List_ListArea, (IPTR) 0,
972 msg->ops_AttrList);
974 if (!area)
975 area = RectangleObject, MUIA_FillArea, FALSE, TAG_MORE,
976 (IPTR) rectattrs, End;
977 else
978 data->area_replaced = TRUE;
979 data->area = area;
981 /* parse initial taglist */
982 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
984 switch (tag->ti_Tag)
986 case MUIA_List_Active:
987 new_entries_active = tag->ti_Data;
988 break;
990 case MUIA_List_Pool:
991 data->pool = (APTR) tag->ti_Data;
992 break;
994 case MUIA_List_PoolPuddleSize:
995 data->intern_puddle_size = tag->ti_Data;
996 break;
998 case MUIA_List_PoolThreshSize:
999 data->intern_thresh_size = tag->ti_Data;
1000 break;
1002 case MUIA_List_CompareHook:
1003 data->compare_hook = (struct Hook *)tag->ti_Data;
1004 if (data->compare_hook == NULL)
1005 data->compare_hook = &data->default_compare_hook;
1006 break;
1008 case MUIA_List_ConstructHook:
1009 data->construct_hook = (struct Hook *)tag->ti_Data;
1010 break;
1012 case MUIA_List_DestructHook:
1013 data->destruct_hook = (struct Hook *)tag->ti_Data;
1014 break;
1016 case MUIA_List_DisplayHook:
1017 data->display_hook = (struct Hook *)tag->ti_Data;
1018 break;
1020 case MUIA_List_MultiTestHook:
1021 data->multi_test_hook = (struct Hook *)tag->ti_Data;
1022 break;
1024 case MUIA_List_SourceArray:
1025 array = (APTR *) tag->ti_Data;
1026 break;
1028 case MUIA_List_Format:
1029 data->format = StrDup((STRPTR) tag->ti_Data);
1030 break;
1032 case MUIA_List_Title:
1033 data->title = (STRPTR) tag->ti_Data;
1034 break;
1036 case MUIA_List_MinLineHeight:
1037 data->entry_minheight = tag->ti_Data;
1038 break;
1040 case MUIA_List_AdjustHeight:
1041 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTHEIGHT);
1042 break;
1044 case MUIA_List_AdjustWidth:
1045 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTWIDTH);
1046 break;
1048 case MUIA_List_AutoVisible:
1049 _handle_bool_tag(data->flags, tag->ti_Data, LIST_AUTOVISIBLE);
1050 break;
1052 case MUIA_List_ShowDropMarks:
1053 _handle_bool_tag(data->flags, tag->ti_Data, LIST_SHOWDROPMARKS);
1054 break;
1056 case MUIA_List_DragSortable:
1057 _handle_bool_tag(data->flags, tag->ti_Data, LIST_DRAGSORTABLE);
1058 set(obj, MUIA_Draggable, tag->ti_Data);
1059 break;
1061 case MUIA_Listview_ScrollerPos:
1062 data->scroller_pos = tag->ti_Data;
1063 break;
1065 case MUIA_Listview_Input:
1066 data->read_only = !tag->ti_Data;
1067 break;
1069 case MUIA_Listview_MultiSelect:
1070 data->multiselect = tag->ti_Data;
1071 break;
1073 case MUIA_Listview_DoubleClick:
1074 data->doubleclick = tag->ti_Data != 0;
1075 break;
1077 case MUIA_Listview_DefClickColumn:
1078 data->def_click_column = tag->ti_Data;
1079 break;
1083 List_HandleScrollerPos(cl, obj);
1085 if (!data->pool)
1087 /* No memory pool given, so we create our own */
1088 data->pool = data->intern_pool =
1089 CreatePool(0, data->intern_puddle_size,
1090 data->intern_thresh_size);
1091 if (!data->pool)
1093 CoerceMethod(cl, obj, OM_DISPOSE);
1094 return 0;
1098 /* parse the list format */
1099 if (!(ParseListFormat(data, data->format)))
1101 CoerceMethod(cl, obj, OM_DISPOSE);
1102 return 0;
1105 /* This is neccessary for at least the title */
1106 if (!SetListSize(data, 0))
1108 CoerceMethod(cl, obj, OM_DISPOSE);
1109 return 0;
1112 if (!(data->entries[ENTRY_TITLE] = AllocListEntry(data)))
1114 CoerceMethod(cl, obj, OM_DISPOSE);
1115 return 0;
1118 if (array)
1120 int i;
1121 /* Count the number of elements */
1122 for (i = 0; array[i] != NULL; i++)
1124 /* Insert them */
1125 DoMethod(obj, MUIM_List_Insert, (IPTR) array, i,
1126 MUIV_List_Insert_Top);
1129 if ((data->entries_num) && (new_entries_active != MUIV_List_Active_Off))
1131 switch (new_entries_active)
1133 case MUIV_List_Active_Top:
1134 new_entries_active = 0;
1135 break;
1137 case MUIV_List_Active_Bottom:
1138 new_entries_active = data->entries_num - 1;
1139 break;
1142 if (new_entries_active < 0)
1143 new_entries_active = 0;
1144 else if (new_entries_active >= data->entries_num)
1145 new_entries_active = data->entries_num - 1;
1147 data->entries_active = new_entries_active;
1148 /* Selected entry will be moved into visible area */
1151 NewList((struct List *)&data->images);
1153 D(bug("List_New(%lx)\n", obj));
1155 return (IPTR) obj;
1158 /**************************************************************************
1159 OM_DISPOSE
1160 **************************************************************************/
1161 IPTR List__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
1163 struct MUI_ListData *data = INST_DATA(cl, obj);
1165 D(bug("List Dispose\n"));
1167 /* Call destruct method for every entry and free the entries manually
1168 * to avoid notification */
1169 while (data->confirm_entries_num)
1171 struct ListEntry *lentry =
1172 data->entries[--data->confirm_entries_num];
1173 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1174 (IPTR) data->pool);
1175 FreeListEntry(data, lentry);
1178 if (data->intern_pool)
1179 DeletePool(data->intern_pool);
1180 if (data->entries)
1181 FreeVec(data->entries - 1);
1182 /* title is currently before all other elements */
1184 FreeListFormat(data);
1185 FreeVec(data->format);
1187 return DoSuperMethodA(cl, obj, msg);
1191 /**************************************************************************
1192 OM_SET
1193 **************************************************************************/
1194 IPTR List__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
1196 struct MUI_ListData *data = INST_DATA(cl, obj);
1197 struct TagItem *tag;
1198 struct TagItem *tags;
1200 /* parse taglist */
1201 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
1203 switch (tag->ti_Tag)
1205 case MUIA_List_CompareHook:
1206 data->compare_hook = (struct Hook *)tag->ti_Data;
1207 if (data->compare_hook == NULL)
1208 data->compare_hook = &data->default_compare_hook;
1209 break;
1211 case MUIA_List_ConstructHook:
1212 data->construct_hook = (struct Hook *)tag->ti_Data;
1213 break;
1215 case MUIA_List_DestructHook:
1216 data->destruct_hook = (struct Hook *)tag->ti_Data;
1217 break;
1219 case MUIA_List_DisplayHook:
1220 data->display_hook = (struct Hook *)tag->ti_Data;
1221 break;
1223 case MUIA_List_MultiTestHook:
1224 data->multi_test_hook = (struct Hook *)tag->ti_Data;
1225 if (data->multi_test_hook != NULL)
1227 /* Clearing current selections is the easiest way to keep
1228 * selections consistent with the new hook */
1229 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
1230 MUIV_List_Select_Off, NULL);
1232 break;
1234 case MUIA_List_Title:
1235 data->title = (STRPTR) tag->ti_Data;
1236 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1237 break;
1239 case MUIA_List_VertProp_First:
1240 data->vertprop_first = tag->ti_Data;
1241 if (data->entries_first != tag->ti_Data)
1243 set(obj, MUIA_List_First, tag->ti_Data);
1245 break;
1247 case MUIA_List_Format:
1248 data->format = StrDup((STRPTR) tag->ti_Data);
1249 ParseListFormat(data, data->format);
1250 // FIXME: should we check for errors?
1251 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1252 break;
1254 case MUIA_List_VertProp_Entries:
1255 data->vertprop_entries = tag->ti_Data;
1256 break;
1258 case MUIA_List_VertProp_Visible:
1259 data->vertprop_visible = tag->ti_Data;
1260 data->entries_visible = tag->ti_Data;
1261 break;
1263 case MUIA_List_Active:
1265 LONG new_entries_active = tag->ti_Data;
1267 if ((data->entries_num)
1268 && (new_entries_active != MUIV_List_Active_Off))
1270 switch (new_entries_active)
1272 case MUIV_List_Active_Top:
1273 new_entries_active = 0;
1274 break;
1276 case MUIV_List_Active_Bottom:
1277 new_entries_active = data->entries_num - 1;
1278 break;
1280 case MUIV_List_Active_Up:
1281 new_entries_active = data->entries_active - 1;
1282 break;
1284 case MUIV_List_Active_Down:
1285 new_entries_active = data->entries_active + 1;
1286 break;
1288 case MUIV_List_Active_PageUp:
1289 new_entries_active =
1290 data->entries_active - data->entries_visible;
1291 break;
1293 case MUIV_List_Active_PageDown:
1294 new_entries_active =
1295 data->entries_active + data->entries_visible;
1296 break;
1299 if (new_entries_active < 0)
1300 new_entries_active = 0;
1301 else if (new_entries_active >= data->entries_num)
1302 new_entries_active = data->entries_num - 1;
1304 else
1305 new_entries_active = -1;
1307 if (data->entries_active != new_entries_active)
1309 LONG old = data->entries_active;
1310 data->entries_active = new_entries_active;
1312 /* SelectChange stuff */
1313 if (new_entries_active != -1)
1315 DoMethod(obj, MUIM_List_SelectChange,
1316 new_entries_active, MUIV_List_Select_On, 0);
1317 DoMethod(obj, MUIM_List_SelectChange,
1318 new_entries_active, MUIV_List_Select_Active, 0);
1320 else
1321 DoMethod(obj, MUIM_List_SelectChange,
1322 MUIV_List_Active_Off, MUIV_List_Select_Off, 0);
1324 if (!data->read_only)
1326 data->update = 2;
1327 data->update_pos = old;
1328 MUI_Redraw(obj, MADF_DRAWUPDATE);
1329 data->update = 2;
1330 data->update_pos = data->entries_active;
1331 MUI_Redraw(obj, MADF_DRAWUPDATE);
1334 /* Make new active entry visible (if there is one and
1335 list is visible) */
1336 if (new_entries_active != -1
1337 && (_flags(obj) & MADF_SETUP))
1339 DoMethod(obj, MUIM_List_Jump,
1340 MUIV_List_Jump_Active);
1344 break;
1346 case MUIA_List_First:
1347 data->update_pos = data->entries_first;
1348 data->update = 3;
1349 data->entries_first = tag->ti_Data;
1351 MUI_Redraw(obj, MADF_DRAWUPDATE);
1352 if ((data->vertprop_first != tag->ti_Data)
1353 && (!(data->flags & LIST_QUIET)))
1355 set(obj, MUIA_List_VertProp_First, tag->ti_Data);
1357 break;
1359 case MUIA_List_Visible: /* Shouldn't be settable? */
1360 if (data->vertprop_visible != tag->ti_Data)
1361 set(obj, MUIA_List_VertProp_Visible, tag->ti_Data);
1362 break;
1364 case MUIA_List_Entries:
1365 if (data->confirm_entries_num == tag->ti_Data)
1367 data->entries_num = tag->ti_Data;
1368 if (!(data->flags & LIST_QUIET))
1370 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
1373 else
1375 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1377 break;
1379 case MUIA_List_Quiet:
1380 _handle_bool_tag(data->flags, tag->ti_Data, LIST_QUIET);
1381 if (!tag->ti_Data)
1383 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1384 if (data->entries_num != XGET(obj, MUIA_List_VertProp_Entries))
1385 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
1386 if (data->entries_first != XGET(obj, MUIA_List_VertProp_First))
1387 set(obj, MUIA_List_VertProp_First, data->entries_first);
1389 break;
1391 case MUIA_List_AutoVisible:
1392 _handle_bool_tag(data->flags, tag->ti_Data, LIST_AUTOVISIBLE);
1393 break;
1395 case MUIA_List_ShowDropMarks:
1396 _handle_bool_tag(data->flags, tag->ti_Data, LIST_SHOWDROPMARKS);
1397 break;
1399 case MUIA_List_DragSortable:
1400 _handle_bool_tag(data->flags, tag->ti_Data, LIST_DRAGSORTABLE);
1401 set(obj, MUIA_Draggable, tag->ti_Data);
1402 break;
1404 case MUIA_Selected:
1405 /* Swallow this so the Area class doesn't redraw us */
1406 tag->ti_Tag = TAG_IGNORE;
1407 break;
1409 case MUIA_Disabled:
1410 if (_flags(obj) & MADF_SETUP)
1412 /* Stop listening for events we only listen to when mouse
1413 button is down: we will not be informed of the button
1414 being released */
1415 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1416 (IPTR) &data->ehn);
1417 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
1418 | IDCMP_INACTIVEWINDOW);
1419 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1420 (IPTR) &data->ehn);
1422 break;
1424 case MUIA_Listview_DoubleClick: /* private set */
1425 data->doubleclick = tag->ti_Data != 0;
1426 break;
1428 case MUIA_Listview_SelectChange: /* private set */
1429 data->select_change = tag->ti_Data != 0;
1430 break;
1432 case MUIA_Listview_ScrollerPos: /* private set */
1433 data->scroller_pos = tag->ti_Data;
1434 List_HandleScrollerPos(cl, obj);
1435 break;
1437 case MUIA_Listview_Input: /* private set */
1438 data->read_only = !tag->ti_Data;
1439 break;
1441 case MUIA_Listview_MultiSelect: /* private set */
1442 data->multiselect = tag->ti_Data;
1443 break;
1445 case MUIA_Listview_DefClickColumn:
1446 data->def_click_column = tag->ti_Data;
1447 break;
1451 return DoSuperMethodA(cl, obj, (Msg) msg);
1454 /**************************************************************************
1455 OM_GET
1456 **************************************************************************/
1457 IPTR List__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
1459 /* small macro to simplify return value storage */
1460 #define STORE *(msg->opg_Storage)
1461 struct MUI_ListData *data = INST_DATA(cl, obj);
1463 switch (msg->opg_AttrID)
1465 case MUIA_List_Entries:
1466 STORE = data->entries_num;
1467 return 1;
1468 case MUIA_List_First:
1469 STORE = data->entries_first;
1470 return 1;
1471 case MUIA_List_Active:
1472 STORE = data->entries_active;
1473 return 1;
1474 case MUIA_List_InsertPosition:
1475 STORE = data->insert_position;
1476 return 1;
1477 case MUIA_List_Title:
1478 STORE = (IPTR) data->title;
1479 return 1;
1480 case MUIA_List_VertProp_Entries:
1481 STORE = data->vertprop_entries;
1482 return 1;
1483 case MUIA_List_VertProp_Visible:
1484 case MUIA_List_Visible:
1485 STORE = data->vertprop_visible;
1486 return 1;
1487 case MUIA_List_VertProp_First:
1488 STORE = data->vertprop_first;
1489 return 1;
1490 case MUIA_List_Format:
1491 STORE = (IPTR) data->format;
1492 return 1;
1493 case MUIA_List_AutoVisible:
1494 STORE = data->flags & LIST_AUTOVISIBLE;
1495 return 1;
1496 case MUIA_List_ShowDropMarks:
1497 STORE = data->flags & LIST_SHOWDROPMARKS;
1498 return 1;
1499 case MUIA_List_DragSortable:
1500 STORE = data->flags & LIST_DRAGSORTABLE;
1501 return 1;
1502 case MUIA_Listview_ClickColumn:
1503 STORE = data->click_column;
1504 return 1;
1505 case MUIA_Listview_DoubleClick:
1506 STORE = data->doubleclick;
1507 return 1;
1508 case MUIA_Listview_SelectChange:
1509 STORE = data->select_change;
1510 return 1;
1511 case MUIA_Listview_List:
1512 STORE = (IPTR)obj;
1513 return 1;
1514 case MUIA_Listview_DefClickColumn:
1515 STORE = data->def_click_column;
1516 return 1;
1519 if (DoSuperMethodA(cl, obj, (Msg) msg))
1520 return 1;
1521 return 0;
1522 #undef STORE
1525 /**************************************************************************
1526 MUIM_Setup
1527 **************************************************************************/
1528 IPTR List__MUIM_Setup(struct IClass *cl, Object *obj,
1529 struct MUIP_Setup *msg)
1531 struct MUI_ListData *data = INST_DATA(cl, obj);
1533 if (!DoSuperMethodA(cl, obj, (Msg) msg))
1534 return 0;
1536 data->prefs_refresh = muiGlobalInfo(obj)->mgi_Prefs->list_refresh;
1537 data->prefs_linespacing =
1538 muiGlobalInfo(obj)->mgi_Prefs->list_linespacing;
1539 data->prefs_smoothed = muiGlobalInfo(obj)->mgi_Prefs->list_smoothed;
1540 data->prefs_smoothval = muiGlobalInfo(obj)->mgi_Prefs->list_smoothval;
1542 data->list_cursor =
1543 zune_imspec_setup(MUII_ListCursor, muiRenderInfo(obj));
1544 data->list_select =
1545 zune_imspec_setup(MUII_ListSelect, muiRenderInfo(obj));
1546 data->list_selcur =
1547 zune_imspec_setup(MUII_ListSelCur, muiRenderInfo(obj));
1549 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
1550 if (data->multiselect == MUIV_Listview_MultiSelect_Default)
1552 if (data->prefs_multi == LISTVIEW_MULTI_SHIFTED)
1553 data->multiselect = MUIV_Listview_MultiSelect_Shifted;
1554 else
1555 data->multiselect = MUIV_Listview_MultiSelect_Always;
1558 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) &data->ehn);
1560 return 1;
1563 /**************************************************************************
1564 MUIM_Cleanup
1565 **************************************************************************/
1566 IPTR List__MUIM_Cleanup(struct IClass *cl, Object *obj,
1567 struct MUIP_Cleanup *msg)
1569 struct MUI_ListData *data = INST_DATA(cl, obj);
1571 zune_imspec_cleanup(data->list_cursor);
1572 zune_imspec_cleanup(data->list_select);
1573 zune_imspec_cleanup(data->list_selcur);
1575 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) &data->ehn);
1576 data->mouse_click = 0;
1578 return DoSuperMethodA(cl, obj, (Msg) msg);
1581 /**************************************************************************
1582 MUIM_AskMinMax
1583 **************************************************************************/
1584 IPTR List__MUIM_AskMinMax(struct IClass *cl, Object *obj,
1585 struct MUIP_AskMinMax *msg)
1587 struct MUI_ListData *data = INST_DATA(cl, obj);
1589 DoSuperMethodA(cl, obj, (Msg) msg);
1591 CalcWidths(cl, obj);
1593 if ((data->flags & LIST_ADJUSTWIDTH) && (data->entries_num > 0))
1595 msg->MinMaxInfo->MinWidth += data->entries_maxwidth;
1596 msg->MinMaxInfo->DefWidth += data->entries_maxwidth;
1597 msg->MinMaxInfo->MaxWidth += data->entries_maxwidth;
1599 else
1601 msg->MinMaxInfo->MinWidth += 40;
1602 msg->MinMaxInfo->DefWidth += 100;
1603 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1606 if (data->entries_num > 0)
1608 if (data->flags & LIST_ADJUSTHEIGHT)
1610 msg->MinMaxInfo->MinHeight += data->entries_totalheight;
1611 msg->MinMaxInfo->DefHeight += data->entries_totalheight;
1612 msg->MinMaxInfo->MaxHeight += data->entries_totalheight;
1614 else
1616 ULONG h = data->entry_maxheight + data->prefs_linespacing;
1617 msg->MinMaxInfo->MinHeight += 2 * h + data->prefs_linespacing;
1618 msg->MinMaxInfo->DefHeight += 8 * h + data->prefs_linespacing;
1619 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1622 else
1624 msg->MinMaxInfo->MinHeight += 36;
1625 msg->MinMaxInfo->DefHeight += 96;
1626 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1628 D(bug("List %p minheigh=%d, line maxh=%d\n",
1629 obj, msg->MinMaxInfo->MinHeight, data->entry_maxheight));
1630 return TRUE;
1633 /****i* List.mui/MUIM_Layout *************************************************
1635 * NAME
1636 * MUIM_Layout
1638 ******************************************************************************
1642 IPTR List__MUIM_Layout(struct IClass *cl, Object *obj,
1643 struct MUIP_Layout *msg)
1645 struct MUI_ListData *data = INST_DATA(cl, obj);
1646 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1647 LONG new_entries_first = data->entries_first;
1649 /* Calc the numbers of entries visible */
1650 CalcVertVisible(cl, obj);
1652 /* Ensure active entry is visible if requested */
1653 if (data->entries_active + 1 >=
1654 (data->entries_first + data->entries_visible)
1655 && (data->flags & LIST_AUTOVISIBLE) != 0)
1656 new_entries_first =
1657 data->entries_active - data->entries_visible + 1;
1659 /* Ensure there are no unnecessary empty lines */
1660 if ((new_entries_first + data->entries_visible >=
1661 data->entries_num)
1662 && (data->entries_visible <= data->entries_num))
1663 new_entries_first = data->entries_num - data->entries_visible;
1665 /* Always show the start of the list if it isn't long enough to fill the
1666 view */
1667 if (data->entries_num <= data->entries_visible)
1668 new_entries_first = 0;
1670 if (new_entries_first < 0)
1671 new_entries_first = 0;
1673 set(obj, new_entries_first != data->entries_first ?
1674 MUIA_List_First : TAG_IGNORE, new_entries_first);
1676 /* So the notify happens */
1677 set(obj, MUIA_List_VertProp_Visible, data->entries_visible);
1679 return rc;
1683 /**************************************************************************
1684 MUIM_Show
1685 **************************************************************************/
1686 IPTR List__MUIM_Show(struct IClass *cl, Object *obj,
1687 struct MUIP_Show *msg)
1689 struct MUI_ListData *data = INST_DATA(cl, obj);
1690 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1692 zune_imspec_show(data->list_cursor, obj);
1693 zune_imspec_show(data->list_select, obj);
1694 zune_imspec_show(data->list_selcur, obj);
1695 return rc;
1699 /**************************************************************************
1700 MUIM_Hide
1701 **************************************************************************/
1702 IPTR List__MUIM_Hide(struct IClass *cl, Object *obj,
1703 struct MUIP_Hide *msg)
1705 struct MUI_ListData *data = INST_DATA(cl, obj);
1707 zune_imspec_hide(data->list_cursor);
1708 zune_imspec_hide(data->list_select);
1709 zune_imspec_hide(data->list_selcur);
1711 return DoSuperMethodA(cl, obj, (Msg) msg);
1715 /**************************************************************************
1716 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1717 ENTRY_TITLE
1718 **************************************************************************/
1719 static VOID List_DrawEntry(struct IClass *cl, Object *obj, int entry_pos,
1720 int y)
1722 struct MUI_ListData *data = INST_DATA(cl, obj);
1723 int col, x1, x2;
1725 /* To be sure we don't draw anything if there is no title */
1726 if (entry_pos == ENTRY_TITLE && !data->title)
1727 return;
1729 DisplayEntry(cl, obj, entry_pos);
1730 x1 = _mleft(data->area);
1732 for (col = 0; col < data->columns; col++)
1734 ZText *text;
1735 x2 = x1 + data->ci[col].entries_width;
1737 if ((text =
1738 zune_text_new(data->preparses[col], data->strings[col],
1739 ZTEXT_ARG_NONE, 0)))
1741 /* Could be made simpler, as we don't really need the bounds */
1742 zune_text_get_bounds(text, obj);
1743 /* Note, this was MPEN_SHADOW before */
1744 SetAPen(_rp(obj), muiRenderInfo(obj)->mri_Pens[MPEN_TEXT]);
1745 zune_text_draw(text, obj, x1, x2, y); /* totally wrong! */
1746 zune_text_destroy(text);
1748 x1 = x2 + data->ci[col].delta + (data->ci[col].bar ? BAR_WIDTH : 0);
1752 /**************************************************************************
1753 MUIM_Draw
1754 **************************************************************************/
1755 IPTR List__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1757 struct MUI_ListData *data = INST_DATA(cl, obj);
1758 int entry_pos, y;
1759 APTR clip;
1760 int start, end;
1761 BOOL scroll_caused_damage = FALSE;
1762 struct MUI_ImageSpec_intern *highlight;
1763 IPTR ret = (IPTR)0;
1765 if (data->flags & LIST_QUIET)
1766 return 0;
1768 ret = DoSuperMethodA(cl, obj, (Msg) msg);
1770 if (data->area_replaced)
1771 return ret;
1773 /* Calculate the title height */
1774 if (data->title)
1776 data->title_height = data->entries[ENTRY_TITLE]->height + 2;
1778 else
1780 data->title_height = 0;
1783 /* Calc the numbers of entries visible */
1784 CalcVertVisible(cl, obj);
1786 if ((msg->flags & MADF_DRAWUPDATE) == 0 || data->update == 1)
1788 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
1789 _mtop(data->area), _mwidth(data->area), _mheight(data->area),
1790 0, data->entries_first * data->entry_maxheight, 0);
1793 clip = MUI_AddClipping(muiRenderInfo(obj), _mleft(data->area),
1794 _mtop(data->area), _mwidth(data->area), _mheight(data->area));
1796 if ((msg->flags & MADF_DRAWUPDATE) == 0 || data->update == 1)
1798 y = _mtop(data->area);
1799 /* Draw Title
1801 if (data->title_height && data->title)
1803 List_DrawEntry(cl, obj, ENTRY_TITLE, y);
1804 y += data->entries[ENTRY_TITLE]->height;
1805 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1806 Move(_rp(obj), _mleft(data->area), y);
1807 Draw(_rp(obj), _mright(data->area), y);
1808 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1809 y++;
1810 Move(_rp(obj), _mleft(data->area), y);
1811 Draw(_rp(obj), _mright(data->area), y);
1815 y = data->entries_top_pixel;
1817 start = data->entries_first;
1818 end = data->entries_first + data->entries_visible;
1820 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3)
1822 int diffy = data->entries_first - data->update_pos;
1823 int top, bottom;
1824 if (abs(diffy) < data->entries_visible)
1826 scroll_caused_damage =
1827 (_rp(obj)->Layer->Flags & LAYERREFRESH) ? FALSE : TRUE;
1829 ScrollRaster(_rp(obj), 0, diffy * data->entry_maxheight,
1830 _mleft(data->area), y,
1831 _mright(data->area),
1832 y + data->entry_maxheight * data->entries_visible);
1834 scroll_caused_damage =
1835 scroll_caused_damage
1836 && (_rp(obj)->Layer->Flags & LAYERREFRESH);
1838 if (diffy > 0)
1840 start = end - diffy;
1841 y += data->entry_maxheight * (data->entries_visible -
1842 diffy);
1844 else
1845 end = start - diffy;
1848 top = y;
1849 bottom = y + (end - start) * data->entry_maxheight;
1851 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area), top,
1852 _mwidth(data->area), bottom - top + 1, 0,
1853 top - _mtop(data->area) + data->entries_first
1854 * data->entry_maxheight, 0);
1857 for (entry_pos = start;
1858 entry_pos < end && entry_pos < data->entries_num; entry_pos++)
1860 struct ListEntry *entry = data->entries[entry_pos];
1862 if (!(msg->flags & MADF_DRAWUPDATE) ||
1863 ((msg->flags & MADF_DRAWUPDATE) && data->update == 1) ||
1864 ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) ||
1865 ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1866 && data->update_pos == entry_pos))
1868 /* Choose appropriate highlight image */
1870 if (entry_pos == data->entries_active
1871 && (entry->flags & ENTRY_SELECTED) && !data->read_only)
1872 highlight = data->list_selcur;
1873 else if (entry_pos == data->entries_active && !data->read_only)
1874 highlight = data->list_cursor;
1875 else if (entry->flags & ENTRY_SELECTED)
1876 highlight = data->list_select;
1877 else
1878 highlight = NULL;
1880 /* Draw highlight or background */
1882 if (highlight != NULL)
1884 zune_imspec_draw(highlight, muiRenderInfo(obj),
1885 _mleft(data->area), y, _mwidth(data->area),
1886 data->entry_maxheight,
1887 0, y - data->entries_top_pixel, 0);
1889 else if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1890 && data->update_pos == entry_pos)
1892 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area), y,
1893 _mwidth(data->area), data->entry_maxheight, 0,
1894 y - _mtop(data->area) +
1895 data->entries_first * data->entry_maxheight, 0);
1898 List_DrawEntry(cl, obj, entry_pos, y);
1900 y += data->entry_maxheight;
1903 MUI_RemoveClipping(muiRenderInfo(obj), clip);
1905 data->update = 0;
1907 if (scroll_caused_damage)
1909 if (MUI_BeginRefresh(muiRenderInfo(obj), 0))
1911 /* Theoretically it might happen that more damage is caused
1912 after ScrollRaster. By something else, like window movement
1913 in front of our window. Therefore refresh root object of
1914 window, not just this object */
1916 Object *o = NULL;
1918 get(_win(obj), MUIA_Window_RootObject, &o);
1919 MUI_Redraw(o, MADF_DRAWOBJECT);
1921 MUI_EndRefresh(muiRenderInfo(obj), 0);
1925 ULONG x1 = _mleft(data->area);
1926 ULONG col;
1927 y = _mtop(data->area);
1929 if (data->title_height && data->title)
1931 for (col = 0; col < data->columns; col++)
1933 ULONG halfdelta = data->ci[col].delta / 2;
1934 x1 += data->ci[col].entries_width + halfdelta;
1936 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(data->area))
1937 break;
1939 if (data->ci[col].bar)
1941 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1942 Move(_rp(obj), x1, y);
1943 Draw(_rp(obj), x1,
1944 y + data->entries[ENTRY_TITLE]->height - 1);
1945 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1946 Move(_rp(obj), x1 + 1, y);
1947 Draw(_rp(obj), x1 + 1,
1948 y + data->entries[ENTRY_TITLE]->height - 1);
1950 x1 += BAR_WIDTH;
1952 x1 += data->ci[col].delta - halfdelta;
1954 y += data->entries[ENTRY_TITLE]->height + 1;
1957 x1 = _mleft(data->area);
1959 for (col = 0; col < data->columns; col++)
1961 ULONG halfdelta = data->ci[col].delta / 2;
1962 x1 += data->ci[col].entries_width + halfdelta;
1964 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(data->area))
1965 break;
1967 if (data->ci[col].bar)
1969 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1970 Move(_rp(obj), x1, y);
1971 Draw(_rp(obj), x1, _mbottom(data->area));
1972 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1973 Move(_rp(obj), x1 + 1, y);
1974 Draw(_rp(obj), x1 + 1, _mbottom(data->area));
1976 x1 += BAR_WIDTH;
1979 x1 += data->ci[col].delta - halfdelta;
1982 return 0;
1985 /****** List.mui/MUIM_List_Clear *********************************************
1987 * NAME
1988 * MUIM_List_Clear (V4)
1990 * SYNOPSIS
1991 * DoMethod(obj, MUIM_List_Clear);
1993 * FUNCTION
1994 * Removes all entries from the list.
1996 ******************************************************************************
2000 IPTR List__MUIM_Clear(struct IClass *cl, Object *obj,
2001 struct MUIP_List_Clear *msg)
2003 struct MUI_ListData *data = INST_DATA(cl, obj);
2005 while (data->confirm_entries_num)
2007 struct ListEntry *lentry =
2008 data->entries[--data->confirm_entries_num];
2009 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
2010 (IPTR) data->pool);
2011 FreeListEntry(data, lentry);
2013 /* Should never fail when shrinking */
2014 SetListSize(data, 0);
2016 if (data->confirm_entries_num != data->entries_num)
2018 SetAttrs(obj, MUIA_List_Entries, 0, MUIA_List_First, 0,
2019 /* Notify only when no entry was active */
2020 data->entries_active !=
2021 MUIV_List_Active_Off ? MUIA_List_Active : TAG_DONE,
2022 MUIV_List_Active_Off, TAG_DONE);
2024 data->update = 1;
2025 MUI_Redraw(obj, MADF_DRAWUPDATE);
2028 return 0;
2031 /****** List.mui/MUIM_List_Exchange ******************************************
2033 * NAME
2034 * MUIM_List_Exchange (V4)
2036 * SYNOPSIS
2037 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2039 * FUNCTION
2040 * Exchange two entries' positions.
2042 * INPUTS
2043 * pos1 - the current index of the first entry that should be moved, or
2044 * one of these special values:
2045 * MUIV_List_Exchange_Active: the active entry.
2046 * MUIV_List_Exchange_Top: the first entry.
2047 * MUIV_List_Exchange_Bottom: the last entry.
2048 * pos2 - the index of the entry that the first entry should be exchanged
2049 * with, or one of these special values:
2050 * MUIV_List_Exchange_Active: the active entry.
2051 * MUIV_List_Exchange_Top: the first entry.
2052 * MUIV_List_Exchange_Bottom: the last entry.
2053 * MUIV_List_Exchange_Next: the next entry after pos1.
2054 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2056 * NOTES
2057 * This method will do nothing if either index is greater than the last
2058 * index in the list, or if MUIV_List_Exchange_Next or
2059 * MUIV_List_Exchange_Previous imply an index outside the list.
2061 * SEE ALSO
2062 * MUIM_List_Move
2064 ******************************************************************************
2068 IPTR List__MUIM_Exchange(struct IClass *cl, Object *obj,
2069 struct MUIP_List_Exchange *msg)
2071 struct MUI_ListData *data = INST_DATA(cl, obj);
2072 LONG pos1, pos2;
2074 switch (msg->pos1)
2076 case MUIV_List_Exchange_Top:
2077 pos1 = 0;
2078 break;
2079 case MUIV_List_Exchange_Active:
2080 pos1 = data->entries_active;
2081 break;
2082 case MUIV_List_Exchange_Bottom:
2083 pos1 = data->entries_num - 1;
2084 break;
2085 default:
2086 pos1 = msg->pos1;
2089 switch (msg->pos2)
2091 case MUIV_List_Exchange_Top:
2092 pos2 = 0;
2093 break;
2094 case MUIV_List_Exchange_Active:
2095 pos2 = data->entries_active;
2096 break;
2097 case MUIV_List_Exchange_Bottom:
2098 pos2 = data->entries_num - 1;
2099 break;
2100 case MUIV_List_Exchange_Next:
2101 pos2 = pos1 + 1;
2102 break;
2103 case MUIV_List_Exchange_Previous:
2104 pos2 = pos1 - 1;
2105 break;
2106 default:
2107 pos2 = msg->pos2;
2110 if (pos1 >= 0 && pos1 < data->entries_num && pos2 >= 0
2111 && pos2 < data->entries_num && pos1 != pos2)
2113 struct ListEntry *save = data->entries[pos1];
2114 data->entries[pos1] = data->entries[pos2];
2115 data->entries[pos2] = save;
2117 data->update = 2;
2118 data->update_pos = pos1;
2119 MUI_Redraw(obj, MADF_DRAWUPDATE);
2121 data->update = 2;
2122 data->update_pos = pos2;
2123 MUI_Redraw(obj, MADF_DRAWUPDATE);
2125 return TRUE;
2127 else
2129 return FALSE;
2133 /**************************************************************************
2134 MUIM_List_Redraw
2135 **************************************************************************/
2136 IPTR List__MUIM_Redraw(struct IClass *cl, Object *obj,
2137 struct MUIP_List_Redraw *msg)
2139 struct MUI_ListData *data = INST_DATA(cl, obj);
2141 if (!(data->flags & LIST_QUIET))
2143 if (msg->pos == MUIV_List_Redraw_All)
2145 data->update = 1;
2146 CalcWidths(cl, obj);
2147 MUI_Redraw(obj, MADF_DRAWUPDATE);
2149 else
2151 LONG pos = -1;
2152 if (msg->pos == MUIV_List_Redraw_Active)
2153 pos = data->entries_active;
2154 else if (msg->pos == MUIV_List_Redraw_Entry)
2156 LONG i;
2157 for (i = 0; i < data->entries_num; i++)
2158 if (data->entries[i]->data == msg->entry)
2160 pos = i;
2161 break;
2164 else
2165 pos = msg->pos;
2167 if (pos != -1)
2169 if (CalcDimsOfEntry(cl, obj, pos))
2170 data->update = 1;
2171 else
2173 data->update = 2;
2174 data->update_pos = pos;
2176 MUI_Redraw(obj, MADF_DRAWUPDATE);
2180 return 0;
2183 /****** List.mui/MUIM_List_Remove ********************************************
2185 * NAME
2186 * MUIM_List_Remove (V4)
2188 * SYNOPSIS
2189 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2191 * FUNCTION
2192 * Removes entries from the list. If a destruct hook has been
2193 * installed, it will be called for the removed entry.
2195 * INPUTS
2196 * pos - the index of the entry to be removed. The following
2197 * special values can also be used:
2198 * MUIV_List_Remove_First: remove the first entry.
2199 * MUIV_List_Remove_Last: remove the last entry.
2200 * MUIV_List_Remove_Active: remove the active entry.
2201 * MUIV_List_Remove_Selected: remove all selected entries
2202 * (or the active entry if there are no selected entries).
2204 * NOTES
2205 * When the active entry is removed, the next entry becomes active
2206 * (if there is no entry below the active entry, the previous entry
2207 * becomes active instead).
2209 * SEE ALSO
2210 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2212 ******************************************************************************
2214 * It was not possible to use MUIM_List_NextSelected here because that method
2215 * may skip entries if entries are removed during an iteration.
2219 IPTR List__MUIM_Remove(struct IClass *cl, Object *obj,
2220 struct MUIP_List_Remove *msg)
2222 struct MUI_ListData *data = INST_DATA(cl, obj);
2223 LONG pos;
2224 LONG new_act;
2225 UWORD i;
2226 BOOL found, done = FALSE;
2227 struct ListEntry *lentry;
2228 Tag active_tag = TAG_DONE;
2230 if (!data->entries_num)
2231 return 0;
2233 switch (msg->pos)
2235 case MUIV_List_Remove_First:
2236 pos = 0;
2237 break;
2239 case MUIV_List_Remove_Active:
2240 pos = data->entries_active;
2241 break;
2243 case MUIV_List_Remove_Last:
2244 pos = data->entries_num - 1;
2245 break;
2247 case MUIV_List_Remove_Selected:
2248 pos = 0;
2249 break;
2251 default:
2252 pos = msg->pos;
2253 break;
2256 if (pos < 0 || pos >= data->entries_num)
2257 return 0;
2259 new_act = data->entries_active;
2261 while (!done)
2263 if (msg->pos == MUIV_List_Remove_Selected)
2265 /* Find the next selected entry */
2266 for (found = FALSE, i = pos;
2267 i < data->confirm_entries_num && !found; i++)
2269 if (data->entries[i]->flags & ENTRY_SELECTED)
2271 pos = i;
2272 found = TRUE;
2276 if (!found)
2278 done = TRUE;
2280 /* If there were no selected entries, remove the active one */
2281 if (data->confirm_entries_num == data->entries_num
2282 && data->entries_active != MUIV_List_Active_Off)
2284 pos = data->entries_active;
2285 found = TRUE;
2289 else
2291 done = TRUE;
2292 found = TRUE;
2295 if (found)
2297 lentry = data->entries[pos];
2298 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
2299 (IPTR) data->pool);
2300 RemoveListEntries(data, pos, 1);
2301 data->confirm_entries_num--;
2303 if (pos < new_act)
2305 new_act--;
2306 active_tag = MUIA_List_Active;
2308 else if (pos == new_act)
2309 active_tag = MUIA_List_Active;
2313 /* ensure that the active element is in a valid range (it might become
2314 * MUIV_List_Active_Off (-1), but that's OK) */
2315 if (new_act >= data->entries_num)
2316 new_act = data->entries_num - 1;
2318 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num,
2319 active_tag, new_act, /* Inform only if necessary (for notify) */
2320 TAG_DONE);
2322 data->update = 1;
2323 MUI_Redraw(obj, MADF_DRAWUPDATE);
2325 return 0;
2328 /**************************************************************************
2329 MUIM_List_Select
2330 **************************************************************************/
2331 IPTR List__MUIM_Select(struct IClass *cl, Object *obj,
2332 struct MUIP_List_Select *msg)
2334 struct MUI_ListData *data = INST_DATA(cl, obj);
2335 LONG pos, i, count, selcount=0, state=0;
2336 BOOL multi_allowed = TRUE, new_select_state = FALSE;
2338 /* Establish the range of entries affected */
2339 switch (msg->pos)
2341 case MUIV_List_Select_Active:
2342 pos = data->entries_active;
2343 if (pos == MUIV_List_Active_Off)
2344 count = 0;
2345 else
2346 count = 1;
2347 break;
2349 case MUIV_List_Select_All:
2350 pos = 0;
2351 count = data->entries_num;
2352 break;
2354 default:
2355 pos = msg->pos;
2356 count = 1;
2357 if (pos < 0 || pos >= data->entries_num)
2358 return 0;
2359 break;
2362 if (msg->seltype != MUIV_List_Select_Ask && data->multi_test_hook != NULL)
2364 /* Disallow selection of an additional entry if there is a currently
2365 selected entry that is not multi-selectable (in such case there
2366 will only be one entry currently selected, so no need to iterate) */
2367 i = MUIV_List_NextSelected_Start;
2368 DoMethod(obj, MUIM_List_NextSelected, (IPTR) &i);
2369 if (i != MUIV_List_NextSelected_End)
2370 selcount++;
2371 if (data->multi_test_hook != NULL && selcount != 0)
2372 multi_allowed = CallHookPkt(data->multi_test_hook, NULL,
2373 data->entries[i]->data);
2376 /* Change or check state of each entry in the range */
2377 for (i = pos; i < pos + count; i++)
2379 state = data->entries[i]->flags & ENTRY_SELECTED;
2380 switch (msg->seltype)
2382 case MUIV_List_Select_Off:
2383 new_select_state = FALSE;
2384 break;
2386 case MUIV_List_Select_On:
2387 new_select_state = TRUE;
2388 break;
2390 case MUIV_List_Select_Toggle:
2391 new_select_state = !state;
2392 break;
2394 default:
2395 if (data->entries[i]->flags & ENTRY_SELECTED)
2396 selcount++;
2397 break;
2400 if (msg->seltype != MUIV_List_Select_Ask)
2402 /* Disallow selection if entry is not multi-selectable and
2403 * there are already selected entries */
2404 if (data->multi_test_hook != NULL && new_select_state)
2405 new_select_state = multi_allowed && (selcount == 0 ||
2406 CallHookPkt(data->multi_test_hook, NULL,
2407 data->entries[i]->data));
2409 if (new_select_state)
2410 data->entries[i]->flags |= ENTRY_SELECTED;
2411 else
2412 data->entries[i]->flags &= ~ENTRY_SELECTED;
2416 /* Report old state or number of selected entries */
2417 if (msg->info)
2419 if (msg->pos == MUIV_List_Select_All
2420 && msg->seltype == MUIV_List_Select_Ask)
2421 *msg->info = selcount;
2422 else
2423 *msg->info = state;
2426 /* Redraw unless it was just an enquiry */
2427 if (msg->seltype != MUIV_List_Select_Ask)
2429 if (count > 1)
2430 data->update = 1;
2431 else
2433 data->update = 2;
2434 data->update_pos = pos;
2436 MUI_Redraw(obj, MADF_DRAWUPDATE);
2439 return 0;
2442 /****** List.mui/MUIM_List_Insert ********************************************
2444 * NAME
2445 * MUIM_List_Insert (V4)
2447 * SYNOPSIS
2448 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2450 * FUNCTION
2451 * Adds multiple entries to the list. If a construct hook has been
2452 * installed, the results of passing the entries to this hook will be
2453 * inserted.
2455 * INPUTS
2456 * entries - an array of entries to be inserted.
2457 * count - the number of entries to insert. A special value of -1 may be
2458 * used, indicating that the array of entries is NULL-terminated.
2459 * pos - the index at which to insert the new entries. The following
2460 * special values can also be used:
2461 * MUIV_List_Insert_Top: insert at index 0.
2462 * MUIV_List_Insert_Bottom: insert after all existing entries.
2463 * MUIV_List_Insert_Active: insert at the index of the active entry
2464 * (or at index 0 if there is no active entry).
2465 * MUIV_List_Insert_Sorted: keep the list sorted.
2467 * SEE ALSO
2468 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2470 ******************************************************************************
2474 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
2475 struct MUIP_List_Insert *msg)
2477 struct MUI_ListData *data = INST_DATA(cl, obj);
2478 LONG pos, count, sort, active;
2480 count = msg->count;
2481 sort = 0;
2483 if (count == -1)
2485 /* Count the number of entries */
2486 for (count = 0; msg->entries[count] != NULL; count++)
2490 if (count <= 0)
2491 return ~0;
2493 switch (msg->pos)
2495 case MUIV_List_Insert_Top:
2496 pos = 0;
2497 break;
2499 case MUIV_List_Insert_Active:
2500 if (data->entries_active != -1)
2501 pos = data->entries_active;
2502 else
2503 pos = 0;
2504 break;
2506 case MUIV_List_Insert_Sorted:
2507 pos = data->entries_num;
2508 sort = 1; /* we sort'em later */
2509 break;
2511 case MUIV_List_Insert_Bottom:
2512 pos = data->entries_num;
2513 break;
2515 default:
2516 if (msg->pos > data->entries_num)
2517 pos = data->entries_num;
2518 else if (msg->pos < 0)
2519 pos = 0;
2520 else
2521 pos = msg->pos;
2522 break;
2524 data->insert_position = pos;
2526 if (!(SetListSize(data, data->entries_num + count)))
2527 return ~0;
2529 LONG until = pos + count;
2530 APTR *toinsert = msg->entries;
2532 if (!(PrepareInsertListEntries(data, pos, count)))
2533 return ~0;
2535 while (pos < until)
2537 struct ListEntry *lentry;
2539 if (!(lentry = AllocListEntry(data)))
2541 /* Panic, but we must be in a consistent state, so remove
2542 * the space where the following list entries should have gone
2544 RemoveListEntries(data, pos, until - pos);
2545 return ~0;
2548 /* now call the construct method which returns us a pointer which
2549 we need to store */
2550 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2551 (IPTR) * toinsert, (IPTR) data->pool);
2552 if (!lentry->data)
2554 FreeListEntry(data, lentry);
2555 RemoveListEntries(data, pos, until - pos);
2557 /* TODO: Also check for visible stuff like below */
2558 if (data->entries_num != data->confirm_entries_num)
2559 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2560 return ~0;
2563 data->entries[pos] = lentry;
2564 data->confirm_entries_num++;
2566 if (_flags(obj) & MADF_SETUP)
2568 /* We have to calculate the width and height of the newly
2569 * inserted entry. This has to be done after inserting the
2570 * element into the list */
2571 CalcDimsOfEntry(cl, obj, pos);
2574 toinsert++;
2575 pos++;
2577 pos--;
2579 /* Recalculate the number of visible entries */
2580 if (_flags(obj) & MADF_SETUP)
2581 CalcVertVisible(cl, obj);
2583 if (data->entries_num != data->confirm_entries_num)
2585 SetAttrs(obj,
2586 MUIA_List_Entries, data->confirm_entries_num,
2587 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2590 /* If the array is already sorted, we could do a simple insert
2591 * sort and would be much faster than with qsort.
2592 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2593 * sort the whole array?
2595 * I think, we better sort the whole array:
2597 if (sort)
2599 DoMethod(obj, MUIM_List_Sort);
2600 /* TODO: which pos to return here !? */
2601 /* MUIM_List_Sort already called MUI_Redraw */
2603 else
2605 data->update = 1;
2606 MUI_Redraw(obj, MADF_DRAWUPDATE);
2608 superset(cl, obj, MUIA_List_InsertPosition, data->insert_position);
2610 /* Update index of active entry */
2611 if (data->entries_active >= data->insert_position)
2613 active = data->entries_active + count;
2614 SET(obj, MUIA_List_Active, active);
2617 return (ULONG) pos;
2620 /****** List.mui/MUIM_List_InsertSingle **************************************
2622 * NAME
2623 * MUIM_List_InsertSingle (V7)
2625 * SYNOPSIS
2626 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2628 * FUNCTION
2629 * Adds a single entry to the list. If a construct hook has been
2630 * installed, the result of passing the entry to this hook will be
2631 * inserted.
2633 * INPUTS
2634 * entry - the entry to be inserted.
2635 * pos - the index at which to insert the new entry. The following
2636 * special values can also be used:
2637 * MUIV_List_Insert_Top: insert at index 0.
2638 * MUIV_List_Insert_Bottom: insert after all existing entries.
2639 * MUIV_List_Insert_Active: insert at the index of the active entry
2640 * (or at index 0 if there is no active entry).
2641 * MUIV_List_Insert_Sorted: keep the list sorted.
2643 * SEE ALSO
2644 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2646 ******************************************************************************
2650 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2651 struct MUIP_List_InsertSingle *msg)
2653 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2654 msg->pos);
2657 /**************************************************************************
2658 MUIM_List_GetEntry
2659 **************************************************************************/
2660 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2661 struct MUIP_List_GetEntry *msg)
2663 struct MUI_ListData *data = INST_DATA(cl, obj);
2664 int pos = msg->pos;
2666 if (pos == MUIV_List_GetEntry_Active)
2667 pos = data->entries_active;
2669 if (pos < 0 || pos >= data->entries_num)
2671 *msg->entry = NULL;
2672 return 0;
2674 *msg->entry = data->entries[pos]->data;
2675 return (IPTR) *msg->entry;
2678 /**************************************************************************
2679 MUIM_List_Construct
2680 **************************************************************************/
2681 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2682 struct MUIP_List_Construct *msg)
2684 struct MUI_ListData *data = INST_DATA(cl, obj);
2686 if (NULL == data->construct_hook)
2687 return (IPTR) msg->entry;
2688 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2690 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2691 ULONG *mem = AllocPooled(msg->pool, len + 5);
2693 if (NULL == mem)
2694 return 0;
2695 mem[0] = len + 5;
2696 if (msg->entry != NULL)
2697 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2698 else
2699 *(STRPTR) (mem + 1) = 0;
2700 return (IPTR) (mem + 1);
2702 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2705 /**************************************************************************
2706 MUIM_List_Destruct
2707 **************************************************************************/
2708 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2709 struct MUIP_List_Destruct *msg)
2711 struct MUI_ListData *data = INST_DATA(cl, obj);
2713 if (NULL == data->destruct_hook)
2714 return 0;
2716 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2718 ULONG *mem = ((ULONG *) msg->entry) - 1;
2719 FreePooled(msg->pool, mem, mem[0]);
2721 else
2723 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2725 return 0;
2728 /****** List.mui/MUIM_List_Compare *******************************************
2730 * NAME
2731 * MUIM_List_Compare (V20)
2733 * SYNOPSIS
2734 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2735 * LONG sort_type1, LONG sort_type2);
2737 * FUNCTION
2738 * Compare two list entries according to the current comparison hook
2739 * (MUIA_List_CompareHook).
2741 * INPUTS
2742 * entry1 - the first entry data.
2743 * entry2 - the second entry data.
2744 * sort_type1 - undocumented.
2745 * sort_type2 - undocumented.
2747 * SEE ALSO
2748 * MUIA_List_CompareHook, MUIM_List_Sort.
2750 ******************************************************************************
2754 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2755 struct MUIP_List_Compare *msg)
2757 struct MUI_ListData *data = INST_DATA(cl, obj);
2759 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2762 /**************************************************************************
2763 MUIM_List_Display
2764 **************************************************************************/
2765 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2766 struct MUIP_List_Display *msg)
2768 struct MUI_ListData *data = INST_DATA(cl, obj);
2770 if (NULL == data->display_hook)
2772 if (msg->entry)
2773 *msg->array = msg->entry;
2774 else
2775 *msg->array = 0;
2776 return 1;
2779 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2780 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2783 /**************************************************************************
2784 MUIM_List_SelectChange
2785 **************************************************************************/
2786 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2787 struct MUIP_List_SelectChange *msg)
2789 return 1;
2792 /**************************************************************************
2793 MUIM_List_CreateImage
2794 Called by a List subclass in its Setup method.
2795 Connects an Area subclass object to the list, much like an object gets
2796 connected to a window. List calls Setup and AskMinMax on that object,
2797 keeps a reference to it (that reference will be returned).
2798 Text engine will dereference that pointer and draw the object with its
2799 default size.
2800 **************************************************************************/
2801 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2802 struct MUIP_List_CreateImage *msg)
2804 struct MUI_ListData *data = INST_DATA(cl, obj);
2805 struct ListImage *li;
2807 if (!msg->obj)
2808 return 0;
2810 /* List must be already setup in Setup of your subclass */
2811 if (!(_flags(obj) & MADF_SETUP))
2812 return 0;
2813 li = AllocPooled(data->pool, sizeof(struct ListImage));
2814 if (!li)
2815 return 0;
2816 li->obj = msg->obj;
2818 AddTail((struct List *)&data->images, (struct Node *)li);
2819 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2820 DoSetupMethod(li->obj, muiRenderInfo(obj));
2823 return (IPTR) li;
2826 /**************************************************************************
2827 MUIM_List_DeleteImage
2828 **************************************************************************/
2829 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2830 struct MUIP_List_DeleteImage *msg)
2832 struct MUI_ListData *data = INST_DATA(cl, obj);
2833 struct ListImage *li = (struct ListImage *)msg->listimg;
2835 if (li)
2837 DoMethod(li->obj, MUIM_Cleanup);
2838 DoMethod(li->obj, MUIM_DisconnectParent);
2839 Remove((struct Node *)li);
2840 FreePooled(data->pool, li, sizeof(struct ListImage));
2843 return 0;
2846 /****** List.mui/MUIM_List_Jump **********************************************
2848 * NAME
2849 * MUIM_List_Jump (V4)
2851 * SYNOPSIS
2852 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2854 * FUNCTION
2855 * Scrolls the list so that a particular entry is visible.
2857 * INPUTS
2858 * pos - index of entry that should become visible, or one of these
2859 * special values:
2860 * MUIV_List_Jump_Active: show the active entry.
2861 * MUIV_List_Jump_Top: show the first entry.
2862 * MUIV_List_Jump_Bottom: show the last entry.
2863 * MUIV_List_Jump_Up: show the previous hidden entry.
2864 * MUIV_List_Jump_Down: show the next hidden entry.
2866 ******************************************************************************
2870 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2871 struct MUIP_List_Jump *msg)
2873 struct MUI_ListData *data = INST_DATA(cl, obj);
2874 LONG pos = msg->pos;
2876 switch (pos)
2878 case MUIV_List_Jump_Top:
2879 pos = 0;
2880 break;
2882 case MUIV_List_Jump_Active:
2883 pos = data->entries_active;
2884 break;
2886 case MUIV_List_Jump_Bottom:
2887 pos = data->entries_num - 1;
2888 break;
2890 case MUIV_List_Jump_Down:
2891 pos = data->entries_first + data->entries_visible;
2892 break;
2894 case MUIV_List_Jump_Up:
2895 pos = data->entries_first - 1;
2896 break;
2899 if (pos >= data->entries_num)
2901 pos = data->entries_num - 1;
2903 if (pos < 0)
2904 pos = 0;
2906 if (pos < data->entries_first)
2908 set(obj, MUIA_List_First, pos);
2910 else if (pos >= data->entries_first + data->entries_visible)
2912 pos -= (data->entries_visible - 1);
2913 if (pos < 0)
2914 pos = 0;
2915 if (pos != data->entries_first)
2917 set(obj, MUIA_List_First, pos);
2921 return TRUE;
2924 /****** List.mui/MUIM_List_Sort **********************************************
2926 * NAME
2927 * MUIM_List_Sort (V4)
2929 * SYNOPSIS
2930 * DoMethod(obj, MUIM_List_Sort);
2932 * FUNCTION
2933 * Sort the list's entries according to the current comparison hook
2934 * (MUIA_List_CompareHook).
2936 * NOTES
2937 * The active index does not change, so the active entry may do so.
2939 * SEE ALSO
2940 * MUIA_List_CompareHook, MUIM_List_Compare.
2942 ******************************************************************************
2946 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2947 struct MUIP_List_Sort *msg)
2949 struct MUI_ListData *data = INST_DATA(cl, obj);
2951 int i, j, max;
2952 struct MUIP_List_Compare cmpmsg =
2953 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2955 if (data->entries_num > 1)
2958 Simple sort algorithm. Feel free to improve it.
2960 for (i = 0; i < data->entries_num - 1; i++)
2962 max = i;
2963 for (j = i + 1; j < data->entries_num; j++)
2965 cmpmsg.entry1 = data->entries[max]->data;
2966 cmpmsg.entry2 = data->entries[j]->data;
2967 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2969 max = j;
2972 if (i != max)
2974 APTR tmp = data->entries[i];
2975 data->entries[i] = data->entries[max];
2976 data->entries[max] = tmp;
2981 data->update = 1;
2982 MUI_Redraw(obj, MADF_DRAWUPDATE);
2984 return 0;
2987 /****** List.mui/MUIM_List_Move **********************************************
2989 * NAME
2990 * MUIM_List_Move (V9)
2992 * SYNOPSIS
2993 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2995 * FUNCTION
2996 * Move a list entry to a new position.
2998 * INPUTS
2999 * from - the current index of the entry that should be moved, or one of
3000 * these special values:
3001 * MUIV_List_Move_Active: the active entry.
3002 * MUIV_List_Move_Top: the first entry.
3003 * MUIV_List_Move_Bottom: the last entry.
3004 * to - the index of the entry's new position, or one of
3005 * these special values:
3006 * MUIV_List_Move_Active: the active entry.
3007 * MUIV_List_Move_Top: the first entry.
3008 * MUIV_List_Move_Bottom: the last entry.
3010 * NOTES
3011 * The active index does not change, so the active entry may do so.
3013 * SEE ALSO
3014 * MUIM_List_Exchange
3016 ******************************************************************************
3020 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
3021 struct MUIP_List_Move *msg)
3023 struct MUI_ListData *data = INST_DATA(cl, obj);
3025 LONG from, to;
3026 int i;
3028 /* Normalise special 'from' values */
3029 switch (msg->from)
3031 case MUIV_List_Move_Top:
3032 from = 0;
3033 break;
3034 case MUIV_List_Move_Active:
3035 from = data->entries_active;
3036 break;
3037 case MUIV_List_Move_Bottom:
3038 from = data->entries_num - 1;
3039 break;
3040 default:
3041 from = msg->from;
3044 /* Normalise special 'to' values */
3045 switch (msg->to)
3047 case MUIV_List_Move_Top:
3048 to = 0;
3049 break;
3050 case MUIV_List_Move_Active:
3051 to = data->entries_active;
3052 break;
3053 case MUIV_List_Move_Bottom:
3054 to = data->entries_num - 1;
3055 break;
3056 case MUIV_List_Move_Next:
3057 to = from + 1;
3058 break;
3059 case MUIV_List_Move_Previous:
3060 to = from - 1;
3061 break;
3062 default:
3063 to = msg->to;
3066 /* Check that values are within valid bounds */
3067 if (from > data->entries_num - 1 || from < 0
3068 || to > data->entries_num - 1 || to < 0 || from == to)
3069 return (IPTR) FALSE;
3071 /* Shift all entries in the range between the 'from' and 'to' positions */
3072 if (from < to)
3074 struct ListEntry *backup = data->entries[from];
3075 for (i = from; i < to; i++)
3076 data->entries[i] = data->entries[i + 1];
3077 data->entries[to] = backup;
3079 else
3081 struct ListEntry *backup = data->entries[from];
3082 for (i = from; i > to; i--)
3083 data->entries[i] = data->entries[i - 1];
3084 data->entries[to] = backup;
3087 #if 0 /* Not done in MUI 3 */
3088 /* Update index of active entry */
3089 if (from == data->entries_active)
3090 data->entries_active = to;
3091 else if (data->entries_active > from && data->entries_active < to)
3092 data->entries_active--;
3093 else if (data->entries_active < from && data->entries_active >= to)
3094 data->entries_active++;
3095 #endif
3097 /* Reflect list changes visually */
3098 data->update = 1;
3099 MUI_Redraw(obj, MADF_DRAWUPDATE);
3101 return TRUE;
3104 /****** List.mui/MUIM_List_NextSelected **************************************
3106 * NAME
3107 * MUIM_List_NextSelected (V6)
3109 * SYNOPSIS
3110 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3112 * FUNCTION
3113 * Allows iteration through a list's selected entries by providing the
3114 * index of the next selected entry after the specified index.
3116 * INPUTS
3117 * pos - the address of a variable containing the index of the previous
3118 * selected entry. The variable must be initialised to the special
3119 * value MUIV_List_NextSelected_Start to find the first selected
3120 * entry. When this method returns, the variable will contain the
3121 * index of the next selected entry, or MUIV_List_NextSelected_End if
3122 * there are no more.
3124 * NOTES
3125 * If there are no selected entries but there is an active entry, the
3126 * index of the active entry will be stored (when
3127 * MUIV_List_NextSelected_Start is specified).
3129 * Some selected entries may be skipped if any entries are removed
3130 * between calls to this method during an iteration of a list.
3132 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3133 * the same numeric value.
3135 * SEE ALSO
3136 * MUIM_List_Select, MUIM_List_Remove.
3138 ******************************************************************************
3142 IPTR List__MUIM_NextSelected(struct IClass *cl, Object *obj,
3143 struct MUIP_List_NextSelected *msg)
3145 struct MUI_ListData *data = INST_DATA(cl, obj);
3146 LONG pos, i;
3147 BOOL found = FALSE;
3149 /* Get the first entry to check */
3150 pos = *msg->pos;
3151 if (pos == MUIV_List_NextSelected_Start)
3152 pos = 0;
3153 else
3154 pos++;
3156 /* Find the next selected entry */
3157 for (i = pos; i < data->entries_num && !found; i++)
3159 if (data->entries[i]->flags & ENTRY_SELECTED)
3161 pos = i;
3162 found = TRUE;
3166 /* Return index of selected or active entry, or indicate there are no
3167 more */
3168 if (!found)
3170 if (*msg->pos == MUIV_List_NextSelected_Start
3171 && data->entries_active != MUIV_List_Active_Off)
3172 pos = data->entries_active;
3173 else
3174 pos = MUIV_List_NextSelected_End;
3176 *msg->pos = pos;
3178 return TRUE;
3181 /**************************************************************************
3182 MUIM_List_TestPos
3183 **************************************************************************/
3184 IPTR List__MUIM_TestPos(struct IClass *cl, Object *obj,
3185 struct MUIP_List_TestPos *msg)
3187 struct MUI_ListData *data = INST_DATA(cl, obj);
3188 struct MUI_List_TestPos_Result *result = msg->res;
3189 LONG col = -1, row = -1;
3190 UWORD flags = 0, i;
3191 LONG mx = msg->x - _left(data->area);
3192 LONG entries_visible;
3194 if (data->entries_visible <= data->entries_num)
3195 entries_visible = data->entries_visible;
3196 else
3197 entries_visible = data->entries_num;
3198 LONG ey = msg->y - data->entries_top_pixel;
3199 /* y coordinates transformed to the entries */
3201 /* Now check if it was clicked on a title or on entries */
3202 if (ey < 0)
3203 flags |= MUI_LPR_ABOVE;
3204 else if (ey >= entries_visible * data->entry_maxheight)
3205 flags |= MUI_LPR_BELOW;
3206 else
3208 /* Identify row */
3209 row = ey / data->entry_maxheight + data->entries_first;
3210 result->yoffset =
3211 ey % data->entry_maxheight - data->entry_maxheight / 2;
3214 if (mx < 0)
3215 flags |= MUI_LPR_LEFT;
3216 else if (mx >= _width(data->area))
3217 flags |= MUI_LPR_RIGHT;
3218 else
3220 /* Identify column */
3221 if (data->entries_num > 0 && data->columns > 0)
3223 LONG width_sum = 0;
3224 col = data->columns - 1;
3225 for (i = 0; i < data->columns; i++)
3227 result->xoffset = mx - width_sum;
3228 width_sum +=
3229 data->ci[i].entries_width +
3230 data->ci[i].delta +
3231 (data->ci[i].bar ? BAR_WIDTH : 0);
3232 D(bug("[List/MUIM_TestPos] i %d "
3233 "width %d width_sum %d mx %d\n",
3234 i, data->ci[i].entries_width, width_sum, mx));
3235 if (mx < width_sum)
3237 col = i;
3238 D(bug("[List/MUIM_TestPos] Column hit %d\n", col));
3239 break;
3245 result->entry = row;
3246 result->column = col;
3247 result->flags = flags;
3249 return TRUE;
3252 /****i* List.mui/MUIM_DragQuery **********************************************
3254 * NAME
3255 * MUIM_DragQuery
3257 ******************************************************************************
3261 IPTR List__MUIM_DragQuery(struct IClass *cl, Object *obj,
3262 struct MUIP_DragQuery *msg)
3264 if (msg->obj == obj)
3265 return MUIV_DragQuery_Accept;
3266 else
3267 return MUIV_DragQuery_Refuse;
3271 /****i* List.mui/MUIM_DragFinish *********************************************
3273 * NAME
3274 * MUIM_DragFinish
3276 ******************************************************************************
3280 IPTR List__MUIM_DragFinish(struct IClass *cl, Object *obj,
3281 struct MUIP_DragFinish *msg)
3283 struct MUI_ListData *data = INST_DATA(cl, obj);
3285 data->drop_mark_y = -1;
3287 return DoSuperMethodA(cl, obj, (Msg) msg);
3290 /****i* List.mui/MUIM_DragReport *********************************************
3292 * NAME
3293 * MUIM_DragReport
3295 ******************************************************************************
3299 IPTR List__MUIM_DragReport(struct IClass *cl, Object *obj,
3300 struct MUIP_DragReport *msg)
3302 struct MUI_ListData *data = INST_DATA(cl, obj);
3303 struct MUI_List_TestPos_Result pos;
3304 struct RastPort *rp = _rp(obj);
3305 LONG n, y;
3306 UWORD old_pattern;
3308 /* Choose new drop mark position */
3310 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3311 if (pos.entry != -1)
3313 n = pos.entry;
3314 if (pos.yoffset > 0)
3315 n++;
3317 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3318 n = data->entries_first;
3319 else
3321 n = MIN(data->entries_visible, data->entries_num)
3322 - data->entries_first;
3325 /* Clear old drop mark */
3327 if ((data->flags & LIST_SHOWDROPMARKS) != 0)
3329 y = data->entries_top_pixel + (n - data->entries_first)
3330 * data->entry_maxheight;
3331 if (y != data->drop_mark_y)
3333 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
3334 data->drop_mark_y, _mwidth(data->area), 1, 0, 0, 0);
3336 /* Draw new drop mark and store its position */
3338 SetABPenDrMd(rp, _pens(obj)[MPEN_SHINE], _pens(obj)[MPEN_SHADOW],
3339 JAM2);
3340 old_pattern = rp->LinePtrn;
3341 SetDrPt(rp, 0xF0F0);
3342 Move(rp, _mleft(data->area), y);
3343 Draw(rp, _mright(data->area), y);
3344 SetDrPt(rp, old_pattern);
3345 data->drop_mark_y = y;
3349 return TRUE;
3353 /****i* List.mui/MUIM_DragDrop ***********************************************
3355 * NAME
3356 * MUIM_DragDrop
3358 ******************************************************************************
3362 IPTR List__MUIM_DragDrop(struct IClass *cl, Object *obj,
3363 struct MUIP_DragDrop *msg)
3365 struct MUI_ListData *data = INST_DATA(cl, obj);
3366 struct MUI_List_TestPos_Result pos;
3367 LONG n;
3369 /* Find drop position */
3371 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3372 if (pos.entry != -1)
3374 /* Change drop position when coords move past centre of entry, not
3375 * entry boundary */
3377 n = pos.entry;
3378 if (pos.yoffset > 0)
3379 n++;
3381 /* Ensure that dropped entry will be positioned between the two
3382 * entries that are above and below the drop mark, rather than
3383 * strictly at the numeric index shown */
3385 if (n > data->entries_active)
3386 n--;
3388 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3389 n = MUIV_List_Move_Top;
3390 else
3391 n = MUIV_List_Move_Bottom;
3393 DoMethod(msg->obj, MUIM_List_Move, MUIV_List_Move_Active, n);
3395 return TRUE;
3399 /****i* List.mui/MUIM_CreateDragImage ****************************************
3401 * NAME
3402 * MUIM_CreateDragImage
3404 ******************************************************************************
3408 static IPTR List__MUIM_CreateDragImage(struct IClass *cl, Object *obj,
3409 struct MUIP_CreateDragImage *msg)
3411 struct MUI_ListData *data = INST_DATA(cl, obj);
3412 BOOL success = TRUE;
3413 struct MUI_List_TestPos_Result pos;
3414 WORD width, height, left, top;
3415 struct MUI_DragImage *img = NULL;
3416 const struct ZuneFrameGfx *zframe;
3417 LONG depth;
3419 /* Get info on dragged entry */
3420 DoMethod(obj, MUIM_List_TestPos, _left(data->area) - msg->touchx,
3421 _top(data->area) - msg->touchy, (IPTR) &pos);
3422 if (pos.entry == -1)
3423 success = FALSE;
3425 if (success)
3427 /* Get boundaries of entry */
3428 width = _mwidth(data->area);
3429 height = data->entry_maxheight;
3430 left = _mleft(data->area);
3431 top = _top(data->area) - msg->touchy
3432 - (pos.yoffset + data->entry_maxheight / 2);
3434 /* Allocate drag image structure */
3435 img = (struct MUI_DragImage *)
3436 AllocVec(sizeof(struct MUI_DragImage), MEMF_CLEAR);
3437 if (img == NULL)
3438 success = FALSE;
3441 if (success)
3443 /* Get drag frame */
3444 zframe = zune_zframe_get(obj,
3445 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Drag]);
3447 /* Allocate drag image buffer */
3448 img->width = width + zframe->ileft + zframe->iright;
3449 img->height = height + zframe->itop + zframe->ibottom;
3450 depth = GetBitMapAttr(_screen(obj)->RastPort.BitMap, BMA_DEPTH);
3451 img->bm = AllocBitMap(img->width, img->height, depth, BMF_MINPLANES,
3452 _screen(obj)->RastPort.BitMap);
3454 if (img->bm != NULL)
3456 /* Render entry */
3457 struct RastPort temprp;
3458 InitRastPort(&temprp);
3459 temprp.BitMap = img->bm;
3460 ClipBlit(_rp(obj), left, top, &temprp,
3461 zframe->ileft, zframe->itop, width, height,
3462 0xc0);
3464 /* Render frame */
3465 struct RastPort *rp_save = muiRenderInfo(obj)->mri_RastPort;
3466 muiRenderInfo(obj)->mri_RastPort = &temprp;
3467 zframe->draw(zframe->customframe, muiRenderInfo(obj), 0, 0,
3468 img->width, img->height, 0, 0, img->width, img->height);
3469 muiRenderInfo(obj)->mri_RastPort = rp_save;
3472 /* Ensure drag point matches where user clicked */
3473 img->touchx = msg->touchx - zframe->ileft + _addleft(obj);
3474 img->touchy = -(pos.yoffset + data->entry_maxheight / 2)
3475 - zframe->itop;
3476 img->flags = 0;
3479 return (IPTR) img;
3482 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely)
3484 LONG new, first, entries, visible;
3486 new = first = XGET(obj, MUIA_List_First);
3487 entries = XGET(obj, MUIA_List_Entries);
3488 visible = XGET(obj, MUIA_List_Visible);
3490 new += wheely;
3492 if (new > entries - visible)
3494 new = entries - visible;
3497 if (new < 0)
3499 new = 0;
3502 if (new != first)
3504 set(obj, MUIA_List_First, new);
3508 /**************************************************************************
3509 MUIM_HandleEvent
3510 **************************************************************************/
3511 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
3512 struct MUIP_HandleEvent *msg)
3514 struct MUI_ListData *data = INST_DATA(cl, obj);
3515 struct MUI_List_TestPos_Result pos;
3516 LONG seltype, old_active, new_active, visible, first, last, i;
3517 IPTR result = 0;
3518 BOOL select = FALSE, clear = FALSE, range_select = FALSE, changing;
3519 WORD delta;
3520 typeof(msg->muikey) muikey = msg->muikey;
3522 new_active = old_active = XGET(obj, MUIA_List_Active);
3523 visible = XGET(obj, MUIA_List_Visible);
3525 if (muikey != MUIKEY_NONE)
3527 result = MUI_EventHandlerRC_Eat;
3529 /* Make keys behave differently in read-only mode */
3530 if (data->read_only)
3532 switch (muikey)
3534 case MUIKEY_TOP:
3535 muikey = MUIKEY_LINESTART;
3536 break;
3538 case MUIKEY_BOTTOM:
3539 muikey = MUIKEY_LINEEND;
3540 break;
3542 case MUIKEY_UP:
3543 muikey = MUIKEY_LEFT;
3544 break;
3546 case MUIKEY_DOWN:
3547 case MUIKEY_PRESS:
3548 muikey = MUIKEY_RIGHT;
3549 break;
3553 switch (muikey)
3555 case MUIKEY_TOGGLE:
3556 if (data->multiselect != MUIV_Listview_MultiSelect_None
3557 && !data->read_only)
3559 select = TRUE;
3560 data->click_column = data->def_click_column;
3561 new_active = MUIV_List_Active_Down;
3563 else
3565 DoMethod(obj, MUIM_List_Jump, 0);
3566 muikey = MUIKEY_NONE;
3568 break;
3570 case MUIKEY_TOP:
3571 new_active = MUIV_List_Active_Top;
3572 break;
3574 case MUIKEY_BOTTOM:
3575 new_active = MUIV_List_Active_Bottom;
3576 break;
3578 case MUIKEY_LEFT:
3579 case MUIKEY_WORDLEFT:
3580 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Up);
3581 break;
3583 case MUIKEY_RIGHT:
3584 case MUIKEY_WORDRIGHT:
3585 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Down);
3586 break;
3588 case MUIKEY_LINESTART:
3589 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Top);
3590 break;
3592 case MUIKEY_LINEEND:
3593 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Bottom);
3594 break;
3596 case MUIKEY_UP:
3597 new_active = MUIV_List_Active_Up;
3598 break;
3600 case MUIKEY_DOWN:
3601 new_active = MUIV_List_Active_Down;
3602 break;
3604 case MUIKEY_PRESS:
3605 data->click_column = data->def_click_column;
3606 superset(cl, obj, MUIA_Listview_ClickColumn,
3607 data->click_column);
3608 set(obj, MUIA_Listview_DoubleClick, TRUE);
3609 break;
3611 case MUIKEY_PAGEUP:
3612 if (data->read_only)
3613 DoWheelMove(cl, obj, -visible);
3614 else
3615 new_active = MUIV_List_Active_PageUp;
3616 break;
3618 case MUIKEY_PAGEDOWN:
3619 if (data->read_only)
3620 DoWheelMove(cl, obj, visible);
3621 else
3622 new_active = MUIV_List_Active_PageDown;
3623 break;
3625 default:
3626 result = 0;
3629 else if (msg->imsg)
3631 DoMethod(obj, MUIM_List_TestPos, msg->imsg->MouseX, msg->imsg->MouseY,
3632 (IPTR) &pos);
3634 switch (msg->imsg->Class)
3636 case IDCMP_MOUSEBUTTONS:
3637 if (msg->imsg->Code == SELECTDOWN)
3639 if (_isinobject(data->area, msg->imsg->MouseX,
3640 msg->imsg->MouseY))
3642 data->mouse_click = MOUSE_CLICK_ENTRY;
3644 if (!data->read_only && pos.entry != -1)
3646 new_active = pos.entry;
3648 clear = (data->multiselect
3649 == MUIV_Listview_MultiSelect_Shifted
3650 && (msg->imsg->Qualifier
3651 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0);
3652 seltype = clear ? MUIV_List_Select_On
3653 : MUIV_List_Select_Toggle;
3654 select = data->multiselect
3655 != MUIV_Listview_MultiSelect_None;
3657 /* Handle MUIA_Listview_ClickColumn */
3658 data->click_column = pos.column;
3659 superset(cl, obj, MUIA_Listview_ClickColumn,
3660 data->click_column);
3662 /* Handle double clicking */
3663 if (data->last_active == pos.entry
3664 && DoubleClick(data->last_secs, data->last_mics,
3665 msg->imsg->Seconds, msg->imsg->Micros))
3667 set(obj, MUIA_Listview_DoubleClick, TRUE);
3668 data->last_active = -1;
3669 data->last_secs = data->last_mics = 0;
3671 else
3673 data->last_active = pos.entry;
3674 data->last_secs = msg->imsg->Seconds;
3675 data->last_mics = msg->imsg->Micros;
3678 /* Look out for mouse movement, timer and
3679 inactive-window events while mouse button is
3680 down */
3681 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3682 (IPTR) &data->ehn);
3683 data->ehn.ehn_Events |= (IDCMP_MOUSEMOVE
3684 | IDCMP_INTUITICKS |IDCMP_INACTIVEWINDOW);
3685 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3686 (IPTR) &data->ehn);
3690 else
3692 /* Activate object */
3693 if (msg->imsg->Code == SELECTUP && data->mouse_click)
3695 set(_win(obj), MUIA_Window_ActiveObject, (IPTR)obj);
3696 data->mouse_click = 0;
3699 /* Restore normal event mask */
3700 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3701 (IPTR) &data->ehn);
3702 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
3703 | IDCMP_INACTIVEWINDOW);
3704 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3705 (IPTR) &data->ehn);
3707 break;
3709 case IDCMP_MOUSEMOVE:
3710 case IDCMP_INTUITICKS:
3711 if (pos.flags & MUI_LPR_ABOVE)
3712 new_active = MUIV_List_Active_Up;
3713 else if (pos.flags & MUI_LPR_BELOW)
3714 new_active = MUIV_List_Active_Down;
3715 else
3716 new_active = pos.entry;
3718 select = new_active != old_active
3719 && data->multiselect != MUIV_Listview_MultiSelect_None;
3720 if (select)
3722 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3723 MUIV_List_Select_Ask, &seltype);
3724 range_select = new_active >= 0;
3727 break;
3729 case IDCMP_INACTIVEWINDOW:
3730 /* Stop listening for events we only listen to when mouse button is
3731 down: we will not be informed of the button being released */
3732 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3733 (IPTR) &data->ehn);
3734 data->ehn.ehn_Events &=
3735 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS | IDCMP_INACTIVEWINDOW);
3736 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3737 (IPTR) &data->ehn);
3738 break;
3740 case IDCMP_RAWKEY:
3741 /* Scroll wheel */
3742 if (data->vert && _isinobject(data->vert, msg->imsg->MouseX,
3743 msg->imsg->MouseY))
3744 delta = 1;
3745 else if (_isinobject(data->area, msg->imsg->MouseX,
3746 msg->imsg->MouseY))
3747 delta = 4;
3748 else
3749 delta = 0;
3751 if (delta != 0)
3753 switch (msg->imsg->Code)
3755 case RAWKEY_NM_WHEEL_UP:
3756 DoWheelMove(cl, obj, -delta);
3757 break;
3759 case RAWKEY_NM_WHEEL_DOWN:
3760 DoWheelMove(cl, obj, delta);
3761 break;
3763 result = MUI_EventHandlerRC_Eat;
3765 break;
3769 /* Decide in advance if any selections may change */
3770 changing = clear || muikey == MUIKEY_TOGGLE || select;
3772 /* Change selected and active entries */
3773 if (changing)
3774 set(obj, MUIA_Listview_SelectChange, TRUE);
3776 if (clear)
3778 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
3779 MUIV_List_Select_Off, NULL);
3782 if (muikey == MUIKEY_TOGGLE)
3784 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3785 MUIV_List_Select_Toggle, NULL);
3786 select = FALSE;
3789 if (new_active != old_active)
3790 set(obj, MUIA_List_Active, new_active);
3792 if (select)
3794 if (range_select)
3796 if (old_active < new_active)
3797 first = old_active + 1, last = new_active;
3798 else
3799 first = new_active, last = old_active - 1;
3800 for (i = first; i <= last; i++)
3801 DoMethod(obj, MUIM_List_Select, i, seltype, NULL);
3803 else
3804 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3805 seltype, NULL);
3808 if (changing)
3809 set(obj, MUIA_Listview_SelectChange, FALSE);
3811 return result;
3814 /**************************************************************************
3815 Dispatcher
3816 **************************************************************************/
3817 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
3819 switch (msg->MethodID)
3821 case OM_NEW:
3822 return List__OM_NEW(cl, obj, (struct opSet *)msg);
3823 case OM_DISPOSE:
3824 return List__OM_DISPOSE(cl, obj, msg);
3825 case OM_SET:
3826 return List__OM_SET(cl, obj, (struct opSet *)msg);
3827 case OM_GET:
3828 return List__OM_GET(cl, obj, (struct opGet *)msg);
3830 case MUIM_Setup:
3831 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
3832 case MUIM_Cleanup:
3833 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
3834 case MUIM_HandleEvent:
3835 return List__MUIM_HandleEvent(cl, obj, (struct MUIP_HandleEvent *)msg);
3836 case MUIM_AskMinMax:
3837 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
3838 case MUIM_Show:
3839 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
3840 case MUIM_Hide:
3841 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
3842 case MUIM_Draw:
3843 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
3844 case MUIM_Layout:
3845 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
3846 case MUIM_List_Clear:
3847 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
3848 case MUIM_List_Sort:
3849 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
3850 case MUIM_List_Exchange:
3851 return List__MUIM_Exchange(cl, obj,
3852 (struct MUIP_List_Exchange *)msg);
3853 case MUIM_List_Insert:
3854 return List__MUIM_Insert(cl, obj, (APTR) msg);
3855 case MUIM_List_InsertSingle:
3856 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
3857 case MUIM_List_GetEntry:
3858 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
3859 case MUIM_List_Redraw:
3860 return List__MUIM_Redraw(cl, obj, (APTR) msg);
3861 case MUIM_List_Remove:
3862 return List__MUIM_Remove(cl, obj, (APTR) msg);
3863 case MUIM_List_Select:
3864 return List__MUIM_Select(cl, obj, (APTR) msg);
3865 case MUIM_List_Construct:
3866 return List__MUIM_Construct(cl, obj, (APTR) msg);
3867 case MUIM_List_Destruct:
3868 return List__MUIM_Destruct(cl, obj, (APTR) msg);
3869 case MUIM_List_Compare:
3870 return List__MUIM_Compare(cl, obj, (APTR) msg);
3871 case MUIM_List_Display:
3872 return List__MUIM_Display(cl, obj, (APTR) msg);
3873 case MUIM_List_SelectChange:
3874 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
3875 case MUIM_List_CreateImage:
3876 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
3877 case MUIM_List_DeleteImage:
3878 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
3879 case MUIM_List_Jump:
3880 return List__MUIM_Jump(cl, obj, (APTR) msg);
3881 case MUIM_List_Move:
3882 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
3883 case MUIM_List_NextSelected:
3884 return List__MUIM_NextSelected(cl, obj,
3885 (struct MUIP_List_NextSelected *)msg);
3886 case MUIM_List_TestPos:
3887 return List__MUIM_TestPos(cl, obj, (APTR) msg);
3888 case MUIM_DragQuery:
3889 return List__MUIM_DragQuery(cl, obj, (APTR) msg);
3890 case MUIM_DragFinish:
3891 return List__MUIM_DragFinish(cl, obj, (APTR) msg);
3892 case MUIM_DragReport:
3893 return List__MUIM_DragReport(cl, obj, (APTR) msg);
3894 case MUIM_DragDrop:
3895 return List__MUIM_DragDrop(cl, obj, (APTR) msg);
3896 case MUIM_CreateDragImage:
3897 return List__MUIM_CreateDragImage(cl, obj, (APTR) msg);
3900 return DoSuperMethodA(cl, obj, msg);
3902 BOOPSI_DISPATCHER_END
3905 * Class descriptor.
3907 const struct __MUIBuiltinClass _MUI_List_desc =
3909 MUIC_List,
3910 MUIC_Group,
3911 sizeof(struct MUI_ListData),
3912 (void *) List_Dispatcher