2 Copyright © 2002-2015, The AROS Development Team. All rights reserved.
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <devices/rawkeycodes.h>
14 #include <clib/alib_protos.h>
15 #include <proto/exec.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
20 #include <proto/muimaster.h>
22 /* #define MYDEBUG 1 */
25 #include "muimaster_intern.h"
28 #include "textengine.h"
29 #include "listimage.h"
32 extern struct Library
*MUIMasterBase
;
34 #define ENTRY_TITLE (-1)
36 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
37 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
57 LONG
*widths
; /* Widths of the columns */
58 LONG width
; /* Line width */
59 LONG height
; /* Line height */
60 WORD flags
; /* see below */
63 #define ENTRY_SELECTED (1<<0)
68 int colno
; /* Column number */
69 int user_width
; /* user set width; -1 if entry width */
70 int min_width
; /* min width percentage */
71 int max_width
; /* min width percentage */
73 int delta
; /* ignored for the first and last column, defaults to 4 */
76 int entries_width
; /* width of the entries (maximum of all widths) */
79 struct MUI_ImageSpec_intern
;
86 APTR intern_pool
; /* The internal pool which the class has allocated */
87 LONG intern_puddle_size
;
88 LONG intern_thresh_size
;
89 APTR pool
; /* the pool which is used to allocate list entries */
91 struct Hook
*construct_hook
;
92 struct Hook
*compare_hook
;
93 struct Hook
*destruct_hook
;
94 struct Hook
*display_hook
;
95 struct Hook
*multi_test_hook
;
97 struct Hook default_compare_hook
;
99 /* List management, currently we use a simple flat array, which is not
100 * good if many entries are inserted/deleted */
101 LONG entries_num
; /* Number of Entries in the list */
102 LONG entries_allocated
;
103 struct ListEntry
**entries
;
105 LONG entries_first
; /* first visible entry */
106 LONG entries_visible
; /* number of visible entries,
107 * determined at MUIM_Layout */
109 LONG insert_position
; /* pos of the last insertion */
111 LONG entry_maxheight
; /* Maximum height of an entry */
112 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
114 LONG entries_totalheight
;
115 LONG entries_maxwidth
;
117 LONG vertprop_entries
;
118 LONG vertprop_visible
;
121 LONG confirm_entries_num
; /* These are the correct entries num, used
122 * so you cannot set MUIA_List_Entries to
125 LONG entries_top_pixel
; /* Where the entries start */
127 /* Column managment, is allocated by ParseListFormat() and freed
128 * by CleanListFormat() */
130 LONG columns
; /* Number of columns the list has */
131 struct ColumnInfo
*ci
;
133 STRPTR
*strings
; /* the strings for the display function, one
134 * more than needed (for the entry position) */
137 int title_height
; /* The complete height of the title */
138 STRPTR title
; /* On single column lists this is the title,
139 * otherwise 1. NULL for no title(s) */
142 struct MUI_ImageSpec_intern
*list_cursor
;
143 struct MUI_ImageSpec_intern
*list_select
;
144 struct MUI_ImageSpec_intern
*list_selcur
;
146 /* Render optimization */
147 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
148 * 3 - scroll to current entries_first (old value is in
155 struct MinList images
;
158 ListviewRefresh prefs_refresh
;
159 UWORD prefs_linespacing
;
161 UWORD prefs_smoothval
;
163 /* render space handling */
167 /***************************/
168 /* Former Listview members */
169 /***************************/
178 LONG def_click_column
;
180 LONG mouse_click
; /* see below if mouse is held down */
187 struct MUI_EventHandlerNode ehn
;
190 ListviewMulti prefs_multi
;
198 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
199 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
201 #define LIST_ADJUSTWIDTH (1<<0)
202 #define LIST_ADJUSTHEIGHT (1<<1)
203 #define LIST_AUTOVISIBLE (1<<2)
204 #define LIST_DRAGSORTABLE (1<<3)
205 #define LIST_SHOWDROPMARKS (1<<4)
206 #define LIST_QUIET (1<<5)
209 /****** List.mui/MUIA_List_CompareHook ***************************************
212 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
215 * The provided hook indicates the sort ordering of two list entries.
216 * The hook receives list-entry data pointers as its second and third
217 * arguments. The hook should return a negative value if the first entry
218 * should be placed before the second entry, a positive value if the
219 * first entry should be placed after the second entry, and zero if the
222 * In addition to being used internally for sorting operations, this hook
223 * will be called when MUIM_List_Compare is externally invoked.
225 * If this attribute is not specified or is set to NULL, all list entries
228 ******************************************************************************
232 /****** List.mui/MUIA_List_MultiTestHook *************************************
235 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
238 * The provided hook indicates whether a particular list entry
239 * may be multiselected. The hook receives the list-entry data pointer as
240 * its third argument, and returns a Boolean value. If this attribute is
241 * not specified or is set to NULL, all list entries are considered
244 * Whenever an entry is about to be selected, this hook is called if
245 * there are other entries already selected. If the hook returns TRUE,
246 * the entry may be multi-selected; if the hook returns FALSE, the entry
247 * remains unselected.
249 * Additionally, if a non-multi-selectable entry has been selected (as
250 * the only selected entry in the list), any attempt to select an
251 * additional entry will fail.
253 ******************************************************************************
257 /**************************************************************************
258 Allocate a single list entry, does not initialize it (except the pointer)
259 **************************************************************************/
260 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
263 struct ListEntry
*le
;
264 int size
= sizeof(struct ListEntry
) + sizeof(LONG
) * data
->columns
+ 4;
268 mem
= AllocPooled(data
->pool
, size
);
271 D(bug("List AllocListEntry %p, %ld bytes\n", mem
, size
));
273 mem
[0] = size
; /* Save the size */
274 le
= (struct ListEntry
*)(mem
+ 1);
275 le
->widths
= (LONG
*) (le
+ 1);
277 /* Initialize fields */
281 for (j
= 0; j
< data
->columns
; j
++)
287 /**************************************************************************
288 Deallocate a single list entry, does not deinitialize it
289 **************************************************************************/
290 static void FreeListEntry(struct MUI_ListData
*data
,
291 struct ListEntry
*entry
)
293 ULONG
*mem
= ((ULONG
*) entry
) - 1;
294 D(bug("FreeListEntry %p size=%ld\n", mem
, mem
[0]));
295 FreePooled(data
->pool
, mem
, mem
[0]);
298 /**************************************************************************
299 Ensures that there can be at least the given amount of entries within
300 the list. Returns 0 if not. It also allocates the space for the title.
301 It can be accessed with data->entries[ENTRY_TITLE]
302 **************************************************************************/
303 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
305 struct ListEntry
**new_entries
;
306 int new_entries_allocated
;
308 if (size
+ 1 <= data
->entries_allocated
)
311 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
312 if (new_entries_allocated
< size
+ 1)
313 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
315 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
316 new_entries_allocated
* sizeof(struct ListEntry
*)));
318 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
319 if (NULL
== new_entries
)
323 CopyMem(data
->entries
- 1, new_entries
,
324 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
325 FreeVec(data
->entries
- 1);
327 data
->entries
= new_entries
+ 1;
328 data
->entries_allocated
= new_entries_allocated
;
332 /**************************************************************************
333 Prepares the insertion of count entries at pos.
334 This function doesn't care if there is enough space in the datastructure.
335 SetListSize() must be used first.
336 With current implementation, this call will never fail
337 **************************************************************************/
338 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
341 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
342 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
346 /**************************************************************************
347 Removes count (already deinitalized) list entries starting az pos.
348 **************************************************************************/
349 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
351 // FIXME: segfault if entries_num = pos = count = 1
352 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
353 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
356 /**************************************************************************
357 Frees all memory allocated by ParseListFormat()
358 **************************************************************************/
359 static void FreeListFormat(struct MUI_ListData
*data
)
365 for (i
= 0; i
< data
->columns
; i
++)
367 FreeVec(data
->ci
[i
].preparse
);
368 data
->ci
[i
].preparse
= NULL
;
373 FreeVec(data
->preparses
);
374 data
->preparses
= NULL
;
377 FreeVec(data
->strings
- 1);
378 data
->strings
= NULL
;
383 /**************************************************************************
384 Parses the given format string (also frees a previously parsed format).
386 **************************************************************************/
387 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
395 struct RDArgs
*rdargs
;
398 format
= (STRPTR
) "";
402 FreeListFormat(data
);
406 /* Count the number of columns first */
411 if (!(data
->preparses
=
412 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
415 if (!(data
->strings
= AllocVec((new_columns
+ 1 + 10)
416 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
417 * used by orginal MUI and also some
421 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
425 for (i
= 0; i
< new_columns
; i
++)
427 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
428 data
->ci
[i
].weight
= 100;
429 data
->ci
[i
].delta
= 4;
430 data
->ci
[i
].min_width
= -1;
431 data
->ci
[i
].max_width
= -1;
432 data
->ci
[i
].user_width
= -1;
433 data
->ci
[i
].bar
= FALSE
;
434 data
->ci
[i
].preparse
= NULL
;
437 if ((format_sep
= StrDup(format
)) != 0)
439 for (i
= 0; format_sep
[i
] != '\0'; i
++)
441 if (format_sep
[i
] == ',')
442 format_sep
[i
] = '\0';
445 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
451 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
452 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
453 rdargs
->RDA_Source
.CS_CurChr
= 0;
454 rdargs
->RDA_DAList
= 0;
455 rdargs
->RDA_Buffer
= NULL
;
456 rdargs
->RDA_BufSiz
= 0;
457 rdargs
->RDA_ExtHelp
= NULL
;
458 rdargs
->RDA_Flags
= 0;
460 memset(args
, 0, sizeof args
);
461 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
464 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
465 if (args
[ARG_WEIGHT
])
466 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
468 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
469 if (args
[ARG_MINWIDTH
])
470 data
->ci
[i
].min_width
=
471 *(LONG
*) args
[ARG_MINWIDTH
];
472 if (args
[ARG_MAXWIDTH
])
473 data
->ci
[i
].max_width
=
474 *(LONG
*) args
[ARG_MAXWIDTH
];
475 data
->ci
[i
].bar
= args
[ARG_BAR
];
476 if (args
[ARG_PREPARSE
])
477 data
->ci
[i
].preparse
=
478 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
482 ptr
+= strlen(ptr
) + 1;
485 while (i
< new_columns
);
486 FreeDosObject(DOS_RDARGS
, rdargs
);
491 for (i
= 0; i
< new_columns
; i
++)
493 D(bug("colno %d weight %d delta %d preparse %s\n",
494 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
495 data
->ci
[i
].preparse
));
498 data
->columns
= new_columns
;
499 data
->strings
++; /* Skip entry pos */
504 /**************************************************************************
505 Call the MUIM_List_Display for the given entry. It fills out
506 data->string and data->preparses
507 **************************************************************************/
508 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
510 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
514 for (col
= 0; col
< data
->columns
; col
++)
515 data
->preparses
[col
] = data
->ci
[col
].preparse
;
517 if (entry_pos
== ENTRY_TITLE
)
519 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
521 *data
->strings
= data
->title
;
524 entry_data
= NULL
; /* it's a title request */
527 entry_data
= data
->entries
[entry_pos
]->data
;
529 /* Get the display formation */
530 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
531 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
534 /**************************************************************************
535 Determine the dims of a single entry and adapt the columninfo according
536 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
537 be redrawn after this operation, 1 if all entries need to be redrawn.
538 **************************************************************************/
539 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
541 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
542 struct ListEntry
*entry
= data
->entries
[pos
];
549 if (!(_flags(obj
) & MADF_SETUP
))
552 DisplayEntry(cl
, obj
, pos
);
554 /* Set height to at least minheight */
555 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
556 data
->entries
[pos
]->height
= data
->entry_minheight
;
558 for (j
= 0; j
< data
->columns
; j
++)
561 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
565 zune_text_get_bounds(text
, obj
);
567 if (text
->height
> data
->entries
[pos
]->height
)
569 data
->entries
[pos
]->height
= text
->height
;
570 /* entry height changed, redraw all entries later */
573 data
->entries
[pos
]->widths
[j
] = text
->width
;
575 if (text
->width
> data
->ci
[j
].entries_width
)
577 /* This columns width is bigger than the other in the same
578 * columns, so we store this value
580 data
->ci
[j
].entries_width
= text
->width
;
581 /* column width changed, redraw all entries later */
585 zune_text_destroy(text
);
588 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
590 data
->entry_maxheight
= data
->entries
[pos
]->height
;
591 /* maximum entry height changed, redraw all entries later */
598 /**************************************************************************
599 Determine the widths of the entries
600 **************************************************************************/
601 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
604 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
606 if (!(_flags(obj
) & MADF_SETUP
))
609 for (j
= 0; j
< data
->columns
; j
++)
610 data
->ci
[j
].entries_width
= 0;
612 data
->entry_maxheight
= 0;
613 data
->entries_totalheight
= 0;
614 data
->entries_maxwidth
= 0;
616 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
618 CalcDimsOfEntry(cl
, obj
, i
);
619 data
->entries_totalheight
+= data
->entries
[i
]->height
;
622 for (j
= 0; j
< data
->columns
; j
++)
623 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
625 if (!data
->entry_maxheight
)
626 data
->entry_maxheight
= 1;
629 /**************************************************************************
630 Calculates the number of visible entry lines. Returns 1 if it has
632 **************************************************************************/
633 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
635 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
636 int old_entries_visible
= data
->entries_visible
;
637 int old_entries_top_pixel
= data
->entries_top_pixel
;
639 data
->entries_visible
= (_mheight(data
->area
) - data
->title_height
)
640 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
642 /* Distribute extra vertical space evenly between top and bottom of
645 data
->entries_top_pixel
= _mtop(data
->area
) + data
->title_height
646 + (_mheight(data
->area
) - data
->title_height
648 data
->entries_visible
*
649 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
651 return (old_entries_visible
!= data
->entries_visible
)
652 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
655 /**************************************************************************
656 Default hook to compare two list entries. Works for strings only.
657 **************************************************************************/
658 AROS_UFH3S(int, default_compare_func
,
659 AROS_UFHA(struct Hook
*, h
, A0
),
660 AROS_UFHA(char *, s2
, A2
),
661 AROS_UFHA(char *, s1
, A1
))
665 return Stricmp(s1
, s2
);
670 /**************************************************************************
672 **************************************************************************/
673 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
675 struct MUI_ListData
*data
;
677 struct TagItem
*tags
;
679 LONG new_entries_active
= MUIV_List_Active_Off
;
680 struct TagItem rectattrs
[2] = {{TAG_IGNORE
, TAG_IGNORE
}, {TAG_DONE
, TAG_DONE
}};
683 /* search for MUIA_Frame as it has to be passed to rectangle object */
684 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
686 if (tag
->ti_Tag
== MUIA_Frame
)
688 rectattrs
[0].ti_Tag
= MUIA_Frame
;
689 rectattrs
[0].ti_Data
= tag
->ti_Data
;
690 tag
->ti_Tag
= TAG_IGNORE
;
695 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
696 MUIA_Group_Horiz
, TRUE
,
699 MUIA_Group_Spacing
, 0,
700 MUIA_Font
, MUIV_Font_List
,
701 MUIA_ShowSelState
, FALSE
,
702 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
703 MUIA_Background
, MUII_ListBack
,
704 TAG_MORE
, (IPTR
) msg
->ops_AttrList
,
710 data
= INST_DATA(cl
, obj
);
713 data
->entries_active
= MUIV_List_Active_Off
;
714 data
->intern_puddle_size
= 2008;
715 data
->intern_thresh_size
= 1024;
716 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
717 data
->default_compare_hook
.h_SubEntry
= 0;
718 data
->compare_hook
= &(data
->default_compare_hook
);
719 data
->flags
= LIST_SHOWDROPMARKS
;
720 data
->area_replaced
= FALSE
;
722 data
->last_active
= -1;
724 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
725 data
->ehn
.ehn_Priority
= 0;
726 data
->ehn
.ehn_Flags
= 0;
727 data
->ehn
.ehn_Object
= obj
;
728 data
->ehn
.ehn_Class
= cl
;
730 area
= (Object
*)GetTagData(MUIA_List_ListArea
, (IPTR
) 0, msg
->ops_AttrList
);
733 area
= RectangleObject
, TAG_MORE
, (IPTR
) rectattrs
, End
;
735 data
->area_replaced
= TRUE
;
738 vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
741 /* parse initial taglist */
742 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
746 case MUIA_List_Active
:
747 new_entries_active
= tag
->ti_Data
;
751 data
->pool
= (APTR
) tag
->ti_Data
;
754 case MUIA_List_PoolPuddleSize
:
755 data
->intern_puddle_size
= tag
->ti_Data
;
758 case MUIA_List_PoolThreshSize
:
759 data
->intern_thresh_size
= tag
->ti_Data
;
762 case MUIA_List_CompareHook
:
763 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
764 if (data
->compare_hook
== NULL
)
765 data
->compare_hook
= &data
->default_compare_hook
;
768 case MUIA_List_ConstructHook
:
769 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
772 case MUIA_List_DestructHook
:
773 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
776 case MUIA_List_DisplayHook
:
777 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
780 case MUIA_List_MultiTestHook
:
781 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
784 case MUIA_List_SourceArray
:
785 array
= (APTR
*) tag
->ti_Data
;
788 case MUIA_List_Format
:
789 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
792 case MUIA_List_Title
:
793 data
->title
= (STRPTR
) tag
->ti_Data
;
796 case MUIA_List_MinLineHeight
:
797 data
->entry_minheight
= tag
->ti_Data
;
800 case MUIA_List_AdjustHeight
:
801 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
804 case MUIA_List_AdjustWidth
:
805 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
808 case MUIA_List_AutoVisible
:
809 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
812 case MUIA_List_ShowDropMarks
:
813 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
816 case MUIA_List_DragSortable
:
817 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
818 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
821 case MUIA_Listview_ScrollerPos
:
822 data
->scroller_pos
= tag
->ti_Data
;
825 case MUIA_Listview_Input
:
826 data
->read_only
= !tag
->ti_Data
;
829 case MUIA_Listview_MultiSelect
:
830 data
->multiselect
= tag
->ti_Data
;
833 case MUIA_Listview_DoubleClick
:
834 data
->doubleclick
= tag
->ti_Data
!= 0;
839 /* Add list and/or scroller */
840 switch (data
->scroller_pos
)
842 case MUIV_Listview_ScrollerPos_None
:
843 DoMethod(obj
, OM_ADDMEMBER
, area
);
845 case MUIV_Listview_ScrollerPos_Left
:
846 DoMethod(obj
, OM_ADDMEMBER
, vert
);
847 DoMethod(obj
, OM_ADDMEMBER
, area
);
850 DoMethod(obj
, OM_ADDMEMBER
, area
);
851 DoMethod(obj
, OM_ADDMEMBER
, vert
);
857 LONG entries
= 0, first
= 0, visible
= 0;
859 get(obj
, MUIA_List_VertProp_First
, &first
);
860 get(obj
, MUIA_List_VertProp_Visible
, &visible
);
861 get(obj
, MUIA_List_VertProp_Entries
, &entries
);
864 MUIA_Prop_First
, first
,
865 MUIA_Prop_Visible
, visible
, MUIA_Prop_Entries
, entries
, TAG_DONE
);
867 /* Pass prop object as DestObj (based on code in NList) */
868 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_First
, MUIV_EveryTime
,
869 (IPTR
) vert
, 3, MUIM_NoNotifySet
, MUIA_Prop_First
, MUIV_TriggerValue
);
870 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Visible
, MUIV_EveryTime
,
871 (IPTR
) vert
, 3, MUIM_NoNotifySet
, MUIA_Prop_Visible
, MUIV_TriggerValue
);
872 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Entries
, MUIV_EveryTime
,
873 (IPTR
) vert
, 3, MUIM_NoNotifySet
, MUIA_Prop_Entries
, MUIV_TriggerValue
);
878 /* No memory pool given, so we create our own */
879 data
->pool
= data
->intern_pool
=
880 CreatePool(0, data
->intern_puddle_size
,
881 data
->intern_thresh_size
);
884 CoerceMethod(cl
, obj
, OM_DISPOSE
);
889 /* parse the list format */
890 if (!(ParseListFormat(data
, data
->format
)))
892 CoerceMethod(cl
, obj
, OM_DISPOSE
);
896 /* This is neccessary for at least the title */
897 if (!SetListSize(data
, 0))
899 CoerceMethod(cl
, obj
, OM_DISPOSE
);
905 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
907 CoerceMethod(cl
, obj
, OM_DISPOSE
);
912 data
->entries
[ENTRY_TITLE
] = NULL
;
917 /* Count the number of elements */
918 for (i
= 0; array
[i
] != NULL
; i
++)
921 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
922 MUIV_List_Insert_Top
);
925 if ((data
->entries_num
) && (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;
938 if (new_entries_active
< 0)
939 new_entries_active
= 0;
940 else if (new_entries_active
>= data
->entries_num
)
941 new_entries_active
= data
->entries_num
- 1;
943 data
->entries_active
= new_entries_active
;
944 /* Selected entry will be moved into visible area */
947 NewList((struct List
*)&data
->images
);
949 D(bug("List_New(%lx)\n", obj
));
954 /**************************************************************************
956 **************************************************************************/
957 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
959 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
961 D(bug("List Dispose\n"));
963 /* Call destruct method for every entry and free the entries manually
964 * to avoid notification */
965 while (data
->confirm_entries_num
)
967 struct ListEntry
*lentry
=
968 data
->entries
[--data
->confirm_entries_num
];
969 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
971 FreeListEntry(data
, lentry
);
974 if (data
->intern_pool
)
975 DeletePool(data
->intern_pool
);
977 FreeVec(data
->entries
- 1);
978 /* title is currently before all other elements */
980 FreeListFormat(data
);
981 FreeVec(data
->format
);
983 return DoSuperMethodA(cl
, obj
, msg
);
987 /**************************************************************************
989 **************************************************************************/
990 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
992 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
994 struct TagItem
*tags
;
997 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1001 case MUIA_List_CompareHook
:
1002 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1003 if (data
->compare_hook
== NULL
)
1004 data
->compare_hook
= &data
->default_compare_hook
;
1007 case MUIA_List_ConstructHook
:
1008 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1011 case MUIA_List_DestructHook
:
1012 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1015 case MUIA_List_DisplayHook
:
1016 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1019 case MUIA_List_MultiTestHook
:
1020 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1021 if (data
->multi_test_hook
!= NULL
)
1023 /* Clearing current selections is the easiest way to keep
1024 * selections consistent with the new hook */
1025 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
1026 MUIV_List_Select_Off
, NULL
);
1030 case MUIA_List_Title
:
1031 data
->title
= (STRPTR
) tag
->ti_Data
;
1032 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1035 case MUIA_List_VertProp_First
:
1036 data
->vertprop_first
= tag
->ti_Data
;
1037 if (data
->entries_first
!= tag
->ti_Data
)
1039 set(obj
, MUIA_List_First
, tag
->ti_Data
);
1043 case MUIA_List_Format
:
1044 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1045 ParseListFormat(data
, data
->format
);
1046 // FIXME: should we check for errors?
1047 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1050 case MUIA_List_VertProp_Entries
:
1051 data
->vertprop_entries
= tag
->ti_Data
;
1054 case MUIA_List_VertProp_Visible
:
1055 data
->vertprop_visible
= tag
->ti_Data
;
1056 data
->entries_visible
= tag
->ti_Data
;
1059 case MUIA_List_Active
:
1061 LONG new_entries_active
= tag
->ti_Data
;
1063 if ((data
->entries_num
)
1064 && (new_entries_active
!= MUIV_List_Active_Off
))
1066 switch (new_entries_active
)
1068 case MUIV_List_Active_Top
:
1069 new_entries_active
= 0;
1072 case MUIV_List_Active_Bottom
:
1073 new_entries_active
= data
->entries_num
- 1;
1076 case MUIV_List_Active_Up
:
1077 new_entries_active
= data
->entries_active
- 1;
1080 case MUIV_List_Active_Down
:
1081 new_entries_active
= data
->entries_active
+ 1;
1084 case MUIV_List_Active_PageUp
:
1085 new_entries_active
=
1086 data
->entries_active
- data
->entries_visible
;
1089 case MUIV_List_Active_PageDown
:
1090 new_entries_active
=
1091 data
->entries_active
+ data
->entries_visible
;
1095 if (new_entries_active
< 0)
1096 new_entries_active
= 0;
1097 else if (new_entries_active
>= data
->entries_num
)
1098 new_entries_active
= data
->entries_num
- 1;
1101 new_entries_active
= -1;
1103 if (data
->entries_active
!= new_entries_active
)
1105 LONG old
= data
->entries_active
;
1106 data
->entries_active
= new_entries_active
;
1108 /* Selectchange stuff */
1109 if (new_entries_active
!= -1)
1111 DoMethod(obj
, MUIM_List_SelectChange
,
1112 new_entries_active
, MUIV_List_Select_On
, 0);
1113 DoMethod(obj
, MUIM_List_SelectChange
,
1114 new_entries_active
, MUIV_List_Select_Active
, 0);
1117 DoMethod(obj
, MUIM_List_SelectChange
,
1118 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1121 data
->update_pos
= old
;
1122 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1124 data
->update_pos
= data
->entries_active
;
1125 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1127 /* Make new active entry visible (if there is one and
1129 if (new_entries_active
!= -1
1130 && (_flags(obj
) & MADF_SETUP
))
1132 DoMethod(obj
, MUIM_List_Jump
,
1133 MUIV_List_Jump_Active
);
1139 case MUIA_List_First
:
1140 data
->update_pos
= data
->entries_first
;
1142 data
->entries_first
= tag
->ti_Data
;
1144 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1145 if ((data
->vertprop_first
!= tag
->ti_Data
)
1146 && (!(data
->flags
& LIST_QUIET
)))
1148 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1152 case MUIA_List_Visible
: /* Shouldn't be settable? */
1153 if (data
->vertprop_visible
!= tag
->ti_Data
)
1154 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1157 case MUIA_List_Entries
:
1158 if (data
->confirm_entries_num
== tag
->ti_Data
)
1160 data
->entries_num
= tag
->ti_Data
;
1161 if (!(data
->flags
& LIST_QUIET
))
1163 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1168 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1172 case MUIA_List_Quiet
:
1173 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1176 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1177 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1178 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1179 if (data
->vertprop_first
!=
1180 XGET(obj
, MUIA_List_VertProp_First
))
1181 set(obj
, MUIA_List_VertProp_First
, data
->vertprop_first
);
1185 case MUIA_List_AutoVisible
:
1186 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1189 case MUIA_List_ShowDropMarks
:
1190 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1193 case MUIA_List_DragSortable
:
1194 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1195 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1199 /* Swallow this so the Area class doesn't redraw us */
1200 tag
->ti_Tag
= TAG_IGNORE
;
1204 if (_flags(obj
) & MADF_SETUP
)
1206 /* Stop listening for events we only listen to when mouse
1207 button is down: we will not be informed of the button
1209 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1210 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
1211 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1215 case MUIA_Listview_DoubleClick
: /* private set */
1216 data
->doubleclick
= tag
->ti_Data
!= 0;
1219 case MUIA_Listview_SelectChange
: /* private set */
1220 data
->select_change
= tag
->ti_Data
!= 0;
1223 case MUIA_Listview_ScrollerPos
: /* private set */
1224 data
->scroller_pos
= tag
->ti_Data
;
1227 case MUIA_Listview_Input
: /* private set */
1228 data
->read_only
= !tag
->ti_Data
;
1231 case MUIA_Listview_MultiSelect
: /* private set */
1232 data
->multiselect
= tag
->ti_Data
;
1237 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1240 /**************************************************************************
1242 **************************************************************************/
1243 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1245 /* small macro to simplify return value storage */
1246 #define STORE *(msg->opg_Storage)
1247 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1249 switch (msg
->opg_AttrID
)
1251 case MUIA_List_Entries
:
1252 STORE
= data
->entries_num
;
1254 case MUIA_List_First
:
1255 STORE
= data
->entries_first
;
1257 case MUIA_List_Active
:
1258 STORE
= data
->entries_active
;
1260 case MUIA_List_InsertPosition
:
1261 STORE
= data
->insert_position
;
1263 case MUIA_List_Title
:
1264 STORE
= (IPTR
) data
->title
;
1266 case MUIA_List_VertProp_Entries
:
1267 STORE
= data
->vertprop_entries
;
1269 case MUIA_List_VertProp_Visible
:
1270 case MUIA_List_Visible
:
1271 STORE
= data
->vertprop_visible
;
1273 case MUIA_List_VertProp_First
:
1274 STORE
= data
->vertprop_first
;
1276 case MUIA_List_Format
:
1277 STORE
= (IPTR
) data
->format
;
1279 case MUIA_List_AutoVisible
:
1280 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1282 case MUIA_List_ShowDropMarks
:
1283 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1285 case MUIA_List_DragSortable
:
1286 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1288 case MUIA_Listview_ClickColumn
:
1289 STORE
= data
->click_column
;
1291 case MUIA_Listview_DoubleClick
:
1292 STORE
= data
->doubleclick
;
1294 case MUIA_Listview_SelectChange
:
1295 STORE
= data
->select_change
;
1297 case MUIA_Listview_List
:
1302 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1308 /**************************************************************************
1310 **************************************************************************/
1311 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1312 struct MUIP_Setup
*msg
)
1314 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1316 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1319 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1320 data
->prefs_linespacing
=
1321 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1322 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1323 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1325 CalcWidths(cl
, obj
);
1328 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1330 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1332 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1334 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
1335 if (data
->multiselect
== MUIV_Listview_MultiSelect_Default
)
1337 if (data
->prefs_multi
== LISTVIEW_MULTI_SHIFTED
)
1338 data
->multiselect
= MUIV_Listview_MultiSelect_Shifted
;
1340 data
->multiselect
= MUIV_Listview_MultiSelect_Always
;
1343 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1348 /**************************************************************************
1350 **************************************************************************/
1351 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1352 struct MUIP_Cleanup
*msg
)
1354 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1355 struct ListImage
*li
= List_First(&data
->images
);
1359 struct ListImage
*next
= Node_Next(li
);
1360 DoMethod(obj
, MUIM_List_DeleteImage
, (IPTR
) li
);
1364 zune_imspec_cleanup(data
->list_cursor
);
1365 zune_imspec_cleanup(data
->list_select
);
1366 zune_imspec_cleanup(data
->list_selcur
);
1368 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1369 data
->mouse_click
= 0;
1371 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1374 /**************************************************************************
1376 **************************************************************************/
1377 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1378 struct MUIP_AskMinMax
*msg
)
1380 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1382 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1385 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1387 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1388 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1389 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1393 msg
->MinMaxInfo
->MinWidth
+= 40;
1394 msg
->MinMaxInfo
->DefWidth
+= 100;
1395 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1398 if (data
->entries_num
> 0)
1400 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1402 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1403 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1404 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1408 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1409 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1410 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1411 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1416 msg
->MinMaxInfo
->MinHeight
+= 36;
1417 msg
->MinMaxInfo
->DefHeight
+= 96;
1418 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1420 D(bug("List %p minheigh=%d, line maxh=%d\n",
1421 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1425 /****i* List.mui/MUIM_Layout *************************************************
1430 ******************************************************************************
1434 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1435 struct MUIP_Layout
*msg
)
1437 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1438 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1439 LONG new_entries_first
= data
->entries_first
;
1441 /* Calc the numbers of entries visible */
1442 CalcVertVisible(cl
, obj
);
1444 /* Ensure active entry is visible if requested */
1445 if (data
->entries_active
+ 1 >=
1446 (data
->entries_first
+ data
->entries_visible
)
1447 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1449 data
->entries_active
- data
->entries_visible
+ 1;
1451 /* Ensure there are no unnecessary empty lines */
1452 if ((new_entries_first
+ data
->entries_visible
>=
1454 && (data
->entries_visible
<= data
->entries_num
))
1455 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1457 /* Always show the start of the list if it isn't long enough to fill the
1459 if (data
->entries_num
<= data
->entries_visible
)
1460 new_entries_first
= 0;
1462 if (new_entries_first
< 0)
1463 new_entries_first
= 0;
1465 set(obj
, new_entries_first
!= data
->entries_first
?
1466 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1468 /* So the notify happens */
1469 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1475 /**************************************************************************
1477 **************************************************************************/
1478 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1479 struct MUIP_Show
*msg
)
1481 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1482 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1484 zune_imspec_show(data
->list_cursor
, obj
);
1485 zune_imspec_show(data
->list_select
, obj
);
1486 zune_imspec_show(data
->list_selcur
, obj
);
1491 /**************************************************************************
1493 **************************************************************************/
1494 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1495 struct MUIP_Hide
*msg
)
1497 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1499 zune_imspec_hide(data
->list_cursor
);
1500 zune_imspec_hide(data
->list_select
);
1501 zune_imspec_hide(data
->list_selcur
);
1503 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1507 /**************************************************************************
1508 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1510 **************************************************************************/
1511 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1514 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1517 /* To be sure we don't draw anything if there is no title */
1518 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1521 DisplayEntry(cl
, obj
, entry_pos
);
1522 x1
= _mleft(data
->area
);
1524 for (col
= 0; col
< data
->columns
; col
++)
1527 x2
= x1
+ data
->ci
[col
].entries_width
;
1530 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1531 ZTEXT_ARG_NONE
, 0)))
1533 /* Could be made simpler, as we don't really need the bounds */
1534 zune_text_get_bounds(text
, obj
);
1535 /* Note, this was MPEN_SHADOW before */
1536 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1537 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1538 zune_text_destroy(text
);
1540 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1544 /**************************************************************************
1546 **************************************************************************/
1547 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1549 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1553 BOOL scroll_caused_damage
= FALSE
;
1554 struct MUI_ImageSpec_intern
*highlight
;
1557 if (data
->flags
& LIST_QUIET
)
1560 ret
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1562 if (data
->area_replaced
)
1565 /* Calculate the title height */
1568 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1572 data
->title_height
= 0;
1575 /* Calc the numbers of entries visible */
1576 CalcVertVisible(cl
, obj
);
1578 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1580 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), _mtop(data
->area
),
1581 _mwidth(data
->area
), _mheight(data
->area
),
1582 0, data
->entries_first
* data
->entry_maxheight
, 0);
1585 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(data
->area
), _mtop(data
->area
),
1586 _mwidth(data
->area
), _mheight(data
->area
));
1588 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1590 y
= _mtop(data
->area
);
1593 if (data
->title_height
&& data
->title
)
1595 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1596 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1597 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1598 Move(_rp(obj
), _mleft(data
->area
), y
);
1599 Draw(_rp(obj
), _mright(data
->area
), y
);
1600 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1602 Move(_rp(obj
), _mleft(data
->area
), y
);
1603 Draw(_rp(obj
), _mright(data
->area
), y
);
1607 y
= data
->entries_top_pixel
;
1609 start
= data
->entries_first
;
1610 end
= data
->entries_first
+ data
->entries_visible
;
1612 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1614 int diffy
= data
->entries_first
- data
->update_pos
;
1616 if (abs(diffy
) < data
->entries_visible
)
1618 scroll_caused_damage
=
1619 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1621 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1622 _mleft(data
->area
), y
,
1623 _mright(data
->area
),
1624 y
+ data
->entry_maxheight
* data
->entries_visible
);
1626 scroll_caused_damage
=
1627 scroll_caused_damage
1628 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1632 start
= end
- diffy
;
1633 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1637 end
= start
- diffy
;
1641 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1643 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), top
,
1644 _mwidth(data
->area
), bottom
- top
+ 1,
1646 top
- _mtop(data
->area
) + data
->entries_first
* data
->entry_maxheight
,
1650 for (entry_pos
= start
;
1651 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1653 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1655 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1656 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1657 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1658 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1659 && data
->update_pos
== entry_pos
))
1661 /* Choose appropriate highlight image */
1663 if (entry_pos
== data
->entries_active
1664 && entry
->flags
& ENTRY_SELECTED
)
1665 highlight
= data
->list_selcur
;
1666 else if (entry_pos
== data
->entries_active
)
1667 highlight
= data
->list_cursor
;
1668 else if (entry
->flags
& ENTRY_SELECTED
)
1669 highlight
= data
->list_select
;
1673 /* Draw highlight or background */
1675 if (highlight
!= NULL
)
1677 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1678 _mleft(data
->area
), y
, _mwidth(data
->area
), data
->entry_maxheight
,
1679 0, y
- data
->entries_top_pixel
, 0);
1681 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1682 && data
->update_pos
== entry_pos
)
1684 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), y
,
1685 _mwidth(data
->area
), data
->entry_maxheight
, 0,
1686 y
- _mtop(data
->area
) +
1687 data
->entries_first
* data
->entry_maxheight
, 0);
1690 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1692 y
+= data
->entry_maxheight
;
1695 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1699 if (scroll_caused_damage
)
1701 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1703 /* Theoretically it might happen that more damage is caused
1704 after ScrollRaster. By something else, like window movement
1705 in front of our window. Therefore refresh root object of
1706 window, not just this object */
1710 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1711 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1713 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1717 ULONG x1
= _mleft(data
->area
);
1719 y
= _mtop(data
->area
);
1721 if (data
->title_height
&& data
->title
)
1723 for (col
= 0; col
< data
->columns
; col
++)
1725 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1726 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1728 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1731 if (data
->ci
[col
].bar
)
1733 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1734 Move(_rp(obj
), x1
, y
);
1736 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1737 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1738 Move(_rp(obj
), x1
+ 1, y
);
1739 Draw(_rp(obj
), x1
+ 1,
1740 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1744 x1
+= data
->ci
[col
].delta
- halfdelta
;
1746 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1749 x1
= _mleft(data
->area
);
1751 for (col
= 0; col
< data
->columns
; col
++)
1753 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1754 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1756 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1759 if (data
->ci
[col
].bar
)
1761 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1762 Move(_rp(obj
), x1
, y
);
1763 Draw(_rp(obj
), x1
, _mbottom(data
->area
));
1764 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1765 Move(_rp(obj
), x1
+ 1, y
);
1766 Draw(_rp(obj
), x1
+ 1, _mbottom(data
->area
));
1771 x1
+= data
->ci
[col
].delta
- halfdelta
;
1777 /****** List.mui/MUIM_List_Clear *********************************************
1780 * MUIM_List_Clear (V4)
1783 * DoMethod(obj, MUIM_List_Clear);
1786 * Removes all entries from the list.
1788 ******************************************************************************
1792 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
1793 struct MUIP_List_Clear
*msg
)
1795 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1797 while (data
->confirm_entries_num
)
1799 struct ListEntry
*lentry
=
1800 data
->entries
[--data
->confirm_entries_num
];
1801 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1803 FreeListEntry(data
, lentry
);
1805 /* Should never fail when shrinking */
1806 SetListSize(data
, 0);
1809 if (data
->confirm_entries_num
!= data
->entries_num
)
1811 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
1812 /* Notify only when no entry was active */
1813 data
->entries_active
!=
1814 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
1815 MUIV_List_Active_Off
, TAG_DONE
);
1818 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1824 /**************************************************************************
1826 **************************************************************************/
1827 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
1828 struct MUIP_List_Exchange
*msg
)
1830 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1835 case MUIV_List_Exchange_Top
:
1838 case MUIV_List_Exchange_Active
:
1839 pos1
= data
->entries_active
;
1841 case MUIV_List_Exchange_Bottom
:
1842 pos1
= data
->entries_num
- 1;
1850 case MUIV_List_Exchange_Top
:
1853 case MUIV_List_Exchange_Active
:
1854 pos2
= data
->entries_active
;
1856 case MUIV_List_Exchange_Bottom
:
1857 pos2
= data
->entries_num
- 1;
1859 case MUIV_List_Exchange_Next
:
1862 case MUIV_List_Exchange_Previous
:
1869 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
1870 && pos2
< data
->entries_num
&& pos1
!= pos2
)
1872 struct ListEntry
*save
= data
->entries
[pos1
];
1873 data
->entries
[pos1
] = data
->entries
[pos2
];
1874 data
->entries
[pos2
] = save
;
1877 data
->update_pos
= pos1
;
1878 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1881 data
->update_pos
= pos2
;
1882 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1892 /**************************************************************************
1894 **************************************************************************/
1895 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
1896 struct MUIP_List_Redraw
*msg
)
1898 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1900 if (!(data
->flags
& LIST_QUIET
))
1902 if (msg
->pos
== MUIV_List_Redraw_All
)
1905 CalcWidths(cl
, obj
);
1906 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1911 if (msg
->pos
== MUIV_List_Redraw_Active
)
1912 pos
= data
->entries_active
;
1913 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
1916 for (i
= 0; i
< data
->entries_num
; i
++)
1917 if (data
->entries
[i
]->data
== msg
->entry
)
1928 if (CalcDimsOfEntry(cl
, obj
, pos
))
1933 data
->update_pos
= pos
;
1935 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1942 /**************************************************************************
1944 **************************************************************************/
1945 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
1946 struct MUIP_List_Remove
*msg
)
1948 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1951 struct ListEntry
*lentry
;
1952 //int rem_count = 1;
1954 if (!data
->entries_num
)
1959 case MUIV_List_Remove_First
:
1963 case MUIV_List_Remove_Active
:
1964 pos
= data
->entries_active
;
1967 case MUIV_List_Remove_Last
:
1968 pos
= data
->entries_num
- 1;
1971 case MUIV_List_Remove_Selected
:
1972 /* TODO: needs special handling */
1973 pos
= data
->entries_active
;
1981 if (pos
< 0 || pos
>= data
->entries_num
)
1984 new_act
= data
->entries_active
;
1986 if (pos
== new_act
&& new_act
== data
->entries_num
- 1)
1987 new_act
--; /* might become MUIV_List_Active_Off */
1989 lentry
= data
->entries
[pos
];
1990 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1995 RemoveListEntries(data
, pos
, cur
- pos
);
1996 data
->confirm_entries_num
-= cur
- pos
;
1998 /* ensure that the active element is in a valid range */
1999 if (new_act
>= data
->entries_num
)
2000 new_act
= data
->entries_num
- 1;
2002 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
,
2003 (new_act
>= pos
) || (new_act
!= data
->entries_active
) ?
2004 MUIA_List_Active
: TAG_DONE
,
2005 new_act
, /* Inform only if neccessary (for notify) */
2009 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2014 /**************************************************************************
2016 **************************************************************************/
2017 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2018 struct MUIP_List_Select
*msg
)
2020 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2021 LONG pos
, i
, count
, selcount
=0, state
=0;
2022 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
2024 /* Establish the range of entries affected */
2027 case MUIV_List_Select_Active
:
2028 pos
= data
->entries_active
;
2029 if (pos
== MUIV_List_Active_Off
)
2035 case MUIV_List_Select_All
:
2037 count
= data
->entries_num
;
2043 if (pos
< 0 || pos
>= data
->entries_num
)
2048 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2050 /* Disallow selection of an additional entry if there is a currently
2051 selected entry that is not multi-selectable (in such case there
2052 will only be one entry currently selected, so no need to iterate) */
2053 i
= MUIV_List_NextSelected_Start
;
2054 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
2055 if (i
!= MUIV_List_NextSelected_End
)
2057 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
2058 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2059 data
->entries
[i
]->data
);
2062 /* Change or check state of each entry in the range */
2063 for (i
= pos
; i
< pos
+ count
; i
++)
2065 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2066 switch (msg
->seltype
)
2068 case MUIV_List_Select_Off
:
2069 new_select_state
= FALSE
;
2072 case MUIV_List_Select_On
:
2073 new_select_state
= TRUE
;
2076 case MUIV_List_Select_Toggle
:
2077 new_select_state
= !state
;
2081 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2086 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2088 /* Disallow selection if entry is not multi-selectable and
2089 * there are already selected entries */
2090 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
2091 new_select_state
= multi_allowed
&& (selcount
== 0 ||
2092 CallHookPkt(data
->multi_test_hook
, NULL
,
2093 data
->entries
[i
]->data
));
2095 if (new_select_state
)
2096 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2098 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2102 /* Report old state or number of selected entries */
2105 if (msg
->pos
== MUIV_List_Select_All
2106 && msg
->seltype
== MUIV_List_Select_Ask
)
2107 *msg
->info
= selcount
;
2112 /* Redraw unless it was just an enquiry */
2113 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2120 data
->update_pos
= pos
;
2122 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2128 /**************************************************************************
2130 **************************************************************************/
2132 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2133 struct MUIP_List_Insert
*msg
)
2135 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2136 LONG pos
, count
, sort
;
2143 /* Count the number of entries */
2144 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2153 case MUIV_List_Insert_Top
:
2157 case MUIV_List_Insert_Active
:
2158 if (data
->entries_active
!= -1)
2159 pos
= data
->entries_active
;
2164 case MUIV_List_Insert_Sorted
:
2165 pos
= data
->entries_num
;
2166 sort
= 1; /* we sort'em later */
2169 case MUIV_List_Insert_Bottom
:
2170 pos
= data
->entries_num
;
2174 if (msg
->pos
> data
->entries_num
)
2175 pos
= data
->entries_num
;
2176 else if (msg
->pos
< 0)
2183 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2186 LONG until
= pos
+ count
;
2187 APTR
*toinsert
= msg
->entries
;
2189 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2194 struct ListEntry
*lentry
;
2196 if (!(lentry
= AllocListEntry(data
)))
2198 /* Panic, but we must be in a consistent state, so remove
2199 * the space where the following list entries should have gone
2201 RemoveListEntries(data
, pos
, until
- pos
);
2205 /* now call the construct method which returns us a pointer which
2207 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2208 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2211 FreeListEntry(data
, lentry
);
2212 RemoveListEntries(data
, pos
, until
- pos
);
2214 /* TODO: Also check for visible stuff like below */
2215 if (data
->entries_num
!= data
->confirm_entries_num
)
2216 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2220 data
->entries
[pos
] = lentry
;
2221 data
->confirm_entries_num
++;
2223 if (_flags(obj
) & MADF_SETUP
)
2225 /* We have to calculate the width and height of the newly
2226 * inserted entry. This has to be done after inserting the
2227 * element into the list */
2228 CalcDimsOfEntry(cl
, obj
, pos
);
2235 /* Recalculate the number of visible entries */
2236 if (_flags(obj
) & MADF_SETUP
)
2237 CalcVertVisible(cl
, obj
);
2239 if (data
->entries_num
!= data
->confirm_entries_num
)
2242 MUIA_List_Entries
, data
->confirm_entries_num
,
2243 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2246 /* If the array is already sorted, we could do a simple insert
2247 * sort and would be much faster than with qsort.
2248 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2249 * sort the whole array?
2251 * I think, we better sort the whole array:
2255 DoMethod(obj
, MUIM_List_Sort
);
2256 /* TODO: which pos to return here !? */
2257 /* MUIM_List_Sort already called MUI_Redraw */
2262 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2264 data
->insert_position
= pos
;
2269 /**************************************************************************
2270 MUIM_List_InsertSingle
2271 **************************************************************************/
2272 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2273 struct MUIP_List_InsertSingle
*msg
)
2275 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2279 /**************************************************************************
2281 **************************************************************************/
2282 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2283 struct MUIP_List_GetEntry
*msg
)
2285 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2288 if (pos
== MUIV_List_GetEntry_Active
)
2289 pos
= data
->entries_active
;
2291 if (pos
< 0 || pos
>= data
->entries_num
)
2296 *msg
->entry
= data
->entries
[pos
]->data
;
2297 return (IPTR
) *msg
->entry
;
2300 /**************************************************************************
2302 **************************************************************************/
2303 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2304 struct MUIP_List_Construct
*msg
)
2306 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2308 if (NULL
== data
->construct_hook
)
2309 return (IPTR
) msg
->entry
;
2310 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2312 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2313 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2318 if (msg
->entry
!= NULL
)
2319 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2321 *(STRPTR
) (mem
+ 1) = 0;
2322 return (IPTR
) (mem
+ 1);
2324 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2327 /**************************************************************************
2329 **************************************************************************/
2330 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2331 struct MUIP_List_Destruct
*msg
)
2333 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2335 if (NULL
== data
->destruct_hook
)
2338 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2340 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2341 FreePooled(msg
->pool
, mem
, mem
[0]);
2345 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2350 /****** List.mui/MUIM_List_Compare *******************************************
2353 * MUIM_List_Compare (V20)
2356 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2357 * LONG sort_type1, LONG sort_type2);
2360 * Compare two list entries according to the current comparison hook
2361 * (MUIA_List_CompareHook).
2364 * entry1 - the first entry data.
2365 * entry2 - the second entry data.
2366 * sort_type1 - undocumented.
2367 * sort_type2 - undocumented.
2370 * MUIA_List_CompareHook, MUIM_List_Sort.
2372 ******************************************************************************
2376 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2377 struct MUIP_List_Compare
*msg
)
2379 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2381 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2384 /**************************************************************************
2386 **************************************************************************/
2387 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2388 struct MUIP_List_Display
*msg
)
2390 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2392 if (NULL
== data
->display_hook
)
2395 *msg
->array
= msg
->entry
;
2401 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2402 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2405 /**************************************************************************
2406 MUIM_List_SelectChange
2407 **************************************************************************/
2408 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2409 struct MUIP_List_SelectChange
*msg
)
2414 /**************************************************************************
2415 MUIM_List_CreateImage
2416 Called by a List subclass in its Setup method.
2417 Connects an Area subclass object to the list, much like an object gets
2418 connected to a window. List calls Setup and AskMinMax on that object,
2419 keeps a reference to it (that reference will be returned).
2420 Text engine will dereference that pointer and draw the object with its
2422 **************************************************************************/
2423 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2424 struct MUIP_List_CreateImage
*msg
)
2426 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2427 struct ListImage
*li
;
2432 /* List must be already setup in Setup of your subclass */
2433 if (!(_flags(obj
) & MADF_SETUP
))
2435 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2440 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2441 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2442 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2448 /**************************************************************************
2449 MUIM_List_DeleteImage
2450 **************************************************************************/
2451 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2452 struct MUIP_List_DeleteImage
*msg
)
2454 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2455 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2459 DoMethod(li
->obj
, MUIM_Cleanup
);
2460 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2461 Remove((struct Node
*)li
);
2462 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2468 /****** List.mui/MUIM_List_Jump **********************************************
2471 * MUIM_List_Jump (V4)
2474 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2477 * Scrolls the list so that a particular entry is visible.
2480 * pos - index of entry that should become visible, or one of these
2482 * MUIV_List_Jump_Active: show the active entry.
2483 * MUIV_List_Jump_Top: show the first entry.
2484 * MUIV_List_Jump_Bottom: show the last entry.
2485 * MUIV_List_Jump_Up: show the previous hidden entry.
2486 * MUIV_List_Jump_Down: show the next hidden entry.
2488 ******************************************************************************
2492 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2493 struct MUIP_List_Jump
*msg
)
2495 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2496 LONG pos
= msg
->pos
;
2500 case MUIV_List_Jump_Top
:
2504 case MUIV_List_Jump_Active
:
2505 pos
= data
->entries_active
;
2508 case MUIV_List_Jump_Bottom
:
2509 pos
= data
->entries_num
- 1;
2512 case MUIV_List_Jump_Down
:
2513 pos
= data
->entries_first
+ data
->entries_visible
;
2516 case MUIV_List_Jump_Up
:
2517 pos
= data
->entries_first
- 1;
2521 if (pos
>= data
->entries_num
)
2523 pos
= data
->entries_num
- 1;
2528 if (pos
< data
->entries_first
)
2530 set(obj
, MUIA_List_First
, pos
);
2532 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2534 pos
-= (data
->entries_visible
- 1);
2537 if (pos
!= data
->entries_first
)
2539 set(obj
, MUIA_List_First
, pos
);
2546 /****** List.mui/MUIM_List_Sort **********************************************
2549 * MUIM_List_Sort (V4)
2552 * DoMethod(obj, MUIM_List_Sort);
2555 * Sort the list's entries according to the current comparison hook
2556 * (MUIA_List_CompareHook).
2559 * MUIA_List_CompareHook, MUIM_List_Compare.
2561 ******************************************************************************
2565 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2566 struct MUIP_List_Sort
*msg
)
2568 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2571 struct MUIP_List_Compare cmpmsg
=
2572 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2574 if (data
->entries_num
> 1)
2577 Simple sort algorithm. Feel free to improve it.
2579 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2582 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2584 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2585 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2586 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2593 APTR tmp
= data
->entries
[i
];
2594 data
->entries
[i
] = data
->entries
[max
];
2595 data
->entries
[max
] = tmp
;
2601 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2606 /****** List.mui/MUIM_List_Move **********************************************
2609 * MUIM_List_Move (V9)
2612 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2615 * Move a list entry to a new position.
2618 * from - the current index of the entry that should be moved, or one of
2619 * these special values:
2620 * MUIV_List_Move_Active: the active entry.
2621 * MUIV_List_Move_Top: the first entry.
2622 * MUIV_List_Move_Bottom: the last entry.
2623 * to - the index of the entry's new position, or one of
2624 * these special values:
2625 * MUIV_List_Move_Active: the active entry.
2626 * MUIV_List_Move_Top: the first entry.
2627 * MUIV_List_Move_Bottom: the last entry.
2629 ******************************************************************************
2633 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
2634 struct MUIP_List_Move
*msg
)
2636 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2641 /* Normalise special 'from' values */
2644 case MUIV_List_Move_Top
:
2647 case MUIV_List_Move_Active
:
2648 from
= data
->entries_active
;
2650 case MUIV_List_Move_Bottom
:
2651 from
= data
->entries_num
- 1;
2657 /* Normalise special 'to' values */
2660 case MUIV_List_Move_Top
:
2663 case MUIV_List_Move_Active
:
2664 to
= data
->entries_active
;
2666 case MUIV_List_Move_Bottom
:
2667 to
= data
->entries_num
- 1;
2669 case MUIV_List_Move_Next
:
2672 case MUIV_List_Move_Previous
:
2679 /* Check that values are within valid bounds */
2680 if (from
> data
->entries_num
- 1 || from
< 0
2681 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
2682 return (IPTR
) FALSE
;
2684 /* Shift all entries in the range between the 'from' and 'to' positions */
2687 struct ListEntry
*backup
= data
->entries
[from
];
2688 for (i
= from
; i
< to
; i
++)
2689 data
->entries
[i
] = data
->entries
[i
+ 1];
2690 data
->entries
[to
] = backup
;
2694 struct ListEntry
*backup
= data
->entries
[from
];
2695 for (i
= from
; i
> to
; i
--)
2696 data
->entries
[i
] = data
->entries
[i
- 1];
2697 data
->entries
[to
] = backup
;
2700 /* Update index of active entry */
2701 if (from
== data
->entries_active
)
2702 data
->entries_active
= to
;
2703 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
2704 data
->entries_active
--;
2705 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
2706 data
->entries_active
++;
2708 /* Reflect list changes visually */
2710 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2715 /**************************************************************************
2716 MUIM_List_NextSelected
2717 **************************************************************************/
2718 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
2719 struct MUIP_List_NextSelected
*msg
)
2721 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2725 /* Get the first entry to check */
2727 if (pos
== MUIV_List_NextSelected_Start
)
2732 /* Find the next selected entry */
2733 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
2735 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2742 /* Return index of selected entry, or indicate there are no more */
2744 pos
= MUIV_List_NextSelected_End
;
2750 /**************************************************************************
2752 **************************************************************************/
2753 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
2754 struct MUIP_List_TestPos
*msg
)
2756 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2757 struct MUI_List_TestPos_Result
*result
= msg
->res
;
2758 LONG col
= -1, row
= -1;
2760 LONG mx
= msg
->x
- _left(data
->area
);
2761 LONG entries_visible
;
2763 if (data
->entries_visible
<= data
->entries_num
)
2764 entries_visible
= data
->entries_visible
;
2766 entries_visible
= data
->entries_num
;
2767 LONG ey
= msg
->y
- data
->entries_top_pixel
;
2768 /* y coordinates transformed to the entries */
2770 /* Now check if it was clicked on a title or on entries */
2772 flags
|= MUI_LPR_ABOVE
;
2773 else if (ey
>= entries_visible
* data
->entry_maxheight
)
2774 flags
|= MUI_LPR_BELOW
;
2778 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
2780 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
2784 flags
|= MUI_LPR_LEFT
;
2785 else if (mx
>= _width(data
->area
))
2786 flags
|= MUI_LPR_RIGHT
;
2789 /* Identify column */
2790 if (data
->entries_num
> 0 && data
->columns
> 0)
2793 col
= data
->columns
- 1;
2794 for (i
= 0; i
< data
->columns
; i
++)
2796 result
->xoffset
= mx
- width_sum
;
2798 data
->ci
[i
].entries_width
+
2800 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
2801 D(bug("[List/MUIM_TestPos] i %d "
2802 "width %d width_sum %d mx %d\n",
2803 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
2807 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
2814 result
->entry
= row
;
2815 result
->column
= col
;
2816 result
->flags
= flags
;
2821 /****i* List.mui/MUIM_DragQuery **********************************************
2826 ******************************************************************************
2830 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
2831 struct MUIP_DragQuery
*msg
)
2833 if (msg
->obj
== obj
)
2834 return MUIV_DragQuery_Accept
;
2836 return MUIV_DragQuery_Refuse
;
2840 /****i* List.mui/MUIM_DragFinish *********************************************
2845 ******************************************************************************
2849 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
2850 struct MUIP_DragFinish
*msg
)
2852 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2854 data
->drop_mark_y
= -1;
2856 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2859 /****i* List.mui/MUIM_DragReport *********************************************
2864 ******************************************************************************
2868 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
2869 struct MUIP_DragReport
*msg
)
2871 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2872 struct MUI_List_TestPos_Result pos
;
2873 struct RastPort
*rp
= _rp(obj
);
2877 /* Choose new drop mark position */
2879 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2880 if (pos
.entry
!= -1)
2883 if (pos
.yoffset
> 0)
2886 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2887 n
= data
->entries_first
;
2890 n
= MIN(data
->entries_visible
, data
->entries_num
)
2891 - data
->entries_first
;
2894 /* Clear old drop mark */
2896 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
2898 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
2899 * data
->entry_maxheight
;
2900 if (y
!= data
->drop_mark_y
)
2902 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), data
->drop_mark_y
,
2903 _mwidth(data
->area
), 1, 0, 0, 0);
2905 /* Draw new drop mark and store its position */
2907 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
2909 old_pattern
= rp
->LinePtrn
;
2910 SetDrPt(rp
, 0xF0F0);
2911 Move(rp
, _mleft(data
->area
), y
);
2912 Draw(rp
, _mright(data
->area
), y
);
2913 SetDrPt(rp
, old_pattern
);
2914 data
->drop_mark_y
= y
;
2922 /****i* List.mui/MUIM_DragDrop ***********************************************
2927 ******************************************************************************
2931 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
2932 struct MUIP_DragDrop
*msg
)
2934 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2935 struct MUI_List_TestPos_Result pos
;
2938 /* Find drop position */
2940 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2941 if (pos
.entry
!= -1)
2943 /* Change drop position when coords move past centre of entry, not
2947 if (pos
.yoffset
> 0)
2950 /* Ensure that dropped entry will be positioned between the two
2951 * entries that are above and below the drop mark, rather than
2952 * strictly at the numeric index shown */
2954 if (n
> data
->entries_active
)
2957 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2958 n
= MUIV_List_Move_Top
;
2960 n
= MUIV_List_Move_Bottom
;
2962 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
2968 /****i* List.mui/MUIM_CreateDragImage ****************************************
2971 * MUIM_CreateDragImage
2973 ******************************************************************************
2977 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
2978 struct MUIP_CreateDragImage
*msg
)
2980 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2981 BOOL success
= TRUE
;
2982 struct MUI_List_TestPos_Result pos
;
2983 WORD width
, height
, left
, top
;
2984 struct MUI_DragImage
*img
= NULL
;
2985 const struct ZuneFrameGfx
*zframe
;
2988 /* Get info on dragged entry */
2989 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
2990 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
2991 if (pos
.entry
== -1)
2996 /* Get boundaries of entry */
2997 width
= _mwidth(data
->area
);
2998 height
= data
->entry_maxheight
;
2999 left
= _mleft(data
->area
);
3000 top
= _top(data
->area
) - msg
->touchy
3001 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3003 /* Allocate drag image structure */
3004 img
= (struct MUI_DragImage
*)
3005 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3012 /* Get drag frame */
3013 zframe
= zune_zframe_get(obj
,
3014 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3016 /* Allocate drag image buffer */
3017 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3018 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3019 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3020 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3021 _screen(obj
)->RastPort
.BitMap
);
3023 if (img
->bm
!= NULL
)
3026 struct RastPort temprp
;
3027 InitRastPort(&temprp
);
3028 temprp
.BitMap
= img
->bm
;
3029 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3030 zframe
->ileft
, zframe
->itop
, width
, height
,
3034 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3035 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3036 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3037 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3038 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3041 /* Ensure drag point matches where user clicked */
3042 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3043 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3051 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3053 LONG
new, first
, entries
, visible
;
3055 new = first
= XGET(obj
, MUIA_List_First
);
3056 entries
= XGET(obj
, MUIA_List_Entries
);
3057 visible
= XGET(obj
, MUIA_List_Visible
);
3061 if (new > entries
- visible
)
3063 new = entries
- visible
;
3073 set(obj
, MUIA_List_First
, new);
3077 /**************************************************************************
3079 **************************************************************************/
3080 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
, struct MUIP_HandleEvent
*msg
)
3082 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3083 struct MUI_List_TestPos_Result pos
;
3084 LONG seltype
, old_active
, new_active
, visible
, first
, last
, i
;
3086 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3088 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3090 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3091 visible
= XGET(obj
, MUIA_List_Visible
);
3093 if (muikey
!= MUIKEY_NONE
)
3095 result
= MUI_EventHandlerRC_Eat
;
3097 /* Make keys behave differently in read-only mode */
3098 if (data
->read_only
)
3103 muikey
= MUIKEY_LINESTART
;
3107 muikey
= MUIKEY_LINEEND
;
3111 muikey
= MUIKEY_LEFT
;
3116 muikey
= MUIKEY_RIGHT
;
3124 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
3125 && !data
->read_only
)
3128 data
->click_column
= data
->def_click_column
;
3129 new_active
= MUIV_List_Active_Down
;
3133 DoMethod(obj
, MUIM_List_Jump
, 0);
3134 muikey
= MUIKEY_NONE
;
3139 new_active
= MUIV_List_Active_Top
;
3143 new_active
= MUIV_List_Active_Bottom
;
3147 case MUIKEY_WORDLEFT
:
3148 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
3152 case MUIKEY_WORDRIGHT
:
3153 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
3156 case MUIKEY_LINESTART
:
3157 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
3160 case MUIKEY_LINEEND
:
3161 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
3165 new_active
= MUIV_List_Active_Up
;
3169 new_active
= MUIV_List_Active_Down
;
3173 if (data
->read_only
)
3174 DoWheelMove(cl
, obj
, -visible
);
3176 new_active
= MUIV_List_Active_PageUp
;
3179 case MUIKEY_PAGEDOWN
:
3180 if (data
->read_only
)
3181 DoWheelMove(cl
, obj
, visible
);
3183 new_active
= MUIV_List_Active_PageDown
;
3192 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
, (IPTR
) &pos
);
3194 switch (msg
->imsg
->Class
)
3196 case IDCMP_MOUSEBUTTONS
:
3197 if (msg
->imsg
->Code
== SELECTDOWN
)
3199 if (_isinobject(data
->area
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
3201 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
3203 if (!data
->read_only
&& pos
.entry
!= -1)
3205 new_active
= pos
.entry
;
3207 clear
= (data
->multiselect
== MUIV_Listview_MultiSelect_Shifted
3208 && (msg
->imsg
->Qualifier
& (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
3209 seltype
= clear
? MUIV_List_Select_On
: MUIV_List_Select_Toggle
;
3210 select
= data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3212 /* Handle MUIA_Listview_ClickColumn */
3213 data
->click_column
= pos
.column
;
3214 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3215 data
->click_column
);
3217 /* Handle double clicking */
3218 if (data
->last_active
== pos
.entry
3219 && DoubleClick(data
->last_secs
, data
->last_mics
, msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
3221 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3222 data
->last_active
= -1;
3223 data
->last_secs
= data
->last_mics
= 0;
3227 data
->last_active
= pos
.entry
;
3228 data
->last_secs
= msg
->imsg
->Seconds
;
3229 data
->last_mics
= msg
->imsg
->Micros
;
3232 /* Look out for mouse movement, timer and
3233 inactive-window events while mouse button is
3235 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
3236 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
3237 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
3243 /* Activate object */
3244 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
3246 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
3247 data
->mouse_click
= 0;
3250 /* Restore normal event mask */
3251 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
3252 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3253 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
3257 case IDCMP_MOUSEMOVE
:
3258 case IDCMP_INTUITICKS
:
3259 if (pos
.flags
& MUI_LPR_ABOVE
)
3260 new_active
= MUIV_List_Active_Up
;
3261 else if (pos
.flags
& MUI_LPR_BELOW
)
3262 new_active
= MUIV_List_Active_Down
;
3264 new_active
= pos
.entry
;
3266 select
= new_active
!= old_active
&& data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3269 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
, MUIV_List_Select_Ask
, &seltype
);
3270 range_select
= new_active
>= 0;
3275 case IDCMP_INACTIVEWINDOW
:
3276 /* Stop listening for events we only listen to when mouse button is
3277 down: we will not be informed of the button being released */
3278 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
3279 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3280 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
3285 if (_isinobject(data
->vert
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
3287 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
3294 switch (msg
->imsg
->Code
)
3296 case RAWKEY_NM_WHEEL_UP
:
3297 DoWheelMove(cl
, obj
, -delta
);
3300 case RAWKEY_NM_WHEEL_DOWN
:
3301 DoWheelMove(cl
, obj
, delta
);
3304 result
= MUI_EventHandlerRC_Eat
;
3310 /* Decide in advance if any selections may change */
3311 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
3313 /* Change selected and active entries */
3315 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
3319 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
, MUIV_List_Select_Off
, NULL
);
3322 if (muikey
== MUIKEY_TOGGLE
)
3324 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
, MUIV_List_Select_Toggle
, NULL
);
3328 if (new_active
!= old_active
)
3329 set(obj
, MUIA_List_Active
, new_active
);
3335 if (old_active
< new_active
)
3336 first
= old_active
+ 1, last
= new_active
;
3338 first
= new_active
, last
= old_active
- 1;
3339 for (i
= first
; i
<= last
; i
++)
3340 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
3343 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
, seltype
, NULL
);
3347 set(obj
, MUIA_Listview_SelectChange
, FALSE
);
3352 /**************************************************************************
3354 **************************************************************************/
3355 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3357 switch (msg
->MethodID
)
3360 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3362 return List__OM_DISPOSE(cl
, obj
, msg
);
3364 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3366 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3369 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3371 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3372 case MUIM_HandleEvent
:
3373 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
3374 case MUIM_AskMinMax
:
3375 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3377 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3379 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3381 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3383 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3384 case MUIM_List_Clear
:
3385 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3386 case MUIM_List_Sort
:
3387 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3388 case MUIM_List_Exchange
:
3389 return List__MUIM_Exchange(cl
, obj
,
3390 (struct MUIP_List_Exchange
*)msg
);
3391 case MUIM_List_Insert
:
3392 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3393 case MUIM_List_InsertSingle
:
3394 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3395 case MUIM_List_GetEntry
:
3396 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3397 case MUIM_List_Redraw
:
3398 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3399 case MUIM_List_Remove
:
3400 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3401 case MUIM_List_Select
:
3402 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3403 case MUIM_List_Construct
:
3404 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3405 case MUIM_List_Destruct
:
3406 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3407 case MUIM_List_Compare
:
3408 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3409 case MUIM_List_Display
:
3410 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3411 case MUIM_List_SelectChange
:
3412 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3413 case MUIM_List_CreateImage
:
3414 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3415 case MUIM_List_DeleteImage
:
3416 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3417 case MUIM_List_Jump
:
3418 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3419 case MUIM_List_Move
:
3420 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3421 case MUIM_List_NextSelected
:
3422 return List__MUIM_NextSelected(cl
, obj
,
3423 (struct MUIP_List_NextSelected
*)msg
);
3424 case MUIM_List_TestPos
:
3425 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3426 case MUIM_DragQuery
:
3427 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3428 case MUIM_DragFinish
:
3429 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3430 case MUIM_DragReport
:
3431 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3433 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3434 case MUIM_CreateDragImage
:
3435 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3438 return DoSuperMethodA(cl
, obj
, msg
);
3440 BOOPSI_DISPATCHER_END
3445 const struct __MUIBuiltinClass _MUI_List_desc
=
3449 sizeof(struct MUI_ListData
),
3450 (void *) List_Dispatcher