2 Copyright © 1995-2005, The AROS Development Team. All rights reserved.
5 AROS specific list class implementation.
8 #include <exec/types.h>
10 #include <proto/exec.h>
11 #include <proto/intuition.h>
12 #include <proto/utility.h>
13 #include <exec/memory.h>
14 #include <intuition/classusr.h>
15 #include <aros/asmcall.h>
18 #include "aroslist_intern.h"
19 #include <gadgets/aroslist.h>
23 #include <aros/debug.h>
26 #define AROSListBase ((struct LVBase *)(cl->cl_UserData))
29 /*****************************************************************************/
33 #define SETFLAG(flagvar, boolvar, flag) \
45 STATIC VOID
SetActive(LONG pos
, struct ListData
*data
)
47 if (data
->ld_Active
!= AROSV_List_Active_None
)
49 data
->ld_PointerArray
[data
->ld_Active
]->le_Flags
&= ~LEFLG_SELECTED
;
52 if (pos
!= AROSV_List_Active_None
)
54 data
->ld_PointerArray
[pos
]->le_Flags
|= LEFLG_SELECTED
;
56 data
->ld_Active
= pos
;
59 STATIC
_OM_SET(Class
*cl
, Object
*o
,struct opSet
*msg
)
61 IPTR retval
= (IPTR
)0;
63 const struct TagItem
*tag
, *tstate
;
64 struct ListData
*data
;
66 data
= INST_DATA(cl
, o
);
67 tstate
= msg
->ops_AttrList
;
69 /* Set to 1 to signal visual changes */
70 while ((tag
= NextTagItem(&tstate
)) != NULL
)
75 case AROSA_List_ConstructHook
:
76 data
->ld_ConstructHook
= (struct Hook
*)tag
->ti_Data
;
79 case AROSA_List_DestructHook
:
80 data
->ld_DestructHook
= (struct Hook
*)tag
->ti_Data
;
84 case AROSA_List_Active
:
85 SetActive((LONG
)tag
->ti_Data
, data
);
91 } /* switch (tag->ti_Tag) */
93 } /* while ((tag = NextTagItem(&tstate)) != NULL) */
95 ReturnPtr("list_set", IPTR
, retval
);
97 IPTR
AROSList__OM_SET(Class
*cl
, Object
*o
,struct opSet
*msg
)
99 IPTR retval
= DoSuperMethodA(cl
, o
, msg
);
100 retval
+= _OM_SET(cl
, o
, msg
);
107 IPTR
AROSList__OM_NEW(Class
*cl
, Object
*o
, struct opSet
*msg
)
109 o
= (Object
*)DoSuperMethodA(cl
, o
, (Msg
)msg
);
113 struct ListData
*data
;
114 APTR
*srcarray
= NULL
;
115 const struct TagItem
*tag
, *tstate
;
117 ULONG puddlesz
= 2008, threshsz
= 1024;
119 D(bug("list, OM_NEW: obj returned from superclass\n"));
120 data
= INST_DATA(cl
, o
);
121 memset(data
, 0, sizeof (struct ListData
));
123 /* Initialize the object's internal lists */
124 NewLEList(data
->ld_EntryTables
);
125 NewLEList(data
->ld_UnusedEntries
);
127 /* Parse for some init only tags */
128 tstate
= msg
->ops_AttrList
;
129 while ((tag
= NextTagItem(&tstate
)) != NULL
)
133 case AROSA_List_SourceArray
:
134 srcarray
= (APTR
*)tag
->ti_Data
;
137 case AROSA_List_PoolPuddleSize
:
138 puddlesz
= (ULONG
)tag
->ti_Data
;
141 case AROSA_List_PoolThreshSize
:
142 threshsz
= (ULONG
)tag
->ti_Data
;
144 case AROSA_List_Pool
:
145 data
->ld_Pool
= (APTR
)tag
->ti_Data
;
148 } /* switch (tag->ti_Tag) */
150 } /* while (more tags in taglist) */
153 /* User supplied source array ? */
154 srcarray
= (APTR
*)GetTagData(AROSA_List_SourceArray
, (IPTR
) NULL
, msg
->ops_AttrList
);
156 /* Allocate a bunch of free listentries */
157 data
->ld_PointerArray
= AllocEntries( (srcarray
!= NULL
)
158 ? CountItems(srcarray
)
165 data
->ld_Pool
= CreatePool(MEMF_ANY
, puddlesz
, threshsz
);
168 D(bug("listclass, OM_NEW: pointerarray = %p, pool = %p\n",
169 data
->ld_PointerArray
, data
->ld_Pool
));
171 if (!data
->ld_PointerArray
|| !data
->ld_Pool
)
173 CoerceMethod(cl
, o
, OM_DISPOSE
);
177 /* As default there is no active entry */
178 data
->ld_Active
= AROSV_List_Active_None
;
180 /* Handle our special tags - overrides defaults. This must be done
181 before the AROSM_List_Insert call, because we must get the ConstructHook and
188 DoMethod(o
, AROSM_List_Insert
, (IPTR
) srcarray
, AROSV_List_Insert_Top
);
193 } /* if (object created) */
198 /*********************
199 ** List::Dispose() **
200 *********************/
202 VOID
AROSList__OM_DISPOSE(Class
*cl
, Object
*o
, Msg msg
)
204 #warning TODO: Call destructhook too
206 struct ListData
*data
;
207 struct ListEntry
*entry
, *next
;
209 data
= INST_DATA(cl
, o
);
211 D(bug("Inside OM_DISPOSE\n"));
212 DoMethod(o
, AROSM_List_Clear
);
214 entry
= data
->ld_EntryTables
;
217 next
= entry
->le_Next
;
222 if (data
->ld_PointerArray
)
223 FreeVec(data
->ld_PointerArray
);
226 DeletePool(data
->ld_Pool
);
228 DoSuperMethodA(cl
, o
, msg
);
235 IPTR
AROSList__OM_GET(Class
*cl
, Object
*o
, struct opGet
*msg
)
238 struct ListData
*data
;
240 data
= INST_DATA(cl
, o
);
242 switch (msg
->opg_AttrID
)
244 case AROSA_List_Entries
:
245 *(msg
->opg_Storage
) = (IPTR
)data
->ld_NumEntries
;
248 case AROSA_List_Active
:
249 *(msg
->opg_Storage
) = (IPTR
)data
->ld_Active
;
253 retval
= DoSuperMethodA(cl
, o
, (Msg
)msg
);
259 /********************
261 ********************/
262 ULONG
AROSList__AROSM_List_Insert(Class
*cl
, Object
*o
, struct AROSP_List_Insert
*msg
)
264 struct ListData
*data
;
266 register ULONG items2insert
;
271 ULONG items_below_insertion
;
274 data
= INST_DATA(cl
, o
);
276 items2insert
= CountItems(msg
->ItemArray
);
279 /* Special value ? */
284 case AROSV_List_Insert_Top
:
287 case AROSV_List_Insert_Bottom
:
288 pos
= data
->ld_NumEntries
;
292 pos
= data
->ld_NumEntries
;
299 else if (pos
> data
->ld_NumEntries
)
301 pos
= data
->ld_NumEntries
;
304 items_below_insertion
= data
->ld_NumEntries
- pos
;
306 /* To little space left ? */
307 if (items2insert
> data
->ld_NumAllocated
- data
->ld_NumEntries
)
309 struct ListEntry
**newptrarray
;
311 newptrarray
= AllocEntries(items2insert
, data
);
315 /* Copy all old entries BEFORE the new ones, into the new array */
316 if (pos
!= AROSV_List_Insert_Top
)
318 CopyMem( data
->ld_PointerArray
,
320 UB(newptrarray
[pos
]) - UB(newptrarray
[0]));
323 /* Now insert the entries themselves */
324 numinserted
= InsertItems(msg
->ItemArray
, newptrarray
, pos
, data
);
326 /* Copy all the entries BELOW the inserted value */
327 if (pos
!= data
->ld_NumEntries
)
329 CopyMem(&(data
->ld_PointerArray
[pos
]),
330 &newptrarray
[pos
+ numinserted
],
331 UB(newptrarray
[items_below_insertion
] ) - UB(newptrarray
[0]));
333 /* Free the old buffer */
334 FreeVec(data
->ld_PointerArray
);
336 data
->ld_PointerArray
= newptrarray
;
342 /* Insert at end of array ? */
343 if (pos
== data
->ld_NumEntries
)
346 numinserted
= InsertItems(msg
->ItemArray
,
347 data
->ld_PointerArray
,
351 D(bug("lins: inserted %d entries at end of list\n", numinserted
));
356 /* Insertion in the middle of the array.
357 We have to move the some items down so we can
358 to get space for inserting the items */
360 register struct ListEntry
**ptr
;
362 ptr
= &(data
->ld_PointerArray
[data
->ld_NumEntries
- 1]);
363 for (i
= items_below_insertion
; i
; i
-- )
365 ptr
[items2insert
] = *ptr
;
369 numinserted
= InsertItems(msg
->ItemArray
, data
->ld_PointerArray
, pos
, data
);
370 if (numinserted
< items2insert
)
373 * Ouch ! Insertion of some (or all) items failed, and we have to move
374 * the below items up again
377 ULONG delta
= items2insert
- numinserted
;
379 ptr
= &(data
->ld_PointerArray
[pos
+ numinserted
/* This is where the items got moved */]);
381 for (i
= items_below_insertion
; i
; i
--)
387 } /* for (number of items to move) */
389 } /* if (not all entries inserted successfully) */
391 } /* if (Insert at end of arry or in middle) */
393 } /* if (Enough entries left for insertion) */
397 /* "Refresh" pos of the active entry */
398 if (pos
<= data
->ld_Active
&& data
->ld_Active
!= AROSV_List_Active_None
)
400 SetActive(data
->ld_Active
+ numinserted
, data
);
403 data
->ld_NumEntries
+= numinserted
;
406 return (numinserted
);
409 /***************************
410 ** List::InsertSingle() **
411 ***************************/
412 IPTR
AROSList__AROSM_List_InsertSingle(Class
*cl
, Object
*o
, struct AROSP_List_InsertSingle
*msg
)
416 struct AROSP_List_Insert insert_msg
;
418 ptrarray
[0] = msg
->Item
;
421 insert_msg
.MethodID
= AROSM_List_Insert
;
422 insert_msg
.ItemArray
= ptrarray
;
423 insert_msg
.Position
= msg
->Position
;
425 return (IPTR
)AROSList__AROSM_List_Insert(cl
, o
, &insert_msg
);
428 /*********************
430 *********************/
431 VOID
AROSList__AROSM_List_Remove(Class
*cl
, Object
*o
, struct AROSP_List_Remove
*msg
)
435 struct ListData
*data
;
438 struct ListEntry
**ptr
;
440 data
= INST_DATA(cl
, o
);
443 lastpos
= data
->ld_NumEntries
- 1;
445 if (pos
< 0) /* Special value ? */
449 case AROSV_List_Remove_First
:
453 case AROSV_List_Remove_Last
:
465 /* Cannot remove a non-existing entry */
470 /* Call destructhook for entry */
471 if (data
->ld_DestructHook
)
473 CallHookPkt(data
->ld_DestructHook
,
475 data
->ld_PointerArray
[pos
]->le_Item
);
477 /* Add item to freelist */
478 AddLEHead(data
->ld_UnusedEntries
, data
->ld_PointerArray
[pos
]);
479 data
->ld_NumEntries
--;
481 /* "Refresh" pos of the active entry */
482 if ( pos
<= data
->ld_Active
483 && data
->ld_Active
!= AROSV_List_Active_None
484 && data
->ld_Active
!= 0)
486 SetActive( ((data
->ld_NumEntries
)
487 ? data
->ld_Active
- 1 : AROSV_List_Active_None
),
491 /* Skip the specialcase where we remove the last entry */
496 ptr
= &(data
->ld_PointerArray
[pos
]);
498 /* We remove a entry in the middle of the array and must move
499 all lower items up to fill the gap */
501 for (i
= lastpos
- pos
; i
; i
--)
510 /********************
512 ********************/
513 VOID
AROSList__AROSM_List_Clear(Class
*cl
, Object
*o
, Msg msg
)
516 struct ListData
*data
= INST_DATA(cl
, o
);
518 D(bug("List::Clear()\n"));
520 for (pos
= 0; pos
< data
->ld_NumEntries
; pos
++)
522 D(bug("\tClearing entry at pos %d\n", pos
));
524 if (data
->ld_DestructHook
)
526 CallHookPkt(data
->ld_DestructHook
,
528 data
->ld_PointerArray
[pos
]->le_Item
);
531 D(bug("Addidng to freeentrylist\n"));
532 /* Add item to freelist */
533 AddLEHead(data
->ld_UnusedEntries
, data
->ld_PointerArray
[pos
]);
536 data
->ld_NumEntries
= 0;
537 /* "Refresh" pos of the active entry */
538 SetActive(AROSV_List_Active_None
, data
);
544 /*********************
546 *********************/
547 VOID
AROSList__AROSM_List_Select(Class
*cl
, Object
*o
, Msg msg
)
549 /* We _could_ put the Select_All stuff together
550 with the singlemode but that would slow down singlemode a little */
552 #define S(msg) ((struct AROSP_List_Select *)msg)
553 struct ListData
*data
= INST_DATA(cl
, o
);
555 if (S(msg
)->Position
!= AROSV_List_Select_All
)
557 struct ListEntry
*le
;
559 le
= data
->ld_PointerArray
[S(msg
)->Position
];
561 switch (S(msg
)->SelType
)
563 case AROSV_List_Select_On
:
564 le
->le_Flags
|= LEFLG_SELECTED
;
567 case AROSV_List_Select_Off
:
568 le
->le_Flags
&= ~LEFLG_SELECTED
;
571 case AROSV_List_Select_Toggle
:
572 le
->le_Flags
^= LEFLG_SELECTED
;
575 case AROSV_List_Select_Ask
:
576 *(S(msg
)->State
) = ((le
->le_Flags
& LEFLG_SELECTED
) != 0);
583 register struct ListEntry
*le
;
585 *(S(msg
)->State
) = 0;
587 for (pos
= 0; pos
< data
->ld_NumEntries
; pos
++)
589 le
= data
->ld_PointerArray
[S(msg
)->Position
];
590 switch (S(msg
)->SelType
)
592 case AROSV_List_Select_On
:
593 le
->le_Flags
|= LEFLG_SELECTED
;
596 case AROSV_List_Select_Off
:
597 le
->le_Flags
&= ~LEFLG_SELECTED
;
600 case AROSV_List_Select_Toggle
:
601 le
->le_Flags
^= LEFLG_SELECTED
;
604 case AROSV_List_Select_Ask
:
605 if (le
->le_Flags
& LEFLG_SELECTED
)
607 *(S(msg
)->State
) += 1;
616 /***************************
617 ** List::NextSelected() **
618 ***************************/
619 VOID
AROSList__AROSM_List_NextSelected(Class
*cl
, Object
*o
, Msg msg
)
622 #define NS(msg) ((struct AROSP_List_NextSelected *)msg)
624 struct ListData
*data
= INST_DATA(cl
, o
);
627 pos
= *(NS(msg
)->Position
);
629 if (pos
== AROSV_List_NextSelected_Start
)
632 for (; pos
< data
->ld_NumEntries
; pos
++)
634 if (data
->ld_PointerArray
[pos
]->le_Flags
& LEFLG_SELECTED
)
636 *(NS(msg
)->Position
) = pos
;
641 *(NS(msg
)->Position
) = AROSV_List_NextSelected_End
;
645 /***********************
646 ** List::GetEntry() **
647 ***********************/
648 VOID
AROSList__AROSM_List_GetEntry(Class
*cl
, Object
*o
, Msg msg
)
651 #define GE(msg) ((struct AROSP_List_GetEntry *)msg)
653 struct ListData
*data
;
655 data
= INST_DATA(cl
, o
);
657 if (GE(msg
)->Position
>= data
->ld_NumEntries
|| GE(msg
)->Position
< 0)
658 *(GE(msg
)->ItemPtr
) = NULL
;
660 *(GE(msg
)->ItemPtr
) = data
->ld_PointerArray
[GE(msg
)->Position
]->le_Item
;