4 * BGUI Tree List View class
6 * (C) Copyright 1999 Manuel Lemos.
7 * (C) Copyright 1996-1999 Nick Christie.
11 * Revision 42.2 2004/06/16 20:16:49 verhaegs
12 * Use METHODPROTO, METHOD_END and REGFUNCPROTOn where needed.
14 * Revision 42.1 2000/05/15 19:29:08 stegerg
15 * replacements for REG macro
17 * Revision 42.0 2000/05/09 22:21:48 mlemos
18 * Bumped to revision 42.0 before handing BGUI to AROS team
20 * Revision 41.11 2000/05/09 20:35:34 mlemos
21 * Bumped to revision 41.11
23 * Revision 1.2 2000/05/09 20:00:32 mlemos
24 * Merged with the branch Manuel_Lemos_fixes.
26 * Revision 1.1.2.3 1999/05/31 01:14:43 mlemos
27 * Fixed bug of trying to access the last clicked entry when was not set.
29 * Revision 1.1.2.2 1999/05/24 23:58:36 mlemos
30 * Fixed bug of attempting to notifying a change in NULL tree node pointer.
32 * Revision 1.1.2.1 1999/02/21 04:07:47 mlemos
33 * Nick Christie sources.
39 /************************************************************************
40 ****************** TREEVIEW CLASS: LISTVIEW HANDLERS ******************
41 ************************************************************************/
44 /************************************************************************
45 ****************************** INCLUDES *******************************
46 ************************************************************************/
48 #include "TreeViewPrivate.h"
51 /************************************************************************
52 ************************** LOCAL DEFINITIONS **************************
53 ************************************************************************/
56 /************************************************************************
57 ************************* EXTERNAL REFERENCES *************************
58 ************************************************************************/
61 * Functions from TVUtil are listed in TVUtil.h
64 /************************************************************************
65 ***************************** PROTOTYPES ******************************
66 ************************************************************************/
68 /************************************************************************
69 ***************************** LOCAL DATA ******************************
70 ************************************************************************/
73 * Default DrawInfo pens
76 LOCAL UWORD DefDriPens
[ 12 ] = { 0, 1, 1, 2, 1, 3, 1, 0, 2, 1, 2, 1 };
79 * Pattern used for ghosting disabled entries
82 //LOCAL UWORD GhostPattern[] = { 0x2222, 0x8888 };
84 /************************************************************************
85 ************************* TV_LVRSRCHANDLER() **************************
86 *************************************************************************
87 * Resource handler for embedded listview. We add TreeNodes to this
88 * listview and we don't want them copied or anything, so this handler
89 * just tells the listview to add the TreeNode ptr itself. When removing
90 * entries, there is similarly nothing special to do.
92 *************************************************************************/
94 //ASM SAVEDS ULONG TV_LVRsrcHandler(REG(a0) struct Hook *hook,
95 // REG(a2) Object *obj, REG(a1) struct lvResource *lvr)
96 ASM SAVEDS
REGFUNC3(ULONG
, TV_LVRsrcHandler
,
97 REGPARAM(A0
, struct Hook
*, hook
),
98 REGPARAM(A2
, Object
*, obj
),
99 REGPARAM(A1
, struct lvResource
*, lvr
))
101 if (lvr
->lvr_Command
== LVRC_MAKE
)
102 return((IPTR
) lvr
->lvr_Entry
);
108 /************************************************************************
109 ************************* TV_LVDISPHANDLER() **************************
110 *************************************************************************
111 * Display handler for embedded listview. The members of the list are
112 * TreeNodes, so the display must take into account their depth in the
113 * hierarchy (represented by indentation), and whether their children
114 * are expanded out (render a boxed plus sign or minus sign to the
115 * left). The last item to render is the treenode's label, this will
116 * need to be passed to the user's custom display hook (if any).
118 * STUB! Doesn't use custom display hook yet.
120 *************************************************************************/
122 //ASM SAVEDS ULONG TV_LVDispHandler(REG(a0) struct Hook *hook,
123 // REG(a2) Object *obj, REG(a1) struct lvRender *lvr)
124 ASM SAVEDS
REGFUNC3(ULONG
, TV_LVDispHandler
,
125 REGPARAM(A0
, struct Hook
*, hook
),
126 REGPARAM(A2
, Object
*, obj
),
127 REGPARAM(A1
, struct lvRender
*, lvr
))
131 struct Rectangle
*rect
;
136 struct TextExtent te
;
145 tv
= (TVData
*) hook
->h_Data
;
146 tn
= (TNPTR
) lvr
->lvr_Entry
;
149 rect
= &lvr
->lvr_Bounds
;
151 depth
= TV_TreeNodeDepth(tn
) - 1;
154 KPrintF("Render 1: Node:%08lx Name:%s L:%ld T:%ld R:%ld B:%ld\n",
155 tn, tn->tn_Entry, rect->MinX, rect->MinY, rect->MaxX, rect->MaxY);
159 * Determine pens to use
162 dripens
= lvr
->lvr_DrawInfo
? lvr
->lvr_DrawInfo
->dri_Pens
: DefDriPens
;
164 switch(lvr
->lvr_State
)
169 imgstate
= IDS_SELECTED
;
172 case LVRS_NORMAL_DISABLED
:
174 bpen
= BACKGROUNDPEN
;
175 imgstate
= IDS_DISABLED
;
179 case LVRS_SELECTED_DISABLED
:
182 imgstate
= IDS_DISABLED
;
186 /* case LVRS_NORMAL: */
189 bpen
= BACKGROUNDPEN
;
190 imgstate
= IDS_NORMAL
;
193 } /* endswitch lvr_State */
195 fpen
= dripens
[fpen
];
196 bpen
= dripens
[bpen
];
199 * Prefill the area with the background pen
204 RectFill(rp
,rect
->MinX
,rect
->MinY
,rect
->MaxX
,rect
->MaxY
);
207 * Leave appropriate indentation based on node's depth in tree,
208 * unless TVA_LeftAlignImage has been set.
211 box
.Left
= rect
->MinX
+ 2;
212 if (!tv
->tv_LeftAlignImage
)
213 box
.Left
+= depth
* tv
->tv_Indentation
;
214 box
.Top
= rect
->MinY
;
215 box
.Width
= rect
->MaxX
- box
.Left
+ 1;
216 box
.Height
= rect
->MaxY
- rect
->MinY
+ 1;
219 * Render the node image for this item, if there's space.
220 * If TVA_NoLeafImage is set, don't draw an image for
224 if (tv
->tv_NoLeafImage
&& !HasChildren(tn
))
227 imgwid
= ((IMGPTR
) tv
->tv_ExpandedImage
)->Width
;
228 imghgt
= ((IMGPTR
) tv
->tv_ExpandedImage
)->Height
;
232 img
= (IMGPTR
) (IsExpanded(tn
) ?
233 tv
->tv_ExpandedImage
: tv
->tv_ContractedImage
);
235 imghgt
= img
->Height
;
238 if (imgwid
<= box
.Width
)
240 if (img
&& (imghgt
<= box
.Height
))
244 y
= box
.Top
+ (box
.Height
- imghgt
) / 2;
245 DrawImageState(rp
,img
,box
.Left
,y
,imgstate
,lvr
->lvr_DrawInfo
);
248 if ( tv
->tv_GoingActive
&& img
&&
249 (tv
->tv_LastClickX
>= box
.Left
) &&
250 (tv
->tv_LastClickX
<= box
.Left
+ imgwid
- 1) &&
251 (tv
->tv_LastClickY
>= box
.Top
) &&
252 (tv
->tv_LastClickY
<= box
.Top
+ box
.Height
- 1)
255 tv
->tv_ImageClicked
= tn
;
258 KPrintF("Render 2: ImageClicked: Node:%08lx Name:%s\n",
264 * If TVA_LeftAlignImage was set, put indentation in now,
268 if (tv
->tv_LeftAlignImage
)
270 box
.Left
+= depth
* tv
->tv_Indentation
;
271 box
.Width
= rect
->MaxX
- box
.Left
+ 1;
275 * Determine if we need to draw connecting lines,
276 * and in what style, from tv_LineStyle. If the
277 * image is left-aligned, we don't draw lines.
280 if ((tv
->tv_LineStyle
!= TVLS_NONE
) && !tv
->tv_LeftAlignImage
)
285 SetAPen(rp
,dripens
[TEXTPEN
]);
288 switch(tv
->tv_LineStyle
)
305 * If entry has children, draw small vertical below image
308 if (IsExpanded(tn
) && HasChildren(tn
))
310 x
= box
.Left
+ (imgwid
/ 2) - 1;
311 y
= box
.Top
+ imghgt
+ (box
.Height
- imghgt
) / 2;
313 Draw(rp
,x
,box
.Top
+ box
.Height
- 1);
317 * If depth > 0, draw horizontal to left of image.
318 * If img is NULL then this was an image-less leaf
319 * node and we should start just to the left of the
320 * label, not the left of the (nonexistent) image.
325 y
= box
.Top
+ (box
.Height
/ 2);
327 Move(rp
,x
+ (img
? 0 : imgwid
),y
);
328 x
-= tv
->tv_Indentation
- (imgwid
/ 2);
332 * If entry has next sibling, draw full height vertical
333 * at lefthand point of horizontal line, otherwise just
334 * draw half-height vertical.
338 Draw(rp
,x
,NextSiblingOf(tn
) ? box
.Top
+ box
.Height
- 1 : y
);
341 * For each further parent with a next sibling,
342 * draw a full height vertical line.
347 while((pn2
= ParentOf(pn
)))
349 x
-= tv
->tv_Indentation
;
351 if (NextSiblingOf(pn
))
354 Draw(rp
,x
,box
.Top
+ box
.Height
- 1);
362 * Reset rastport to solid line pattern
368 box
.Left
+= imgwid
+ rp
->TxWidth
;
369 box
.Width
-= imgwid
+ rp
->TxWidth
;
373 Move(rp
,box
.Left
,box
.Top
+ rp
->Font
->tf_Baseline
);
374 len
= TextFit(rp
,text
,strlen(text
),&te
,NULL
,1,box
.Width
,32767);
382 /************************************************************************
383 ************************* TV_LVCOMPHANDLER() **************************
384 *************************************************************************
385 * Compare handler for embedded listview. Sorts entries by parents
386 * before sorting by individual entry.
388 *************************************************************************/
390 //ASM SAVEDS ULONG TV_LVCompHandler(REG(a0) struct Hook *hook,
391 // REG(a2) Object *obj, REG(a1) struct lvCompare *lvc)
392 ASM SAVEDS
REGFUNC3(ULONG
, TV_LVCompHandler
,
393 REGPARAM(A0
, struct Hook
*, hook
),
394 REGPARAM(A2
, Object
*, obj
),
395 REGPARAM(A1
, struct lvCompare
*, lvc
))
397 struct tvCompare tvc
;
402 tv
= (TVData
*) hook
->h_Data
;
403 tna
= (TNPTR
) lvc
->lvc_EntryA
;
404 tnb
= (TNPTR
) lvc
->lvc_EntryB
;
405 da
= TV_TreeNodeDepth(tna
);
406 db
= TV_TreeNodeDepth(tnb
);
409 { tna
= ParentOf(tna
); da
--; }
412 { tnb
= ParentOf(tnb
); db
--; }
414 tvc
.tvc_EntryA
= tna
->tn_Entry
;
415 tvc
.tvc_EntryB
= tnb
->tn_Entry
;
417 return(CallHookPkt(tv
->tv_CompareHook
,tv
->tv_TreeView
,&tvc
));
421 /************************************************************************
422 ************************ TV_LVNOTIFYHANDLER() *************************
423 *************************************************************************
424 * Notification hook added to embedded listview: called when the currently
425 * selected item in the listview changes. If the user clicked on the
426 * tree image for an entry, and the released the LMB while the mouse
427 * pointer was over that entry, we expand or contract it. Same applies
428 * if the user has just double-clicked on an entry.
430 * This relies on the fact that our TV_GoActive method has determined
431 * the initial position of the mousepointer, and our TV_LVDispHandler
432 * hook has set tv_ImageClicked to point at the clicked entry, if the
433 * user clicked on the tree image, rather than the entry itself.
435 *************************************************************************/
437 //ASM SAVEDS ULONG TV_LVNotifyHandler(REG(a0) struct Hook *hook,
438 // REG(a2) Object *obj, REG(a1) struct opUpdate *opu)
439 ASM SAVEDS
REGFUNC3(ULONG
, TV_LVNotifyHandler
,
440 REGPARAM(A0
, struct Hook
*, hook
),
441 REGPARAM(A2
, Object
*, obj
),
442 REGPARAM(A1
, struct opUpdate
*, opu
))
450 tv
= (TVData
*) hook
->h_Data
;
454 * Find the LISTV_Entry tag in the notification taglist, and verify
455 * that this notification is a final one, not an interim update.
458 if ((tag
= FindTagItem(LISTV_Entry
,opu
->opu_AttrList
)))
460 tn
= (TNPTR
) tag
->ti_Data
;
462 if (!(opu
->opu_Flags
& OPUF_INTERIM
))
465 * User activated gadget with LMB down on a tree image,
466 * and released the LMB with the pointer over that entry?
469 if (tv
->tv_ImageClicked
&& (tn
== tv
->tv_ImageClicked
))
472 * Yes: expand/contract this entry
475 tv
->tv_LastClickTime
[0] = tv
->tv_LastClickTime
[1] = 0;
479 KPrintF("LVNotifyHandler: Image click expand node: %s\n",
480 tv->tv_ImageClicked->tn_Entry);
486 * User double-clicked on entry? And it's not an
487 * image-less leaf node?
490 CurrentTime(&time
[0],&time
[1]);
493 && (tn
== tv
->tv_LastClicked
)
494 && (!tv
->tv_NoLeafImage
|| HasChildren(tn
))
495 && (DoubleClick(tv
->tv_LastClickTime
[0],tv
->tv_LastClickTime
[1],
499 * Yes: expand/contract this entry
502 tv
->tv_LastClickTime
[0] = tv
->tv_LastClickTime
[1] = 0;
506 KPrintF("LVNotifyHandler: Double click expand node: %s\n",
512 tv
->tv_LastClickTime
[0] = time
[0];
513 tv
->tv_LastClickTime
[1] = time
[1];
517 if (tv
->tv_LastClicked
)
518 tv
->tv_LastClicked
->tn_Flags
&= ~TNF_SELECTED
;
520 if (rc
) /* expand/contract entry */
522 rc
= BGUI_DoGadgetMethod(tv
->tv_TreeView
,
523 opu
->opu_GInfo
? opu
->opu_GInfo
->gi_Window
: NULL
,
524 NULL
, TVM_EXPAND
, NULL
, tv
->tv_LastClicked
,
525 TVW_ENTRY
, TVF_TOGGLE
|TVF_USER_ACTION
|TVF_INTERNAL
);
529 if((tv
->tv_LastClicked
= tn
))
531 tn
->tn_Flags
|= TNF_SELECTED
;
534 TV_NotifyAttrChange(tv
->tv_TreeView
,opu
->opu_GInfo
,opu
->opu_Flags
,
535 TVA_Entry
, tn
->tn_Entry
,
536 TVA_Parent
, pn
? pn
->tn_Entry
: NULL
,