1 //========================================================================
5 // Copyright 2002-2003 Glyph & Cog, LLC
7 //========================================================================
11 #include "XPDFTreeP.h"
13 //------------------------------------------------------------------------
15 #define xpdfTreeIndent 16
17 //------------------------------------------------------------------------
19 struct _XPDFTreeEntry
{
21 XPDFTreeEntry
*children
;
25 //------------------------------------------------------------------------
27 static void classPartInitialize(WidgetClass widgetClass
);
28 static void initialize(Widget requestWidget
, Widget newWidget
,
29 ArgList args
, Cardinal
*numArgs
);
30 static void destroy(Widget widget
);
31 static void destroySubtree(XPDFTreeEntry
*e
);
32 static void resize(Widget widget
);
33 static void redisplay(Widget widget
, XEvent
*event
, Region region
);
34 static void redisplaySubtree(XPDFTreeWidget w
, XPDFTreeEntry
*e
,
35 XEvent
*event
, Region region
);
36 static void drawExpandedIcon(XPDFTreeWidget w
, Position x
, Position y
);
37 static void drawCollapsedIcon(XPDFTreeWidget w
, Position x
, Position y
);
38 static Boolean
setValues(Widget oldWidget
, Widget requestWidget
,
39 Widget newWidget
, ArgList args
, Cardinal
*numArgs
);
40 static void setValuesAlmost(Widget oldWidget
, Widget newWidget
,
41 XtWidgetGeometry
*request
,
42 XtWidgetGeometry
*reply
);
43 static XtGeometryResult
queryGeometry(Widget widget
,
44 XtWidgetGeometry
*request
,
45 XtWidgetGeometry
*reply
);
46 static XtGeometryResult
geometryManager(Widget widget
,
47 XtWidgetGeometry
*request
,
48 XtWidgetGeometry
*reply
);
49 static void changeManaged(Widget widget
);
50 static void initConstraint(Widget requestWidget
, Widget newWidget
,
51 ArgList args
, Cardinal
*numArgs
);
52 static void destroyConstraint(Widget widget
);
53 static void deleteSubtree(Widget widget
);
54 static Boolean
constraintSetValues(Widget oldWidget
, Widget requestWidget
,
56 ArgList args
, Cardinal
*numArgs
);
57 static void insertChildOnList(XPDFTreeEntry
*e
, XPDFTreeEntry
**listHead
);
58 static void deleteChildFromList(XPDFTreeEntry
*e
, XPDFTreeEntry
**listHead
);
59 static void createGC(Widget widget
);
60 static void destroyGC(Widget widget
);
61 static void layout(Widget widget
, Widget instigator
);
62 static int layoutSubtree(XPDFTreeWidget w
, Widget instigator
,
63 XPDFTreeEntry
*e
, Position x
, Position y
,
65 static void calcSize(Widget widget
, Widget instigator
,
66 Dimension
*totalWidth
,
67 Dimension
*totalHeight
);
68 static void calcSubtreeSize(XPDFTreeWidget w
, Widget instigator
,
70 Dimension
*width
, Dimension
*height
);
71 static Boolean
needRelayout(Widget oldWidget
, Widget newWidget
);
72 static void click(Widget widget
, XEvent
*event
,
73 String
*params
, Cardinal
*numParams
);
74 static Boolean
findPosition(XPDFTreeWidget w
, int x
, int y
,
75 XPDFTreeEntry
**e
, Boolean
*onExpandIcon
);
76 static Boolean
findPositionInSubtree(XPDFTreeWidget w
, int x
, int y
,
78 Boolean
*onExpandIcon
);
80 //------------------------------------------------------------------------
82 static XtResource resources
[] = {
83 { XmNmarginWidth
, XmCMarginWidth
, XmRHorizontalDimension
,
84 sizeof(Dimension
), XtOffsetOf(XPDFTreeRec
, tree
.marginWidth
),
85 XmRImmediate
, (XtPointer
)0 },
86 { XmNmarginHeight
, XmCMarginHeight
, XmRVerticalDimension
,
87 sizeof(Dimension
), XtOffsetOf(XPDFTreeRec
, tree
.marginHeight
),
88 XmRImmediate
, (XtPointer
)0 },
89 { XPDFNselectionCallback
, XmCCallback
, XmRCallback
,
90 sizeof(XtCallbackList
), XtOffsetOf(XPDFTreeRec
, tree
.selectCallback
),
91 XmRImmediate
, (XtPointer
)NULL
}
94 static XmSyntheticResource synResources
[] = {
95 { XmNmarginWidth
, sizeof(Dimension
),
96 XtOffsetOf(XPDFTreeRec
, tree
.marginWidth
),
98 XmeFromHorizontalPixels
, XmeToHorizontalPixels
100 _XmFromHorizontalPixels
, _XmToHorizontalPixels
103 { XmNmarginHeight
, sizeof(Dimension
),
104 XtOffsetOf(XPDFTreeRec
, tree
.marginHeight
),
106 XmeFromVerticalPixels
, XmeToVerticalPixels
108 _XmFromVerticalPixels
, _XmToVerticalPixels
113 static XtResource constraints
[] = {
114 { XPDFNentryParent
, XPDFCentryParent
, XmRWidget
,
115 sizeof(Widget
), XtOffsetOf(XPDFTreeConstraintRec
, tree
.entryParent
),
116 XmRImmediate
, (XtPointer
)NULL
},
117 { XPDFNentryExpanded
, XPDFCentryExpanded
, XmRBoolean
,
118 sizeof(Boolean
), XtOffsetOf(XPDFTreeConstraintRec
, tree
.entryExpanded
),
119 XmRImmediate
, (XtPointer
)False
},
120 { XPDFNentryPosition
, XPDFCentryPosition
, XmRInt
,
121 sizeof(int), XtOffsetOf(XPDFTreeConstraintRec
, tree
.entryPosition
),
122 XmRImmediate
, (XtPointer
)0 }
125 static char defaultTranslations
[] =
126 "<Btn1Down>: XPDFTreeClick()";
128 static XtActionsRec actions
[] = {
129 { "XPDFTreeClick", click
}
132 externaldef(xpdftreeclassrec
) XPDFTreeClassRec xpdfTreeClassRec
= {
134 (WidgetClass
)&xmManagerClassRec
, // superclass
135 "XPDFTree", // class_name
136 sizeof(XPDFTreeRec
), // widget_size
137 NULL
, // class_initialize
138 &classPartInitialize
, // class_part_initialize
139 FALSE
, // class_inited
140 &initialize
, // initialize
141 NULL
, // initialize_hook
142 XtInheritRealize
, // realize
144 XtNumber(actions
), // num_actions
145 resources
, // resources
146 XtNumber(resources
), // num_resources
147 NULLQUARK
, // xrm_class
148 TRUE
, // compress_motion
149 XtExposeCompressMaximal
, // compress_exposure
150 TRUE
, // compress_enterleave
151 FALSE
, // visible_interest
154 &redisplay
, // expose
155 &setValues
, // set_values
156 NULL
, // set_values_hook
157 &setValuesAlmost
, // set_values_almost
158 NULL
, // get_values_hook
159 NULL
, // accept_focus
160 XtVersion
, // version
161 NULL
, // callback_private
162 defaultTranslations
, // tm_table
163 &queryGeometry
, // query_geometry
164 NULL
, // display_accelerator
168 &geometryManager
, // geometry_manager
169 &changeManaged
, // change_managed
170 XtInheritInsertChild
, // insert_child
171 XtInheritDeleteChild
, // delete_child
175 constraints
, // constraint_resources
176 XtNumber(constraints
), // constraint_num_resources
177 sizeof(XPDFTreeConstraintRec
), // constraint_size
178 &initConstraint
, // constraint_initialize
179 &destroyConstraint
, // constraint_destroy
180 &constraintSetValues
, // constraint_set_values
184 XtInheritTranslations
, // translations
186 synResources
, // syn_resources
187 XtNumber(synResources
), // num_syn_resources
189 NULL
, // syn_resources
190 0, // num_syn_resources
192 NULL
, // syn_constraint_resources
193 0, // num_syn_constraint_res's
194 XmInheritParentProcess
, // parent_process
198 &createGC
, // createGC
199 &destroyGC
, // destroyGC
201 &calcSize
, // calcSize
202 &needRelayout
, // needRelayout
207 externaldef(xpdftreewidgetclass
) WidgetClass xpdfTreeWidgetClass
=
208 (WidgetClass
)&xpdfTreeClassRec
;
210 //------------------------------------------------------------------------
212 static void classPartInitialize(WidgetClass widgetCls
) {
213 XPDFTreeWidgetClass wc
= (XPDFTreeWidgetClass
)widgetCls
;
214 XPDFTreeWidgetClass sc
= (XPDFTreeWidgetClass
)wc
->coreClass
.superclass
;
216 // method inheritance
217 if (wc
->treeClass
.createGC
== XPDFInheritCreateGC
) {
218 wc
->treeClass
.createGC
= sc
->treeClass
.createGC
;
220 if (wc
->treeClass
.destroyGC
== XPDFInheritDestroyGC
) {
221 wc
->treeClass
.destroyGC
= sc
->treeClass
.destroyGC
;
223 if (wc
->treeClass
.layout
== XPDFInheritLayout
) {
224 wc
->treeClass
.layout
= sc
->treeClass
.layout
;
226 if (wc
->treeClass
.calcSize
== XPDFInheritCalcSize
) {
227 wc
->treeClass
.calcSize
= sc
->treeClass
.calcSize
;
229 if (wc
->treeClass
.needRelayout
== XPDFInheritNeedRelayout
) {
230 wc
->treeClass
.needRelayout
= sc
->treeClass
.needRelayout
;
234 static void initialize(Widget requestWidget
, Widget newWidget
,
235 ArgList args
, Cardinal
*numArgs
) {
236 XPDFTreeWidget nw
= (XPDFTreeWidget
)newWidget
;
237 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(newWidget
);
239 nw
->tree
.root
= NULL
;
240 nw
->tree
.redrawY
= -1;
241 if (cls
->treeClass
.createGC
) {
242 (*cls
->treeClass
.createGC
)(newWidget
);
248 static void destroy(Widget widget
) {
249 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
250 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(widget
);
253 destroySubtree(w
->tree
.root
);
256 if (cls
->treeClass
.destroyGC
) {
257 (*cls
->treeClass
.destroyGC
)(widget
);
263 static void destroySubtree(XPDFTreeEntry
*e
) {
265 destroySubtree(e
->children
);
268 destroySubtree(e
->next
);
272 static void resize(Widget widget
) {
273 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(widget
);
275 if (cls
->treeClass
.layout
) {
276 (*cls
->treeClass
.layout
)(widget
, NULL
);
278 layout(widget
, NULL
);
282 static void redisplay(Widget widget
, XEvent
*event
, Region region
) {
283 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
286 if (w
->tree
.redrawY
>= 0) {
287 XClearArea(XtDisplay((Widget
)w
), XtWindow((Widget
)w
),
288 0, w
->tree
.redrawY
, w
->core
.width
, w
->core
.height
, False
);
289 w
->tree
.redrawY
= -1;
291 for (e
= w
->tree
.root
; e
; e
= e
->next
) {
292 redisplaySubtree(w
, e
, event
, region
);
296 static void redisplaySubtree(XPDFTreeWidget w
, XPDFTreeEntry
*e
,
297 XEvent
*event
, Region region
) {
298 XPDFTreeConstraint c
;
300 XPDFTreeEntry
*child
;
302 (*XtClass(e
->widget
)->core_class
.expose
)(e
->widget
, event
, region
);
303 c
= XPDFTreeCPart(e
->widget
);
304 x
= e
->widget
->core
.x
;
305 y
= e
->widget
->core
.y
+ e
->widget
->core
.height
/ 2;
307 if (c
->entryExpanded
) {
308 drawExpandedIcon(w
, x
- 8, y
);
309 y2
= y
; // make gcc happy
310 for (child
= e
->children
; child
; child
= child
->next
) {
311 y2
= child
->widget
->core
.y
+ child
->widget
->core
.height
/ 2;
312 XDrawLine(XtDisplay((Widget
)w
), XtWindow((Widget
)w
), w
->tree
.dottedGC
,
313 x
- 8, y2
, x
+ 6, y2
);
314 redisplaySubtree(w
, child
, event
, region
);
316 XDrawLine(XtDisplay((Widget
)w
), XtWindow((Widget
)w
), w
->tree
.dottedGC
,
317 x
- 8, y
+ 2, x
- 8, y2
);
319 drawCollapsedIcon(w
, x
- 8, y
);
324 static void drawExpandedIcon(XPDFTreeWidget w
, Position x
, Position y
) {
327 pts
[0].x
= x
- 4; pts
[0].y
= y
- 2;
328 pts
[1].x
= x
+ 4; pts
[1].y
= y
- 2;
329 pts
[2].x
= x
; pts
[2].y
= y
+ 2;
330 pts
[3].x
= x
- 4; pts
[3].y
= y
- 2;
331 XDrawLines(XtDisplay((Widget
)w
), XtWindow((Widget
)w
), w
->tree
.plainGC
,
332 pts
, 4, CoordModeOrigin
);
335 static void drawCollapsedIcon(XPDFTreeWidget w
, Position x
, Position y
) {
338 pts
[0].x
= x
- 2; pts
[0].y
= y
- 4;
339 pts
[1].x
= x
- 2; pts
[1].y
= y
+ 4;
340 pts
[2].x
= x
+ 2; pts
[2].y
= y
;
341 pts
[3].x
= x
- 2; pts
[3].y
= y
- 4;
342 XDrawLines(XtDisplay((Widget
)w
), XtWindow((Widget
)w
), w
->tree
.plainGC
,
343 pts
, 4, CoordModeOrigin
);
346 static Boolean
setValues(Widget oldWidget
, Widget requestWidget
,
347 Widget newWidget
, ArgList args
, Cardinal
*numArgs
) {
348 XPDFTreeWidget ow
= (XPDFTreeWidget
)oldWidget
;
349 XPDFTreeWidget nw
= (XPDFTreeWidget
)newWidget
;
350 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(nw
);
351 Boolean relayout
, redisp
;
353 // check to see if layout-affecting resources have changed
354 if (cls
->treeClass
.needRelayout
) {
355 relayout
= (*cls
->treeClass
.needRelayout
)((Widget
)ow
, (Widget
)nw
);
357 relayout
= needRelayout((Widget
)ow
, (Widget
)nw
);
362 // calculate a new ideal size (reset the widget size first so
363 // calcSize will compute a new one)
364 if (nw
->core
.width
== ow
->core
.width
) {
367 if (nw
->core
.height
== ow
->core
.height
) {
370 if (cls
->treeClass
.calcSize
) {
371 (*cls
->treeClass
.calcSize
)((Widget
)nw
, NULL
,
372 &nw
->core
.width
, &nw
->core
.height
);
374 calcSize((Widget
)nw
, NULL
, &nw
->core
.width
, &nw
->core
.height
);
377 // if resources have changed but size hasn't, layout manually
378 // (because Xt just looks at the size)
379 if (nw
->core
.width
== ow
->core
.width
&&
380 nw
->core
.height
== ow
->core
.height
) {
381 if (cls
->treeClass
.layout
) {
382 (*cls
->treeClass
.layout
)((Widget
)nw
, NULL
);
384 layout((Widget
)nw
, NULL
);
393 static void setValuesAlmost(Widget oldWidget
, Widget newWidget
,
394 XtWidgetGeometry
*request
,
395 XtWidgetGeometry
*reply
) {
396 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(newWidget
);
398 // our parent rejected a geometry request, so accept the compromise
400 if (!reply
->request_mode
) {
401 if (cls
->treeClass
.layout
) {
402 (*cls
->treeClass
.layout
)(newWidget
, NULL
);
404 layout(newWidget
, NULL
);
410 static XtGeometryResult
queryGeometry(Widget widget
,
411 XtWidgetGeometry
*request
,
412 XtWidgetGeometry
*reply
) {
413 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(widget
);
415 if (!XtIsRealized(widget
)) {
416 reply
->width
= XtWidth(widget
);
417 reply
->height
= XtHeight(widget
);
422 if (cls
->treeClass
.calcSize
) {
423 (*cls
->treeClass
.calcSize
)(widget
, NULL
, &reply
->width
, &reply
->height
);
425 calcSize(widget
, NULL
, &reply
->width
, &reply
->height
);
428 return XmeReplyToQueryGeometry(widget
, request
, reply
);
430 if ((request
->request_mode
& CWWidth
) &&
431 (request
->request_mode
& CWHeight
) &&
432 request
->width
== reply
->width
&&
433 request
->height
== reply
->height
) {
434 return XtGeometryYes
;
436 if (reply
->width
== XtWidth(widget
) &&
437 reply
->height
== XtHeight(widget
)) {
440 reply
->request_mode
= CWWidth
| CWHeight
;
441 return XtGeometryAlmost
;
445 static XtGeometryResult
geometryManager(Widget widget
,
446 XtWidgetGeometry
*request
,
447 XtWidgetGeometry
*reply
) {
448 XPDFTreeWidget w
= (XPDFTreeWidget
)XtParent(widget
);
449 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(w
);
450 Dimension curWidth
, curHeight
, curBW
;
451 XtWidgetGeometry parentReq
;
452 XtGeometryResult result
;
454 // deny any requests for a new position
455 if ((request
->request_mode
& CWX
) || (request
->request_mode
& CWY
)) {
459 // save the current geometry
460 curWidth
= w
->core
.width
;
461 curHeight
= w
->core
.height
;
462 curBW
= w
->core
.border_width
;
464 // make the requested changes
465 if (request
->request_mode
& CWWidth
) {
466 w
->core
.width
= request
->width
;
468 if (request
->request_mode
& CWHeight
) {
469 w
->core
.height
= request
->height
;
471 if (request
->request_mode
& CWBorderWidth
) {
472 w
->core
.border_width
= request
->border_width
;
475 // calculate the new ideal size
477 parentReq
.height
= 0;
478 if (cls
->treeClass
.calcSize
) {
479 (*cls
->treeClass
.calcSize
)((Widget
)w
, widget
,
480 &parentReq
.width
, &reply
->height
);
482 calcSize((Widget
)w
, widget
, &parentReq
.width
, &reply
->height
);
485 // send geometry request to our parent
486 parentReq
.request_mode
= CWWidth
| CWHeight
;
487 if (request
->request_mode
& XtCWQueryOnly
) {
488 parentReq
.request_mode
|= XtCWQueryOnly
;
490 result
= XtMakeGeometryRequest((Widget
)w
, &parentReq
, NULL
);
491 if (result
== XtGeometryAlmost
) {
492 result
= XtGeometryNo
;
495 if (result
== XtGeometryNo
|| (request
->request_mode
& XtCWQueryOnly
)) {
496 // restore the original geometry
497 w
->core
.width
= curWidth
;
498 w
->core
.height
= curHeight
;
499 w
->core
.border_width
= curBW
;
501 if (cls
->treeClass
.layout
) {
502 (*cls
->treeClass
.layout
)((Widget
)w
, widget
);
504 layout((Widget
)w
, widget
);
511 static void changeManaged(Widget widget
) {
512 Dimension width
, height
;
513 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass(widget
);
515 // compute the ideal size
516 if (!XtIsRealized(widget
)) {
517 width
= XtWidth(widget
);
518 height
= XtHeight(widget
);
523 if (cls
->treeClass
.calcSize
) {
524 (*cls
->treeClass
.calcSize
)(widget
, NULL
, &width
, &height
);
526 calcSize(widget
, NULL
, &width
, &height
);
529 // make resize request to parent -- keep asking until we get a yes
531 while (XtMakeResizeRequest(widget
, width
, height
, &width
, &height
)
532 == XtGeometryAlmost
) ;
535 if (cls
->treeClass
.layout
) {
536 (*cls
->treeClass
.layout
)(widget
, NULL
);
538 layout(widget
, NULL
);
542 // update keyboard traversal
543 XmeNavigChangeManaged(widget
);
545 _XmNavigChangeManaged(widget
);
549 static void initConstraint(Widget requestWidget
, Widget newWidget
,
550 ArgList args
, Cardinal
*numArgs
) {
551 XPDFTreeWidget w
= (XPDFTreeWidget
)XtParent(newWidget
);
552 XPDFTreeConstraint c
;
554 c
= XPDFTreeCPart(newWidget
);
555 c
->e
= (XPDFTreeEntry
*)gmalloc(sizeof(XPDFTreeEntry
));
556 c
->e
->widget
= newWidget
;
557 c
->e
->children
= NULL
;
559 if (c
->entryParent
) {
560 insertChildOnList(c
->e
, &XPDFTreeCPart(c
->entryParent
)->e
->children
);
562 insertChildOnList(c
->e
, &w
->tree
.root
);
566 static void destroyConstraint(Widget widget
) {
567 deleteSubtree(widget
);
570 static void deleteSubtree(Widget widget
) {
571 XPDFTreeWidget w
= (XPDFTreeWidget
)XtParent(widget
);
572 XPDFTreeConstraint c
;
574 c
= XPDFTreeCPart(widget
);
578 while (c
->e
->children
) {
579 deleteSubtree(c
->e
->children
->widget
);
581 if (c
->entryParent
) {
582 deleteChildFromList(c
->e
, &XPDFTreeCPart(c
->entryParent
)->e
->children
);
584 deleteChildFromList(c
->e
, &w
->tree
.root
);
590 static Boolean
constraintSetValues(Widget oldWidget
, Widget requestWidget
,
592 ArgList args
, Cardinal
*numArgs
) {
593 XPDFTreeWidget w
= (XPDFTreeWidget
)XtParent(newWidget
);
594 XPDFTreeWidgetClass cls
= (XPDFTreeWidgetClass
)XtClass((Widget
)w
);
595 XPDFTreeConstraint oc
, nc
;
597 Dimension width
, height
;
599 if (!XtIsManaged(newWidget
)) {
602 oc
= XPDFTreeCPart(oldWidget
);
603 nc
= XPDFTreeCPart(newWidget
);
605 if (nc
->entryParent
!= oc
->entryParent
||
606 nc
->entryPosition
!= oc
->entryPosition
) {
607 if (oc
->entryParent
) {
608 deleteChildFromList(oc
->e
, &XPDFTreeCPart(oc
->entryParent
)->e
->children
);
610 deleteChildFromList(oc
->e
, &w
->tree
.root
);
612 if (nc
->entryParent
) {
613 insertChildOnList(nc
->e
, &XPDFTreeCPart(nc
->entryParent
)->e
->children
);
615 insertChildOnList(nc
->e
, &w
->tree
.root
);
618 } else if (nc
->entryExpanded
!= oc
->entryExpanded
) {
624 // calculate a new ideal size (reset the widget size first so
625 // calcSize will compute a new one)
628 if (cls
->treeClass
.calcSize
) {
629 (*cls
->treeClass
.calcSize
)((Widget
)w
, NULL
, &width
, &height
);
631 calcSize((Widget
)w
, NULL
, &width
, &height
);
634 // make resize request to parent -- keep asking until we get a yes
636 while (XtMakeResizeRequest((Widget
)w
, width
, height
, &width
, &height
)
637 == XtGeometryAlmost
) ;
639 // relayout the widget
640 if (cls
->treeClass
.layout
) {
641 (*cls
->treeClass
.layout
)((Widget
)w
, NULL
);
643 layout((Widget
)w
, NULL
);
650 static void insertChildOnList(XPDFTreeEntry
*e
, XPDFTreeEntry
**listHead
) {
654 pos
= XPDFTreeCPart(e
->widget
)->entryPosition
;
655 if (!*listHead
|| pos
< XPDFTreeCPart((*listHead
)->widget
)->entryPosition
) {
660 e2
->next
&& pos
>= XPDFTreeCPart(e2
->next
->widget
)->entryPosition
;
667 static void deleteChildFromList(XPDFTreeEntry
*e
, XPDFTreeEntry
**listHead
) {
670 for (p
= listHead
; *p
; p
= &(*p
)->next
) {
679 static void createGC(Widget widget
) {
680 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
683 gcValues
.foreground
= w
->manager
.foreground
;
684 gcValues
.line_width
= 0;
685 gcValues
.line_style
= LineSolid
;
686 w
->tree
.plainGC
= XtGetGC(widget
,
687 GCForeground
| GCLineWidth
| GCLineStyle
,
690 gcValues
.line_style
= LineOnOffDash
;
692 gcValues
.dash_offset
= 0;
693 w
->tree
.dottedGC
= XtGetGC(widget
,
694 GCForeground
| GCLineWidth
| GCLineStyle
|
695 GCDashList
| GCDashOffset
,
699 static void destroyGC(Widget widget
) {
700 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
702 XtReleaseGC(widget
, w
->tree
.plainGC
);
703 XtReleaseGC(widget
, w
->tree
.dottedGC
);
706 static void layout(Widget widget
, Widget instigator
) {
707 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
711 x
= w
->tree
.marginWidth
+ xpdfTreeIndent
;
712 y
= w
->tree
.marginHeight
;
713 for (e
= w
->tree
.root
; e
; e
= e
->next
) {
714 y
= layoutSubtree(w
, instigator
, e
, x
, y
, True
);
718 static int layoutSubtree(XPDFTreeWidget w
, Widget instigator
,
719 XPDFTreeEntry
*e
, Position x
, Position y
,
722 XPDFTreeEntry
*child
;
723 XPDFTreeConstraint c
;
726 if (!XtIsManaged(ew
)) {
729 c
= XPDFTreeCPart(ew
);
734 if (ew
== instigator
) {
739 XmeConfigureObject(ew
, x
, y
, ew
->core
.width
, ew
->core
.height
,
740 ew
->core
.border_width
);
742 _XmConfigureObject(ew
, x
, y
, ew
->core
.width
, ew
->core
.height
,
743 ew
->core
.border_width
);
746 y
+= ew
->core
.height
+ 2 * ew
->core
.border_width
;
750 // place this entry's children
752 for (child
= e
->children
; child
; child
= child
->next
) {
753 y
= layoutSubtree(w
, instigator
, child
, x
, y
,
754 visible
&& (!c
|| c
->entryExpanded
));
760 static void calcSize(Widget widget
, Widget instigator
,
761 Dimension
*totalWidth
,
762 Dimension
*totalHeight
) {
763 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
765 Dimension w1
, h1
, w2
, h2
;
768 for (e
= w
->tree
.root
; e
; e
= e
->next
) {
769 calcSubtreeSize(w
, instigator
, e
, &w2
, &h2
);
775 w1
+= xpdfTreeIndent
+ 2 * w
->tree
.marginWidth
;
776 h1
+= 2 * w
->tree
.marginHeight
;
788 static void calcSubtreeSize(XPDFTreeWidget w
, Widget instigator
,
790 Dimension
*width
, Dimension
*height
) {
792 XPDFTreeEntry
*child
;
793 XPDFTreeConstraint c
;
794 XtWidgetGeometry geom
;
795 Dimension w1
, h1
, w2
, h2
;
798 if (!XtIsManaged(ew
)) {
799 *width
= *height
= 0;
802 c
= XPDFTreeCPart(ew
);
804 // get size of this entry
806 if (!XtIsManaged(ew
)) {
807 *width
= *height
= 0;
810 if (ew
== instigator
) {
812 h1
= ew
->core
.height
;
814 XtQueryGeometry(ew
, NULL
, &geom
);
815 w1
= (geom
.request_mode
& CWWidth
) ? geom
.width
: ew
->core
.width
;
816 h1
= (geom
.request_mode
& CWHeight
) ? geom
.height
: ew
->core
.height
;
818 h1
+= 2 * ew
->core
.border_width
;
825 // if this entry is expanded, get size of all of its children
826 if (c
->entryExpanded
) {
827 for (child
= e
->children
; child
; child
= child
->next
) {
828 calcSubtreeSize(w
, instigator
, child
, &w2
, &h2
);
829 w2
+= xpdfTreeIndent
;
841 static Boolean
needRelayout(Widget oldWidget
, Widget newWidget
) {
842 XPDFTreeWidget ow
= (XPDFTreeWidget
)oldWidget
;
843 XPDFTreeWidget nw
= (XPDFTreeWidget
)newWidget
;
845 if (nw
->tree
.marginWidth
!= ow
->tree
.marginWidth
||
846 nw
->tree
.marginHeight
!= ow
->tree
.marginHeight
) {
852 static void click(Widget widget
, XEvent
*event
,
853 String
*params
, Cardinal
*numParams
) {
854 XPDFTreeWidget w
= (XPDFTreeWidget
)widget
;
855 XButtonPressedEvent
*bpe
;
857 Boolean onExpandIcon
;
858 XPDFTreeConstraint c
;
859 XPDFTreeSelectCallbackStruct cbs
;
861 if (event
->type
!= ButtonPress
) {
864 bpe
= (XButtonPressedEvent
*)event
;
865 if (findPosition(w
, bpe
->x
, bpe
->y
, &e
, &onExpandIcon
)) {
867 c
= XPDFTreeCPart(e
->widget
);
868 w
->tree
.redrawY
= e
->widget
->core
.y
;
869 XtVaSetValues(e
->widget
, XPDFNentryExpanded
, !c
->entryExpanded
, NULL
);
871 XmProcessTraversal(e
->widget
, XmTRAVERSE_CURRENT
);
872 XtCallActionProc(widget
, "ManagerGadgetActivate", event
, NULL
, 0);
873 cbs
.reason
= XmCR_ACTIVATE
;
875 cbs
.selectedItem
= e
->widget
;
876 XtCallCallbackList(widget
, w
->tree
.selectCallback
, &cbs
);
881 static Boolean
findPosition(XPDFTreeWidget w
, int x
, int y
,
882 XPDFTreeEntry
**e
, Boolean
*onExpandIcon
) {
885 for (e2
= w
->tree
.root
; e2
; e2
= e2
->next
) {
887 if (findPositionInSubtree(w
, x
, y
, e
, onExpandIcon
)) {
894 // If (x,y) falls on either an expand/collapse icon or a label gadget,
895 // set *<e> and *<onExpandIcon> and return true.
896 static Boolean
findPositionInSubtree(XPDFTreeWidget w
, int x
, int y
,
898 Boolean
*onExpandIcon
) {
900 XPDFTreeConstraint c
;
904 child
= (*e
)->widget
;
905 y1
= child
->core
.y
+ child
->core
.height
/ 2;
906 if (x
>= child
->core
.x
&& x
< child
->core
.x
+ child
->core
.width
&&
907 y
>= child
->core
.y
&& y
< child
->core
.y
+ child
->core
.height
) {
908 *onExpandIcon
= False
;
910 } else if (x
>= child
->core
.x
- 16 && x
< child
->core
.x
- 4 &&
911 y
>= y1
- 6 && y
< y1
+ 6 &&
913 *onExpandIcon
= True
;
916 c
= XPDFTreeCPart(child
);
917 if (!c
|| c
->entryExpanded
) {
918 for (e2
= (*e
)->children
; e2
; e2
= e2
->next
) {
920 if (findPositionInSubtree(w
, x
, y
, e
, onExpandIcon
)) {
928 Widget
XPDFCreateTree(Widget parent
, char *name
,
929 ArgList argList
, Cardinal numArgs
) {
930 return XtCreateWidget(name
, xpdfTreeWidgetClass
, parent
, argList
, numArgs
);