Minor fixes to comments, formatting etc.
[AROS.git] / workbench / libs / muimaster / classes / list.c
blob79aba3be5dfb463dccd3eee9ce454360b1094f0d
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 */
62 #define ENTRY_SELECTED (1<<0)
65 struct ColumnInfo
67 int colno; /* Column number */
68 int user_width; /* user set width; -1 if entry width */
69 int min_width; /* min width percentage */
70 int max_width; /* min width percentage */
71 int weight;
72 int delta; /* ignored for the first and last column, defaults to 4 */
73 int bar;
74 STRPTR preparse;
75 int entries_width; /* width of the entries (maximum of all widths) */
78 struct MUI_ImageSpec_intern;
80 struct MUI_ListData
82 /* bool attrs */
83 ULONG flags;
85 APTR intern_pool; /* The internal pool which the class has allocated */
86 LONG intern_puddle_size;
87 LONG intern_thresh_size;
88 APTR pool; /* the pool which is used to allocate list entries */
90 struct Hook *construct_hook;
91 struct Hook *compare_hook;
92 struct Hook *destruct_hook;
93 struct Hook *display_hook;
95 struct Hook default_compare_hook;
97 /* List management, currently we use a simple flat array, which is not
98 * good if many entries are inserted/deleted */
99 LONG entries_num; /* Number of Entries in the list */
100 LONG entries_allocated;
101 struct ListEntry **entries;
103 LONG entries_first; /* first visible entry */
104 LONG entries_visible; /* number of visible entries,
105 * determined at MUIM_Layout */
106 LONG entries_active;
107 LONG insert_position; /* pos of the last insertion */
109 LONG entry_maxheight; /* Maximum height of an entry */
110 ULONG entry_minheight; /* from MUIA_List_MinLineHeight */
112 LONG entries_totalheight;
113 LONG entries_maxwidth;
115 LONG vertprop_entries;
116 LONG vertprop_visible;
117 LONG vertprop_first;
119 LONG confirm_entries_num; /* These are the correct entries num, used
120 * so you cannot set MUIA_List_Entries to
121 * wrong values */
123 LONG entries_top_pixel; /* Where the entries start */
125 /* Column managment, is allocated by ParseListFormat() and freed
126 * by CleanListFormat() */
127 STRPTR format;
128 LONG columns; /* Number of columns the list has */
129 struct ColumnInfo *ci;
130 STRPTR *preparses;
131 STRPTR *strings; /* the strings for the display function, one
132 * more than needed (for the entry position) */
134 /* Titlestuff */
135 int title_height; /* The complete height of the title */
136 STRPTR title; /* On single comlums this is the title, otherwise 1 */
138 struct MUI_EventHandlerNode ehn;
139 int mouse_click; /* see below if mouse is hold down */
141 /* Cursor images */
142 struct MUI_ImageSpec_intern *list_cursor;
143 struct MUI_ImageSpec_intern *list_select;
144 struct MUI_ImageSpec_intern *list_selcur;
146 /* Render optimization */
147 int update; /* 1 - update everything, 2 - redraw entry at update_pos,
148 * 3 - scroll to current entries_first (old value is in
149 * update_pos) */
150 int update_pos;
152 /* double click */
153 ULONG last_secs;
154 ULONG last_mics;
155 ULONG last_active;
156 ULONG doubleclick;
158 /* clicked column */
159 LONG click_column;
161 /* list type */
162 ULONG input; /* FALSE - readonly, otherwise TRUE */
164 /* list images */
165 struct MinList images;
167 /* user prefs */
168 ListviewMulti prefs_multi;
169 ListviewRefresh prefs_refresh;
170 UWORD prefs_linespacing;
171 BOOL prefs_smoothed;
172 UWORD prefs_smoothval;
175 #define LIST_ADJUSTWIDTH (1<<0)
176 #define LIST_ADJUSTHEIGHT (1<<1)
177 #define LIST_AUTOVISIBLE (1<<2)
178 #define LIST_DRAGSORTABLE (1<<3)
179 #define LIST_SHOWDROPMARKS (1<<4)
180 #define LIST_QUIET (1<<5)
183 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
184 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
186 /**************************************************************************
187 Allocate a single list entry, does not initialize it (except the pointer)
188 **************************************************************************/
189 static struct ListEntry *AllocListEntry(struct MUI_ListData *data)
191 ULONG *mem;
192 struct ListEntry *le;
193 int size = sizeof(struct ListEntry) + sizeof(LONG) * data->columns + 4;
194 /* sizeinfo */
195 LONG j;
197 mem = AllocPooled(data->pool, size);
198 if (!mem)
199 return NULL;
200 D(bug("List AllocListEntry %p, %ld bytes\n", mem, size));
202 mem[0] = size; /* Save the size */
203 le = (struct ListEntry *)(mem + 1);
204 le->widths = (LONG *) (le + 1);
206 /* Initialize fields */
207 le->height = 0;
208 le->width = 0;
209 for (j = 0; j < data->columns; j++)
210 le->widths[j] = 0;
212 return le;
215 /**************************************************************************
216 Deallocate a single list entry, does not deinitialize it
217 **************************************************************************/
218 static void FreeListEntry(struct MUI_ListData *data,
219 struct ListEntry *entry)
221 ULONG *mem = ((ULONG *) entry) - 1;
222 D(bug("FreeListEntry %p size=%ld\n", mem, mem[0]));
223 FreePooled(data->pool, mem, mem[0]);
226 /**************************************************************************
227 Ensures that we there can be at least the given amount of entries within
228 the list. Returns 0 if not. It also allocates the space for the title.
229 It can be accesses with data->entries[ENTRY_TITLE]
230 **************************************************************************/
231 static int SetListSize(struct MUI_ListData *data, LONG size)
233 struct ListEntry **new_entries;
234 int new_entries_allocated;
236 if (size + 1 <= data->entries_allocated)
237 return 1;
239 new_entries_allocated = data->entries_allocated * 2 + 4;
240 if (new_entries_allocated < size + 1)
241 new_entries_allocated = size + 1 + 10; /* 10 is just random */
243 D(bug("List %p : SetListSize allocating %ld bytes\n", data,
244 new_entries_allocated * sizeof(struct ListEntry *)));
245 new_entries =
246 AllocVec(new_entries_allocated * sizeof(struct ListEntry *), 0);
247 if (NULL == new_entries)
248 return 0;
249 if (data->entries)
251 CopyMem(data->entries - 1, new_entries,
252 (data->entries_num + 1) * sizeof(struct ListEntry *));
253 FreeVec(data->entries - 1);
255 data->entries = new_entries + 1;
256 data->entries_allocated = new_entries_allocated;
257 return 1;
260 /**************************************************************************
261 Prepares the insertion of count entries at pos.
262 This function doesn't care if there is enough space in the datastructure.
263 SetListSize() must be used first.
264 With current implementation, this call will never fail
265 **************************************************************************/
266 static int PrepareInsertListEntries(struct MUI_ListData *data, int pos,
267 int count)
269 memmove(&data->entries[pos + count], &data->entries[pos],
270 (data->entries_num - pos) * sizeof(struct ListEntry *));
271 return 1;
274 /**************************************************************************
275 Inserts a already initialized array of Entries at the given position.
276 This function doesn't care if there is enough space in the datastructure
277 Returns 1 if something failed (never in current implementation)
278 **************************************************************************/
279 #if 0
280 static int InsertListEntries(struct MUI_ListData *data, int pos,
281 struct ListEntry **array, int count)
283 memmove(&data->entries[pos + count], &data->entries[pos],
284 data->entries_num - pos);
285 memcpy(&data->entries[pos], array, count);
286 return 1;
288 #endif
291 /**************************************************************************
292 Removes count (already deinitalized) list entries starting az pos.
293 **************************************************************************/
294 static void RemoveListEntries(struct MUI_ListData *data, int pos, int count)
296 // FIXME: segfault if entries_num = pos = count = 1
297 memmove(&data->entries[pos], &data->entries[pos + count],
298 (data->entries_num - (pos + count)) * sizeof(struct ListEntry *));
301 /**************************************************************************
302 Frees all memory allocated by ParseListFormat()
303 **************************************************************************/
304 static void FreeListFormat(struct MUI_ListData *data)
306 int i;
308 if (data->ci)
310 for (i = 0; i < data->columns; i++)
312 FreeVec(data->ci[i].preparse);
313 data->ci[i].preparse = NULL;
315 FreeVec(data->ci);
316 data->ci = NULL;
318 FreeVec(data->preparses);
319 data->preparses = NULL;
320 if (data->strings)
322 FreeVec(data->strings - 1);
323 data->strings = NULL;
325 data->columns = 0;
328 /**************************************************************************
329 Parses the given format string (also frees a previouly parsed format).
330 Return 0 on failure.
331 **************************************************************************/
332 static int ParseListFormat(struct MUI_ListData *data, STRPTR format)
334 int new_columns, i;
335 STRPTR ptr;
336 STRPTR format_sep;
337 char c;
339 IPTR args[ARG_CNT];
340 struct RDArgs *rdargs;
342 if (!format)
343 format = (STRPTR) "";
345 ptr = format;
347 FreeListFormat(data);
349 new_columns = 1;
351 /* Count the number of columns first */
352 while ((c = *ptr++))
353 if (c == ',')
354 new_columns++;
356 if (!(data->preparses =
357 AllocVec((new_columns + 10) * sizeof(STRPTR), 0)))
358 return 0;
360 if (!(data->strings = AllocVec((new_columns + 1 + 10)
361 * sizeof(STRPTR), 0))) /* hold enough space also for the entry pos,
362 * used by orginal MUI and also some
363 * security space */
364 return 0;
366 if (!(data->ci = AllocVec(new_columns * sizeof(struct ColumnInfo), 0)))
367 return 0;
369 // set defaults
370 for (i = 0; i < new_columns; i++)
372 data->ci[i].colno = -1; // -1 means: use unassigned column
373 data->ci[i].weight = 100;
374 data->ci[i].delta = 4;
375 data->ci[i].min_width = -1;
376 data->ci[i].max_width = -1;
377 data->ci[i].user_width = -1;
378 data->ci[i].bar = FALSE;
379 data->ci[i].preparse = NULL;
382 if ((format_sep = StrDup(format)) != 0)
384 for (i = 0; format_sep[i] != '\0'; i++)
386 if (format_sep[i] == ',')
387 format_sep[i] = '\0';
390 if ((rdargs = AllocDosObject(DOS_RDARGS, NULL)) != 0)
392 ptr = format_sep;
393 i = 0;
396 rdargs->RDA_Source.CS_Buffer = ptr;
397 rdargs->RDA_Source.CS_Length = strlen(ptr);
398 rdargs->RDA_Source.CS_CurChr = 0;
399 rdargs->RDA_DAList = 0;
400 rdargs->RDA_Buffer = NULL;
401 rdargs->RDA_BufSiz = 0;
402 rdargs->RDA_ExtHelp = NULL;
403 rdargs->RDA_Flags = 0;
405 memset(args, 0, sizeof args);
406 if (ReadArgs(FORMAT_TEMPLATE, args, rdargs))
408 if (args[ARG_COL])
409 data->ci[i].colno = *(LONG *) args[ARG_COL];
410 if (args[ARG_WEIGHT])
411 data->ci[i].weight = *(LONG *) args[ARG_WEIGHT];
412 if (args[ARG_DELTA])
413 data->ci[i].delta = *(LONG *) args[ARG_DELTA];
414 if (args[ARG_MINWIDTH])
415 data->ci[i].min_width =
416 *(LONG *) args[ARG_MINWIDTH];
417 if (args[ARG_MAXWIDTH])
418 data->ci[i].max_width =
419 *(LONG *) args[ARG_MAXWIDTH];
420 data->ci[i].bar = args[ARG_BAR];
421 if (args[ARG_PREPARSE])
422 data->ci[i].preparse =
423 StrDup((STRPTR) args[ARG_PREPARSE]);
425 FreeArgs(rdargs);
427 ptr += strlen(ptr) + 1;
428 i++;
430 while (i < new_columns);
431 FreeDosObject(DOS_RDARGS, rdargs);
433 FreeVec(format_sep);
436 for (i = 0; i < new_columns; i++)
438 D(bug("colno %d weight %d delta %d preparse %s\n",
439 data->ci[i].colno, data->ci[i].weight, data->ci[i].delta,
440 data->ci[i].preparse));
443 data->columns = new_columns;
444 data->strings++; /* Skip entry pos */
446 return 1;
449 /**************************************************************************
450 Call the MUIM_List_Display for the given entry. It fills out
451 data->string and data->preparses
452 **************************************************************************/
453 static void DisplayEntry(struct IClass *cl, Object *obj, int entry_pos)
455 struct MUI_ListData *data = INST_DATA(cl, obj);
456 APTR entry_data;
457 int col;
459 for (col = 0; col < data->columns; col++)
460 data->preparses[col] = data->ci[col].preparse;
462 if (entry_pos == ENTRY_TITLE)
464 if ((data->columns == 1) && (data->title != (STRPTR) 1))
466 *data->strings = data->title;
467 return;
469 entry_data = NULL; /* it's a title request */
471 else
472 entry_data = data->entries[entry_pos]->data;
474 /* Get the display formation */
475 DoMethod(obj, MUIM_List_Display, (IPTR) entry_data,
476 (IPTR) data->strings, entry_pos, (IPTR) data->preparses);
479 /**************************************************************************
480 Determine the dims of a single entry and adapt the columninfo according
481 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
482 be redrawn after this operation, 1 if all entries need to be redrawn.
483 **************************************************************************/
484 static int CalcDimsOfEntry(struct IClass *cl, Object *obj, int pos)
486 struct MUI_ListData *data = INST_DATA(cl, obj);
487 struct ListEntry *entry = data->entries[pos];
488 int j;
489 int ret = 0;
491 if (!entry)
492 return ret;
494 if (!(_flags(obj) & MADF_SETUP))
495 return ret;
497 DisplayEntry(cl, obj, pos);
499 /* Set height to at least minheight */
500 if (data->entries[pos]->height < data->entry_minheight)
501 data->entries[pos]->height = data->entry_minheight;
503 for (j = 0; j < data->columns; j++)
505 ZText *text =
506 zune_text_new(data->preparses[j], data->strings[j],
507 ZTEXT_ARG_NONE, 0);
508 if (text != NULL)
510 zune_text_get_bounds(text, obj);
512 if (text->height > data->entries[pos]->height)
514 data->entries[pos]->height = text->height;
515 /* entry height changed, redraw all entries later */
516 ret = 1;
518 data->entries[pos]->widths[j] = text->width;
520 if (text->width > data->ci[j].entries_width)
522 /* This columns width is bigger than the other in the same
523 * columns, so we store this value
525 data->ci[j].entries_width = text->width;
526 /* column width changed, redraw all entries later */
527 ret = 1;
530 zune_text_destroy(text);
533 if (data->entries[pos]->height > data->entry_maxheight)
535 data->entry_maxheight = data->entries[pos]->height;
536 /* maximum entry height changed, redraw all entries later */
537 ret = 1;
540 return ret;
543 /**************************************************************************
544 Determine the widths of the entries
545 **************************************************************************/
546 static void CalcWidths(struct IClass *cl, Object *obj)
548 int i, j;
549 struct MUI_ListData *data = INST_DATA(cl, obj);
551 if (!(_flags(obj) & MADF_SETUP))
552 return;
554 for (j = 0; j < data->columns; j++)
555 data->ci[j].entries_width = 0;
557 data->entry_maxheight = 0;
558 data->entries_totalheight = 0;
559 data->entries_maxwidth = 0;
561 for (i = (data->title ? ENTRY_TITLE : 0); i < data->entries_num; i++)
563 CalcDimsOfEntry(cl, obj, i);
564 data->entries_totalheight += data->entries[i]->height;
567 for (j = 0; j < data->columns; j++)
568 data->entries_maxwidth += data->ci[j].entries_width;
570 if (!data->entry_maxheight)
571 data->entry_maxheight = 1;
574 /**************************************************************************
575 Calculates the number of visible entry lines. Returns 1 if it has
576 changed
577 **************************************************************************/
578 static int CalcVertVisible(struct IClass *cl, Object *obj)
580 struct MUI_ListData *data = INST_DATA(cl, obj);
581 int old_entries_visible = data->entries_visible;
582 int old_entries_top_pixel = data->entries_top_pixel;
584 data->entries_visible = (_mheight(obj) - data->title_height)
585 / (data->entry_maxheight /* + data->prefs_linespacing */ );
587 data->entries_top_pixel = _mtop(obj) + data->title_height
588 + (_mheight(obj) - data->title_height
590 data->entries_visible *
591 (data->entry_maxheight /* + data->prefs_linespacing */ )) / 2;
593 return (old_entries_visible != data->entries_visible)
594 || (old_entries_top_pixel != data->entries_top_pixel);
597 /**************************************************************************
598 Default hook to compare two list entries. Works for strings only.
599 **************************************************************************/
600 AROS_UFH3S(int, default_compare_func,
601 AROS_UFHA(struct Hook *, h, A0),
602 AROS_UFHA(char *, s2, A2),
603 AROS_UFHA(char *, s1, A1))
605 AROS_USERFUNC_INIT
607 return Stricmp(s1, s2);
609 AROS_USERFUNC_EXIT
612 /**************************************************************************
613 OM_NEW
614 **************************************************************************/
615 IPTR List__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
617 struct MUI_ListData *data;
618 struct TagItem *tag;
619 struct TagItem *tags;
620 APTR *array = NULL;
621 LONG new_entries_active = MUIV_List_Active_Off;
623 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
624 MUIA_Font, MUIV_Font_List,
625 MUIA_Background, MUII_ListBack, TAG_MORE, (IPTR) msg->ops_AttrList);
626 if (!obj)
627 return FALSE;
629 data = INST_DATA(cl, obj);
631 data->columns = 1;
632 data->entries_active = MUIV_List_Active_Off;
633 data->intern_puddle_size = 2008;
634 data->intern_thresh_size = 1024;
635 data->input = 1;
636 data->default_compare_hook.h_Entry = (HOOKFUNC) default_compare_func;
637 data->default_compare_hook.h_SubEntry = 0;
638 data->compare_hook = &(data->default_compare_hook);
640 /* parse initial taglist */
641 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
643 switch (tag->ti_Tag)
645 case MUIA_List_Active:
646 new_entries_active = tag->ti_Data;
647 break;
649 case MUIA_List_Pool:
650 data->pool = (APTR) tag->ti_Data;
651 break;
653 case MUIA_List_PoolPuddleSize:
654 data->intern_puddle_size = tag->ti_Data;
655 break;
657 case MUIA_List_PoolThreshSize:
658 data->intern_thresh_size = tag->ti_Data;
659 break;
661 case MUIA_List_CompareHook:
662 /* Not tested, if List_CompareHook really works. */
663 data->compare_hook = (struct Hook *)tag->ti_Data;
664 break;
666 case MUIA_List_ConstructHook:
667 data->construct_hook = (struct Hook *)tag->ti_Data;
668 break;
670 case MUIA_List_DestructHook:
671 data->destruct_hook = (struct Hook *)tag->ti_Data;
672 break;
674 case MUIA_List_DisplayHook:
675 data->display_hook = (struct Hook *)tag->ti_Data;
676 break;
678 case MUIA_List_SourceArray:
679 array = (APTR *) tag->ti_Data;
680 break;
682 case MUIA_List_Format:
683 data->format = StrDup((STRPTR) tag->ti_Data);
684 break;
686 case MUIA_List_Title:
687 data->title = (STRPTR) tag->ti_Data;
688 break;
690 case MUIA_List_MinLineHeight:
691 data->entry_minheight = tag->ti_Data;
692 break;
694 case MUIA_List_AdjustHeight:
695 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTHEIGHT);
696 break;
698 case MUIA_List_AdjustWidth:
699 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTWIDTH);
700 break;
705 if (!data->pool)
707 /* No memory pool given, so we create our own */
708 data->pool = data->intern_pool =
709 CreatePool(0, data->intern_puddle_size,
710 data->intern_thresh_size);
711 if (!data->pool)
713 CoerceMethod(cl, obj, OM_DISPOSE);
714 return 0;
718 /* parse the list format */
719 if (!(ParseListFormat(data, data->format)))
721 CoerceMethod(cl, obj, OM_DISPOSE);
722 return 0;
725 /* This is neccessary for at least the title */
726 if (!SetListSize(data, 0))
728 CoerceMethod(cl, obj, OM_DISPOSE);
729 return 0;
732 if (data->title)
734 if (!(data->entries[ENTRY_TITLE] = AllocListEntry(data)))
736 CoerceMethod(cl, obj, OM_DISPOSE);
737 return 0;
740 else
741 data->entries[ENTRY_TITLE] = NULL;
744 if (array)
746 int i;
747 /* Count the number of elements */
748 for (i = 0; array[i] != NULL; i++)
750 /* Insert them */
751 DoMethod(obj, MUIM_List_Insert, (IPTR) array, i,
752 MUIV_List_Insert_Top);
756 if ((data->entries_num) && (new_entries_active != MUIV_List_Active_Off))
758 switch (new_entries_active)
760 case MUIV_List_Active_Top:
761 new_entries_active = 0;
762 break;
764 case MUIV_List_Active_Bottom:
765 new_entries_active = data->entries_num - 1;
766 break;
769 if (new_entries_active < 0)
770 new_entries_active = 0;
771 else if (new_entries_active >= data->entries_num)
772 new_entries_active = data->entries_num - 1;
774 data->entries_active = new_entries_active;
775 /* Selected entry will be moved into visible area */
779 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS |
780 IDCMP_RAWKEY | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW;
781 data->ehn.ehn_Priority = 0;
782 data->ehn.ehn_Flags = 0;
783 data->ehn.ehn_Object = obj;
784 data->ehn.ehn_Class = cl;
786 NewList((struct List *)&data->images);
788 D(bug("List_New(%lx)\n", obj));
790 return (IPTR) obj;
793 /**************************************************************************
794 OM_DISPOSE
795 **************************************************************************/
796 IPTR List__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
798 struct MUI_ListData *data = INST_DATA(cl, obj);
800 D(bug("List Dispose\n"));
802 /* Call destruct method for every entry and free the entries manually
803 * to avoid notification */
804 while (data->confirm_entries_num)
806 struct ListEntry *lentry =
807 data->entries[--data->confirm_entries_num];
808 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
809 (IPTR) data->pool);
810 FreeListEntry(data, lentry);
813 if (data->intern_pool)
814 DeletePool(data->intern_pool);
815 if (data->entries)
816 FreeVec(data->entries - 1);
817 /* title is currently before all other elements */
819 FreeListFormat(data);
820 FreeVec(data->format);
822 return DoSuperMethodA(cl, obj, msg);
826 /**************************************************************************
827 OM_SET
828 **************************************************************************/
829 IPTR List__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
831 struct MUI_ListData *data = INST_DATA(cl, obj);
832 struct TagItem *tag;
833 struct TagItem *tags;
835 /* parse initial taglist */
836 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
838 switch (tag->ti_Tag)
840 case MUIA_List_CompareHook:
841 data->compare_hook = (struct Hook *)tag->ti_Data;
842 break;
844 case MUIA_List_ConstructHook:
845 data->construct_hook = (struct Hook *)tag->ti_Data;
846 break;
848 case MUIA_List_DestructHook:
849 data->destruct_hook = (struct Hook *)tag->ti_Data;
850 break;
852 case MUIA_List_DisplayHook:
853 data->display_hook = (struct Hook *)tag->ti_Data;
854 break;
856 case MUIA_List_VertProp_First:
857 data->vertprop_first = tag->ti_Data;
858 if (data->entries_first != tag->ti_Data)
860 set(obj, MUIA_List_First, tag->ti_Data);
862 break;
864 case MUIA_List_Format:
865 data->format = StrDup((STRPTR) tag->ti_Data);
866 ParseListFormat(data, data->format);
867 // FIXME: should we check for errors?
868 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
869 break;
871 case MUIA_List_VertProp_Entries:
872 data->vertprop_entries = tag->ti_Data;
873 break;
875 case MUIA_List_VertProp_Visible:
876 data->vertprop_visible = tag->ti_Data;
877 data->entries_visible = tag->ti_Data;
878 break;
880 case MUIA_List_Active:
882 LONG new_entries_active = tag->ti_Data;
884 if ((data->entries_num)
885 && (new_entries_active != MUIV_List_Active_Off))
887 switch (new_entries_active)
889 case MUIV_List_Active_Top:
890 new_entries_active = 0;
891 break;
893 case MUIV_List_Active_Bottom:
894 new_entries_active = data->entries_num - 1;
895 break;
897 case MUIV_List_Active_Up:
898 new_entries_active = data->entries_active - 1;
899 break;
901 case MUIV_List_Active_Down:
902 new_entries_active = data->entries_active + 1;
903 break;
905 case MUIV_List_Active_PageUp:
906 new_entries_active =
907 data->entries_active - data->entries_visible;
908 break;
910 case MUIV_List_Active_PageDown:
911 new_entries_active =
912 data->entries_active + data->entries_visible;
913 break;
916 if (new_entries_active < 0)
917 new_entries_active = 0;
918 else if (new_entries_active >= data->entries_num)
919 new_entries_active = data->entries_num - 1;
921 else
922 new_entries_active = -1;
924 if (data->entries_active != new_entries_active)
926 LONG old = data->entries_active;
927 data->entries_active = new_entries_active;
929 data->update = 2;
930 data->update_pos = old;
931 MUI_Redraw(obj, MADF_DRAWUPDATE);
932 data->update = 2;
933 data->update_pos = data->entries_active;
934 MUI_Redraw(obj, MADF_DRAWUPDATE);
936 /* Selectchange stuff */
937 if (old != -1)
939 data->entries[old]->flags &= ~ENTRY_SELECTED;
940 DoMethod(obj, MUIM_List_SelectChange, old,
941 MUIV_List_Select_Off, 0);
944 if (new_entries_active != -1)
946 data->entries[new_entries_active]->flags |=
947 ENTRY_SELECTED;
948 DoMethod(obj, MUIM_List_SelectChange,
949 new_entries_active, MUIV_List_Select_On, 0);
950 DoMethod(obj, MUIM_List_SelectChange,
951 new_entries_active, MUIV_List_Select_Active, 0);
953 else
954 DoMethod(obj, MUIM_List_SelectChange,
955 MUIV_List_Active_Off, MUIV_List_Select_Off, 0);
957 set(obj, MUIA_Listview_SelectChange, TRUE);
959 if (new_entries_active != -1)
961 DoMethod(obj, MUIM_List_Jump,
962 MUIV_List_Jump_Active);
966 break;
968 case MUIA_List_First:
969 data->update_pos = data->entries_first;
970 data->update = 3;
971 data->entries_first = tag->ti_Data;
973 MUI_Redraw(obj, MADF_DRAWUPDATE);
974 if (data->vertprop_first != tag->ti_Data)
976 set(obj, MUIA_List_VertProp_First, tag->ti_Data);
978 break;
980 case MUIA_List_Visible:
981 if (data->vertprop_visible != tag->ti_Data)
982 set(obj, MUIA_List_VertProp_Visible, tag->ti_Data);
983 break;
985 case MUIA_List_Entries:
986 if (data->confirm_entries_num == tag->ti_Data)
988 data->entries_num = tag->ti_Data;
989 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
991 else
993 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
995 break;
997 case MUIA_List_Quiet:
998 _handle_bool_tag(data->flags, tag->ti_Data, LIST_QUIET);
999 if (!tag->ti_Data)
1001 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1003 break;
1005 case MUIA_Listview_ClickColumn:
1006 data->click_column = tag->ti_Data;
1007 break;
1011 return DoSuperMethodA(cl, obj, (Msg) msg);
1014 /**************************************************************************
1015 OM_GET
1016 **************************************************************************/
1017 IPTR List__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
1019 /* small macro to simplify return value storage */
1020 #define STORE *(msg->opg_Storage)
1021 struct MUI_ListData *data = INST_DATA(cl, obj);
1023 switch (msg->opg_AttrID)
1025 case MUIA_List_Entries:
1026 STORE = data->entries_num;
1027 return 1;
1028 case MUIA_List_First:
1029 STORE = data->entries_first;
1030 return 1;
1031 case MUIA_List_Active:
1032 STORE = data->entries_active;
1033 return 1;
1034 case MUIA_List_InsertPosition:
1035 STORE = data->insert_position;
1036 return 1;
1037 case MUIA_List_Title:
1038 STORE = (unsigned long)data->title;
1039 return 1;
1040 case MUIA_List_VertProp_Entries:
1041 STORE = data->vertprop_entries;
1042 return 1;
1043 case MUIA_List_VertProp_Visible:
1044 STORE = data->vertprop_visible;
1045 return 1;
1046 case MUIA_List_VertProp_First:
1047 STORE = data->vertprop_first;
1048 return 1;
1049 case MUIA_List_Format:
1050 STORE = (IPTR) data->format;
1051 return 1;
1053 case MUIA_Listview_DoubleClick:
1054 STORE = 0;
1055 return 1;
1056 case MUIA_Listview_ClickColumn:
1057 STORE = data->click_column;
1058 return 1;
1059 case MUIA_Listview_List:
1060 STORE = (IPTR) obj;
1061 return 1; /* Validated with 3rd party application */
1064 if (DoSuperMethodA(cl, obj, (Msg) msg))
1065 return 1;
1066 return 0;
1067 #undef STORE
1070 /**************************************************************************
1071 MUIM_Setup
1072 **************************************************************************/
1073 IPTR List__MUIM_Setup(struct IClass *cl, Object *obj,
1074 struct MUIP_Setup *msg)
1076 struct MUI_ListData *data = INST_DATA(cl, obj);
1078 if (!DoSuperMethodA(cl, obj, (Msg) msg))
1079 return 0;
1081 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
1082 data->prefs_refresh = muiGlobalInfo(obj)->mgi_Prefs->list_refresh;
1083 data->prefs_linespacing =
1084 muiGlobalInfo(obj)->mgi_Prefs->list_linespacing;
1085 data->prefs_smoothed = muiGlobalInfo(obj)->mgi_Prefs->list_smoothed;
1086 data->prefs_smoothval = muiGlobalInfo(obj)->mgi_Prefs->list_smoothval;
1088 CalcWidths(cl, obj);
1090 if (data->title)
1092 data->title_height = data->entries[ENTRY_TITLE]->height + 2;
1094 else
1096 data->title_height = 0;
1099 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
1101 data->list_cursor =
1102 zune_imspec_setup(MUII_ListCursor, muiRenderInfo(obj));
1103 data->list_select =
1104 zune_imspec_setup(MUII_ListSelect, muiRenderInfo(obj));
1105 data->list_selcur =
1106 zune_imspec_setup(MUII_ListSelCur, muiRenderInfo(obj));
1108 return 1;
1111 /**************************************************************************
1112 MUIM_Cleanup
1113 **************************************************************************/
1114 IPTR List__MUIM_Cleanup(struct IClass *cl, Object *obj,
1115 struct MUIP_Cleanup *msg)
1117 struct MUI_ListData *data = INST_DATA(cl, obj);
1118 struct ListImage *li = List_First(&data->images);
1120 while (li)
1122 struct ListImage *next = Node_Next(li);
1123 DoMethod(obj, MUIM_List_DeleteImage, (IPTR) li);
1124 li = next;
1127 zune_imspec_cleanup(data->list_cursor);
1128 zune_imspec_cleanup(data->list_select);
1129 zune_imspec_cleanup(data->list_selcur);
1131 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
1132 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1133 data->mouse_click = 0;
1135 return DoSuperMethodA(cl, obj, (Msg) msg);
1138 /**************************************************************************
1139 MUIM_AskMinMax
1140 **************************************************************************/
1141 IPTR List__MUIM_AskMinMax(struct IClass *cl, Object *obj,
1142 struct MUIP_AskMinMax *msg)
1144 struct MUI_ListData *data = INST_DATA(cl, obj);
1146 DoSuperMethodA(cl, obj, (Msg) msg);
1149 if ((data->flags & LIST_ADJUSTWIDTH) && (data->entries_num > 0))
1151 msg->MinMaxInfo->MinWidth += data->entries_maxwidth;
1152 msg->MinMaxInfo->DefWidth += data->entries_maxwidth;
1153 msg->MinMaxInfo->MaxWidth += data->entries_maxwidth;
1155 else
1157 msg->MinMaxInfo->MinWidth += 40;
1158 msg->MinMaxInfo->DefWidth += 100;
1159 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1162 if (data->entries_num > 0)
1164 if (data->flags & LIST_ADJUSTHEIGHT)
1166 msg->MinMaxInfo->MinHeight += data->entries_totalheight;
1167 msg->MinMaxInfo->DefHeight += data->entries_totalheight;
1168 msg->MinMaxInfo->MaxHeight += data->entries_totalheight;
1170 else
1172 ULONG h = data->entry_maxheight + data->prefs_linespacing;
1173 msg->MinMaxInfo->MinHeight += 2 * h + data->prefs_linespacing;
1174 msg->MinMaxInfo->DefHeight += 8 * h + data->prefs_linespacing;
1175 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1178 else
1180 msg->MinMaxInfo->MinHeight += 36;
1181 msg->MinMaxInfo->DefHeight += 96;
1182 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1184 D(bug("List %p minheigh=%d, line maxh=%d\n",
1185 obj, msg->MinMaxInfo->MinHeight, data->entry_maxheight));
1186 return TRUE;
1189 /**************************************************************************
1190 MUIM_Layout
1191 **************************************************************************/
1192 IPTR List__MUIM_Layout(struct IClass *cl, Object *obj,
1193 struct MUIP_Layout *msg)
1195 struct MUI_ListData *data = INST_DATA(cl, obj);
1196 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1197 LONG new_entries_first = data->entries_first;
1199 /* Calc the numbers of entries visible */
1200 CalcVertVisible(cl, obj);
1202 #if 0 /* Don't do this! */
1203 if (data->entries_active < new_entries_first)
1204 new_entries_first = data->entries_active;
1205 #endif
1207 if (data->entries_active + 1 >=
1208 (data->entries_first + data->entries_visible))
1209 new_entries_first =
1210 data->entries_active - data->entries_visible + 1;
1212 if ((new_entries_first + data->entries_visible >=
1213 data->entries_num)
1214 && (data->entries_visible <= data->entries_num))
1215 new_entries_first = data->entries_num - data->entries_visible;
1217 if (data->entries_num <= data->entries_visible)
1218 new_entries_first = 0;
1220 if (new_entries_first < 0)
1221 new_entries_first = 0;
1223 set(obj, new_entries_first != data->entries_first ?
1224 MUIA_List_First : TAG_IGNORE, new_entries_first);
1226 /* So the notify takes happens */
1227 set(obj, MUIA_List_VertProp_Visible, data->entries_visible);
1229 return rc;
1233 /**************************************************************************
1234 MUIM_Show
1235 **************************************************************************/
1236 IPTR List__MUIM_Show(struct IClass *cl, Object *obj,
1237 struct MUIP_Show *msg)
1239 struct MUI_ListData *data = INST_DATA(cl, obj);
1240 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1242 zune_imspec_show(data->list_cursor, obj);
1243 zune_imspec_show(data->list_select, obj);
1244 zune_imspec_show(data->list_selcur, obj);
1245 return rc;
1249 /**************************************************************************
1250 MUIM_Hide
1251 **************************************************************************/
1252 IPTR List__MUIM_Hide(struct IClass *cl, Object *obj,
1253 struct MUIP_Hide *msg)
1255 struct MUI_ListData *data = INST_DATA(cl, obj);
1257 #if 0
1258 if (data->ehn.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
1260 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1261 (IPTR) & data->ehn);
1262 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1263 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1264 (IPTR) & data->ehn);
1266 data->mouse_click = 0;
1267 #endif
1269 zune_imspec_hide(data->list_cursor);
1270 zune_imspec_hide(data->list_select);
1271 zune_imspec_hide(data->list_selcur);
1273 return DoSuperMethodA(cl, obj, (Msg) msg);
1277 /**************************************************************************
1278 Draw an entry at entry_pos at the given y location. To draw the title,
1279 set pos to ENTRY_TITLE
1280 **************************************************************************/
1281 static VOID List_DrawEntry(struct IClass *cl, Object *obj, int entry_pos,
1282 int y)
1284 struct MUI_ListData *data = INST_DATA(cl, obj);
1285 int col, x1, x2;
1287 /* To be sure we don't draw anything if there is no title */
1288 if (entry_pos == ENTRY_TITLE && !data->title)
1289 return;
1291 DisplayEntry(cl, obj, entry_pos);
1292 x1 = _mleft(obj);
1294 for (col = 0; col < data->columns; col++)
1296 ZText *text;
1297 x2 = x1 + data->ci[col].entries_width;
1299 if ((text =
1300 zune_text_new(data->preparses[col], data->strings[col],
1301 ZTEXT_ARG_NONE, 0)))
1303 /* Could be made simpler, as we don't really need the bounds */
1304 zune_text_get_bounds(text, obj);
1305 /* Note, this was MPEN_SHADOW before */
1306 SetAPen(_rp(obj), muiRenderInfo(obj)->mri_Pens[MPEN_TEXT]);
1307 zune_text_draw(text, obj, x1, x2, y); /* totally wrong! */
1308 zune_text_destroy(text);
1310 x1 = x2 + data->ci[col].delta + (data->ci[col].bar ? BAR_WIDTH : 0);
1314 /**************************************************************************
1315 MUIM_Draw
1316 **************************************************************************/
1317 IPTR List__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1319 struct MUI_ListData *data = INST_DATA(cl, obj);
1320 int entry_pos, y;
1321 APTR clip;
1322 int start, end;
1323 BOOL scroll_caused_damage = FALSE;
1325 DoSuperMethodA(cl, obj, (Msg) msg);
1327 if (msg->flags & MADF_DRAWUPDATE)
1329 if (data->update == 1)
1330 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1331 _mwidth(obj), _mheight(obj),
1332 0, data->entries_first * data->entry_maxheight, 0);
1334 else
1336 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1337 _mwidth(obj), _mheight(obj),
1338 0, data->entries_first * data->entry_maxheight, 0);
1341 clip = MUI_AddClipping(muiRenderInfo(obj), _mleft(obj), _mtop(obj),
1342 _mwidth(obj), _mheight(obj));
1344 if (!(msg->flags & MADF_DRAWUPDATE)
1345 || ((msg->flags & MADF_DRAWUPDATE) && data->update == 1))
1347 y = _mtop(obj);
1348 /* Draw Title
1350 if (data->title_height && data->title)
1352 List_DrawEntry(cl, obj, ENTRY_TITLE, y);
1353 y += data->entries[ENTRY_TITLE]->height;
1354 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1355 Move(_rp(obj), _mleft(obj), y);
1356 Draw(_rp(obj), _mright(obj), y);
1357 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1358 y++;
1359 Move(_rp(obj), _mleft(obj), y);
1360 Draw(_rp(obj), _mright(obj), y);
1364 y = data->entries_top_pixel;
1366 start = data->entries_first;
1367 end = data->entries_first + data->entries_visible;
1369 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3)
1371 int diffy = data->entries_first - data->update_pos;
1372 int top, bottom;
1373 if (abs(diffy) < data->entries_visible)
1375 scroll_caused_damage =
1376 (_rp(obj)->Layer->Flags & LAYERREFRESH) ? FALSE : TRUE;
1378 ScrollRaster(_rp(obj), 0, diffy * data->entry_maxheight,
1379 _mleft(obj), y,
1380 _mright(obj),
1381 y + data->entry_maxheight * data->entries_visible);
1383 scroll_caused_damage =
1384 scroll_caused_damage
1385 && (_rp(obj)->Layer->Flags & LAYERREFRESH);
1387 if (diffy > 0)
1389 start = end - diffy;
1390 y += data->entry_maxheight * (data->entries_visible -
1391 diffy);
1393 else
1394 end = start - diffy;
1397 top = y;
1398 bottom = y + (end - start) * data->entry_maxheight;
1400 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), top,
1401 _mwidth(obj), bottom - top + 1,
1403 top - _mtop(obj) + data->entries_first * data->entry_maxheight,
1407 for (entry_pos = start;
1408 entry_pos < end && entry_pos < data->entries_num; entry_pos++)
1410 //struct ListEntry *entry = data->entries[entry_pos];
1412 if (!(msg->flags & MADF_DRAWUPDATE) ||
1413 ((msg->flags & MADF_DRAWUPDATE) && data->update == 1) ||
1414 ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) ||
1415 ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1416 && data->update_pos == entry_pos))
1418 if (entry_pos == data->entries_active)
1420 zune_imspec_draw(data->list_cursor, muiRenderInfo(obj),
1421 _mleft(obj), y, _mwidth(obj), data->entry_maxheight,
1422 0, y - data->entries_top_pixel, 0);
1424 else
1426 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1427 && data->update_pos == entry_pos)
1429 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), y,
1430 _mwidth(obj), data->entry_maxheight, 0,
1431 y - _mtop(obj) +
1432 data->entries_first * data->entry_maxheight, 0);
1435 List_DrawEntry(cl, obj, entry_pos, y);
1437 y += data->entry_maxheight;
1438 } /* for */
1440 MUI_RemoveClipping(muiRenderInfo(obj), clip);
1442 data->update = 0;
1444 if (scroll_caused_damage)
1446 if (MUI_BeginRefresh(muiRenderInfo(obj), 0))
1448 /* Theoretically it might happen that more damage is caused
1449 after ScrollRaster. By something else, like window movement
1450 in front of our window. Therefore refresh root object of
1451 window, not just this object */
1453 Object *o = NULL;
1455 get(_win(obj), MUIA_Window_RootObject, &o);
1456 MUI_Redraw(o, MADF_DRAWOBJECT);
1458 MUI_EndRefresh(muiRenderInfo(obj), 0);
1462 ULONG x1 = _mleft(obj);
1463 ULONG col;
1464 y = _mtop(obj);
1466 if (data->title_height && data->title)
1468 for (col = 0; col < data->columns; col++)
1470 ULONG halfdelta = data->ci[col].delta / 2;
1471 x1 += data->ci[col].entries_width + halfdelta;
1473 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(obj))
1474 break;
1476 if (data->ci[col].bar)
1478 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1479 Move(_rp(obj), x1, y);
1480 Draw(_rp(obj), x1,
1481 y + data->entries[ENTRY_TITLE]->height - 1);
1482 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1483 Move(_rp(obj), x1 + 1, y);
1484 Draw(_rp(obj), x1 + 1,
1485 y + data->entries[ENTRY_TITLE]->height - 1);
1487 x1 += BAR_WIDTH;
1489 x1 += data->ci[col].delta - halfdelta;
1491 y += data->entries[ENTRY_TITLE]->height + 1;
1494 x1 = _mleft(obj);
1496 for (col = 0; col < data->columns; col++)
1498 ULONG halfdelta = data->ci[col].delta / 2;
1499 x1 += data->ci[col].entries_width + halfdelta;
1501 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(obj))
1502 break;
1504 if (data->ci[col].bar)
1506 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1507 Move(_rp(obj), x1, y);
1508 Draw(_rp(obj), x1, _mbottom(obj));
1509 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1510 Move(_rp(obj), x1 + 1, y);
1511 Draw(_rp(obj), x1 + 1, _mbottom(obj));
1513 x1 += BAR_WIDTH;
1516 x1 += data->ci[col].delta - halfdelta;
1519 return 0;
1522 /**************************************************************************
1523 Makes the entry at the given mouse position the active one.
1524 Relx and Rely are relative mouse coordinates to the upper left of
1525 the object
1526 **************************************************************************/
1527 static VOID List_MakeActive(struct IClass *cl, Object *obj, LONG relx,
1528 LONG rely)
1530 struct MUI_ListData *data = INST_DATA(cl, obj);
1532 if (data->entries_num == 0)
1533 return;
1535 LONG eclicky = rely + _top(obj) - data->entries_top_pixel;
1536 /* y coordinates transformed to the entries */
1537 LONG new_act = eclicky / data->entry_maxheight + data->entries_first;
1538 LONG old_act = data->entries_active;
1540 if (eclicky < 0)
1542 new_act = data->entries_first - 1;
1544 else if (new_act > data->entries_first + data->entries_visible)
1546 new_act = data->entries_first + data->entries_visible;
1549 if (new_act >= data->entries_num)
1550 new_act = data->entries_num - 1;
1551 else if (new_act < 0)
1552 new_act = 0;
1554 /* Notify only when active entry has changed */
1555 if (old_act != new_act)
1556 set(obj, MUIA_List_Active, new_act);
1559 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely,
1560 UWORD qual)
1562 struct MUI_ListData *data = INST_DATA(cl, obj);
1563 LONG new = data->entries_first;
1565 if (qual & IEQUALIFIER_CONTROL)
1567 if (wheely < 0)
1568 new = 0;
1569 if (wheely > 0)
1570 new = data->entries_num;
1572 else if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
1574 new += (wheely * data->entries_visible);
1576 else
1578 new += wheely * 3;
1581 if (new > data->entries_num - data->entries_visible)
1583 new = data->entries_num - data->entries_visible;
1586 if (new < 0)
1588 new = 0;
1591 if (new != data->entries_first)
1593 set(obj, MUIA_List_First, new);
1598 /**************************************************************************
1599 MUIM_HandleEvent
1600 **************************************************************************/
1601 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
1602 struct MUIP_HandleEvent *msg)
1604 struct MUI_ListData *data = INST_DATA(cl, obj);
1606 if (msg->imsg)
1608 LONG mx = msg->imsg->MouseX - _left(obj);
1609 LONG my = msg->imsg->MouseY - _top(obj);
1610 switch (msg->imsg->Class)
1612 case IDCMP_MOUSEBUTTONS:
1613 if (msg->imsg->Code == SELECTDOWN)
1615 if (mx >= 0 && mx < _width(obj) && my >= 0
1616 && my < _height(obj))
1618 LONG eclicky = my + _top(obj) - data->entries_top_pixel;
1619 /* y coordinates transformed to the entries */
1620 data->mouse_click = MOUSE_CLICK_ENTRY;
1622 /* Now check if it was clicked on a title or on entries */
1623 if (eclicky >= 0
1624 && eclicky <
1625 data->entries_visible * data->entry_maxheight)
1627 List_MakeActive(cl, obj, mx, my);
1628 /* sets data->entries_active */
1630 if (data->last_active == data->entries_active
1631 && DoubleClick(data->last_secs, data->last_mics,
1632 msg->imsg->Seconds, msg->imsg->Micros))
1634 /* Handle MUIA_ListView_ClickColumn */
1635 data->click_column = 0;
1636 if (data->entries_num > 0 && data->columns > 0)
1638 LONG width_sum = 0;
1639 LONG col;
1640 for (col = 0; col < data->columns; col++)
1642 width_sum +=
1643 data->ci[col].entries_width +
1644 data->ci[col].delta +
1645 (data->ci[col].bar ? BAR_WIDTH : 0);
1646 D(bug
1647 ("[List/MUIM_HandleEvent] col %d "
1648 "width %d width_sum %d mx %d\n",
1649 col,
1650 data->ci[col].entries_width,
1651 width_sum, mx));
1652 if (mx < width_sum)
1654 D(bug
1655 ("[List/MUIM_HandleEvent] "
1656 "Column hit %d\n",
1657 col));
1658 set(obj, MUIA_Listview_ClickColumn,
1659 col);
1660 break;
1665 set(obj, MUIA_Listview_DoubleClick, TRUE);
1666 data->last_active = -1;
1667 data->last_secs = data->last_mics = 0;
1669 else
1671 data->last_active = data->entries_active;
1672 data->last_secs = msg->imsg->Seconds;
1673 data->last_mics = msg->imsg->Micros;
1677 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1678 (IPTR) & data->ehn);
1679 data->ehn.ehn_Events |=
1680 (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1681 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1682 (IPTR) & data->ehn);
1684 return MUI_EventHandlerRC_Eat;
1687 else
1689 if (msg->imsg->Code == SELECTUP && data->mouse_click)
1691 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1692 (IPTR) & data->ehn);
1693 data->ehn.ehn_Events &=
1694 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1695 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1696 (IPTR) & data->ehn);
1697 data->mouse_click = 0;
1698 return 0;
1701 break;
1703 case IDCMP_INTUITICKS:
1704 case IDCMP_MOUSEMOVE:
1705 if (data->mouse_click)
1707 List_MakeActive(cl, obj, mx, my);
1709 break;
1711 case IDCMP_RAWKEY:
1712 switch (msg->imsg->Code)
1714 case RAWKEY_NM_WHEEL_UP:
1715 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
1717 DoWheelMove(cl, obj, -1, msg->imsg->Qualifier);
1719 break;
1721 case RAWKEY_NM_WHEEL_DOWN:
1722 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
1724 DoWheelMove(cl, obj, 1, msg->imsg->Qualifier);
1726 break;
1729 break;
1731 case IDCMP_ACTIVEWINDOW:
1732 case IDCMP_INACTIVEWINDOW:
1733 if (data->ehn.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
1735 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1736 (IPTR) & data->ehn);
1737 data->ehn.ehn_Events &=
1738 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1739 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1740 (IPTR) & data->ehn);
1741 data->mouse_click = 0;
1743 break;
1747 return 0;
1750 /**************************************************************************
1751 MUIM_List_Clear
1752 **************************************************************************/
1753 IPTR List__MUIM_Clear(struct IClass *cl, Object *obj,
1754 struct MUIP_List_Clear *msg)
1756 struct MUI_ListData *data = INST_DATA(cl, obj);
1758 while (data->confirm_entries_num)
1760 struct ListEntry *lentry =
1761 data->entries[--data->confirm_entries_num];
1762 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1763 (IPTR) data->pool);
1764 FreeListEntry(data, lentry);
1766 /* Should never fail when shrinking */
1767 SetListSize(data, 0);
1769 if (data->confirm_entries_num != data->entries_num)
1771 SetAttrs(obj, MUIA_List_Entries, 0, MUIA_List_First, 0,
1772 /* Notify only when no entry was active */
1773 data->entries_active !=
1774 MUIV_List_Active_Off ? MUIA_List_Active : TAG_DONE,
1775 MUIV_List_Active_Off, TAG_DONE);
1777 data->update = 1;
1778 MUI_Redraw(obj, MADF_DRAWUPDATE);
1781 return 0;
1784 /**************************************************************************
1785 MUIM_List_Exchange
1786 **************************************************************************/
1787 IPTR List__MUIM_Exchange(struct IClass *cl, Object *obj,
1788 struct MUIP_List_Exchange *msg)
1790 struct MUI_ListData *data = INST_DATA(cl, obj);
1791 LONG pos1, pos2;
1793 switch (msg->pos1)
1795 case MUIV_List_Exchange_Top:
1796 pos1 = 0;
1797 break;
1798 case MUIV_List_Exchange_Active:
1799 pos1 = data->entries_active;
1800 break;
1801 case MUIV_List_Exchange_Bottom:
1802 pos1 = data->entries_num - 1;
1803 break;
1804 default:
1805 pos1 = msg->pos1;
1808 switch (msg->pos2)
1810 case MUIV_List_Exchange_Top:
1811 pos2 = 0;
1812 break;
1813 case MUIV_List_Exchange_Active:
1814 pos2 = data->entries_active;
1815 break;
1816 case MUIV_List_Exchange_Bottom:
1817 pos2 = data->entries_num - 1;
1818 break;
1819 case MUIV_List_Exchange_Next:
1820 pos2 = pos1 + 1;
1821 break;
1822 case MUIV_List_Exchange_Previous:
1823 pos2 = pos1 - 1;
1824 break;
1825 default:
1826 pos2 = msg->pos2;
1829 if (pos1 >= 0 && pos1 < data->entries_num && pos2 >= 0
1830 && pos2 < data->entries_num && pos1 != pos2)
1832 struct ListEntry *save = data->entries[pos1];
1833 data->entries[pos1] = data->entries[pos2];
1834 data->entries[pos2] = save;
1836 data->update = 2;
1837 data->update_pos = pos1;
1838 MUI_Redraw(obj, MADF_DRAWUPDATE);
1840 data->update = 2;
1841 data->update_pos = pos2;
1842 MUI_Redraw(obj, MADF_DRAWUPDATE);
1844 return TRUE;
1846 else
1848 return FALSE;
1852 /**************************************************************************
1853 MUIM_List_Redraw
1854 **************************************************************************/
1855 IPTR List__MUIM_Redraw(struct IClass *cl, Object *obj,
1856 struct MUIP_List_Redraw *msg)
1858 struct MUI_ListData *data = INST_DATA(cl, obj);
1860 if (msg->pos == MUIV_List_Redraw_All)
1862 data->update = 1;
1863 CalcWidths(cl, obj);
1864 MUI_Redraw(obj, MADF_DRAWUPDATE);
1866 else
1868 LONG pos = -1;
1869 if (msg->pos == MUIV_List_Redraw_Active)
1870 pos = data->entries_active;
1871 else if (msg->pos == MUIV_List_Redraw_Entry)
1873 LONG i;
1874 for (i = 0; i < data->entries_num; i++)
1875 if (data->entries[i]->data == msg->entry)
1877 pos = i;
1878 break;
1881 else
1882 pos = msg->pos;
1884 if (pos != -1)
1886 if (CalcDimsOfEntry(cl, obj, pos))
1887 data->update = 1;
1888 else
1890 data->update = 2;
1891 data->update_pos = pos;
1893 MUI_Redraw(obj, MADF_DRAWUPDATE);
1896 return 0;
1899 /**************************************************************************
1900 MUIM_List_Remove
1901 **************************************************************************/
1902 IPTR List__MUIM_Remove(struct IClass *cl, Object *obj,
1903 struct MUIP_List_Remove *msg)
1905 struct MUI_ListData *data = INST_DATA(cl, obj);
1906 LONG pos, cur;
1907 LONG new_act;
1908 struct ListEntry *lentry;
1909 //int rem_count = 1;
1911 if (!data->entries_num)
1912 return 0;
1914 switch (msg->pos)
1916 case MUIV_List_Remove_First:
1917 pos = 0;
1918 break;
1920 case MUIV_List_Remove_Active:
1921 pos = data->entries_active;
1922 break;
1924 case MUIV_List_Remove_Last:
1925 pos = data->entries_num - 1;
1926 break;
1928 case MUIV_List_Remove_Selected:
1929 /* TODO: needs special handling */
1930 pos = data->entries_active;
1931 break;
1933 default:
1934 pos = msg->pos;
1935 break;
1938 if (pos < 0 || pos >= data->entries_num)
1939 return 0;
1941 new_act = data->entries_active;
1943 if (pos == new_act && new_act == data->entries_num - 1)
1944 new_act--; /* might become MUIV_List_Active_Off */
1946 lentry = data->entries[pos];
1947 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1948 (IPTR) data->pool);
1950 cur = pos + 1;
1952 RemoveListEntries(data, pos, cur - pos);
1953 data->confirm_entries_num -= cur - pos;
1955 /* ensure that the active element is in a valid range */
1956 if (new_act >= data->entries_num)
1957 new_act = data->entries_num - 1;
1959 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num,
1960 (new_act >= pos) || (new_act != data->entries_active) ?
1961 MUIA_List_Active : TAG_DONE,
1962 new_act, /* Inform only if neccessary (for notify) */
1963 TAG_DONE);
1965 data->update = 1;
1966 MUI_Redraw(obj, MADF_DRAWUPDATE);
1968 return 0;
1971 /**************************************************************************
1972 MUIM_List_Select
1973 **************************************************************************/
1974 IPTR List__MUIM_Select(struct IClass *cl, Object *obj,
1975 struct MUIP_List_Select *msg)
1977 struct MUI_ListData *data = INST_DATA(cl, obj);
1978 LONG pos, i, count, selcount=0, state=0;
1980 /* Establish the range of entries affected */
1981 switch (msg->pos)
1983 case MUIV_List_Select_Active:
1984 pos = data->entries_active;
1985 if (pos == MUIV_List_Active_Off)
1986 count = 0;
1987 else
1988 count = 1;
1989 break;
1991 case MUIV_List_Select_All:
1992 pos = 0;
1993 count = data->entries_num;
1994 break;
1996 default:
1997 pos = msg->pos;
1998 count = 1;
1999 if (pos < 0 || pos >= data->entries_num)
2000 return 0;
2001 break;
2004 /* Change or check state of each entry in the range */
2005 for (i = pos; i < pos + count; i++)
2007 state = data->entries[i]->flags & ENTRY_SELECTED;
2008 switch (msg->seltype)
2010 case MUIV_List_Select_Off:
2011 data->entries[i]->flags &= ~ENTRY_SELECTED;
2012 break;
2014 case MUIV_List_Select_On:
2015 data->entries[i]->flags |= ENTRY_SELECTED;
2016 break;
2018 case MUIV_List_Select_Toggle:
2019 data->entries[i]->flags ^= ENTRY_SELECTED;
2020 break;
2022 default:
2023 if (data->entries[i]->flags & ENTRY_SELECTED)
2024 selcount++;
2025 break;
2029 /* Report old state or number of selected entries */
2030 if (msg->info)
2032 if (msg->pos == MUIV_List_Select_All
2033 && msg->seltype == MUIV_List_Select_Ask)
2034 *msg->info = selcount;
2035 else
2036 *msg->info = state;
2039 /* Redraw unless it was just an enquiry */
2040 if (msg->seltype != MUIV_List_Select_Ask)
2042 data->update = 1;
2043 MUI_Redraw(obj, MADF_DRAWUPDATE);
2046 return 0;
2049 /**************************************************************************
2050 MUIM_List_Insert
2051 **************************************************************************/
2053 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
2054 struct MUIP_List_Insert *msg)
2056 struct MUI_ListData *data = INST_DATA(cl, obj);
2057 LONG pos, count, sort;
2059 count = msg->count;
2060 sort = 0;
2062 if (count == -1)
2064 /* Count the number of entries */
2065 for (count = 0; msg->entries[count] != NULL; count++)
2069 if (count <= 0)
2070 return ~0;
2072 switch (msg->pos)
2074 case MUIV_List_Insert_Top:
2075 pos = 0;
2076 break;
2078 case MUIV_List_Insert_Active:
2079 if (data->entries_active != -1)
2080 pos = data->entries_active;
2081 else
2082 pos = 0;
2083 break;
2085 case MUIV_List_Insert_Sorted:
2086 pos = data->entries_num;
2087 sort = 1; /* we sort'em later */
2088 break;
2090 case MUIV_List_Insert_Bottom:
2091 pos = data->entries_num;
2092 break;
2094 default:
2095 if (msg->pos > data->entries_num)
2096 pos = data->entries_num;
2097 else if (msg->pos < 0)
2098 pos = 0;
2099 else
2100 pos = msg->pos;
2101 break;
2104 if (!(SetListSize(data, data->entries_num + count)))
2105 return ~0;
2107 LONG until = pos + count;
2108 APTR *toinsert = msg->entries;
2110 if (!(PrepareInsertListEntries(data, pos, count)))
2111 return ~0;
2113 while (pos < until)
2115 struct ListEntry *lentry;
2117 if (!(lentry = AllocListEntry(data)))
2119 /* Panic, but we must be in a consistent state, so remove
2120 * the space where the following list entries should have gone
2122 RemoveListEntries(data, pos, until - pos);
2123 return ~0;
2126 /* now call the construct method which returns us a pointer which
2127 we need to store */
2128 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2129 (IPTR) * toinsert, (IPTR) data->pool);
2130 if (!lentry->data)
2132 FreeListEntry(data, lentry);
2133 RemoveListEntries(data, pos, until - pos);
2135 /* TODO: Also check for visible stuff like below */
2136 if (data->entries_num != data->confirm_entries_num)
2137 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2138 return ~0;
2141 data->entries[pos] = lentry;
2142 data->confirm_entries_num++;
2144 if (_flags(obj) & MADF_SETUP)
2146 /* We have to calculate the width and height of the newly
2147 * inserted entry. This has to be done after inserting the
2148 * element into the list */
2149 CalcDimsOfEntry(cl, obj, pos);
2152 toinsert++;
2153 pos++;
2154 } // while (pos < until)
2157 /* Recalculate the number of visible entries */
2158 if (_flags(obj) & MADF_SETUP)
2159 CalcVertVisible(cl, obj);
2161 if (data->entries_num != data->confirm_entries_num)
2163 SetAttrs(obj,
2164 MUIA_List_Entries, data->confirm_entries_num,
2165 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2168 /* If the array is already sorted, we could do a simple insert
2169 * sort and would be much faster than with qsort.
2170 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2171 * sort the whole array?
2173 * I think, we better sort the whole array:
2175 if (sort)
2177 DoMethod(obj, MUIM_List_Sort);
2178 /* TODO: which pos to return here !? */
2179 /* MUIM_List_Sort already called MUI_Redraw */
2181 else
2183 if (!(data->flags & LIST_QUIET))
2185 data->update = 1;
2186 MUI_Redraw(obj, MADF_DRAWUPDATE);
2189 data->insert_position = pos;
2191 return (ULONG) pos;
2194 /**************************************************************************
2195 MUIM_List_InsertSingle
2196 **************************************************************************/
2197 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2198 struct MUIP_List_InsertSingle *msg)
2200 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2201 msg->pos);
2204 /**************************************************************************
2205 MUIM_List_GetEntry
2206 **************************************************************************/
2207 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2208 struct MUIP_List_GetEntry *msg)
2210 struct MUI_ListData *data = INST_DATA(cl, obj);
2211 int pos = msg->pos;
2213 if (pos == MUIV_List_GetEntry_Active)
2214 pos = data->entries_active;
2216 if (pos < 0 || pos >= data->entries_num)
2218 *msg->entry = NULL;
2219 return 0;
2221 *msg->entry = data->entries[pos]->data;
2222 return (IPTR) *msg->entry;
2225 /**************************************************************************
2226 MUIM_List_Construct
2227 **************************************************************************/
2228 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2229 struct MUIP_List_Construct *msg)
2231 struct MUI_ListData *data = INST_DATA(cl, obj);
2233 if (NULL == data->construct_hook)
2234 return (IPTR) msg->entry;
2235 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2237 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2238 ULONG *mem = AllocPooled(msg->pool, len + 5);
2240 if (NULL == mem)
2241 return 0;
2242 mem[0] = len + 5;
2243 if (msg->entry != NULL)
2244 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2245 else
2246 *(STRPTR) (mem + 1) = 0;
2247 return (IPTR) (mem + 1);
2249 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2252 /**************************************************************************
2253 MUIM_List_Destruct
2254 **************************************************************************/
2255 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2256 struct MUIP_List_Destruct *msg)
2258 struct MUI_ListData *data = INST_DATA(cl, obj);
2260 if (NULL == data->destruct_hook)
2261 return 0;
2263 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2265 ULONG *mem = ((ULONG *) msg->entry) - 1;
2266 FreePooled(msg->pool, mem, mem[0]);
2268 else
2270 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2272 return 0;
2275 /**************************************************************************
2276 MUIM_List_Compare
2277 **************************************************************************/
2278 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2279 struct MUIP_List_Compare *msg)
2281 struct MUI_ListData *data = INST_DATA(cl, obj);
2283 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2286 /**************************************************************************
2287 MUIM_List_Display
2288 **************************************************************************/
2289 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2290 struct MUIP_List_Display *msg)
2292 struct MUI_ListData *data = INST_DATA(cl, obj);
2294 if (NULL == data->display_hook)
2296 if (msg->entry)
2297 *msg->array = msg->entry;
2298 else
2299 *msg->array = 0;
2300 return 1;
2303 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2304 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2307 /**************************************************************************
2308 MUIM_List_SelectChange
2309 **************************************************************************/
2310 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2311 struct MUIP_List_SelectChange *msg)
2313 return 1;
2316 /**************************************************************************
2317 MUIM_List_CreateImage
2318 Called by a List subclass in its Setup method.
2319 Connects an Area subclass object to the list, much like an object gets
2320 connected to a window. List calls Setup and AskMinMax on that object,
2321 keeps a reference to it (that reference will be returned).
2322 Text engine will dereference that pointer and draw the object with its
2323 default size.
2324 **************************************************************************/
2325 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2326 struct MUIP_List_CreateImage *msg)
2328 struct MUI_ListData *data = INST_DATA(cl, obj);
2329 struct ListImage *li;
2331 /* List must be already setup in Setup of your subclass */
2332 if (!(_flags(obj) & MADF_SETUP))
2333 return 0;
2334 li = AllocPooled(data->pool, sizeof(struct ListImage));
2335 if (!li)
2336 return 0;
2337 li->obj = msg->obj;
2339 AddTail((struct List *)&data->images, (struct Node *)li);
2340 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2341 DoSetupMethod(li->obj, muiRenderInfo(obj));
2344 return (IPTR) li;
2347 /**************************************************************************
2348 MUIM_List_DeleteImage
2349 **************************************************************************/
2350 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2351 struct MUIP_List_DeleteImage *msg)
2353 struct MUI_ListData *data = INST_DATA(cl, obj);
2354 struct ListImage *li = (struct ListImage *)msg->listimg;
2356 if (li)
2358 DoMethod(li->obj, MUIM_Cleanup);
2359 DoMethod(li->obj, MUIM_DisconnectParent);
2360 Remove((struct Node *)li);
2361 FreePooled(data->pool, li, sizeof(struct ListImage));
2364 return 0;
2367 /**************************************************************************
2368 MUIM_List_Jump
2369 **************************************************************************/
2370 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2371 struct MUIP_List_Jump *msg)
2373 struct MUI_ListData *data = INST_DATA(cl, obj);
2374 LONG pos = msg->pos;
2376 switch (pos)
2378 case MUIV_List_Jump_Top:
2379 pos = 0;
2380 break;
2382 case MUIV_List_Jump_Active:
2383 pos = data->entries_active;
2384 break;
2386 case MUIV_List_Jump_Bottom:
2387 pos = data->entries_num - 1;
2388 break;
2390 case MUIV_List_Jump_Down:
2391 pos = data->entries_first + data->entries_visible;
2392 break;
2394 case MUIV_List_Jump_Up:
2395 pos = data->entries_first - 1;
2396 break;
2400 if (pos > data->entries_num)
2402 pos = data->entries_num - 1;
2404 if (pos < 0)
2405 pos = 0;
2407 if (pos < data->entries_first)
2409 set(obj, MUIA_List_First, pos);
2411 else if (pos >= data->entries_first + data->entries_visible)
2413 pos -= (data->entries_visible - 1);
2414 if (pos < 0)
2415 pos = 0;
2416 if (pos != data->entries_first)
2418 set(obj, MUIA_List_First, pos);
2423 return TRUE;
2426 /**************************************************************************
2427 MUIM_List_Sort
2428 **************************************************************************/
2429 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2430 struct MUIP_List_Sort *msg)
2432 struct MUI_ListData *data = INST_DATA(cl, obj);
2434 int i, j, max;
2435 struct MUIP_List_Compare cmpmsg =
2436 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2438 if (data->entries_num > 1)
2441 Simple sort algorithm. Feel free to improve it.
2443 for (i = 0; i < data->entries_num - 1; i++)
2445 max = i;
2446 for (j = i + 1; j < data->entries_num; j++)
2448 cmpmsg.entry1 = data->entries[max]->data;
2449 cmpmsg.entry2 = data->entries[j]->data;
2450 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2452 max = j;
2455 if (i != max)
2457 APTR tmp = data->entries[i];
2458 data->entries[i] = data->entries[max];
2459 data->entries[max] = tmp;
2464 if (!(data->flags & LIST_QUIET))
2466 data->update = 1;
2467 MUI_Redraw(obj, MADF_DRAWUPDATE);
2470 return 0;
2473 /**************************************************************************
2474 MUIM_List_Move
2475 **************************************************************************/
2476 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
2477 struct MUIP_List_Move *msg)
2479 struct MUI_ListData *data = INST_DATA(cl, obj);
2481 LONG from, to;
2482 int i;
2484 switch (msg->from)
2486 case MUIV_List_Move_Top:
2487 from = 0;
2488 break;
2489 case MUIV_List_Move_Active:
2490 from = data->entries_active;
2491 break;
2492 case MUIV_List_Move_Bottom:
2493 from = data->entries_num - 1;
2494 break;
2495 default:
2496 from = msg->from;
2499 switch (msg->to)
2501 case MUIV_List_Move_Top:
2502 to = 0;
2503 break;
2504 case MUIV_List_Move_Active:
2505 to = data->entries_active;
2506 break;
2507 case MUIV_List_Move_Bottom:
2508 to = data->entries_num - 1;
2509 break;
2510 case MUIV_List_Move_Next:
2511 to = from + 1;
2512 break;
2513 case MUIV_List_Move_Previous:
2514 to = from - 1;
2515 break;
2516 default:
2517 to = msg->to;
2520 if (from > data->entries_num - 1 || from < 0
2521 || to > data->entries_num - 1 || to < 0 || from == to)
2522 return (IPTR) FALSE;
2524 if (from < to)
2526 struct ListEntry *backup = data->entries[from];
2527 for (i = from; i < to; i++)
2528 data->entries[i] = data->entries[i + 1];
2529 data->entries[to] = backup;
2531 else
2533 struct ListEntry *backup = data->entries[from];
2534 for (i = from; i > to; i--)
2535 data->entries[i] = data->entries[i - 1];
2536 data->entries[to] = backup;
2539 data->update = 1;
2540 MUI_Redraw(obj, MADF_DRAWUPDATE);
2542 return TRUE;
2545 /**************************************************************************
2546 MUIM_List_NextSelected
2547 **************************************************************************/
2548 IPTR List__MUIM_NextSelected(struct IClass *cl, Object *obj,
2549 struct MUIP_List_NextSelected *msg)
2551 struct MUI_ListData *data = INST_DATA(cl, obj);
2552 LONG pos, i;
2553 BOOL found = FALSE;
2555 /* Get the first entry to check */
2556 pos = *msg->pos;
2557 if (pos == MUIV_List_NextSelected_Start)
2558 pos = 0;
2559 else
2560 pos++;
2562 /* Find the next selected entry */
2563 for (i = pos; i < data->entries_num && !found; i++)
2565 if (data->entries[i]->flags & ENTRY_SELECTED)
2567 pos = i;
2568 found = TRUE;
2572 /* Return index of selected entry, or indicate there are no more */
2573 if (!found)
2574 pos = MUIV_List_NextSelected_End;
2575 *msg->pos = pos;
2577 return TRUE;
2580 /**************************************************************************
2581 Dispatcher
2582 **************************************************************************/
2583 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
2585 switch (msg->MethodID)
2587 case OM_NEW:
2588 return List__OM_NEW(cl, obj, (struct opSet *)msg);
2589 case OM_DISPOSE:
2590 return List__OM_DISPOSE(cl, obj, msg);
2591 case OM_SET:
2592 return List__OM_SET(cl, obj, (struct opSet *)msg);
2593 case OM_GET:
2594 return List__OM_GET(cl, obj, (struct opGet *)msg);
2596 case MUIM_Setup:
2597 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
2598 case MUIM_Cleanup:
2599 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
2600 case MUIM_AskMinMax:
2601 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
2602 case MUIM_Show:
2603 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
2604 case MUIM_Hide:
2605 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
2606 case MUIM_Draw:
2607 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
2608 case MUIM_Layout:
2609 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
2610 case MUIM_HandleEvent:
2611 return List__MUIM_HandleEvent(cl, obj,
2612 (struct MUIP_HandleEvent *)msg);
2613 case MUIM_List_Clear:
2614 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
2615 case MUIM_List_Sort:
2616 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
2617 case MUIM_List_Exchange:
2618 return List__MUIM_Exchange(cl, obj,
2619 (struct MUIP_List_Exchange *)msg);
2620 case MUIM_List_Insert:
2621 return List__MUIM_Insert(cl, obj, (APTR) msg);
2622 case MUIM_List_InsertSingle:
2623 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
2624 case MUIM_List_GetEntry:
2625 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
2626 case MUIM_List_Redraw:
2627 return List__MUIM_Redraw(cl, obj, (APTR) msg);
2628 case MUIM_List_Remove:
2629 return List__MUIM_Remove(cl, obj, (APTR) msg);
2630 case MUIM_List_Select:
2631 return List__MUIM_Select(cl, obj, (APTR) msg);
2632 case MUIM_List_Construct:
2633 return List__MUIM_Construct(cl, obj, (APTR) msg);
2634 case MUIM_List_Destruct:
2635 return List__MUIM_Destruct(cl, obj, (APTR) msg);
2636 case MUIM_List_Compare:
2637 return List__MUIM_Compare(cl, obj, (APTR) msg);
2638 case MUIM_List_Display:
2639 return List__MUIM_Display(cl, obj, (APTR) msg);
2640 case MUIM_List_SelectChange:
2641 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
2642 case MUIM_List_CreateImage:
2643 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
2644 case MUIM_List_DeleteImage:
2645 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
2646 case MUIM_List_Jump:
2647 return List__MUIM_Jump(cl, obj, (APTR) msg);
2648 case MUIM_List_Move:
2649 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
2650 case MUIM_List_NextSelected:
2651 return List__MUIM_NextSelected(cl, obj,
2652 (struct MUIP_List_NextSelected *)msg);
2655 return DoSuperMethodA(cl, obj, msg);
2657 BOOPSI_DISPATCHER_END
2660 * Class descriptor.
2662 const struct __MUIBuiltinClass _MUI_List_desc =
2664 MUIC_List,
2665 MUIC_Area,
2666 sizeof(struct MUI_ListData),
2667 (void *) List_Dispatcher