Fixed MUIA_List_AdjustWidth and MUIA_List_AdjustHeight. As well as the
[AROS.git] / workbench / libs / muimaster / classes / list.c
bloba5d0d97589d8bc823890975ae0b90d628ba8d243
1 /*
2 Copyright © 2002-2016, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <string.h>
7 #include <stdlib.h>
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <devices/rawkeycodes.h>
14 #include <clib/alib_protos.h>
15 #include <proto/exec.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
20 #include <proto/muimaster.h>
22 /* #define MYDEBUG 1 */
23 #include "debug.h"
24 #include "mui.h"
25 #include "muimaster_intern.h"
26 #include "support.h"
27 #include "imspec.h"
28 #include "textengine.h"
29 #include "listimage.h"
30 #include "prefs.h"
32 extern struct Library *MUIMasterBase;
34 #define ENTRY_TITLE (-1)
36 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
37 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
39 #define BAR_WIDTH 2
41 enum
43 ARG_DELTA,
44 ARG_PREPARSE,
45 ARG_WEIGHT,
46 ARG_MINWIDTH,
47 ARG_MAXWIDTH,
48 ARG_COL,
49 ARG_BAR,
50 ARG_CNT
54 struct ListEntry
56 APTR data;
57 LONG width; /* Line width */
58 LONG height; /* Line height */
59 WORD flags; /* see below */
60 LONG widths[]; /* Widths of the columns */
63 #define ENTRY_SELECTED (1<<0)
66 struct ColumnInfo
68 int colno; /* Column number */
69 int user_width; /* user set width; -1 if entry width */
70 int min_width; /* min width percentage */
71 int max_width; /* min width percentage */
72 int weight;
73 int delta; /* ignored for the first and last column, defaults to 4 */
74 int bar;
75 STRPTR preparse;
76 int entries_width; /* width of the entries (maximum of all widths) */
79 struct MUI_ImageSpec_intern;
81 struct MUI_ListData
83 /* bool attrs */
84 ULONG flags;
86 APTR intern_pool; /* The internal pool which the class has allocated */
87 LONG intern_puddle_size;
88 LONG intern_thresh_size;
89 APTR pool; /* the pool which is used to allocate list entries */
91 struct Hook *construct_hook;
92 struct Hook *compare_hook;
93 struct Hook *destruct_hook;
94 struct Hook *display_hook;
95 struct Hook *multi_test_hook;
97 struct Hook default_compare_hook;
99 /* List management, currently we use a simple flat array, which is not
100 * good if many entries are inserted/deleted */
101 LONG entries_num; /* Number of Entries in the list */
102 LONG entries_allocated;
103 struct ListEntry **entries;
105 LONG entries_first; /* first visible entry */
106 LONG entries_visible; /* number of visible entries,
107 * determined at MUIM_Layout */
108 LONG entries_active;
109 LONG insert_position; /* pos of the last insertion */
111 LONG entry_maxheight; /* Maximum height of an entry */
112 ULONG entry_minheight; /* from MUIA_List_MinLineHeight */
114 LONG entries_totalheight;
115 LONG entries_maxwidth;
117 LONG vertprop_entries;
118 LONG vertprop_visible;
119 LONG vertprop_first;
121 LONG confirm_entries_num; /* These are the correct entries num, used
122 * so you cannot set MUIA_List_Entries to
123 * wrong values */
125 LONG entries_top_pixel; /* Where the entries start */
127 /* Column managment, is allocated by ParseListFormat() and freed
128 * by CleanListFormat() */
129 STRPTR format;
130 LONG columns; /* Number of columns the list has */
131 struct ColumnInfo *ci;
132 STRPTR *preparses;
133 STRPTR *strings_mem; /* safe pointer to allocated memory for strings[] */
134 STRPTR *strings; /* the strings for the display function, one
135 * more than needed (for the entry position) */
137 /* Titlestuff */
138 int title_height; /* The complete height of the title */
139 STRPTR title; /* On single column lists this is the title,
140 * otherwise 1. NULL for no title(s) */
142 /* Cursor images */
143 struct MUI_ImageSpec_intern *list_cursor;
144 struct MUI_ImageSpec_intern *list_select;
145 struct MUI_ImageSpec_intern *list_selcur;
147 /* Render optimization */
148 int update; /* 1 - update everything, 2 - redraw entry at update_pos,
149 * 3 - scroll to current entries_first (old value is in
150 * update_pos) */
151 int update_pos;
153 LONG drop_mark_y;
155 /* list images */
156 struct MinList images;
158 /* user prefs */
159 ListviewRefresh prefs_refresh;
160 UWORD prefs_linespacing;
161 BOOL prefs_smoothed;
162 UWORD prefs_smoothval;
164 /* render space handling */
165 Object *area;
166 BOOL area_replaced;
167 BOOL area_connected;
169 /***************************/
170 /* Former Listview members */
171 /***************************/
173 Object *vert;
174 BOOL vert_connected;
175 IPTR scroller_pos;
176 BOOL read_only;
177 IPTR multiselect;
179 /* clicked column */
180 LONG click_column;
181 LONG def_click_column;
183 LONG mouse_click; /* see below if mouse is held down */
185 /* double click */
186 ULONG last_secs;
187 ULONG last_mics;
188 ULONG last_active;
190 struct MUI_EventHandlerNode ehn;
192 /* user prefs */
193 ListviewMulti prefs_multi;
195 BOOL select_change;
196 BOOL doubleclick;
198 struct Hook hook;
201 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
202 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
204 #define LIST_ADJUSTWIDTH (1<<0)
205 #define LIST_ADJUSTHEIGHT (1<<1)
206 #define LIST_AUTOVISIBLE (1<<2)
207 #define LIST_DRAGSORTABLE (1<<3)
208 #define LIST_SHOWDROPMARKS (1<<4)
209 #define LIST_QUIET (1<<5)
212 /****** List.mui/MUIA_List_Active ********************************************
214 * NAME
215 * MUIA_List_Active -- (V4) [ISG], LONG
217 * FUNCTION
218 * The index of the active entry. There can be at most one active entry
219 * in a list. The active entry is highlighted visibly, except for
220 * read-only lists (those whose Listview has MUIA_Listview_Input set to
221 * FALSE). Selecting an entry with the mouse, or moving through the list
222 * with keyboard controls will also change the active entry (again
223 * excepting read-only lists).
225 * When set programmatically through this attribute, some special values
226 * can be used:
228 * MUIV_List_Active_Off
229 * MUIV_List_Active_Top
230 * MUIV_List_Active_Bottom
231 * MUIV_List_Active_Up
232 * MUIV_List_Active_Down
233 * MUIV_List_Active_PageUp
234 * MUIV_List_Active_PageDown
236 * When this attribute is read, either the index of the active entry or
237 * the special value MUIV_List_Active_Off will be returned.
239 * Setting this attribute to a new value will additionally have the same
240 * effect as calling the MUIM_List_Jump method with the specified or
241 * implied index.
243 * NOTES
244 * The concept of an active entry must not be confused with that of a
245 * selected entry.
247 * SEE ALSO
248 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
250 ******************************************************************************
254 /****** List.mui/MUIA_List_CompareHook ***************************************
256 * NAME
257 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
259 * FUNCTION
260 * The provided hook indicates the sort ordering of two list entries.
261 * The hook receives list-entry data pointers as its second and third
262 * arguments. The hook should return a negative value if the first entry
263 * should be placed before the second entry, a positive value if the
264 * first entry should be placed after the second entry, and zero if the
265 * entries are equal.
267 * In addition to being used internally for sorting operations, this hook
268 * will be called when MUIM_List_Compare is externally invoked.
270 * If this attribute is not specified or is set to NULL, all list entries
271 * must be strings.
273 ******************************************************************************
277 /****** List.mui/MUIA_List_First *********************************************
279 * NAME
280 * MUIA_List_First -- (V4) [..G], LONG
282 * FUNCTION
283 * The index of the first entry that can be seen (assuming nothing
284 * obscures the list) This value of this attribute is -1 when the
285 * list's window is not open.
287 * NOTES
288 * Notification does not occur on this attribute in MUI.
290 * SEE ALSO
291 * MUIA_List_First, MUIA_List_Entries
293 ******************************************************************************
297 /****** List.mui/MUIA_List_MultiTestHook *************************************
299 * NAME
300 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
302 * FUNCTION
303 * The provided hook indicates whether a particular list entry
304 * may be multiselected. The hook receives the list-entry data pointer as
305 * its third argument, and returns a Boolean value. If this attribute is
306 * not specified or is set to NULL, all list entries are considered
307 * multi-selectable.
309 * Whenever an entry is about to be selected, this hook is called if
310 * there are other entries already selected. If the hook returns TRUE,
311 * the entry may be multi-selected; if the hook returns FALSE, the entry
312 * remains unselected.
314 * Additionally, if a non-multi-selectable entry has been selected (as
315 * the only selected entry in the list), any attempt to select an
316 * additional entry will fail.
318 ******************************************************************************
322 /****** List.mui/MUIA_List_Title *********************************************
324 * NAME
325 * MUIA_List_Title -- (V6) [ISG], char *
327 * FUNCTION
328 * A heading for the list, placed above list entries. A value of NULL
329 * means no title is used. A value of TRUE means that the custom
330 * display hook provides a separate title for each column; the hook
331 * must then provide column titles instead of normal column data when
332 * the entry pointer provided is NULL.
334 * NOTES
335 * If a string is set for this attribute, it is not cached within the
336 * object.
338 * SEE ALSO
339 * MUIA_List_DisplayHook
341 ******************************************************************************
345 /****** List.mui/MUIA_List_Visible *******************************************
347 * NAME
348 * MUIA_List_Visible -- (V4) [..G], LONG
350 * FUNCTION
351 * The number of entries that can be seen at once with the list's
352 * current dimensions. This value of this attribute is -1 when the
353 * list's window is not open.
355 * NOTES
356 * Notification does not occur on this attribute in MUI.
358 * SEE ALSO
359 * MUIA_List_First, MUIA_List_Entries
361 ******************************************************************************
365 /**************************************************************************
366 Allocate a single list entry, does not initialize it (except the pointer)
367 **************************************************************************/
368 static struct ListEntry *AllocListEntry(struct MUI_ListData *data)
370 struct ListEntry *le;
371 /* what happens, if data->columns is later increased by MUIA_List_Format? */
372 IPTR size = sizeof(struct ListEntry) + sizeof(LONG) * (data->columns + 1);
374 le = (struct ListEntry *) AllocVecPooled(data->pool, size);
375 D(bug("List AllocListEntry %p, %ld bytes\n", le, size));
376 if(le)
378 /* possible, that we have an external pool, which does not have
379 MEMF_CLEAR set.. */
380 memset(le, 0, size);
382 return le;
385 /**************************************************************************
386 Deallocate a single list entry, does not deinitialize it
387 **************************************************************************/
388 static void FreeListEntry(struct MUI_ListData *data,
389 struct ListEntry *entry)
391 D(bug("FreeListEntry %p\n", entry));
392 FreeVecPooled(data->pool, entry);
395 /**************************************************************************
396 Ensures that there can be at least the given amount of entries within
397 the list. Returns 0 if not. It also allocates the space for the title.
398 It can be accessed with data->entries[ENTRY_TITLE]
399 **************************************************************************/
400 static int SetListSize(struct MUI_ListData *data, LONG size)
402 struct ListEntry **new_entries;
403 int new_entries_allocated;
405 if (size + 1 <= data->entries_allocated)
406 return 1;
408 new_entries_allocated = data->entries_allocated * 2 + 4;
409 if (new_entries_allocated < size + 1)
410 new_entries_allocated = size + 1 + 10; /* 10 is just random */
412 D(bug("List %p : SetListSize allocating %ld bytes\n", data,
413 new_entries_allocated * sizeof(struct ListEntry *)));
414 new_entries =
415 AllocVec(new_entries_allocated * sizeof(struct ListEntry *), 0);
416 if (NULL == new_entries)
417 return 0;
418 if (data->entries)
420 CopyMem(data->entries - 1, new_entries,
421 (data->entries_num + 1) * sizeof(struct ListEntry *));
422 FreeVec(data->entries - 1);
424 data->entries = new_entries + 1;
425 data->entries_allocated = new_entries_allocated;
426 return 1;
429 /**************************************************************************
430 Prepares the insertion of count entries at pos.
431 This function doesn't care if there is enough space in the datastructure.
432 SetListSize() must be used first.
433 With current implementation, this call will never fail
434 **************************************************************************/
435 static int PrepareInsertListEntries(struct MUI_ListData *data, int pos,
436 int count)
438 memmove(&data->entries[pos + count], &data->entries[pos],
439 (data->entries_num - pos) * sizeof(struct ListEntry *));
440 return 1;
443 /**************************************************************************
444 Removes count (already deinitalized) list entries starting az pos.
445 **************************************************************************/
446 static void RemoveListEntries(struct MUI_ListData *data, int pos, int count)
448 // FIXME: segfault if entries_num = pos = count = 1
449 memmove(&data->entries[pos], &data->entries[pos + count],
450 (data->entries_num - (pos + count)) * sizeof(struct ListEntry *));
453 /**************************************************************************
454 Frees all memory allocated by ParseListFormat()
455 **************************************************************************/
456 static void FreeListFormat(struct MUI_ListData *data)
458 int i;
460 if (data->ci)
462 for (i = 0; i < data->columns; i++)
464 FreeVec(data->ci[i].preparse);
465 data->ci[i].preparse = NULL;
467 FreeVec(data->ci);
468 data->ci = NULL;
470 FreeVec(data->preparses);
471 data->preparses = NULL;
472 if (data->strings_mem)
474 FreeVec(data->strings_mem);
475 data->strings_mem = NULL;
476 data->strings = NULL;
478 data->columns = 0;
481 /**************************************************************************
482 Parses the given format string (also frees a previously parsed format).
483 Return 0 on failure.
484 **************************************************************************/
485 static int ParseListFormat(struct MUI_ListData *data, STRPTR format)
487 int new_columns, i;
488 STRPTR ptr;
489 STRPTR format_sep;
490 char c;
492 IPTR args[ARG_CNT];
493 struct RDArgs *rdargs;
495 if (!format)
496 format = (STRPTR) "";
498 ptr = format;
500 FreeListFormat(data);
502 new_columns = 1;
504 /* Count the number of columns first */
505 while ((c = *ptr++))
506 if (c == ',')
507 new_columns++;
509 if (!(data->preparses =
510 AllocVec((new_columns + 10) * sizeof(STRPTR), 0)))
511 return 0;
513 if (!(data->strings_mem = AllocVec((new_columns + 1 + 10)
514 * sizeof(STRPTR), 0))) /* hold enough space also for the entry pos,
515 * used by orginal MUI and also some
516 * security space */
517 return 0;
518 data->strings=data->strings_mem;
520 if (!(data->ci = AllocVec(new_columns * sizeof(struct ColumnInfo), 0)))
521 return 0;
523 // set defaults
524 for (i = 0; i < new_columns; i++)
526 data->ci[i].colno = -1; // -1 means: use unassigned column
527 data->ci[i].weight = 100;
528 data->ci[i].delta = 4;
529 data->ci[i].min_width = -1;
530 data->ci[i].max_width = -1;
531 data->ci[i].user_width = -1;
532 data->ci[i].bar = FALSE;
533 data->ci[i].preparse = NULL;
536 if ((format_sep = StrDup(format)) != 0)
538 for (i = 0; format_sep[i] != '\0'; i++)
540 if (format_sep[i] == ',')
541 format_sep[i] = '\0';
544 if ((rdargs = AllocDosObject(DOS_RDARGS, NULL)) != 0)
546 ptr = format_sep;
547 i = 0;
550 rdargs->RDA_Source.CS_Buffer = ptr;
551 rdargs->RDA_Source.CS_Length = strlen(ptr);
552 rdargs->RDA_Source.CS_CurChr = 0;
553 rdargs->RDA_DAList = 0;
554 rdargs->RDA_Buffer = NULL;
555 rdargs->RDA_BufSiz = 0;
556 rdargs->RDA_ExtHelp = NULL;
557 rdargs->RDA_Flags = 0;
559 memset(args, 0, sizeof args);
560 if (ReadArgs(FORMAT_TEMPLATE, args, rdargs))
562 if (args[ARG_COL])
563 data->ci[i].colno = *(LONG *) args[ARG_COL];
564 if (args[ARG_WEIGHT])
565 data->ci[i].weight = *(LONG *) args[ARG_WEIGHT];
566 if (args[ARG_DELTA])
567 data->ci[i].delta = *(LONG *) args[ARG_DELTA];
568 if (args[ARG_MINWIDTH])
569 data->ci[i].min_width =
570 *(LONG *) args[ARG_MINWIDTH];
571 if (args[ARG_MAXWIDTH])
572 data->ci[i].max_width =
573 *(LONG *) args[ARG_MAXWIDTH];
574 data->ci[i].bar = args[ARG_BAR];
575 if (args[ARG_PREPARSE])
576 data->ci[i].preparse =
577 StrDup((STRPTR) args[ARG_PREPARSE]);
579 FreeArgs(rdargs);
581 ptr += strlen(ptr) + 1;
582 i++;
584 while (i < new_columns);
585 FreeDosObject(DOS_RDARGS, rdargs);
587 FreeVec(format_sep);
590 for (i = 0; i < new_columns; i++)
592 D(bug("colno %d weight %d delta %d preparse %s\n",
593 data->ci[i].colno, data->ci[i].weight, data->ci[i].delta,
594 data->ci[i].preparse));
597 data->columns = new_columns;
598 data->strings++; /* Skip entry pos */
600 return 1;
603 /**************************************************************************
604 Call the MUIM_List_Display for the given entry. It fills out
605 data->string and data->preparses
606 **************************************************************************/
607 static void DisplayEntry(struct IClass *cl, Object *obj, int entry_pos)
609 struct MUI_ListData *data = INST_DATA(cl, obj);
610 APTR entry_data;
611 int col;
613 for (col = 0; col < data->columns; col++)
614 data->preparses[col] = data->ci[col].preparse;
616 if (entry_pos == ENTRY_TITLE)
618 if ((data->columns == 1) && (data->title != (STRPTR) 1))
620 *data->strings = data->title;
621 return;
623 entry_data = NULL; /* it's a title request */
625 else
626 entry_data = data->entries[entry_pos]->data;
628 /* Get the display formation */
629 DoMethod(obj, MUIM_List_Display, (IPTR) entry_data,
630 (IPTR) data->strings, entry_pos, (IPTR) data->preparses);
633 /**************************************************************************
634 Determine the dims of a single entry and adapt the columninfo according
635 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
636 be redrawn after this operation, 1 if all entries need to be redrawn.
637 **************************************************************************/
638 static int CalcDimsOfEntry(struct IClass *cl, Object *obj, int pos)
640 struct MUI_ListData *data = INST_DATA(cl, obj);
641 struct ListEntry *entry = data->entries[pos];
642 int j;
643 int ret = 0;
645 if (!entry)
646 return ret;
648 if (!(_flags(obj) & MADF_SETUP))
649 return ret;
651 DisplayEntry(cl, obj, pos);
653 /* Set height to at least minheight */
654 if (data->entries[pos]->height < data->entry_minheight)
655 data->entries[pos]->height = data->entry_minheight;
657 for (j = 0; j < data->columns; j++)
659 ZText *text =
660 zune_text_new(data->preparses[j], data->strings[j],
661 ZTEXT_ARG_NONE, 0);
662 if (text != NULL)
664 zune_text_get_bounds(text, obj);
666 if (text->height > data->entries[pos]->height)
668 data->entries[pos]->height = text->height;
669 /* entry height changed, redraw all entries later */
670 ret = 1;
672 data->entries[pos]->widths[j] = text->width;
674 if (text->width > data->ci[j].entries_width)
676 /* This entry has a greater width for this column than any
677 * other entry, so we store this value
679 data->ci[j].entries_width = text->width;
680 /* column width changed, redraw all entries later */
681 ret = 1;
684 zune_text_destroy(text);
687 if (data->entries[pos]->height > data->entry_maxheight)
689 data->entry_maxheight = data->entries[pos]->height;
690 /* maximum entry height changed, redraw all entries later */
691 ret = 1;
694 return ret;
697 /**************************************************************************
698 Determine the widths of the entries
699 **************************************************************************/
700 static void CalcWidths(struct IClass *cl, Object *obj)
702 int i, j;
703 struct MUI_ListData *data = INST_DATA(cl, obj);
705 if (!(_flags(obj) & MADF_SETUP))
706 return;
708 for (j = 0; j < data->columns; j++)
709 data->ci[j].entries_width = 0;
711 data->entry_maxheight = 0;
712 data->entries_totalheight = 0;
713 data->entries_maxwidth = 0;
715 for (i = (data->title ? ENTRY_TITLE : 0); i < data->entries_num; i++)
717 CalcDimsOfEntry(cl, obj, i);
718 data->entries_totalheight += data->entries[i]->height;
721 for (j = 0; j < data->columns; j++)
722 data->entries_maxwidth += data->ci[j].entries_width
723 + data->ci[j].delta + (data->ci[j].bar ? BAR_WIDTH : 0);
725 if (!data->entry_maxheight)
726 data->entry_maxheight = 1;
729 /**************************************************************************
730 Calculates the number of visible entry lines. Returns 1 if it has
731 changed
732 **************************************************************************/
733 static int CalcVertVisible(struct IClass *cl, Object *obj)
735 struct MUI_ListData *data = INST_DATA(cl, obj);
736 int old_entries_visible = data->entries_visible;
737 int old_entries_top_pixel = data->entries_top_pixel;
739 data->vertprop_visible = data->entries_visible =
740 (_mheight(data->area) - data->title_height)
741 / (data->entry_maxheight /* + data->prefs_linespacing */ );
743 /* Distribute extra vertical space evenly between top and bottom of
744 * list */
746 data->entries_top_pixel = _mtop(data->area) + data->title_height
747 + (_mheight(data->area) - data->title_height
749 data->entries_visible *
750 (data->entry_maxheight /* + data->prefs_linespacing */ )) / 2;
752 if (data->entries_visible != old_entries_visible)
754 superset(cl, obj, MUIA_List_Visible, data->entries_visible);
755 superset(cl, obj, MUIA_List_VertProp_Visible, data->entries_visible);
758 return (old_entries_visible != data->entries_visible)
759 || (old_entries_top_pixel != data->entries_top_pixel);
762 /**************************************************************************
763 Default hook to compare two list entries. Works for strings only.
764 **************************************************************************/
765 AROS_UFH3S(int, default_compare_func,
766 AROS_UFHA(struct Hook *, h, A0),
767 AROS_UFHA(char *, s2, A2),
768 AROS_UFHA(char *, s1, A1))
770 AROS_USERFUNC_INIT
772 return Stricmp(s1, s2);
774 AROS_USERFUNC_EXIT
777 #define PROP_VERT_FIRST 1
779 static ULONG List_Function(struct Hook *hook, Object * obj, void **msg)
781 struct MUI_ListData *data = (struct MUI_ListData *)hook->h_Data;
782 SIPTR type = (SIPTR) msg[0];
783 SIPTR val = (SIPTR) msg[1];
785 switch (type)
787 case PROP_VERT_FIRST:
788 get(data->vert, MUIA_Prop_First, &val);
789 nnset(obj, MUIA_List_VertProp_First, val);
790 break;
792 return 0;
795 /* At entry to this function, data->area is always set, but data->vert may
796 * or may not be set */
797 static void List_HandleScrollerPos(struct IClass *cl, Object *obj)
799 struct MUI_ListData *data = INST_DATA(cl, obj);
800 BOOL vert_not_used = FALSE;
802 /* Disallow any changes after setup. This function should basically be
803 * creation-time only */
804 if (_flags(obj) & MADF_SETUP)
805 return;
807 /* Remove both objects */
808 if (data->area_connected)
809 DoMethod(obj, OM_REMMEMBER, data->area);
810 if (data->vert_connected)
811 DoMethod(obj, OM_REMMEMBER, data->vert);
813 /* Add list and/or scroller */
814 switch (data->scroller_pos)
816 case MUIV_Listview_ScrollerPos_None:
817 vert_not_used = TRUE;
818 DoMethod(obj, OM_ADDMEMBER, data->area);
819 break;
820 case MUIV_Listview_ScrollerPos_Left:
821 if (!data->vert)
822 data->vert =ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
823 DoMethod(obj, OM_ADDMEMBER, data->vert);
824 DoMethod(obj, OM_ADDMEMBER, data->area);
825 break;
826 default:
827 if (!data->vert)
828 data->vert = ScrollbarObject, MUIA_Group_Horiz, FALSE, End;
829 DoMethod(obj, OM_ADDMEMBER, data->area);
830 DoMethod(obj, OM_ADDMEMBER, data->vert);
831 break;
834 data->area_connected = TRUE;
836 /* Handle case where it was decided that vert will not be used */
837 if (vert_not_used)
839 if (data->vert)
841 if (data->vert_connected)
843 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_First,
844 (IPTR) data->vert);
845 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_Visible,
846 (IPTR) data->vert);
847 DoMethod(obj, MUIM_KillNotifyObj, MUIA_List_VertProp_Entries,
848 (IPTR) data->vert);
849 data->vert_connected = FALSE;
852 MUI_DisposeObject(data->vert);
853 data->vert = NULL;
857 /* If at this point data->vert is not null, it means vert is to be
858 * connected */
859 if (data->vert && !data->vert_connected)
861 LONG entries = 0, first = 0, visible = 0;
863 get(obj, MUIA_List_VertProp_First, &first);
864 get(obj, MUIA_List_VertProp_Visible, &visible);
865 get(obj, MUIA_List_VertProp_Entries, &entries);
867 SetAttrs(data->vert, MUIA_Prop_First, first,
868 MUIA_Prop_Visible, visible, MUIA_Prop_Entries, entries, TAG_DONE);
870 DoMethod(data->vert, MUIM_Notify, MUIA_Prop_First, MUIV_EveryTime,
871 (IPTR) obj, 4, MUIM_CallHook, (IPTR) &data->hook, PROP_VERT_FIRST,
872 MUIV_TriggerValue);
874 /* Pass prop object as DestObj (based on code in NList) */
875 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_First, MUIV_EveryTime,
876 (IPTR) data->vert, 3, MUIM_NoNotifySet,
877 MUIA_Prop_First, MUIV_TriggerValue);
878 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_Visible, MUIV_EveryTime,
879 (IPTR) data->vert, 3, MUIM_NoNotifySet,
880 MUIA_Prop_Visible, MUIV_TriggerValue);
881 DoMethod(obj, MUIM_Notify, MUIA_List_VertProp_Entries, MUIV_EveryTime,
882 (IPTR) data->vert, 3, MUIM_NoNotifySet,
883 MUIA_Prop_Entries, MUIV_TriggerValue);
885 data->vert_connected = TRUE;
889 /**************************************************************************
890 OM_NEW
891 **************************************************************************/
892 IPTR List__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
894 struct MUI_ListData *data;
895 struct TagItem *tag;
896 struct TagItem *tags;
897 APTR *array = NULL;
898 LONG new_entries_active = MUIV_List_Active_Off;
899 struct TagItem rectattrs[2] =
900 {{TAG_IGNORE, TAG_IGNORE }, {TAG_DONE, TAG_DONE}};
901 Object *area;
903 /* search for MUIA_Frame as it has to be passed to rectangle object */
904 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
906 if (tag->ti_Tag == MUIA_Frame)
908 rectattrs[0].ti_Tag = MUIA_Frame;
909 rectattrs[0].ti_Data = tag->ti_Data;
910 tag->ti_Tag = TAG_IGNORE;
911 break;
915 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
916 MUIA_Group_Horiz, TRUE,
917 MUIA_InnerLeft, 0,
918 MUIA_InnerRight, 0,
919 MUIA_Group_Spacing, 0,
920 MUIA_Font, MUIV_Font_List,
921 MUIA_ShowSelState, FALSE,
922 MUIA_InputMode, MUIV_InputMode_RelVerify,
923 MUIA_Background, MUII_ListBack,
924 TAG_MORE, (IPTR) msg->ops_AttrList,
925 TAG_DONE);
927 if (!obj)
928 return FALSE;
930 data = INST_DATA(cl, obj);
932 data->columns = 1;
933 data->entries_active = MUIV_List_Active_Off;
934 data->intern_puddle_size = 2008;
935 data->intern_thresh_size = 1024;
936 data->default_compare_hook.h_Entry = (HOOKFUNC) default_compare_func;
937 data->default_compare_hook.h_SubEntry = 0;
938 data->compare_hook = &(data->default_compare_hook);
939 data->flags = LIST_SHOWDROPMARKS;
940 data->area_replaced = FALSE;
941 data->area_connected = FALSE;
942 data->vert_connected = FALSE;
944 data->entries_visible = data->vertprop_visible = -1;
945 data->last_active = -1;
947 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS | IDCMP_RAWKEY;
948 data->ehn.ehn_Priority = 0;
949 data->ehn.ehn_Flags = 0;
950 data->ehn.ehn_Object = obj;
951 data->ehn.ehn_Class = cl;
953 /* HACK:
954 * List is a group where part of area is rendered and part is filled
955 * with other objects (inside of List dimensions). One such object is
956 * up/down arrow. This object depends on RelVerify mode to control
957 * behaviour. List also has the RelVerify mode. Area super class in case
958 * of both of those objects adds an event handler node with the same
959 * priority. Depending on the sort order, the event handler node of
960 * "list" can eat a click event and up/down arrows stop working. The
961 * hack is to decrease the priority of Area event handler for list to
962 * always favor up/down arrow. There are other hacky ways of solving
963 * this, but this seems least evil approach, as this hack is
964 * encapsulated in the List class itself.
966 muiAreaData(obj)->mad_ehn.ehn_Priority--;
968 data->hook.h_Entry = HookEntry;
969 data->hook.h_SubEntry = (HOOKFUNC) List_Function;
970 data->hook.h_Data = data;
972 area = (Object *)GetTagData(MUIA_List_ListArea, (IPTR) 0,
973 msg->ops_AttrList);
975 if (!area)
976 area = RectangleObject, MUIA_FillArea, FALSE, TAG_MORE,
977 (IPTR) rectattrs, End;
978 else
979 data->area_replaced = TRUE;
980 data->area = area;
982 /* parse initial taglist */
983 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
985 switch (tag->ti_Tag)
987 case MUIA_List_Active:
988 new_entries_active = tag->ti_Data;
989 break;
991 case MUIA_List_Pool:
992 data->pool = (APTR) tag->ti_Data;
993 break;
995 case MUIA_List_PoolPuddleSize:
996 data->intern_puddle_size = tag->ti_Data;
997 break;
999 case MUIA_List_PoolThreshSize:
1000 data->intern_thresh_size = tag->ti_Data;
1001 break;
1003 case MUIA_List_CompareHook:
1004 data->compare_hook = (struct Hook *)tag->ti_Data;
1005 if (data->compare_hook == NULL)
1006 data->compare_hook = &data->default_compare_hook;
1007 break;
1009 case MUIA_List_ConstructHook:
1010 data->construct_hook = (struct Hook *)tag->ti_Data;
1011 break;
1013 case MUIA_List_DestructHook:
1014 data->destruct_hook = (struct Hook *)tag->ti_Data;
1015 break;
1017 case MUIA_List_DisplayHook:
1018 data->display_hook = (struct Hook *)tag->ti_Data;
1019 break;
1021 case MUIA_List_MultiTestHook:
1022 data->multi_test_hook = (struct Hook *)tag->ti_Data;
1023 break;
1025 case MUIA_List_SourceArray:
1026 array = (APTR *) tag->ti_Data;
1027 break;
1029 case MUIA_List_Format:
1030 data->format = StrDup((STRPTR) tag->ti_Data);
1031 break;
1033 case MUIA_List_Title:
1034 data->title = (STRPTR) tag->ti_Data;
1035 break;
1037 case MUIA_List_MinLineHeight:
1038 data->entry_minheight = tag->ti_Data;
1039 break;
1041 case MUIA_List_AdjustHeight:
1042 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTHEIGHT);
1043 break;
1045 case MUIA_List_AdjustWidth:
1046 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTWIDTH);
1047 break;
1049 case MUIA_List_AutoVisible:
1050 _handle_bool_tag(data->flags, tag->ti_Data, LIST_AUTOVISIBLE);
1051 break;
1053 case MUIA_List_ShowDropMarks:
1054 _handle_bool_tag(data->flags, tag->ti_Data, LIST_SHOWDROPMARKS);
1055 break;
1057 case MUIA_List_DragSortable:
1058 _handle_bool_tag(data->flags, tag->ti_Data, LIST_DRAGSORTABLE);
1059 set(obj, MUIA_Draggable, tag->ti_Data);
1060 break;
1062 case MUIA_Listview_ScrollerPos:
1063 data->scroller_pos = tag->ti_Data;
1064 break;
1066 case MUIA_Listview_Input:
1067 data->read_only = !tag->ti_Data;
1068 break;
1070 case MUIA_Listview_MultiSelect:
1071 data->multiselect = tag->ti_Data;
1072 break;
1074 case MUIA_Listview_DoubleClick:
1075 data->doubleclick = tag->ti_Data != 0;
1076 break;
1078 case MUIA_Listview_DefClickColumn:
1079 data->def_click_column = tag->ti_Data;
1080 break;
1084 List_HandleScrollerPos(cl, obj);
1086 if (!data->pool)
1088 /* No memory pool given, so we create our own */
1089 data->pool = data->intern_pool =
1090 CreatePool(0, data->intern_puddle_size,
1091 data->intern_thresh_size);
1092 if (!data->pool)
1094 CoerceMethod(cl, obj, OM_DISPOSE);
1095 return 0;
1099 /* parse the list format */
1100 if (!(ParseListFormat(data, data->format)))
1102 CoerceMethod(cl, obj, OM_DISPOSE);
1103 return 0;
1106 /* This is neccessary for at least the title */
1107 if (!SetListSize(data, 0))
1109 CoerceMethod(cl, obj, OM_DISPOSE);
1110 return 0;
1113 if (!(data->entries[ENTRY_TITLE] = AllocListEntry(data)))
1115 CoerceMethod(cl, obj, OM_DISPOSE);
1116 return 0;
1119 if (array)
1121 int i;
1122 /* Count the number of elements */
1123 for (i = 0; array[i] != NULL; i++)
1125 /* Insert them */
1126 DoMethod(obj, MUIM_List_Insert, (IPTR) array, i,
1127 MUIV_List_Insert_Top);
1130 if ((data->entries_num) && (new_entries_active != MUIV_List_Active_Off))
1132 switch (new_entries_active)
1134 case MUIV_List_Active_Top:
1135 new_entries_active = 0;
1136 break;
1138 case MUIV_List_Active_Bottom:
1139 new_entries_active = data->entries_num - 1;
1140 break;
1143 if (new_entries_active < 0)
1144 new_entries_active = 0;
1145 else if (new_entries_active >= data->entries_num)
1146 new_entries_active = data->entries_num - 1;
1148 data->entries_active = new_entries_active;
1149 /* Selected entry will be moved into visible area */
1152 NewList((struct List *)&data->images);
1154 D(bug("List_New(%lx)\n", obj));
1156 return (IPTR) obj;
1159 /**************************************************************************
1160 OM_DISPOSE
1161 **************************************************************************/
1162 IPTR List__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
1164 struct MUI_ListData *data = INST_DATA(cl, obj);
1166 D(bug("List Dispose\n"));
1168 /* Call destruct method for every entry and free the entries manually
1169 * to avoid notification */
1170 while (data->confirm_entries_num)
1172 struct ListEntry *lentry =
1173 data->entries[--data->confirm_entries_num];
1174 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1175 (IPTR) data->pool);
1176 FreeListEntry(data, lentry);
1179 if (data->intern_pool)
1180 DeletePool(data->intern_pool);
1181 if (data->entries)
1182 FreeVec(data->entries - 1);
1183 /* title is currently before all other elements */
1185 FreeListFormat(data);
1186 FreeVec(data->format);
1188 return DoSuperMethodA(cl, obj, msg);
1192 /**************************************************************************
1193 OM_SET
1194 **************************************************************************/
1195 IPTR List__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
1197 struct MUI_ListData *data = INST_DATA(cl, obj);
1198 struct TagItem *tag;
1199 struct TagItem *tags;
1201 /* parse taglist */
1202 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
1204 switch (tag->ti_Tag)
1206 case MUIA_List_CompareHook:
1207 data->compare_hook = (struct Hook *)tag->ti_Data;
1208 if (data->compare_hook == NULL)
1209 data->compare_hook = &data->default_compare_hook;
1210 break;
1212 case MUIA_List_ConstructHook:
1213 data->construct_hook = (struct Hook *)tag->ti_Data;
1214 break;
1216 case MUIA_List_DestructHook:
1217 data->destruct_hook = (struct Hook *)tag->ti_Data;
1218 break;
1220 case MUIA_List_DisplayHook:
1221 data->display_hook = (struct Hook *)tag->ti_Data;
1222 break;
1224 case MUIA_List_MultiTestHook:
1225 data->multi_test_hook = (struct Hook *)tag->ti_Data;
1226 if (data->multi_test_hook != NULL)
1228 /* Clearing current selections is the easiest way to keep
1229 * selections consistent with the new hook */
1230 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
1231 MUIV_List_Select_Off, NULL);
1233 break;
1235 case MUIA_List_Title:
1236 data->title = (STRPTR) tag->ti_Data;
1237 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1238 break;
1240 case MUIA_List_VertProp_First:
1241 data->vertprop_first = tag->ti_Data;
1242 if (data->entries_first != tag->ti_Data)
1244 set(obj, MUIA_List_First, tag->ti_Data);
1246 break;
1248 case MUIA_List_Format:
1249 data->format = StrDup((STRPTR) tag->ti_Data);
1250 ParseListFormat(data, data->format);
1251 // FIXME: should we check for errors?
1252 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1253 break;
1255 case MUIA_List_VertProp_Entries:
1256 data->vertprop_entries = tag->ti_Data;
1257 break;
1259 case MUIA_List_VertProp_Visible:
1260 data->vertprop_visible = tag->ti_Data;
1261 data->entries_visible = tag->ti_Data;
1262 break;
1264 case MUIA_List_Active:
1266 LONG new_entries_active = tag->ti_Data;
1268 if ((data->entries_num)
1269 && (new_entries_active != MUIV_List_Active_Off))
1271 switch (new_entries_active)
1273 case MUIV_List_Active_Top:
1274 new_entries_active = 0;
1275 break;
1277 case MUIV_List_Active_Bottom:
1278 new_entries_active = data->entries_num - 1;
1279 break;
1281 case MUIV_List_Active_Up:
1282 new_entries_active = data->entries_active - 1;
1283 break;
1285 case MUIV_List_Active_Down:
1286 new_entries_active = data->entries_active + 1;
1287 break;
1289 case MUIV_List_Active_PageUp:
1290 new_entries_active =
1291 data->entries_active - data->entries_visible;
1292 break;
1294 case MUIV_List_Active_PageDown:
1295 new_entries_active =
1296 data->entries_active + data->entries_visible;
1297 break;
1300 if (new_entries_active < 0)
1301 new_entries_active = 0;
1302 else if (new_entries_active >= data->entries_num)
1303 new_entries_active = data->entries_num - 1;
1305 else
1306 new_entries_active = -1;
1308 if (data->entries_active != new_entries_active)
1310 LONG old = data->entries_active;
1311 data->entries_active = new_entries_active;
1313 /* SelectChange stuff */
1314 if (new_entries_active != -1)
1316 DoMethod(obj, MUIM_List_SelectChange,
1317 new_entries_active, MUIV_List_Select_On, 0);
1318 DoMethod(obj, MUIM_List_SelectChange,
1319 new_entries_active, MUIV_List_Select_Active, 0);
1321 else
1322 DoMethod(obj, MUIM_List_SelectChange,
1323 MUIV_List_Active_Off, MUIV_List_Select_Off, 0);
1325 if (!data->read_only)
1327 data->update = 2;
1328 data->update_pos = old;
1329 MUI_Redraw(obj, MADF_DRAWUPDATE);
1330 data->update = 2;
1331 data->update_pos = data->entries_active;
1332 MUI_Redraw(obj, MADF_DRAWUPDATE);
1335 /* Make new active entry visible (if there is one and
1336 list is visible) */
1337 if (new_entries_active != -1
1338 && (_flags(obj) & MADF_SETUP))
1340 DoMethod(obj, MUIM_List_Jump,
1341 MUIV_List_Jump_Active);
1345 break;
1347 case MUIA_List_First:
1348 data->update_pos = data->entries_first;
1349 data->update = 3;
1350 data->entries_first = tag->ti_Data;
1352 MUI_Redraw(obj, MADF_DRAWUPDATE);
1353 if ((data->vertprop_first != tag->ti_Data)
1354 && (!(data->flags & LIST_QUIET)))
1356 set(obj, MUIA_List_VertProp_First, tag->ti_Data);
1358 break;
1360 case MUIA_List_Visible: /* Shouldn't be settable? */
1361 if (data->vertprop_visible != tag->ti_Data)
1362 set(obj, MUIA_List_VertProp_Visible, tag->ti_Data);
1363 break;
1365 case MUIA_List_Entries:
1366 if (data->confirm_entries_num == tag->ti_Data)
1368 data->entries_num = tag->ti_Data;
1369 if (!(data->flags & LIST_QUIET))
1371 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
1374 else
1376 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1378 break;
1380 case MUIA_List_Quiet:
1381 _handle_bool_tag(data->flags, tag->ti_Data, LIST_QUIET);
1382 if (!tag->ti_Data)
1384 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1385 if (data->entries_num != XGET(obj, MUIA_List_VertProp_Entries))
1386 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
1387 if (data->entries_first != XGET(obj, MUIA_List_VertProp_First))
1388 set(obj, MUIA_List_VertProp_First, data->entries_first);
1390 break;
1392 case MUIA_List_AutoVisible:
1393 _handle_bool_tag(data->flags, tag->ti_Data, LIST_AUTOVISIBLE);
1394 break;
1396 case MUIA_List_ShowDropMarks:
1397 _handle_bool_tag(data->flags, tag->ti_Data, LIST_SHOWDROPMARKS);
1398 break;
1400 case MUIA_List_DragSortable:
1401 _handle_bool_tag(data->flags, tag->ti_Data, LIST_DRAGSORTABLE);
1402 set(obj, MUIA_Draggable, tag->ti_Data);
1403 break;
1405 case MUIA_Selected:
1406 /* Swallow this so the Area class doesn't redraw us */
1407 tag->ti_Tag = TAG_IGNORE;
1408 break;
1410 case MUIA_Disabled:
1411 if (_flags(obj) & MADF_SETUP)
1413 /* Stop listening for events we only listen to when mouse
1414 button is down: we will not be informed of the button
1415 being released */
1416 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1417 (IPTR) &data->ehn);
1418 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
1419 | IDCMP_INACTIVEWINDOW);
1420 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1421 (IPTR) &data->ehn);
1423 break;
1425 case MUIA_Listview_DoubleClick: /* private set */
1426 data->doubleclick = tag->ti_Data != 0;
1427 break;
1429 case MUIA_Listview_SelectChange: /* private set */
1430 data->select_change = tag->ti_Data != 0;
1431 break;
1433 case MUIA_Listview_ScrollerPos: /* private set */
1434 data->scroller_pos = tag->ti_Data;
1435 List_HandleScrollerPos(cl, obj);
1436 break;
1438 case MUIA_Listview_Input: /* private set */
1439 data->read_only = !tag->ti_Data;
1440 break;
1442 case MUIA_Listview_MultiSelect: /* private set */
1443 data->multiselect = tag->ti_Data;
1444 break;
1446 case MUIA_Listview_DefClickColumn:
1447 data->def_click_column = tag->ti_Data;
1448 break;
1452 return DoSuperMethodA(cl, obj, (Msg) msg);
1455 /**************************************************************************
1456 OM_GET
1457 **************************************************************************/
1458 IPTR List__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
1460 /* small macro to simplify return value storage */
1461 #define STORE *(msg->opg_Storage)
1462 struct MUI_ListData *data = INST_DATA(cl, obj);
1464 switch (msg->opg_AttrID)
1466 case MUIA_List_Entries:
1467 STORE = data->entries_num;
1468 return 1;
1469 case MUIA_List_First:
1470 STORE = data->entries_first;
1471 return 1;
1472 case MUIA_List_Active:
1473 STORE = data->entries_active;
1474 return 1;
1475 case MUIA_List_InsertPosition:
1476 STORE = data->insert_position;
1477 return 1;
1478 case MUIA_List_Title:
1479 STORE = (IPTR) data->title;
1480 return 1;
1481 case MUIA_List_VertProp_Entries:
1482 STORE = data->vertprop_entries;
1483 return 1;
1484 case MUIA_List_VertProp_Visible:
1485 case MUIA_List_Visible:
1486 STORE = data->vertprop_visible;
1487 return 1;
1488 case MUIA_List_VertProp_First:
1489 STORE = data->vertprop_first;
1490 return 1;
1491 case MUIA_List_Format:
1492 STORE = (IPTR) data->format;
1493 return 1;
1494 case MUIA_List_AutoVisible:
1495 STORE = data->flags & LIST_AUTOVISIBLE;
1496 return 1;
1497 case MUIA_List_ShowDropMarks:
1498 STORE = data->flags & LIST_SHOWDROPMARKS;
1499 return 1;
1500 case MUIA_List_DragSortable:
1501 STORE = data->flags & LIST_DRAGSORTABLE;
1502 return 1;
1503 case MUIA_Listview_ClickColumn:
1504 STORE = data->click_column;
1505 return 1;
1506 case MUIA_Listview_DoubleClick:
1507 STORE = data->doubleclick;
1508 return 1;
1509 case MUIA_Listview_SelectChange:
1510 STORE = data->select_change;
1511 return 1;
1512 case MUIA_Listview_List:
1513 STORE = (IPTR)obj;
1514 return 1;
1515 case MUIA_Listview_DefClickColumn:
1516 STORE = data->def_click_column;
1517 return 1;
1520 if (DoSuperMethodA(cl, obj, (Msg) msg))
1521 return 1;
1522 return 0;
1523 #undef STORE
1526 /**************************************************************************
1527 MUIM_Setup
1528 **************************************************************************/
1529 IPTR List__MUIM_Setup(struct IClass *cl, Object *obj,
1530 struct MUIP_Setup *msg)
1532 struct MUI_ListData *data = INST_DATA(cl, obj);
1534 if (!DoSuperMethodA(cl, obj, (Msg) msg))
1535 return 0;
1537 data->prefs_refresh = muiGlobalInfo(obj)->mgi_Prefs->list_refresh;
1538 data->prefs_linespacing =
1539 muiGlobalInfo(obj)->mgi_Prefs->list_linespacing;
1540 data->prefs_smoothed = muiGlobalInfo(obj)->mgi_Prefs->list_smoothed;
1541 data->prefs_smoothval = muiGlobalInfo(obj)->mgi_Prefs->list_smoothval;
1543 data->list_cursor =
1544 zune_imspec_setup(MUII_ListCursor, muiRenderInfo(obj));
1545 data->list_select =
1546 zune_imspec_setup(MUII_ListSelect, muiRenderInfo(obj));
1547 data->list_selcur =
1548 zune_imspec_setup(MUII_ListSelCur, muiRenderInfo(obj));
1550 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
1551 if (data->multiselect == MUIV_Listview_MultiSelect_Default)
1553 if (data->prefs_multi == LISTVIEW_MULTI_SHIFTED)
1554 data->multiselect = MUIV_Listview_MultiSelect_Shifted;
1555 else
1556 data->multiselect = MUIV_Listview_MultiSelect_Always;
1559 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) &data->ehn);
1561 return 1;
1564 /**************************************************************************
1565 MUIM_Cleanup
1566 **************************************************************************/
1567 IPTR List__MUIM_Cleanup(struct IClass *cl, Object *obj,
1568 struct MUIP_Cleanup *msg)
1570 struct MUI_ListData *data = INST_DATA(cl, obj);
1572 zune_imspec_cleanup(data->list_cursor);
1573 zune_imspec_cleanup(data->list_select);
1574 zune_imspec_cleanup(data->list_selcur);
1576 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) &data->ehn);
1577 data->mouse_click = 0;
1579 return DoSuperMethodA(cl, obj, (Msg) msg);
1582 /**************************************************************************
1583 MUIM_AskMinMax
1584 **************************************************************************/
1585 IPTR List__MUIM_AskMinMax(struct IClass *cl, Object *obj,
1586 struct MUIP_AskMinMax *msg)
1588 struct MUI_ListData *data = INST_DATA(cl, obj);
1590 DoSuperMethodA(cl, obj, (Msg) msg);
1592 CalcWidths(cl, obj);
1594 if ((data->flags & LIST_ADJUSTWIDTH) && (data->entries_num > 0))
1596 msg->MinMaxInfo->MinWidth += data->entries_maxwidth;
1597 msg->MinMaxInfo->DefWidth = msg->MinMaxInfo->MinWidth;
1598 msg->MinMaxInfo->MaxWidth = msg->MinMaxInfo->MinWidth;
1600 else
1602 msg->MinMaxInfo->MinWidth += 40;
1603 msg->MinMaxInfo->DefWidth += 100;
1604 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1607 if (data->entries_num > 0)
1609 if (data->flags & LIST_ADJUSTHEIGHT)
1611 msg->MinMaxInfo->MinHeight += data->entries_totalheight;
1612 msg->MinMaxInfo->DefHeight = msg->MinMaxInfo->MinHeight;
1613 msg->MinMaxInfo->MaxHeight = msg->MinMaxInfo->MinHeight;
1615 else
1617 ULONG h = data->entry_maxheight + data->prefs_linespacing;
1618 msg->MinMaxInfo->MinHeight += 2 * h + data->prefs_linespacing;
1619 msg->MinMaxInfo->DefHeight += 8 * h + data->prefs_linespacing;
1620 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1623 else
1625 msg->MinMaxInfo->MinHeight += 36;
1626 msg->MinMaxInfo->DefHeight += 96;
1627 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1629 D(bug("List %p minheight=%d, line maxh=%d\n",
1630 obj, msg->MinMaxInfo->MinHeight, data->entry_maxheight));
1632 return TRUE;
1635 /****i* List.mui/MUIM_Layout *************************************************
1637 * NAME
1638 * MUIM_Layout
1640 ******************************************************************************
1644 IPTR List__MUIM_Layout(struct IClass *cl, Object *obj,
1645 struct MUIP_Layout *msg)
1647 struct MUI_ListData *data = INST_DATA(cl, obj);
1648 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1649 LONG new_entries_first = data->entries_first;
1651 /* Calc the numbers of entries visible */
1652 CalcVertVisible(cl, obj);
1654 /* Ensure active entry is visible if requested */
1655 if (data->entries_active + 1 >=
1656 (data->entries_first + data->entries_visible)
1657 && (data->flags & LIST_AUTOVISIBLE) != 0)
1658 new_entries_first =
1659 data->entries_active - data->entries_visible + 1;
1661 /* Ensure there are no unnecessary empty lines */
1662 if ((new_entries_first + data->entries_visible >=
1663 data->entries_num)
1664 && (data->entries_visible <= data->entries_num))
1665 new_entries_first = data->entries_num - data->entries_visible;
1667 /* Always show the start of the list if it isn't long enough to fill the
1668 view */
1669 if (data->entries_num <= data->entries_visible)
1670 new_entries_first = 0;
1672 if (new_entries_first < 0)
1673 new_entries_first = 0;
1675 set(obj, new_entries_first != data->entries_first ?
1676 MUIA_List_First : TAG_IGNORE, new_entries_first);
1678 /* So the notify happens */
1679 set(obj, MUIA_List_VertProp_Visible, data->entries_visible);
1681 return rc;
1685 /**************************************************************************
1686 MUIM_Show
1687 **************************************************************************/
1688 IPTR List__MUIM_Show(struct IClass *cl, Object *obj,
1689 struct MUIP_Show *msg)
1691 struct MUI_ListData *data = INST_DATA(cl, obj);
1692 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1694 zune_imspec_show(data->list_cursor, obj);
1695 zune_imspec_show(data->list_select, obj);
1696 zune_imspec_show(data->list_selcur, obj);
1697 return rc;
1701 /**************************************************************************
1702 MUIM_Hide
1703 **************************************************************************/
1704 IPTR List__MUIM_Hide(struct IClass *cl, Object *obj,
1705 struct MUIP_Hide *msg)
1707 struct MUI_ListData *data = INST_DATA(cl, obj);
1709 zune_imspec_hide(data->list_cursor);
1710 zune_imspec_hide(data->list_select);
1711 zune_imspec_hide(data->list_selcur);
1713 return DoSuperMethodA(cl, obj, (Msg) msg);
1717 /**************************************************************************
1718 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1719 ENTRY_TITLE
1720 **************************************************************************/
1721 static VOID List_DrawEntry(struct IClass *cl, Object *obj, int entry_pos,
1722 int y)
1724 struct MUI_ListData *data = INST_DATA(cl, obj);
1725 int col, x1, x2;
1727 /* To be sure we don't draw anything if there is no title */
1728 if (entry_pos == ENTRY_TITLE && !data->title)
1729 return;
1731 DisplayEntry(cl, obj, entry_pos);
1732 x1 = _mleft(data->area);
1734 for (col = 0; col < data->columns; col++)
1736 ZText *text;
1737 x2 = x1 + data->ci[col].entries_width;
1739 if ((text =
1740 zune_text_new(data->preparses[col], data->strings[col],
1741 ZTEXT_ARG_NONE, 0)))
1743 /* Could be made simpler, as we don't really need the bounds */
1744 zune_text_get_bounds(text, obj);
1745 /* Note, this was MPEN_SHADOW before */
1746 SetAPen(_rp(obj), muiRenderInfo(obj)->mri_Pens[MPEN_TEXT]);
1747 zune_text_draw(text, obj, x1, x2, y); /* totally wrong! */
1748 zune_text_destroy(text);
1750 x1 = x2 + data->ci[col].delta + (data->ci[col].bar ? BAR_WIDTH : 0);
1754 /**************************************************************************
1755 MUIM_Draw
1756 **************************************************************************/
1757 IPTR List__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1759 struct MUI_ListData *data = INST_DATA(cl, obj);
1760 int entry_pos, y;
1761 APTR clip;
1762 int start, end;
1763 BOOL scroll_caused_damage = FALSE;
1764 struct MUI_ImageSpec_intern *highlight;
1765 IPTR ret = (IPTR)0;
1767 if (data->flags & LIST_QUIET)
1768 return 0;
1770 ret = DoSuperMethodA(cl, obj, (Msg) msg);
1772 if (data->area_replaced)
1773 return ret;
1775 /* Calculate the title height */
1776 if (data->title)
1778 data->title_height = data->entries[ENTRY_TITLE]->height + 2;
1780 else
1782 data->title_height = 0;
1785 /* Calc the numbers of entries visible */
1786 CalcVertVisible(cl, obj);
1788 if ((msg->flags & MADF_DRAWUPDATE) == 0 || data->update == 1)
1790 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
1791 _mtop(data->area), _mwidth(data->area), _mheight(data->area),
1792 0, data->entries_first * data->entry_maxheight, 0);
1795 clip = MUI_AddClipping(muiRenderInfo(obj), _mleft(data->area),
1796 _mtop(data->area), _mwidth(data->area), _mheight(data->area));
1798 if ((msg->flags & MADF_DRAWUPDATE) == 0 || data->update == 1)
1800 y = _mtop(data->area);
1801 /* Draw Title
1803 if (data->title_height && data->title)
1805 List_DrawEntry(cl, obj, ENTRY_TITLE, y);
1806 y += data->entries[ENTRY_TITLE]->height;
1807 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1808 Move(_rp(obj), _mleft(data->area), y);
1809 Draw(_rp(obj), _mright(data->area), y);
1810 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1811 y++;
1812 Move(_rp(obj), _mleft(data->area), y);
1813 Draw(_rp(obj), _mright(data->area), y);
1817 y = data->entries_top_pixel;
1819 start = data->entries_first;
1820 end = data->entries_first + data->entries_visible;
1822 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3)
1824 int diffy = data->entries_first - data->update_pos;
1825 int top, bottom;
1826 if (abs(diffy) < data->entries_visible)
1828 scroll_caused_damage =
1829 (_rp(obj)->Layer->Flags & LAYERREFRESH) ? FALSE : TRUE;
1831 ScrollRaster(_rp(obj), 0, diffy * data->entry_maxheight,
1832 _mleft(data->area), y,
1833 _mright(data->area),
1834 y + data->entry_maxheight * data->entries_visible);
1836 scroll_caused_damage =
1837 scroll_caused_damage
1838 && (_rp(obj)->Layer->Flags & LAYERREFRESH);
1840 if (diffy > 0)
1842 start = end - diffy;
1843 y += data->entry_maxheight * (data->entries_visible -
1844 diffy);
1846 else
1847 end = start - diffy;
1850 top = y;
1851 bottom = y + (end - start) * data->entry_maxheight;
1853 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area), top,
1854 _mwidth(data->area), bottom - top + 1, 0,
1855 top - _mtop(data->area) + data->entries_first
1856 * data->entry_maxheight, 0);
1859 for (entry_pos = start;
1860 entry_pos < end && entry_pos < data->entries_num; entry_pos++)
1862 struct ListEntry *entry = data->entries[entry_pos];
1864 if (!(msg->flags & MADF_DRAWUPDATE) ||
1865 ((msg->flags & MADF_DRAWUPDATE) && data->update == 1) ||
1866 ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) ||
1867 ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1868 && data->update_pos == entry_pos))
1870 /* Choose appropriate highlight image */
1872 if (entry_pos == data->entries_active
1873 && (entry->flags & ENTRY_SELECTED) && !data->read_only)
1874 highlight = data->list_selcur;
1875 else if (entry_pos == data->entries_active && !data->read_only)
1876 highlight = data->list_cursor;
1877 else if (entry->flags & ENTRY_SELECTED)
1878 highlight = data->list_select;
1879 else
1880 highlight = NULL;
1882 /* Draw highlight or background */
1884 if (highlight != NULL)
1886 zune_imspec_draw(highlight, muiRenderInfo(obj),
1887 _mleft(data->area), y, _mwidth(data->area),
1888 data->entry_maxheight,
1889 0, y - data->entries_top_pixel, 0);
1891 else if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1892 && data->update_pos == entry_pos)
1894 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area), y,
1895 _mwidth(data->area), data->entry_maxheight, 0,
1896 y - _mtop(data->area) +
1897 data->entries_first * data->entry_maxheight, 0);
1900 List_DrawEntry(cl, obj, entry_pos, y);
1902 y += data->entry_maxheight;
1905 MUI_RemoveClipping(muiRenderInfo(obj), clip);
1907 data->update = 0;
1909 if (scroll_caused_damage)
1911 if (MUI_BeginRefresh(muiRenderInfo(obj), 0))
1913 /* Theoretically it might happen that more damage is caused
1914 after ScrollRaster. By something else, like window movement
1915 in front of our window. Therefore refresh root object of
1916 window, not just this object */
1918 Object *o = NULL;
1920 get(_win(obj), MUIA_Window_RootObject, &o);
1921 MUI_Redraw(o, MADF_DRAWOBJECT);
1923 MUI_EndRefresh(muiRenderInfo(obj), 0);
1927 ULONG x1 = _mleft(data->area);
1928 ULONG col;
1929 y = _mtop(data->area);
1931 if (data->title_height && data->title)
1933 for (col = 0; col < data->columns; col++)
1935 ULONG halfdelta = data->ci[col].delta / 2;
1936 x1 += data->ci[col].entries_width + halfdelta;
1938 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(data->area))
1939 break;
1941 if (data->ci[col].bar)
1943 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1944 Move(_rp(obj), x1, y);
1945 Draw(_rp(obj), x1,
1946 y + data->entries[ENTRY_TITLE]->height - 1);
1947 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1948 Move(_rp(obj), x1 + 1, y);
1949 Draw(_rp(obj), x1 + 1,
1950 y + data->entries[ENTRY_TITLE]->height - 1);
1952 x1 += BAR_WIDTH;
1954 x1 += data->ci[col].delta - halfdelta;
1956 y += data->entries[ENTRY_TITLE]->height + 1;
1959 x1 = _mleft(data->area);
1961 for (col = 0; col < data->columns; col++)
1963 ULONG halfdelta = data->ci[col].delta / 2;
1964 x1 += data->ci[col].entries_width + halfdelta;
1966 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(data->area))
1967 break;
1969 if (data->ci[col].bar)
1971 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1972 Move(_rp(obj), x1, y);
1973 Draw(_rp(obj), x1, _mbottom(data->area));
1974 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1975 Move(_rp(obj), x1 + 1, y);
1976 Draw(_rp(obj), x1 + 1, _mbottom(data->area));
1978 x1 += BAR_WIDTH;
1981 x1 += data->ci[col].delta - halfdelta;
1984 return 0;
1987 /****** List.mui/MUIM_List_Clear *********************************************
1989 * NAME
1990 * MUIM_List_Clear (V4)
1992 * SYNOPSIS
1993 * DoMethod(obj, MUIM_List_Clear);
1995 * FUNCTION
1996 * Removes all entries from the list.
1998 ******************************************************************************
2002 IPTR List__MUIM_Clear(struct IClass *cl, Object *obj,
2003 struct MUIP_List_Clear *msg)
2005 struct MUI_ListData *data = INST_DATA(cl, obj);
2007 while (data->confirm_entries_num)
2009 struct ListEntry *lentry =
2010 data->entries[--data->confirm_entries_num];
2011 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
2012 (IPTR) data->pool);
2013 FreeListEntry(data, lentry);
2015 /* Should never fail when shrinking */
2016 SetListSize(data, 0);
2018 if (data->confirm_entries_num != data->entries_num)
2020 SetAttrs(obj, MUIA_List_Entries, 0, MUIA_List_First, 0,
2021 /* Notify only when no entry was active */
2022 data->entries_active !=
2023 MUIV_List_Active_Off ? MUIA_List_Active : TAG_DONE,
2024 MUIV_List_Active_Off, TAG_DONE);
2026 data->update = 1;
2027 MUI_Redraw(obj, MADF_DRAWUPDATE);
2030 return 0;
2033 /****** List.mui/MUIM_List_Exchange ******************************************
2035 * NAME
2036 * MUIM_List_Exchange (V4)
2038 * SYNOPSIS
2039 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2041 * FUNCTION
2042 * Exchange two entries' positions.
2044 * INPUTS
2045 * pos1 - the current index of the first entry that should be moved, or
2046 * one of these special values:
2047 * MUIV_List_Exchange_Active: the active entry.
2048 * MUIV_List_Exchange_Top: the first entry.
2049 * MUIV_List_Exchange_Bottom: the last entry.
2050 * pos2 - the index of the entry that the first entry should be exchanged
2051 * with, or one of these special values:
2052 * MUIV_List_Exchange_Active: the active entry.
2053 * MUIV_List_Exchange_Top: the first entry.
2054 * MUIV_List_Exchange_Bottom: the last entry.
2055 * MUIV_List_Exchange_Next: the next entry after pos1.
2056 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2058 * NOTES
2059 * This method will do nothing if either index is greater than the last
2060 * index in the list, or if MUIV_List_Exchange_Next or
2061 * MUIV_List_Exchange_Previous imply an index outside the list.
2063 * SEE ALSO
2064 * MUIM_List_Move
2066 ******************************************************************************
2070 IPTR List__MUIM_Exchange(struct IClass *cl, Object *obj,
2071 struct MUIP_List_Exchange *msg)
2073 struct MUI_ListData *data = INST_DATA(cl, obj);
2074 LONG pos1, pos2;
2076 switch (msg->pos1)
2078 case MUIV_List_Exchange_Top:
2079 pos1 = 0;
2080 break;
2081 case MUIV_List_Exchange_Active:
2082 pos1 = data->entries_active;
2083 break;
2084 case MUIV_List_Exchange_Bottom:
2085 pos1 = data->entries_num - 1;
2086 break;
2087 default:
2088 pos1 = msg->pos1;
2091 switch (msg->pos2)
2093 case MUIV_List_Exchange_Top:
2094 pos2 = 0;
2095 break;
2096 case MUIV_List_Exchange_Active:
2097 pos2 = data->entries_active;
2098 break;
2099 case MUIV_List_Exchange_Bottom:
2100 pos2 = data->entries_num - 1;
2101 break;
2102 case MUIV_List_Exchange_Next:
2103 pos2 = pos1 + 1;
2104 break;
2105 case MUIV_List_Exchange_Previous:
2106 pos2 = pos1 - 1;
2107 break;
2108 default:
2109 pos2 = msg->pos2;
2112 if (pos1 >= 0 && pos1 < data->entries_num && pos2 >= 0
2113 && pos2 < data->entries_num && pos1 != pos2)
2115 struct ListEntry *save = data->entries[pos1];
2116 data->entries[pos1] = data->entries[pos2];
2117 data->entries[pos2] = save;
2119 data->update = 2;
2120 data->update_pos = pos1;
2121 MUI_Redraw(obj, MADF_DRAWUPDATE);
2123 data->update = 2;
2124 data->update_pos = pos2;
2125 MUI_Redraw(obj, MADF_DRAWUPDATE);
2127 return TRUE;
2129 else
2131 return FALSE;
2135 /**************************************************************************
2136 MUIM_List_Redraw
2137 **************************************************************************/
2138 IPTR List__MUIM_Redraw(struct IClass *cl, Object *obj,
2139 struct MUIP_List_Redraw *msg)
2141 struct MUI_ListData *data = INST_DATA(cl, obj);
2143 if (!(data->flags & LIST_QUIET))
2145 if (msg->pos == MUIV_List_Redraw_All)
2147 data->update = 1;
2148 CalcWidths(cl, obj);
2149 MUI_Redraw(obj, MADF_DRAWUPDATE);
2151 else
2153 LONG pos = -1;
2154 if (msg->pos == MUIV_List_Redraw_Active)
2155 pos = data->entries_active;
2156 else if (msg->pos == MUIV_List_Redraw_Entry)
2158 LONG i;
2159 for (i = 0; i < data->entries_num; i++)
2160 if (data->entries[i]->data == msg->entry)
2162 pos = i;
2163 break;
2166 else
2167 pos = msg->pos;
2169 if (pos != -1)
2171 if (CalcDimsOfEntry(cl, obj, pos))
2172 data->update = 1;
2173 else
2175 data->update = 2;
2176 data->update_pos = pos;
2178 MUI_Redraw(obj, MADF_DRAWUPDATE);
2182 return 0;
2185 /****** List.mui/MUIM_List_Remove ********************************************
2187 * NAME
2188 * MUIM_List_Remove (V4)
2190 * SYNOPSIS
2191 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2193 * FUNCTION
2194 * Removes entries from the list. If a destruct hook has been
2195 * installed, it will be called for the removed entry.
2197 * INPUTS
2198 * pos - the index of the entry to be removed. The following
2199 * special values can also be used:
2200 * MUIV_List_Remove_First: remove the first entry.
2201 * MUIV_List_Remove_Last: remove the last entry.
2202 * MUIV_List_Remove_Active: remove the active entry.
2203 * MUIV_List_Remove_Selected: remove all selected entries
2204 * (or the active entry if there are no selected entries).
2206 * NOTES
2207 * When the active entry is removed, the next entry becomes active
2208 * (if there is no entry below the active entry, the previous entry
2209 * becomes active instead).
2211 * SEE ALSO
2212 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2214 ******************************************************************************
2216 * It was not possible to use MUIM_List_NextSelected here because that method
2217 * may skip entries if entries are removed during an iteration.
2221 IPTR List__MUIM_Remove(struct IClass *cl, Object *obj,
2222 struct MUIP_List_Remove *msg)
2224 struct MUI_ListData *data = INST_DATA(cl, obj);
2225 LONG pos;
2226 LONG new_act;
2227 UWORD i;
2228 BOOL found, done = FALSE;
2229 struct ListEntry *lentry;
2230 Tag active_tag = TAG_DONE;
2232 if (!data->entries_num)
2233 return 0;
2235 switch (msg->pos)
2237 case MUIV_List_Remove_First:
2238 pos = 0;
2239 break;
2241 case MUIV_List_Remove_Active:
2242 pos = data->entries_active;
2243 break;
2245 case MUIV_List_Remove_Last:
2246 pos = data->entries_num - 1;
2247 break;
2249 case MUIV_List_Remove_Selected:
2250 pos = 0;
2251 break;
2253 default:
2254 pos = msg->pos;
2255 break;
2258 if (pos < 0 || pos >= data->entries_num)
2259 return 0;
2261 new_act = data->entries_active;
2263 while (!done)
2265 if (msg->pos == MUIV_List_Remove_Selected)
2267 /* Find the next selected entry */
2268 for (found = FALSE, i = pos;
2269 i < data->confirm_entries_num && !found; i++)
2271 if (data->entries[i]->flags & ENTRY_SELECTED)
2273 pos = i;
2274 found = TRUE;
2278 if (!found)
2280 done = TRUE;
2282 /* If there were no selected entries, remove the active one */
2283 if (data->confirm_entries_num == data->entries_num
2284 && data->entries_active != MUIV_List_Active_Off)
2286 pos = data->entries_active;
2287 found = TRUE;
2291 else
2293 done = TRUE;
2294 found = TRUE;
2297 if (found)
2299 lentry = data->entries[pos];
2300 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
2301 (IPTR) data->pool);
2302 RemoveListEntries(data, pos, 1);
2303 data->confirm_entries_num--;
2305 if (pos < new_act)
2307 new_act--;
2308 active_tag = MUIA_List_Active;
2310 else if (pos == new_act)
2311 active_tag = MUIA_List_Active;
2315 /* Update entries count prior to range check */
2316 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num, TAG_DONE);
2318 /* Ensure that the active element is in a valid range (it might become
2319 * MUIV_List_Active_Off (-1), but that's OK) */
2320 if (new_act >= data->entries_num)
2321 new_act = data->entries_num - 1;
2323 SetAttrs(obj,
2324 active_tag, new_act, /* Inform only if necessary (for notify) */
2325 TAG_DONE);
2327 data->update = 1;
2328 MUI_Redraw(obj, MADF_DRAWUPDATE);
2330 return 0;
2333 /**************************************************************************
2334 MUIM_List_Select
2335 **************************************************************************/
2336 IPTR List__MUIM_Select(struct IClass *cl, Object *obj,
2337 struct MUIP_List_Select *msg)
2339 struct MUI_ListData *data = INST_DATA(cl, obj);
2340 LONG pos, i, count, selcount=0, state=0;
2341 BOOL multi_allowed = TRUE, new_select_state = FALSE;
2343 /* Establish the range of entries affected */
2344 switch (msg->pos)
2346 case MUIV_List_Select_Active:
2347 pos = data->entries_active;
2348 if (pos == MUIV_List_Active_Off)
2349 count = 0;
2350 else
2351 count = 1;
2352 break;
2354 case MUIV_List_Select_All:
2355 pos = 0;
2356 count = data->entries_num;
2357 break;
2359 default:
2360 pos = msg->pos;
2361 count = 1;
2362 if (pos < 0 || pos >= data->entries_num)
2363 return 0;
2364 break;
2367 if (msg->seltype != MUIV_List_Select_Ask && data->multi_test_hook != NULL)
2369 /* Disallow selection of an additional entry if there is a currently
2370 selected entry that is not multi-selectable (in such case there
2371 will only be one entry currently selected, so no need to iterate) */
2372 i = MUIV_List_NextSelected_Start;
2373 DoMethod(obj, MUIM_List_NextSelected, (IPTR) &i);
2374 if (i != MUIV_List_NextSelected_End)
2375 selcount++;
2376 if (data->multi_test_hook != NULL && selcount != 0)
2377 multi_allowed = CallHookPkt(data->multi_test_hook, NULL,
2378 data->entries[i]->data);
2381 /* Change or check state of each entry in the range */
2382 for (i = pos; i < pos + count; i++)
2384 state = data->entries[i]->flags & ENTRY_SELECTED;
2385 switch (msg->seltype)
2387 case MUIV_List_Select_Off:
2388 new_select_state = FALSE;
2389 break;
2391 case MUIV_List_Select_On:
2392 new_select_state = TRUE;
2393 break;
2395 case MUIV_List_Select_Toggle:
2396 new_select_state = !state;
2397 break;
2399 default:
2400 if (data->entries[i]->flags & ENTRY_SELECTED)
2401 selcount++;
2402 break;
2405 if (msg->seltype != MUIV_List_Select_Ask)
2407 /* Disallow selection if entry is not multi-selectable and
2408 * there are already selected entries */
2409 if (data->multi_test_hook != NULL && new_select_state)
2410 new_select_state = multi_allowed && (selcount == 0 ||
2411 CallHookPkt(data->multi_test_hook, NULL,
2412 data->entries[i]->data));
2414 if (new_select_state)
2415 data->entries[i]->flags |= ENTRY_SELECTED;
2416 else
2417 data->entries[i]->flags &= ~ENTRY_SELECTED;
2421 /* Report old state or number of selected entries */
2422 if (msg->info)
2424 if (msg->pos == MUIV_List_Select_All
2425 && msg->seltype == MUIV_List_Select_Ask)
2426 *msg->info = selcount;
2427 else
2428 *msg->info = state;
2431 /* Redraw unless it was just an enquiry */
2432 if (msg->seltype != MUIV_List_Select_Ask)
2434 if (count > 1)
2435 data->update = 1;
2436 else
2438 data->update = 2;
2439 data->update_pos = pos;
2441 MUI_Redraw(obj, MADF_DRAWUPDATE);
2444 return 0;
2447 /****** List.mui/MUIM_List_Insert ********************************************
2449 * NAME
2450 * MUIM_List_Insert (V4)
2452 * SYNOPSIS
2453 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2455 * FUNCTION
2456 * Adds multiple entries to the list. If a construct hook has been
2457 * installed, the results of passing the entries to this hook will be
2458 * inserted.
2460 * INPUTS
2461 * entries - an array of entries to be inserted.
2462 * count - the number of entries to insert. A special value of -1 may be
2463 * used, indicating that the array of entries is NULL-terminated.
2464 * pos - the index at which to insert the new entries. The following
2465 * special values can also be used:
2466 * MUIV_List_Insert_Top: insert at index 0.
2467 * MUIV_List_Insert_Bottom: insert after all existing entries.
2468 * MUIV_List_Insert_Active: insert at the index of the active entry
2469 * (or at index 0 if there is no active entry).
2470 * MUIV_List_Insert_Sorted: keep the list sorted.
2472 * SEE ALSO
2473 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2475 ******************************************************************************
2479 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
2480 struct MUIP_List_Insert *msg)
2482 struct MUI_ListData *data = INST_DATA(cl, obj);
2483 LONG pos, count, sort, active;
2485 count = msg->count;
2486 sort = 0;
2488 if (count == -1)
2490 /* Count the number of entries */
2491 for (count = 0; msg->entries[count] != NULL; count++)
2495 if (count <= 0)
2496 return ~0;
2498 switch (msg->pos)
2500 case MUIV_List_Insert_Top:
2501 pos = 0;
2502 break;
2504 case MUIV_List_Insert_Active:
2505 if (data->entries_active != -1)
2506 pos = data->entries_active;
2507 else
2508 pos = 0;
2509 break;
2511 case MUIV_List_Insert_Sorted:
2512 pos = data->entries_num;
2513 sort = 1; /* we sort'em later */
2514 break;
2516 case MUIV_List_Insert_Bottom:
2517 pos = data->entries_num;
2518 break;
2520 default:
2521 if (msg->pos > data->entries_num)
2522 pos = data->entries_num;
2523 else if (msg->pos < 0)
2524 pos = 0;
2525 else
2526 pos = msg->pos;
2527 break;
2529 data->insert_position = pos;
2531 if (!(SetListSize(data, data->entries_num + count)))
2532 return ~0;
2534 LONG until = pos + count;
2535 APTR *toinsert = msg->entries;
2537 if (!(PrepareInsertListEntries(data, pos, count)))
2538 return ~0;
2540 while (pos < until)
2542 struct ListEntry *lentry;
2544 if (!(lentry = AllocListEntry(data)))
2546 /* Panic, but we must be in a consistent state, so remove
2547 * the space where the following list entries should have gone
2549 RemoveListEntries(data, pos, until - pos);
2550 return ~0;
2553 /* now call the construct method which returns us a pointer which
2554 we need to store */
2555 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2556 (IPTR) * toinsert, (IPTR) data->pool);
2557 if (!lentry->data)
2559 FreeListEntry(data, lentry);
2560 RemoveListEntries(data, pos, until - pos);
2562 /* TODO: Also check for visible stuff like below */
2563 if (data->entries_num != data->confirm_entries_num)
2564 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2565 return ~0;
2568 data->entries[pos] = lentry;
2569 data->confirm_entries_num++;
2571 if (_flags(obj) & MADF_SETUP)
2573 /* We have to calculate the width and height of the newly
2574 * inserted entry. This has to be done after inserting the
2575 * element into the list */
2576 CalcDimsOfEntry(cl, obj, pos);
2579 toinsert++;
2580 pos++;
2582 pos--;
2584 /* Recalculate the number of visible entries */
2585 if (_flags(obj) & MADF_SETUP)
2586 CalcVertVisible(cl, obj);
2588 if (data->entries_num != data->confirm_entries_num)
2590 SetAttrs(obj,
2591 MUIA_List_Entries, data->confirm_entries_num,
2592 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2595 /* If the array is already sorted, we could do a simple insert
2596 * sort and would be much faster than with qsort.
2597 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2598 * sort the whole array?
2600 * I think, we better sort the whole array:
2602 if (sort)
2604 DoMethod(obj, MUIM_List_Sort);
2605 /* TODO: which pos to return here !? */
2606 /* MUIM_List_Sort already called MUI_Redraw */
2608 else
2610 data->update = 1;
2611 MUI_Redraw(obj, MADF_DRAWUPDATE);
2613 superset(cl, obj, MUIA_List_InsertPosition, data->insert_position);
2615 /* Update index of active entry */
2616 if (data->entries_active >= data->insert_position)
2618 active = data->entries_active + count;
2619 SET(obj, MUIA_List_Active, active);
2622 return (ULONG) pos;
2625 /****** List.mui/MUIM_List_InsertSingle **************************************
2627 * NAME
2628 * MUIM_List_InsertSingle (V7)
2630 * SYNOPSIS
2631 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2633 * FUNCTION
2634 * Adds a single entry to the list. If a construct hook has been
2635 * installed, the result of passing the entry to this hook will be
2636 * inserted.
2638 * INPUTS
2639 * entry - the entry to be inserted.
2640 * pos - the index at which to insert the new entry. The following
2641 * special values can also be used:
2642 * MUIV_List_Insert_Top: insert at index 0.
2643 * MUIV_List_Insert_Bottom: insert after all existing entries.
2644 * MUIV_List_Insert_Active: insert at the index of the active entry
2645 * (or at index 0 if there is no active entry).
2646 * MUIV_List_Insert_Sorted: keep the list sorted.
2648 * SEE ALSO
2649 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2651 ******************************************************************************
2655 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2656 struct MUIP_List_InsertSingle *msg)
2658 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2659 msg->pos);
2662 /**************************************************************************
2663 MUIM_List_GetEntry
2664 **************************************************************************/
2665 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2666 struct MUIP_List_GetEntry *msg)
2668 struct MUI_ListData *data = INST_DATA(cl, obj);
2669 int pos = msg->pos;
2671 if (pos == MUIV_List_GetEntry_Active)
2672 pos = data->entries_active;
2674 if (pos < 0 || pos >= data->entries_num)
2676 *msg->entry = NULL;
2677 return 0;
2679 *msg->entry = data->entries[pos]->data;
2680 return (IPTR) *msg->entry;
2683 /**************************************************************************
2684 MUIM_List_Construct
2685 **************************************************************************/
2686 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2687 struct MUIP_List_Construct *msg)
2689 struct MUI_ListData *data = INST_DATA(cl, obj);
2691 if (NULL == data->construct_hook)
2692 return (IPTR) msg->entry;
2693 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2695 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2696 ULONG *mem = AllocPooled(msg->pool, len + 5);
2698 if (NULL == mem)
2699 return 0;
2700 mem[0] = len + 5;
2701 if (msg->entry != NULL)
2702 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2703 else
2704 *(STRPTR) (mem + 1) = 0;
2705 return (IPTR) (mem + 1);
2707 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2710 /**************************************************************************
2711 MUIM_List_Destruct
2712 **************************************************************************/
2713 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2714 struct MUIP_List_Destruct *msg)
2716 struct MUI_ListData *data = INST_DATA(cl, obj);
2718 if (NULL == data->destruct_hook)
2719 return 0;
2721 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2723 ULONG *mem = ((ULONG *) msg->entry) - 1;
2724 FreePooled(msg->pool, mem, mem[0]);
2726 else
2728 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2730 return 0;
2733 /****** List.mui/MUIM_List_Compare *******************************************
2735 * NAME
2736 * MUIM_List_Compare (V20)
2738 * SYNOPSIS
2739 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2740 * LONG sort_type1, LONG sort_type2);
2742 * FUNCTION
2743 * Compare two list entries according to the current comparison hook
2744 * (MUIA_List_CompareHook).
2746 * INPUTS
2747 * entry1 - the first entry data.
2748 * entry2 - the second entry data.
2749 * sort_type1 - undocumented.
2750 * sort_type2 - undocumented.
2752 * SEE ALSO
2753 * MUIA_List_CompareHook, MUIM_List_Sort.
2755 ******************************************************************************
2759 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2760 struct MUIP_List_Compare *msg)
2762 struct MUI_ListData *data = INST_DATA(cl, obj);
2764 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2767 /**************************************************************************
2768 MUIM_List_Display
2769 **************************************************************************/
2770 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2771 struct MUIP_List_Display *msg)
2773 struct MUI_ListData *data = INST_DATA(cl, obj);
2775 if (NULL == data->display_hook)
2777 if (msg->entry)
2778 *msg->array = msg->entry;
2779 else
2780 *msg->array = 0;
2781 return 1;
2784 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2785 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2788 /**************************************************************************
2789 MUIM_List_SelectChange
2790 **************************************************************************/
2791 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2792 struct MUIP_List_SelectChange *msg)
2794 return 1;
2797 /**************************************************************************
2798 MUIM_List_CreateImage
2799 Called by a List subclass in its Setup method.
2800 Connects an Area subclass object to the list, much like an object gets
2801 connected to a window. List calls Setup and AskMinMax on that object,
2802 keeps a reference to it (that reference will be returned).
2803 Text engine will dereference that pointer and draw the object with its
2804 default size.
2805 **************************************************************************/
2806 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2807 struct MUIP_List_CreateImage *msg)
2809 struct MUI_ListData *data = INST_DATA(cl, obj);
2810 struct ListImage *li;
2812 if (!msg->obj)
2813 return 0;
2815 /* List must be already setup in Setup of your subclass */
2816 if (!(_flags(obj) & MADF_SETUP))
2817 return 0;
2818 li = AllocPooled(data->pool, sizeof(struct ListImage));
2819 if (!li)
2820 return 0;
2821 li->obj = msg->obj;
2823 AddTail((struct List *)&data->images, (struct Node *)li);
2824 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2825 DoSetupMethod(li->obj, muiRenderInfo(obj));
2828 return (IPTR) li;
2831 /**************************************************************************
2832 MUIM_List_DeleteImage
2833 **************************************************************************/
2834 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2835 struct MUIP_List_DeleteImage *msg)
2837 struct MUI_ListData *data = INST_DATA(cl, obj);
2838 struct ListImage *li = (struct ListImage *)msg->listimg;
2840 if (li)
2842 DoMethod(li->obj, MUIM_Cleanup);
2843 DoMethod(li->obj, MUIM_DisconnectParent);
2844 Remove((struct Node *)li);
2845 FreePooled(data->pool, li, sizeof(struct ListImage));
2848 return 0;
2851 /****** List.mui/MUIM_List_Jump **********************************************
2853 * NAME
2854 * MUIM_List_Jump (V4)
2856 * SYNOPSIS
2857 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2859 * FUNCTION
2860 * Scrolls the list so that a particular entry is visible.
2862 * INPUTS
2863 * pos - index of entry that should become visible, or one of these
2864 * special values:
2865 * MUIV_List_Jump_Active: show the active entry.
2866 * MUIV_List_Jump_Top: show the first entry.
2867 * MUIV_List_Jump_Bottom: show the last entry.
2868 * MUIV_List_Jump_Up: show the previous hidden entry.
2869 * MUIV_List_Jump_Down: show the next hidden entry.
2871 ******************************************************************************
2875 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2876 struct MUIP_List_Jump *msg)
2878 struct MUI_ListData *data = INST_DATA(cl, obj);
2879 LONG pos = msg->pos;
2881 switch (pos)
2883 case MUIV_List_Jump_Top:
2884 pos = 0;
2885 break;
2887 case MUIV_List_Jump_Active:
2888 pos = data->entries_active;
2889 break;
2891 case MUIV_List_Jump_Bottom:
2892 pos = data->entries_num - 1;
2893 break;
2895 case MUIV_List_Jump_Down:
2896 pos = data->entries_first + data->entries_visible;
2897 break;
2899 case MUIV_List_Jump_Up:
2900 pos = data->entries_first - 1;
2901 break;
2904 if (pos >= data->entries_num)
2906 pos = data->entries_num - 1;
2908 if (pos < 0)
2909 pos = 0;
2911 if (pos < data->entries_first)
2913 set(obj, MUIA_List_First, pos);
2915 else if (pos >= data->entries_first + data->entries_visible)
2917 pos -= (data->entries_visible - 1);
2918 if (pos < 0)
2919 pos = 0;
2920 if (pos != data->entries_first)
2922 set(obj, MUIA_List_First, pos);
2926 return TRUE;
2929 /****** List.mui/MUIM_List_Sort **********************************************
2931 * NAME
2932 * MUIM_List_Sort (V4)
2934 * SYNOPSIS
2935 * DoMethod(obj, MUIM_List_Sort);
2937 * FUNCTION
2938 * Sort the list's entries according to the current comparison hook
2939 * (MUIA_List_CompareHook).
2941 * NOTES
2942 * The active index does not change, so the active entry may do so.
2944 * SEE ALSO
2945 * MUIA_List_CompareHook, MUIM_List_Compare.
2947 ******************************************************************************
2951 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2952 struct MUIP_List_Sort *msg)
2954 struct MUI_ListData *data = INST_DATA(cl, obj);
2956 int i, j, max;
2957 struct MUIP_List_Compare cmpmsg =
2958 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2960 if (data->entries_num > 1)
2963 Simple sort algorithm. Feel free to improve it.
2965 for (i = 0; i < data->entries_num - 1; i++)
2967 max = i;
2968 for (j = i + 1; j < data->entries_num; j++)
2970 cmpmsg.entry1 = data->entries[max]->data;
2971 cmpmsg.entry2 = data->entries[j]->data;
2972 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2974 max = j;
2977 if (i != max)
2979 APTR tmp = data->entries[i];
2980 data->entries[i] = data->entries[max];
2981 data->entries[max] = tmp;
2986 data->update = 1;
2987 MUI_Redraw(obj, MADF_DRAWUPDATE);
2989 return 0;
2992 /****** List.mui/MUIM_List_Move **********************************************
2994 * NAME
2995 * MUIM_List_Move (V9)
2997 * SYNOPSIS
2998 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
3000 * FUNCTION
3001 * Move a list entry to a new position.
3003 * INPUTS
3004 * from - the current index of the entry that should be moved, or one of
3005 * these special values:
3006 * MUIV_List_Move_Active: the active entry.
3007 * MUIV_List_Move_Top: the first entry.
3008 * MUIV_List_Move_Bottom: the last entry.
3009 * to - the index of the entry's new position, or one of
3010 * these special values:
3011 * MUIV_List_Move_Active: the active entry.
3012 * MUIV_List_Move_Top: the first entry.
3013 * MUIV_List_Move_Bottom: the last entry.
3015 * NOTES
3016 * The active index does not change, so the active entry may do so.
3018 * SEE ALSO
3019 * MUIM_List_Exchange
3021 ******************************************************************************
3025 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
3026 struct MUIP_List_Move *msg)
3028 struct MUI_ListData *data = INST_DATA(cl, obj);
3030 LONG from, to;
3031 int i;
3033 /* Normalise special 'from' values */
3034 switch (msg->from)
3036 case MUIV_List_Move_Top:
3037 from = 0;
3038 break;
3039 case MUIV_List_Move_Active:
3040 from = data->entries_active;
3041 break;
3042 case MUIV_List_Move_Bottom:
3043 from = data->entries_num - 1;
3044 break;
3045 default:
3046 from = msg->from;
3049 /* Normalise special 'to' values */
3050 switch (msg->to)
3052 case MUIV_List_Move_Top:
3053 to = 0;
3054 break;
3055 case MUIV_List_Move_Active:
3056 to = data->entries_active;
3057 break;
3058 case MUIV_List_Move_Bottom:
3059 to = data->entries_num - 1;
3060 break;
3061 case MUIV_List_Move_Next:
3062 to = from + 1;
3063 break;
3064 case MUIV_List_Move_Previous:
3065 to = from - 1;
3066 break;
3067 default:
3068 to = msg->to;
3071 /* Check that values are within valid bounds */
3072 if (from > data->entries_num - 1 || from < 0
3073 || to > data->entries_num - 1 || to < 0 || from == to)
3074 return (IPTR) FALSE;
3076 /* Shift all entries in the range between the 'from' and 'to' positions */
3077 if (from < to)
3079 struct ListEntry *backup = data->entries[from];
3080 for (i = from; i < to; i++)
3081 data->entries[i] = data->entries[i + 1];
3082 data->entries[to] = backup;
3084 else
3086 struct ListEntry *backup = data->entries[from];
3087 for (i = from; i > to; i--)
3088 data->entries[i] = data->entries[i - 1];
3089 data->entries[to] = backup;
3092 #if 0 /* Not done in MUI 3 */
3093 /* Update index of active entry */
3094 if (from == data->entries_active)
3095 data->entries_active = to;
3096 else if (data->entries_active > from && data->entries_active < to)
3097 data->entries_active--;
3098 else if (data->entries_active < from && data->entries_active >= to)
3099 data->entries_active++;
3100 #endif
3102 /* Reflect list changes visually */
3103 data->update = 1;
3104 MUI_Redraw(obj, MADF_DRAWUPDATE);
3106 return TRUE;
3109 /****** List.mui/MUIM_List_NextSelected **************************************
3111 * NAME
3112 * MUIM_List_NextSelected (V6)
3114 * SYNOPSIS
3115 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3117 * FUNCTION
3118 * Allows iteration through a list's selected entries by providing the
3119 * index of the next selected entry after the specified index.
3121 * INPUTS
3122 * pos - the address of a variable containing the index of the previous
3123 * selected entry. The variable must be initialised to the special
3124 * value MUIV_List_NextSelected_Start to find the first selected
3125 * entry. When this method returns, the variable will contain the
3126 * index of the next selected entry, or MUIV_List_NextSelected_End if
3127 * there are no more.
3129 * NOTES
3130 * If there are no selected entries but there is an active entry, the
3131 * index of the active entry will be stored (when
3132 * MUIV_List_NextSelected_Start is specified).
3134 * Some selected entries may be skipped if any entries are removed
3135 * between calls to this method during an iteration of a list.
3137 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3138 * the same numeric value.
3140 * SEE ALSO
3141 * MUIM_List_Select, MUIM_List_Remove.
3143 ******************************************************************************
3147 IPTR List__MUIM_NextSelected(struct IClass *cl, Object *obj,
3148 struct MUIP_List_NextSelected *msg)
3150 struct MUI_ListData *data = INST_DATA(cl, obj);
3151 LONG pos, i;
3152 BOOL found = FALSE;
3154 /* Get the first entry to check */
3155 pos = *msg->pos;
3156 if (pos == MUIV_List_NextSelected_Start)
3157 pos = 0;
3158 else
3159 pos++;
3161 /* Find the next selected entry */
3162 for (i = pos; i < data->entries_num && !found; i++)
3164 if (data->entries[i]->flags & ENTRY_SELECTED)
3166 pos = i;
3167 found = TRUE;
3171 /* Return index of selected or active entry, or indicate there are no
3172 more */
3173 if (!found)
3175 if (*msg->pos == MUIV_List_NextSelected_Start
3176 && data->entries_active != MUIV_List_Active_Off)
3177 pos = data->entries_active;
3178 else
3179 pos = MUIV_List_NextSelected_End;
3181 *msg->pos = pos;
3183 return TRUE;
3186 /**************************************************************************
3187 MUIM_List_TestPos
3188 **************************************************************************/
3189 IPTR List__MUIM_TestPos(struct IClass *cl, Object *obj,
3190 struct MUIP_List_TestPos *msg)
3192 struct MUI_ListData *data = INST_DATA(cl, obj);
3193 struct MUI_List_TestPos_Result *result = msg->res;
3194 LONG col = -1, row = -1;
3195 UWORD flags = 0, i;
3196 LONG mx = msg->x - _left(data->area);
3197 LONG entries_visible;
3199 if (data->entries_visible <= data->entries_num)
3200 entries_visible = data->entries_visible;
3201 else
3202 entries_visible = data->entries_num;
3203 LONG ey = msg->y - data->entries_top_pixel;
3204 /* y coordinates transformed to the entries */
3206 /* Now check if it was clicked on a title or on entries */
3207 if (ey < 0)
3208 flags |= MUI_LPR_ABOVE;
3209 else if (ey >= entries_visible * data->entry_maxheight)
3210 flags |= MUI_LPR_BELOW;
3211 else
3213 /* Identify row */
3214 row = ey / data->entry_maxheight + data->entries_first;
3215 result->yoffset =
3216 ey % data->entry_maxheight - data->entry_maxheight / 2;
3219 if (mx < 0)
3220 flags |= MUI_LPR_LEFT;
3221 else if (mx >= _width(data->area))
3222 flags |= MUI_LPR_RIGHT;
3223 else
3225 /* Identify column */
3226 if (data->entries_num > 0 && data->columns > 0)
3228 LONG width_sum = 0;
3229 col = data->columns - 1;
3230 for (i = 0; i < data->columns; i++)
3232 result->xoffset = mx - width_sum;
3233 width_sum +=
3234 data->ci[i].entries_width +
3235 data->ci[i].delta +
3236 (data->ci[i].bar ? BAR_WIDTH : 0);
3237 D(bug("[List/MUIM_TestPos] i %d "
3238 "width %d width_sum %d mx %d\n",
3239 i, data->ci[i].entries_width, width_sum, mx));
3240 if (mx < width_sum)
3242 col = i;
3243 D(bug("[List/MUIM_TestPos] Column hit %d\n", col));
3244 break;
3250 result->entry = row;
3251 result->column = col;
3252 result->flags = flags;
3254 return TRUE;
3257 /****i* List.mui/MUIM_DragQuery **********************************************
3259 * NAME
3260 * MUIM_DragQuery
3262 ******************************************************************************
3266 IPTR List__MUIM_DragQuery(struct IClass *cl, Object *obj,
3267 struct MUIP_DragQuery *msg)
3269 if (msg->obj == obj)
3270 return MUIV_DragQuery_Accept;
3271 else
3272 return MUIV_DragQuery_Refuse;
3276 /****i* List.mui/MUIM_DragFinish *********************************************
3278 * NAME
3279 * MUIM_DragFinish
3281 ******************************************************************************
3285 IPTR List__MUIM_DragFinish(struct IClass *cl, Object *obj,
3286 struct MUIP_DragFinish *msg)
3288 struct MUI_ListData *data = INST_DATA(cl, obj);
3290 data->drop_mark_y = -1;
3292 return DoSuperMethodA(cl, obj, (Msg) msg);
3295 /****i* List.mui/MUIM_DragReport *********************************************
3297 * NAME
3298 * MUIM_DragReport
3300 ******************************************************************************
3304 IPTR List__MUIM_DragReport(struct IClass *cl, Object *obj,
3305 struct MUIP_DragReport *msg)
3307 struct MUI_ListData *data = INST_DATA(cl, obj);
3308 struct MUI_List_TestPos_Result pos;
3309 struct RastPort *rp = _rp(obj);
3310 LONG n, y;
3311 UWORD old_pattern;
3313 /* Choose new drop mark position */
3315 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3316 if (pos.entry != -1)
3318 n = pos.entry;
3319 if (pos.yoffset > 0)
3320 n++;
3322 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3323 n = data->entries_first;
3324 else
3326 n = MIN(data->entries_visible, data->entries_num)
3327 - data->entries_first;
3330 /* Clear old drop mark */
3332 if ((data->flags & LIST_SHOWDROPMARKS) != 0)
3334 y = data->entries_top_pixel + (n - data->entries_first)
3335 * data->entry_maxheight;
3336 if (y != data->drop_mark_y)
3338 DoMethod(obj, MUIM_DrawBackground, _mleft(data->area),
3339 data->drop_mark_y, _mwidth(data->area), 1, 0, 0, 0);
3341 /* Draw new drop mark and store its position */
3343 SetABPenDrMd(rp, _pens(obj)[MPEN_SHINE], _pens(obj)[MPEN_SHADOW],
3344 JAM2);
3345 old_pattern = rp->LinePtrn;
3346 SetDrPt(rp, 0xF0F0);
3347 Move(rp, _mleft(data->area), y);
3348 Draw(rp, _mright(data->area), y);
3349 SetDrPt(rp, old_pattern);
3350 data->drop_mark_y = y;
3354 return TRUE;
3358 /****i* List.mui/MUIM_DragDrop ***********************************************
3360 * NAME
3361 * MUIM_DragDrop
3363 ******************************************************************************
3367 IPTR List__MUIM_DragDrop(struct IClass *cl, Object *obj,
3368 struct MUIP_DragDrop *msg)
3370 struct MUI_ListData *data = INST_DATA(cl, obj);
3371 struct MUI_List_TestPos_Result pos;
3372 LONG n;
3374 /* Find drop position */
3376 DoMethod(obj, MUIM_List_TestPos, msg->x, msg->y, (IPTR) &pos);
3377 if (pos.entry != -1)
3379 /* Change drop position when coords move past centre of entry, not
3380 * entry boundary */
3382 n = pos.entry;
3383 if (pos.yoffset > 0)
3384 n++;
3386 /* Ensure that dropped entry will be positioned between the two
3387 * entries that are above and below the drop mark, rather than
3388 * strictly at the numeric index shown */
3390 if (n > data->entries_active)
3391 n--;
3393 else if ((pos.flags & MUI_LPR_ABOVE) != 0)
3394 n = MUIV_List_Move_Top;
3395 else
3396 n = MUIV_List_Move_Bottom;
3398 DoMethod(msg->obj, MUIM_List_Move, MUIV_List_Move_Active, n);
3400 return TRUE;
3404 /****i* List.mui/MUIM_CreateDragImage ****************************************
3406 * NAME
3407 * MUIM_CreateDragImage
3409 ******************************************************************************
3413 static IPTR List__MUIM_CreateDragImage(struct IClass *cl, Object *obj,
3414 struct MUIP_CreateDragImage *msg)
3416 struct MUI_ListData *data = INST_DATA(cl, obj);
3417 BOOL success = TRUE;
3418 struct MUI_List_TestPos_Result pos;
3419 WORD width, height, left, top;
3420 struct MUI_DragImage *img = NULL;
3421 const struct ZuneFrameGfx *zframe;
3422 LONG depth;
3424 /* Get info on dragged entry */
3425 DoMethod(obj, MUIM_List_TestPos, _left(data->area) - msg->touchx,
3426 _top(data->area) - msg->touchy, (IPTR) &pos);
3427 if (pos.entry == -1)
3428 success = FALSE;
3430 if (success)
3432 /* Get boundaries of entry */
3433 width = _mwidth(data->area);
3434 height = data->entry_maxheight;
3435 left = _mleft(data->area);
3436 top = _top(data->area) - msg->touchy
3437 - (pos.yoffset + data->entry_maxheight / 2);
3439 /* Allocate drag image structure */
3440 img = (struct MUI_DragImage *)
3441 AllocVec(sizeof(struct MUI_DragImage), MEMF_CLEAR);
3442 if (img == NULL)
3443 success = FALSE;
3446 if (success)
3448 /* Get drag frame */
3449 zframe = zune_zframe_get(obj,
3450 &muiGlobalInfo(obj)->mgi_Prefs->frames[MUIV_Frame_Drag]);
3452 /* Allocate drag image buffer */
3453 img->width = width + zframe->ileft + zframe->iright;
3454 img->height = height + zframe->itop + zframe->ibottom;
3455 depth = GetBitMapAttr(_screen(obj)->RastPort.BitMap, BMA_DEPTH);
3456 img->bm = AllocBitMap(img->width, img->height, depth, BMF_MINPLANES,
3457 _screen(obj)->RastPort.BitMap);
3459 if (img->bm != NULL)
3461 /* Render entry */
3462 struct RastPort temprp;
3463 InitRastPort(&temprp);
3464 temprp.BitMap = img->bm;
3465 ClipBlit(_rp(obj), left, top, &temprp,
3466 zframe->ileft, zframe->itop, width, height,
3467 0xc0);
3469 /* Render frame */
3470 struct RastPort *rp_save = muiRenderInfo(obj)->mri_RastPort;
3471 muiRenderInfo(obj)->mri_RastPort = &temprp;
3472 zframe->draw(zframe->customframe, muiRenderInfo(obj), 0, 0,
3473 img->width, img->height, 0, 0, img->width, img->height);
3474 muiRenderInfo(obj)->mri_RastPort = rp_save;
3477 /* Ensure drag point matches where user clicked */
3478 img->touchx = msg->touchx - zframe->ileft + _addleft(obj);
3479 img->touchy = -(pos.yoffset + data->entry_maxheight / 2)
3480 - zframe->itop;
3481 img->flags = 0;
3484 return (IPTR) img;
3487 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely)
3489 LONG new, first, entries, visible;
3491 new = first = XGET(obj, MUIA_List_First);
3492 entries = XGET(obj, MUIA_List_Entries);
3493 visible = XGET(obj, MUIA_List_Visible);
3495 new += wheely;
3497 if (new > entries - visible)
3499 new = entries - visible;
3502 if (new < 0)
3504 new = 0;
3507 if (new != first)
3509 set(obj, MUIA_List_First, new);
3513 /**************************************************************************
3514 MUIM_HandleEvent
3515 **************************************************************************/
3516 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
3517 struct MUIP_HandleEvent *msg)
3519 struct MUI_ListData *data = INST_DATA(cl, obj);
3520 struct MUI_List_TestPos_Result pos;
3521 LONG seltype, old_active, new_active, visible, first, last, i;
3522 IPTR result = 0;
3523 BOOL select = FALSE, clear = FALSE, range_select = FALSE, changing;
3524 WORD delta;
3525 typeof(msg->muikey) muikey = msg->muikey;
3527 new_active = old_active = XGET(obj, MUIA_List_Active);
3528 visible = XGET(obj, MUIA_List_Visible);
3530 if (muikey != MUIKEY_NONE)
3532 result = MUI_EventHandlerRC_Eat;
3534 /* Make keys behave differently in read-only mode */
3535 if (data->read_only)
3537 switch (muikey)
3539 case MUIKEY_TOP:
3540 muikey = MUIKEY_LINESTART;
3541 break;
3543 case MUIKEY_BOTTOM:
3544 muikey = MUIKEY_LINEEND;
3545 break;
3547 case MUIKEY_UP:
3548 muikey = MUIKEY_LEFT;
3549 break;
3551 case MUIKEY_DOWN:
3552 case MUIKEY_PRESS:
3553 muikey = MUIKEY_RIGHT;
3554 break;
3558 switch (muikey)
3560 case MUIKEY_TOGGLE:
3561 if (data->multiselect != MUIV_Listview_MultiSelect_None
3562 && !data->read_only)
3564 select = TRUE;
3565 data->click_column = data->def_click_column;
3566 new_active = MUIV_List_Active_Down;
3568 else
3570 DoMethod(obj, MUIM_List_Jump, 0);
3571 muikey = MUIKEY_NONE;
3573 break;
3575 case MUIKEY_TOP:
3576 new_active = MUIV_List_Active_Top;
3577 break;
3579 case MUIKEY_BOTTOM:
3580 new_active = MUIV_List_Active_Bottom;
3581 break;
3583 case MUIKEY_LEFT:
3584 case MUIKEY_WORDLEFT:
3585 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Up);
3586 break;
3588 case MUIKEY_RIGHT:
3589 case MUIKEY_WORDRIGHT:
3590 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Down);
3591 break;
3593 case MUIKEY_LINESTART:
3594 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Top);
3595 break;
3597 case MUIKEY_LINEEND:
3598 DoMethod(obj, MUIM_List_Jump, MUIV_List_Jump_Bottom);
3599 break;
3601 case MUIKEY_UP:
3602 new_active = MUIV_List_Active_Up;
3603 break;
3605 case MUIKEY_DOWN:
3606 new_active = MUIV_List_Active_Down;
3607 break;
3609 case MUIKEY_PRESS:
3610 data->click_column = data->def_click_column;
3611 superset(cl, obj, MUIA_Listview_ClickColumn,
3612 data->click_column);
3613 set(obj, MUIA_Listview_DoubleClick, TRUE);
3614 break;
3616 case MUIKEY_PAGEUP:
3617 if (data->read_only)
3618 DoWheelMove(cl, obj, -visible);
3619 else
3620 new_active = MUIV_List_Active_PageUp;
3621 break;
3623 case MUIKEY_PAGEDOWN:
3624 if (data->read_only)
3625 DoWheelMove(cl, obj, visible);
3626 else
3627 new_active = MUIV_List_Active_PageDown;
3628 break;
3630 default:
3631 result = 0;
3634 else if (msg->imsg)
3636 DoMethod(obj, MUIM_List_TestPos, msg->imsg->MouseX, msg->imsg->MouseY,
3637 (IPTR) &pos);
3639 switch (msg->imsg->Class)
3641 case IDCMP_MOUSEBUTTONS:
3642 if (msg->imsg->Code == SELECTDOWN)
3644 if (_isinobject(data->area, msg->imsg->MouseX,
3645 msg->imsg->MouseY))
3647 data->mouse_click = MOUSE_CLICK_ENTRY;
3649 if (!data->read_only && pos.entry != -1)
3651 new_active = pos.entry;
3653 clear = (data->multiselect
3654 == MUIV_Listview_MultiSelect_Shifted
3655 && (msg->imsg->Qualifier
3656 & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT)) == 0);
3657 seltype = clear ? MUIV_List_Select_On
3658 : MUIV_List_Select_Toggle;
3659 select = data->multiselect
3660 != MUIV_Listview_MultiSelect_None;
3662 /* Handle MUIA_Listview_ClickColumn */
3663 data->click_column = pos.column;
3664 superset(cl, obj, MUIA_Listview_ClickColumn,
3665 data->click_column);
3667 /* Handle double clicking */
3668 if (data->last_active == pos.entry
3669 && DoubleClick(data->last_secs, data->last_mics,
3670 msg->imsg->Seconds, msg->imsg->Micros))
3672 set(obj, MUIA_Listview_DoubleClick, TRUE);
3673 data->last_active = -1;
3674 data->last_secs = data->last_mics = 0;
3676 else
3678 data->last_active = pos.entry;
3679 data->last_secs = msg->imsg->Seconds;
3680 data->last_mics = msg->imsg->Micros;
3683 /* Look out for mouse movement, timer and
3684 inactive-window events while mouse button is
3685 down */
3686 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3687 (IPTR) &data->ehn);
3688 data->ehn.ehn_Events |= (IDCMP_MOUSEMOVE
3689 | IDCMP_INTUITICKS |IDCMP_INACTIVEWINDOW);
3690 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3691 (IPTR) &data->ehn);
3695 else
3697 /* Activate object */
3698 if (msg->imsg->Code == SELECTUP && data->mouse_click)
3700 set(_win(obj), MUIA_Window_ActiveObject, (IPTR)obj);
3701 data->mouse_click = 0;
3704 /* Restore normal event mask */
3705 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3706 (IPTR) &data->ehn);
3707 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS
3708 | IDCMP_INACTIVEWINDOW);
3709 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3710 (IPTR) &data->ehn);
3712 break;
3714 case IDCMP_MOUSEMOVE:
3715 case IDCMP_INTUITICKS:
3716 if (pos.flags & MUI_LPR_ABOVE)
3717 new_active = MUIV_List_Active_Up;
3718 else if (pos.flags & MUI_LPR_BELOW)
3719 new_active = MUIV_List_Active_Down;
3720 else
3721 new_active = pos.entry;
3723 select = new_active != old_active
3724 && data->multiselect != MUIV_Listview_MultiSelect_None;
3725 if (select)
3727 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3728 MUIV_List_Select_Ask, &seltype);
3729 range_select = new_active >= 0;
3732 break;
3734 case IDCMP_INACTIVEWINDOW:
3735 /* Stop listening for events we only listen to when mouse button is
3736 down: we will not be informed of the button being released */
3737 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
3738 (IPTR) &data->ehn);
3739 data->ehn.ehn_Events &=
3740 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS | IDCMP_INACTIVEWINDOW);
3741 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
3742 (IPTR) &data->ehn);
3743 break;
3745 case IDCMP_RAWKEY:
3746 /* Scroll wheel */
3747 if (data->vert && _isinobject(data->vert, msg->imsg->MouseX,
3748 msg->imsg->MouseY))
3749 delta = 1;
3750 else if (_isinobject(data->area, msg->imsg->MouseX,
3751 msg->imsg->MouseY))
3752 delta = 4;
3753 else
3754 delta = 0;
3756 if (delta != 0)
3758 switch (msg->imsg->Code)
3760 case RAWKEY_NM_WHEEL_UP:
3761 DoWheelMove(cl, obj, -delta);
3762 break;
3764 case RAWKEY_NM_WHEEL_DOWN:
3765 DoWheelMove(cl, obj, delta);
3766 break;
3768 result = MUI_EventHandlerRC_Eat;
3770 break;
3774 /* Decide in advance if any selections may change */
3775 changing = clear || muikey == MUIKEY_TOGGLE || select;
3777 /* Change selected and active entries */
3778 if (changing)
3779 set(obj, MUIA_Listview_SelectChange, TRUE);
3781 if (clear)
3783 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_All,
3784 MUIV_List_Select_Off, NULL);
3787 if (muikey == MUIKEY_TOGGLE)
3789 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3790 MUIV_List_Select_Toggle, NULL);
3791 select = FALSE;
3794 if (new_active != old_active)
3795 set(obj, MUIA_List_Active, new_active);
3797 if (select)
3799 if (range_select)
3801 if (old_active < new_active)
3802 first = old_active + 1, last = new_active;
3803 else
3804 first = new_active, last = old_active - 1;
3805 for (i = first; i <= last; i++)
3806 DoMethod(obj, MUIM_List_Select, i, seltype, NULL);
3808 else
3809 DoMethod(obj, MUIM_List_Select, MUIV_List_Select_Active,
3810 seltype, NULL);
3813 if (changing)
3814 set(obj, MUIA_Listview_SelectChange, FALSE);
3816 return result;
3819 /**************************************************************************
3820 Dispatcher
3821 **************************************************************************/
3822 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
3824 switch (msg->MethodID)
3826 case OM_NEW:
3827 return List__OM_NEW(cl, obj, (struct opSet *)msg);
3828 case OM_DISPOSE:
3829 return List__OM_DISPOSE(cl, obj, msg);
3830 case OM_SET:
3831 return List__OM_SET(cl, obj, (struct opSet *)msg);
3832 case OM_GET:
3833 return List__OM_GET(cl, obj, (struct opGet *)msg);
3835 case MUIM_Setup:
3836 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
3837 case MUIM_Cleanup:
3838 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
3839 case MUIM_HandleEvent:
3840 return List__MUIM_HandleEvent(cl, obj, (struct MUIP_HandleEvent *)msg);
3841 case MUIM_AskMinMax:
3842 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
3843 case MUIM_Show:
3844 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
3845 case MUIM_Hide:
3846 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
3847 case MUIM_Draw:
3848 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
3849 case MUIM_Layout:
3850 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
3851 case MUIM_List_Clear:
3852 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
3853 case MUIM_List_Sort:
3854 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
3855 case MUIM_List_Exchange:
3856 return List__MUIM_Exchange(cl, obj,
3857 (struct MUIP_List_Exchange *)msg);
3858 case MUIM_List_Insert:
3859 return List__MUIM_Insert(cl, obj, (APTR) msg);
3860 case MUIM_List_InsertSingle:
3861 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
3862 case MUIM_List_GetEntry:
3863 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
3864 case MUIM_List_Redraw:
3865 return List__MUIM_Redraw(cl, obj, (APTR) msg);
3866 case MUIM_List_Remove:
3867 return List__MUIM_Remove(cl, obj, (APTR) msg);
3868 case MUIM_List_Select:
3869 return List__MUIM_Select(cl, obj, (APTR) msg);
3870 case MUIM_List_Construct:
3871 return List__MUIM_Construct(cl, obj, (APTR) msg);
3872 case MUIM_List_Destruct:
3873 return List__MUIM_Destruct(cl, obj, (APTR) msg);
3874 case MUIM_List_Compare:
3875 return List__MUIM_Compare(cl, obj, (APTR) msg);
3876 case MUIM_List_Display:
3877 return List__MUIM_Display(cl, obj, (APTR) msg);
3878 case MUIM_List_SelectChange:
3879 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
3880 case MUIM_List_CreateImage:
3881 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
3882 case MUIM_List_DeleteImage:
3883 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
3884 case MUIM_List_Jump:
3885 return List__MUIM_Jump(cl, obj, (APTR) msg);
3886 case MUIM_List_Move:
3887 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
3888 case MUIM_List_NextSelected:
3889 return List__MUIM_NextSelected(cl, obj,
3890 (struct MUIP_List_NextSelected *)msg);
3891 case MUIM_List_TestPos:
3892 return List__MUIM_TestPos(cl, obj, (APTR) msg);
3893 case MUIM_DragQuery:
3894 return List__MUIM_DragQuery(cl, obj, (APTR) msg);
3895 case MUIM_DragFinish:
3896 return List__MUIM_DragFinish(cl, obj, (APTR) msg);
3897 case MUIM_DragReport:
3898 return List__MUIM_DragReport(cl, obj, (APTR) msg);
3899 case MUIM_DragDrop:
3900 return List__MUIM_DragDrop(cl, obj, (APTR) msg);
3901 case MUIM_CreateDragImage:
3902 return List__MUIM_CreateDragImage(cl, obj, (APTR) msg);
3905 return DoSuperMethodA(cl, obj, msg);
3907 BOOPSI_DISPATCHER_END
3910 * Class descriptor.
3912 const struct __MUIBuiltinClass _MUI_List_desc =
3914 MUIC_List,
3915 MUIC_Group,
3916 sizeof(struct MUI_ListData),
3917 (void *) List_Dispatcher