2 Copyright © 2002-2015, 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
*widths
; /* Widths of the columns */
58 LONG width
; /* Line width */
59 LONG height
; /* Line height */
60 WORD flags
; /* see below */
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
; /* the strings for the display function, one
134 * more than needed (for the entry position) */
137 int title_height
; /* The complete height of the title */
138 STRPTR title
; /* On single column lists this is the title,
139 * otherwise 1. NULL for no title(s) */
142 struct MUI_ImageSpec_intern
*list_cursor
;
143 struct MUI_ImageSpec_intern
*list_select
;
144 struct MUI_ImageSpec_intern
*list_selcur
;
146 /* Render optimization */
147 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
148 * 3 - scroll to current entries_first (old value is in
155 struct MinList images
;
158 ListviewRefresh prefs_refresh
;
159 UWORD prefs_linespacing
;
161 UWORD prefs_smoothval
;
163 /* render space handling */
168 /***************************/
169 /* Former Listview members */
170 /***************************/
180 LONG def_click_column
;
182 LONG mouse_click
; /* see below if mouse is held down */
189 struct MUI_EventHandlerNode ehn
;
192 ListviewMulti prefs_multi
;
200 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
201 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
203 #define LIST_ADJUSTWIDTH (1<<0)
204 #define LIST_ADJUSTHEIGHT (1<<1)
205 #define LIST_AUTOVISIBLE (1<<2)
206 #define LIST_DRAGSORTABLE (1<<3)
207 #define LIST_SHOWDROPMARKS (1<<4)
208 #define LIST_QUIET (1<<5)
211 /****** List.mui/MUIA_List_Active ********************************************
214 * MUIA_List_Active -- (V4) [ISG], LONG
217 * The index of the active entry. There can be at most one active entry
218 * in a list. The active entry is highlighted visibly, except for
219 * read-only lists (those whose Listview has MUIA_Listview_Input set to
220 * FALSE). Selecting an entry with the mouse, or moving through the list
221 * with keyboard controls will also change the active entry (again
222 * excepting read-only lists).
224 * When set programmatically through this attribute, some special values
227 * MUIV_List_Active_Off
228 * MUIV_List_Active_Top
229 * MUIV_List_Active_Bottom
230 * MUIV_List_Active_Up
231 * MUIV_List_Active_Down
232 * MUIV_List_Active_PageUp
233 * MUIV_List_Active_PageDown
235 * When this attribute is read, either the index of the active entry or
236 * the special value MUIV_List_Active_Off will be returned.
238 * Setting this attribute to a new value will additionally have the same
239 * effect as calling the MUIM_List_Jump method with the specified or
243 * The concept of an active entry must not be confused with that of a
247 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
249 ******************************************************************************
253 /****** List.mui/MUIA_List_CompareHook ***************************************
256 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
259 * The provided hook indicates the sort ordering of two list entries.
260 * The hook receives list-entry data pointers as its second and third
261 * arguments. The hook should return a negative value if the first entry
262 * should be placed before the second entry, a positive value if the
263 * first entry should be placed after the second entry, and zero if the
266 * In addition to being used internally for sorting operations, this hook
267 * will be called when MUIM_List_Compare is externally invoked.
269 * If this attribute is not specified or is set to NULL, all list entries
272 ******************************************************************************
276 /****** List.mui/MUIA_List_First *********************************************
279 * MUIA_List_First -- (V4) [..G], LONG
282 * The index of the first entry that can be seen (assuming nothing
283 * obscures the list) This value of this attribute is -1 when the
284 * list's window is not open.
287 * Notification does not occur on this attribute in MUI.
290 * MUIA_List_First, MUIA_List_Entries
292 ******************************************************************************
296 /****** List.mui/MUIA_List_MultiTestHook *************************************
299 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
302 * The provided hook indicates whether a particular list entry
303 * may be multiselected. The hook receives the list-entry data pointer as
304 * its third argument, and returns a Boolean value. If this attribute is
305 * not specified or is set to NULL, all list entries are considered
308 * Whenever an entry is about to be selected, this hook is called if
309 * there are other entries already selected. If the hook returns TRUE,
310 * the entry may be multi-selected; if the hook returns FALSE, the entry
311 * remains unselected.
313 * Additionally, if a non-multi-selectable entry has been selected (as
314 * the only selected entry in the list), any attempt to select an
315 * additional entry will fail.
317 ******************************************************************************
321 /****** List.mui/MUIA_List_Title *********************************************
324 * MUIA_List_Title -- (V6) [ISG], char *
327 * A heading for the list, placed above list entries. A value of NULL
328 * means no title is used. A value of TRUE means that the custom
329 * display hook provides a separate title for each column; the hook
330 * must then provide column titles instead of normal column data when
331 * the entry pointer provided is NULL.
334 * If a string is set for this attribute, it is not cached within the
338 * MUIA_List_DisplayHook
340 ******************************************************************************
344 /****** List.mui/MUIA_List_Visible *******************************************
347 * MUIA_List_Visible -- (V4) [..G], LONG
350 * The number of entries that can be seen at once with the list's
351 * current dimensions. This value of this attribute is -1 when the
352 * list's window is not open.
355 * Notification does not occur on this attribute in MUI.
358 * MUIA_List_First, MUIA_List_Entries
360 ******************************************************************************
364 /**************************************************************************
365 Allocate a single list entry, does not initialize it (except the pointer)
366 **************************************************************************/
367 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
370 struct ListEntry
*le
;
371 int size
= sizeof(struct ListEntry
) + sizeof(LONG
) * data
->columns
+ 4;
375 mem
= AllocPooled(data
->pool
, size
);
378 D(bug("List AllocListEntry %p, %ld bytes\n", mem
, size
));
380 mem
[0] = size
; /* Save the size */
381 le
= (struct ListEntry
*)(mem
+ 1);
382 le
->widths
= (LONG
*) (le
+ 1);
384 /* Initialize fields */
388 for (j
= 0; j
< data
->columns
; j
++)
394 /**************************************************************************
395 Deallocate a single list entry, does not deinitialize it
396 **************************************************************************/
397 static void FreeListEntry(struct MUI_ListData
*data
,
398 struct ListEntry
*entry
)
400 ULONG
*mem
= ((ULONG
*) entry
) - 1;
401 D(bug("FreeListEntry %p size=%ld\n", mem
, mem
[0]));
402 FreePooled(data
->pool
, mem
, mem
[0]);
405 /**************************************************************************
406 Ensures that there can be at least the given amount of entries within
407 the list. Returns 0 if not. It also allocates the space for the title.
408 It can be accessed with data->entries[ENTRY_TITLE]
409 **************************************************************************/
410 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
412 struct ListEntry
**new_entries
;
413 int new_entries_allocated
;
415 if (size
+ 1 <= data
->entries_allocated
)
418 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
419 if (new_entries_allocated
< size
+ 1)
420 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
422 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
423 new_entries_allocated
* sizeof(struct ListEntry
*)));
425 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
426 if (NULL
== new_entries
)
430 CopyMem(data
->entries
- 1, new_entries
,
431 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
432 FreeVec(data
->entries
- 1);
434 data
->entries
= new_entries
+ 1;
435 data
->entries_allocated
= new_entries_allocated
;
439 /**************************************************************************
440 Prepares the insertion of count entries at pos.
441 This function doesn't care if there is enough space in the datastructure.
442 SetListSize() must be used first.
443 With current implementation, this call will never fail
444 **************************************************************************/
445 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
448 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
449 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
453 /**************************************************************************
454 Removes count (already deinitalized) list entries starting az pos.
455 **************************************************************************/
456 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
458 // FIXME: segfault if entries_num = pos = count = 1
459 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
460 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
463 /**************************************************************************
464 Frees all memory allocated by ParseListFormat()
465 **************************************************************************/
466 static void FreeListFormat(struct MUI_ListData
*data
)
472 for (i
= 0; i
< data
->columns
; i
++)
474 FreeVec(data
->ci
[i
].preparse
);
475 data
->ci
[i
].preparse
= NULL
;
480 FreeVec(data
->preparses
);
481 data
->preparses
= NULL
;
484 FreeVec(data
->strings
- 1);
485 data
->strings
= NULL
;
490 /**************************************************************************
491 Parses the given format string (also frees a previously parsed format).
493 **************************************************************************/
494 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
502 struct RDArgs
*rdargs
;
505 format
= (STRPTR
) "";
509 FreeListFormat(data
);
513 /* Count the number of columns first */
518 if (!(data
->preparses
=
519 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
522 if (!(data
->strings
= AllocVec((new_columns
+ 1 + 10)
523 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
524 * used by orginal MUI and also some
528 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
532 for (i
= 0; i
< new_columns
; i
++)
534 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
535 data
->ci
[i
].weight
= 100;
536 data
->ci
[i
].delta
= 4;
537 data
->ci
[i
].min_width
= -1;
538 data
->ci
[i
].max_width
= -1;
539 data
->ci
[i
].user_width
= -1;
540 data
->ci
[i
].bar
= FALSE
;
541 data
->ci
[i
].preparse
= NULL
;
544 if ((format_sep
= StrDup(format
)) != 0)
546 for (i
= 0; format_sep
[i
] != '\0'; i
++)
548 if (format_sep
[i
] == ',')
549 format_sep
[i
] = '\0';
552 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
558 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
559 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
560 rdargs
->RDA_Source
.CS_CurChr
= 0;
561 rdargs
->RDA_DAList
= 0;
562 rdargs
->RDA_Buffer
= NULL
;
563 rdargs
->RDA_BufSiz
= 0;
564 rdargs
->RDA_ExtHelp
= NULL
;
565 rdargs
->RDA_Flags
= 0;
567 memset(args
, 0, sizeof args
);
568 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
571 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
572 if (args
[ARG_WEIGHT
])
573 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
575 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
576 if (args
[ARG_MINWIDTH
])
577 data
->ci
[i
].min_width
=
578 *(LONG
*) args
[ARG_MINWIDTH
];
579 if (args
[ARG_MAXWIDTH
])
580 data
->ci
[i
].max_width
=
581 *(LONG
*) args
[ARG_MAXWIDTH
];
582 data
->ci
[i
].bar
= args
[ARG_BAR
];
583 if (args
[ARG_PREPARSE
])
584 data
->ci
[i
].preparse
=
585 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
589 ptr
+= strlen(ptr
) + 1;
592 while (i
< new_columns
);
593 FreeDosObject(DOS_RDARGS
, rdargs
);
598 for (i
= 0; i
< new_columns
; i
++)
600 D(bug("colno %d weight %d delta %d preparse %s\n",
601 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
602 data
->ci
[i
].preparse
));
605 data
->columns
= new_columns
;
606 data
->strings
++; /* Skip entry pos */
611 /**************************************************************************
612 Call the MUIM_List_Display for the given entry. It fills out
613 data->string and data->preparses
614 **************************************************************************/
615 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
617 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
621 for (col
= 0; col
< data
->columns
; col
++)
622 data
->preparses
[col
] = data
->ci
[col
].preparse
;
624 if (entry_pos
== ENTRY_TITLE
)
626 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
628 *data
->strings
= data
->title
;
631 entry_data
= NULL
; /* it's a title request */
634 entry_data
= data
->entries
[entry_pos
]->data
;
636 /* Get the display formation */
637 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
638 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
641 /**************************************************************************
642 Determine the dims of a single entry and adapt the columninfo according
643 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
644 be redrawn after this operation, 1 if all entries need to be redrawn.
645 **************************************************************************/
646 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
648 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
649 struct ListEntry
*entry
= data
->entries
[pos
];
656 if (!(_flags(obj
) & MADF_SETUP
))
659 DisplayEntry(cl
, obj
, pos
);
661 /* Set height to at least minheight */
662 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
663 data
->entries
[pos
]->height
= data
->entry_minheight
;
665 for (j
= 0; j
< data
->columns
; j
++)
668 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
672 zune_text_get_bounds(text
, obj
);
674 if (text
->height
> data
->entries
[pos
]->height
)
676 data
->entries
[pos
]->height
= text
->height
;
677 /* entry height changed, redraw all entries later */
680 data
->entries
[pos
]->widths
[j
] = text
->width
;
682 if (text
->width
> data
->ci
[j
].entries_width
)
684 /* This columns width is bigger than the other in the same
685 * columns, so we store this value
687 data
->ci
[j
].entries_width
= text
->width
;
688 /* column width changed, redraw all entries later */
692 zune_text_destroy(text
);
695 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
697 data
->entry_maxheight
= data
->entries
[pos
]->height
;
698 /* maximum entry height changed, redraw all entries later */
705 /**************************************************************************
706 Determine the widths of the entries
707 **************************************************************************/
708 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
711 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
713 if (!(_flags(obj
) & MADF_SETUP
))
716 for (j
= 0; j
< data
->columns
; j
++)
717 data
->ci
[j
].entries_width
= 0;
719 data
->entry_maxheight
= 0;
720 data
->entries_totalheight
= 0;
721 data
->entries_maxwidth
= 0;
723 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
725 CalcDimsOfEntry(cl
, obj
, i
);
726 data
->entries_totalheight
+= data
->entries
[i
]->height
;
729 for (j
= 0; j
< data
->columns
; j
++)
730 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
732 if (!data
->entry_maxheight
)
733 data
->entry_maxheight
= 1;
736 /**************************************************************************
737 Calculates the number of visible entry lines. Returns 1 if it has
739 **************************************************************************/
740 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
742 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
743 int old_entries_visible
= data
->entries_visible
;
744 int old_entries_top_pixel
= data
->entries_top_pixel
;
746 data
->vertprop_visible
= data
->entries_visible
=
747 (_mheight(data
->area
) - data
->title_height
)
748 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
750 /* Distribute extra vertical space evenly between top and bottom of
753 data
->entries_top_pixel
= _mtop(data
->area
) + data
->title_height
754 + (_mheight(data
->area
) - data
->title_height
756 data
->entries_visible
*
757 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
759 if (data
->entries_visible
!= old_entries_visible
)
761 superset(cl
, obj
, MUIA_List_Visible
, data
->entries_visible
);
762 superset(cl
, obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
765 return (old_entries_visible
!= data
->entries_visible
)
766 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
769 /**************************************************************************
770 Default hook to compare two list entries. Works for strings only.
771 **************************************************************************/
772 AROS_UFH3S(int, default_compare_func
,
773 AROS_UFHA(struct Hook
*, h
, A0
),
774 AROS_UFHA(char *, s2
, A2
),
775 AROS_UFHA(char *, s1
, A1
))
779 return Stricmp(s1
, s2
);
784 #define PROP_VERT_FIRST 1
786 static ULONG
List_Function(struct Hook
*hook
, Object
* obj
, void **msg
)
788 struct MUI_ListData
*data
= (struct MUI_ListData
*)hook
->h_Data
;
789 SIPTR type
= (SIPTR
) msg
[0];
790 SIPTR val
= (SIPTR
) msg
[1];
794 case PROP_VERT_FIRST
:
795 get(data
->vert
, MUIA_Prop_First
, &val
);
796 nnset(obj
, MUIA_List_VertProp_First
, val
);
802 /* At entry to this function, data->area is always set, but data->vert may
803 * or may not be set */
804 static void List_HandleScrollerPos(struct IClass
*cl
, Object
*obj
)
806 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
807 BOOL vert_not_used
= FALSE
;
809 /* Disallow any changes after setup. This function should basically be
810 * creation-time only */
811 if (_flags(obj
) & MADF_SETUP
)
814 /* Remove both objects */
815 if (data
->area_connected
)
816 DoMethod(obj
, OM_REMMEMBER
, data
->area
);
817 if (data
->vert_connected
)
818 DoMethod(obj
, OM_REMMEMBER
, data
->vert
);
820 /* Add list and/or scroller */
821 switch (data
->scroller_pos
)
823 case MUIV_Listview_ScrollerPos_None
:
824 vert_not_used
= TRUE
;
825 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
827 case MUIV_Listview_ScrollerPos_Left
:
829 data
->vert
=ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
830 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
831 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
835 data
->vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
836 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
837 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
841 data
->area_connected
= TRUE
;
843 /* Handle case where it was decided that vert will not be used */
848 if (data
->vert_connected
)
850 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_First
,
852 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Visible
,
854 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Entries
,
856 data
->vert_connected
= FALSE
;
859 MUI_DisposeObject(data
->vert
);
864 /* If at this point data->vert is not null, it means vert is to be
866 if (data
->vert
&& !data
->vert_connected
)
868 LONG entries
= 0, first
= 0, visible
= 0;
870 get(obj
, MUIA_List_VertProp_First
, &first
);
871 get(obj
, MUIA_List_VertProp_Visible
, &visible
);
872 get(obj
, MUIA_List_VertProp_Entries
, &entries
);
874 SetAttrs(data
->vert
, MUIA_Prop_First
, first
,
875 MUIA_Prop_Visible
, visible
, MUIA_Prop_Entries
, entries
, TAG_DONE
);
877 DoMethod(data
->vert
, MUIM_Notify
, MUIA_Prop_First
, MUIV_EveryTime
,
878 (IPTR
) obj
, 4, MUIM_CallHook
, (IPTR
) &data
->hook
, PROP_VERT_FIRST
,
881 /* Pass prop object as DestObj (based on code in NList) */
882 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_First
, MUIV_EveryTime
,
883 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
884 MUIA_Prop_First
, MUIV_TriggerValue
);
885 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Visible
, MUIV_EveryTime
,
886 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
887 MUIA_Prop_Visible
, MUIV_TriggerValue
);
888 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Entries
, MUIV_EveryTime
,
889 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
890 MUIA_Prop_Entries
, MUIV_TriggerValue
);
892 data
->vert_connected
= TRUE
;
896 /**************************************************************************
898 **************************************************************************/
899 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
901 struct MUI_ListData
*data
;
903 struct TagItem
*tags
;
905 LONG new_entries_active
= MUIV_List_Active_Off
;
906 struct TagItem rectattrs
[2] =
907 {{TAG_IGNORE
, TAG_IGNORE
}, {TAG_DONE
, TAG_DONE
}};
910 /* search for MUIA_Frame as it has to be passed to rectangle object */
911 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
913 if (tag
->ti_Tag
== MUIA_Frame
)
915 rectattrs
[0].ti_Tag
= MUIA_Frame
;
916 rectattrs
[0].ti_Data
= tag
->ti_Data
;
917 tag
->ti_Tag
= TAG_IGNORE
;
922 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
923 MUIA_Group_Horiz
, TRUE
,
926 MUIA_Group_Spacing
, 0,
927 MUIA_Font
, MUIV_Font_List
,
928 MUIA_ShowSelState
, FALSE
,
929 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
930 MUIA_Background
, MUII_ListBack
,
931 TAG_MORE
, (IPTR
) msg
->ops_AttrList
,
937 data
= INST_DATA(cl
, obj
);
940 data
->entries_active
= MUIV_List_Active_Off
;
941 data
->intern_puddle_size
= 2008;
942 data
->intern_thresh_size
= 1024;
943 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
944 data
->default_compare_hook
.h_SubEntry
= 0;
945 data
->compare_hook
= &(data
->default_compare_hook
);
946 data
->flags
= LIST_SHOWDROPMARKS
;
947 data
->area_replaced
= FALSE
;
948 data
->area_connected
= FALSE
;
949 data
->vert_connected
= FALSE
;
951 data
->entries_visible
= data
->vertprop_visible
= -1;
952 data
->last_active
= -1;
954 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
955 data
->ehn
.ehn_Priority
= 0;
956 data
->ehn
.ehn_Flags
= 0;
957 data
->ehn
.ehn_Object
= obj
;
958 data
->ehn
.ehn_Class
= cl
;
961 * List is a group where part of area is rendered and part is filled
962 * with other objects (inside of List dimensions). One such object is
963 * up/down arrow. This object depends on RelVerify mode to control
964 * behaviour. List also has the RelVerify mode. Area super class in case
965 * of both of those objects adds an event handler node with the same
966 * priority. Depending on the sort order, the event handler node of
967 * "list" can eat a click event and up/down arrows stop working. The
968 * hack is to decrease the priority of Area event handler for list to
969 * always favor up/down arrow. There are other hacky ways of solving
970 * this, but this seems least evil approach, as this hack is
971 * encapsulated in the List class itself.
973 muiAreaData(obj
)->mad_ehn
.ehn_Priority
--;
975 data
->hook
.h_Entry
= HookEntry
;
976 data
->hook
.h_SubEntry
= (HOOKFUNC
) List_Function
;
977 data
->hook
.h_Data
= data
;
979 area
= (Object
*)GetTagData(MUIA_List_ListArea
, (IPTR
) 0,
983 area
= RectangleObject
, MUIA_FillArea
, FALSE
, TAG_MORE
,
984 (IPTR
) rectattrs
, End
;
986 data
->area_replaced
= TRUE
;
989 /* parse initial taglist */
990 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
994 case MUIA_List_Active
:
995 new_entries_active
= tag
->ti_Data
;
999 data
->pool
= (APTR
) tag
->ti_Data
;
1002 case MUIA_List_PoolPuddleSize
:
1003 data
->intern_puddle_size
= tag
->ti_Data
;
1006 case MUIA_List_PoolThreshSize
:
1007 data
->intern_thresh_size
= tag
->ti_Data
;
1010 case MUIA_List_CompareHook
:
1011 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1012 if (data
->compare_hook
== NULL
)
1013 data
->compare_hook
= &data
->default_compare_hook
;
1016 case MUIA_List_ConstructHook
:
1017 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1020 case MUIA_List_DestructHook
:
1021 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1024 case MUIA_List_DisplayHook
:
1025 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1028 case MUIA_List_MultiTestHook
:
1029 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1032 case MUIA_List_SourceArray
:
1033 array
= (APTR
*) tag
->ti_Data
;
1036 case MUIA_List_Format
:
1037 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1040 case MUIA_List_Title
:
1041 data
->title
= (STRPTR
) tag
->ti_Data
;
1044 case MUIA_List_MinLineHeight
:
1045 data
->entry_minheight
= tag
->ti_Data
;
1048 case MUIA_List_AdjustHeight
:
1049 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
1052 case MUIA_List_AdjustWidth
:
1053 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
1056 case MUIA_List_AutoVisible
:
1057 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1060 case MUIA_List_ShowDropMarks
:
1061 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1064 case MUIA_List_DragSortable
:
1065 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1066 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1069 case MUIA_Listview_ScrollerPos
:
1070 data
->scroller_pos
= tag
->ti_Data
;
1073 case MUIA_Listview_Input
:
1074 data
->read_only
= !tag
->ti_Data
;
1077 case MUIA_Listview_MultiSelect
:
1078 data
->multiselect
= tag
->ti_Data
;
1081 case MUIA_Listview_DoubleClick
:
1082 data
->doubleclick
= tag
->ti_Data
!= 0;
1085 case MUIA_Listview_DefClickColumn
:
1086 data
->def_click_column
= tag
->ti_Data
;
1091 List_HandleScrollerPos(cl
, obj
);
1095 /* No memory pool given, so we create our own */
1096 data
->pool
= data
->intern_pool
=
1097 CreatePool(0, data
->intern_puddle_size
,
1098 data
->intern_thresh_size
);
1101 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1106 /* parse the list format */
1107 if (!(ParseListFormat(data
, data
->format
)))
1109 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1113 /* This is neccessary for at least the title */
1114 if (!SetListSize(data
, 0))
1116 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1120 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
1122 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1129 /* Count the number of elements */
1130 for (i
= 0; array
[i
] != NULL
; i
++)
1133 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
1134 MUIV_List_Insert_Top
);
1137 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
1139 switch (new_entries_active
)
1141 case MUIV_List_Active_Top
:
1142 new_entries_active
= 0;
1145 case MUIV_List_Active_Bottom
:
1146 new_entries_active
= data
->entries_num
- 1;
1150 if (new_entries_active
< 0)
1151 new_entries_active
= 0;
1152 else if (new_entries_active
>= data
->entries_num
)
1153 new_entries_active
= data
->entries_num
- 1;
1155 data
->entries_active
= new_entries_active
;
1156 /* Selected entry will be moved into visible area */
1159 NewList((struct List
*)&data
->images
);
1161 D(bug("List_New(%lx)\n", obj
));
1166 /**************************************************************************
1168 **************************************************************************/
1169 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
1171 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1173 D(bug("List Dispose\n"));
1175 /* Call destruct method for every entry and free the entries manually
1176 * to avoid notification */
1177 while (data
->confirm_entries_num
)
1179 struct ListEntry
*lentry
=
1180 data
->entries
[--data
->confirm_entries_num
];
1181 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1183 FreeListEntry(data
, lentry
);
1186 if (data
->intern_pool
)
1187 DeletePool(data
->intern_pool
);
1189 FreeVec(data
->entries
- 1);
1190 /* title is currently before all other elements */
1192 FreeListFormat(data
);
1193 FreeVec(data
->format
);
1195 return DoSuperMethodA(cl
, obj
, msg
);
1199 /**************************************************************************
1201 **************************************************************************/
1202 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
1204 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1205 struct TagItem
*tag
;
1206 struct TagItem
*tags
;
1209 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1211 switch (tag
->ti_Tag
)
1213 case MUIA_List_CompareHook
:
1214 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1215 if (data
->compare_hook
== NULL
)
1216 data
->compare_hook
= &data
->default_compare_hook
;
1219 case MUIA_List_ConstructHook
:
1220 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1223 case MUIA_List_DestructHook
:
1224 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1227 case MUIA_List_DisplayHook
:
1228 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1231 case MUIA_List_MultiTestHook
:
1232 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1233 if (data
->multi_test_hook
!= NULL
)
1235 /* Clearing current selections is the easiest way to keep
1236 * selections consistent with the new hook */
1237 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
1238 MUIV_List_Select_Off
, NULL
);
1242 case MUIA_List_Title
:
1243 data
->title
= (STRPTR
) tag
->ti_Data
;
1244 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1247 case MUIA_List_VertProp_First
:
1248 data
->vertprop_first
= tag
->ti_Data
;
1249 if (data
->entries_first
!= tag
->ti_Data
)
1251 set(obj
, MUIA_List_First
, tag
->ti_Data
);
1255 case MUIA_List_Format
:
1256 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1257 ParseListFormat(data
, data
->format
);
1258 // FIXME: should we check for errors?
1259 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1262 case MUIA_List_VertProp_Entries
:
1263 data
->vertprop_entries
= tag
->ti_Data
;
1266 case MUIA_List_VertProp_Visible
:
1267 data
->vertprop_visible
= tag
->ti_Data
;
1268 data
->entries_visible
= tag
->ti_Data
;
1271 case MUIA_List_Active
:
1273 LONG new_entries_active
= tag
->ti_Data
;
1275 if ((data
->entries_num
)
1276 && (new_entries_active
!= MUIV_List_Active_Off
))
1278 switch (new_entries_active
)
1280 case MUIV_List_Active_Top
:
1281 new_entries_active
= 0;
1284 case MUIV_List_Active_Bottom
:
1285 new_entries_active
= data
->entries_num
- 1;
1288 case MUIV_List_Active_Up
:
1289 new_entries_active
= data
->entries_active
- 1;
1292 case MUIV_List_Active_Down
:
1293 new_entries_active
= data
->entries_active
+ 1;
1296 case MUIV_List_Active_PageUp
:
1297 new_entries_active
=
1298 data
->entries_active
- data
->entries_visible
;
1301 case MUIV_List_Active_PageDown
:
1302 new_entries_active
=
1303 data
->entries_active
+ data
->entries_visible
;
1307 if (new_entries_active
< 0)
1308 new_entries_active
= 0;
1309 else if (new_entries_active
>= data
->entries_num
)
1310 new_entries_active
= data
->entries_num
- 1;
1313 new_entries_active
= -1;
1315 if (data
->entries_active
!= new_entries_active
)
1317 LONG old
= data
->entries_active
;
1318 data
->entries_active
= new_entries_active
;
1320 /* SelectChange stuff */
1321 if (new_entries_active
!= -1)
1323 DoMethod(obj
, MUIM_List_SelectChange
,
1324 new_entries_active
, MUIV_List_Select_On
, 0);
1325 DoMethod(obj
, MUIM_List_SelectChange
,
1326 new_entries_active
, MUIV_List_Select_Active
, 0);
1329 DoMethod(obj
, MUIM_List_SelectChange
,
1330 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1332 if (!data
->read_only
)
1335 data
->update_pos
= old
;
1336 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1338 data
->update_pos
= data
->entries_active
;
1339 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1342 /* Make new active entry visible (if there is one and
1344 if (new_entries_active
!= -1
1345 && (_flags(obj
) & MADF_SETUP
))
1347 DoMethod(obj
, MUIM_List_Jump
,
1348 MUIV_List_Jump_Active
);
1354 case MUIA_List_First
:
1355 data
->update_pos
= data
->entries_first
;
1357 data
->entries_first
= tag
->ti_Data
;
1359 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1360 if ((data
->vertprop_first
!= tag
->ti_Data
)
1361 && (!(data
->flags
& LIST_QUIET
)))
1363 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1367 case MUIA_List_Visible
: /* Shouldn't be settable? */
1368 if (data
->vertprop_visible
!= tag
->ti_Data
)
1369 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1372 case MUIA_List_Entries
:
1373 if (data
->confirm_entries_num
== tag
->ti_Data
)
1375 data
->entries_num
= tag
->ti_Data
;
1376 if (!(data
->flags
& LIST_QUIET
))
1378 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1383 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1387 case MUIA_List_Quiet
:
1388 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1391 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1392 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1393 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1394 if (data
->entries_first
!= XGET(obj
, MUIA_List_VertProp_First
))
1395 set(obj
, MUIA_List_VertProp_First
, data
->entries_first
);
1399 case MUIA_List_AutoVisible
:
1400 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1403 case MUIA_List_ShowDropMarks
:
1404 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1407 case MUIA_List_DragSortable
:
1408 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1409 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1413 /* Swallow this so the Area class doesn't redraw us */
1414 tag
->ti_Tag
= TAG_IGNORE
;
1418 if (_flags(obj
) & MADF_SETUP
)
1420 /* Stop listening for events we only listen to when mouse
1421 button is down: we will not be informed of the button
1423 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1425 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
1426 | IDCMP_INACTIVEWINDOW
);
1427 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1432 case MUIA_Listview_DoubleClick
: /* private set */
1433 data
->doubleclick
= tag
->ti_Data
!= 0;
1436 case MUIA_Listview_SelectChange
: /* private set */
1437 data
->select_change
= tag
->ti_Data
!= 0;
1440 case MUIA_Listview_ScrollerPos
: /* private set */
1441 data
->scroller_pos
= tag
->ti_Data
;
1442 List_HandleScrollerPos(cl
, obj
);
1445 case MUIA_Listview_Input
: /* private set */
1446 data
->read_only
= !tag
->ti_Data
;
1449 case MUIA_Listview_MultiSelect
: /* private set */
1450 data
->multiselect
= tag
->ti_Data
;
1453 case MUIA_Listview_DefClickColumn
:
1454 data
->def_click_column
= tag
->ti_Data
;
1459 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1462 /**************************************************************************
1464 **************************************************************************/
1465 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1467 /* small macro to simplify return value storage */
1468 #define STORE *(msg->opg_Storage)
1469 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1471 switch (msg
->opg_AttrID
)
1473 case MUIA_List_Entries
:
1474 STORE
= data
->entries_num
;
1476 case MUIA_List_First
:
1477 STORE
= data
->entries_first
;
1479 case MUIA_List_Active
:
1480 STORE
= data
->entries_active
;
1482 case MUIA_List_InsertPosition
:
1483 STORE
= data
->insert_position
;
1485 case MUIA_List_Title
:
1486 STORE
= (IPTR
) data
->title
;
1488 case MUIA_List_VertProp_Entries
:
1489 STORE
= data
->vertprop_entries
;
1491 case MUIA_List_VertProp_Visible
:
1492 case MUIA_List_Visible
:
1493 STORE
= data
->vertprop_visible
;
1495 case MUIA_List_VertProp_First
:
1496 STORE
= data
->vertprop_first
;
1498 case MUIA_List_Format
:
1499 STORE
= (IPTR
) data
->format
;
1501 case MUIA_List_AutoVisible
:
1502 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1504 case MUIA_List_ShowDropMarks
:
1505 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1507 case MUIA_List_DragSortable
:
1508 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1510 case MUIA_Listview_ClickColumn
:
1511 STORE
= data
->click_column
;
1513 case MUIA_Listview_DoubleClick
:
1514 STORE
= data
->doubleclick
;
1516 case MUIA_Listview_SelectChange
:
1517 STORE
= data
->select_change
;
1519 case MUIA_Listview_List
:
1522 case MUIA_Listview_DefClickColumn
:
1523 STORE
= data
->def_click_column
;
1527 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1533 /**************************************************************************
1535 **************************************************************************/
1536 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1537 struct MUIP_Setup
*msg
)
1539 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1541 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1544 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1545 data
->prefs_linespacing
=
1546 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1547 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1548 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1550 CalcWidths(cl
, obj
);
1553 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1555 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1557 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1559 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
1560 if (data
->multiselect
== MUIV_Listview_MultiSelect_Default
)
1562 if (data
->prefs_multi
== LISTVIEW_MULTI_SHIFTED
)
1563 data
->multiselect
= MUIV_Listview_MultiSelect_Shifted
;
1565 data
->multiselect
= MUIV_Listview_MultiSelect_Always
;
1568 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1573 /**************************************************************************
1575 **************************************************************************/
1576 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1577 struct MUIP_Cleanup
*msg
)
1579 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1580 struct ListImage
*li
= List_First(&data
->images
);
1584 struct ListImage
*next
= Node_Next(li
);
1585 DoMethod(obj
, MUIM_List_DeleteImage
, (IPTR
) li
);
1589 zune_imspec_cleanup(data
->list_cursor
);
1590 zune_imspec_cleanup(data
->list_select
);
1591 zune_imspec_cleanup(data
->list_selcur
);
1593 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1594 data
->mouse_click
= 0;
1596 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1599 /**************************************************************************
1601 **************************************************************************/
1602 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1603 struct MUIP_AskMinMax
*msg
)
1605 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1607 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1610 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1612 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1613 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1614 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1618 msg
->MinMaxInfo
->MinWidth
+= 40;
1619 msg
->MinMaxInfo
->DefWidth
+= 100;
1620 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1623 if (data
->entries_num
> 0)
1625 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1627 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1628 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1629 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1633 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1634 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1635 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1636 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1641 msg
->MinMaxInfo
->MinHeight
+= 36;
1642 msg
->MinMaxInfo
->DefHeight
+= 96;
1643 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1645 D(bug("List %p minheigh=%d, line maxh=%d\n",
1646 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1650 /****i* List.mui/MUIM_Layout *************************************************
1655 ******************************************************************************
1659 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1660 struct MUIP_Layout
*msg
)
1662 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1663 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1664 LONG new_entries_first
= data
->entries_first
;
1666 /* Calc the numbers of entries visible */
1667 CalcVertVisible(cl
, obj
);
1669 /* Ensure active entry is visible if requested */
1670 if (data
->entries_active
+ 1 >=
1671 (data
->entries_first
+ data
->entries_visible
)
1672 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1674 data
->entries_active
- data
->entries_visible
+ 1;
1676 /* Ensure there are no unnecessary empty lines */
1677 if ((new_entries_first
+ data
->entries_visible
>=
1679 && (data
->entries_visible
<= data
->entries_num
))
1680 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1682 /* Always show the start of the list if it isn't long enough to fill the
1684 if (data
->entries_num
<= data
->entries_visible
)
1685 new_entries_first
= 0;
1687 if (new_entries_first
< 0)
1688 new_entries_first
= 0;
1690 set(obj
, new_entries_first
!= data
->entries_first
?
1691 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1693 /* So the notify happens */
1694 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1700 /**************************************************************************
1702 **************************************************************************/
1703 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1704 struct MUIP_Show
*msg
)
1706 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1707 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1709 zune_imspec_show(data
->list_cursor
, obj
);
1710 zune_imspec_show(data
->list_select
, obj
);
1711 zune_imspec_show(data
->list_selcur
, obj
);
1716 /**************************************************************************
1718 **************************************************************************/
1719 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1720 struct MUIP_Hide
*msg
)
1722 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1724 zune_imspec_hide(data
->list_cursor
);
1725 zune_imspec_hide(data
->list_select
);
1726 zune_imspec_hide(data
->list_selcur
);
1728 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1732 /**************************************************************************
1733 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1735 **************************************************************************/
1736 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1739 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1742 /* To be sure we don't draw anything if there is no title */
1743 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1746 DisplayEntry(cl
, obj
, entry_pos
);
1747 x1
= _mleft(data
->area
);
1749 for (col
= 0; col
< data
->columns
; col
++)
1752 x2
= x1
+ data
->ci
[col
].entries_width
;
1755 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1756 ZTEXT_ARG_NONE
, 0)))
1758 /* Could be made simpler, as we don't really need the bounds */
1759 zune_text_get_bounds(text
, obj
);
1760 /* Note, this was MPEN_SHADOW before */
1761 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1762 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1763 zune_text_destroy(text
);
1765 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1769 /**************************************************************************
1771 **************************************************************************/
1772 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1774 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1778 BOOL scroll_caused_damage
= FALSE
;
1779 struct MUI_ImageSpec_intern
*highlight
;
1782 if (data
->flags
& LIST_QUIET
)
1785 ret
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1787 if (data
->area_replaced
)
1790 /* Calculate the title height */
1793 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1797 data
->title_height
= 0;
1800 /* Calc the numbers of entries visible */
1801 CalcVertVisible(cl
, obj
);
1803 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1805 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
1806 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
),
1807 0, data
->entries_first
* data
->entry_maxheight
, 0);
1810 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(data
->area
),
1811 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
));
1813 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1815 y
= _mtop(data
->area
);
1818 if (data
->title_height
&& data
->title
)
1820 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1821 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1822 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1823 Move(_rp(obj
), _mleft(data
->area
), y
);
1824 Draw(_rp(obj
), _mright(data
->area
), y
);
1825 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1827 Move(_rp(obj
), _mleft(data
->area
), y
);
1828 Draw(_rp(obj
), _mright(data
->area
), y
);
1832 y
= data
->entries_top_pixel
;
1834 start
= data
->entries_first
;
1835 end
= data
->entries_first
+ data
->entries_visible
;
1837 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1839 int diffy
= data
->entries_first
- data
->update_pos
;
1841 if (abs(diffy
) < data
->entries_visible
)
1843 scroll_caused_damage
=
1844 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1846 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1847 _mleft(data
->area
), y
,
1848 _mright(data
->area
),
1849 y
+ data
->entry_maxheight
* data
->entries_visible
);
1851 scroll_caused_damage
=
1852 scroll_caused_damage
1853 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1857 start
= end
- diffy
;
1858 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1862 end
= start
- diffy
;
1866 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1868 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), top
,
1869 _mwidth(data
->area
), bottom
- top
+ 1, 0,
1870 top
- _mtop(data
->area
) + data
->entries_first
1871 * data
->entry_maxheight
, 0);
1874 for (entry_pos
= start
;
1875 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1877 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1879 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1880 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1881 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1882 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1883 && data
->update_pos
== entry_pos
))
1885 /* Choose appropriate highlight image */
1887 if (entry_pos
== data
->entries_active
1888 && (entry
->flags
& ENTRY_SELECTED
) && !data
->read_only
)
1889 highlight
= data
->list_selcur
;
1890 else if (entry_pos
== data
->entries_active
&& !data
->read_only
)
1891 highlight
= data
->list_cursor
;
1892 else if (entry
->flags
& ENTRY_SELECTED
)
1893 highlight
= data
->list_select
;
1897 /* Draw highlight or background */
1899 if (highlight
!= NULL
)
1901 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1902 _mleft(data
->area
), y
, _mwidth(data
->area
),
1903 data
->entry_maxheight
,
1904 0, y
- data
->entries_top_pixel
, 0);
1906 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1907 && data
->update_pos
== entry_pos
)
1909 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), y
,
1910 _mwidth(data
->area
), data
->entry_maxheight
, 0,
1911 y
- _mtop(data
->area
) +
1912 data
->entries_first
* data
->entry_maxheight
, 0);
1915 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1917 y
+= data
->entry_maxheight
;
1920 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1924 if (scroll_caused_damage
)
1926 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1928 /* Theoretically it might happen that more damage is caused
1929 after ScrollRaster. By something else, like window movement
1930 in front of our window. Therefore refresh root object of
1931 window, not just this object */
1935 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1936 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1938 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1942 ULONG x1
= _mleft(data
->area
);
1944 y
= _mtop(data
->area
);
1946 if (data
->title_height
&& data
->title
)
1948 for (col
= 0; col
< data
->columns
; col
++)
1950 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1951 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1953 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1956 if (data
->ci
[col
].bar
)
1958 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1959 Move(_rp(obj
), x1
, y
);
1961 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1962 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1963 Move(_rp(obj
), x1
+ 1, y
);
1964 Draw(_rp(obj
), x1
+ 1,
1965 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1969 x1
+= data
->ci
[col
].delta
- halfdelta
;
1971 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1974 x1
= _mleft(data
->area
);
1976 for (col
= 0; col
< data
->columns
; col
++)
1978 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1979 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1981 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1984 if (data
->ci
[col
].bar
)
1986 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1987 Move(_rp(obj
), x1
, y
);
1988 Draw(_rp(obj
), x1
, _mbottom(data
->area
));
1989 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1990 Move(_rp(obj
), x1
+ 1, y
);
1991 Draw(_rp(obj
), x1
+ 1, _mbottom(data
->area
));
1996 x1
+= data
->ci
[col
].delta
- halfdelta
;
2002 /****** List.mui/MUIM_List_Clear *********************************************
2005 * MUIM_List_Clear (V4)
2008 * DoMethod(obj, MUIM_List_Clear);
2011 * Removes all entries from the list.
2013 ******************************************************************************
2017 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
2018 struct MUIP_List_Clear
*msg
)
2020 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2022 while (data
->confirm_entries_num
)
2024 struct ListEntry
*lentry
=
2025 data
->entries
[--data
->confirm_entries_num
];
2026 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2028 FreeListEntry(data
, lentry
);
2030 /* Should never fail when shrinking */
2031 SetListSize(data
, 0);
2033 if (data
->confirm_entries_num
!= data
->entries_num
)
2035 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
2036 /* Notify only when no entry was active */
2037 data
->entries_active
!=
2038 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
2039 MUIV_List_Active_Off
, TAG_DONE
);
2042 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2048 /****** List.mui/MUIM_List_Exchange ******************************************
2051 * MUIM_List_Exchange (V4)
2054 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2057 * Exchange two entries' positions.
2060 * pos1 - the current index of the first entry that should be moved, or
2061 * one of these special values:
2062 * MUIV_List_Exchange_Active: the active entry.
2063 * MUIV_List_Exchange_Top: the first entry.
2064 * MUIV_List_Exchange_Bottom: the last entry.
2065 * pos2 - the index of the entry that the first entry should be exchanged
2066 * with, or one of these special values:
2067 * MUIV_List_Exchange_Active: the active entry.
2068 * MUIV_List_Exchange_Top: the first entry.
2069 * MUIV_List_Exchange_Bottom: the last entry.
2070 * MUIV_List_Exchange_Next: the next entry after pos1.
2071 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2074 * This method will do nothing if either index is greater than the last
2075 * index in the list, or if MUIV_List_Exchange_Next or
2076 * MUIV_List_Exchange_Previous imply an index outside the list.
2081 ******************************************************************************
2085 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
2086 struct MUIP_List_Exchange
*msg
)
2088 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2093 case MUIV_List_Exchange_Top
:
2096 case MUIV_List_Exchange_Active
:
2097 pos1
= data
->entries_active
;
2099 case MUIV_List_Exchange_Bottom
:
2100 pos1
= data
->entries_num
- 1;
2108 case MUIV_List_Exchange_Top
:
2111 case MUIV_List_Exchange_Active
:
2112 pos2
= data
->entries_active
;
2114 case MUIV_List_Exchange_Bottom
:
2115 pos2
= data
->entries_num
- 1;
2117 case MUIV_List_Exchange_Next
:
2120 case MUIV_List_Exchange_Previous
:
2127 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
2128 && pos2
< data
->entries_num
&& pos1
!= pos2
)
2130 struct ListEntry
*save
= data
->entries
[pos1
];
2131 data
->entries
[pos1
] = data
->entries
[pos2
];
2132 data
->entries
[pos2
] = save
;
2135 data
->update_pos
= pos1
;
2136 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2139 data
->update_pos
= pos2
;
2140 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2150 /**************************************************************************
2152 **************************************************************************/
2153 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
2154 struct MUIP_List_Redraw
*msg
)
2156 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2158 if (!(data
->flags
& LIST_QUIET
))
2160 if (msg
->pos
== MUIV_List_Redraw_All
)
2163 CalcWidths(cl
, obj
);
2164 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2169 if (msg
->pos
== MUIV_List_Redraw_Active
)
2170 pos
= data
->entries_active
;
2171 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
2174 for (i
= 0; i
< data
->entries_num
; i
++)
2175 if (data
->entries
[i
]->data
== msg
->entry
)
2186 if (CalcDimsOfEntry(cl
, obj
, pos
))
2191 data
->update_pos
= pos
;
2193 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2200 /****** List.mui/MUIM_List_Remove ********************************************
2203 * MUIM_List_Remove (V4)
2206 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2209 * Removes entries from the list. If a destruct hook has been
2210 * installed, it will be called for the removed entry.
2213 * pos - the index of the entry to be removed. The following
2214 * special values can also be used:
2215 * MUIV_List_Remove_First: remove the first entry.
2216 * MUIV_List_Remove_Last: remove the last entry.
2217 * MUIV_List_Remove_Active: remove the active entry.
2218 * MUIV_List_Remove_Selected: remove all selected entries
2219 * (or the active entry if there are no selected entries).
2222 * When the active entry is removed, the next entry becomes active
2223 * (if there is no entry below the active entry, the previous entry
2224 * becomes active instead).
2227 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2229 ******************************************************************************
2231 * It was not possible to use MUIM_List_NextSelected here because that method
2232 * may skip entries if entries are removed during an iteration.
2236 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
2237 struct MUIP_List_Remove
*msg
)
2239 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2243 BOOL found
, done
= FALSE
;
2244 struct ListEntry
*lentry
;
2245 Tag active_tag
= TAG_DONE
;
2247 if (!data
->entries_num
)
2252 case MUIV_List_Remove_First
:
2256 case MUIV_List_Remove_Active
:
2257 pos
= data
->entries_active
;
2260 case MUIV_List_Remove_Last
:
2261 pos
= data
->entries_num
- 1;
2264 case MUIV_List_Remove_Selected
:
2273 if (pos
< 0 || pos
>= data
->entries_num
)
2276 new_act
= data
->entries_active
;
2280 if (msg
->pos
== MUIV_List_Remove_Selected
)
2282 /* Find the next selected entry */
2283 for (found
= FALSE
, i
= pos
;
2284 i
< data
->confirm_entries_num
&& !found
; i
++)
2286 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2297 /* If there were no selected entries, remove the active one */
2298 if (data
->confirm_entries_num
== data
->entries_num
2299 && data
->entries_active
!= MUIV_List_Active_Off
)
2301 pos
= data
->entries_active
;
2311 lentry
= data
->entries
[pos
];
2312 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2314 RemoveListEntries(data
, pos
, 1);
2315 data
->confirm_entries_num
--;
2320 active_tag
= MUIA_List_Active
;
2322 else if (pos
== new_act
)
2323 active_tag
= MUIA_List_Active
;
2327 /* ensure that the active element is in a valid range (it might become
2328 * MUIV_List_Active_Off (-1), but that's OK) */
2329 if (new_act
>= data
->entries_num
)
2330 new_act
= data
->entries_num
- 1;
2332 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
,
2333 active_tag
, new_act
, /* Inform only if necessary (for notify) */
2337 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2342 /**************************************************************************
2344 **************************************************************************/
2345 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2346 struct MUIP_List_Select
*msg
)
2348 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2349 LONG pos
, i
, count
, selcount
=0, state
=0;
2350 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
2352 /* Establish the range of entries affected */
2355 case MUIV_List_Select_Active
:
2356 pos
= data
->entries_active
;
2357 if (pos
== MUIV_List_Active_Off
)
2363 case MUIV_List_Select_All
:
2365 count
= data
->entries_num
;
2371 if (pos
< 0 || pos
>= data
->entries_num
)
2376 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2378 /* Disallow selection of an additional entry if there is a currently
2379 selected entry that is not multi-selectable (in such case there
2380 will only be one entry currently selected, so no need to iterate) */
2381 i
= MUIV_List_NextSelected_Start
;
2382 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
2383 if (i
!= MUIV_List_NextSelected_End
)
2385 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
2386 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2387 data
->entries
[i
]->data
);
2390 /* Change or check state of each entry in the range */
2391 for (i
= pos
; i
< pos
+ count
; i
++)
2393 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2394 switch (msg
->seltype
)
2396 case MUIV_List_Select_Off
:
2397 new_select_state
= FALSE
;
2400 case MUIV_List_Select_On
:
2401 new_select_state
= TRUE
;
2404 case MUIV_List_Select_Toggle
:
2405 new_select_state
= !state
;
2409 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2414 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2416 /* Disallow selection if entry is not multi-selectable and
2417 * there are already selected entries */
2418 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
2419 new_select_state
= multi_allowed
&& (selcount
== 0 ||
2420 CallHookPkt(data
->multi_test_hook
, NULL
,
2421 data
->entries
[i
]->data
));
2423 if (new_select_state
)
2424 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2426 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2430 /* Report old state or number of selected entries */
2433 if (msg
->pos
== MUIV_List_Select_All
2434 && msg
->seltype
== MUIV_List_Select_Ask
)
2435 *msg
->info
= selcount
;
2440 /* Redraw unless it was just an enquiry */
2441 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2448 data
->update_pos
= pos
;
2450 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2456 /****** List.mui/MUIM_List_Insert ********************************************
2459 * MUIM_List_Insert (V4)
2462 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2465 * Adds multiple entries to the list. If a construct hook has been
2466 * installed, the results of passing the entries to this hook will be
2470 * entries - an array of entries to be inserted.
2471 * count - the number of entries to insert. A special value of -1 may be
2472 * used, indicating that the array of entries is NULL-terminated.
2473 * pos - the index at which to insert the new entries. The following
2474 * special values can also be used:
2475 * MUIV_List_Insert_Top: insert at index 0.
2476 * MUIV_List_Insert_Bottom: insert after all existing entries.
2477 * MUIV_List_Insert_Active: insert at the index of the active entry
2478 * (or at index 0 if there is no active entry).
2479 * MUIV_List_Insert_Sorted: keep the list sorted.
2482 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2484 ******************************************************************************
2488 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2489 struct MUIP_List_Insert
*msg
)
2491 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2492 LONG pos
, count
, sort
, active
;
2499 /* Count the number of entries */
2500 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2509 case MUIV_List_Insert_Top
:
2513 case MUIV_List_Insert_Active
:
2514 if (data
->entries_active
!= -1)
2515 pos
= data
->entries_active
;
2520 case MUIV_List_Insert_Sorted
:
2521 pos
= data
->entries_num
;
2522 sort
= 1; /* we sort'em later */
2525 case MUIV_List_Insert_Bottom
:
2526 pos
= data
->entries_num
;
2530 if (msg
->pos
> data
->entries_num
)
2531 pos
= data
->entries_num
;
2532 else if (msg
->pos
< 0)
2538 data
->insert_position
= pos
;
2540 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2543 LONG until
= pos
+ count
;
2544 APTR
*toinsert
= msg
->entries
;
2546 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2551 struct ListEntry
*lentry
;
2553 if (!(lentry
= AllocListEntry(data
)))
2555 /* Panic, but we must be in a consistent state, so remove
2556 * the space where the following list entries should have gone
2558 RemoveListEntries(data
, pos
, until
- pos
);
2562 /* now call the construct method which returns us a pointer which
2564 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2565 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2568 FreeListEntry(data
, lentry
);
2569 RemoveListEntries(data
, pos
, until
- pos
);
2571 /* TODO: Also check for visible stuff like below */
2572 if (data
->entries_num
!= data
->confirm_entries_num
)
2573 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2577 data
->entries
[pos
] = lentry
;
2578 data
->confirm_entries_num
++;
2580 if (_flags(obj
) & MADF_SETUP
)
2582 /* We have to calculate the width and height of the newly
2583 * inserted entry. This has to be done after inserting the
2584 * element into the list */
2585 CalcDimsOfEntry(cl
, obj
, pos
);
2593 /* Recalculate the number of visible entries */
2594 if (_flags(obj
) & MADF_SETUP
)
2595 CalcVertVisible(cl
, obj
);
2597 if (data
->entries_num
!= data
->confirm_entries_num
)
2600 MUIA_List_Entries
, data
->confirm_entries_num
,
2601 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2604 /* If the array is already sorted, we could do a simple insert
2605 * sort and would be much faster than with qsort.
2606 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2607 * sort the whole array?
2609 * I think, we better sort the whole array:
2613 DoMethod(obj
, MUIM_List_Sort
);
2614 /* TODO: which pos to return here !? */
2615 /* MUIM_List_Sort already called MUI_Redraw */
2620 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2622 superset(cl
, obj
, MUIA_List_InsertPosition
, data
->insert_position
);
2624 /* Update index of active entry */
2625 if (data
->entries_active
>= data
->insert_position
)
2627 active
= data
->entries_active
+ count
;
2628 SET(obj
, MUIA_List_Active
, active
);
2634 /****** List.mui/MUIM_List_InsertSingle **************************************
2637 * MUIM_List_InsertSingle (V7)
2640 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2643 * Adds a single entry to the list. If a construct hook has been
2644 * installed, the result of passing the entry to this hook will be
2648 * entry - the entry to be inserted.
2649 * pos - the index at which to insert the new entry. The following
2650 * special values can also be used:
2651 * MUIV_List_Insert_Top: insert at index 0.
2652 * MUIV_List_Insert_Bottom: insert after all existing entries.
2653 * MUIV_List_Insert_Active: insert at the index of the active entry
2654 * (or at index 0 if there is no active entry).
2655 * MUIV_List_Insert_Sorted: keep the list sorted.
2658 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2660 ******************************************************************************
2664 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2665 struct MUIP_List_InsertSingle
*msg
)
2667 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2671 /**************************************************************************
2673 **************************************************************************/
2674 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2675 struct MUIP_List_GetEntry
*msg
)
2677 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2680 if (pos
== MUIV_List_GetEntry_Active
)
2681 pos
= data
->entries_active
;
2683 if (pos
< 0 || pos
>= data
->entries_num
)
2688 *msg
->entry
= data
->entries
[pos
]->data
;
2689 return (IPTR
) *msg
->entry
;
2692 /**************************************************************************
2694 **************************************************************************/
2695 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2696 struct MUIP_List_Construct
*msg
)
2698 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2700 if (NULL
== data
->construct_hook
)
2701 return (IPTR
) msg
->entry
;
2702 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2704 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2705 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2710 if (msg
->entry
!= NULL
)
2711 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2713 *(STRPTR
) (mem
+ 1) = 0;
2714 return (IPTR
) (mem
+ 1);
2716 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2719 /**************************************************************************
2721 **************************************************************************/
2722 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2723 struct MUIP_List_Destruct
*msg
)
2725 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2727 if (NULL
== data
->destruct_hook
)
2730 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2732 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2733 FreePooled(msg
->pool
, mem
, mem
[0]);
2737 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2742 /****** List.mui/MUIM_List_Compare *******************************************
2745 * MUIM_List_Compare (V20)
2748 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2749 * LONG sort_type1, LONG sort_type2);
2752 * Compare two list entries according to the current comparison hook
2753 * (MUIA_List_CompareHook).
2756 * entry1 - the first entry data.
2757 * entry2 - the second entry data.
2758 * sort_type1 - undocumented.
2759 * sort_type2 - undocumented.
2762 * MUIA_List_CompareHook, MUIM_List_Sort.
2764 ******************************************************************************
2768 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2769 struct MUIP_List_Compare
*msg
)
2771 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2773 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2776 /**************************************************************************
2778 **************************************************************************/
2779 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2780 struct MUIP_List_Display
*msg
)
2782 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2784 if (NULL
== data
->display_hook
)
2787 *msg
->array
= msg
->entry
;
2793 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2794 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2797 /**************************************************************************
2798 MUIM_List_SelectChange
2799 **************************************************************************/
2800 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2801 struct MUIP_List_SelectChange
*msg
)
2806 /**************************************************************************
2807 MUIM_List_CreateImage
2808 Called by a List subclass in its Setup method.
2809 Connects an Area subclass object to the list, much like an object gets
2810 connected to a window. List calls Setup and AskMinMax on that object,
2811 keeps a reference to it (that reference will be returned).
2812 Text engine will dereference that pointer and draw the object with its
2814 **************************************************************************/
2815 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2816 struct MUIP_List_CreateImage
*msg
)
2818 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2819 struct ListImage
*li
;
2824 /* List must be already setup in Setup of your subclass */
2825 if (!(_flags(obj
) & MADF_SETUP
))
2827 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2832 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2833 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2834 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2840 /**************************************************************************
2841 MUIM_List_DeleteImage
2842 **************************************************************************/
2843 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2844 struct MUIP_List_DeleteImage
*msg
)
2846 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2847 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2851 DoMethod(li
->obj
, MUIM_Cleanup
);
2852 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2853 Remove((struct Node
*)li
);
2854 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2860 /****** List.mui/MUIM_List_Jump **********************************************
2863 * MUIM_List_Jump (V4)
2866 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2869 * Scrolls the list so that a particular entry is visible.
2872 * pos - index of entry that should become visible, or one of these
2874 * MUIV_List_Jump_Active: show the active entry.
2875 * MUIV_List_Jump_Top: show the first entry.
2876 * MUIV_List_Jump_Bottom: show the last entry.
2877 * MUIV_List_Jump_Up: show the previous hidden entry.
2878 * MUIV_List_Jump_Down: show the next hidden entry.
2880 ******************************************************************************
2884 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2885 struct MUIP_List_Jump
*msg
)
2887 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2888 LONG pos
= msg
->pos
;
2892 case MUIV_List_Jump_Top
:
2896 case MUIV_List_Jump_Active
:
2897 pos
= data
->entries_active
;
2900 case MUIV_List_Jump_Bottom
:
2901 pos
= data
->entries_num
- 1;
2904 case MUIV_List_Jump_Down
:
2905 pos
= data
->entries_first
+ data
->entries_visible
;
2908 case MUIV_List_Jump_Up
:
2909 pos
= data
->entries_first
- 1;
2913 if (pos
>= data
->entries_num
)
2915 pos
= data
->entries_num
- 1;
2920 if (pos
< data
->entries_first
)
2922 set(obj
, MUIA_List_First
, pos
);
2924 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2926 pos
-= (data
->entries_visible
- 1);
2929 if (pos
!= data
->entries_first
)
2931 set(obj
, MUIA_List_First
, pos
);
2938 /****** List.mui/MUIM_List_Sort **********************************************
2941 * MUIM_List_Sort (V4)
2944 * DoMethod(obj, MUIM_List_Sort);
2947 * Sort the list's entries according to the current comparison hook
2948 * (MUIA_List_CompareHook).
2951 * The active index does not change, so the active entry may do so.
2954 * MUIA_List_CompareHook, MUIM_List_Compare.
2956 ******************************************************************************
2960 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2961 struct MUIP_List_Sort
*msg
)
2963 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2966 struct MUIP_List_Compare cmpmsg
=
2967 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2969 if (data
->entries_num
> 1)
2972 Simple sort algorithm. Feel free to improve it.
2974 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2977 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2979 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2980 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2981 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2988 APTR tmp
= data
->entries
[i
];
2989 data
->entries
[i
] = data
->entries
[max
];
2990 data
->entries
[max
] = tmp
;
2996 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3001 /****** List.mui/MUIM_List_Move **********************************************
3004 * MUIM_List_Move (V9)
3007 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
3010 * Move a list entry to a new position.
3013 * from - the current index of the entry that should be moved, or one of
3014 * these special values:
3015 * MUIV_List_Move_Active: the active entry.
3016 * MUIV_List_Move_Top: the first entry.
3017 * MUIV_List_Move_Bottom: the last entry.
3018 * to - the index of the entry's new position, or one of
3019 * these special values:
3020 * MUIV_List_Move_Active: the active entry.
3021 * MUIV_List_Move_Top: the first entry.
3022 * MUIV_List_Move_Bottom: the last entry.
3025 * The active index does not change, so the active entry may do so.
3028 * MUIM_List_Exchange
3030 ******************************************************************************
3034 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
3035 struct MUIP_List_Move
*msg
)
3037 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3042 /* Normalise special 'from' values */
3045 case MUIV_List_Move_Top
:
3048 case MUIV_List_Move_Active
:
3049 from
= data
->entries_active
;
3051 case MUIV_List_Move_Bottom
:
3052 from
= data
->entries_num
- 1;
3058 /* Normalise special 'to' values */
3061 case MUIV_List_Move_Top
:
3064 case MUIV_List_Move_Active
:
3065 to
= data
->entries_active
;
3067 case MUIV_List_Move_Bottom
:
3068 to
= data
->entries_num
- 1;
3070 case MUIV_List_Move_Next
:
3073 case MUIV_List_Move_Previous
:
3080 /* Check that values are within valid bounds */
3081 if (from
> data
->entries_num
- 1 || from
< 0
3082 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
3083 return (IPTR
) FALSE
;
3085 /* Shift all entries in the range between the 'from' and 'to' positions */
3088 struct ListEntry
*backup
= data
->entries
[from
];
3089 for (i
= from
; i
< to
; i
++)
3090 data
->entries
[i
] = data
->entries
[i
+ 1];
3091 data
->entries
[to
] = backup
;
3095 struct ListEntry
*backup
= data
->entries
[from
];
3096 for (i
= from
; i
> to
; i
--)
3097 data
->entries
[i
] = data
->entries
[i
- 1];
3098 data
->entries
[to
] = backup
;
3101 #if 0 /* Not done in MUI 3 */
3102 /* Update index of active entry */
3103 if (from
== data
->entries_active
)
3104 data
->entries_active
= to
;
3105 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
3106 data
->entries_active
--;
3107 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
3108 data
->entries_active
++;
3111 /* Reflect list changes visually */
3113 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3118 /****** List.mui/MUIM_List_NextSelected **************************************
3121 * MUIM_List_NextSelected (V6)
3124 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3127 * Allows iteration through a list's selected entries by providing the
3128 * index of the next selected entry after the specified index.
3131 * pos - the address of a variable containing the index of the previous
3132 * selected entry. The variable must be initialised to the special
3133 * value MUIV_List_NextSelected_Start to find the first selected
3134 * entry. When this method returns, the variable will contain the
3135 * index of the next selected entry, or MUIV_List_NextSelected_End if
3136 * there are no more.
3139 * If there are no selected entries but there is an active entry, the
3140 * index of the active entry will be stored (when
3141 * MUIV_List_NextSelected_Start is specified).
3143 * Some selected entries may be skipped if any entries are removed
3144 * between calls to this method during an iteration of a list.
3146 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3147 * the same numeric value.
3150 * MUIM_List_Select, MUIM_List_Remove.
3152 ******************************************************************************
3156 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
3157 struct MUIP_List_NextSelected
*msg
)
3159 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3163 /* Get the first entry to check */
3165 if (pos
== MUIV_List_NextSelected_Start
)
3170 /* Find the next selected entry */
3171 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
3173 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
3180 /* Return index of selected or active entry, or indicate there are no
3184 if (*msg
->pos
== MUIV_List_NextSelected_Start
3185 && data
->entries_active
!= MUIV_List_Active_Off
)
3186 pos
= data
->entries_active
;
3188 pos
= MUIV_List_NextSelected_End
;
3195 /**************************************************************************
3197 **************************************************************************/
3198 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
3199 struct MUIP_List_TestPos
*msg
)
3201 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3202 struct MUI_List_TestPos_Result
*result
= msg
->res
;
3203 LONG col
= -1, row
= -1;
3205 LONG mx
= msg
->x
- _left(data
->area
);
3206 LONG entries_visible
;
3208 if (data
->entries_visible
<= data
->entries_num
)
3209 entries_visible
= data
->entries_visible
;
3211 entries_visible
= data
->entries_num
;
3212 LONG ey
= msg
->y
- data
->entries_top_pixel
;
3213 /* y coordinates transformed to the entries */
3215 /* Now check if it was clicked on a title or on entries */
3217 flags
|= MUI_LPR_ABOVE
;
3218 else if (ey
>= entries_visible
* data
->entry_maxheight
)
3219 flags
|= MUI_LPR_BELOW
;
3223 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
3225 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
3229 flags
|= MUI_LPR_LEFT
;
3230 else if (mx
>= _width(data
->area
))
3231 flags
|= MUI_LPR_RIGHT
;
3234 /* Identify column */
3235 if (data
->entries_num
> 0 && data
->columns
> 0)
3238 col
= data
->columns
- 1;
3239 for (i
= 0; i
< data
->columns
; i
++)
3241 result
->xoffset
= mx
- width_sum
;
3243 data
->ci
[i
].entries_width
+
3245 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
3246 D(bug("[List/MUIM_TestPos] i %d "
3247 "width %d width_sum %d mx %d\n",
3248 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
3252 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
3259 result
->entry
= row
;
3260 result
->column
= col
;
3261 result
->flags
= flags
;
3266 /****i* List.mui/MUIM_DragQuery **********************************************
3271 ******************************************************************************
3275 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
3276 struct MUIP_DragQuery
*msg
)
3278 if (msg
->obj
== obj
)
3279 return MUIV_DragQuery_Accept
;
3281 return MUIV_DragQuery_Refuse
;
3285 /****i* List.mui/MUIM_DragFinish *********************************************
3290 ******************************************************************************
3294 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
3295 struct MUIP_DragFinish
*msg
)
3297 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3299 data
->drop_mark_y
= -1;
3301 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3304 /****i* List.mui/MUIM_DragReport *********************************************
3309 ******************************************************************************
3313 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
3314 struct MUIP_DragReport
*msg
)
3316 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3317 struct MUI_List_TestPos_Result pos
;
3318 struct RastPort
*rp
= _rp(obj
);
3322 /* Choose new drop mark position */
3324 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3325 if (pos
.entry
!= -1)
3328 if (pos
.yoffset
> 0)
3331 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3332 n
= data
->entries_first
;
3335 n
= MIN(data
->entries_visible
, data
->entries_num
)
3336 - data
->entries_first
;
3339 /* Clear old drop mark */
3341 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
3343 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
3344 * data
->entry_maxheight
;
3345 if (y
!= data
->drop_mark_y
)
3347 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
3348 data
->drop_mark_y
, _mwidth(data
->area
), 1, 0, 0, 0);
3350 /* Draw new drop mark and store its position */
3352 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
3354 old_pattern
= rp
->LinePtrn
;
3355 SetDrPt(rp
, 0xF0F0);
3356 Move(rp
, _mleft(data
->area
), y
);
3357 Draw(rp
, _mright(data
->area
), y
);
3358 SetDrPt(rp
, old_pattern
);
3359 data
->drop_mark_y
= y
;
3367 /****i* List.mui/MUIM_DragDrop ***********************************************
3372 ******************************************************************************
3376 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
3377 struct MUIP_DragDrop
*msg
)
3379 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3380 struct MUI_List_TestPos_Result pos
;
3383 /* Find drop position */
3385 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3386 if (pos
.entry
!= -1)
3388 /* Change drop position when coords move past centre of entry, not
3392 if (pos
.yoffset
> 0)
3395 /* Ensure that dropped entry will be positioned between the two
3396 * entries that are above and below the drop mark, rather than
3397 * strictly at the numeric index shown */
3399 if (n
> data
->entries_active
)
3402 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3403 n
= MUIV_List_Move_Top
;
3405 n
= MUIV_List_Move_Bottom
;
3407 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
3413 /****i* List.mui/MUIM_CreateDragImage ****************************************
3416 * MUIM_CreateDragImage
3418 ******************************************************************************
3422 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
3423 struct MUIP_CreateDragImage
*msg
)
3425 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3426 BOOL success
= TRUE
;
3427 struct MUI_List_TestPos_Result pos
;
3428 WORD width
, height
, left
, top
;
3429 struct MUI_DragImage
*img
= NULL
;
3430 const struct ZuneFrameGfx
*zframe
;
3433 /* Get info on dragged entry */
3434 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
3435 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
3436 if (pos
.entry
== -1)
3441 /* Get boundaries of entry */
3442 width
= _mwidth(data
->area
);
3443 height
= data
->entry_maxheight
;
3444 left
= _mleft(data
->area
);
3445 top
= _top(data
->area
) - msg
->touchy
3446 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3448 /* Allocate drag image structure */
3449 img
= (struct MUI_DragImage
*)
3450 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3457 /* Get drag frame */
3458 zframe
= zune_zframe_get(obj
,
3459 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3461 /* Allocate drag image buffer */
3462 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3463 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3464 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3465 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3466 _screen(obj
)->RastPort
.BitMap
);
3468 if (img
->bm
!= NULL
)
3471 struct RastPort temprp
;
3472 InitRastPort(&temprp
);
3473 temprp
.BitMap
= img
->bm
;
3474 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3475 zframe
->ileft
, zframe
->itop
, width
, height
,
3479 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3480 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3481 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3482 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3483 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3486 /* Ensure drag point matches where user clicked */
3487 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3488 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3496 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3498 LONG
new, first
, entries
, visible
;
3500 new = first
= XGET(obj
, MUIA_List_First
);
3501 entries
= XGET(obj
, MUIA_List_Entries
);
3502 visible
= XGET(obj
, MUIA_List_Visible
);
3506 if (new > entries
- visible
)
3508 new = entries
- visible
;
3518 set(obj
, MUIA_List_First
, new);
3522 /**************************************************************************
3524 **************************************************************************/
3525 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3526 struct MUIP_HandleEvent
*msg
)
3528 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3529 struct MUI_List_TestPos_Result pos
;
3530 LONG seltype
, old_active
, new_active
, visible
, first
, last
, i
;
3532 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3534 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3536 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3537 visible
= XGET(obj
, MUIA_List_Visible
);
3539 if (muikey
!= MUIKEY_NONE
)
3541 result
= MUI_EventHandlerRC_Eat
;
3543 /* Make keys behave differently in read-only mode */
3544 if (data
->read_only
)
3549 muikey
= MUIKEY_LINESTART
;
3553 muikey
= MUIKEY_LINEEND
;
3557 muikey
= MUIKEY_LEFT
;
3562 muikey
= MUIKEY_RIGHT
;
3570 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
3571 && !data
->read_only
)
3574 data
->click_column
= data
->def_click_column
;
3575 new_active
= MUIV_List_Active_Down
;
3579 DoMethod(obj
, MUIM_List_Jump
, 0);
3580 muikey
= MUIKEY_NONE
;
3585 new_active
= MUIV_List_Active_Top
;
3589 new_active
= MUIV_List_Active_Bottom
;
3593 case MUIKEY_WORDLEFT
:
3594 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
3598 case MUIKEY_WORDRIGHT
:
3599 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
3602 case MUIKEY_LINESTART
:
3603 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
3606 case MUIKEY_LINEEND
:
3607 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
3611 new_active
= MUIV_List_Active_Up
;
3615 new_active
= MUIV_List_Active_Down
;
3619 data
->click_column
= data
->def_click_column
;
3620 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3621 data
->click_column
);
3622 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3626 if (data
->read_only
)
3627 DoWheelMove(cl
, obj
, -visible
);
3629 new_active
= MUIV_List_Active_PageUp
;
3632 case MUIKEY_PAGEDOWN
:
3633 if (data
->read_only
)
3634 DoWheelMove(cl
, obj
, visible
);
3636 new_active
= MUIV_List_Active_PageDown
;
3645 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
,
3648 switch (msg
->imsg
->Class
)
3650 case IDCMP_MOUSEBUTTONS
:
3651 if (msg
->imsg
->Code
== SELECTDOWN
)
3653 if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3656 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
3658 if (!data
->read_only
&& pos
.entry
!= -1)
3660 new_active
= pos
.entry
;
3662 clear
= (data
->multiselect
3663 == MUIV_Listview_MultiSelect_Shifted
3664 && (msg
->imsg
->Qualifier
3665 & (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
3666 seltype
= clear
? MUIV_List_Select_On
3667 : MUIV_List_Select_Toggle
;
3668 select
= data
->multiselect
3669 != MUIV_Listview_MultiSelect_None
;
3671 /* Handle MUIA_Listview_ClickColumn */
3672 data
->click_column
= pos
.column
;
3673 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3674 data
->click_column
);
3676 /* Handle double clicking */
3677 if (data
->last_active
== pos
.entry
3678 && DoubleClick(data
->last_secs
, data
->last_mics
,
3679 msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
3681 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3682 data
->last_active
= -1;
3683 data
->last_secs
= data
->last_mics
= 0;
3687 data
->last_active
= pos
.entry
;
3688 data
->last_secs
= msg
->imsg
->Seconds
;
3689 data
->last_mics
= msg
->imsg
->Micros
;
3692 /* Look out for mouse movement, timer and
3693 inactive-window events while mouse button is
3695 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3697 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
3698 | IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
3699 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3706 /* Activate object */
3707 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
3709 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
3710 data
->mouse_click
= 0;
3713 /* Restore normal event mask */
3714 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3716 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
3717 | IDCMP_INACTIVEWINDOW
);
3718 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3723 case IDCMP_MOUSEMOVE
:
3724 case IDCMP_INTUITICKS
:
3725 if (pos
.flags
& MUI_LPR_ABOVE
)
3726 new_active
= MUIV_List_Active_Up
;
3727 else if (pos
.flags
& MUI_LPR_BELOW
)
3728 new_active
= MUIV_List_Active_Down
;
3730 new_active
= pos
.entry
;
3732 select
= new_active
!= old_active
3733 && data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3736 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3737 MUIV_List_Select_Ask
, &seltype
);
3738 range_select
= new_active
>= 0;
3743 case IDCMP_INACTIVEWINDOW
:
3744 /* Stop listening for events we only listen to when mouse button is
3745 down: we will not be informed of the button being released */
3746 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3748 data
->ehn
.ehn_Events
&=
3749 ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3750 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3756 if (data
->vert
&& _isinobject(data
->vert
, msg
->imsg
->MouseX
,
3759 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3767 switch (msg
->imsg
->Code
)
3769 case RAWKEY_NM_WHEEL_UP
:
3770 DoWheelMove(cl
, obj
, -delta
);
3773 case RAWKEY_NM_WHEEL_DOWN
:
3774 DoWheelMove(cl
, obj
, delta
);
3777 result
= MUI_EventHandlerRC_Eat
;
3783 /* Decide in advance if any selections may change */
3784 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
3786 /* Change selected and active entries */
3788 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
3792 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
3793 MUIV_List_Select_Off
, NULL
);
3796 if (muikey
== MUIKEY_TOGGLE
)
3798 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3799 MUIV_List_Select_Toggle
, NULL
);
3803 if (new_active
!= old_active
)
3804 set(obj
, MUIA_List_Active
, new_active
);
3810 if (old_active
< new_active
)
3811 first
= old_active
+ 1, last
= new_active
;
3813 first
= new_active
, last
= old_active
- 1;
3814 for (i
= first
; i
<= last
; i
++)
3815 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
3818 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3823 set(obj
, MUIA_Listview_SelectChange
, FALSE
);
3828 /**************************************************************************
3830 **************************************************************************/
3831 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3833 switch (msg
->MethodID
)
3836 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3838 return List__OM_DISPOSE(cl
, obj
, msg
);
3840 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3842 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3845 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3847 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3848 case MUIM_HandleEvent
:
3849 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
3850 case MUIM_AskMinMax
:
3851 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3853 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3855 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3857 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3859 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3860 case MUIM_List_Clear
:
3861 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3862 case MUIM_List_Sort
:
3863 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3864 case MUIM_List_Exchange
:
3865 return List__MUIM_Exchange(cl
, obj
,
3866 (struct MUIP_List_Exchange
*)msg
);
3867 case MUIM_List_Insert
:
3868 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3869 case MUIM_List_InsertSingle
:
3870 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3871 case MUIM_List_GetEntry
:
3872 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3873 case MUIM_List_Redraw
:
3874 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3875 case MUIM_List_Remove
:
3876 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3877 case MUIM_List_Select
:
3878 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3879 case MUIM_List_Construct
:
3880 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3881 case MUIM_List_Destruct
:
3882 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3883 case MUIM_List_Compare
:
3884 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3885 case MUIM_List_Display
:
3886 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3887 case MUIM_List_SelectChange
:
3888 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3889 case MUIM_List_CreateImage
:
3890 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3891 case MUIM_List_DeleteImage
:
3892 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3893 case MUIM_List_Jump
:
3894 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3895 case MUIM_List_Move
:
3896 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3897 case MUIM_List_NextSelected
:
3898 return List__MUIM_NextSelected(cl
, obj
,
3899 (struct MUIP_List_NextSelected
*)msg
);
3900 case MUIM_List_TestPos
:
3901 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3902 case MUIM_DragQuery
:
3903 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3904 case MUIM_DragFinish
:
3905 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3906 case MUIM_DragReport
:
3907 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3909 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3910 case MUIM_CreateDragImage
:
3911 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3914 return DoSuperMethodA(cl
, obj
, msg
);
3916 BOOPSI_DISPATCHER_END
3921 const struct __MUIBuiltinClass _MUI_List_desc
=
3925 sizeof(struct MUI_ListData
),
3926 (void *) List_Dispatcher