2 Copyright © 2002-2016, 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"
57 LONG width
; /* Line width */
58 LONG height
; /* Line height */
59 WORD flags
; /* see below */
60 LONG widths
[]; /* Widths of the columns */
63 #define ENTRY_SELECTED (1<<0)
68 int colno
; /* Column number */
69 int user_width
; /* user set width; -1 if entry width */
70 int min_width
; /* min width percentage */
71 int max_width
; /* min width percentage */
73 int delta
; /* ignored for the first and last column, defaults to 4 */
76 int entries_width
; /* width of the entries (maximum of all widths) */
79 struct MUI_ImageSpec_intern
;
86 APTR intern_pool
; /* The internal pool which the class has allocated */
87 LONG intern_puddle_size
;
88 LONG intern_thresh_size
;
89 APTR pool
; /* the pool which is used to allocate list entries */
91 struct Hook
*construct_hook
;
92 struct Hook
*compare_hook
;
93 struct Hook
*destruct_hook
;
94 struct Hook
*display_hook
;
95 struct Hook
*multi_test_hook
;
97 struct Hook default_compare_hook
;
99 /* List management, currently we use a simple flat array, which is not
100 * good if many entries are inserted/deleted */
101 LONG entries_num
; /* Number of Entries in the list */
102 LONG entries_allocated
;
103 struct ListEntry
**entries
;
105 LONG entries_first
; /* first visible entry */
106 LONG entries_visible
; /* number of visible entries,
107 * determined at MUIM_Layout */
109 LONG insert_position
; /* pos of the last insertion */
111 LONG entry_maxheight
; /* Maximum height of an entry */
112 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
114 LONG entries_totalheight
;
115 LONG entries_maxwidth
;
117 LONG vertprop_entries
;
118 LONG vertprop_visible
;
121 LONG confirm_entries_num
; /* These are the correct entries num, used
122 * so you cannot set MUIA_List_Entries to
125 LONG entries_top_pixel
; /* Where the entries start */
127 /* Column managment, is allocated by ParseListFormat() and freed
128 * by CleanListFormat() */
130 LONG columns
; /* Number of columns the list has */
131 struct ColumnInfo
*ci
;
133 STRPTR
*strings_mem
; /* safe pointer to allocated memory for strings[] */
134 STRPTR
*strings
; /* the strings for the display function, one
135 * more than needed (for the entry position) */
138 int title_height
; /* The complete height of the title */
139 STRPTR title
; /* On single column lists this is the title,
140 * otherwise 1. NULL for no title(s) */
143 struct MUI_ImageSpec_intern
*list_cursor
;
144 struct MUI_ImageSpec_intern
*list_select
;
145 struct MUI_ImageSpec_intern
*list_selcur
;
147 /* Render optimization */
148 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
149 * 3 - scroll to current entries_first (old value is in
156 struct MinList images
;
159 ListviewRefresh prefs_refresh
;
160 UWORD prefs_linespacing
;
162 UWORD prefs_smoothval
;
164 /* render space handling */
169 /***************************/
170 /* Former Listview members */
171 /***************************/
181 LONG def_click_column
;
183 LONG mouse_click
; /* see below if mouse is held down */
190 struct MUI_EventHandlerNode ehn
;
193 ListviewMulti prefs_multi
;
201 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
202 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
204 #define LIST_ADJUSTWIDTH (1<<0)
205 #define LIST_ADJUSTHEIGHT (1<<1)
206 #define LIST_AUTOVISIBLE (1<<2)
207 #define LIST_DRAGSORTABLE (1<<3)
208 #define LIST_SHOWDROPMARKS (1<<4)
209 #define LIST_QUIET (1<<5)
212 /****** List.mui/MUIA_List_Active ********************************************
215 * MUIA_List_Active -- (V4) [ISG], LONG
218 * The index of the active entry. There can be at most one active entry
219 * in a list. The active entry is highlighted visibly, except for
220 * read-only lists (those whose Listview has MUIA_Listview_Input set to
221 * FALSE). Selecting an entry with the mouse, or moving through the list
222 * with keyboard controls will also change the active entry (again
223 * excepting read-only lists).
225 * When set programmatically through this attribute, some special values
228 * MUIV_List_Active_Off
229 * MUIV_List_Active_Top
230 * MUIV_List_Active_Bottom
231 * MUIV_List_Active_Up
232 * MUIV_List_Active_Down
233 * MUIV_List_Active_PageUp
234 * MUIV_List_Active_PageDown
236 * When this attribute is read, either the index of the active entry or
237 * the special value MUIV_List_Active_Off will be returned.
239 * Setting this attribute to a new value will additionally have the same
240 * effect as calling the MUIM_List_Jump method with the specified or
244 * The concept of an active entry must not be confused with that of a
248 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
250 ******************************************************************************
254 /****** List.mui/MUIA_List_CompareHook ***************************************
257 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
260 * The provided hook indicates the sort ordering of two list entries.
261 * The hook receives list-entry data pointers as its second and third
262 * arguments. The hook should return a negative value if the first entry
263 * should be placed before the second entry, a positive value if the
264 * first entry should be placed after the second entry, and zero if the
267 * In addition to being used internally for sorting operations, this hook
268 * will be called when MUIM_List_Compare is externally invoked.
270 * If this attribute is not specified or is set to NULL, all list entries
273 ******************************************************************************
277 /****** List.mui/MUIA_List_First *********************************************
280 * MUIA_List_First -- (V4) [..G], LONG
283 * The index of the first entry that can be seen (assuming nothing
284 * obscures the list) This value of this attribute is -1 when the
285 * list's window is not open.
288 * Notification does not occur on this attribute in MUI.
291 * MUIA_List_First, MUIA_List_Entries
293 ******************************************************************************
297 /****** List.mui/MUIA_List_MultiTestHook *************************************
300 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
303 * The provided hook indicates whether a particular list entry
304 * may be multiselected. The hook receives the list-entry data pointer as
305 * its third argument, and returns a Boolean value. If this attribute is
306 * not specified or is set to NULL, all list entries are considered
309 * Whenever an entry is about to be selected, this hook is called if
310 * there are other entries already selected. If the hook returns TRUE,
311 * the entry may be multi-selected; if the hook returns FALSE, the entry
312 * remains unselected.
314 * Additionally, if a non-multi-selectable entry has been selected (as
315 * the only selected entry in the list), any attempt to select an
316 * additional entry will fail.
318 ******************************************************************************
322 /****** List.mui/MUIA_List_Title *********************************************
325 * MUIA_List_Title -- (V6) [ISG], char *
328 * A heading for the list, placed above list entries. A value of NULL
329 * means no title is used. A value of TRUE means that the custom
330 * display hook provides a separate title for each column; the hook
331 * must then provide column titles instead of normal column data when
332 * the entry pointer provided is NULL.
335 * If a string is set for this attribute, it is not cached within the
339 * MUIA_List_DisplayHook
341 ******************************************************************************
345 /****** List.mui/MUIA_List_Visible *******************************************
348 * MUIA_List_Visible -- (V4) [..G], LONG
351 * The number of entries that can be seen at once with the list's
352 * current dimensions. This value of this attribute is -1 when the
353 * list's window is not open.
356 * Notification does not occur on this attribute in MUI.
359 * MUIA_List_First, MUIA_List_Entries
361 ******************************************************************************
365 /**************************************************************************
366 Allocate a single list entry, does not initialize it (except the pointer)
367 **************************************************************************/
368 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
370 struct ListEntry
*le
;
371 /* what happens, if data->columns is later increased by MUIA_List_Format? */
372 IPTR size
= sizeof(struct ListEntry
) + sizeof(LONG
) * (data
->columns
+ 1);
374 le
= (struct ListEntry
*) AllocVecPooled(data
->pool
, size
);
375 D(bug("List AllocListEntry %p, %ld bytes\n", le
, size
));
378 /* possible, that we have an external pool, which does not have
385 /**************************************************************************
386 Deallocate a single list entry, does not deinitialize it
387 **************************************************************************/
388 static void FreeListEntry(struct MUI_ListData
*data
,
389 struct ListEntry
*entry
)
391 D(bug("FreeListEntry %p\n", entry
));
392 FreeVecPooled(data
->pool
, entry
);
395 /**************************************************************************
396 Ensures that there can be at least the given amount of entries within
397 the list. Returns 0 if not. It also allocates the space for the title.
398 It can be accessed with data->entries[ENTRY_TITLE]
399 **************************************************************************/
400 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
402 struct ListEntry
**new_entries
;
403 int new_entries_allocated
;
405 if (size
+ 1 <= data
->entries_allocated
)
408 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
409 if (new_entries_allocated
< size
+ 1)
410 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
412 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
413 new_entries_allocated
* sizeof(struct ListEntry
*)));
415 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
416 if (NULL
== new_entries
)
420 CopyMem(data
->entries
- 1, new_entries
,
421 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
422 FreeVec(data
->entries
- 1);
424 data
->entries
= new_entries
+ 1;
425 data
->entries_allocated
= new_entries_allocated
;
429 /**************************************************************************
430 Prepares the insertion of count entries at pos.
431 This function doesn't care if there is enough space in the datastructure.
432 SetListSize() must be used first.
433 With current implementation, this call will never fail
434 **************************************************************************/
435 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
438 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
439 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
443 /**************************************************************************
444 Removes count (already deinitalized) list entries starting az pos.
445 **************************************************************************/
446 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
448 // FIXME: segfault if entries_num = pos = count = 1
449 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
450 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
453 /**************************************************************************
454 Frees all memory allocated by ParseListFormat()
455 **************************************************************************/
456 static void FreeListFormat(struct MUI_ListData
*data
)
462 for (i
= 0; i
< data
->columns
; i
++)
464 FreeVec(data
->ci
[i
].preparse
);
465 data
->ci
[i
].preparse
= NULL
;
470 FreeVec(data
->preparses
);
471 data
->preparses
= NULL
;
472 if (data
->strings_mem
)
474 FreeVec(data
->strings_mem
);
475 data
->strings_mem
= NULL
;
476 data
->strings
= NULL
;
481 /**************************************************************************
482 Parses the given format string (also frees a previously parsed format).
484 **************************************************************************/
485 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
493 struct RDArgs
*rdargs
;
496 format
= (STRPTR
) "";
500 FreeListFormat(data
);
504 /* Count the number of columns first */
509 if (!(data
->preparses
=
510 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
513 if (!(data
->strings_mem
= AllocVec((new_columns
+ 1 + 10)
514 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
515 * used by orginal MUI and also some
518 data
->strings
=data
->strings_mem
;
520 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
524 for (i
= 0; i
< new_columns
; i
++)
526 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
527 data
->ci
[i
].weight
= 100;
528 data
->ci
[i
].delta
= 4;
529 data
->ci
[i
].min_width
= -1;
530 data
->ci
[i
].max_width
= -1;
531 data
->ci
[i
].user_width
= -1;
532 data
->ci
[i
].bar
= FALSE
;
533 data
->ci
[i
].preparse
= NULL
;
536 if ((format_sep
= StrDup(format
)) != 0)
538 for (i
= 0; format_sep
[i
] != '\0'; i
++)
540 if (format_sep
[i
] == ',')
541 format_sep
[i
] = '\0';
544 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
550 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
551 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
552 rdargs
->RDA_Source
.CS_CurChr
= 0;
553 rdargs
->RDA_DAList
= 0;
554 rdargs
->RDA_Buffer
= NULL
;
555 rdargs
->RDA_BufSiz
= 0;
556 rdargs
->RDA_ExtHelp
= NULL
;
557 rdargs
->RDA_Flags
= 0;
559 memset(args
, 0, sizeof args
);
560 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
563 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
564 if (args
[ARG_WEIGHT
])
565 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
567 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
568 if (args
[ARG_MINWIDTH
])
569 data
->ci
[i
].min_width
=
570 *(LONG
*) args
[ARG_MINWIDTH
];
571 if (args
[ARG_MAXWIDTH
])
572 data
->ci
[i
].max_width
=
573 *(LONG
*) args
[ARG_MAXWIDTH
];
574 data
->ci
[i
].bar
= args
[ARG_BAR
];
575 if (args
[ARG_PREPARSE
])
576 data
->ci
[i
].preparse
=
577 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
581 ptr
+= strlen(ptr
) + 1;
584 while (i
< new_columns
);
585 FreeDosObject(DOS_RDARGS
, rdargs
);
590 for (i
= 0; i
< new_columns
; i
++)
592 D(bug("colno %d weight %d delta %d preparse %s\n",
593 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
594 data
->ci
[i
].preparse
));
597 data
->columns
= new_columns
;
598 data
->strings
++; /* Skip entry pos */
603 /**************************************************************************
604 Call the MUIM_List_Display for the given entry. It fills out
605 data->string and data->preparses
606 **************************************************************************/
607 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
609 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
613 for (col
= 0; col
< data
->columns
; col
++)
614 data
->preparses
[col
] = data
->ci
[col
].preparse
;
616 if (entry_pos
== ENTRY_TITLE
)
618 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
620 *data
->strings
= data
->title
;
623 entry_data
= NULL
; /* it's a title request */
626 entry_data
= data
->entries
[entry_pos
]->data
;
628 /* Get the display formation */
629 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
630 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
633 /**************************************************************************
634 Determine the dims of a single entry and adapt the columninfo according
635 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
636 be redrawn after this operation, 1 if all entries need to be redrawn.
637 **************************************************************************/
638 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
640 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
641 struct ListEntry
*entry
= data
->entries
[pos
];
648 if (!(_flags(obj
) & MADF_SETUP
))
651 DisplayEntry(cl
, obj
, pos
);
653 /* Set height to at least minheight */
654 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
655 data
->entries
[pos
]->height
= data
->entry_minheight
;
657 for (j
= 0; j
< data
->columns
; j
++)
660 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
664 zune_text_get_bounds(text
, obj
);
666 if (text
->height
> data
->entries
[pos
]->height
)
668 data
->entries
[pos
]->height
= text
->height
;
669 /* entry height changed, redraw all entries later */
672 data
->entries
[pos
]->widths
[j
] = text
->width
;
674 if (text
->width
> data
->ci
[j
].entries_width
)
676 /* This entry has a greater width for this column than any
677 * other entry, so we store this value
679 data
->ci
[j
].entries_width
= text
->width
;
680 /* column width changed, redraw all entries later */
684 zune_text_destroy(text
);
687 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
689 data
->entry_maxheight
= data
->entries
[pos
]->height
;
690 /* maximum entry height changed, redraw all entries later */
697 /**************************************************************************
698 Determine the widths of the entries
699 **************************************************************************/
700 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
703 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
705 if (!(_flags(obj
) & MADF_SETUP
))
708 for (j
= 0; j
< data
->columns
; j
++)
709 data
->ci
[j
].entries_width
= 0;
711 data
->entry_maxheight
= 0;
712 data
->entries_totalheight
= 0;
713 data
->entries_maxwidth
= 0;
715 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
717 CalcDimsOfEntry(cl
, obj
, i
);
718 data
->entries_totalheight
+= data
->entries
[i
]->height
;
721 for (j
= 0; j
< data
->columns
; j
++)
722 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
724 if (!data
->entry_maxheight
)
725 data
->entry_maxheight
= 1;
728 /**************************************************************************
729 Calculates the number of visible entry lines. Returns 1 if it has
731 **************************************************************************/
732 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
734 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
735 int old_entries_visible
= data
->entries_visible
;
736 int old_entries_top_pixel
= data
->entries_top_pixel
;
738 data
->vertprop_visible
= data
->entries_visible
=
739 (_mheight(data
->area
) - data
->title_height
)
740 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
742 /* Distribute extra vertical space evenly between top and bottom of
745 data
->entries_top_pixel
= _mtop(data
->area
) + data
->title_height
746 + (_mheight(data
->area
) - data
->title_height
748 data
->entries_visible
*
749 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
751 if (data
->entries_visible
!= old_entries_visible
)
753 superset(cl
, obj
, MUIA_List_Visible
, data
->entries_visible
);
754 superset(cl
, obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
757 return (old_entries_visible
!= data
->entries_visible
)
758 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
761 /**************************************************************************
762 Default hook to compare two list entries. Works for strings only.
763 **************************************************************************/
764 AROS_UFH3S(int, default_compare_func
,
765 AROS_UFHA(struct Hook
*, h
, A0
),
766 AROS_UFHA(char *, s2
, A2
),
767 AROS_UFHA(char *, s1
, A1
))
771 return Stricmp(s1
, s2
);
776 #define PROP_VERT_FIRST 1
778 static ULONG
List_Function(struct Hook
*hook
, Object
* obj
, void **msg
)
780 struct MUI_ListData
*data
= (struct MUI_ListData
*)hook
->h_Data
;
781 SIPTR type
= (SIPTR
) msg
[0];
782 SIPTR val
= (SIPTR
) msg
[1];
786 case PROP_VERT_FIRST
:
787 get(data
->vert
, MUIA_Prop_First
, &val
);
788 nnset(obj
, MUIA_List_VertProp_First
, val
);
794 /* At entry to this function, data->area is always set, but data->vert may
795 * or may not be set */
796 static void List_HandleScrollerPos(struct IClass
*cl
, Object
*obj
)
798 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
799 BOOL vert_not_used
= FALSE
;
801 /* Disallow any changes after setup. This function should basically be
802 * creation-time only */
803 if (_flags(obj
) & MADF_SETUP
)
806 /* Remove both objects */
807 if (data
->area_connected
)
808 DoMethod(obj
, OM_REMMEMBER
, data
->area
);
809 if (data
->vert_connected
)
810 DoMethod(obj
, OM_REMMEMBER
, data
->vert
);
812 /* Add list and/or scroller */
813 switch (data
->scroller_pos
)
815 case MUIV_Listview_ScrollerPos_None
:
816 vert_not_used
= TRUE
;
817 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
819 case MUIV_Listview_ScrollerPos_Left
:
821 data
->vert
=ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
822 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
823 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
827 data
->vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
828 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
829 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
833 data
->area_connected
= TRUE
;
835 /* Handle case where it was decided that vert will not be used */
840 if (data
->vert_connected
)
842 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_First
,
844 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Visible
,
846 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Entries
,
848 data
->vert_connected
= FALSE
;
851 MUI_DisposeObject(data
->vert
);
856 /* If at this point data->vert is not null, it means vert is to be
858 if (data
->vert
&& !data
->vert_connected
)
860 LONG entries
= 0, first
= 0, visible
= 0;
862 get(obj
, MUIA_List_VertProp_First
, &first
);
863 get(obj
, MUIA_List_VertProp_Visible
, &visible
);
864 get(obj
, MUIA_List_VertProp_Entries
, &entries
);
866 SetAttrs(data
->vert
, MUIA_Prop_First
, first
,
867 MUIA_Prop_Visible
, visible
, MUIA_Prop_Entries
, entries
, TAG_DONE
);
869 DoMethod(data
->vert
, MUIM_Notify
, MUIA_Prop_First
, MUIV_EveryTime
,
870 (IPTR
) obj
, 4, MUIM_CallHook
, (IPTR
) &data
->hook
, PROP_VERT_FIRST
,
873 /* Pass prop object as DestObj (based on code in NList) */
874 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_First
, MUIV_EveryTime
,
875 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
876 MUIA_Prop_First
, MUIV_TriggerValue
);
877 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Visible
, MUIV_EveryTime
,
878 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
879 MUIA_Prop_Visible
, MUIV_TriggerValue
);
880 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Entries
, MUIV_EveryTime
,
881 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
882 MUIA_Prop_Entries
, MUIV_TriggerValue
);
884 data
->vert_connected
= TRUE
;
888 /**************************************************************************
890 **************************************************************************/
891 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
893 struct MUI_ListData
*data
;
895 struct TagItem
*tags
;
897 LONG new_entries_active
= MUIV_List_Active_Off
;
898 struct TagItem rectattrs
[2] =
899 {{TAG_IGNORE
, TAG_IGNORE
}, {TAG_DONE
, TAG_DONE
}};
902 /* search for MUIA_Frame as it has to be passed to rectangle object */
903 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
905 if (tag
->ti_Tag
== MUIA_Frame
)
907 rectattrs
[0].ti_Tag
= MUIA_Frame
;
908 rectattrs
[0].ti_Data
= tag
->ti_Data
;
909 tag
->ti_Tag
= TAG_IGNORE
;
914 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
915 MUIA_Group_Horiz
, TRUE
,
918 MUIA_Group_Spacing
, 0,
919 MUIA_Font
, MUIV_Font_List
,
920 MUIA_ShowSelState
, FALSE
,
921 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
922 MUIA_Background
, MUII_ListBack
,
923 TAG_MORE
, (IPTR
) msg
->ops_AttrList
,
929 data
= INST_DATA(cl
, obj
);
932 data
->entries_active
= MUIV_List_Active_Off
;
933 data
->intern_puddle_size
= 2008;
934 data
->intern_thresh_size
= 1024;
935 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
936 data
->default_compare_hook
.h_SubEntry
= 0;
937 data
->compare_hook
= &(data
->default_compare_hook
);
938 data
->flags
= LIST_SHOWDROPMARKS
;
939 data
->area_replaced
= FALSE
;
940 data
->area_connected
= FALSE
;
941 data
->vert_connected
= FALSE
;
943 data
->entries_visible
= data
->vertprop_visible
= -1;
944 data
->last_active
= -1;
946 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
947 data
->ehn
.ehn_Priority
= 0;
948 data
->ehn
.ehn_Flags
= 0;
949 data
->ehn
.ehn_Object
= obj
;
950 data
->ehn
.ehn_Class
= cl
;
953 * List is a group where part of area is rendered and part is filled
954 * with other objects (inside of List dimensions). One such object is
955 * up/down arrow. This object depends on RelVerify mode to control
956 * behaviour. List also has the RelVerify mode. Area super class in case
957 * of both of those objects adds an event handler node with the same
958 * priority. Depending on the sort order, the event handler node of
959 * "list" can eat a click event and up/down arrows stop working. The
960 * hack is to decrease the priority of Area event handler for list to
961 * always favor up/down arrow. There are other hacky ways of solving
962 * this, but this seems least evil approach, as this hack is
963 * encapsulated in the List class itself.
965 muiAreaData(obj
)->mad_ehn
.ehn_Priority
--;
967 data
->hook
.h_Entry
= HookEntry
;
968 data
->hook
.h_SubEntry
= (HOOKFUNC
) List_Function
;
969 data
->hook
.h_Data
= data
;
971 area
= (Object
*)GetTagData(MUIA_List_ListArea
, (IPTR
) 0,
975 area
= RectangleObject
, MUIA_FillArea
, FALSE
, TAG_MORE
,
976 (IPTR
) rectattrs
, End
;
978 data
->area_replaced
= TRUE
;
981 /* parse initial taglist */
982 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
986 case MUIA_List_Active
:
987 new_entries_active
= tag
->ti_Data
;
991 data
->pool
= (APTR
) tag
->ti_Data
;
994 case MUIA_List_PoolPuddleSize
:
995 data
->intern_puddle_size
= tag
->ti_Data
;
998 case MUIA_List_PoolThreshSize
:
999 data
->intern_thresh_size
= tag
->ti_Data
;
1002 case MUIA_List_CompareHook
:
1003 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1004 if (data
->compare_hook
== NULL
)
1005 data
->compare_hook
= &data
->default_compare_hook
;
1008 case MUIA_List_ConstructHook
:
1009 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1012 case MUIA_List_DestructHook
:
1013 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1016 case MUIA_List_DisplayHook
:
1017 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1020 case MUIA_List_MultiTestHook
:
1021 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1024 case MUIA_List_SourceArray
:
1025 array
= (APTR
*) tag
->ti_Data
;
1028 case MUIA_List_Format
:
1029 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1032 case MUIA_List_Title
:
1033 data
->title
= (STRPTR
) tag
->ti_Data
;
1036 case MUIA_List_MinLineHeight
:
1037 data
->entry_minheight
= tag
->ti_Data
;
1040 case MUIA_List_AdjustHeight
:
1041 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
1044 case MUIA_List_AdjustWidth
:
1045 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
1048 case MUIA_List_AutoVisible
:
1049 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1052 case MUIA_List_ShowDropMarks
:
1053 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1056 case MUIA_List_DragSortable
:
1057 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1058 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1061 case MUIA_Listview_ScrollerPos
:
1062 data
->scroller_pos
= tag
->ti_Data
;
1065 case MUIA_Listview_Input
:
1066 data
->read_only
= !tag
->ti_Data
;
1069 case MUIA_Listview_MultiSelect
:
1070 data
->multiselect
= tag
->ti_Data
;
1073 case MUIA_Listview_DoubleClick
:
1074 data
->doubleclick
= tag
->ti_Data
!= 0;
1077 case MUIA_Listview_DefClickColumn
:
1078 data
->def_click_column
= tag
->ti_Data
;
1083 List_HandleScrollerPos(cl
, obj
);
1087 /* No memory pool given, so we create our own */
1088 data
->pool
= data
->intern_pool
=
1089 CreatePool(0, data
->intern_puddle_size
,
1090 data
->intern_thresh_size
);
1093 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1098 /* parse the list format */
1099 if (!(ParseListFormat(data
, data
->format
)))
1101 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1105 /* This is neccessary for at least the title */
1106 if (!SetListSize(data
, 0))
1108 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1112 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
1114 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1121 /* Count the number of elements */
1122 for (i
= 0; array
[i
] != NULL
; i
++)
1125 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
1126 MUIV_List_Insert_Top
);
1129 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
1131 switch (new_entries_active
)
1133 case MUIV_List_Active_Top
:
1134 new_entries_active
= 0;
1137 case MUIV_List_Active_Bottom
:
1138 new_entries_active
= data
->entries_num
- 1;
1142 if (new_entries_active
< 0)
1143 new_entries_active
= 0;
1144 else if (new_entries_active
>= data
->entries_num
)
1145 new_entries_active
= data
->entries_num
- 1;
1147 data
->entries_active
= new_entries_active
;
1148 /* Selected entry will be moved into visible area */
1151 NewList((struct List
*)&data
->images
);
1153 D(bug("List_New(%lx)\n", obj
));
1158 /**************************************************************************
1160 **************************************************************************/
1161 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
1163 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1165 D(bug("List Dispose\n"));
1167 /* Call destruct method for every entry and free the entries manually
1168 * to avoid notification */
1169 while (data
->confirm_entries_num
)
1171 struct ListEntry
*lentry
=
1172 data
->entries
[--data
->confirm_entries_num
];
1173 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1175 FreeListEntry(data
, lentry
);
1178 if (data
->intern_pool
)
1179 DeletePool(data
->intern_pool
);
1181 FreeVec(data
->entries
- 1);
1182 /* title is currently before all other elements */
1184 FreeListFormat(data
);
1185 FreeVec(data
->format
);
1187 return DoSuperMethodA(cl
, obj
, msg
);
1191 /**************************************************************************
1193 **************************************************************************/
1194 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
1196 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1197 struct TagItem
*tag
;
1198 struct TagItem
*tags
;
1201 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1203 switch (tag
->ti_Tag
)
1205 case MUIA_List_CompareHook
:
1206 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1207 if (data
->compare_hook
== NULL
)
1208 data
->compare_hook
= &data
->default_compare_hook
;
1211 case MUIA_List_ConstructHook
:
1212 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1215 case MUIA_List_DestructHook
:
1216 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1219 case MUIA_List_DisplayHook
:
1220 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1223 case MUIA_List_MultiTestHook
:
1224 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1225 if (data
->multi_test_hook
!= NULL
)
1227 /* Clearing current selections is the easiest way to keep
1228 * selections consistent with the new hook */
1229 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
1230 MUIV_List_Select_Off
, NULL
);
1234 case MUIA_List_Title
:
1235 data
->title
= (STRPTR
) tag
->ti_Data
;
1236 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1239 case MUIA_List_VertProp_First
:
1240 data
->vertprop_first
= tag
->ti_Data
;
1241 if (data
->entries_first
!= tag
->ti_Data
)
1243 set(obj
, MUIA_List_First
, tag
->ti_Data
);
1247 case MUIA_List_Format
:
1248 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1249 ParseListFormat(data
, data
->format
);
1250 // FIXME: should we check for errors?
1251 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1254 case MUIA_List_VertProp_Entries
:
1255 data
->vertprop_entries
= tag
->ti_Data
;
1258 case MUIA_List_VertProp_Visible
:
1259 data
->vertprop_visible
= tag
->ti_Data
;
1260 data
->entries_visible
= tag
->ti_Data
;
1263 case MUIA_List_Active
:
1265 LONG new_entries_active
= tag
->ti_Data
;
1267 if ((data
->entries_num
)
1268 && (new_entries_active
!= MUIV_List_Active_Off
))
1270 switch (new_entries_active
)
1272 case MUIV_List_Active_Top
:
1273 new_entries_active
= 0;
1276 case MUIV_List_Active_Bottom
:
1277 new_entries_active
= data
->entries_num
- 1;
1280 case MUIV_List_Active_Up
:
1281 new_entries_active
= data
->entries_active
- 1;
1284 case MUIV_List_Active_Down
:
1285 new_entries_active
= data
->entries_active
+ 1;
1288 case MUIV_List_Active_PageUp
:
1289 new_entries_active
=
1290 data
->entries_active
- data
->entries_visible
;
1293 case MUIV_List_Active_PageDown
:
1294 new_entries_active
=
1295 data
->entries_active
+ data
->entries_visible
;
1299 if (new_entries_active
< 0)
1300 new_entries_active
= 0;
1301 else if (new_entries_active
>= data
->entries_num
)
1302 new_entries_active
= data
->entries_num
- 1;
1305 new_entries_active
= -1;
1307 if (data
->entries_active
!= new_entries_active
)
1309 LONG old
= data
->entries_active
;
1310 data
->entries_active
= new_entries_active
;
1312 /* SelectChange stuff */
1313 if (new_entries_active
!= -1)
1315 DoMethod(obj
, MUIM_List_SelectChange
,
1316 new_entries_active
, MUIV_List_Select_On
, 0);
1317 DoMethod(obj
, MUIM_List_SelectChange
,
1318 new_entries_active
, MUIV_List_Select_Active
, 0);
1321 DoMethod(obj
, MUIM_List_SelectChange
,
1322 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1324 if (!data
->read_only
)
1327 data
->update_pos
= old
;
1328 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1330 data
->update_pos
= data
->entries_active
;
1331 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1334 /* Make new active entry visible (if there is one and
1336 if (new_entries_active
!= -1
1337 && (_flags(obj
) & MADF_SETUP
))
1339 DoMethod(obj
, MUIM_List_Jump
,
1340 MUIV_List_Jump_Active
);
1346 case MUIA_List_First
:
1347 data
->update_pos
= data
->entries_first
;
1349 data
->entries_first
= tag
->ti_Data
;
1351 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1352 if ((data
->vertprop_first
!= tag
->ti_Data
)
1353 && (!(data
->flags
& LIST_QUIET
)))
1355 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1359 case MUIA_List_Visible
: /* Shouldn't be settable? */
1360 if (data
->vertprop_visible
!= tag
->ti_Data
)
1361 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1364 case MUIA_List_Entries
:
1365 if (data
->confirm_entries_num
== tag
->ti_Data
)
1367 data
->entries_num
= tag
->ti_Data
;
1368 if (!(data
->flags
& LIST_QUIET
))
1370 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1375 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1379 case MUIA_List_Quiet
:
1380 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1383 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1384 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1385 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1386 if (data
->entries_first
!= XGET(obj
, MUIA_List_VertProp_First
))
1387 set(obj
, MUIA_List_VertProp_First
, data
->entries_first
);
1391 case MUIA_List_AutoVisible
:
1392 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1395 case MUIA_List_ShowDropMarks
:
1396 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1399 case MUIA_List_DragSortable
:
1400 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1401 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1405 /* Swallow this so the Area class doesn't redraw us */
1406 tag
->ti_Tag
= TAG_IGNORE
;
1410 if (_flags(obj
) & MADF_SETUP
)
1412 /* Stop listening for events we only listen to when mouse
1413 button is down: we will not be informed of the button
1415 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1417 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
1418 | IDCMP_INACTIVEWINDOW
);
1419 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1424 case MUIA_Listview_DoubleClick
: /* private set */
1425 data
->doubleclick
= tag
->ti_Data
!= 0;
1428 case MUIA_Listview_SelectChange
: /* private set */
1429 data
->select_change
= tag
->ti_Data
!= 0;
1432 case MUIA_Listview_ScrollerPos
: /* private set */
1433 data
->scroller_pos
= tag
->ti_Data
;
1434 List_HandleScrollerPos(cl
, obj
);
1437 case MUIA_Listview_Input
: /* private set */
1438 data
->read_only
= !tag
->ti_Data
;
1441 case MUIA_Listview_MultiSelect
: /* private set */
1442 data
->multiselect
= tag
->ti_Data
;
1445 case MUIA_Listview_DefClickColumn
:
1446 data
->def_click_column
= tag
->ti_Data
;
1451 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1454 /**************************************************************************
1456 **************************************************************************/
1457 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1459 /* small macro to simplify return value storage */
1460 #define STORE *(msg->opg_Storage)
1461 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1463 switch (msg
->opg_AttrID
)
1465 case MUIA_List_Entries
:
1466 STORE
= data
->entries_num
;
1468 case MUIA_List_First
:
1469 STORE
= data
->entries_first
;
1471 case MUIA_List_Active
:
1472 STORE
= data
->entries_active
;
1474 case MUIA_List_InsertPosition
:
1475 STORE
= data
->insert_position
;
1477 case MUIA_List_Title
:
1478 STORE
= (IPTR
) data
->title
;
1480 case MUIA_List_VertProp_Entries
:
1481 STORE
= data
->vertprop_entries
;
1483 case MUIA_List_VertProp_Visible
:
1484 case MUIA_List_Visible
:
1485 STORE
= data
->vertprop_visible
;
1487 case MUIA_List_VertProp_First
:
1488 STORE
= data
->vertprop_first
;
1490 case MUIA_List_Format
:
1491 STORE
= (IPTR
) data
->format
;
1493 case MUIA_List_AutoVisible
:
1494 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1496 case MUIA_List_ShowDropMarks
:
1497 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1499 case MUIA_List_DragSortable
:
1500 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1502 case MUIA_Listview_ClickColumn
:
1503 STORE
= data
->click_column
;
1505 case MUIA_Listview_DoubleClick
:
1506 STORE
= data
->doubleclick
;
1508 case MUIA_Listview_SelectChange
:
1509 STORE
= data
->select_change
;
1511 case MUIA_Listview_List
:
1514 case MUIA_Listview_DefClickColumn
:
1515 STORE
= data
->def_click_column
;
1519 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1525 /**************************************************************************
1527 **************************************************************************/
1528 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1529 struct MUIP_Setup
*msg
)
1531 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1533 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1536 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1537 data
->prefs_linespacing
=
1538 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1539 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1540 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1543 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1545 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1547 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1549 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
1550 if (data
->multiselect
== MUIV_Listview_MultiSelect_Default
)
1552 if (data
->prefs_multi
== LISTVIEW_MULTI_SHIFTED
)
1553 data
->multiselect
= MUIV_Listview_MultiSelect_Shifted
;
1555 data
->multiselect
= MUIV_Listview_MultiSelect_Always
;
1558 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1563 /**************************************************************************
1565 **************************************************************************/
1566 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1567 struct MUIP_Cleanup
*msg
)
1569 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1571 zune_imspec_cleanup(data
->list_cursor
);
1572 zune_imspec_cleanup(data
->list_select
);
1573 zune_imspec_cleanup(data
->list_selcur
);
1575 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1576 data
->mouse_click
= 0;
1578 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1581 /**************************************************************************
1583 **************************************************************************/
1584 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1585 struct MUIP_AskMinMax
*msg
)
1587 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1589 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1591 CalcWidths(cl
, obj
);
1593 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1595 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1596 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1597 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1601 msg
->MinMaxInfo
->MinWidth
+= 40;
1602 msg
->MinMaxInfo
->DefWidth
+= 100;
1603 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1606 if (data
->entries_num
> 0)
1608 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1610 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1611 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1612 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1616 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1617 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1618 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1619 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1624 msg
->MinMaxInfo
->MinHeight
+= 36;
1625 msg
->MinMaxInfo
->DefHeight
+= 96;
1626 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1628 D(bug("List %p minheigh=%d, line maxh=%d\n",
1629 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1633 /****i* List.mui/MUIM_Layout *************************************************
1638 ******************************************************************************
1642 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1643 struct MUIP_Layout
*msg
)
1645 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1646 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1647 LONG new_entries_first
= data
->entries_first
;
1649 /* Calc the numbers of entries visible */
1650 CalcVertVisible(cl
, obj
);
1652 /* Ensure active entry is visible if requested */
1653 if (data
->entries_active
+ 1 >=
1654 (data
->entries_first
+ data
->entries_visible
)
1655 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1657 data
->entries_active
- data
->entries_visible
+ 1;
1659 /* Ensure there are no unnecessary empty lines */
1660 if ((new_entries_first
+ data
->entries_visible
>=
1662 && (data
->entries_visible
<= data
->entries_num
))
1663 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1665 /* Always show the start of the list if it isn't long enough to fill the
1667 if (data
->entries_num
<= data
->entries_visible
)
1668 new_entries_first
= 0;
1670 if (new_entries_first
< 0)
1671 new_entries_first
= 0;
1673 set(obj
, new_entries_first
!= data
->entries_first
?
1674 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1676 /* So the notify happens */
1677 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1683 /**************************************************************************
1685 **************************************************************************/
1686 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1687 struct MUIP_Show
*msg
)
1689 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1690 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1692 zune_imspec_show(data
->list_cursor
, obj
);
1693 zune_imspec_show(data
->list_select
, obj
);
1694 zune_imspec_show(data
->list_selcur
, obj
);
1699 /**************************************************************************
1701 **************************************************************************/
1702 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1703 struct MUIP_Hide
*msg
)
1705 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1707 zune_imspec_hide(data
->list_cursor
);
1708 zune_imspec_hide(data
->list_select
);
1709 zune_imspec_hide(data
->list_selcur
);
1711 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1715 /**************************************************************************
1716 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1718 **************************************************************************/
1719 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1722 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1725 /* To be sure we don't draw anything if there is no title */
1726 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1729 DisplayEntry(cl
, obj
, entry_pos
);
1730 x1
= _mleft(data
->area
);
1732 for (col
= 0; col
< data
->columns
; col
++)
1735 x2
= x1
+ data
->ci
[col
].entries_width
;
1738 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1739 ZTEXT_ARG_NONE
, 0)))
1741 /* Could be made simpler, as we don't really need the bounds */
1742 zune_text_get_bounds(text
, obj
);
1743 /* Note, this was MPEN_SHADOW before */
1744 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1745 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1746 zune_text_destroy(text
);
1748 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1752 /**************************************************************************
1754 **************************************************************************/
1755 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1757 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1761 BOOL scroll_caused_damage
= FALSE
;
1762 struct MUI_ImageSpec_intern
*highlight
;
1765 if (data
->flags
& LIST_QUIET
)
1768 ret
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1770 if (data
->area_replaced
)
1773 /* Calculate the title height */
1776 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1780 data
->title_height
= 0;
1783 /* Calc the numbers of entries visible */
1784 CalcVertVisible(cl
, obj
);
1786 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1788 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
1789 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
),
1790 0, data
->entries_first
* data
->entry_maxheight
, 0);
1793 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(data
->area
),
1794 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
));
1796 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1798 y
= _mtop(data
->area
);
1801 if (data
->title_height
&& data
->title
)
1803 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1804 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1805 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1806 Move(_rp(obj
), _mleft(data
->area
), y
);
1807 Draw(_rp(obj
), _mright(data
->area
), y
);
1808 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1810 Move(_rp(obj
), _mleft(data
->area
), y
);
1811 Draw(_rp(obj
), _mright(data
->area
), y
);
1815 y
= data
->entries_top_pixel
;
1817 start
= data
->entries_first
;
1818 end
= data
->entries_first
+ data
->entries_visible
;
1820 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1822 int diffy
= data
->entries_first
- data
->update_pos
;
1824 if (abs(diffy
) < data
->entries_visible
)
1826 scroll_caused_damage
=
1827 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1829 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1830 _mleft(data
->area
), y
,
1831 _mright(data
->area
),
1832 y
+ data
->entry_maxheight
* data
->entries_visible
);
1834 scroll_caused_damage
=
1835 scroll_caused_damage
1836 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1840 start
= end
- diffy
;
1841 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1845 end
= start
- diffy
;
1849 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1851 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), top
,
1852 _mwidth(data
->area
), bottom
- top
+ 1, 0,
1853 top
- _mtop(data
->area
) + data
->entries_first
1854 * data
->entry_maxheight
, 0);
1857 for (entry_pos
= start
;
1858 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1860 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1862 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1863 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1864 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1865 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1866 && data
->update_pos
== entry_pos
))
1868 /* Choose appropriate highlight image */
1870 if (entry_pos
== data
->entries_active
1871 && (entry
->flags
& ENTRY_SELECTED
) && !data
->read_only
)
1872 highlight
= data
->list_selcur
;
1873 else if (entry_pos
== data
->entries_active
&& !data
->read_only
)
1874 highlight
= data
->list_cursor
;
1875 else if (entry
->flags
& ENTRY_SELECTED
)
1876 highlight
= data
->list_select
;
1880 /* Draw highlight or background */
1882 if (highlight
!= NULL
)
1884 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1885 _mleft(data
->area
), y
, _mwidth(data
->area
),
1886 data
->entry_maxheight
,
1887 0, y
- data
->entries_top_pixel
, 0);
1889 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1890 && data
->update_pos
== entry_pos
)
1892 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), y
,
1893 _mwidth(data
->area
), data
->entry_maxheight
, 0,
1894 y
- _mtop(data
->area
) +
1895 data
->entries_first
* data
->entry_maxheight
, 0);
1898 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1900 y
+= data
->entry_maxheight
;
1903 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1907 if (scroll_caused_damage
)
1909 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1911 /* Theoretically it might happen that more damage is caused
1912 after ScrollRaster. By something else, like window movement
1913 in front of our window. Therefore refresh root object of
1914 window, not just this object */
1918 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1919 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1921 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1925 ULONG x1
= _mleft(data
->area
);
1927 y
= _mtop(data
->area
);
1929 if (data
->title_height
&& data
->title
)
1931 for (col
= 0; col
< data
->columns
; col
++)
1933 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1934 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1936 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1939 if (data
->ci
[col
].bar
)
1941 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1942 Move(_rp(obj
), x1
, y
);
1944 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1945 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1946 Move(_rp(obj
), x1
+ 1, y
);
1947 Draw(_rp(obj
), x1
+ 1,
1948 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1952 x1
+= data
->ci
[col
].delta
- halfdelta
;
1954 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1957 x1
= _mleft(data
->area
);
1959 for (col
= 0; col
< data
->columns
; col
++)
1961 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1962 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1964 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1967 if (data
->ci
[col
].bar
)
1969 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1970 Move(_rp(obj
), x1
, y
);
1971 Draw(_rp(obj
), x1
, _mbottom(data
->area
));
1972 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1973 Move(_rp(obj
), x1
+ 1, y
);
1974 Draw(_rp(obj
), x1
+ 1, _mbottom(data
->area
));
1979 x1
+= data
->ci
[col
].delta
- halfdelta
;
1985 /****** List.mui/MUIM_List_Clear *********************************************
1988 * MUIM_List_Clear (V4)
1991 * DoMethod(obj, MUIM_List_Clear);
1994 * Removes all entries from the list.
1996 ******************************************************************************
2000 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
2001 struct MUIP_List_Clear
*msg
)
2003 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2005 while (data
->confirm_entries_num
)
2007 struct ListEntry
*lentry
=
2008 data
->entries
[--data
->confirm_entries_num
];
2009 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2011 FreeListEntry(data
, lentry
);
2013 /* Should never fail when shrinking */
2014 SetListSize(data
, 0);
2016 if (data
->confirm_entries_num
!= data
->entries_num
)
2018 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
2019 /* Notify only when no entry was active */
2020 data
->entries_active
!=
2021 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
2022 MUIV_List_Active_Off
, TAG_DONE
);
2025 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2031 /****** List.mui/MUIM_List_Exchange ******************************************
2034 * MUIM_List_Exchange (V4)
2037 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2040 * Exchange two entries' positions.
2043 * pos1 - the current index of the first entry that should be moved, or
2044 * one of these special values:
2045 * MUIV_List_Exchange_Active: the active entry.
2046 * MUIV_List_Exchange_Top: the first entry.
2047 * MUIV_List_Exchange_Bottom: the last entry.
2048 * pos2 - the index of the entry that the first entry should be exchanged
2049 * with, or one of these special values:
2050 * MUIV_List_Exchange_Active: the active entry.
2051 * MUIV_List_Exchange_Top: the first entry.
2052 * MUIV_List_Exchange_Bottom: the last entry.
2053 * MUIV_List_Exchange_Next: the next entry after pos1.
2054 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2057 * This method will do nothing if either index is greater than the last
2058 * index in the list, or if MUIV_List_Exchange_Next or
2059 * MUIV_List_Exchange_Previous imply an index outside the list.
2064 ******************************************************************************
2068 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
2069 struct MUIP_List_Exchange
*msg
)
2071 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2076 case MUIV_List_Exchange_Top
:
2079 case MUIV_List_Exchange_Active
:
2080 pos1
= data
->entries_active
;
2082 case MUIV_List_Exchange_Bottom
:
2083 pos1
= data
->entries_num
- 1;
2091 case MUIV_List_Exchange_Top
:
2094 case MUIV_List_Exchange_Active
:
2095 pos2
= data
->entries_active
;
2097 case MUIV_List_Exchange_Bottom
:
2098 pos2
= data
->entries_num
- 1;
2100 case MUIV_List_Exchange_Next
:
2103 case MUIV_List_Exchange_Previous
:
2110 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
2111 && pos2
< data
->entries_num
&& pos1
!= pos2
)
2113 struct ListEntry
*save
= data
->entries
[pos1
];
2114 data
->entries
[pos1
] = data
->entries
[pos2
];
2115 data
->entries
[pos2
] = save
;
2118 data
->update_pos
= pos1
;
2119 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2122 data
->update_pos
= pos2
;
2123 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2133 /**************************************************************************
2135 **************************************************************************/
2136 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
2137 struct MUIP_List_Redraw
*msg
)
2139 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2141 if (!(data
->flags
& LIST_QUIET
))
2143 if (msg
->pos
== MUIV_List_Redraw_All
)
2146 CalcWidths(cl
, obj
);
2147 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2152 if (msg
->pos
== MUIV_List_Redraw_Active
)
2153 pos
= data
->entries_active
;
2154 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
2157 for (i
= 0; i
< data
->entries_num
; i
++)
2158 if (data
->entries
[i
]->data
== msg
->entry
)
2169 if (CalcDimsOfEntry(cl
, obj
, pos
))
2174 data
->update_pos
= pos
;
2176 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2183 /****** List.mui/MUIM_List_Remove ********************************************
2186 * MUIM_List_Remove (V4)
2189 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2192 * Removes entries from the list. If a destruct hook has been
2193 * installed, it will be called for the removed entry.
2196 * pos - the index of the entry to be removed. The following
2197 * special values can also be used:
2198 * MUIV_List_Remove_First: remove the first entry.
2199 * MUIV_List_Remove_Last: remove the last entry.
2200 * MUIV_List_Remove_Active: remove the active entry.
2201 * MUIV_List_Remove_Selected: remove all selected entries
2202 * (or the active entry if there are no selected entries).
2205 * When the active entry is removed, the next entry becomes active
2206 * (if there is no entry below the active entry, the previous entry
2207 * becomes active instead).
2210 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2212 ******************************************************************************
2214 * It was not possible to use MUIM_List_NextSelected here because that method
2215 * may skip entries if entries are removed during an iteration.
2219 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
2220 struct MUIP_List_Remove
*msg
)
2222 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2226 BOOL found
, done
= FALSE
;
2227 struct ListEntry
*lentry
;
2228 Tag active_tag
= TAG_DONE
;
2230 if (!data
->entries_num
)
2235 case MUIV_List_Remove_First
:
2239 case MUIV_List_Remove_Active
:
2240 pos
= data
->entries_active
;
2243 case MUIV_List_Remove_Last
:
2244 pos
= data
->entries_num
- 1;
2247 case MUIV_List_Remove_Selected
:
2256 if (pos
< 0 || pos
>= data
->entries_num
)
2259 new_act
= data
->entries_active
;
2263 if (msg
->pos
== MUIV_List_Remove_Selected
)
2265 /* Find the next selected entry */
2266 for (found
= FALSE
, i
= pos
;
2267 i
< data
->confirm_entries_num
&& !found
; i
++)
2269 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2280 /* If there were no selected entries, remove the active one */
2281 if (data
->confirm_entries_num
== data
->entries_num
2282 && data
->entries_active
!= MUIV_List_Active_Off
)
2284 pos
= data
->entries_active
;
2297 lentry
= data
->entries
[pos
];
2298 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2300 RemoveListEntries(data
, pos
, 1);
2301 data
->confirm_entries_num
--;
2306 active_tag
= MUIA_List_Active
;
2308 else if (pos
== new_act
)
2309 active_tag
= MUIA_List_Active
;
2313 /* ensure that the active element is in a valid range (it might become
2314 * MUIV_List_Active_Off (-1), but that's OK) */
2315 if (new_act
>= data
->entries_num
)
2316 new_act
= data
->entries_num
- 1;
2318 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
,
2319 active_tag
, new_act
, /* Inform only if necessary (for notify) */
2323 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2328 /**************************************************************************
2330 **************************************************************************/
2331 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2332 struct MUIP_List_Select
*msg
)
2334 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2335 LONG pos
, i
, count
, selcount
=0, state
=0;
2336 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
2338 /* Establish the range of entries affected */
2341 case MUIV_List_Select_Active
:
2342 pos
= data
->entries_active
;
2343 if (pos
== MUIV_List_Active_Off
)
2349 case MUIV_List_Select_All
:
2351 count
= data
->entries_num
;
2357 if (pos
< 0 || pos
>= data
->entries_num
)
2362 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2364 /* Disallow selection of an additional entry if there is a currently
2365 selected entry that is not multi-selectable (in such case there
2366 will only be one entry currently selected, so no need to iterate) */
2367 i
= MUIV_List_NextSelected_Start
;
2368 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
2369 if (i
!= MUIV_List_NextSelected_End
)
2371 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
2372 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2373 data
->entries
[i
]->data
);
2376 /* Change or check state of each entry in the range */
2377 for (i
= pos
; i
< pos
+ count
; i
++)
2379 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2380 switch (msg
->seltype
)
2382 case MUIV_List_Select_Off
:
2383 new_select_state
= FALSE
;
2386 case MUIV_List_Select_On
:
2387 new_select_state
= TRUE
;
2390 case MUIV_List_Select_Toggle
:
2391 new_select_state
= !state
;
2395 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2400 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2402 /* Disallow selection if entry is not multi-selectable and
2403 * there are already selected entries */
2404 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
2405 new_select_state
= multi_allowed
&& (selcount
== 0 ||
2406 CallHookPkt(data
->multi_test_hook
, NULL
,
2407 data
->entries
[i
]->data
));
2409 if (new_select_state
)
2410 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2412 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2416 /* Report old state or number of selected entries */
2419 if (msg
->pos
== MUIV_List_Select_All
2420 && msg
->seltype
== MUIV_List_Select_Ask
)
2421 *msg
->info
= selcount
;
2426 /* Redraw unless it was just an enquiry */
2427 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2434 data
->update_pos
= pos
;
2436 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2442 /****** List.mui/MUIM_List_Insert ********************************************
2445 * MUIM_List_Insert (V4)
2448 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2451 * Adds multiple entries to the list. If a construct hook has been
2452 * installed, the results of passing the entries to this hook will be
2456 * entries - an array of entries to be inserted.
2457 * count - the number of entries to insert. A special value of -1 may be
2458 * used, indicating that the array of entries is NULL-terminated.
2459 * pos - the index at which to insert the new entries. The following
2460 * special values can also be used:
2461 * MUIV_List_Insert_Top: insert at index 0.
2462 * MUIV_List_Insert_Bottom: insert after all existing entries.
2463 * MUIV_List_Insert_Active: insert at the index of the active entry
2464 * (or at index 0 if there is no active entry).
2465 * MUIV_List_Insert_Sorted: keep the list sorted.
2468 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2470 ******************************************************************************
2474 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2475 struct MUIP_List_Insert
*msg
)
2477 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2478 LONG pos
, count
, sort
, active
;
2485 /* Count the number of entries */
2486 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2495 case MUIV_List_Insert_Top
:
2499 case MUIV_List_Insert_Active
:
2500 if (data
->entries_active
!= -1)
2501 pos
= data
->entries_active
;
2506 case MUIV_List_Insert_Sorted
:
2507 pos
= data
->entries_num
;
2508 sort
= 1; /* we sort'em later */
2511 case MUIV_List_Insert_Bottom
:
2512 pos
= data
->entries_num
;
2516 if (msg
->pos
> data
->entries_num
)
2517 pos
= data
->entries_num
;
2518 else if (msg
->pos
< 0)
2524 data
->insert_position
= pos
;
2526 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2529 LONG until
= pos
+ count
;
2530 APTR
*toinsert
= msg
->entries
;
2532 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2537 struct ListEntry
*lentry
;
2539 if (!(lentry
= AllocListEntry(data
)))
2541 /* Panic, but we must be in a consistent state, so remove
2542 * the space where the following list entries should have gone
2544 RemoveListEntries(data
, pos
, until
- pos
);
2548 /* now call the construct method which returns us a pointer which
2550 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2551 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2554 FreeListEntry(data
, lentry
);
2555 RemoveListEntries(data
, pos
, until
- pos
);
2557 /* TODO: Also check for visible stuff like below */
2558 if (data
->entries_num
!= data
->confirm_entries_num
)
2559 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2563 data
->entries
[pos
] = lentry
;
2564 data
->confirm_entries_num
++;
2566 if (_flags(obj
) & MADF_SETUP
)
2568 /* We have to calculate the width and height of the newly
2569 * inserted entry. This has to be done after inserting the
2570 * element into the list */
2571 CalcDimsOfEntry(cl
, obj
, pos
);
2579 /* Recalculate the number of visible entries */
2580 if (_flags(obj
) & MADF_SETUP
)
2581 CalcVertVisible(cl
, obj
);
2583 if (data
->entries_num
!= data
->confirm_entries_num
)
2586 MUIA_List_Entries
, data
->confirm_entries_num
,
2587 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2590 /* If the array is already sorted, we could do a simple insert
2591 * sort and would be much faster than with qsort.
2592 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2593 * sort the whole array?
2595 * I think, we better sort the whole array:
2599 DoMethod(obj
, MUIM_List_Sort
);
2600 /* TODO: which pos to return here !? */
2601 /* MUIM_List_Sort already called MUI_Redraw */
2606 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2608 superset(cl
, obj
, MUIA_List_InsertPosition
, data
->insert_position
);
2610 /* Update index of active entry */
2611 if (data
->entries_active
>= data
->insert_position
)
2613 active
= data
->entries_active
+ count
;
2614 SET(obj
, MUIA_List_Active
, active
);
2620 /****** List.mui/MUIM_List_InsertSingle **************************************
2623 * MUIM_List_InsertSingle (V7)
2626 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2629 * Adds a single entry to the list. If a construct hook has been
2630 * installed, the result of passing the entry to this hook will be
2634 * entry - the entry to be inserted.
2635 * pos - the index at which to insert the new entry. The following
2636 * special values can also be used:
2637 * MUIV_List_Insert_Top: insert at index 0.
2638 * MUIV_List_Insert_Bottom: insert after all existing entries.
2639 * MUIV_List_Insert_Active: insert at the index of the active entry
2640 * (or at index 0 if there is no active entry).
2641 * MUIV_List_Insert_Sorted: keep the list sorted.
2644 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2646 ******************************************************************************
2650 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2651 struct MUIP_List_InsertSingle
*msg
)
2653 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2657 /**************************************************************************
2659 **************************************************************************/
2660 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2661 struct MUIP_List_GetEntry
*msg
)
2663 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2666 if (pos
== MUIV_List_GetEntry_Active
)
2667 pos
= data
->entries_active
;
2669 if (pos
< 0 || pos
>= data
->entries_num
)
2674 *msg
->entry
= data
->entries
[pos
]->data
;
2675 return (IPTR
) *msg
->entry
;
2678 /**************************************************************************
2680 **************************************************************************/
2681 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2682 struct MUIP_List_Construct
*msg
)
2684 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2686 if (NULL
== data
->construct_hook
)
2687 return (IPTR
) msg
->entry
;
2688 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2690 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2691 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2696 if (msg
->entry
!= NULL
)
2697 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2699 *(STRPTR
) (mem
+ 1) = 0;
2700 return (IPTR
) (mem
+ 1);
2702 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2705 /**************************************************************************
2707 **************************************************************************/
2708 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2709 struct MUIP_List_Destruct
*msg
)
2711 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2713 if (NULL
== data
->destruct_hook
)
2716 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2718 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2719 FreePooled(msg
->pool
, mem
, mem
[0]);
2723 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2728 /****** List.mui/MUIM_List_Compare *******************************************
2731 * MUIM_List_Compare (V20)
2734 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2735 * LONG sort_type1, LONG sort_type2);
2738 * Compare two list entries according to the current comparison hook
2739 * (MUIA_List_CompareHook).
2742 * entry1 - the first entry data.
2743 * entry2 - the second entry data.
2744 * sort_type1 - undocumented.
2745 * sort_type2 - undocumented.
2748 * MUIA_List_CompareHook, MUIM_List_Sort.
2750 ******************************************************************************
2754 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2755 struct MUIP_List_Compare
*msg
)
2757 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2759 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2762 /**************************************************************************
2764 **************************************************************************/
2765 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2766 struct MUIP_List_Display
*msg
)
2768 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2770 if (NULL
== data
->display_hook
)
2773 *msg
->array
= msg
->entry
;
2779 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2780 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2783 /**************************************************************************
2784 MUIM_List_SelectChange
2785 **************************************************************************/
2786 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2787 struct MUIP_List_SelectChange
*msg
)
2792 /**************************************************************************
2793 MUIM_List_CreateImage
2794 Called by a List subclass in its Setup method.
2795 Connects an Area subclass object to the list, much like an object gets
2796 connected to a window. List calls Setup and AskMinMax on that object,
2797 keeps a reference to it (that reference will be returned).
2798 Text engine will dereference that pointer and draw the object with its
2800 **************************************************************************/
2801 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2802 struct MUIP_List_CreateImage
*msg
)
2804 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2805 struct ListImage
*li
;
2810 /* List must be already setup in Setup of your subclass */
2811 if (!(_flags(obj
) & MADF_SETUP
))
2813 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2818 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2819 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2820 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2826 /**************************************************************************
2827 MUIM_List_DeleteImage
2828 **************************************************************************/
2829 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2830 struct MUIP_List_DeleteImage
*msg
)
2832 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2833 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2837 DoMethod(li
->obj
, MUIM_Cleanup
);
2838 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2839 Remove((struct Node
*)li
);
2840 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2846 /****** List.mui/MUIM_List_Jump **********************************************
2849 * MUIM_List_Jump (V4)
2852 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2855 * Scrolls the list so that a particular entry is visible.
2858 * pos - index of entry that should become visible, or one of these
2860 * MUIV_List_Jump_Active: show the active entry.
2861 * MUIV_List_Jump_Top: show the first entry.
2862 * MUIV_List_Jump_Bottom: show the last entry.
2863 * MUIV_List_Jump_Up: show the previous hidden entry.
2864 * MUIV_List_Jump_Down: show the next hidden entry.
2866 ******************************************************************************
2870 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2871 struct MUIP_List_Jump
*msg
)
2873 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2874 LONG pos
= msg
->pos
;
2878 case MUIV_List_Jump_Top
:
2882 case MUIV_List_Jump_Active
:
2883 pos
= data
->entries_active
;
2886 case MUIV_List_Jump_Bottom
:
2887 pos
= data
->entries_num
- 1;
2890 case MUIV_List_Jump_Down
:
2891 pos
= data
->entries_first
+ data
->entries_visible
;
2894 case MUIV_List_Jump_Up
:
2895 pos
= data
->entries_first
- 1;
2899 if (pos
>= data
->entries_num
)
2901 pos
= data
->entries_num
- 1;
2906 if (pos
< data
->entries_first
)
2908 set(obj
, MUIA_List_First
, pos
);
2910 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2912 pos
-= (data
->entries_visible
- 1);
2915 if (pos
!= data
->entries_first
)
2917 set(obj
, MUIA_List_First
, pos
);
2924 /****** List.mui/MUIM_List_Sort **********************************************
2927 * MUIM_List_Sort (V4)
2930 * DoMethod(obj, MUIM_List_Sort);
2933 * Sort the list's entries according to the current comparison hook
2934 * (MUIA_List_CompareHook).
2937 * The active index does not change, so the active entry may do so.
2940 * MUIA_List_CompareHook, MUIM_List_Compare.
2942 ******************************************************************************
2946 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2947 struct MUIP_List_Sort
*msg
)
2949 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2952 struct MUIP_List_Compare cmpmsg
=
2953 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2955 if (data
->entries_num
> 1)
2958 Simple sort algorithm. Feel free to improve it.
2960 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2963 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2965 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2966 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2967 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2974 APTR tmp
= data
->entries
[i
];
2975 data
->entries
[i
] = data
->entries
[max
];
2976 data
->entries
[max
] = tmp
;
2982 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2987 /****** List.mui/MUIM_List_Move **********************************************
2990 * MUIM_List_Move (V9)
2993 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2996 * Move a list entry to a new position.
2999 * from - the current index of the entry that should be moved, or one of
3000 * these special values:
3001 * MUIV_List_Move_Active: the active entry.
3002 * MUIV_List_Move_Top: the first entry.
3003 * MUIV_List_Move_Bottom: the last entry.
3004 * to - the index of the entry's new position, or one of
3005 * these special values:
3006 * MUIV_List_Move_Active: the active entry.
3007 * MUIV_List_Move_Top: the first entry.
3008 * MUIV_List_Move_Bottom: the last entry.
3011 * The active index does not change, so the active entry may do so.
3014 * MUIM_List_Exchange
3016 ******************************************************************************
3020 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
3021 struct MUIP_List_Move
*msg
)
3023 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3028 /* Normalise special 'from' values */
3031 case MUIV_List_Move_Top
:
3034 case MUIV_List_Move_Active
:
3035 from
= data
->entries_active
;
3037 case MUIV_List_Move_Bottom
:
3038 from
= data
->entries_num
- 1;
3044 /* Normalise special 'to' values */
3047 case MUIV_List_Move_Top
:
3050 case MUIV_List_Move_Active
:
3051 to
= data
->entries_active
;
3053 case MUIV_List_Move_Bottom
:
3054 to
= data
->entries_num
- 1;
3056 case MUIV_List_Move_Next
:
3059 case MUIV_List_Move_Previous
:
3066 /* Check that values are within valid bounds */
3067 if (from
> data
->entries_num
- 1 || from
< 0
3068 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
3069 return (IPTR
) FALSE
;
3071 /* Shift all entries in the range between the 'from' and 'to' positions */
3074 struct ListEntry
*backup
= data
->entries
[from
];
3075 for (i
= from
; i
< to
; i
++)
3076 data
->entries
[i
] = data
->entries
[i
+ 1];
3077 data
->entries
[to
] = backup
;
3081 struct ListEntry
*backup
= data
->entries
[from
];
3082 for (i
= from
; i
> to
; i
--)
3083 data
->entries
[i
] = data
->entries
[i
- 1];
3084 data
->entries
[to
] = backup
;
3087 #if 0 /* Not done in MUI 3 */
3088 /* Update index of active entry */
3089 if (from
== data
->entries_active
)
3090 data
->entries_active
= to
;
3091 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
3092 data
->entries_active
--;
3093 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
3094 data
->entries_active
++;
3097 /* Reflect list changes visually */
3099 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3104 /****** List.mui/MUIM_List_NextSelected **************************************
3107 * MUIM_List_NextSelected (V6)
3110 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3113 * Allows iteration through a list's selected entries by providing the
3114 * index of the next selected entry after the specified index.
3117 * pos - the address of a variable containing the index of the previous
3118 * selected entry. The variable must be initialised to the special
3119 * value MUIV_List_NextSelected_Start to find the first selected
3120 * entry. When this method returns, the variable will contain the
3121 * index of the next selected entry, or MUIV_List_NextSelected_End if
3122 * there are no more.
3125 * If there are no selected entries but there is an active entry, the
3126 * index of the active entry will be stored (when
3127 * MUIV_List_NextSelected_Start is specified).
3129 * Some selected entries may be skipped if any entries are removed
3130 * between calls to this method during an iteration of a list.
3132 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3133 * the same numeric value.
3136 * MUIM_List_Select, MUIM_List_Remove.
3138 ******************************************************************************
3142 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
3143 struct MUIP_List_NextSelected
*msg
)
3145 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3149 /* Get the first entry to check */
3151 if (pos
== MUIV_List_NextSelected_Start
)
3156 /* Find the next selected entry */
3157 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
3159 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
3166 /* Return index of selected or active entry, or indicate there are no
3170 if (*msg
->pos
== MUIV_List_NextSelected_Start
3171 && data
->entries_active
!= MUIV_List_Active_Off
)
3172 pos
= data
->entries_active
;
3174 pos
= MUIV_List_NextSelected_End
;
3181 /**************************************************************************
3183 **************************************************************************/
3184 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
3185 struct MUIP_List_TestPos
*msg
)
3187 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3188 struct MUI_List_TestPos_Result
*result
= msg
->res
;
3189 LONG col
= -1, row
= -1;
3191 LONG mx
= msg
->x
- _left(data
->area
);
3192 LONG entries_visible
;
3194 if (data
->entries_visible
<= data
->entries_num
)
3195 entries_visible
= data
->entries_visible
;
3197 entries_visible
= data
->entries_num
;
3198 LONG ey
= msg
->y
- data
->entries_top_pixel
;
3199 /* y coordinates transformed to the entries */
3201 /* Now check if it was clicked on a title or on entries */
3203 flags
|= MUI_LPR_ABOVE
;
3204 else if (ey
>= entries_visible
* data
->entry_maxheight
)
3205 flags
|= MUI_LPR_BELOW
;
3209 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
3211 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
3215 flags
|= MUI_LPR_LEFT
;
3216 else if (mx
>= _width(data
->area
))
3217 flags
|= MUI_LPR_RIGHT
;
3220 /* Identify column */
3221 if (data
->entries_num
> 0 && data
->columns
> 0)
3224 col
= data
->columns
- 1;
3225 for (i
= 0; i
< data
->columns
; i
++)
3227 result
->xoffset
= mx
- width_sum
;
3229 data
->ci
[i
].entries_width
+
3231 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
3232 D(bug("[List/MUIM_TestPos] i %d "
3233 "width %d width_sum %d mx %d\n",
3234 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
3238 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
3245 result
->entry
= row
;
3246 result
->column
= col
;
3247 result
->flags
= flags
;
3252 /****i* List.mui/MUIM_DragQuery **********************************************
3257 ******************************************************************************
3261 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
3262 struct MUIP_DragQuery
*msg
)
3264 if (msg
->obj
== obj
)
3265 return MUIV_DragQuery_Accept
;
3267 return MUIV_DragQuery_Refuse
;
3271 /****i* List.mui/MUIM_DragFinish *********************************************
3276 ******************************************************************************
3280 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
3281 struct MUIP_DragFinish
*msg
)
3283 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3285 data
->drop_mark_y
= -1;
3287 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3290 /****i* List.mui/MUIM_DragReport *********************************************
3295 ******************************************************************************
3299 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
3300 struct MUIP_DragReport
*msg
)
3302 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3303 struct MUI_List_TestPos_Result pos
;
3304 struct RastPort
*rp
= _rp(obj
);
3308 /* Choose new drop mark position */
3310 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3311 if (pos
.entry
!= -1)
3314 if (pos
.yoffset
> 0)
3317 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3318 n
= data
->entries_first
;
3321 n
= MIN(data
->entries_visible
, data
->entries_num
)
3322 - data
->entries_first
;
3325 /* Clear old drop mark */
3327 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
3329 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
3330 * data
->entry_maxheight
;
3331 if (y
!= data
->drop_mark_y
)
3333 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
3334 data
->drop_mark_y
, _mwidth(data
->area
), 1, 0, 0, 0);
3336 /* Draw new drop mark and store its position */
3338 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
3340 old_pattern
= rp
->LinePtrn
;
3341 SetDrPt(rp
, 0xF0F0);
3342 Move(rp
, _mleft(data
->area
), y
);
3343 Draw(rp
, _mright(data
->area
), y
);
3344 SetDrPt(rp
, old_pattern
);
3345 data
->drop_mark_y
= y
;
3353 /****i* List.mui/MUIM_DragDrop ***********************************************
3358 ******************************************************************************
3362 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
3363 struct MUIP_DragDrop
*msg
)
3365 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3366 struct MUI_List_TestPos_Result pos
;
3369 /* Find drop position */
3371 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3372 if (pos
.entry
!= -1)
3374 /* Change drop position when coords move past centre of entry, not
3378 if (pos
.yoffset
> 0)
3381 /* Ensure that dropped entry will be positioned between the two
3382 * entries that are above and below the drop mark, rather than
3383 * strictly at the numeric index shown */
3385 if (n
> data
->entries_active
)
3388 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3389 n
= MUIV_List_Move_Top
;
3391 n
= MUIV_List_Move_Bottom
;
3393 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
3399 /****i* List.mui/MUIM_CreateDragImage ****************************************
3402 * MUIM_CreateDragImage
3404 ******************************************************************************
3408 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
3409 struct MUIP_CreateDragImage
*msg
)
3411 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3412 BOOL success
= TRUE
;
3413 struct MUI_List_TestPos_Result pos
;
3414 WORD width
, height
, left
, top
;
3415 struct MUI_DragImage
*img
= NULL
;
3416 const struct ZuneFrameGfx
*zframe
;
3419 /* Get info on dragged entry */
3420 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
3421 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
3422 if (pos
.entry
== -1)
3427 /* Get boundaries of entry */
3428 width
= _mwidth(data
->area
);
3429 height
= data
->entry_maxheight
;
3430 left
= _mleft(data
->area
);
3431 top
= _top(data
->area
) - msg
->touchy
3432 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3434 /* Allocate drag image structure */
3435 img
= (struct MUI_DragImage
*)
3436 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3443 /* Get drag frame */
3444 zframe
= zune_zframe_get(obj
,
3445 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3447 /* Allocate drag image buffer */
3448 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3449 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3450 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3451 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3452 _screen(obj
)->RastPort
.BitMap
);
3454 if (img
->bm
!= NULL
)
3457 struct RastPort temprp
;
3458 InitRastPort(&temprp
);
3459 temprp
.BitMap
= img
->bm
;
3460 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3461 zframe
->ileft
, zframe
->itop
, width
, height
,
3465 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3466 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3467 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3468 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3469 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3472 /* Ensure drag point matches where user clicked */
3473 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3474 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3482 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3484 LONG
new, first
, entries
, visible
;
3486 new = first
= XGET(obj
, MUIA_List_First
);
3487 entries
= XGET(obj
, MUIA_List_Entries
);
3488 visible
= XGET(obj
, MUIA_List_Visible
);
3492 if (new > entries
- visible
)
3494 new = entries
- visible
;
3504 set(obj
, MUIA_List_First
, new);
3508 /**************************************************************************
3510 **************************************************************************/
3511 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3512 struct MUIP_HandleEvent
*msg
)
3514 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3515 struct MUI_List_TestPos_Result pos
;
3516 LONG seltype
, old_active
, new_active
, visible
, first
, last
, i
;
3518 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3520 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3522 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3523 visible
= XGET(obj
, MUIA_List_Visible
);
3525 if (muikey
!= MUIKEY_NONE
)
3527 result
= MUI_EventHandlerRC_Eat
;
3529 /* Make keys behave differently in read-only mode */
3530 if (data
->read_only
)
3535 muikey
= MUIKEY_LINESTART
;
3539 muikey
= MUIKEY_LINEEND
;
3543 muikey
= MUIKEY_LEFT
;
3548 muikey
= MUIKEY_RIGHT
;
3556 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
3557 && !data
->read_only
)
3560 data
->click_column
= data
->def_click_column
;
3561 new_active
= MUIV_List_Active_Down
;
3565 DoMethod(obj
, MUIM_List_Jump
, 0);
3566 muikey
= MUIKEY_NONE
;
3571 new_active
= MUIV_List_Active_Top
;
3575 new_active
= MUIV_List_Active_Bottom
;
3579 case MUIKEY_WORDLEFT
:
3580 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
3584 case MUIKEY_WORDRIGHT
:
3585 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
3588 case MUIKEY_LINESTART
:
3589 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
3592 case MUIKEY_LINEEND
:
3593 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
3597 new_active
= MUIV_List_Active_Up
;
3601 new_active
= MUIV_List_Active_Down
;
3605 data
->click_column
= data
->def_click_column
;
3606 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3607 data
->click_column
);
3608 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3612 if (data
->read_only
)
3613 DoWheelMove(cl
, obj
, -visible
);
3615 new_active
= MUIV_List_Active_PageUp
;
3618 case MUIKEY_PAGEDOWN
:
3619 if (data
->read_only
)
3620 DoWheelMove(cl
, obj
, visible
);
3622 new_active
= MUIV_List_Active_PageDown
;
3631 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
,
3634 switch (msg
->imsg
->Class
)
3636 case IDCMP_MOUSEBUTTONS
:
3637 if (msg
->imsg
->Code
== SELECTDOWN
)
3639 if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3642 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
3644 if (!data
->read_only
&& pos
.entry
!= -1)
3646 new_active
= pos
.entry
;
3648 clear
= (data
->multiselect
3649 == MUIV_Listview_MultiSelect_Shifted
3650 && (msg
->imsg
->Qualifier
3651 & (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
3652 seltype
= clear
? MUIV_List_Select_On
3653 : MUIV_List_Select_Toggle
;
3654 select
= data
->multiselect
3655 != MUIV_Listview_MultiSelect_None
;
3657 /* Handle MUIA_Listview_ClickColumn */
3658 data
->click_column
= pos
.column
;
3659 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3660 data
->click_column
);
3662 /* Handle double clicking */
3663 if (data
->last_active
== pos
.entry
3664 && DoubleClick(data
->last_secs
, data
->last_mics
,
3665 msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
3667 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3668 data
->last_active
= -1;
3669 data
->last_secs
= data
->last_mics
= 0;
3673 data
->last_active
= pos
.entry
;
3674 data
->last_secs
= msg
->imsg
->Seconds
;
3675 data
->last_mics
= msg
->imsg
->Micros
;
3678 /* Look out for mouse movement, timer and
3679 inactive-window events while mouse button is
3681 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3683 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
3684 | IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
3685 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3692 /* Activate object */
3693 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
3695 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
3696 data
->mouse_click
= 0;
3699 /* Restore normal event mask */
3700 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3702 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
3703 | IDCMP_INACTIVEWINDOW
);
3704 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3709 case IDCMP_MOUSEMOVE
:
3710 case IDCMP_INTUITICKS
:
3711 if (pos
.flags
& MUI_LPR_ABOVE
)
3712 new_active
= MUIV_List_Active_Up
;
3713 else if (pos
.flags
& MUI_LPR_BELOW
)
3714 new_active
= MUIV_List_Active_Down
;
3716 new_active
= pos
.entry
;
3718 select
= new_active
!= old_active
3719 && data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3722 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3723 MUIV_List_Select_Ask
, &seltype
);
3724 range_select
= new_active
>= 0;
3729 case IDCMP_INACTIVEWINDOW
:
3730 /* Stop listening for events we only listen to when mouse button is
3731 down: we will not be informed of the button being released */
3732 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3734 data
->ehn
.ehn_Events
&=
3735 ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3736 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3742 if (data
->vert
&& _isinobject(data
->vert
, msg
->imsg
->MouseX
,
3745 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3753 switch (msg
->imsg
->Code
)
3755 case RAWKEY_NM_WHEEL_UP
:
3756 DoWheelMove(cl
, obj
, -delta
);
3759 case RAWKEY_NM_WHEEL_DOWN
:
3760 DoWheelMove(cl
, obj
, delta
);
3763 result
= MUI_EventHandlerRC_Eat
;
3769 /* Decide in advance if any selections may change */
3770 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
3772 /* Change selected and active entries */
3774 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
3778 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
3779 MUIV_List_Select_Off
, NULL
);
3782 if (muikey
== MUIKEY_TOGGLE
)
3784 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3785 MUIV_List_Select_Toggle
, NULL
);
3789 if (new_active
!= old_active
)
3790 set(obj
, MUIA_List_Active
, new_active
);
3796 if (old_active
< new_active
)
3797 first
= old_active
+ 1, last
= new_active
;
3799 first
= new_active
, last
= old_active
- 1;
3800 for (i
= first
; i
<= last
; i
++)
3801 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
3804 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3809 set(obj
, MUIA_Listview_SelectChange
, FALSE
);
3814 /**************************************************************************
3816 **************************************************************************/
3817 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3819 switch (msg
->MethodID
)
3822 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3824 return List__OM_DISPOSE(cl
, obj
, msg
);
3826 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3828 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3831 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3833 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3834 case MUIM_HandleEvent
:
3835 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
3836 case MUIM_AskMinMax
:
3837 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3839 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3841 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3843 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3845 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3846 case MUIM_List_Clear
:
3847 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3848 case MUIM_List_Sort
:
3849 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3850 case MUIM_List_Exchange
:
3851 return List__MUIM_Exchange(cl
, obj
,
3852 (struct MUIP_List_Exchange
*)msg
);
3853 case MUIM_List_Insert
:
3854 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3855 case MUIM_List_InsertSingle
:
3856 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3857 case MUIM_List_GetEntry
:
3858 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3859 case MUIM_List_Redraw
:
3860 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3861 case MUIM_List_Remove
:
3862 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3863 case MUIM_List_Select
:
3864 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3865 case MUIM_List_Construct
:
3866 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3867 case MUIM_List_Destruct
:
3868 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3869 case MUIM_List_Compare
:
3870 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3871 case MUIM_List_Display
:
3872 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3873 case MUIM_List_SelectChange
:
3874 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3875 case MUIM_List_CreateImage
:
3876 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3877 case MUIM_List_DeleteImage
:
3878 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3879 case MUIM_List_Jump
:
3880 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3881 case MUIM_List_Move
:
3882 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3883 case MUIM_List_NextSelected
:
3884 return List__MUIM_NextSelected(cl
, obj
,
3885 (struct MUIP_List_NextSelected
*)msg
);
3886 case MUIM_List_TestPos
:
3887 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3888 case MUIM_DragQuery
:
3889 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3890 case MUIM_DragFinish
:
3891 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3892 case MUIM_DragReport
:
3893 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3895 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3896 case MUIM_CreateDragImage
:
3897 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3900 return DoSuperMethodA(cl
, obj
, msg
);
3902 BOOPSI_DISPATCHER_END
3907 const struct __MUIBuiltinClass _MUI_List_desc
=
3911 sizeof(struct MUI_ListData
),
3912 (void *) List_Dispatcher