MUIM_List_InsertSingle: if there's no active entry,
[AROS.git] / workbench / libs / muimaster / classes / list.c
blobdda187dc1dd92825be4186108536fea443924b85
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 if (data->preparses)
320 FreeVec(data->preparses);
321 data->preparses = NULL;
323 if (data->strings)
325 FreeVec(data->strings - 1);
326 data->strings = NULL;
328 data->columns = 0;
331 /**************************************************************************
332 Parses the given format string (also frees a previouly parsed format).
333 Return 0 on failure.
334 **************************************************************************/
335 static int ParseListFormat(struct MUI_ListData *data, STRPTR format)
337 int new_columns, i;
338 STRPTR ptr;
339 STRPTR format_sep;
340 char c;
342 IPTR args[ARG_CNT];
343 struct RDArgs *rdargs;
345 if (!format)
346 format = (STRPTR) "";
348 ptr = format;
350 FreeListFormat(data);
352 new_columns = 1;
354 /* Count the number of columns first */
355 while ((c = *ptr++))
356 if (c == ',')
357 new_columns++;
359 if (!(data->preparses =
360 AllocVec((new_columns + 10) * sizeof(STRPTR), 0)))
361 return 0;
363 if (!(data->strings = AllocVec((new_columns + 1 + 10)
364 * sizeof(STRPTR), 0))) /* hold enough space also for the entry pos,
365 * used by orginal MUI and also some
366 * security space */
367 return 0;
369 if (!(data->ci = AllocVec(new_columns * sizeof(struct ColumnInfo), 0)))
370 return 0;
372 // set defaults
373 for (i = 0; i < new_columns; i++)
375 data->ci[i].colno = -1; // -1 means: use unassigned column
376 data->ci[i].weight = 100;
377 data->ci[i].delta = 4;
378 data->ci[i].min_width = -1;
379 data->ci[i].max_width = -1;
380 data->ci[i].user_width = -1;
381 data->ci[i].bar = FALSE;
382 data->ci[i].preparse = NULL;
385 if ((format_sep = StrDup(format)) != 0)
387 for (i = 0; format_sep[i] != '\0'; i++)
389 if (format_sep[i] == ',')
390 format_sep[i] = '\0';
393 if ((rdargs = AllocDosObject(DOS_RDARGS, NULL)) != 0)
395 ptr = format_sep;
396 i = 0;
399 rdargs->RDA_Source.CS_Buffer = ptr;
400 rdargs->RDA_Source.CS_Length = strlen(ptr);
401 rdargs->RDA_Source.CS_CurChr = 0;
402 rdargs->RDA_DAList = 0;
403 rdargs->RDA_Buffer = NULL;
404 rdargs->RDA_BufSiz = 0;
405 rdargs->RDA_ExtHelp = NULL;
406 rdargs->RDA_Flags = 0;
408 memset(args, 0, sizeof args);
409 if (ReadArgs(FORMAT_TEMPLATE, args, rdargs))
411 if (args[ARG_COL])
412 data->ci[i].colno = *(LONG *) args[ARG_COL];
413 if (args[ARG_WEIGHT])
414 data->ci[i].weight = *(LONG *) args[ARG_WEIGHT];
415 if (args[ARG_DELTA])
416 data->ci[i].delta = *(LONG *) args[ARG_DELTA];
417 if (args[ARG_MINWIDTH])
418 data->ci[i].min_width =
419 *(LONG *) args[ARG_MINWIDTH];
420 if (args[ARG_MAXWIDTH])
421 data->ci[i].max_width =
422 *(LONG *) args[ARG_MAXWIDTH];
423 data->ci[i].bar = args[ARG_BAR];
424 if (args[ARG_PREPARSE])
425 data->ci[i].preparse =
426 StrDup((STRPTR) args[ARG_PREPARSE]);
428 FreeArgs(rdargs);
430 ptr += strlen(ptr) + 1;
431 i++;
433 while (i < new_columns);
434 FreeDosObject(DOS_RDARGS, rdargs);
436 FreeVec(format_sep);
439 for (i = 0; i < new_columns; i++)
441 D(bug("colno %d weight %d delta %d preparse %s\n",
442 data->ci[i].colno, data->ci[i].weight, data->ci[i].delta,
443 data->ci[i].preparse));
446 data->columns = new_columns;
447 data->strings++; /* Skip entry pos */
449 return 1;
452 /**************************************************************************
453 Call the MUIM_List_Display for the given entry. It fills out
454 data->string and data->preparses
455 **************************************************************************/
456 static void DisplayEntry(struct IClass *cl, Object *obj, int entry_pos)
458 struct MUI_ListData *data = INST_DATA(cl, obj);
459 APTR entry_data;
460 int col;
462 for (col = 0; col < data->columns; col++)
463 data->preparses[col] = data->ci[col].preparse;
465 if (entry_pos == ENTRY_TITLE)
467 if ((data->columns == 1) && (data->title != (STRPTR) 1))
469 *data->strings = data->title;
470 return;
472 entry_data = NULL; /* it's a title request */
474 else
475 entry_data = data->entries[entry_pos]->data;
477 /* Get the display formation */
478 DoMethod(obj, MUIM_List_Display, (IPTR) entry_data,
479 (IPTR) data->strings, entry_pos, (IPTR) data->preparses);
482 /**************************************************************************
483 Determine the dims of a single entry and adapt the columinfo according
484 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
485 be redrawn after this operation, 1 if all entries need to be redrawn.
486 **************************************************************************/
487 static int CalcDimsOfEntry(struct IClass *cl, Object *obj, int pos)
489 struct MUI_ListData *data = INST_DATA(cl, obj);
490 struct ListEntry *entry = data->entries[pos];
491 int j;
492 int ret = 0;
494 if (!entry)
495 return ret;
497 if (!(_flags(obj) & MADF_SETUP))
498 return ret;
500 DisplayEntry(cl, obj, pos);
502 /* Set height to at least minheight */
503 if (data->entries[pos]->height < data->entry_minheight)
504 data->entries[pos]->height = data->entry_minheight;
506 for (j = 0; j < data->columns; j++)
508 ZText *text =
509 zune_text_new(data->preparses[j], data->strings[j],
510 ZTEXT_ARG_NONE, 0);
511 if (text != NULL)
513 zune_text_get_bounds(text, obj);
515 if (text->height > data->entries[pos]->height)
517 data->entries[pos]->height = text->height;
518 /* entry height changed, redraw all entries later */
519 ret = 1;
521 data->entries[pos]->widths[j] = text->width;
523 if (text->width > data->ci[j].entries_width)
525 /* This columns width is bigger than the other in the same
526 * columns, so we store this value
528 data->ci[j].entries_width = text->width;
529 /* column width changed, redraw all entries later */
530 ret = 1;
533 zune_text_destroy(text);
536 if (data->entries[pos]->height > data->entry_maxheight)
538 data->entry_maxheight = data->entries[pos]->height;
539 /* maximum entry height changed, redraw all entries later */
540 ret = 1;
543 return ret;
546 /**************************************************************************
547 Determine the widths of the entries
548 **************************************************************************/
549 static void CalcWidths(struct IClass *cl, Object *obj)
551 int i, j;
552 struct MUI_ListData *data = INST_DATA(cl, obj);
554 if (!(_flags(obj) & MADF_SETUP))
555 return;
557 for (j = 0; j < data->columns; j++)
558 data->ci[j].entries_width = 0;
560 data->entry_maxheight = 0;
561 data->entries_totalheight = 0;
562 data->entries_maxwidth = 0;
564 for (i = (data->title ? ENTRY_TITLE : 0); i < data->entries_num; i++)
566 CalcDimsOfEntry(cl, obj, i);
567 data->entries_totalheight += data->entries[i]->height;
570 for (j = 0; j < data->columns; j++)
571 data->entries_maxwidth += data->ci[j].entries_width;
573 if (!data->entry_maxheight)
574 data->entry_maxheight = 1;
577 /**************************************************************************
578 Calculates the number of visible entry lines. Returns 1 if it has
579 changed
580 **************************************************************************/
581 static int CalcVertVisible(struct IClass *cl, Object *obj)
583 struct MUI_ListData *data = INST_DATA(cl, obj);
584 int old_entries_visible = data->entries_visible;
585 int old_entries_top_pixel = data->entries_top_pixel;
587 data->entries_visible = (_mheight(obj) - data->title_height)
588 / (data->entry_maxheight /* + data->prefs_linespacing */ );
590 data->entries_top_pixel = _mtop(obj) + data->title_height
591 + (_mheight(obj) - data->title_height
593 data->entries_visible *
594 (data->entry_maxheight /* + data->prefs_linespacing */ )) / 2;
596 return (old_entries_visible != data->entries_visible)
597 || (old_entries_top_pixel != data->entries_top_pixel);
600 /**************************************************************************
601 Default hook to compare two list entries. Works for strings only.
602 **************************************************************************/
603 AROS_UFH3S(int, default_compare_func,
604 AROS_UFHA(struct Hook *, h, A0),
605 AROS_UFHA(char *, s2, A2),
606 AROS_UFHA(char *, s1, A1))
608 AROS_USERFUNC_INIT
610 return Stricmp(s1, s2);
612 AROS_USERFUNC_EXIT
615 /**************************************************************************
616 OM_NEW
617 **************************************************************************/
618 IPTR List__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
620 struct MUI_ListData *data;
621 struct TagItem *tag;
622 struct TagItem *tags;
623 APTR *array = NULL;
624 LONG new_entries_active = MUIV_List_Active_Off;
626 obj = (Object *) DoSuperNewTags(cl, obj, NULL,
627 MUIA_Font, MUIV_Font_List,
628 MUIA_Background, MUII_ListBack, TAG_MORE, (IPTR) msg->ops_AttrList);
629 if (!obj)
630 return FALSE;
632 data = INST_DATA(cl, obj);
634 data->columns = 1;
635 data->entries_active = MUIV_List_Active_Off;
636 data->intern_puddle_size = 2008;
637 data->intern_thresh_size = 1024;
638 data->input = 1;
639 data->default_compare_hook.h_Entry = (HOOKFUNC) default_compare_func;
640 data->default_compare_hook.h_SubEntry = 0;
641 data->compare_hook = &(data->default_compare_hook);
643 /* parse initial taglist */
644 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
646 switch (tag->ti_Tag)
648 case MUIA_List_Active:
649 new_entries_active = tag->ti_Data;
650 break;
652 case MUIA_List_Pool:
653 data->pool = (APTR) tag->ti_Data;
654 break;
656 case MUIA_List_PoolPuddleSize:
657 data->intern_puddle_size = tag->ti_Data;
658 break;
660 case MUIA_List_PoolThreshSize:
661 data->intern_thresh_size = tag->ti_Data;
662 break;
664 case MUIA_List_CompareHook:
665 /* Not tested, if List_CompareHook really works. */
666 data->compare_hook = (struct Hook *)tag->ti_Data;
667 break;
669 case MUIA_List_ConstructHook:
670 data->construct_hook = (struct Hook *)tag->ti_Data;
671 break;
673 case MUIA_List_DestructHook:
674 data->destruct_hook = (struct Hook *)tag->ti_Data;
675 break;
677 case MUIA_List_DisplayHook:
678 data->display_hook = (struct Hook *)tag->ti_Data;
679 break;
681 case MUIA_List_SourceArray:
682 array = (APTR *) tag->ti_Data;
683 break;
685 case MUIA_List_Format:
686 data->format = StrDup((STRPTR) tag->ti_Data);
687 break;
689 case MUIA_List_Title:
690 data->title = (STRPTR) tag->ti_Data;
691 break;
693 case MUIA_List_MinLineHeight:
694 data->entry_minheight = tag->ti_Data;
695 break;
697 case MUIA_List_AdjustHeight:
698 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTHEIGHT);
699 break;
701 case MUIA_List_AdjustWidth:
702 _handle_bool_tag(data->flags, tag->ti_Data, LIST_ADJUSTWIDTH);
703 break;
708 if (!data->pool)
710 /* No memory pool given, so we create our own */
711 data->pool = data->intern_pool =
712 CreatePool(0, data->intern_puddle_size,
713 data->intern_thresh_size);
714 if (!data->pool)
716 CoerceMethod(cl, obj, OM_DISPOSE);
717 return 0;
721 /* parse the list format */
722 if (!(ParseListFormat(data, data->format)))
724 CoerceMethod(cl, obj, OM_DISPOSE);
725 return 0;
728 /* This is neccessary for at least the title */
729 if (!SetListSize(data, 0))
731 CoerceMethod(cl, obj, OM_DISPOSE);
732 return 0;
735 if (data->title)
737 if (!(data->entries[ENTRY_TITLE] = AllocListEntry(data)))
739 CoerceMethod(cl, obj, OM_DISPOSE);
740 return 0;
743 else
744 data->entries[ENTRY_TITLE] = NULL;
747 if (array)
749 int i;
750 /* Count the number of elements */
751 for (i = 0; array[i] != NULL; i++)
753 /* Insert them */
754 DoMethod(obj, MUIM_List_Insert, (IPTR) array, i,
755 MUIV_List_Insert_Top);
759 if ((data->entries_num) && (new_entries_active != MUIV_List_Active_Off))
761 switch (new_entries_active)
763 case MUIV_List_Active_Top:
764 new_entries_active = 0;
765 break;
767 case MUIV_List_Active_Bottom:
768 new_entries_active = data->entries_num - 1;
769 break;
772 if (new_entries_active < 0)
773 new_entries_active = 0;
774 else if (new_entries_active >= data->entries_num)
775 new_entries_active = data->entries_num - 1;
777 data->entries_active = new_entries_active;
778 /* Selected entry will be moved into visible area */
782 data->ehn.ehn_Events = IDCMP_MOUSEBUTTONS |
783 IDCMP_RAWKEY | IDCMP_ACTIVEWINDOW | IDCMP_INACTIVEWINDOW;
784 data->ehn.ehn_Priority = 0;
785 data->ehn.ehn_Flags = 0;
786 data->ehn.ehn_Object = obj;
787 data->ehn.ehn_Class = cl;
789 NewList((struct List *)&data->images);
791 D(bug("List_New(%lx)\n", obj));
793 return (IPTR) obj;
796 /**************************************************************************
797 OM_DISPOSE
798 **************************************************************************/
799 IPTR List__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
801 struct MUI_ListData *data = INST_DATA(cl, obj);
803 D(bug("List Dispose\n"));
805 /* Call destruct method for every entry and free the entries manually
806 * to avoid notification */
807 while (data->confirm_entries_num)
809 struct ListEntry *lentry =
810 data->entries[--data->confirm_entries_num];
811 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
812 (IPTR) data->pool);
813 FreeListEntry(data, lentry);
816 if (data->intern_pool)
817 DeletePool(data->intern_pool);
818 if (data->entries)
819 FreeVec(data->entries - 1);
820 /* title is currently before all other elements */
822 FreeListFormat(data);
823 FreeVec(data->format);
825 return DoSuperMethodA(cl, obj, msg);
829 /**************************************************************************
830 OM_SET
831 **************************************************************************/
832 IPTR List__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
834 struct MUI_ListData *data = INST_DATA(cl, obj);
835 struct TagItem *tag;
836 struct TagItem *tags;
838 /* parse initial taglist */
839 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags));)
841 switch (tag->ti_Tag)
843 case MUIA_List_CompareHook:
844 data->compare_hook = (struct Hook *)tag->ti_Data;
845 break;
847 case MUIA_List_ConstructHook:
848 data->construct_hook = (struct Hook *)tag->ti_Data;
849 break;
851 case MUIA_List_DestructHook:
852 data->destruct_hook = (struct Hook *)tag->ti_Data;
853 break;
855 case MUIA_List_DisplayHook:
856 data->display_hook = (struct Hook *)tag->ti_Data;
857 break;
859 case MUIA_List_VertProp_First:
860 data->vertprop_first = tag->ti_Data;
861 if (data->entries_first != tag->ti_Data)
863 set(obj, MUIA_List_First, tag->ti_Data);
865 break;
867 case MUIA_List_Format:
868 data->format = StrDup((STRPTR) tag->ti_Data);
869 ParseListFormat(data, data->format);
870 // FIXME: should we check for errors?
871 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
872 break;
874 case MUIA_List_VertProp_Entries:
875 data->vertprop_entries = tag->ti_Data;
876 break;
878 case MUIA_List_VertProp_Visible:
879 data->vertprop_visible = tag->ti_Data;
880 data->entries_visible = tag->ti_Data;
881 break;
883 case MUIA_List_Active:
885 LONG new_entries_active = tag->ti_Data;
887 if ((data->entries_num)
888 && (new_entries_active != MUIV_List_Active_Off))
890 switch (new_entries_active)
892 case MUIV_List_Active_Top:
893 new_entries_active = 0;
894 break;
896 case MUIV_List_Active_Bottom:
897 new_entries_active = data->entries_num - 1;
898 break;
900 case MUIV_List_Active_Up:
901 new_entries_active = data->entries_active - 1;
902 break;
904 case MUIV_List_Active_Down:
905 new_entries_active = data->entries_active + 1;
906 break;
908 case MUIV_List_Active_PageUp:
909 new_entries_active =
910 data->entries_active - data->entries_visible;
911 break;
913 case MUIV_List_Active_PageDown:
914 new_entries_active =
915 data->entries_active + data->entries_visible;
916 break;
919 if (new_entries_active < 0)
920 new_entries_active = 0;
921 else if (new_entries_active >= data->entries_num)
922 new_entries_active = data->entries_num - 1;
924 else
925 new_entries_active = -1;
927 if (data->entries_active != new_entries_active)
929 LONG old = data->entries_active;
930 data->entries_active = new_entries_active;
932 data->update = 2;
933 data->update_pos = old;
934 MUI_Redraw(obj, MADF_DRAWUPDATE);
935 data->update = 2;
936 data->update_pos = data->entries_active;
937 MUI_Redraw(obj, MADF_DRAWUPDATE);
939 /* Selectchange stuff */
940 if (old != -1)
942 data->entries[old]->flags &= ~ENTRY_SELECTED;
943 DoMethod(obj, MUIM_List_SelectChange, old,
944 MUIV_List_Select_Off, 0);
947 if (new_entries_active != -1)
949 data->entries[new_entries_active]->flags |=
950 ENTRY_SELECTED;
951 DoMethod(obj, MUIM_List_SelectChange,
952 new_entries_active, MUIV_List_Select_On, 0);
953 DoMethod(obj, MUIM_List_SelectChange,
954 new_entries_active, MUIV_List_Select_Active, 0);
956 else
957 DoMethod(obj, MUIM_List_SelectChange,
958 MUIV_List_Active_Off, MUIV_List_Select_Off, 0);
960 set(obj, MUIA_Listview_SelectChange, TRUE);
962 if (new_entries_active != -1)
964 DoMethod(obj, MUIM_List_Jump,
965 MUIV_List_Jump_Active);
969 break;
971 case MUIA_List_First:
972 data->update_pos = data->entries_first;
973 data->update = 3;
974 data->entries_first = tag->ti_Data;
976 MUI_Redraw(obj, MADF_DRAWUPDATE);
977 if (data->vertprop_first != tag->ti_Data)
979 set(obj, MUIA_List_VertProp_First, tag->ti_Data);
981 break;
983 case MUIA_List_Visible:
984 if (data->vertprop_visible != tag->ti_Data)
985 set(obj, MUIA_List_VertProp_Visible, tag->ti_Data);
986 break;
988 case MUIA_List_Entries:
989 if (data->confirm_entries_num == tag->ti_Data)
991 data->entries_num = tag->ti_Data;
992 set(obj, MUIA_List_VertProp_Entries, data->entries_num);
994 else
996 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
998 break;
1000 case MUIA_List_Quiet:
1001 _handle_bool_tag(data->flags, tag->ti_Data, LIST_QUIET);
1002 if (!tag->ti_Data)
1004 DoMethod(obj, MUIM_List_Redraw, MUIV_List_Redraw_All);
1006 break;
1008 case MUIA_Listview_ClickColumn:
1009 data->click_column = tag->ti_Data;
1010 break;
1014 return DoSuperMethodA(cl, obj, (Msg) msg);
1017 /**************************************************************************
1018 OM_GET
1019 **************************************************************************/
1020 IPTR List__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
1022 /* small macro to simplify return value storage */
1023 #define STORE *(msg->opg_Storage)
1024 struct MUI_ListData *data = INST_DATA(cl, obj);
1026 switch (msg->opg_AttrID)
1028 case MUIA_List_Entries:
1029 STORE = data->entries_num;
1030 return 1;
1031 case MUIA_List_First:
1032 STORE = data->entries_first;
1033 return 1;
1034 case MUIA_List_Active:
1035 STORE = data->entries_active;
1036 return 1;
1037 case MUIA_List_InsertPosition:
1038 STORE = data->insert_position;
1039 return 1;
1040 case MUIA_List_Title:
1041 STORE = (unsigned long)data->title;
1042 return 1;
1043 case MUIA_List_VertProp_Entries:
1044 STORE = data->vertprop_entries;
1045 return 1;
1046 case MUIA_List_VertProp_Visible:
1047 STORE = data->vertprop_visible;
1048 return 1;
1049 case MUIA_List_VertProp_First:
1050 STORE = data->vertprop_first;
1051 return 1;
1052 case MUIA_List_Format:
1053 STORE = (IPTR) data->format;
1054 return 1;
1056 case MUIA_Listview_DoubleClick:
1057 STORE = 0;
1058 return 1;
1059 case MUIA_Listview_ClickColumn:
1060 STORE = data->click_column;
1061 return 1;
1062 case MUIA_Listview_List:
1063 STORE = (IPTR) obj;
1064 return 1; /* Validated with 3rd party application */
1067 if (DoSuperMethodA(cl, obj, (Msg) msg))
1068 return 1;
1069 return 0;
1070 #undef STORE
1073 /**************************************************************************
1074 MUIM_Setup
1075 **************************************************************************/
1076 IPTR List__MUIM_Setup(struct IClass *cl, Object *obj,
1077 struct MUIP_Setup *msg)
1079 struct MUI_ListData *data = INST_DATA(cl, obj);
1081 if (!DoSuperMethodA(cl, obj, (Msg) msg))
1082 return 0;
1084 data->prefs_multi = muiGlobalInfo(obj)->mgi_Prefs->list_multi;
1085 data->prefs_refresh = muiGlobalInfo(obj)->mgi_Prefs->list_refresh;
1086 data->prefs_linespacing =
1087 muiGlobalInfo(obj)->mgi_Prefs->list_linespacing;
1088 data->prefs_smoothed = muiGlobalInfo(obj)->mgi_Prefs->list_smoothed;
1089 data->prefs_smoothval = muiGlobalInfo(obj)->mgi_Prefs->list_smoothval;
1091 CalcWidths(cl, obj);
1093 if (data->title)
1095 data->title_height = data->entries[ENTRY_TITLE]->height + 2;
1097 else
1099 data->title_height = 0;
1102 DoMethod(_win(obj), MUIM_Window_AddEventHandler, (IPTR) & data->ehn);
1104 data->list_cursor =
1105 zune_imspec_setup(MUII_ListCursor, muiRenderInfo(obj));
1106 data->list_select =
1107 zune_imspec_setup(MUII_ListSelect, muiRenderInfo(obj));
1108 data->list_selcur =
1109 zune_imspec_setup(MUII_ListSelCur, muiRenderInfo(obj));
1111 return 1;
1114 /**************************************************************************
1115 MUIM_Cleanup
1116 **************************************************************************/
1117 IPTR List__MUIM_Cleanup(struct IClass *cl, Object *obj,
1118 struct MUIP_Cleanup *msg)
1120 struct MUI_ListData *data = INST_DATA(cl, obj);
1121 struct ListImage *li = List_First(&data->images);
1123 while (li)
1125 struct ListImage *next = Node_Next(li);
1126 DoMethod(obj, MUIM_List_DeleteImage, (IPTR) li);
1127 li = next;
1130 zune_imspec_cleanup(data->list_cursor);
1131 zune_imspec_cleanup(data->list_select);
1132 zune_imspec_cleanup(data->list_selcur);
1134 DoMethod(_win(obj), MUIM_Window_RemEventHandler, (IPTR) & data->ehn);
1135 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1136 data->mouse_click = 0;
1138 return DoSuperMethodA(cl, obj, (Msg) msg);
1141 /**************************************************************************
1142 MUIM_AskMinMax
1143 **************************************************************************/
1144 IPTR List__MUIM_AskMinMax(struct IClass *cl, Object *obj,
1145 struct MUIP_AskMinMax *msg)
1147 struct MUI_ListData *data = INST_DATA(cl, obj);
1149 DoSuperMethodA(cl, obj, (Msg) msg);
1152 if ((data->flags & LIST_ADJUSTWIDTH) && (data->entries_num > 0))
1154 msg->MinMaxInfo->MinWidth += data->entries_maxwidth;
1155 msg->MinMaxInfo->DefWidth += data->entries_maxwidth;
1156 msg->MinMaxInfo->MaxWidth += data->entries_maxwidth;
1158 else
1160 msg->MinMaxInfo->MinWidth += 40;
1161 msg->MinMaxInfo->DefWidth += 100;
1162 msg->MinMaxInfo->MaxWidth = MUI_MAXMAX;
1165 if (data->entries_num > 0)
1167 if (data->flags & LIST_ADJUSTHEIGHT)
1169 msg->MinMaxInfo->MinHeight += data->entries_totalheight;
1170 msg->MinMaxInfo->DefHeight += data->entries_totalheight;
1171 msg->MinMaxInfo->MaxHeight += data->entries_totalheight;
1173 else
1175 ULONG h = data->entry_maxheight + data->prefs_linespacing;
1176 msg->MinMaxInfo->MinHeight += 2 * h + data->prefs_linespacing;
1177 msg->MinMaxInfo->DefHeight += 8 * h + data->prefs_linespacing;
1178 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1181 else
1183 msg->MinMaxInfo->MinHeight += 36;
1184 msg->MinMaxInfo->DefHeight += 96;
1185 msg->MinMaxInfo->MaxHeight = MUI_MAXMAX;
1187 D(bug("List %p minheigh=%d, line maxh=%d\n",
1188 obj, msg->MinMaxInfo->MinHeight, data->entry_maxheight));
1189 return TRUE;
1192 /**************************************************************************
1193 MUIM_Layout
1194 **************************************************************************/
1195 IPTR List__MUIM_Layout(struct IClass *cl, Object *obj,
1196 struct MUIP_Layout *msg)
1198 struct MUI_ListData *data = INST_DATA(cl, obj);
1199 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1200 LONG new_entries_first = data->entries_first;
1202 /* Calc the numbers of entries visible */
1203 CalcVertVisible(cl, obj);
1205 #if 0 /* Don't do this! */
1206 if (data->entries_active < new_entries_first)
1207 new_entries_first = data->entries_active;
1208 #endif
1210 if (data->entries_active + 1 >=
1211 (data->entries_first + data->entries_visible))
1212 new_entries_first =
1213 data->entries_active - data->entries_visible + 1;
1215 if ((new_entries_first + data->entries_visible >=
1216 data->entries_num)
1217 && (data->entries_visible <= data->entries_num))
1218 new_entries_first = data->entries_num - data->entries_visible;
1220 if (data->entries_num <= data->entries_visible)
1221 new_entries_first = 0;
1223 if (new_entries_first < 0)
1224 new_entries_first = 0;
1226 set(obj, new_entries_first != data->entries_first ?
1227 MUIA_List_First : TAG_IGNORE, new_entries_first);
1229 /* So the notify takes happens */
1230 set(obj, MUIA_List_VertProp_Visible, data->entries_visible);
1232 return rc;
1236 /**************************************************************************
1237 MUIM_Show
1238 **************************************************************************/
1239 IPTR List__MUIM_Show(struct IClass *cl, Object *obj,
1240 struct MUIP_Show *msg)
1242 struct MUI_ListData *data = INST_DATA(cl, obj);
1243 ULONG rc = DoSuperMethodA(cl, obj, (Msg) msg);
1245 zune_imspec_show(data->list_cursor, obj);
1246 zune_imspec_show(data->list_select, obj);
1247 zune_imspec_show(data->list_selcur, obj);
1248 return rc;
1252 /**************************************************************************
1253 MUIM_Hide
1254 **************************************************************************/
1255 IPTR List__MUIM_Hide(struct IClass *cl, Object *obj,
1256 struct MUIP_Hide *msg)
1258 struct MUI_ListData *data = INST_DATA(cl, obj);
1260 #if 0
1261 if (data->ehn.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
1263 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1264 (IPTR) & data->ehn);
1265 data->ehn.ehn_Events &= ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1266 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1267 (IPTR) & data->ehn);
1269 data->mouse_click = 0;
1270 #endif
1272 zune_imspec_hide(data->list_cursor);
1273 zune_imspec_hide(data->list_select);
1274 zune_imspec_hide(data->list_selcur);
1276 return DoSuperMethodA(cl, obj, (Msg) msg);
1280 /**************************************************************************
1281 Draw an entry at entry_pos at the given y location. To draw the title,
1282 set pos to ENTRY_TITLE
1283 **************************************************************************/
1284 static VOID List_DrawEntry(struct IClass *cl, Object *obj, int entry_pos,
1285 int y)
1287 struct MUI_ListData *data = INST_DATA(cl, obj);
1288 int col, x1, x2;
1290 /* To be surem we don't draw anything if there is no title */
1291 if (entry_pos == ENTRY_TITLE && !data->title)
1292 return;
1294 DisplayEntry(cl, obj, entry_pos);
1295 x1 = _mleft(obj);
1297 for (col = 0; col < data->columns; col++)
1299 ZText *text;
1300 x2 = x1 + data->ci[col].entries_width;
1302 if ((text =
1303 zune_text_new(data->preparses[col], data->strings[col],
1304 ZTEXT_ARG_NONE, 0)))
1306 /* Could be made simpler, as we don't really need the bounds */
1307 zune_text_get_bounds(text, obj);
1308 /* Note, this was MPEN_SHADOW before */
1309 SetAPen(_rp(obj), muiRenderInfo(obj)->mri_Pens[MPEN_TEXT]);
1310 zune_text_draw(text, obj, x1, x2, y); /* totally wrong! */
1311 zune_text_destroy(text);
1313 x1 = x2 + data->ci[col].delta + (data->ci[col].bar ? BAR_WIDTH : 0);
1317 /**************************************************************************
1318 MUIM_Draw
1319 **************************************************************************/
1320 IPTR List__MUIM_Draw(struct IClass *cl, Object *obj, struct MUIP_Draw *msg)
1322 struct MUI_ListData *data = INST_DATA(cl, obj);
1323 int entry_pos, y;
1324 APTR clip;
1325 int start, end;
1326 BOOL scroll_caused_damage = FALSE;
1328 DoSuperMethodA(cl, obj, (Msg) msg);
1330 if (msg->flags & MADF_DRAWUPDATE)
1332 if (data->update == 1)
1333 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1334 _mwidth(obj), _mheight(obj),
1335 0, data->entries_first * data->entry_maxheight, 0);
1337 else
1339 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), _mtop(obj),
1340 _mwidth(obj), _mheight(obj),
1341 0, data->entries_first * data->entry_maxheight, 0);
1344 clip = MUI_AddClipping(muiRenderInfo(obj), _mleft(obj), _mtop(obj),
1345 _mwidth(obj), _mheight(obj));
1347 if (!(msg->flags & MADF_DRAWUPDATE)
1348 || ((msg->flags & MADF_DRAWUPDATE) && data->update == 1))
1350 y = _mtop(obj);
1351 /* Draw Title
1353 if (data->title_height && data->title)
1355 List_DrawEntry(cl, obj, ENTRY_TITLE, y);
1356 y += data->entries[ENTRY_TITLE]->height;
1357 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1358 Move(_rp(obj), _mleft(obj), y);
1359 Draw(_rp(obj), _mright(obj), y);
1360 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1361 y++;
1362 Move(_rp(obj), _mleft(obj), y);
1363 Draw(_rp(obj), _mright(obj), y);
1367 y = data->entries_top_pixel;
1369 start = data->entries_first;
1370 end = data->entries_first + data->entries_visible;
1372 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3)
1374 int diffy = data->entries_first - data->update_pos;
1375 int top, bottom;
1376 if (abs(diffy) < data->entries_visible)
1378 scroll_caused_damage =
1379 (_rp(obj)->Layer->Flags & LAYERREFRESH) ? FALSE : TRUE;
1381 ScrollRaster(_rp(obj), 0, diffy * data->entry_maxheight,
1382 _mleft(obj), y,
1383 _mright(obj),
1384 y + data->entry_maxheight * data->entries_visible);
1386 scroll_caused_damage =
1387 scroll_caused_damage
1388 && (_rp(obj)->Layer->Flags & LAYERREFRESH);
1390 if (diffy > 0)
1392 start = end - diffy;
1393 y += data->entry_maxheight * (data->entries_visible -
1394 diffy);
1396 else
1397 end = start - diffy;
1400 top = y;
1401 bottom = y + (end - start) * data->entry_maxheight;
1403 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), top,
1404 _mwidth(obj), bottom - top + 1,
1406 top - _mtop(obj) + data->entries_first * data->entry_maxheight,
1410 for (entry_pos = start;
1411 entry_pos < end && entry_pos < data->entries_num; entry_pos++)
1413 //struct ListEntry *entry = data->entries[entry_pos];
1415 if (!(msg->flags & MADF_DRAWUPDATE) ||
1416 ((msg->flags & MADF_DRAWUPDATE) && data->update == 1) ||
1417 ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) ||
1418 ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1419 && data->update_pos == entry_pos))
1421 if (entry_pos == data->entries_active)
1423 zune_imspec_draw(data->list_cursor, muiRenderInfo(obj),
1424 _mleft(obj), y, _mwidth(obj), data->entry_maxheight,
1425 0, y - data->entries_top_pixel, 0);
1427 else
1429 if ((msg->flags & MADF_DRAWUPDATE) && data->update == 2
1430 && data->update_pos == entry_pos)
1432 DoMethod(obj, MUIM_DrawBackground, _mleft(obj), y,
1433 _mwidth(obj), data->entry_maxheight, 0,
1434 y - _mtop(obj) +
1435 data->entries_first * data->entry_maxheight, 0);
1438 List_DrawEntry(cl, obj, entry_pos, y);
1440 y += data->entry_maxheight;
1441 } /* for */
1443 MUI_RemoveClipping(muiRenderInfo(obj), clip);
1445 data->update = 0;
1447 if (scroll_caused_damage)
1449 if (MUI_BeginRefresh(muiRenderInfo(obj), 0))
1451 /* Theoretically it might happen that more damage is caused
1452 after ScrollRaster. By something else, like window movement
1453 in front of our window. Therefore refresh root object of
1454 window, not just this object */
1456 Object *o = NULL;
1458 get(_win(obj), MUIA_Window_RootObject, &o);
1459 MUI_Redraw(o, MADF_DRAWOBJECT);
1461 MUI_EndRefresh(muiRenderInfo(obj), 0);
1465 ULONG x1 = _mleft(obj);
1466 ULONG col;
1467 y = _mtop(obj);
1469 if (data->title_height && data->title)
1471 for (col = 0; col < data->columns; col++)
1473 ULONG halfdelta = data->ci[col].delta / 2;
1474 x1 += data->ci[col].entries_width + halfdelta;
1476 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(obj))
1477 break;
1479 if (data->ci[col].bar)
1481 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1482 Move(_rp(obj), x1, y);
1483 Draw(_rp(obj), x1,
1484 y + data->entries[ENTRY_TITLE]->height - 1);
1485 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1486 Move(_rp(obj), x1 + 1, y);
1487 Draw(_rp(obj), x1 + 1,
1488 y + data->entries[ENTRY_TITLE]->height - 1);
1490 x1 += BAR_WIDTH;
1492 x1 += data->ci[col].delta - halfdelta;
1494 y += data->entries[ENTRY_TITLE]->height + 1;
1497 x1 = _mleft(obj);
1499 for (col = 0; col < data->columns; col++)
1501 ULONG halfdelta = data->ci[col].delta / 2;
1502 x1 += data->ci[col].entries_width + halfdelta;
1504 if (x1 + (data->ci[col].bar ? BAR_WIDTH : 0) > _mright(obj))
1505 break;
1507 if (data->ci[col].bar)
1509 SetAPen(_rp(obj), _pens(obj)[MPEN_SHINE]);
1510 Move(_rp(obj), x1, y);
1511 Draw(_rp(obj), x1, _mbottom(obj));
1512 SetAPen(_rp(obj), _pens(obj)[MPEN_SHADOW]);
1513 Move(_rp(obj), x1 + 1, y);
1514 Draw(_rp(obj), x1 + 1, _mbottom(obj));
1516 x1 += BAR_WIDTH;
1519 x1 += data->ci[col].delta - halfdelta;
1522 return 0;
1525 /**************************************************************************
1526 Makes the entry at the given mouse position the active one.
1527 Relx and Rely are relative mouse coordinates to the upper left of
1528 the object
1529 **************************************************************************/
1530 static VOID List_MakeActive(struct IClass *cl, Object *obj, LONG relx,
1531 LONG rely)
1533 struct MUI_ListData *data = INST_DATA(cl, obj);
1535 if (data->entries_num == 0)
1536 return;
1538 LONG eclicky = rely + _top(obj) - data->entries_top_pixel;
1539 /* y coordinates transformed to the entries */
1540 LONG new_act = eclicky / data->entry_maxheight + data->entries_first;
1541 LONG old_act = data->entries_active;
1543 if (eclicky < 0)
1545 new_act = data->entries_first - 1;
1547 else if (new_act > data->entries_first + data->entries_visible)
1549 new_act = data->entries_first + data->entries_visible;
1552 if (new_act >= data->entries_num)
1553 new_act = data->entries_num - 1;
1554 else if (new_act < 0)
1555 new_act = 0;
1557 /* Notify only when active entry has changed */
1558 if (old_act != new_act)
1559 set(obj, MUIA_List_Active, new_act);
1562 static void DoWheelMove(struct IClass *cl, Object *obj, LONG wheely,
1563 UWORD qual)
1565 struct MUI_ListData *data = INST_DATA(cl, obj);
1566 LONG new = data->entries_first;
1568 if (qual & IEQUALIFIER_CONTROL)
1570 if (wheely < 0)
1571 new = 0;
1572 if (wheely > 0)
1573 new = data->entries_num;
1575 else if (qual & (IEQUALIFIER_LSHIFT | IEQUALIFIER_RSHIFT))
1577 new += (wheely * data->entries_visible);
1579 else
1581 new += wheely * 3;
1584 if (new > data->entries_num - data->entries_visible)
1586 new = data->entries_num - data->entries_visible;
1589 if (new < 0)
1591 new = 0;
1594 if (new != data->entries_first)
1596 set(obj, MUIA_List_First, new);
1601 /**************************************************************************
1602 MUIM_HandleEvent
1603 **************************************************************************/
1604 IPTR List__MUIM_HandleEvent(struct IClass *cl, Object *obj,
1605 struct MUIP_HandleEvent *msg)
1607 struct MUI_ListData *data = INST_DATA(cl, obj);
1609 if (msg->imsg)
1611 LONG mx = msg->imsg->MouseX - _left(obj);
1612 LONG my = msg->imsg->MouseY - _top(obj);
1613 switch (msg->imsg->Class)
1615 case IDCMP_MOUSEBUTTONS:
1616 if (msg->imsg->Code == SELECTDOWN)
1618 if (mx >= 0 && mx < _width(obj) && my >= 0
1619 && my < _height(obj))
1621 LONG eclicky = my + _top(obj) - data->entries_top_pixel;
1622 /* y coordinates transformed to the entries */
1623 data->mouse_click = MOUSE_CLICK_ENTRY;
1625 /* Now check if it was clicked on a title or on entries */
1626 if (eclicky >= 0
1627 && eclicky <
1628 data->entries_visible * data->entry_maxheight)
1630 List_MakeActive(cl, obj, mx, my);
1631 /* sets data->entries_active */
1633 if (data->last_active == data->entries_active
1634 && DoubleClick(data->last_secs, data->last_mics,
1635 msg->imsg->Seconds, msg->imsg->Micros))
1637 /* Handle MUIA_ListView_ClickColumn */
1638 data->click_column = 0;
1639 if (data->entries_num > 0 && data->columns > 0)
1641 LONG width_sum = 0;
1642 LONG col;
1643 for (col = 0; col < data->columns; col++)
1645 width_sum +=
1646 data->ci[col].entries_width +
1647 data->ci[col].delta +
1648 (data->ci[col].bar ? BAR_WIDTH : 0);
1649 D(bug
1650 ("[List/MUIM_HandleEvent] col %d "
1651 "width %d width_sum %d mx %d\n",
1652 col,
1653 data->ci[col].entries_width,
1654 width_sum, mx));
1655 if (mx < width_sum)
1657 D(bug
1658 ("[List/MUIM_HandleEvent] "
1659 "Column hit %d\n",
1660 col));
1661 set(obj, MUIA_Listview_ClickColumn,
1662 col);
1663 break;
1668 set(obj, MUIA_Listview_DoubleClick, TRUE);
1669 data->last_active = -1;
1670 data->last_secs = data->last_mics = 0;
1672 else
1674 data->last_active = data->entries_active;
1675 data->last_secs = msg->imsg->Seconds;
1676 data->last_mics = msg->imsg->Micros;
1680 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1681 (IPTR) & data->ehn);
1682 data->ehn.ehn_Events |=
1683 (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1684 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1685 (IPTR) & data->ehn);
1687 return MUI_EventHandlerRC_Eat;
1690 else
1692 if (msg->imsg->Code == SELECTUP && data->mouse_click)
1694 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1695 (IPTR) & data->ehn);
1696 data->ehn.ehn_Events &=
1697 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1698 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1699 (IPTR) & data->ehn);
1700 data->mouse_click = 0;
1701 return 0;
1704 break;
1706 case IDCMP_INTUITICKS:
1707 case IDCMP_MOUSEMOVE:
1708 if (data->mouse_click)
1710 List_MakeActive(cl, obj, mx, my);
1712 break;
1714 case IDCMP_RAWKEY:
1715 switch (msg->imsg->Code)
1717 case RAWKEY_NM_WHEEL_UP:
1718 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
1720 DoWheelMove(cl, obj, -1, msg->imsg->Qualifier);
1722 break;
1724 case RAWKEY_NM_WHEEL_DOWN:
1725 if (_isinobject(msg->imsg->MouseX, msg->imsg->MouseY))
1727 DoWheelMove(cl, obj, 1, msg->imsg->Qualifier);
1729 break;
1732 break;
1734 case IDCMP_ACTIVEWINDOW:
1735 case IDCMP_INACTIVEWINDOW:
1736 if (data->ehn.ehn_Events & (IDCMP_MOUSEMOVE | IDCMP_INTUITICKS))
1738 DoMethod(_win(obj), MUIM_Window_RemEventHandler,
1739 (IPTR) & data->ehn);
1740 data->ehn.ehn_Events &=
1741 ~(IDCMP_MOUSEMOVE | IDCMP_INTUITICKS);
1742 DoMethod(_win(obj), MUIM_Window_AddEventHandler,
1743 (IPTR) & data->ehn);
1744 data->mouse_click = 0;
1746 break;
1750 return 0;
1753 /**************************************************************************
1754 MUIM_List_Clear
1755 **************************************************************************/
1756 IPTR List__MUIM_Clear(struct IClass *cl, Object *obj,
1757 struct MUIP_List_Clear *msg)
1759 struct MUI_ListData *data = INST_DATA(cl, obj);
1761 while (data->confirm_entries_num)
1763 struct ListEntry *lentry =
1764 data->entries[--data->confirm_entries_num];
1765 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1766 (IPTR) data->pool);
1767 FreeListEntry(data, lentry);
1769 /* Should never fail when shrinking */
1770 SetListSize(data, 0);
1772 if (data->confirm_entries_num != data->entries_num)
1774 SetAttrs(obj, MUIA_List_Entries, 0, MUIA_List_First, 0,
1775 /* Notify only when no entry was active */
1776 data->entries_active !=
1777 MUIV_List_Active_Off ? MUIA_List_Active : TAG_DONE,
1778 MUIV_List_Active_Off, TAG_DONE);
1780 data->update = 1;
1781 MUI_Redraw(obj, MADF_DRAWUPDATE);
1784 return 0;
1787 /**************************************************************************
1788 MUIM_List_Exchange
1789 **************************************************************************/
1790 IPTR List__MUIM_Exchange(struct IClass *cl, Object *obj,
1791 struct MUIP_List_Exchange *msg)
1793 struct MUI_ListData *data = INST_DATA(cl, obj);
1794 LONG pos1, pos2;
1796 switch (msg->pos1)
1798 case MUIV_List_Exchange_Top:
1799 pos1 = 0;
1800 break;
1801 case MUIV_List_Exchange_Active:
1802 pos1 = data->entries_active;
1803 break;
1804 case MUIV_List_Exchange_Bottom:
1805 pos1 = data->entries_num - 1;
1806 break;
1807 default:
1808 pos1 = msg->pos1;
1811 switch (msg->pos2)
1813 case MUIV_List_Exchange_Top:
1814 pos2 = 0;
1815 break;
1816 case MUIV_List_Exchange_Active:
1817 pos2 = data->entries_active;
1818 break;
1819 case MUIV_List_Exchange_Bottom:
1820 pos2 = data->entries_num - 1;
1821 break;
1822 case MUIV_List_Exchange_Next:
1823 pos2 = pos1 + 1;
1824 break;
1825 case MUIV_List_Exchange_Previous:
1826 pos2 = pos1 - 1;
1827 break;
1828 default:
1829 pos2 = msg->pos2;
1832 if (pos1 >= 0 && pos1 < data->entries_num && pos2 >= 0
1833 && pos2 < data->entries_num && pos1 != pos2)
1835 struct ListEntry *save = data->entries[pos1];
1836 data->entries[pos1] = data->entries[pos2];
1837 data->entries[pos2] = save;
1839 data->update = 2;
1840 data->update_pos = pos1;
1841 MUI_Redraw(obj, MADF_DRAWUPDATE);
1843 data->update = 2;
1844 data->update_pos = pos2;
1845 MUI_Redraw(obj, MADF_DRAWUPDATE);
1847 return TRUE;
1849 else
1851 return FALSE;
1855 /**************************************************************************
1856 MUIM_List_Redraw
1857 **************************************************************************/
1858 IPTR List__MUIM_Redraw(struct IClass *cl, Object *obj,
1859 struct MUIP_List_Redraw *msg)
1861 struct MUI_ListData *data = INST_DATA(cl, obj);
1863 if (msg->pos == MUIV_List_Redraw_All)
1865 data->update = 1;
1866 CalcWidths(cl, obj);
1867 MUI_Redraw(obj, MADF_DRAWUPDATE);
1869 else
1871 LONG pos = -1;
1872 if (msg->pos == MUIV_List_Redraw_Active)
1873 pos = data->entries_active;
1874 else if (msg->pos == MUIV_List_Redraw_Entry)
1876 LONG i;
1877 for (i = 0; i < data->entries_num; i++)
1878 if (data->entries[i]->data == msg->entry)
1880 pos = i;
1881 break;
1884 else
1885 pos = msg->pos;
1887 if (pos != -1)
1889 if (CalcDimsOfEntry(cl, obj, pos))
1890 data->update = 1;
1891 else
1893 data->update = 2;
1894 data->update_pos = pos;
1896 MUI_Redraw(obj, MADF_DRAWUPDATE);
1899 return 0;
1902 /**************************************************************************
1903 MUIM_List_Remove
1904 **************************************************************************/
1905 IPTR List__MUIM_Remove(struct IClass *cl, Object *obj,
1906 struct MUIP_List_Remove *msg)
1908 struct MUI_ListData *data = INST_DATA(cl, obj);
1909 LONG pos, cur;
1910 LONG new_act;
1911 struct ListEntry *lentry;
1912 //int rem_count = 1;
1914 if (!data->entries_num)
1915 return 0;
1917 switch (msg->pos)
1919 case MUIV_List_Remove_First:
1920 pos = 0;
1921 break;
1923 case MUIV_List_Remove_Active:
1924 pos = data->entries_active;
1925 break;
1927 case MUIV_List_Remove_Last:
1928 pos = data->entries_num - 1;
1929 break;
1931 case MUIV_List_Remove_Selected:
1932 /* TODO: needs special handling */
1933 pos = data->entries_active;
1934 break;
1936 default:
1937 pos = msg->pos;
1938 break;
1941 if (pos < 0 || pos >= data->entries_num)
1942 return 0;
1944 new_act = data->entries_active;
1946 if (pos == new_act && new_act == data->entries_num - 1)
1947 new_act--; /* might become MUIV_List_Active_Off */
1949 lentry = data->entries[pos];
1950 DoMethod(obj, MUIM_List_Destruct, (IPTR) lentry->data,
1951 (IPTR) data->pool);
1953 cur = pos + 1;
1955 RemoveListEntries(data, pos, cur - pos);
1956 data->confirm_entries_num -= cur - pos;
1958 /* ensure that the active element is in a valid range */
1959 if (new_act >= data->entries_num)
1960 new_act = data->entries_num - 1;
1962 SetAttrs(obj, MUIA_List_Entries, data->confirm_entries_num,
1963 (new_act >= pos) || (new_act != data->entries_active) ?
1964 MUIA_List_Active : TAG_DONE,
1965 new_act, /* Inform only if neccessary (for notify) */
1966 TAG_DONE);
1968 data->update = 1;
1969 MUI_Redraw(obj, MADF_DRAWUPDATE);
1971 return 0;
1974 /**************************************************************************
1975 MUIM_List_Select
1976 **************************************************************************/
1977 IPTR List__MUIM_Select(struct IClass *cl, Object *obj,
1978 struct MUIP_List_Select *msg)
1980 struct MUI_ListData *data = INST_DATA(cl, obj);
1981 LONG pos,i,count,selcount=0,state=0;
1983 /* Establish the range of entries affected */
1984 switch (msg->pos)
1986 case MUIV_List_Select_Active:
1987 pos = data->entries_active;
1988 if (pos == MUIV_List_Active_Off)
1989 count = 0;
1990 else
1991 count = 1;
1992 break;
1994 case MUIV_List_Select_All:
1995 pos = 0;
1996 count = data->entries_num;
1997 break;
1999 default:
2000 pos = msg->pos;
2001 count = 1;
2002 if (pos < 0 || pos >= data->entries_num)
2003 return 0;
2004 break;
2007 /* Change or check state of each entry in the range */
2008 for (i = pos; i < pos + count; i++)
2010 state = data->entries[i]->flags & ENTRY_SELECTED;
2011 switch (msg->seltype)
2013 case MUIV_List_Select_Off:
2014 data->entries[i]->flags &= ~ENTRY_SELECTED;
2015 break;
2017 case MUIV_List_Select_On:
2018 data->entries[i]->flags |= ENTRY_SELECTED;
2019 break;
2021 case MUIV_List_Select_Toggle:
2022 data->entries[i]->flags ^= ENTRY_SELECTED;
2023 break;
2025 default:
2026 if (data->entries[i]->flags & ENTRY_SELECTED)
2027 selcount++;
2028 break;
2032 /* Report old state or number of selected entries */
2033 if (msg->info)
2035 if (msg->pos == MUIV_List_Select_All
2036 && msg->seltype == MUIV_List_Select_Ask)
2037 *msg->info = selcount;
2038 else
2039 *msg->info = state;
2042 /* Redraw unless it was just an enquiry */
2043 if (msg->seltype != MUIV_List_Select_Ask)
2045 data->update = 1;
2046 MUI_Redraw(obj,MADF_DRAWUPDATE);
2049 return 0;
2052 /**************************************************************************
2053 MUIM_List_Insert
2054 **************************************************************************/
2056 IPTR List__MUIM_Insert(struct IClass *cl, Object *obj,
2057 struct MUIP_List_Insert *msg)
2059 struct MUI_ListData *data = INST_DATA(cl, obj);
2060 LONG pos, count, sort;
2062 count = msg->count;
2063 sort = 0;
2065 if (count == -1)
2067 /* Count the number of entries */
2068 for (count = 0; msg->entries[count] != NULL; count++)
2072 if (count <= 0)
2073 return ~0;
2075 switch (msg->pos)
2077 case MUIV_List_Insert_Top:
2078 pos = 0;
2079 break;
2081 case MUIV_List_Insert_Active:
2082 if (data->entries_active != -1)
2083 pos = data->entries_active;
2084 else
2085 pos = 0;
2086 break;
2088 case MUIV_List_Insert_Sorted:
2089 pos = data->entries_num;
2090 sort = 1; /* we sort'em later */
2091 break;
2093 case MUIV_List_Insert_Bottom:
2094 pos = data->entries_num;
2095 break;
2097 default:
2098 if (msg->pos > data->entries_num)
2099 pos = data->entries_num;
2100 else if (msg->pos < 0)
2101 pos = 0;
2102 else
2103 pos = msg->pos;
2104 break;
2107 if (!(SetListSize(data, data->entries_num + count)))
2108 return ~0;
2110 LONG until = pos + count;
2111 APTR *toinsert = msg->entries;
2113 if (!(PrepareInsertListEntries(data, pos, count)))
2114 return ~0;
2116 while (pos < until)
2118 struct ListEntry *lentry;
2120 if (!(lentry = AllocListEntry(data)))
2122 /* Panic, but we must be in a consistent state, so remove
2123 ** the space where the following list entries should have gone
2125 RemoveListEntries(data, pos, until - pos);
2126 return ~0;
2129 /* now call the construct method which returns us a pointer which
2130 we need to store */
2131 lentry->data = (APTR) DoMethod(obj, MUIM_List_Construct,
2132 (IPTR) * toinsert, (IPTR) data->pool);
2133 if (!lentry->data)
2135 FreeListEntry(data, lentry);
2136 RemoveListEntries(data, pos, until - pos);
2138 /* TODO: Also check for visible stuff like below */
2139 if (data->entries_num != data->confirm_entries_num)
2140 set(obj, MUIA_List_Entries, data->confirm_entries_num);
2141 return ~0;
2144 data->entries[pos] = lentry;
2145 data->confirm_entries_num++;
2147 if (_flags(obj) & MADF_SETUP)
2149 /* We have to calculate the width and height of the newly
2150 * inserted entry. This has to be done after inserting the
2151 * element into the list */
2152 CalcDimsOfEntry(cl, obj, pos);
2155 toinsert++;
2156 pos++;
2157 } // while (pos < until)
2160 /* Recalculate the number of visible entries */
2161 if (_flags(obj) & MADF_SETUP)
2162 CalcVertVisible(cl, obj);
2164 if (data->entries_num != data->confirm_entries_num)
2166 SetAttrs(obj,
2167 MUIA_List_Entries, data->confirm_entries_num,
2168 MUIA_List_Visible, data->entries_visible, TAG_DONE);
2171 /* If the array is already sorted, we could do a simple insert
2172 * sort and would be much faster than with qsort.
2173 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2174 * sort the whole array?
2176 * I think, we better sort the whole array:
2178 if (sort)
2180 DoMethod(obj, MUIM_List_Sort);
2181 /* TODO: which pos to return here !? */
2182 /* MUIM_List_Sort already called MUI_Redraw */
2184 else
2186 if (!(data->flags & LIST_QUIET))
2188 data->update = 1;
2189 MUI_Redraw(obj, MADF_DRAWUPDATE);
2192 data->insert_position = pos;
2194 return (ULONG) pos;
2197 /**************************************************************************
2198 MUIM_List_InsertSingle
2199 **************************************************************************/
2200 IPTR List__MUIM_InsertSingle(struct IClass *cl, Object *obj,
2201 struct MUIP_List_InsertSingle *msg)
2203 return DoMethod(obj, MUIM_List_Insert, (IPTR) & msg->entry, 1,
2204 msg->pos);
2207 /**************************************************************************
2208 MUIM_List_GetEntry
2209 **************************************************************************/
2210 IPTR List__MUIM_GetEntry(struct IClass *cl, Object *obj,
2211 struct MUIP_List_GetEntry *msg)
2213 struct MUI_ListData *data = INST_DATA(cl, obj);
2214 int pos = msg->pos;
2216 if (pos == MUIV_List_GetEntry_Active)
2217 pos = data->entries_active;
2219 if (pos < 0 || pos >= data->entries_num)
2221 *msg->entry = NULL;
2222 return 0;
2224 *msg->entry = data->entries[pos]->data;
2225 return (IPTR) *msg->entry;
2228 /**************************************************************************
2229 MUIM_List_Construct
2230 **************************************************************************/
2231 IPTR List__MUIM_Construct(struct IClass *cl, Object *obj,
2232 struct MUIP_List_Construct *msg)
2234 struct MUI_ListData *data = INST_DATA(cl, obj);
2236 if (NULL == data->construct_hook)
2237 return (IPTR) msg->entry;
2238 if ((IPTR) data->construct_hook == MUIV_List_ConstructHook_String)
2240 int len = msg->entry ? strlen((STRPTR) msg->entry) : 0;
2241 ULONG *mem = AllocPooled(msg->pool, len + 5);
2243 if (NULL == mem)
2244 return 0;
2245 mem[0] = len + 5;
2246 if (msg->entry != NULL)
2247 strcpy((STRPTR) (mem + 1), (STRPTR) msg->entry);
2248 else
2249 *(STRPTR) (mem + 1) = 0;
2250 return (IPTR) (mem + 1);
2252 return CallHookPkt(data->construct_hook, msg->pool, msg->entry);
2255 /**************************************************************************
2256 MUIM_List_Destruct
2257 **************************************************************************/
2258 IPTR List__MUIM_Destruct(struct IClass *cl, Object *obj,
2259 struct MUIP_List_Destruct *msg)
2261 struct MUI_ListData *data = INST_DATA(cl, obj);
2263 if (NULL == data->destruct_hook)
2264 return 0;
2266 if ((IPTR) data->destruct_hook == MUIV_List_DestructHook_String)
2268 ULONG *mem = ((ULONG *) msg->entry) - 1;
2269 FreePooled(msg->pool, mem, mem[0]);
2271 else
2273 CallHookPkt(data->destruct_hook, msg->pool, msg->entry);
2275 return 0;
2278 /**************************************************************************
2279 MUIM_List_Compare
2280 **************************************************************************/
2281 IPTR List__MUIM_Compare(struct IClass *cl, Object *obj,
2282 struct MUIP_List_Compare *msg)
2284 struct MUI_ListData *data = INST_DATA(cl, obj);
2286 return CallHookPkt(data->compare_hook, msg->entry2, msg->entry1);
2289 /**************************************************************************
2290 MUIM_List_Display
2291 **************************************************************************/
2292 IPTR List__MUIM_Display(struct IClass *cl, Object *obj,
2293 struct MUIP_List_Display *msg)
2295 struct MUI_ListData *data = INST_DATA(cl, obj);
2297 if (NULL == data->display_hook)
2299 if (msg->entry)
2300 *msg->array = msg->entry;
2301 else
2302 *msg->array = 0;
2303 return 1;
2306 *((ULONG *) (msg->array - 1)) = msg->entry_pos;
2307 return CallHookPkt(data->display_hook, msg->array, msg->entry);
2310 /**************************************************************************
2311 MUIM_List_SelectChange
2312 **************************************************************************/
2313 IPTR List__MUIM_SelectChange(struct IClass *cl, Object *obj,
2314 struct MUIP_List_SelectChange *msg)
2316 return 1;
2319 /**************************************************************************
2320 MUIM_List_CreateImage
2321 Called by a List subclass in its Setup method.
2322 Connects an Area subclass object to the list, much like an object gets
2323 connected to a window. List call Setup and AskMinMax on that object,
2324 keeps a reference to it (that reference will be returned).
2325 Text engine will dereference that pointer and draw the object with its
2326 default size.
2327 **************************************************************************/
2328 IPTR List__MUIM_CreateImage(struct IClass *cl, Object *obj,
2329 struct MUIP_List_CreateImage *msg)
2331 struct MUI_ListData *data = INST_DATA(cl, obj);
2332 struct ListImage *li;
2334 /* List must be already setup in Setup of your subclass */
2335 if (!(_flags(obj) & MADF_SETUP))
2336 return 0;
2337 li = AllocPooled(data->pool, sizeof(struct ListImage));
2338 if (!li)
2339 return 0;
2340 li->obj = msg->obj;
2342 AddTail((struct List *)&data->images, (struct Node *)li);
2343 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
2344 DoSetupMethod(li->obj, muiRenderInfo(obj));
2347 return (IPTR) li;
2350 /**************************************************************************
2351 MUIM_List_DeleteImage
2352 **************************************************************************/
2353 IPTR List__MUIM_DeleteImage(struct IClass *cl, Object *obj,
2354 struct MUIP_List_DeleteImage *msg)
2356 struct MUI_ListData *data = INST_DATA(cl, obj);
2357 struct ListImage *li = (struct ListImage *)msg->listimg;
2359 if (li)
2361 DoMethod(li->obj, MUIM_Cleanup);
2362 DoMethod(li->obj, MUIM_DisconnectParent);
2363 Remove((struct Node *)li);
2364 FreePooled(data->pool, li, sizeof(struct ListImage));
2367 return 0;
2370 /**************************************************************************
2371 MUIM_List_Jump
2372 **************************************************************************/
2373 IPTR List__MUIM_Jump(struct IClass *cl, Object *obj,
2374 struct MUIP_List_Jump *msg)
2376 struct MUI_ListData *data = INST_DATA(cl, obj);
2377 LONG pos = msg->pos;
2379 switch (pos)
2381 case MUIV_List_Jump_Top:
2382 pos = 0;
2383 break;
2385 case MUIV_List_Jump_Active:
2386 pos = data->entries_active;
2387 break;
2389 case MUIV_List_Jump_Bottom:
2390 pos = data->entries_num - 1;
2391 break;
2393 case MUIV_List_Jump_Down:
2394 pos = data->entries_first + data->entries_visible;
2395 break;
2397 case MUIV_List_Jump_Up:
2398 pos = data->entries_first - 1;
2399 break;
2403 if (pos > data->entries_num)
2405 pos = data->entries_num - 1;
2407 if (pos < 0)
2408 pos = 0;
2410 if (pos < data->entries_first)
2412 set(obj, MUIA_List_First, pos);
2414 else if (pos >= data->entries_first + data->entries_visible)
2416 pos -= (data->entries_visible - 1);
2417 if (pos < 0)
2418 pos = 0;
2419 if (pos != data->entries_first)
2421 set(obj, MUIA_List_First, pos);
2426 return TRUE;
2429 /**************************************************************************
2430 MUIM_List_Sort
2431 **************************************************************************/
2432 IPTR List__MUIM_Sort(struct IClass *cl, Object *obj,
2433 struct MUIP_List_Sort *msg)
2435 struct MUI_ListData *data = INST_DATA(cl, obj);
2437 int i, j, max;
2438 struct MUIP_List_Compare cmpmsg =
2439 { MUIM_List_Compare, NULL, NULL, 0, 0 };
2441 if (data->entries_num > 1)
2444 Simple sort algorithm. Feel free to improve it.
2446 for (i = 0; i < data->entries_num - 1; i++)
2448 max = i;
2449 for (j = i + 1; j < data->entries_num; j++)
2451 cmpmsg.entry1 = data->entries[max]->data;
2452 cmpmsg.entry2 = data->entries[j]->data;
2453 if ((LONG) DoMethodA(obj, (Msg) & cmpmsg) > 0)
2455 max = j;
2458 if (i != max)
2460 APTR tmp = data->entries[i];
2461 data->entries[i] = data->entries[max];
2462 data->entries[max] = tmp;
2467 if (!(data->flags & LIST_QUIET))
2469 data->update = 1;
2470 MUI_Redraw(obj, MADF_DRAWUPDATE);
2473 return 0;
2476 /**************************************************************************
2477 MUIM_List_Move
2478 **************************************************************************/
2479 IPTR List__MUIM_Move(struct IClass *cl, Object *obj,
2480 struct MUIP_List_Move *msg)
2482 struct MUI_ListData *data = INST_DATA(cl, obj);
2484 LONG from, to;
2485 int i;
2487 switch (msg->from)
2489 case MUIV_List_Move_Top:
2490 from = 0;
2491 break;
2492 case MUIV_List_Move_Active:
2493 from = data->entries_active;
2494 break;
2495 case MUIV_List_Move_Bottom:
2496 from = data->entries_num - 1;
2497 break;
2498 default:
2499 from = msg->from;
2502 switch (msg->to)
2504 case MUIV_List_Move_Top:
2505 to = 0;
2506 break;
2507 case MUIV_List_Move_Active:
2508 to = data->entries_active;
2509 break;
2510 case MUIV_List_Move_Bottom:
2511 to = data->entries_num - 1;
2512 break;
2513 case MUIV_List_Move_Next:
2514 to = from + 1;
2515 break;
2516 case MUIV_List_Move_Previous:
2517 to = from - 1;
2518 break;
2519 default:
2520 to = msg->to;
2523 if (from > data->entries_num - 1 || from < 0
2524 || to > data->entries_num - 1 || to < 0 || from == to)
2525 return (IPTR) FALSE;
2527 if (from < to)
2529 struct ListEntry *backup = data->entries[from];
2530 for (i = from; i < to; i++)
2531 data->entries[i] = data->entries[i + 1];
2532 data->entries[to] = backup;
2534 else
2536 struct ListEntry *backup = data->entries[from];
2537 for (i = from; i > to; i--)
2538 data->entries[i] = data->entries[i - 1];
2539 data->entries[to] = backup;
2542 data->update = 1;
2543 MUI_Redraw(obj, MADF_DRAWUPDATE);
2545 return TRUE;
2548 /**************************************************************************
2549 MUIM_List_NextSelected
2550 **************************************************************************/
2551 IPTR List__MUIM_NextSelected(struct IClass *cl, Object *obj,
2552 struct MUIP_List_NextSelected *msg)
2554 struct MUI_ListData *data = INST_DATA(cl, obj);
2555 LONG pos, i;
2556 BOOL found = FALSE;
2558 /* Get the first entry to check */
2559 pos = *msg->pos;
2560 if (pos == MUIV_List_NextSelected_Start)
2561 pos = 0;
2562 else
2563 pos++;
2565 /* Find the next selected entry */
2566 for (i = pos; i < data->entries_num && !found; i++)
2568 if (data->entries[i]->flags & ENTRY_SELECTED)
2570 pos = i;
2571 found = TRUE;
2575 /* Return index of selected entry, or indicate there are no more */
2576 if (!found)
2577 pos = MUIV_List_NextSelected_End;
2578 *msg->pos = pos;
2580 return TRUE;
2583 /**************************************************************************
2584 Dispatcher
2585 **************************************************************************/
2586 BOOPSI_DISPATCHER(IPTR, List_Dispatcher, cl, obj, msg)
2588 switch (msg->MethodID)
2590 case OM_NEW:
2591 return List__OM_NEW(cl, obj, (struct opSet *)msg);
2592 case OM_DISPOSE:
2593 return List__OM_DISPOSE(cl, obj, msg);
2594 case OM_SET:
2595 return List__OM_SET(cl, obj, (struct opSet *)msg);
2596 case OM_GET:
2597 return List__OM_GET(cl, obj, (struct opGet *)msg);
2599 case MUIM_Setup:
2600 return List__MUIM_Setup(cl, obj, (struct MUIP_Setup *)msg);
2601 case MUIM_Cleanup:
2602 return List__MUIM_Cleanup(cl, obj, (struct MUIP_Cleanup *)msg);
2603 case MUIM_AskMinMax:
2604 return List__MUIM_AskMinMax(cl, obj, (struct MUIP_AskMinMax *)msg);
2605 case MUIM_Show:
2606 return List__MUIM_Show(cl, obj, (struct MUIP_Show *)msg);
2607 case MUIM_Hide:
2608 return List__MUIM_Hide(cl, obj, (struct MUIP_Hide *)msg);
2609 case MUIM_Draw:
2610 return List__MUIM_Draw(cl, obj, (struct MUIP_Draw *)msg);
2611 case MUIM_Layout:
2612 return List__MUIM_Layout(cl, obj, (struct MUIP_Layout *)msg);
2613 case MUIM_HandleEvent:
2614 return List__MUIM_HandleEvent(cl, obj,
2615 (struct MUIP_HandleEvent *)msg);
2616 case MUIM_List_Clear:
2617 return List__MUIM_Clear(cl, obj, (struct MUIP_List_Clear *)msg);
2618 case MUIM_List_Sort:
2619 return List__MUIM_Sort(cl, obj, (struct MUIP_List_Sort *)msg);
2620 case MUIM_List_Exchange:
2621 return List__MUIM_Exchange(cl, obj,
2622 (struct MUIP_List_Exchange *)msg);
2623 case MUIM_List_Insert:
2624 return List__MUIM_Insert(cl, obj, (APTR) msg);
2625 case MUIM_List_InsertSingle:
2626 return List__MUIM_InsertSingle(cl, obj, (APTR) msg);
2627 case MUIM_List_GetEntry:
2628 return List__MUIM_GetEntry(cl, obj, (APTR) msg);
2629 case MUIM_List_Redraw:
2630 return List__MUIM_Redraw(cl, obj, (APTR) msg);
2631 case MUIM_List_Remove:
2632 return List__MUIM_Remove(cl, obj, (APTR) msg);
2633 case MUIM_List_Select:
2634 return List__MUIM_Select(cl, obj, (APTR) msg);
2635 case MUIM_List_Construct:
2636 return List__MUIM_Construct(cl, obj, (APTR) msg);
2637 case MUIM_List_Destruct:
2638 return List__MUIM_Destruct(cl, obj, (APTR) msg);
2639 case MUIM_List_Compare:
2640 return List__MUIM_Compare(cl, obj, (APTR) msg);
2641 case MUIM_List_Display:
2642 return List__MUIM_Display(cl, obj, (APTR) msg);
2643 case MUIM_List_SelectChange:
2644 return List__MUIM_SelectChange(cl, obj, (APTR) msg);
2645 case MUIM_List_CreateImage:
2646 return List__MUIM_CreateImage(cl, obj, (APTR) msg);
2647 case MUIM_List_DeleteImage:
2648 return List__MUIM_DeleteImage(cl, obj, (APTR) msg);
2649 case MUIM_List_Jump:
2650 return List__MUIM_Jump(cl, obj, (APTR) msg);
2651 case MUIM_List_Move:
2652 return List__MUIM_Move(cl, obj, (struct MUIP_List_Move *)msg);
2653 case MUIM_List_NextSelected:
2654 return List__MUIM_NextSelected(cl, obj,
2655 (struct MUIP_List_NextSelected *)msg);
2658 return DoSuperMethodA(cl, obj, msg);
2660 BOOPSI_DISPATCHER_END
2663 * Class descriptor.
2665 const struct __MUIBuiltinClass _MUI_List_desc =
2667 MUIC_List,
2668 MUIC_Area,
2669 sizeof(struct MUI_ListData),
2670 (void *) List_Dispatcher