2 Copyright © 2002-2016, The AROS Development Team. All rights reserved.
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <devices/rawkeycodes.h>
14 #include <clib/alib_protos.h>
15 #include <proto/exec.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
20 #include <proto/muimaster.h>
22 /* #define MYDEBUG 1 */
25 #include "muimaster_intern.h"
28 #include "textengine.h"
29 #include "listimage.h"
32 extern struct Library
*MUIMasterBase
;
34 #define ENTRY_TITLE (-1)
36 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
37 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
57 LONG width
; /* Line width */
58 LONG height
; /* Line height */
59 WORD flags
; /* see below */
60 LONG widths
[]; /* Widths of the columns */
63 #define ENTRY_SELECTED (1<<0)
68 int colno
; /* Column number */
69 int user_width
; /* user set width; -1 if entry width */
70 int min_width
; /* min width percentage */
71 int max_width
; /* min width percentage */
73 int delta
; /* ignored for the first and last column, defaults to 4 */
76 int entries_width
; /* width of the entries (maximum of all widths) */
79 struct MUI_ImageSpec_intern
;
86 APTR intern_pool
; /* The internal pool which the class has allocated */
87 LONG intern_puddle_size
;
88 LONG intern_thresh_size
;
89 APTR pool
; /* the pool which is used to allocate list entries */
91 struct Hook
*construct_hook
;
92 struct Hook
*compare_hook
;
93 struct Hook
*destruct_hook
;
94 struct Hook
*display_hook
;
95 struct Hook
*multi_test_hook
;
97 struct Hook default_compare_hook
;
99 /* List management, currently we use a simple flat array, which is not
100 * good if many entries are inserted/deleted */
101 LONG entries_num
; /* Number of Entries in the list */
102 LONG entries_allocated
;
103 struct ListEntry
**entries
;
105 LONG entries_first
; /* first visible entry */
106 LONG entries_visible
; /* number of visible entries,
107 * determined at MUIM_Layout */
109 LONG insert_position
; /* pos of the last insertion */
111 LONG entry_maxheight
; /* Maximum height of an entry */
112 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
114 LONG entries_totalheight
;
115 LONG entries_maxwidth
;
117 LONG vertprop_entries
;
118 LONG vertprop_visible
;
121 LONG confirm_entries_num
; /* These are the correct entries num, used
122 * so you cannot set MUIA_List_Entries to
125 LONG entries_top_pixel
; /* Where the entries start */
127 /* Column managment, is allocated by ParseListFormat() and freed
128 * by CleanListFormat() */
130 LONG columns
; /* Number of columns the list has */
131 struct ColumnInfo
*ci
;
133 STRPTR
*strings_mem
; /* safe pointer to allocated memory for strings[] */
134 STRPTR
*strings
; /* the strings for the display function, one
135 * more than needed (for the entry position) */
138 int title_height
; /* The complete height of the title */
139 STRPTR title
; /* On single column lists this is the title,
140 * otherwise 1. NULL for no title(s) */
143 struct MUI_ImageSpec_intern
*list_cursor
;
144 struct MUI_ImageSpec_intern
*list_select
;
145 struct MUI_ImageSpec_intern
*list_selcur
;
147 /* Render optimization */
148 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
149 * 3 - scroll to current entries_first (old value is in
156 struct MinList images
;
159 ListviewRefresh prefs_refresh
;
160 UWORD prefs_linespacing
;
162 UWORD prefs_smoothval
;
164 /* render space handling */
169 /***************************/
170 /* Former Listview members */
171 /***************************/
181 LONG def_click_column
;
183 LONG mouse_click
; /* see below if mouse is held down */
190 struct MUI_EventHandlerNode ehn
;
193 ListviewMulti prefs_multi
;
201 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
202 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
204 #define LIST_ADJUSTWIDTH (1<<0)
205 #define LIST_ADJUSTHEIGHT (1<<1)
206 #define LIST_AUTOVISIBLE (1<<2)
207 #define LIST_DRAGSORTABLE (1<<3)
208 #define LIST_SHOWDROPMARKS (1<<4)
209 #define LIST_QUIET (1<<5)
212 /****** List.mui/MUIA_List_Active ********************************************
215 * MUIA_List_Active -- (V4) [ISG], LONG
218 * The index of the active entry. There can be at most one active entry
219 * in a list. The active entry is highlighted visibly, except for
220 * read-only lists (those whose Listview has MUIA_Listview_Input set to
221 * FALSE). Selecting an entry with the mouse, or moving through the list
222 * with keyboard controls will also change the active entry (again
223 * excepting read-only lists).
225 * When set programmatically through this attribute, some special values
228 * MUIV_List_Active_Off
229 * MUIV_List_Active_Top
230 * MUIV_List_Active_Bottom
231 * MUIV_List_Active_Up
232 * MUIV_List_Active_Down
233 * MUIV_List_Active_PageUp
234 * MUIV_List_Active_PageDown
236 * When this attribute is read, either the index of the active entry or
237 * the special value MUIV_List_Active_Off will be returned.
239 * Setting this attribute to a new value will additionally have the same
240 * effect as calling the MUIM_List_Jump method with the specified or
244 * The concept of an active entry must not be confused with that of a
248 * MUIM_List_Jump, MUIM_List_Select, MUIA_Listview_Input
250 ******************************************************************************
254 /****** List.mui/MUIA_List_CompareHook ***************************************
257 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
260 * The provided hook indicates the sort ordering of two list entries.
261 * The hook receives list-entry data pointers as its second and third
262 * arguments. The hook should return a negative value if the first entry
263 * should be placed before the second entry, a positive value if the
264 * first entry should be placed after the second entry, and zero if the
267 * In addition to being used internally for sorting operations, this hook
268 * will be called when MUIM_List_Compare is externally invoked.
270 * If this attribute is not specified or is set to NULL, all list entries
273 ******************************************************************************
277 /****** List.mui/MUIA_List_First *********************************************
280 * MUIA_List_First -- (V4) [..G], LONG
283 * The index of the first entry that can be seen (assuming nothing
284 * obscures the list) This value of this attribute is -1 when the
285 * list's window is not open.
288 * Notification does not occur on this attribute in MUI.
291 * MUIA_List_First, MUIA_List_Entries
293 ******************************************************************************
297 /****** List.mui/MUIA_List_MultiTestHook *************************************
300 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
303 * The provided hook indicates whether a particular list entry
304 * may be multiselected. The hook receives the list-entry data pointer as
305 * its third argument, and returns a Boolean value. If this attribute is
306 * not specified or is set to NULL, all list entries are considered
309 * Whenever an entry is about to be selected, this hook is called if
310 * there are other entries already selected. If the hook returns TRUE,
311 * the entry may be multi-selected; if the hook returns FALSE, the entry
312 * remains unselected.
314 * Additionally, if a non-multi-selectable entry has been selected (as
315 * the only selected entry in the list), any attempt to select an
316 * additional entry will fail.
318 ******************************************************************************
322 /****** List.mui/MUIA_List_Title *********************************************
325 * MUIA_List_Title -- (V6) [ISG], char *
328 * A heading for the list, placed above list entries. A value of NULL
329 * means no title is used. A value of TRUE means that the custom
330 * display hook provides a separate title for each column; the hook
331 * must then provide column titles instead of normal column data when
332 * the entry pointer provided is NULL.
335 * If a string is set for this attribute, it is not cached within the
339 * MUIA_List_DisplayHook
341 ******************************************************************************
345 /****** List.mui/MUIA_List_Visible *******************************************
348 * MUIA_List_Visible -- (V4) [..G], LONG
351 * The number of entries that can be seen at once with the list's
352 * current dimensions. This value of this attribute is -1 when the
353 * list's window is not open.
356 * Notification does not occur on this attribute in MUI.
359 * MUIA_List_First, MUIA_List_Entries
361 ******************************************************************************
365 /**************************************************************************
366 Allocate a single list entry, does not initialize it (except the pointer)
367 **************************************************************************/
368 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
370 struct ListEntry
*le
;
371 /* what happens, if data->columns is later increased by MUIA_List_Format? */
372 IPTR size
= sizeof(struct ListEntry
) + sizeof(LONG
) * (data
->columns
+ 1);
374 le
= (struct ListEntry
*) AllocVecPooled(data
->pool
, size
);
375 D(bug("List AllocListEntry %p, %ld bytes\n", le
, size
));
378 /* possible, that we have an external pool, which does not have
385 /**************************************************************************
386 Deallocate a single list entry, does not deinitialize it
387 **************************************************************************/
388 static void FreeListEntry(struct MUI_ListData
*data
,
389 struct ListEntry
*entry
)
391 D(bug("FreeListEntry %p\n", entry
));
392 FreeVecPooled(data
->pool
, entry
);
395 /**************************************************************************
396 Ensures that there can be at least the given amount of entries within
397 the list. Returns 0 if not. It also allocates the space for the title.
398 It can be accessed with data->entries[ENTRY_TITLE]
399 **************************************************************************/
400 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
402 struct ListEntry
**new_entries
;
403 int new_entries_allocated
;
405 if (size
+ 1 <= data
->entries_allocated
)
408 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
409 if (new_entries_allocated
< size
+ 1)
410 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
412 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
413 new_entries_allocated
* sizeof(struct ListEntry
*)));
415 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
416 if (NULL
== new_entries
)
420 CopyMem(data
->entries
- 1, new_entries
,
421 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
422 FreeVec(data
->entries
- 1);
424 data
->entries
= new_entries
+ 1;
425 data
->entries_allocated
= new_entries_allocated
;
429 /**************************************************************************
430 Prepares the insertion of count entries at pos.
431 This function doesn't care if there is enough space in the datastructure.
432 SetListSize() must be used first.
433 With current implementation, this call will never fail
434 **************************************************************************/
435 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
438 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
439 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
443 /**************************************************************************
444 Removes count (already deinitalized) list entries starting az pos.
445 **************************************************************************/
446 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
448 // FIXME: segfault if entries_num = pos = count = 1
449 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
450 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
453 /**************************************************************************
454 Frees all memory allocated by ParseListFormat()
455 **************************************************************************/
456 static void FreeListFormat(struct MUI_ListData
*data
)
462 for (i
= 0; i
< data
->columns
; i
++)
464 FreeVec(data
->ci
[i
].preparse
);
465 data
->ci
[i
].preparse
= NULL
;
470 FreeVec(data
->preparses
);
471 data
->preparses
= NULL
;
472 if (data
->strings_mem
)
474 FreeVec(data
->strings_mem
);
475 data
->strings_mem
= NULL
;
476 data
->strings
= NULL
;
481 /**************************************************************************
482 Parses the given format string (also frees a previously parsed format).
484 **************************************************************************/
485 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
493 struct RDArgs
*rdargs
;
496 format
= (STRPTR
) "";
500 FreeListFormat(data
);
504 /* Count the number of columns first */
509 if (!(data
->preparses
=
510 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
513 if (!(data
->strings_mem
= AllocVec((new_columns
+ 1 + 10)
514 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
515 * used by orginal MUI and also some
518 data
->strings
=data
->strings_mem
;
520 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
524 for (i
= 0; i
< new_columns
; i
++)
526 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
527 data
->ci
[i
].weight
= 100;
528 data
->ci
[i
].delta
= 4;
529 data
->ci
[i
].min_width
= -1;
530 data
->ci
[i
].max_width
= -1;
531 data
->ci
[i
].user_width
= -1;
532 data
->ci
[i
].bar
= FALSE
;
533 data
->ci
[i
].preparse
= NULL
;
536 if ((format_sep
= StrDup(format
)) != 0)
538 for (i
= 0; format_sep
[i
] != '\0'; i
++)
540 if (format_sep
[i
] == ',')
541 format_sep
[i
] = '\0';
544 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
550 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
551 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
552 rdargs
->RDA_Source
.CS_CurChr
= 0;
553 rdargs
->RDA_DAList
= 0;
554 rdargs
->RDA_Buffer
= NULL
;
555 rdargs
->RDA_BufSiz
= 0;
556 rdargs
->RDA_ExtHelp
= NULL
;
557 rdargs
->RDA_Flags
= 0;
559 memset(args
, 0, sizeof args
);
560 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
563 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
564 if (args
[ARG_WEIGHT
])
565 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
567 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
568 if (args
[ARG_MINWIDTH
])
569 data
->ci
[i
].min_width
=
570 *(LONG
*) args
[ARG_MINWIDTH
];
571 if (args
[ARG_MAXWIDTH
])
572 data
->ci
[i
].max_width
=
573 *(LONG
*) args
[ARG_MAXWIDTH
];
574 data
->ci
[i
].bar
= args
[ARG_BAR
];
575 if (args
[ARG_PREPARSE
])
576 data
->ci
[i
].preparse
=
577 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
581 ptr
+= strlen(ptr
) + 1;
584 while (i
< new_columns
);
585 FreeDosObject(DOS_RDARGS
, rdargs
);
590 for (i
= 0; i
< new_columns
; i
++)
592 D(bug("colno %d weight %d delta %d preparse %s\n",
593 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
594 data
->ci
[i
].preparse
));
597 data
->columns
= new_columns
;
598 data
->strings
++; /* Skip entry pos */
603 /**************************************************************************
604 Call the MUIM_List_Display for the given entry. It fills out
605 data->string and data->preparses
606 **************************************************************************/
607 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
609 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
613 for (col
= 0; col
< data
->columns
; col
++)
614 data
->preparses
[col
] = data
->ci
[col
].preparse
;
616 if (entry_pos
== ENTRY_TITLE
)
618 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
620 *data
->strings
= data
->title
;
623 entry_data
= NULL
; /* it's a title request */
626 entry_data
= data
->entries
[entry_pos
]->data
;
628 /* Get the display formation */
629 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
630 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
633 /**************************************************************************
634 Determine the dims of a single entry and adapt the columninfo according
635 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
636 be redrawn after this operation, 1 if all entries need to be redrawn.
637 **************************************************************************/
638 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
640 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
641 struct ListEntry
*entry
= data
->entries
[pos
];
648 if (!(_flags(obj
) & MADF_SETUP
))
651 DisplayEntry(cl
, obj
, pos
);
653 /* Set height to at least minheight */
654 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
655 data
->entries
[pos
]->height
= data
->entry_minheight
;
657 for (j
= 0; j
< data
->columns
; j
++)
660 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
664 zune_text_get_bounds(text
, obj
);
666 if (text
->height
> data
->entries
[pos
]->height
)
668 data
->entries
[pos
]->height
= text
->height
;
669 /* entry height changed, redraw all entries later */
672 data
->entries
[pos
]->widths
[j
] = text
->width
;
674 if (text
->width
> data
->ci
[j
].entries_width
)
676 /* This entry has a greater width for this column than any
677 * other entry, so we store this value
679 data
->ci
[j
].entries_width
= text
->width
;
680 /* column width changed, redraw all entries later */
684 zune_text_destroy(text
);
687 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
689 data
->entry_maxheight
= data
->entries
[pos
]->height
;
690 /* maximum entry height changed, redraw all entries later */
697 /**************************************************************************
698 Determine the widths of the entries
699 **************************************************************************/
700 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
703 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
705 if (!(_flags(obj
) & MADF_SETUP
))
708 for (j
= 0; j
< data
->columns
; j
++)
709 data
->ci
[j
].entries_width
= 0;
711 data
->entry_maxheight
= 0;
712 data
->entries_totalheight
= 0;
713 data
->entries_maxwidth
= 0;
715 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
717 CalcDimsOfEntry(cl
, obj
, i
);
718 data
->entries_totalheight
+= data
->entries
[i
]->height
;
721 for (j
= 0; j
< data
->columns
; j
++)
722 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
723 + data
->ci
[j
].delta
+ (data
->ci
[j
].bar
? BAR_WIDTH
: 0);
725 if (!data
->entry_maxheight
)
726 data
->entry_maxheight
= 1;
729 /**************************************************************************
730 Calculates the number of visible entry lines. Returns 1 if it has
732 **************************************************************************/
733 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
735 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
736 int old_entries_visible
= data
->entries_visible
;
737 int old_entries_top_pixel
= data
->entries_top_pixel
;
739 data
->vertprop_visible
= data
->entries_visible
=
740 (_mheight(data
->area
) - data
->title_height
)
741 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
743 /* Distribute extra vertical space evenly between top and bottom of
746 data
->entries_top_pixel
= _mtop(data
->area
) + data
->title_height
747 + (_mheight(data
->area
) - data
->title_height
749 data
->entries_visible
*
750 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
752 if (data
->entries_visible
!= old_entries_visible
)
754 superset(cl
, obj
, MUIA_List_Visible
, data
->entries_visible
);
755 superset(cl
, obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
758 return (old_entries_visible
!= data
->entries_visible
)
759 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
762 /**************************************************************************
763 Default hook to compare two list entries. Works for strings only.
764 **************************************************************************/
765 AROS_UFH3S(int, default_compare_func
,
766 AROS_UFHA(struct Hook
*, h
, A0
),
767 AROS_UFHA(char *, s2
, A2
),
768 AROS_UFHA(char *, s1
, A1
))
772 return Stricmp(s1
, s2
);
777 #define PROP_VERT_FIRST 1
779 static ULONG
List_Function(struct Hook
*hook
, Object
* obj
, void **msg
)
781 struct MUI_ListData
*data
= (struct MUI_ListData
*)hook
->h_Data
;
782 SIPTR type
= (SIPTR
) msg
[0];
783 SIPTR val
= (SIPTR
) msg
[1];
787 case PROP_VERT_FIRST
:
788 get(data
->vert
, MUIA_Prop_First
, &val
);
789 nnset(obj
, MUIA_List_VertProp_First
, val
);
795 /* At entry to this function, data->area is always set, but data->vert may
796 * or may not be set */
797 static void List_HandleScrollerPos(struct IClass
*cl
, Object
*obj
)
799 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
800 BOOL vert_not_used
= FALSE
;
802 /* Disallow any changes after setup. This function should basically be
803 * creation-time only */
804 if (_flags(obj
) & MADF_SETUP
)
807 /* Remove both objects */
808 if (data
->area_connected
)
809 DoMethod(obj
, OM_REMMEMBER
, data
->area
);
810 if (data
->vert_connected
)
811 DoMethod(obj
, OM_REMMEMBER
, data
->vert
);
813 /* Add list and/or scroller */
814 switch (data
->scroller_pos
)
816 case MUIV_Listview_ScrollerPos_None
:
817 vert_not_used
= TRUE
;
818 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
820 case MUIV_Listview_ScrollerPos_Left
:
822 data
->vert
=ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
823 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
824 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
828 data
->vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
829 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
830 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
834 data
->area_connected
= TRUE
;
836 /* Handle case where it was decided that vert will not be used */
841 if (data
->vert_connected
)
843 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_First
,
845 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Visible
,
847 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Entries
,
849 data
->vert_connected
= FALSE
;
852 MUI_DisposeObject(data
->vert
);
857 /* If at this point data->vert is not null, it means vert is to be
859 if (data
->vert
&& !data
->vert_connected
)
861 LONG entries
= 0, first
= 0, visible
= 0;
863 get(obj
, MUIA_List_VertProp_First
, &first
);
864 get(obj
, MUIA_List_VertProp_Visible
, &visible
);
865 get(obj
, MUIA_List_VertProp_Entries
, &entries
);
867 SetAttrs(data
->vert
, MUIA_Prop_First
, first
,
868 MUIA_Prop_Visible
, visible
, MUIA_Prop_Entries
, entries
, TAG_DONE
);
870 DoMethod(data
->vert
, MUIM_Notify
, MUIA_Prop_First
, MUIV_EveryTime
,
871 (IPTR
) obj
, 4, MUIM_CallHook
, (IPTR
) &data
->hook
, PROP_VERT_FIRST
,
874 /* Pass prop object as DestObj (based on code in NList) */
875 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_First
, MUIV_EveryTime
,
876 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
877 MUIA_Prop_First
, MUIV_TriggerValue
);
878 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Visible
, MUIV_EveryTime
,
879 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
880 MUIA_Prop_Visible
, MUIV_TriggerValue
);
881 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Entries
, MUIV_EveryTime
,
882 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
,
883 MUIA_Prop_Entries
, MUIV_TriggerValue
);
885 data
->vert_connected
= TRUE
;
889 /**************************************************************************
891 **************************************************************************/
892 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
894 struct MUI_ListData
*data
;
896 struct TagItem
*tags
;
898 LONG new_entries_active
= MUIV_List_Active_Off
;
899 struct TagItem rectattrs
[2] =
900 {{TAG_IGNORE
, TAG_IGNORE
}, {TAG_DONE
, TAG_DONE
}};
903 /* search for MUIA_Frame as it has to be passed to rectangle object */
904 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
906 if (tag
->ti_Tag
== MUIA_Frame
)
908 rectattrs
[0].ti_Tag
= MUIA_Frame
;
909 rectattrs
[0].ti_Data
= tag
->ti_Data
;
910 tag
->ti_Tag
= TAG_IGNORE
;
915 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
916 MUIA_Group_Horiz
, TRUE
,
919 MUIA_Group_Spacing
, 0,
920 MUIA_Font
, MUIV_Font_List
,
921 MUIA_ShowSelState
, FALSE
,
922 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
923 MUIA_Background
, MUII_ListBack
,
924 TAG_MORE
, (IPTR
) msg
->ops_AttrList
,
930 data
= INST_DATA(cl
, obj
);
933 data
->entries_active
= MUIV_List_Active_Off
;
934 data
->intern_puddle_size
= 2008;
935 data
->intern_thresh_size
= 1024;
936 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
937 data
->default_compare_hook
.h_SubEntry
= 0;
938 data
->compare_hook
= &(data
->default_compare_hook
);
939 data
->flags
= LIST_SHOWDROPMARKS
;
940 data
->area_replaced
= FALSE
;
941 data
->area_connected
= FALSE
;
942 data
->vert_connected
= FALSE
;
944 data
->entries_visible
= data
->vertprop_visible
= -1;
945 data
->last_active
= -1;
947 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
948 data
->ehn
.ehn_Priority
= 0;
949 data
->ehn
.ehn_Flags
= 0;
950 data
->ehn
.ehn_Object
= obj
;
951 data
->ehn
.ehn_Class
= cl
;
954 * List is a group where part of area is rendered and part is filled
955 * with other objects (inside of List dimensions). One such object is
956 * up/down arrow. This object depends on RelVerify mode to control
957 * behaviour. List also has the RelVerify mode. Area super class in case
958 * of both of those objects adds an event handler node with the same
959 * priority. Depending on the sort order, the event handler node of
960 * "list" can eat a click event and up/down arrows stop working. The
961 * hack is to decrease the priority of Area event handler for list to
962 * always favor up/down arrow. There are other hacky ways of solving
963 * this, but this seems least evil approach, as this hack is
964 * encapsulated in the List class itself.
966 muiAreaData(obj
)->mad_ehn
.ehn_Priority
--;
968 data
->hook
.h_Entry
= HookEntry
;
969 data
->hook
.h_SubEntry
= (HOOKFUNC
) List_Function
;
970 data
->hook
.h_Data
= data
;
972 area
= (Object
*)GetTagData(MUIA_List_ListArea
, (IPTR
) 0,
976 area
= RectangleObject
, MUIA_FillArea
, FALSE
, TAG_MORE
,
977 (IPTR
) rectattrs
, End
;
979 data
->area_replaced
= TRUE
;
982 /* parse initial taglist */
983 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
987 case MUIA_List_Active
:
988 new_entries_active
= tag
->ti_Data
;
992 data
->pool
= (APTR
) tag
->ti_Data
;
995 case MUIA_List_PoolPuddleSize
:
996 data
->intern_puddle_size
= tag
->ti_Data
;
999 case MUIA_List_PoolThreshSize
:
1000 data
->intern_thresh_size
= tag
->ti_Data
;
1003 case MUIA_List_CompareHook
:
1004 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1005 if (data
->compare_hook
== NULL
)
1006 data
->compare_hook
= &data
->default_compare_hook
;
1009 case MUIA_List_ConstructHook
:
1010 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1013 case MUIA_List_DestructHook
:
1014 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1017 case MUIA_List_DisplayHook
:
1018 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1021 case MUIA_List_MultiTestHook
:
1022 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1025 case MUIA_List_SourceArray
:
1026 array
= (APTR
*) tag
->ti_Data
;
1029 case MUIA_List_Format
:
1030 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1033 case MUIA_List_Title
:
1034 data
->title
= (STRPTR
) tag
->ti_Data
;
1037 case MUIA_List_MinLineHeight
:
1038 data
->entry_minheight
= tag
->ti_Data
;
1041 case MUIA_List_AdjustHeight
:
1042 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
1045 case MUIA_List_AdjustWidth
:
1046 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
1049 case MUIA_List_AutoVisible
:
1050 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1053 case MUIA_List_ShowDropMarks
:
1054 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1057 case MUIA_List_DragSortable
:
1058 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1059 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1062 case MUIA_Listview_ScrollerPos
:
1063 data
->scroller_pos
= tag
->ti_Data
;
1066 case MUIA_Listview_Input
:
1067 data
->read_only
= !tag
->ti_Data
;
1070 case MUIA_Listview_MultiSelect
:
1071 data
->multiselect
= tag
->ti_Data
;
1074 case MUIA_Listview_DoubleClick
:
1075 data
->doubleclick
= tag
->ti_Data
!= 0;
1078 case MUIA_Listview_DefClickColumn
:
1079 data
->def_click_column
= tag
->ti_Data
;
1084 List_HandleScrollerPos(cl
, obj
);
1088 /* No memory pool given, so we create our own */
1089 data
->pool
= data
->intern_pool
=
1090 CreatePool(0, data
->intern_puddle_size
,
1091 data
->intern_thresh_size
);
1094 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1099 /* parse the list format */
1100 if (!(ParseListFormat(data
, data
->format
)))
1102 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1106 /* This is neccessary for at least the title */
1107 if (!SetListSize(data
, 0))
1109 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1113 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
1115 CoerceMethod(cl
, obj
, OM_DISPOSE
);
1122 /* Count the number of elements */
1123 for (i
= 0; array
[i
] != NULL
; i
++)
1126 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
1127 MUIV_List_Insert_Top
);
1130 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
1132 switch (new_entries_active
)
1134 case MUIV_List_Active_Top
:
1135 new_entries_active
= 0;
1138 case MUIV_List_Active_Bottom
:
1139 new_entries_active
= data
->entries_num
- 1;
1143 if (new_entries_active
< 0)
1144 new_entries_active
= 0;
1145 else if (new_entries_active
>= data
->entries_num
)
1146 new_entries_active
= data
->entries_num
- 1;
1148 data
->entries_active
= new_entries_active
;
1149 /* Selected entry will be moved into visible area */
1152 NewList((struct List
*)&data
->images
);
1154 D(bug("List_New(%lx)\n", obj
));
1159 /**************************************************************************
1161 **************************************************************************/
1162 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
1164 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1166 D(bug("List Dispose\n"));
1168 /* Call destruct method for every entry and free the entries manually
1169 * to avoid notification */
1170 while (data
->confirm_entries_num
)
1172 struct ListEntry
*lentry
=
1173 data
->entries
[--data
->confirm_entries_num
];
1174 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1176 FreeListEntry(data
, lentry
);
1179 if (data
->intern_pool
)
1180 DeletePool(data
->intern_pool
);
1182 FreeVec(data
->entries
- 1);
1183 /* title is currently before all other elements */
1185 FreeListFormat(data
);
1186 FreeVec(data
->format
);
1188 return DoSuperMethodA(cl
, obj
, msg
);
1192 /**************************************************************************
1194 **************************************************************************/
1195 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
1197 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1198 struct TagItem
*tag
;
1199 struct TagItem
*tags
;
1202 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1204 switch (tag
->ti_Tag
)
1206 case MUIA_List_CompareHook
:
1207 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1208 if (data
->compare_hook
== NULL
)
1209 data
->compare_hook
= &data
->default_compare_hook
;
1212 case MUIA_List_ConstructHook
:
1213 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1216 case MUIA_List_DestructHook
:
1217 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1220 case MUIA_List_DisplayHook
:
1221 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1224 case MUIA_List_MultiTestHook
:
1225 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1226 if (data
->multi_test_hook
!= NULL
)
1228 /* Clearing current selections is the easiest way to keep
1229 * selections consistent with the new hook */
1230 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
1231 MUIV_List_Select_Off
, NULL
);
1235 case MUIA_List_Title
:
1236 data
->title
= (STRPTR
) tag
->ti_Data
;
1237 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1240 case MUIA_List_VertProp_First
:
1241 data
->vertprop_first
= tag
->ti_Data
;
1242 if (data
->entries_first
!= tag
->ti_Data
)
1244 set(obj
, MUIA_List_First
, tag
->ti_Data
);
1248 case MUIA_List_Format
:
1249 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1250 ParseListFormat(data
, data
->format
);
1251 // FIXME: should we check for errors?
1252 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1255 case MUIA_List_VertProp_Entries
:
1256 data
->vertprop_entries
= tag
->ti_Data
;
1259 case MUIA_List_VertProp_Visible
:
1260 data
->vertprop_visible
= tag
->ti_Data
;
1261 data
->entries_visible
= tag
->ti_Data
;
1264 case MUIA_List_Active
:
1266 LONG new_entries_active
= tag
->ti_Data
;
1268 if ((data
->entries_num
)
1269 && (new_entries_active
!= MUIV_List_Active_Off
))
1271 switch (new_entries_active
)
1273 case MUIV_List_Active_Top
:
1274 new_entries_active
= 0;
1277 case MUIV_List_Active_Bottom
:
1278 new_entries_active
= data
->entries_num
- 1;
1281 case MUIV_List_Active_Up
:
1282 new_entries_active
= data
->entries_active
- 1;
1285 case MUIV_List_Active_Down
:
1286 new_entries_active
= data
->entries_active
+ 1;
1289 case MUIV_List_Active_PageUp
:
1290 new_entries_active
=
1291 data
->entries_active
- data
->entries_visible
;
1294 case MUIV_List_Active_PageDown
:
1295 new_entries_active
=
1296 data
->entries_active
+ data
->entries_visible
;
1300 if (new_entries_active
< 0)
1301 new_entries_active
= 0;
1302 else if (new_entries_active
>= data
->entries_num
)
1303 new_entries_active
= data
->entries_num
- 1;
1306 new_entries_active
= -1;
1308 if (data
->entries_active
!= new_entries_active
)
1310 LONG old
= data
->entries_active
;
1311 data
->entries_active
= new_entries_active
;
1313 /* SelectChange stuff */
1314 if (new_entries_active
!= -1)
1316 DoMethod(obj
, MUIM_List_SelectChange
,
1317 new_entries_active
, MUIV_List_Select_On
, 0);
1318 DoMethod(obj
, MUIM_List_SelectChange
,
1319 new_entries_active
, MUIV_List_Select_Active
, 0);
1322 DoMethod(obj
, MUIM_List_SelectChange
,
1323 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1325 if (!data
->read_only
)
1328 data
->update_pos
= old
;
1329 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1331 data
->update_pos
= data
->entries_active
;
1332 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1335 /* Make new active entry visible (if there is one and
1337 if (new_entries_active
!= -1
1338 && (_flags(obj
) & MADF_SETUP
))
1340 DoMethod(obj
, MUIM_List_Jump
,
1341 MUIV_List_Jump_Active
);
1347 case MUIA_List_First
:
1348 data
->update_pos
= data
->entries_first
;
1350 data
->entries_first
= tag
->ti_Data
;
1352 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1353 if ((data
->vertprop_first
!= tag
->ti_Data
)
1354 && (!(data
->flags
& LIST_QUIET
)))
1356 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1360 case MUIA_List_Visible
: /* Shouldn't be settable? */
1361 if (data
->vertprop_visible
!= tag
->ti_Data
)
1362 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1365 case MUIA_List_Entries
:
1366 if (data
->confirm_entries_num
== tag
->ti_Data
)
1368 data
->entries_num
= tag
->ti_Data
;
1369 if (!(data
->flags
& LIST_QUIET
))
1371 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1376 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1380 case MUIA_List_Quiet
:
1381 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1384 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1385 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1386 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1387 if (data
->entries_first
!= XGET(obj
, MUIA_List_VertProp_First
))
1388 set(obj
, MUIA_List_VertProp_First
, data
->entries_first
);
1392 case MUIA_List_AutoVisible
:
1393 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1396 case MUIA_List_ShowDropMarks
:
1397 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1400 case MUIA_List_DragSortable
:
1401 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1402 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1406 /* Swallow this so the Area class doesn't redraw us */
1407 tag
->ti_Tag
= TAG_IGNORE
;
1411 if (_flags(obj
) & MADF_SETUP
)
1413 /* Stop listening for events we only listen to when mouse
1414 button is down: we will not be informed of the button
1416 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
1418 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
1419 | IDCMP_INACTIVEWINDOW
);
1420 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
1425 case MUIA_Listview_DoubleClick
: /* private set */
1426 data
->doubleclick
= tag
->ti_Data
!= 0;
1429 case MUIA_Listview_SelectChange
: /* private set */
1430 data
->select_change
= tag
->ti_Data
!= 0;
1433 case MUIA_Listview_ScrollerPos
: /* private set */
1434 data
->scroller_pos
= tag
->ti_Data
;
1435 List_HandleScrollerPos(cl
, obj
);
1438 case MUIA_Listview_Input
: /* private set */
1439 data
->read_only
= !tag
->ti_Data
;
1442 case MUIA_Listview_MultiSelect
: /* private set */
1443 data
->multiselect
= tag
->ti_Data
;
1446 case MUIA_Listview_DefClickColumn
:
1447 data
->def_click_column
= tag
->ti_Data
;
1452 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1455 /**************************************************************************
1457 **************************************************************************/
1458 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1460 /* small macro to simplify return value storage */
1461 #define STORE *(msg->opg_Storage)
1462 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1464 switch (msg
->opg_AttrID
)
1466 case MUIA_List_Entries
:
1467 STORE
= data
->entries_num
;
1469 case MUIA_List_First
:
1470 STORE
= data
->entries_first
;
1472 case MUIA_List_Active
:
1473 STORE
= data
->entries_active
;
1475 case MUIA_List_InsertPosition
:
1476 STORE
= data
->insert_position
;
1478 case MUIA_List_Title
:
1479 STORE
= (IPTR
) data
->title
;
1481 case MUIA_List_VertProp_Entries
:
1482 STORE
= data
->vertprop_entries
;
1484 case MUIA_List_VertProp_Visible
:
1485 case MUIA_List_Visible
:
1486 STORE
= data
->vertprop_visible
;
1488 case MUIA_List_VertProp_First
:
1489 STORE
= data
->vertprop_first
;
1491 case MUIA_List_Format
:
1492 STORE
= (IPTR
) data
->format
;
1494 case MUIA_List_AutoVisible
:
1495 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1497 case MUIA_List_ShowDropMarks
:
1498 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1500 case MUIA_List_DragSortable
:
1501 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1503 case MUIA_Listview_ClickColumn
:
1504 STORE
= data
->click_column
;
1506 case MUIA_Listview_DoubleClick
:
1507 STORE
= data
->doubleclick
;
1509 case MUIA_Listview_SelectChange
:
1510 STORE
= data
->select_change
;
1512 case MUIA_Listview_List
:
1515 case MUIA_Listview_DefClickColumn
:
1516 STORE
= data
->def_click_column
;
1520 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1526 /**************************************************************************
1528 **************************************************************************/
1529 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1530 struct MUIP_Setup
*msg
)
1532 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1534 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1537 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1538 data
->prefs_linespacing
=
1539 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1540 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1541 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1544 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1546 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1548 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1550 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
1551 if (data
->multiselect
== MUIV_Listview_MultiSelect_Default
)
1553 if (data
->prefs_multi
== LISTVIEW_MULTI_SHIFTED
)
1554 data
->multiselect
= MUIV_Listview_MultiSelect_Shifted
;
1556 data
->multiselect
= MUIV_Listview_MultiSelect_Always
;
1559 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1564 /**************************************************************************
1566 **************************************************************************/
1567 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1568 struct MUIP_Cleanup
*msg
)
1570 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1572 zune_imspec_cleanup(data
->list_cursor
);
1573 zune_imspec_cleanup(data
->list_select
);
1574 zune_imspec_cleanup(data
->list_selcur
);
1576 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1577 data
->mouse_click
= 0;
1579 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1582 /**************************************************************************
1584 **************************************************************************/
1585 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1586 struct MUIP_AskMinMax
*msg
)
1588 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1590 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1592 CalcWidths(cl
, obj
);
1594 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1596 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1597 msg
->MinMaxInfo
->DefWidth
= msg
->MinMaxInfo
->MinWidth
;
1598 msg
->MinMaxInfo
->MaxWidth
= msg
->MinMaxInfo
->MinWidth
;
1602 msg
->MinMaxInfo
->MinWidth
+= 40;
1603 msg
->MinMaxInfo
->DefWidth
+= 100;
1604 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1607 if (data
->entries_num
> 0)
1609 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1611 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1612 msg
->MinMaxInfo
->DefHeight
= msg
->MinMaxInfo
->MinHeight
;
1613 msg
->MinMaxInfo
->MaxHeight
= msg
->MinMaxInfo
->MinHeight
;
1617 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1618 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1619 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1620 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1625 msg
->MinMaxInfo
->MinHeight
+= 36;
1626 msg
->MinMaxInfo
->DefHeight
+= 96;
1627 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1629 D(bug("List %p minheight=%d, line maxh=%d\n",
1630 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1635 /****i* List.mui/MUIM_Layout *************************************************
1640 ******************************************************************************
1644 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1645 struct MUIP_Layout
*msg
)
1647 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1648 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1649 LONG new_entries_first
= data
->entries_first
;
1651 /* Calc the numbers of entries visible */
1652 CalcVertVisible(cl
, obj
);
1654 /* Ensure active entry is visible if requested */
1655 if (data
->entries_active
+ 1 >=
1656 (data
->entries_first
+ data
->entries_visible
)
1657 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1659 data
->entries_active
- data
->entries_visible
+ 1;
1661 /* Ensure there are no unnecessary empty lines */
1662 if ((new_entries_first
+ data
->entries_visible
>=
1664 && (data
->entries_visible
<= data
->entries_num
))
1665 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1667 /* Always show the start of the list if it isn't long enough to fill the
1669 if (data
->entries_num
<= data
->entries_visible
)
1670 new_entries_first
= 0;
1672 if (new_entries_first
< 0)
1673 new_entries_first
= 0;
1675 set(obj
, new_entries_first
!= data
->entries_first
?
1676 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1678 /* So the notify happens */
1679 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1685 /**************************************************************************
1687 **************************************************************************/
1688 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1689 struct MUIP_Show
*msg
)
1691 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1692 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1694 zune_imspec_show(data
->list_cursor
, obj
);
1695 zune_imspec_show(data
->list_select
, obj
);
1696 zune_imspec_show(data
->list_selcur
, obj
);
1701 /**************************************************************************
1703 **************************************************************************/
1704 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1705 struct MUIP_Hide
*msg
)
1707 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1709 zune_imspec_hide(data
->list_cursor
);
1710 zune_imspec_hide(data
->list_select
);
1711 zune_imspec_hide(data
->list_selcur
);
1713 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1717 /**************************************************************************
1718 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1720 **************************************************************************/
1721 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1724 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1727 /* To be sure we don't draw anything if there is no title */
1728 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1731 DisplayEntry(cl
, obj
, entry_pos
);
1732 x1
= _mleft(data
->area
);
1734 for (col
= 0; col
< data
->columns
; col
++)
1737 x2
= x1
+ data
->ci
[col
].entries_width
;
1740 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1741 ZTEXT_ARG_NONE
, 0)))
1743 /* Could be made simpler, as we don't really need the bounds */
1744 zune_text_get_bounds(text
, obj
);
1745 /* Note, this was MPEN_SHADOW before */
1746 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1747 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1748 zune_text_destroy(text
);
1750 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1754 /**************************************************************************
1756 **************************************************************************/
1757 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1759 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1763 BOOL scroll_caused_damage
= FALSE
;
1764 struct MUI_ImageSpec_intern
*highlight
;
1767 if (data
->flags
& LIST_QUIET
)
1770 ret
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1772 if (data
->area_replaced
)
1775 /* Calculate the title height */
1778 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1782 data
->title_height
= 0;
1785 /* Calc the numbers of entries visible */
1786 CalcVertVisible(cl
, obj
);
1788 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1790 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
1791 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
),
1792 0, data
->entries_first
* data
->entry_maxheight
, 0);
1795 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(data
->area
),
1796 _mtop(data
->area
), _mwidth(data
->area
), _mheight(data
->area
));
1798 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1800 y
= _mtop(data
->area
);
1803 if (data
->title_height
&& data
->title
)
1805 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1806 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1807 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1808 Move(_rp(obj
), _mleft(data
->area
), y
);
1809 Draw(_rp(obj
), _mright(data
->area
), y
);
1810 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1812 Move(_rp(obj
), _mleft(data
->area
), y
);
1813 Draw(_rp(obj
), _mright(data
->area
), y
);
1817 y
= data
->entries_top_pixel
;
1819 start
= data
->entries_first
;
1820 end
= data
->entries_first
+ data
->entries_visible
;
1822 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1824 int diffy
= data
->entries_first
- data
->update_pos
;
1826 if (abs(diffy
) < data
->entries_visible
)
1828 scroll_caused_damage
=
1829 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1831 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1832 _mleft(data
->area
), y
,
1833 _mright(data
->area
),
1834 y
+ data
->entry_maxheight
* data
->entries_visible
);
1836 scroll_caused_damage
=
1837 scroll_caused_damage
1838 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1842 start
= end
- diffy
;
1843 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1847 end
= start
- diffy
;
1851 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1853 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), top
,
1854 _mwidth(data
->area
), bottom
- top
+ 1, 0,
1855 top
- _mtop(data
->area
) + data
->entries_first
1856 * data
->entry_maxheight
, 0);
1859 for (entry_pos
= start
;
1860 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1862 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1864 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1865 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1866 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1867 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1868 && data
->update_pos
== entry_pos
))
1870 /* Choose appropriate highlight image */
1872 if (entry_pos
== data
->entries_active
1873 && (entry
->flags
& ENTRY_SELECTED
) && !data
->read_only
)
1874 highlight
= data
->list_selcur
;
1875 else if (entry_pos
== data
->entries_active
&& !data
->read_only
)
1876 highlight
= data
->list_cursor
;
1877 else if (entry
->flags
& ENTRY_SELECTED
)
1878 highlight
= data
->list_select
;
1882 /* Draw highlight or background */
1884 if (highlight
!= NULL
)
1886 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1887 _mleft(data
->area
), y
, _mwidth(data
->area
),
1888 data
->entry_maxheight
,
1889 0, y
- data
->entries_top_pixel
, 0);
1891 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1892 && data
->update_pos
== entry_pos
)
1894 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), y
,
1895 _mwidth(data
->area
), data
->entry_maxheight
, 0,
1896 y
- _mtop(data
->area
) +
1897 data
->entries_first
* data
->entry_maxheight
, 0);
1900 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1902 y
+= data
->entry_maxheight
;
1905 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1909 if (scroll_caused_damage
)
1911 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1913 /* Theoretically it might happen that more damage is caused
1914 after ScrollRaster. By something else, like window movement
1915 in front of our window. Therefore refresh root object of
1916 window, not just this object */
1920 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1921 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1923 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1927 ULONG x1
= _mleft(data
->area
);
1929 y
= _mtop(data
->area
);
1931 if (data
->title_height
&& data
->title
)
1933 for (col
= 0; col
< data
->columns
; col
++)
1935 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1936 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1938 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1941 if (data
->ci
[col
].bar
)
1943 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1944 Move(_rp(obj
), x1
, y
);
1946 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1947 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1948 Move(_rp(obj
), x1
+ 1, y
);
1949 Draw(_rp(obj
), x1
+ 1,
1950 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1954 x1
+= data
->ci
[col
].delta
- halfdelta
;
1956 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1959 x1
= _mleft(data
->area
);
1961 for (col
= 0; col
< data
->columns
; col
++)
1963 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1964 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1966 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1969 if (data
->ci
[col
].bar
)
1971 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1972 Move(_rp(obj
), x1
, y
);
1973 Draw(_rp(obj
), x1
, _mbottom(data
->area
));
1974 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1975 Move(_rp(obj
), x1
+ 1, y
);
1976 Draw(_rp(obj
), x1
+ 1, _mbottom(data
->area
));
1981 x1
+= data
->ci
[col
].delta
- halfdelta
;
1987 /****** List.mui/MUIM_List_Clear *********************************************
1990 * MUIM_List_Clear (V4)
1993 * DoMethod(obj, MUIM_List_Clear);
1996 * Removes all entries from the list.
1998 ******************************************************************************
2002 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
2003 struct MUIP_List_Clear
*msg
)
2005 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2007 while (data
->confirm_entries_num
)
2009 struct ListEntry
*lentry
=
2010 data
->entries
[--data
->confirm_entries_num
];
2011 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2013 FreeListEntry(data
, lentry
);
2015 /* Should never fail when shrinking */
2016 SetListSize(data
, 0);
2018 if (data
->confirm_entries_num
!= data
->entries_num
)
2020 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
2021 /* Notify only when no entry was active */
2022 data
->entries_active
!=
2023 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
2024 MUIV_List_Active_Off
, TAG_DONE
);
2027 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2033 /****** List.mui/MUIM_List_Exchange ******************************************
2036 * MUIM_List_Exchange (V4)
2039 * DoMethod(obj, MUIM_List_Exchange, LONG pos1, LONG pos2);
2042 * Exchange two entries' positions.
2045 * pos1 - the current index of the first entry that should be moved, or
2046 * one of these special values:
2047 * MUIV_List_Exchange_Active: the active entry.
2048 * MUIV_List_Exchange_Top: the first entry.
2049 * MUIV_List_Exchange_Bottom: the last entry.
2050 * pos2 - the index of the entry that the first entry should be exchanged
2051 * with, or one of these special values:
2052 * MUIV_List_Exchange_Active: the active entry.
2053 * MUIV_List_Exchange_Top: the first entry.
2054 * MUIV_List_Exchange_Bottom: the last entry.
2055 * MUIV_List_Exchange_Next: the next entry after pos1.
2056 * MUIV_List_Exchange_Previous: the previous entry before pos1.
2059 * This method will do nothing if either index is greater than the last
2060 * index in the list, or if MUIV_List_Exchange_Next or
2061 * MUIV_List_Exchange_Previous imply an index outside the list.
2066 ******************************************************************************
2070 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
2071 struct MUIP_List_Exchange
*msg
)
2073 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2078 case MUIV_List_Exchange_Top
:
2081 case MUIV_List_Exchange_Active
:
2082 pos1
= data
->entries_active
;
2084 case MUIV_List_Exchange_Bottom
:
2085 pos1
= data
->entries_num
- 1;
2093 case MUIV_List_Exchange_Top
:
2096 case MUIV_List_Exchange_Active
:
2097 pos2
= data
->entries_active
;
2099 case MUIV_List_Exchange_Bottom
:
2100 pos2
= data
->entries_num
- 1;
2102 case MUIV_List_Exchange_Next
:
2105 case MUIV_List_Exchange_Previous
:
2112 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
2113 && pos2
< data
->entries_num
&& pos1
!= pos2
)
2115 struct ListEntry
*save
= data
->entries
[pos1
];
2116 data
->entries
[pos1
] = data
->entries
[pos2
];
2117 data
->entries
[pos2
] = save
;
2120 data
->update_pos
= pos1
;
2121 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2124 data
->update_pos
= pos2
;
2125 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2135 /**************************************************************************
2137 **************************************************************************/
2138 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
2139 struct MUIP_List_Redraw
*msg
)
2141 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2143 if (!(data
->flags
& LIST_QUIET
))
2145 if (msg
->pos
== MUIV_List_Redraw_All
)
2148 CalcWidths(cl
, obj
);
2149 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2154 if (msg
->pos
== MUIV_List_Redraw_Active
)
2155 pos
= data
->entries_active
;
2156 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
2159 for (i
= 0; i
< data
->entries_num
; i
++)
2160 if (data
->entries
[i
]->data
== msg
->entry
)
2171 if (CalcDimsOfEntry(cl
, obj
, pos
))
2176 data
->update_pos
= pos
;
2178 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2185 /****** List.mui/MUIM_List_Remove ********************************************
2188 * MUIM_List_Remove (V4)
2191 * DoMethod(obj, MUIM_List_Remove, LONG pos);
2194 * Removes entries from the list. If a destruct hook has been
2195 * installed, it will be called for the removed entry.
2198 * pos - the index of the entry to be removed. The following
2199 * special values can also be used:
2200 * MUIV_List_Remove_First: remove the first entry.
2201 * MUIV_List_Remove_Last: remove the last entry.
2202 * MUIV_List_Remove_Active: remove the active entry.
2203 * MUIV_List_Remove_Selected: remove all selected entries
2204 * (or the active entry if there are no selected entries).
2207 * When the active entry is removed, the next entry becomes active
2208 * (if there is no entry below the active entry, the previous entry
2209 * becomes active instead).
2212 * MUIM_List_Insertsingle, MUIM_List_Insert, MUIA_List_DestructHook.
2214 ******************************************************************************
2216 * It was not possible to use MUIM_List_NextSelected here because that method
2217 * may skip entries if entries are removed during an iteration.
2221 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
2222 struct MUIP_List_Remove
*msg
)
2224 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2228 BOOL found
, done
= FALSE
;
2229 struct ListEntry
*lentry
;
2230 Tag active_tag
= TAG_DONE
;
2232 if (!data
->entries_num
)
2237 case MUIV_List_Remove_First
:
2241 case MUIV_List_Remove_Active
:
2242 pos
= data
->entries_active
;
2245 case MUIV_List_Remove_Last
:
2246 pos
= data
->entries_num
- 1;
2249 case MUIV_List_Remove_Selected
:
2258 if (pos
< 0 || pos
>= data
->entries_num
)
2261 new_act
= data
->entries_active
;
2265 if (msg
->pos
== MUIV_List_Remove_Selected
)
2267 /* Find the next selected entry */
2268 for (found
= FALSE
, i
= pos
;
2269 i
< data
->confirm_entries_num
&& !found
; i
++)
2271 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2282 /* If there were no selected entries, remove the active one */
2283 if (data
->confirm_entries_num
== data
->entries_num
2284 && data
->entries_active
!= MUIV_List_Active_Off
)
2286 pos
= data
->entries_active
;
2299 lentry
= data
->entries
[pos
];
2300 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2302 RemoveListEntries(data
, pos
, 1);
2303 data
->confirm_entries_num
--;
2308 active_tag
= MUIA_List_Active
;
2310 else if (pos
== new_act
)
2311 active_tag
= MUIA_List_Active
;
2315 /* Update entries count prior to range check */
2316 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
, TAG_DONE
);
2318 /* Ensure that the active element is in a valid range (it might become
2319 * MUIV_List_Active_Off (-1), but that's OK) */
2320 if (new_act
>= data
->entries_num
)
2321 new_act
= data
->entries_num
- 1;
2324 active_tag
, new_act
, /* Inform only if necessary (for notify) */
2328 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2333 /**************************************************************************
2335 **************************************************************************/
2336 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2337 struct MUIP_List_Select
*msg
)
2339 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2340 LONG pos
, i
, count
, selcount
=0, state
=0;
2341 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
2343 /* Establish the range of entries affected */
2346 case MUIV_List_Select_Active
:
2347 pos
= data
->entries_active
;
2348 if (pos
== MUIV_List_Active_Off
)
2354 case MUIV_List_Select_All
:
2356 count
= data
->entries_num
;
2362 if (pos
< 0 || pos
>= data
->entries_num
)
2367 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2369 /* Disallow selection of an additional entry if there is a currently
2370 selected entry that is not multi-selectable (in such case there
2371 will only be one entry currently selected, so no need to iterate) */
2372 i
= MUIV_List_NextSelected_Start
;
2373 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
2374 if (i
!= MUIV_List_NextSelected_End
)
2376 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
2377 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2378 data
->entries
[i
]->data
);
2381 /* Change or check state of each entry in the range */
2382 for (i
= pos
; i
< pos
+ count
; i
++)
2384 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2385 switch (msg
->seltype
)
2387 case MUIV_List_Select_Off
:
2388 new_select_state
= FALSE
;
2391 case MUIV_List_Select_On
:
2392 new_select_state
= TRUE
;
2395 case MUIV_List_Select_Toggle
:
2396 new_select_state
= !state
;
2400 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2405 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2407 /* Disallow selection if entry is not multi-selectable and
2408 * there are already selected entries */
2409 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
2410 new_select_state
= multi_allowed
&& (selcount
== 0 ||
2411 CallHookPkt(data
->multi_test_hook
, NULL
,
2412 data
->entries
[i
]->data
));
2414 if (new_select_state
)
2415 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2417 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2421 /* Report old state or number of selected entries */
2424 if (msg
->pos
== MUIV_List_Select_All
2425 && msg
->seltype
== MUIV_List_Select_Ask
)
2426 *msg
->info
= selcount
;
2431 /* Redraw unless it was just an enquiry */
2432 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2439 data
->update_pos
= pos
;
2441 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2447 /****** List.mui/MUIM_List_Insert ********************************************
2450 * MUIM_List_Insert (V4)
2453 * DoMethod(obj, MUIM_List_Insert, APTR *entries, LONG count, LONG pos);
2456 * Adds multiple entries to the list. If a construct hook has been
2457 * installed, the results of passing the entries to this hook will be
2461 * entries - an array of entries to be inserted.
2462 * count - the number of entries to insert. A special value of -1 may be
2463 * used, indicating that the array of entries is NULL-terminated.
2464 * pos - the index at which to insert the new entries. The following
2465 * special values can also be used:
2466 * MUIV_List_Insert_Top: insert at index 0.
2467 * MUIV_List_Insert_Bottom: insert after all existing entries.
2468 * MUIV_List_Insert_Active: insert at the index of the active entry
2469 * (or at index 0 if there is no active entry).
2470 * MUIV_List_Insert_Sorted: keep the list sorted.
2473 * MUIM_List_Insertsingle, MUIM_List_Remove, MUIA_List_ConstructHook.
2475 ******************************************************************************
2479 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2480 struct MUIP_List_Insert
*msg
)
2482 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2483 LONG pos
, count
, sort
, active
;
2490 /* Count the number of entries */
2491 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2500 case MUIV_List_Insert_Top
:
2504 case MUIV_List_Insert_Active
:
2505 if (data
->entries_active
!= -1)
2506 pos
= data
->entries_active
;
2511 case MUIV_List_Insert_Sorted
:
2512 pos
= data
->entries_num
;
2513 sort
= 1; /* we sort'em later */
2516 case MUIV_List_Insert_Bottom
:
2517 pos
= data
->entries_num
;
2521 if (msg
->pos
> data
->entries_num
)
2522 pos
= data
->entries_num
;
2523 else if (msg
->pos
< 0)
2529 data
->insert_position
= pos
;
2531 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2534 LONG until
= pos
+ count
;
2535 APTR
*toinsert
= msg
->entries
;
2537 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2542 struct ListEntry
*lentry
;
2544 if (!(lentry
= AllocListEntry(data
)))
2546 /* Panic, but we must be in a consistent state, so remove
2547 * the space where the following list entries should have gone
2549 RemoveListEntries(data
, pos
, until
- pos
);
2553 /* now call the construct method which returns us a pointer which
2555 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2556 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2559 FreeListEntry(data
, lentry
);
2560 RemoveListEntries(data
, pos
, until
- pos
);
2562 /* TODO: Also check for visible stuff like below */
2563 if (data
->entries_num
!= data
->confirm_entries_num
)
2564 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2568 data
->entries
[pos
] = lentry
;
2569 data
->confirm_entries_num
++;
2571 if (_flags(obj
) & MADF_SETUP
)
2573 /* We have to calculate the width and height of the newly
2574 * inserted entry. This has to be done after inserting the
2575 * element into the list */
2576 CalcDimsOfEntry(cl
, obj
, pos
);
2584 /* Recalculate the number of visible entries */
2585 if (_flags(obj
) & MADF_SETUP
)
2586 CalcVertVisible(cl
, obj
);
2588 if (data
->entries_num
!= data
->confirm_entries_num
)
2591 MUIA_List_Entries
, data
->confirm_entries_num
,
2592 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2595 /* If the array is already sorted, we could do a simple insert
2596 * sort and would be much faster than with qsort.
2597 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2598 * sort the whole array?
2600 * I think, we better sort the whole array:
2604 DoMethod(obj
, MUIM_List_Sort
);
2605 /* TODO: which pos to return here !? */
2606 /* MUIM_List_Sort already called MUI_Redraw */
2611 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2613 superset(cl
, obj
, MUIA_List_InsertPosition
, data
->insert_position
);
2615 /* Update index of active entry */
2616 if (data
->entries_active
>= data
->insert_position
)
2618 active
= data
->entries_active
+ count
;
2619 SET(obj
, MUIA_List_Active
, active
);
2625 /****** List.mui/MUIM_List_InsertSingle **************************************
2628 * MUIM_List_InsertSingle (V7)
2631 * DoMethod(obj, MUIM_List_InsertSingle, APTR entry, LONG pos);
2634 * Adds a single entry to the list. If a construct hook has been
2635 * installed, the result of passing the entry to this hook will be
2639 * entry - the entry to be inserted.
2640 * pos - the index at which to insert the new entry. The following
2641 * special values can also be used:
2642 * MUIV_List_Insert_Top: insert at index 0.
2643 * MUIV_List_Insert_Bottom: insert after all existing entries.
2644 * MUIV_List_Insert_Active: insert at the index of the active entry
2645 * (or at index 0 if there is no active entry).
2646 * MUIV_List_Insert_Sorted: keep the list sorted.
2649 * MUIM_List_Insert, MUIM_List_Remove, MUIA_List_ConstructHook.
2651 ******************************************************************************
2655 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2656 struct MUIP_List_InsertSingle
*msg
)
2658 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2662 /**************************************************************************
2664 **************************************************************************/
2665 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2666 struct MUIP_List_GetEntry
*msg
)
2668 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2671 if (pos
== MUIV_List_GetEntry_Active
)
2672 pos
= data
->entries_active
;
2674 if (pos
< 0 || pos
>= data
->entries_num
)
2679 *msg
->entry
= data
->entries
[pos
]->data
;
2680 return (IPTR
) *msg
->entry
;
2683 /**************************************************************************
2685 **************************************************************************/
2686 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2687 struct MUIP_List_Construct
*msg
)
2689 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2691 if (NULL
== data
->construct_hook
)
2692 return (IPTR
) msg
->entry
;
2693 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2695 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2696 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2701 if (msg
->entry
!= NULL
)
2702 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2704 *(STRPTR
) (mem
+ 1) = 0;
2705 return (IPTR
) (mem
+ 1);
2707 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2710 /**************************************************************************
2712 **************************************************************************/
2713 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2714 struct MUIP_List_Destruct
*msg
)
2716 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2718 if (NULL
== data
->destruct_hook
)
2721 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2723 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2724 FreePooled(msg
->pool
, mem
, mem
[0]);
2728 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2733 /****** List.mui/MUIM_List_Compare *******************************************
2736 * MUIM_List_Compare (V20)
2739 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2740 * LONG sort_type1, LONG sort_type2);
2743 * Compare two list entries according to the current comparison hook
2744 * (MUIA_List_CompareHook).
2747 * entry1 - the first entry data.
2748 * entry2 - the second entry data.
2749 * sort_type1 - undocumented.
2750 * sort_type2 - undocumented.
2753 * MUIA_List_CompareHook, MUIM_List_Sort.
2755 ******************************************************************************
2759 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2760 struct MUIP_List_Compare
*msg
)
2762 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2764 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2767 /**************************************************************************
2769 **************************************************************************/
2770 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2771 struct MUIP_List_Display
*msg
)
2773 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2775 if (NULL
== data
->display_hook
)
2778 *msg
->array
= msg
->entry
;
2784 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2785 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2788 /**************************************************************************
2789 MUIM_List_SelectChange
2790 **************************************************************************/
2791 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2792 struct MUIP_List_SelectChange
*msg
)
2797 /**************************************************************************
2798 MUIM_List_CreateImage
2799 Called by a List subclass in its Setup method.
2800 Connects an Area subclass object to the list, much like an object gets
2801 connected to a window. List calls Setup and AskMinMax on that object,
2802 keeps a reference to it (that reference will be returned).
2803 Text engine will dereference that pointer and draw the object with its
2805 **************************************************************************/
2806 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2807 struct MUIP_List_CreateImage
*msg
)
2809 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2810 struct ListImage
*li
;
2815 /* List must be already setup in Setup of your subclass */
2816 if (!(_flags(obj
) & MADF_SETUP
))
2818 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2823 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2824 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2825 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2831 /**************************************************************************
2832 MUIM_List_DeleteImage
2833 **************************************************************************/
2834 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2835 struct MUIP_List_DeleteImage
*msg
)
2837 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2838 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2842 DoMethod(li
->obj
, MUIM_Cleanup
);
2843 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2844 Remove((struct Node
*)li
);
2845 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2851 /****** List.mui/MUIM_List_Jump **********************************************
2854 * MUIM_List_Jump (V4)
2857 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2860 * Scrolls the list so that a particular entry is visible.
2863 * pos - index of entry that should become visible, or one of these
2865 * MUIV_List_Jump_Active: show the active entry.
2866 * MUIV_List_Jump_Top: show the first entry.
2867 * MUIV_List_Jump_Bottom: show the last entry.
2868 * MUIV_List_Jump_Up: show the previous hidden entry.
2869 * MUIV_List_Jump_Down: show the next hidden entry.
2871 ******************************************************************************
2875 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2876 struct MUIP_List_Jump
*msg
)
2878 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2879 LONG pos
= msg
->pos
;
2883 case MUIV_List_Jump_Top
:
2887 case MUIV_List_Jump_Active
:
2888 pos
= data
->entries_active
;
2891 case MUIV_List_Jump_Bottom
:
2892 pos
= data
->entries_num
- 1;
2895 case MUIV_List_Jump_Down
:
2896 pos
= data
->entries_first
+ data
->entries_visible
;
2899 case MUIV_List_Jump_Up
:
2900 pos
= data
->entries_first
- 1;
2904 if (pos
>= data
->entries_num
)
2906 pos
= data
->entries_num
- 1;
2911 if (pos
< data
->entries_first
)
2913 set(obj
, MUIA_List_First
, pos
);
2915 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2917 pos
-= (data
->entries_visible
- 1);
2920 if (pos
!= data
->entries_first
)
2922 set(obj
, MUIA_List_First
, pos
);
2929 /****** List.mui/MUIM_List_Sort **********************************************
2932 * MUIM_List_Sort (V4)
2935 * DoMethod(obj, MUIM_List_Sort);
2938 * Sort the list's entries according to the current comparison hook
2939 * (MUIA_List_CompareHook).
2942 * The active index does not change, so the active entry may do so.
2945 * MUIA_List_CompareHook, MUIM_List_Compare.
2947 ******************************************************************************
2951 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2952 struct MUIP_List_Sort
*msg
)
2954 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2957 struct MUIP_List_Compare cmpmsg
=
2958 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2960 if (data
->entries_num
> 1)
2963 Simple sort algorithm. Feel free to improve it.
2965 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2968 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2970 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2971 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2972 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2979 APTR tmp
= data
->entries
[i
];
2980 data
->entries
[i
] = data
->entries
[max
];
2981 data
->entries
[max
] = tmp
;
2987 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2992 /****** List.mui/MUIM_List_Move **********************************************
2995 * MUIM_List_Move (V9)
2998 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
3001 * Move a list entry to a new position.
3004 * from - the current index of the entry that should be moved, or one of
3005 * these special values:
3006 * MUIV_List_Move_Active: the active entry.
3007 * MUIV_List_Move_Top: the first entry.
3008 * MUIV_List_Move_Bottom: the last entry.
3009 * to - the index of the entry's new position, or one of
3010 * these special values:
3011 * MUIV_List_Move_Active: the active entry.
3012 * MUIV_List_Move_Top: the first entry.
3013 * MUIV_List_Move_Bottom: the last entry.
3016 * The active index does not change, so the active entry may do so.
3019 * MUIM_List_Exchange
3021 ******************************************************************************
3025 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
3026 struct MUIP_List_Move
*msg
)
3028 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3033 /* Normalise special 'from' values */
3036 case MUIV_List_Move_Top
:
3039 case MUIV_List_Move_Active
:
3040 from
= data
->entries_active
;
3042 case MUIV_List_Move_Bottom
:
3043 from
= data
->entries_num
- 1;
3049 /* Normalise special 'to' values */
3052 case MUIV_List_Move_Top
:
3055 case MUIV_List_Move_Active
:
3056 to
= data
->entries_active
;
3058 case MUIV_List_Move_Bottom
:
3059 to
= data
->entries_num
- 1;
3061 case MUIV_List_Move_Next
:
3064 case MUIV_List_Move_Previous
:
3071 /* Check that values are within valid bounds */
3072 if (from
> data
->entries_num
- 1 || from
< 0
3073 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
3074 return (IPTR
) FALSE
;
3076 /* Shift all entries in the range between the 'from' and 'to' positions */
3079 struct ListEntry
*backup
= data
->entries
[from
];
3080 for (i
= from
; i
< to
; i
++)
3081 data
->entries
[i
] = data
->entries
[i
+ 1];
3082 data
->entries
[to
] = backup
;
3086 struct ListEntry
*backup
= data
->entries
[from
];
3087 for (i
= from
; i
> to
; i
--)
3088 data
->entries
[i
] = data
->entries
[i
- 1];
3089 data
->entries
[to
] = backup
;
3092 #if 0 /* Not done in MUI 3 */
3093 /* Update index of active entry */
3094 if (from
== data
->entries_active
)
3095 data
->entries_active
= to
;
3096 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
3097 data
->entries_active
--;
3098 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
3099 data
->entries_active
++;
3102 /* Reflect list changes visually */
3104 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
3109 /****** List.mui/MUIM_List_NextSelected **************************************
3112 * MUIM_List_NextSelected (V6)
3115 * DoMethod(obj, MUIM_List_NextSelected, LONG *pos);
3118 * Allows iteration through a list's selected entries by providing the
3119 * index of the next selected entry after the specified index.
3122 * pos - the address of a variable containing the index of the previous
3123 * selected entry. The variable must be initialised to the special
3124 * value MUIV_List_NextSelected_Start to find the first selected
3125 * entry. When this method returns, the variable will contain the
3126 * index of the next selected entry, or MUIV_List_NextSelected_End if
3127 * there are no more.
3130 * If there are no selected entries but there is an active entry, the
3131 * index of the active entry will be stored (when
3132 * MUIV_List_NextSelected_Start is specified).
3134 * Some selected entries may be skipped if any entries are removed
3135 * between calls to this method during an iteration of a list.
3137 * MUIV_List_NextSelected_Start and MUIV_List_NextSelected_End may have
3138 * the same numeric value.
3141 * MUIM_List_Select, MUIM_List_Remove.
3143 ******************************************************************************
3147 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
3148 struct MUIP_List_NextSelected
*msg
)
3150 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3154 /* Get the first entry to check */
3156 if (pos
== MUIV_List_NextSelected_Start
)
3161 /* Find the next selected entry */
3162 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
3164 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
3171 /* Return index of selected or active entry, or indicate there are no
3175 if (*msg
->pos
== MUIV_List_NextSelected_Start
3176 && data
->entries_active
!= MUIV_List_Active_Off
)
3177 pos
= data
->entries_active
;
3179 pos
= MUIV_List_NextSelected_End
;
3186 /**************************************************************************
3188 **************************************************************************/
3189 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
3190 struct MUIP_List_TestPos
*msg
)
3192 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3193 struct MUI_List_TestPos_Result
*result
= msg
->res
;
3194 LONG col
= -1, row
= -1;
3196 LONG mx
= msg
->x
- _left(data
->area
);
3197 LONG entries_visible
;
3199 if (data
->entries_visible
<= data
->entries_num
)
3200 entries_visible
= data
->entries_visible
;
3202 entries_visible
= data
->entries_num
;
3203 LONG ey
= msg
->y
- data
->entries_top_pixel
;
3204 /* y coordinates transformed to the entries */
3206 /* Now check if it was clicked on a title or on entries */
3208 flags
|= MUI_LPR_ABOVE
;
3209 else if (ey
>= entries_visible
* data
->entry_maxheight
)
3210 flags
|= MUI_LPR_BELOW
;
3214 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
3216 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
3220 flags
|= MUI_LPR_LEFT
;
3221 else if (mx
>= _width(data
->area
))
3222 flags
|= MUI_LPR_RIGHT
;
3225 /* Identify column */
3226 if (data
->entries_num
> 0 && data
->columns
> 0)
3229 col
= data
->columns
- 1;
3230 for (i
= 0; i
< data
->columns
; i
++)
3232 result
->xoffset
= mx
- width_sum
;
3234 data
->ci
[i
].entries_width
+
3236 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
3237 D(bug("[List/MUIM_TestPos] i %d "
3238 "width %d width_sum %d mx %d\n",
3239 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
3243 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
3250 result
->entry
= row
;
3251 result
->column
= col
;
3252 result
->flags
= flags
;
3257 /****i* List.mui/MUIM_DragQuery **********************************************
3262 ******************************************************************************
3266 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
3267 struct MUIP_DragQuery
*msg
)
3269 if (msg
->obj
== obj
)
3270 return MUIV_DragQuery_Accept
;
3272 return MUIV_DragQuery_Refuse
;
3276 /****i* List.mui/MUIM_DragFinish *********************************************
3281 ******************************************************************************
3285 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
3286 struct MUIP_DragFinish
*msg
)
3288 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3290 data
->drop_mark_y
= -1;
3292 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
3295 /****i* List.mui/MUIM_DragReport *********************************************
3300 ******************************************************************************
3304 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
3305 struct MUIP_DragReport
*msg
)
3307 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3308 struct MUI_List_TestPos_Result pos
;
3309 struct RastPort
*rp
= _rp(obj
);
3313 /* Choose new drop mark position */
3315 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3316 if (pos
.entry
!= -1)
3319 if (pos
.yoffset
> 0)
3322 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3323 n
= data
->entries_first
;
3326 n
= MIN(data
->entries_visible
, data
->entries_num
)
3327 - data
->entries_first
;
3330 /* Clear old drop mark */
3332 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
3334 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
3335 * data
->entry_maxheight
;
3336 if (y
!= data
->drop_mark_y
)
3338 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
),
3339 data
->drop_mark_y
, _mwidth(data
->area
), 1, 0, 0, 0);
3341 /* Draw new drop mark and store its position */
3343 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
3345 old_pattern
= rp
->LinePtrn
;
3346 SetDrPt(rp
, 0xF0F0);
3347 Move(rp
, _mleft(data
->area
), y
);
3348 Draw(rp
, _mright(data
->area
), y
);
3349 SetDrPt(rp
, old_pattern
);
3350 data
->drop_mark_y
= y
;
3358 /****i* List.mui/MUIM_DragDrop ***********************************************
3363 ******************************************************************************
3367 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
3368 struct MUIP_DragDrop
*msg
)
3370 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3371 struct MUI_List_TestPos_Result pos
;
3374 /* Find drop position */
3376 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3377 if (pos
.entry
!= -1)
3379 /* Change drop position when coords move past centre of entry, not
3383 if (pos
.yoffset
> 0)
3386 /* Ensure that dropped entry will be positioned between the two
3387 * entries that are above and below the drop mark, rather than
3388 * strictly at the numeric index shown */
3390 if (n
> data
->entries_active
)
3393 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3394 n
= MUIV_List_Move_Top
;
3396 n
= MUIV_List_Move_Bottom
;
3398 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
3404 /****i* List.mui/MUIM_CreateDragImage ****************************************
3407 * MUIM_CreateDragImage
3409 ******************************************************************************
3413 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
3414 struct MUIP_CreateDragImage
*msg
)
3416 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3417 BOOL success
= TRUE
;
3418 struct MUI_List_TestPos_Result pos
;
3419 WORD width
, height
, left
, top
;
3420 struct MUI_DragImage
*img
= NULL
;
3421 const struct ZuneFrameGfx
*zframe
;
3424 /* Get info on dragged entry */
3425 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
3426 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
3427 if (pos
.entry
== -1)
3432 /* Get boundaries of entry */
3433 width
= _mwidth(data
->area
);
3434 height
= data
->entry_maxheight
;
3435 left
= _mleft(data
->area
);
3436 top
= _top(data
->area
) - msg
->touchy
3437 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3439 /* Allocate drag image structure */
3440 img
= (struct MUI_DragImage
*)
3441 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3448 /* Get drag frame */
3449 zframe
= zune_zframe_get(obj
,
3450 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3452 /* Allocate drag image buffer */
3453 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3454 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3455 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3456 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3457 _screen(obj
)->RastPort
.BitMap
);
3459 if (img
->bm
!= NULL
)
3462 struct RastPort temprp
;
3463 InitRastPort(&temprp
);
3464 temprp
.BitMap
= img
->bm
;
3465 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3466 zframe
->ileft
, zframe
->itop
, width
, height
,
3470 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3471 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3472 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3473 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3474 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3477 /* Ensure drag point matches where user clicked */
3478 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3479 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3487 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3489 LONG
new, first
, entries
, visible
;
3491 new = first
= XGET(obj
, MUIA_List_First
);
3492 entries
= XGET(obj
, MUIA_List_Entries
);
3493 visible
= XGET(obj
, MUIA_List_Visible
);
3497 if (new > entries
- visible
)
3499 new = entries
- visible
;
3509 set(obj
, MUIA_List_First
, new);
3513 /**************************************************************************
3515 **************************************************************************/
3516 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
,
3517 struct MUIP_HandleEvent
*msg
)
3519 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3520 struct MUI_List_TestPos_Result pos
;
3521 LONG seltype
, old_active
, new_active
, visible
, first
, last
, i
;
3523 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3525 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3527 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3528 visible
= XGET(obj
, MUIA_List_Visible
);
3530 if (muikey
!= MUIKEY_NONE
)
3532 result
= MUI_EventHandlerRC_Eat
;
3534 /* Make keys behave differently in read-only mode */
3535 if (data
->read_only
)
3540 muikey
= MUIKEY_LINESTART
;
3544 muikey
= MUIKEY_LINEEND
;
3548 muikey
= MUIKEY_LEFT
;
3553 muikey
= MUIKEY_RIGHT
;
3561 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
3562 && !data
->read_only
)
3565 data
->click_column
= data
->def_click_column
;
3566 new_active
= MUIV_List_Active_Down
;
3570 DoMethod(obj
, MUIM_List_Jump
, 0);
3571 muikey
= MUIKEY_NONE
;
3576 new_active
= MUIV_List_Active_Top
;
3580 new_active
= MUIV_List_Active_Bottom
;
3584 case MUIKEY_WORDLEFT
:
3585 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
3589 case MUIKEY_WORDRIGHT
:
3590 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
3593 case MUIKEY_LINESTART
:
3594 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
3597 case MUIKEY_LINEEND
:
3598 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
3602 new_active
= MUIV_List_Active_Up
;
3606 new_active
= MUIV_List_Active_Down
;
3610 data
->click_column
= data
->def_click_column
;
3611 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3612 data
->click_column
);
3613 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3617 if (data
->read_only
)
3618 DoWheelMove(cl
, obj
, -visible
);
3620 new_active
= MUIV_List_Active_PageUp
;
3623 case MUIKEY_PAGEDOWN
:
3624 if (data
->read_only
)
3625 DoWheelMove(cl
, obj
, visible
);
3627 new_active
= MUIV_List_Active_PageDown
;
3636 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
,
3639 switch (msg
->imsg
->Class
)
3641 case IDCMP_MOUSEBUTTONS
:
3642 if (msg
->imsg
->Code
== SELECTDOWN
)
3644 if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3647 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
3649 if (!data
->read_only
&& pos
.entry
!= -1)
3651 new_active
= pos
.entry
;
3653 clear
= (data
->multiselect
3654 == MUIV_Listview_MultiSelect_Shifted
3655 && (msg
->imsg
->Qualifier
3656 & (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
3657 seltype
= clear
? MUIV_List_Select_On
3658 : MUIV_List_Select_Toggle
;
3659 select
= data
->multiselect
3660 != MUIV_Listview_MultiSelect_None
;
3662 /* Handle MUIA_Listview_ClickColumn */
3663 data
->click_column
= pos
.column
;
3664 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3665 data
->click_column
);
3667 /* Handle double clicking */
3668 if (data
->last_active
== pos
.entry
3669 && DoubleClick(data
->last_secs
, data
->last_mics
,
3670 msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
3672 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3673 data
->last_active
= -1;
3674 data
->last_secs
= data
->last_mics
= 0;
3678 data
->last_active
= pos
.entry
;
3679 data
->last_secs
= msg
->imsg
->Seconds
;
3680 data
->last_mics
= msg
->imsg
->Micros
;
3683 /* Look out for mouse movement, timer and
3684 inactive-window events while mouse button is
3686 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3688 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
3689 | IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
3690 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3697 /* Activate object */
3698 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
3700 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
3701 data
->mouse_click
= 0;
3704 /* Restore normal event mask */
3705 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3707 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
3708 | IDCMP_INACTIVEWINDOW
);
3709 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3714 case IDCMP_MOUSEMOVE
:
3715 case IDCMP_INTUITICKS
:
3716 if (pos
.flags
& MUI_LPR_ABOVE
)
3717 new_active
= MUIV_List_Active_Up
;
3718 else if (pos
.flags
& MUI_LPR_BELOW
)
3719 new_active
= MUIV_List_Active_Down
;
3721 new_active
= pos
.entry
;
3723 select
= new_active
!= old_active
3724 && data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3727 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3728 MUIV_List_Select_Ask
, &seltype
);
3729 range_select
= new_active
>= 0;
3734 case IDCMP_INACTIVEWINDOW
:
3735 /* Stop listening for events we only listen to when mouse button is
3736 down: we will not be informed of the button being released */
3737 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
,
3739 data
->ehn
.ehn_Events
&=
3740 ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3741 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
,
3747 if (data
->vert
&& _isinobject(data
->vert
, msg
->imsg
->MouseX
,
3750 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
,
3758 switch (msg
->imsg
->Code
)
3760 case RAWKEY_NM_WHEEL_UP
:
3761 DoWheelMove(cl
, obj
, -delta
);
3764 case RAWKEY_NM_WHEEL_DOWN
:
3765 DoWheelMove(cl
, obj
, delta
);
3768 result
= MUI_EventHandlerRC_Eat
;
3774 /* Decide in advance if any selections may change */
3775 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
3777 /* Change selected and active entries */
3779 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
3783 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
3784 MUIV_List_Select_Off
, NULL
);
3787 if (muikey
== MUIKEY_TOGGLE
)
3789 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3790 MUIV_List_Select_Toggle
, NULL
);
3794 if (new_active
!= old_active
)
3795 set(obj
, MUIA_List_Active
, new_active
);
3801 if (old_active
< new_active
)
3802 first
= old_active
+ 1, last
= new_active
;
3804 first
= new_active
, last
= old_active
- 1;
3805 for (i
= first
; i
<= last
; i
++)
3806 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
3809 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
,
3814 set(obj
, MUIA_Listview_SelectChange
, FALSE
);
3819 /**************************************************************************
3821 **************************************************************************/
3822 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3824 switch (msg
->MethodID
)
3827 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3829 return List__OM_DISPOSE(cl
, obj
, msg
);
3831 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3833 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3836 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3838 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3839 case MUIM_HandleEvent
:
3840 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
3841 case MUIM_AskMinMax
:
3842 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3844 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3846 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3848 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3850 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3851 case MUIM_List_Clear
:
3852 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3853 case MUIM_List_Sort
:
3854 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3855 case MUIM_List_Exchange
:
3856 return List__MUIM_Exchange(cl
, obj
,
3857 (struct MUIP_List_Exchange
*)msg
);
3858 case MUIM_List_Insert
:
3859 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3860 case MUIM_List_InsertSingle
:
3861 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3862 case MUIM_List_GetEntry
:
3863 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3864 case MUIM_List_Redraw
:
3865 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3866 case MUIM_List_Remove
:
3867 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3868 case MUIM_List_Select
:
3869 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3870 case MUIM_List_Construct
:
3871 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3872 case MUIM_List_Destruct
:
3873 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3874 case MUIM_List_Compare
:
3875 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3876 case MUIM_List_Display
:
3877 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3878 case MUIM_List_SelectChange
:
3879 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3880 case MUIM_List_CreateImage
:
3881 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3882 case MUIM_List_DeleteImage
:
3883 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3884 case MUIM_List_Jump
:
3885 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3886 case MUIM_List_Move
:
3887 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3888 case MUIM_List_NextSelected
:
3889 return List__MUIM_NextSelected(cl
, obj
,
3890 (struct MUIP_List_NextSelected
*)msg
);
3891 case MUIM_List_TestPos
:
3892 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3893 case MUIM_DragQuery
:
3894 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3895 case MUIM_DragFinish
:
3896 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3897 case MUIM_DragReport
:
3898 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3900 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3901 case MUIM_CreateDragImage
:
3902 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3905 return DoSuperMethodA(cl
, obj
, msg
);
3907 BOOPSI_DISPATCHER_END
3912 const struct __MUIBuiltinClass _MUI_List_desc
=
3916 sizeof(struct MUI_ListData
),
3917 (void *) List_Dispatcher