List.mui: Update entries count prior to range change
[AROS.git] / workbench / libs / muimaster / classes / list.c
blob6bcd289031cbbac6e6f790ca1cf4720f27b371bc
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 /* Update entries count prior to range check */
2314 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num, TAG_DONE);
2316 /* Ensure that the active element is in a valid range (it might become
2317 * MUIV_List_Active_Off (-1), but that's OK) */
2318 if (new_act >= data->entries_num)
2319 new_act = data->entries_num - 1;
2321 SetAttrs(obj,
2322 active_tag, new_act, /* Inform only if necessary (for notify) */
2323 TAG_DONE);
2325 data->update = 1;
2326 MUI_Redraw(obj, MADF_DRAWUPDATE);
2328 return 0;
2331 /**************************************************************************
2332 MUIM_List_Select
2333 **************************************************************************/
2334 IPTR List__MUIM_Select(struct IClass *cl, Object *obj,
2335 struct MUIP_List_Select *msg)
2337 struct MUI_ListData *data = INST_DATA(cl, obj);
2338 LONG pos, i, count, selcount=0, state=0;
2339 BOOL multi_allowed = TRUE, new_select_state = FALSE;
2341 /* Establish the range of entries affected */
2342 switch (msg->pos)
2344 case MUIV_List_Select_Active:
2345 pos = data->entries_active;
2346 if (pos == MUIV_List_Active_Off)
2347 count = 0;
2348 else
2349 count = 1;
2350 break;
2352 case MUIV_List_Select_All:
2353 pos = 0;
2354 count = data->entries_num;
2355 break;
2357 default:
2358 pos = msg->pos;
2359 count = 1;
2360 if (pos < 0 || pos >= data->entries_num)
2361 return 0;
2362 break;
2365 if (msg->seltype != MUIV_List_Select_Ask && data->multi_test_hook != NULL)
2367 /* Disallow selection of an additional entry if there is a currently
2368 selected entry that is not multi-selectable (in such case there
2369 will only be one entry currently selected, so no need to iterate) */
2370 i = MUIV_List_NextSelected_Start;
2371 DoMethod(obj, MUIM_List_NextSelected, (IPTR) &i);
2372 if (i != MUIV_List_NextSelected_End)
2373 selcount++;
2374 if (data->multi_test_hook != NULL && selcount != 0)
2375 multi_allowed = CallHookPkt(data->multi_test_hook, NULL,
2376 data->entries[i]->data);
2379 /* Change or check state of each entry in the range */
2380 for (i = pos; i < pos + count; i++)
2382 state = data->entries[i]->flags & ENTRY_SELECTED;
2383 switch (msg->seltype)
2385 case MUIV_List_Select_Off:
2386 new_select_state = FALSE;
2387 break;
2389 case MUIV_List_Select_On:
2390 new_select_state = TRUE;
2391 break;
2393 case MUIV_List_Select_Toggle:
2394 new_select_state = !state;
2395 break;
2397 default:
2398 if (data->entries[i]->flags & ENTRY_SELECTED)
2399 selcount++;
2400 break;
2403 if (msg->seltype != MUIV_List_Select_Ask)
2405 /* Disallow selection if entry is not multi-selectable and
2406 * there are already selected entries */
2407 if (data->multi_test_hook != NULL && new_select_state)
2408 new_select_state = multi_allowed && (selcount == 0 ||
2409 CallHookPkt(data->multi_test_hook, NULL,
2410 data->entries[i]->data));
2412 if (new_select_state)
2413 data->entries[i]->flags |= ENTRY_SELECTED;
2414 else
2415 data->entries[i]->flags &= ~ENTRY_SELECTED;
2419 /* Report old state or number of selected entries */
2420 if (msg->info)
2422 if (msg->pos == MUIV_List_Select_All
2423 && msg->seltype == MUIV_List_Select_Ask)
2424 *msg->info = selcount;
2425 else
2426 *msg->info = state;
2429 /* Redraw unless it was just an enquiry */
2430 if (msg->seltype != MUIV_List_Select_Ask)
2432 if (count > 1)
2433 data->update = 1;
2434 else
2436 data->update = 2;
2437 data->update_pos = pos;
2439 MUI_Redraw(obj, MADF_DRAWUPDATE);
2442 return 0;
2445 /****** List.mui/MUIM_List_Insert ********************************************
2447 * NAME
2448 * MUIM_List_Insert (V4)
2450 * SYNOPSIS
2451 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2453 * FUNCTION
2454 * Adds multiple entries to the list. If a construct hook has been
2455 * installed, the results of passing the entries to this hook will be
2456 * inserted.
2458 * INPUTS
2459 * entries - an array of entries to be inserted.
2460 * count - the number of entries to insert. A special value of -1 may be
2461 * used, indicating that the array of entries is NULL-terminated.
2462 * pos - the index at which to insert the new entries. The following
2463 * special values can also be used:
2464 * MUIV_List_Insert_Top: insert at index 0.
2465 * MUIV_List_Insert_Bottom: insert after all existing entries.
2466 * MUIV_List_Insert_Active: insert at the index of the active entry
2467 * (or at index 0 if there is no active entry).
2468 * MUIV_List_Insert_Sorted: keep the list sorted.
2470 * SEE ALSO
2471 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2473 ******************************************************************************
2477 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
2478 struct MUIP_List_Insert *msg)
2480 struct MUI_ListData *data = INST_DATA(cl, obj);
2481 LONG pos, count, sort, active;
2483 count = msg->count;
2484 sort = 0;
2486 if (count == -1)
2488 /* Count the number of entries */
2489 for (count = 0; msg->entries[count] != NULL; count++)
2493 if (count <= 0)
2494 return ~0;
2496 switch (msg->pos)
2498 case MUIV_List_Insert_Top:
2499 pos = 0;
2500 break;
2502 case MUIV_List_Insert_Active:
2503 if (data->entries_active != -1)
2504 pos = data->entries_active;
2505 else
2506 pos = 0;
2507 break;
2509 case MUIV_List_Insert_Sorted:
2510 pos = data->entries_num;
2511 sort = 1; /* we sort'em later */
2512 break;
2514 case MUIV_List_Insert_Bottom:
2515 pos = data->entries_num;
2516 break;
2518 default:
2519 if (msg->pos > data->entries_num)
2520 pos = data->entries_num;
2521 else if (msg->pos < 0)
2522 pos = 0;
2523 else
2524 pos = msg->pos;
2525 break;
2527 data->insert_position = pos;
2529 if (!(SetListSize(data, data->entries_num + count)))
2530 return ~0;
2532 LONG until = pos + count;
2533 APTR *toinsert = msg->entries;
2535 if (!(PrepareInsertListEntries(data, pos, count)))
2536 return ~0;
2538 while (pos < until)
2540 struct ListEntry *lentry;
2542 if (!(lentry = AllocListEntry(data)))
2544 /* Panic, but we must be in a consistent state, so remove
2545 * the space where the following list entries should have gone
2547 RemoveListEntries(data, pos, until - pos);
2548 return ~0;
2551 /* now call the construct method which returns us a pointer which
2552 we need to store */
2553 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2554 (IPTR) * toinsert, (IPTR) data->pool);
2555 if (!lentry->data)
2557 FreeListEntry(data, lentry);
2558 RemoveListEntries(data, pos, until - pos);
2560 /* TODO: Also check for visible stuff like below */
2561 if (data->entries_num != data->confirm_entries_num)
2562 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2563 return ~0;
2566 data->entries[pos] = lentry;
2567 data->confirm_entries_num++;
2569 if (_flags(obj) & MADF_SETUP)
2571 /* We have to calculate the width and height of the newly
2572 * inserted entry. This has to be done after inserting the
2573 * element into the list */
2574 CalcDimsOfEntry(cl, obj, pos);
2577 toinsert++;
2578 pos++;
2580 pos--;
2582 /* Recalculate the number of visible entries */
2583 if (_flags(obj) & MADF_SETUP)
2584 CalcVertVisible(cl, obj);
2586 if (data->entries_num != data->confirm_entries_num)
2588 SetAttrs(obj,
2589 MUIA_List_Entries, data->confirm_entries_num,
2590 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2593 /* If the array is already sorted, we could do a simple insert
2594 * sort and would be much faster than with qsort.
2595 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2596 * sort the whole array?
2598 * I think, we better sort the whole array:
2600 if (sort)
2602 DoMethod(obj, MUIM_List_Sort);
2603 /* TODO: which pos to return here !? */
2604 /* MUIM_List_Sort already called MUI_Redraw */
2606 else
2608 data->update = 1;
2609 MUI_Redraw(obj, MADF_DRAWUPDATE);
2611 superset(cl, obj, MUIA_List_InsertPosition, data->insert_position);
2613 /* Update index of active entry */
2614 if (data->entries_active >= data->insert_position)
2616 active = data->entries_active + count;
2617 SET(obj, MUIA_List_Active, active);
2620 return (ULONG) pos;
2623 /****** List.mui/MUIM_List_InsertSingle **************************************
2625 * NAME
2626 * MUIM_List_InsertSingle (V7)
2628 * SYNOPSIS
2629 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2631 * FUNCTION
2632 * Adds a single entry to the list. If a construct hook has been
2633 * installed, the result of passing the entry to this hook will be
2634 * inserted.
2636 * INPUTS
2637 * entry - the entry to be inserted.
2638 * pos - the index at which to insert the new entry. The following
2639 * special values can also be used:
2640 * MUIV_List_Insert_Top: insert at index 0.
2641 * MUIV_List_Insert_Bottom: insert after all existing entries.
2642 * MUIV_List_Insert_Active: insert at the index of the active entry
2643 * (or at index 0 if there is no active entry).
2644 * MUIV_List_Insert_Sorted: keep the list sorted.
2646 * SEE ALSO
2647 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2649 ******************************************************************************
2653 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2654 struct MUIP_List_InsertSingle *msg)
2656 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2657 msg->pos);
2660 /**************************************************************************
2661 MUIM_List_GetEntry
2662 **************************************************************************/
2663 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2664 struct MUIP_List_GetEntry *msg)
2666 struct MUI_ListData *data = INST_DATA(cl, obj);
2667 int pos = msg->pos;
2669 if (pos == MUIV_List_GetEntry_Active)
2670 pos = data->entries_active;
2672 if (pos < 0 || pos >= data->entries_num)
2674 *msg->entry = NULL;
2675 return 0;
2677 *msg->entry = data->entries[pos]->data;
2678 return (IPTR) *msg->entry;
2681 /**************************************************************************
2682 MUIM_List_Construct
2683 **************************************************************************/
2684 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2685 struct MUIP_List_Construct *msg)
2687 struct MUI_ListData *data = INST_DATA(cl, obj);
2689 if (NULL == data->construct_hook)
2690 return (IPTR) msg->entry;
2691 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2693 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2694 ULONG *mem = AllocPooled(msg->pool, len + 5);
2696 if (NULL == mem)
2697 return 0;
2698 mem[0] = len + 5;
2699 if (msg->entry != NULL)
2700 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2701 else
2702 *(STRPTR) (mem + 1) = 0;
2703 return (IPTR) (mem + 1);
2705 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2708 /**************************************************************************
2709 MUIM_List_Destruct
2710 **************************************************************************/
2711 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2712 struct MUIP_List_Destruct *msg)
2714 struct MUI_ListData *data = INST_DATA(cl, obj);
2716 if (NULL == data->destruct_hook)
2717 return 0;
2719 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2721 ULONG *mem = ((ULONG *) msg->entry) - 1;
2722 FreePooled(msg->pool, mem, mem[0]);
2724 else
2726 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2728 return 0;
2731 /****** List.mui/MUIM_List_Compare *******************************************
2733 * NAME
2734 * MUIM_List_Compare (V20)
2736 * SYNOPSIS
2737 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2738 * LONG sort_type1, LONG sort_type2);
2740 * FUNCTION
2741 * Compare two list entries according to the current comparison hook
2742 * (MUIA_List_CompareHook).
2744 * INPUTS
2745 * entry1 - the first entry data.
2746 * entry2 - the second entry data.
2747 * sort_type1 - undocumented.
2748 * sort_type2 - undocumented.
2750 * SEE ALSO
2751 * MUIA_List_CompareHook, MUIM_List_Sort.
2753 ******************************************************************************
2757 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2758 struct MUIP_List_Compare *msg)
2760 struct MUI_ListData *data = INST_DATA(cl, obj);
2762 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2765 /**************************************************************************
2766 MUIM_List_Display
2767 **************************************************************************/
2768 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2769 struct MUIP_List_Display *msg)
2771 struct MUI_ListData *data = INST_DATA(cl, obj);
2773 if (NULL == data->display_hook)
2775 if (msg->entry)
2776 *msg->array = msg->entry;
2777 else
2778 *msg->array = 0;
2779 return 1;
2782 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2783 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2786 /**************************************************************************
2787 MUIM_List_SelectChange
2788 **************************************************************************/
2789 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2790 struct MUIP_List_SelectChange *msg)
2792 return 1;
2795 /**************************************************************************
2796 MUIM_List_CreateImage
2797 Called by a List subclass in its Setup method.
2798 Connects an Area subclass object to the list, much like an object gets
2799 connected to a window. List calls Setup and AskMinMax on that object,
2800 keeps a reference to it (that reference will be returned).
2801 Text engine will dereference that pointer and draw the object with its
2802 default size.
2803 **************************************************************************/
2804 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2805 struct MUIP_List_CreateImage *msg)
2807 struct MUI_ListData *data = INST_DATA(cl, obj);
2808 struct ListImage *li;
2810 if (!msg->obj)
2811 return 0;
2813 /* List must be already setup in Setup of your subclass */
2814 if (!(_flags(obj) & MADF_SETUP))
2815 return 0;
2816 li = AllocPooled(data->pool, sizeof(struct ListImage));
2817 if (!li)
2818 return 0;
2819 li->obj = msg->obj;
2821 AddTail((struct List *)&data->images, (struct Node *)li);
2822 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2823 DoSetupMethod(li->obj, muiRenderInfo(obj));
2826 return (IPTR) li;
2829 /**************************************************************************
2830 MUIM_List_DeleteImage
2831 **************************************************************************/
2832 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2833 struct MUIP_List_DeleteImage *msg)
2835 struct MUI_ListData *data = INST_DATA(cl, obj);
2836 struct ListImage *li = (struct ListImage *)msg->listimg;
2838 if (li)
2840 DoMethod(li->obj, MUIM_Cleanup);
2841 DoMethod(li->obj, MUIM_DisconnectParent);
2842 Remove((struct Node *)li);
2843 FreePooled(data->pool, li, sizeof(struct ListImage));
2846 return 0;
2849 /****** List.mui/MUIM_List_Jump **********************************************
2851 * NAME
2852 * MUIM_List_Jump (V4)
2854 * SYNOPSIS
2855 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2857 * FUNCTION
2858 * Scrolls the list so that a particular entry is visible.
2860 * INPUTS
2861 * pos - index of entry that should become visible, or one of these
2862 * special values:
2863 * MUIV_List_Jump_Active: show the active entry.
2864 * MUIV_List_Jump_Top: show the first entry.
2865 * MUIV_List_Jump_Bottom: show the last entry.
2866 * MUIV_List_Jump_Up: show the previous hidden entry.
2867 * MUIV_List_Jump_Down: show the next hidden entry.
2869 ******************************************************************************
2873 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2874 struct MUIP_List_Jump *msg)
2876 struct MUI_ListData *data = INST_DATA(cl, obj);
2877 LONG pos = msg->pos;
2879 switch (pos)
2881 case MUIV_List_Jump_Top:
2882 pos = 0;
2883 break;
2885 case MUIV_List_Jump_Active:
2886 pos = data->entries_active;
2887 break;
2889 case MUIV_List_Jump_Bottom:
2890 pos = data->entries_num - 1;
2891 break;
2893 case MUIV_List_Jump_Down:
2894 pos = data->entries_first + data->entries_visible;
2895 break;
2897 case MUIV_List_Jump_Up:
2898 pos = data->entries_first - 1;
2899 break;
2902 if (pos >= data->entries_num)
2904 pos = data->entries_num - 1;
2906 if (pos < 0)
2907 pos = 0;
2909 if (pos < data->entries_first)
2911 set(obj, MUIA_List_First, pos);
2913 else if (pos >= data->entries_first + data->entries_visible)
2915 pos -= (data->entries_visible - 1);
2916 if (pos < 0)
2917 pos = 0;
2918 if (pos != data->entries_first)
2920 set(obj, MUIA_List_First, pos);
2924 return TRUE;
2927 /****** List.mui/MUIM_List_Sort **********************************************
2929 * NAME
2930 * MUIM_List_Sort (V4)
2932 * SYNOPSIS
2933 * DoMethod(obj, MUIM_List_Sort);
2935 * FUNCTION
2936 * Sort the list's entries according to the current comparison hook
2937 * (MUIA_List_CompareHook).
2939 * NOTES
2940 * The active index does not change, so the active entry may do so.
2942 * SEE ALSO
2943 * MUIA_List_CompareHook, MUIM_List_Compare.
2945 ******************************************************************************
2949 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2950 struct MUIP_List_Sort *msg)
2952 struct MUI_ListData *data = INST_DATA(cl, obj);
2954 int i, j, max;
2955 struct MUIP_List_Compare cmpmsg =
2956 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2958 if (data->entries_num > 1)
2961 Simple sort algorithm. Feel free to improve it.
2963 for (i = 0; i < data->entries_num - 1; i++)
2965 max = i;
2966 for (j = i + 1; j < data->entries_num; j++)
2968 cmpmsg.entry1 = data->entries[max]->data;
2969 cmpmsg.entry2 = data->entries[j]->data;
2970 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2972 max = j;
2975 if (i != max)
2977 APTR tmp = data->entries[i];
2978 data->entries[i] = data->entries[max];
2979 data->entries[max] = tmp;
2984 data->update = 1;
2985 MUI_Redraw(obj, MADF_DRAWUPDATE);
2987 return 0;
2990 /****** List.mui/MUIM_List_Move **********************************************
2992 * NAME
2993 * MUIM_List_Move (V9)
2995 * SYNOPSIS
2996 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2998 * FUNCTION
2999 * Move a list entry to a new position.
3001 * INPUTS
3002 * from - the current index of the entry that should be moved, or one of
3003 * these special values:
3004 * MUIV_List_Move_Active: the active entry.
3005 * MUIV_List_Move_Top: the first entry.
3006 * MUIV_List_Move_Bottom: the last entry.
3007 * to - the index of the entry's new position, or one of
3008 * these special values:
3009 * MUIV_List_Move_Active: the active entry.
3010 * MUIV_List_Move_Top: the first entry.
3011 * MUIV_List_Move_Bottom: the last entry.
3013 * NOTES
3014 * The active index does not change, so the active entry may do so.
3016 * SEE ALSO
3017 * MUIM_List_Exchange
3019 ******************************************************************************
3023 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
3024 struct MUIP_List_Move *msg)
3026 struct MUI_ListData *data = INST_DATA(cl, obj);
3028 LONG from, to;
3029 int i;
3031 /* Normalise special 'from' values */
3032 switch (msg->from)
3034 case MUIV_List_Move_Top:
3035 from = 0;
3036 break;
3037 case MUIV_List_Move_Active:
3038 from = data->entries_active;
3039 break;
3040 case MUIV_List_Move_Bottom:
3041 from = data->entries_num - 1;
3042 break;
3043 default:
3044 from = msg->from;
3047 /* Normalise special 'to' values */
3048 switch (msg->to)
3050 case MUIV_List_Move_Top:
3051 to = 0;
3052 break;
3053 case MUIV_List_Move_Active:
3054 to = data->entries_active;
3055 break;
3056 case MUIV_List_Move_Bottom:
3057 to = data->entries_num - 1;
3058 break;
3059 case MUIV_List_Move_Next:
3060 to = from + 1;
3061 break;
3062 case MUIV_List_Move_Previous:
3063 to = from - 1;
3064 break;
3065 default:
3066 to = msg->to;
3069 /* Check that values are within valid bounds */
3070 if (from > data->entries_num - 1 || from < 0
3071 || to > data->entries_num - 1 || to < 0 || from == to)
3072 return (IPTR) FALSE;
3074 /* Shift all entries in the range between the 'from' and 'to' positions */
3075 if (from < to)
3077 struct ListEntry *backup = data->entries[from];
3078 for (i = from; i < to; i++)
3079 data->entries[i] = data->entries[i + 1];
3080 data->entries[to] = backup;
3082 else
3084 struct ListEntry *backup = data->entries[from];
3085 for (i = from; i > to; i--)
3086 data->entries[i] = data->entries[i - 1];
3087 data->entries[to] = backup;
3090 #if 0 /* Not done in MUI 3 */
3091 /* Update index of active entry */
3092 if (from == data->entries_active)
3093 data->entries_active = to;
3094 else if (data->entries_active > from && data->entries_active < to)
3095 data->entries_active--;
3096 else if (data->entries_active < from && data->entries_active >= to)
3097 data->entries_active++;
3098 #endif
3100 /* Reflect list changes visually */
3101 data->update = 1;
3102 MUI_Redraw(obj, MADF_DRAWUPDATE);
3104 return TRUE;
3107 /****** List.mui/MUIM_List_NextSelected **************************************
3109 * NAME
3110 * MUIM_List_NextSelected (V6)
3112 * SYNOPSIS
3113 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3115 * FUNCTION
3116 * Allows iteration through a list's selected entries by providing the
3117 * index of the next selected entry after the specified index.
3119 * INPUTS
3120 * pos - the address of a variable containing the index of the previous
3121 * selected entry. The variable must be initialised to the special
3122 * value MUIV_List_NextSelected_Start to find the first selected
3123 * entry. When this method returns, the variable will contain the
3124 * index of the next selected entry, or MUIV_List_NextSelected_End if
3125 * there are no more.
3127 * NOTES
3128 * If there are no selected entries but there is an active entry, the
3129 * index of the active entry will be stored (when
3130 * MUIV_List_NextSelected_Start is specified).
3132 * Some selected entries may be skipped if any entries are removed
3133 * between calls to this method during an iteration of a list.
3135 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3136 * the same numeric value.
3138 * SEE ALSO
3139 * MUIM_List_Select, MUIM_List_Remove.
3141 ******************************************************************************
3145 IPTR List__MUIM_NextSelected(struct IClass *cl, Object *obj,
3146 struct MUIP_List_NextSelected *msg)
3148 struct MUI_ListData *data = INST_DATA(cl, obj);
3149 LONG pos, i;
3150 BOOL found = FALSE;
3152 /* Get the first entry to check */
3153 pos = *msg->pos;
3154 if (pos == MUIV_List_NextSelected_Start)
3155 pos = 0;
3156 else
3157 pos++;
3159 /* Find the next selected entry */
3160 for (i = pos; i < data->entries_num && !found; i++)
3162 if (data->entries[i]->flags & ENTRY_SELECTED)
3164 pos = i;
3165 found = TRUE;
3169 /* Return index of selected or active entry, or indicate there are no
3170 more */
3171 if (!found)
3173 if (*msg->pos == MUIV_List_NextSelected_Start
3174 && data->entries_active != MUIV_List_Active_Off)
3175 pos = data->entries_active;
3176 else
3177 pos = MUIV_List_NextSelected_End;
3179 *msg->pos = pos;
3181 return TRUE;
3184 /**************************************************************************
3185 MUIM_List_TestPos
3186 **************************************************************************/
3187 IPTR List__MUIM_TestPos(struct IClass *cl, Object *obj,
3188 struct MUIP_List_TestPos *msg)
3190 struct MUI_ListData *data = INST_DATA(cl, obj);
3191 struct MUI_List_TestPos_Result *result = msg->res;
3192 LONG col = -1, row = -1;
3193 UWORD flags = 0, i;
3194 LONG mx = msg->x - _left(data->area);
3195 LONG entries_visible;
3197 if (data->entries_visible <= data->entries_num)
3198 entries_visible = data->entries_visible;
3199 else
3200 entries_visible = data->entries_num;
3201 LONG ey = msg->y - data->entries_top_pixel;
3202 /* y coordinates transformed to the entries */
3204 /* Now check if it was clicked on a title or on entries */
3205 if (ey < 0)
3206 flags |= MUI_LPR_ABOVE;
3207 else if (ey >= entries_visible * data->entry_maxheight)
3208 flags |= MUI_LPR_BELOW;
3209 else
3211 /* Identify row */
3212 row = ey / data->entry_maxheight + data->entries_first;
3213 result->yoffset =
3214 ey % data->entry_maxheight - data->entry_maxheight / 2;
3217 if (mx < 0)
3218 flags |= MUI_LPR_LEFT;
3219 else if (mx >= _width(data->area))
3220 flags |= MUI_LPR_RIGHT;
3221 else
3223 /* Identify column */
3224 if (data->entries_num > 0 && data->columns > 0)
3226 LONG width_sum = 0;
3227 col = data->columns - 1;
3228 for (i = 0; i < data->columns; i++)
3230 result->xoffset = mx - width_sum;
3231 width_sum +=
3232 data->ci[i].entries_width +
3233 data->ci[i].delta +
3234 (data->ci[i].bar ? BAR_WIDTH : 0);
3235 D(bug("[List/MUIM_TestPos] i %d "
3236 "width %d width_sum %d mx %d\n",
3237 i, data->ci[i].entries_width, width_sum, mx));
3238 if (mx < width_sum)
3240 col = i;
3241 D(bug("[List/MUIM_TestPos] Column hit %d\n", col));
3242 break;
3248 result->entry = row;
3249 result->column = col;
3250 result->flags = flags;
3252 return TRUE;
3255 /****i* List.mui/MUIM_DragQuery **********************************************
3257 * NAME
3258 * MUIM_DragQuery
3260 ******************************************************************************
3264 IPTR List__MUIM_DragQuery(struct IClass *cl, Object *obj,
3265 struct MUIP_DragQuery *msg)
3267 if (msg->obj == obj)
3268 return MUIV_DragQuery_Accept;
3269 else
3270 return MUIV_DragQuery_Refuse;
3274 /****i* List.mui/MUIM_DragFinish *********************************************
3276 * NAME
3277 * MUIM_DragFinish
3279 ******************************************************************************
3283 IPTR List__MUIM_DragFinish(struct IClass *cl, Object *obj,
3284 struct MUIP_DragFinish *msg)
3286 struct MUI_ListData *data = INST_DATA(cl, obj);
3288 data->drop_mark_y = -1;
3290 return DoSuperMethodA(cl, obj, (Msg) msg);
3293 /****i* List.mui/MUIM_DragReport *********************************************
3295 * NAME
3296 * MUIM_DragReport
3298 ******************************************************************************
3302 IPTR List__MUIM_DragReport(struct IClass *cl, Object *obj,
3303 struct MUIP_DragReport *msg)
3305 struct MUI_ListData *data = INST_DATA(cl, obj);
3306 struct MUI_List_TestPos_Result pos;
3307 struct RastPort *rp = _rp(obj);
3308 LONG n, y;
3309 UWORD old_pattern;
3311 /* Choose new drop mark position */
3313 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3314 if (pos.entry != -1)
3316 n = pos.entry;
3317 if (pos.yoffset > 0)
3318 n++;
3320 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3321 n = data->entries_first;
3322 else
3324 n = MIN(data->entries_visible, data->entries_num)
3325 - data->entries_first;
3328 /* Clear old drop mark */
3330 if ((data->flags & LIST_SHOWDROPMARKS) != 0)
3332 y = data->entries_top_pixel + (n - data->entries_first)
3333 * data->entry_maxheight;
3334 if (y != data->drop_mark_y)
3336 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
3337 data->drop_mark_y, _mwidth(data->area), 1, 0, 0, 0);
3339 /* Draw new drop mark and store its position */
3341 SetABPenDrMd(rp, _pens(obj)[MPEN_SHINE], _pens(obj)[MPEN_SHADOW],
3342 JAM2);
3343 old_pattern = rp->LinePtrn;
3344 SetDrPt(rp, 0xF0F0);
3345 Move(rp, _mleft(data->area), y);
3346 Draw(rp, _mright(data->area), y);
3347 SetDrPt(rp, old_pattern);
3348 data->drop_mark_y = y;
3352 return TRUE;
3356 /****i* List.mui/MUIM_DragDrop ***********************************************
3358 * NAME
3359 * MUIM_DragDrop
3361 ******************************************************************************
3365 IPTR List__MUIM_DragDrop(struct IClass *cl, Object *obj,
3366 struct MUIP_DragDrop *msg)
3368 struct MUI_ListData *data = INST_DATA(cl, obj);
3369 struct MUI_List_TestPos_Result pos;
3370 LONG n;
3372 /* Find drop position */
3374 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3375 if (pos.entry != -1)
3377 /* Change drop position when coords move past centre of entry, not
3378 * entry boundary */
3380 n = pos.entry;
3381 if (pos.yoffset > 0)
3382 n++;
3384 /* Ensure that dropped entry will be positioned between the two
3385 * entries that are above and below the drop mark, rather than
3386 * strictly at the numeric index shown */
3388 if (n > data->entries_active)
3389 n--;
3391 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3392 n = MUIV_List_Move_Top;
3393 else
3394 n = MUIV_List_Move_Bottom;
3396 DoMethod(msg->obj, MUIM_List_Move, MUIV_List_Move_Active, n);
3398 return TRUE;
3402 /****i* List.mui/MUIM_CreateDragImage ****************************************
3404 * NAME
3405 * MUIM_CreateDragImage
3407 ******************************************************************************
3411 static IPTR List__MUIM_CreateDragImage(struct IClass *cl, Object *obj,
3412 struct MUIP_CreateDragImage *msg)
3414 struct MUI_ListData *data = INST_DATA(cl, obj);
3415 BOOL success = TRUE;
3416 struct MUI_List_TestPos_Result pos;
3417 WORD width, height, left, top;
3418 struct MUI_DragImage *img = NULL;
3419 const struct ZuneFrameGfx *zframe;
3420 LONG depth;
3422 /* Get info on dragged entry */
3423 DoMethod(obj, MUIM_List_TestPos, _left(data->area) - msg->touchx,
3424 _top(data->area) - msg->touchy, (IPTR) &pos);
3425 if (pos.entry == -1)
3426 success = FALSE;
3428 if (success)
3430 /* Get boundaries of entry */
3431 width = _mwidth(data->area);
3432 height = data->entry_maxheight;
3433 left = _mleft(data->area);
3434 top = _top(data->area) - msg->touchy
3435 - (pos.yoffset + data->entry_maxheight / 2);
3437 /* Allocate drag image structure */
3438 img = (struct MUI_DragImage *)
3439 AllocVec(sizeof(struct MUI_DragImage), MEMF_CLEAR);
3440 if (img == NULL)
3441 success = FALSE;
3444 if (success)
3446 /* Get drag frame */
3447 zframe = zune_zframe_get(obj,
3448 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Drag]);
3450 /* Allocate drag image buffer */
3451 img->width = width + zframe->ileft + zframe->iright;
3452 img->height = height + zframe->itop + zframe->ibottom;
3453 depth = GetBitMapAttr(_screen(obj)->RastPort.BitMap, BMA_DEPTH);
3454 img->bm = AllocBitMap(img->width, img->height, depth, BMF_MINPLANES,
3455 _screen(obj)->RastPort.BitMap);
3457 if (img->bm != NULL)
3459 /* Render entry */
3460 struct RastPort temprp;
3461 InitRastPort(&temprp);
3462 temprp.BitMap = img->bm;
3463 ClipBlit(_rp(obj), left, top, &temprp,
3464 zframe->ileft, zframe->itop, width, height,
3465 0xc0);
3467 /* Render frame */
3468 struct RastPort *rp_save = muiRenderInfo(obj)->mri_RastPort;
3469 muiRenderInfo(obj)->mri_RastPort = &temprp;
3470 zframe->draw(zframe->customframe, muiRenderInfo(obj), 0, 0,
3471 img->width, img->height, 0, 0, img->width, img->height);
3472 muiRenderInfo(obj)->mri_RastPort = rp_save;
3475 /* Ensure drag point matches where user clicked */
3476 img->touchx = msg->touchx - zframe->ileft + _addleft(obj);
3477 img->touchy = -(pos.yoffset + data->entry_maxheight / 2)
3478 - zframe->itop;
3479 img->flags = 0;
3482 return (IPTR) img;
3485 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely)
3487 LONG new, first, entries, visible;
3489 new = first = XGET(obj, MUIA_List_First);
3490 entries = XGET(obj, MUIA_List_Entries);
3491 visible = XGET(obj, MUIA_List_Visible);
3493 new += wheely;
3495 if (new > entries - visible)
3497 new = entries - visible;
3500 if (new < 0)
3502 new = 0;
3505 if (new != first)
3507 set(obj, MUIA_List_First, new);
3511 /**************************************************************************
3512 MUIM_HandleEvent
3513 **************************************************************************/
3514 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
3515 struct MUIP_HandleEvent *msg)
3517 struct MUI_ListData *data = INST_DATA(cl, obj);
3518 struct MUI_List_TestPos_Result pos;
3519 LONG seltype, old_active, new_active, visible, first, last, i;
3520 IPTR result = 0;
3521 BOOL select = FALSE, clear = FALSE, range_select = FALSE, changing;
3522 WORD delta;
3523 typeof(msg->muikey) muikey = msg->muikey;
3525 new_active = old_active = XGET(obj, MUIA_List_Active);
3526 visible = XGET(obj, MUIA_List_Visible);
3528 if (muikey != MUIKEY_NONE)
3530 result = MUI_EventHandlerRC_Eat;
3532 /* Make keys behave differently in read-only mode */
3533 if (data->read_only)
3535 switch (muikey)
3537 case MUIKEY_TOP:
3538 muikey = MUIKEY_LINESTART;
3539 break;
3541 case MUIKEY_BOTTOM:
3542 muikey = MUIKEY_LINEEND;
3543 break;
3545 case MUIKEY_UP:
3546 muikey = MUIKEY_LEFT;
3547 break;
3549 case MUIKEY_DOWN:
3550 case MUIKEY_PRESS:
3551 muikey = MUIKEY_RIGHT;
3552 break;
3556 switch (muikey)
3558 case MUIKEY_TOGGLE:
3559 if (data->multiselect != MUIV_Listview_MultiSelect_None
3560 && !data->read_only)
3562 select = TRUE;
3563 data->click_column = data->def_click_column;
3564 new_active = MUIV_List_Active_Down;
3566 else
3568 DoMethod(obj, MUIM_List_Jump, 0);
3569 muikey = MUIKEY_NONE;
3571 break;
3573 case MUIKEY_TOP:
3574 new_active = MUIV_List_Active_Top;
3575 break;
3577 case MUIKEY_BOTTOM:
3578 new_active = MUIV_List_Active_Bottom;
3579 break;
3581 case MUIKEY_LEFT:
3582 case MUIKEY_WORDLEFT:
3583 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Up);
3584 break;
3586 case MUIKEY_RIGHT:
3587 case MUIKEY_WORDRIGHT:
3588 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Down);
3589 break;
3591 case MUIKEY_LINESTART:
3592 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Top);
3593 break;
3595 case MUIKEY_LINEEND:
3596 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Bottom);
3597 break;
3599 case MUIKEY_UP:
3600 new_active = MUIV_List_Active_Up;
3601 break;
3603 case MUIKEY_DOWN:
3604 new_active = MUIV_List_Active_Down;
3605 break;
3607 case MUIKEY_PRESS:
3608 data->click_column = data->def_click_column;
3609 superset(cl, obj, MUIA_Listview_ClickColumn,
3610 data->click_column);
3611 set(obj, MUIA_Listview_DoubleClick, TRUE);
3612 break;
3614 case MUIKEY_PAGEUP:
3615 if (data->read_only)
3616 DoWheelMove(cl, obj, -visible);
3617 else
3618 new_active = MUIV_List_Active_PageUp;
3619 break;
3621 case MUIKEY_PAGEDOWN:
3622 if (data->read_only)
3623 DoWheelMove(cl, obj, visible);
3624 else
3625 new_active = MUIV_List_Active_PageDown;
3626 break;
3628 default:
3629 result = 0;
3632 else if (msg->imsg)
3634 DoMethod(obj, MUIM_List_TestPos, msg->imsg->MouseX, msg->imsg->MouseY,
3635 (IPTR) &pos);
3637 switch (msg->imsg->Class)
3639 case IDCMP_MOUSEBUTTONS:
3640 if (msg->imsg->Code == SELECTDOWN)
3642 if (_isinobject(data->area, msg->imsg->MouseX,
3643 msg->imsg->MouseY))
3645 data->mouse_click = MOUSE_CLICK_ENTRY;
3647 if (!data->read_only && pos.entry != -1)
3649 new_active = pos.entry;
3651 clear = (data->multiselect
3652 == MUIV_Listview_MultiSelect_Shifted
3653 && (msg->imsg->Qualifier
3654 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0);
3655 seltype = clear ? MUIV_List_Select_On
3656 : MUIV_List_Select_Toggle;
3657 select = data->multiselect
3658 != MUIV_Listview_MultiSelect_None;
3660 /* Handle MUIA_Listview_ClickColumn */
3661 data->click_column = pos.column;
3662 superset(cl, obj, MUIA_Listview_ClickColumn,
3663 data->click_column);
3665 /* Handle double clicking */
3666 if (data->last_active == pos.entry
3667 && DoubleClick(data->last_secs, data->last_mics,
3668 msg->imsg->Seconds, msg->imsg->Micros))
3670 set(obj, MUIA_Listview_DoubleClick, TRUE);
3671 data->last_active = -1;
3672 data->last_secs = data->last_mics = 0;
3674 else
3676 data->last_active = pos.entry;
3677 data->last_secs = msg->imsg->Seconds;
3678 data->last_mics = msg->imsg->Micros;
3681 /* Look out for mouse movement, timer and
3682 inactive-window events while mouse button is
3683 down */
3684 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3685 (IPTR) &data->ehn);
3686 data->ehn.ehn_Events |= (IDCMP_MOUSEMOVE
3687 | IDCMP_INTUITICKS |IDCMP_INACTIVEWINDOW);
3688 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3689 (IPTR) &data->ehn);
3693 else
3695 /* Activate object */
3696 if (msg->imsg->Code == SELECTUP && data->mouse_click)
3698 set(_win(obj), MUIA_Window_ActiveObject, (IPTR)obj);
3699 data->mouse_click = 0;
3702 /* Restore normal event mask */
3703 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3704 (IPTR) &data->ehn);
3705 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
3706 | IDCMP_INACTIVEWINDOW);
3707 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3708 (IPTR) &data->ehn);
3710 break;
3712 case IDCMP_MOUSEMOVE:
3713 case IDCMP_INTUITICKS:
3714 if (pos.flags & MUI_LPR_ABOVE)
3715 new_active = MUIV_List_Active_Up;
3716 else if (pos.flags & MUI_LPR_BELOW)
3717 new_active = MUIV_List_Active_Down;
3718 else
3719 new_active = pos.entry;
3721 select = new_active != old_active
3722 && data->multiselect != MUIV_Listview_MultiSelect_None;
3723 if (select)
3725 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3726 MUIV_List_Select_Ask, &seltype);
3727 range_select = new_active >= 0;
3730 break;
3732 case IDCMP_INACTIVEWINDOW:
3733 /* Stop listening for events we only listen to when mouse button is
3734 down: we will not be informed of the button being released */
3735 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3736 (IPTR) &data->ehn);
3737 data->ehn.ehn_Events &=
3738 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS | IDCMP_INACTIVEWINDOW);
3739 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3740 (IPTR) &data->ehn);
3741 break;
3743 case IDCMP_RAWKEY:
3744 /* Scroll wheel */
3745 if (data->vert && _isinobject(data->vert, msg->imsg->MouseX,
3746 msg->imsg->MouseY))
3747 delta = 1;
3748 else if (_isinobject(data->area, msg->imsg->MouseX,
3749 msg->imsg->MouseY))
3750 delta = 4;
3751 else
3752 delta = 0;
3754 if (delta != 0)
3756 switch (msg->imsg->Code)
3758 case RAWKEY_NM_WHEEL_UP:
3759 DoWheelMove(cl, obj, -delta);
3760 break;
3762 case RAWKEY_NM_WHEEL_DOWN:
3763 DoWheelMove(cl, obj, delta);
3764 break;
3766 result = MUI_EventHandlerRC_Eat;
3768 break;
3772 /* Decide in advance if any selections may change */
3773 changing = clear || muikey == MUIKEY_TOGGLE || select;
3775 /* Change selected and active entries */
3776 if (changing)
3777 set(obj, MUIA_Listview_SelectChange, TRUE);
3779 if (clear)
3781 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
3782 MUIV_List_Select_Off, NULL);
3785 if (muikey == MUIKEY_TOGGLE)
3787 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3788 MUIV_List_Select_Toggle, NULL);
3789 select = FALSE;
3792 if (new_active != old_active)
3793 set(obj, MUIA_List_Active, new_active);
3795 if (select)
3797 if (range_select)
3799 if (old_active < new_active)
3800 first = old_active + 1, last = new_active;
3801 else
3802 first = new_active, last = old_active - 1;
3803 for (i = first; i <= last; i++)
3804 DoMethod(obj, MUIM_List_Select, i, seltype, NULL);
3806 else
3807 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3808 seltype, NULL);
3811 if (changing)
3812 set(obj, MUIA_Listview_SelectChange, FALSE);
3814 return result;
3817 /**************************************************************************
3818 Dispatcher
3819 **************************************************************************/
3820 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
3822 switch (msg->MethodID)
3824 case OM_NEW:
3825 return List__OM_NEW(cl, obj, (struct opSet *)msg);
3826 case OM_DISPOSE:
3827 return List__OM_DISPOSE(cl, obj, msg);
3828 case OM_SET:
3829 return List__OM_SET(cl, obj, (struct opSet *)msg);
3830 case OM_GET:
3831 return List__OM_GET(cl, obj, (struct opGet *)msg);
3833 case MUIM_Setup:
3834 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
3835 case MUIM_Cleanup:
3836 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
3837 case MUIM_HandleEvent:
3838 return List__MUIM_HandleEvent(cl, obj, (struct MUIP_HandleEvent *)msg);
3839 case MUIM_AskMinMax:
3840 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
3841 case MUIM_Show:
3842 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
3843 case MUIM_Hide:
3844 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
3845 case MUIM_Draw:
3846 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
3847 case MUIM_Layout:
3848 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
3849 case MUIM_List_Clear:
3850 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
3851 case MUIM_List_Sort:
3852 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
3853 case MUIM_List_Exchange:
3854 return List__MUIM_Exchange(cl, obj,
3855 (struct MUIP_List_Exchange *)msg);
3856 case MUIM_List_Insert:
3857 return List__MUIM_Insert(cl, obj, (APTR) msg);
3858 case MUIM_List_InsertSingle:
3859 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
3860 case MUIM_List_GetEntry:
3861 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
3862 case MUIM_List_Redraw:
3863 return List__MUIM_Redraw(cl, obj, (APTR) msg);
3864 case MUIM_List_Remove:
3865 return List__MUIM_Remove(cl, obj, (APTR) msg);
3866 case MUIM_List_Select:
3867 return List__MUIM_Select(cl, obj, (APTR) msg);
3868 case MUIM_List_Construct:
3869 return List__MUIM_Construct(cl, obj, (APTR) msg);
3870 case MUIM_List_Destruct:
3871 return List__MUIM_Destruct(cl, obj, (APTR) msg);
3872 case MUIM_List_Compare:
3873 return List__MUIM_Compare(cl, obj, (APTR) msg);
3874 case MUIM_List_Display:
3875 return List__MUIM_Display(cl, obj, (APTR) msg);
3876 case MUIM_List_SelectChange:
3877 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
3878 case MUIM_List_CreateImage:
3879 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
3880 case MUIM_List_DeleteImage:
3881 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
3882 case MUIM_List_Jump:
3883 return List__MUIM_Jump(cl, obj, (APTR) msg);
3884 case MUIM_List_Move:
3885 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
3886 case MUIM_List_NextSelected:
3887 return List__MUIM_NextSelected(cl, obj,
3888 (struct MUIP_List_NextSelected *)msg);
3889 case MUIM_List_TestPos:
3890 return List__MUIM_TestPos(cl, obj, (APTR) msg);
3891 case MUIM_DragQuery:
3892 return List__MUIM_DragQuery(cl, obj, (APTR) msg);
3893 case MUIM_DragFinish:
3894 return List__MUIM_DragFinish(cl, obj, (APTR) msg);
3895 case MUIM_DragReport:
3896 return List__MUIM_DragReport(cl, obj, (APTR) msg);
3897 case MUIM_DragDrop:
3898 return List__MUIM_DragDrop(cl, obj, (APTR) msg);
3899 case MUIM_CreateDragImage:
3900 return List__MUIM_CreateDragImage(cl, obj, (APTR) msg);
3903 return DoSuperMethodA(cl, obj, msg);
3905 BOOPSI_DISPATCHER_END
3908 * Class descriptor.
3910 const struct __MUIBuiltinClass _MUI_List_desc =
3912 MUIC_List,
3913 MUIC_Group,
3914 sizeof(struct MUI_ListData),
3915 (void *) List_Dispatcher