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 /* Update entries count prior to range check */
2314 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
, TAG_DONE
);
2316 /* Ensure that the active element is in a valid range (it might become
2317 * MUIV_List_Active_Off (-1), but that's OK) */
2318 if (new_act
>= data
->entries_num
)
2319 new_act
= data
->entries_num
- 1;
2322 active_tag
, new_act
, /* Inform only if necessary (for notify) */
2326 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2331 /**************************************************************************
2333 **************************************************************************/
2334 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2335 struct MUIP_List_Select
*msg
)
2337 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2338 LONG pos
, i
, count
, selcount
=0, state
=0;
2339 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
2341 /* Establish the range of entries affected */
2344 case MUIV_List_Select_Active
:
2345 pos
= data
->entries_active
;
2346 if (pos
== MUIV_List_Active_Off
)
2352 case MUIV_List_Select_All
:
2354 count
= data
->entries_num
;
2360 if (pos
< 0 || pos
>= data
->entries_num
)
2365 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2367 /* Disallow selection of an additional entry if there is a currently
2368 selected entry that is not multi-selectable (in such case there
2369 will only be one entry currently selected, so no need to iterate) */
2370 i
= MUIV_List_NextSelected_Start
;
2371 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
2372 if (i
!= MUIV_List_NextSelected_End
)
2374 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
2375 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2376 data
->entries
[i
]->data
);
2379 /* Change or check state of each entry in the range */
2380 for (i
= pos
; i
< pos
+ count
; i
++)
2382 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2383 switch (msg
->seltype
)
2385 case MUIV_List_Select_Off
:
2386 new_select_state
= FALSE
;
2389 case MUIV_List_Select_On
:
2390 new_select_state
= TRUE
;
2393 case MUIV_List_Select_Toggle
:
2394 new_select_state
= !state
;
2398 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2403 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2405 /* Disallow selection if entry is not multi-selectable and
2406 * there are already selected entries */
2407 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
2408 new_select_state
= multi_allowed
&& (selcount
== 0 ||
2409 CallHookPkt(data
->multi_test_hook
, NULL
,
2410 data
->entries
[i
]->data
));
2412 if (new_select_state
)
2413 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2415 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2419 /* Report old state or number of selected entries */
2422 if (msg
->pos
== MUIV_List_Select_All
2423 && msg
->seltype
== MUIV_List_Select_Ask
)
2424 *msg
->info
= selcount
;
2429 /* Redraw unless it was just an enquiry */
2430 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2437 data
->update_pos
= pos
;
2439 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2445 /****** List.mui/MUIM_List_Insert ********************************************
2448 * MUIM_List_Insert (V4)
2451 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2454 * Adds multiple entries to the list. If a construct hook has been
2455 * installed, the results of passing the entries to this hook will be
2459 * entries - an array of entries to be inserted.
2460 * count - the number of entries to insert. A special value of -1 may be
2461 * used, indicating that the array of entries is NULL-terminated.
2462 * pos - the index at which to insert the new entries. The following
2463 * special values can also be used:
2464 * MUIV_List_Insert_Top: insert at index 0.
2465 * MUIV_List_Insert_Bottom: insert after all existing entries.
2466 * MUIV_List_Insert_Active: insert at the index of the active entry
2467 * (or at index 0 if there is no active entry).
2468 * MUIV_List_Insert_Sorted: keep the list sorted.
2471 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2473 ******************************************************************************
2477 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2478 struct MUIP_List_Insert
*msg
)
2480 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2481 LONG pos
, count
, sort
, active
;
2488 /* Count the number of entries */
2489 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2498 case MUIV_List_Insert_Top
:
2502 case MUIV_List_Insert_Active
:
2503 if (data
->entries_active
!= -1)
2504 pos
= data
->entries_active
;
2509 case MUIV_List_Insert_Sorted
:
2510 pos
= data
->entries_num
;
2511 sort
= 1; /* we sort'em later */
2514 case MUIV_List_Insert_Bottom
:
2515 pos
= data
->entries_num
;
2519 if (msg
->pos
> data
->entries_num
)
2520 pos
= data
->entries_num
;
2521 else if (msg
->pos
< 0)
2527 data
->insert_position
= pos
;
2529 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2532 LONG until
= pos
+ count
;
2533 APTR
*toinsert
= msg
->entries
;
2535 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2540 struct ListEntry
*lentry
;
2542 if (!(lentry
= AllocListEntry(data
)))
2544 /* Panic, but we must be in a consistent state, so remove
2545 * the space where the following list entries should have gone
2547 RemoveListEntries(data
, pos
, until
- pos
);
2551 /* now call the construct method which returns us a pointer which
2553 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2554 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2557 FreeListEntry(data
, lentry
);
2558 RemoveListEntries(data
, pos
, until
- pos
);
2560 /* TODO: Also check for visible stuff like below */
2561 if (data
->entries_num
!= data
->confirm_entries_num
)
2562 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2566 data
->entries
[pos
] = lentry
;
2567 data
->confirm_entries_num
++;
2569 if (_flags(obj
) & MADF_SETUP
)
2571 /* We have to calculate the width and height of the newly
2572 * inserted entry. This has to be done after inserting the
2573 * element into the list */
2574 CalcDimsOfEntry(cl
, obj
, pos
);
2582 /* Recalculate the number of visible entries */
2583 if (_flags(obj
) & MADF_SETUP
)
2584 CalcVertVisible(cl
, obj
);
2586 if (data
->entries_num
!= data
->confirm_entries_num
)
2589 MUIA_List_Entries
, data
->confirm_entries_num
,
2590 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2593 /* If the array is already sorted, we could do a simple insert
2594 * sort and would be much faster than with qsort.
2595 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2596 * sort the whole array?
2598 * I think, we better sort the whole array:
2602 DoMethod(obj
, MUIM_List_Sort
);
2603 /* TODO: which pos to return here !? */
2604 /* MUIM_List_Sort already called MUI_Redraw */
2609 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2611 superset(cl
, obj
, MUIA_List_InsertPosition
, data
->insert_position
);
2613 /* Update index of active entry */
2614 if (data
->entries_active
>= data
->insert_position
)
2616 active
= data
->entries_active
+ count
;
2617 SET(obj
, MUIA_List_Active
, active
);
2623 /****** List.mui/MUIM_List_InsertSingle **************************************
2626 * MUIM_List_InsertSingle (V7)
2629 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2632 * Adds a single entry to the list. If a construct hook has been
2633 * installed, the result of passing the entry to this hook will be
2637 * entry - the entry to be inserted.
2638 * pos - the index at which to insert the new entry. The following
2639 * special values can also be used:
2640 * MUIV_List_Insert_Top: insert at index 0.
2641 * MUIV_List_Insert_Bottom: insert after all existing entries.
2642 * MUIV_List_Insert_Active: insert at the index of the active entry
2643 * (or at index 0 if there is no active entry).
2644 * MUIV_List_Insert_Sorted: keep the list sorted.
2647 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2649 ******************************************************************************
2653 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2654 struct MUIP_List_InsertSingle
*msg
)
2656 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2660 /**************************************************************************
2662 **************************************************************************/
2663 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2664 struct MUIP_List_GetEntry
*msg
)
2666 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2669 if (pos
== MUIV_List_GetEntry_Active
)
2670 pos
= data
->entries_active
;
2672 if (pos
< 0 || pos
>= data
->entries_num
)
2677 *msg
->entry
= data
->entries
[pos
]->data
;
2678 return (IPTR
) *msg
->entry
;
2681 /**************************************************************************
2683 **************************************************************************/
2684 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2685 struct MUIP_List_Construct
*msg
)
2687 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2689 if (NULL
== data
->construct_hook
)
2690 return (IPTR
) msg
->entry
;
2691 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2693 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2694 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2699 if (msg
->entry
!= NULL
)
2700 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2702 *(STRPTR
) (mem
+ 1) = 0;
2703 return (IPTR
) (mem
+ 1);
2705 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2708 /**************************************************************************
2710 **************************************************************************/
2711 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2712 struct MUIP_List_Destruct
*msg
)
2714 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2716 if (NULL
== data
->destruct_hook
)
2719 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2721 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2722 FreePooled(msg
->pool
, mem
, mem
[0]);
2726 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2731 /****** List.mui/MUIM_List_Compare *******************************************
2734 * MUIM_List_Compare (V20)
2737 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2738 * LONG sort_type1, LONG sort_type2);
2741 * Compare two list entries according to the current comparison hook
2742 * (MUIA_List_CompareHook).
2745 * entry1 - the first entry data.
2746 * entry2 - the second entry data.
2747 * sort_type1 - undocumented.
2748 * sort_type2 - undocumented.
2751 * MUIA_List_CompareHook, MUIM_List_Sort.
2753 ******************************************************************************
2757 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2758 struct MUIP_List_Compare
*msg
)
2760 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2762 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2765 /**************************************************************************
2767 **************************************************************************/
2768 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2769 struct MUIP_List_Display
*msg
)
2771 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2773 if (NULL
== data
->display_hook
)
2776 *msg
->array
= msg
->entry
;
2782 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2783 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2786 /**************************************************************************
2787 MUIM_List_SelectChange
2788 **************************************************************************/
2789 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2790 struct MUIP_List_SelectChange
*msg
)
2795 /**************************************************************************
2796 MUIM_List_CreateImage
2797 Called by a List subclass in its Setup method.
2798 Connects an Area subclass object to the list, much like an object gets
2799 connected to a window. List calls Setup and AskMinMax on that object,
2800 keeps a reference to it (that reference will be returned).
2801 Text engine will dereference that pointer and draw the object with its
2803 **************************************************************************/
2804 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2805 struct MUIP_List_CreateImage
*msg
)
2807 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2808 struct ListImage
*li
;
2813 /* List must be already setup in Setup of your subclass */
2814 if (!(_flags(obj
) & MADF_SETUP
))
2816 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2821 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2822 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2823 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2829 /**************************************************************************
2830 MUIM_List_DeleteImage
2831 **************************************************************************/
2832 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2833 struct MUIP_List_DeleteImage
*msg
)
2835 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2836 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2840 DoMethod(li
->obj
, MUIM_Cleanup
);
2841 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2842 Remove((struct Node
*)li
);
2843 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2849 /****** List.mui/MUIM_List_Jump **********************************************
2852 * MUIM_List_Jump (V4)
2855 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2858 * Scrolls the list so that a particular entry is visible.
2861 * pos - index of entry that should become visible, or one of these
2863 * MUIV_List_Jump_Active: show the active entry.
2864 * MUIV_List_Jump_Top: show the first entry.
2865 * MUIV_List_Jump_Bottom: show the last entry.
2866 * MUIV_List_Jump_Up: show the previous hidden entry.
2867 * MUIV_List_Jump_Down: show the next hidden entry.
2869 ******************************************************************************
2873 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2874 struct MUIP_List_Jump
*msg
)
2876 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2877 LONG pos
= msg
->pos
;
2881 case MUIV_List_Jump_Top
:
2885 case MUIV_List_Jump_Active
:
2886 pos
= data
->entries_active
;
2889 case MUIV_List_Jump_Bottom
:
2890 pos
= data
->entries_num
- 1;
2893 case MUIV_List_Jump_Down
:
2894 pos
= data
->entries_first
+ data
->entries_visible
;
2897 case MUIV_List_Jump_Up
:
2898 pos
= data
->entries_first
- 1;
2902 if (pos
>= data
->entries_num
)
2904 pos
= data
->entries_num
- 1;
2909 if (pos
< data
->entries_first
)
2911 set(obj
, MUIA_List_First
, pos
);
2913 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2915 pos
-= (data
->entries_visible
- 1);
2918 if (pos
!= data
->entries_first
)
2920 set(obj
, MUIA_List_First
, pos
);
2927 /****** List.mui/MUIM_List_Sort **********************************************
2930 * MUIM_List_Sort (V4)
2933 * DoMethod(obj, MUIM_List_Sort);
2936 * Sort the list's entries according to the current comparison hook
2937 * (MUIA_List_CompareHook).
2940 * The active index does not change, so the active entry may do so.
2943 * MUIA_List_CompareHook, MUIM_List_Compare.
2945 ******************************************************************************
2949 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2950 struct MUIP_List_Sort
*msg
)
2952 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2955 struct MUIP_List_Compare cmpmsg
=
2956 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2958 if (data
->entries_num
> 1)
2961 Simple sort algorithm. Feel free to improve it.
2963 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2966 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2968 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2969 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2970 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2977 APTR tmp
= data
->entries
[i
];
2978 data
->entries
[i
] = data
->entries
[max
];
2979 data
->entries
[max
] = tmp
;
2985 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2990 /****** List.mui/MUIM_List_Move **********************************************
2993 * MUIM_List_Move (V9)
2996 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2999 * Move a list entry to a new position.
3002 * from - the current index of the entry that should be moved, or one of
3003 * these special values:
3004 * MUIV_List_Move_Active: the active entry.
3005 * MUIV_List_Move_Top: the first entry.
3006 * MUIV_List_Move_Bottom: the last entry.
3007 * to - the index of the entry's new position, or one of
3008 * these special values:
3009 * MUIV_List_Move_Active: the active entry.
3010 * MUIV_List_Move_Top: the first entry.
3011 * MUIV_List_Move_Bottom: the last entry.
3014 * The active index does not change, so the active entry may do so.
3017 * MUIM_List_Exchange
3019 ******************************************************************************
3023 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
3024 struct MUIP_List_Move
*msg
)
3026 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3031 /* Normalise special 'from' values */
3034 case MUIV_List_Move_Top
:
3037 case MUIV_List_Move_Active
:
3038 from
= data
->entries_active
;
3040 case MUIV_List_Move_Bottom
:
3041 from
= data
->entries_num
- 1;
3047 /* Normalise special 'to' values */
3050 case MUIV_List_Move_Top
:
3053 case MUIV_List_Move_Active
:
3054 to
= data
->entries_active
;
3056 case MUIV_List_Move_Bottom
:
3057 to
= data
->entries_num
- 1;
3059 case MUIV_List_Move_Next
:
3062 case MUIV_List_Move_Previous
:
3069 /* Check that values are within valid bounds */
3070 if (from
> data
->entries_num
- 1 || from
< 0
3071 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
3072 return (IPTR
) FALSE
;
3074 /* Shift all entries in the range between the 'from' and 'to' positions */
3077 struct ListEntry
*backup
= data
->entries
[from
];
3078 for (i
= from
; i
< to
; i
++)
3079 data
->entries
[i
] = data
->entries
[i
+ 1];
3080 data
->entries
[to
] = backup
;
3084 struct ListEntry
*backup
= data
->entries
[from
];
3085 for (i
= from
; i
> to
; i
--)
3086 data
->entries
[i
] = data
->entries
[i
- 1];
3087 data
->entries
[to
] = backup
;
3090 #if 0 /* Not done in MUI 3 */
3091 /* Update index of active entry */
3092 if (from
== data
->entries_active
)
3093 data
->entries_active
= to
;
3094 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
3095 data
->entries_active
--;
3096 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
3097 data
->entries_active
++;
3100 /* Reflect list changes visually */
3102 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3107 /****** List.mui/MUIM_List_NextSelected **************************************
3110 * MUIM_List_NextSelected (V6)
3113 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3116 * Allows iteration through a list's selected entries by providing the
3117 * index of the next selected entry after the specified index.
3120 * pos - the address of a variable containing the index of the previous
3121 * selected entry. The variable must be initialised to the special
3122 * value MUIV_List_NextSelected_Start to find the first selected
3123 * entry. When this method returns, the variable will contain the
3124 * index of the next selected entry, or MUIV_List_NextSelected_End if
3125 * there are no more.
3128 * If there are no selected entries but there is an active entry, the
3129 * index of the active entry will be stored (when
3130 * MUIV_List_NextSelected_Start is specified).
3132 * Some selected entries may be skipped if any entries are removed
3133 * between calls to this method during an iteration of a list.
3135 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3136 * the same numeric value.
3139 * MUIM_List_Select, MUIM_List_Remove.
3141 ******************************************************************************
3145 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
3146 struct MUIP_List_NextSelected
*msg
)
3148 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3152 /* Get the first entry to check */
3154 if (pos
== MUIV_List_NextSelected_Start
)
3159 /* Find the next selected entry */
3160 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
3162 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
3169 /* Return index of selected or active entry, or indicate there are no
3173 if (*msg
->pos
== MUIV_List_NextSelected_Start
3174 && data
->entries_active
!= MUIV_List_Active_Off
)
3175 pos
= data
->entries_active
;
3177 pos
= MUIV_List_NextSelected_End
;
3184 /**************************************************************************
3186 **************************************************************************/
3187 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
3188 struct MUIP_List_TestPos
*msg
)
3190 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3191 struct MUI_List_TestPos_Result
*result
= msg
->res
;
3192 LONG col
= -1, row
= -1;
3194 LONG mx
= msg
->x
- _left(data
->area
);
3195 LONG entries_visible
;
3197 if (data
->entries_visible
<= data
->entries_num
)
3198 entries_visible
= data
->entries_visible
;
3200 entries_visible
= data
->entries_num
;
3201 LONG ey
= msg
->y
- data
->entries_top_pixel
;
3202 /* y coordinates transformed to the entries */
3204 /* Now check if it was clicked on a title or on entries */
3206 flags
|= MUI_LPR_ABOVE
;
3207 else if (ey
>= entries_visible
* data
->entry_maxheight
)
3208 flags
|= MUI_LPR_BELOW
;
3212 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
3214 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
3218 flags
|= MUI_LPR_LEFT
;
3219 else if (mx
>= _width(data
->area
))
3220 flags
|= MUI_LPR_RIGHT
;
3223 /* Identify column */
3224 if (data
->entries_num
> 0 && data
->columns
> 0)
3227 col
= data
->columns
- 1;
3228 for (i
= 0; i
< data
->columns
; i
++)
3230 result
->xoffset
= mx
- width_sum
;
3232 data
->ci
[i
].entries_width
+
3234 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
3235 D(bug("[List/MUIM_TestPos] i %d "
3236 "width %d width_sum %d mx %d\n",
3237 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
3241 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
3248 result
->entry
= row
;
3249 result
->column
= col
;
3250 result
->flags
= flags
;
3255 /****i* List.mui/MUIM_DragQuery **********************************************
3260 ******************************************************************************
3264 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
3265 struct MUIP_DragQuery
*msg
)
3267 if (msg
->obj
== obj
)
3268 return MUIV_DragQuery_Accept
;
3270 return MUIV_DragQuery_Refuse
;
3274 /****i* List.mui/MUIM_DragFinish *********************************************
3279 ******************************************************************************
3283 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
3284 struct MUIP_DragFinish
*msg
)
3286 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3288 data
->drop_mark_y
= -1;
3290 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3293 /****i* List.mui/MUIM_DragReport *********************************************
3298 ******************************************************************************
3302 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
3303 struct MUIP_DragReport
*msg
)
3305 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3306 struct MUI_List_TestPos_Result pos
;
3307 struct RastPort
*rp
= _rp(obj
);
3311 /* Choose new drop mark position */
3313 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3314 if (pos
.entry
!= -1)
3317 if (pos
.yoffset
> 0)
3320 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3321 n
= data
->entries_first
;
3324 n
= MIN(data
->entries_visible
, data
->entries_num
)
3325 - data
->entries_first
;
3328 /* Clear old drop mark */
3330 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
3332 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
3333 * data
->entry_maxheight
;
3334 if (y
!= data
->drop_mark_y
)
3336 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
3337 data
->drop_mark_y
, _mwidth(data
->area
), 1, 0, 0, 0);
3339 /* Draw new drop mark and store its position */
3341 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
3343 old_pattern
= rp
->LinePtrn
;
3344 SetDrPt(rp
, 0xF0F0);
3345 Move(rp
, _mleft(data
->area
), y
);
3346 Draw(rp
, _mright(data
->area
), y
);
3347 SetDrPt(rp
, old_pattern
);
3348 data
->drop_mark_y
= y
;
3356 /****i* List.mui/MUIM_DragDrop ***********************************************
3361 ******************************************************************************
3365 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
3366 struct MUIP_DragDrop
*msg
)
3368 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3369 struct MUI_List_TestPos_Result pos
;
3372 /* Find drop position */
3374 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3375 if (pos
.entry
!= -1)
3377 /* Change drop position when coords move past centre of entry, not
3381 if (pos
.yoffset
> 0)
3384 /* Ensure that dropped entry will be positioned between the two
3385 * entries that are above and below the drop mark, rather than
3386 * strictly at the numeric index shown */
3388 if (n
> data
->entries_active
)
3391 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3392 n
= MUIV_List_Move_Top
;
3394 n
= MUIV_List_Move_Bottom
;
3396 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
3402 /****i* List.mui/MUIM_CreateDragImage ****************************************
3405 * MUIM_CreateDragImage
3407 ******************************************************************************
3411 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
3412 struct MUIP_CreateDragImage
*msg
)
3414 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3415 BOOL success
= TRUE
;
3416 struct MUI_List_TestPos_Result pos
;
3417 WORD width
, height
, left
, top
;
3418 struct MUI_DragImage
*img
= NULL
;
3419 const struct ZuneFrameGfx
*zframe
;
3422 /* Get info on dragged entry */
3423 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
3424 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
3425 if (pos
.entry
== -1)
3430 /* Get boundaries of entry */
3431 width
= _mwidth(data
->area
);
3432 height
= data
->entry_maxheight
;
3433 left
= _mleft(data
->area
);
3434 top
= _top(data
->area
) - msg
->touchy
3435 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3437 /* Allocate drag image structure */
3438 img
= (struct MUI_DragImage
*)
3439 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3446 /* Get drag frame */
3447 zframe
= zune_zframe_get(obj
,
3448 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3450 /* Allocate drag image buffer */
3451 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3452 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3453 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3454 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3455 _screen(obj
)->RastPort
.BitMap
);
3457 if (img
->bm
!= NULL
)
3460 struct RastPort temprp
;
3461 InitRastPort(&temprp
);
3462 temprp
.BitMap
= img
->bm
;
3463 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3464 zframe
->ileft
, zframe
->itop
, width
, height
,
3468 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3469 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3470 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3471 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3472 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3475 /* Ensure drag point matches where user clicked */
3476 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3477 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3485 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3487 LONG
new, first
, entries
, visible
;
3489 new = first
= XGET(obj
, MUIA_List_First
);
3490 entries
= XGET(obj
, MUIA_List_Entries
);
3491 visible
= XGET(obj
, MUIA_List_Visible
);
3495 if (new > entries
- visible
)
3497 new = entries
- visible
;
3507 set(obj
, MUIA_List_First
, new);
3511 /**************************************************************************
3513 **************************************************************************/
3514 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3515 struct MUIP_HandleEvent
*msg
)
3517 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3518 struct MUI_List_TestPos_Result pos
;
3519 LONG seltype
, old_active
, new_active
, visible
, first
, last
, i
;
3521 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3523 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3525 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3526 visible
= XGET(obj
, MUIA_List_Visible
);
3528 if (muikey
!= MUIKEY_NONE
)
3530 result
= MUI_EventHandlerRC_Eat
;
3532 /* Make keys behave differently in read-only mode */
3533 if (data
->read_only
)
3538 muikey
= MUIKEY_LINESTART
;
3542 muikey
= MUIKEY_LINEEND
;
3546 muikey
= MUIKEY_LEFT
;
3551 muikey
= MUIKEY_RIGHT
;
3559 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
3560 && !data
->read_only
)
3563 data
->click_column
= data
->def_click_column
;
3564 new_active
= MUIV_List_Active_Down
;
3568 DoMethod(obj
, MUIM_List_Jump
, 0);
3569 muikey
= MUIKEY_NONE
;
3574 new_active
= MUIV_List_Active_Top
;
3578 new_active
= MUIV_List_Active_Bottom
;
3582 case MUIKEY_WORDLEFT
:
3583 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
3587 case MUIKEY_WORDRIGHT
:
3588 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
3591 case MUIKEY_LINESTART
:
3592 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
3595 case MUIKEY_LINEEND
:
3596 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
3600 new_active
= MUIV_List_Active_Up
;
3604 new_active
= MUIV_List_Active_Down
;
3608 data
->click_column
= data
->def_click_column
;
3609 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3610 data
->click_column
);
3611 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3615 if (data
->read_only
)
3616 DoWheelMove(cl
, obj
, -visible
);
3618 new_active
= MUIV_List_Active_PageUp
;
3621 case MUIKEY_PAGEDOWN
:
3622 if (data
->read_only
)
3623 DoWheelMove(cl
, obj
, visible
);
3625 new_active
= MUIV_List_Active_PageDown
;
3634 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
,
3637 switch (msg
->imsg
->Class
)
3639 case IDCMP_MOUSEBUTTONS
:
3640 if (msg
->imsg
->Code
== SELECTDOWN
)
3642 if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3645 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
3647 if (!data
->read_only
&& pos
.entry
!= -1)
3649 new_active
= pos
.entry
;
3651 clear
= (data
->multiselect
3652 == MUIV_Listview_MultiSelect_Shifted
3653 && (msg
->imsg
->Qualifier
3654 & (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
3655 seltype
= clear
? MUIV_List_Select_On
3656 : MUIV_List_Select_Toggle
;
3657 select
= data
->multiselect
3658 != MUIV_Listview_MultiSelect_None
;
3660 /* Handle MUIA_Listview_ClickColumn */
3661 data
->click_column
= pos
.column
;
3662 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3663 data
->click_column
);
3665 /* Handle double clicking */
3666 if (data
->last_active
== pos
.entry
3667 && DoubleClick(data
->last_secs
, data
->last_mics
,
3668 msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
3670 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3671 data
->last_active
= -1;
3672 data
->last_secs
= data
->last_mics
= 0;
3676 data
->last_active
= pos
.entry
;
3677 data
->last_secs
= msg
->imsg
->Seconds
;
3678 data
->last_mics
= msg
->imsg
->Micros
;
3681 /* Look out for mouse movement, timer and
3682 inactive-window events while mouse button is
3684 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3686 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
3687 | IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
3688 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3695 /* Activate object */
3696 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
3698 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
3699 data
->mouse_click
= 0;
3702 /* Restore normal event mask */
3703 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3705 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
3706 | IDCMP_INACTIVEWINDOW
);
3707 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3712 case IDCMP_MOUSEMOVE
:
3713 case IDCMP_INTUITICKS
:
3714 if (pos
.flags
& MUI_LPR_ABOVE
)
3715 new_active
= MUIV_List_Active_Up
;
3716 else if (pos
.flags
& MUI_LPR_BELOW
)
3717 new_active
= MUIV_List_Active_Down
;
3719 new_active
= pos
.entry
;
3721 select
= new_active
!= old_active
3722 && data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3725 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3726 MUIV_List_Select_Ask
, &seltype
);
3727 range_select
= new_active
>= 0;
3732 case IDCMP_INACTIVEWINDOW
:
3733 /* Stop listening for events we only listen to when mouse button is
3734 down: we will not be informed of the button being released */
3735 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3737 data
->ehn
.ehn_Events
&=
3738 ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3739 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3745 if (data
->vert
&& _isinobject(data
->vert
, msg
->imsg
->MouseX
,
3748 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3756 switch (msg
->imsg
->Code
)
3758 case RAWKEY_NM_WHEEL_UP
:
3759 DoWheelMove(cl
, obj
, -delta
);
3762 case RAWKEY_NM_WHEEL_DOWN
:
3763 DoWheelMove(cl
, obj
, delta
);
3766 result
= MUI_EventHandlerRC_Eat
;
3772 /* Decide in advance if any selections may change */
3773 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
3775 /* Change selected and active entries */
3777 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
3781 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
3782 MUIV_List_Select_Off
, NULL
);
3785 if (muikey
== MUIKEY_TOGGLE
)
3787 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3788 MUIV_List_Select_Toggle
, NULL
);
3792 if (new_active
!= old_active
)
3793 set(obj
, MUIA_List_Active
, new_active
);
3799 if (old_active
< new_active
)
3800 first
= old_active
+ 1, last
= new_active
;
3802 first
= new_active
, last
= old_active
- 1;
3803 for (i
= first
; i
<= last
; i
++)
3804 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
3807 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3812 set(obj
, MUIA_Listview_SelectChange
, FALSE
);
3817 /**************************************************************************
3819 **************************************************************************/
3820 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3822 switch (msg
->MethodID
)
3825 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3827 return List__OM_DISPOSE(cl
, obj
, msg
);
3829 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3831 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3834 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3836 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3837 case MUIM_HandleEvent
:
3838 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
3839 case MUIM_AskMinMax
:
3840 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3842 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3844 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3846 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3848 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3849 case MUIM_List_Clear
:
3850 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3851 case MUIM_List_Sort
:
3852 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3853 case MUIM_List_Exchange
:
3854 return List__MUIM_Exchange(cl
, obj
,
3855 (struct MUIP_List_Exchange
*)msg
);
3856 case MUIM_List_Insert
:
3857 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3858 case MUIM_List_InsertSingle
:
3859 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3860 case MUIM_List_GetEntry
:
3861 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3862 case MUIM_List_Redraw
:
3863 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3864 case MUIM_List_Remove
:
3865 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3866 case MUIM_List_Select
:
3867 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3868 case MUIM_List_Construct
:
3869 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3870 case MUIM_List_Destruct
:
3871 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3872 case MUIM_List_Compare
:
3873 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3874 case MUIM_List_Display
:
3875 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3876 case MUIM_List_SelectChange
:
3877 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3878 case MUIM_List_CreateImage
:
3879 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3880 case MUIM_List_DeleteImage
:
3881 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3882 case MUIM_List_Jump
:
3883 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3884 case MUIM_List_Move
:
3885 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3886 case MUIM_List_NextSelected
:
3887 return List__MUIM_NextSelected(cl
, obj
,
3888 (struct MUIP_List_NextSelected
*)msg
);
3889 case MUIM_List_TestPos
:
3890 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3891 case MUIM_DragQuery
:
3892 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3893 case MUIM_DragFinish
:
3894 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3895 case MUIM_DragReport
:
3896 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3898 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3899 case MUIM_CreateDragImage
:
3900 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3903 return DoSuperMethodA(cl
, obj
, msg
);
3905 BOOPSI_DISPATCHER_END
3910 const struct __MUIBuiltinClass _MUI_List_desc
=
3914 sizeof(struct MUI_ListData
),
3915 (void *) List_Dispatcher