2 Copyright © 2002-2015, The AROS Development Team. All rights reserved.
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/gfxmacros.h>
12 #include <graphics/view.h>
13 #include <devices/rawkeycodes.h>
14 #include <clib/alib_protos.h>
15 #include <proto/exec.h>
16 #include <proto/graphics.h>
17 #include <proto/utility.h>
18 #include <proto/dos.h>
19 #include <proto/intuition.h>
20 #include <proto/muimaster.h>
22 /* #define MYDEBUG 1 */
25 #include "muimaster_intern.h"
28 #include "textengine.h"
29 #include "listimage.h"
32 extern struct Library
*MUIMasterBase
;
34 #define ENTRY_TITLE (-1)
36 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N," \
37 "MAXWIDTH=MAW/N,COL=C/N,BAR/S"
57 LONG
*widths
; /* Widths of the columns */
58 LONG width
; /* Line width */
59 LONG height
; /* Line height */
60 WORD flags
; /* see below */
63 #define ENTRY_SELECTED (1<<0)
68 int colno
; /* Column number */
69 int user_width
; /* user set width; -1 if entry width */
70 int min_width
; /* min width percentage */
71 int max_width
; /* min width percentage */
73 int delta
; /* ignored for the first and last column, defaults to 4 */
76 int entries_width
; /* width of the entries (maximum of all widths) */
79 struct MUI_ImageSpec_intern
;
86 APTR intern_pool
; /* The internal pool which the class has allocated */
87 LONG intern_puddle_size
;
88 LONG intern_thresh_size
;
89 APTR pool
; /* the pool which is used to allocate list entries */
91 struct Hook
*construct_hook
;
92 struct Hook
*compare_hook
;
93 struct Hook
*destruct_hook
;
94 struct Hook
*display_hook
;
95 struct Hook
*multi_test_hook
;
97 struct Hook default_compare_hook
;
99 /* List management, currently we use a simple flat array, which is not
100 * good if many entries are inserted/deleted */
101 LONG entries_num
; /* Number of Entries in the list */
102 LONG entries_allocated
;
103 struct ListEntry
**entries
;
105 LONG entries_first
; /* first visible entry */
106 LONG entries_visible
; /* number of visible entries,
107 * determined at MUIM_Layout */
109 LONG insert_position
; /* pos of the last insertion */
111 LONG entry_maxheight
; /* Maximum height of an entry */
112 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
114 LONG entries_totalheight
;
115 LONG entries_maxwidth
;
117 LONG vertprop_entries
;
118 LONG vertprop_visible
;
121 LONG confirm_entries_num
; /* These are the correct entries num, used
122 * so you cannot set MUIA_List_Entries to
125 LONG entries_top_pixel
; /* Where the entries start */
127 /* Column managment, is allocated by ParseListFormat() and freed
128 * by CleanListFormat() */
130 LONG columns
; /* Number of columns the list has */
131 struct ColumnInfo
*ci
;
133 STRPTR
*strings
; /* the strings for the display function, one
134 * more than needed (for the entry position) */
137 int title_height
; /* The complete height of the title */
138 STRPTR title
; /* On single column lists this is the title,
139 * otherwise 1. NULL for no title(s) */
142 struct MUI_ImageSpec_intern
*list_cursor
;
143 struct MUI_ImageSpec_intern
*list_select
;
144 struct MUI_ImageSpec_intern
*list_selcur
;
146 /* Render optimization */
147 int update
; /* 1 - update everything, 2 - redraw entry at update_pos,
148 * 3 - scroll to current entries_first (old value is in
155 struct MinList images
;
158 ListviewRefresh prefs_refresh
;
159 UWORD prefs_linespacing
;
161 UWORD prefs_smoothval
;
163 /* render space handling */
168 /***************************/
169 /* Former Listview members */
170 /***************************/
180 LONG def_click_column
;
182 LONG mouse_click
; /* see below if mouse is held down */
189 struct MUI_EventHandlerNode ehn
;
192 ListviewMulti prefs_multi
;
200 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
201 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
203 #define LIST_ADJUSTWIDTH (1<<0)
204 #define LIST_ADJUSTHEIGHT (1<<1)
205 #define LIST_AUTOVISIBLE (1<<2)
206 #define LIST_DRAGSORTABLE (1<<3)
207 #define LIST_SHOWDROPMARKS (1<<4)
208 #define LIST_QUIET (1<<5)
211 /****** List.mui/MUIA_List_CompareHook ***************************************
214 * MUIA_List_CompareHook -- (V4) [IS.], struct Hook *
217 * The provided hook indicates the sort ordering of two list entries.
218 * The hook receives list-entry data pointers as its second and third
219 * arguments. The hook should return a negative value if the first entry
220 * should be placed before the second entry, a positive value if the
221 * first entry should be placed after the second entry, and zero if the
224 * In addition to being used internally for sorting operations, this hook
225 * will be called when MUIM_List_Compare is externally invoked.
227 * If this attribute is not specified or is set to NULL, all list entries
230 ******************************************************************************
234 /****** List.mui/MUIA_List_MultiTestHook *************************************
237 * MUIA_List_MultiTestHook -- (V4) [IS.], struct Hook *
240 * The provided hook indicates whether a particular list entry
241 * may be multiselected. The hook receives the list-entry data pointer as
242 * its third argument, and returns a Boolean value. If this attribute is
243 * not specified or is set to NULL, all list entries are considered
246 * Whenever an entry is about to be selected, this hook is called if
247 * there are other entries already selected. If the hook returns TRUE,
248 * the entry may be multi-selected; if the hook returns FALSE, the entry
249 * remains unselected.
251 * Additionally, if a non-multi-selectable entry has been selected (as
252 * the only selected entry in the list), any attempt to select an
253 * additional entry will fail.
255 ******************************************************************************
259 /**************************************************************************
260 Allocate a single list entry, does not initialize it (except the pointer)
261 **************************************************************************/
262 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
265 struct ListEntry
*le
;
266 int size
= sizeof(struct ListEntry
) + sizeof(LONG
) * data
->columns
+ 4;
270 mem
= AllocPooled(data
->pool
, size
);
273 D(bug("List AllocListEntry %p, %ld bytes\n", mem
, size
));
275 mem
[0] = size
; /* Save the size */
276 le
= (struct ListEntry
*)(mem
+ 1);
277 le
->widths
= (LONG
*) (le
+ 1);
279 /* Initialize fields */
283 for (j
= 0; j
< data
->columns
; j
++)
289 /**************************************************************************
290 Deallocate a single list entry, does not deinitialize it
291 **************************************************************************/
292 static void FreeListEntry(struct MUI_ListData
*data
,
293 struct ListEntry
*entry
)
295 ULONG
*mem
= ((ULONG
*) entry
) - 1;
296 D(bug("FreeListEntry %p size=%ld\n", mem
, mem
[0]));
297 FreePooled(data
->pool
, mem
, mem
[0]);
300 /**************************************************************************
301 Ensures that there can be at least the given amount of entries within
302 the list. Returns 0 if not. It also allocates the space for the title.
303 It can be accessed with data->entries[ENTRY_TITLE]
304 **************************************************************************/
305 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
307 struct ListEntry
**new_entries
;
308 int new_entries_allocated
;
310 if (size
+ 1 <= data
->entries_allocated
)
313 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
314 if (new_entries_allocated
< size
+ 1)
315 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
317 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
318 new_entries_allocated
* sizeof(struct ListEntry
*)));
320 AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*), 0);
321 if (NULL
== new_entries
)
325 CopyMem(data
->entries
- 1, new_entries
,
326 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
327 FreeVec(data
->entries
- 1);
329 data
->entries
= new_entries
+ 1;
330 data
->entries_allocated
= new_entries_allocated
;
334 /**************************************************************************
335 Prepares the insertion of count entries at pos.
336 This function doesn't care if there is enough space in the datastructure.
337 SetListSize() must be used first.
338 With current implementation, this call will never fail
339 **************************************************************************/
340 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
,
343 memmove(&data
->entries
[pos
+ count
], &data
->entries
[pos
],
344 (data
->entries_num
- pos
) * sizeof(struct ListEntry
*));
348 /**************************************************************************
349 Removes count (already deinitalized) list entries starting az pos.
350 **************************************************************************/
351 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
353 // FIXME: segfault if entries_num = pos = count = 1
354 memmove(&data
->entries
[pos
], &data
->entries
[pos
+ count
],
355 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
358 /**************************************************************************
359 Frees all memory allocated by ParseListFormat()
360 **************************************************************************/
361 static void FreeListFormat(struct MUI_ListData
*data
)
367 for (i
= 0; i
< data
->columns
; i
++)
369 FreeVec(data
->ci
[i
].preparse
);
370 data
->ci
[i
].preparse
= NULL
;
375 FreeVec(data
->preparses
);
376 data
->preparses
= NULL
;
379 FreeVec(data
->strings
- 1);
380 data
->strings
= NULL
;
385 /**************************************************************************
386 Parses the given format string (also frees a previously parsed format).
388 **************************************************************************/
389 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
397 struct RDArgs
*rdargs
;
400 format
= (STRPTR
) "";
404 FreeListFormat(data
);
408 /* Count the number of columns first */
413 if (!(data
->preparses
=
414 AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
417 if (!(data
->strings
= AllocVec((new_columns
+ 1 + 10)
418 * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos,
419 * used by orginal MUI and also some
423 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
427 for (i
= 0; i
< new_columns
; i
++)
429 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
430 data
->ci
[i
].weight
= 100;
431 data
->ci
[i
].delta
= 4;
432 data
->ci
[i
].min_width
= -1;
433 data
->ci
[i
].max_width
= -1;
434 data
->ci
[i
].user_width
= -1;
435 data
->ci
[i
].bar
= FALSE
;
436 data
->ci
[i
].preparse
= NULL
;
439 if ((format_sep
= StrDup(format
)) != 0)
441 for (i
= 0; format_sep
[i
] != '\0'; i
++)
443 if (format_sep
[i
] == ',')
444 format_sep
[i
] = '\0';
447 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
453 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
454 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
455 rdargs
->RDA_Source
.CS_CurChr
= 0;
456 rdargs
->RDA_DAList
= 0;
457 rdargs
->RDA_Buffer
= NULL
;
458 rdargs
->RDA_BufSiz
= 0;
459 rdargs
->RDA_ExtHelp
= NULL
;
460 rdargs
->RDA_Flags
= 0;
462 memset(args
, 0, sizeof args
);
463 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
466 data
->ci
[i
].colno
= *(LONG
*) args
[ARG_COL
];
467 if (args
[ARG_WEIGHT
])
468 data
->ci
[i
].weight
= *(LONG
*) args
[ARG_WEIGHT
];
470 data
->ci
[i
].delta
= *(LONG
*) args
[ARG_DELTA
];
471 if (args
[ARG_MINWIDTH
])
472 data
->ci
[i
].min_width
=
473 *(LONG
*) args
[ARG_MINWIDTH
];
474 if (args
[ARG_MAXWIDTH
])
475 data
->ci
[i
].max_width
=
476 *(LONG
*) args
[ARG_MAXWIDTH
];
477 data
->ci
[i
].bar
= args
[ARG_BAR
];
478 if (args
[ARG_PREPARSE
])
479 data
->ci
[i
].preparse
=
480 StrDup((STRPTR
) args
[ARG_PREPARSE
]);
484 ptr
+= strlen(ptr
) + 1;
487 while (i
< new_columns
);
488 FreeDosObject(DOS_RDARGS
, rdargs
);
493 for (i
= 0; i
< new_columns
; i
++)
495 D(bug("colno %d weight %d delta %d preparse %s\n",
496 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
,
497 data
->ci
[i
].preparse
));
500 data
->columns
= new_columns
;
501 data
->strings
++; /* Skip entry pos */
506 /**************************************************************************
507 Call the MUIM_List_Display for the given entry. It fills out
508 data->string and data->preparses
509 **************************************************************************/
510 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
512 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
516 for (col
= 0; col
< data
->columns
; col
++)
517 data
->preparses
[col
] = data
->ci
[col
].preparse
;
519 if (entry_pos
== ENTRY_TITLE
)
521 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
) 1))
523 *data
->strings
= data
->title
;
526 entry_data
= NULL
; /* it's a title request */
529 entry_data
= data
->entries
[entry_pos
]->data
;
531 /* Get the display formation */
532 DoMethod(obj
, MUIM_List_Display
, (IPTR
) entry_data
,
533 (IPTR
) data
->strings
, entry_pos
, (IPTR
) data
->preparses
);
536 /**************************************************************************
537 Determine the dims of a single entry and adapt the columninfo according
538 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
539 be redrawn after this operation, 1 if all entries need to be redrawn.
540 **************************************************************************/
541 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
543 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
544 struct ListEntry
*entry
= data
->entries
[pos
];
551 if (!(_flags(obj
) & MADF_SETUP
))
554 DisplayEntry(cl
, obj
, pos
);
556 /* Set height to at least minheight */
557 if (data
->entries
[pos
]->height
< data
->entry_minheight
)
558 data
->entries
[pos
]->height
= data
->entry_minheight
;
560 for (j
= 0; j
< data
->columns
; j
++)
563 zune_text_new(data
->preparses
[j
], data
->strings
[j
],
567 zune_text_get_bounds(text
, obj
);
569 if (text
->height
> data
->entries
[pos
]->height
)
571 data
->entries
[pos
]->height
= text
->height
;
572 /* entry height changed, redraw all entries later */
575 data
->entries
[pos
]->widths
[j
] = text
->width
;
577 if (text
->width
> data
->ci
[j
].entries_width
)
579 /* This columns width is bigger than the other in the same
580 * columns, so we store this value
582 data
->ci
[j
].entries_width
= text
->width
;
583 /* column width changed, redraw all entries later */
587 zune_text_destroy(text
);
590 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
592 data
->entry_maxheight
= data
->entries
[pos
]->height
;
593 /* maximum entry height changed, redraw all entries later */
600 /**************************************************************************
601 Determine the widths of the entries
602 **************************************************************************/
603 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
606 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
608 if (!(_flags(obj
) & MADF_SETUP
))
611 for (j
= 0; j
< data
->columns
; j
++)
612 data
->ci
[j
].entries_width
= 0;
614 data
->entry_maxheight
= 0;
615 data
->entries_totalheight
= 0;
616 data
->entries_maxwidth
= 0;
618 for (i
= (data
->title
? ENTRY_TITLE
: 0); i
< data
->entries_num
; i
++)
620 CalcDimsOfEntry(cl
, obj
, i
);
621 data
->entries_totalheight
+= data
->entries
[i
]->height
;
624 for (j
= 0; j
< data
->columns
; j
++)
625 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
627 if (!data
->entry_maxheight
)
628 data
->entry_maxheight
= 1;
631 /**************************************************************************
632 Calculates the number of visible entry lines. Returns 1 if it has
634 **************************************************************************/
635 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
637 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
638 int old_entries_visible
= data
->entries_visible
;
639 int old_entries_top_pixel
= data
->entries_top_pixel
;
641 data
->entries_visible
= (_mheight(data
->area
) - data
->title_height
)
642 / (data
->entry_maxheight
/* + data->prefs_linespacing */ );
644 /* Distribute extra vertical space evenly between top and bottom of
647 data
->entries_top_pixel
= _mtop(data
->area
) + data
->title_height
648 + (_mheight(data
->area
) - data
->title_height
650 data
->entries_visible
*
651 (data
->entry_maxheight
/* + data->prefs_linespacing */ )) / 2;
653 return (old_entries_visible
!= data
->entries_visible
)
654 || (old_entries_top_pixel
!= data
->entries_top_pixel
);
657 /**************************************************************************
658 Default hook to compare two list entries. Works for strings only.
659 **************************************************************************/
660 AROS_UFH3S(int, default_compare_func
,
661 AROS_UFHA(struct Hook
*, h
, A0
),
662 AROS_UFHA(char *, s2
, A2
),
663 AROS_UFHA(char *, s1
, A1
))
667 return Stricmp(s1
, s2
);
672 #define PROP_VERT_FIRST 1
674 static ULONG
List_Function(struct Hook
*hook
, Object
* obj
, void **msg
)
676 struct MUI_ListData
*data
= (struct MUI_ListData
*)hook
->h_Data
;
677 SIPTR type
= (SIPTR
) msg
[0];
678 SIPTR val
= (SIPTR
) msg
[1];
682 case PROP_VERT_FIRST
:
683 get(data
->vert
, MUIA_Prop_First
, &val
);
684 nnset(obj
, MUIA_List_VertProp_First
, val
);
690 /* At entry to this function, data->area is always set, but data->vert may or may not be set */
691 static void List_HandleScrollerPos(struct IClass
*cl
, Object
*obj
)
693 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
694 BOOL vert_not_used
= FALSE
;
696 /* Disallow any changes after setup, this function should basically a creation-time only */
697 if (_flags(obj
) & MADF_SETUP
)
700 /* Remove both objects */
701 if (data
->area_connected
)
702 DoMethod(obj
, OM_REMMEMBER
, data
->area
);
703 if (data
->vert_connected
)
704 DoMethod(obj
, OM_REMMEMBER
, data
->vert
);
706 /* Add list and/or scroller */
707 switch (data
->scroller_pos
)
709 case MUIV_Listview_ScrollerPos_None
:
710 vert_not_used
= TRUE
;
711 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
713 case MUIV_Listview_ScrollerPos_Left
:
714 if (!data
->vert
) data
->vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
715 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
716 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
719 if (!data
->vert
) data
->vert
= ScrollbarObject
, MUIA_Group_Horiz
, FALSE
, End
;
720 DoMethod(obj
, OM_ADDMEMBER
, data
->area
);
721 DoMethod(obj
, OM_ADDMEMBER
, data
->vert
);
725 data
->area_connected
= TRUE
;
727 /* Handle case where it was decided that vert will not be used */
732 if (data
->vert_connected
)
734 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_First
, (IPTR
) data
->vert
);
735 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Visible
, (IPTR
) data
->vert
);
736 DoMethod(obj
, MUIM_KillNotifyObj
, MUIA_List_VertProp_Entries
, (IPTR
) data
->vert
);
737 data
->vert_connected
= FALSE
;
740 MUI_DisposeObject(data
->vert
);
745 /* If at this point data->vert is not null, it means vert is to be connected */
746 if (data
->vert
&& !data
->vert_connected
)
748 LONG entries
= 0, first
= 0, visible
= 0;
750 get(obj
, MUIA_List_VertProp_First
, &first
);
751 get(obj
, MUIA_List_VertProp_Visible
, &visible
);
752 get(obj
, MUIA_List_VertProp_Entries
, &entries
);
755 MUIA_Prop_First
, first
,
756 MUIA_Prop_Visible
, visible
, MUIA_Prop_Entries
, entries
, TAG_DONE
);
759 DoMethod(data
->vert
, MUIM_Notify
, MUIA_Prop_First
, MUIV_EveryTime
, (IPTR
) obj
,
760 4, MUIM_CallHook
, (IPTR
) &data
->hook
, PROP_VERT_FIRST
,
763 /* Pass prop object as DestObj (based on code in NList) */
764 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_First
, MUIV_EveryTime
,
765 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
, MUIA_Prop_First
, MUIV_TriggerValue
);
766 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Visible
, MUIV_EveryTime
,
767 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
, MUIA_Prop_Visible
, MUIV_TriggerValue
);
768 DoMethod(obj
, MUIM_Notify
, MUIA_List_VertProp_Entries
, MUIV_EveryTime
,
769 (IPTR
) data
->vert
, 3, MUIM_NoNotifySet
, MUIA_Prop_Entries
, MUIV_TriggerValue
);
771 data
->vert_connected
= TRUE
;
776 /**************************************************************************
778 **************************************************************************/
779 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
781 struct MUI_ListData
*data
;
783 struct TagItem
*tags
;
785 LONG new_entries_active
= MUIV_List_Active_Off
;
786 struct TagItem rectattrs
[2] = {{TAG_IGNORE
, TAG_IGNORE
}, {TAG_DONE
, TAG_DONE
}};
789 /* search for MUIA_Frame as it has to be passed to rectangle object */
790 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
792 if (tag
->ti_Tag
== MUIA_Frame
)
794 rectattrs
[0].ti_Tag
= MUIA_Frame
;
795 rectattrs
[0].ti_Data
= tag
->ti_Data
;
796 tag
->ti_Tag
= TAG_IGNORE
;
801 obj
= (Object
*) DoSuperNewTags(cl
, obj
, NULL
,
802 MUIA_Group_Horiz
, TRUE
,
805 MUIA_Group_Spacing
, 0,
806 MUIA_Font
, MUIV_Font_List
,
807 MUIA_ShowSelState
, FALSE
,
808 MUIA_InputMode
, MUIV_InputMode_RelVerify
,
809 MUIA_Background
, MUII_ListBack
,
810 TAG_MORE
, (IPTR
) msg
->ops_AttrList
,
816 data
= INST_DATA(cl
, obj
);
819 data
->entries_active
= MUIV_List_Active_Off
;
820 data
->intern_puddle_size
= 2008;
821 data
->intern_thresh_size
= 1024;
822 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
823 data
->default_compare_hook
.h_SubEntry
= 0;
824 data
->compare_hook
= &(data
->default_compare_hook
);
825 data
->flags
= LIST_SHOWDROPMARKS
;
826 data
->area_replaced
= FALSE
;
827 data
->area_connected
= FALSE
;
828 data
->vert_connected
= FALSE
;
830 data
->last_active
= -1;
832 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
| IDCMP_RAWKEY
;
833 data
->ehn
.ehn_Priority
= 0;
834 data
->ehn
.ehn_Flags
= 0;
835 data
->ehn
.ehn_Object
= obj
;
836 data
->ehn
.ehn_Class
= cl
;
838 data
->hook
.h_Entry
= HookEntry
;
839 data
->hook
.h_SubEntry
= (HOOKFUNC
) List_Function
;
840 data
->hook
.h_Data
= data
;
842 area
= (Object
*)GetTagData(MUIA_List_ListArea
, (IPTR
) 0, msg
->ops_AttrList
);
845 area
= RectangleObject
, MUIA_FillArea
, FALSE
, TAG_MORE
, (IPTR
) rectattrs
, End
;
847 data
->area_replaced
= TRUE
;
850 /* parse initial taglist */
851 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
855 case MUIA_List_Active
:
856 new_entries_active
= tag
->ti_Data
;
860 data
->pool
= (APTR
) tag
->ti_Data
;
863 case MUIA_List_PoolPuddleSize
:
864 data
->intern_puddle_size
= tag
->ti_Data
;
867 case MUIA_List_PoolThreshSize
:
868 data
->intern_thresh_size
= tag
->ti_Data
;
871 case MUIA_List_CompareHook
:
872 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
873 if (data
->compare_hook
== NULL
)
874 data
->compare_hook
= &data
->default_compare_hook
;
877 case MUIA_List_ConstructHook
:
878 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
881 case MUIA_List_DestructHook
:
882 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
885 case MUIA_List_DisplayHook
:
886 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
889 case MUIA_List_MultiTestHook
:
890 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
893 case MUIA_List_SourceArray
:
894 array
= (APTR
*) tag
->ti_Data
;
897 case MUIA_List_Format
:
898 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
901 case MUIA_List_Title
:
902 data
->title
= (STRPTR
) tag
->ti_Data
;
905 case MUIA_List_MinLineHeight
:
906 data
->entry_minheight
= tag
->ti_Data
;
909 case MUIA_List_AdjustHeight
:
910 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
913 case MUIA_List_AdjustWidth
:
914 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
917 case MUIA_List_AutoVisible
:
918 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
921 case MUIA_List_ShowDropMarks
:
922 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
925 case MUIA_List_DragSortable
:
926 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
927 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
930 case MUIA_Listview_ScrollerPos
:
931 data
->scroller_pos
= tag
->ti_Data
;
934 case MUIA_Listview_Input
:
935 data
->read_only
= !tag
->ti_Data
;
938 case MUIA_Listview_MultiSelect
:
939 data
->multiselect
= tag
->ti_Data
;
942 case MUIA_Listview_DoubleClick
:
943 data
->doubleclick
= tag
->ti_Data
!= 0;
948 List_HandleScrollerPos(cl
, obj
);
952 /* No memory pool given, so we create our own */
953 data
->pool
= data
->intern_pool
=
954 CreatePool(0, data
->intern_puddle_size
,
955 data
->intern_thresh_size
);
958 CoerceMethod(cl
, obj
, OM_DISPOSE
);
963 /* parse the list format */
964 if (!(ParseListFormat(data
, data
->format
)))
966 CoerceMethod(cl
, obj
, OM_DISPOSE
);
970 /* This is neccessary for at least the title */
971 if (!SetListSize(data
, 0))
973 CoerceMethod(cl
, obj
, OM_DISPOSE
);
979 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
981 CoerceMethod(cl
, obj
, OM_DISPOSE
);
986 data
->entries
[ENTRY_TITLE
] = NULL
;
991 /* Count the number of elements */
992 for (i
= 0; array
[i
] != NULL
; i
++)
995 DoMethod(obj
, MUIM_List_Insert
, (IPTR
) array
, i
,
996 MUIV_List_Insert_Top
);
999 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
1001 switch (new_entries_active
)
1003 case MUIV_List_Active_Top
:
1004 new_entries_active
= 0;
1007 case MUIV_List_Active_Bottom
:
1008 new_entries_active
= data
->entries_num
- 1;
1012 if (new_entries_active
< 0)
1013 new_entries_active
= 0;
1014 else if (new_entries_active
>= data
->entries_num
)
1015 new_entries_active
= data
->entries_num
- 1;
1017 data
->entries_active
= new_entries_active
;
1018 /* Selected entry will be moved into visible area */
1021 NewList((struct List
*)&data
->images
);
1023 D(bug("List_New(%lx)\n", obj
));
1028 /**************************************************************************
1030 **************************************************************************/
1031 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
1033 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1035 D(bug("List Dispose\n"));
1037 /* Call destruct method for every entry and free the entries manually
1038 * to avoid notification */
1039 while (data
->confirm_entries_num
)
1041 struct ListEntry
*lentry
=
1042 data
->entries
[--data
->confirm_entries_num
];
1043 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1045 FreeListEntry(data
, lentry
);
1048 if (data
->intern_pool
)
1049 DeletePool(data
->intern_pool
);
1051 FreeVec(data
->entries
- 1);
1052 /* title is currently before all other elements */
1054 FreeListFormat(data
);
1055 FreeVec(data
->format
);
1057 return DoSuperMethodA(cl
, obj
, msg
);
1061 /**************************************************************************
1063 **************************************************************************/
1064 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
1066 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1067 struct TagItem
*tag
;
1068 struct TagItem
*tags
;
1071 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
));)
1073 switch (tag
->ti_Tag
)
1075 case MUIA_List_CompareHook
:
1076 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
1077 if (data
->compare_hook
== NULL
)
1078 data
->compare_hook
= &data
->default_compare_hook
;
1081 case MUIA_List_ConstructHook
:
1082 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
1085 case MUIA_List_DestructHook
:
1086 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
1089 case MUIA_List_DisplayHook
:
1090 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
1093 case MUIA_List_MultiTestHook
:
1094 data
->multi_test_hook
= (struct Hook
*)tag
->ti_Data
;
1095 if (data
->multi_test_hook
!= NULL
)
1097 /* Clearing current selections is the easiest way to keep
1098 * selections consistent with the new hook */
1099 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
,
1100 MUIV_List_Select_Off
, NULL
);
1104 case MUIA_List_Title
:
1105 data
->title
= (STRPTR
) tag
->ti_Data
;
1106 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1109 case MUIA_List_VertProp_First
:
1110 data
->vertprop_first
= tag
->ti_Data
;
1111 if (data
->entries_first
!= tag
->ti_Data
)
1113 set(obj
, MUIA_List_First
, tag
->ti_Data
);
1117 case MUIA_List_Format
:
1118 data
->format
= StrDup((STRPTR
) tag
->ti_Data
);
1119 ParseListFormat(data
, data
->format
);
1120 // FIXME: should we check for errors?
1121 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1124 case MUIA_List_VertProp_Entries
:
1125 data
->vertprop_entries
= tag
->ti_Data
;
1128 case MUIA_List_VertProp_Visible
:
1129 data
->vertprop_visible
= tag
->ti_Data
;
1130 data
->entries_visible
= tag
->ti_Data
;
1133 case MUIA_List_Active
:
1135 LONG new_entries_active
= tag
->ti_Data
;
1137 if ((data
->entries_num
)
1138 && (new_entries_active
!= MUIV_List_Active_Off
))
1140 switch (new_entries_active
)
1142 case MUIV_List_Active_Top
:
1143 new_entries_active
= 0;
1146 case MUIV_List_Active_Bottom
:
1147 new_entries_active
= data
->entries_num
- 1;
1150 case MUIV_List_Active_Up
:
1151 new_entries_active
= data
->entries_active
- 1;
1154 case MUIV_List_Active_Down
:
1155 new_entries_active
= data
->entries_active
+ 1;
1158 case MUIV_List_Active_PageUp
:
1159 new_entries_active
=
1160 data
->entries_active
- data
->entries_visible
;
1163 case MUIV_List_Active_PageDown
:
1164 new_entries_active
=
1165 data
->entries_active
+ data
->entries_visible
;
1169 if (new_entries_active
< 0)
1170 new_entries_active
= 0;
1171 else if (new_entries_active
>= data
->entries_num
)
1172 new_entries_active
= data
->entries_num
- 1;
1175 new_entries_active
= -1;
1177 if (data
->entries_active
!= new_entries_active
)
1179 LONG old
= data
->entries_active
;
1180 data
->entries_active
= new_entries_active
;
1182 /* Selectchange stuff */
1183 if (new_entries_active
!= -1)
1185 DoMethod(obj
, MUIM_List_SelectChange
,
1186 new_entries_active
, MUIV_List_Select_On
, 0);
1187 DoMethod(obj
, MUIM_List_SelectChange
,
1188 new_entries_active
, MUIV_List_Select_Active
, 0);
1191 DoMethod(obj
, MUIM_List_SelectChange
,
1192 MUIV_List_Active_Off
, MUIV_List_Select_Off
, 0);
1195 data
->update_pos
= old
;
1196 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1198 data
->update_pos
= data
->entries_active
;
1199 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1201 /* Make new active entry visible (if there is one and
1203 if (new_entries_active
!= -1
1204 && (_flags(obj
) & MADF_SETUP
))
1206 DoMethod(obj
, MUIM_List_Jump
,
1207 MUIV_List_Jump_Active
);
1213 case MUIA_List_First
:
1214 data
->update_pos
= data
->entries_first
;
1216 data
->entries_first
= tag
->ti_Data
;
1218 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1219 if ((data
->vertprop_first
!= tag
->ti_Data
)
1220 && (!(data
->flags
& LIST_QUIET
)))
1222 set(obj
, MUIA_List_VertProp_First
, tag
->ti_Data
);
1226 case MUIA_List_Visible
: /* Shouldn't be settable? */
1227 if (data
->vertprop_visible
!= tag
->ti_Data
)
1228 set(obj
, MUIA_List_VertProp_Visible
, tag
->ti_Data
);
1231 case MUIA_List_Entries
:
1232 if (data
->confirm_entries_num
== tag
->ti_Data
)
1234 data
->entries_num
= tag
->ti_Data
;
1235 if (!(data
->flags
& LIST_QUIET
))
1237 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1242 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
1246 case MUIA_List_Quiet
:
1247 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
1250 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
1251 if (data
->entries_num
!= XGET(obj
, MUIA_List_VertProp_Entries
))
1252 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
1253 if (data
->entries_first
!= XGET(obj
, MUIA_List_VertProp_First
))
1254 set(obj
, MUIA_List_VertProp_First
, data
->entries_first
);
1258 case MUIA_List_AutoVisible
:
1259 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_AUTOVISIBLE
);
1262 case MUIA_List_ShowDropMarks
:
1263 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_SHOWDROPMARKS
);
1266 case MUIA_List_DragSortable
:
1267 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_DRAGSORTABLE
);
1268 set(obj
, MUIA_Draggable
, tag
->ti_Data
);
1272 /* Swallow this so the Area class doesn't redraw us */
1273 tag
->ti_Tag
= TAG_IGNORE
;
1277 if (_flags(obj
) & MADF_SETUP
)
1279 /* Stop listening for events we only listen to when mouse
1280 button is down: we will not be informed of the button
1282 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1283 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
1284 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1288 case MUIA_Listview_DoubleClick
: /* private set */
1289 data
->doubleclick
= tag
->ti_Data
!= 0;
1292 case MUIA_Listview_SelectChange
: /* private set */
1293 data
->select_change
= tag
->ti_Data
!= 0;
1296 case MUIA_Listview_ScrollerPos
: /* private set */
1297 data
->scroller_pos
= tag
->ti_Data
;
1298 List_HandleScrollerPos(cl
, obj
);
1301 case MUIA_Listview_Input
: /* private set */
1302 data
->read_only
= !tag
->ti_Data
;
1305 case MUIA_Listview_MultiSelect
: /* private set */
1306 data
->multiselect
= tag
->ti_Data
;
1311 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1314 /**************************************************************************
1316 **************************************************************************/
1317 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
1319 /* small macro to simplify return value storage */
1320 #define STORE *(msg->opg_Storage)
1321 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1323 switch (msg
->opg_AttrID
)
1325 case MUIA_List_Entries
:
1326 STORE
= data
->entries_num
;
1328 case MUIA_List_First
:
1329 STORE
= data
->entries_first
;
1331 case MUIA_List_Active
:
1332 STORE
= data
->entries_active
;
1334 case MUIA_List_InsertPosition
:
1335 STORE
= data
->insert_position
;
1337 case MUIA_List_Title
:
1338 STORE
= (IPTR
) data
->title
;
1340 case MUIA_List_VertProp_Entries
:
1341 STORE
= data
->vertprop_entries
;
1343 case MUIA_List_VertProp_Visible
:
1344 case MUIA_List_Visible
:
1345 STORE
= data
->vertprop_visible
;
1347 case MUIA_List_VertProp_First
:
1348 STORE
= data
->vertprop_first
;
1350 case MUIA_List_Format
:
1351 STORE
= (IPTR
) data
->format
;
1353 case MUIA_List_AutoVisible
:
1354 STORE
= data
->flags
& LIST_AUTOVISIBLE
;
1356 case MUIA_List_ShowDropMarks
:
1357 STORE
= data
->flags
& LIST_SHOWDROPMARKS
;
1359 case MUIA_List_DragSortable
:
1360 STORE
= data
->flags
& LIST_DRAGSORTABLE
;
1362 case MUIA_Listview_ClickColumn
:
1363 STORE
= data
->click_column
;
1365 case MUIA_Listview_DoubleClick
:
1366 STORE
= data
->doubleclick
;
1368 case MUIA_Listview_SelectChange
:
1369 STORE
= data
->select_change
;
1371 case MUIA_Listview_List
:
1376 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1382 /**************************************************************************
1384 **************************************************************************/
1385 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
,
1386 struct MUIP_Setup
*msg
)
1388 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1390 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
1393 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
1394 data
->prefs_linespacing
=
1395 muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
1396 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
1397 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
1399 CalcWidths(cl
, obj
);
1402 zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
1404 zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
1406 zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
1408 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
1409 if (data
->multiselect
== MUIV_Listview_MultiSelect_Default
)
1411 if (data
->prefs_multi
== LISTVIEW_MULTI_SHIFTED
)
1412 data
->multiselect
= MUIV_Listview_MultiSelect_Shifted
;
1414 data
->multiselect
= MUIV_Listview_MultiSelect_Always
;
1417 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
1422 /**************************************************************************
1424 **************************************************************************/
1425 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
,
1426 struct MUIP_Cleanup
*msg
)
1428 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1429 struct ListImage
*li
= List_First(&data
->images
);
1433 struct ListImage
*next
= Node_Next(li
);
1434 DoMethod(obj
, MUIM_List_DeleteImage
, (IPTR
) li
);
1438 zune_imspec_cleanup(data
->list_cursor
);
1439 zune_imspec_cleanup(data
->list_select
);
1440 zune_imspec_cleanup(data
->list_selcur
);
1442 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
1443 data
->mouse_click
= 0;
1445 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1448 /**************************************************************************
1450 **************************************************************************/
1451 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,
1452 struct MUIP_AskMinMax
*msg
)
1454 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1456 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1459 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1461 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1462 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1463 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1467 msg
->MinMaxInfo
->MinWidth
+= 40;
1468 msg
->MinMaxInfo
->DefWidth
+= 100;
1469 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1472 if (data
->entries_num
> 0)
1474 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1476 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1477 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1478 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1482 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1483 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1484 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1485 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1490 msg
->MinMaxInfo
->MinHeight
+= 36;
1491 msg
->MinMaxInfo
->DefHeight
+= 96;
1492 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1494 D(bug("List %p minheigh=%d, line maxh=%d\n",
1495 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1499 /****i* List.mui/MUIM_Layout *************************************************
1504 ******************************************************************************
1508 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,
1509 struct MUIP_Layout
*msg
)
1511 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1512 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1513 LONG new_entries_first
= data
->entries_first
;
1515 /* Calc the numbers of entries visible */
1516 CalcVertVisible(cl
, obj
);
1518 /* Ensure active entry is visible if requested */
1519 if (data
->entries_active
+ 1 >=
1520 (data
->entries_first
+ data
->entries_visible
)
1521 && (data
->flags
& LIST_AUTOVISIBLE
) != 0)
1523 data
->entries_active
- data
->entries_visible
+ 1;
1525 /* Ensure there are no unnecessary empty lines */
1526 if ((new_entries_first
+ data
->entries_visible
>=
1528 && (data
->entries_visible
<= data
->entries_num
))
1529 new_entries_first
= data
->entries_num
- data
->entries_visible
;
1531 /* Always show the start of the list if it isn't long enough to fill the
1533 if (data
->entries_num
<= data
->entries_visible
)
1534 new_entries_first
= 0;
1536 if (new_entries_first
< 0)
1537 new_entries_first
= 0;
1539 set(obj
, new_entries_first
!= data
->entries_first
?
1540 MUIA_List_First
: TAG_IGNORE
, new_entries_first
);
1542 /* So the notify happens */
1543 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1549 /**************************************************************************
1551 **************************************************************************/
1552 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
,
1553 struct MUIP_Show
*msg
)
1555 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1556 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1558 zune_imspec_show(data
->list_cursor
, obj
);
1559 zune_imspec_show(data
->list_select
, obj
);
1560 zune_imspec_show(data
->list_selcur
, obj
);
1565 /**************************************************************************
1567 **************************************************************************/
1568 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
,
1569 struct MUIP_Hide
*msg
)
1571 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1573 zune_imspec_hide(data
->list_cursor
);
1574 zune_imspec_hide(data
->list_select
);
1575 zune_imspec_hide(data
->list_selcur
);
1577 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1581 /**************************************************************************
1582 Draw an entry at entry_pos at the given row. To draw the title, set pos to
1584 **************************************************************************/
1585 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
,
1588 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1591 /* To be sure we don't draw anything if there is no title */
1592 if (entry_pos
== ENTRY_TITLE
&& !data
->title
)
1595 DisplayEntry(cl
, obj
, entry_pos
);
1596 x1
= _mleft(data
->area
);
1598 for (col
= 0; col
< data
->columns
; col
++)
1601 x2
= x1
+ data
->ci
[col
].entries_width
;
1604 zune_text_new(data
->preparses
[col
], data
->strings
[col
],
1605 ZTEXT_ARG_NONE
, 0)))
1607 /* Could be made simpler, as we don't really need the bounds */
1608 zune_text_get_bounds(text
, obj
);
1609 /* Note, this was MPEN_SHADOW before */
1610 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1611 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1612 zune_text_destroy(text
);
1614 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1618 /**************************************************************************
1620 **************************************************************************/
1621 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1623 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1627 BOOL scroll_caused_damage
= FALSE
;
1628 struct MUI_ImageSpec_intern
*highlight
;
1631 if (data
->flags
& LIST_QUIET
)
1634 ret
= DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1636 if (data
->area_replaced
)
1639 /* Calculate the title height */
1642 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
1646 data
->title_height
= 0;
1649 /* Calc the numbers of entries visible */
1650 CalcVertVisible(cl
, obj
);
1652 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1654 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), _mtop(data
->area
),
1655 _mwidth(data
->area
), _mheight(data
->area
),
1656 0, data
->entries_first
* data
->entry_maxheight
, 0);
1659 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(data
->area
), _mtop(data
->area
),
1660 _mwidth(data
->area
), _mheight(data
->area
));
1662 if ((msg
->flags
& MADF_DRAWUPDATE
) == 0 || data
->update
== 1)
1664 y
= _mtop(data
->area
);
1667 if (data
->title_height
&& data
->title
)
1669 List_DrawEntry(cl
, obj
, ENTRY_TITLE
, y
);
1670 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1671 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1672 Move(_rp(obj
), _mleft(data
->area
), y
);
1673 Draw(_rp(obj
), _mright(data
->area
), y
);
1674 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1676 Move(_rp(obj
), _mleft(data
->area
), y
);
1677 Draw(_rp(obj
), _mright(data
->area
), y
);
1681 y
= data
->entries_top_pixel
;
1683 start
= data
->entries_first
;
1684 end
= data
->entries_first
+ data
->entries_visible
;
1686 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1688 int diffy
= data
->entries_first
- data
->update_pos
;
1690 if (abs(diffy
) < data
->entries_visible
)
1692 scroll_caused_damage
=
1693 (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1695 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1696 _mleft(data
->area
), y
,
1697 _mright(data
->area
),
1698 y
+ data
->entry_maxheight
* data
->entries_visible
);
1700 scroll_caused_damage
=
1701 scroll_caused_damage
1702 && (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1706 start
= end
- diffy
;
1707 y
+= data
->entry_maxheight
* (data
->entries_visible
-
1711 end
= start
- diffy
;
1715 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1717 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), top
,
1718 _mwidth(data
->area
), bottom
- top
+ 1,
1720 top
- _mtop(data
->area
) + data
->entries_first
* data
->entry_maxheight
,
1724 for (entry_pos
= start
;
1725 entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1727 struct ListEntry
*entry
= data
->entries
[entry_pos
];
1729 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1730 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1731 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1732 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1733 && data
->update_pos
== entry_pos
))
1735 /* Choose appropriate highlight image */
1737 if (entry_pos
== data
->entries_active
1738 && entry
->flags
& ENTRY_SELECTED
)
1739 highlight
= data
->list_selcur
;
1740 else if (entry_pos
== data
->entries_active
)
1741 highlight
= data
->list_cursor
;
1742 else if (entry
->flags
& ENTRY_SELECTED
)
1743 highlight
= data
->list_select
;
1747 /* Draw highlight or background */
1749 if (highlight
!= NULL
)
1751 zune_imspec_draw(highlight
, muiRenderInfo(obj
),
1752 _mleft(data
->area
), y
, _mwidth(data
->area
), data
->entry_maxheight
,
1753 0, y
- data
->entries_top_pixel
, 0);
1755 else if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2
1756 && data
->update_pos
== entry_pos
)
1758 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), y
,
1759 _mwidth(data
->area
), data
->entry_maxheight
, 0,
1760 y
- _mtop(data
->area
) +
1761 data
->entries_first
* data
->entry_maxheight
, 0);
1764 List_DrawEntry(cl
, obj
, entry_pos
, y
);
1766 y
+= data
->entry_maxheight
;
1769 MUI_RemoveClipping(muiRenderInfo(obj
), clip
);
1773 if (scroll_caused_damage
)
1775 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1777 /* Theoretically it might happen that more damage is caused
1778 after ScrollRaster. By something else, like window movement
1779 in front of our window. Therefore refresh root object of
1780 window, not just this object */
1784 get(_win(obj
), MUIA_Window_RootObject
, &o
);
1785 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1787 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1791 ULONG x1
= _mleft(data
->area
);
1793 y
= _mtop(data
->area
);
1795 if (data
->title_height
&& data
->title
)
1797 for (col
= 0; col
< data
->columns
; col
++)
1799 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1800 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1802 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1805 if (data
->ci
[col
].bar
)
1807 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1808 Move(_rp(obj
), x1
, y
);
1810 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1811 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1812 Move(_rp(obj
), x1
+ 1, y
);
1813 Draw(_rp(obj
), x1
+ 1,
1814 y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1818 x1
+= data
->ci
[col
].delta
- halfdelta
;
1820 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1823 x1
= _mleft(data
->area
);
1825 for (col
= 0; col
< data
->columns
; col
++)
1827 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1828 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1830 if (x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(data
->area
))
1833 if (data
->ci
[col
].bar
)
1835 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHINE
]);
1836 Move(_rp(obj
), x1
, y
);
1837 Draw(_rp(obj
), x1
, _mbottom(data
->area
));
1838 SetAPen(_rp(obj
), _pens(obj
)[MPEN_SHADOW
]);
1839 Move(_rp(obj
), x1
+ 1, y
);
1840 Draw(_rp(obj
), x1
+ 1, _mbottom(data
->area
));
1845 x1
+= data
->ci
[col
].delta
- halfdelta
;
1851 /****** List.mui/MUIM_List_Clear *********************************************
1854 * MUIM_List_Clear (V4)
1857 * DoMethod(obj, MUIM_List_Clear);
1860 * Removes all entries from the list.
1862 ******************************************************************************
1866 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
,
1867 struct MUIP_List_Clear
*msg
)
1869 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1871 while (data
->confirm_entries_num
)
1873 struct ListEntry
*lentry
=
1874 data
->entries
[--data
->confirm_entries_num
];
1875 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
1877 FreeListEntry(data
, lentry
);
1879 /* Should never fail when shrinking */
1880 SetListSize(data
, 0);
1883 if (data
->confirm_entries_num
!= data
->entries_num
)
1885 SetAttrs(obj
, MUIA_List_Entries
, 0, MUIA_List_First
, 0,
1886 /* Notify only when no entry was active */
1887 data
->entries_active
!=
1888 MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
,
1889 MUIV_List_Active_Off
, TAG_DONE
);
1892 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1898 /**************************************************************************
1900 **************************************************************************/
1901 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
,
1902 struct MUIP_List_Exchange
*msg
)
1904 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1909 case MUIV_List_Exchange_Top
:
1912 case MUIV_List_Exchange_Active
:
1913 pos1
= data
->entries_active
;
1915 case MUIV_List_Exchange_Bottom
:
1916 pos1
= data
->entries_num
- 1;
1924 case MUIV_List_Exchange_Top
:
1927 case MUIV_List_Exchange_Active
:
1928 pos2
= data
->entries_active
;
1930 case MUIV_List_Exchange_Bottom
:
1931 pos2
= data
->entries_num
- 1;
1933 case MUIV_List_Exchange_Next
:
1936 case MUIV_List_Exchange_Previous
:
1943 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0
1944 && pos2
< data
->entries_num
&& pos1
!= pos2
)
1946 struct ListEntry
*save
= data
->entries
[pos1
];
1947 data
->entries
[pos1
] = data
->entries
[pos2
];
1948 data
->entries
[pos2
] = save
;
1951 data
->update_pos
= pos1
;
1952 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1955 data
->update_pos
= pos2
;
1956 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1966 /**************************************************************************
1968 **************************************************************************/
1969 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
,
1970 struct MUIP_List_Redraw
*msg
)
1972 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1974 if (!(data
->flags
& LIST_QUIET
))
1976 if (msg
->pos
== MUIV_List_Redraw_All
)
1979 CalcWidths(cl
, obj
);
1980 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
1985 if (msg
->pos
== MUIV_List_Redraw_Active
)
1986 pos
= data
->entries_active
;
1987 else if (msg
->pos
== MUIV_List_Redraw_Entry
)
1990 for (i
= 0; i
< data
->entries_num
; i
++)
1991 if (data
->entries
[i
]->data
== msg
->entry
)
2002 if (CalcDimsOfEntry(cl
, obj
, pos
))
2007 data
->update_pos
= pos
;
2009 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2016 /**************************************************************************
2018 **************************************************************************/
2019 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
,
2020 struct MUIP_List_Remove
*msg
)
2022 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2025 struct ListEntry
*lentry
;
2026 //int rem_count = 1;
2028 if (!data
->entries_num
)
2033 case MUIV_List_Remove_First
:
2037 case MUIV_List_Remove_Active
:
2038 pos
= data
->entries_active
;
2041 case MUIV_List_Remove_Last
:
2042 pos
= data
->entries_num
- 1;
2045 case MUIV_List_Remove_Selected
:
2046 /* TODO: needs special handling */
2047 pos
= data
->entries_active
;
2055 if (pos
< 0 || pos
>= data
->entries_num
)
2058 new_act
= data
->entries_active
;
2060 if (pos
== new_act
&& new_act
== data
->entries_num
- 1)
2061 new_act
--; /* might become MUIV_List_Active_Off */
2063 lentry
= data
->entries
[pos
];
2064 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
) lentry
->data
,
2069 RemoveListEntries(data
, pos
, cur
- pos
);
2070 data
->confirm_entries_num
-= cur
- pos
;
2072 /* ensure that the active element is in a valid range */
2073 if (new_act
>= data
->entries_num
)
2074 new_act
= data
->entries_num
- 1;
2076 SetAttrs(obj
, MUIA_List_Entries
, data
->confirm_entries_num
,
2077 (new_act
>= pos
) || (new_act
!= data
->entries_active
) ?
2078 MUIA_List_Active
: TAG_DONE
,
2079 new_act
, /* Inform only if neccessary (for notify) */
2083 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2088 /**************************************************************************
2090 **************************************************************************/
2091 IPTR
List__MUIM_Select(struct IClass
*cl
, Object
*obj
,
2092 struct MUIP_List_Select
*msg
)
2094 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2095 LONG pos
, i
, count
, selcount
=0, state
=0;
2096 BOOL multi_allowed
= TRUE
, new_select_state
= FALSE
;
2098 /* Establish the range of entries affected */
2101 case MUIV_List_Select_Active
:
2102 pos
= data
->entries_active
;
2103 if (pos
== MUIV_List_Active_Off
)
2109 case MUIV_List_Select_All
:
2111 count
= data
->entries_num
;
2117 if (pos
< 0 || pos
>= data
->entries_num
)
2122 if (msg
->seltype
!= MUIV_List_Select_Ask
&& data
->multi_test_hook
!= NULL
)
2124 /* Disallow selection of an additional entry if there is a currently
2125 selected entry that is not multi-selectable (in such case there
2126 will only be one entry currently selected, so no need to iterate) */
2127 i
= MUIV_List_NextSelected_Start
;
2128 DoMethod(obj
, MUIM_List_NextSelected
, (IPTR
) &i
);
2129 if (i
!= MUIV_List_NextSelected_End
)
2131 if (data
->multi_test_hook
!= NULL
&& selcount
!= 0)
2132 multi_allowed
= CallHookPkt(data
->multi_test_hook
, NULL
,
2133 data
->entries
[i
]->data
);
2136 /* Change or check state of each entry in the range */
2137 for (i
= pos
; i
< pos
+ count
; i
++)
2139 state
= data
->entries
[i
]->flags
& ENTRY_SELECTED
;
2140 switch (msg
->seltype
)
2142 case MUIV_List_Select_Off
:
2143 new_select_state
= FALSE
;
2146 case MUIV_List_Select_On
:
2147 new_select_state
= TRUE
;
2150 case MUIV_List_Select_Toggle
:
2151 new_select_state
= !state
;
2155 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2160 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2162 /* Disallow selection if entry is not multi-selectable and
2163 * there are already selected entries */
2164 if (data
->multi_test_hook
!= NULL
&& new_select_state
)
2165 new_select_state
= multi_allowed
&& (selcount
== 0 ||
2166 CallHookPkt(data
->multi_test_hook
, NULL
,
2167 data
->entries
[i
]->data
));
2169 if (new_select_state
)
2170 data
->entries
[i
]->flags
|= ENTRY_SELECTED
;
2172 data
->entries
[i
]->flags
&= ~ENTRY_SELECTED
;
2176 /* Report old state or number of selected entries */
2179 if (msg
->pos
== MUIV_List_Select_All
2180 && msg
->seltype
== MUIV_List_Select_Ask
)
2181 *msg
->info
= selcount
;
2186 /* Redraw unless it was just an enquiry */
2187 if (msg
->seltype
!= MUIV_List_Select_Ask
)
2194 data
->update_pos
= pos
;
2196 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2202 /**************************************************************************
2204 **************************************************************************/
2206 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
,
2207 struct MUIP_List_Insert
*msg
)
2209 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2210 LONG pos
, count
, sort
;
2217 /* Count the number of entries */
2218 for (count
= 0; msg
->entries
[count
] != NULL
; count
++)
2227 case MUIV_List_Insert_Top
:
2231 case MUIV_List_Insert_Active
:
2232 if (data
->entries_active
!= -1)
2233 pos
= data
->entries_active
;
2238 case MUIV_List_Insert_Sorted
:
2239 pos
= data
->entries_num
;
2240 sort
= 1; /* we sort'em later */
2243 case MUIV_List_Insert_Bottom
:
2244 pos
= data
->entries_num
;
2248 if (msg
->pos
> data
->entries_num
)
2249 pos
= data
->entries_num
;
2250 else if (msg
->pos
< 0)
2257 if (!(SetListSize(data
, data
->entries_num
+ count
)))
2260 LONG until
= pos
+ count
;
2261 APTR
*toinsert
= msg
->entries
;
2263 if (!(PrepareInsertListEntries(data
, pos
, count
)))
2268 struct ListEntry
*lentry
;
2270 if (!(lentry
= AllocListEntry(data
)))
2272 /* Panic, but we must be in a consistent state, so remove
2273 * the space where the following list entries should have gone
2275 RemoveListEntries(data
, pos
, until
- pos
);
2279 /* now call the construct method which returns us a pointer which
2281 lentry
->data
= (APTR
) DoMethod(obj
, MUIM_List_Construct
,
2282 (IPTR
) * toinsert
, (IPTR
) data
->pool
);
2285 FreeListEntry(data
, lentry
);
2286 RemoveListEntries(data
, pos
, until
- pos
);
2288 /* TODO: Also check for visible stuff like below */
2289 if (data
->entries_num
!= data
->confirm_entries_num
)
2290 set(obj
, MUIA_List_Entries
, data
->confirm_entries_num
);
2294 data
->entries
[pos
] = lentry
;
2295 data
->confirm_entries_num
++;
2297 if (_flags(obj
) & MADF_SETUP
)
2299 /* We have to calculate the width and height of the newly
2300 * inserted entry. This has to be done after inserting the
2301 * element into the list */
2302 CalcDimsOfEntry(cl
, obj
, pos
);
2309 /* Recalculate the number of visible entries */
2310 if (_flags(obj
) & MADF_SETUP
)
2311 CalcVertVisible(cl
, obj
);
2313 if (data
->entries_num
!= data
->confirm_entries_num
)
2316 MUIA_List_Entries
, data
->confirm_entries_num
,
2317 MUIA_List_Visible
, data
->entries_visible
, TAG_DONE
);
2320 /* If the array is already sorted, we could do a simple insert
2321 * sort and would be much faster than with qsort.
2322 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
2323 * sort the whole array?
2325 * I think, we better sort the whole array:
2329 DoMethod(obj
, MUIM_List_Sort
);
2330 /* TODO: which pos to return here !? */
2331 /* MUIM_List_Sort already called MUI_Redraw */
2336 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2338 data
->insert_position
= pos
;
2343 /**************************************************************************
2344 MUIM_List_InsertSingle
2345 **************************************************************************/
2346 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
,
2347 struct MUIP_List_InsertSingle
*msg
)
2349 return DoMethod(obj
, MUIM_List_Insert
, (IPTR
) & msg
->entry
, 1,
2353 /**************************************************************************
2355 **************************************************************************/
2356 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
,
2357 struct MUIP_List_GetEntry
*msg
)
2359 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2362 if (pos
== MUIV_List_GetEntry_Active
)
2363 pos
= data
->entries_active
;
2365 if (pos
< 0 || pos
>= data
->entries_num
)
2370 *msg
->entry
= data
->entries
[pos
]->data
;
2371 return (IPTR
) *msg
->entry
;
2374 /**************************************************************************
2376 **************************************************************************/
2377 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
,
2378 struct MUIP_List_Construct
*msg
)
2380 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2382 if (NULL
== data
->construct_hook
)
2383 return (IPTR
) msg
->entry
;
2384 if ((IPTR
) data
->construct_hook
== MUIV_List_ConstructHook_String
)
2386 int len
= msg
->entry
? strlen((STRPTR
) msg
->entry
) : 0;
2387 ULONG
*mem
= AllocPooled(msg
->pool
, len
+ 5);
2392 if (msg
->entry
!= NULL
)
2393 strcpy((STRPTR
) (mem
+ 1), (STRPTR
) msg
->entry
);
2395 *(STRPTR
) (mem
+ 1) = 0;
2396 return (IPTR
) (mem
+ 1);
2398 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
2401 /**************************************************************************
2403 **************************************************************************/
2404 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
,
2405 struct MUIP_List_Destruct
*msg
)
2407 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2409 if (NULL
== data
->destruct_hook
)
2412 if ((IPTR
) data
->destruct_hook
== MUIV_List_DestructHook_String
)
2414 ULONG
*mem
= ((ULONG
*) msg
->entry
) - 1;
2415 FreePooled(msg
->pool
, mem
, mem
[0]);
2419 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
2424 /****** List.mui/MUIM_List_Compare *******************************************
2427 * MUIM_List_Compare (V20)
2430 * DoMethod(obj, MUIM_List_Compare, APTR entry1, APTR entry2,
2431 * LONG sort_type1, LONG sort_type2);
2434 * Compare two list entries according to the current comparison hook
2435 * (MUIA_List_CompareHook).
2438 * entry1 - the first entry data.
2439 * entry2 - the second entry data.
2440 * sort_type1 - undocumented.
2441 * sort_type2 - undocumented.
2444 * MUIA_List_CompareHook, MUIM_List_Sort.
2446 ******************************************************************************
2450 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
,
2451 struct MUIP_List_Compare
*msg
)
2453 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2455 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
2458 /**************************************************************************
2460 **************************************************************************/
2461 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
,
2462 struct MUIP_List_Display
*msg
)
2464 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2466 if (NULL
== data
->display_hook
)
2469 *msg
->array
= msg
->entry
;
2475 *((ULONG
*) (msg
->array
- 1)) = msg
->entry_pos
;
2476 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
2479 /**************************************************************************
2480 MUIM_List_SelectChange
2481 **************************************************************************/
2482 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
,
2483 struct MUIP_List_SelectChange
*msg
)
2488 /**************************************************************************
2489 MUIM_List_CreateImage
2490 Called by a List subclass in its Setup method.
2491 Connects an Area subclass object to the list, much like an object gets
2492 connected to a window. List calls Setup and AskMinMax on that object,
2493 keeps a reference to it (that reference will be returned).
2494 Text engine will dereference that pointer and draw the object with its
2496 **************************************************************************/
2497 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
,
2498 struct MUIP_List_CreateImage
*msg
)
2500 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2501 struct ListImage
*li
;
2506 /* List must be already setup in Setup of your subclass */
2507 if (!(_flags(obj
) & MADF_SETUP
))
2509 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2514 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2515 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
) obj
);
2516 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2522 /**************************************************************************
2523 MUIM_List_DeleteImage
2524 **************************************************************************/
2525 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
,
2526 struct MUIP_List_DeleteImage
*msg
)
2528 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2529 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2533 DoMethod(li
->obj
, MUIM_Cleanup
);
2534 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2535 Remove((struct Node
*)li
);
2536 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2542 /****** List.mui/MUIM_List_Jump **********************************************
2545 * MUIM_List_Jump (V4)
2548 * DoMethod(obj, MUIM_List_Jump, LONG pos);
2551 * Scrolls the list so that a particular entry is visible.
2554 * pos - index of entry that should become visible, or one of these
2556 * MUIV_List_Jump_Active: show the active entry.
2557 * MUIV_List_Jump_Top: show the first entry.
2558 * MUIV_List_Jump_Bottom: show the last entry.
2559 * MUIV_List_Jump_Up: show the previous hidden entry.
2560 * MUIV_List_Jump_Down: show the next hidden entry.
2562 ******************************************************************************
2566 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
,
2567 struct MUIP_List_Jump
*msg
)
2569 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2570 LONG pos
= msg
->pos
;
2574 case MUIV_List_Jump_Top
:
2578 case MUIV_List_Jump_Active
:
2579 pos
= data
->entries_active
;
2582 case MUIV_List_Jump_Bottom
:
2583 pos
= data
->entries_num
- 1;
2586 case MUIV_List_Jump_Down
:
2587 pos
= data
->entries_first
+ data
->entries_visible
;
2590 case MUIV_List_Jump_Up
:
2591 pos
= data
->entries_first
- 1;
2595 if (pos
>= data
->entries_num
)
2597 pos
= data
->entries_num
- 1;
2602 if (pos
< data
->entries_first
)
2604 set(obj
, MUIA_List_First
, pos
);
2606 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2608 pos
-= (data
->entries_visible
- 1);
2611 if (pos
!= data
->entries_first
)
2613 set(obj
, MUIA_List_First
, pos
);
2620 /****** List.mui/MUIM_List_Sort **********************************************
2623 * MUIM_List_Sort (V4)
2626 * DoMethod(obj, MUIM_List_Sort);
2629 * Sort the list's entries according to the current comparison hook
2630 * (MUIA_List_CompareHook).
2633 * MUIA_List_CompareHook, MUIM_List_Compare.
2635 ******************************************************************************
2639 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
,
2640 struct MUIP_List_Sort
*msg
)
2642 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2645 struct MUIP_List_Compare cmpmsg
=
2646 { MUIM_List_Compare
, NULL
, NULL
, 0, 0 };
2648 if (data
->entries_num
> 1)
2651 Simple sort algorithm. Feel free to improve it.
2653 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2656 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2658 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2659 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2660 if ((LONG
) DoMethodA(obj
, (Msg
) & cmpmsg
) > 0)
2667 APTR tmp
= data
->entries
[i
];
2668 data
->entries
[i
] = data
->entries
[max
];
2669 data
->entries
[max
] = tmp
;
2675 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2680 /****** List.mui/MUIM_List_Move **********************************************
2683 * MUIM_List_Move (V9)
2686 * DoMethod(obj, MUIM_List_Move, LONG from, LONG to);
2689 * Move a list entry to a new position.
2692 * from - the current index of the entry that should be moved, or one of
2693 * these special values:
2694 * MUIV_List_Move_Active: the active entry.
2695 * MUIV_List_Move_Top: the first entry.
2696 * MUIV_List_Move_Bottom: the last entry.
2697 * to - the index of the entry's new position, or one of
2698 * these special values:
2699 * MUIV_List_Move_Active: the active entry.
2700 * MUIV_List_Move_Top: the first entry.
2701 * MUIV_List_Move_Bottom: the last entry.
2703 ******************************************************************************
2707 IPTR
List__MUIM_Move(struct IClass
*cl
, Object
*obj
,
2708 struct MUIP_List_Move
*msg
)
2710 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2715 /* Normalise special 'from' values */
2718 case MUIV_List_Move_Top
:
2721 case MUIV_List_Move_Active
:
2722 from
= data
->entries_active
;
2724 case MUIV_List_Move_Bottom
:
2725 from
= data
->entries_num
- 1;
2731 /* Normalise special 'to' values */
2734 case MUIV_List_Move_Top
:
2737 case MUIV_List_Move_Active
:
2738 to
= data
->entries_active
;
2740 case MUIV_List_Move_Bottom
:
2741 to
= data
->entries_num
- 1;
2743 case MUIV_List_Move_Next
:
2746 case MUIV_List_Move_Previous
:
2753 /* Check that values are within valid bounds */
2754 if (from
> data
->entries_num
- 1 || from
< 0
2755 || to
> data
->entries_num
- 1 || to
< 0 || from
== to
)
2756 return (IPTR
) FALSE
;
2758 /* Shift all entries in the range between the 'from' and 'to' positions */
2761 struct ListEntry
*backup
= data
->entries
[from
];
2762 for (i
= from
; i
< to
; i
++)
2763 data
->entries
[i
] = data
->entries
[i
+ 1];
2764 data
->entries
[to
] = backup
;
2768 struct ListEntry
*backup
= data
->entries
[from
];
2769 for (i
= from
; i
> to
; i
--)
2770 data
->entries
[i
] = data
->entries
[i
- 1];
2771 data
->entries
[to
] = backup
;
2774 /* Update index of active entry */
2775 if (from
== data
->entries_active
)
2776 data
->entries_active
= to
;
2777 else if (data
->entries_active
> from
&& data
->entries_active
< to
)
2778 data
->entries_active
--;
2779 else if (data
->entries_active
< from
&& data
->entries_active
>= to
)
2780 data
->entries_active
++;
2782 /* Reflect list changes visually */
2784 MUI_Redraw(obj
, MADF_DRAWUPDATE
);
2789 /**************************************************************************
2790 MUIM_List_NextSelected
2791 **************************************************************************/
2792 IPTR
List__MUIM_NextSelected(struct IClass
*cl
, Object
*obj
,
2793 struct MUIP_List_NextSelected
*msg
)
2795 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2799 /* Get the first entry to check */
2801 if (pos
== MUIV_List_NextSelected_Start
)
2806 /* Find the next selected entry */
2807 for (i
= pos
; i
< data
->entries_num
&& !found
; i
++)
2809 if (data
->entries
[i
]->flags
& ENTRY_SELECTED
)
2816 /* Return index of selected entry, or indicate there are no more */
2818 pos
= MUIV_List_NextSelected_End
;
2824 /**************************************************************************
2826 **************************************************************************/
2827 IPTR
List__MUIM_TestPos(struct IClass
*cl
, Object
*obj
,
2828 struct MUIP_List_TestPos
*msg
)
2830 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2831 struct MUI_List_TestPos_Result
*result
= msg
->res
;
2832 LONG col
= -1, row
= -1;
2834 LONG mx
= msg
->x
- _left(data
->area
);
2835 LONG entries_visible
;
2837 if (data
->entries_visible
<= data
->entries_num
)
2838 entries_visible
= data
->entries_visible
;
2840 entries_visible
= data
->entries_num
;
2841 LONG ey
= msg
->y
- data
->entries_top_pixel
;
2842 /* y coordinates transformed to the entries */
2844 /* Now check if it was clicked on a title or on entries */
2846 flags
|= MUI_LPR_ABOVE
;
2847 else if (ey
>= entries_visible
* data
->entry_maxheight
)
2848 flags
|= MUI_LPR_BELOW
;
2852 row
= ey
/ data
->entry_maxheight
+ data
->entries_first
;
2854 ey
% data
->entry_maxheight
- data
->entry_maxheight
/ 2;
2858 flags
|= MUI_LPR_LEFT
;
2859 else if (mx
>= _width(data
->area
))
2860 flags
|= MUI_LPR_RIGHT
;
2863 /* Identify column */
2864 if (data
->entries_num
> 0 && data
->columns
> 0)
2867 col
= data
->columns
- 1;
2868 for (i
= 0; i
< data
->columns
; i
++)
2870 result
->xoffset
= mx
- width_sum
;
2872 data
->ci
[i
].entries_width
+
2874 (data
->ci
[i
].bar
? BAR_WIDTH
: 0);
2875 D(bug("[List/MUIM_TestPos] i %d "
2876 "width %d width_sum %d mx %d\n",
2877 i
, data
->ci
[i
].entries_width
, width_sum
, mx
));
2881 D(bug("[List/MUIM_TestPos] Column hit %d\n", col
));
2888 result
->entry
= row
;
2889 result
->column
= col
;
2890 result
->flags
= flags
;
2895 /****i* List.mui/MUIM_DragQuery **********************************************
2900 ******************************************************************************
2904 IPTR
List__MUIM_DragQuery(struct IClass
*cl
, Object
*obj
,
2905 struct MUIP_DragQuery
*msg
)
2907 if (msg
->obj
== obj
)
2908 return MUIV_DragQuery_Accept
;
2910 return MUIV_DragQuery_Refuse
;
2914 /****i* List.mui/MUIM_DragFinish *********************************************
2919 ******************************************************************************
2923 IPTR
List__MUIM_DragFinish(struct IClass
*cl
, Object
*obj
,
2924 struct MUIP_DragFinish
*msg
)
2926 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2928 data
->drop_mark_y
= -1;
2930 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
2933 /****i* List.mui/MUIM_DragReport *********************************************
2938 ******************************************************************************
2942 IPTR
List__MUIM_DragReport(struct IClass
*cl
, Object
*obj
,
2943 struct MUIP_DragReport
*msg
)
2945 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2946 struct MUI_List_TestPos_Result pos
;
2947 struct RastPort
*rp
= _rp(obj
);
2951 /* Choose new drop mark position */
2953 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
2954 if (pos
.entry
!= -1)
2957 if (pos
.yoffset
> 0)
2960 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
2961 n
= data
->entries_first
;
2964 n
= MIN(data
->entries_visible
, data
->entries_num
)
2965 - data
->entries_first
;
2968 /* Clear old drop mark */
2970 if ((data
->flags
& LIST_SHOWDROPMARKS
) != 0)
2972 y
= data
->entries_top_pixel
+ (n
- data
->entries_first
)
2973 * data
->entry_maxheight
;
2974 if (y
!= data
->drop_mark_y
)
2976 DoMethod(obj
, MUIM_DrawBackground
, _mleft(data
->area
), data
->drop_mark_y
,
2977 _mwidth(data
->area
), 1, 0, 0, 0);
2979 /* Draw new drop mark and store its position */
2981 SetABPenDrMd(rp
, _pens(obj
)[MPEN_SHINE
], _pens(obj
)[MPEN_SHADOW
],
2983 old_pattern
= rp
->LinePtrn
;
2984 SetDrPt(rp
, 0xF0F0);
2985 Move(rp
, _mleft(data
->area
), y
);
2986 Draw(rp
, _mright(data
->area
), y
);
2987 SetDrPt(rp
, old_pattern
);
2988 data
->drop_mark_y
= y
;
2996 /****i* List.mui/MUIM_DragDrop ***********************************************
3001 ******************************************************************************
3005 IPTR
List__MUIM_DragDrop(struct IClass
*cl
, Object
*obj
,
3006 struct MUIP_DragDrop
*msg
)
3008 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3009 struct MUI_List_TestPos_Result pos
;
3012 /* Find drop position */
3014 DoMethod(obj
, MUIM_List_TestPos
, msg
->x
, msg
->y
, (IPTR
) &pos
);
3015 if (pos
.entry
!= -1)
3017 /* Change drop position when coords move past centre of entry, not
3021 if (pos
.yoffset
> 0)
3024 /* Ensure that dropped entry will be positioned between the two
3025 * entries that are above and below the drop mark, rather than
3026 * strictly at the numeric index shown */
3028 if (n
> data
->entries_active
)
3031 else if ((pos
.flags
& MUI_LPR_ABOVE
) != 0)
3032 n
= MUIV_List_Move_Top
;
3034 n
= MUIV_List_Move_Bottom
;
3036 DoMethod(msg
->obj
, MUIM_List_Move
, MUIV_List_Move_Active
, n
);
3042 /****i* List.mui/MUIM_CreateDragImage ****************************************
3045 * MUIM_CreateDragImage
3047 ******************************************************************************
3051 static IPTR
List__MUIM_CreateDragImage(struct IClass
*cl
, Object
*obj
,
3052 struct MUIP_CreateDragImage
*msg
)
3054 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3055 BOOL success
= TRUE
;
3056 struct MUI_List_TestPos_Result pos
;
3057 WORD width
, height
, left
, top
;
3058 struct MUI_DragImage
*img
= NULL
;
3059 const struct ZuneFrameGfx
*zframe
;
3062 /* Get info on dragged entry */
3063 DoMethod(obj
, MUIM_List_TestPos
, _left(data
->area
) - msg
->touchx
,
3064 _top(data
->area
) - msg
->touchy
, (IPTR
) &pos
);
3065 if (pos
.entry
== -1)
3070 /* Get boundaries of entry */
3071 width
= _mwidth(data
->area
);
3072 height
= data
->entry_maxheight
;
3073 left
= _mleft(data
->area
);
3074 top
= _top(data
->area
) - msg
->touchy
3075 - (pos
.yoffset
+ data
->entry_maxheight
/ 2);
3077 /* Allocate drag image structure */
3078 img
= (struct MUI_DragImage
*)
3079 AllocVec(sizeof(struct MUI_DragImage
), MEMF_CLEAR
);
3086 /* Get drag frame */
3087 zframe
= zune_zframe_get(obj
,
3088 &muiGlobalInfo(obj
)->mgi_Prefs
->frames
[MUIV_Frame_Drag
]);
3090 /* Allocate drag image buffer */
3091 img
->width
= width
+ zframe
->ileft
+ zframe
->iright
;
3092 img
->height
= height
+ zframe
->itop
+ zframe
->ibottom
;
3093 depth
= GetBitMapAttr(_screen(obj
)->RastPort
.BitMap
, BMA_DEPTH
);
3094 img
->bm
= AllocBitMap(img
->width
, img
->height
, depth
, BMF_MINPLANES
,
3095 _screen(obj
)->RastPort
.BitMap
);
3097 if (img
->bm
!= NULL
)
3100 struct RastPort temprp
;
3101 InitRastPort(&temprp
);
3102 temprp
.BitMap
= img
->bm
;
3103 ClipBlit(_rp(obj
), left
, top
, &temprp
,
3104 zframe
->ileft
, zframe
->itop
, width
, height
,
3108 struct RastPort
*rp_save
= muiRenderInfo(obj
)->mri_RastPort
;
3109 muiRenderInfo(obj
)->mri_RastPort
= &temprp
;
3110 zframe
->draw(zframe
->customframe
, muiRenderInfo(obj
), 0, 0,
3111 img
->width
, img
->height
, 0, 0, img
->width
, img
->height
);
3112 muiRenderInfo(obj
)->mri_RastPort
= rp_save
;
3115 /* Ensure drag point matches where user clicked */
3116 img
->touchx
= msg
->touchx
- zframe
->ileft
+ _addleft(obj
);
3117 img
->touchy
= -(pos
.yoffset
+ data
->entry_maxheight
/ 2)
3125 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
)
3127 LONG
new, first
, entries
, visible
;
3129 new = first
= XGET(obj
, MUIA_List_First
);
3130 entries
= XGET(obj
, MUIA_List_Entries
);
3131 visible
= XGET(obj
, MUIA_List_Visible
);
3135 if (new > entries
- visible
)
3137 new = entries
- visible
;
3147 set(obj
, MUIA_List_First
, new);
3151 /**************************************************************************
3153 **************************************************************************/
3154 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
, struct MUIP_HandleEvent
*msg
)
3156 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
3157 struct MUI_List_TestPos_Result pos
;
3158 LONG seltype
, old_active
, new_active
, visible
, first
, last
, i
;
3160 BOOL select
= FALSE
, clear
= FALSE
, range_select
= FALSE
, changing
;
3162 typeof(msg
->muikey
) muikey
= msg
->muikey
;
3164 new_active
= old_active
= XGET(obj
, MUIA_List_Active
);
3165 visible
= XGET(obj
, MUIA_List_Visible
);
3167 if (muikey
!= MUIKEY_NONE
)
3169 result
= MUI_EventHandlerRC_Eat
;
3171 /* Make keys behave differently in read-only mode */
3172 if (data
->read_only
)
3177 muikey
= MUIKEY_LINESTART
;
3181 muikey
= MUIKEY_LINEEND
;
3185 muikey
= MUIKEY_LEFT
;
3190 muikey
= MUIKEY_RIGHT
;
3198 if (data
->multiselect
!= MUIV_Listview_MultiSelect_None
3199 && !data
->read_only
)
3202 data
->click_column
= data
->def_click_column
;
3203 new_active
= MUIV_List_Active_Down
;
3207 DoMethod(obj
, MUIM_List_Jump
, 0);
3208 muikey
= MUIKEY_NONE
;
3213 new_active
= MUIV_List_Active_Top
;
3217 new_active
= MUIV_List_Active_Bottom
;
3221 case MUIKEY_WORDLEFT
:
3222 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Up
);
3226 case MUIKEY_WORDRIGHT
:
3227 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Down
);
3230 case MUIKEY_LINESTART
:
3231 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Top
);
3234 case MUIKEY_LINEEND
:
3235 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Bottom
);
3239 new_active
= MUIV_List_Active_Up
;
3243 new_active
= MUIV_List_Active_Down
;
3247 if (data
->read_only
)
3248 DoWheelMove(cl
, obj
, -visible
);
3250 new_active
= MUIV_List_Active_PageUp
;
3253 case MUIKEY_PAGEDOWN
:
3254 if (data
->read_only
)
3255 DoWheelMove(cl
, obj
, visible
);
3257 new_active
= MUIV_List_Active_PageDown
;
3266 DoMethod(obj
, MUIM_List_TestPos
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
, (IPTR
) &pos
);
3268 switch (msg
->imsg
->Class
)
3270 case IDCMP_MOUSEBUTTONS
:
3271 if (msg
->imsg
->Code
== SELECTDOWN
)
3273 if (_isinobject(data
->area
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
3275 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
3277 if (!data
->read_only
&& pos
.entry
!= -1)
3279 new_active
= pos
.entry
;
3281 clear
= (data
->multiselect
== MUIV_Listview_MultiSelect_Shifted
3282 && (msg
->imsg
->Qualifier
& (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
)) == 0);
3283 seltype
= clear
? MUIV_List_Select_On
: MUIV_List_Select_Toggle
;
3284 select
= data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3286 /* Handle MUIA_Listview_ClickColumn */
3287 data
->click_column
= pos
.column
;
3288 superset(cl
, obj
, MUIA_Listview_ClickColumn
,
3289 data
->click_column
);
3291 /* Handle double clicking */
3292 if (data
->last_active
== pos
.entry
3293 && DoubleClick(data
->last_secs
, data
->last_mics
, msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
3295 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
3296 data
->last_active
= -1;
3297 data
->last_secs
= data
->last_mics
= 0;
3301 data
->last_active
= pos
.entry
;
3302 data
->last_secs
= msg
->imsg
->Seconds
;
3303 data
->last_mics
= msg
->imsg
->Micros
;
3306 /* Look out for mouse movement, timer and
3307 inactive-window events while mouse button is
3309 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
3310 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
|IDCMP_INACTIVEWINDOW
);
3311 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
3317 /* Activate object */
3318 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
3320 set(_win(obj
), MUIA_Window_ActiveObject
, (IPTR
)obj
);
3321 data
->mouse_click
= 0;
3324 /* Restore normal event mask */
3325 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
3326 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3327 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
3331 case IDCMP_MOUSEMOVE
:
3332 case IDCMP_INTUITICKS
:
3333 if (pos
.flags
& MUI_LPR_ABOVE
)
3334 new_active
= MUIV_List_Active_Up
;
3335 else if (pos
.flags
& MUI_LPR_BELOW
)
3336 new_active
= MUIV_List_Active_Down
;
3338 new_active
= pos
.entry
;
3340 select
= new_active
!= old_active
&& data
->multiselect
!= MUIV_Listview_MultiSelect_None
;
3343 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
, MUIV_List_Select_Ask
, &seltype
);
3344 range_select
= new_active
>= 0;
3349 case IDCMP_INACTIVEWINDOW
:
3350 /* Stop listening for events we only listen to when mouse button is
3351 down: we will not be informed of the button being released */
3352 DoMethod(_win(obj
), MUIM_Window_RemEventHandler
, (IPTR
) &data
->ehn
);
3353 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
| IDCMP_INACTIVEWINDOW
);
3354 DoMethod(_win(obj
), MUIM_Window_AddEventHandler
, (IPTR
) &data
->ehn
);
3359 if (data
->vert
&& _isinobject(data
->vert
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
3361 else if (_isinobject(data
->area
, msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
3368 switch (msg
->imsg
->Code
)
3370 case RAWKEY_NM_WHEEL_UP
:
3371 DoWheelMove(cl
, obj
, -delta
);
3374 case RAWKEY_NM_WHEEL_DOWN
:
3375 DoWheelMove(cl
, obj
, delta
);
3378 result
= MUI_EventHandlerRC_Eat
;
3384 /* Decide in advance if any selections may change */
3385 changing
= clear
|| muikey
== MUIKEY_TOGGLE
|| select
;
3387 /* Change selected and active entries */
3389 set(obj
, MUIA_Listview_SelectChange
, TRUE
);
3393 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_All
, MUIV_List_Select_Off
, NULL
);
3396 if (muikey
== MUIKEY_TOGGLE
)
3398 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
, MUIV_List_Select_Toggle
, NULL
);
3402 if (new_active
!= old_active
)
3403 set(obj
, MUIA_List_Active
, new_active
);
3409 if (old_active
< new_active
)
3410 first
= old_active
+ 1, last
= new_active
;
3412 first
= new_active
, last
= old_active
- 1;
3413 for (i
= first
; i
<= last
; i
++)
3414 DoMethod(obj
, MUIM_List_Select
, i
, seltype
, NULL
);
3417 DoMethod(obj
, MUIM_List_Select
, MUIV_List_Select_Active
, seltype
, NULL
);
3421 set(obj
, MUIA_Listview_SelectChange
, FALSE
);
3426 /**************************************************************************
3428 **************************************************************************/
3429 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
3431 switch (msg
->MethodID
)
3434 return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
3436 return List__OM_DISPOSE(cl
, obj
, msg
);
3438 return List__OM_SET(cl
, obj
, (struct opSet
*)msg
);
3440 return List__OM_GET(cl
, obj
, (struct opGet
*)msg
);
3443 return List__MUIM_Setup(cl
, obj
, (struct MUIP_Setup
*)msg
);
3445 return List__MUIM_Cleanup(cl
, obj
, (struct MUIP_Cleanup
*)msg
);
3446 case MUIM_HandleEvent
:
3447 return List__MUIM_HandleEvent(cl
, obj
, (struct MUIP_HandleEvent
*)msg
);
3448 case MUIM_AskMinMax
:
3449 return List__MUIM_AskMinMax(cl
, obj
, (struct MUIP_AskMinMax
*)msg
);
3451 return List__MUIM_Show(cl
, obj
, (struct MUIP_Show
*)msg
);
3453 return List__MUIM_Hide(cl
, obj
, (struct MUIP_Hide
*)msg
);
3455 return List__MUIM_Draw(cl
, obj
, (struct MUIP_Draw
*)msg
);
3457 return List__MUIM_Layout(cl
, obj
, (struct MUIP_Layout
*)msg
);
3458 case MUIM_List_Clear
:
3459 return List__MUIM_Clear(cl
, obj
, (struct MUIP_List_Clear
*)msg
);
3460 case MUIM_List_Sort
:
3461 return List__MUIM_Sort(cl
, obj
, (struct MUIP_List_Sort
*)msg
);
3462 case MUIM_List_Exchange
:
3463 return List__MUIM_Exchange(cl
, obj
,
3464 (struct MUIP_List_Exchange
*)msg
);
3465 case MUIM_List_Insert
:
3466 return List__MUIM_Insert(cl
, obj
, (APTR
) msg
);
3467 case MUIM_List_InsertSingle
:
3468 return List__MUIM_InsertSingle(cl
, obj
, (APTR
) msg
);
3469 case MUIM_List_GetEntry
:
3470 return List__MUIM_GetEntry(cl
, obj
, (APTR
) msg
);
3471 case MUIM_List_Redraw
:
3472 return List__MUIM_Redraw(cl
, obj
, (APTR
) msg
);
3473 case MUIM_List_Remove
:
3474 return List__MUIM_Remove(cl
, obj
, (APTR
) msg
);
3475 case MUIM_List_Select
:
3476 return List__MUIM_Select(cl
, obj
, (APTR
) msg
);
3477 case MUIM_List_Construct
:
3478 return List__MUIM_Construct(cl
, obj
, (APTR
) msg
);
3479 case MUIM_List_Destruct
:
3480 return List__MUIM_Destruct(cl
, obj
, (APTR
) msg
);
3481 case MUIM_List_Compare
:
3482 return List__MUIM_Compare(cl
, obj
, (APTR
) msg
);
3483 case MUIM_List_Display
:
3484 return List__MUIM_Display(cl
, obj
, (APTR
) msg
);
3485 case MUIM_List_SelectChange
:
3486 return List__MUIM_SelectChange(cl
, obj
, (APTR
) msg
);
3487 case MUIM_List_CreateImage
:
3488 return List__MUIM_CreateImage(cl
, obj
, (APTR
) msg
);
3489 case MUIM_List_DeleteImage
:
3490 return List__MUIM_DeleteImage(cl
, obj
, (APTR
) msg
);
3491 case MUIM_List_Jump
:
3492 return List__MUIM_Jump(cl
, obj
, (APTR
) msg
);
3493 case MUIM_List_Move
:
3494 return List__MUIM_Move(cl
, obj
, (struct MUIP_List_Move
*)msg
);
3495 case MUIM_List_NextSelected
:
3496 return List__MUIM_NextSelected(cl
, obj
,
3497 (struct MUIP_List_NextSelected
*)msg
);
3498 case MUIM_List_TestPos
:
3499 return List__MUIM_TestPos(cl
, obj
, (APTR
) msg
);
3500 case MUIM_DragQuery
:
3501 return List__MUIM_DragQuery(cl
, obj
, (APTR
) msg
);
3502 case MUIM_DragFinish
:
3503 return List__MUIM_DragFinish(cl
, obj
, (APTR
) msg
);
3504 case MUIM_DragReport
:
3505 return List__MUIM_DragReport(cl
, obj
, (APTR
) msg
);
3507 return List__MUIM_DragDrop(cl
, obj
, (APTR
) msg
);
3508 case MUIM_CreateDragImage
:
3509 return List__MUIM_CreateDragImage(cl
, obj
, (APTR
) msg
);
3512 return DoSuperMethodA(cl
, obj
, msg
);
3514 BOOPSI_DISPATCHER_END
3519 const struct __MUIBuiltinClass _MUI_List_desc
=
3523 sizeof(struct MUI_ListData
),
3524 (void *) List_Dispatcher