Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / muimaster / classes / list.c
blob99f1538c9abdc7b9323b7ca2956cce506be45ec3
1 /*
2 Copyright © 2002-2012, 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/view.h>
12 #include <devices/rawkeycodes.h>
13 #include <clib/alib_protos.h>
14 #include <proto/exec.h>
15 #include <proto/graphics.h>
16 #include <proto/utility.h>
17 #include <proto/dos.h>
18 #include <proto/intuition.h>
19 #include <proto/muimaster.h>
21 /* #define MYDEBUG 1 */
22 #include "debug.h"
23 #include "mui.h"
24 #include "muimaster_intern.h"
25 #include "support.h"
26 #include "imspec.h"
27 #include "textengine.h"
28 #include "listimage.h"
29 #include "prefs.h"
31 extern struct Library *MUIMasterBase;
33 #define ENTRY_TITLE (-1)
35 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
36 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
38 #define BAR_WIDTH 2
40 enum
42 ARG_DELTA,
43 ARG_PREPARSE,
44 ARG_WEIGHT,
45 ARG_MINWIDTH,
46 ARG_MAXWIDTH,
47 ARG_COL,
48 ARG_BAR,
49 ARG_CNT
53 struct ListEntry
55 APTR data;
56 LONG *widths; /* Widths of the columns */
57 LONG width; /* Line width */
58 LONG height; /* Line height */
59 WORD flags; /* see below */
63 struct ColumnInfo
65 int colno; /* Column number */
66 int user_width; /* user set width; -1 if entry width */
67 int min_width; /* min width percentage */
68 int max_width; /* min width percentage */
69 int weight;
70 int delta; /* ignored for the first and last column, defaults to 4 */
71 int bar;
72 STRPTR preparse;
73 int entries_width; /* width of the entries (maximum of all widths) */
76 struct MUI_ImageSpec_intern;
78 struct MUI_ListData
80 /* bool attrs */
81 ULONG flags;
83 APTR intern_pool; /* The internal pool which the class has allocated */
84 LONG intern_puddle_size;
85 LONG intern_tresh_size;
86 APTR pool; /* the pool which is used to allocate list entries */
88 struct Hook *construct_hook;
89 struct Hook *compare_hook;
90 struct Hook *destruct_hook;
91 struct Hook *display_hook;
93 struct Hook default_compare_hook;
95 /* List managment, currently we use a simple flat array, which is not
96 * good if many entries are inserted/deleted */
97 LONG entries_num; /* Number of Entries in the list */
98 LONG entries_allocated;
99 struct ListEntry **entries;
101 LONG entries_first; /* first visible entry */
102 LONG entries_visible; /* number of visible entries,
103 * determined at MUIM_Layout */
104 LONG entries_active;
105 LONG insert_position; /* pos of the last insertion */
107 LONG entry_maxheight; /* Maximum height of an entry */
108 ULONG entry_minheight; /* from MUIA_List_MinLineHeight */
110 LONG entries_totalheight;
111 LONG entries_maxwidth;
113 LONG vertprop_entries;
114 LONG vertprop_visible;
115 LONG vertprop_first;
117 LONG confirm_entries_num; /* These are the correct entries num, used
118 * so you cannot set MUIA_List_Entries to
119 * wrong values */
121 LONG entries_top_pixel; /* Where the entries start */
123 /* Column managment, is allocated by ParseListFormat() and freed
124 * by CleanListFormat() */
125 STRPTR format;
126 LONG columns; /* Number of columns the list has */
127 struct ColumnInfo *ci;
128 STRPTR *preparses;
129 STRPTR *strings; /* the strings for the display function, one
130 * more than needed (for the entry position) */
132 /* Titlestuff */
133 int title_height; /* The complete height of the title */
134 STRPTR title; /* On single comlums this is the title, otherwise 1 */
136 struct MUI_EventHandlerNode ehn;
137 int mouse_click; /* see below if mouse is hold down */
139 /* Cursor images */
140 struct MUI_ImageSpec_intern *list_cursor;
141 struct MUI_ImageSpec_intern *list_select;
142 struct MUI_ImageSpec_intern *list_selcur;
144 /* Render optimization */
145 int update; /* 1 - update everything, 2 - redraw entry at update_pos,
146 * 3 - scroll to current entries_first (old value is in
147 * update_pos) */
148 int update_pos;
150 /* double click */
151 ULONG last_secs;
152 ULONG last_mics;
153 ULONG last_active;
154 ULONG doubleclick;
156 /* clicked column */
157 LONG click_column;
159 /* list type */
160 ULONG input; /* FALSE - readonly, otherwise TRUE */
162 /* list images */
163 struct MinList images;
165 /* user prefs */
166 ListviewMulti prefs_multi;
167 ListviewRefresh prefs_refresh;
168 UWORD prefs_linespacing;
169 BOOL prefs_smoothed;
170 UWORD prefs_smoothval;
173 #define LIST_ADJUSTWIDTH (1<<0)
174 #define LIST_ADJUSTHEIGHT (1<<1)
175 #define LIST_AUTOVISIBLE (1<<2)
176 #define LIST_DRAGSORTABLE (1<<3)
177 #define LIST_SHOWDROPMARKS (1<<4)
178 #define LIST_QUIET (1<<5)
181 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
182 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
184 /**************************************************************************
185 Allocate a single list entry, does not initialize it (except the pointer)
186 **************************************************************************/
187 static struct ListEntry *AllocListEntry(struct MUI_ListData *data)
189 ULONG *mem;
190 struct ListEntry *le;
191 int size = sizeof(struct ListEntry) + sizeof(LONG) * data->columns + 4;
192 /* sizeinfo */
193 LONG j;
195 mem = AllocPooled(data->pool, size);
196 if (!mem)
197 return NULL;
198 D(bug("List AllocListEntry %p, %ld bytes\n", mem, size));
200 mem[0] = size; /* Save the size */
201 le = (struct ListEntry *)(mem + 1);
202 le->widths = (LONG *) (le + 1);
204 /* Initialize fields */
205 le->height = 0;
206 le->width = 0;
207 for (j = 0; j < data->columns; j++)
208 le->widths[j] = 0;
210 return le;
213 /**************************************************************************
214 Deallocate a single list entry, does not deinitialize it
215 **************************************************************************/
216 static void FreeListEntry(struct MUI_ListData *data,
217 struct ListEntry *entry)
219 ULONG *mem = ((ULONG *) entry) - 1;
220 D(bug("FreeListEntry %p size=%ld\n", mem, mem[0]));
221 FreePooled(data->pool, mem, mem[0]);
224 /**************************************************************************
225 Ensures that we there can be at least the given amount of entries within
226 the list. Returns 0 if not. It also allocates the space for the title.
227 It can be accesses with data->entries[ENTRY_TITLE]
228 **************************************************************************/
229 static int SetListSize(struct MUI_ListData *data, LONG size)
231 struct ListEntry **new_entries;
232 int new_entries_allocated;
234 if (size + 1 <= data->entries_allocated)
235 return 1;
237 new_entries_allocated = data->entries_allocated * 2 + 4;
238 if (new_entries_allocated < size + 1)
239 new_entries_allocated = size + 1 + 10; /* 10 is just random */
241 D(bug("List %p : SetListSize allocating %ld bytes\n", data,
242 new_entries_allocated * sizeof(struct ListEntry *)));
243 new_entries =
244 AllocVec(new_entries_allocated * sizeof(struct ListEntry *), 0);
245 if (NULL == new_entries)
246 return 0;
247 if (data->entries)
249 CopyMem(data->entries - 1, new_entries,
250 (data->entries_num + 1) * sizeof(struct ListEntry *));
251 FreeVec(data->entries - 1);
253 data->entries = new_entries + 1;
254 data->entries_allocated = new_entries_allocated;
255 return 1;
258 /**************************************************************************
259 Prepares the insertion of count entries at pos.
260 This function doesn't care if there is enough space in the datastructure.
261 SetListSize() must be used first.
262 With current implementation, this call will never fail
263 **************************************************************************/
264 static int PrepareInsertListEntries(struct MUI_ListData *data, int pos,
265 int count)
267 memmove(&data->entries[pos + count], &data->entries[pos],
268 (data->entries_num - pos) * sizeof(struct ListEntry *));
269 return 1;
272 /**************************************************************************
273 Inserts a already initialized array of Entries at the given position.
274 This function doesn't care if there is enough space in the datastructure
275 Returns 1 if something failed (never in current implementation)
276 **************************************************************************/
277 #if 0
278 static int InsertListEntries(struct MUI_ListData *data, int pos,
279 struct ListEntry **array, int count)
281 memmove(&data->entries[pos + count], &data->entries[pos],
282 data->entries_num - pos);
283 memcpy(&data->entries[pos], array, count);
284 return 1;
286 #endif
289 /**************************************************************************
290 Removes count (already deinitalized) list entries starting az pos.
291 **************************************************************************/
292 static void RemoveListEntries(struct MUI_ListData *data, int pos, int count)
294 // FIXME: segfault if entries_num = pos = count = 1
295 memmove(&data->entries[pos], &data->entries[pos + count],
296 (data->entries_num - (pos + count)) * sizeof(struct ListEntry *));
299 /**************************************************************************
300 Frees all memory allocated by ParseListFormat()
301 **************************************************************************/
302 static void FreeListFormat(struct MUI_ListData *data)
304 int i;
306 if (data->ci)
308 for (i = 0; i < data->columns; i++)
310 FreeVec(data->ci[i].preparse);
311 data->ci[i].preparse = NULL;
313 FreeVec(data->ci);
314 data->ci = NULL;
316 if (data->preparses)
318 FreeVec(data->preparses);
319 data->preparses = NULL;
321 if (data->strings)
323 FreeVec(data->strings - 1);
324 data->strings = NULL;
326 data->columns = 0;
329 /**************************************************************************
330 Parses the given format string (also frees a previouly parsed format).
331 Return 0 on failure.
332 **************************************************************************/
333 static int ParseListFormat(struct MUI_ListData *data, STRPTR format)
335 int new_columns, i;
336 STRPTR ptr;
337 STRPTR format_sep;
338 char c;
340 IPTR args[ARG_CNT];
341 struct RDArgs *rdargs;
343 if (!format)
344 format = (STRPTR) "";
346 ptr = format;
348 FreeListFormat(data);
350 new_columns = 1;
352 /* Count the number of columns first */
353 while ((c = *ptr++))
354 if (c == ',')
355 new_columns++;
357 if (!(data->preparses =
358 AllocVec((new_columns + 10) * sizeof(STRPTR), 0)))
359 return 0;
361 if (!(data->strings = AllocVec((new_columns + 1 + 10)
362 * sizeof(STRPTR), 0))) /* hold enough space also for the entry pos,
363 * used by orginal MUI and also some
364 * security space */
365 return 0;
367 if (!(data->ci = AllocVec(new_columns * sizeof(struct ColumnInfo), 0)))
368 return 0;
370 // set defaults
371 for (i = 0; i < new_columns; i++)
373 data->ci[i].colno = -1; // -1 means: use unassigned column
374 data->ci[i].weight = 100;
375 data->ci[i].delta = 4;
376 data->ci[i].min_width = -1;
377 data->ci[i].max_width = -1;
378 data->ci[i].user_width = -1;
379 data->ci[i].bar = FALSE;
380 data->ci[i].preparse = NULL;
383 if ((format_sep = StrDup(format)) != 0)
385 for (i = 0; format_sep[i] != '\0'; i++)
387 if (format_sep[i] == ',')
388 format_sep[i] = '\0';
391 if ((rdargs = AllocDosObject(DOS_RDARGS, NULL)) != 0)
393 ptr = format_sep;
394 i = 0;
397 rdargs->RDA_Source.CS_Buffer = ptr;
398 rdargs->RDA_Source.CS_Length = strlen(ptr);
399 rdargs->RDA_Source.CS_CurChr = 0;
400 rdargs->RDA_DAList = 0;
401 rdargs->RDA_Buffer = NULL;
402 rdargs->RDA_BufSiz = 0;
403 rdargs->RDA_ExtHelp = NULL;
404 rdargs->RDA_Flags = 0;
406 memset(args, 0, sizeof args);
407 if (ReadArgs(FORMAT_TEMPLATE, args, rdargs))
409 if (args[ARG_COL])
410 data->ci[i].colno = *(LONG *) args[ARG_COL];
411 if (args[ARG_WEIGHT])
412 data->ci[i].weight = *(LONG *) args[ARG_WEIGHT];
413 if (args[ARG_DELTA])
414 data->ci[i].delta = *(LONG *) args[ARG_DELTA];
415 if (args[ARG_MINWIDTH])
416 data->ci[i].min_width =
417 *(LONG *) args[ARG_MINWIDTH];
418 if (args[ARG_MAXWIDTH])
419 data->ci[i].max_width =
420 *(LONG *) args[ARG_MAXWIDTH];
421 data->ci[i].bar = args[ARG_BAR];
422 if (args[ARG_PREPARSE])
423 data->ci[i].preparse =
424 StrDup((STRPTR) args[ARG_PREPARSE]);
426 FreeArgs(rdargs);
428 ptr += strlen(ptr) + 1;
429 i++;
431 while (i < new_columns);
432 FreeDosObject(DOS_RDARGS, rdargs);
434 FreeVec(format_sep);
437 for (i = 0; i < new_columns; i++)
439 D(bug("colno %d weight %d delta %d preparse %s\n",
440 data->ci[i].colno, data->ci[i].weight, data->ci[i].delta,
441 data->ci[i].preparse));
444 data->columns = new_columns;
445 data->strings++; /* Skip entry pos */
447 return 1;
450 /**************************************************************************
451 Call the MUIM_List_Display for the given entry. It fills out
452 data->string and data->preparses
453 **************************************************************************/
454 static void DisplayEntry(struct IClass *cl, Object *obj, int entry_pos)
456 struct MUI_ListData *data = INST_DATA(cl, obj);
457 APTR entry_data;
458 int col;
460 for (col = 0; col < data->columns; col++)
461 data->preparses[col] = data->ci[col].preparse;
463 if (entry_pos == ENTRY_TITLE)
465 if ((data->columns == 1) && (data->title != (STRPTR) 1))
467 *data->strings = data->title;
468 return;
470 entry_data = NULL; /* it's a title request */
472 else
473 entry_data = data->entries[entry_pos]->data;
475 /* Get the display formation */
476 DoMethod(obj, MUIM_List_Display, (IPTR) entry_data,
477 (IPTR) data->strings, entry_pos, (IPTR) data->preparses);
480 /**************************************************************************
481 Determine the dims of a single entry and adapt the columinfo according
482 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
483 be redrawn after this operation, 1 if all entries need to be redrawn.
484 **************************************************************************/
485 static int CalcDimsOfEntry(struct IClass *cl, Object *obj, int pos)
487 struct MUI_ListData *data = INST_DATA(cl, obj);
488 struct ListEntry *entry = data->entries[pos];
489 int j;
490 int ret = 0;
492 if (!entry)
493 return ret;
495 if (!(_flags(obj) & MADF_SETUP))
496 return ret;
498 DisplayEntry(cl, obj, pos);
500 /* Set height to at least minheight */
501 if (data->entries[pos]->height < data->entry_minheight)
502 data->entries[pos]->height = data->entry_minheight;
504 for (j = 0; j < data->columns; j++)
506 ZText *text =
507 zune_text_new(data->preparses[j], data->strings[j],
508 ZTEXT_ARG_NONE, 0);
509 if (text != NULL)
511 zune_text_get_bounds(text, obj);
513 if (text->height > data->entries[pos]->height)
515 data->entries[pos]->height = text->height;
516 /* entry height changed, redraw all entries later */
517 ret = 1;
519 data->entries[pos]->widths[j] = text->width;
521 if (text->width > data->ci[j].entries_width)
523 /* This columns width is bigger than the other in the same
524 * columns, so we store this value
526 data->ci[j].entries_width = text->width;
527 /* column width changed, redraw all entries later */
528 ret = 1;
531 zune_text_destroy(text);
534 if (data->entries[pos]->height > data->entry_maxheight)
536 data->entry_maxheight = data->entries[pos]->height;
537 /* maximum entry height changed, redraw all entries later */
538 ret = 1;
541 return ret;
544 /**************************************************************************
545 Determine the widths of the entries
546 **************************************************************************/
547 static void CalcWidths(struct IClass *cl, Object *obj)
549 int i, j;
550 struct MUI_ListData *data = INST_DATA(cl, obj);
552 if (!(_flags(obj) & MADF_SETUP))
553 return;
555 for (j = 0; j < data->columns; j++)
556 data->ci[j].entries_width = 0;
558 data->entry_maxheight = 0;
559 data->entries_totalheight = 0;
560 data->entries_maxwidth = 0;
562 for (i = (data->title ? ENTRY_TITLE : 0); i < data->entries_num; i++)
564 CalcDimsOfEntry(cl, obj, i);
565 data->entries_totalheight += data->entries[i]->height;
568 for (j = 0; j < data->columns; j++)
569 data->entries_maxwidth += data->ci[j].entries_width;
571 if (!data->entry_maxheight)
572 data->entry_maxheight = 1;
575 /**************************************************************************
576 Calculates the number of visible entry lines. Returns 1 if it has
577 changed
578 **************************************************************************/
579 static int CalcVertVisible(struct IClass *cl, Object *obj)
581 struct MUI_ListData *data = INST_DATA(cl, obj);
582 int old_entries_visible = data->entries_visible;
583 int old_entries_top_pixel = data->entries_top_pixel;
585 data->entries_visible = (_mheight(obj) - data->title_height)
586 / (data->entry_maxheight /* + data->prefs_linespacing */ );
588 data->entries_top_pixel = _mtop(obj) + data->title_height
589 + (_mheight(obj) - data->title_height
591 data->entries_visible *
592 (data->entry_maxheight /* + data->prefs_linespacing */ )) / 2;
594 return (old_entries_visible != data->entries_visible)
595 || (old_entries_top_pixel != data->entries_top_pixel);
598 /**************************************************************************
599 Default hook to compare two list entries. Works for strings only.
600 **************************************************************************/
601 AROS_UFH3S(int, default_compare_func,
602 AROS_UFHA(struct Hook *, h, A0),
603 AROS_UFHA(char *, s2, A2),
604 AROS_UFHA(char *, s1, A1))
606 AROS_USERFUNC_INIT
608 return Stricmp(s1, s2);
610 AROS_USERFUNC_EXIT
613 /**************************************************************************
614 OM_NEW
615 **************************************************************************/
616 IPTR List__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
618 struct MUI_ListData *data;
619 struct TagItem *tag;
620 struct TagItem *tags;
621 APTR *array = NULL;
622 LONG new_entries_active = MUIV_List_Active_Off;
624 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
625 MUIA_Font, MUIV_Font_List,
626 MUIA_Background, MUII_ListBack, TAG_MORE, (IPTR) msg->ops_AttrList);
627 if (!obj)
628 return FALSE;
630 data = INST_DATA(cl, obj);
632 data->columns = 1;
633 data->entries_active = MUIV_List_Active_Off;
634 data->intern_puddle_size = 2008;
635 data->intern_tresh_size = 1024;
636 data->input = 1;
637 data->default_compare_hook.h_Entry = (HOOKFUNC) default_compare_func;
638 data->default_compare_hook.h_SubEntry = 0;
639 data->compare_hook = &(data->default_compare_hook);
641 /* parse initial taglist */
642 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
644 switch (tag->ti_Tag)
646 case MUIA_List_Active:
647 new_entries_active = tag->ti_Data;
648 break;
650 case MUIA_List_Pool:
651 data->pool = (APTR) tag->ti_Data;
652 break;
654 case MUIA_List_PoolPuddleSize:
655 data->intern_puddle_size = tag->ti_Data;
656 break;
658 case MUIA_List_PoolThreshSize:
659 data->intern_tresh_size = tag->ti_Data;
660 break;
662 case MUIA_List_CompareHook:
663 /* Not tested, if List_CompareHook really works. */
664 data->compare_hook = (struct Hook *)tag->ti_Data;
665 break;
667 case MUIA_List_ConstructHook:
668 data->construct_hook = (struct Hook *)tag->ti_Data;
669 break;
671 case MUIA_List_DestructHook:
672 data->destruct_hook = (struct Hook *)tag->ti_Data;
673 break;
675 case MUIA_List_DisplayHook:
676 data->display_hook = (struct Hook *)tag->ti_Data;
677 break;
679 case MUIA_List_SourceArray:
680 array = (APTR *) tag->ti_Data;
681 break;
683 case MUIA_List_Format:
684 data->format = StrDup((STRPTR) tag->ti_Data);
685 break;
687 case MUIA_List_Title:
688 data->title = (STRPTR) tag->ti_Data;
689 break;
691 case MUIA_List_MinLineHeight:
692 data->entry_minheight = tag->ti_Data;
693 break;
695 case MUIA_List_AdjustHeight:
696 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTHEIGHT);
697 break;
699 case MUIA_List_AdjustWidth:
700 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTWIDTH);
701 break;
706 if (!data->pool)
708 /* No memory pool given, so we create our own */
709 data->pool = data->intern_pool =
710 CreatePool(0, data->intern_puddle_size,
711 data->intern_tresh_size);
712 if (!data->pool)
714 CoerceMethod(cl, obj, OM_DISPOSE);
715 return 0;
719 /* parse the list format */
720 if (!(ParseListFormat(data, data->format)))
722 CoerceMethod(cl, obj, OM_DISPOSE);
723 return 0;
726 /* This is neccessary for at least the title */
727 if (!SetListSize(data, 0))
729 CoerceMethod(cl, obj, OM_DISPOSE);
730 return 0;
733 if (data->title)
735 if (!(data->entries[ENTRY_TITLE] = AllocListEntry(data)))
737 CoerceMethod(cl, obj, OM_DISPOSE);
738 return 0;
741 else
742 data->entries[ENTRY_TITLE] = NULL;
745 if (array)
747 int i;
748 /* Count the number of elements */
749 for (i = 0; array[i] != NULL; i++)
751 /* Insert them */
752 DoMethod(obj, MUIM_List_Insert, (IPTR) array, i,
753 MUIV_List_Insert_Top);
757 if ((data->entries_num) && (new_entries_active != MUIV_List_Active_Off))
759 switch (new_entries_active)
761 case MUIV_List_Active_Top:
762 new_entries_active = 0;
763 break;
765 case MUIV_List_Active_Bottom:
766 new_entries_active = data->entries_num - 1;
767 break;
770 if (new_entries_active < 0)
771 new_entries_active = 0;
772 else if (new_entries_active >= data->entries_num)
773 new_entries_active = data->entries_num - 1;
775 data->entries_active = new_entries_active;
776 /* Selected entry will be moved into visible area */
780 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS |
781 IDCMP_RAWKEY | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW;
782 data->ehn.ehn_Priority = 0;
783 data->ehn.ehn_Flags = 0;
784 data->ehn.ehn_Object = obj;
785 data->ehn.ehn_Class = cl;
787 NewList((struct List *)&data->images);
789 D(bug("List_New(%lx)\n", obj));
791 return (IPTR) obj;
794 /**************************************************************************
795 OM_DISPOSE
796 **************************************************************************/
797 IPTR List__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
799 struct MUI_ListData *data = INST_DATA(cl, obj);
801 D(bug("List Dispose\n"));
803 /* Call destruct method for every entry and free the entries manually
804 * to avoid notification */
805 while (data->confirm_entries_num)
807 struct ListEntry *lentry =
808 data->entries[--data->confirm_entries_num];
809 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
810 (IPTR) data->pool);
811 FreeListEntry(data, lentry);
814 if (data->intern_pool)
815 DeletePool(data->intern_pool);
816 if (data->entries)
817 FreeVec(data->entries - 1);
818 /* title is currently before all other elements */
820 FreeListFormat(data);
821 FreeVec(data->format);
823 return DoSuperMethodA(cl, obj, msg);
827 /**************************************************************************
828 OM_SET
829 **************************************************************************/
830 IPTR List__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
832 struct MUI_ListData *data = INST_DATA(cl, obj);
833 struct TagItem *tag;
834 struct TagItem *tags;
836 /* parse initial taglist */
837 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
839 switch (tag->ti_Tag)
841 case MUIA_List_CompareHook:
842 data->compare_hook = (struct Hook *)tag->ti_Data;
843 break;
845 case MUIA_List_ConstructHook:
846 data->construct_hook = (struct Hook *)tag->ti_Data;
847 break;
849 case MUIA_List_DestructHook:
850 data->destruct_hook = (struct Hook *)tag->ti_Data;
851 break;
853 case MUIA_List_DisplayHook:
854 data->display_hook = (struct Hook *)tag->ti_Data;
855 break;
857 case MUIA_List_VertProp_First:
858 data->vertprop_first = tag->ti_Data;
859 if (data->entries_first != tag->ti_Data)
861 set(obj, MUIA_List_First, tag->ti_Data);
863 break;
865 case MUIA_List_Format:
866 data->format = StrDup((STRPTR) tag->ti_Data);
867 ParseListFormat(data, data->format);
868 // FIXME: should we check for errors?
869 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
870 break;
872 case MUIA_List_VertProp_Entries:
873 data->vertprop_entries = tag->ti_Data;
874 break;
876 case MUIA_List_VertProp_Visible:
877 data->vertprop_visible = tag->ti_Data;
878 data->entries_visible = tag->ti_Data;
879 break;
881 case MUIA_List_Active:
883 LONG new_entries_active = tag->ti_Data;
885 if ((data->entries_num)
886 && (new_entries_active != MUIV_List_Active_Off))
888 switch (new_entries_active)
890 case MUIV_List_Active_Top:
891 new_entries_active = 0;
892 break;
894 case MUIV_List_Active_Bottom:
895 new_entries_active = data->entries_num - 1;
896 break;
898 case MUIV_List_Active_Up:
899 new_entries_active = data->entries_active - 1;
900 break;
902 case MUIV_List_Active_Down:
903 new_entries_active = data->entries_active + 1;
904 break;
906 case MUIV_List_Active_PageUp:
907 new_entries_active =
908 data->entries_active - data->entries_visible;
909 break;
911 case MUIV_List_Active_PageDown:
912 new_entries_active =
913 data->entries_active + data->entries_visible;
914 break;
917 if (new_entries_active < 0)
918 new_entries_active = 0;
919 else if (new_entries_active >= data->entries_num)
920 new_entries_active = data->entries_num - 1;
922 else
923 new_entries_active = -1;
925 if (data->entries_active != new_entries_active)
927 LONG old = data->entries_active;
928 data->entries_active = new_entries_active;
930 data->update = 2;
931 data->update_pos = old;
932 MUI_Redraw(obj, MADF_DRAWUPDATE);
933 data->update = 2;
934 data->update_pos = data->entries_active;
935 MUI_Redraw(obj, MADF_DRAWUPDATE);
937 /* Selectchange stuff */
938 if (old != -1)
940 DoMethod(obj, MUIM_List_SelectChange, old,
941 MUIV_List_Select_Off, 0);
944 if (new_entries_active != -1)
946 DoMethod(obj, MUIM_List_SelectChange,
947 new_entries_active, MUIV_List_Select_On, 0);
948 DoMethod(obj, MUIM_List_SelectChange,
949 new_entries_active, MUIV_List_Select_Active, 0);
951 else
952 DoMethod(obj, MUIM_List_SelectChange,
953 MUIV_List_Active_Off, MUIV_List_Select_Off, 0);
955 set(obj, MUIA_Listview_SelectChange, TRUE);
957 if (new_entries_active != -1)
959 DoMethod(obj, MUIM_List_Jump,
960 MUIV_List_Jump_Active);
964 break;
966 case MUIA_List_First:
967 data->update_pos = data->entries_first;
968 data->update = 3;
969 data->entries_first = tag->ti_Data;
971 MUI_Redraw(obj, MADF_DRAWUPDATE);
972 if (data->vertprop_first != tag->ti_Data)
974 set(obj, MUIA_List_VertProp_First, tag->ti_Data);
976 break;
978 case MUIA_List_Visible:
979 if (data->vertprop_visible != tag->ti_Data)
980 set(obj, MUIA_List_VertProp_Visible, tag->ti_Data);
981 break;
983 case MUIA_List_Entries:
984 if (data->confirm_entries_num == tag->ti_Data)
986 data->entries_num = tag->ti_Data;
987 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
989 else
991 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
993 break;
995 case MUIA_List_Quiet:
996 _handle_bool_tag(data->flags, tag->ti_Data, LIST_QUIET);
997 if (!tag->ti_Data)
999 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1001 break;
1003 case MUIA_Listview_ClickColumn:
1004 data->click_column = tag->ti_Data;
1005 break;
1009 return DoSuperMethodA(cl, obj, (Msg) msg);
1012 /**************************************************************************
1013 OM_GET
1014 **************************************************************************/
1015 IPTR List__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
1017 /* small macro to simplify return value storage */
1018 #define STORE *(msg->opg_Storage)
1019 struct MUI_ListData *data = INST_DATA(cl, obj);
1021 switch (msg->opg_AttrID)
1023 case MUIA_List_Entries:
1024 STORE = data->entries_num;
1025 return 1;
1026 case MUIA_List_First:
1027 STORE = data->entries_first;
1028 return 1;
1029 case MUIA_List_Active:
1030 STORE = data->entries_active;
1031 return 1;
1032 case MUIA_List_InsertPosition:
1033 STORE = data->insert_position;
1034 return 1;
1035 case MUIA_List_Title:
1036 STORE = (unsigned long)data->title;
1037 return 1;
1038 case MUIA_List_VertProp_Entries:
1039 STORE = data->vertprop_entries;
1040 return 1;
1041 case MUIA_List_VertProp_Visible:
1042 STORE = data->vertprop_visible;
1043 return 1;
1044 case MUIA_List_VertProp_First:
1045 STORE = data->vertprop_first;
1046 return 1;
1047 case MUIA_List_Format:
1048 STORE = (IPTR) data->format;
1049 return 1;
1051 case MUIA_Listview_DoubleClick:
1052 STORE = 0;
1053 return 1;
1054 case MUIA_Listview_ClickColumn:
1055 STORE = data->click_column;
1056 return 1;
1057 case MUIA_Listview_List:
1058 STORE = (IPTR) obj;
1059 return 1; /* Validated with 3rd party application */
1062 if (DoSuperMethodA(cl, obj, (Msg) msg))
1063 return 1;
1064 return 0;
1065 #undef STORE
1068 /**************************************************************************
1069 MUIM_Setup
1070 **************************************************************************/
1071 IPTR List__MUIM_Setup(struct IClass *cl, Object *obj,
1072 struct MUIP_Setup *msg)
1074 struct MUI_ListData *data = INST_DATA(cl, obj);
1076 if (!DoSuperMethodA(cl, obj, (Msg) msg))
1077 return 0;
1079 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
1080 data->prefs_refresh = muiGlobalInfo(obj)->mgi_Prefs->list_refresh;
1081 data->prefs_linespacing =
1082 muiGlobalInfo(obj)->mgi_Prefs->list_linespacing;
1083 data->prefs_smoothed = muiGlobalInfo(obj)->mgi_Prefs->list_smoothed;
1084 data->prefs_smoothval = muiGlobalInfo(obj)->mgi_Prefs->list_smoothval;
1086 CalcWidths(cl, obj);
1088 if (data->title)
1090 data->title_height = data->entries[ENTRY_TITLE]->height + 2;
1092 else
1094 data->title_height = 0;
1097 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
1099 data->list_cursor =
1100 zune_imspec_setup(MUII_ListCursor, muiRenderInfo(obj));
1101 data->list_select =
1102 zune_imspec_setup(MUII_ListSelect, muiRenderInfo(obj));
1103 data->list_selcur =
1104 zune_imspec_setup(MUII_ListSelCur, muiRenderInfo(obj));
1106 return 1;
1109 /**************************************************************************
1110 MUIM_Cleanup
1111 **************************************************************************/
1112 IPTR List__MUIM_Cleanup(struct IClass *cl, Object *obj,
1113 struct MUIP_Cleanup *msg)
1115 struct MUI_ListData *data = INST_DATA(cl, obj);
1116 struct ListImage *li = List_First(&data->images);
1118 while (li)
1120 struct ListImage *next = Node_Next(li);
1121 DoMethod(obj, MUIM_List_DeleteImage, (IPTR) li);
1122 li = next;
1125 zune_imspec_cleanup(data->list_cursor);
1126 zune_imspec_cleanup(data->list_select);
1127 zune_imspec_cleanup(data->list_selcur);
1129 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
1130 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1131 data->mouse_click = 0;
1133 return DoSuperMethodA(cl, obj, (Msg) msg);
1136 /**************************************************************************
1137 MUIM_AskMinMax
1138 **************************************************************************/
1139 IPTR List__MUIM_AskMinMax(struct IClass *cl, Object *obj,
1140 struct MUIP_AskMinMax *msg)
1142 struct MUI_ListData *data = INST_DATA(cl, obj);
1144 DoSuperMethodA(cl, obj, (Msg) msg);
1147 if ((data->flags & LIST_ADJUSTWIDTH) && (data->entries_num > 0))
1149 msg->MinMaxInfo->MinWidth += data->entries_maxwidth;
1150 msg->MinMaxInfo->DefWidth += data->entries_maxwidth;
1151 msg->MinMaxInfo->MaxWidth += data->entries_maxwidth;
1153 else
1155 msg->MinMaxInfo->MinWidth += 40;
1156 msg->MinMaxInfo->DefWidth += 100;
1157 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1160 if (data->entries_num > 0)
1162 if (data->flags & LIST_ADJUSTHEIGHT)
1164 msg->MinMaxInfo->MinHeight += data->entries_totalheight;
1165 msg->MinMaxInfo->DefHeight += data->entries_totalheight;
1166 msg->MinMaxInfo->MaxHeight += data->entries_totalheight;
1168 else
1170 ULONG h = data->entry_maxheight + data->prefs_linespacing;
1171 msg->MinMaxInfo->MinHeight += 2 * h + data->prefs_linespacing;
1172 msg->MinMaxInfo->DefHeight += 8 * h + data->prefs_linespacing;
1173 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1176 else
1178 msg->MinMaxInfo->MinHeight += 36;
1179 msg->MinMaxInfo->DefHeight += 96;
1180 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1182 D(bug("List %p minheigh=%d, line maxh=%d\n",
1183 obj, msg->MinMaxInfo->MinHeight, data->entry_maxheight));
1184 return TRUE;
1187 /**************************************************************************
1188 MUIM_Layout
1189 **************************************************************************/
1190 IPTR List__MUIM_Layout(struct IClass *cl, Object *obj,
1191 struct MUIP_Layout *msg)
1193 struct MUI_ListData *data = INST_DATA(cl, obj);
1194 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1195 LONG new_entries_first = data->entries_first;
1197 /* Calc the numbers of entries visible */
1198 CalcVertVisible(cl, obj);
1200 #if 0 /* Don't do this! */
1201 if (data->entries_active < new_entries_first)
1202 new_entries_first = data->entries_active;
1203 #endif
1205 if (data->entries_active + 1 >=
1206 (data->entries_first + data->entries_visible))
1207 new_entries_first =
1208 data->entries_active - data->entries_visible + 1;
1210 if ((new_entries_first + data->entries_visible >=
1211 data->entries_num)
1212 && (data->entries_visible <= data->entries_num))
1213 new_entries_first = data->entries_num - data->entries_visible;
1215 if (data->entries_num <= data->entries_visible)
1216 new_entries_first = 0;
1218 if (new_entries_first < 0)
1219 new_entries_first = 0;
1221 set(obj, new_entries_first != data->entries_first ?
1222 MUIA_List_First : TAG_IGNORE, new_entries_first);
1224 /* So the notify takes happens */
1225 set(obj, MUIA_List_VertProp_Visible, data->entries_visible);
1227 return rc;
1231 /**************************************************************************
1232 MUIM_Show
1233 **************************************************************************/
1234 IPTR List__MUIM_Show(struct IClass *cl, Object *obj,
1235 struct MUIP_Show *msg)
1237 struct MUI_ListData *data = INST_DATA(cl, obj);
1238 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1240 zune_imspec_show(data->list_cursor, obj);
1241 zune_imspec_show(data->list_select, obj);
1242 zune_imspec_show(data->list_selcur, obj);
1243 return rc;
1247 /**************************************************************************
1248 MUIM_Hide
1249 **************************************************************************/
1250 IPTR List__MUIM_Hide(struct IClass *cl, Object *obj,
1251 struct MUIP_Hide *msg)
1253 struct MUI_ListData *data = INST_DATA(cl, obj);
1255 #if 0
1256 if (data->ehn.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
1258 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1259 (IPTR) & data->ehn);
1260 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1261 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1262 (IPTR) & data->ehn);
1264 data->mouse_click = 0;
1265 #endif
1267 zune_imspec_hide(data->list_cursor);
1268 zune_imspec_hide(data->list_select);
1269 zune_imspec_hide(data->list_selcur);
1271 return DoSuperMethodA(cl, obj, (Msg) msg);
1275 /**************************************************************************
1276 Draw an entry at entry_pos at the given y location. To draw the title,
1277 set pos to ENTRY_TITLE
1278 **************************************************************************/
1279 static VOID List_DrawEntry(struct IClass *cl, Object *obj, int entry_pos,
1280 int y)
1282 struct MUI_ListData *data = INST_DATA(cl, obj);
1283 int col, x1, x2;
1285 /* To be surem we don't draw anything if there is no title */
1286 if (entry_pos == ENTRY_TITLE && !data->title)
1287 return;
1289 DisplayEntry(cl, obj, entry_pos);
1290 x1 = _mleft(obj);
1292 for (col = 0; col < data->columns; col++)
1294 ZText *text;
1295 x2 = x1 + data->ci[col].entries_width;
1297 if ((text =
1298 zune_text_new(data->preparses[col], data->strings[col],
1299 ZTEXT_ARG_NONE, 0)))
1301 /* Could be made simpler, as we don't really need the bounds */
1302 zune_text_get_bounds(text, obj);
1303 /* Note, this was MPEN_SHADOW before */
1304 SetAPen(_rp(obj), muiRenderInfo(obj)->mri_Pens[MPEN_TEXT]);
1305 zune_text_draw(text, obj, x1, x2, y); /* totally wrong! */
1306 zune_text_destroy(text);
1308 x1 = x2 + data->ci[col].delta + (data->ci[col].bar ? BAR_WIDTH : 0);
1312 /**************************************************************************
1313 MUIM_Draw
1314 **************************************************************************/
1315 IPTR List__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1317 struct MUI_ListData *data = INST_DATA(cl, obj);
1318 int entry_pos, y;
1319 APTR clip;
1320 int start, end;
1321 BOOL scroll_caused_damage = FALSE;
1323 DoSuperMethodA(cl, obj, (Msg) msg);
1325 if (msg->flags & MADF_DRAWUPDATE)
1327 if (data->update == 1)
1328 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1329 _mwidth(obj), _mheight(obj),
1330 0, data->entries_first * data->entry_maxheight, 0);
1332 else
1334 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1335 _mwidth(obj), _mheight(obj),
1336 0, data->entries_first * data->entry_maxheight, 0);
1339 clip = MUI_AddClipping(muiRenderInfo(obj), _mleft(obj), _mtop(obj),
1340 _mwidth(obj), _mheight(obj));
1342 if (!(msg->flags & MADF_DRAWUPDATE)
1343 || ((msg->flags & MADF_DRAWUPDATE) && data->update == 1))
1345 y = _mtop(obj);
1346 /* Draw Title
1348 if (data->title_height && data->title)
1350 List_DrawEntry(cl, obj, ENTRY_TITLE, y);
1351 y += data->entries[ENTRY_TITLE]->height;
1352 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1353 Move(_rp(obj), _mleft(obj), y);
1354 Draw(_rp(obj), _mright(obj), y);
1355 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1356 y++;
1357 Move(_rp(obj), _mleft(obj), y);
1358 Draw(_rp(obj), _mright(obj), y);
1362 y = data->entries_top_pixel;
1364 start = data->entries_first;
1365 end = data->entries_first + data->entries_visible;
1367 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3)
1369 int diffy = data->entries_first - data->update_pos;
1370 int top, bottom;
1371 if (abs(diffy) < data->entries_visible)
1373 scroll_caused_damage =
1374 (_rp(obj)->Layer->Flags & LAYERREFRESH) ? FALSE : TRUE;
1376 ScrollRaster(_rp(obj), 0, diffy * data->entry_maxheight,
1377 _mleft(obj), y,
1378 _mright(obj),
1379 y + data->entry_maxheight * data->entries_visible);
1381 scroll_caused_damage =
1382 scroll_caused_damage
1383 && (_rp(obj)->Layer->Flags & LAYERREFRESH);
1385 if (diffy > 0)
1387 start = end - diffy;
1388 y += data->entry_maxheight * (data->entries_visible -
1389 diffy);
1391 else
1392 end = start - diffy;
1395 top = y;
1396 bottom = y + (end - start) * data->entry_maxheight;
1398 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), top,
1399 _mwidth(obj), bottom - top + 1,
1401 top - _mtop(obj) + data->entries_first * data->entry_maxheight,
1405 for (entry_pos = start;
1406 entry_pos < end && entry_pos < data->entries_num; entry_pos++)
1408 //struct ListEntry *entry = data->entries[entry_pos];
1410 if (!(msg->flags & MADF_DRAWUPDATE) ||
1411 ((msg->flags & MADF_DRAWUPDATE) && data->update == 1) ||
1412 ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) ||
1413 ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1414 && data->update_pos == entry_pos))
1416 if (entry_pos == data->entries_active)
1418 zune_imspec_draw(data->list_cursor, muiRenderInfo(obj),
1419 _mleft(obj), y, _mwidth(obj), data->entry_maxheight,
1420 0, y - data->entries_top_pixel, 0);
1422 else
1424 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1425 && data->update_pos == entry_pos)
1427 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), y,
1428 _mwidth(obj), data->entry_maxheight, 0,
1429 y - _mtop(obj) +
1430 data->entries_first * data->entry_maxheight, 0);
1433 List_DrawEntry(cl, obj, entry_pos, y);
1435 y += data->entry_maxheight;
1436 } /* for */
1438 MUI_RemoveClipping(muiRenderInfo(obj), clip);
1440 data->update = 0;
1442 if (scroll_caused_damage)
1444 if (MUI_BeginRefresh(muiRenderInfo(obj), 0))
1446 /* Theoretically it might happen that more damage is caused
1447 after ScrollRaster. By something else, like window movement
1448 in front of our window. Therefore refresh root object of
1449 window, not just this object */
1451 Object *o = NULL;
1453 get(_win(obj), MUIA_Window_RootObject, &o);
1454 MUI_Redraw(o, MADF_DRAWOBJECT);
1456 MUI_EndRefresh(muiRenderInfo(obj), 0);
1460 ULONG x1 = _mleft(obj);
1461 ULONG col;
1462 y = _mtop(obj);
1464 if (data->title_height && data->title)
1466 for (col = 0; col < data->columns; col++)
1468 ULONG halfdelta = data->ci[col].delta / 2;
1469 x1 += data->ci[col].entries_width + halfdelta;
1471 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(obj))
1472 break;
1474 if (data->ci[col].bar)
1476 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1477 Move(_rp(obj), x1, y);
1478 Draw(_rp(obj), x1,
1479 y + data->entries[ENTRY_TITLE]->height - 1);
1480 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1481 Move(_rp(obj), x1 + 1, y);
1482 Draw(_rp(obj), x1 + 1,
1483 y + data->entries[ENTRY_TITLE]->height - 1);
1485 x1 += BAR_WIDTH;
1487 x1 += data->ci[col].delta - halfdelta;
1489 y += data->entries[ENTRY_TITLE]->height + 1;
1492 x1 = _mleft(obj);
1494 for (col = 0; col < data->columns; col++)
1496 ULONG halfdelta = data->ci[col].delta / 2;
1497 x1 += data->ci[col].entries_width + halfdelta;
1499 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(obj))
1500 break;
1502 if (data->ci[col].bar)
1504 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1505 Move(_rp(obj), x1, y);
1506 Draw(_rp(obj), x1, _mbottom(obj));
1507 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1508 Move(_rp(obj), x1 + 1, y);
1509 Draw(_rp(obj), x1 + 1, _mbottom(obj));
1511 x1 += BAR_WIDTH;
1514 x1 += data->ci[col].delta - halfdelta;
1517 return 0;
1520 /**************************************************************************
1521 Makes the entry at the given mouse position the active one.
1522 Relx and Rely are relative mouse coordinates to the upper left of
1523 the object
1524 **************************************************************************/
1525 static VOID List_MakeActive(struct IClass *cl, Object *obj, LONG relx,
1526 LONG rely)
1528 struct MUI_ListData *data = INST_DATA(cl, obj);
1530 if (data->entries_num == 0)
1531 return;
1533 LONG eclicky = rely + _top(obj) - data->entries_top_pixel;
1534 /* y coordinates transformed to the entries */
1535 LONG new_act = eclicky / data->entry_maxheight + data->entries_first;
1536 LONG old_act = data->entries_active;
1538 if (eclicky < 0)
1540 new_act = data->entries_first - 1;
1542 else if (new_act > data->entries_first + data->entries_visible)
1544 new_act = data->entries_first + data->entries_visible;
1547 if (new_act >= data->entries_num)
1548 new_act = data->entries_num - 1;
1549 else if (new_act < 0)
1550 new_act = 0;
1552 /* Notify only when active entry has changed */
1553 if (old_act != new_act)
1554 set(obj, MUIA_List_Active, new_act);
1557 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely,
1558 UWORD qual)
1560 struct MUI_ListData *data = INST_DATA(cl, obj);
1561 LONG new = data->entries_first;
1563 if (qual & IEQUALIFIER_CONTROL)
1565 if (wheely < 0)
1566 new = 0;
1567 if (wheely > 0)
1568 new = data->entries_num;
1570 else if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
1572 new += (wheely * data->entries_visible);
1574 else
1576 new += wheely * 3;
1579 if (new > data->entries_num - data->entries_visible)
1581 new = data->entries_num - data->entries_visible;
1584 if (new < 0)
1586 new = 0;
1589 if (new != data->entries_first)
1591 set(obj, MUIA_List_First, new);
1596 /**************************************************************************
1597 MUIM_HandleEvent
1598 **************************************************************************/
1599 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
1600 struct MUIP_HandleEvent *msg)
1602 struct MUI_ListData *data = INST_DATA(cl, obj);
1604 if (msg->imsg)
1606 LONG mx = msg->imsg->MouseX - _left(obj);
1607 LONG my = msg->imsg->MouseY - _top(obj);
1608 switch (msg->imsg->Class)
1610 case IDCMP_MOUSEBUTTONS:
1611 if (msg->imsg->Code == SELECTDOWN)
1613 if (mx >= 0 && mx < _width(obj) && my >= 0
1614 && my < _height(obj))
1616 LONG eclicky = my + _top(obj) - data->entries_top_pixel;
1617 /* y coordinates transformed to the entries */
1618 data->mouse_click = MOUSE_CLICK_ENTRY;
1620 /* Now check if it was clicked on a title or on entries */
1621 if (eclicky >= 0
1622 && eclicky <
1623 data->entries_visible * data->entry_maxheight)
1625 List_MakeActive(cl, obj, mx, my);
1626 /* sets data->entries_active */
1628 if (data->last_active == data->entries_active
1629 && DoubleClick(data->last_secs, data->last_mics,
1630 msg->imsg->Seconds, msg->imsg->Micros))
1632 /* Handle MUIA_ListView_ClickColumn */
1633 data->click_column = 0;
1634 if (data->entries_num > 0 && data->columns > 0)
1636 LONG width_sum = 0;
1637 LONG col;
1638 for (col = 0; col < data->columns; col++)
1640 width_sum +=
1641 data->ci[col].entries_width +
1642 data->ci[col].delta +
1643 (data->ci[col].bar ? BAR_WIDTH : 0);
1644 D(bug
1645 ("[List/MUIM_HandleEvent] col %d "
1646 "width %d width_sum %d mx %d\n",
1647 col,
1648 data->ci[col].entries_width,
1649 width_sum, mx));
1650 if (mx < width_sum)
1652 D(bug
1653 ("[List/MUIM_HandleEvent] "
1654 "Column hit %d\n",
1655 col));
1656 set(obj, MUIA_Listview_ClickColumn,
1657 col);
1658 break;
1663 set(obj, MUIA_Listview_DoubleClick, TRUE);
1664 data->last_active = -1;
1665 data->last_secs = data->last_mics = 0;
1667 else
1669 data->last_active = data->entries_active;
1670 data->last_secs = msg->imsg->Seconds;
1671 data->last_mics = msg->imsg->Micros;
1675 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1676 (IPTR) & data->ehn);
1677 data->ehn.ehn_Events |=
1678 (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1679 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1680 (IPTR) & data->ehn);
1682 return MUI_EventHandlerRC_Eat;
1685 else
1687 if (msg->imsg->Code == SELECTUP && data->mouse_click)
1689 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1690 (IPTR) & data->ehn);
1691 data->ehn.ehn_Events &=
1692 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1693 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1694 (IPTR) & data->ehn);
1695 data->mouse_click = 0;
1696 return 0;
1699 break;
1701 case IDCMP_INTUITICKS:
1702 case IDCMP_MOUSEMOVE:
1703 if (data->mouse_click)
1705 List_MakeActive(cl, obj, mx, my);
1707 break;
1709 case IDCMP_RAWKEY:
1710 switch (msg->imsg->Code)
1712 case RAWKEY_NM_WHEEL_UP:
1713 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
1715 DoWheelMove(cl, obj, -1, msg->imsg->Qualifier);
1717 break;
1719 case RAWKEY_NM_WHEEL_DOWN:
1720 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
1722 DoWheelMove(cl, obj, 1, msg->imsg->Qualifier);
1724 break;
1727 break;
1729 case IDCMP_ACTIVEWINDOW:
1730 case IDCMP_INACTIVEWINDOW:
1731 if (data->ehn.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
1733 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1734 (IPTR) & data->ehn);
1735 data->ehn.ehn_Events &=
1736 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1737 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1738 (IPTR) & data->ehn);
1739 data->mouse_click = 0;
1741 break;
1745 return 0;
1748 /**************************************************************************
1749 MUIM_List_Clear
1750 **************************************************************************/
1751 IPTR List__MUIM_Clear(struct IClass *cl, Object *obj,
1752 struct MUIP_List_Clear *msg)
1754 struct MUI_ListData *data = INST_DATA(cl, obj);
1756 while (data->confirm_entries_num)
1758 struct ListEntry *lentry =
1759 data->entries[--data->confirm_entries_num];
1760 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1761 (IPTR) data->pool);
1762 FreeListEntry(data, lentry);
1764 /* Should never fail when shrinking */
1765 SetListSize(data, 0);
1767 if (data->confirm_entries_num != data->entries_num)
1769 SetAttrs(obj, MUIA_List_Entries, 0, MUIA_List_First, 0,
1770 /* Notify only when no entry was active */
1771 data->entries_active !=
1772 MUIV_List_Active_Off ? MUIA_List_Active : TAG_DONE,
1773 MUIV_List_Active_Off, TAG_DONE);
1775 data->update = 1;
1776 MUI_Redraw(obj, MADF_DRAWUPDATE);
1779 return 0;
1782 /**************************************************************************
1783 MUIM_List_Exchange
1784 **************************************************************************/
1785 IPTR List__MUIM_Exchange(struct IClass *cl, Object *obj,
1786 struct MUIP_List_Exchange *msg)
1788 struct MUI_ListData *data = INST_DATA(cl, obj);
1789 LONG pos1, pos2;
1791 switch (msg->pos1)
1793 case MUIV_List_Exchange_Top:
1794 pos1 = 0;
1795 break;
1796 case MUIV_List_Exchange_Active:
1797 pos1 = data->entries_active;
1798 break;
1799 case MUIV_List_Exchange_Bottom:
1800 pos1 = data->entries_num - 1;
1801 break;
1802 default:
1803 pos1 = msg->pos1;
1806 switch (msg->pos2)
1808 case MUIV_List_Exchange_Top:
1809 pos2 = 0;
1810 break;
1811 case MUIV_List_Exchange_Active:
1812 pos2 = data->entries_active;
1813 break;
1814 case MUIV_List_Exchange_Bottom:
1815 pos2 = data->entries_num - 1;
1816 break;
1817 case MUIV_List_Exchange_Next:
1818 pos2 = pos1 + 1;
1819 break;
1820 case MUIV_List_Exchange_Previous:
1821 pos2 = pos1 - 1;
1822 break;
1823 default:
1824 pos2 = msg->pos2;
1827 if (pos1 >= 0 && pos1 < data->entries_num && pos2 >= 0
1828 && pos2 < data->entries_num && pos1 != pos2)
1830 struct ListEntry *save = data->entries[pos1];
1831 data->entries[pos1] = data->entries[pos2];
1832 data->entries[pos2] = save;
1834 data->update = 2;
1835 data->update_pos = pos1;
1836 MUI_Redraw(obj, MADF_DRAWUPDATE);
1838 data->update = 2;
1839 data->update_pos = pos2;
1840 MUI_Redraw(obj, MADF_DRAWUPDATE);
1842 return TRUE;
1844 else
1846 return FALSE;
1850 /**************************************************************************
1851 MUIM_List_Redraw
1852 **************************************************************************/
1853 IPTR List__MUIM_Redraw(struct IClass *cl, Object *obj,
1854 struct MUIP_List_Redraw *msg)
1856 struct MUI_ListData *data = INST_DATA(cl, obj);
1858 if (msg->pos == MUIV_List_Redraw_All)
1860 data->update = 1;
1861 CalcWidths(cl, obj);
1862 MUI_Redraw(obj, MADF_DRAWUPDATE);
1864 else
1866 LONG pos = -1;
1867 if (msg->pos == MUIV_List_Redraw_Active)
1868 pos = data->entries_active;
1869 else if (msg->pos == MUIV_List_Redraw_Entry)
1871 LONG i;
1872 for (i = 0; i < data->entries_num; i++)
1873 if (data->entries[i]->data == msg->entry)
1875 pos = i;
1876 break;
1879 else
1880 pos = msg->pos;
1882 if (pos != -1)
1884 if (CalcDimsOfEntry(cl, obj, pos))
1885 data->update = 1;
1886 else
1888 data->update = 2;
1889 data->update_pos = pos;
1891 MUI_Redraw(obj, MADF_DRAWUPDATE);
1894 return 0;
1897 /**************************************************************************
1898 MUIM_List_Remove
1899 **************************************************************************/
1900 IPTR List__MUIM_Remove(struct IClass *cl, Object *obj,
1901 struct MUIP_List_Remove *msg)
1903 struct MUI_ListData *data = INST_DATA(cl, obj);
1904 LONG pos, cur;
1905 LONG new_act;
1906 struct ListEntry *lentry;
1907 //int rem_count = 1;
1909 if (!data->entries_num)
1910 return 0;
1912 switch (msg->pos)
1914 case MUIV_List_Remove_First:
1915 pos = 0;
1916 break;
1918 case MUIV_List_Remove_Active:
1919 pos = data->entries_active;
1920 break;
1922 case MUIV_List_Remove_Last:
1923 pos = data->entries_num - 1;
1924 break;
1926 case MUIV_List_Remove_Selected:
1927 /* TODO: needs special handling */
1928 pos = data->entries_active;
1929 break;
1931 default:
1932 pos = msg->pos;
1933 break;
1936 if (pos < 0 || pos >= data->entries_num)
1937 return 0;
1939 new_act = data->entries_active;
1941 if (pos == new_act && new_act == data->entries_num - 1)
1942 new_act--; /* might become MUIV_List_Active_Off */
1944 lentry = data->entries[pos];
1945 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1946 (IPTR) data->pool);
1948 cur = pos + 1;
1950 RemoveListEntries(data, pos, cur - pos);
1951 data->confirm_entries_num -= cur - pos;
1953 /* ensure that the active element is in a valid range */
1954 if (new_act >= data->entries_num)
1955 new_act = data->entries_num - 1;
1957 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num,
1958 (new_act >= pos) || (new_act != data->entries_active) ?
1959 MUIA_List_Active : TAG_DONE,
1960 new_act, /* Inform only if neccessary (for notify) */
1961 TAG_DONE);
1963 data->update = 1;
1964 MUI_Redraw(obj, MADF_DRAWUPDATE);
1966 return 0;
1969 /**************************************************************************
1970 MUIM_List_Insert
1971 **************************************************************************/
1973 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
1974 struct MUIP_List_Insert *msg)
1976 struct MUI_ListData *data = INST_DATA(cl, obj);
1977 LONG pos, count, sort;
1979 count = msg->count;
1980 sort = 0;
1982 if (count == -1)
1984 /* Count the number of entries */
1985 for (count = 0; msg->entries[count] != NULL; count++)
1989 if (count <= 0)
1990 return ~0;
1992 switch (msg->pos)
1994 case MUIV_List_Insert_Top:
1995 pos = 0;
1996 break;
1998 case MUIV_List_Insert_Active:
1999 if (data->entries_active != -1)
2000 pos = data->entries_active;
2001 else
2002 pos = data->entries_active;
2003 break;
2005 case MUIV_List_Insert_Sorted:
2006 pos = data->entries_num;
2007 sort = 1; /* we sort'em later */
2008 break;
2010 case MUIV_List_Insert_Bottom:
2011 pos = data->entries_num;
2012 break;
2014 default:
2015 if (msg->pos > data->entries_num)
2016 pos = data->entries_num;
2017 else if (msg->pos < 0)
2018 pos = 0;
2019 else
2020 pos = msg->pos;
2021 break;
2024 if (!(SetListSize(data, data->entries_num + count)))
2025 return ~0;
2027 LONG until = pos + count;
2028 APTR *toinsert = msg->entries;
2030 if (!(PrepareInsertListEntries(data, pos, count)))
2031 return ~0;
2033 while (pos < until)
2035 struct ListEntry *lentry;
2037 if (!(lentry = AllocListEntry(data)))
2039 /* Panic, but we must be in a consistent state, so remove
2040 ** the space where the following list entries should have gone
2042 RemoveListEntries(data, pos, until - pos);
2043 return ~0;
2046 /* now call the construct method which returns us a pointer which
2047 we need to store */
2048 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2049 (IPTR) * toinsert, (IPTR) data->pool);
2050 if (!lentry->data)
2052 FreeListEntry(data, lentry);
2053 RemoveListEntries(data, pos, until - pos);
2055 /* TODO: Also check for visible stuff like below */
2056 if (data->entries_num != data->confirm_entries_num)
2057 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2058 return ~0;
2061 data->entries[pos] = lentry;
2062 data->confirm_entries_num++;
2064 if (_flags(obj) & MADF_SETUP)
2066 /* We have to calculate the width and height of the newly
2067 * inserted entry. This has to be done after inserting the
2068 * element into the list */
2069 CalcDimsOfEntry(cl, obj, pos);
2072 toinsert++;
2073 pos++;
2074 } // while (pos < until)
2077 /* Recalculate the number of visible entries */
2078 if (_flags(obj) & MADF_SETUP)
2079 CalcVertVisible(cl, obj);
2081 if (data->entries_num != data->confirm_entries_num)
2083 SetAttrs(obj,
2084 MUIA_List_Entries, data->confirm_entries_num,
2085 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2088 /* If the array is already sorted, we could do a simple insert
2089 * sort and would be much faster than with qsort.
2090 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2091 * sort the whole array?
2093 * I think, we better sort the whole array:
2095 if (sort)
2097 DoMethod(obj, MUIM_List_Sort);
2098 /* TODO: which pos to return here !? */
2099 /* MUIM_List_Sort already called MUI_Redraw */
2101 else
2103 if (!(data->flags & LIST_QUIET))
2105 data->update = 1;
2106 MUI_Redraw(obj, MADF_DRAWUPDATE);
2109 data->insert_position = pos;
2111 return (ULONG) pos;
2114 /**************************************************************************
2115 MUIM_List_InsertSingle
2116 **************************************************************************/
2117 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2118 struct MUIP_List_InsertSingle *msg)
2120 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2121 msg->pos);
2124 /**************************************************************************
2125 MUIM_List_GetEntry
2126 **************************************************************************/
2127 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2128 struct MUIP_List_GetEntry *msg)
2130 struct MUI_ListData *data = INST_DATA(cl, obj);
2131 int pos = msg->pos;
2133 if (pos == MUIV_List_GetEntry_Active)
2134 pos = data->entries_active;
2136 if (pos < 0 || pos >= data->entries_num)
2138 *msg->entry = NULL;
2139 return 0;
2141 *msg->entry = data->entries[pos]->data;
2142 return (IPTR) *msg->entry;
2145 /**************************************************************************
2146 MUIM_List_Construct
2147 **************************************************************************/
2148 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2149 struct MUIP_List_Construct *msg)
2151 struct MUI_ListData *data = INST_DATA(cl, obj);
2153 if (NULL == data->construct_hook)
2154 return (IPTR) msg->entry;
2155 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2157 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2158 ULONG *mem = AllocPooled(msg->pool, len + 5);
2160 if (NULL == mem)
2161 return 0;
2162 mem[0] = len + 5;
2163 if (msg->entry != NULL)
2164 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2165 else
2166 *(STRPTR) (mem + 1) = 0;
2167 return (IPTR) (mem + 1);
2169 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2172 /**************************************************************************
2173 MUIM_List_Destruct
2174 **************************************************************************/
2175 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2176 struct MUIP_List_Destruct *msg)
2178 struct MUI_ListData *data = INST_DATA(cl, obj);
2180 if (NULL == data->destruct_hook)
2181 return 0;
2183 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2185 ULONG *mem = ((ULONG *) msg->entry) - 1;
2186 FreePooled(msg->pool, mem, mem[0]);
2188 else
2190 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2192 return 0;
2195 /**************************************************************************
2196 MUIM_List_Compare
2197 **************************************************************************/
2198 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2199 struct MUIP_List_Compare *msg)
2201 struct MUI_ListData *data = INST_DATA(cl, obj);
2203 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2206 /**************************************************************************
2207 MUIM_List_Display
2208 **************************************************************************/
2209 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2210 struct MUIP_List_Display *msg)
2212 struct MUI_ListData *data = INST_DATA(cl, obj);
2214 if (NULL == data->display_hook)
2216 if (msg->entry)
2217 *msg->array = msg->entry;
2218 else
2219 *msg->array = 0;
2220 return 1;
2223 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2224 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2227 /**************************************************************************
2228 MUIM_List_SelectChange
2229 **************************************************************************/
2230 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2231 struct MUIP_List_SelectChange *msg)
2233 return 1;
2236 /**************************************************************************
2237 MUIM_List_CreateImage
2238 Called by a List subclass in its Setup method.
2239 Connects an Area subclass object to the list, much like an object gets
2240 connected to a window. List call Setup and AskMinMax on that object,
2241 keeps a reference to it (that reference will be returned).
2242 Text engine will dereference that pointer and draw the object with its
2243 default size.
2244 **************************************************************************/
2245 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2246 struct MUIP_List_CreateImage *msg)
2248 struct MUI_ListData *data = INST_DATA(cl, obj);
2249 struct ListImage *li;
2251 /* List must be already setup in Setup of your subclass */
2252 if (!(_flags(obj) & MADF_SETUP))
2253 return 0;
2254 li = AllocPooled(data->pool, sizeof(struct ListImage));
2255 if (!li)
2256 return 0;
2257 li->obj = msg->obj;
2259 AddTail((struct List *)&data->images, (struct Node *)li);
2260 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2261 DoSetupMethod(li->obj, muiRenderInfo(obj));
2264 return (IPTR) li;
2267 /**************************************************************************
2268 MUIM_List_DeleteImage
2269 **************************************************************************/
2270 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2271 struct MUIP_List_DeleteImage *msg)
2273 struct MUI_ListData *data = INST_DATA(cl, obj);
2274 struct ListImage *li = (struct ListImage *)msg->listimg;
2276 if (li)
2278 DoMethod(li->obj, MUIM_Cleanup);
2279 DoMethod(li->obj, MUIM_DisconnectParent);
2280 Remove((struct Node *)li);
2281 FreePooled(data->pool, li, sizeof(struct ListImage));
2284 return 0;
2287 /**************************************************************************
2288 MUIM_List_Jump
2289 **************************************************************************/
2290 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2291 struct MUIP_List_Jump *msg)
2293 struct MUI_ListData *data = INST_DATA(cl, obj);
2294 LONG pos = msg->pos;
2296 switch (pos)
2298 case MUIV_List_Jump_Top:
2299 pos = 0;
2300 break;
2302 case MUIV_List_Jump_Active:
2303 pos = data->entries_active;
2304 break;
2306 case MUIV_List_Jump_Bottom:
2307 pos = data->entries_num - 1;
2308 break;
2310 case MUIV_List_Jump_Down:
2311 pos = data->entries_first + data->entries_visible;
2312 break;
2314 case MUIV_List_Jump_Up:
2315 pos = data->entries_first - 1;
2316 break;
2320 if (pos > data->entries_num)
2322 pos = data->entries_num - 1;
2324 if (pos < 0)
2325 pos = 0;
2327 if (pos < data->entries_first)
2329 set(obj, MUIA_List_First, pos);
2331 else if (pos >= data->entries_first + data->entries_visible)
2333 pos -= (data->entries_visible - 1);
2334 if (pos < 0)
2335 pos = 0;
2336 if (pos != data->entries_first)
2338 set(obj, MUIA_List_First, pos);
2343 return TRUE;
2346 /**************************************************************************
2347 MUIM_List_Sort
2348 **************************************************************************/
2349 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2350 struct MUIP_List_Sort *msg)
2352 struct MUI_ListData *data = INST_DATA(cl, obj);
2354 int i, j, max;
2355 struct MUIP_List_Compare cmpmsg =
2356 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2358 if (data->entries_num > 1)
2361 Simple sort algorithm. Feel free to improve it.
2363 for (i = 0; i < data->entries_num - 1; i++)
2365 max = i;
2366 for (j = i + 1; j < data->entries_num; j++)
2368 cmpmsg.entry1 = data->entries[max]->data;
2369 cmpmsg.entry2 = data->entries[j]->data;
2370 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2372 max = j;
2375 if (i != max)
2377 APTR tmp = data->entries[i];
2378 data->entries[i] = data->entries[max];
2379 data->entries[max] = tmp;
2384 if (!(data->flags & LIST_QUIET))
2386 data->update = 1;
2387 MUI_Redraw(obj, MADF_DRAWUPDATE);
2390 return 0;
2393 /**************************************************************************
2394 MUIM_List_Move
2395 **************************************************************************/
2396 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
2397 struct MUIP_List_Move *msg)
2399 struct MUI_ListData *data = INST_DATA(cl, obj);
2401 LONG from, to;
2402 int i;
2404 switch (msg->from)
2406 case MUIV_List_Move_Top:
2407 from = 0;
2408 break;
2409 case MUIV_List_Move_Active:
2410 from = data->entries_active;
2411 break;
2412 case MUIV_List_Move_Bottom:
2413 from = data->entries_num - 1;
2414 break;
2415 default:
2416 from = msg->from;
2419 switch (msg->to)
2421 case MUIV_List_Move_Top:
2422 to = 0;
2423 break;
2424 case MUIV_List_Move_Active:
2425 to = data->entries_active;
2426 break;
2427 case MUIV_List_Move_Bottom:
2428 to = data->entries_num - 1;
2429 break;
2430 case MUIV_List_Move_Next:
2431 to = from + 1;
2432 break;
2433 case MUIV_List_Move_Previous:
2434 to = from - 1;
2435 break;
2436 default:
2437 to = msg->to;
2440 if (from > data->entries_num - 1 || from < 0
2441 || to > data->entries_num - 1 || to < 0 || from == to)
2442 return (IPTR) FALSE;
2444 if (from < to)
2446 struct ListEntry *backup = data->entries[from];
2447 for (i = from; i < to; i++)
2448 data->entries[i] = data->entries[i + 1];
2449 data->entries[to] = backup;
2451 else
2453 struct ListEntry *backup = data->entries[from];
2454 for (i = from; i > to; i--)
2455 data->entries[i] = data->entries[i - 1];
2456 data->entries[to] = backup;
2459 data->update = 1;
2460 MUI_Redraw(obj, MADF_DRAWUPDATE);
2462 return TRUE;
2465 /**************************************************************************
2466 Dispatcher
2467 **************************************************************************/
2468 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
2470 switch (msg->MethodID)
2472 case OM_NEW:
2473 return List__OM_NEW(cl, obj, (struct opSet *)msg);
2474 case OM_DISPOSE:
2475 return List__OM_DISPOSE(cl, obj, msg);
2476 case OM_SET:
2477 return List__OM_SET(cl, obj, (struct opSet *)msg);
2478 case OM_GET:
2479 return List__OM_GET(cl, obj, (struct opGet *)msg);
2481 case MUIM_Setup:
2482 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
2483 case MUIM_Cleanup:
2484 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
2485 case MUIM_AskMinMax:
2486 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
2487 case MUIM_Show:
2488 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
2489 case MUIM_Hide:
2490 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
2491 case MUIM_Draw:
2492 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
2493 case MUIM_Layout:
2494 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
2495 case MUIM_HandleEvent:
2496 return List__MUIM_HandleEvent(cl, obj,
2497 (struct MUIP_HandleEvent *)msg);
2498 case MUIM_List_Clear:
2499 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
2500 case MUIM_List_Sort:
2501 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
2502 case MUIM_List_Exchange:
2503 return List__MUIM_Exchange(cl, obj,
2504 (struct MUIP_List_Exchange *)msg);
2505 case MUIM_List_Insert:
2506 return List__MUIM_Insert(cl, obj, (APTR) msg);
2507 case MUIM_List_InsertSingle:
2508 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
2509 case MUIM_List_GetEntry:
2510 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
2511 case MUIM_List_Redraw:
2512 return List__MUIM_Redraw(cl, obj, (APTR) msg);
2513 case MUIM_List_Remove:
2514 return List__MUIM_Remove(cl, obj, (APTR) msg);
2516 case MUIM_List_Construct:
2517 return List__MUIM_Construct(cl, obj, (APTR) msg);
2518 case MUIM_List_Destruct:
2519 return List__MUIM_Destruct(cl, obj, (APTR) msg);
2520 case MUIM_List_Compare:
2521 return List__MUIM_Compare(cl, obj, (APTR) msg);
2522 case MUIM_List_Display:
2523 return List__MUIM_Display(cl, obj, (APTR) msg);
2524 case MUIM_List_SelectChange:
2525 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
2526 case MUIM_List_CreateImage:
2527 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
2528 case MUIM_List_DeleteImage:
2529 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
2530 case MUIM_List_Jump:
2531 return List__MUIM_Jump(cl, obj, (APTR) msg);
2532 case MUIM_List_Move:
2533 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
2536 return DoSuperMethodA(cl, obj, msg);
2538 BOOPSI_DISPATCHER_END
2541 * Class descriptor.
2543 const struct __MUIBuiltinClass _MUI_List_desc =
2545 MUIC_List,
2546 MUIC_Area,
2547 sizeof(struct MUI_ListData),
2548 (void *) List_Dispatcher