Listtree.mcc: use local pointer as instance data gets destroyed in Object DISPOSE
[AROS.git] / workbench / classes / zune / listtree / listtree.c
blobd996323edcb9d18c7c2f66a5bb947e22e1eb2830
1 /*
2 Copyright © 2012-2015, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <proto/intuition.h>
7 #include <proto/utility.h>
8 #include <proto/graphics.h>
9 #include <clib/alib_protos.h>
10 #include <mui/NListtree_mcc.h>
11 #include <mui/NList_mcc.h>
13 #undef TNF_OPEN
14 #undef TNF_LIST
15 #include "Listtree_mcc.h"
16 #include "listtree_private.h"
17 #include "support.h"
19 #include <aros/debug.h>
21 #define MUIA_List_ListArea (MUIB_List | 0x00000003)
23 #define MUIA_List_Prop_Entries (MUIB_MUI | 0x0042a8f5) /* .sg LONG PRIV */
24 #define MUIA_List_Prop_Visible (MUIB_MUI | 0x004273e9) /* .sg LONG PRIV */
25 #define MUIA_List_Prop_First (MUIB_MUI | 0x00429df3) /* .sg LONG PRIV */
27 #define MUIA_List_VertProp_Entries MUIA_List_Prop_Entries /* PRIV */
28 #define MUIA_List_VertProp_Visible MUIA_List_Prop_Visible /* PRIV */
29 #define MUIA_List_VertProp_First MUIA_List_Prop_First /* PRIV */
31 struct ListImage
33 struct MinNode node;
34 Object *obj;
37 #define MADF_SETUP (1<< 28) /* PRIV - zune-specific */
39 /* Relations:
40 * MUIS_Listtree_Treenode -> MUI_NListtree_Treenode via MUIS_Listtree_TreeNodeInt.ref
41 * MUI_NListtree_Treenode -> MUIS_Listtree_Treenode via MUI_NListtree_Treenode.tn_User
43 struct MUIS_Listtree_TreeNodeInt
45 struct MUIS_Listtree_TreeNode base;
46 struct MUI_NListtree_TreeNode *ref;
49 #define SYNC_TREENODE_FLAGS(tn) \
50 if (tn && tn->tn_User) \
51 ((struct MUIS_Listtree_TreeNode *)tn->tn_User)->tn_Flags = tn->tn_Flags;
53 #define SYNC_TREENODE_NAME(tn) \
54 if (tn && tn->tn_User) \
55 ((struct MUIS_Listtree_TreeNode *)tn->tn_User)->tn_Name = tn->tn_Name;
57 static IPTR NotifySimulate_Function(struct Hook *hook, Object *obj, void ** msg)
59 struct opSet setmsg;
60 struct TagItem setti[] = {{0,0},{TAG_DONE, TAG_DONE}};
62 IPTR attr = (IPTR)msg[0];
63 IPTR val = (IPTR)msg[1];
64 struct IClass * cl = hook->h_Data;
66 setmsg.MethodID = OM_SET;
67 setmsg.ops_AttrList = setti;
68 setmsg.ops_GInfo = NULL;
70 switch(attr)
72 case(MUIA_NListtree_Active):
73 setti[0].ti_Tag = MUIA_Listtree_Active;
74 setti[0].ti_Data = val ? (IPTR)((struct MUI_NListtree_TreeNode *)val)->tn_User : 0;
75 break;
76 case(MUIA_NListtree_DoubleClick):
77 setti[0].ti_Tag = MUIA_Listtree_DoubleClick;
78 setti[0].ti_Data = val;
79 break;
80 case(MUIA_NListtree_Quiet):
81 setti[0].ti_Tag = MUIA_Listtree_Quiet;
82 setti[0].ti_Data = val;
83 break;
84 default:
85 bug("[Listtree] NotifySimulate_Function - unhandled attribute %x\n", attr);
88 /* Super method OM_SET call will go to Notify class and trigger notifications */
89 return DoSuperMethodA(cl, obj, (Msg) &setmsg);
92 static IPTR DisplayHook_Proxy(struct Hook *hook, Object *obj, struct MUIP_NListtree_DisplayMessage *msg)
94 struct Hook * displayhook = (struct Hook *)hook->h_Data;
95 APTR tn = NULL;
97 if (!displayhook)
98 return 0;
100 SYNC_TREENODE_FLAGS(msg->TreeNode);
102 tn = msg->TreeNode ? msg->TreeNode->tn_User : NULL;
104 return CallHookPkt(displayhook, msg->Array, tn);
107 static IPTR SortHook_Proxy(struct Hook *hook, Object *obj, struct MUIP_NListtree_CompareMessage *msg)
109 struct Hook * sorthook = (struct Hook *)hook->h_Data;
110 APTR tn1 = NULL, tn2 = NULL;
112 if (!sorthook)
113 return 0;
115 SYNC_TREENODE_FLAGS(msg->TreeNode1);
116 SYNC_TREENODE_FLAGS(msg->TreeNode2);
118 tn1 = msg->TreeNode1 ? msg->TreeNode1->tn_User : NULL;
119 tn2 = msg->TreeNode2 ? msg->TreeNode2->tn_User : NULL;
121 return CallHookPkt(sorthook, tn1, tn2);
124 static IPTR DestructHook_Proxy(struct Hook *hook, Object *obj, struct MUIP_NListtree_DestructMessage *msg)
126 struct Listtree_DATA * data = (struct Listtree_DATA *)hook->h_Data;
127 struct MUIS_Listtree_TreeNode * tn = (struct MUIS_Listtree_TreeNode *)msg->UserData;
128 if (!data)
129 return 0;
131 if (data->destrhook && tn)
132 CallHookPkt(data->destrhook, data->pool, tn->tn_User);
134 FreePooled(data->pool, tn, sizeof(struct MUIS_Listtree_TreeNodeInt));
136 return 0;
139 static IPTR ConstructHook_Proxy(struct Hook *hook, Object *obj, struct MUIP_NListtree_ConstructMessage *msg)
141 struct Listtree_DATA * data = (struct Listtree_DATA *)hook->h_Data;
142 struct MUIS_Listtree_TreeNode * tn = NULL;
143 if(!data)
144 return 0;
146 tn = AllocPooled(data->pool, sizeof(struct MUIS_Listtree_TreeNodeInt));
148 if (tn == NULL)
149 return 0;
151 if (data->constrhook)
152 tn->tn_User = (APTR)CallHookPkt(data->constrhook, data->pool, msg->UserData);
153 else
154 tn->tn_User = msg->UserData;
156 return (IPTR)tn;
159 #define CONV(AATTR, BATTR) \
160 case(AATTR): \
161 convtags[i].ti_Tag = BATTR; \
162 convtags[i++].ti_Data = tag->ti_Data; \
163 break;
165 #define COPY(AATTR) \
166 case(AATTR): \
167 supertags[i].ti_Tag = AATTR; \
168 supertags[i++].ti_Data = tag->ti_Data; \
169 break;
171 #define NOTIFY_FORWARD(AATTR) \
172 DoMethod(data->nlisttree, MUIM_Notify, AATTR, MUIV_EveryTime, \
173 obj, 4, MUIM_CallHook, &data->notifysimulatehook, AATTR, MUIV_TriggerValue);
175 /*** Methods ****************************************************************/
176 Object *Listtree__OM_NEW(struct IClass *cl, Object *obj, struct opSet *msg)
178 struct Listtree_DATA *data = NULL;
179 struct TagItem *tag;
180 struct TagItem *tags;
181 Object *nlisttree = NULL;
182 struct TagItem convtags[20];
183 struct TagItem supertags[20];
184 LONG i;
186 /* Convert tags designated for NListtree */
187 for (i = 0, tags = msg->ops_AttrList; (tag = NextTagItem(&tags)); )
189 switch (tag->ti_Tag)
191 CONV(MUIA_Frame, MUIA_Frame)
192 CONV(MUIA_Listtree_Format, MUIA_NListtree_Format)
193 CONV(MUIA_Listtree_Title, MUIA_NListtree_Title)
194 CONV(MUIA_Listtree_DragDropSort, MUIA_NListtree_DragDropSort)
195 CONV(MUIA_List_Title, MUIA_NList_Title)
196 CONV(MUIA_List_DragSortable, MUIA_NList_DragSortable)
197 CONV(MUIA_List_MinLineHeight, MUIA_NList_MinLineHeight)
200 convtags[i].ti_Tag = TAG_DONE;
202 /* Copy tags designated for super class */
203 for (i = 0, tags = msg->ops_AttrList; (tag = NextTagItem(&tags)); )
205 switch (tag->ti_Tag)
207 COPY(MUIA_ContextMenu) /* ContextMenuBuild/Choice will be called on child classes of Listtree */
210 supertags[i].ti_Tag = TAG_DONE;
212 nlisttree = (Object *) NewObjectA(CL_NListtreeInt->mcc_Class, NULL, convtags);
214 obj = (Object *) DoSuperNewTags(cl, obj, 0,
215 MUIA_List_ListArea, nlisttree,
216 TAG_MORE, (IPTR)supertags,
217 TAG_DONE);
219 if (!obj) return FALSE;
221 data = INST_DATA(cl, obj);
222 data->nlisttree = nlisttree;
223 data->notifysimulatehook.h_Entry = HookEntry;
224 data->notifysimulatehook.h_SubEntry = (HOOKFUNC)NotifySimulate_Function;
225 data->notifysimulatehook.h_Data = cl;
227 data->pool = CreatePool(MEMF_ANY | MEMF_CLEAR, 16 * 1024, 8 * 1024);
229 /* parse initial taglist */
230 for (tags = msg->ops_AttrList; (tag = NextTagItem(&tags)); )
232 switch (tag->ti_Tag)
234 case(MUIA_Listtree_ConstructHook):
235 data->constrhook = (struct Hook *)tag->ti_Data;
236 break;
237 case(MUIA_Listtree_DestructHook):
238 data->destrhook = (struct Hook *)tag->ti_Data;
239 break;
240 case(MUIA_Listtree_DisplayHook):
241 data->displayhook = (struct Hook *)tag->ti_Data;
242 break;
243 case(MUIA_Listtree_SortHook):
244 data->sorthook = (struct Hook *)tag->ti_Data;
245 break;
247 /* Forwarded to NListtree */
248 case(MUIA_List_MinLineHeight):
249 case(MUIA_List_DragSortable):
250 case(MUIA_List_Title):
251 case(MUIA_Listtree_DragDropSort):
252 case(MUIA_Listtree_Format):
253 case(MUIA_Listtree_Title):
254 case(MUIA_Frame):
255 break;
257 /* Forwarded to super class */
258 case(MUIA_ContextMenu):
259 break;
261 default:
262 bug("[Listtree] OM_NEW: unhandled %x\n", tag->ti_Tag);
266 /* Setup connection */
267 set(data->nlisttree, MUIA_NListtreeInt_Listtree, obj);
269 /* Setup root node */
272 * Leave the tn_User of root node as NULL. It is expected that
273 * parent of first level item is returned as NULL in Listtree
277 /* Setup hook proxies */
278 if (data->displayhook)
280 data->displayhookproxy.h_Entry = HookEntry;
281 data->displayhookproxy.h_SubEntry = (HOOKFUNC)DisplayHook_Proxy;
282 data->displayhookproxy.h_Data = data->displayhook;
283 nnset(data->nlisttree, MUIA_NListtree_DisplayHook, &data->displayhookproxy);
285 if (data->sorthook)
287 data->sorthookproxy.h_Entry = HookEntry;
288 data->sorthookproxy.h_SubEntry = (HOOKFUNC)SortHook_Proxy;
289 data->sorthookproxy.h_Data = data->sorthook;
290 nnset(data->nlisttree, MUIA_NListtree_CompareHook, &data->sorthookproxy);
293 /* Construct hook is mandatory to allocate proxy structures */
295 data->constructhookproxy.h_Entry = HookEntry;
296 data->constructhookproxy.h_SubEntry = (HOOKFUNC)ConstructHook_Proxy;
297 data->constructhookproxy.h_Data = data;
298 nnset(data->nlisttree, MUIA_NListtree_ConstructHook, &data->constructhookproxy);
300 /* Destroy hook is mandatory to free proxy structures */
302 data->destructhookproxy.h_Entry = HookEntry;
303 data->destructhookproxy.h_SubEntry = (HOOKFUNC)DestructHook_Proxy;
304 data->destructhookproxy.h_Data = data;
305 nnset(data->nlisttree, MUIA_NListtree_DestructHook, &data->destructhookproxy);
308 /* Setup notification forwarding */
309 NOTIFY_FORWARD(MUIA_NListtree_Active)
310 NOTIFY_FORWARD(MUIA_NListtree_DoubleClick)
311 NOTIFY_FORWARD(MUIA_NListtree_Quiet)
313 return obj;
316 IPTR Listtree__OM_DISPOSE(struct IClass *cl, Object *obj, Msg msg)
318 struct Listtree_DATA *data = INST_DATA(cl, obj);
320 APTR pool = data->pool;
321 IPTR result = DoSuperMethodA(cl, obj, msg);
323 /* Destruct hook called by dispose on NListree will need the pool,
324 * so destroy it only after super dispose is called */
325 DeletePool(pool);
327 return result;
330 #define FORWARDSET(AATTR, BATTR) \
331 case(AATTR): \
332 set(data->nlisttree, BATTR, tag->ti_Data); \
333 break;
335 IPTR Listtree__OM_SET(struct IClass *cl, Object *obj, struct opSet *msg)
337 struct Listtree_DATA *data = INST_DATA(cl, obj);
338 struct TagItem *tstate = msg->ops_AttrList;
339 struct TagItem *tag;
341 if (!data->nlisttree)
342 return DoSuperMethodA(cl, obj, (Msg) msg);
344 while ((tag = NextTagItem(&tstate)) != NULL)
346 switch (tag->ti_Tag)
348 FORWARDSET(MUIA_Listtree_Quiet, MUIA_NListtree_Quiet)
349 FORWARDSET(MUIA_List_Active, MUIA_NList_Active)
350 FORWARDSET(MUIA_List_Prop_First, MUIA_NList_Prop_First)
351 FORWARDSET(MUIA_List_Prop_Visible, MUIA_NList_Prop_Visible)
353 case(MUIA_Listtree_Active):
354 set(data->nlisttree, MUIA_NListtree_Active,
355 ((struct MUIS_Listtree_TreeNodeInt *)tag->ti_Data)->ref);
356 break;
358 /* Setting MUIA_List_First causes weird behaviour of scroll bar */
359 case(MUIA_List_First):
360 /* set(data->nlisttree, MUIA_NList_First, tag->ti_Data); */ /* Don't set directly */
361 tag->ti_Tag = TAG_IGNORE; /* Don't set via forward via Group(List)->NListtree */
362 break;
365 case MUIA_Listtree_DoubleClick:
366 case MUIA_Listview_SelectChange:
367 case MUIA_Prop_First:
368 case MUIA_Prop_DoSmooth:
369 case MUIA_NoNotify:
370 case MUIA_Prop_Entries:
371 case MUIA_Prop_Visible:
372 case MUIA_Prop_DeltaFactor:
373 case MUIA_Timer:
374 case MUIA_Selected:
375 case MUIA_Pressed:
376 break;
378 default:
379 bug("[Listtree] OM_SET: passing to parent class %x\n", tag->ti_Tag);
384 return DoSuperMethodA(cl, obj, (Msg) msg);
387 #define FORWARDGET(AATTR, BATTR) \
388 case(AATTR): \
389 *(msg->opg_Storage) = XGET(data->nlisttree, BATTR); \
390 return TRUE;
392 IPTR Listtree__OM_GET(struct IClass *cl, Object *obj, struct opGet *msg)
394 struct Listtree_DATA *data = INST_DATA(cl, obj);
396 if (!data->nlisttree)
397 return FALSE;
399 switch (msg->opg_AttrID)
401 FORWARDGET(MUIA_Frame, MUIA_Frame)
402 FORWARDGET(MUIA_Listtree_DoubleClick, MUIA_NListtree_DoubleClick)
403 FORWARDGET(MUIA_List_Active, MUIA_NList_Active)
404 FORWARDGET(MUIA_Listtree_Active, MUIA_NListtree_Active)
405 FORWARDGET(MUIA_Listtree_Quiet, MUIA_NListtree_Quiet)
406 FORWARDGET(MUIA_List_Visible, MUIA_NList_Visible)
407 FORWARDGET(MUIA_List_VertProp_First, MUIA_NList_Prop_First)
408 FORWARDGET(MUIA_List_VertProp_Entries, MUIA_NList_Prop_Entries)
409 FORWARDGET(MUIA_List_VertProp_Visible, MUIA_NList_Prop_Visible)
411 case MUIA_Disabled:
412 case MUIA_Parent:
413 case MUIA_Group_ChildList:
414 case MUIA_Prop_First:
415 case MUIA_Prop_DoSmooth:
416 case MUIA_Listview_List:
417 case MUIA_Virtgroup_Left:
418 case MUIA_Virtgroup_Top:
419 case 0x9d510020 /*MUIA_NListview_NList*/:
420 case MUIA_Listview_DoubleClick:
421 case MUIA_Listview_SelectChange:
422 case MUIA_Timer:
423 case MUIA_Selected:
424 break;
426 default:
427 bug("[Listtree] OM_GET: passing to parent class %x\n", msg->opg_AttrID);
430 return DoSuperMethodA(cl, obj, (Msg) msg);
433 IPTR Listtree__MUIM_Listtree_Insert(struct IClass *cl, Object *obj, struct MUIP_Listtree_Insert *msg)
435 struct Listtree_DATA *data = INST_DATA(cl, obj);
436 struct MUI_NListtree_TreeNode * ln = NULL, * pn = NULL, * created = NULL;
438 switch((IPTR)msg->ListNode)
440 case(MUIV_Listtree_Insert_ListNode_Root):
441 case(MUIV_Listtree_Insert_ListNode_Active):
442 ln = msg->ListNode;
443 break;
444 default:
445 ln = ((struct MUIS_Listtree_TreeNodeInt *)msg->ListNode)->ref;
448 switch((IPTR)msg->PrevNode)
450 case(MUIV_Listtree_Insert_PrevNode_Head):
451 case(MUIV_Listtree_Insert_PrevNode_Tail):
452 case(MUIV_Listtree_Insert_PrevNode_Active):
453 case(MUIV_Listtree_Insert_PrevNode_Sorted):
454 pn = msg->PrevNode;
455 break;
456 default:
457 pn = ((struct MUIS_Listtree_TreeNodeInt *)msg->PrevNode)->ref;
460 created = (struct MUI_NListtree_TreeNode *)DoMethod(data->nlisttree,
461 MUIM_NListtree_Insert, msg->Name, msg->User, ln, pn, msg->Flags);
463 if (created)
465 SYNC_TREENODE_FLAGS(created);
466 SYNC_TREENODE_NAME(created);
467 ((struct MUIS_Listtree_TreeNodeInt *)created->tn_User)->ref = created;
468 return (IPTR)created->tn_User;
470 else
471 return (IPTR)NULL;
474 IPTR Listtree__MUIM_Listtree_GetEntry(struct IClass *cl, Object *obj, struct MUIP_Listtree_GetEntry *msg)
476 struct Listtree_DATA *data = INST_DATA(cl, obj);
477 struct MUI_NListtree_TreeNode * tn = NULL, * found = NULL;
479 switch ((IPTR)msg->Node)
481 case(MUIV_Listtree_GetEntry_ListNode_Root):
482 case(MUIV_Listtree_GetEntry_ListNode_Active):
483 tn = msg->Node;
484 break;
485 default:
486 tn = ((struct MUIS_Listtree_TreeNodeInt *)msg->Node)->ref;
489 found = (struct MUI_NListtree_TreeNode *) DoMethod(data->nlisttree,
490 MUIM_NListtree_GetEntry, tn, msg->Position, msg->Flags);
492 if (found)
494 SYNC_TREENODE_FLAGS(found);
495 return (IPTR)found->tn_User;
497 else
498 return (IPTR)NULL;
501 IPTR Listtree__MUIM_Listtree_Remove(struct IClass *cl, Object *obj, struct MUIP_Listtree_Remove *msg)
503 struct Listtree_DATA *data = INST_DATA(cl, obj);
504 struct MUI_NListtree_TreeNode * tn = NULL, * ln = NULL;
506 switch((IPTR)msg->ListNode)
508 case(MUIV_Listtree_Remove_ListNode_Root):
509 case(MUIV_Listtree_Remove_ListNode_Active):
510 ln = msg->ListNode;
511 break;
512 default:
513 ln = ((struct MUIS_Listtree_TreeNodeInt *)msg->ListNode)->ref;
516 switch((IPTR)msg->TreeNode)
518 case(MUIV_Listtree_Remove_TreeNode_Head):
519 case(MUIV_Listtree_Remove_TreeNode_Tail):
520 case(MUIV_Listtree_Remove_TreeNode_Active):
521 case(MUIV_Listtree_Remove_TreeNode_All):
522 tn = msg->TreeNode;
523 break;
524 default:
525 tn = ((struct MUIS_Listtree_TreeNodeInt *)msg->TreeNode)->ref;
528 /* Deallocating of MUIS_Listtree_TreeNode is happening in the DestructHook */
529 return DoMethod(data->nlisttree, MUIM_NListtree_Remove, ln, tn, msg->Flags);
533 IPTR Listtree__MUIM_List_TestPos(struct IClass *cl, Object *obj, struct MUIP_List_TestPos *msg)
535 struct Listtree_DATA *data = INST_DATA(cl, obj);
537 struct MUI_NList_TestPos_Result res;
538 if (DoMethod(data->nlisttree, MUIM_List_TestPos, msg->x, msg->y, &res))
540 msg->res->entry = res.entry;
541 msg->res->column = res.column;
542 msg->res->flags = res.flags;
543 msg->res->xoffset = res.xoffset;
544 msg->res->yoffset = res.yoffset;
545 return TRUE;
548 return FALSE;
551 IPTR Listtree__MUIM_Listtree_TestPos(struct IClass *cl, Object *obj, struct MUIP_Listtree_TestPos *msg)
553 struct Listtree_DATA *data = INST_DATA(cl, obj);
555 struct MUI_NListtree_TestPos_Result res;
556 struct MUIS_Listtree_TestPos_Result * _ret = (struct MUIS_Listtree_TestPos_Result *)msg->Result;
558 _ret->tpr_TreeNode = NULL;
560 DoMethod(data->nlisttree, MUIM_NListtree_TestPos, msg->X, msg->Y, &res);
562 _ret->tpr_Flags = res.tpr_Type;
563 _ret->tpr_ListEntry = res.tpr_ListEntry;
564 _ret->tpr_ListFlags = res.tpr_ListFlags;
566 if (res.tpr_TreeNode != NULL)
568 SYNC_TREENODE_FLAGS(res.tpr_TreeNode);
569 _ret->tpr_TreeNode = res.tpr_TreeNode->tn_User;
570 return TRUE;
573 return FALSE;
576 IPTR Listtree__MUIM_Listtree_GetNr(struct IClass *cl, Object *obj, struct MUIP_Listtree_GetNr *msg)
578 struct Listtree_DATA *data = INST_DATA(cl, obj);
579 struct MUI_NListtree_TreeNode * tn = NULL;
581 switch((IPTR)msg->TreeNode)
583 case(MUIV_Listtree_GetNr_TreeNode_Active):
584 tn = msg->TreeNode;
585 break;
586 default:
587 tn = ((struct MUIS_Listtree_TreeNodeInt *)msg->TreeNode)->ref;
590 return DoMethod(data->nlisttree, MUIM_NListtree_GetNr, tn, msg->Flags);
593 IPTR Listtree__MUIM_Listtree_Rename(struct IClass *cl, Object *obj, struct MUIP_Listtree_Rename *msg)
595 struct Listtree_DATA *data = INST_DATA(cl, obj);
596 struct MUI_NListtree_TreeNode * tn = NULL, * renamed = NULL;
598 switch((IPTR)msg->TreeNode)
600 case(MUIV_Listtree_Rename_TreeNode_Active):
601 tn = msg->TreeNode;
602 break;
603 default:
604 tn = ((struct MUIS_Listtree_TreeNodeInt *)msg->TreeNode)->ref;
607 renamed = (struct MUI_NListtree_TreeNode *)DoMethod(data->nlisttree,
608 MUIM_NListtree_Rename, tn, msg->NewName, msg->Flags);
610 if (renamed)
612 ((struct MUIS_Listtree_TreeNode *)renamed->tn_User)->tn_Name = renamed->tn_Name;
613 return (IPTR)renamed->tn_User;
615 else
616 return (IPTR)NULL;
619 IPTR Listtree__MUIM_List_Redraw(struct IClass *cl, Object *obj, struct MUIP_List_Redraw *msg)
621 struct Listtree_DATA *data = INST_DATA(cl, obj);
622 struct MUI_NListtree_TreeNode * entry = msg->entry ?
623 ((struct MUIS_Listtree_TreeNodeInt *)msg->entry)->ref : NULL;
625 switch(msg->pos)
627 case(MUIV_List_Redraw_Entry):
628 return DoMethod(data->nlisttree, MUIM_NList_RedrawEntry, entry);
629 default:
630 return DoMethod(data->nlisttree, MUIM_NList_Redraw, msg->pos);
634 IPTR Listtree__MUIM_Listtree_Open(struct IClass *cl, Object *obj, struct MUIP_Listtree_Open *msg)
636 struct Listtree_DATA *data = INST_DATA(cl, obj);
637 struct MUI_NListtree_TreeNode * tn = NULL, * ln = NULL;
639 switch((IPTR)msg->ListNode)
641 case(MUIV_Listtree_Open_ListNode_Root):
642 case(MUIV_Listtree_Open_ListNode_Parent):
643 case(MUIV_Listtree_Open_ListNode_Active):
644 ln = msg->ListNode;
645 break;
646 default:
647 ln = ((struct MUIS_Listtree_TreeNodeInt *)msg->ListNode)->ref;
650 switch((IPTR)msg->TreeNode)
652 case(MUIV_Listtree_Open_TreeNode_Head):
653 case(MUIV_Listtree_Open_TreeNode_Tail):
654 case(MUIV_Listtree_Open_TreeNode_Active):
655 case(MUIV_Listtree_Open_TreeNode_All):
656 tn = msg->TreeNode;
657 break;
658 default:
659 tn = ((struct MUIS_Listtree_TreeNodeInt *)msg->TreeNode)->ref;
662 return DoMethod(data->nlisttree, MUIM_NListtree_Open, ln, tn, msg->Flags);
665 IPTR Listtree__MUIM_Listtree_FindName(struct IClass *cl, Object *obj, struct MUIP_Listtree_FindName *msg)
667 struct Listtree_DATA *data = INST_DATA(cl, obj);
668 struct MUI_NListtree_TreeNode * ln = NULL, * found = NULL;
670 switch((IPTR)msg->ListNode)
672 case(MUIV_Listtree_FindName_ListNode_Root):
673 case(MUIV_Listtree_FindName_ListNode_Active):
674 ln = msg->ListNode;
675 break;
676 default:
677 ln = ((struct MUIS_Listtree_TreeNodeInt *)msg->ListNode)->ref;
680 found = (struct MUI_NListtree_TreeNode *) DoMethod(data->nlisttree, MUIM_NListtree_FindName,
681 ln, msg->Name, msg->Flags);
683 if (found)
684 return (IPTR)found->tn_User;
685 else
686 return (IPTR)NULL;
689 IPTR DoSetupMethod(Object * obj, struct MUI_RenderInfo * info)
691 /* MUI set the correct render info *before* it calls MUIM_Setup so please
692 * only use this function instead of DoMethodA() */
693 muiRenderInfo(obj) = info;
694 return DoMethod(obj, MUIM_Setup, (IPTR) info);
697 IPTR Listtree__MUIM_List_CreateImage(struct IClass *cl, Object *obj, struct MUIP_List_CreateImage *msg)
699 struct Listtree_DATA *data = INST_DATA(cl, obj);
701 if (!(_flags(obj) & MADF_SETUP))
702 return 0;
704 IPTR _ret = DoMethod(data->nlisttree, MUIM_NList_CreateImage, msg->obj, msg->flags);
706 /* There is a use case where an image object created in a Listtree can be passed as O[address]
707 * in the text in the display callback of List. Since Listtree just wraps around NListtree and the
708 * return structures from List_CreateImage and NList_CreateImage are different, this would normally
709 * not work. Luckily, List needs only the msg->obj and it is at the same offset in ListImage and
710 * in structure returned by NList. The case will work as long as this is met.
712 struct ListImage * li = (struct ListImage *)_ret;
713 if (li->obj != msg->obj)
714 bug("[Listtree] CreateImage condition BROKEN, see comment in code!\n");
716 /* Setup the msg->obj as the List is doing */
717 DoMethod(li->obj, MUIM_ConnectParent, (IPTR) obj);
718 DoSetupMethod(li->obj, muiRenderInfo(obj));
720 return _ret;
723 IPTR Listtree__MUIM_List_DeleteImage(struct IClass *cl, Object *obj, struct MUIP_List_DeleteImage *msg)
725 struct Listtree_DATA *data = INST_DATA(cl, obj);
726 struct ListImage * li = (struct ListImage *)msg->listimg;
728 if (!li)
729 return 0;
731 /* DoMethod(li->obj, MUIM_Cleanup); // Called in MUIM_NList_DeleteImage */
732 DoMethod(li->obj, MUIM_DisconnectParent);
733 return DoMethod(data->nlisttree, MUIM_NList_DeleteImage, msg->listimg);
736 IPTR Listtree__MUIM_Listtree_Close(struct IClass *cl, Object *obj, struct MUIP_Listtree_Close *msg)
738 struct Listtree_DATA *data = INST_DATA(cl, obj);
739 struct MUI_NListtree_TreeNode * tn = NULL, * ln = NULL;
741 switch((IPTR)msg->ListNode)
743 case(MUIV_Listtree_Close_ListNode_Root):
744 case(MUIV_Listtree_Close_ListNode_Parent):
745 case(MUIV_Listtree_Close_ListNode_Active):
746 ln = msg->ListNode;
747 break;
748 default:
749 ln = ((struct MUIS_Listtree_TreeNodeInt *)msg->ListNode)->ref;
752 switch((IPTR)msg->TreeNode)
754 case(MUIV_Listtree_Close_TreeNode_Head):
755 case(MUIV_Listtree_Close_TreeNode_Tail):
756 case(MUIV_Listtree_Close_TreeNode_Active):
757 case(MUIV_Listtree_Close_TreeNode_All):
758 tn = msg->TreeNode;
759 break;
760 default:
761 tn = ((struct MUIS_Listtree_TreeNodeInt *)msg->TreeNode)->ref;
764 return DoMethod(data->nlisttree, MUIM_NListtree_Close, ln, tn, msg->Flags);
767 #define FORWARDNLISTTREEMETHOD(methodname) \
768 IPTR Listtree__##methodname(struct IClass *cl, Object *obj, Msg msg) \
770 struct Listtree_DATA *data = INST_DATA(cl, obj); \
771 return DoMethodA(data->nlisttree, msg); \
774 FORWARDNLISTTREEMETHOD(MUIM_CreateDragImage)
775 FORWARDNLISTTREEMETHOD(MUIM_DeleteDragImage)
777 IPTR Listtree__MUIM_Notify(struct IClass *cl, Object *obj, struct MUIP_Notify *msg)
779 struct Listtree_DATA *data = INST_DATA(cl, obj);
781 /* NList expects this notification to be set and uses its content */
782 if (msg->TrigAttr == MUIA_List_Prop_First)
783 DoMethodA(data->nlisttree, msg);
785 if (msg->TrigAttr == MUIA_List_First)
786 bug("Listtree.mcc: notifications on MUIA_List_First are not fired!\n");
788 return DoSuperMethodA(cl, obj, msg);
791 #define METHODSTUB(methodname) \
792 IPTR Listtree__##methodname(struct IClass *cl, Object *obj, Msg msg) \
794 bug("[Listtree] Usupported : %s\n", #methodname); \
795 return (IPTR)FALSE; \
798 /* SetDropMark has no counterpart in NListtree and no documentation */
799 METHODSTUB(MUIM_Listtree_SetDropMark)