2 Copyright © 2002-2017, The AROS Development Team. All rights reserved.
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <devices/rawkeycodes.h>
14 #include <clib/alib_protos.h>
15 #include <proto/exec.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
20 #include <proto/muimaster.h>
22 /* #define MYDEBUG 1 */
25 #include "muimaster_intern.h"
28 #include "textengine.h"
29 #include "listimage.h"
32 extern struct Library
*MUIMasterBase
;
34 #define ENTRY_TITLE (-1)
36 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
37 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
41 #define UPDATEMODE_ALL (1 << 0)
42 #define UPDATEMODE_ENTRY (1 << 1)
43 #define UPDATEMODE_NEEDED (1 << 2)
61 LONG width
; /* Line width */
62 LONG height
; /* Line height */
63 WORD flags
; /* see below */
64 LONG widths
[]; /* Widths of the columns */
67 #define ENTRY_SELECTED (1<<0)
68 #define ENTRY_RENDER (1<<1)
73 int colno
; /* Column number */
74 int user_width
; /* user set width; -1 if entry width */
75 int min_width
; /* min width percentage */
76 int max_width
; /* min width percentage */
78 int delta
; /* ignored for the first and last column, defaults to 4 */
81 int entries_width
; /* width of the entries (maximum of all widths) */
84 struct MUI_ImageSpec_intern
;
91 APTR intern_pool
; /* The internal pool which the class has allocated */
92 LONG intern_puddle_size
;
93 LONG intern_thresh_size
;
94 APTR pool
; /* the pool which is used to allocate list entries */
96 struct Hook
*construct_hook
;
97 struct Hook
*compare_hook
;
98 struct Hook
*destruct_hook
;
99 struct Hook
*display_hook
;
100 struct Hook
*multi_test_hook
;
102 struct Hook default_compare_hook
;
104 /* List management, currently we use a simple flat array, which is not
105 * good if many entries are inserted/deleted */
106 LONG entries_num
; /* Number of Entries in the list */
107 LONG entries_allocated
;
108 struct ListEntry
**entries
;
110 LONG entries_first
; /* first visible entry */
111 LONG entries_visible
; /* number of visible entries,
112 * determined at MUIM_Layout */
114 LONG insert_position
; /* pos of the last insertion */
116 LONG entry_maxheight
; /* Maximum height of an entry */
117 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
119 LONG entries_totalheight
;
120 LONG entries_maxwidth
;
122 LONG vertprop_entries
;
123 LONG vertprop_visible
;
126 LONG confirm_entries_num
; /* These are the correct entries num, used
127 * so you cannot set MUIA_List_Entries to
130 LONG entries_top_pixel
; /* Where the entries start */
132 /* Column managment, is allocated by ParseListFormat() and freed
133 * by CleanListFormat() */
135 LONG columns
; /* Number of columns the list has */
136 LONG columns_allocated
; /* List has space for columns_allocated columns */
137 struct ColumnInfo
*ci
;
139 STRPTR
*strings_mem
; /* safe pointer to allocated memory for strings[] */
140 STRPTR
*strings
; /* the strings for the display function, one
141 * more than needed (for the entry position) */
144 int title_height
; /* The complete height of the title */
145 STRPTR title
; /* On single column lists this is the title,
146 * otherwise 1. NULL for no title(s) */
149 struct MUI_ImageSpec_intern
*list_cursor
;
150 struct MUI_ImageSpec_intern
*list_select
;
151 struct MUI_ImageSpec_intern
*list_selcur
;
153 /* Render optimization */
154 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
155 * 3 - scroll to current entries_first (old value is in
163 struct MinList images
;
166 ListviewRefresh prefs_refresh
;
167 UWORD prefs_linespacing
;
169 UWORD prefs_smoothval
;
171 /* render space handling */
176 /***************************/
177 /* Former Listview members */
178 /***************************/
189 LONG def_click_column
;
191 LONG mouse_click
; /* see below if mouse is held down */
200 struct MUI_EventHandlerNode ehn
;
203 ListviewMulti prefs_multi
;
211 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
212 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
214 #define LIST_ADJUSTWIDTH (1<<0)
215 #define LIST_ADJUSTHEIGHT (1<<1)
216 #define LIST_AUTOVISIBLE (1<<2)
217 #define LIST_DRAGSORTABLE (1<<3)
218 #define LIST_SHOWDROPMARKS (1<<4)
219 #define LIST_QUIET (1<<5)
220 #define LIST_CHANGED (1<<6)
222 static BOOL
IncreaseColumns(struct MUI_ListData
*data
, int new_columns
);
224 /****** List.mui/MUIA_List_Active ********************************************
227 * MUIA_List_Active -- (V4) [ISG], LONG
230 * The index of the active entry. There can be at most one active entry
231 * in a list. The active entry is highlighted visibly, except for
232 * read-only lists (those whose Listview has MUIA_Listview_Input set to
233 * FALSE). Selecting an entry with the mouse, or moving through the list
234 * with keyboard controls will also change the active entry (again
235 * excepting read-only lists).
237 * When set programmatically through this attribute, some special values
240 * MUIV_List_Active_Off
241 * MUIV_List_Active_Top
242 * MUIV_List_Active_Bottom
243 * MUIV_List_Active_Up
244 * MUIV_List_Active_Down
245 * MUIV_List_Active_PageUp
246 * MUIV_List_Active_PageDown
248 * When this attribute is read, either the index of the active entry or
249 * the special value MUIV_List_Active_Off will be returned.
251 * Setting this attribute to a new value will additionally have the same
252 * effect as calling the MUIM_List_Jump method with the specified or
256 * The concept of an active entry must not be confused with that of a
260 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
262 ******************************************************************************
266 /****** List.mui/MUIA_List_AutoVisible ***************************************
269 * MUIA_List_Visible -- (V11) [ISG], BOOL
272 * When this attribute is set to true, the active entry will be in the
273 * visible portion of the list whenever the list is unhidden.
278 ******************************************************************************
282 /****** List.mui/MUIA_List_CompareHook ***************************************
285 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
288 * The provided hook indicates the sort ordering of two list entries.
289 * The hook receives list-entry data pointers as its second and third
290 * arguments. The hook should return a negative value if the first entry
291 * should be placed before the second entry, a positive value if the
292 * first entry should be placed after the second entry, and zero if the
295 * In addition to being used internally for sorting operations, this hook
296 * will be called when MUIM_List_Compare is externally invoked.
298 * If this attribute is not specified or is set to NULL, all list entries
301 ******************************************************************************
305 /****** List.mui/MUIA_List_ConstructHook *************************************
308 * MUIA_List_ConstructHook -- (V4) [IS.], struct Hook *
311 * The provided hook creates a list entry. Whenever a data item is added
312 * to the list, it is the result of this hook that is really added.
314 * The hook receives the list's memory pool as its second argument and
315 * the data item for the entry as its third argument. The memory pool may
316 * be used for allocating memory for the new entry if desired. The hook
317 * should return the new data entry, or NULL if an error occurred.
319 * If this attribute is not specified or is set to NULL, all list entries
320 * must be strings (which must continue to exist for the lifetime of the
323 * If you want string entries to be duplicated within the list, so that
324 * they do not have to be preserved externally, a built-in hook for this
325 * purpose can be used by providing the special value
326 * MUIV_List_ConstructHook_String.
328 * Whenever this attribute is specified, a matching hook must be
329 * specified for the MUIA_ListDestructHook attribute.
332 * MUIA_List_DestructHook
334 ******************************************************************************
338 /****** List.mui/MUIA_List_DestructHook **************************************
341 * MUIA_List_DestructHook -- (V4) [IS.], struct Hook *
344 * The provided hook destroys a list entry, and is called whenever a data
345 * item is removed from the list. It can be used to deallocate any
346 * resources for the entry that were allocated by the hook specified for
347 * MUIA_List_ConstructHook.
349 * The hook receives the list's memory pool as its second argument and
350 * the list entry to be destroyed as its third argument. The hook should
351 * have no return value.
353 * If this attribute is not specified or is set to NULL, all list entries
354 * must be strings (which must continue to exist for the lifetime of the
357 * If you want string entries to be duplicated within the list, so that
358 * they do not have to be preserved externally, a built-in hook for this
359 * purpose can be used by providing the special value
360 * MUIV_List_ConstructHook_String.
362 * This attribute must only be specified when a matching hook has been
363 * specified for the MUIA_List_ConstructHook attribute. If you specified
364 * MUIV_List_ConstructHook_String for MUIA_List_ConstructHook, you must
365 * specify MUIV_List_DestructHook_String for this attribute.
368 * MUIA_List_ConstructHook
370 ******************************************************************************
374 /****** List.mui/MUIA_List_DropMark ******************************************
377 * MUIA_List_DropMark -- (V11) [..G], LONG
380 * Provides the index of the last position where a list entry was
381 * successfully dropped. The initial value before any entry has been
382 * dropped is undefined.
385 * MUIA_List_DragSortable, MUIA_List_ShowDropMarks,
386 * MUIA_Listview_Draggable
388 ******************************************************************************
392 /****** List.mui/MUIA_List_First *********************************************
395 * MUIA_List_First -- (V4) [..G], LONG
398 * The index of the first entry that can be seen (assuming nothing
399 * obscures the list) This value of this attribute is -1 when the
400 * list's window is not open.
403 * Notification does not occur on this attribute in MUI.
406 * MUIA_List_First, MUIA_List_Entries
408 ******************************************************************************
412 /****** List.mui/MUIA_List_MultiTestHook *************************************
415 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
418 * The provided hook indicates whether a particular list entry
419 * may be multiselected. The hook receives the list-entry data pointer as
420 * its third argument, and returns a Boolean value. If this attribute is
421 * not specified or is set to NULL, all list entries are considered
424 * Whenever an entry is about to be selected, this hook is called if
425 * there are other entries already selected. If the hook returns TRUE,
426 * the entry may be multi-selected; if the hook returns FALSE, the entry
427 * remains unselected.
429 * Additionally, if a non-multi-selectable entry has been selected (as
430 * the only selected entry in the list), any attempt to select an
431 * additional entry will fail.
433 ******************************************************************************
437 /****** List.mui/MUIA_List_ShowDropMarks *************************************
440 * MUIA_List_ShowDropMarks -- (V11) [ISG], BOOL
443 * Specifies whether a visual indication will be shown of where a list
444 * item will be inserted if dropped during a drag-and-drop operation.
445 * Defaults to TRUE. Only has an affect when the list is a drop target
446 * (e.g. when MUIA_List_DragSortable is TRUE).
449 * MUIA_List_DragSortable, MUIA_List_DropMark, MUIA_Listview_Draggable
451 ******************************************************************************
455 /****** List.mui/MUIA_List_Title *********************************************
458 * MUIA_List_Title -- (V6) [ISG], char *
461 * A heading for the list, placed above list entries. A value of NULL
462 * means no title is used. A value of TRUE means that the custom
463 * display hook provides a separate title for each column; the hook
464 * must then provide column titles instead of normal column data when
465 * the entry pointer provided is NULL.
468 * If a string is set for this attribute, it is not cached within the
472 * MUIA_List_DisplayHook
474 ******************************************************************************
478 /****** List.mui/MUIA_List_Visible *******************************************
481 * MUIA_List_Visible -- (V4) [..G], LONG
484 * The number of entries that can be seen at once with the list's
485 * current dimensions. This value of this attribute is -1 when the
486 * list's window is not open.
489 * Notification does not occur on this attribute in MUI.
492 * MUIA_List_First, MUIA_List_Entries
494 ******************************************************************************
498 /**************************************************************************
499 Allocate a single list entry, does not initialize it (except the pointer)
500 **************************************************************************/
501 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
503 struct ListEntry
*le
;
504 /* use IncreaseColumns() to enlarge column entry array */
505 IPTR size
= sizeof(struct ListEntry
) + sizeof(LONG
) * (data
->columns
+ 1);
507 le
= (struct ListEntry
*) AllocVecPooled(data
->pool
, size
);
508 D(bug("List AllocListEntry %p, %ld bytes\n", le
, size
));
511 /* possible, that we have an external pool, which does not have
518 /**************************************************************************
519 Deallocate a single list entry, does not deinitialize it
520 **************************************************************************/
521 static void FreeListEntry(struct MUI_ListData
*data
,
522 struct ListEntry
*entry
)
524 D(bug("FreeListEntry %p\n", entry
));
525 FreeVecPooled(data
->pool
, entry
);
528 /**************************************************************************
529 Ensures that there can be at least the given amount of entries within
530 the list. Returns 0 if not. It also allocates the space for the title.
531 It can be accessed with data->entries[ENTRY_TITLE]
532 **************************************************************************/
533 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
535 struct ListEntry
**new_entries
;
536 int new_entries_allocated
;
538 if (size
+ 1 <= data
->entries_allocated
)
541 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
542 if (new_entries_allocated
< size
+ 1)
543 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
545 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
546 new_entries_allocated
* sizeof(struct ListEntry
*)));
548 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
549 if (NULL
== new_entries
)
553 CopyMem(data
->entries
- 1, new_entries
,
554 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
555 FreeVec(data
->entries
- 1);
557 data
->entries
= new_entries
+ 1;
558 data
->entries_allocated
= new_entries_allocated
;
562 /**************************************************************************
563 Prepares the insertion of count entries at pos.
564 This function doesn't care if there is enough space in the datastructure.
565 SetListSize() must be used first.
566 With current implementation, this call will never fail
567 **************************************************************************/
568 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
571 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
572 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
576 /**************************************************************************
577 Removes count (already deinitalized) list entries starting az pos.
578 **************************************************************************/
579 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
581 // FIXME: segfault if entries_num = pos = count = 1
582 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
583 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
586 /**************************************************************************
587 Frees all memory allocated by ParseListFormat()
588 **************************************************************************/
589 static void FreeListFormat(struct MUI_ListData
*data
)
595 for (i
= 0; i
< data
->columns
; i
++)
597 FreeVec(data
->ci
[i
].preparse
);
598 data
->ci
[i
].preparse
= NULL
;
603 FreeVec(data
->preparses
);
604 data
->preparses
= NULL
;
605 if (data
->strings_mem
)
607 FreeVec(data
->strings_mem
);
608 data
->strings_mem
= NULL
;
609 data
->strings
= NULL
;
614 /**************************************************************************
615 Parses the given format string (also frees a previously parsed format).
616 Use initial=FALSE for format changes outside OM_NEW.
617 Return FALSE on failure.
618 **************************************************************************/
619 static BOOL
ParseListFormat(struct MUI_ListData
*data
, STRPTR format
,
628 struct RDArgs
*rdargs
;
631 format
= (STRPTR
) "";
635 FreeListFormat(data
);
639 /* Count the number of columns first */
644 if (!(data
->preparses
=
645 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), MEMF_CLEAR
)))
648 if (!(data
->strings_mem
= AllocVec((new_columns
+ 1 + 10)
649 * sizeof(STRPTR
), MEMF_CLEAR
)))
650 /* hold enough space also for the entry pos,
651 * used by orginal MUI and also some
654 data
->strings
=data
->strings_mem
;
656 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), MEMF_CLEAR
)))
660 for (i
= 0; i
< new_columns
; i
++)
662 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
663 data
->ci
[i
].weight
= 100;
664 data
->ci
[i
].delta
= 4;
665 data
->ci
[i
].min_width
= -1;
666 data
->ci
[i
].max_width
= -1;
667 data
->ci
[i
].user_width
= -1;
668 data
->ci
[i
].bar
= FALSE
;
669 data
->ci
[i
].preparse
= NULL
;
672 if ((format_sep
= StrDup(format
)) != 0)
674 for (i
= 0; format_sep
[i
] != '\0'; i
++)
676 if (format_sep
[i
] == ',')
677 format_sep
[i
] = '\0';
680 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
686 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
687 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
688 rdargs
->RDA_Source
.CS_CurChr
= 0;
689 rdargs
->RDA_DAList
= 0;
690 rdargs
->RDA_Buffer
= NULL
;
691 rdargs
->RDA_BufSiz
= 0;
692 rdargs
->RDA_ExtHelp
= NULL
;
693 rdargs
->RDA_Flags
= 0;
695 memset(args
, 0, sizeof args
);
696 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
699 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
700 if (args
[ARG_WEIGHT
])
701 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
703 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
704 if (args
[ARG_MINWIDTH
])
705 data
->ci
[i
].min_width
=
706 *(LONG
*) args
[ARG_MINWIDTH
];
707 if (args
[ARG_MAXWIDTH
])
708 data
->ci
[i
].max_width
=
709 *(LONG
*) args
[ARG_MAXWIDTH
];
710 data
->ci
[i
].bar
= args
[ARG_BAR
];
711 if (args
[ARG_PREPARSE
])
712 data
->ci
[i
].preparse
=
713 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
717 ptr
+= strlen(ptr
) + 1;
720 while (i
< new_columns
);
721 FreeDosObject(DOS_RDARGS
, rdargs
);
726 for (i
= 0; i
< new_columns
; i
++)
728 D(bug("colno %d weight %d delta %d preparse %s\n",
729 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
730 data
->ci
[i
].preparse
));
735 /* called from OM_NEW */
736 data
->columns_allocated
= new_columns
;
738 else if (data
->columns_allocated
< new_columns
)
740 /* called by MUIA_List_Format */
741 if (!IncreaseColumns(data
, new_columns
))
743 bug("[Zune:List] not enough memory for new columns!!\n");
744 /* FIXME: proper handling? */
747 data
->columns_allocated
= new_columns
;
749 data
->columns
= new_columns
;
750 data
->strings
++; /* Skip entry pos */
755 /**************************************************************************
756 Call the MUIM_List_Display for the given entry. It fills out
757 data->string and data->preparses
758 **************************************************************************/
759 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
761 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
765 for (col
= 0; col
< data
->columns
; col
++)
766 data
->preparses
[col
] = data
->ci
[col
].preparse
;
768 if (entry_pos
== ENTRY_TITLE
)
770 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
772 *data
->strings
= data
->title
;
775 entry_data
= NULL
; /* it's a title request */
778 entry_data
= data
->entries
[entry_pos
]->data
;
780 /* Get the display formation */
781 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
782 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
785 /**************************************************************************
786 Determine the dims of a single entry and adapt the columninfo according
787 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
788 be redrawn after this operation, 1 if all entries need to be redrawn.
789 **************************************************************************/
790 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
792 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
793 struct ListEntry
*entry
= data
->entries
[pos
];
800 if (!(_flags(obj
) & MADF_SETUP
))
803 DisplayEntry(cl
, obj
, pos
);
805 /* Set height to at least minheight */
806 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
807 data
->entries
[pos
]->height
= data
->entry_minheight
;
809 for (j
= 0; j
< data
->columns
; j
++)
812 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
816 zune_text_get_bounds(text
, obj
);
818 if (text
->height
> data
->entries
[pos
]->height
)
820 data
->entries
[pos
]->height
= text
->height
;
821 /* entry height changed, redraw all entries later */
824 data
->entries
[pos
]->widths
[j
] = text
->width
;
826 if (text
->width
> data
->ci
[j
].entries_width
)
828 /* This entry has a greater width for this column than any
829 * other entry, so we store this value
831 data
->ci
[j
].entries_width
= text
->width
;
832 /* column width changed, redraw all entries later */
836 zune_text_destroy(text
);
839 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
841 data
->entry_maxheight
= data
->entries
[pos
]->height
;
842 /* maximum entry height changed, redraw all entries later */
849 /**************************************************************************
850 Determine the widths of the entries
851 **************************************************************************/
852 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
855 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
857 if (!(_flags(obj
) & MADF_SETUP
))
860 for (j
= 0; j
< data
->columns
; j
++)
861 data
->ci
[j
].entries_width
= 0;
863 data
->entry_maxheight
= 0;
864 data
->entries_totalheight
= 0;
865 data
->entries_maxwidth
= 0;
867 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
869 CalcDimsOfEntry(cl
, obj
, i
);
870 data
->entries_totalheight
+= data
->entries
[i
]->height
;
873 for (j
= 0; j
< data
->columns
; j
++)
874 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
875 + data
->ci
[j
].delta
+ (data
->ci
[j
].bar
? BAR_WIDTH
: 0);
877 if (!data
->entry_maxheight
)
878 data
->entry_maxheight
= 1;
881 /**************************************************************************
882 Calculates the number of visible entry lines. Returns 1 if it has
884 **************************************************************************/
885 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
887 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
888 int old_entries_visible
= data
->entries_visible
;
889 int old_entries_top_pixel
= data
->entries_top_pixel
;
891 data
->vertprop_visible
= data
->entries_visible
=
892 (_mheight(data
->area
) - data
->title_height
)
893 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
895 /* Distribute extra vertical space evenly between top and bottom of
898 data
->entries_top_pixel
= _mtop(data
->area
) + data
->title_height
899 + (_mheight(data
->area
) - data
->title_height
901 data
->entries_visible
*
902 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
904 if (data
->entries_visible
!= old_entries_visible
)
906 superset(cl
, obj
, MUIA_List_Visible
, data
->entries_visible
);
907 superset(cl
, obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
910 return (old_entries_visible
!= data
->entries_visible
)
911 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
914 /**************************************************************************
915 Resize arrays, so that there is enough space for new columns.
916 The widths[] array must grow with increasing columns.
917 columns_allocated must be checked, before calling this function.
918 Space can only grow, not shrink.
919 Return FALSE on error (no memory).
920 **************************************************************************/
921 static BOOL
IncreaseColumns(struct MUI_ListData
*data
, int new_columns
)
924 IPTR newsize
, oldsize
;
925 struct ListEntry
*le
;
927 D(bug("IncreaseColumns: %d => %d columns\n", data
->columns_allocated
, new_columns
));
929 newsize
= sizeof(struct ListEntry
) + sizeof(LONG
) * (new_columns
+ 1);
930 oldsize
= sizeof(struct ListEntry
) + sizeof(LONG
) * (data
->columns_allocated
+ 1);
937 for (; i
< data
->entries_num
; i
++)
939 D(bug("IncreaseColumns: i: %d, size: %d => %d\n", i
, oldsize
, newsize
));
940 le
= (struct ListEntry
*) AllocVecPooled(data
->pool
, newsize
);
945 memset(le
, 0, newsize
);
946 D(bug("IncreaseColumns: CopyMem(%p, %p, %d)\n", data
->entries
[i
],
948 CopyMem(data
->entries
[i
], le
, oldsize
);
949 FreeVecPooled(data
->pool
, data
->entries
[i
]);
956 /**************************************************************************
957 Default hook to compare two list entries. Works for strings only.
958 **************************************************************************/
959 AROS_UFH3S(int, default_compare_func
,
960 AROS_UFHA(struct Hook
*, h
, A0
),
961 AROS_UFHA(char *, s2
, A2
),
962 AROS_UFHA(char *, s1
, A1
))
966 return Stricmp(s1
, s2
);
971 #define PROP_VERT_FIRST 1
973 static ULONG
List_Function(struct Hook
*hook
, Object
* obj
, void **msg
)
975 struct MUI_ListData
*data
= (struct MUI_ListData
*)hook
->h_Data
;
976 SIPTR type
= (SIPTR
) msg
[0];
977 SIPTR val
= (SIPTR
) msg
[1];
981 case PROP_VERT_FIRST
:
982 get(data
->vert
, MUIA_Prop_First
, &val
);
983 nnset(obj
, MUIA_List_VertProp_First
, val
);
989 /* At entry to this function, data->area is always set, but data->vert may
990 * or may not be set */
991 static void List_HandleScrollerPos(struct IClass
*cl
, Object
*obj
)
993 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
994 BOOL vert_not_used
= FALSE
;
996 /* Disallow any changes after setup. This function should basically be
997 * creation-time only */
998 if (_flags(obj
) & MADF_SETUP
)
1001 /* Remove both objects */
1002 if (data
->area_connected
)
1003 DoMethod(obj
, OM_REMMEMBER
, data
->area
);
1004 if (data
->vert_connected
)
1005 DoMethod(obj
, OM_REMMEMBER
, data
->vert
);
1007 /* Add list and/or scroller */
1008 switch (data
->scroller_pos
)
1010 case MUIV_Listview_ScrollerPos_None
:
1011 vert_not_used
= TRUE
;
1012 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
1014 case MUIV_Listview_ScrollerPos_Left
:
1016 data
->vert
=ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
1017 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
1018 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
1022 data
->vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
1023 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
1024 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
1028 data
->area_connected
= TRUE
;
1030 /* Handle case where it was decided that vert will not be used */
1035 if (data
->vert_connected
)
1037 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_First
,
1039 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Visible
,
1041 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Entries
,
1043 data
->vert_connected
= FALSE
;
1046 MUI_DisposeObject(data
->vert
);
1051 /* If at this point data->vert is not null, it means vert is to be
1053 if (data
->vert
&& !data
->vert_connected
)
1055 LONG entries
= 0, first
= 0, visible
= 0;
1057 get(obj
, MUIA_List_VertProp_First
, &first
);
1058 get(obj
, MUIA_List_VertProp_Visible
, &visible
);
1059 get(obj
, MUIA_List_VertProp_Entries
, &entries
);
1061 SetAttrs(data
->vert
, MUIA_Prop_First
, first
,
1062 MUIA_Prop_Visible
, visible
, MUIA_Prop_Entries
, entries
, TAG_DONE
);
1064 DoMethod(data
->vert
, MUIM_Notify
, MUIA_Prop_First
, MUIV_EveryTime
,
1065 (IPTR
) obj
, 4, MUIM_CallHook
, (IPTR
) &data
->hook
, PROP_VERT_FIRST
,
1068 /* Pass prop object as DestObj (based on code in NList) */
1069 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_First
, MUIV_EveryTime
,
1070 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
1071 MUIA_Prop_First
, MUIV_TriggerValue
);
1072 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Visible
, MUIV_EveryTime
,
1073 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
1074 MUIA_Prop_Visible
, MUIV_TriggerValue
);
1075 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Entries
, MUIV_EveryTime
,
1076 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
1077 MUIA_Prop_Entries
, MUIV_TriggerValue
);
1079 data
->vert_connected
= TRUE
;
1083 /**************************************************************************
1085 **************************************************************************/
1086 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
1088 struct MUI_ListData
*data
;
1089 struct TagItem
*tag
;
1090 struct TagItem
*tags
;
1092 LONG new_entries_active
= MUIV_List_Active_Off
;
1093 struct TagItem rectattrs
[2] =
1094 {{TAG_IGNORE
, TAG_IGNORE
}, {TAG_DONE
, TAG_DONE
}};
1097 /* search for MUIA_Frame as it has to be passed to rectangle object */
1098 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1100 if (tag
->ti_Tag
== MUIA_Frame
)
1102 rectattrs
[0].ti_Tag
= MUIA_Frame
;
1103 rectattrs
[0].ti_Data
= tag
->ti_Data
;
1104 tag
->ti_Tag
= TAG_IGNORE
;
1109 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
1110 MUIA_Group_Horiz
, TRUE
,
1113 MUIA_Group_Spacing
, 0,
1114 MUIA_Font
, MUIV_Font_List
,
1115 MUIA_ShowSelState
, FALSE
,
1116 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
1117 MUIA_Background
, MUII_ListBack
,
1118 TAG_MORE
, (IPTR
) msg
->ops_AttrList
,
1124 data
= INST_DATA(cl
, obj
);
1127 data
->entries_active
= MUIV_List_Active_Off
;
1128 data
->intern_puddle_size
= 2008;
1129 data
->intern_thresh_size
= 1024;
1130 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
1131 data
->default_compare_hook
.h_SubEntry
= 0;
1132 data
->compare_hook
= &(data
->default_compare_hook
);
1133 data
->flags
= LIST_SHOWDROPMARKS
;
1134 data
->area_replaced
= FALSE
;
1135 data
->area_connected
= FALSE
;
1136 data
->vert_connected
= FALSE
;
1138 data
->entries_visible
= data
->vertprop_visible
= -1;
1139 data
->last_active
= -1;
1140 data
->drop_mark
= 0;
1142 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
1143 data
->ehn
.ehn_Priority
= 0;
1144 data
->ehn
.ehn_Flags
= 0;
1145 data
->ehn
.ehn_Object
= obj
;
1146 data
->ehn
.ehn_Class
= cl
;
1148 data
->mouse_click
= 0;
1149 data
->mouse_x
= MUI_MAXMAX
;
1150 data
->mouse_y
= MUI_MAXMAX
;
1153 * List is a group where part of area is rendered and part is filled
1154 * with other objects (inside of List dimensions). One such object is
1155 * up/down arrow. This object depends on RelVerify mode to control
1156 * behaviour. List also has the RelVerify mode. Area super class in case
1157 * of both of those objects adds an event handler node with the same
1158 * priority. Depending on the sort order, the event handler node of
1159 * "list" can eat a click event and up/down arrows stop working. The
1160 * hack is to decrease the priority of Area event handler for list to
1161 * always favor up/down arrow. There are other hacky ways of solving
1162 * this, but this seems least evil approach, as this hack is
1163 * encapsulated in the List class itself.
1165 muiAreaData(obj
)->mad_ehn
.ehn_Priority
--;
1167 data
->hook
.h_Entry
= HookEntry
;
1168 data
->hook
.h_SubEntry
= (HOOKFUNC
) List_Function
;
1169 data
->hook
.h_Data
= data
;
1171 area
= (Object
*)GetTagData(MUIA_List_ListArea
, (IPTR
) 0,
1175 area
= RectangleObject
, MUIA_FillArea
, FALSE
, TAG_MORE
,
1176 (IPTR
) rectattrs
, End
;
1178 data
->area_replaced
= TRUE
;
1181 /* parse initial taglist */
1182 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1184 switch (tag
->ti_Tag
)
1186 case MUIA_List_Active
:
1187 new_entries_active
= tag
->ti_Data
;
1190 case MUIA_List_Pool
:
1191 data
->pool
= (APTR
) tag
->ti_Data
;
1194 case MUIA_List_PoolPuddleSize
:
1195 data
->intern_puddle_size
= tag
->ti_Data
;
1198 case MUIA_List_PoolThreshSize
:
1199 data
->intern_thresh_size
= tag
->ti_Data
;
1202 case MUIA_List_CompareHook
:
1203 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1204 if (data
->compare_hook
== NULL
)
1205 data
->compare_hook
= &data
->default_compare_hook
;
1208 case MUIA_List_ConstructHook
:
1209 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1212 case MUIA_List_DestructHook
:
1213 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1216 case MUIA_List_DisplayHook
:
1217 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1220 case MUIA_List_MultiTestHook
:
1221 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1224 case MUIA_List_SourceArray
:
1225 array
= (APTR
*) tag
->ti_Data
;
1228 case MUIA_List_Format
:
1229 data
->format
= (STRPTR
) tag
->ti_Data
;
1232 case MUIA_List_Title
:
1233 data
->title
= (STRPTR
) tag
->ti_Data
;
1236 case MUIA_List_MinLineHeight
:
1237 data
->entry_minheight
= tag
->ti_Data
;
1240 case MUIA_List_AdjustHeight
:
1241 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
1244 case MUIA_List_AdjustWidth
:
1245 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
1248 case MUIA_List_AutoVisible
:
1249 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1252 case MUIA_List_ShowDropMarks
:
1253 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1256 case MUIA_List_DragSortable
:
1257 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1260 case MUIA_Listview_ScrollerPos
:
1261 data
->scroller_pos
= tag
->ti_Data
;
1264 case MUIA_Listview_Input
:
1265 data
->read_only
= !tag
->ti_Data
;
1268 case MUIA_Listview_MultiSelect
:
1269 data
->multiselect
= tag
->ti_Data
;
1272 case MUIA_Listview_DefClickColumn
:
1273 data
->def_click_column
= tag
->ti_Data
;
1276 case MUIA_Listview_DragType
:
1277 data
->drag_type
= tag
->ti_Data
;
1278 if (data
->drag_type
!= MUIV_Listview_DragType_None
)
1279 set(obj
, MUIA_Draggable
, TRUE
);
1284 List_HandleScrollerPos(cl
, obj
);
1288 /* No memory pool given, so we create our own */
1289 data
->pool
= data
->intern_pool
=
1290 CreatePool(0, data
->intern_puddle_size
,
1291 data
->intern_thresh_size
);
1294 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1299 /* parse the list format */
1300 if (!ParseListFormat(data
, data
->format
, TRUE
))
1302 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1306 /* This is necessary for at least the title */
1307 if (!SetListSize(data
, 0))
1309 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1313 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
1315 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1322 /* Count the number of elements */
1323 for (i
= 0; array
[i
] != NULL
; i
++)
1326 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
1327 MUIV_List_Insert_Top
);
1330 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
1332 switch (new_entries_active
)
1334 case MUIV_List_Active_Top
:
1335 new_entries_active
= 0;
1338 case MUIV_List_Active_Bottom
:
1339 new_entries_active
= data
->entries_num
- 1;
1343 if (new_entries_active
< 0)
1344 new_entries_active
= 0;
1345 else if (new_entries_active
>= data
->entries_num
)
1346 new_entries_active
= data
->entries_num
- 1;
1348 data
->entries_active
= new_entries_active
;
1349 /* Selected entry will be moved into visible area */
1352 NewList((struct List
*)&data
->images
);
1354 D(bug("List_New(%lx)\n", obj
));
1359 /**************************************************************************
1361 **************************************************************************/
1362 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
1364 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1366 D(bug("List Dispose\n"));
1368 /* Call destruct method for every entry and free the entries manually
1369 * to avoid notification */
1370 while (data
->confirm_entries_num
)
1372 struct ListEntry
*lentry
=
1373 data
->entries
[--data
->confirm_entries_num
];
1374 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1376 FreeListEntry(data
, lentry
);
1379 if (data
->intern_pool
)
1380 DeletePool(data
->intern_pool
);
1382 FreeVec(data
->entries
- 1);
1383 /* title is currently before all other elements */
1385 FreeListFormat(data
);
1387 return DoSuperMethodA(cl
, obj
, msg
);
1391 /**************************************************************************
1393 **************************************************************************/
1394 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
1396 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1397 struct TagItem
*tag
;
1398 struct TagItem
*tags
;
1401 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1403 switch (tag
->ti_Tag
)
1405 case MUIA_List_CompareHook
:
1406 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1407 if (data
->compare_hook
== NULL
)
1408 data
->compare_hook
= &data
->default_compare_hook
;
1411 case MUIA_List_ConstructHook
:
1412 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1415 case MUIA_List_DestructHook
:
1416 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1419 case MUIA_List_DisplayHook
:
1420 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1423 case MUIA_List_MultiTestHook
:
1424 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1425 if (data
->multi_test_hook
!= NULL
)
1427 /* Clearing current selections is the easiest way to keep
1428 * selections consistent with the new hook */
1429 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
1430 MUIV_List_Select_Off
, NULL
);
1434 case MUIA_List_Title
:
1435 data
->title
= (STRPTR
) tag
->ti_Data
;
1436 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1439 case MUIA_List_VertProp_First
:
1440 data
->vertprop_first
= tag
->ti_Data
;
1441 if (data
->entries_first
!= tag
->ti_Data
)
1443 set(obj
, MUIA_List_First
, tag
->ti_Data
);
1447 case MUIA_List_Format
:
1448 data
->format
= (STRPTR
) tag
->ti_Data
;
1449 ParseListFormat(data
, data
->format
, FALSE
);
1450 // FIXME: should we check for errors?
1451 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1454 case MUIA_List_VertProp_Entries
:
1455 data
->vertprop_entries
= tag
->ti_Data
;
1458 case MUIA_List_VertProp_Visible
:
1459 data
->vertprop_visible
= tag
->ti_Data
;
1460 data
->entries_visible
= tag
->ti_Data
;
1463 case MUIA_List_Active
:
1465 LONG new_entries_active
= tag
->ti_Data
;
1467 if ((data
->entries_num
)
1468 && (new_entries_active
!= MUIV_List_Active_Off
))
1470 switch (new_entries_active
)
1472 case MUIV_List_Active_Top
:
1473 new_entries_active
= 0;
1476 case MUIV_List_Active_Bottom
:
1477 new_entries_active
= data
->entries_num
- 1;
1480 case MUIV_List_Active_Up
:
1481 new_entries_active
= data
->entries_active
- 1;
1484 case MUIV_List_Active_Down
:
1485 new_entries_active
= data
->entries_active
+ 1;
1488 case MUIV_List_Active_PageUp
:
1489 new_entries_active
=
1490 data
->entries_active
- data
->entries_visible
;
1493 case MUIV_List_Active_PageDown
:
1494 new_entries_active
=
1495 data
->entries_active
+ data
->entries_visible
;
1499 if (new_entries_active
< 0)
1500 new_entries_active
= 0;
1501 else if (new_entries_active
>= data
->entries_num
)
1502 new_entries_active
= data
->entries_num
- 1;
1505 new_entries_active
= -1;
1507 if (data
->entries_active
!= new_entries_active
)
1509 LONG old
= data
->entries_active
;
1510 data
->entries_active
= new_entries_active
;
1512 /* SelectChange stuff */
1513 if (new_entries_active
!= -1)
1515 DoMethod(obj
, MUIM_List_SelectChange
,
1516 new_entries_active
, MUIV_List_Select_On
, 0);
1517 DoMethod(obj
, MUIM_List_SelectChange
,
1518 new_entries_active
, MUIV_List_Select_Active
, 0);
1521 DoMethod(obj
, MUIM_List_SelectChange
,
1522 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1524 if (!data
->read_only
)
1526 data
->entries
[old
]->flags
|= ENTRY_RENDER
;
1527 if (!(data
->flags
& LIST_QUIET
))
1529 data
->update
= UPDATEMODE_ENTRY
;
1530 data
->update_pos
= old
;
1531 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1533 data
->entries
[data
->entries_active
]->flags
|= ENTRY_RENDER
;
1534 if (!(data
->flags
& LIST_QUIET
))
1536 data
->update
= UPDATEMODE_ENTRY
;
1537 data
->update_pos
= data
->entries_active
;
1538 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1542 data
->update
= UPDATEMODE_NEEDED
;
1543 data
->flags
|= LIST_CHANGED
;
1547 /* Make new active entry visible (if there is one and
1549 if (new_entries_active
!= -1
1550 && (_flags(obj
) & MADF_SETUP
))
1552 DoMethod(obj
, MUIM_List_Jump
,
1553 MUIV_List_Jump_Active
);
1559 case MUIA_List_First
:
1560 data
->update_pos
= data
->entries_first
;
1561 data
->entries_first
= tag
->ti_Data
;
1562 if (!(data
->flags
& LIST_QUIET
))
1564 data
->update
= (UPDATEMODE_ENTRY
|UPDATEMODE_ALL
);
1565 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1566 if (data
->vertprop_first
!= tag
->ti_Data
)
1568 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1573 data
->update
= UPDATEMODE_ALL
;
1574 data
->flags
|= LIST_CHANGED
;
1578 case MUIA_List_Visible
: /* Shouldn't be settable? */
1579 if (data
->vertprop_visible
!= tag
->ti_Data
)
1580 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1583 case MUIA_List_Entries
:
1584 if (data
->confirm_entries_num
== tag
->ti_Data
)
1586 data
->entries_num
= tag
->ti_Data
;
1587 if (!(data
->flags
& LIST_QUIET
))
1589 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1594 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1598 case MUIA_List_Quiet
:
1599 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1600 if (!(data
->flags
& LIST_QUIET
))
1602 if (data
->flags
& LIST_CHANGED
)
1604 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1605 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1606 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1607 if (data
->entries_first
!= XGET(obj
, MUIA_List_VertProp_First
))
1608 set(obj
, MUIA_List_VertProp_First
, data
->entries_first
);
1610 data
->flags
&= ~LIST_CHANGED
;
1614 case MUIA_List_AutoVisible
:
1615 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1618 case MUIA_List_ShowDropMarks
:
1619 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1622 case MUIA_List_DragSortable
:
1623 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1627 /* Swallow this so the Area class doesn't redraw us */
1628 tag
->ti_Tag
= TAG_IGNORE
;
1632 if (_flags(obj
) & MADF_SETUP
)
1634 /* Stop listening for events we only listen to when mouse
1635 button is down: we will not be informed of the button
1637 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1639 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
1640 | IDCMP_INACTIVEWINDOW
);
1641 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1646 case MUIA_Listview_DoubleClick
: /* private set */
1647 data
->doubleclick
= tag
->ti_Data
!= 0;
1650 case MUIA_Listview_ScrollerPos
: /* private set */
1651 data
->scroller_pos
= tag
->ti_Data
;
1652 List_HandleScrollerPos(cl
, obj
);
1655 case MUIA_Listview_Input
: /* private set */
1656 data
->read_only
= !tag
->ti_Data
;
1659 case MUIA_Listview_MultiSelect
: /* private set */
1660 data
->multiselect
= tag
->ti_Data
;
1663 case MUIA_Listview_DefClickColumn
:
1664 data
->def_click_column
= tag
->ti_Data
;
1667 case MUIA_Listview_DragType
:
1668 data
->drag_type
= tag
->ti_Data
;
1669 set(obj
, MUIA_Draggable
,
1670 tag
->ti_Data
!= MUIV_Listview_DragType_None
);
1675 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1678 /**************************************************************************
1680 **************************************************************************/
1681 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1683 /* small macro to simplify return value storage */
1684 #define STORE *(msg->opg_Storage)
1685 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1687 switch (msg
->opg_AttrID
)
1689 case MUIA_List_Entries
:
1690 STORE
= data
->entries_num
;
1692 case MUIA_List_First
:
1693 STORE
= data
->entries_first
;
1695 case MUIA_List_Active
:
1696 STORE
= data
->entries_active
;
1698 case MUIA_List_InsertPosition
:
1699 STORE
= data
->insert_position
;
1701 case MUIA_List_Title
:
1702 STORE
= (IPTR
) data
->title
;
1704 case MUIA_List_VertProp_Entries
:
1705 STORE
= data
->vertprop_entries
;
1707 case MUIA_List_VertProp_Visible
:
1708 case MUIA_List_Visible
:
1709 STORE
= data
->vertprop_visible
;
1711 case MUIA_List_VertProp_First
:
1712 STORE
= data
->vertprop_first
;
1714 case MUIA_List_Format
:
1715 STORE
= (IPTR
) data
->format
;
1717 case MUIA_List_AutoVisible
:
1718 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1720 case MUIA_List_ShowDropMarks
:
1721 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1723 case MUIA_List_DragSortable
:
1724 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1726 case MUIA_List_DropMark
:
1727 STORE
= data
->drop_mark
;
1729 case MUIA_Listview_ClickColumn
:
1730 STORE
= data
->click_column
;
1732 case MUIA_Listview_DoubleClick
:
1733 STORE
= data
->doubleclick
;
1735 case MUIA_Listview_SelectChange
:
1738 case MUIA_Listview_List
:
1741 case MUIA_Listview_DefClickColumn
:
1742 STORE
= data
->def_click_column
;
1744 case MUIA_Listview_DragType
:
1745 STORE
= data
->drag_type
;
1749 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1755 /**************************************************************************
1757 **************************************************************************/
1758 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1759 struct MUIP_Setup
*msg
)
1761 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1763 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1766 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1767 data
->prefs_linespacing
=
1768 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1769 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1770 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1773 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1775 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1777 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1779 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
1780 if (data
->multiselect
== MUIV_Listview_MultiSelect_Default
)
1782 if (data
->prefs_multi
== LISTVIEW_MULTI_SHIFTED
)
1783 data
->multiselect
= MUIV_Listview_MultiSelect_Shifted
;
1785 data
->multiselect
= MUIV_Listview_MultiSelect_Always
;
1788 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1793 /**************************************************************************
1795 **************************************************************************/
1796 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1797 struct MUIP_Cleanup
*msg
)
1799 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1801 zune_imspec_cleanup(data
->list_cursor
);
1802 zune_imspec_cleanup(data
->list_select
);
1803 zune_imspec_cleanup(data
->list_selcur
);
1805 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1806 data
->mouse_click
= 0;
1808 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1811 /**************************************************************************
1813 **************************************************************************/
1814 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1815 struct MUIP_AskMinMax
*msg
)
1817 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1819 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1821 CalcWidths(cl
, obj
);
1823 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1825 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1826 msg
->MinMaxInfo
->DefWidth
= msg
->MinMaxInfo
->MinWidth
;
1827 msg
->MinMaxInfo
->MaxWidth
= msg
->MinMaxInfo
->MinWidth
;
1831 msg
->MinMaxInfo
->MinWidth
+= 40;
1832 msg
->MinMaxInfo
->DefWidth
+= 100;
1833 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1836 if (data
->entries_num
> 0)
1838 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1840 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1841 msg
->MinMaxInfo
->DefHeight
= msg
->MinMaxInfo
->MinHeight
;
1842 msg
->MinMaxInfo
->MaxHeight
= msg
->MinMaxInfo
->MinHeight
;
1846 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1847 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1848 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1849 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1854 msg
->MinMaxInfo
->MinHeight
+= 36;
1855 msg
->MinMaxInfo
->DefHeight
+= 96;
1856 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1858 D(bug("List %p minheight=%d, line maxh=%d\n",
1859 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1864 /****i* List.mui/MUIM_Layout *************************************************
1869 ******************************************************************************
1873 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1874 struct MUIP_Layout
*msg
)
1876 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1877 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1878 LONG new_entries_first
= data
->entries_first
;
1880 /* Calc the numbers of entries visible */
1881 CalcVertVisible(cl
, obj
);
1883 /* Ensure active entry is visible if requested */
1884 if (data
->entries_active
+ 1 >=
1885 (data
->entries_first
+ data
->entries_visible
)
1886 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1888 data
->entries_active
- data
->entries_visible
+ 1;
1890 /* Ensure there are no unnecessary empty lines */
1891 if ((new_entries_first
+ data
->entries_visible
>=
1893 && (data
->entries_visible
<= data
->entries_num
))
1894 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1896 /* Always show the start of the list if it isn't long enough to fill the
1898 if (data
->entries_num
<= data
->entries_visible
)
1899 new_entries_first
= 0;
1901 if (new_entries_first
< 0)
1902 new_entries_first
= 0;
1904 set(obj
, new_entries_first
!= data
->entries_first
?
1905 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1907 /* So the notify happens */
1908 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1914 /**************************************************************************
1916 **************************************************************************/
1917 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1918 struct MUIP_Show
*msg
)
1920 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1921 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1923 zune_imspec_show(data
->list_cursor
, obj
);
1924 zune_imspec_show(data
->list_select
, obj
);
1925 zune_imspec_show(data
->list_selcur
, obj
);
1930 /**************************************************************************
1932 **************************************************************************/
1933 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1934 struct MUIP_Hide
*msg
)
1936 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1938 zune_imspec_hide(data
->list_cursor
);
1939 zune_imspec_hide(data
->list_select
);
1940 zune_imspec_hide(data
->list_selcur
);
1942 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1946 /**************************************************************************
1947 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1949 **************************************************************************/
1950 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1953 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1956 /* To be sure we don't draw anything if there is no title */
1957 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1960 DisplayEntry(cl
, obj
, entry_pos
);
1961 x1
= _mleft(data
->area
);
1963 for (col
= 0; col
< data
->columns
; col
++)
1966 x2
= x1
+ data
->ci
[col
].entries_width
;
1969 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1970 ZTEXT_ARG_NONE
, 0)))
1972 /* Could be made simpler, as we don't really need the bounds */
1973 zune_text_get_bounds(text
, obj
);
1974 /* Note, this was MPEN_SHADOW before */
1975 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1976 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1977 zune_text_destroy(text
);
1979 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1983 /**************************************************************************
1985 **************************************************************************/
1986 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1988 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1992 BOOL scroll_caused_damage
= FALSE
;
1993 struct MUI_ImageSpec_intern
*highlight
;
1996 D(bug("[Zune:List] %s()\n", __func__
);)
1998 if (data
->flags
& LIST_QUIET
)
2002 bug("[Zune:List] %s: Rendering...\n", __func__
);
2003 bug("[Zune:List] %s: update = %d\n", __func__
, data
->update
);
2006 ret
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2008 if (data
->area_replaced
)
2011 /* Calculate the title height */
2014 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
2018 data
->title_height
= 0;
2021 /* Calc the numbers of entries visible */
2022 CalcVertVisible(cl
, obj
);
2024 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== UPDATEMODE_ALL
)
2026 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
2027 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
),
2028 0, data
->entries_first
* data
->entry_maxheight
, 0);
2031 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(data
->area
),
2032 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
));
2034 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== UPDATEMODE_ALL
)
2036 y
= _mtop(data
->area
);
2039 if (data
->title_height
&& data
->title
)
2041 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
2042 y
+= data
->entries
[ENTRY_TITLE
]->height
;
2043 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
2044 Move(_rp(obj
), _mleft(data
->area
), y
);
2045 Draw(_rp(obj
), _mright(data
->area
), y
);
2046 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
2048 Move(_rp(obj
), _mleft(data
->area
), y
);
2049 Draw(_rp(obj
), _mright(data
->area
), y
);
2053 y
= data
->entries_top_pixel
;
2055 start
= data
->entries_first
;
2056 end
= data
->entries_first
+ data
->entries_visible
;
2058 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== (UPDATEMODE_ENTRY
|UPDATEMODE_ALL
))
2060 int diffy
= data
->entries_first
- data
->update_pos
;
2062 if (abs(diffy
) < data
->entries_visible
)
2064 scroll_caused_damage
=
2065 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
2067 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
2068 _mleft(data
->area
), y
,
2069 _mright(data
->area
),
2070 y
+ data
->entry_maxheight
* data
->entries_visible
);
2072 scroll_caused_damage
=
2073 scroll_caused_damage
2074 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
2078 start
= end
- diffy
;
2079 y
+= data
->entry_maxheight
* (data
->entries_visible
-
2083 end
= start
- diffy
;
2087 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
2089 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), top
,
2090 _mwidth(data
->area
), bottom
- top
+ 1, 0,
2091 top
- _mtop(data
->area
) + data
->entries_first
2092 * data
->entry_maxheight
, 0);
2095 for (entry_pos
= start
;
2096 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
2098 struct ListEntry
*entry
= data
->entries
[entry_pos
];
2100 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
2101 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== UPDATEMODE_ALL
) ||
2102 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== (UPDATEMODE_ENTRY
|UPDATEMODE_ALL
)) ||
2103 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== UPDATEMODE_ENTRY
2104 && data
->update_pos
== entry_pos
) ||
2105 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== UPDATEMODE_NEEDED
2106 && (entry
->flags
& ENTRY_RENDER
)))
2108 /* Choose appropriate highlight image */
2110 if (entry_pos
== data
->entries_active
2111 && (entry
->flags
& ENTRY_SELECTED
) && !data
->read_only
)
2112 highlight
= data
->list_selcur
;
2113 else if (entry_pos
== data
->entries_active
&& !data
->read_only
)
2114 highlight
= data
->list_cursor
;
2115 else if (entry
->flags
& ENTRY_SELECTED
)
2116 highlight
= data
->list_select
;
2120 /* Draw highlight or background */
2122 if (highlight
!= NULL
)
2124 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
2125 _mleft(data
->area
), y
, _mwidth(data
->area
),
2126 data
->entry_maxheight
,
2127 0, y
- data
->entries_top_pixel
, 0);
2129 else if (((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== UPDATEMODE_ENTRY
2130 && data
->update_pos
== entry_pos
) ||
2131 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== UPDATEMODE_NEEDED
2132 && (entry
->flags
& ENTRY_RENDER
)))
2134 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), y
,
2135 _mwidth(data
->area
), data
->entry_maxheight
, 0,
2136 y
- _mtop(data
->area
) +
2137 data
->entries_first
* data
->entry_maxheight
, 0);
2140 List_DrawEntry(cl
, obj
, entry_pos
, y
);
2141 entry
->flags
&= ~ENTRY_RENDER
;
2143 y
+= data
->entry_maxheight
;
2146 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
2150 if (scroll_caused_damage
)
2152 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
2154 /* Theoretically it might happen that more damage is caused
2155 after ScrollRaster. By something else, like window movement
2156 in front of our window. Therefore refresh root object of
2157 window, not just this object */
2161 get(_win(obj
), MUIA_Window_RootObject
, &o
);
2162 MUI_Redraw(o
, MADF_DRAWOBJECT
);
2164 MUI_EndRefresh(muiRenderInfo(obj
), 0);
2168 ULONG x1
= _mleft(data
->area
);
2170 y
= _mtop(data
->area
);
2172 if (data
->title_height
&& data
->title
)
2174 for (col
= 0; col
< data
->columns
; col
++)
2176 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
2177 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
2179 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
2182 if (data
->ci
[col
].bar
)
2184 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
2185 Move(_rp(obj
), x1
, y
);
2187 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
2188 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
2189 Move(_rp(obj
), x1
+ 1, y
);
2190 Draw(_rp(obj
), x1
+ 1,
2191 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
2195 x1
+= data
->ci
[col
].delta
- halfdelta
;
2197 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
2200 x1
= _mleft(data
->area
);
2202 for (col
= 0; col
< data
->columns
; col
++)
2204 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
2205 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
2207 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
2210 if (data
->ci
[col
].bar
)
2212 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
2213 Move(_rp(obj
), x1
, y
);
2214 Draw(_rp(obj
), x1
, _mbottom(data
->area
));
2215 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
2216 Move(_rp(obj
), x1
+ 1, y
);
2217 Draw(_rp(obj
), x1
+ 1, _mbottom(data
->area
));
2222 x1
+= data
->ci
[col
].delta
- halfdelta
;
2225 data
->flags
&= ~LIST_CHANGED
;
2230 /****** List.mui/MUIM_List_Clear *********************************************
2233 * MUIM_List_Clear (V4)
2236 * DoMethod(obj, MUIM_List_Clear);
2239 * Removes all entries from the list.
2241 ******************************************************************************
2245 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
2246 struct MUIP_List_Clear
*msg
)
2248 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2250 while (data
->confirm_entries_num
)
2252 struct ListEntry
*lentry
=
2253 data
->entries
[--data
->confirm_entries_num
];
2254 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2256 FreeListEntry(data
, lentry
);
2258 data
->flags
|= LIST_CHANGED
;
2260 /* Should never fail when shrinking */
2261 SetListSize(data
, 0);
2263 if (data
->confirm_entries_num
!= data
->entries_num
)
2265 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
2266 /* Notify only when no entry was active */
2267 data
->entries_active
!=
2268 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
2269 MUIV_List_Active_Off
, TAG_DONE
);
2271 data
->update
= UPDATEMODE_ALL
;
2272 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2278 /****** List.mui/MUIM_List_Exchange ******************************************
2281 * MUIM_List_Exchange (V4)
2284 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2287 * Exchange two entries' positions.
2290 * pos1 - the current index of the first entry that should be moved, or
2291 * one of these special values:
2292 * MUIV_List_Exchange_Active: the active entry.
2293 * MUIV_List_Exchange_Top: the first entry.
2294 * MUIV_List_Exchange_Bottom: the last entry.
2295 * pos2 - the index of the entry that the first entry should be exchanged
2296 * with, or one of these special values:
2297 * MUIV_List_Exchange_Active: the active entry.
2298 * MUIV_List_Exchange_Top: the first entry.
2299 * MUIV_List_Exchange_Bottom: the last entry.
2300 * MUIV_List_Exchange_Next: the next entry after pos1.
2301 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2304 * This method will do nothing if either index is greater than the last
2305 * index in the list, or if MUIV_List_Exchange_Next or
2306 * MUIV_List_Exchange_Previous imply an index outside the list.
2311 ******************************************************************************
2315 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
2316 struct MUIP_List_Exchange
*msg
)
2318 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2323 case MUIV_List_Exchange_Top
:
2326 case MUIV_List_Exchange_Active
:
2327 pos1
= data
->entries_active
;
2329 case MUIV_List_Exchange_Bottom
:
2330 pos1
= data
->entries_num
- 1;
2338 case MUIV_List_Exchange_Top
:
2341 case MUIV_List_Exchange_Active
:
2342 pos2
= data
->entries_active
;
2344 case MUIV_List_Exchange_Bottom
:
2345 pos2
= data
->entries_num
- 1;
2347 case MUIV_List_Exchange_Next
:
2350 case MUIV_List_Exchange_Previous
:
2357 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
2358 && pos2
< data
->entries_num
&& pos1
!= pos2
)
2360 struct ListEntry
*save
= data
->entries
[pos1
];
2361 data
->entries
[pos1
] = data
->entries
[pos2
];
2362 data
->entries
[pos2
] = save
;
2364 data
->update
= UPDATEMODE_ENTRY
;
2365 data
->update_pos
= pos1
;
2366 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2368 data
->update
= UPDATEMODE_ENTRY
;
2369 data
->update_pos
= pos2
;
2370 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2380 /**************************************************************************
2382 **************************************************************************/
2383 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
2384 struct MUIP_List_Redraw
*msg
)
2386 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2388 D(bug("[Zune:List] %s()\n", __func__
);)
2390 if (msg
->pos
== MUIV_List_Redraw_All
)
2392 CalcWidths(cl
, obj
);
2393 data
->update
= UPDATEMODE_ALL
;
2394 if (!(data
->flags
& LIST_QUIET
))
2396 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2399 data
->flags
|= LIST_CHANGED
;
2404 if (msg
->pos
== MUIV_List_Redraw_Active
)
2405 pos
= data
->entries_active
;
2406 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
2409 for (i
= 0; i
< data
->entries_num
; i
++)
2410 if (data
->entries
[i
]->data
== msg
->entry
)
2421 data
->entries
[pos
]->flags
|= ENTRY_RENDER
;
2422 if (!(data
->flags
& LIST_QUIET
))
2424 if (CalcDimsOfEntry(cl
, obj
, pos
))
2425 data
->update
= UPDATEMODE_ALL
;
2428 data
->update
= UPDATEMODE_ENTRY
;
2429 data
->update_pos
= pos
;
2432 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2436 if (CalcDimsOfEntry(cl
, obj
, pos
))
2437 data
->update
= UPDATEMODE_ALL
;
2438 else if (!(data
->update
& UPDATEMODE_ALL
))
2439 data
->update
= UPDATEMODE_NEEDED
;
2440 data
->flags
|= LIST_CHANGED
;
2448 /****** List.mui/MUIM_List_Remove ********************************************
2451 * MUIM_List_Remove (V4)
2454 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2457 * Removes entries from the list. If a destruct hook has been
2458 * installed, it will be called for the removed entry.
2461 * pos - the index of the entry to be removed. The following
2462 * special values can also be used:
2463 * MUIV_List_Remove_First: remove the first entry.
2464 * MUIV_List_Remove_Last: remove the last entry.
2465 * MUIV_List_Remove_Active: remove the active entry.
2466 * MUIV_List_Remove_Selected: remove all selected entries
2467 * (or the active entry if there are no selected entries).
2470 * When the active entry is removed, the next entry becomes active
2471 * (if there is no entry below the active entry, the previous entry
2472 * becomes active instead).
2475 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2477 ******************************************************************************
2479 * It was not possible to use MUIM_List_NextSelected here because that method
2480 * may skip entries if entries are removed during an iteration.
2484 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
2485 struct MUIP_List_Remove
*msg
)
2487 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2491 BOOL found
, done
= FALSE
;
2492 struct ListEntry
*lentry
;
2493 Tag active_tag
= TAG_DONE
;
2495 if (!data
->entries_num
)
2500 case MUIV_List_Remove_First
:
2504 case MUIV_List_Remove_Active
:
2505 pos
= data
->entries_active
;
2508 case MUIV_List_Remove_Last
:
2509 pos
= data
->entries_num
- 1;
2512 case MUIV_List_Remove_Selected
:
2521 if (pos
< 0 || pos
>= data
->entries_num
)
2524 new_act
= data
->entries_active
;
2528 if (msg
->pos
== MUIV_List_Remove_Selected
)
2530 /* Find the next selected entry */
2531 for (found
= FALSE
, i
= pos
;
2532 i
< data
->confirm_entries_num
&& !found
; i
++)
2534 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2545 /* If there were no selected entries, remove the active one */
2546 if (data
->confirm_entries_num
== data
->entries_num
2547 && data
->entries_active
!= MUIV_List_Active_Off
)
2549 pos
= data
->entries_active
;
2562 lentry
= data
->entries
[pos
];
2563 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2565 RemoveListEntries(data
, pos
, 1);
2566 data
->confirm_entries_num
--;
2571 active_tag
= MUIA_List_Active
;
2573 else if (pos
== new_act
)
2574 active_tag
= MUIA_List_Active
;
2578 /* Update entries count prior to range check */
2579 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
, TAG_DONE
);
2581 /* Ensure that the active element is in a valid range (it might become
2582 * MUIV_List_Active_Off (-1), but that's OK) */
2583 if (new_act
>= data
->entries_num
)
2584 new_act
= data
->entries_num
- 1;
2587 active_tag
, new_act
, /* Inform only if necessary (for notify) */
2590 data
->flags
|= LIST_CHANGED
;
2591 data
->update
= UPDATEMODE_ALL
;
2592 if (!(data
->flags
& LIST_QUIET
))
2593 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2598 /****** List.mui/MUIM_List_Select ********************************************
2601 * MUIM_List_Select (V4)
2604 * DoMethod(obj, MUIM_List_Select, LONG pos, LONG seltype, LONG *state);
2607 * Selects or deselects entries in the list and/or enquires about their
2608 * current selection state. If a multiselection test hook has been
2609 * installed via MUIA_List_MultiTestHook, it will be called to validate
2610 * the requested selection.
2612 * This method may also be used to count the number of selected entries
2616 * pos - the index of the entry to be selected. The following
2617 * special values can also be used:
2618 * MUIV_List_Select_Active: Select the active entry.
2619 * MUIV_List_Select_All: Select all entries.
2620 * seltype - the new selection state; one of the following:
2621 * MUIV_List_Select_Off: Select the entry.
2622 * MUIV_List_Select_On: Deselect the entry.
2623 * MUIV_List_Select_Toggle: Switch to the alternate selection state.
2624 * MUIV_List_Select_Ask: Do not change the selection state, just
2625 * retrieve the current state. If 'pos' is MUIV_List_Select_All,
2626 * the number of selected entries will be retrieved instead (V9).
2627 * state - a pointer in which to fill in the previous selection state
2628 * (either MUIV_List_Select_On or MUIV_List_Select_Off) or the
2629 * number of selected entries. May be NULL.
2632 * If pos is MUIV_List_Select_All and seltype is not
2633 * MUIV_List_Select_Ask, the value filled in 'state' is undefined.
2636 * MUIA_List_Active, MUIA_List_MultiTestHook.
2638 ******************************************************************************
2642 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2643 struct MUIP_List_Select
*msg
)
2645 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2646 LONG pos
, i
, count
, selcount
= 0, state
= 0;
2647 BOOL multi_allowed
= TRUE
, new_multi_allowed
, new_select_state
= FALSE
;
2649 /* Establish the range of entries affected */
2652 case MUIV_List_Select_Active
:
2653 pos
= data
->entries_active
;
2654 if (pos
== MUIV_List_Active_Off
)
2660 case MUIV_List_Select_All
:
2662 count
= data
->entries_num
;
2668 if (pos
< 0 || pos
>= data
->entries_num
)
2673 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2675 /* Count selected entries and disallow selection of additional
2676 entries if there is a currently selected entry that is not
2678 for (i
= 0; i
< data
->entries_num
&& multi_allowed
; i
++)
2680 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2683 if (data
->multi_test_hook
!= NULL
&& selcount
== 1)
2684 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2685 data
->entries
[i
]->data
);
2690 /* Change or check state of each entry in the range */
2691 for (i
= pos
; i
< pos
+ count
; i
++)
2693 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2694 switch (msg
->seltype
)
2696 case MUIV_List_Select_Off
:
2697 new_select_state
= FALSE
;
2700 case MUIV_List_Select_On
:
2701 new_select_state
= TRUE
;
2704 case MUIV_List_Select_Toggle
:
2705 new_select_state
= !state
;
2709 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2714 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2716 if (new_select_state
&& !state
)
2718 /* Check if there is potential to select an additional entry */
2719 if (multi_allowed
|| selcount
== 0)
2721 /* Check if the entry to be selected is multi-selectable */
2722 if (data
->multi_test_hook
!= NULL
)
2723 new_multi_allowed
= CallHookPkt(data
->multi_test_hook
,
2724 NULL
, data
->entries
[i
]->data
);
2726 new_multi_allowed
= TRUE
;
2728 /* Check if the entry to be selected can be selected at
2729 the same time as the already selected entries */
2730 if (new_multi_allowed
|| selcount
== 0)
2732 /* Select the entry and update the selection count
2734 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2737 multi_allowed
= new_multi_allowed
;
2741 else if (!new_select_state
&& state
)
2743 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2749 /* Report old state or number of selected entries */
2752 if (msg
->pos
== MUIV_List_Select_All
2753 && msg
->seltype
== MUIV_List_Select_Ask
)
2754 *msg
->info
= selcount
;
2759 /* Redraw unless it was just an enquiry */
2760 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2763 data
->update
= UPDATEMODE_ALL
;
2766 data
->update
= UPDATEMODE_ENTRY
;
2767 data
->update_pos
= pos
;
2769 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2775 /****** List.mui/MUIM_List_Insert ********************************************
2778 * MUIM_List_Insert (V4)
2781 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2784 * Adds multiple entries to the list. If a construct hook has been
2785 * installed, the results of passing the entries to this hook will be
2789 * entries - an array of entries to be inserted.
2790 * count - the number of entries to insert. A special value of -1 may be
2791 * used, indicating that the array of entries is NULL-terminated.
2792 * pos - the index at which to insert the new entries. The following
2793 * special values can also be used:
2794 * MUIV_List_Insert_Top: insert at index 0.
2795 * MUIV_List_Insert_Bottom: insert after all existing entries.
2796 * MUIV_List_Insert_Active: insert at the index of the active entry
2797 * (or at index 0 if there is no active entry).
2798 * MUIV_List_Insert_Sorted: keep the list sorted.
2801 * MUIM_List_InsertSingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2803 ******************************************************************************
2807 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2808 struct MUIP_List_Insert
*msg
)
2810 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2811 LONG pos
, count
, sort
, active
;
2812 BOOL adjusted
= FALSE
;
2819 /* Count the number of entries */
2820 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2829 case MUIV_List_Insert_Top
:
2833 case MUIV_List_Insert_Active
:
2834 if (data
->entries_active
!= -1)
2835 pos
= data
->entries_active
;
2840 case MUIV_List_Insert_Sorted
:
2841 pos
= data
->entries_num
;
2842 sort
= 1; /* we sort'em later */
2845 case MUIV_List_Insert_Bottom
:
2846 pos
= data
->entries_num
;
2850 if (msg
->pos
> data
->entries_num
)
2851 pos
= data
->entries_num
;
2852 else if (msg
->pos
< 0)
2858 data
->insert_position
= pos
;
2860 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2863 LONG until
= pos
+ count
;
2864 APTR
*toinsert
= msg
->entries
;
2866 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2871 struct ListEntry
*lentry
;
2873 if (!(lentry
= AllocListEntry(data
)))
2875 /* Panic, but we must be in a consistent state, so remove
2876 * the space where the following list entries should have gone
2878 RemoveListEntries(data
, pos
, until
- pos
);
2882 /* now call the construct method which returns us a pointer which
2884 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2885 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2888 FreeListEntry(data
, lentry
);
2889 RemoveListEntries(data
, pos
, until
- pos
);
2891 /* TODO: Also check for visible stuff like below */
2892 if (data
->entries_num
!= data
->confirm_entries_num
)
2893 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2897 lentry
->flags
|= ENTRY_RENDER
;
2898 data
->entries
[pos
] = lentry
;
2899 data
->confirm_entries_num
++;
2901 data
->flags
|= LIST_CHANGED
;
2903 if (_flags(obj
) & MADF_SETUP
)
2905 /* We have to calculate the width and height of the newly
2906 * inserted entry. This has to be done after inserting the
2907 * element into the list */
2908 if (CalcDimsOfEntry(cl
, obj
, pos
))
2917 /* Recalculate the number of visible entries */
2918 if (_flags(obj
) & MADF_SETUP
)
2919 CalcVertVisible(cl
, obj
);
2921 if (data
->entries_num
!= data
->confirm_entries_num
)
2924 MUIA_List_Entries
, data
->confirm_entries_num
,
2925 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2928 /* If the array is already sorted, we could do a simple insert
2929 * sort and would be much faster than with qsort.
2930 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2931 * sort the whole array?
2933 * I think, we better sort the whole array:
2937 /* TODO: which pos to return here !? */
2938 DoMethod(obj
, MUIM_List_Sort
);
2940 if ((adjusted
) && (data
->flags
& LIST_QUIET
))
2941 data
->update
= UPDATEMODE_ALL
;
2945 data
->update
= UPDATEMODE_ALL
;
2946 if (!(data
->flags
& LIST_QUIET
))
2947 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2949 superset(cl
, obj
, MUIA_List_InsertPosition
, data
->insert_position
);
2951 /* Update index of active entry */
2952 if (data
->entries_active
>= data
->insert_position
)
2954 active
= data
->entries_active
+ count
;
2955 SET(obj
, MUIA_List_Active
, active
);
2961 /****** List.mui/MUIM_List_InsertSingle **************************************
2964 * MUIM_List_InsertSingle (V7)
2967 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2970 * Adds a single entry to the list. If a construct hook has been
2971 * installed, the result of passing the entry to this hook will be
2975 * entry - the entry to be inserted.
2976 * pos - the index at which to insert the new entry. The following
2977 * special values can also be used:
2978 * MUIV_List_Insert_Top: insert at index 0.
2979 * MUIV_List_Insert_Bottom: insert after all existing entries.
2980 * MUIV_List_Insert_Active: insert at the index of the active entry
2981 * (or at index 0 if there is no active entry).
2982 * MUIV_List_Insert_Sorted: keep the list sorted.
2985 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2987 ******************************************************************************
2991 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2992 struct MUIP_List_InsertSingle
*msg
)
2994 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2998 /****** List.mui/MUIM_List_GetEntry ******************************************
3001 * MUIM_List_GetEntry (V4)
3004 * DoMethod(obj, MUIM_List_GetEntry, LONG pos, APTR *entry);
3007 * Retrieves an entry from the list. If the requested entry position is
3008 * invalid, the entry will be NULL.
3011 * pos - the index of the entry to get, or the special value
3012 * MUIV_List_GetEntry_Active to get the active entry.
3013 * entry - a pointer to a variable in which to store a pointer to the
3017 * MUIM_List_Insert, MUIM_List_InsertSingle, MUIM_List_Remove.
3019 ******************************************************************************
3023 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
3024 struct MUIP_List_GetEntry
*msg
)
3026 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3029 if (pos
== MUIV_List_GetEntry_Active
)
3030 pos
= data
->entries_active
;
3032 if (pos
< 0 || pos
>= data
->entries_num
)
3037 *msg
->entry
= data
->entries
[pos
]->data
;
3038 return (IPTR
) *msg
->entry
;
3041 /**************************************************************************
3043 **************************************************************************/
3044 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
3045 struct MUIP_List_Construct
*msg
)
3047 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3049 if (NULL
== data
->construct_hook
)
3050 return (IPTR
) msg
->entry
;
3051 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
3053 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
3054 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
3059 if (msg
->entry
!= NULL
)
3060 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
3062 *(STRPTR
) (mem
+ 1) = 0;
3063 return (IPTR
) (mem
+ 1);
3065 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
3068 /**************************************************************************
3070 **************************************************************************/
3071 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
3072 struct MUIP_List_Destruct
*msg
)
3074 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3076 if (NULL
== data
->destruct_hook
)
3079 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
3081 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
3082 FreePooled(msg
->pool
, mem
, mem
[0]);
3086 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
3091 /****** List.mui/MUIM_List_Compare *******************************************
3094 * MUIM_List_Compare (V20)
3097 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
3098 * LONG sort_type1, LONG sort_type2);
3101 * Compare two list entries according to the current comparison hook
3102 * (MUIA_List_CompareHook).
3105 * entry1 - the first entry data.
3106 * entry2 - the second entry data.
3107 * sort_type1 - undocumented.
3108 * sort_type2 - undocumented.
3111 * MUIA_List_CompareHook, MUIM_List_Sort.
3113 ******************************************************************************
3117 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
3118 struct MUIP_List_Compare
*msg
)
3120 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3122 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
3125 /**************************************************************************
3127 **************************************************************************/
3128 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
3129 struct MUIP_List_Display
*msg
)
3131 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3133 if (NULL
== data
->display_hook
)
3136 *msg
->array
= msg
->entry
;
3142 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
3143 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
3146 /**************************************************************************
3147 MUIM_List_SelectChange
3148 **************************************************************************/
3149 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
3150 struct MUIP_List_SelectChange
*msg
)
3155 /****** List.mui/MUIM_List_CreateImage ***************************************
3158 * MUIM_List_CreateImage (V11)
3161 * DoMethod(obj, MUIM_List_CreateImage, Object *area, ULONG flags);
3164 * Creates an image to be inserted within list entries. An instance of
3165 * any Area subclass is passed in and a blackbox value is returned that
3166 * can be displayed by embedding its hexadecimal representation within
3167 * any of the list's display strings (provided either statically or by
3168 * the list's display hook. The format string to be used is
3171 * It is recommended that lists that embed images are instances of a
3172 * custom subclass so that this method can be called in the list's
3173 * MUIM_Setup method, and MUIM_List_DeleteImage can be called in the
3174 * list's MUIM_Cleanup method. However, this is not necessary as long as
3175 * MUIM_List_CreateImage is called after the list has had its MUIM_Setup
3176 * called, and MUIM_List_DeleteImage is called after the list has had its
3177 * MUIM_Cleanup method called.
3180 * area - the area object that is used to generate the image.
3181 * flags - must be zero.
3184 * A blackbox reference to the list image, or NULL on an error.
3187 * If this method returns NULL, no special action needs to be taken, as
3188 * embedding this value in a list string will simply cause no image to
3191 * The object passed in becomes a child of the list, so it cannot be used
3192 * elsewhere simultaneously.
3195 * MUIM_List_DeleteImage, MUIA_List_DisplayHook.
3197 ******************************************************************************
3199 * Connects an Area subclass object to the list, much like an object gets
3200 * connected to a window. List calls Setup and AskMinMax on that object,
3201 * keeps a reference to it (that reference will be returned).
3202 * Text engine will dereference that pointer and draw the object with its
3207 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
3208 struct MUIP_List_CreateImage
*msg
)
3210 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3211 struct ListImage
*li
;
3216 /* List must be already setup in Setup of your subclass */
3217 if (!(_flags(obj
) & MADF_SETUP
))
3219 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
3224 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
3225 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
3226 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
3232 /****** List.mui/MUIM_List_DeleteImage ***************************************
3235 * MUIM_List_DeleteImage (V11)
3238 * DoMethod(obj, MUIM_List_DeleteImage, APTR image);
3241 * Deletes an image created by MUIM_List_CreateImage.
3244 * image - a blackbox reference to the list image, or NULL.
3247 * MUIM_List_CreateImage, MUIA_List_DisplayHook.
3249 ******************************************************************************
3253 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
3254 struct MUIP_List_DeleteImage
*msg
)
3256 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3257 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
3261 DoMethod(li
->obj
, MUIM_Cleanup
);
3262 DoMethod(li
->obj
, MUIM_DisconnectParent
);
3263 Remove((struct Node
*)li
);
3264 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
3270 /****** List.mui/MUIM_List_Jump **********************************************
3273 * MUIM_List_Jump (V4)
3276 * DoMethod(obj, MUIM_List_Jump, LONG pos);
3279 * Scrolls the list so that a particular entry is visible.
3282 * pos - index of entry that should become visible, or one of these
3284 * MUIV_List_Jump_Active: show the active entry.
3285 * MUIV_List_Jump_Top: show the first entry.
3286 * MUIV_List_Jump_Bottom: show the last entry.
3287 * MUIV_List_Jump_Up: show the previous hidden entry.
3288 * MUIV_List_Jump_Down: show the next hidden entry.
3290 ******************************************************************************
3294 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
3295 struct MUIP_List_Jump
*msg
)
3297 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3298 LONG pos
= msg
->pos
;
3302 case MUIV_List_Jump_Top
:
3306 case MUIV_List_Jump_Active
:
3307 pos
= data
->entries_active
;
3310 case MUIV_List_Jump_Bottom
:
3311 pos
= data
->entries_num
- 1;
3314 case MUIV_List_Jump_Down
:
3315 pos
= data
->entries_first
+ data
->entries_visible
;
3318 case MUIV_List_Jump_Up
:
3319 pos
= data
->entries_first
- 1;
3323 if (pos
>= data
->entries_num
)
3325 pos
= data
->entries_num
- 1;
3330 if (pos
< data
->entries_first
)
3332 set(obj
, MUIA_List_First
, pos
);
3334 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
3336 pos
-= (data
->entries_visible
- 1);
3339 if (pos
!= data
->entries_first
)
3341 set(obj
, MUIA_List_First
, pos
);
3348 /****** List.mui/MUIM_List_Sort **********************************************
3351 * MUIM_List_Sort (V4)
3354 * DoMethod(obj, MUIM_List_Sort);
3357 * Sort the list's entries according to the current comparison hook
3358 * (MUIA_List_CompareHook).
3361 * The active index does not change, so the active entry may do so.
3364 * MUIA_List_CompareHook, MUIM_List_Compare.
3366 ******************************************************************************
3370 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
3371 struct MUIP_List_Sort
*msg
)
3373 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3376 struct MUIP_List_Compare cmpmsg
=
3377 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
3378 BOOL changed
= FALSE
;
3380 D(bug("[Zune:List] %s()\n", __func__
);)
3382 if (data
->entries_num
> 1)
3385 Simple sort algorithm. Feel free to improve it.
3387 for (i
= 0; i
< data
->entries_num
- 1; i
++)
3390 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
3392 cmpmsg
.entry1
= data
->entries
[max
]->data
;
3393 cmpmsg
.entry2
= data
->entries
[j
]->data
;
3394 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
3401 APTR tmp
= data
->entries
[i
];
3402 data
->entries
[i
] = data
->entries
[max
];
3403 data
->entries
[i
]->flags
|= ENTRY_RENDER
;
3404 data
->entries
[max
] = tmp
;
3405 data
->entries
[max
]->flags
|= ENTRY_RENDER
;
3406 if (data
->entries_active
== i
)
3407 data
->entries_active
= max
;
3408 else if (data
->entries_active
== max
)
3409 data
->entries_active
= i
;
3417 data
->flags
|= LIST_CHANGED
;
3418 if (!(data
->update
& UPDATEMODE_ALL
))
3419 data
->update
= UPDATEMODE_NEEDED
;
3420 if (!(data
->flags
& LIST_QUIET
))
3421 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3427 /****** List.mui/MUIM_List_Move **********************************************
3430 * MUIM_List_Move (V9)
3433 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
3436 * Move a list entry to a new position.
3439 * from - the current index of the entry that should be moved, or one of
3440 * these special values:
3441 * MUIV_List_Move_Active: the active entry.
3442 * MUIV_List_Move_Top: the first entry.
3443 * MUIV_List_Move_Bottom: the last entry.
3444 * to - the index of the entry's new position, or one of
3445 * these special values:
3446 * MUIV_List_Move_Active: the active entry.
3447 * MUIV_List_Move_Top: the first entry.
3448 * MUIV_List_Move_Bottom: the last entry.
3451 * The active index does not change, so the active entry may do so.
3454 * MUIM_List_Exchange
3456 ******************************************************************************
3460 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
3461 struct MUIP_List_Move
*msg
)
3463 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3468 /* Normalise special 'from' values */
3471 case MUIV_List_Move_Top
:
3474 case MUIV_List_Move_Active
:
3475 from
= data
->entries_active
;
3477 case MUIV_List_Move_Bottom
:
3478 from
= data
->entries_num
- 1;
3484 /* Normalise special 'to' values */
3487 case MUIV_List_Move_Top
:
3490 case MUIV_List_Move_Active
:
3491 to
= data
->entries_active
;
3493 case MUIV_List_Move_Bottom
:
3494 to
= data
->entries_num
- 1;
3496 case MUIV_List_Move_Next
:
3499 case MUIV_List_Move_Previous
:
3506 /* Check that values are within valid bounds */
3507 if (from
> data
->entries_num
- 1 || from
< 0
3508 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
3509 return (IPTR
) FALSE
;
3511 /* Shift all entries in the range between the 'from' and 'to' positions */
3514 struct ListEntry
*backup
= data
->entries
[from
];
3515 for (i
= from
; i
< to
; i
++)
3516 data
->entries
[i
] = data
->entries
[i
+ 1];
3517 data
->entries
[to
] = backup
;
3521 struct ListEntry
*backup
= data
->entries
[from
];
3522 for (i
= from
; i
> to
; i
--)
3523 data
->entries
[i
] = data
->entries
[i
- 1];
3524 data
->entries
[to
] = backup
;
3527 #if 0 /* Not done in MUI 3 */
3528 /* Update index of active entry */
3529 if (from
== data
->entries_active
)
3530 data
->entries_active
= to
;
3531 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
3532 data
->entries_active
--;
3533 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
3534 data
->entries_active
++;
3537 /* Reflect list changes visually */
3538 data
->flags
|= LIST_CHANGED
;
3539 data
->update
= UPDATEMODE_ALL
;
3540 if (!(data
->flags
& LIST_QUIET
))
3541 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3546 /****** List.mui/MUIM_List_NextSelected **************************************
3549 * MUIM_List_NextSelected (V6)
3552 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3555 * Allows iteration through a list's selected entries by providing the
3556 * index of the next selected entry after the specified index.
3559 * pos - the address of a variable containing the index of the previous
3560 * selected entry. The variable must be initialised to the special
3561 * value MUIV_List_NextSelected_Start to find the first selected
3562 * entry. When this method returns, the variable will contain the
3563 * index of the next selected entry, or MUIV_List_NextSelected_End if
3564 * there are no more.
3567 * If there are no selected entries but there is an active entry, the
3568 * index of the active entry will be stored (when
3569 * MUIV_List_NextSelected_Start is specified).
3571 * Some selected entries may be skipped if any entries are removed
3572 * between calls to this method during an iteration of a list.
3574 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3575 * the same numeric value.
3578 * MUIM_List_Select, MUIM_List_Remove.
3580 ******************************************************************************
3584 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
3585 struct MUIP_List_NextSelected
*msg
)
3587 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3591 /* Get the first entry to check */
3593 if (pos
== MUIV_List_NextSelected_Start
)
3598 /* Find the next selected entry */
3599 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
3601 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
3608 /* Return index of selected or active entry, or indicate there are no
3612 if (*msg
->pos
== MUIV_List_NextSelected_Start
3613 && data
->entries_active
!= MUIV_List_Active_Off
)
3614 pos
= data
->entries_active
;
3616 pos
= MUIV_List_NextSelected_End
;
3623 /**************************************************************************
3625 **************************************************************************/
3626 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
3627 struct MUIP_List_TestPos
*msg
)
3629 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3630 struct MUI_List_TestPos_Result
*result
= msg
->res
;
3631 LONG col
= -1, row
= -1;
3635 LONG entries_visible
;
3637 if (data
->entries_visible
<= data
->entries_num
)
3638 entries_visible
= data
->entries_visible
;
3640 entries_visible
= data
->entries_num
;
3642 if ((msg
->x
== MUI_MAXMAX
) && (msg
->y
== MUI_MAXMAX
))
3653 if ((mx
!= MUI_MAXMAX
) && (ey
!= MUI_MAXMAX
))
3655 mx
-= _left(data
->area
);
3656 /* y coordinates transformed to the entries */
3657 ey
-= data
->entries_top_pixel
;
3659 /* Now check if it was clicked on a title or on entries */
3661 flags
|= MUI_LPR_ABOVE
;
3662 else if (ey
>= entries_visible
* data
->entry_maxheight
)
3663 flags
|= MUI_LPR_BELOW
;
3667 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
3669 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
3673 flags
|= MUI_LPR_LEFT
;
3674 else if (mx
>= _width(data
->area
))
3675 flags
|= MUI_LPR_RIGHT
;
3678 /* Identify column */
3679 if (data
->entries_num
> 0 && data
->columns
> 0)
3682 col
= data
->columns
- 1;
3683 for (i
= 0; i
< data
->columns
; i
++)
3685 result
->xoffset
= mx
- width_sum
;
3687 data
->ci
[i
].entries_width
+
3689 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
3690 D(bug("[List/MUIM_TestPos] i %d "
3691 "width %d width_sum %d mx %d\n",
3692 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
3696 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
3704 result
->entry
= row
;
3705 result
->column
= col
;
3706 result
->flags
= flags
;
3711 /****i* List.mui/MUIM_DragQuery **********************************************
3716 ******************************************************************************
3720 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
3721 struct MUIP_DragQuery
*msg
)
3723 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3725 if (msg
->obj
== obj
&& (data
->flags
& LIST_DRAGSORTABLE
))
3726 return MUIV_DragQuery_Accept
;
3728 return MUIV_DragQuery_Refuse
;
3732 /****i* List.mui/MUIM_DragFinish *********************************************
3737 ******************************************************************************
3741 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
3742 struct MUIP_DragFinish
*msg
)
3744 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3746 data
->drop_mark_y
= -1;
3748 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3751 /****i* List.mui/MUIM_DragReport *********************************************
3756 ******************************************************************************
3760 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
3761 struct MUIP_DragReport
*msg
)
3763 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3764 struct MUI_List_TestPos_Result pos
;
3765 struct RastPort
*rp
= _rp(obj
);
3769 /* Choose new drop mark position */
3771 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3772 if (pos
.entry
!= -1)
3775 if (pos
.yoffset
> 0)
3778 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3779 n
= data
->entries_first
;
3782 n
= MIN(data
->entries_visible
, data
->entries_num
)
3783 - data
->entries_first
;
3786 /* Clear old drop mark */
3788 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
3790 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
3791 * data
->entry_maxheight
;
3792 if (y
!= data
->drop_mark_y
)
3794 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
3795 data
->drop_mark_y
, _mwidth(data
->area
), 1, 0, 0, 0);
3797 /* Draw new drop mark and store its position */
3799 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
3801 old_pattern
= rp
->LinePtrn
;
3802 SetDrPt(rp
, 0xF0F0);
3803 Move(rp
, _mleft(data
->area
), y
);
3804 Draw(rp
, _mright(data
->area
), y
);
3805 SetDrPt(rp
, old_pattern
);
3806 data
->drop_mark_y
= y
;
3814 /****i* List.mui/MUIM_DragDrop ***********************************************
3819 ******************************************************************************
3823 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
3824 struct MUIP_DragDrop
*msg
)
3826 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3827 struct MUI_List_TestPos_Result pos
;
3830 /* Find drop position */
3832 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3833 if (pos
.entry
!= -1)
3835 /* Change drop position when coords move past centre of entry, not
3839 if (pos
.yoffset
> 0)
3842 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3845 n
= data
->entries_num
;
3847 data
->drop_mark
= n
;
3849 if (data
->flags
& LIST_DRAGSORTABLE
)
3851 /* Ensure that dropped entry will be positioned between the two
3852 * entries that are above and below the drop mark, rather than
3853 * strictly at the numeric index shown */
3855 if (n
> data
->entries_active
)
3858 DoMethod(obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
3859 SET(obj
, MUIA_List_Active
, n
);
3866 /****i* List.mui/MUIM_CreateDragImage ****************************************
3869 * MUIM_CreateDragImage
3871 ******************************************************************************
3875 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
3876 struct MUIP_CreateDragImage
*msg
)
3878 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3879 BOOL success
= TRUE
;
3880 struct MUI_List_TestPos_Result pos
;
3881 WORD width
, height
, left
, top
;
3882 struct MUI_DragImage
*img
= NULL
;
3883 const struct ZuneFrameGfx
*zframe
;
3886 /* If entries aren't draggable, allow the list as a whole to be */
3887 if (data
->drag_type
== MUIV_Listview_DragType_None
)
3888 return DoSuperMethodA(cl
, obj
, msg
);
3890 /* Get info on dragged entry */
3891 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
3892 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
3893 if (pos
.entry
== -1)
3898 /* Get boundaries of entry */
3899 width
= _mwidth(data
->area
);
3900 height
= data
->entry_maxheight
;
3901 left
= _mleft(data
->area
);
3902 top
= _top(data
->area
) - msg
->touchy
3903 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3905 /* Allocate drag image structure */
3906 img
= (struct MUI_DragImage
*)
3907 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3914 /* Get drag frame */
3915 zframe
= zune_zframe_get(obj
,
3916 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3918 /* Allocate drag image buffer */
3919 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3920 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3921 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3922 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3923 _screen(obj
)->RastPort
.BitMap
);
3925 if (img
->bm
!= NULL
)
3928 struct RastPort temprp
;
3929 InitRastPort(&temprp
);
3930 temprp
.BitMap
= img
->bm
;
3931 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3932 zframe
->ileft
, zframe
->itop
, width
, height
,
3936 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3937 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3938 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3939 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3940 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3943 /* Ensure drag point matches where user clicked */
3944 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3945 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3953 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3955 LONG
new, first
, entries
, visible
;
3957 new = first
= XGET(obj
, MUIA_List_First
);
3958 entries
= XGET(obj
, MUIA_List_Entries
);
3959 visible
= XGET(obj
, MUIA_List_Visible
);
3963 if (new > entries
- visible
)
3965 new = entries
- visible
;
3975 set(obj
, MUIA_List_First
, new);
3979 /**************************************************************************
3981 **************************************************************************/
3982 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3983 struct MUIP_HandleEvent
*msg
)
3985 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3986 struct MUI_List_TestPos_Result pos
;
3987 LONG seltype
= MUIV_List_Select_On
, old_active
, new_active
, visible
,
3990 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3992 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3994 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3995 visible
= XGET(obj
, MUIA_List_Visible
);
3997 if (muikey
!= MUIKEY_NONE
)
3999 result
= MUI_EventHandlerRC_Eat
;
4001 /* Make keys behave differently in read-only mode */
4002 if (data
->read_only
)
4007 muikey
= MUIKEY_LINESTART
;
4011 muikey
= MUIKEY_LINEEND
;
4015 muikey
= MUIKEY_LEFT
;
4020 muikey
= MUIKEY_RIGHT
;
4028 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
4029 && !data
->read_only
)
4032 data
->click_column
= data
->def_click_column
;
4033 new_active
= MUIV_List_Active_Down
;
4037 DoMethod(obj
, MUIM_List_Jump
, 0);
4038 muikey
= MUIKEY_NONE
;
4043 new_active
= MUIV_List_Active_Top
;
4047 new_active
= MUIV_List_Active_Bottom
;
4051 case MUIKEY_WORDLEFT
:
4052 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
4056 case MUIKEY_WORDRIGHT
:
4057 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
4060 case MUIKEY_LINESTART
:
4061 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
4064 case MUIKEY_LINEEND
:
4065 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
4069 new_active
= MUIV_List_Active_Up
;
4073 new_active
= MUIV_List_Active_Down
;
4077 data
->click_column
= data
->def_click_column
;
4078 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
4079 data
->click_column
);
4080 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
4084 if (data
->read_only
)
4085 DoWheelMove(cl
, obj
, -visible
);
4087 new_active
= MUIV_List_Active_PageUp
;
4090 case MUIKEY_PAGEDOWN
:
4091 if (data
->read_only
)
4092 DoWheelMove(cl
, obj
, visible
);
4094 new_active
= MUIV_List_Active_PageDown
;
4103 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
,
4106 switch (msg
->imsg
->Class
)
4108 case IDCMP_MOUSEBUTTONS
:
4109 if (msg
->imsg
->Code
== SELECTDOWN
)
4111 if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
4114 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
4116 if (!data
->read_only
&& pos
.entry
!= -1)
4118 new_active
= pos
.entry
;
4120 clear
= (data
->multiselect
4121 == MUIV_Listview_MultiSelect_Shifted
4122 && (msg
->imsg
->Qualifier
4123 & (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
4124 seltype
= clear
? MUIV_List_Select_On
4125 : MUIV_List_Select_Toggle
;
4126 select
= data
->multiselect
4127 != MUIV_Listview_MultiSelect_None
;
4129 /* Handle MUIA_Listview_ClickColumn */
4130 data
->click_column
= pos
.column
;
4131 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
4132 data
->click_column
);
4134 /* Handle double clicking */
4135 if (data
->last_active
== pos
.entry
4136 && DoubleClick(data
->last_secs
, data
->last_mics
,
4137 msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
4139 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
4140 data
->last_active
= -1;
4141 data
->last_secs
= data
->last_mics
= 0;
4145 data
->last_active
= pos
.entry
;
4146 data
->last_secs
= msg
->imsg
->Seconds
;
4147 data
->last_mics
= msg
->imsg
->Micros
;
4150 /* Look out for mouse movement, timer and
4151 inactive-window events while mouse button is
4153 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
4155 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
4156 | IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
4157 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
4164 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
4166 /* cache click position ... */
4167 data
->mouse_x
= msg
->imsg
->MouseX
;
4168 data
->mouse_y
= msg
->imsg
->MouseY
;
4170 /* ... and activate the object */
4171 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
4172 data
->mouse_click
= 0;
4175 /* Restore normal event mask */
4176 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
4178 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
4179 | IDCMP_INACTIVEWINDOW
);
4180 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
4185 case IDCMP_MOUSEMOVE
:
4186 case IDCMP_INTUITICKS
:
4187 if (pos
.flags
& MUI_LPR_ABOVE
)
4188 new_active
= MUIV_List_Active_Up
;
4189 else if (pos
.flags
& MUI_LPR_BELOW
)
4190 new_active
= MUIV_List_Active_Down
;
4192 new_active
= pos
.entry
;
4194 select
= new_active
!= old_active
4195 && data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
4198 seltype
= data
->seltype
;
4199 range_select
= new_active
>= 0;
4204 case IDCMP_INACTIVEWINDOW
:
4205 /* Stop listening for events we only listen to when mouse button is
4206 down: we will not be informed of the button being released */
4207 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
4209 data
->ehn
.ehn_Events
&=
4210 ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
4211 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
4217 if (data
->vert
&& _isinobject(data
->vert
, msg
->imsg
->MouseX
,
4220 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
4228 switch (msg
->imsg
->Code
)
4230 case RAWKEY_NM_WHEEL_UP
:
4231 DoWheelMove(cl
, obj
, -delta
);
4234 case RAWKEY_NM_WHEEL_DOWN
:
4235 DoWheelMove(cl
, obj
, delta
);
4238 result
= MUI_EventHandlerRC_Eat
;
4244 /* Decide in advance if any selections may change */
4245 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
4247 /* Change selected and active entries */
4250 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
4251 MUIV_List_Select_Off
, NULL
);
4254 if (muikey
== MUIKEY_TOGGLE
)
4256 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
4257 MUIV_List_Select_Toggle
, NULL
);
4261 if (new_active
!= old_active
)
4262 set(obj
, MUIA_List_Active
, new_active
);
4268 if (old_active
< new_active
)
4269 first
= old_active
+ 1, last
= new_active
;
4271 first
= new_active
, last
= old_active
- 1;
4272 for (i
= first
; i
<= last
; i
++)
4273 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
4277 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
4279 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
4280 MUIV_List_Select_Ask
, &data
->seltype
);
4285 superset(cl
, obj
, MUIA_Listview_SelectChange
, TRUE
);
4290 /**************************************************************************
4292 **************************************************************************/
4293 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
4295 switch (msg
->MethodID
)
4298 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
4300 return List__OM_DISPOSE(cl
, obj
, msg
);
4302 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
4304 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
4307 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
4309 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
4310 case MUIM_HandleEvent
:
4311 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
4312 case MUIM_AskMinMax
:
4313 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
4315 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
4317 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
4319 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
4321 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
4322 case MUIM_List_Clear
:
4323 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
4324 case MUIM_List_Sort
:
4325 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
4326 case MUIM_List_Exchange
:
4327 return List__MUIM_Exchange(cl
, obj
,
4328 (struct MUIP_List_Exchange
*)msg
);
4329 case MUIM_List_Insert
:
4330 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
4331 case MUIM_List_InsertSingle
:
4332 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
4333 case MUIM_List_GetEntry
:
4334 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
4335 case MUIM_List_Redraw
:
4336 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
4337 case MUIM_List_Remove
:
4338 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
4339 case MUIM_List_Select
:
4340 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
4341 case MUIM_List_Construct
:
4342 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
4343 case MUIM_List_Destruct
:
4344 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
4345 case MUIM_List_Compare
:
4346 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
4347 case MUIM_List_Display
:
4348 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
4349 case MUIM_List_SelectChange
:
4350 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
4351 case MUIM_List_CreateImage
:
4352 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
4353 case MUIM_List_DeleteImage
:
4354 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
4355 case MUIM_List_Jump
:
4356 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
4357 case MUIM_List_Move
:
4358 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
4359 case MUIM_List_NextSelected
:
4360 return List__MUIM_NextSelected(cl
, obj
,
4361 (struct MUIP_List_NextSelected
*)msg
);
4362 case MUIM_List_TestPos
:
4363 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
4364 case MUIM_DragQuery
:
4365 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
4366 case MUIM_DragFinish
:
4367 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
4368 case MUIM_DragReport
:
4369 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
4371 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
4372 case MUIM_CreateDragImage
:
4373 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
4376 return DoSuperMethodA(cl
, obj
, msg
);
4378 BOOPSI_DISPATCHER_END
4383 const struct __MUIBuiltinClass _MUI_List_desc
=
4387 sizeof(struct MUI_ListData
),
4388 (void *) List_Dispatcher