2 Copyright © 2002-2009, The AROS Development Team. All rights reserved.
9 #include <exec/memory.h>
10 #include <graphics/gfx.h>
11 #include <graphics/view.h>
12 #include <devices/rawkeycodes.h>
13 #include <clib/alib_protos.h>
14 #include <proto/exec.h>
15 #include <proto/graphics.h>
16 #include <proto/utility.h>
17 #include <proto/dos.h>
18 #include <proto/intuition.h>
19 #include <proto/muimaster.h>
21 /* #define MYDEBUG 1 */
24 #include "muimaster_intern.h"
27 #include "textengine.h"
28 #include "listimage.h"
31 extern struct Library
*MUIMasterBase
;
33 #define ENTRY_TITLE (-1)
35 #define FORMAT_TEMPLATE "DELTA=D/N,PREPARSE=P/K,WEIGHT=W/N,MINWIDTH=MIW/N,MAXWIDTH=MAW/N,COL=C/N,BAR/S"
54 LONG
*widths
; /* Widths of the columns */
55 LONG width
; /* Line width */
56 LONG height
; /* Line height */
57 WORD flags
; /* see below */
63 int colno
; /* Column number */
64 int user_width
; /* user setted width -1 if entry width */
65 int min_width
; /* min width percentage */
66 int max_width
; /* min width percentage */
68 int delta
; /* ignored for the first and last column, defaults to 4 */
72 int entries_width
; /* width of the entries (the maximum of the widths of all entries) */
75 struct MUI_ImageSpec_intern
;
82 APTR intern_pool
; /* The internal pool which the class has allocated */
83 LONG intern_puddle_size
;
84 LONG intern_tresh_size
;
85 APTR pool
; /* the pool which is used to allocate list entries */
87 struct Hook
*construct_hook
;
88 struct Hook
*compare_hook
;
89 struct Hook
*destruct_hook
;
90 struct Hook
*display_hook
;
92 struct Hook default_compare_hook
;
94 /* List managment, currently we use a simple flat array, which is not good if many entries are inserted/deleted */
95 LONG entries_num
; /* Number of Entries in the list */
96 LONG entries_allocated
;
97 struct ListEntry
**entries
;
99 LONG entries_first
; /* first visible entry */
100 LONG entries_visible
; /* number of visible entries, determined at MUIM_Layout */
102 LONG insert_position
; /* pos of the last insertion */
104 LONG entry_maxheight
; /* Maximum height of an entry */
105 ULONG entry_minheight
; /* from MUIA_List_MinLineHeight */
107 LONG entries_totalheight
;
108 LONG entries_maxwidth
;
110 LONG vertprop_entries
;
111 LONG vertprop_visible
;
114 LONG confirm_entries_num
; /* These are the correct entries num, used so you cannot set MUIA_List_Entries to wrong values */
116 LONG entries_top_pixel
; /* Where the entries start */
118 /* Column managment, is allocated by ParseListFormat() and freed by CleanListFormat() */
119 LONG columns
; /* Number of columns the list has */
120 struct ColumnInfo
*ci
;
122 STRPTR
*strings
; /* the strings for the display function, one more as needed (for the entry position) */
125 int title_height
; /* The complete height of the title */
126 STRPTR title
; /* On single comlums this is the title, otherwise 1 */
128 struct MUI_EventHandlerNode ehn
;
129 int mouse_click
; /* see below if mouse is hold down */
132 struct MUI_ImageSpec_intern
*list_cursor
;
133 struct MUI_ImageSpec_intern
*list_select
;
134 struct MUI_ImageSpec_intern
*list_selcur
;
136 /* Render optimization */
137 int update
; /* 1 - update everything, 2 - redraw entry at update_pos, 3 - scroll to current entries_first (old value is is update_pos) */
147 ULONG input
; /* FALSE - readonly, otherwise TRUE */
150 struct MinList images
;
153 ListviewMulti prefs_multi
;
154 ListviewRefresh prefs_refresh
;
155 UWORD prefs_linespacing
;
157 UWORD prefs_smoothval
;
160 #define LIST_ADJUSTWIDTH (1<<0)
161 #define LIST_ADJUSTHEIGHT (1<<1)
162 #define LIST_AUTOVISIBLE (1<<2)
163 #define LIST_DRAGSORTABLE (1<<3)
164 #define LIST_SHOWDROPMARKS (1<<4)
165 #define LIST_QUIET (1<<5)
168 #define MOUSE_CLICK_ENTRY 1 /* on entry clicked */
169 #define MOUSE_CLICK_TITLE 2 /* on title clicked */
171 /**************************************************************************
172 Allocate a single list entry, does not initialize it (except the pointer)
173 **************************************************************************/
174 static struct ListEntry
*AllocListEntry(struct MUI_ListData
*data
)
177 struct ListEntry
*le
;
178 int size
= sizeof(struct ListEntry
) + sizeof(LONG
)*data
->columns
+ 4; /* sizeinfo */
180 mem
= AllocPooled(data
->pool
, size
);
181 if (!mem
) return NULL
;
182 D(bug("List AllocListEntry %p, %ld bytes\n", mem
, size
));
184 mem
[0] = size
; /* Save the size */
185 le
= (struct ListEntry
*)(mem
+1);
186 le
->widths
= (LONG
*)(le
+ 1);
190 /**************************************************************************
191 Deallocate a single list entry, does not deinitialize it
192 **************************************************************************/
193 static void FreeListEntry(struct MUI_ListData
*data
, struct ListEntry
*entry
)
195 ULONG
*mem
= ((ULONG
*)entry
)-1;
196 D(bug("FreeListEntry %p size=%ld\n", mem
, mem
[0]));
197 FreePooled(data
->pool
, mem
, mem
[0]);
200 /**************************************************************************
201 Ensures that we there can be at least the given amount of entries within
202 the list. Returns 0 if not. It also allocates the space for the title.
203 It can be accesses with data->entries[ENTRY_TITLE]
204 **************************************************************************/
205 static int SetListSize(struct MUI_ListData
*data
, LONG size
)
207 struct ListEntry
**new_entries
;
208 int new_entries_allocated
;
210 if (size
+ 1 <= data
->entries_allocated
)
213 new_entries_allocated
= data
->entries_allocated
* 2 + 4;
214 if (new_entries_allocated
< size
+ 1)
215 new_entries_allocated
= size
+ 1 + 10; /* 10 is just random */
217 D(bug("List %p : SetListSize allocating %ld bytes\n", data
,
218 new_entries_allocated
* sizeof(struct ListEntry
*)));
219 new_entries
= AllocVec(new_entries_allocated
* sizeof(struct ListEntry
*),0);
220 if (NULL
== new_entries
)
224 CopyMem(data
->entries
- 1, new_entries
,
225 (data
->entries_num
+ 1) * sizeof(struct ListEntry
*));
226 FreeVec(data
->entries
- 1);
228 data
->entries
= new_entries
+ 1;
229 data
->entries_allocated
= new_entries_allocated
;
233 /**************************************************************************
234 Prepares the insertion of count entries at pos.
235 This function doesn't care if there is enough space in the datastructure.
236 SetListSize() must be used first.
237 With current implementation, this call will never fail
238 **************************************************************************/
239 static int PrepareInsertListEntries(struct MUI_ListData
*data
, int pos
, int count
)
241 memmove(&data
->entries
[pos
+count
],&data
->entries
[pos
],(data
->entries_num
- pos
)*sizeof(struct ListEntry
*));
245 /**************************************************************************
246 Inserts a already initialized array of Entries at the given position.
247 This function doesn't care if there is enough space in the datastructure
248 Returns 1 if something failed (never in current implementation)
249 **************************************************************************/
251 static int InsertListEntries(struct MUI_ListData
*data
, int pos
, struct ListEntry
**array
, int count
)
253 memmove(&data
->entries
[pos
+count
],&data
->entries
[pos
],data
->entries_num
- pos
);
254 memcpy(&data
->entries
[pos
],array
,count
);
260 /**************************************************************************
261 Removes count (already deinitalized) list entries starting az pos.
262 **************************************************************************/
263 static void RemoveListEntries(struct MUI_ListData
*data
, int pos
, int count
)
265 #warning segfault if entries_num = pos = count = 1
266 memmove(&data
->entries
[pos
], &data
->entries
[pos
+count
],
267 (data
->entries_num
- (pos
+ count
)) * sizeof(struct ListEntry
*));
270 /**************************************************************************
271 Frees all memory allocated by ParseListFormat()
272 **************************************************************************/
273 static void FreeListFormat(struct MUI_ListData
*data
)
279 for (i
= 0; i
< data
->columns
; i
++)
281 FreeVec(data
->ci
[i
].preparse
);
282 data
->ci
[i
].preparse
= NULL
;
289 FreeVec(data
->preparses
);
290 data
->preparses
= NULL
;
294 FreeVec(data
->strings
-1);
295 data
->strings
= NULL
;
300 /**************************************************************************
301 Parses the given format string (also frees a previouly parsed format).
303 **************************************************************************/
304 static int ParseListFormat(struct MUI_ListData
*data
, STRPTR format
)
312 struct RDArgs
*rdargs
;
314 if (!format
) format
= (STRPTR
) "";
318 FreeListFormat(data
);
322 /* Count the number of columns first */
327 if (!(data
->preparses
= AllocVec((new_columns
+ 10) * sizeof(STRPTR
), 0)))
330 if (!(data
->strings
= AllocVec((new_columns
+ 1 + 10) * sizeof(STRPTR
), 0))) /* hold enough space also for the entry pos, used by orginal MUI and also some security space */
333 if (!(data
->ci
= AllocVec(new_columns
* sizeof(struct ColumnInfo
), 0)))
337 for (i
= 0; i
< new_columns
; i
++)
339 data
->ci
[i
].colno
= -1; // -1 means: use unassigned column
340 data
->ci
[i
].weight
= 100;
341 data
->ci
[i
].delta
= 4;
342 data
->ci
[i
].min_width
= -1;
343 data
->ci
[i
].max_width
= -1;
344 data
->ci
[i
].user_width
= -1;
345 data
->ci
[i
].bar
= FALSE
;
346 data
->ci
[i
].preparse
= NULL
;
349 if ((format_sep
= StrDup(format
)) != 0)
351 for (i
= 0 ; format_sep
[i
] != '\0' ; i
++)
353 if (format_sep
[i
] == ',')
354 format_sep
[i
] = '\0';
357 if ((rdargs
= AllocDosObject(DOS_RDARGS
, NULL
)) != 0)
363 rdargs
->RDA_Source
.CS_Buffer
= ptr
;
364 rdargs
->RDA_Source
.CS_Length
= strlen(ptr
);
365 rdargs
->RDA_Source
.CS_CurChr
= 0;
366 rdargs
->RDA_DAList
= 0;
367 rdargs
->RDA_Buffer
= NULL
;
368 rdargs
->RDA_BufSiz
= 0;
369 rdargs
->RDA_ExtHelp
= NULL
;
370 rdargs
->RDA_Flags
= 0;
372 memset(args
, 0, sizeof args
);
373 if (ReadArgs(FORMAT_TEMPLATE
, args
, rdargs
))
376 data
->ci
[i
].colno
= *(LONG
*)args
[ARG_COL
];
377 if (args
[ARG_WEIGHT
])
378 data
->ci
[i
].weight
= *(LONG
*)args
[ARG_WEIGHT
];
380 data
->ci
[i
].delta
= *(LONG
*)args
[ARG_DELTA
];
381 if (args
[ARG_MINWIDTH
])
382 data
->ci
[i
].min_width
= *(LONG
*)args
[ARG_MINWIDTH
];
383 if (args
[ARG_MAXWIDTH
])
384 data
->ci
[i
].max_width
= *(LONG
*)args
[ARG_MAXWIDTH
];
385 data
->ci
[i
].bar
= args
[ARG_BAR
];
386 if (args
[ARG_PREPARSE
])
387 data
->ci
[i
].preparse
= StrDup((STRPTR
)args
[ARG_PREPARSE
]);
391 ptr
+= strlen(ptr
) + 1;
393 } while(i
< new_columns
);
394 FreeDosObject(DOS_RDARGS
, rdargs
);
399 for (i
= 0; i
< new_columns
; i
++)
401 D(bug("colno %d weight %d delta %d preparse %s\n",
402 data
->ci
[i
].colno
, data
->ci
[i
].weight
, data
->ci
[i
].delta
, data
->ci
[i
].preparse
));
405 data
->columns
= new_columns
;
406 data
->strings
++; /* Skip entry pos */
411 /**************************************************************************
412 Call the MUIM_List_Display for the given entry. It fills out
413 data->string and data->preparses
414 **************************************************************************/
415 static void DisplayEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
)
417 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
421 for (col
= 0; col
< data
->columns
; col
++)
422 data
->preparses
[col
] = data
->ci
[col
].preparse
;
424 if (entry_pos
== ENTRY_TITLE
)
426 if ((data
->columns
== 1) && (data
->title
!= (STRPTR
)1))
428 *data
->strings
= data
->title
;
431 entry_data
= NULL
; /* it's a title request */
434 entry_data
= data
->entries
[entry_pos
]->data
;
436 /* Get the display formation */
437 DoMethod(obj
, MUIM_List_Display
, (IPTR
)entry_data
, (IPTR
)data
->strings
,
438 entry_pos
, (IPTR
)data
->preparses
);
441 /**************************************************************************
442 Determine the dims of a single entry and adapt the columinfo according
443 to it. pos might be ENTRY_TITLE. Returns 0 if pos entry needs to
444 be redrawn after this operation, 1 if all entries need to be redrawn.
445 **************************************************************************/
446 static int CalcDimsOfEntry(struct IClass
*cl
, Object
*obj
, int pos
)
448 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
449 struct ListEntry
*entry
= data
->entries
[pos
];
456 DisplayEntry(cl
, obj
, pos
);
458 /* Clear the height */
459 data
->entries
[pos
]->height
= data
->entry_minheight
;
461 for (j
= 0; j
< data
->columns
; j
++)
463 ZText
*text
= zune_text_new(data
->preparses
[j
], data
->strings
[j
], ZTEXT_ARG_NONE
, 0);
466 zune_text_get_bounds(text
, obj
);
468 if (text
->height
> data
->entries
[pos
]->height
)
470 data
->entries
[pos
]->height
= text
->height
;
471 /* entry height changed, redraw all entries later */
474 data
->entries
[pos
]->widths
[j
] = text
->width
;
476 if (text
->width
> data
->ci
[j
].entries_width
)
478 /* This columns width is bigger than the other in the same
479 * columns, so we store this value
481 data
->ci
[j
].entries_width
= text
->width
;
482 /* column width changed, redraw all entries later */
486 zune_text_destroy(text
);
489 if (data
->entries
[pos
]->height
> data
->entry_maxheight
)
491 data
->entry_maxheight
= data
->entries
[pos
]->height
;
492 /* maximum entry height changed, redraw all entries later */
499 /**************************************************************************
500 Determine the widths of the entries
501 **************************************************************************/
502 static void CalcWidths(struct IClass
*cl
, Object
*obj
)
505 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
507 if (!(_flags(obj
) & MADF_SETUP
))
510 for (j
= 0; j
< data
->columns
; j
++)
511 data
->ci
[j
].entries_width
= 0;
513 data
->entry_maxheight
= 0;
514 data
->entries_totalheight
= 0;
515 data
->entries_maxwidth
= 0;
517 for (i
= (data
->title
? ENTRY_TITLE
: 0) ; i
< data
->entries_num
; i
++)
519 CalcDimsOfEntry(cl
,obj
,i
);
520 data
->entries_totalheight
+= data
->entries
[i
]->height
;
523 for (j
= 0; j
< data
->columns
; j
++)
524 data
->entries_maxwidth
+= data
->ci
[j
].entries_width
;
526 if (!data
->entry_maxheight
)
527 data
->entry_maxheight
= 1;
530 /**************************************************************************
531 Calculates the number of visible entry lines. Returns 1 if it has
533 **************************************************************************/
534 static int CalcVertVisible(struct IClass
*cl
, Object
*obj
)
536 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
537 int old_entries_visible
= data
->entries_visible
;
538 int old_entries_top_pixel
= data
->entries_top_pixel
;
540 data
->entries_visible
= (_mheight(obj
) - data
->title_height
)
541 / (data
->entry_maxheight
/* + data->prefs_linespacing */);
543 data
->entries_top_pixel
= _mtop(obj
) + data
->title_height
544 + (_mheight(obj
) - data
->title_height
545 - data
->entries_visible
* (data
->entry_maxheight
/* + data->prefs_linespacing */)) / 2;
547 return (old_entries_visible
!= data
->entries_visible
) || (old_entries_top_pixel
!= data
->entries_top_pixel
);
550 /**************************************************************************
551 Default hook to compare two list entries. Works for strings only.
552 **************************************************************************/
553 AROS_UFH3S(int, default_compare_func
,
554 AROS_UFHA(struct Hook
*, h
, A0
),
555 AROS_UFHA(char *, s2
, A2
),
556 AROS_UFHA(char *, s1
, A1
))
560 return Stricmp(s1
, s2
);
565 /**************************************************************************
567 **************************************************************************/
568 IPTR
List__OM_NEW(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
570 struct MUI_ListData
*data
;
572 const struct TagItem
*tags
;
574 STRPTR format
= NULL
;
575 LONG new_entries_active
= MUIV_List_Active_Off
;
577 obj
= (Object
*)DoSuperNewTags(cl
, obj
, NULL
,
578 MUIA_Font
, MUIV_Font_List
,
579 MUIA_Background
, MUII_ListBack
,
580 TAG_MORE
, (IPTR
)msg
->ops_AttrList
);
581 if (!obj
) return FALSE
;
583 data
= INST_DATA(cl
, obj
);
586 data
->entries_active
= MUIV_List_Active_Off
;
587 data
->intern_puddle_size
= 2008;
588 data
->intern_tresh_size
= 1024;
590 data
->default_compare_hook
.h_Entry
= (HOOKFUNC
) default_compare_func
;
591 data
->default_compare_hook
.h_SubEntry
= 0;
592 data
->compare_hook
= &(data
->default_compare_hook
);
594 /* parse initial taglist */
595 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
)); )
599 case MUIA_List_Active
:
600 new_entries_active
= tag
->ti_Data
;
604 data
->pool
= (APTR
)tag
->ti_Data
;
607 case MUIA_List_PoolPuddleSize
:
608 data
->intern_puddle_size
= tag
->ti_Data
;
611 case MUIA_List_PoolThreshSize
:
612 data
->intern_tresh_size
= tag
->ti_Data
;
615 case MUIA_List_CompareHook
:
616 /* Not tested, if List_CompareHook really works. */
617 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
620 case MUIA_List_ConstructHook
:
621 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
624 case MUIA_List_DestructHook
:
625 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
628 case MUIA_List_DisplayHook
:
629 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
632 case MUIA_List_SourceArray
:
633 array
= (APTR
*)tag
->ti_Data
;
636 case MUIA_List_Format
:
637 format
= (STRPTR
)tag
->ti_Data
;
640 case MUIA_List_Title
:
641 data
->title
= (STRPTR
)tag
->ti_Data
;
644 case MUIA_List_MinLineHeight
:
645 data
->entry_minheight
= tag
->ti_Data
;
648 case MUIA_List_AdjustHeight
:
649 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTHEIGHT
);
652 case MUIA_List_AdjustWidth
:
653 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_ADJUSTWIDTH
);
661 /* No memory pool given, so we create our own */
662 data
->pool
= data
->intern_pool
= CreatePool(0,data
->intern_puddle_size
,data
->intern_tresh_size
);
665 CoerceMethod(cl
,obj
,OM_DISPOSE
);
670 /* parse the list format */
671 if (!(ParseListFormat(data
,format
)))
673 CoerceMethod(cl
,obj
,OM_DISPOSE
);
677 /* This is neccessary for at least the title */
678 if (!SetListSize(data
,0))
680 CoerceMethod(cl
,obj
,OM_DISPOSE
);
686 if (!(data
->entries
[ENTRY_TITLE
] = AllocListEntry(data
)))
688 CoerceMethod(cl
,obj
,OM_DISPOSE
);
691 } else data
->entries
[ENTRY_TITLE
] = NULL
;
697 /* Count the number of elements */
698 for (i
= 0; array
[i
] != NULL
; i
++)
701 DoMethod(obj
, MUIM_List_Insert
, (IPTR
)array
, i
, MUIV_List_Insert_Top
);
705 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
707 switch (new_entries_active
)
709 case MUIV_List_Active_Top
:
710 new_entries_active
= 0;
713 case MUIV_List_Active_Bottom
:
714 new_entries_active
= data
->entries_num
- 1;
718 if (new_entries_active
< 0)
719 new_entries_active
= 0;
720 else if (new_entries_active
>= data
->entries_num
)
721 new_entries_active
= data
->entries_num
- 1;
723 data
->entries_active
= new_entries_active
;
724 /* Selected entry will be moved into visible area */
728 data
->ehn
.ehn_Events
= IDCMP_MOUSEBUTTONS
|
731 IDCMP_INACTIVEWINDOW
;
732 data
->ehn
.ehn_Priority
= 0;
733 data
->ehn
.ehn_Flags
= 0;
734 data
->ehn
.ehn_Object
= obj
;
735 data
->ehn
.ehn_Class
= cl
;
737 NewList((struct List
*)&data
->images
);
739 D(bug("List_New(%lx)\n", obj
));
744 /**************************************************************************
746 **************************************************************************/
747 IPTR
List__OM_DISPOSE(struct IClass
*cl
, Object
*obj
, Msg msg
)
749 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
751 D(bug("List Dispose\n"));
753 /* Call destruct method for every entry and free the entries manual to avoid notification */
754 while (data
->confirm_entries_num
)
756 struct ListEntry
*lentry
= data
->entries
[--data
->confirm_entries_num
];
757 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
)lentry
->data
, (IPTR
)data
->pool
);
758 FreeListEntry(data
, lentry
);
761 if (data
->intern_pool
)
762 DeletePool(data
->intern_pool
);
764 FreeVec(data
->entries
- 1); /* title is currently before all other elements */
766 FreeListFormat(data
);
768 return DoSuperMethodA(cl
,obj
,msg
);
772 /**************************************************************************
774 **************************************************************************/
775 IPTR
List__OM_SET(struct IClass
*cl
, Object
*obj
, struct opSet
*msg
)
777 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
779 const struct TagItem
*tags
;
781 /* parse initial taglist */
782 for (tags
= msg
->ops_AttrList
; (tag
= NextTagItem(&tags
)); )
786 case MUIA_List_CompareHook
:
787 data
->compare_hook
= (struct Hook
*)tag
->ti_Data
;
790 case MUIA_List_ConstructHook
:
791 data
->construct_hook
= (struct Hook
*)tag
->ti_Data
;
794 case MUIA_List_DestructHook
:
795 data
->destruct_hook
= (struct Hook
*)tag
->ti_Data
;
798 case MUIA_List_DisplayHook
:
799 data
->display_hook
= (struct Hook
*)tag
->ti_Data
;
802 case MUIA_List_VertProp_First
:
803 data
->vertprop_first
= tag
->ti_Data
;
804 if (data
->entries_first
!= tag
->ti_Data
)
806 set(obj
,MUIA_List_First
,tag
->ti_Data
);
810 case MUIA_List_VertProp_Entries
:
811 data
->vertprop_entries
= tag
->ti_Data
;
814 case MUIA_List_VertProp_Visible
:
815 data
->vertprop_visible
= tag
->ti_Data
;
816 data
->entries_visible
= tag
->ti_Data
;
819 case MUIA_List_Active
:
821 LONG new_entries_active
= tag
->ti_Data
;
823 if ((data
->entries_num
) && (new_entries_active
!= MUIV_List_Active_Off
))
825 switch (new_entries_active
)
827 case MUIV_List_Active_Top
:
828 new_entries_active
= 0;
831 case MUIV_List_Active_Bottom
:
832 new_entries_active
= data
->entries_num
- 1;
835 case MUIV_List_Active_Up
:
836 new_entries_active
= data
->entries_active
- 1;
839 case MUIV_List_Active_Down
:
840 new_entries_active
= data
->entries_active
+ 1;
843 case MUIV_List_Active_PageUp
:
844 new_entries_active
= data
->entries_active
- data
->entries_visible
;
847 case MUIV_List_Active_PageDown
:
848 new_entries_active
= data
->entries_active
+ data
->entries_visible
;
852 if (new_entries_active
< 0) new_entries_active
= 0;
853 else if (new_entries_active
>= data
->entries_num
) new_entries_active
= data
->entries_num
- 1;
854 } else new_entries_active
= -1;
856 if (data
->entries_active
!= new_entries_active
)
858 LONG old
= data
->entries_active
;
859 data
->entries_active
= new_entries_active
;
862 data
->update_pos
= old
;
863 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
865 data
->update_pos
= data
->entries_active
;
866 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
868 /* Selectchange stuff */
871 DoMethod(obj
,MUIM_List_SelectChange
,old
,MUIV_List_Select_Off
,0);
874 if (new_entries_active
!= -1)
876 DoMethod(obj
,MUIM_List_SelectChange
,new_entries_active
,MUIV_List_Select_On
,0);
877 DoMethod(obj
,MUIM_List_SelectChange
,new_entries_active
,MUIV_List_Select_Active
,0);
878 } else DoMethod(obj
,MUIM_List_SelectChange
,MUIV_List_Active_Off
,MUIV_List_Select_Off
,0);
880 set(obj
,MUIA_Listview_SelectChange
,TRUE
);
882 if (new_entries_active
!= -1)
884 DoMethod(obj
, MUIM_List_Jump
, MUIV_List_Jump_Active
);
890 case MUIA_List_First
:
891 data
->update_pos
= data
->entries_first
;
893 data
->entries_first
= tag
->ti_Data
;
895 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
896 if (data
->vertprop_first
!= tag
->ti_Data
)
898 set(obj
,MUIA_List_VertProp_First
,tag
->ti_Data
);
902 case MUIA_List_Visible
:
903 if (data
->vertprop_visible
!= tag
->ti_Data
)
904 set(obj
,MUIA_List_VertProp_Visible
, tag
->ti_Data
);
907 case MUIA_List_Entries
:
908 if (data
->confirm_entries_num
== tag
->ti_Data
)
910 data
->entries_num
= tag
->ti_Data
;
911 set(obj
, MUIA_List_VertProp_Entries
, data
->entries_num
);
914 D(bug("Bug: confirm_entries != MUIA_List_Entries!\n"));
918 case MUIA_List_Quiet
:
919 _handle_bool_tag(data
->flags
, tag
->ti_Data
, LIST_QUIET
);
922 DoMethod(obj
, MUIM_List_Redraw
, MUIV_List_Redraw_All
);
928 return DoSuperMethodA(cl
, obj
, (Msg
)msg
);
931 /**************************************************************************
933 **************************************************************************/
934 IPTR
List__OM_GET(struct IClass
*cl
, Object
*obj
, struct opGet
*msg
)
936 /* small macro to simplify return value storage */
937 #define STORE *(msg->opg_Storage)
938 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
940 switch (msg
->opg_AttrID
)
942 case MUIA_List_Entries
: STORE
= data
->entries_num
; return 1;
943 case MUIA_List_First
: STORE
= data
->entries_first
; return 1;
944 case MUIA_List_Active
: STORE
= data
->entries_active
; return 1;
945 case MUIA_List_InsertPosition
: STORE
= data
->insert_position
; return 1;
946 case MUIA_List_Title
: STORE
= (unsigned long)data
->title
; return 1;
947 case MUIA_List_VertProp_Entries
: STORE
= STORE
= data
->vertprop_entries
; return 1;
948 case MUIA_List_VertProp_Visible
: STORE
= data
->vertprop_visible
; return 1;
949 case MUIA_List_VertProp_First
: STORE
= data
->vertprop_first
; return 1;
951 case MUIA_Listview_DoubleClick
: STORE
= 0; return 1;
954 if (DoSuperMethodA(cl
, obj
, (Msg
) msg
)) return 1;
959 /**************************************************************************
961 **************************************************************************/
962 IPTR
List__MUIM_Setup(struct IClass
*cl
, Object
*obj
, struct MUIP_Setup
*msg
)
964 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
966 if (!DoSuperMethodA(cl
, obj
, (Msg
) msg
))
969 data
->prefs_multi
= muiGlobalInfo(obj
)->mgi_Prefs
->list_multi
;
970 data
->prefs_refresh
= muiGlobalInfo(obj
)->mgi_Prefs
->list_refresh
;
971 data
->prefs_linespacing
= muiGlobalInfo(obj
)->mgi_Prefs
->list_linespacing
;
972 data
->prefs_smoothed
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothed
;
973 data
->prefs_smoothval
= muiGlobalInfo(obj
)->mgi_Prefs
->list_smoothval
;
979 data
->title_height
= data
->entries
[ENTRY_TITLE
]->height
+ 2;
983 data
->title_height
= 0;
986 DoMethod(_win(obj
),MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
988 data
->list_cursor
= zune_imspec_setup(MUII_ListCursor
, muiRenderInfo(obj
));
989 data
->list_select
= zune_imspec_setup(MUII_ListSelect
, muiRenderInfo(obj
));
990 data
->list_selcur
= zune_imspec_setup(MUII_ListSelCur
, muiRenderInfo(obj
));
995 /**************************************************************************
997 **************************************************************************/
998 IPTR
List__MUIM_Cleanup(struct IClass
*cl
, Object
*obj
, struct MUIP_Cleanup
*msg
)
1000 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1001 struct ListImage
*li
= List_First(&data
->images
);
1005 struct ListImage
*next
= Node_Next(li
);
1006 DoMethod(obj
, MUIM_List_DeleteImage
, (IPTR
)li
);
1010 zune_imspec_cleanup(data
->list_cursor
);
1011 zune_imspec_cleanup(data
->list_select
);
1012 zune_imspec_cleanup(data
->list_selcur
);
1014 DoMethod(_win(obj
),MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
1015 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
);
1016 data
->mouse_click
= 0;
1018 return DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1021 /**************************************************************************
1023 **************************************************************************/
1024 IPTR
List__MUIM_AskMinMax(struct IClass
*cl
, Object
*obj
,struct MUIP_AskMinMax
*msg
)
1026 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1028 DoSuperMethodA(cl
, obj
, (Msg
)msg
);
1031 if ((data
->flags
& LIST_ADJUSTWIDTH
) && (data
->entries_num
> 0))
1033 msg
->MinMaxInfo
->MinWidth
+= data
->entries_maxwidth
;
1034 msg
->MinMaxInfo
->DefWidth
+= data
->entries_maxwidth
;
1035 msg
->MinMaxInfo
->MaxWidth
+= data
->entries_maxwidth
;
1039 msg
->MinMaxInfo
->MinWidth
+= 40;
1040 msg
->MinMaxInfo
->DefWidth
+= 100;
1041 msg
->MinMaxInfo
->MaxWidth
= MUI_MAXMAX
;
1044 if (data
->entries_num
> 0)
1046 if (data
->flags
& LIST_ADJUSTHEIGHT
)
1048 msg
->MinMaxInfo
->MinHeight
+= data
->entries_totalheight
;
1049 msg
->MinMaxInfo
->DefHeight
+= data
->entries_totalheight
;
1050 msg
->MinMaxInfo
->MaxHeight
+= data
->entries_totalheight
;
1054 ULONG h
= data
->entry_maxheight
+ data
->prefs_linespacing
;
1055 msg
->MinMaxInfo
->MinHeight
+= 2 * h
+ data
->prefs_linespacing
;
1056 msg
->MinMaxInfo
->DefHeight
+= 8 * h
+ data
->prefs_linespacing
;
1057 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1062 msg
->MinMaxInfo
->MinHeight
+= 36;
1063 msg
->MinMaxInfo
->DefHeight
+= 96;
1064 msg
->MinMaxInfo
->MaxHeight
= MUI_MAXMAX
;
1066 D(bug("List %p minheigh=%d, line maxh=%d\n",
1067 obj
, msg
->MinMaxInfo
->MinHeight
, data
->entry_maxheight
));
1071 /**************************************************************************
1073 **************************************************************************/
1074 IPTR
List__MUIM_Layout(struct IClass
*cl
, Object
*obj
,struct MUIP_Layout
*msg
)
1076 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1077 ULONG rc
= DoSuperMethodA(cl
,obj
,(Msg
)msg
);
1078 LONG new_entries_first
= data
->entries_first
;
1080 /* Calc the numbers of entries visible */
1081 CalcVertVisible(cl
,obj
);
1083 #if 0 /* Don't do this! */
1084 if (data
->entries_active
< new_entries_first
)
1085 new_entries_first
= data
->entries_active
;
1088 if (data
->entries_active
+ 1 >=
1089 (data
->entries_first
+ data
->entries_visible
))
1091 data
->entries_active
- data
->entries_visible
+ 1;
1093 if ((new_entries_first
+ data
->entries_visible
>=
1096 (data
->entries_visible
<= data
->entries_num
))
1098 data
->entries_num
- data
->entries_visible
;
1100 if (data
->entries_num
<= data
->entries_visible
)
1101 new_entries_first
= 0;
1103 if (new_entries_first
< 0) new_entries_first
= 0;
1105 set(obj
, new_entries_first
!= data
->entries_first
?
1106 MUIA_List_First
: TAG_IGNORE
,
1109 /* So the notify takes happens */
1110 set(obj
, MUIA_List_VertProp_Visible
, data
->entries_visible
);
1116 /**************************************************************************
1118 **************************************************************************/
1119 IPTR
List__MUIM_Show(struct IClass
*cl
, Object
*obj
, struct MUIP_Show
*msg
)
1121 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1122 ULONG rc
= DoSuperMethodA(cl
, obj
, (Msg
)msg
);
1124 zune_imspec_show(data
->list_cursor
, obj
);
1125 zune_imspec_show(data
->list_select
, obj
);
1126 zune_imspec_show(data
->list_selcur
, obj
);
1131 /**************************************************************************
1133 **************************************************************************/
1134 IPTR
List__MUIM_Hide(struct IClass
*cl
, Object
*obj
, struct MUIP_Hide
*msg
)
1136 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1139 if (data
->ehn
.ehn_Events
& (IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
))
1141 DoMethod(_win(obj
),MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
1142 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
);
1143 DoMethod(_win(obj
),MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
1145 data
->mouse_click
= 0;
1148 zune_imspec_hide(data
->list_cursor
);
1149 zune_imspec_hide(data
->list_select
);
1150 zune_imspec_hide(data
->list_selcur
);
1152 return DoSuperMethodA(cl
, obj
, (Msg
)msg
);
1156 /**************************************************************************
1157 Draw an entry at entry_pos at the given y location. To draw the title,
1158 set pos to ENTRY_TITLE
1159 **************************************************************************/
1160 static VOID
List_DrawEntry(struct IClass
*cl
, Object
*obj
, int entry_pos
, int y
)
1162 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1165 /* To be surem we don't draw anything if there is no title */
1166 if (entry_pos
== ENTRY_TITLE
&& !data
->title
) return;
1168 DisplayEntry(cl
,obj
,entry_pos
);
1171 for (col
= 0; col
< data
->columns
; col
++)
1174 x2
= x1
+ data
->ci
[col
].entries_width
;
1176 if ((text
= zune_text_new(data
->preparses
[col
], data
->strings
[col
], ZTEXT_ARG_NONE
, 0)))
1178 /* Could be made simpler, as we don't really need the bounds */
1179 zune_text_get_bounds(text
, obj
);
1180 /* Note, this was MPEN_SHADOW before */
1181 SetAPen(_rp(obj
), muiRenderInfo(obj
)->mri_Pens
[MPEN_TEXT
]);
1182 zune_text_draw(text
, obj
, x1
, x2
, y
); /* totally wrong! */
1183 zune_text_destroy(text
);
1185 x1
= x2
+ data
->ci
[col
].delta
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0);
1189 /**************************************************************************
1191 **************************************************************************/
1192 IPTR
List__MUIM_Draw(struct IClass
*cl
, Object
*obj
, struct MUIP_Draw
*msg
)
1194 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1198 BOOL scroll_caused_damage
= FALSE
;
1200 DoSuperMethodA(cl
, obj
, (Msg
) msg
);
1202 if (msg
->flags
& MADF_DRAWUPDATE
)
1204 if (data
->update
== 1)
1205 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), _mtop(obj
),
1206 _mwidth(obj
), _mheight(obj
),
1207 0, data
->entries_first
* data
->entry_maxheight
, 0);
1211 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), _mtop(obj
),
1212 _mwidth(obj
), _mheight(obj
),
1213 0, data
->entries_first
* data
->entry_maxheight
, 0);
1216 clip
= MUI_AddClipping(muiRenderInfo(obj
), _mleft(obj
), _mtop(obj
),
1217 _mwidth(obj
), _mheight(obj
));
1219 if (!(msg
->flags
& MADF_DRAWUPDATE
)
1220 || ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1))
1225 if (data
->title_height
&& data
->title
)
1227 List_DrawEntry(cl
,obj
,ENTRY_TITLE
,y
);
1228 y
+= data
->entries
[ENTRY_TITLE
]->height
;
1229 SetAPen(_rp(obj
),_pens(obj
)[MPEN_SHADOW
]);
1230 Move(_rp(obj
),_mleft(obj
), y
);
1231 Draw(_rp(obj
),_mright(obj
), y
);
1232 SetAPen(_rp(obj
),_pens(obj
)[MPEN_SHINE
]);
1234 Move(_rp(obj
),_mleft(obj
), y
);
1235 Draw(_rp(obj
),_mright(obj
), y
);
1239 y
= data
->entries_top_pixel
;
1241 start
= data
->entries_first
;
1242 end
= data
->entries_first
+ data
->entries_visible
;
1244 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3)
1246 int diffy
= data
->entries_first
- data
->update_pos
;
1248 if (abs(diffy
) < data
->entries_visible
)
1250 scroll_caused_damage
= (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
) ? FALSE
: TRUE
;
1252 ScrollRaster(_rp(obj
), 0, diffy
* data
->entry_maxheight
,
1254 _mright(obj
), y
+ data
->entry_maxheight
* data
->entries_visible
);
1256 scroll_caused_damage
=
1257 scroll_caused_damage
&& (_rp(obj
)->Layer
->Flags
& LAYERREFRESH
);
1261 start
= end
- diffy
;
1262 y
+= data
->entry_maxheight
* (data
->entries_visible
- diffy
);
1264 else end
= start
- diffy
;
1268 bottom
= y
+ (end
- start
) * data
->entry_maxheight
;
1270 DoMethod(obj
, MUIM_DrawBackground
, _mleft(obj
), top
,
1271 _mwidth(obj
), bottom
- top
+ 1,
1272 0, top
- _mtop(obj
) + data
->entries_first
* data
->entry_maxheight
, 0);
1273 } /* if ((msg->flags & MADF_DRAWUPDATE) && data->update == 3) */
1275 for (entry_pos
= start
; entry_pos
< end
&& entry_pos
< data
->entries_num
; entry_pos
++)
1277 //struct ListEntry *entry = data->entries[entry_pos];
1279 if (!(msg
->flags
& MADF_DRAWUPDATE
) ||
1280 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 1) ||
1281 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 3) ||
1282 ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2 && data
->update_pos
== entry_pos
))
1284 if (entry_pos
== data
->entries_active
)
1286 zune_imspec_draw(data
->list_cursor
, muiRenderInfo(obj
),
1287 _mleft(obj
),y
,_mwidth(obj
), data
->entry_maxheight
,
1288 0, y
- data
->entries_top_pixel
,0);
1291 if ((msg
->flags
& MADF_DRAWUPDATE
) && data
->update
== 2 && data
->update_pos
== entry_pos
)
1293 DoMethod(obj
,MUIM_DrawBackground
,_mleft(obj
),y
,_mwidth(obj
), data
->entry_maxheight
,
1294 0,y
- _mtop(obj
) + data
->entries_first
* data
->entry_maxheight
,0);
1297 List_DrawEntry(cl
,obj
,entry_pos
,y
);
1299 y
+= data
->entry_maxheight
;
1302 MUI_RemoveClipping(muiRenderInfo(obj
),clip
);
1306 if (scroll_caused_damage
)
1308 if (MUI_BeginRefresh(muiRenderInfo(obj
), 0))
1310 /* Theoretically it might happen that more damage is caused
1311 after ScrollRaster. By something else, like window movement
1312 in front of our window. Therefore refresh root object of
1313 window, not just this object */
1317 get(_win(obj
),MUIA_Window_RootObject
, &o
);
1318 MUI_Redraw(o
, MADF_DRAWOBJECT
);
1320 MUI_EndRefresh(muiRenderInfo(obj
), 0);
1324 ULONG x1
= _mleft(obj
);
1328 if (data
->title_height
&& data
->title
)
1330 for (col
= 0; col
< data
->columns
; col
++)
1332 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1333 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1335 if(x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(obj
))
1338 if(data
->ci
[col
].bar
)
1340 SetAPen(_rp(obj
),_pens(obj
)[MPEN_SHINE
]);
1341 Move(_rp(obj
),x1
, y
);
1342 Draw(_rp(obj
),x1
, y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1343 SetAPen(_rp(obj
),_pens(obj
)[MPEN_SHADOW
]);
1344 Move(_rp(obj
),x1
+ 1, y
);
1345 Draw(_rp(obj
),x1
+ 1, y
+ data
->entries
[ENTRY_TITLE
]->height
- 1);
1349 x1
+= data
->ci
[col
].delta
- halfdelta
;
1351 y
+= data
->entries
[ENTRY_TITLE
]->height
+ 1;
1356 for (col
= 0; col
< data
->columns
; col
++)
1358 ULONG halfdelta
= data
->ci
[col
].delta
/ 2;
1359 x1
+= data
->ci
[col
].entries_width
+ halfdelta
;
1361 if(x1
+ (data
->ci
[col
].bar
? BAR_WIDTH
: 0) > _mright(obj
))
1364 if(data
->ci
[col
].bar
)
1366 SetAPen(_rp(obj
),_pens(obj
)[MPEN_SHINE
]);
1367 Move(_rp(obj
),x1
, y
);
1368 Draw(_rp(obj
),x1
, _mbottom(obj
));
1369 SetAPen(_rp(obj
),_pens(obj
)[MPEN_SHADOW
]);
1370 Move(_rp(obj
),x1
+ 1, y
);
1371 Draw(_rp(obj
),x1
+ 1, _mbottom(obj
));
1376 x1
+= data
->ci
[col
].delta
- halfdelta
;
1382 /**************************************************************************
1383 Makes the entry at the given mouse position the active one.
1384 Relx and Rely are relative mouse coordinates to the upper left of
1386 **************************************************************************/
1387 static VOID
List_MakeActive(struct IClass
*cl
, Object
*obj
, LONG relx
, LONG rely
)
1389 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1391 if (data
->entries_num
== 0)
1394 LONG eclicky
= rely
+ _top(obj
) - data
->entries_top_pixel
; /* y coordinates transfromed to the entries */
1395 LONG new_act
= eclicky
/ data
->entry_maxheight
+ data
->entries_first
;
1396 LONG old_act
= data
->entries_active
;
1400 new_act
= data
->entries_first
- 1;
1402 else if (new_act
> data
->entries_first
+ data
->entries_visible
)
1404 new_act
= data
->entries_first
+ data
->entries_visible
;
1407 if (new_act
>= data
->entries_num
) new_act
= data
->entries_num
- 1;
1408 else if (new_act
< 0) new_act
= 0;
1410 /* Notify only when active entry has changed */
1411 if (old_act
!= new_act
)
1412 set(obj
, MUIA_List_Active
, new_act
);
1415 static void DoWheelMove(struct IClass
*cl
, Object
*obj
, LONG wheely
, UWORD qual
)
1417 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1418 LONG
new = data
->entries_first
;
1420 if (qual
& IEQUALIFIER_CONTROL
)
1422 if (wheely
< 0) new = 0;
1423 if (wheely
> 0) new = data
->entries_num
;
1425 else if (qual
& (IEQUALIFIER_LSHIFT
| IEQUALIFIER_RSHIFT
))
1427 new += (wheely
* data
->entries_visible
);
1434 if (new > data
->entries_num
- data
->entries_visible
)
1436 new = data
->entries_num
- data
->entries_visible
;
1444 if (new != data
->entries_first
)
1446 set(obj
, MUIA_List_First
, new);
1451 /**************************************************************************
1453 **************************************************************************/
1454 IPTR
List__MUIM_HandleEvent(struct IClass
*cl
, Object
*obj
, struct MUIP_HandleEvent
*msg
)
1456 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1460 LONG mx
= msg
->imsg
->MouseX
- _left(obj
);
1461 LONG my
= msg
->imsg
->MouseY
- _top(obj
);
1462 switch (msg
->imsg
->Class
)
1464 case IDCMP_MOUSEBUTTONS
:
1465 if (msg
->imsg
->Code
== SELECTDOWN
)
1467 if (mx
>= 0 && mx
< _width(obj
) && my
>= 0 && my
< _height(obj
))
1469 LONG eclicky
= my
+ _top(obj
) - data
->entries_top_pixel
; /* y coordinates transfromed to the entries */
1470 data
->mouse_click
= MOUSE_CLICK_ENTRY
;
1471 /* Now check if it was clicked on a title or on the entries */
1472 if (eclicky
>= 0 && eclicky
< data
->entries_visible
* data
->entry_maxheight
)
1474 List_MakeActive(cl
, obj
, mx
, my
); /* sets data->entries_active */
1476 if (data
->last_active
== data
->entries_active
1477 && DoubleClick(data
->last_secs
, data
->last_mics
, msg
->imsg
->Seconds
, msg
->imsg
->Micros
))
1479 set(obj
, MUIA_Listview_DoubleClick
, TRUE
);
1480 data
->last_active
= -1;
1481 data
->last_secs
= data
->last_mics
= 0;
1484 data
->last_active
= data
->entries_active
;
1485 data
->last_secs
= msg
->imsg
->Seconds
;
1486 data
->last_mics
= msg
->imsg
->Micros
;
1490 DoMethod(_win(obj
),MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
1491 data
->ehn
.ehn_Events
|= (IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
);
1492 DoMethod(_win(obj
),MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
1494 return MUI_EventHandlerRC_Eat
;
1498 if (msg
->imsg
->Code
== SELECTUP
&& data
->mouse_click
)
1500 DoMethod(_win(obj
),MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
1501 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
);
1502 DoMethod(_win(obj
),MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
1503 data
->mouse_click
= 0;
1509 case IDCMP_INTUITICKS
:
1510 case IDCMP_MOUSEMOVE
:
1511 if (data
->mouse_click
)
1513 List_MakeActive(cl
, obj
, mx
, my
);
1518 switch(msg
->imsg
->Code
)
1520 case RAWKEY_NM_WHEEL_UP
:
1521 if (_isinobject(msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
1523 DoWheelMove(cl
, obj
, -1, msg
->imsg
->Qualifier
);
1527 case RAWKEY_NM_WHEEL_DOWN
:
1528 if (_isinobject(msg
->imsg
->MouseX
, msg
->imsg
->MouseY
))
1530 DoWheelMove(cl
, obj
, 1, msg
->imsg
->Qualifier
);
1537 case IDCMP_ACTIVEWINDOW
:
1538 case IDCMP_INACTIVEWINDOW
:
1539 if (data
->ehn
.ehn_Events
& (IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
))
1541 DoMethod(_win(obj
),MUIM_Window_RemEventHandler
, (IPTR
)&data
->ehn
);
1542 data
->ehn
.ehn_Events
&= ~(IDCMP_MOUSEMOVE
| IDCMP_INTUITICKS
);
1543 DoMethod(_win(obj
),MUIM_Window_AddEventHandler
, (IPTR
)&data
->ehn
);
1544 data
->mouse_click
= 0;
1553 /**************************************************************************
1555 **************************************************************************/
1556 IPTR
List__MUIM_Clear(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Clear
*msg
)
1558 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1560 while (data
->confirm_entries_num
)
1562 struct ListEntry
*lentry
= data
->entries
[--data
->confirm_entries_num
];
1563 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
)lentry
->data
, (IPTR
)data
->pool
);
1564 FreeListEntry(data
,lentry
);
1566 /* Should never fail when shrinking */
1567 SetListSize(data
,0);
1569 if (data
->confirm_entries_num
!= data
->entries_num
)
1572 MUIA_List_Entries
,0,
1574 /* Notify only when no entry was active */
1575 data
->entries_active
!= MUIV_List_Active_Off
? MUIA_List_Active
: TAG_DONE
, MUIV_List_Active_Off
,
1579 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1585 /**************************************************************************
1587 **************************************************************************/
1588 IPTR
List__MUIM_Exchange(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Exchange
*msg
)
1590 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1596 case MUIV_List_Exchange_Top
: pos1
= 0; break;
1597 case MUIV_List_Exchange_Active
: pos1
= data
->entries_active
; break;
1598 case MUIV_List_Exchange_Bottom
: pos1
= data
->entries_num
- 1; break;
1599 default: pos1
= msg
->pos1
;
1604 case MUIV_List_Exchange_Top
: pos2
= 0; break;
1605 case MUIV_List_Exchange_Active
: pos2
= data
->entries_active
; break;
1606 case MUIV_List_Exchange_Bottom
: pos2
= data
->entries_num
- 1; break;
1607 case MUIV_List_Exchange_Next
: pos2
= pos1
+ 1; break;
1608 case MUIV_List_Exchange_Previous
: pos2
= pos1
- 1; break;
1609 default: pos2
= msg
->pos2
;
1612 if (pos1
>= 0 && pos1
< data
->entries_num
&& pos2
>= 0 && pos2
<= data
->entries_num
&& pos1
!= pos2
)
1614 struct ListEntry
*save
= data
->entries
[pos1
];
1615 data
->entries
[pos1
] = data
->entries
[pos2
];
1616 data
->entries
[pos2
] = save
;
1619 data
->update_pos
= pos1
;
1620 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1623 data
->update_pos
= pos2
;
1624 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1634 /**************************************************************************
1636 **************************************************************************/
1637 IPTR
List__MUIM_Redraw(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Redraw
*msg
)
1639 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1641 if (msg
->pos
== MUIV_List_Redraw_All
)
1645 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1649 if (msg
->pos
== MUIV_List_Redraw_Active
) pos
= data
->entries_active
;
1650 else pos
= msg
->pos
;
1654 if(CalcDimsOfEntry(cl
, obj
, pos
))
1659 data
->update_pos
= pos
;
1661 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1667 /**************************************************************************
1669 **************************************************************************/
1670 IPTR
List__MUIM_Remove(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Remove
*msg
)
1672 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1675 struct ListEntry
*lentry
;
1676 //int rem_count = 1;
1678 if (!data
->entries_num
) return 0;
1682 case MUIV_List_Remove_First
:
1686 case MUIV_List_Remove_Active
:
1687 pos
= data
->entries_active
;
1690 case MUIV_List_Remove_Last
:
1691 pos
= data
->entries_num
- 1;
1694 case MUIV_List_Remove_Selected
:
1695 /* TODO: needs special handling */
1696 pos
= data
->entries_active
;
1704 if (pos
< 0 || pos
>= data
->entries_num
)
1707 new_act
= data
->entries_active
;
1709 if (pos
== new_act
&& new_act
== data
->entries_num
- 1)
1710 new_act
--; /* might become MUIV_List_Active_Off */
1712 lentry
= data
->entries
[pos
];
1713 DoMethod(obj
, MUIM_List_Destruct
, (IPTR
)lentry
->data
, (IPTR
)data
->pool
);
1717 RemoveListEntries(data
, pos
, cur
- pos
);
1718 data
->confirm_entries_num
-= cur
- pos
;
1720 /* ensure that the active element is in a valid range */
1721 if (new_act
>= data
->entries_num
) new_act
= data
->entries_num
- 1;
1724 MUIA_List_Entries
, data
->confirm_entries_num
,
1725 (new_act
>= pos
) || (new_act
!= data
->entries_active
) ?
1726 MUIA_List_Active
: TAG_DONE
, new_act
, /* Inform only if neccessary (for notify) */
1730 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1735 /**************************************************************************
1737 **************************************************************************/
1739 IPTR
List__MUIM_Insert(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Insert
*msg
)
1741 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1742 LONG pos
,count
,sort
;
1749 /* Count the number of entries */
1750 for(count
= 0; msg
->entries
[count
] != NULL
; count
++)
1759 case MUIV_List_Insert_Top
:
1763 case MUIV_List_Insert_Active
:
1764 if (data
->entries_active
!= -1) pos
= data
->entries_active
;
1765 else pos
= data
->entries_active
;
1768 case MUIV_List_Insert_Sorted
:
1769 pos
= data
->entries_num
;
1770 sort
= 1; /* we sort'em later */
1773 case MUIV_List_Insert_Bottom
:
1774 pos
= data
->entries_num
;
1778 if (msg
->pos
> data
->entries_num
) pos
= data
->entries_num
;
1779 else if (msg
->pos
< 0) pos
= 0;
1780 else pos
= msg
->pos
;
1784 if (!(SetListSize(data
,data
->entries_num
+ count
)))
1787 LONG until
= pos
+ count
;
1788 APTR
*toinsert
= msg
->entries
;
1790 if (!(PrepareInsertListEntries(data
, pos
, count
)))
1795 struct ListEntry
*lentry
;
1797 if (!(lentry
= AllocListEntry(data
)))
1799 /* Panic, but we must be in a consistent state, so remove
1800 ** the space where the following list entries should have gone
1802 RemoveListEntries(data
, pos
, until
- pos
);
1806 /* now call the construct method which returns us a pointer which
1808 lentry
->data
= (APTR
)DoMethod(obj
, MUIM_List_Construct
,
1809 (IPTR
)*toinsert
, (IPTR
)data
->pool
);
1812 FreeListEntry(data
,lentry
);
1813 RemoveListEntries(data
, pos
, until
- pos
);
1815 /* TODO: Also check for visible stuff like below */
1816 if (data
->entries_num
!= data
->confirm_entries_num
)
1817 set(obj
,MUIA_List_Entries
,data
->confirm_entries_num
);
1821 data
->entries
[pos
] = lentry
;
1822 data
->confirm_entries_num
++;
1824 if (_flags(obj
) & MADF_SETUP
)
1826 /* We have to calculate the width and height of the newly inserted entry,
1827 this has to be done after inserting the element into the list */
1828 CalcDimsOfEntry(cl
, obj
, pos
);
1833 } // while (pos < until)
1836 if (_flags(obj
) & MADF_SETUP
)
1837 CalcVertVisible(cl
,obj
); /* Recalculate the number of visible entries */
1839 if (data
->entries_num
!= data
->confirm_entries_num
)
1842 MUIA_List_Entries
, data
->confirm_entries_num
,
1843 MUIA_List_Visible
, data
->entries_visible
,
1847 /* If the array is already sorted, we could do a simple insert
1848 * sort and would be much faster than with qsort.
1849 * If an array is not yet sorted, does a MUIV_List_Insert_Sorted
1850 * sort the whole array?
1852 * I think, we better sort the whole array:
1856 DoMethod(obj
,MUIM_List_Sort
);
1857 /* TODO: which pos to return here !? */
1858 /* MUIM_List_Sort already called MUI_Redraw */
1862 if (!(data
->flags
& LIST_QUIET
))
1865 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
1868 data
->insert_position
= pos
;
1873 /**************************************************************************
1874 MUIM_List_InsertSingle
1875 **************************************************************************/
1876 IPTR
List__MUIM_InsertSingle(struct IClass
*cl
, Object
*obj
, struct MUIP_List_InsertSingle
*msg
)
1878 return DoMethod(obj
,MUIM_List_Insert
, (IPTR
)&msg
->entry
, 1, msg
->pos
);
1881 /**************************************************************************
1883 **************************************************************************/
1884 IPTR
List__MUIM_GetEntry(struct IClass
*cl
, Object
*obj
, struct MUIP_List_GetEntry
*msg
)
1886 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1889 if (pos
== MUIV_List_GetEntry_Active
) pos
= data
->entries_active
;
1891 if (pos
< 0 || pos
>= data
->entries_num
)
1896 *msg
->entry
= data
->entries
[pos
]->data
;
1897 return (IPTR
)*msg
->entry
;
1900 /**************************************************************************
1902 **************************************************************************/
1903 IPTR
List__MUIM_Construct(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Construct
*msg
)
1905 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1907 if (NULL
== data
->construct_hook
)
1908 return (IPTR
)msg
->entry
;
1909 if ((ULONG
)data
->construct_hook
== MUIV_List_ConstructHook_String
)
1911 int len
= msg
->entry
? strlen((STRPTR
)msg
->entry
) : 0;
1912 ULONG
*mem
= AllocPooled(msg
->pool
, len
+5);
1917 if (msg
->entry
!= NULL
)
1918 strcpy((STRPTR
)(mem
+1), (STRPTR
)msg
->entry
);
1920 *(STRPTR
)(mem
+1) = 0;
1921 return (IPTR
)(mem
+1);
1923 return CallHookPkt(data
->construct_hook
, msg
->pool
, msg
->entry
);
1926 /**************************************************************************
1928 **************************************************************************/
1929 IPTR
List__MUIM_Destruct(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Destruct
*msg
)
1931 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1933 if (NULL
== data
->destruct_hook
)
1936 if ((ULONG
)data
->destruct_hook
== MUIV_List_DestructHook_String
)
1938 ULONG
*mem
= ((ULONG
*)msg
->entry
) - 1;
1939 FreePooled(msg
->pool
, mem
, mem
[0]);
1943 CallHookPkt(data
->destruct_hook
, msg
->pool
, msg
->entry
);
1948 /**************************************************************************
1950 **************************************************************************/
1951 IPTR
List__MUIM_Compare(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Compare
*msg
)
1953 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1955 return CallHookPkt(data
->compare_hook
, msg
->entry2
, msg
->entry1
);
1958 /**************************************************************************
1960 **************************************************************************/
1961 IPTR
List__MUIM_Display(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Display
*msg
)
1963 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1965 if (NULL
== data
->display_hook
)
1968 *msg
->array
= msg
->entry
;
1974 *((ULONG
*)(msg
->array
- 1)) = msg
->entry_pos
;
1975 return CallHookPkt(data
->display_hook
, msg
->array
, msg
->entry
);
1978 /**************************************************************************
1979 MUIM_List_SelectChange
1980 **************************************************************************/
1981 IPTR
List__MUIM_SelectChange(struct IClass
*cl
, Object
*obj
, struct MUIP_List_SelectChange
*msg
)
1986 /**************************************************************************
1987 MUIM_List_CreateImage
1988 Called by a List subclass in its Setup method.
1989 Connects an Area subclass object to the list, much like an object gets
1990 connected to a window. List call Setup and AskMinMax on that object,
1991 keeps a reference to it (that reference will be returned).
1992 Text engine will dereference that pointer and draw the object with its
1994 **************************************************************************/
1995 IPTR
List__MUIM_CreateImage(struct IClass
*cl
, Object
*obj
, struct MUIP_List_CreateImage
*msg
)
1997 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
1998 struct ListImage
*li
;
2000 /* List must be already setup in Setup of your subclass */
2001 if (!(_flags(obj
) & MADF_SETUP
))
2003 li
= AllocPooled(data
->pool
, sizeof(struct ListImage
));
2008 AddTail((struct List
*)&data
->images
, (struct Node
*)li
);
2009 DoMethod(li
->obj
, MUIM_ConnectParent
, (IPTR
)obj
);
2010 DoSetupMethod(li
->obj
, muiRenderInfo(obj
));
2016 /**************************************************************************
2017 MUIM_List_DeleteImage
2018 **************************************************************************/
2019 IPTR
List__MUIM_DeleteImage(struct IClass
*cl
, Object
*obj
, struct MUIP_List_DeleteImage
*msg
)
2021 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2022 struct ListImage
*li
= (struct ListImage
*)msg
->listimg
;
2026 DoMethod(li
->obj
, MUIM_Cleanup
);
2027 DoMethod(li
->obj
, MUIM_DisconnectParent
);
2028 Remove((struct Node
*)li
);
2029 FreePooled(data
->pool
, li
, sizeof(struct ListImage
));
2035 /**************************************************************************
2037 **************************************************************************/
2038 IPTR
List__MUIM_Jump(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Jump
*msg
)
2040 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2041 LONG pos
= msg
->pos
;
2045 case MUIV_List_Jump_Top
:
2049 case MUIV_List_Jump_Active
:
2050 pos
= data
->entries_active
;
2053 case MUIV_List_Jump_Bottom
:
2054 pos
= data
->entries_num
- 1;
2057 case MUIV_List_Jump_Down
:
2058 pos
= data
->entries_first
+ data
->entries_visible
;
2061 case MUIV_List_Jump_Up
:
2062 pos
= data
->entries_first
- 1;
2067 if (pos
> data
->entries_num
)
2069 pos
= data
->entries_num
- 1;
2071 if (pos
< 0) pos
= 0;
2073 if (pos
< data
->entries_first
)
2075 set(obj
, MUIA_List_First
, pos
);
2077 else if (pos
>= data
->entries_first
+ data
->entries_visible
)
2079 pos
-= (data
->entries_visible
- 1);
2080 if (pos
< 0) pos
= 0;
2081 if (pos
!= data
->entries_first
)
2083 set(obj
, MUIA_List_First
, pos
);
2091 /**************************************************************************
2093 **************************************************************************/
2094 IPTR
List__MUIM_Sort(struct IClass
*cl
, Object
*obj
, struct MUIP_List_Sort
*msg
)
2096 struct MUI_ListData
*data
= INST_DATA(cl
, obj
);
2099 struct MUIP_List_Compare cmpmsg
= {MUIM_List_Compare
, NULL
, NULL
, 0, 0};
2101 if (data
->entries_num
> 1)
2104 Simple sort algorithm. Feel free to improve it.
2106 for (i
= 0; i
< data
->entries_num
- 1; i
++)
2109 for (j
= i
+ 1; j
< data
->entries_num
; j
++)
2111 cmpmsg
.entry1
= data
->entries
[max
]->data
;
2112 cmpmsg
.entry2
= data
->entries
[j
]->data
;
2113 if ((LONG
)DoMethodA(obj
, (Msg
)&cmpmsg
) > 0)
2120 APTR tmp
= data
->entries
[i
];
2121 data
->entries
[i
] = data
->entries
[max
];
2122 data
->entries
[max
] = tmp
;
2127 if (!(data
->flags
& LIST_QUIET
))
2130 MUI_Redraw(obj
,MADF_DRAWUPDATE
);
2136 /**************************************************************************
2138 **************************************************************************/
2139 BOOPSI_DISPATCHER(IPTR
, List_Dispatcher
, cl
, obj
, msg
)
2141 switch (msg
->MethodID
)
2143 case OM_NEW
: return List__OM_NEW(cl
, obj
, (struct opSet
*)msg
);
2144 case OM_DISPOSE
: return List__OM_DISPOSE(cl
,obj
, msg
);
2145 case OM_SET
: return List__OM_SET(cl
,obj
,(struct opSet
*)msg
);
2146 case OM_GET
: return List__OM_GET(cl
,obj
,(struct opGet
*)msg
);
2148 case MUIM_Setup
: return List__MUIM_Setup(cl
,obj
,(struct MUIP_Setup
*)msg
);
2149 case MUIM_Cleanup
: return List__MUIM_Cleanup(cl
,obj
,(struct MUIP_Cleanup
*)msg
);
2150 case MUIM_AskMinMax
: return List__MUIM_AskMinMax(cl
,obj
,(struct MUIP_AskMinMax
*)msg
);
2151 case MUIM_Show
: return List__MUIM_Show(cl
,obj
,(struct MUIP_Show
*)msg
);
2152 case MUIM_Hide
: return List__MUIM_Hide(cl
,obj
,(struct MUIP_Hide
*)msg
);
2153 case MUIM_Draw
: return List__MUIM_Draw(cl
,obj
,(struct MUIP_Draw
*)msg
);
2154 case MUIM_Layout
: return List__MUIM_Layout(cl
,obj
,(struct MUIP_Layout
*)msg
);
2155 case MUIM_HandleEvent
: return List__MUIM_HandleEvent(cl
,obj
,(struct MUIP_HandleEvent
*)msg
);
2156 case MUIM_List_Clear
: return List__MUIM_Clear(cl
,obj
,(struct MUIP_List_Clear
*)msg
);
2157 case MUIM_List_Sort
: return List__MUIM_Sort(cl
,obj
,(struct MUIP_List_Sort
*)msg
);
2158 case MUIM_List_Exchange
: return List__MUIM_Exchange(cl
,obj
,(struct MUIP_List_Exchange
*)msg
);
2159 case MUIM_List_Insert
: return List__MUIM_Insert(cl
,obj
,(APTR
)msg
);
2160 case MUIM_List_InsertSingle
: return List__MUIM_InsertSingle(cl
,obj
,(APTR
)msg
);
2161 case MUIM_List_GetEntry
: return List__MUIM_GetEntry(cl
,obj
,(APTR
)msg
);
2162 case MUIM_List_Redraw
: return List__MUIM_Redraw(cl
,obj
,(APTR
)msg
);
2163 case MUIM_List_Remove
: return List__MUIM_Remove(cl
,obj
,(APTR
)msg
);
2165 case MUIM_List_Construct
: return List__MUIM_Construct(cl
,obj
,(APTR
)msg
);
2166 case MUIM_List_Destruct
: return List__MUIM_Destruct(cl
,obj
,(APTR
)msg
);
2167 case MUIM_List_Compare
: return List__MUIM_Compare(cl
,obj
,(APTR
)msg
);
2168 case MUIM_List_Display
: return List__MUIM_Display(cl
,obj
,(APTR
)msg
);
2169 case MUIM_List_SelectChange
: return List__MUIM_SelectChange(cl
,obj
,(APTR
)msg
);
2170 case MUIM_List_CreateImage
: return List__MUIM_CreateImage(cl
,obj
,(APTR
)msg
);
2171 case MUIM_List_DeleteImage
: return List__MUIM_DeleteImage(cl
,obj
,(APTR
)msg
);
2172 case MUIM_List_Jump
: return List__MUIM_Jump(cl
,obj
,(APTR
)msg
);
2175 return DoSuperMethodA(cl
, obj
, msg
);
2177 BOOPSI_DISPATCHER_END
2182 const struct __MUIBuiltinClass _MUI_List_desc
= {
2185 sizeof(struct MUI_ListData
),
2186 (void*)List_Dispatcher