2 Copyright © 2002-2015, The AROS Development Team. All rights reserved.
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <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 column lists this is the title,
138 * otherwise 1. NULL for no title(s) */
141 struct MUI_ImageSpec_intern
*list_cursor
;
142 struct MUI_ImageSpec_intern
*list_select
;
143 struct MUI_ImageSpec_intern
*list_selcur
;
145 /* Render optimization */
146 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
147 * 3 - scroll to current entries_first (old value is in
154 struct MinList images
;
157 ListviewRefresh prefs_refresh
;
158 UWORD prefs_linespacing
;
160 UWORD prefs_smoothval
;
163 #define LIST_ADJUSTWIDTH (1<<0)
164 #define LIST_ADJUSTHEIGHT (1<<1)
165 #define LIST_AUTOVISIBLE (1<<2)
166 #define LIST_DRAGSORTABLE (1<<3)
167 #define LIST_SHOWDROPMARKS (1<<4)
168 #define LIST_QUIET (1<<5)
170 /*****************************************************************************************
173 MUIA_List_CompareHook
182 The provided hook indicates the sort ordering of two list entries.
183 The hook receives list-entry data pointers as its second and third
184 arguments. The hook should return a negative value if the first entry
185 should be placed before the second entry, a positive value if the
186 first entry should be placed after the second entry, and zero if the
189 In addition to being used internally for sorting operations, this hook
190 will be called when MUIM_List_Compare is externally invoked.
192 If this attribute is not specified or is set to NULL, all list entries
206 *****************************************************************************************/
208 /*****************************************************************************************
211 MUIA_List_MultiTestHook
220 The provided hook indicates whether a particular list entry
221 may be multiselected. The hook receives the list-entry data pointer as
222 its third argument, and returns a Boolean value. If this attribute is
223 not specified or is set to NULL, all list entries are considered
226 Whenever an entry is about to be selected, this hook is called if
227 there are other entries already selected. If the hook returns TRUE,
228 the entry may be multi-selected; if the hook returns FALSE, the entry
231 Additionally, if a non-multi-selectable entry has been selected (as
232 the only selected entry in the list), any attempt to select an
233 additional entry will fail.
246 *****************************************************************************************/
249 /**************************************************************************
250 Allocate a single list entry, does not initialize it (except the pointer)
251 **************************************************************************/
252 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
255 struct ListEntry
*le
;
256 int size
= sizeof(struct ListEntry
) + sizeof(LONG
) * data
->columns
+ 4;
260 mem
= AllocPooled(data
->pool
, size
);
263 D(bug("List AllocListEntry %p, %ld bytes\n", mem
, size
));
265 mem
[0] = size
; /* Save the size */
266 le
= (struct ListEntry
*)(mem
+ 1);
267 le
->widths
= (LONG
*) (le
+ 1);
269 /* Initialize fields */
273 for (j
= 0; j
< data
->columns
; j
++)
279 /**************************************************************************
280 Deallocate a single list entry, does not deinitialize it
281 **************************************************************************/
282 static void FreeListEntry(struct MUI_ListData
*data
,
283 struct ListEntry
*entry
)
285 ULONG
*mem
= ((ULONG
*) entry
) - 1;
286 D(bug("FreeListEntry %p size=%ld\n", mem
, mem
[0]));
287 FreePooled(data
->pool
, mem
, mem
[0]);
290 /**************************************************************************
291 Ensures that there can be at least the given amount of entries within
292 the list. Returns 0 if not. It also allocates the space for the title.
293 It can be accessed with data->entries[ENTRY_TITLE]
294 **************************************************************************/
295 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
297 struct ListEntry
**new_entries
;
298 int new_entries_allocated
;
300 if (size
+ 1 <= data
->entries_allocated
)
303 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
304 if (new_entries_allocated
< size
+ 1)
305 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
307 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
308 new_entries_allocated
* sizeof(struct ListEntry
*)));
310 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
311 if (NULL
== new_entries
)
315 CopyMem(data
->entries
- 1, new_entries
,
316 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
317 FreeVec(data
->entries
- 1);
319 data
->entries
= new_entries
+ 1;
320 data
->entries_allocated
= new_entries_allocated
;
324 /**************************************************************************
325 Prepares the insertion of count entries at pos.
326 This function doesn't care if there is enough space in the datastructure.
327 SetListSize() must be used first.
328 With current implementation, this call will never fail
329 **************************************************************************/
330 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
333 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
334 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
338 /**************************************************************************
339 Removes count (already deinitalized) list entries starting az pos.
340 **************************************************************************/
341 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
343 // FIXME: segfault if entries_num = pos = count = 1
344 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
345 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
348 /**************************************************************************
349 Frees all memory allocated by ParseListFormat()
350 **************************************************************************/
351 static void FreeListFormat(struct MUI_ListData
*data
)
357 for (i
= 0; i
< data
->columns
; i
++)
359 FreeVec(data
->ci
[i
].preparse
);
360 data
->ci
[i
].preparse
= NULL
;
365 FreeVec(data
->preparses
);
366 data
->preparses
= NULL
;
369 FreeVec(data
->strings
- 1);
370 data
->strings
= NULL
;
375 /**************************************************************************
376 Parses the given format string (also frees a previously parsed format).
378 **************************************************************************/
379 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
387 struct RDArgs
*rdargs
;
390 format
= (STRPTR
) "";
394 FreeListFormat(data
);
398 /* Count the number of columns first */
403 if (!(data
->preparses
=
404 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
407 if (!(data
->strings
= AllocVec((new_columns
+ 1 + 10)
408 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
409 * used by orginal MUI and also some
413 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
417 for (i
= 0; i
< new_columns
; i
++)
419 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
420 data
->ci
[i
].weight
= 100;
421 data
->ci
[i
].delta
= 4;
422 data
->ci
[i
].min_width
= -1;
423 data
->ci
[i
].max_width
= -1;
424 data
->ci
[i
].user_width
= -1;
425 data
->ci
[i
].bar
= FALSE
;
426 data
->ci
[i
].preparse
= NULL
;
429 if ((format_sep
= StrDup(format
)) != 0)
431 for (i
= 0; format_sep
[i
] != '\0'; i
++)
433 if (format_sep
[i
] == ',')
434 format_sep
[i
] = '\0';
437 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
443 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
444 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
445 rdargs
->RDA_Source
.CS_CurChr
= 0;
446 rdargs
->RDA_DAList
= 0;
447 rdargs
->RDA_Buffer
= NULL
;
448 rdargs
->RDA_BufSiz
= 0;
449 rdargs
->RDA_ExtHelp
= NULL
;
450 rdargs
->RDA_Flags
= 0;
452 memset(args
, 0, sizeof args
);
453 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
456 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
457 if (args
[ARG_WEIGHT
])
458 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
460 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
461 if (args
[ARG_MINWIDTH
])
462 data
->ci
[i
].min_width
=
463 *(LONG
*) args
[ARG_MINWIDTH
];
464 if (args
[ARG_MAXWIDTH
])
465 data
->ci
[i
].max_width
=
466 *(LONG
*) args
[ARG_MAXWIDTH
];
467 data
->ci
[i
].bar
= args
[ARG_BAR
];
468 if (args
[ARG_PREPARSE
])
469 data
->ci
[i
].preparse
=
470 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
474 ptr
+= strlen(ptr
) + 1;
477 while (i
< new_columns
);
478 FreeDosObject(DOS_RDARGS
, rdargs
);
483 for (i
= 0; i
< new_columns
; i
++)
485 D(bug("colno %d weight %d delta %d preparse %s\n",
486 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
487 data
->ci
[i
].preparse
));
490 data
->columns
= new_columns
;
491 data
->strings
++; /* Skip entry pos */
496 /**************************************************************************
497 Call the MUIM_List_Display for the given entry. It fills out
498 data->string and data->preparses
499 **************************************************************************/
500 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
502 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
506 for (col
= 0; col
< data
->columns
; col
++)
507 data
->preparses
[col
] = data
->ci
[col
].preparse
;
509 if (entry_pos
== ENTRY_TITLE
)
511 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
513 *data
->strings
= data
->title
;
516 entry_data
= NULL
; /* it's a title request */
519 entry_data
= data
->entries
[entry_pos
]->data
;
521 /* Get the display formation */
522 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
523 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
526 /**************************************************************************
527 Determine the dims of a single entry and adapt the columninfo according
528 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
529 be redrawn after this operation, 1 if all entries need to be redrawn.
530 **************************************************************************/
531 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
533 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
534 struct ListEntry
*entry
= data
->entries
[pos
];
541 if (!(_flags(obj
) & MADF_SETUP
))
544 DisplayEntry(cl
, obj
, pos
);
546 /* Set height to at least minheight */
547 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
548 data
->entries
[pos
]->height
= data
->entry_minheight
;
550 for (j
= 0; j
< data
->columns
; j
++)
553 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
557 zune_text_get_bounds(text
, obj
);
559 if (text
->height
> data
->entries
[pos
]->height
)
561 data
->entries
[pos
]->height
= text
->height
;
562 /* entry height changed, redraw all entries later */
565 data
->entries
[pos
]->widths
[j
] = text
->width
;
567 if (text
->width
> data
->ci
[j
].entries_width
)
569 /* This columns width is bigger than the other in the same
570 * columns, so we store this value
572 data
->ci
[j
].entries_width
= text
->width
;
573 /* column width changed, redraw all entries later */
577 zune_text_destroy(text
);
580 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
582 data
->entry_maxheight
= data
->entries
[pos
]->height
;
583 /* maximum entry height changed, redraw all entries later */
590 /**************************************************************************
591 Determine the widths of the entries
592 **************************************************************************/
593 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
596 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
598 if (!(_flags(obj
) & MADF_SETUP
))
601 for (j
= 0; j
< data
->columns
; j
++)
602 data
->ci
[j
].entries_width
= 0;
604 data
->entry_maxheight
= 0;
605 data
->entries_totalheight
= 0;
606 data
->entries_maxwidth
= 0;
608 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
610 CalcDimsOfEntry(cl
, obj
, i
);
611 data
->entries_totalheight
+= data
->entries
[i
]->height
;
614 for (j
= 0; j
< data
->columns
; j
++)
615 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
617 if (!data
->entry_maxheight
)
618 data
->entry_maxheight
= 1;
621 /**************************************************************************
622 Calculates the number of visible entry lines. Returns 1 if it has
624 **************************************************************************/
625 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
627 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
628 int old_entries_visible
= data
->entries_visible
;
629 int old_entries_top_pixel
= data
->entries_top_pixel
;
631 data
->entries_visible
= (_mheight(obj
) - data
->title_height
)
632 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
634 /* Distribute extra vertical space evenly between top and bottom of
637 data
->entries_top_pixel
= _mtop(obj
) + data
->title_height
638 + (_mheight(obj
) - data
->title_height
640 data
->entries_visible
*
641 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
643 return (old_entries_visible
!= data
->entries_visible
)
644 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
647 /**************************************************************************
648 Default hook to compare two list entries. Works for strings only.
649 **************************************************************************/
650 AROS_UFH3S(int, default_compare_func
,
651 AROS_UFHA(struct Hook
*, h
, A0
),
652 AROS_UFHA(char *, s2
, A2
),
653 AROS_UFHA(char *, s1
, A1
))
657 return Stricmp(s1
, s2
);
662 /**************************************************************************
664 **************************************************************************/
665 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
667 struct MUI_ListData
*data
;
669 struct TagItem
*tags
;
671 LONG new_entries_active
= MUIV_List_Active_Off
;
673 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
674 MUIA_Font
, MUIV_Font_List
,
675 MUIA_ShowSelState
, FALSE
,
676 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
677 MUIA_Background
, MUII_ListBack
, TAG_MORE
, (IPTR
) msg
->ops_AttrList
);
681 data
= INST_DATA(cl
, obj
);
684 data
->entries_active
= MUIV_List_Active_Off
;
685 data
->intern_puddle_size
= 2008;
686 data
->intern_thresh_size
= 1024;
687 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
688 data
->default_compare_hook
.h_SubEntry
= 0;
689 data
->compare_hook
= &(data
->default_compare_hook
);
690 data
->flags
= LIST_SHOWDROPMARKS
;
692 /* parse initial taglist */
693 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
697 case MUIA_List_Active
:
698 new_entries_active
= tag
->ti_Data
;
702 data
->pool
= (APTR
) tag
->ti_Data
;
705 case MUIA_List_PoolPuddleSize
:
706 data
->intern_puddle_size
= tag
->ti_Data
;
709 case MUIA_List_PoolThreshSize
:
710 data
->intern_thresh_size
= tag
->ti_Data
;
713 case MUIA_List_CompareHook
:
714 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
715 if (data
->compare_hook
== NULL
)
716 data
->compare_hook
= &data
->default_compare_hook
;
719 case MUIA_List_ConstructHook
:
720 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
723 case MUIA_List_DestructHook
:
724 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
727 case MUIA_List_DisplayHook
:
728 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
731 case MUIA_List_MultiTestHook
:
732 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
735 case MUIA_List_SourceArray
:
736 array
= (APTR
*) tag
->ti_Data
;
739 case MUIA_List_Format
:
740 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
743 case MUIA_List_Title
:
744 data
->title
= (STRPTR
) tag
->ti_Data
;
747 case MUIA_List_MinLineHeight
:
748 data
->entry_minheight
= tag
->ti_Data
;
751 case MUIA_List_AdjustHeight
:
752 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
755 case MUIA_List_AdjustWidth
:
756 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
759 case MUIA_List_AutoVisible
:
760 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
763 case MUIA_List_ShowDropMarks
:
764 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
767 case MUIA_List_DragSortable
:
768 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
769 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
776 /* No memory pool given, so we create our own */
777 data
->pool
= data
->intern_pool
=
778 CreatePool(0, data
->intern_puddle_size
,
779 data
->intern_thresh_size
);
782 CoerceMethod(cl
, obj
, OM_DISPOSE
);
787 /* parse the list format */
788 if (!(ParseListFormat(data
, data
->format
)))
790 CoerceMethod(cl
, obj
, OM_DISPOSE
);
794 /* This is neccessary for at least the title */
795 if (!SetListSize(data
, 0))
797 CoerceMethod(cl
, obj
, OM_DISPOSE
);
803 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
805 CoerceMethod(cl
, obj
, OM_DISPOSE
);
810 data
->entries
[ENTRY_TITLE
] = NULL
;
815 /* Count the number of elements */
816 for (i
= 0; array
[i
] != NULL
; i
++)
819 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
820 MUIV_List_Insert_Top
);
823 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
825 switch (new_entries_active
)
827 case MUIV_List_Active_Top
:
828 new_entries_active
= 0;
831 case MUIV_List_Active_Bottom
:
832 new_entries_active
= data
->entries_num
- 1;
836 if (new_entries_active
< 0)
837 new_entries_active
= 0;
838 else if (new_entries_active
>= data
->entries_num
)
839 new_entries_active
= data
->entries_num
- 1;
841 data
->entries_active
= new_entries_active
;
842 /* Selected entry will be moved into visible area */
845 NewList((struct List
*)&data
->images
);
847 D(bug("List_New(%lx)\n", obj
));
852 /**************************************************************************
854 **************************************************************************/
855 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
857 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
859 D(bug("List Dispose\n"));
861 /* Call destruct method for every entry and free the entries manually
862 * to avoid notification */
863 while (data
->confirm_entries_num
)
865 struct ListEntry
*lentry
=
866 data
->entries
[--data
->confirm_entries_num
];
867 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
869 FreeListEntry(data
, lentry
);
872 if (data
->intern_pool
)
873 DeletePool(data
->intern_pool
);
875 FreeVec(data
->entries
- 1);
876 /* title is currently before all other elements */
878 FreeListFormat(data
);
879 FreeVec(data
->format
);
881 return DoSuperMethodA(cl
, obj
, msg
);
885 /**************************************************************************
887 **************************************************************************/
888 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
890 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
892 struct TagItem
*tags
;
895 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
899 case MUIA_List_CompareHook
:
900 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
901 if (data
->compare_hook
== NULL
)
902 data
->compare_hook
= &data
->default_compare_hook
;
905 case MUIA_List_ConstructHook
:
906 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
909 case MUIA_List_DestructHook
:
910 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
913 case MUIA_List_DisplayHook
:
914 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
917 case MUIA_List_MultiTestHook
:
918 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
919 if (data
->multi_test_hook
!= NULL
)
921 /* Clearing current selections is the easiest way to keep
922 * selections consistent with the new hook */
923 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
924 MUIV_List_Select_Off
, NULL
);
928 case MUIA_List_Title
:
929 data
->title
= (STRPTR
) tag
->ti_Data
;
930 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
933 case MUIA_List_VertProp_First
:
934 data
->vertprop_first
= tag
->ti_Data
;
935 if (data
->entries_first
!= tag
->ti_Data
)
937 set(obj
, MUIA_List_First
, tag
->ti_Data
);
941 case MUIA_List_Format
:
942 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
943 ParseListFormat(data
, data
->format
);
944 // FIXME: should we check for errors?
945 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
948 case MUIA_List_VertProp_Entries
:
949 data
->vertprop_entries
= tag
->ti_Data
;
952 case MUIA_List_VertProp_Visible
:
953 data
->vertprop_visible
= tag
->ti_Data
;
954 data
->entries_visible
= tag
->ti_Data
;
957 case MUIA_List_Active
:
959 LONG new_entries_active
= tag
->ti_Data
;
961 if ((data
->entries_num
)
962 && (new_entries_active
!= MUIV_List_Active_Off
))
964 switch (new_entries_active
)
966 case MUIV_List_Active_Top
:
967 new_entries_active
= 0;
970 case MUIV_List_Active_Bottom
:
971 new_entries_active
= data
->entries_num
- 1;
974 case MUIV_List_Active_Up
:
975 new_entries_active
= data
->entries_active
- 1;
978 case MUIV_List_Active_Down
:
979 new_entries_active
= data
->entries_active
+ 1;
982 case MUIV_List_Active_PageUp
:
984 data
->entries_active
- data
->entries_visible
;
987 case MUIV_List_Active_PageDown
:
989 data
->entries_active
+ data
->entries_visible
;
993 if (new_entries_active
< 0)
994 new_entries_active
= 0;
995 else if (new_entries_active
>= data
->entries_num
)
996 new_entries_active
= data
->entries_num
- 1;
999 new_entries_active
= -1;
1001 if (data
->entries_active
!= new_entries_active
)
1003 LONG old
= data
->entries_active
;
1004 data
->entries_active
= new_entries_active
;
1006 /* Selectchange stuff */
1007 if (new_entries_active
!= -1)
1009 DoMethod(obj
, MUIM_List_SelectChange
,
1010 new_entries_active
, MUIV_List_Select_On
, 0);
1011 DoMethod(obj
, MUIM_List_SelectChange
,
1012 new_entries_active
, MUIV_List_Select_Active
, 0);
1015 DoMethod(obj
, MUIM_List_SelectChange
,
1016 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1019 data
->update_pos
= old
;
1020 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1022 data
->update_pos
= data
->entries_active
;
1023 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1025 /* Make new active entry visible (if there is one and
1027 if (new_entries_active
!= -1
1028 && (_flags(obj
) & MADF_SETUP
))
1030 DoMethod(obj
, MUIM_List_Jump
,
1031 MUIV_List_Jump_Active
);
1037 case MUIA_List_First
:
1038 data
->update_pos
= data
->entries_first
;
1040 data
->entries_first
= tag
->ti_Data
;
1042 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1043 if ((data
->vertprop_first
!= tag
->ti_Data
)
1044 && (!(data
->flags
& LIST_QUIET
)))
1046 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1050 case MUIA_List_Visible
: /* Shouldn't be settable? */
1051 if (data
->vertprop_visible
!= tag
->ti_Data
)
1052 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1055 case MUIA_List_Entries
:
1056 if (data
->confirm_entries_num
== tag
->ti_Data
)
1058 data
->entries_num
= tag
->ti_Data
;
1059 if (!(data
->flags
& LIST_QUIET
))
1061 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1066 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1070 case MUIA_List_Quiet
:
1071 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1074 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1075 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1076 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1077 if (data
->vertprop_first
!=
1078 XGET(obj
, MUIA_List_VertProp_First
))
1079 set(obj
, MUIA_List_VertProp_First
, data
->vertprop_first
);
1083 case MUIA_List_AutoVisible
:
1084 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1087 case MUIA_List_ShowDropMarks
:
1088 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1091 case MUIA_List_DragSortable
:
1092 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1093 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1097 /* Swallow this so the Area class doesn't redraw us */
1098 tag
->ti_Tag
= TAG_IGNORE
;
1103 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1106 /**************************************************************************
1108 **************************************************************************/
1109 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1111 /* small macro to simplify return value storage */
1112 #define STORE *(msg->opg_Storage)
1113 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1115 switch (msg
->opg_AttrID
)
1117 case MUIA_List_Entries
:
1118 STORE
= data
->entries_num
;
1120 case MUIA_List_First
:
1121 STORE
= data
->entries_first
;
1123 case MUIA_List_Active
:
1124 STORE
= data
->entries_active
;
1126 case MUIA_List_InsertPosition
:
1127 STORE
= data
->insert_position
;
1129 case MUIA_List_Title
:
1130 STORE
= (IPTR
) data
->title
;
1132 case MUIA_List_VertProp_Entries
:
1133 STORE
= data
->vertprop_entries
;
1135 case MUIA_List_VertProp_Visible
:
1136 case MUIA_List_Visible
:
1137 STORE
= data
->vertprop_visible
;
1139 case MUIA_List_VertProp_First
:
1140 STORE
= data
->vertprop_first
;
1142 case MUIA_List_Format
:
1143 STORE
= (IPTR
) data
->format
;
1145 case MUIA_List_AutoVisible
:
1146 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1148 case MUIA_List_ShowDropMarks
:
1149 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1151 case MUIA_List_DragSortable
:
1152 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1157 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1163 /**************************************************************************
1165 **************************************************************************/
1166 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1167 struct MUIP_Setup
*msg
)
1169 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1171 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1174 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1175 data
->prefs_linespacing
=
1176 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1177 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1178 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1180 CalcWidths(cl
, obj
);
1183 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1185 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1187 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1192 /**************************************************************************
1194 **************************************************************************/
1195 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1196 struct MUIP_Cleanup
*msg
)
1198 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1199 struct ListImage
*li
= List_First(&data
->images
);
1203 struct ListImage
*next
= Node_Next(li
);
1204 DoMethod(obj
, MUIM_List_DeleteImage
, (IPTR
) li
);
1208 zune_imspec_cleanup(data
->list_cursor
);
1209 zune_imspec_cleanup(data
->list_select
);
1210 zune_imspec_cleanup(data
->list_selcur
);
1212 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1215 /**************************************************************************
1217 **************************************************************************/
1218 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1219 struct MUIP_AskMinMax
*msg
)
1221 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1223 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1226 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1228 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1229 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1230 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1234 msg
->MinMaxInfo
->MinWidth
+= 40;
1235 msg
->MinMaxInfo
->DefWidth
+= 100;
1236 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1239 if (data
->entries_num
> 0)
1241 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1243 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1244 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1245 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1249 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1250 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1251 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1252 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1257 msg
->MinMaxInfo
->MinHeight
+= 36;
1258 msg
->MinMaxInfo
->DefHeight
+= 96;
1259 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1261 D(bug("List %p minheigh=%d, line maxh=%d\n",
1262 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1266 /****i*************************************************************************************
1288 *****************************************************************************************/
1291 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1292 struct MUIP_Layout
*msg
)
1294 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1295 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1296 LONG new_entries_first
= data
->entries_first
;
1298 /* Calc the numbers of entries visible */
1299 CalcVertVisible(cl
, obj
);
1301 /* Ensure active entry is visible if requested */
1302 if (data
->entries_active
+ 1 >=
1303 (data
->entries_first
+ data
->entries_visible
)
1304 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1306 data
->entries_active
- data
->entries_visible
+ 1;
1308 /* Ensure there are no unnecessary empty lines */
1309 if ((new_entries_first
+ data
->entries_visible
>=
1311 && (data
->entries_visible
<= data
->entries_num
))
1312 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1314 /* Always show the start of the list if it isn't long enough to fill the
1316 if (data
->entries_num
<= data
->entries_visible
)
1317 new_entries_first
= 0;
1319 if (new_entries_first
< 0)
1320 new_entries_first
= 0;
1322 set(obj
, new_entries_first
!= data
->entries_first
?
1323 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1325 /* So the notify happens */
1326 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1332 /**************************************************************************
1334 **************************************************************************/
1335 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1336 struct MUIP_Show
*msg
)
1338 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1339 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1341 zune_imspec_show(data
->list_cursor
, obj
);
1342 zune_imspec_show(data
->list_select
, obj
);
1343 zune_imspec_show(data
->list_selcur
, obj
);
1348 /**************************************************************************
1350 **************************************************************************/
1351 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1352 struct MUIP_Hide
*msg
)
1354 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1356 zune_imspec_hide(data
->list_cursor
);
1357 zune_imspec_hide(data
->list_select
);
1358 zune_imspec_hide(data
->list_selcur
);
1360 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1364 /**************************************************************************
1365 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1367 **************************************************************************/
1368 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1371 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1374 /* To be sure we don't draw anything if there is no title */
1375 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1378 DisplayEntry(cl
, obj
, entry_pos
);
1381 for (col
= 0; col
< data
->columns
; col
++)
1384 x2
= x1
+ data
->ci
[col
].entries_width
;
1387 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1388 ZTEXT_ARG_NONE
, 0)))
1390 /* Could be made simpler, as we don't really need the bounds */
1391 zune_text_get_bounds(text
, obj
);
1392 /* Note, this was MPEN_SHADOW before */
1393 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1394 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1395 zune_text_destroy(text
);
1397 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1401 /**************************************************************************
1403 **************************************************************************/
1404 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1406 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1410 BOOL scroll_caused_damage
= FALSE
;
1411 struct MUI_ImageSpec_intern
*highlight
;
1413 if (data
->flags
& LIST_QUIET
)
1416 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1418 /* Calculate the title height */
1421 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1425 data
->title_height
= 0;
1428 /* Calc the numbers of entries visible */
1429 CalcVertVisible(cl
, obj
);
1431 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1433 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), _mtop(obj
),
1434 _mwidth(obj
), _mheight(obj
),
1435 0, data
->entries_first
* data
->entry_maxheight
, 0);
1438 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(obj
), _mtop(obj
),
1439 _mwidth(obj
), _mheight(obj
));
1441 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1446 if (data
->title_height
&& data
->title
)
1448 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1449 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1450 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1451 Move(_rp(obj
), _mleft(obj
), y
);
1452 Draw(_rp(obj
), _mright(obj
), y
);
1453 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1455 Move(_rp(obj
), _mleft(obj
), y
);
1456 Draw(_rp(obj
), _mright(obj
), y
);
1460 y
= data
->entries_top_pixel
;
1462 start
= data
->entries_first
;
1463 end
= data
->entries_first
+ data
->entries_visible
;
1465 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1467 int diffy
= data
->entries_first
- data
->update_pos
;
1469 if (abs(diffy
) < data
->entries_visible
)
1471 scroll_caused_damage
=
1472 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1474 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1477 y
+ data
->entry_maxheight
* data
->entries_visible
);
1479 scroll_caused_damage
=
1480 scroll_caused_damage
1481 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1485 start
= end
- diffy
;
1486 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1490 end
= start
- diffy
;
1494 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1496 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), top
,
1497 _mwidth(obj
), bottom
- top
+ 1,
1499 top
- _mtop(obj
) + data
->entries_first
* data
->entry_maxheight
,
1503 for (entry_pos
= start
;
1504 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1506 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1508 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1509 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1510 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1511 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1512 && data
->update_pos
== entry_pos
))
1514 /* Choose appropriate highlight image */
1516 if (entry_pos
== data
->entries_active
1517 && entry
->flags
& ENTRY_SELECTED
)
1518 highlight
= data
->list_selcur
;
1519 else if (entry_pos
== data
->entries_active
)
1520 highlight
= data
->list_cursor
;
1521 else if (entry
->flags
& ENTRY_SELECTED
)
1522 highlight
= data
->list_select
;
1526 /* Draw highlight or background */
1528 if (highlight
!= NULL
)
1530 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1531 _mleft(obj
), y
, _mwidth(obj
), data
->entry_maxheight
,
1532 0, y
- data
->entries_top_pixel
, 0);
1534 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1535 && data
->update_pos
== entry_pos
)
1537 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), y
,
1538 _mwidth(obj
), data
->entry_maxheight
, 0,
1540 data
->entries_first
* data
->entry_maxheight
, 0);
1543 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1545 y
+= data
->entry_maxheight
;
1548 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1552 if (scroll_caused_damage
)
1554 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1556 /* Theoretically it might happen that more damage is caused
1557 after ScrollRaster. By something else, like window movement
1558 in front of our window. Therefore refresh root object of
1559 window, not just this object */
1563 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1564 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1566 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1570 ULONG x1
= _mleft(obj
);
1574 if (data
->title_height
&& data
->title
)
1576 for (col
= 0; col
< data
->columns
; col
++)
1578 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1579 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1581 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(obj
))
1584 if (data
->ci
[col
].bar
)
1586 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1587 Move(_rp(obj
), x1
, y
);
1589 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1590 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1591 Move(_rp(obj
), x1
+ 1, y
);
1592 Draw(_rp(obj
), x1
+ 1,
1593 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1597 x1
+= data
->ci
[col
].delta
- halfdelta
;
1599 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1604 for (col
= 0; col
< data
->columns
; col
++)
1606 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1607 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1609 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(obj
))
1612 if (data
->ci
[col
].bar
)
1614 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1615 Move(_rp(obj
), x1
, y
);
1616 Draw(_rp(obj
), x1
, _mbottom(obj
));
1617 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1618 Move(_rp(obj
), x1
+ 1, y
);
1619 Draw(_rp(obj
), x1
+ 1, _mbottom(obj
));
1624 x1
+= data
->ci
[col
].delta
- halfdelta
;
1630 /*****************************************************************************************
1636 DoMethod(obj, MUIM_List_Clear);
1642 Removes all entries from the list.
1655 *****************************************************************************************/
1658 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
1659 struct MUIP_List_Clear
*msg
)
1661 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1663 while (data
->confirm_entries_num
)
1665 struct ListEntry
*lentry
=
1666 data
->entries
[--data
->confirm_entries_num
];
1667 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1669 FreeListEntry(data
, lentry
);
1671 /* Should never fail when shrinking */
1672 SetListSize(data
, 0);
1675 if (data
->confirm_entries_num
!= data
->entries_num
)
1677 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
1678 /* Notify only when no entry was active */
1679 data
->entries_active
!=
1680 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
1681 MUIV_List_Active_Off
, TAG_DONE
);
1684 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1690 /**************************************************************************
1692 **************************************************************************/
1693 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
1694 struct MUIP_List_Exchange
*msg
)
1696 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1701 case MUIV_List_Exchange_Top
:
1704 case MUIV_List_Exchange_Active
:
1705 pos1
= data
->entries_active
;
1707 case MUIV_List_Exchange_Bottom
:
1708 pos1
= data
->entries_num
- 1;
1716 case MUIV_List_Exchange_Top
:
1719 case MUIV_List_Exchange_Active
:
1720 pos2
= data
->entries_active
;
1722 case MUIV_List_Exchange_Bottom
:
1723 pos2
= data
->entries_num
- 1;
1725 case MUIV_List_Exchange_Next
:
1728 case MUIV_List_Exchange_Previous
:
1735 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
1736 && pos2
< data
->entries_num
&& pos1
!= pos2
)
1738 struct ListEntry
*save
= data
->entries
[pos1
];
1739 data
->entries
[pos1
] = data
->entries
[pos2
];
1740 data
->entries
[pos2
] = save
;
1743 data
->update_pos
= pos1
;
1744 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1747 data
->update_pos
= pos2
;
1748 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1758 /**************************************************************************
1760 **************************************************************************/
1761 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
1762 struct MUIP_List_Redraw
*msg
)
1764 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1766 if (!(data
->flags
& LIST_QUIET
))
1768 if (msg
->pos
== MUIV_List_Redraw_All
)
1771 CalcWidths(cl
, obj
);
1772 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1777 if (msg
->pos
== MUIV_List_Redraw_Active
)
1778 pos
= data
->entries_active
;
1779 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
1782 for (i
= 0; i
< data
->entries_num
; i
++)
1783 if (data
->entries
[i
]->data
== msg
->entry
)
1794 if (CalcDimsOfEntry(cl
, obj
, pos
))
1799 data
->update_pos
= pos
;
1801 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1808 /**************************************************************************
1810 **************************************************************************/
1811 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
1812 struct MUIP_List_Remove
*msg
)
1814 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1817 struct ListEntry
*lentry
;
1818 //int rem_count = 1;
1820 if (!data
->entries_num
)
1825 case MUIV_List_Remove_First
:
1829 case MUIV_List_Remove_Active
:
1830 pos
= data
->entries_active
;
1833 case MUIV_List_Remove_Last
:
1834 pos
= data
->entries_num
- 1;
1837 case MUIV_List_Remove_Selected
:
1838 /* TODO: needs special handling */
1839 pos
= data
->entries_active
;
1847 if (pos
< 0 || pos
>= data
->entries_num
)
1850 new_act
= data
->entries_active
;
1852 if (pos
== new_act
&& new_act
== data
->entries_num
- 1)
1853 new_act
--; /* might become MUIV_List_Active_Off */
1855 lentry
= data
->entries
[pos
];
1856 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1861 RemoveListEntries(data
, pos
, cur
- pos
);
1862 data
->confirm_entries_num
-= cur
- pos
;
1864 /* ensure that the active element is in a valid range */
1865 if (new_act
>= data
->entries_num
)
1866 new_act
= data
->entries_num
- 1;
1868 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
,
1869 (new_act
>= pos
) || (new_act
!= data
->entries_active
) ?
1870 MUIA_List_Active
: TAG_DONE
,
1871 new_act
, /* Inform only if neccessary (for notify) */
1875 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1880 /**************************************************************************
1882 **************************************************************************/
1883 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
1884 struct MUIP_List_Select
*msg
)
1886 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1887 LONG pos
, i
, count
, selcount
=0, state
=0;
1888 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
1890 /* Establish the range of entries affected */
1893 case MUIV_List_Select_Active
:
1894 pos
= data
->entries_active
;
1895 if (pos
== MUIV_List_Active_Off
)
1901 case MUIV_List_Select_All
:
1903 count
= data
->entries_num
;
1909 if (pos
< 0 || pos
>= data
->entries_num
)
1914 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
1916 /* Disallow selection of an additional entry if there is a currently
1917 selected entry that is not multi-selectable (in such case there
1918 will only be one entry currently selected, so no need to iterate) */
1919 i
= MUIV_List_NextSelected_Start
;
1920 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
1921 if (i
!= MUIV_List_NextSelected_End
)
1923 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
1924 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
1925 data
->entries
[i
]->data
);
1928 /* Change or check state of each entry in the range */
1929 for (i
= pos
; i
< pos
+ count
; i
++)
1931 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
1932 switch (msg
->seltype
)
1934 case MUIV_List_Select_Off
:
1935 new_select_state
= FALSE
;
1938 case MUIV_List_Select_On
:
1939 new_select_state
= TRUE
;
1942 case MUIV_List_Select_Toggle
:
1943 new_select_state
= !state
;
1947 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
1952 if (msg
->seltype
!= MUIV_List_Select_Ask
)
1954 /* Disallow selection if entry is not multi-selectable and
1955 * there are already selected entries */
1956 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
1957 new_select_state
= multi_allowed
&& (selcount
== 0 ||
1958 CallHookPkt(data
->multi_test_hook
, NULL
,
1959 data
->entries
[i
]->data
));
1961 if (new_select_state
)
1962 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
1964 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
1968 /* Report old state or number of selected entries */
1971 if (msg
->pos
== MUIV_List_Select_All
1972 && msg
->seltype
== MUIV_List_Select_Ask
)
1973 *msg
->info
= selcount
;
1978 /* Redraw unless it was just an enquiry */
1979 if (msg
->seltype
!= MUIV_List_Select_Ask
)
1986 data
->update_pos
= pos
;
1988 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1994 /**************************************************************************
1996 **************************************************************************/
1998 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
1999 struct MUIP_List_Insert
*msg
)
2001 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2002 LONG pos
, count
, sort
;
2009 /* Count the number of entries */
2010 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2019 case MUIV_List_Insert_Top
:
2023 case MUIV_List_Insert_Active
:
2024 if (data
->entries_active
!= -1)
2025 pos
= data
->entries_active
;
2030 case MUIV_List_Insert_Sorted
:
2031 pos
= data
->entries_num
;
2032 sort
= 1; /* we sort'em later */
2035 case MUIV_List_Insert_Bottom
:
2036 pos
= data
->entries_num
;
2040 if (msg
->pos
> data
->entries_num
)
2041 pos
= data
->entries_num
;
2042 else if (msg
->pos
< 0)
2049 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2052 LONG until
= pos
+ count
;
2053 APTR
*toinsert
= msg
->entries
;
2055 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2060 struct ListEntry
*lentry
;
2062 if (!(lentry
= AllocListEntry(data
)))
2064 /* Panic, but we must be in a consistent state, so remove
2065 * the space where the following list entries should have gone
2067 RemoveListEntries(data
, pos
, until
- pos
);
2071 /* now call the construct method which returns us a pointer which
2073 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2074 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2077 FreeListEntry(data
, lentry
);
2078 RemoveListEntries(data
, pos
, until
- pos
);
2080 /* TODO: Also check for visible stuff like below */
2081 if (data
->entries_num
!= data
->confirm_entries_num
)
2082 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2086 data
->entries
[pos
] = lentry
;
2087 data
->confirm_entries_num
++;
2089 if (_flags(obj
) & MADF_SETUP
)
2091 /* We have to calculate the width and height of the newly
2092 * inserted entry. This has to be done after inserting the
2093 * element into the list */
2094 CalcDimsOfEntry(cl
, obj
, pos
);
2101 /* Recalculate the number of visible entries */
2102 if (_flags(obj
) & MADF_SETUP
)
2103 CalcVertVisible(cl
, obj
);
2105 if (data
->entries_num
!= data
->confirm_entries_num
)
2108 MUIA_List_Entries
, data
->confirm_entries_num
,
2109 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2112 /* If the array is already sorted, we could do a simple insert
2113 * sort and would be much faster than with qsort.
2114 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2115 * sort the whole array?
2117 * I think, we better sort the whole array:
2121 DoMethod(obj
, MUIM_List_Sort
);
2122 /* TODO: which pos to return here !? */
2123 /* MUIM_List_Sort already called MUI_Redraw */
2128 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2130 data
->insert_position
= pos
;
2135 /**************************************************************************
2136 MUIM_List_InsertSingle
2137 **************************************************************************/
2138 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2139 struct MUIP_List_InsertSingle
*msg
)
2141 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2145 /**************************************************************************
2147 **************************************************************************/
2148 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2149 struct MUIP_List_GetEntry
*msg
)
2151 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2154 if (pos
== MUIV_List_GetEntry_Active
)
2155 pos
= data
->entries_active
;
2157 if (pos
< 0 || pos
>= data
->entries_num
)
2162 *msg
->entry
= data
->entries
[pos
]->data
;
2163 return (IPTR
) *msg
->entry
;
2166 /**************************************************************************
2168 **************************************************************************/
2169 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2170 struct MUIP_List_Construct
*msg
)
2172 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2174 if (NULL
== data
->construct_hook
)
2175 return (IPTR
) msg
->entry
;
2176 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2178 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2179 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2184 if (msg
->entry
!= NULL
)
2185 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2187 *(STRPTR
) (mem
+ 1) = 0;
2188 return (IPTR
) (mem
+ 1);
2190 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2193 /**************************************************************************
2195 **************************************************************************/
2196 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2197 struct MUIP_List_Destruct
*msg
)
2199 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2201 if (NULL
== data
->destruct_hook
)
2204 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2206 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2207 FreePooled(msg
->pool
, mem
, mem
[0]);
2211 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2216 /*****************************************************************************************
2222 DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2223 LONG sort_type1, LONG sort_type2);
2229 Compare two list entries according to the current comparison hook
2230 (MUIA_List_CompareHook).
2233 entry1 - the first entry data.
2234 entry2 - the second entry data.
2235 sort_type1 - undocumented.
2236 sort_type2 - undocumented.
2246 MUIA_List_CompareHook, MUIM_List_Sort.
2250 *****************************************************************************************/
2253 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2254 struct MUIP_List_Compare
*msg
)
2256 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2258 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2261 /**************************************************************************
2263 **************************************************************************/
2264 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2265 struct MUIP_List_Display
*msg
)
2267 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2269 if (NULL
== data
->display_hook
)
2272 *msg
->array
= msg
->entry
;
2278 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2279 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2282 /**************************************************************************
2283 MUIM_List_SelectChange
2284 **************************************************************************/
2285 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2286 struct MUIP_List_SelectChange
*msg
)
2291 /**************************************************************************
2292 MUIM_List_CreateImage
2293 Called by a List subclass in its Setup method.
2294 Connects an Area subclass object to the list, much like an object gets
2295 connected to a window. List calls Setup and AskMinMax on that object,
2296 keeps a reference to it (that reference will be returned).
2297 Text engine will dereference that pointer and draw the object with its
2299 **************************************************************************/
2300 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2301 struct MUIP_List_CreateImage
*msg
)
2303 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2304 struct ListImage
*li
;
2306 /* List must be already setup in Setup of your subclass */
2307 if (!(_flags(obj
) & MADF_SETUP
))
2309 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2314 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2315 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2316 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2322 /**************************************************************************
2323 MUIM_List_DeleteImage
2324 **************************************************************************/
2325 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2326 struct MUIP_List_DeleteImage
*msg
)
2328 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2329 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2333 DoMethod(li
->obj
, MUIM_Cleanup
);
2334 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2335 Remove((struct Node
*)li
);
2336 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2342 /*****************************************************************************************
2348 DoMethod(obj, MUIM_List_Jump, LONG pos);
2354 Scrolls the list so that a particular entry is visible.
2357 pos - index of entry that should become visible, or one of these
2359 MUIV_List_Jump_Active: show the active entry.
2360 MUIV_List_Jump_Top: show the first entry.
2361 MUIV_List_Jump_Bottom: show the last entry.
2362 MUIV_List_Jump_Up: show the previous hidden entry.
2363 MUIV_List_Jump_Down: show the next hidden entry.
2376 *****************************************************************************************/
2378 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2379 struct MUIP_List_Jump
*msg
)
2381 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2382 LONG pos
= msg
->pos
;
2386 case MUIV_List_Jump_Top
:
2390 case MUIV_List_Jump_Active
:
2391 pos
= data
->entries_active
;
2394 case MUIV_List_Jump_Bottom
:
2395 pos
= data
->entries_num
- 1;
2398 case MUIV_List_Jump_Down
:
2399 pos
= data
->entries_first
+ data
->entries_visible
;
2402 case MUIV_List_Jump_Up
:
2403 pos
= data
->entries_first
- 1;
2407 if (pos
>= data
->entries_num
)
2409 pos
= data
->entries_num
- 1;
2414 if (pos
< data
->entries_first
)
2416 set(obj
, MUIA_List_First
, pos
);
2418 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2420 pos
-= (data
->entries_visible
- 1);
2423 if (pos
!= data
->entries_first
)
2425 set(obj
, MUIA_List_First
, pos
);
2432 /*****************************************************************************************
2438 DoMethod(obj, MUIM_List_Sort);
2444 Sort the list's entries according to the current comparison hook
2445 (MUIA_List_CompareHook).
2455 MUIA_List_CompareHook, MUIM_List_Compare.
2459 *****************************************************************************************/
2461 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2462 struct MUIP_List_Sort
*msg
)
2464 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2467 struct MUIP_List_Compare cmpmsg
=
2468 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2470 if (data
->entries_num
> 1)
2473 Simple sort algorithm. Feel free to improve it.
2475 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2478 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2480 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2481 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2482 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2489 APTR tmp
= data
->entries
[i
];
2490 data
->entries
[i
] = data
->entries
[max
];
2491 data
->entries
[max
] = tmp
;
2497 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2502 /*****************************************************************************************
2508 DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2514 Move a list entry to a new position.
2517 from - the current index of the entry that should be moved, or one of
2518 these special values:
2519 MUIV_List_Move_Active: the active entry.
2520 MUIV_List_Move_Top: the first entry.
2521 MUIV_List_Move_Bottom: the last entry.
2522 to - the index of the entry's new position, or one of
2523 these special values:
2524 MUIV_List_Move_Active: the active entry.
2525 MUIV_List_Move_Top: the first entry.
2526 MUIV_List_Move_Bottom: the last entry.
2539 *****************************************************************************************/
2541 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
2542 struct MUIP_List_Move
*msg
)
2544 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2549 /* Normalise special 'from' values */
2552 case MUIV_List_Move_Top
:
2555 case MUIV_List_Move_Active
:
2556 from
= data
->entries_active
;
2558 case MUIV_List_Move_Bottom
:
2559 from
= data
->entries_num
- 1;
2565 /* Normalise special 'to' values */
2568 case MUIV_List_Move_Top
:
2571 case MUIV_List_Move_Active
:
2572 to
= data
->entries_active
;
2574 case MUIV_List_Move_Bottom
:
2575 to
= data
->entries_num
- 1;
2577 case MUIV_List_Move_Next
:
2580 case MUIV_List_Move_Previous
:
2587 /* Check that values are within valid bounds */
2588 if (from
> data
->entries_num
- 1 || from
< 0
2589 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
2590 return (IPTR
) FALSE
;
2592 /* Shift all entries in the range between the 'from' and 'to' positions */
2595 struct ListEntry
*backup
= data
->entries
[from
];
2596 for (i
= from
; i
< to
; i
++)
2597 data
->entries
[i
] = data
->entries
[i
+ 1];
2598 data
->entries
[to
] = backup
;
2602 struct ListEntry
*backup
= data
->entries
[from
];
2603 for (i
= from
; i
> to
; i
--)
2604 data
->entries
[i
] = data
->entries
[i
- 1];
2605 data
->entries
[to
] = backup
;
2608 /* Update index of active entry */
2609 if (from
== data
->entries_active
)
2610 data
->entries_active
= to
;
2611 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
2612 data
->entries_active
--;
2613 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
2614 data
->entries_active
++;
2616 /* Reflect list changes visually */
2618 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2623 /**************************************************************************
2624 MUIM_List_NextSelected
2625 **************************************************************************/
2626 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
2627 struct MUIP_List_NextSelected
*msg
)
2629 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2633 /* Get the first entry to check */
2635 if (pos
== MUIV_List_NextSelected_Start
)
2640 /* Find the next selected entry */
2641 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
2643 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2650 /* Return index of selected entry, or indicate there are no more */
2652 pos
= MUIV_List_NextSelected_End
;
2658 /**************************************************************************
2660 **************************************************************************/
2661 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
2662 struct MUIP_List_TestPos
*msg
)
2664 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2665 struct MUI_List_TestPos_Result
*result
= msg
->res
;
2666 LONG col
= -1, row
= -1;
2668 LONG mx
= msg
->x
- _left(obj
);
2669 LONG entries_visible
;
2671 if (data
->entries_visible
<= data
->entries_num
)
2672 entries_visible
= data
->entries_visible
;
2674 entries_visible
= data
->entries_num
;
2675 LONG ey
= msg
->y
- data
->entries_top_pixel
;
2676 /* y coordinates transformed to the entries */
2678 /* Now check if it was clicked on a title or on entries */
2680 flags
|= MUI_LPR_ABOVE
;
2681 else if (ey
>= entries_visible
* data
->entry_maxheight
)
2682 flags
|= MUI_LPR_BELOW
;
2686 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
2688 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
2692 flags
|= MUI_LPR_LEFT
;
2693 else if (mx
>= _width(obj
))
2694 flags
|= MUI_LPR_RIGHT
;
2697 /* Identify column */
2698 if (data
->entries_num
> 0 && data
->columns
> 0)
2701 col
= data
->columns
- 1;
2702 for (i
= 0; i
< data
->columns
; i
++)
2704 result
->xoffset
= mx
- width_sum
;
2706 data
->ci
[i
].entries_width
+
2708 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
2709 D(bug("[List/MUIM_TestPos] i %d "
2710 "width %d width_sum %d mx %d\n",
2711 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
2715 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
2722 result
->entry
= row
;
2723 result
->column
= col
;
2724 result
->flags
= flags
;
2729 /****i*************************************************************************************
2751 *****************************************************************************************/
2753 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
2754 struct MUIP_DragQuery
*msg
)
2756 if (msg
->obj
== obj
)
2757 return MUIV_DragQuery_Accept
;
2759 return MUIV_DragQuery_Refuse
;
2762 /****i************************************************************************************
2784 *****************************************************************************************/
2786 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
2787 struct MUIP_DragFinish
*msg
)
2789 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2791 data
->drop_mark_y
= -1;
2793 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2797 /****i*************************************************************************************
2819 *****************************************************************************************/
2821 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
2822 struct MUIP_DragReport
*msg
)
2824 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2825 struct MUI_List_TestPos_Result pos
;
2826 struct RastPort
*rp
= _rp(obj
);
2830 /* Choose new drop mark position */
2832 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2833 if (pos
.entry
!= -1)
2836 if (pos
.yoffset
> 0)
2839 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2840 n
= data
->entries_first
;
2843 n
= MIN(data
->entries_visible
, data
->entries_num
)
2844 - data
->entries_first
;
2847 /* Clear old drop mark */
2849 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
2851 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
2852 * data
->entry_maxheight
;
2853 if (y
!= data
->drop_mark_y
)
2855 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), data
->drop_mark_y
,
2856 _mwidth(obj
), 1, 0, 0, 0);
2858 /* Draw new drop mark and store its position */
2860 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
2862 old_pattern
= rp
->LinePtrn
;
2863 SetDrPt(rp
, 0xF0F0);
2864 Move(rp
, _mleft(obj
), y
);
2865 Draw(rp
, _mright(obj
), y
);
2866 SetDrPt(rp
, old_pattern
);
2867 data
->drop_mark_y
= y
;
2874 /****i*************************************************************************************
2896 *****************************************************************************************/
2898 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
2899 struct MUIP_DragDrop
*msg
)
2901 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2902 struct MUI_List_TestPos_Result pos
;
2905 /* Find drop position */
2907 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2908 if (pos
.entry
!= -1)
2910 /* Change drop position when coords move past centre of entry, not
2914 if (pos
.yoffset
> 0)
2917 /* Ensure that dropped entry will be positioned between the two
2918 * entries that are above and below the drop mark, rather than
2919 * strictly at the numeric index shown */
2921 if (n
> data
->entries_active
)
2924 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2925 n
= MUIV_List_Move_Top
;
2927 n
= MUIV_List_Move_Bottom
;
2929 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
2934 /****i************************************************************************************
2937 MUIM_CreateDragImage
2956 *****************************************************************************************/
2958 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
2959 struct MUIP_CreateDragImage
*msg
)
2961 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2962 BOOL success
= TRUE
;
2963 struct MUI_List_TestPos_Result pos
;
2964 WORD width
, height
, left
, top
;
2965 struct MUI_DragImage
*img
= NULL
;
2966 const struct ZuneFrameGfx
*zframe
;
2969 /* Get info on dragged entry */
2970 DoMethod(obj
, MUIM_List_TestPos
, _left(obj
) - msg
->touchx
,
2971 _top(obj
) - msg
->touchy
, (IPTR
) &pos
);
2972 if (pos
.entry
== -1)
2977 /* Get boundaries of entry */
2978 width
= _mwidth(obj
);
2979 height
= data
->entry_maxheight
;
2981 top
= _top(obj
) - msg
->touchy
2982 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
2984 /* Allocate drag image structure */
2985 img
= (struct MUI_DragImage
*)
2986 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
2993 /* Get drag frame */
2994 zframe
= zune_zframe_get(obj
,
2995 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
2997 /* Allocate drag image buffer */
2998 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
2999 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3000 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3001 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3002 _screen(obj
)->RastPort
.BitMap
);
3004 if (img
->bm
!= NULL
)
3007 struct RastPort temprp
;
3008 InitRastPort(&temprp
);
3009 temprp
.BitMap
= img
->bm
;
3010 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3011 zframe
->ileft
, zframe
->itop
, width
, height
,
3015 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3016 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3017 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3018 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3019 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3022 /* Ensure drag point matches where user clicked */
3023 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3024 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3032 /**************************************************************************
3034 **************************************************************************/
3035 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3037 switch (msg
->MethodID
)
3040 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3042 return List__OM_DISPOSE(cl
, obj
, msg
);
3044 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3046 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3049 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3051 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3052 case MUIM_AskMinMax
:
3053 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3055 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3057 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3059 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3061 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3062 case MUIM_List_Clear
:
3063 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3064 case MUIM_List_Sort
:
3065 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3066 case MUIM_List_Exchange
:
3067 return List__MUIM_Exchange(cl
, obj
,
3068 (struct MUIP_List_Exchange
*)msg
);
3069 case MUIM_List_Insert
:
3070 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3071 case MUIM_List_InsertSingle
:
3072 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3073 case MUIM_List_GetEntry
:
3074 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3075 case MUIM_List_Redraw
:
3076 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3077 case MUIM_List_Remove
:
3078 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3079 case MUIM_List_Select
:
3080 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3081 case MUIM_List_Construct
:
3082 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3083 case MUIM_List_Destruct
:
3084 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3085 case MUIM_List_Compare
:
3086 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3087 case MUIM_List_Display
:
3088 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3089 case MUIM_List_SelectChange
:
3090 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3091 case MUIM_List_CreateImage
:
3092 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3093 case MUIM_List_DeleteImage
:
3094 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3095 case MUIM_List_Jump
:
3096 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3097 case MUIM_List_Move
:
3098 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3099 case MUIM_List_NextSelected
:
3100 return List__MUIM_NextSelected(cl
, obj
,
3101 (struct MUIP_List_NextSelected
*)msg
);
3102 case MUIM_List_TestPos
:
3103 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3104 case MUIM_DragQuery
:
3105 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3106 case MUIM_DragFinish
:
3107 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3108 case MUIM_DragReport
:
3109 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3111 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3112 case MUIM_CreateDragImage
:
3113 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3116 return DoSuperMethodA(cl
, obj
, msg
);
3118 BOOPSI_DISPATCHER_END
3123 const struct __MUIBuiltinClass _MUI_List_desc
=
3127 sizeof(struct MUI_ListData
),
3128 (void *) List_Dispatcher