Ensure notification occurs when MUIA_List_Active changes as a result of
[AROS.git] / workbench / libs / muimaster / classes / list.c
blobeb891b1623a72fd63ba140e377b12cbbf07ce464
1 /*
2 Copyright © 2002-2015, 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 *widths; /* Widths of the columns */
58 LONG width; /* Line width */
59 LONG height; /* Line height */
60 WORD flags; /* see below */
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; /* the strings for the display function, one
134 * more than needed (for the entry position) */
136 /* Titlestuff */
137 int title_height; /* The complete height of the title */
138 STRPTR title; /* On single column lists this is the title,
139 * otherwise 1. NULL for no title(s) */
141 /* Cursor images */
142 struct MUI_ImageSpec_intern *list_cursor;
143 struct MUI_ImageSpec_intern *list_select;
144 struct MUI_ImageSpec_intern *list_selcur;
146 /* Render optimization */
147 int update; /* 1 - update everything, 2 - redraw entry at update_pos,
148 * 3 - scroll to current entries_first (old value is in
149 * update_pos) */
150 int update_pos;
152 LONG drop_mark_y;
154 /* list images */
155 struct MinList images;
157 /* user prefs */
158 ListviewRefresh prefs_refresh;
159 UWORD prefs_linespacing;
160 BOOL prefs_smoothed;
161 UWORD prefs_smoothval;
163 /* render space handling */
164 Object *area;
165 BOOL area_replaced;
166 BOOL area_connected;
168 /***************************/
169 /* Former Listview members */
170 /***************************/
172 Object *vert;
173 BOOL vert_connected;
174 IPTR scroller_pos;
175 BOOL read_only;
176 IPTR multiselect;
178 /* clicked column */
179 LONG click_column;
180 LONG def_click_column;
182 LONG mouse_click; /* see below if mouse is held down */
184 /* double click */
185 ULONG last_secs;
186 ULONG last_mics;
187 ULONG last_active;
189 struct MUI_EventHandlerNode ehn;
191 /* user prefs */
192 ListviewMulti prefs_multi;
194 BOOL select_change;
195 BOOL doubleclick;
197 struct Hook hook;
200 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
201 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
203 #define LIST_ADJUSTWIDTH (1<<0)
204 #define LIST_ADJUSTHEIGHT (1<<1)
205 #define LIST_AUTOVISIBLE (1<<2)
206 #define LIST_DRAGSORTABLE (1<<3)
207 #define LIST_SHOWDROPMARKS (1<<4)
208 #define LIST_QUIET (1<<5)
211 /****** List.mui/MUIA_List_Active ********************************************
213 * NAME
214 * MUIA_List_Active -- (V4) [ISG], LONG
216 * FUNCTION
217 * The index of the active entry. There can be at most one active entry
218 * in a list. The active entry is highlighted visibly, except for
219 * read-only lists (those whose Listview has MUIA_Listview_Input set to
220 * FALSE). Selecting an entry with the mouse, or moving through the list
221 * with keyboard controls will also change the active entry (again
222 * excepting read-only lists).
224 * When set programmatically through this attribute, some special values
225 * can be used:
227 * MUIV_List_Active_Off
228 * MUIV_List_Active_Top
229 * MUIV_List_Active_Bottom
230 * MUIV_List_Active_Up
231 * MUIV_List_Active_Down
232 * MUIV_List_Active_PageUp
233 * MUIV_List_Active_PageDown
235 * When this attribute is read, either the index of the active entry or
236 * the special value MUIV_List_Active_Off will be returned.
238 * Setting this attribute to a new value will additionally have the same
239 * effect as calling the MUIM_List_Jump method with the specified or
240 * implied index.
242 * NOTES
243 * The concept of an active entry must not be confused with that of a
244 * selected entry.
246 * SEE ALSO
247 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
249 ******************************************************************************
253 /****** List.mui/MUIA_List_CompareHook ***************************************
255 * NAME
256 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
258 * FUNCTION
259 * The provided hook indicates the sort ordering of two list entries.
260 * The hook receives list-entry data pointers as its second and third
261 * arguments. The hook should return a negative value if the first entry
262 * should be placed before the second entry, a positive value if the
263 * first entry should be placed after the second entry, and zero if the
264 * entries are equal.
266 * In addition to being used internally for sorting operations, this hook
267 * will be called when MUIM_List_Compare is externally invoked.
269 * If this attribute is not specified or is set to NULL, all list entries
270 * must be strings.
272 ******************************************************************************
276 /****** List.mui/MUIA_List_First *********************************************
278 * NAME
279 * MUIA_List_First -- (V4) [..G], LONG
281 * FUNCTION
282 * The index of the first entry that can be seen (assuming nothing
283 * obscures the list) This value of this attribute is -1 when the
284 * list's window is not open.
286 * NOTES
287 * Notification does not occur on this attribute in MUI.
289 * SEE ALSO
290 * MUIA_List_First, MUIA_List_Entries
292 ******************************************************************************
296 /****** List.mui/MUIA_List_MultiTestHook *************************************
298 * NAME
299 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
301 * FUNCTION
302 * The provided hook indicates whether a particular list entry
303 * may be multiselected. The hook receives the list-entry data pointer as
304 * its third argument, and returns a Boolean value. If this attribute is
305 * not specified or is set to NULL, all list entries are considered
306 * multi-selectable.
308 * Whenever an entry is about to be selected, this hook is called if
309 * there are other entries already selected. If the hook returns TRUE,
310 * the entry may be multi-selected; if the hook returns FALSE, the entry
311 * remains unselected.
313 * Additionally, if a non-multi-selectable entry has been selected (as
314 * the only selected entry in the list), any attempt to select an
315 * additional entry will fail.
317 ******************************************************************************
321 /****** List.mui/MUIA_List_Title *********************************************
323 * NAME
324 * MUIA_List_Title -- (V6) [ISG], char *
326 * FUNCTION
327 * A heading for the list, placed above list entries. A value of NULL
328 * means no title is used. A value of TRUE means that the custom
329 * display hook provides a separate title for each column; the hook
330 * must then provide column titles instead of normal column data when
331 * the entry pointer provided is NULL.
333 * NOTES
334 * If a string is set for this attribute, it is not cached within the
335 * object.
337 * SEE ALSO
338 * MUIA_List_DisplayHook
340 ******************************************************************************
344 /****** List.mui/MUIA_List_Visible *******************************************
346 * NAME
347 * MUIA_List_Visible -- (V4) [..G], LONG
349 * FUNCTION
350 * The number of entries that can be seen at once with the list's
351 * current dimensions. This value of this attribute is -1 when the
352 * list's window is not open.
354 * NOTES
355 * Notification does not occur on this attribute in MUI.
357 * SEE ALSO
358 * MUIA_List_First, MUIA_List_Entries
360 ******************************************************************************
364 /**************************************************************************
365 Allocate a single list entry, does not initialize it (except the pointer)
366 **************************************************************************/
367 static struct ListEntry *AllocListEntry(struct MUI_ListData *data)
369 ULONG *mem;
370 struct ListEntry *le;
371 int size = sizeof(struct ListEntry) + sizeof(LONG) * data->columns + 4;
372 /* sizeinfo */
373 LONG j;
375 mem = AllocPooled(data->pool, size);
376 if (!mem)
377 return NULL;
378 D(bug("List AllocListEntry %p, %ld bytes\n", mem, size));
380 mem[0] = size; /* Save the size */
381 le = (struct ListEntry *)(mem + 1);
382 le->widths = (LONG *) (le + 1);
384 /* Initialize fields */
385 le->height = 0;
386 le->width = 0;
387 le->flags = 0;
388 for (j = 0; j < data->columns; j++)
389 le->widths[j] = 0;
391 return le;
394 /**************************************************************************
395 Deallocate a single list entry, does not deinitialize it
396 **************************************************************************/
397 static void FreeListEntry(struct MUI_ListData *data,
398 struct ListEntry *entry)
400 ULONG *mem = ((ULONG *) entry) - 1;
401 D(bug("FreeListEntry %p size=%ld\n", mem, mem[0]));
402 FreePooled(data->pool, mem, mem[0]);
405 /**************************************************************************
406 Ensures that there can be at least the given amount of entries within
407 the list. Returns 0 if not. It also allocates the space for the title.
408 It can be accessed with data->entries[ENTRY_TITLE]
409 **************************************************************************/
410 static int SetListSize(struct MUI_ListData *data, LONG size)
412 struct ListEntry **new_entries;
413 int new_entries_allocated;
415 if (size + 1 <= data->entries_allocated)
416 return 1;
418 new_entries_allocated = data->entries_allocated * 2 + 4;
419 if (new_entries_allocated < size + 1)
420 new_entries_allocated = size + 1 + 10; /* 10 is just random */
422 D(bug("List %p : SetListSize allocating %ld bytes\n", data,
423 new_entries_allocated * sizeof(struct ListEntry *)));
424 new_entries =
425 AllocVec(new_entries_allocated * sizeof(struct ListEntry *), 0);
426 if (NULL == new_entries)
427 return 0;
428 if (data->entries)
430 CopyMem(data->entries - 1, new_entries,
431 (data->entries_num + 1) * sizeof(struct ListEntry *));
432 FreeVec(data->entries - 1);
434 data->entries = new_entries + 1;
435 data->entries_allocated = new_entries_allocated;
436 return 1;
439 /**************************************************************************
440 Prepares the insertion of count entries at pos.
441 This function doesn't care if there is enough space in the datastructure.
442 SetListSize() must be used first.
443 With current implementation, this call will never fail
444 **************************************************************************/
445 static int PrepareInsertListEntries(struct MUI_ListData *data, int pos,
446 int count)
448 memmove(&data->entries[pos + count], &data->entries[pos],
449 (data->entries_num - pos) * sizeof(struct ListEntry *));
450 return 1;
453 /**************************************************************************
454 Removes count (already deinitalized) list entries starting az pos.
455 **************************************************************************/
456 static void RemoveListEntries(struct MUI_ListData *data, int pos, int count)
458 // FIXME: segfault if entries_num = pos = count = 1
459 memmove(&data->entries[pos], &data->entries[pos + count],
460 (data->entries_num - (pos + count)) * sizeof(struct ListEntry *));
463 /**************************************************************************
464 Frees all memory allocated by ParseListFormat()
465 **************************************************************************/
466 static void FreeListFormat(struct MUI_ListData *data)
468 int i;
470 if (data->ci)
472 for (i = 0; i < data->columns; i++)
474 FreeVec(data->ci[i].preparse);
475 data->ci[i].preparse = NULL;
477 FreeVec(data->ci);
478 data->ci = NULL;
480 FreeVec(data->preparses);
481 data->preparses = NULL;
482 if (data->strings)
484 FreeVec(data->strings - 1);
485 data->strings = NULL;
487 data->columns = 0;
490 /**************************************************************************
491 Parses the given format string (also frees a previously parsed format).
492 Return 0 on failure.
493 **************************************************************************/
494 static int ParseListFormat(struct MUI_ListData *data, STRPTR format)
496 int new_columns, i;
497 STRPTR ptr;
498 STRPTR format_sep;
499 char c;
501 IPTR args[ARG_CNT];
502 struct RDArgs *rdargs;
504 if (!format)
505 format = (STRPTR) "";
507 ptr = format;
509 FreeListFormat(data);
511 new_columns = 1;
513 /* Count the number of columns first */
514 while ((c = *ptr++))
515 if (c == ',')
516 new_columns++;
518 if (!(data->preparses =
519 AllocVec((new_columns + 10) * sizeof(STRPTR), 0)))
520 return 0;
522 if (!(data->strings = AllocVec((new_columns + 1 + 10)
523 * sizeof(STRPTR), 0))) /* hold enough space also for the entry pos,
524 * used by orginal MUI and also some
525 * security space */
526 return 0;
528 if (!(data->ci = AllocVec(new_columns * sizeof(struct ColumnInfo), 0)))
529 return 0;
531 // set defaults
532 for (i = 0; i < new_columns; i++)
534 data->ci[i].colno = -1; // -1 means: use unassigned column
535 data->ci[i].weight = 100;
536 data->ci[i].delta = 4;
537 data->ci[i].min_width = -1;
538 data->ci[i].max_width = -1;
539 data->ci[i].user_width = -1;
540 data->ci[i].bar = FALSE;
541 data->ci[i].preparse = NULL;
544 if ((format_sep = StrDup(format)) != 0)
546 for (i = 0; format_sep[i] != '\0'; i++)
548 if (format_sep[i] == ',')
549 format_sep[i] = '\0';
552 if ((rdargs = AllocDosObject(DOS_RDARGS, NULL)) != 0)
554 ptr = format_sep;
555 i = 0;
558 rdargs->RDA_Source.CS_Buffer = ptr;
559 rdargs->RDA_Source.CS_Length = strlen(ptr);
560 rdargs->RDA_Source.CS_CurChr = 0;
561 rdargs->RDA_DAList = 0;
562 rdargs->RDA_Buffer = NULL;
563 rdargs->RDA_BufSiz = 0;
564 rdargs->RDA_ExtHelp = NULL;
565 rdargs->RDA_Flags = 0;
567 memset(args, 0, sizeof args);
568 if (ReadArgs(FORMAT_TEMPLATE, args, rdargs))
570 if (args[ARG_COL])
571 data->ci[i].colno = *(LONG *) args[ARG_COL];
572 if (args[ARG_WEIGHT])
573 data->ci[i].weight = *(LONG *) args[ARG_WEIGHT];
574 if (args[ARG_DELTA])
575 data->ci[i].delta = *(LONG *) args[ARG_DELTA];
576 if (args[ARG_MINWIDTH])
577 data->ci[i].min_width =
578 *(LONG *) args[ARG_MINWIDTH];
579 if (args[ARG_MAXWIDTH])
580 data->ci[i].max_width =
581 *(LONG *) args[ARG_MAXWIDTH];
582 data->ci[i].bar = args[ARG_BAR];
583 if (args[ARG_PREPARSE])
584 data->ci[i].preparse =
585 StrDup((STRPTR) args[ARG_PREPARSE]);
587 FreeArgs(rdargs);
589 ptr += strlen(ptr) + 1;
590 i++;
592 while (i < new_columns);
593 FreeDosObject(DOS_RDARGS, rdargs);
595 FreeVec(format_sep);
598 for (i = 0; i < new_columns; i++)
600 D(bug("colno %d weight %d delta %d preparse %s\n",
601 data->ci[i].colno, data->ci[i].weight, data->ci[i].delta,
602 data->ci[i].preparse));
605 data->columns = new_columns;
606 data->strings++; /* Skip entry pos */
608 return 1;
611 /**************************************************************************
612 Call the MUIM_List_Display for the given entry. It fills out
613 data->string and data->preparses
614 **************************************************************************/
615 static void DisplayEntry(struct IClass *cl, Object *obj, int entry_pos)
617 struct MUI_ListData *data = INST_DATA(cl, obj);
618 APTR entry_data;
619 int col;
621 for (col = 0; col < data->columns; col++)
622 data->preparses[col] = data->ci[col].preparse;
624 if (entry_pos == ENTRY_TITLE)
626 if ((data->columns == 1) && (data->title != (STRPTR) 1))
628 *data->strings = data->title;
629 return;
631 entry_data = NULL; /* it's a title request */
633 else
634 entry_data = data->entries[entry_pos]->data;
636 /* Get the display formation */
637 DoMethod(obj, MUIM_List_Display, (IPTR) entry_data,
638 (IPTR) data->strings, entry_pos, (IPTR) data->preparses);
641 /**************************************************************************
642 Determine the dims of a single entry and adapt the columninfo according
643 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
644 be redrawn after this operation, 1 if all entries need to be redrawn.
645 **************************************************************************/
646 static int CalcDimsOfEntry(struct IClass *cl, Object *obj, int pos)
648 struct MUI_ListData *data = INST_DATA(cl, obj);
649 struct ListEntry *entry = data->entries[pos];
650 int j;
651 int ret = 0;
653 if (!entry)
654 return ret;
656 if (!(_flags(obj) & MADF_SETUP))
657 return ret;
659 DisplayEntry(cl, obj, pos);
661 /* Set height to at least minheight */
662 if (data->entries[pos]->height < data->entry_minheight)
663 data->entries[pos]->height = data->entry_minheight;
665 for (j = 0; j < data->columns; j++)
667 ZText *text =
668 zune_text_new(data->preparses[j], data->strings[j],
669 ZTEXT_ARG_NONE, 0);
670 if (text != NULL)
672 zune_text_get_bounds(text, obj);
674 if (text->height > data->entries[pos]->height)
676 data->entries[pos]->height = text->height;
677 /* entry height changed, redraw all entries later */
678 ret = 1;
680 data->entries[pos]->widths[j] = text->width;
682 if (text->width > data->ci[j].entries_width)
684 /* This columns width is bigger than the other in the same
685 * columns, so we store this value
687 data->ci[j].entries_width = text->width;
688 /* column width changed, redraw all entries later */
689 ret = 1;
692 zune_text_destroy(text);
695 if (data->entries[pos]->height > data->entry_maxheight)
697 data->entry_maxheight = data->entries[pos]->height;
698 /* maximum entry height changed, redraw all entries later */
699 ret = 1;
702 return ret;
705 /**************************************************************************
706 Determine the widths of the entries
707 **************************************************************************/
708 static void CalcWidths(struct IClass *cl, Object *obj)
710 int i, j;
711 struct MUI_ListData *data = INST_DATA(cl, obj);
713 if (!(_flags(obj) & MADF_SETUP))
714 return;
716 for (j = 0; j < data->columns; j++)
717 data->ci[j].entries_width = 0;
719 data->entry_maxheight = 0;
720 data->entries_totalheight = 0;
721 data->entries_maxwidth = 0;
723 for (i = (data->title ? ENTRY_TITLE : 0); i < data->entries_num; i++)
725 CalcDimsOfEntry(cl, obj, i);
726 data->entries_totalheight += data->entries[i]->height;
729 for (j = 0; j < data->columns; j++)
730 data->entries_maxwidth += data->ci[j].entries_width;
732 if (!data->entry_maxheight)
733 data->entry_maxheight = 1;
736 /**************************************************************************
737 Calculates the number of visible entry lines. Returns 1 if it has
738 changed
739 **************************************************************************/
740 static int CalcVertVisible(struct IClass *cl, Object *obj)
742 struct MUI_ListData *data = INST_DATA(cl, obj);
743 int old_entries_visible = data->entries_visible;
744 int old_entries_top_pixel = data->entries_top_pixel;
746 data->vertprop_visible = data->entries_visible =
747 (_mheight(data->area) - data->title_height)
748 / (data->entry_maxheight /* + data->prefs_linespacing */ );
750 /* Distribute extra vertical space evenly between top and bottom of
751 * list */
753 data->entries_top_pixel = _mtop(data->area) + data->title_height
754 + (_mheight(data->area) - data->title_height
756 data->entries_visible *
757 (data->entry_maxheight /* + data->prefs_linespacing */ )) / 2;
759 if (data->entries_visible != old_entries_visible)
761 superset(cl, obj, MUIA_List_Visible, data->entries_visible);
762 superset(cl, obj, MUIA_List_VertProp_Visible, data->entries_visible);
765 return (old_entries_visible != data->entries_visible)
766 || (old_entries_top_pixel != data->entries_top_pixel);
769 /**************************************************************************
770 Default hook to compare two list entries. Works for strings only.
771 **************************************************************************/
772 AROS_UFH3S(int, default_compare_func,
773 AROS_UFHA(struct Hook *, h, A0),
774 AROS_UFHA(char *, s2, A2),
775 AROS_UFHA(char *, s1, A1))
777 AROS_USERFUNC_INIT
779 return Stricmp(s1, s2);
781 AROS_USERFUNC_EXIT
784 #define PROP_VERT_FIRST 1
786 static ULONG List_Function(struct Hook *hook, Object * obj, void **msg)
788 struct MUI_ListData *data = (struct MUI_ListData *)hook->h_Data;
789 SIPTR type = (SIPTR) msg[0];
790 SIPTR val = (SIPTR) msg[1];
792 switch (type)
794 case PROP_VERT_FIRST:
795 get(data->vert, MUIA_Prop_First, &val);
796 nnset(obj, MUIA_List_VertProp_First, val);
797 break;
799 return 0;
802 /* At entry to this function, data->area is always set, but data->vert may
803 * or may not be set */
804 static void List_HandleScrollerPos(struct IClass *cl, Object *obj)
806 struct MUI_ListData *data = INST_DATA(cl, obj);
807 BOOL vert_not_used = FALSE;
809 /* Disallow any changes after setup. This function should basically be
810 * creation-time only */
811 if (_flags(obj) & MADF_SETUP)
812 return;
814 /* Remove both objects */
815 if (data->area_connected)
816 DoMethod(obj, OM_REMMEMBER, data->area);
817 if (data->vert_connected)
818 DoMethod(obj, OM_REMMEMBER, data->vert);
820 /* Add list and/or scroller */
821 switch (data->scroller_pos)
823 case MUIV_Listview_ScrollerPos_None:
824 vert_not_used = TRUE;
825 DoMethod(obj, OM_ADDMEMBER, data->area);
826 break;
827 case MUIV_Listview_ScrollerPos_Left:
828 if (!data->vert)
829 data->vert =ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
830 DoMethod(obj, OM_ADDMEMBER, data->vert);
831 DoMethod(obj, OM_ADDMEMBER, data->area);
832 break;
833 default:
834 if (!data->vert)
835 data->vert = ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
836 DoMethod(obj, OM_ADDMEMBER, data->area);
837 DoMethod(obj, OM_ADDMEMBER, data->vert);
838 break;
841 data->area_connected = TRUE;
843 /* Handle case where it was decided that vert will not be used */
844 if (vert_not_used)
846 if (data->vert)
848 if (data->vert_connected)
850 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_First,
851 (IPTR) data->vert);
852 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_Visible,
853 (IPTR) data->vert);
854 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_Entries,
855 (IPTR) data->vert);
856 data->vert_connected = FALSE;
859 MUI_DisposeObject(data->vert);
860 data->vert = NULL;
864 /* If at this point data->vert is not null, it means vert is to be
865 * connected */
866 if (data->vert && !data->vert_connected)
868 LONG entries = 0, first = 0, visible = 0;
870 get(obj, MUIA_List_VertProp_First, &first);
871 get(obj, MUIA_List_VertProp_Visible, &visible);
872 get(obj, MUIA_List_VertProp_Entries, &entries);
874 SetAttrs(data->vert, MUIA_Prop_First, first,
875 MUIA_Prop_Visible, visible, MUIA_Prop_Entries, entries, TAG_DONE);
877 DoMethod(data->vert, MUIM_Notify, MUIA_Prop_First, MUIV_EveryTime,
878 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook, PROP_VERT_FIRST,
879 MUIV_TriggerValue);
881 /* Pass prop object as DestObj (based on code in NList) */
882 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_First, MUIV_EveryTime,
883 (IPTR) data->vert, 3, MUIM_NoNotifySet,
884 MUIA_Prop_First, MUIV_TriggerValue);
885 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_Visible, MUIV_EveryTime,
886 (IPTR) data->vert, 3, MUIM_NoNotifySet,
887 MUIA_Prop_Visible, MUIV_TriggerValue);
888 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_Entries, MUIV_EveryTime,
889 (IPTR) data->vert, 3, MUIM_NoNotifySet,
890 MUIA_Prop_Entries, MUIV_TriggerValue);
892 data->vert_connected = TRUE;
896 /**************************************************************************
897 OM_NEW
898 **************************************************************************/
899 IPTR List__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
901 struct MUI_ListData *data;
902 struct TagItem *tag;
903 struct TagItem *tags;
904 APTR *array = NULL;
905 LONG new_entries_active = MUIV_List_Active_Off;
906 struct TagItem rectattrs[2] =
907 {{TAG_IGNORE, TAG_IGNORE }, {TAG_DONE, TAG_DONE}};
908 Object *area;
910 /* search for MUIA_Frame as it has to be passed to rectangle object */
911 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
913 if (tag->ti_Tag == MUIA_Frame)
915 rectattrs[0].ti_Tag = MUIA_Frame;
916 rectattrs[0].ti_Data = tag->ti_Data;
917 tag->ti_Tag = TAG_IGNORE;
918 break;
922 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
923 MUIA_Group_Horiz, TRUE,
924 MUIA_InnerLeft, 0,
925 MUIA_InnerRight, 0,
926 MUIA_Group_Spacing, 0,
927 MUIA_Font, MUIV_Font_List,
928 MUIA_ShowSelState, FALSE,
929 MUIA_InputMode, MUIV_InputMode_RelVerify,
930 MUIA_Background, MUII_ListBack,
931 TAG_MORE, (IPTR) msg->ops_AttrList,
932 TAG_DONE);
934 if (!obj)
935 return FALSE;
937 data = INST_DATA(cl, obj);
939 data->columns = 1;
940 data->entries_active = MUIV_List_Active_Off;
941 data->intern_puddle_size = 2008;
942 data->intern_thresh_size = 1024;
943 data->default_compare_hook.h_Entry = (HOOKFUNC) default_compare_func;
944 data->default_compare_hook.h_SubEntry = 0;
945 data->compare_hook = &(data->default_compare_hook);
946 data->flags = LIST_SHOWDROPMARKS;
947 data->area_replaced = FALSE;
948 data->area_connected = FALSE;
949 data->vert_connected = FALSE;
951 data->entries_visible = data->vertprop_visible = -1;
952 data->last_active = -1;
954 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
955 data->ehn.ehn_Priority = 0;
956 data->ehn.ehn_Flags = 0;
957 data->ehn.ehn_Object = obj;
958 data->ehn.ehn_Class = cl;
960 /* HACK:
961 * List is a group where part of area is rendered and part is filled
962 * with other objects (inside of List dimensions). One such object is
963 * up/down arrow. This object depends on RelVerify mode to control
964 * behaviour. List also has the RelVerify mode. Area super class in case
965 * of both of those objects adds an event handler node with the same
966 * priority. Depending on the sort order, the event handler node of
967 * "list" can eat a click event and up/down arrows stop working. The
968 * hack is to decrease the priority of Area event handler for list to
969 * always favor up/down arrow. There are other hacky ways of solving
970 * this, but this seems least evil approach, as this hack is
971 * encapsulated in the List class itself.
973 muiAreaData(obj)->mad_ehn.ehn_Priority--;
975 data->hook.h_Entry = HookEntry;
976 data->hook.h_SubEntry = (HOOKFUNC) List_Function;
977 data->hook.h_Data = data;
979 area = (Object *)GetTagData(MUIA_List_ListArea, (IPTR) 0,
980 msg->ops_AttrList);
982 if (!area)
983 area = RectangleObject, MUIA_FillArea, FALSE, TAG_MORE,
984 (IPTR) rectattrs, End;
985 else
986 data->area_replaced = TRUE;
987 data->area = area;
989 /* parse initial taglist */
990 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
992 switch (tag->ti_Tag)
994 case MUIA_List_Active:
995 new_entries_active = tag->ti_Data;
996 break;
998 case MUIA_List_Pool:
999 data->pool = (APTR) tag->ti_Data;
1000 break;
1002 case MUIA_List_PoolPuddleSize:
1003 data->intern_puddle_size = tag->ti_Data;
1004 break;
1006 case MUIA_List_PoolThreshSize:
1007 data->intern_thresh_size = tag->ti_Data;
1008 break;
1010 case MUIA_List_CompareHook:
1011 data->compare_hook = (struct Hook *)tag->ti_Data;
1012 if (data->compare_hook == NULL)
1013 data->compare_hook = &data->default_compare_hook;
1014 break;
1016 case MUIA_List_ConstructHook:
1017 data->construct_hook = (struct Hook *)tag->ti_Data;
1018 break;
1020 case MUIA_List_DestructHook:
1021 data->destruct_hook = (struct Hook *)tag->ti_Data;
1022 break;
1024 case MUIA_List_DisplayHook:
1025 data->display_hook = (struct Hook *)tag->ti_Data;
1026 break;
1028 case MUIA_List_MultiTestHook:
1029 data->multi_test_hook = (struct Hook *)tag->ti_Data;
1030 break;
1032 case MUIA_List_SourceArray:
1033 array = (APTR *) tag->ti_Data;
1034 break;
1036 case MUIA_List_Format:
1037 data->format = StrDup((STRPTR) tag->ti_Data);
1038 break;
1040 case MUIA_List_Title:
1041 data->title = (STRPTR) tag->ti_Data;
1042 break;
1044 case MUIA_List_MinLineHeight:
1045 data->entry_minheight = tag->ti_Data;
1046 break;
1048 case MUIA_List_AdjustHeight:
1049 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTHEIGHT);
1050 break;
1052 case MUIA_List_AdjustWidth:
1053 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTWIDTH);
1054 break;
1056 case MUIA_List_AutoVisible:
1057 _handle_bool_tag(data->flags, tag->ti_Data, LIST_AUTOVISIBLE);
1058 break;
1060 case MUIA_List_ShowDropMarks:
1061 _handle_bool_tag(data->flags, tag->ti_Data, LIST_SHOWDROPMARKS);
1062 break;
1064 case MUIA_List_DragSortable:
1065 _handle_bool_tag(data->flags, tag->ti_Data, LIST_DRAGSORTABLE);
1066 set(obj, MUIA_Draggable, tag->ti_Data);
1067 break;
1069 case MUIA_Listview_ScrollerPos:
1070 data->scroller_pos = tag->ti_Data;
1071 break;
1073 case MUIA_Listview_Input:
1074 data->read_only = !tag->ti_Data;
1075 break;
1077 case MUIA_Listview_MultiSelect:
1078 data->multiselect = tag->ti_Data;
1079 break;
1081 case MUIA_Listview_DoubleClick:
1082 data->doubleclick = tag->ti_Data != 0;
1083 break;
1085 case MUIA_Listview_DefClickColumn:
1086 data->def_click_column = tag->ti_Data;
1087 break;
1091 List_HandleScrollerPos(cl, obj);
1093 if (!data->pool)
1095 /* No memory pool given, so we create our own */
1096 data->pool = data->intern_pool =
1097 CreatePool(0, data->intern_puddle_size,
1098 data->intern_thresh_size);
1099 if (!data->pool)
1101 CoerceMethod(cl, obj, OM_DISPOSE);
1102 return 0;
1106 /* parse the list format */
1107 if (!(ParseListFormat(data, data->format)))
1109 CoerceMethod(cl, obj, OM_DISPOSE);
1110 return 0;
1113 /* This is neccessary for at least the title */
1114 if (!SetListSize(data, 0))
1116 CoerceMethod(cl, obj, OM_DISPOSE);
1117 return 0;
1120 if (!(data->entries[ENTRY_TITLE] = AllocListEntry(data)))
1122 CoerceMethod(cl, obj, OM_DISPOSE);
1123 return 0;
1126 if (array)
1128 int i;
1129 /* Count the number of elements */
1130 for (i = 0; array[i] != NULL; i++)
1132 /* Insert them */
1133 DoMethod(obj, MUIM_List_Insert, (IPTR) array, i,
1134 MUIV_List_Insert_Top);
1137 if ((data->entries_num) && (new_entries_active != MUIV_List_Active_Off))
1139 switch (new_entries_active)
1141 case MUIV_List_Active_Top:
1142 new_entries_active = 0;
1143 break;
1145 case MUIV_List_Active_Bottom:
1146 new_entries_active = data->entries_num - 1;
1147 break;
1150 if (new_entries_active < 0)
1151 new_entries_active = 0;
1152 else if (new_entries_active >= data->entries_num)
1153 new_entries_active = data->entries_num - 1;
1155 data->entries_active = new_entries_active;
1156 /* Selected entry will be moved into visible area */
1159 NewList((struct List *)&data->images);
1161 D(bug("List_New(%lx)\n", obj));
1163 return (IPTR) obj;
1166 /**************************************************************************
1167 OM_DISPOSE
1168 **************************************************************************/
1169 IPTR List__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
1171 struct MUI_ListData *data = INST_DATA(cl, obj);
1173 D(bug("List Dispose\n"));
1175 /* Call destruct method for every entry and free the entries manually
1176 * to avoid notification */
1177 while (data->confirm_entries_num)
1179 struct ListEntry *lentry =
1180 data->entries[--data->confirm_entries_num];
1181 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1182 (IPTR) data->pool);
1183 FreeListEntry(data, lentry);
1186 if (data->intern_pool)
1187 DeletePool(data->intern_pool);
1188 if (data->entries)
1189 FreeVec(data->entries - 1);
1190 /* title is currently before all other elements */
1192 FreeListFormat(data);
1193 FreeVec(data->format);
1195 return DoSuperMethodA(cl, obj, msg);
1199 /**************************************************************************
1200 OM_SET
1201 **************************************************************************/
1202 IPTR List__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
1204 struct MUI_ListData *data = INST_DATA(cl, obj);
1205 struct TagItem *tag;
1206 struct TagItem *tags;
1208 /* parse taglist */
1209 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
1211 switch (tag->ti_Tag)
1213 case MUIA_List_CompareHook:
1214 data->compare_hook = (struct Hook *)tag->ti_Data;
1215 if (data->compare_hook == NULL)
1216 data->compare_hook = &data->default_compare_hook;
1217 break;
1219 case MUIA_List_ConstructHook:
1220 data->construct_hook = (struct Hook *)tag->ti_Data;
1221 break;
1223 case MUIA_List_DestructHook:
1224 data->destruct_hook = (struct Hook *)tag->ti_Data;
1225 break;
1227 case MUIA_List_DisplayHook:
1228 data->display_hook = (struct Hook *)tag->ti_Data;
1229 break;
1231 case MUIA_List_MultiTestHook:
1232 data->multi_test_hook = (struct Hook *)tag->ti_Data;
1233 if (data->multi_test_hook != NULL)
1235 /* Clearing current selections is the easiest way to keep
1236 * selections consistent with the new hook */
1237 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
1238 MUIV_List_Select_Off, NULL);
1240 break;
1242 case MUIA_List_Title:
1243 data->title = (STRPTR) tag->ti_Data;
1244 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1245 break;
1247 case MUIA_List_VertProp_First:
1248 data->vertprop_first = tag->ti_Data;
1249 if (data->entries_first != tag->ti_Data)
1251 set(obj, MUIA_List_First, tag->ti_Data);
1253 break;
1255 case MUIA_List_Format:
1256 data->format = StrDup((STRPTR) tag->ti_Data);
1257 ParseListFormat(data, data->format);
1258 // FIXME: should we check for errors?
1259 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1260 break;
1262 case MUIA_List_VertProp_Entries:
1263 data->vertprop_entries = tag->ti_Data;
1264 break;
1266 case MUIA_List_VertProp_Visible:
1267 data->vertprop_visible = tag->ti_Data;
1268 data->entries_visible = tag->ti_Data;
1269 break;
1271 case MUIA_List_Active:
1273 LONG new_entries_active = tag->ti_Data;
1275 if ((data->entries_num)
1276 && (new_entries_active != MUIV_List_Active_Off))
1278 switch (new_entries_active)
1280 case MUIV_List_Active_Top:
1281 new_entries_active = 0;
1282 break;
1284 case MUIV_List_Active_Bottom:
1285 new_entries_active = data->entries_num - 1;
1286 break;
1288 case MUIV_List_Active_Up:
1289 new_entries_active = data->entries_active - 1;
1290 break;
1292 case MUIV_List_Active_Down:
1293 new_entries_active = data->entries_active + 1;
1294 break;
1296 case MUIV_List_Active_PageUp:
1297 new_entries_active =
1298 data->entries_active - data->entries_visible;
1299 break;
1301 case MUIV_List_Active_PageDown:
1302 new_entries_active =
1303 data->entries_active + data->entries_visible;
1304 break;
1307 if (new_entries_active < 0)
1308 new_entries_active = 0;
1309 else if (new_entries_active >= data->entries_num)
1310 new_entries_active = data->entries_num - 1;
1312 else
1313 new_entries_active = -1;
1315 if (data->entries_active != new_entries_active)
1317 LONG old = data->entries_active;
1318 data->entries_active = new_entries_active;
1320 /* SelectChange stuff */
1321 if (new_entries_active != -1)
1323 DoMethod(obj, MUIM_List_SelectChange,
1324 new_entries_active, MUIV_List_Select_On, 0);
1325 DoMethod(obj, MUIM_List_SelectChange,
1326 new_entries_active, MUIV_List_Select_Active, 0);
1328 else
1329 DoMethod(obj, MUIM_List_SelectChange,
1330 MUIV_List_Active_Off, MUIV_List_Select_Off, 0);
1332 if (!data->read_only)
1334 data->update = 2;
1335 data->update_pos = old;
1336 MUI_Redraw(obj, MADF_DRAWUPDATE);
1337 data->update = 2;
1338 data->update_pos = data->entries_active;
1339 MUI_Redraw(obj, MADF_DRAWUPDATE);
1342 /* Make new active entry visible (if there is one and
1343 list is visible) */
1344 if (new_entries_active != -1
1345 && (_flags(obj) & MADF_SETUP))
1347 DoMethod(obj, MUIM_List_Jump,
1348 MUIV_List_Jump_Active);
1352 break;
1354 case MUIA_List_First:
1355 data->update_pos = data->entries_first;
1356 data->update = 3;
1357 data->entries_first = tag->ti_Data;
1359 MUI_Redraw(obj, MADF_DRAWUPDATE);
1360 if ((data->vertprop_first != tag->ti_Data)
1361 && (!(data->flags & LIST_QUIET)))
1363 set(obj, MUIA_List_VertProp_First, tag->ti_Data);
1365 break;
1367 case MUIA_List_Visible: /* Shouldn't be settable? */
1368 if (data->vertprop_visible != tag->ti_Data)
1369 set(obj, MUIA_List_VertProp_Visible, tag->ti_Data);
1370 break;
1372 case MUIA_List_Entries:
1373 if (data->confirm_entries_num == tag->ti_Data)
1375 data->entries_num = tag->ti_Data;
1376 if (!(data->flags & LIST_QUIET))
1378 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
1381 else
1383 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1385 break;
1387 case MUIA_List_Quiet:
1388 _handle_bool_tag(data->flags, tag->ti_Data, LIST_QUIET);
1389 if (!tag->ti_Data)
1391 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1392 if (data->entries_num != XGET(obj, MUIA_List_VertProp_Entries))
1393 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
1394 if (data->entries_first != XGET(obj, MUIA_List_VertProp_First))
1395 set(obj, MUIA_List_VertProp_First, data->entries_first);
1397 break;
1399 case MUIA_List_AutoVisible:
1400 _handle_bool_tag(data->flags, tag->ti_Data, LIST_AUTOVISIBLE);
1401 break;
1403 case MUIA_List_ShowDropMarks:
1404 _handle_bool_tag(data->flags, tag->ti_Data, LIST_SHOWDROPMARKS);
1405 break;
1407 case MUIA_List_DragSortable:
1408 _handle_bool_tag(data->flags, tag->ti_Data, LIST_DRAGSORTABLE);
1409 set(obj, MUIA_Draggable, tag->ti_Data);
1410 break;
1412 case MUIA_Selected:
1413 /* Swallow this so the Area class doesn't redraw us */
1414 tag->ti_Tag = TAG_IGNORE;
1415 break;
1417 case MUIA_Disabled:
1418 if (_flags(obj) & MADF_SETUP)
1420 /* Stop listening for events we only listen to when mouse
1421 button is down: we will not be informed of the button
1422 being released */
1423 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1424 (IPTR) &data->ehn);
1425 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
1426 | IDCMP_INACTIVEWINDOW);
1427 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1428 (IPTR) &data->ehn);
1430 break;
1432 case MUIA_Listview_DoubleClick: /* private set */
1433 data->doubleclick = tag->ti_Data != 0;
1434 break;
1436 case MUIA_Listview_SelectChange: /* private set */
1437 data->select_change = tag->ti_Data != 0;
1438 break;
1440 case MUIA_Listview_ScrollerPos: /* private set */
1441 data->scroller_pos = tag->ti_Data;
1442 List_HandleScrollerPos(cl, obj);
1443 break;
1445 case MUIA_Listview_Input: /* private set */
1446 data->read_only = !tag->ti_Data;
1447 break;
1449 case MUIA_Listview_MultiSelect: /* private set */
1450 data->multiselect = tag->ti_Data;
1451 break;
1453 case MUIA_Listview_DefClickColumn:
1454 data->def_click_column = tag->ti_Data;
1455 break;
1459 return DoSuperMethodA(cl, obj, (Msg) msg);
1462 /**************************************************************************
1463 OM_GET
1464 **************************************************************************/
1465 IPTR List__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
1467 /* small macro to simplify return value storage */
1468 #define STORE *(msg->opg_Storage)
1469 struct MUI_ListData *data = INST_DATA(cl, obj);
1471 switch (msg->opg_AttrID)
1473 case MUIA_List_Entries:
1474 STORE = data->entries_num;
1475 return 1;
1476 case MUIA_List_First:
1477 STORE = data->entries_first;
1478 return 1;
1479 case MUIA_List_Active:
1480 STORE = data->entries_active;
1481 return 1;
1482 case MUIA_List_InsertPosition:
1483 STORE = data->insert_position;
1484 return 1;
1485 case MUIA_List_Title:
1486 STORE = (IPTR) data->title;
1487 return 1;
1488 case MUIA_List_VertProp_Entries:
1489 STORE = data->vertprop_entries;
1490 return 1;
1491 case MUIA_List_VertProp_Visible:
1492 case MUIA_List_Visible:
1493 STORE = data->vertprop_visible;
1494 return 1;
1495 case MUIA_List_VertProp_First:
1496 STORE = data->vertprop_first;
1497 return 1;
1498 case MUIA_List_Format:
1499 STORE = (IPTR) data->format;
1500 return 1;
1501 case MUIA_List_AutoVisible:
1502 STORE = data->flags & LIST_AUTOVISIBLE;
1503 return 1;
1504 case MUIA_List_ShowDropMarks:
1505 STORE = data->flags & LIST_SHOWDROPMARKS;
1506 return 1;
1507 case MUIA_List_DragSortable:
1508 STORE = data->flags & LIST_DRAGSORTABLE;
1509 return 1;
1510 case MUIA_Listview_ClickColumn:
1511 STORE = data->click_column;
1512 return 1;
1513 case MUIA_Listview_DoubleClick:
1514 STORE = data->doubleclick;
1515 return 1;
1516 case MUIA_Listview_SelectChange:
1517 STORE = data->select_change;
1518 return 1;
1519 case MUIA_Listview_List:
1520 STORE = (IPTR)obj;
1521 return 1;
1522 case MUIA_Listview_DefClickColumn:
1523 STORE = data->def_click_column;
1524 return 1;
1527 if (DoSuperMethodA(cl, obj, (Msg) msg))
1528 return 1;
1529 return 0;
1530 #undef STORE
1533 /**************************************************************************
1534 MUIM_Setup
1535 **************************************************************************/
1536 IPTR List__MUIM_Setup(struct IClass *cl, Object *obj,
1537 struct MUIP_Setup *msg)
1539 struct MUI_ListData *data = INST_DATA(cl, obj);
1541 if (!DoSuperMethodA(cl, obj, (Msg) msg))
1542 return 0;
1544 data->prefs_refresh = muiGlobalInfo(obj)->mgi_Prefs->list_refresh;
1545 data->prefs_linespacing =
1546 muiGlobalInfo(obj)->mgi_Prefs->list_linespacing;
1547 data->prefs_smoothed = muiGlobalInfo(obj)->mgi_Prefs->list_smoothed;
1548 data->prefs_smoothval = muiGlobalInfo(obj)->mgi_Prefs->list_smoothval;
1550 CalcWidths(cl, obj);
1552 data->list_cursor =
1553 zune_imspec_setup(MUII_ListCursor, muiRenderInfo(obj));
1554 data->list_select =
1555 zune_imspec_setup(MUII_ListSelect, muiRenderInfo(obj));
1556 data->list_selcur =
1557 zune_imspec_setup(MUII_ListSelCur, muiRenderInfo(obj));
1559 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
1560 if (data->multiselect == MUIV_Listview_MultiSelect_Default)
1562 if (data->prefs_multi == LISTVIEW_MULTI_SHIFTED)
1563 data->multiselect = MUIV_Listview_MultiSelect_Shifted;
1564 else
1565 data->multiselect = MUIV_Listview_MultiSelect_Always;
1568 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) &data->ehn);
1570 return 1;
1573 /**************************************************************************
1574 MUIM_Cleanup
1575 **************************************************************************/
1576 IPTR List__MUIM_Cleanup(struct IClass *cl, Object *obj,
1577 struct MUIP_Cleanup *msg)
1579 struct MUI_ListData *data = INST_DATA(cl, obj);
1580 struct ListImage *li = List_First(&data->images);
1582 while (li)
1584 struct ListImage *next = Node_Next(li);
1585 DoMethod(obj, MUIM_List_DeleteImage, (IPTR) li);
1586 li = next;
1589 zune_imspec_cleanup(data->list_cursor);
1590 zune_imspec_cleanup(data->list_select);
1591 zune_imspec_cleanup(data->list_selcur);
1593 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) &data->ehn);
1594 data->mouse_click = 0;
1596 return DoSuperMethodA(cl, obj, (Msg) msg);
1599 /**************************************************************************
1600 MUIM_AskMinMax
1601 **************************************************************************/
1602 IPTR List__MUIM_AskMinMax(struct IClass *cl, Object *obj,
1603 struct MUIP_AskMinMax *msg)
1605 struct MUI_ListData *data = INST_DATA(cl, obj);
1607 DoSuperMethodA(cl, obj, (Msg) msg);
1610 if ((data->flags & LIST_ADJUSTWIDTH) && (data->entries_num > 0))
1612 msg->MinMaxInfo->MinWidth += data->entries_maxwidth;
1613 msg->MinMaxInfo->DefWidth += data->entries_maxwidth;
1614 msg->MinMaxInfo->MaxWidth += data->entries_maxwidth;
1616 else
1618 msg->MinMaxInfo->MinWidth += 40;
1619 msg->MinMaxInfo->DefWidth += 100;
1620 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1623 if (data->entries_num > 0)
1625 if (data->flags & LIST_ADJUSTHEIGHT)
1627 msg->MinMaxInfo->MinHeight += data->entries_totalheight;
1628 msg->MinMaxInfo->DefHeight += data->entries_totalheight;
1629 msg->MinMaxInfo->MaxHeight += data->entries_totalheight;
1631 else
1633 ULONG h = data->entry_maxheight + data->prefs_linespacing;
1634 msg->MinMaxInfo->MinHeight += 2 * h + data->prefs_linespacing;
1635 msg->MinMaxInfo->DefHeight += 8 * h + data->prefs_linespacing;
1636 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1639 else
1641 msg->MinMaxInfo->MinHeight += 36;
1642 msg->MinMaxInfo->DefHeight += 96;
1643 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1645 D(bug("List %p minheigh=%d, line maxh=%d\n",
1646 obj, msg->MinMaxInfo->MinHeight, data->entry_maxheight));
1647 return TRUE;
1650 /****i* List.mui/MUIM_Layout *************************************************
1652 * NAME
1653 * MUIM_Layout
1655 ******************************************************************************
1659 IPTR List__MUIM_Layout(struct IClass *cl, Object *obj,
1660 struct MUIP_Layout *msg)
1662 struct MUI_ListData *data = INST_DATA(cl, obj);
1663 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1664 LONG new_entries_first = data->entries_first;
1666 /* Calc the numbers of entries visible */
1667 CalcVertVisible(cl, obj);
1669 /* Ensure active entry is visible if requested */
1670 if (data->entries_active + 1 >=
1671 (data->entries_first + data->entries_visible)
1672 && (data->flags & LIST_AUTOVISIBLE) != 0)
1673 new_entries_first =
1674 data->entries_active - data->entries_visible + 1;
1676 /* Ensure there are no unnecessary empty lines */
1677 if ((new_entries_first + data->entries_visible >=
1678 data->entries_num)
1679 && (data->entries_visible <= data->entries_num))
1680 new_entries_first = data->entries_num - data->entries_visible;
1682 /* Always show the start of the list if it isn't long enough to fill the
1683 view */
1684 if (data->entries_num <= data->entries_visible)
1685 new_entries_first = 0;
1687 if (new_entries_first < 0)
1688 new_entries_first = 0;
1690 set(obj, new_entries_first != data->entries_first ?
1691 MUIA_List_First : TAG_IGNORE, new_entries_first);
1693 /* So the notify happens */
1694 set(obj, MUIA_List_VertProp_Visible, data->entries_visible);
1696 return rc;
1700 /**************************************************************************
1701 MUIM_Show
1702 **************************************************************************/
1703 IPTR List__MUIM_Show(struct IClass *cl, Object *obj,
1704 struct MUIP_Show *msg)
1706 struct MUI_ListData *data = INST_DATA(cl, obj);
1707 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1709 zune_imspec_show(data->list_cursor, obj);
1710 zune_imspec_show(data->list_select, obj);
1711 zune_imspec_show(data->list_selcur, obj);
1712 return rc;
1716 /**************************************************************************
1717 MUIM_Hide
1718 **************************************************************************/
1719 IPTR List__MUIM_Hide(struct IClass *cl, Object *obj,
1720 struct MUIP_Hide *msg)
1722 struct MUI_ListData *data = INST_DATA(cl, obj);
1724 zune_imspec_hide(data->list_cursor);
1725 zune_imspec_hide(data->list_select);
1726 zune_imspec_hide(data->list_selcur);
1728 return DoSuperMethodA(cl, obj, (Msg) msg);
1732 /**************************************************************************
1733 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1734 ENTRY_TITLE
1735 **************************************************************************/
1736 static VOID List_DrawEntry(struct IClass *cl, Object *obj, int entry_pos,
1737 int y)
1739 struct MUI_ListData *data = INST_DATA(cl, obj);
1740 int col, x1, x2;
1742 /* To be sure we don't draw anything if there is no title */
1743 if (entry_pos == ENTRY_TITLE && !data->title)
1744 return;
1746 DisplayEntry(cl, obj, entry_pos);
1747 x1 = _mleft(data->area);
1749 for (col = 0; col < data->columns; col++)
1751 ZText *text;
1752 x2 = x1 + data->ci[col].entries_width;
1754 if ((text =
1755 zune_text_new(data->preparses[col], data->strings[col],
1756 ZTEXT_ARG_NONE, 0)))
1758 /* Could be made simpler, as we don't really need the bounds */
1759 zune_text_get_bounds(text, obj);
1760 /* Note, this was MPEN_SHADOW before */
1761 SetAPen(_rp(obj), muiRenderInfo(obj)->mri_Pens[MPEN_TEXT]);
1762 zune_text_draw(text, obj, x1, x2, y); /* totally wrong! */
1763 zune_text_destroy(text);
1765 x1 = x2 + data->ci[col].delta + (data->ci[col].bar ? BAR_WIDTH : 0);
1769 /**************************************************************************
1770 MUIM_Draw
1771 **************************************************************************/
1772 IPTR List__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1774 struct MUI_ListData *data = INST_DATA(cl, obj);
1775 int entry_pos, y;
1776 APTR clip;
1777 int start, end;
1778 BOOL scroll_caused_damage = FALSE;
1779 struct MUI_ImageSpec_intern *highlight;
1780 IPTR ret = (IPTR)0;
1782 if (data->flags & LIST_QUIET)
1783 return 0;
1785 ret = DoSuperMethodA(cl, obj, (Msg) msg);
1787 if (data->area_replaced)
1788 return ret;
1790 /* Calculate the title height */
1791 if (data->title)
1793 data->title_height = data->entries[ENTRY_TITLE]->height + 2;
1795 else
1797 data->title_height = 0;
1800 /* Calc the numbers of entries visible */
1801 CalcVertVisible(cl, obj);
1803 if ((msg->flags & MADF_DRAWUPDATE) == 0 || data->update == 1)
1805 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
1806 _mtop(data->area), _mwidth(data->area), _mheight(data->area),
1807 0, data->entries_first * data->entry_maxheight, 0);
1810 clip = MUI_AddClipping(muiRenderInfo(obj), _mleft(data->area),
1811 _mtop(data->area), _mwidth(data->area), _mheight(data->area));
1813 if ((msg->flags & MADF_DRAWUPDATE) == 0 || data->update == 1)
1815 y = _mtop(data->area);
1816 /* Draw Title
1818 if (data->title_height && data->title)
1820 List_DrawEntry(cl, obj, ENTRY_TITLE, y);
1821 y += data->entries[ENTRY_TITLE]->height;
1822 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1823 Move(_rp(obj), _mleft(data->area), y);
1824 Draw(_rp(obj), _mright(data->area), y);
1825 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1826 y++;
1827 Move(_rp(obj), _mleft(data->area), y);
1828 Draw(_rp(obj), _mright(data->area), y);
1832 y = data->entries_top_pixel;
1834 start = data->entries_first;
1835 end = data->entries_first + data->entries_visible;
1837 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3)
1839 int diffy = data->entries_first - data->update_pos;
1840 int top, bottom;
1841 if (abs(diffy) < data->entries_visible)
1843 scroll_caused_damage =
1844 (_rp(obj)->Layer->Flags & LAYERREFRESH) ? FALSE : TRUE;
1846 ScrollRaster(_rp(obj), 0, diffy * data->entry_maxheight,
1847 _mleft(data->area), y,
1848 _mright(data->area),
1849 y + data->entry_maxheight * data->entries_visible);
1851 scroll_caused_damage =
1852 scroll_caused_damage
1853 && (_rp(obj)->Layer->Flags & LAYERREFRESH);
1855 if (diffy > 0)
1857 start = end - diffy;
1858 y += data->entry_maxheight * (data->entries_visible -
1859 diffy);
1861 else
1862 end = start - diffy;
1865 top = y;
1866 bottom = y + (end - start) * data->entry_maxheight;
1868 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area), top,
1869 _mwidth(data->area), bottom - top + 1, 0,
1870 top - _mtop(data->area) + data->entries_first
1871 * data->entry_maxheight, 0);
1874 for (entry_pos = start;
1875 entry_pos < end && entry_pos < data->entries_num; entry_pos++)
1877 struct ListEntry *entry = data->entries[entry_pos];
1879 if (!(msg->flags & MADF_DRAWUPDATE) ||
1880 ((msg->flags & MADF_DRAWUPDATE) && data->update == 1) ||
1881 ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) ||
1882 ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1883 && data->update_pos == entry_pos))
1885 /* Choose appropriate highlight image */
1887 if (entry_pos == data->entries_active
1888 && (entry->flags & ENTRY_SELECTED) && !data->read_only)
1889 highlight = data->list_selcur;
1890 else if (entry_pos == data->entries_active && !data->read_only)
1891 highlight = data->list_cursor;
1892 else if (entry->flags & ENTRY_SELECTED)
1893 highlight = data->list_select;
1894 else
1895 highlight = NULL;
1897 /* Draw highlight or background */
1899 if (highlight != NULL)
1901 zune_imspec_draw(highlight, muiRenderInfo(obj),
1902 _mleft(data->area), y, _mwidth(data->area),
1903 data->entry_maxheight,
1904 0, y - data->entries_top_pixel, 0);
1906 else if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1907 && data->update_pos == entry_pos)
1909 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area), y,
1910 _mwidth(data->area), data->entry_maxheight, 0,
1911 y - _mtop(data->area) +
1912 data->entries_first * data->entry_maxheight, 0);
1915 List_DrawEntry(cl, obj, entry_pos, y);
1917 y += data->entry_maxheight;
1920 MUI_RemoveClipping(muiRenderInfo(obj), clip);
1922 data->update = 0;
1924 if (scroll_caused_damage)
1926 if (MUI_BeginRefresh(muiRenderInfo(obj), 0))
1928 /* Theoretically it might happen that more damage is caused
1929 after ScrollRaster. By something else, like window movement
1930 in front of our window. Therefore refresh root object of
1931 window, not just this object */
1933 Object *o = NULL;
1935 get(_win(obj), MUIA_Window_RootObject, &o);
1936 MUI_Redraw(o, MADF_DRAWOBJECT);
1938 MUI_EndRefresh(muiRenderInfo(obj), 0);
1942 ULONG x1 = _mleft(data->area);
1943 ULONG col;
1944 y = _mtop(data->area);
1946 if (data->title_height && data->title)
1948 for (col = 0; col < data->columns; col++)
1950 ULONG halfdelta = data->ci[col].delta / 2;
1951 x1 += data->ci[col].entries_width + halfdelta;
1953 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(data->area))
1954 break;
1956 if (data->ci[col].bar)
1958 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1959 Move(_rp(obj), x1, y);
1960 Draw(_rp(obj), x1,
1961 y + data->entries[ENTRY_TITLE]->height - 1);
1962 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1963 Move(_rp(obj), x1 + 1, y);
1964 Draw(_rp(obj), x1 + 1,
1965 y + data->entries[ENTRY_TITLE]->height - 1);
1967 x1 += BAR_WIDTH;
1969 x1 += data->ci[col].delta - halfdelta;
1971 y += data->entries[ENTRY_TITLE]->height + 1;
1974 x1 = _mleft(data->area);
1976 for (col = 0; col < data->columns; col++)
1978 ULONG halfdelta = data->ci[col].delta / 2;
1979 x1 += data->ci[col].entries_width + halfdelta;
1981 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(data->area))
1982 break;
1984 if (data->ci[col].bar)
1986 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1987 Move(_rp(obj), x1, y);
1988 Draw(_rp(obj), x1, _mbottom(data->area));
1989 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1990 Move(_rp(obj), x1 + 1, y);
1991 Draw(_rp(obj), x1 + 1, _mbottom(data->area));
1993 x1 += BAR_WIDTH;
1996 x1 += data->ci[col].delta - halfdelta;
1999 return 0;
2002 /****** List.mui/MUIM_List_Clear *********************************************
2004 * NAME
2005 * MUIM_List_Clear (V4)
2007 * SYNOPSIS
2008 * DoMethod(obj, MUIM_List_Clear);
2010 * FUNCTION
2011 * Removes all entries from the list.
2013 ******************************************************************************
2017 IPTR List__MUIM_Clear(struct IClass *cl, Object *obj,
2018 struct MUIP_List_Clear *msg)
2020 struct MUI_ListData *data = INST_DATA(cl, obj);
2022 while (data->confirm_entries_num)
2024 struct ListEntry *lentry =
2025 data->entries[--data->confirm_entries_num];
2026 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
2027 (IPTR) data->pool);
2028 FreeListEntry(data, lentry);
2030 /* Should never fail when shrinking */
2031 SetListSize(data, 0);
2033 if (data->confirm_entries_num != data->entries_num)
2035 SetAttrs(obj, MUIA_List_Entries, 0, MUIA_List_First, 0,
2036 /* Notify only when no entry was active */
2037 data->entries_active !=
2038 MUIV_List_Active_Off ? MUIA_List_Active : TAG_DONE,
2039 MUIV_List_Active_Off, TAG_DONE);
2041 data->update = 1;
2042 MUI_Redraw(obj, MADF_DRAWUPDATE);
2045 return 0;
2048 /****** List.mui/MUIM_List_Exchange ******************************************
2050 * NAME
2051 * MUIM_List_Exchange (V4)
2053 * SYNOPSIS
2054 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2056 * FUNCTION
2057 * Exchange two entries' positions.
2059 * INPUTS
2060 * pos1 - the current index of the first entry that should be moved, or
2061 * one of these special values:
2062 * MUIV_List_Exchange_Active: the active entry.
2063 * MUIV_List_Exchange_Top: the first entry.
2064 * MUIV_List_Exchange_Bottom: the last entry.
2065 * pos2 - the index of the entry that the first entry should be exchanged
2066 * with, or one of these special values:
2067 * MUIV_List_Exchange_Active: the active entry.
2068 * MUIV_List_Exchange_Top: the first entry.
2069 * MUIV_List_Exchange_Bottom: the last entry.
2070 * MUIV_List_Exchange_Next: the next entry after pos1.
2071 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2073 * NOTES
2074 * This method will do nothing if either index is greater than the last
2075 * index in the list, or if MUIV_List_Exchange_Next or
2076 * MUIV_List_Exchange_Previous imply an index outside the list.
2078 * SEE ALSO
2079 * MUIM_List_Move
2081 ******************************************************************************
2085 IPTR List__MUIM_Exchange(struct IClass *cl, Object *obj,
2086 struct MUIP_List_Exchange *msg)
2088 struct MUI_ListData *data = INST_DATA(cl, obj);
2089 LONG pos1, pos2;
2091 switch (msg->pos1)
2093 case MUIV_List_Exchange_Top:
2094 pos1 = 0;
2095 break;
2096 case MUIV_List_Exchange_Active:
2097 pos1 = data->entries_active;
2098 break;
2099 case MUIV_List_Exchange_Bottom:
2100 pos1 = data->entries_num - 1;
2101 break;
2102 default:
2103 pos1 = msg->pos1;
2106 switch (msg->pos2)
2108 case MUIV_List_Exchange_Top:
2109 pos2 = 0;
2110 break;
2111 case MUIV_List_Exchange_Active:
2112 pos2 = data->entries_active;
2113 break;
2114 case MUIV_List_Exchange_Bottom:
2115 pos2 = data->entries_num - 1;
2116 break;
2117 case MUIV_List_Exchange_Next:
2118 pos2 = pos1 + 1;
2119 break;
2120 case MUIV_List_Exchange_Previous:
2121 pos2 = pos1 - 1;
2122 break;
2123 default:
2124 pos2 = msg->pos2;
2127 if (pos1 >= 0 && pos1 < data->entries_num && pos2 >= 0
2128 && pos2 < data->entries_num && pos1 != pos2)
2130 struct ListEntry *save = data->entries[pos1];
2131 data->entries[pos1] = data->entries[pos2];
2132 data->entries[pos2] = save;
2134 data->update = 2;
2135 data->update_pos = pos1;
2136 MUI_Redraw(obj, MADF_DRAWUPDATE);
2138 data->update = 2;
2139 data->update_pos = pos2;
2140 MUI_Redraw(obj, MADF_DRAWUPDATE);
2142 return TRUE;
2144 else
2146 return FALSE;
2150 /**************************************************************************
2151 MUIM_List_Redraw
2152 **************************************************************************/
2153 IPTR List__MUIM_Redraw(struct IClass *cl, Object *obj,
2154 struct MUIP_List_Redraw *msg)
2156 struct MUI_ListData *data = INST_DATA(cl, obj);
2158 if (!(data->flags & LIST_QUIET))
2160 if (msg->pos == MUIV_List_Redraw_All)
2162 data->update = 1;
2163 CalcWidths(cl, obj);
2164 MUI_Redraw(obj, MADF_DRAWUPDATE);
2166 else
2168 LONG pos = -1;
2169 if (msg->pos == MUIV_List_Redraw_Active)
2170 pos = data->entries_active;
2171 else if (msg->pos == MUIV_List_Redraw_Entry)
2173 LONG i;
2174 for (i = 0; i < data->entries_num; i++)
2175 if (data->entries[i]->data == msg->entry)
2177 pos = i;
2178 break;
2181 else
2182 pos = msg->pos;
2184 if (pos != -1)
2186 if (CalcDimsOfEntry(cl, obj, pos))
2187 data->update = 1;
2188 else
2190 data->update = 2;
2191 data->update_pos = pos;
2193 MUI_Redraw(obj, MADF_DRAWUPDATE);
2197 return 0;
2200 /****** List.mui/MUIM_List_Remove ********************************************
2202 * NAME
2203 * MUIM_List_Remove (V4)
2205 * SYNOPSIS
2206 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2208 * FUNCTION
2209 * Removes entries from the list. If a destruct hook has been
2210 * installed, it will be called for the removed entry.
2212 * INPUTS
2213 * pos - the index of the entry to be removed. The following
2214 * special values can also be used:
2215 * MUIV_List_Remove_First: remove the first entry.
2216 * MUIV_List_Remove_Last: remove the last entry.
2217 * MUIV_List_Remove_Active: remove the active entry.
2218 * MUIV_List_Remove_Selected: remove all selected entries
2219 * (or the active entry if there are no selected entries).
2221 * NOTES
2222 * When the active entry is removed, the next entry becomes active
2223 * (if there is no entry below the active entry, the previous entry
2224 * becomes active instead).
2226 * SEE ALSO
2227 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2229 ******************************************************************************
2231 * It was not possible to use MUIM_List_NextSelected here because that method
2232 * may skip entries if entries are removed during an iteration.
2236 IPTR List__MUIM_Remove(struct IClass *cl, Object *obj,
2237 struct MUIP_List_Remove *msg)
2239 struct MUI_ListData *data = INST_DATA(cl, obj);
2240 LONG pos;
2241 LONG new_act;
2242 UWORD i;
2243 BOOL found, done = FALSE;
2244 struct ListEntry *lentry;
2245 Tag active_tag = TAG_DONE;
2247 if (!data->entries_num)
2248 return 0;
2250 switch (msg->pos)
2252 case MUIV_List_Remove_First:
2253 pos = 0;
2254 break;
2256 case MUIV_List_Remove_Active:
2257 pos = data->entries_active;
2258 break;
2260 case MUIV_List_Remove_Last:
2261 pos = data->entries_num - 1;
2262 break;
2264 case MUIV_List_Remove_Selected:
2265 pos = 0;
2266 break;
2268 default:
2269 pos = msg->pos;
2270 break;
2273 if (pos < 0 || pos >= data->entries_num)
2274 return 0;
2276 new_act = data->entries_active;
2278 while (!done)
2280 if (msg->pos == MUIV_List_Remove_Selected)
2282 /* Find the next selected entry */
2283 for (found = FALSE, i = pos;
2284 i < data->confirm_entries_num && !found; i++)
2286 if (data->entries[i]->flags & ENTRY_SELECTED)
2288 pos = i;
2289 found = TRUE;
2293 if (!found)
2295 done = TRUE;
2297 /* If there were no selected entries, remove the active one */
2298 if (data->confirm_entries_num == data->entries_num
2299 && data->entries_active != MUIV_List_Active_Off)
2301 pos = data->entries_active;
2302 found = TRUE;
2306 else
2307 done = TRUE;
2309 if (found)
2311 lentry = data->entries[pos];
2312 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
2313 (IPTR) data->pool);
2314 RemoveListEntries(data, pos, 1);
2315 data->confirm_entries_num--;
2317 if (pos < new_act)
2319 new_act--;
2320 active_tag = MUIA_List_Active;
2322 else if (pos == new_act)
2323 active_tag = MUIA_List_Active;
2327 /* ensure that the active element is in a valid range (it might become
2328 * MUIV_List_Active_Off (-1), but that's OK) */
2329 if (new_act >= data->entries_num)
2330 new_act = data->entries_num - 1;
2332 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num,
2333 active_tag, new_act, /* Inform only if necessary (for notify) */
2334 TAG_DONE);
2336 data->update = 1;
2337 MUI_Redraw(obj, MADF_DRAWUPDATE);
2339 return 0;
2342 /**************************************************************************
2343 MUIM_List_Select
2344 **************************************************************************/
2345 IPTR List__MUIM_Select(struct IClass *cl, Object *obj,
2346 struct MUIP_List_Select *msg)
2348 struct MUI_ListData *data = INST_DATA(cl, obj);
2349 LONG pos, i, count, selcount=0, state=0;
2350 BOOL multi_allowed = TRUE, new_select_state = FALSE;
2352 /* Establish the range of entries affected */
2353 switch (msg->pos)
2355 case MUIV_List_Select_Active:
2356 pos = data->entries_active;
2357 if (pos == MUIV_List_Active_Off)
2358 count = 0;
2359 else
2360 count = 1;
2361 break;
2363 case MUIV_List_Select_All:
2364 pos = 0;
2365 count = data->entries_num;
2366 break;
2368 default:
2369 pos = msg->pos;
2370 count = 1;
2371 if (pos < 0 || pos >= data->entries_num)
2372 return 0;
2373 break;
2376 if (msg->seltype != MUIV_List_Select_Ask && data->multi_test_hook != NULL)
2378 /* Disallow selection of an additional entry if there is a currently
2379 selected entry that is not multi-selectable (in such case there
2380 will only be one entry currently selected, so no need to iterate) */
2381 i = MUIV_List_NextSelected_Start;
2382 DoMethod(obj, MUIM_List_NextSelected, (IPTR) &i);
2383 if (i != MUIV_List_NextSelected_End)
2384 selcount++;
2385 if (data->multi_test_hook != NULL && selcount != 0)
2386 multi_allowed = CallHookPkt(data->multi_test_hook, NULL,
2387 data->entries[i]->data);
2390 /* Change or check state of each entry in the range */
2391 for (i = pos; i < pos + count; i++)
2393 state = data->entries[i]->flags & ENTRY_SELECTED;
2394 switch (msg->seltype)
2396 case MUIV_List_Select_Off:
2397 new_select_state = FALSE;
2398 break;
2400 case MUIV_List_Select_On:
2401 new_select_state = TRUE;
2402 break;
2404 case MUIV_List_Select_Toggle:
2405 new_select_state = !state;
2406 break;
2408 default:
2409 if (data->entries[i]->flags & ENTRY_SELECTED)
2410 selcount++;
2411 break;
2414 if (msg->seltype != MUIV_List_Select_Ask)
2416 /* Disallow selection if entry is not multi-selectable and
2417 * there are already selected entries */
2418 if (data->multi_test_hook != NULL && new_select_state)
2419 new_select_state = multi_allowed && (selcount == 0 ||
2420 CallHookPkt(data->multi_test_hook, NULL,
2421 data->entries[i]->data));
2423 if (new_select_state)
2424 data->entries[i]->flags |= ENTRY_SELECTED;
2425 else
2426 data->entries[i]->flags &= ~ENTRY_SELECTED;
2430 /* Report old state or number of selected entries */
2431 if (msg->info)
2433 if (msg->pos == MUIV_List_Select_All
2434 && msg->seltype == MUIV_List_Select_Ask)
2435 *msg->info = selcount;
2436 else
2437 *msg->info = state;
2440 /* Redraw unless it was just an enquiry */
2441 if (msg->seltype != MUIV_List_Select_Ask)
2443 if (count > 1)
2444 data->update = 1;
2445 else
2447 data->update = 2;
2448 data->update_pos = pos;
2450 MUI_Redraw(obj, MADF_DRAWUPDATE);
2453 return 0;
2456 /****** List.mui/MUIM_List_Insert ********************************************
2458 * NAME
2459 * MUIM_List_Insert (V4)
2461 * SYNOPSIS
2462 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2464 * FUNCTION
2465 * Adds multiple entries to the list. If a construct hook has been
2466 * installed, the results of passing the entries to this hook will be
2467 * inserted.
2469 * INPUTS
2470 * entries - an array of entries to be inserted.
2471 * count - the number of entries to insert. A special value of -1 may be
2472 * used, indicating that the array of entries is NULL-terminated.
2473 * pos - the index at which to insert the new entries. The following
2474 * special values can also be used:
2475 * MUIV_List_Insert_Top: insert at index 0.
2476 * MUIV_List_Insert_Bottom: insert after all existing entries.
2477 * MUIV_List_Insert_Active: insert at the index of the active entry
2478 * (or at index 0 if there is no active entry).
2479 * MUIV_List_Insert_Sorted: keep the list sorted.
2481 * SEE ALSO
2482 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2484 ******************************************************************************
2488 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
2489 struct MUIP_List_Insert *msg)
2491 struct MUI_ListData *data = INST_DATA(cl, obj);
2492 LONG pos, count, sort, active;
2494 count = msg->count;
2495 sort = 0;
2497 if (count == -1)
2499 /* Count the number of entries */
2500 for (count = 0; msg->entries[count] != NULL; count++)
2504 if (count <= 0)
2505 return ~0;
2507 switch (msg->pos)
2509 case MUIV_List_Insert_Top:
2510 pos = 0;
2511 break;
2513 case MUIV_List_Insert_Active:
2514 if (data->entries_active != -1)
2515 pos = data->entries_active;
2516 else
2517 pos = 0;
2518 break;
2520 case MUIV_List_Insert_Sorted:
2521 pos = data->entries_num;
2522 sort = 1; /* we sort'em later */
2523 break;
2525 case MUIV_List_Insert_Bottom:
2526 pos = data->entries_num;
2527 break;
2529 default:
2530 if (msg->pos > data->entries_num)
2531 pos = data->entries_num;
2532 else if (msg->pos < 0)
2533 pos = 0;
2534 else
2535 pos = msg->pos;
2536 break;
2538 data->insert_position = pos;
2540 if (!(SetListSize(data, data->entries_num + count)))
2541 return ~0;
2543 LONG until = pos + count;
2544 APTR *toinsert = msg->entries;
2546 if (!(PrepareInsertListEntries(data, pos, count)))
2547 return ~0;
2549 while (pos < until)
2551 struct ListEntry *lentry;
2553 if (!(lentry = AllocListEntry(data)))
2555 /* Panic, but we must be in a consistent state, so remove
2556 * the space where the following list entries should have gone
2558 RemoveListEntries(data, pos, until - pos);
2559 return ~0;
2562 /* now call the construct method which returns us a pointer which
2563 we need to store */
2564 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2565 (IPTR) * toinsert, (IPTR) data->pool);
2566 if (!lentry->data)
2568 FreeListEntry(data, lentry);
2569 RemoveListEntries(data, pos, until - pos);
2571 /* TODO: Also check for visible stuff like below */
2572 if (data->entries_num != data->confirm_entries_num)
2573 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2574 return ~0;
2577 data->entries[pos] = lentry;
2578 data->confirm_entries_num++;
2580 if (_flags(obj) & MADF_SETUP)
2582 /* We have to calculate the width and height of the newly
2583 * inserted entry. This has to be done after inserting the
2584 * element into the list */
2585 CalcDimsOfEntry(cl, obj, pos);
2588 toinsert++;
2589 pos++;
2591 pos--;
2593 /* Recalculate the number of visible entries */
2594 if (_flags(obj) & MADF_SETUP)
2595 CalcVertVisible(cl, obj);
2597 if (data->entries_num != data->confirm_entries_num)
2599 SetAttrs(obj,
2600 MUIA_List_Entries, data->confirm_entries_num,
2601 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2604 /* If the array is already sorted, we could do a simple insert
2605 * sort and would be much faster than with qsort.
2606 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2607 * sort the whole array?
2609 * I think, we better sort the whole array:
2611 if (sort)
2613 DoMethod(obj, MUIM_List_Sort);
2614 /* TODO: which pos to return here !? */
2615 /* MUIM_List_Sort already called MUI_Redraw */
2617 else
2619 data->update = 1;
2620 MUI_Redraw(obj, MADF_DRAWUPDATE);
2622 superset(cl, obj, MUIA_List_InsertPosition, data->insert_position);
2624 /* Update index of active entry */
2625 if (data->entries_active >= data->insert_position)
2627 active = data->entries_active + count;
2628 SET(obj, MUIA_List_Active, active);
2631 return (ULONG) pos;
2634 /****** List.mui/MUIM_List_InsertSingle **************************************
2636 * NAME
2637 * MUIM_List_InsertSingle (V7)
2639 * SYNOPSIS
2640 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2642 * FUNCTION
2643 * Adds a single entry to the list. If a construct hook has been
2644 * installed, the result of passing the entry to this hook will be
2645 * inserted.
2647 * INPUTS
2648 * entry - the entry to be inserted.
2649 * pos - the index at which to insert the new entry. The following
2650 * special values can also be used:
2651 * MUIV_List_Insert_Top: insert at index 0.
2652 * MUIV_List_Insert_Bottom: insert after all existing entries.
2653 * MUIV_List_Insert_Active: insert at the index of the active entry
2654 * (or at index 0 if there is no active entry).
2655 * MUIV_List_Insert_Sorted: keep the list sorted.
2657 * SEE ALSO
2658 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2660 ******************************************************************************
2664 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2665 struct MUIP_List_InsertSingle *msg)
2667 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2668 msg->pos);
2671 /**************************************************************************
2672 MUIM_List_GetEntry
2673 **************************************************************************/
2674 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2675 struct MUIP_List_GetEntry *msg)
2677 struct MUI_ListData *data = INST_DATA(cl, obj);
2678 int pos = msg->pos;
2680 if (pos == MUIV_List_GetEntry_Active)
2681 pos = data->entries_active;
2683 if (pos < 0 || pos >= data->entries_num)
2685 *msg->entry = NULL;
2686 return 0;
2688 *msg->entry = data->entries[pos]->data;
2689 return (IPTR) *msg->entry;
2692 /**************************************************************************
2693 MUIM_List_Construct
2694 **************************************************************************/
2695 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2696 struct MUIP_List_Construct *msg)
2698 struct MUI_ListData *data = INST_DATA(cl, obj);
2700 if (NULL == data->construct_hook)
2701 return (IPTR) msg->entry;
2702 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2704 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2705 ULONG *mem = AllocPooled(msg->pool, len + 5);
2707 if (NULL == mem)
2708 return 0;
2709 mem[0] = len + 5;
2710 if (msg->entry != NULL)
2711 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2712 else
2713 *(STRPTR) (mem + 1) = 0;
2714 return (IPTR) (mem + 1);
2716 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2719 /**************************************************************************
2720 MUIM_List_Destruct
2721 **************************************************************************/
2722 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2723 struct MUIP_List_Destruct *msg)
2725 struct MUI_ListData *data = INST_DATA(cl, obj);
2727 if (NULL == data->destruct_hook)
2728 return 0;
2730 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2732 ULONG *mem = ((ULONG *) msg->entry) - 1;
2733 FreePooled(msg->pool, mem, mem[0]);
2735 else
2737 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2739 return 0;
2742 /****** List.mui/MUIM_List_Compare *******************************************
2744 * NAME
2745 * MUIM_List_Compare (V20)
2747 * SYNOPSIS
2748 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2749 * LONG sort_type1, LONG sort_type2);
2751 * FUNCTION
2752 * Compare two list entries according to the current comparison hook
2753 * (MUIA_List_CompareHook).
2755 * INPUTS
2756 * entry1 - the first entry data.
2757 * entry2 - the second entry data.
2758 * sort_type1 - undocumented.
2759 * sort_type2 - undocumented.
2761 * SEE ALSO
2762 * MUIA_List_CompareHook, MUIM_List_Sort.
2764 ******************************************************************************
2768 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2769 struct MUIP_List_Compare *msg)
2771 struct MUI_ListData *data = INST_DATA(cl, obj);
2773 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2776 /**************************************************************************
2777 MUIM_List_Display
2778 **************************************************************************/
2779 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2780 struct MUIP_List_Display *msg)
2782 struct MUI_ListData *data = INST_DATA(cl, obj);
2784 if (NULL == data->display_hook)
2786 if (msg->entry)
2787 *msg->array = msg->entry;
2788 else
2789 *msg->array = 0;
2790 return 1;
2793 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2794 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2797 /**************************************************************************
2798 MUIM_List_SelectChange
2799 **************************************************************************/
2800 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2801 struct MUIP_List_SelectChange *msg)
2803 return 1;
2806 /**************************************************************************
2807 MUIM_List_CreateImage
2808 Called by a List subclass in its Setup method.
2809 Connects an Area subclass object to the list, much like an object gets
2810 connected to a window. List calls Setup and AskMinMax on that object,
2811 keeps a reference to it (that reference will be returned).
2812 Text engine will dereference that pointer and draw the object with its
2813 default size.
2814 **************************************************************************/
2815 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2816 struct MUIP_List_CreateImage *msg)
2818 struct MUI_ListData *data = INST_DATA(cl, obj);
2819 struct ListImage *li;
2821 if (!msg->obj)
2822 return 0;
2824 /* List must be already setup in Setup of your subclass */
2825 if (!(_flags(obj) & MADF_SETUP))
2826 return 0;
2827 li = AllocPooled(data->pool, sizeof(struct ListImage));
2828 if (!li)
2829 return 0;
2830 li->obj = msg->obj;
2832 AddTail((struct List *)&data->images, (struct Node *)li);
2833 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2834 DoSetupMethod(li->obj, muiRenderInfo(obj));
2837 return (IPTR) li;
2840 /**************************************************************************
2841 MUIM_List_DeleteImage
2842 **************************************************************************/
2843 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2844 struct MUIP_List_DeleteImage *msg)
2846 struct MUI_ListData *data = INST_DATA(cl, obj);
2847 struct ListImage *li = (struct ListImage *)msg->listimg;
2849 if (li)
2851 DoMethod(li->obj, MUIM_Cleanup);
2852 DoMethod(li->obj, MUIM_DisconnectParent);
2853 Remove((struct Node *)li);
2854 FreePooled(data->pool, li, sizeof(struct ListImage));
2857 return 0;
2860 /****** List.mui/MUIM_List_Jump **********************************************
2862 * NAME
2863 * MUIM_List_Jump (V4)
2865 * SYNOPSIS
2866 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2868 * FUNCTION
2869 * Scrolls the list so that a particular entry is visible.
2871 * INPUTS
2872 * pos - index of entry that should become visible, or one of these
2873 * special values:
2874 * MUIV_List_Jump_Active: show the active entry.
2875 * MUIV_List_Jump_Top: show the first entry.
2876 * MUIV_List_Jump_Bottom: show the last entry.
2877 * MUIV_List_Jump_Up: show the previous hidden entry.
2878 * MUIV_List_Jump_Down: show the next hidden entry.
2880 ******************************************************************************
2884 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2885 struct MUIP_List_Jump *msg)
2887 struct MUI_ListData *data = INST_DATA(cl, obj);
2888 LONG pos = msg->pos;
2890 switch (pos)
2892 case MUIV_List_Jump_Top:
2893 pos = 0;
2894 break;
2896 case MUIV_List_Jump_Active:
2897 pos = data->entries_active;
2898 break;
2900 case MUIV_List_Jump_Bottom:
2901 pos = data->entries_num - 1;
2902 break;
2904 case MUIV_List_Jump_Down:
2905 pos = data->entries_first + data->entries_visible;
2906 break;
2908 case MUIV_List_Jump_Up:
2909 pos = data->entries_first - 1;
2910 break;
2913 if (pos >= data->entries_num)
2915 pos = data->entries_num - 1;
2917 if (pos < 0)
2918 pos = 0;
2920 if (pos < data->entries_first)
2922 set(obj, MUIA_List_First, pos);
2924 else if (pos >= data->entries_first + data->entries_visible)
2926 pos -= (data->entries_visible - 1);
2927 if (pos < 0)
2928 pos = 0;
2929 if (pos != data->entries_first)
2931 set(obj, MUIA_List_First, pos);
2935 return TRUE;
2938 /****** List.mui/MUIM_List_Sort **********************************************
2940 * NAME
2941 * MUIM_List_Sort (V4)
2943 * SYNOPSIS
2944 * DoMethod(obj, MUIM_List_Sort);
2946 * FUNCTION
2947 * Sort the list's entries according to the current comparison hook
2948 * (MUIA_List_CompareHook).
2950 * NOTES
2951 * The active index does not change, so the active entry may do so.
2953 * SEE ALSO
2954 * MUIA_List_CompareHook, MUIM_List_Compare.
2956 ******************************************************************************
2960 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2961 struct MUIP_List_Sort *msg)
2963 struct MUI_ListData *data = INST_DATA(cl, obj);
2965 int i, j, max;
2966 struct MUIP_List_Compare cmpmsg =
2967 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2969 if (data->entries_num > 1)
2972 Simple sort algorithm. Feel free to improve it.
2974 for (i = 0; i < data->entries_num - 1; i++)
2976 max = i;
2977 for (j = i + 1; j < data->entries_num; j++)
2979 cmpmsg.entry1 = data->entries[max]->data;
2980 cmpmsg.entry2 = data->entries[j]->data;
2981 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2983 max = j;
2986 if (i != max)
2988 APTR tmp = data->entries[i];
2989 data->entries[i] = data->entries[max];
2990 data->entries[max] = tmp;
2995 data->update = 1;
2996 MUI_Redraw(obj, MADF_DRAWUPDATE);
2998 return 0;
3001 /****** List.mui/MUIM_List_Move **********************************************
3003 * NAME
3004 * MUIM_List_Move (V9)
3006 * SYNOPSIS
3007 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
3009 * FUNCTION
3010 * Move a list entry to a new position.
3012 * INPUTS
3013 * from - the current index of the entry that should be moved, or one of
3014 * these special values:
3015 * MUIV_List_Move_Active: the active entry.
3016 * MUIV_List_Move_Top: the first entry.
3017 * MUIV_List_Move_Bottom: the last entry.
3018 * to - the index of the entry's new position, or one of
3019 * these special values:
3020 * MUIV_List_Move_Active: the active entry.
3021 * MUIV_List_Move_Top: the first entry.
3022 * MUIV_List_Move_Bottom: the last entry.
3024 * NOTES
3025 * The active index does not change, so the active entry may do so.
3027 * SEE ALSO
3028 * MUIM_List_Exchange
3030 ******************************************************************************
3034 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
3035 struct MUIP_List_Move *msg)
3037 struct MUI_ListData *data = INST_DATA(cl, obj);
3039 LONG from, to;
3040 int i;
3042 /* Normalise special 'from' values */
3043 switch (msg->from)
3045 case MUIV_List_Move_Top:
3046 from = 0;
3047 break;
3048 case MUIV_List_Move_Active:
3049 from = data->entries_active;
3050 break;
3051 case MUIV_List_Move_Bottom:
3052 from = data->entries_num - 1;
3053 break;
3054 default:
3055 from = msg->from;
3058 /* Normalise special 'to' values */
3059 switch (msg->to)
3061 case MUIV_List_Move_Top:
3062 to = 0;
3063 break;
3064 case MUIV_List_Move_Active:
3065 to = data->entries_active;
3066 break;
3067 case MUIV_List_Move_Bottom:
3068 to = data->entries_num - 1;
3069 break;
3070 case MUIV_List_Move_Next:
3071 to = from + 1;
3072 break;
3073 case MUIV_List_Move_Previous:
3074 to = from - 1;
3075 break;
3076 default:
3077 to = msg->to;
3080 /* Check that values are within valid bounds */
3081 if (from > data->entries_num - 1 || from < 0
3082 || to > data->entries_num - 1 || to < 0 || from == to)
3083 return (IPTR) FALSE;
3085 /* Shift all entries in the range between the 'from' and 'to' positions */
3086 if (from < to)
3088 struct ListEntry *backup = data->entries[from];
3089 for (i = from; i < to; i++)
3090 data->entries[i] = data->entries[i + 1];
3091 data->entries[to] = backup;
3093 else
3095 struct ListEntry *backup = data->entries[from];
3096 for (i = from; i > to; i--)
3097 data->entries[i] = data->entries[i - 1];
3098 data->entries[to] = backup;
3101 #if 0 /* Not done in MUI 3 */
3102 /* Update index of active entry */
3103 if (from == data->entries_active)
3104 data->entries_active = to;
3105 else if (data->entries_active > from && data->entries_active < to)
3106 data->entries_active--;
3107 else if (data->entries_active < from && data->entries_active >= to)
3108 data->entries_active++;
3109 #endif
3111 /* Reflect list changes visually */
3112 data->update = 1;
3113 MUI_Redraw(obj, MADF_DRAWUPDATE);
3115 return TRUE;
3118 /****** List.mui/MUIM_List_NextSelected **************************************
3120 * NAME
3121 * MUIM_List_NextSelected (V6)
3123 * SYNOPSIS
3124 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3126 * FUNCTION
3127 * Allows iteration through a list's selected entries by providing the
3128 * index of the next selected entry after the specified index.
3130 * INPUTS
3131 * pos - the address of a variable containing the index of the previous
3132 * selected entry. The variable must be initialised to the special
3133 * value MUIV_List_NextSelected_Start to find the first selected
3134 * entry. When this method returns, the variable will contain the
3135 * index of the next selected entry, or MUIV_List_NextSelected_End if
3136 * there are no more.
3138 * NOTES
3139 * If there are no selected entries but there is an active entry, the
3140 * index of the active entry will be stored (when
3141 * MUIV_List_NextSelected_Start is specified).
3143 * Some selected entries may be skipped if any entries are removed
3144 * between calls to this method during an iteration of a list.
3146 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3147 * the same numeric value.
3149 * SEE ALSO
3150 * MUIM_List_Select, MUIM_List_Remove.
3152 ******************************************************************************
3156 IPTR List__MUIM_NextSelected(struct IClass *cl, Object *obj,
3157 struct MUIP_List_NextSelected *msg)
3159 struct MUI_ListData *data = INST_DATA(cl, obj);
3160 LONG pos, i;
3161 BOOL found = FALSE;
3163 /* Get the first entry to check */
3164 pos = *msg->pos;
3165 if (pos == MUIV_List_NextSelected_Start)
3166 pos = 0;
3167 else
3168 pos++;
3170 /* Find the next selected entry */
3171 for (i = pos; i < data->entries_num && !found; i++)
3173 if (data->entries[i]->flags & ENTRY_SELECTED)
3175 pos = i;
3176 found = TRUE;
3180 /* Return index of selected or active entry, or indicate there are no
3181 more */
3182 if (!found)
3184 if (*msg->pos == MUIV_List_NextSelected_Start
3185 && data->entries_active != MUIV_List_Active_Off)
3186 pos = data->entries_active;
3187 else
3188 pos = MUIV_List_NextSelected_End;
3190 *msg->pos = pos;
3192 return TRUE;
3195 /**************************************************************************
3196 MUIM_List_TestPos
3197 **************************************************************************/
3198 IPTR List__MUIM_TestPos(struct IClass *cl, Object *obj,
3199 struct MUIP_List_TestPos *msg)
3201 struct MUI_ListData *data = INST_DATA(cl, obj);
3202 struct MUI_List_TestPos_Result *result = msg->res;
3203 LONG col = -1, row = -1;
3204 UWORD flags = 0, i;
3205 LONG mx = msg->x - _left(data->area);
3206 LONG entries_visible;
3208 if (data->entries_visible <= data->entries_num)
3209 entries_visible = data->entries_visible;
3210 else
3211 entries_visible = data->entries_num;
3212 LONG ey = msg->y - data->entries_top_pixel;
3213 /* y coordinates transformed to the entries */
3215 /* Now check if it was clicked on a title or on entries */
3216 if (ey < 0)
3217 flags |= MUI_LPR_ABOVE;
3218 else if (ey >= entries_visible * data->entry_maxheight)
3219 flags |= MUI_LPR_BELOW;
3220 else
3222 /* Identify row */
3223 row = ey / data->entry_maxheight + data->entries_first;
3224 result->yoffset =
3225 ey % data->entry_maxheight - data->entry_maxheight / 2;
3228 if (mx < 0)
3229 flags |= MUI_LPR_LEFT;
3230 else if (mx >= _width(data->area))
3231 flags |= MUI_LPR_RIGHT;
3232 else
3234 /* Identify column */
3235 if (data->entries_num > 0 && data->columns > 0)
3237 LONG width_sum = 0;
3238 col = data->columns - 1;
3239 for (i = 0; i < data->columns; i++)
3241 result->xoffset = mx - width_sum;
3242 width_sum +=
3243 data->ci[i].entries_width +
3244 data->ci[i].delta +
3245 (data->ci[i].bar ? BAR_WIDTH : 0);
3246 D(bug("[List/MUIM_TestPos] i %d "
3247 "width %d width_sum %d mx %d\n",
3248 i, data->ci[i].entries_width, width_sum, mx));
3249 if (mx < width_sum)
3251 col = i;
3252 D(bug("[List/MUIM_TestPos] Column hit %d\n", col));
3253 break;
3259 result->entry = row;
3260 result->column = col;
3261 result->flags = flags;
3263 return TRUE;
3266 /****i* List.mui/MUIM_DragQuery **********************************************
3268 * NAME
3269 * MUIM_DragQuery
3271 ******************************************************************************
3275 IPTR List__MUIM_DragQuery(struct IClass *cl, Object *obj,
3276 struct MUIP_DragQuery *msg)
3278 if (msg->obj == obj)
3279 return MUIV_DragQuery_Accept;
3280 else
3281 return MUIV_DragQuery_Refuse;
3285 /****i* List.mui/MUIM_DragFinish *********************************************
3287 * NAME
3288 * MUIM_DragFinish
3290 ******************************************************************************
3294 IPTR List__MUIM_DragFinish(struct IClass *cl, Object *obj,
3295 struct MUIP_DragFinish *msg)
3297 struct MUI_ListData *data = INST_DATA(cl, obj);
3299 data->drop_mark_y = -1;
3301 return DoSuperMethodA(cl, obj, (Msg) msg);
3304 /****i* List.mui/MUIM_DragReport *********************************************
3306 * NAME
3307 * MUIM_DragReport
3309 ******************************************************************************
3313 IPTR List__MUIM_DragReport(struct IClass *cl, Object *obj,
3314 struct MUIP_DragReport *msg)
3316 struct MUI_ListData *data = INST_DATA(cl, obj);
3317 struct MUI_List_TestPos_Result pos;
3318 struct RastPort *rp = _rp(obj);
3319 LONG n, y;
3320 UWORD old_pattern;
3322 /* Choose new drop mark position */
3324 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3325 if (pos.entry != -1)
3327 n = pos.entry;
3328 if (pos.yoffset > 0)
3329 n++;
3331 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3332 n = data->entries_first;
3333 else
3335 n = MIN(data->entries_visible, data->entries_num)
3336 - data->entries_first;
3339 /* Clear old drop mark */
3341 if ((data->flags & LIST_SHOWDROPMARKS) != 0)
3343 y = data->entries_top_pixel + (n - data->entries_first)
3344 * data->entry_maxheight;
3345 if (y != data->drop_mark_y)
3347 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
3348 data->drop_mark_y, _mwidth(data->area), 1, 0, 0, 0);
3350 /* Draw new drop mark and store its position */
3352 SetABPenDrMd(rp, _pens(obj)[MPEN_SHINE], _pens(obj)[MPEN_SHADOW],
3353 JAM2);
3354 old_pattern = rp->LinePtrn;
3355 SetDrPt(rp, 0xF0F0);
3356 Move(rp, _mleft(data->area), y);
3357 Draw(rp, _mright(data->area), y);
3358 SetDrPt(rp, old_pattern);
3359 data->drop_mark_y = y;
3363 return TRUE;
3367 /****i* List.mui/MUIM_DragDrop ***********************************************
3369 * NAME
3370 * MUIM_DragDrop
3372 ******************************************************************************
3376 IPTR List__MUIM_DragDrop(struct IClass *cl, Object *obj,
3377 struct MUIP_DragDrop *msg)
3379 struct MUI_ListData *data = INST_DATA(cl, obj);
3380 struct MUI_List_TestPos_Result pos;
3381 LONG n;
3383 /* Find drop position */
3385 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3386 if (pos.entry != -1)
3388 /* Change drop position when coords move past centre of entry, not
3389 * entry boundary */
3391 n = pos.entry;
3392 if (pos.yoffset > 0)
3393 n++;
3395 /* Ensure that dropped entry will be positioned between the two
3396 * entries that are above and below the drop mark, rather than
3397 * strictly at the numeric index shown */
3399 if (n > data->entries_active)
3400 n--;
3402 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3403 n = MUIV_List_Move_Top;
3404 else
3405 n = MUIV_List_Move_Bottom;
3407 DoMethod(msg->obj, MUIM_List_Move, MUIV_List_Move_Active, n);
3409 return TRUE;
3413 /****i* List.mui/MUIM_CreateDragImage ****************************************
3415 * NAME
3416 * MUIM_CreateDragImage
3418 ******************************************************************************
3422 static IPTR List__MUIM_CreateDragImage(struct IClass *cl, Object *obj,
3423 struct MUIP_CreateDragImage *msg)
3425 struct MUI_ListData *data = INST_DATA(cl, obj);
3426 BOOL success = TRUE;
3427 struct MUI_List_TestPos_Result pos;
3428 WORD width, height, left, top;
3429 struct MUI_DragImage *img = NULL;
3430 const struct ZuneFrameGfx *zframe;
3431 LONG depth;
3433 /* Get info on dragged entry */
3434 DoMethod(obj, MUIM_List_TestPos, _left(data->area) - msg->touchx,
3435 _top(data->area) - msg->touchy, (IPTR) &pos);
3436 if (pos.entry == -1)
3437 success = FALSE;
3439 if (success)
3441 /* Get boundaries of entry */
3442 width = _mwidth(data->area);
3443 height = data->entry_maxheight;
3444 left = _mleft(data->area);
3445 top = _top(data->area) - msg->touchy
3446 - (pos.yoffset + data->entry_maxheight / 2);
3448 /* Allocate drag image structure */
3449 img = (struct MUI_DragImage *)
3450 AllocVec(sizeof(struct MUI_DragImage), MEMF_CLEAR);
3451 if (img == NULL)
3452 success = FALSE;
3455 if (success)
3457 /* Get drag frame */
3458 zframe = zune_zframe_get(obj,
3459 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Drag]);
3461 /* Allocate drag image buffer */
3462 img->width = width + zframe->ileft + zframe->iright;
3463 img->height = height + zframe->itop + zframe->ibottom;
3464 depth = GetBitMapAttr(_screen(obj)->RastPort.BitMap, BMA_DEPTH);
3465 img->bm = AllocBitMap(img->width, img->height, depth, BMF_MINPLANES,
3466 _screen(obj)->RastPort.BitMap);
3468 if (img->bm != NULL)
3470 /* Render entry */
3471 struct RastPort temprp;
3472 InitRastPort(&temprp);
3473 temprp.BitMap = img->bm;
3474 ClipBlit(_rp(obj), left, top, &temprp,
3475 zframe->ileft, zframe->itop, width, height,
3476 0xc0);
3478 /* Render frame */
3479 struct RastPort *rp_save = muiRenderInfo(obj)->mri_RastPort;
3480 muiRenderInfo(obj)->mri_RastPort = &temprp;
3481 zframe->draw(zframe->customframe, muiRenderInfo(obj), 0, 0,
3482 img->width, img->height, 0, 0, img->width, img->height);
3483 muiRenderInfo(obj)->mri_RastPort = rp_save;
3486 /* Ensure drag point matches where user clicked */
3487 img->touchx = msg->touchx - zframe->ileft + _addleft(obj);
3488 img->touchy = -(pos.yoffset + data->entry_maxheight / 2)
3489 - zframe->itop;
3490 img->flags = 0;
3493 return (IPTR) img;
3496 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely)
3498 LONG new, first, entries, visible;
3500 new = first = XGET(obj, MUIA_List_First);
3501 entries = XGET(obj, MUIA_List_Entries);
3502 visible = XGET(obj, MUIA_List_Visible);
3504 new += wheely;
3506 if (new > entries - visible)
3508 new = entries - visible;
3511 if (new < 0)
3513 new = 0;
3516 if (new != first)
3518 set(obj, MUIA_List_First, new);
3522 /**************************************************************************
3523 MUIM_HandleEvent
3524 **************************************************************************/
3525 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
3526 struct MUIP_HandleEvent *msg)
3528 struct MUI_ListData *data = INST_DATA(cl, obj);
3529 struct MUI_List_TestPos_Result pos;
3530 LONG seltype, old_active, new_active, visible, first, last, i;
3531 IPTR result = 0;
3532 BOOL select = FALSE, clear = FALSE, range_select = FALSE, changing;
3533 WORD delta;
3534 typeof(msg->muikey) muikey = msg->muikey;
3536 new_active = old_active = XGET(obj, MUIA_List_Active);
3537 visible = XGET(obj, MUIA_List_Visible);
3539 if (muikey != MUIKEY_NONE)
3541 result = MUI_EventHandlerRC_Eat;
3543 /* Make keys behave differently in read-only mode */
3544 if (data->read_only)
3546 switch (muikey)
3548 case MUIKEY_TOP:
3549 muikey = MUIKEY_LINESTART;
3550 break;
3552 case MUIKEY_BOTTOM:
3553 muikey = MUIKEY_LINEEND;
3554 break;
3556 case MUIKEY_UP:
3557 muikey = MUIKEY_LEFT;
3558 break;
3560 case MUIKEY_DOWN:
3561 case MUIKEY_PRESS:
3562 muikey = MUIKEY_RIGHT;
3563 break;
3567 switch (muikey)
3569 case MUIKEY_TOGGLE:
3570 if (data->multiselect != MUIV_Listview_MultiSelect_None
3571 && !data->read_only)
3573 select = TRUE;
3574 data->click_column = data->def_click_column;
3575 new_active = MUIV_List_Active_Down;
3577 else
3579 DoMethod(obj, MUIM_List_Jump, 0);
3580 muikey = MUIKEY_NONE;
3582 break;
3584 case MUIKEY_TOP:
3585 new_active = MUIV_List_Active_Top;
3586 break;
3588 case MUIKEY_BOTTOM:
3589 new_active = MUIV_List_Active_Bottom;
3590 break;
3592 case MUIKEY_LEFT:
3593 case MUIKEY_WORDLEFT:
3594 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Up);
3595 break;
3597 case MUIKEY_RIGHT:
3598 case MUIKEY_WORDRIGHT:
3599 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Down);
3600 break;
3602 case MUIKEY_LINESTART:
3603 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Top);
3604 break;
3606 case MUIKEY_LINEEND:
3607 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Bottom);
3608 break;
3610 case MUIKEY_UP:
3611 new_active = MUIV_List_Active_Up;
3612 break;
3614 case MUIKEY_DOWN:
3615 new_active = MUIV_List_Active_Down;
3616 break;
3618 case MUIKEY_PRESS:
3619 data->click_column = data->def_click_column;
3620 superset(cl, obj, MUIA_Listview_ClickColumn,
3621 data->click_column);
3622 set(obj, MUIA_Listview_DoubleClick, TRUE);
3623 break;
3625 case MUIKEY_PAGEUP:
3626 if (data->read_only)
3627 DoWheelMove(cl, obj, -visible);
3628 else
3629 new_active = MUIV_List_Active_PageUp;
3630 break;
3632 case MUIKEY_PAGEDOWN:
3633 if (data->read_only)
3634 DoWheelMove(cl, obj, visible);
3635 else
3636 new_active = MUIV_List_Active_PageDown;
3637 break;
3639 default:
3640 result = 0;
3643 else if (msg->imsg)
3645 DoMethod(obj, MUIM_List_TestPos, msg->imsg->MouseX, msg->imsg->MouseY,
3646 (IPTR) &pos);
3648 switch (msg->imsg->Class)
3650 case IDCMP_MOUSEBUTTONS:
3651 if (msg->imsg->Code == SELECTDOWN)
3653 if (_isinobject(data->area, msg->imsg->MouseX,
3654 msg->imsg->MouseY))
3656 data->mouse_click = MOUSE_CLICK_ENTRY;
3658 if (!data->read_only && pos.entry != -1)
3660 new_active = pos.entry;
3662 clear = (data->multiselect
3663 == MUIV_Listview_MultiSelect_Shifted
3664 && (msg->imsg->Qualifier
3665 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0);
3666 seltype = clear ? MUIV_List_Select_On
3667 : MUIV_List_Select_Toggle;
3668 select = data->multiselect
3669 != MUIV_Listview_MultiSelect_None;
3671 /* Handle MUIA_Listview_ClickColumn */
3672 data->click_column = pos.column;
3673 superset(cl, obj, MUIA_Listview_ClickColumn,
3674 data->click_column);
3676 /* Handle double clicking */
3677 if (data->last_active == pos.entry
3678 && DoubleClick(data->last_secs, data->last_mics,
3679 msg->imsg->Seconds, msg->imsg->Micros))
3681 set(obj, MUIA_Listview_DoubleClick, TRUE);
3682 data->last_active = -1;
3683 data->last_secs = data->last_mics = 0;
3685 else
3687 data->last_active = pos.entry;
3688 data->last_secs = msg->imsg->Seconds;
3689 data->last_mics = msg->imsg->Micros;
3692 /* Look out for mouse movement, timer and
3693 inactive-window events while mouse button is
3694 down */
3695 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3696 (IPTR) &data->ehn);
3697 data->ehn.ehn_Events |= (IDCMP_MOUSEMOVE
3698 | IDCMP_INTUITICKS |IDCMP_INACTIVEWINDOW);
3699 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3700 (IPTR) &data->ehn);
3704 else
3706 /* Activate object */
3707 if (msg->imsg->Code == SELECTUP && data->mouse_click)
3709 set(_win(obj), MUIA_Window_ActiveObject, (IPTR)obj);
3710 data->mouse_click = 0;
3713 /* Restore normal event mask */
3714 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3715 (IPTR) &data->ehn);
3716 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
3717 | IDCMP_INACTIVEWINDOW);
3718 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3719 (IPTR) &data->ehn);
3721 break;
3723 case IDCMP_MOUSEMOVE:
3724 case IDCMP_INTUITICKS:
3725 if (pos.flags & MUI_LPR_ABOVE)
3726 new_active = MUIV_List_Active_Up;
3727 else if (pos.flags & MUI_LPR_BELOW)
3728 new_active = MUIV_List_Active_Down;
3729 else
3730 new_active = pos.entry;
3732 select = new_active != old_active
3733 && data->multiselect != MUIV_Listview_MultiSelect_None;
3734 if (select)
3736 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3737 MUIV_List_Select_Ask, &seltype);
3738 range_select = new_active >= 0;
3741 break;
3743 case IDCMP_INACTIVEWINDOW:
3744 /* Stop listening for events we only listen to when mouse button is
3745 down: we will not be informed of the button being released */
3746 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3747 (IPTR) &data->ehn);
3748 data->ehn.ehn_Events &=
3749 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS | IDCMP_INACTIVEWINDOW);
3750 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3751 (IPTR) &data->ehn);
3752 break;
3754 case IDCMP_RAWKEY:
3755 /* Scroll wheel */
3756 if (data->vert && _isinobject(data->vert, msg->imsg->MouseX,
3757 msg->imsg->MouseY))
3758 delta = 1;
3759 else if (_isinobject(data->area, msg->imsg->MouseX,
3760 msg->imsg->MouseY))
3761 delta = 4;
3762 else
3763 delta = 0;
3765 if (delta != 0)
3767 switch (msg->imsg->Code)
3769 case RAWKEY_NM_WHEEL_UP:
3770 DoWheelMove(cl, obj, -delta);
3771 break;
3773 case RAWKEY_NM_WHEEL_DOWN:
3774 DoWheelMove(cl, obj, delta);
3775 break;
3777 result = MUI_EventHandlerRC_Eat;
3779 break;
3783 /* Decide in advance if any selections may change */
3784 changing = clear || muikey == MUIKEY_TOGGLE || select;
3786 /* Change selected and active entries */
3787 if (changing)
3788 set(obj, MUIA_Listview_SelectChange, TRUE);
3790 if (clear)
3792 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
3793 MUIV_List_Select_Off, NULL);
3796 if (muikey == MUIKEY_TOGGLE)
3798 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3799 MUIV_List_Select_Toggle, NULL);
3800 select = FALSE;
3803 if (new_active != old_active)
3804 set(obj, MUIA_List_Active, new_active);
3806 if (select)
3808 if (range_select)
3810 if (old_active < new_active)
3811 first = old_active + 1, last = new_active;
3812 else
3813 first = new_active, last = old_active - 1;
3814 for (i = first; i <= last; i++)
3815 DoMethod(obj, MUIM_List_Select, i, seltype, NULL);
3817 else
3818 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3819 seltype, NULL);
3822 if (changing)
3823 set(obj, MUIA_Listview_SelectChange, FALSE);
3825 return result;
3828 /**************************************************************************
3829 Dispatcher
3830 **************************************************************************/
3831 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
3833 switch (msg->MethodID)
3835 case OM_NEW:
3836 return List__OM_NEW(cl, obj, (struct opSet *)msg);
3837 case OM_DISPOSE:
3838 return List__OM_DISPOSE(cl, obj, msg);
3839 case OM_SET:
3840 return List__OM_SET(cl, obj, (struct opSet *)msg);
3841 case OM_GET:
3842 return List__OM_GET(cl, obj, (struct opGet *)msg);
3844 case MUIM_Setup:
3845 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
3846 case MUIM_Cleanup:
3847 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
3848 case MUIM_HandleEvent:
3849 return List__MUIM_HandleEvent(cl, obj, (struct MUIP_HandleEvent *)msg);
3850 case MUIM_AskMinMax:
3851 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
3852 case MUIM_Show:
3853 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
3854 case MUIM_Hide:
3855 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
3856 case MUIM_Draw:
3857 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
3858 case MUIM_Layout:
3859 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
3860 case MUIM_List_Clear:
3861 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
3862 case MUIM_List_Sort:
3863 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
3864 case MUIM_List_Exchange:
3865 return List__MUIM_Exchange(cl, obj,
3866 (struct MUIP_List_Exchange *)msg);
3867 case MUIM_List_Insert:
3868 return List__MUIM_Insert(cl, obj, (APTR) msg);
3869 case MUIM_List_InsertSingle:
3870 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
3871 case MUIM_List_GetEntry:
3872 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
3873 case MUIM_List_Redraw:
3874 return List__MUIM_Redraw(cl, obj, (APTR) msg);
3875 case MUIM_List_Remove:
3876 return List__MUIM_Remove(cl, obj, (APTR) msg);
3877 case MUIM_List_Select:
3878 return List__MUIM_Select(cl, obj, (APTR) msg);
3879 case MUIM_List_Construct:
3880 return List__MUIM_Construct(cl, obj, (APTR) msg);
3881 case MUIM_List_Destruct:
3882 return List__MUIM_Destruct(cl, obj, (APTR) msg);
3883 case MUIM_List_Compare:
3884 return List__MUIM_Compare(cl, obj, (APTR) msg);
3885 case MUIM_List_Display:
3886 return List__MUIM_Display(cl, obj, (APTR) msg);
3887 case MUIM_List_SelectChange:
3888 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
3889 case MUIM_List_CreateImage:
3890 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
3891 case MUIM_List_DeleteImage:
3892 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
3893 case MUIM_List_Jump:
3894 return List__MUIM_Jump(cl, obj, (APTR) msg);
3895 case MUIM_List_Move:
3896 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
3897 case MUIM_List_NextSelected:
3898 return List__MUIM_NextSelected(cl, obj,
3899 (struct MUIP_List_NextSelected *)msg);
3900 case MUIM_List_TestPos:
3901 return List__MUIM_TestPos(cl, obj, (APTR) msg);
3902 case MUIM_DragQuery:
3903 return List__MUIM_DragQuery(cl, obj, (APTR) msg);
3904 case MUIM_DragFinish:
3905 return List__MUIM_DragFinish(cl, obj, (APTR) msg);
3906 case MUIM_DragReport:
3907 return List__MUIM_DragReport(cl, obj, (APTR) msg);
3908 case MUIM_DragDrop:
3909 return List__MUIM_DragDrop(cl, obj, (APTR) msg);
3910 case MUIM_CreateDragImage:
3911 return List__MUIM_CreateDragImage(cl, obj, (APTR) msg);
3914 return DoSuperMethodA(cl, obj, msg);
3916 BOOPSI_DISPATCHER_END
3919 * Class descriptor.
3921 const struct __MUIBuiltinClass _MUI_List_desc =
3923 MUIC_List,
3924 MUIC_Group,
3925 sizeof(struct MUI_ListData),
3926 (void *) List_Dispatcher