2 Copyright © 2002-2013, 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 <clib/alib_protos.h>
14 #include <proto/exec.h>
15 #include <proto/graphics.h>
16 #include <proto/utility.h>
17 #include <proto/dos.h>
18 #include <proto/intuition.h>
19 #include <proto/muimaster.h>
21 /* #define MYDEBUG 1 */
24 #include "muimaster_intern.h"
27 #include "textengine.h"
28 #include "listimage.h"
31 extern struct Library
*MUIMasterBase
;
33 #define ENTRY_TITLE (-1)
35 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
36 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
56 LONG
*widths
; /* Widths of the columns */
57 LONG width
; /* Line width */
58 LONG height
; /* Line height */
59 WORD flags
; /* see below */
62 #define ENTRY_SELECTED (1<<0)
67 int colno
; /* Column number */
68 int user_width
; /* user set width; -1 if entry width */
69 int min_width
; /* min width percentage */
70 int max_width
; /* min width percentage */
72 int delta
; /* ignored for the first and last column, defaults to 4 */
75 int entries_width
; /* width of the entries (maximum of all widths) */
78 struct MUI_ImageSpec_intern
;
85 APTR intern_pool
; /* The internal pool which the class has allocated */
86 LONG intern_puddle_size
;
87 LONG intern_thresh_size
;
88 APTR pool
; /* the pool which is used to allocate list entries */
90 struct Hook
*construct_hook
;
91 struct Hook
*compare_hook
;
92 struct Hook
*destruct_hook
;
93 struct Hook
*display_hook
;
94 struct Hook
*multi_test_hook
;
96 struct Hook default_compare_hook
;
98 /* List management, currently we use a simple flat array, which is not
99 * good if many entries are inserted/deleted */
100 LONG entries_num
; /* Number of Entries in the list */
101 LONG entries_allocated
;
102 struct ListEntry
**entries
;
104 LONG entries_first
; /* first visible entry */
105 LONG entries_visible
; /* number of visible entries,
106 * determined at MUIM_Layout */
108 LONG insert_position
; /* pos of the last insertion */
110 LONG entry_maxheight
; /* Maximum height of an entry */
111 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
113 LONG entries_totalheight
;
114 LONG entries_maxwidth
;
116 LONG vertprop_entries
;
117 LONG vertprop_visible
;
120 LONG confirm_entries_num
; /* These are the correct entries num, used
121 * so you cannot set MUIA_List_Entries to
124 LONG entries_top_pixel
; /* Where the entries start */
126 /* Column managment, is allocated by ParseListFormat() and freed
127 * by CleanListFormat() */
129 LONG columns
; /* Number of columns the list has */
130 struct ColumnInfo
*ci
;
132 STRPTR
*strings
; /* the strings for the display function, one
133 * more than needed (for the entry position) */
136 int title_height
; /* The complete height of the title */
137 STRPTR title
; /* On single comlums this is the title, otherwise 1 */
140 struct MUI_ImageSpec_intern
*list_cursor
;
141 struct MUI_ImageSpec_intern
*list_select
;
142 struct MUI_ImageSpec_intern
*list_selcur
;
144 /* Render optimization */
145 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
146 * 3 - scroll to current entries_first (old value is in
153 struct MinList images
;
156 ListviewRefresh prefs_refresh
;
157 UWORD prefs_linespacing
;
159 UWORD prefs_smoothval
;
162 #define LIST_ADJUSTWIDTH (1<<0)
163 #define LIST_ADJUSTHEIGHT (1<<1)
164 #define LIST_AUTOVISIBLE (1<<2)
165 #define LIST_DRAGSORTABLE (1<<3)
166 #define LIST_SHOWDROPMARKS (1<<4)
167 #define LIST_QUIET (1<<5)
170 /****** List.mui/MUIA_List_CompareHook ***************************************
173 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
176 * The provided hook indicates the sort ordering of two list entries.
177 * The hook receives list-entry data pointers as its second and third
178 * arguments. The hook should return a negative value if the first entry
179 * should be placed before the second entry, a positive value if the
180 * first entry should be placed after the second entry, and zero if the
183 * In addition to being used internally for sorting operations, this hook
184 * will be called when MUIM_List_Compare is externally invoked.
186 * If this attribute is not specified or is set to NULL, all list entries
189 ******************************************************************************
193 /****** List.mui/MUIA_List_MultiTestHook *************************************
196 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
199 * The provided hook indicates whether a particular list entry
200 * may be multiselected. The hook receives the list-entry data pointer as
201 * its third argument, and returns a Boolean value. If this attribute is
202 * not specified or is set to NULL, all list entries are considered
205 * Whenever an entry is about to be selected, this hook is called if
206 * there are other entries already selected. If the hook returns TRUE,
207 * the entry may be multi-selected; if the hook returns FALSE, the entry
208 * remains unselected.
210 * Additionally, if a non-multi-selectable entry has been selected (as
211 * the only selected entry in the list), any attempt to select an
212 * additional entry will fail.
214 ******************************************************************************
218 /**************************************************************************
219 Allocate a single list entry, does not initialize it (except the pointer)
220 **************************************************************************/
221 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
224 struct ListEntry
*le
;
225 int size
= sizeof(struct ListEntry
) + sizeof(LONG
) * data
->columns
+ 4;
229 mem
= AllocPooled(data
->pool
, size
);
232 D(bug("List AllocListEntry %p, %ld bytes\n", mem
, size
));
234 mem
[0] = size
; /* Save the size */
235 le
= (struct ListEntry
*)(mem
+ 1);
236 le
->widths
= (LONG
*) (le
+ 1);
238 /* Initialize fields */
242 for (j
= 0; j
< data
->columns
; j
++)
248 /**************************************************************************
249 Deallocate a single list entry, does not deinitialize it
250 **************************************************************************/
251 static void FreeListEntry(struct MUI_ListData
*data
,
252 struct ListEntry
*entry
)
254 ULONG
*mem
= ((ULONG
*) entry
) - 1;
255 D(bug("FreeListEntry %p size=%ld\n", mem
, mem
[0]));
256 FreePooled(data
->pool
, mem
, mem
[0]);
259 /**************************************************************************
260 Ensures that we there can be at least the given amount of entries within
261 the list. Returns 0 if not. It also allocates the space for the title.
262 It can be accesses with data->entries[ENTRY_TITLE]
263 **************************************************************************/
264 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
266 struct ListEntry
**new_entries
;
267 int new_entries_allocated
;
269 if (size
+ 1 <= data
->entries_allocated
)
272 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
273 if (new_entries_allocated
< size
+ 1)
274 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
276 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
277 new_entries_allocated
* sizeof(struct ListEntry
*)));
279 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
280 if (NULL
== new_entries
)
284 CopyMem(data
->entries
- 1, new_entries
,
285 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
286 FreeVec(data
->entries
- 1);
288 data
->entries
= new_entries
+ 1;
289 data
->entries_allocated
= new_entries_allocated
;
293 /**************************************************************************
294 Prepares the insertion of count entries at pos.
295 This function doesn't care if there is enough space in the datastructure.
296 SetListSize() must be used first.
297 With current implementation, this call will never fail
298 **************************************************************************/
299 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
302 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
303 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
307 /**************************************************************************
308 Removes count (already deinitalized) list entries starting az pos.
309 **************************************************************************/
310 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
312 // FIXME: segfault if entries_num = pos = count = 1
313 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
314 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
317 /**************************************************************************
318 Frees all memory allocated by ParseListFormat()
319 **************************************************************************/
320 static void FreeListFormat(struct MUI_ListData
*data
)
326 for (i
= 0; i
< data
->columns
; i
++)
328 FreeVec(data
->ci
[i
].preparse
);
329 data
->ci
[i
].preparse
= NULL
;
334 FreeVec(data
->preparses
);
335 data
->preparses
= NULL
;
338 FreeVec(data
->strings
- 1);
339 data
->strings
= NULL
;
344 /**************************************************************************
345 Parses the given format string (also frees a previouly parsed format).
347 **************************************************************************/
348 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
356 struct RDArgs
*rdargs
;
359 format
= (STRPTR
) "";
363 FreeListFormat(data
);
367 /* Count the number of columns first */
372 if (!(data
->preparses
=
373 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
376 if (!(data
->strings
= AllocVec((new_columns
+ 1 + 10)
377 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
378 * used by orginal MUI and also some
382 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
386 for (i
= 0; i
< new_columns
; i
++)
388 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
389 data
->ci
[i
].weight
= 100;
390 data
->ci
[i
].delta
= 4;
391 data
->ci
[i
].min_width
= -1;
392 data
->ci
[i
].max_width
= -1;
393 data
->ci
[i
].user_width
= -1;
394 data
->ci
[i
].bar
= FALSE
;
395 data
->ci
[i
].preparse
= NULL
;
398 if ((format_sep
= StrDup(format
)) != 0)
400 for (i
= 0; format_sep
[i
] != '\0'; i
++)
402 if (format_sep
[i
] == ',')
403 format_sep
[i
] = '\0';
406 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
412 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
413 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
414 rdargs
->RDA_Source
.CS_CurChr
= 0;
415 rdargs
->RDA_DAList
= 0;
416 rdargs
->RDA_Buffer
= NULL
;
417 rdargs
->RDA_BufSiz
= 0;
418 rdargs
->RDA_ExtHelp
= NULL
;
419 rdargs
->RDA_Flags
= 0;
421 memset(args
, 0, sizeof args
);
422 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
425 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
426 if (args
[ARG_WEIGHT
])
427 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
429 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
430 if (args
[ARG_MINWIDTH
])
431 data
->ci
[i
].min_width
=
432 *(LONG
*) args
[ARG_MINWIDTH
];
433 if (args
[ARG_MAXWIDTH
])
434 data
->ci
[i
].max_width
=
435 *(LONG
*) args
[ARG_MAXWIDTH
];
436 data
->ci
[i
].bar
= args
[ARG_BAR
];
437 if (args
[ARG_PREPARSE
])
438 data
->ci
[i
].preparse
=
439 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
443 ptr
+= strlen(ptr
) + 1;
446 while (i
< new_columns
);
447 FreeDosObject(DOS_RDARGS
, rdargs
);
452 for (i
= 0; i
< new_columns
; i
++)
454 D(bug("colno %d weight %d delta %d preparse %s\n",
455 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
456 data
->ci
[i
].preparse
));
459 data
->columns
= new_columns
;
460 data
->strings
++; /* Skip entry pos */
465 /**************************************************************************
466 Call the MUIM_List_Display for the given entry. It fills out
467 data->string and data->preparses
468 **************************************************************************/
469 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
471 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
475 for (col
= 0; col
< data
->columns
; col
++)
476 data
->preparses
[col
] = data
->ci
[col
].preparse
;
478 if (entry_pos
== ENTRY_TITLE
)
480 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
482 *data
->strings
= data
->title
;
485 entry_data
= NULL
; /* it's a title request */
488 entry_data
= data
->entries
[entry_pos
]->data
;
490 /* Get the display formation */
491 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
492 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
495 /**************************************************************************
496 Determine the dims of a single entry and adapt the columninfo according
497 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
498 be redrawn after this operation, 1 if all entries need to be redrawn.
499 **************************************************************************/
500 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
502 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
503 struct ListEntry
*entry
= data
->entries
[pos
];
510 if (!(_flags(obj
) & MADF_SETUP
))
513 DisplayEntry(cl
, obj
, pos
);
515 /* Set height to at least minheight */
516 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
517 data
->entries
[pos
]->height
= data
->entry_minheight
;
519 for (j
= 0; j
< data
->columns
; j
++)
522 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
526 zune_text_get_bounds(text
, obj
);
528 if (text
->height
> data
->entries
[pos
]->height
)
530 data
->entries
[pos
]->height
= text
->height
;
531 /* entry height changed, redraw all entries later */
534 data
->entries
[pos
]->widths
[j
] = text
->width
;
536 if (text
->width
> data
->ci
[j
].entries_width
)
538 /* This columns width is bigger than the other in the same
539 * columns, so we store this value
541 data
->ci
[j
].entries_width
= text
->width
;
542 /* column width changed, redraw all entries later */
546 zune_text_destroy(text
);
549 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
551 data
->entry_maxheight
= data
->entries
[pos
]->height
;
552 /* maximum entry height changed, redraw all entries later */
559 /**************************************************************************
560 Determine the widths of the entries
561 **************************************************************************/
562 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
565 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
567 if (!(_flags(obj
) & MADF_SETUP
))
570 for (j
= 0; j
< data
->columns
; j
++)
571 data
->ci
[j
].entries_width
= 0;
573 data
->entry_maxheight
= 0;
574 data
->entries_totalheight
= 0;
575 data
->entries_maxwidth
= 0;
577 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
579 CalcDimsOfEntry(cl
, obj
, i
);
580 data
->entries_totalheight
+= data
->entries
[i
]->height
;
583 for (j
= 0; j
< data
->columns
; j
++)
584 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
586 if (!data
->entry_maxheight
)
587 data
->entry_maxheight
= 1;
590 /**************************************************************************
591 Calculates the number of visible entry lines. Returns 1 if it has
593 **************************************************************************/
594 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
596 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
597 int old_entries_visible
= data
->entries_visible
;
598 int old_entries_top_pixel
= data
->entries_top_pixel
;
600 data
->entries_visible
= (_mheight(obj
) - data
->title_height
)
601 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
603 /* Distribute extra vertical space evenly between top and bottom of
606 data
->entries_top_pixel
= _mtop(obj
) + data
->title_height
607 + (_mheight(obj
) - data
->title_height
609 data
->entries_visible
*
610 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
612 return (old_entries_visible
!= data
->entries_visible
)
613 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
616 /**************************************************************************
617 Default hook to compare two list entries. Works for strings only.
618 **************************************************************************/
619 AROS_UFH3S(int, default_compare_func
,
620 AROS_UFHA(struct Hook
*, h
, A0
),
621 AROS_UFHA(char *, s2
, A2
),
622 AROS_UFHA(char *, s1
, A1
))
626 return Stricmp(s1
, s2
);
631 /**************************************************************************
633 **************************************************************************/
634 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
636 struct MUI_ListData
*data
;
638 struct TagItem
*tags
;
640 LONG new_entries_active
= MUIV_List_Active_Off
;
642 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
643 MUIA_Font
, MUIV_Font_List
,
644 MUIA_Background
, MUII_ListBack
, TAG_MORE
, (IPTR
) msg
->ops_AttrList
);
648 data
= INST_DATA(cl
, obj
);
651 data
->entries_active
= MUIV_List_Active_Off
;
652 data
->intern_puddle_size
= 2008;
653 data
->intern_thresh_size
= 1024;
654 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
655 data
->default_compare_hook
.h_SubEntry
= 0;
656 data
->compare_hook
= &(data
->default_compare_hook
);
658 /* parse initial taglist */
659 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
663 case MUIA_List_Active
:
664 new_entries_active
= tag
->ti_Data
;
668 data
->pool
= (APTR
) tag
->ti_Data
;
671 case MUIA_List_PoolPuddleSize
:
672 data
->intern_puddle_size
= tag
->ti_Data
;
675 case MUIA_List_PoolThreshSize
:
676 data
->intern_thresh_size
= tag
->ti_Data
;
679 case MUIA_List_CompareHook
:
680 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
681 if (data
->compare_hook
== NULL
)
682 data
->compare_hook
= &data
->default_compare_hook
;
685 case MUIA_List_ConstructHook
:
686 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
689 case MUIA_List_DestructHook
:
690 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
693 case MUIA_List_DisplayHook
:
694 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
697 case MUIA_List_MultiTestHook
:
698 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
701 case MUIA_List_SourceArray
:
702 array
= (APTR
*) tag
->ti_Data
;
705 case MUIA_List_Format
:
706 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
709 case MUIA_List_Title
:
710 data
->title
= (STRPTR
) tag
->ti_Data
;
713 case MUIA_List_MinLineHeight
:
714 data
->entry_minheight
= tag
->ti_Data
;
717 case MUIA_List_AdjustHeight
:
718 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
721 case MUIA_List_AdjustWidth
:
722 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
725 case MUIA_List_AutoVisible
:
726 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
729 case MUIA_List_ShowDropMarks
:
730 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
733 case MUIA_List_DragSortable
:
734 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
735 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
742 /* No memory pool given, so we create our own */
743 data
->pool
= data
->intern_pool
=
744 CreatePool(0, data
->intern_puddle_size
,
745 data
->intern_thresh_size
);
748 CoerceMethod(cl
, obj
, OM_DISPOSE
);
753 /* parse the list format */
754 if (!(ParseListFormat(data
, data
->format
)))
756 CoerceMethod(cl
, obj
, OM_DISPOSE
);
760 /* This is neccessary for at least the title */
761 if (!SetListSize(data
, 0))
763 CoerceMethod(cl
, obj
, OM_DISPOSE
);
769 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
771 CoerceMethod(cl
, obj
, OM_DISPOSE
);
776 data
->entries
[ENTRY_TITLE
] = NULL
;
782 /* Count the number of elements */
783 for (i
= 0; array
[i
] != NULL
; i
++)
786 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
787 MUIV_List_Insert_Top
);
791 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
793 switch (new_entries_active
)
795 case MUIV_List_Active_Top
:
796 new_entries_active
= 0;
799 case MUIV_List_Active_Bottom
:
800 new_entries_active
= data
->entries_num
- 1;
804 if (new_entries_active
< 0)
805 new_entries_active
= 0;
806 else if (new_entries_active
>= data
->entries_num
)
807 new_entries_active
= data
->entries_num
- 1;
809 data
->entries_active
= new_entries_active
;
810 /* Selected entry will be moved into visible area */
813 NewList((struct List
*)&data
->images
);
815 D(bug("List_New(%lx)\n", obj
));
820 /**************************************************************************
822 **************************************************************************/
823 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
825 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
827 D(bug("List Dispose\n"));
829 /* Call destruct method for every entry and free the entries manually
830 * to avoid notification */
831 while (data
->confirm_entries_num
)
833 struct ListEntry
*lentry
=
834 data
->entries
[--data
->confirm_entries_num
];
835 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
837 FreeListEntry(data
, lentry
);
840 if (data
->intern_pool
)
841 DeletePool(data
->intern_pool
);
843 FreeVec(data
->entries
- 1);
844 /* title is currently before all other elements */
846 FreeListFormat(data
);
847 FreeVec(data
->format
);
849 return DoSuperMethodA(cl
, obj
, msg
);
853 /**************************************************************************
855 **************************************************************************/
856 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
858 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
860 struct TagItem
*tags
;
863 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
867 case MUIA_List_CompareHook
:
868 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
869 if (data
->compare_hook
== NULL
)
870 data
->compare_hook
= &data
->default_compare_hook
;
873 case MUIA_List_ConstructHook
:
874 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
877 case MUIA_List_DestructHook
:
878 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
881 case MUIA_List_DisplayHook
:
882 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
885 case MUIA_List_MultiTestHook
:
886 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
887 if (data
->multi_test_hook
!= NULL
)
889 /* Clearing current selections is the easiest way to keep
890 * selections consistent with the new hook */
891 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
892 MUIV_List_Select_Off
, NULL
);
896 case MUIA_List_VertProp_First
:
897 data
->vertprop_first
= tag
->ti_Data
;
898 if (data
->entries_first
!= tag
->ti_Data
)
900 set(obj
, MUIA_List_First
, tag
->ti_Data
);
904 case MUIA_List_Format
:
905 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
906 ParseListFormat(data
, data
->format
);
907 // FIXME: should we check for errors?
908 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
911 case MUIA_List_VertProp_Entries
:
912 data
->vertprop_entries
= tag
->ti_Data
;
915 case MUIA_List_VertProp_Visible
:
916 data
->vertprop_visible
= tag
->ti_Data
;
917 data
->entries_visible
= tag
->ti_Data
;
920 case MUIA_List_Active
:
922 LONG new_entries_active
= tag
->ti_Data
;
924 if ((data
->entries_num
)
925 && (new_entries_active
!= MUIV_List_Active_Off
))
927 switch (new_entries_active
)
929 case MUIV_List_Active_Top
:
930 new_entries_active
= 0;
933 case MUIV_List_Active_Bottom
:
934 new_entries_active
= data
->entries_num
- 1;
937 case MUIV_List_Active_Up
:
938 new_entries_active
= data
->entries_active
- 1;
941 case MUIV_List_Active_Down
:
942 new_entries_active
= data
->entries_active
+ 1;
945 case MUIV_List_Active_PageUp
:
947 data
->entries_active
- data
->entries_visible
;
950 case MUIV_List_Active_PageDown
:
952 data
->entries_active
+ data
->entries_visible
;
956 if (new_entries_active
< 0)
957 new_entries_active
= 0;
958 else if (new_entries_active
>= data
->entries_num
)
959 new_entries_active
= data
->entries_num
- 1;
962 new_entries_active
= -1;
964 if (data
->entries_active
!= new_entries_active
)
966 LONG old
= data
->entries_active
;
967 data
->entries_active
= new_entries_active
;
969 /* Selectchange stuff */
970 if (new_entries_active
!= -1)
972 DoMethod(obj
, MUIM_List_SelectChange
,
973 new_entries_active
, MUIV_List_Select_On
, 0);
974 DoMethod(obj
, MUIM_List_SelectChange
,
975 new_entries_active
, MUIV_List_Select_Active
, 0);
978 DoMethod(obj
, MUIM_List_SelectChange
,
979 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
981 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
984 data
->update_pos
= old
;
985 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
987 data
->update_pos
= data
->entries_active
;
988 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
990 /* Make new active entry visible (if there is one and
992 if (new_entries_active
!= -1
993 && (_flags(obj
) & MADF_SETUP
))
995 DoMethod(obj
, MUIM_List_Jump
,
996 MUIV_List_Jump_Active
);
1002 case MUIA_List_First
:
1003 data
->update_pos
= data
->entries_first
;
1005 data
->entries_first
= tag
->ti_Data
;
1007 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1008 if ((data
->vertprop_first
!= tag
->ti_Data
)
1009 && (!(data
->flags
& LIST_QUIET
)))
1011 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1015 case MUIA_List_Visible
: /* Shouldn't be settable? */
1016 if (data
->vertprop_visible
!= tag
->ti_Data
)
1017 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1020 case MUIA_List_Entries
:
1021 if (data
->confirm_entries_num
== tag
->ti_Data
)
1023 data
->entries_num
= tag
->ti_Data
;
1024 if (!(data
->flags
& LIST_QUIET
))
1026 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1031 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1035 case MUIA_List_Quiet
:
1036 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1039 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1040 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1041 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1042 if (data
->vertprop_first
!=
1043 XGET(obj
, MUIA_List_VertProp_First
))
1044 set(obj
, MUIA_List_VertProp_First
, data
->vertprop_first
);
1048 case MUIA_List_AutoVisible
:
1049 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1052 case MUIA_List_ShowDropMarks
:
1053 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1056 case MUIA_List_DragSortable
:
1057 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1058 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1063 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1066 /**************************************************************************
1068 **************************************************************************/
1069 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1071 /* small macro to simplify return value storage */
1072 #define STORE *(msg->opg_Storage)
1073 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1075 switch (msg
->opg_AttrID
)
1077 case MUIA_List_Entries
:
1078 STORE
= data
->entries_num
;
1080 case MUIA_List_First
:
1081 STORE
= data
->entries_first
;
1083 case MUIA_List_Active
:
1084 STORE
= data
->entries_active
;
1086 case MUIA_List_InsertPosition
:
1087 STORE
= data
->insert_position
;
1089 case MUIA_List_Title
:
1090 STORE
= (unsigned long)data
->title
;
1092 case MUIA_List_VertProp_Entries
:
1093 STORE
= data
->vertprop_entries
;
1095 case MUIA_List_VertProp_Visible
:
1096 case MUIA_List_Visible
:
1097 STORE
= data
->vertprop_visible
;
1099 case MUIA_List_VertProp_First
:
1100 STORE
= data
->vertprop_first
;
1102 case MUIA_List_Format
:
1103 STORE
= (IPTR
) data
->format
;
1105 case MUIA_List_AutoVisible
:
1106 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1108 case MUIA_List_ShowDropMarks
:
1109 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1111 case MUIA_List_DragSortable
:
1112 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1117 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1123 /**************************************************************************
1125 **************************************************************************/
1126 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1127 struct MUIP_Setup
*msg
)
1129 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1131 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1134 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1135 data
->prefs_linespacing
=
1136 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1137 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1138 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1140 CalcWidths(cl
, obj
);
1144 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1148 data
->title_height
= 0;
1152 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1154 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1156 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1161 /**************************************************************************
1163 **************************************************************************/
1164 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1165 struct MUIP_Cleanup
*msg
)
1167 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1168 struct ListImage
*li
= List_First(&data
->images
);
1172 struct ListImage
*next
= Node_Next(li
);
1173 DoMethod(obj
, MUIM_List_DeleteImage
, (IPTR
) li
);
1177 zune_imspec_cleanup(data
->list_cursor
);
1178 zune_imspec_cleanup(data
->list_select
);
1179 zune_imspec_cleanup(data
->list_selcur
);
1181 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1184 /**************************************************************************
1186 **************************************************************************/
1187 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1188 struct MUIP_AskMinMax
*msg
)
1190 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1192 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1195 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1197 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1198 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1199 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1203 msg
->MinMaxInfo
->MinWidth
+= 40;
1204 msg
->MinMaxInfo
->DefWidth
+= 100;
1205 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1208 if (data
->entries_num
> 0)
1210 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1212 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1213 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1214 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1218 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1219 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1220 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1221 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1226 msg
->MinMaxInfo
->MinHeight
+= 36;
1227 msg
->MinMaxInfo
->DefHeight
+= 96;
1228 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1230 D(bug("List %p minheigh=%d, line maxh=%d\n",
1231 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1235 /****i* List.mui/MUIM_Layout *************************************************
1240 ******************************************************************************
1244 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1245 struct MUIP_Layout
*msg
)
1247 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1248 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1249 LONG new_entries_first
= data
->entries_first
;
1251 /* Calc the numbers of entries visible */
1252 CalcVertVisible(cl
, obj
);
1254 /* Ensure active entry is visible if requested */
1255 if (data
->entries_active
+ 1 >=
1256 (data
->entries_first
+ data
->entries_visible
)
1257 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1259 data
->entries_active
- data
->entries_visible
+ 1;
1261 /* Ensure there are no unnecessary empty lines */
1262 if ((new_entries_first
+ data
->entries_visible
>=
1264 && (data
->entries_visible
<= data
->entries_num
))
1265 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1267 /* Always show the start of the list if it isn't long enough to fill the
1269 if (data
->entries_num
<= data
->entries_visible
)
1270 new_entries_first
= 0;
1272 if (new_entries_first
< 0)
1273 new_entries_first
= 0;
1275 set(obj
, new_entries_first
!= data
->entries_first
?
1276 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1278 /* So the notify happens */
1279 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1285 /**************************************************************************
1287 **************************************************************************/
1288 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1289 struct MUIP_Show
*msg
)
1291 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1292 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1294 zune_imspec_show(data
->list_cursor
, obj
);
1295 zune_imspec_show(data
->list_select
, obj
);
1296 zune_imspec_show(data
->list_selcur
, obj
);
1301 /**************************************************************************
1303 **************************************************************************/
1304 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1305 struct MUIP_Hide
*msg
)
1307 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1309 zune_imspec_hide(data
->list_cursor
);
1310 zune_imspec_hide(data
->list_select
);
1311 zune_imspec_hide(data
->list_selcur
);
1313 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1317 /**************************************************************************
1318 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1320 **************************************************************************/
1321 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1324 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1327 /* To be sure we don't draw anything if there is no title */
1328 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1331 DisplayEntry(cl
, obj
, entry_pos
);
1334 for (col
= 0; col
< data
->columns
; col
++)
1337 x2
= x1
+ data
->ci
[col
].entries_width
;
1340 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1341 ZTEXT_ARG_NONE
, 0)))
1343 /* Could be made simpler, as we don't really need the bounds */
1344 zune_text_get_bounds(text
, obj
);
1345 /* Note, this was MPEN_SHADOW before */
1346 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1347 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1348 zune_text_destroy(text
);
1350 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1354 /**************************************************************************
1356 **************************************************************************/
1357 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1359 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1363 BOOL scroll_caused_damage
= FALSE
;
1364 struct MUI_ImageSpec_intern
*highlight
;
1366 if (data
->flags
& LIST_QUIET
)
1369 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1371 if (msg
->flags
& MADF_DRAWUPDATE
)
1373 if (data
->update
== 1)
1374 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), _mtop(obj
),
1375 _mwidth(obj
), _mheight(obj
),
1376 0, data
->entries_first
* data
->entry_maxheight
, 0);
1380 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), _mtop(obj
),
1381 _mwidth(obj
), _mheight(obj
),
1382 0, data
->entries_first
* data
->entry_maxheight
, 0);
1385 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(obj
), _mtop(obj
),
1386 _mwidth(obj
), _mheight(obj
));
1388 if (!(msg
->flags
& MADF_DRAWUPDATE
)
1389 || ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1))
1394 if (data
->title_height
&& data
->title
)
1396 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1397 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1398 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1399 Move(_rp(obj
), _mleft(obj
), y
);
1400 Draw(_rp(obj
), _mright(obj
), y
);
1401 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1403 Move(_rp(obj
), _mleft(obj
), y
);
1404 Draw(_rp(obj
), _mright(obj
), y
);
1408 y
= data
->entries_top_pixel
;
1410 start
= data
->entries_first
;
1411 end
= data
->entries_first
+ data
->entries_visible
;
1413 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1415 int diffy
= data
->entries_first
- data
->update_pos
;
1417 if (abs(diffy
) < data
->entries_visible
)
1419 scroll_caused_damage
=
1420 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1422 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1425 y
+ data
->entry_maxheight
* data
->entries_visible
);
1427 scroll_caused_damage
=
1428 scroll_caused_damage
1429 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1433 start
= end
- diffy
;
1434 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1438 end
= start
- diffy
;
1442 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1444 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), top
,
1445 _mwidth(obj
), bottom
- top
+ 1,
1447 top
- _mtop(obj
) + data
->entries_first
* data
->entry_maxheight
,
1451 for (entry_pos
= start
;
1452 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1454 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1456 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1457 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1458 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1459 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1460 && data
->update_pos
== entry_pos
))
1462 /* Choose appropriate highlight image */
1464 if (entry_pos
== data
->entries_active
1465 && entry
->flags
& ENTRY_SELECTED
)
1466 highlight
= data
->list_selcur
;
1467 else if (entry_pos
== data
->entries_active
)
1468 highlight
= data
->list_cursor
;
1469 else if (entry
->flags
& ENTRY_SELECTED
)
1470 highlight
= data
->list_select
;
1474 /* Draw highlight or background */
1476 if (highlight
!= NULL
)
1478 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1479 _mleft(obj
), y
, _mwidth(obj
), data
->entry_maxheight
,
1480 0, y
- data
->entries_top_pixel
, 0);
1482 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1483 && data
->update_pos
== entry_pos
)
1485 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), y
,
1486 _mwidth(obj
), data
->entry_maxheight
, 0,
1488 data
->entries_first
* data
->entry_maxheight
, 0);
1491 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1493 y
+= data
->entry_maxheight
;
1496 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1500 if (scroll_caused_damage
)
1502 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1504 /* Theoretically it might happen that more damage is caused
1505 after ScrollRaster. By something else, like window movement
1506 in front of our window. Therefore refresh root object of
1507 window, not just this object */
1511 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1512 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1514 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1518 ULONG x1
= _mleft(obj
);
1522 if (data
->title_height
&& data
->title
)
1524 for (col
= 0; col
< data
->columns
; col
++)
1526 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1527 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1529 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(obj
))
1532 if (data
->ci
[col
].bar
)
1534 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1535 Move(_rp(obj
), x1
, y
);
1537 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1538 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1539 Move(_rp(obj
), x1
+ 1, y
);
1540 Draw(_rp(obj
), x1
+ 1,
1541 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1545 x1
+= data
->ci
[col
].delta
- halfdelta
;
1547 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1552 for (col
= 0; col
< data
->columns
; col
++)
1554 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1555 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1557 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(obj
))
1560 if (data
->ci
[col
].bar
)
1562 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1563 Move(_rp(obj
), x1
, y
);
1564 Draw(_rp(obj
), x1
, _mbottom(obj
));
1565 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1566 Move(_rp(obj
), x1
+ 1, y
);
1567 Draw(_rp(obj
), x1
+ 1, _mbottom(obj
));
1572 x1
+= data
->ci
[col
].delta
- halfdelta
;
1578 /****** List.mui/MUIM_List_Clear *********************************************
1581 * MUIM_List_Clear (V4)
1584 * DoMethod(obj, MUIM_List_Clear);
1587 * Removes all entries from the list.
1589 ******************************************************************************
1593 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
1594 struct MUIP_List_Clear
*msg
)
1596 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1598 while (data
->confirm_entries_num
)
1600 struct ListEntry
*lentry
=
1601 data
->entries
[--data
->confirm_entries_num
];
1602 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1604 FreeListEntry(data
, lentry
);
1606 /* Should never fail when shrinking */
1607 SetListSize(data
, 0);
1610 if (data
->confirm_entries_num
!= data
->entries_num
)
1612 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
1613 /* Notify only when no entry was active */
1614 data
->entries_active
!=
1615 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
1616 MUIV_List_Active_Off
, TAG_DONE
);
1619 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1625 /**************************************************************************
1627 **************************************************************************/
1628 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
1629 struct MUIP_List_Exchange
*msg
)
1631 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1636 case MUIV_List_Exchange_Top
:
1639 case MUIV_List_Exchange_Active
:
1640 pos1
= data
->entries_active
;
1642 case MUIV_List_Exchange_Bottom
:
1643 pos1
= data
->entries_num
- 1;
1651 case MUIV_List_Exchange_Top
:
1654 case MUIV_List_Exchange_Active
:
1655 pos2
= data
->entries_active
;
1657 case MUIV_List_Exchange_Bottom
:
1658 pos2
= data
->entries_num
- 1;
1660 case MUIV_List_Exchange_Next
:
1663 case MUIV_List_Exchange_Previous
:
1670 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
1671 && pos2
< data
->entries_num
&& pos1
!= pos2
)
1673 struct ListEntry
*save
= data
->entries
[pos1
];
1674 data
->entries
[pos1
] = data
->entries
[pos2
];
1675 data
->entries
[pos2
] = save
;
1678 data
->update_pos
= pos1
;
1679 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1682 data
->update_pos
= pos2
;
1683 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1693 /**************************************************************************
1695 **************************************************************************/
1696 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
1697 struct MUIP_List_Redraw
*msg
)
1699 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1701 if (!(data
->flags
& LIST_QUIET
))
1703 if (msg
->pos
== MUIV_List_Redraw_All
)
1706 CalcWidths(cl
, obj
);
1707 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1712 if (msg
->pos
== MUIV_List_Redraw_Active
)
1713 pos
= data
->entries_active
;
1714 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
1717 for (i
= 0; i
< data
->entries_num
; i
++)
1718 if (data
->entries
[i
]->data
== msg
->entry
)
1729 if (CalcDimsOfEntry(cl
, obj
, pos
))
1734 data
->update_pos
= pos
;
1736 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1743 /**************************************************************************
1745 **************************************************************************/
1746 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
1747 struct MUIP_List_Remove
*msg
)
1749 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1752 struct ListEntry
*lentry
;
1753 //int rem_count = 1;
1755 if (!data
->entries_num
)
1760 case MUIV_List_Remove_First
:
1764 case MUIV_List_Remove_Active
:
1765 pos
= data
->entries_active
;
1768 case MUIV_List_Remove_Last
:
1769 pos
= data
->entries_num
- 1;
1772 case MUIV_List_Remove_Selected
:
1773 /* TODO: needs special handling */
1774 pos
= data
->entries_active
;
1782 if (pos
< 0 || pos
>= data
->entries_num
)
1785 new_act
= data
->entries_active
;
1787 if (pos
== new_act
&& new_act
== data
->entries_num
- 1)
1788 new_act
--; /* might become MUIV_List_Active_Off */
1790 lentry
= data
->entries
[pos
];
1791 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1796 RemoveListEntries(data
, pos
, cur
- pos
);
1797 data
->confirm_entries_num
-= cur
- pos
;
1799 /* ensure that the active element is in a valid range */
1800 if (new_act
>= data
->entries_num
)
1801 new_act
= data
->entries_num
- 1;
1803 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
,
1804 (new_act
>= pos
) || (new_act
!= data
->entries_active
) ?
1805 MUIA_List_Active
: TAG_DONE
,
1806 new_act
, /* Inform only if neccessary (for notify) */
1810 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1815 /**************************************************************************
1817 **************************************************************************/
1818 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
1819 struct MUIP_List_Select
*msg
)
1821 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1822 LONG pos
, i
, count
, selcount
=0, state
;
1823 BOOL multi_allowed
= TRUE
;
1825 /* Establish the range of entries affected */
1828 case MUIV_List_Select_Active
:
1829 pos
= data
->entries_active
;
1830 if (pos
== MUIV_List_Active_Off
)
1836 case MUIV_List_Select_All
:
1838 count
= data
->entries_num
;
1844 if (pos
< 0 || pos
>= data
->entries_num
)
1849 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
1851 /* Disallow selection of an additional entry if there is a currently
1852 selected entry that is not multi-selectable (in such case there
1853 will only be one entry currently selected, so no need to iterate) */
1854 i
= MUIV_List_NextSelected_Start
;
1855 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
1856 if (i
!= MUIV_List_NextSelected_End
)
1858 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
1859 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
1860 data
->entries
[i
]->data
);
1863 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
1865 /* Change or check state of each entry in the range */
1866 for (i
= pos
; i
< pos
+ count
; i
++)
1868 BOOL new_select_state
;
1870 new_select_state
= state
? TRUE
: FALSE
;
1872 switch (msg
->seltype
)
1874 case MUIV_List_Select_Off
:
1875 new_select_state
= FALSE
;
1878 case MUIV_List_Select_On
:
1879 new_select_state
= TRUE
;
1882 case MUIV_List_Select_Toggle
:
1883 new_select_state
= !state
;
1887 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
1892 if (msg
->seltype
!= MUIV_List_Select_Ask
)
1894 /* Disallow selection if entry is not multi-selectable and
1895 * there are already selected entries */
1896 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
1897 new_select_state
= multi_allowed
&& (selcount
== 0 ||
1898 CallHookPkt(data
->multi_test_hook
, NULL
,
1899 data
->entries
[i
]->data
));
1901 if (new_select_state
)
1902 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
1904 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
1908 /* Report old state or number of selected entries */
1911 if (msg
->pos
== MUIV_List_Select_All
1912 && msg
->seltype
== MUIV_List_Select_Ask
)
1913 *msg
->info
= selcount
;
1918 /* Redraw unless it was just an enquiry */
1919 if (msg
->seltype
!= MUIV_List_Select_Ask
)
1926 data
->update_pos
= pos
;
1928 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1934 /**************************************************************************
1936 **************************************************************************/
1938 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
1939 struct MUIP_List_Insert
*msg
)
1941 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1942 LONG pos
, count
, sort
;
1949 /* Count the number of entries */
1950 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
1959 case MUIV_List_Insert_Top
:
1963 case MUIV_List_Insert_Active
:
1964 if (data
->entries_active
!= -1)
1965 pos
= data
->entries_active
;
1970 case MUIV_List_Insert_Sorted
:
1971 pos
= data
->entries_num
;
1972 sort
= 1; /* we sort'em later */
1975 case MUIV_List_Insert_Bottom
:
1976 pos
= data
->entries_num
;
1980 if (msg
->pos
> data
->entries_num
)
1981 pos
= data
->entries_num
;
1982 else if (msg
->pos
< 0)
1989 if (!(SetListSize(data
, data
->entries_num
+ count
)))
1992 LONG until
= pos
+ count
;
1993 APTR
*toinsert
= msg
->entries
;
1995 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2000 struct ListEntry
*lentry
;
2002 if (!(lentry
= AllocListEntry(data
)))
2004 /* Panic, but we must be in a consistent state, so remove
2005 * the space where the following list entries should have gone
2007 RemoveListEntries(data
, pos
, until
- pos
);
2011 /* now call the construct method which returns us a pointer which
2013 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2014 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2017 FreeListEntry(data
, lentry
);
2018 RemoveListEntries(data
, pos
, until
- pos
);
2020 /* TODO: Also check for visible stuff like below */
2021 if (data
->entries_num
!= data
->confirm_entries_num
)
2022 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2026 data
->entries
[pos
] = lentry
;
2027 data
->confirm_entries_num
++;
2029 if (_flags(obj
) & MADF_SETUP
)
2031 /* We have to calculate the width and height of the newly
2032 * inserted entry. This has to be done after inserting the
2033 * element into the list */
2034 CalcDimsOfEntry(cl
, obj
, pos
);
2041 /* Recalculate the number of visible entries */
2042 if (_flags(obj
) & MADF_SETUP
)
2043 CalcVertVisible(cl
, obj
);
2045 if (data
->entries_num
!= data
->confirm_entries_num
)
2048 MUIA_List_Entries
, data
->confirm_entries_num
,
2049 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2052 /* If the array is already sorted, we could do a simple insert
2053 * sort and would be much faster than with qsort.
2054 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2055 * sort the whole array?
2057 * I think, we better sort the whole array:
2061 DoMethod(obj
, MUIM_List_Sort
);
2062 /* TODO: which pos to return here !? */
2063 /* MUIM_List_Sort already called MUI_Redraw */
2068 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2070 data
->insert_position
= pos
;
2075 /**************************************************************************
2076 MUIM_List_InsertSingle
2077 **************************************************************************/
2078 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2079 struct MUIP_List_InsertSingle
*msg
)
2081 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2085 /**************************************************************************
2087 **************************************************************************/
2088 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2089 struct MUIP_List_GetEntry
*msg
)
2091 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2094 if (pos
== MUIV_List_GetEntry_Active
)
2095 pos
= data
->entries_active
;
2097 if (pos
< 0 || pos
>= data
->entries_num
)
2102 *msg
->entry
= data
->entries
[pos
]->data
;
2103 return (IPTR
) *msg
->entry
;
2106 /**************************************************************************
2108 **************************************************************************/
2109 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2110 struct MUIP_List_Construct
*msg
)
2112 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2114 if (NULL
== data
->construct_hook
)
2115 return (IPTR
) msg
->entry
;
2116 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2118 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2119 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2124 if (msg
->entry
!= NULL
)
2125 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2127 *(STRPTR
) (mem
+ 1) = 0;
2128 return (IPTR
) (mem
+ 1);
2130 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2133 /**************************************************************************
2135 **************************************************************************/
2136 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2137 struct MUIP_List_Destruct
*msg
)
2139 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2141 if (NULL
== data
->destruct_hook
)
2144 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2146 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2147 FreePooled(msg
->pool
, mem
, mem
[0]);
2151 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2156 /****** List.mui/MUIM_List_Compare *******************************************
2159 * MUIM_List_Compare (V20)
2162 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2163 * LONG sort_type1, LONG sort_type2);
2166 * Compare two list entries according to the current comparison hook
2167 * (MUIA_List_CompareHook).
2170 * entry1 - the first entry data.
2171 * entry2 - the second entry data.
2172 * sort_type1 - undocumented.
2173 * sort_type2 - undocumented.
2176 * MUIA_List_CompareHook, MUIM_List_Sort.
2178 ******************************************************************************
2182 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2183 struct MUIP_List_Compare
*msg
)
2185 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2187 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2190 /**************************************************************************
2192 **************************************************************************/
2193 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2194 struct MUIP_List_Display
*msg
)
2196 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2198 if (NULL
== data
->display_hook
)
2201 *msg
->array
= msg
->entry
;
2207 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2208 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2211 /**************************************************************************
2212 MUIM_List_SelectChange
2213 **************************************************************************/
2214 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2215 struct MUIP_List_SelectChange
*msg
)
2220 /**************************************************************************
2221 MUIM_List_CreateImage
2222 Called by a List subclass in its Setup method.
2223 Connects an Area subclass object to the list, much like an object gets
2224 connected to a window. List calls Setup and AskMinMax on that object,
2225 keeps a reference to it (that reference will be returned).
2226 Text engine will dereference that pointer and draw the object with its
2228 **************************************************************************/
2229 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2230 struct MUIP_List_CreateImage
*msg
)
2232 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2233 struct ListImage
*li
;
2235 /* List must be already setup in Setup of your subclass */
2236 if (!(_flags(obj
) & MADF_SETUP
))
2238 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2243 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2244 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2245 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2251 /**************************************************************************
2252 MUIM_List_DeleteImage
2253 **************************************************************************/
2254 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2255 struct MUIP_List_DeleteImage
*msg
)
2257 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2258 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2262 DoMethod(li
->obj
, MUIM_Cleanup
);
2263 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2264 Remove((struct Node
*)li
);
2265 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2271 /****** List.mui/MUIM_List_Jump **********************************************
2274 * MUIM_List_Jump (V4)
2277 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2280 * Scrolls the list so that a particular entry is visible.
2283 * pos - index of entry that should become visible, or one of these
2285 * MUIV_List_Jump_Active: show the active entry.
2286 * MUIV_List_Jump_Top: show the first entry.
2287 * MUIV_List_Jump_Bottom: show the last entry.
2288 * MUIV_List_Jump_Up: show the previous hidden entry.
2289 * MUIV_List_Jump_Down: show the next hidden entry.
2291 ******************************************************************************
2295 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2296 struct MUIP_List_Jump
*msg
)
2298 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2299 LONG pos
= msg
->pos
;
2303 case MUIV_List_Jump_Top
:
2307 case MUIV_List_Jump_Active
:
2308 pos
= data
->entries_active
;
2311 case MUIV_List_Jump_Bottom
:
2312 pos
= data
->entries_num
- 1;
2315 case MUIV_List_Jump_Down
:
2316 pos
= data
->entries_first
+ data
->entries_visible
;
2319 case MUIV_List_Jump_Up
:
2320 pos
= data
->entries_first
- 1;
2324 if (pos
> data
->entries_num
)
2326 pos
= data
->entries_num
- 1;
2331 if (pos
< data
->entries_first
)
2333 set(obj
, MUIA_List_First
, pos
);
2335 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2337 pos
-= (data
->entries_visible
- 1);
2340 if (pos
!= data
->entries_first
)
2342 set(obj
, MUIA_List_First
, pos
);
2349 /****** List.mui/MUIM_List_Sort **********************************************
2352 * MUIM_List_Sort (V4)
2355 * DoMethod(obj, MUIM_List_Sort);
2358 * Sort the list's entries according to the current comparison hook
2359 * (MUIA_List_CompareHook).
2362 * MUIA_List_CompareHook, MUIM_List_Compare.
2364 ******************************************************************************
2368 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2369 struct MUIP_List_Sort
*msg
)
2371 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2374 struct MUIP_List_Compare cmpmsg
=
2375 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2377 if (data
->entries_num
> 1)
2380 Simple sort algorithm. Feel free to improve it.
2382 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2385 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2387 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2388 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2389 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2396 APTR tmp
= data
->entries
[i
];
2397 data
->entries
[i
] = data
->entries
[max
];
2398 data
->entries
[max
] = tmp
;
2404 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2409 /****** List.mui/MUIM_List_Move **********************************************
2412 * MUIM_List_Move (V9)
2415 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2418 * Move a list entry to a new position.
2421 * from - the current index of the entry that should be moved, or one of
2422 * these special values:
2423 * MUIV_List_Move_Active: the active entry.
2424 * MUIV_List_Move_Top: the first entry.
2425 * MUIV_List_Move_Bottom: the last entry.
2426 * to - the index of the entry's new position, or one of
2427 * these special values:
2428 * MUIV_List_Move_Active: the active entry.
2429 * MUIV_List_Move_Top: the first entry.
2430 * MUIV_List_Move_Bottom: the last entry.
2432 ******************************************************************************
2436 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
2437 struct MUIP_List_Move
*msg
)
2439 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2444 /* Normalise special 'from' values */
2447 case MUIV_List_Move_Top
:
2450 case MUIV_List_Move_Active
:
2451 from
= data
->entries_active
;
2453 case MUIV_List_Move_Bottom
:
2454 from
= data
->entries_num
- 1;
2460 /* Normalise special 'to' values */
2463 case MUIV_List_Move_Top
:
2466 case MUIV_List_Move_Active
:
2467 to
= data
->entries_active
;
2469 case MUIV_List_Move_Bottom
:
2470 to
= data
->entries_num
- 1;
2472 case MUIV_List_Move_Next
:
2475 case MUIV_List_Move_Previous
:
2482 /* Check that values are within valid bounds */
2483 if (from
> data
->entries_num
- 1 || from
< 0
2484 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
2485 return (IPTR
) FALSE
;
2487 /* Shift all entries in the range between the 'from' and 'to' positions */
2490 struct ListEntry
*backup
= data
->entries
[from
];
2491 for (i
= from
; i
< to
; i
++)
2492 data
->entries
[i
] = data
->entries
[i
+ 1];
2493 data
->entries
[to
] = backup
;
2497 struct ListEntry
*backup
= data
->entries
[from
];
2498 for (i
= from
; i
> to
; i
--)
2499 data
->entries
[i
] = data
->entries
[i
- 1];
2500 data
->entries
[to
] = backup
;
2503 /* Update index of active entry */
2504 if (from
== data
->entries_active
)
2505 data
->entries_active
= to
;
2506 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
2507 data
->entries_active
--;
2508 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
2509 data
->entries_active
++;
2511 /* Reflect list changes visually */
2513 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2518 /**************************************************************************
2519 MUIM_List_NextSelected
2520 **************************************************************************/
2521 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
2522 struct MUIP_List_NextSelected
*msg
)
2524 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2528 /* Get the first entry to check */
2530 if (pos
== MUIV_List_NextSelected_Start
)
2535 /* Find the next selected entry */
2536 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
2538 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2545 /* Return index of selected entry, or indicate there are no more */
2547 pos
= MUIV_List_NextSelected_End
;
2553 /**************************************************************************
2555 **************************************************************************/
2556 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
2557 struct MUIP_List_TestPos
*msg
)
2559 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2560 struct MUI_List_TestPos_Result
*result
= msg
->res
;
2561 LONG col
= -1, row
= -1;
2563 LONG mx
= msg
->x
- _left(obj
);
2564 LONG entries_visible
;
2566 if (data
->entries_visible
<= data
->entries_num
)
2567 entries_visible
= data
->entries_visible
;
2569 entries_visible
= data
->entries_num
;
2570 LONG ey
= msg
->y
- data
->entries_top_pixel
;
2571 /* y coordinates transformed to the entries */
2573 /* Now check if it was clicked on a title or on entries */
2575 flags
|= MUI_LPR_ABOVE
;
2576 else if (ey
>= entries_visible
* data
->entry_maxheight
)
2577 flags
|= MUI_LPR_BELOW
;
2581 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
2583 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
2587 flags
|= MUI_LPR_LEFT
;
2588 if (mx
>= _width(obj
))
2589 flags
|= MUI_LPR_RIGHT
;
2592 /* Identify column */
2593 if (data
->entries_num
> 0 && data
->columns
> 0)
2596 for (col
= 0; col
< data
->columns
; col
++)
2598 result
->xoffset
= mx
- width_sum
;
2600 data
->ci
[col
].entries_width
+
2601 data
->ci
[col
].delta
+
2602 (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
2603 D(bug("[List/MUIM_HandleEvent] col %d "
2604 "width %d width_sum %d mx %d\n",
2605 col
, data
->ci
[col
].entries_width
, width_sum
, mx
));
2608 D(bug("[List/MUIM_HandleEvent] Column hit %d\n", col
));
2615 result
->entry
= row
;
2616 result
->column
= col
;
2617 result
->flags
= flags
;
2622 /****i* List.mui/MUIM_DragQuery **********************************************
2627 ******************************************************************************
2631 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
2632 struct MUIP_DragQuery
*msg
)
2634 if (msg
->obj
== obj
)
2635 return MUIV_DragQuery_Accept
;
2637 return MUIV_DragQuery_Refuse
;
2641 /****i* List.mui/MUIM_DragFinish *********************************************
2646 ******************************************************************************
2650 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
2651 struct MUIP_DragFinish
*msg
)
2653 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2655 data
->drop_mark_y
= -1;
2661 /****i* List.mui/MUIM_DragReport *********************************************
2666 ******************************************************************************
2670 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
2671 struct MUIP_DragReport
*msg
)
2673 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2674 struct MUI_List_TestPos_Result pos
;
2675 struct RastPort
*rp
= _rp(obj
);
2679 /* Choose new drop mark position */
2681 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2682 if (pos
.entry
!= -1)
2685 if (pos
.yoffset
> 0)
2688 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2689 n
= data
->entries_first
;
2690 else if ((pos
.flags
& MUI_LPR_BELOW
) != 0)
2692 n
= MIN(data
->entries_visible
, data
->entries_num
)
2693 - data
->entries_first
;
2695 n
= data
->entries_first
;
2698 /* Clear old drop mark */
2700 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
2701 * data
->entry_maxheight
;
2702 if (y
!= data
->drop_mark_y
)
2704 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), data
->drop_mark_y
,
2708 /* Draw new drop mark and store its position */
2710 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
2712 old_pattern
= rp
->LinePtrn
;
2713 SetDrPt(rp
, 0xF0F0);
2714 Move(rp
, _mleft(obj
), y
);
2715 Draw(rp
, _mright(obj
), y
);
2716 SetDrPt(rp
, old_pattern
);
2717 data
->drop_mark_y
= y
;
2724 /****i* List.mui/MUIM_DragDrop ***********************************************
2729 ******************************************************************************
2733 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
2734 struct MUIP_DragDrop
*msg
)
2736 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2737 struct MUI_List_TestPos_Result pos
;
2740 /* Find drop position */
2742 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2743 if (pos
.entry
!= -1)
2745 /* Change drop position when coords move past centre of entry, not
2749 if (pos
.yoffset
> 0)
2752 /* Ensure that dropped entry will be positioned between the two
2753 * entries that are above and below the drop mark, rather than
2754 * strictly at the numeric index shown */
2756 if (n
> data
->entries_active
)
2759 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2760 n
= MUIV_List_Move_Top
;
2761 else if ((pos
.flags
& MUI_LPR_BELOW
) != 0)
2762 n
= MUIV_List_Move_Bottom
;
2766 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
,
2773 /****i* List.mui/MUIM_CreateDragImage ****************************************
2776 * MUIM_CreateDragImage
2778 ******************************************************************************
2782 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
2783 struct MUIP_CreateDragImage
*msg
)
2785 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2786 BOOL success
= TRUE
;
2787 struct MUI_List_TestPos_Result pos
;
2788 WORD width
, height
, left
, top
;
2789 struct MUI_DragImage
*img
= NULL
;
2790 const struct ZuneFrameGfx
*zframe
;
2793 /* Get info on dragged entry */
2794 DoMethod(obj
, MUIM_List_TestPos
, _left(obj
) - msg
->touchx
,
2795 _top(obj
) - msg
->touchy
, (IPTR
) &pos
);
2796 if (pos
.entry
== -1)
2801 /* Get boundaries of entry */
2802 width
= _mwidth(obj
);
2803 height
= data
->entry_maxheight
;
2805 top
= _top(obj
) - msg
->touchy
2806 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
2808 /* Allocate drag image structure */
2809 img
= (struct MUI_DragImage
*)
2810 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
2817 /* Get drag frame */
2818 zframe
= zune_zframe_get(obj
,
2819 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
2821 /* Allocate drag image buffer */
2822 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
2823 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
2824 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
2825 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
2826 _screen(obj
)->RastPort
.BitMap
);
2828 if (img
->bm
!= NULL
)
2831 struct RastPort temprp
;
2832 InitRastPort(&temprp
);
2833 temprp
.BitMap
= img
->bm
;
2834 ClipBlit(_rp(obj
), left
, top
, &temprp
,
2835 zframe
->ileft
, zframe
->itop
, width
, height
,
2839 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
2840 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
2841 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
2842 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
2843 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
2846 /* Ensure drag point matches where user clicked */
2847 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
2848 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
2856 /**************************************************************************
2858 **************************************************************************/
2859 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
2861 switch (msg
->MethodID
)
2864 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
2866 return List__OM_DISPOSE(cl
, obj
, msg
);
2868 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
2870 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
2873 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
2875 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
2876 case MUIM_AskMinMax
:
2877 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
2879 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
2881 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
2883 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
2885 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
2886 case MUIM_List_Clear
:
2887 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
2888 case MUIM_List_Sort
:
2889 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
2890 case MUIM_List_Exchange
:
2891 return List__MUIM_Exchange(cl
, obj
,
2892 (struct MUIP_List_Exchange
*)msg
);
2893 case MUIM_List_Insert
:
2894 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
2895 case MUIM_List_InsertSingle
:
2896 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
2897 case MUIM_List_GetEntry
:
2898 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
2899 case MUIM_List_Redraw
:
2900 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
2901 case MUIM_List_Remove
:
2902 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
2903 case MUIM_List_Select
:
2904 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
2905 case MUIM_List_Construct
:
2906 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
2907 case MUIM_List_Destruct
:
2908 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
2909 case MUIM_List_Compare
:
2910 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
2911 case MUIM_List_Display
:
2912 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
2913 case MUIM_List_SelectChange
:
2914 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
2915 case MUIM_List_CreateImage
:
2916 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
2917 case MUIM_List_DeleteImage
:
2918 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
2919 case MUIM_List_Jump
:
2920 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
2921 case MUIM_List_Move
:
2922 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
2923 case MUIM_List_NextSelected
:
2924 return List__MUIM_NextSelected(cl
, obj
,
2925 (struct MUIP_List_NextSelected
*)msg
);
2926 case MUIM_List_TestPos
:
2927 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
2928 case MUIM_DragQuery
:
2929 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
2930 case MUIM_DragFinish
:
2931 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
2932 case MUIM_DragReport
:
2933 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
2935 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
2936 case MUIM_CreateDragImage
:
2937 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
2940 return DoSuperMethodA(cl
, obj
, msg
);
2942 BOOPSI_DISPATCHER_END
2947 const struct __MUIBuiltinClass _MUI_List_desc
=
2951 sizeof(struct MUI_ListData
),
2952 (void *) List_Dispatcher