1 //========================================================================
5 //========================================================================
11 //------------------------------------------------------------------------
13 #define xpdfTreeIndent 16
15 //------------------------------------------------------------------------
17 struct _XPDFTreeEntry {
19 XPDFTreeEntry *children;
23 //------------------------------------------------------------------------
25 static void classPartInitialize(WidgetClass widgetClass);
26 static void initialize(Widget requestWidget, Widget newWidget,
27 ArgList args, Cardinal *numArgs);
28 static void destroy(Widget widget);
29 static void destroySubtree(XPDFTreeEntry *e);
30 static void resize(Widget widget);
31 static void redisplay(Widget widget, XEvent *event, Region region);
32 static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e,
33 XEvent *event, Region region);
34 static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y);
35 static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y);
36 static Boolean setValues(Widget oldWidget, Widget requestWidget,
37 Widget newWidget, ArgList args, Cardinal *numArgs);
38 static void setValuesAlmost(Widget oldWidget, Widget newWidget,
39 XtWidgetGeometry *request,
40 XtWidgetGeometry *reply);
41 static XtGeometryResult queryGeometry(Widget widget,
42 XtWidgetGeometry *request,
43 XtWidgetGeometry *reply);
44 static XtGeometryResult geometryManager(Widget widget,
45 XtWidgetGeometry *request,
46 XtWidgetGeometry *reply);
47 static void changeManaged(Widget widget);
48 static void initConstraint(Widget requestWidget, Widget newWidget,
49 ArgList args, Cardinal *numArgs);
50 static void destroyConstraint(Widget widget);
51 static void deleteSubtree(Widget widget);
52 static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget,
54 ArgList args, Cardinal *numArgs);
55 static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead);
56 static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead);
57 static void createGC(Widget widget);
58 static void destroyGC(Widget widget);
59 static void layout(Widget widget, Widget instigator);
60 static int layoutSubtree(XPDFTreeWidget w, Widget instigator,
61 XPDFTreeEntry *e, Position x, Position y,
63 static void calcSize(Widget widget, Widget instigator,
64 Dimension *totalWidth,
65 Dimension *totalHeight);
66 static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator,
68 Dimension *width, Dimension *height);
69 static Boolean needRelayout(Widget oldWidget, Widget newWidget);
70 static void click(Widget widget, XEvent *event,
71 String *params, Cardinal *numParams);
72 static Boolean findPosition(XPDFTreeWidget w, int x, int y,
73 XPDFTreeEntry **e, Boolean *onExpandIcon);
74 static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y,
76 Boolean *onExpandIcon);
78 //------------------------------------------------------------------------
80 static XtResource resources[] = {
81 { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
82 sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginWidth),
83 XmRImmediate, (XtPointer)0 },
84 { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
85 sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginHeight),
86 XmRImmediate, (XtPointer)0 },
87 { XPDFNselectionCallback, XmCCallback, XmRCallback,
88 sizeof(XtCallbackList), XtOffsetOf(XPDFTreeRec, tree.selectCallback),
89 XmRImmediate, (XtPointer)NULL }
92 static XmSyntheticResource synResources[] = {
93 { XmNmarginWidth, sizeof(Dimension),
94 XtOffsetOf(XPDFTreeRec, tree.marginWidth),
96 XmeFromHorizontalPixels, XmeToHorizontalPixels
98 _XmFromHorizontalPixels, _XmToHorizontalPixels
101 { XmNmarginHeight, sizeof(Dimension),
102 XtOffsetOf(XPDFTreeRec, tree.marginHeight),
104 XmeFromVerticalPixels, XmeToVerticalPixels
106 _XmFromVerticalPixels, _XmToVerticalPixels
111 static XtResource constraints[] = {
112 { XPDFNentryParent, XPDFCentryParent, XmRWidget,
113 sizeof(Widget), XtOffsetOf(XPDFTreeConstraintRec, tree.entryParent),
114 XmRImmediate, (XtPointer)NULL },
115 { XPDFNentryExpanded, XPDFCentryExpanded, XmRBoolean,
116 sizeof(Boolean), XtOffsetOf(XPDFTreeConstraintRec, tree.entryExpanded),
117 XmRImmediate, (XtPointer)False },
118 { XPDFNentryPosition, XPDFCentryPosition, XmRInt,
119 sizeof(int), XtOffsetOf(XPDFTreeConstraintRec, tree.entryPosition),
120 XmRImmediate, (XtPointer)0 }
123 static char defaultTranslations[] =
124 "<Btn1Down>: XPDFTreeClick()";
126 static XtActionsRec actions[] = {
127 { "XPDFTreeClick", click }
130 externaldef(xpdftreeclassrec) XPDFTreeClassRec xpdfTreeClassRec = {
132 (WidgetClass)&xmManagerClassRec, // superclass
133 "XPDFTree", // class_name
134 sizeof(XPDFTreeRec), // widget_size
135 NULL, // class_initialize
136 &classPartInitialize, // class_part_initialize
137 FALSE, // class_inited
138 &initialize, // initialize
139 NULL, // initialize_hook
140 XtInheritRealize, // realize
142 XtNumber(actions), // num_actions
143 resources, // resources
144 XtNumber(resources), // num_resources
145 NULLQUARK, // xrm_class
146 TRUE, // compress_motion
147 XtExposeCompressMaximal, // compress_exposure
148 TRUE, // compress_enterleave
149 FALSE, // visible_interest
152 &redisplay, // expose
153 &setValues, // set_values
154 NULL, // set_values_hook
155 &setValuesAlmost, // set_values_almost
156 NULL, // get_values_hook
157 NULL, // accept_focus
158 XtVersion, // version
159 NULL, // callback_private
160 defaultTranslations, // tm_table
161 &queryGeometry, // query_geometry
162 NULL, // display_accelerator
166 &geometryManager, // geometry_manager
167 &changeManaged, // change_managed
168 XtInheritInsertChild, // insert_child
169 XtInheritDeleteChild, // delete_child
173 constraints, // constraint_resources
174 XtNumber(constraints), // constraint_num_resources
175 sizeof(XPDFTreeConstraintRec), // constraint_size
176 &initConstraint, // constraint_initialize
177 &destroyConstraint, // constraint_destroy
178 &constraintSetValues, // constraint_set_values
182 XtInheritTranslations, // translations
184 synResources, // syn_resources
185 XtNumber(synResources), // num_syn_resources
187 NULL, // syn_resources
188 0, // num_syn_resources
190 NULL, // syn_constraint_resources
191 0, // num_syn_constraint_res's
192 XmInheritParentProcess, // parent_process
196 &createGC, // createGC
197 &destroyGC, // destroyGC
199 &calcSize, // calcSize
200 &needRelayout, // needRelayout
205 externaldef(xpdftreewidgetclass) WidgetClass xpdfTreeWidgetClass =
206 (WidgetClass)&xpdfTreeClassRec;
208 //------------------------------------------------------------------------
210 static void classPartInitialize(WidgetClass widgetCls) {
211 XPDFTreeWidgetClass wc = (XPDFTreeWidgetClass)widgetCls;
212 XPDFTreeWidgetClass sc = (XPDFTreeWidgetClass)wc->coreClass.superclass;
214 // method inheritance
215 if (wc->treeClass.createGC == XPDFInheritCreateGC) {
216 wc->treeClass.createGC = sc->treeClass.createGC;
218 if (wc->treeClass.destroyGC == XPDFInheritDestroyGC) {
219 wc->treeClass.destroyGC = sc->treeClass.destroyGC;
221 if (wc->treeClass.layout == XPDFInheritLayout) {
222 wc->treeClass.layout = sc->treeClass.layout;
224 if (wc->treeClass.calcSize == XPDFInheritCalcSize) {
225 wc->treeClass.calcSize = sc->treeClass.calcSize;
227 if (wc->treeClass.needRelayout == XPDFInheritNeedRelayout) {
228 wc->treeClass.needRelayout = sc->treeClass.needRelayout;
232 static void initialize(Widget requestWidget, Widget newWidget,
233 ArgList args, Cardinal *numArgs) {
234 XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
235 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget);
237 nw->tree.root = NULL;
238 nw->tree.redrawY = -1;
239 if (cls->treeClass.createGC) {
240 (*cls->treeClass.createGC)(newWidget);
246 static void destroy(Widget widget) {
247 XPDFTreeWidget w = (XPDFTreeWidget)widget;
248 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
251 destroySubtree(w->tree.root);
254 if (cls->treeClass.destroyGC) {
255 (*cls->treeClass.destroyGC)(widget);
261 static void destroySubtree(XPDFTreeEntry *e) {
263 destroySubtree(e->children);
266 destroySubtree(e->next);
270 static void resize(Widget widget) {
271 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
273 if (cls->treeClass.layout) {
274 (*cls->treeClass.layout)(widget, NULL);
276 layout(widget, NULL);
280 static void redisplay(Widget widget, XEvent *event, Region region) {
281 XPDFTreeWidget w = (XPDFTreeWidget)widget;
284 if (w->tree.redrawY >= 0) {
285 XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
286 0, w->tree.redrawY, w->core.width, w->core.height, False);
287 w->tree.redrawY = -1;
289 for (e = w->tree.root; e; e = e->next) {
290 redisplaySubtree(w, e, event, region);
294 static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e,
295 XEvent *event, Region region) {
296 XPDFTreeConstraint c;
298 XPDFTreeEntry *child;
300 (*XtClass(e->widget)->core_class.expose)(e->widget, event, region);
301 c = XPDFTreeCPart(e->widget);
302 x = e->widget->core.x;
303 y = e->widget->core.y + e->widget->core.height / 2;
305 if (c->entryExpanded) {
306 drawExpandedIcon(w, x - 8, y);
307 y2 = y; // make gcc happy
308 for (child = e->children; child; child = child->next) {
309 y2 = child->widget->core.y + child->widget->core.height / 2;
310 XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC,
311 x - 8, y2, x + 6, y2);
312 redisplaySubtree(w, child, event, region);
314 XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC,
315 x - 8, y + 2, x - 8, y2);
317 drawCollapsedIcon(w, x - 8, y);
322 static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y) {
325 pts[0].x = x - 4; pts[0].y = y - 2;
326 pts[1].x = x + 4; pts[1].y = y - 2;
327 pts[2].x = x; pts[2].y = y + 2;
328 pts[3].x = x - 4; pts[3].y = y - 2;
329 XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC,
330 pts, 4, CoordModeOrigin);
333 static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y) {
336 pts[0].x = x - 2; pts[0].y = y - 4;
337 pts[1].x = x - 2; pts[1].y = y + 4;
338 pts[2].x = x + 2; pts[2].y = y;
339 pts[3].x = x - 2; pts[3].y = y - 4;
340 XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC,
341 pts, 4, CoordModeOrigin);
344 static Boolean setValues(Widget oldWidget, Widget requestWidget,
345 Widget newWidget, ArgList args, Cardinal *numArgs) {
346 XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget;
347 XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
348 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(nw);
349 Boolean relayout, redisp;
351 // check to see if layout-affecting resources have changed
352 if (cls->treeClass.needRelayout) {
353 relayout = (*cls->treeClass.needRelayout)((Widget)ow, (Widget)nw);
355 relayout = needRelayout((Widget)ow, (Widget)nw);
360 // calculate a new ideal size (reset the widget size first so
361 // calcSize will compute a new one)
362 if (nw->core.width == ow->core.width) {
365 if (nw->core.height == ow->core.height) {
368 if (cls->treeClass.calcSize) {
369 (*cls->treeClass.calcSize)((Widget)nw, NULL,
370 &nw->core.width, &nw->core.height);
372 calcSize((Widget)nw, NULL, &nw->core.width, &nw->core.height);
375 // if resources have changed but size hasn't, layout manually
376 // (because Xt just looks at the size)
377 if (nw->core.width == ow->core.width &&
378 nw->core.height == ow->core.height) {
379 if (cls->treeClass.layout) {
380 (*cls->treeClass.layout)((Widget)nw, NULL);
382 layout((Widget)nw, NULL);
391 static void setValuesAlmost(Widget oldWidget, Widget newWidget,
392 XtWidgetGeometry *request,
393 XtWidgetGeometry *reply) {
394 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget);
396 // our parent rejected a geometry request, so accept the compromise
398 if (!reply->request_mode) {
399 if (cls->treeClass.layout) {
400 (*cls->treeClass.layout)(newWidget, NULL);
402 layout(newWidget, NULL);
408 static XtGeometryResult queryGeometry(Widget widget,
409 XtWidgetGeometry *request,
410 XtWidgetGeometry *reply) {
411 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
413 if (!XtIsRealized(widget)) {
414 reply->width = XtWidth(widget);
415 reply->height = XtHeight(widget);
420 if (cls->treeClass.calcSize) {
421 (*cls->treeClass.calcSize)(widget, NULL, &reply->width, &reply->height);
423 calcSize(widget, NULL, &reply->width, &reply->height);
426 return XmeReplyToQueryGeometry(widget, request, reply);
428 if ((request->request_mode & CWWidth) &&
429 (request->request_mode & CWHeight) &&
430 request->width == reply->width &&
431 request->height == reply->height) {
432 return XtGeometryYes;
434 if (reply->width == XtWidth(widget) &&
435 reply->height == XtHeight(widget)) {
438 reply->request_mode = CWWidth | CWHeight;
439 return XtGeometryAlmost;
443 static XtGeometryResult geometryManager(Widget widget,
444 XtWidgetGeometry *request,
445 XtWidgetGeometry *reply) {
446 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget);
447 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(w);
448 Dimension curWidth, curHeight, curBW;
449 XtWidgetGeometry parentReq;
450 XtGeometryResult result;
452 // deny any requests for a new position
453 if ((request->request_mode & CWX) || (request->request_mode & CWY)) {
457 // save the current geometry
458 curWidth = w->core.width;
459 curHeight = w->core.height;
460 curBW = w->core.border_width;
462 // make the requested changes
463 if (request->request_mode & CWWidth) {
464 w->core.width = request->width;
466 if (request->request_mode & CWHeight) {
467 w->core.height = request->height;
469 if (request->request_mode & CWBorderWidth) {
470 w->core.border_width = request->border_width;
473 // calculate the new ideal size
475 parentReq.height = 0;
476 if (cls->treeClass.calcSize) {
477 (*cls->treeClass.calcSize)((Widget)w, widget,
478 &parentReq.width, &reply->height);
480 calcSize((Widget)w, widget, &parentReq.width, &reply->height);
483 // send geometry request to our parent
484 parentReq.request_mode = CWWidth | CWHeight;
485 if (request->request_mode & XtCWQueryOnly) {
486 parentReq.request_mode |= XtCWQueryOnly;
488 result = XtMakeGeometryRequest((Widget)w, &parentReq, NULL);
489 if (result == XtGeometryAlmost) {
490 result = XtGeometryNo;
493 if (result == XtGeometryNo || (request->request_mode & XtCWQueryOnly)) {
494 // restore the original geometry
495 w->core.width = curWidth;
496 w->core.height = curHeight;
497 w->core.border_width = curBW;
499 if (cls->treeClass.layout) {
500 (*cls->treeClass.layout)((Widget)w, widget);
502 layout((Widget)w, widget);
509 static void changeManaged(Widget widget) {
510 Dimension width, height;
511 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
513 // compute the ideal size
514 if (!XtIsRealized(widget)) {
515 width = XtWidth(widget);
516 height = XtHeight(widget);
521 if (cls->treeClass.calcSize) {
522 (*cls->treeClass.calcSize)(widget, NULL, &width, &height);
524 calcSize(widget, NULL, &width, &height);
527 // make resize request to parent -- keep asking until we get a yes
529 while (XtMakeResizeRequest(widget, width, height, &width, &height)
530 == XtGeometryAlmost) ;
533 if (cls->treeClass.layout) {
534 (*cls->treeClass.layout)(widget, NULL);
536 layout(widget, NULL);
540 // update keyboard traversal
541 XmeNavigChangeManaged(widget);
543 _XmNavigChangeManaged(widget);
547 static void initConstraint(Widget requestWidget, Widget newWidget,
548 ArgList args, Cardinal *numArgs) {
549 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget);
550 XPDFTreeConstraint c;
552 c = XPDFTreeCPart(newWidget);
553 c->e = (XPDFTreeEntry *)gmalloc(sizeof(XPDFTreeEntry));
554 c->e->widget = newWidget;
555 c->e->children = NULL;
557 if (c->entryParent) {
558 insertChildOnList(c->e, &XPDFTreeCPart(c->entryParent)->e->children);
560 insertChildOnList(c->e, &w->tree.root);
564 static void destroyConstraint(Widget widget) {
565 deleteSubtree(widget);
568 static void deleteSubtree(Widget widget) {
569 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget);
570 XPDFTreeConstraint c;
572 c = XPDFTreeCPart(widget);
576 while (c->e->children) {
577 deleteSubtree(c->e->children->widget);
579 if (c->entryParent) {
580 deleteChildFromList(c->e, &XPDFTreeCPart(c->entryParent)->e->children);
582 deleteChildFromList(c->e, &w->tree.root);
588 static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget,
590 ArgList args, Cardinal *numArgs) {
591 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget);
592 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass((Widget)w);
593 XPDFTreeConstraint oc, nc;
595 Dimension width, height;
597 if (!XtIsManaged(newWidget)) {
600 oc = XPDFTreeCPart(oldWidget);
601 nc = XPDFTreeCPart(newWidget);
603 if (nc->entryParent != oc->entryParent ||
604 nc->entryPosition != oc->entryPosition) {
605 if (oc->entryParent) {
606 deleteChildFromList(oc->e, &XPDFTreeCPart(oc->entryParent)->e->children);
608 deleteChildFromList(oc->e, &w->tree.root);
610 if (nc->entryParent) {
611 insertChildOnList(nc->e, &XPDFTreeCPart(nc->entryParent)->e->children);
613 insertChildOnList(nc->e, &w->tree.root);
616 } else if (nc->entryExpanded != oc->entryExpanded) {
622 // calculate a new ideal size (reset the widget size first so
623 // calcSize will compute a new one)
626 if (cls->treeClass.calcSize) {
627 (*cls->treeClass.calcSize)((Widget)w, NULL, &width, &height);
629 calcSize((Widget)w, NULL, &width, &height);
632 // make resize request to parent -- keep asking until we get a yes
634 while (XtMakeResizeRequest((Widget)w, width, height, &width, &height)
635 == XtGeometryAlmost) ;
637 // relayout the widget
638 if (cls->treeClass.layout) {
639 (*cls->treeClass.layout)((Widget)w, NULL);
641 layout((Widget)w, NULL);
648 static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) {
652 pos = XPDFTreeCPart(e->widget)->entryPosition;
653 if (!*listHead || pos < XPDFTreeCPart((*listHead)->widget)->entryPosition) {
658 e2->next && pos >= XPDFTreeCPart(e2->next->widget)->entryPosition;
665 static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) {
668 for (p = listHead; *p; p = &(*p)->next) {
677 static void createGC(Widget widget) {
678 XPDFTreeWidget w = (XPDFTreeWidget)widget;
681 gcValues.foreground = w->manager.foreground;
682 gcValues.line_width = 0;
683 gcValues.line_style = LineSolid;
684 w->tree.plainGC = XtGetGC(widget,
685 GCForeground | GCLineWidth | GCLineStyle,
688 gcValues.line_style = LineOnOffDash;
690 gcValues.dash_offset = 0;
691 w->tree.dottedGC = XtGetGC(widget,
692 GCForeground | GCLineWidth | GCLineStyle |
693 GCDashList | GCDashOffset,
697 static void destroyGC(Widget widget) {
698 XPDFTreeWidget w = (XPDFTreeWidget)widget;
700 XtReleaseGC(widget, w->tree.plainGC);
701 XtReleaseGC(widget, w->tree.dottedGC);
704 static void layout(Widget widget, Widget instigator) {
705 XPDFTreeWidget w = (XPDFTreeWidget)widget;
709 x = w->tree.marginWidth + xpdfTreeIndent;
710 y = w->tree.marginHeight;
711 for (e = w->tree.root; e; e = e->next) {
712 y = layoutSubtree(w, instigator, e, x, y, True);
716 static int layoutSubtree(XPDFTreeWidget w, Widget instigator,
717 XPDFTreeEntry *e, Position x, Position y,
720 XPDFTreeEntry *child;
721 XPDFTreeConstraint c;
724 if (!XtIsManaged(ew)) {
727 c = XPDFTreeCPart(ew);
732 if (ew == instigator) {
737 XmeConfigureObject(ew, x, y, ew->core.width, ew->core.height,
738 ew->core.border_width);
740 _XmConfigureObject(ew, x, y, ew->core.width, ew->core.height,
741 ew->core.border_width);
744 y += ew->core.height + 2 * ew->core.border_width;
748 // place this entry's children
750 for (child = e->children; child; child = child->next) {
751 y = layoutSubtree(w, instigator, child, x, y,
752 visible && (!c || c->entryExpanded));
758 static void calcSize(Widget widget, Widget instigator,
759 Dimension *totalWidth,
760 Dimension *totalHeight) {
761 XPDFTreeWidget w = (XPDFTreeWidget)widget;
763 Dimension w1, h1, w2, h2;
766 for (e = w->tree.root; e; e = e->next) {
767 calcSubtreeSize(w, instigator, e, &w2, &h2);
773 w1 += xpdfTreeIndent + 2 * w->tree.marginWidth;
774 h1 += 2 * w->tree.marginHeight;
786 static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator,
788 Dimension *width, Dimension *height) {
790 XPDFTreeEntry *child;
791 XPDFTreeConstraint c;
792 XtWidgetGeometry geom;
793 Dimension w1, h1, w2, h2;
796 if (!XtIsManaged(ew)) {
797 *width = *height = 0;
800 c = XPDFTreeCPart(ew);
802 // get size of this entry
804 if (!XtIsManaged(ew)) {
805 *width = *height = 0;
808 if (ew == instigator) {
810 h1 = ew->core.height;
812 XtQueryGeometry(ew, NULL, &geom);
813 w1 = (geom.request_mode & CWWidth) ? geom.width : ew->core.width;
814 h1 = (geom.request_mode & CWHeight) ? geom.height : ew->core.height;
816 h1 += 2 * ew->core.border_width;
823 // if this entry is expanded, get size of all of its children
824 if (c->entryExpanded) {
825 for (child = e->children; child; child = child->next) {
826 calcSubtreeSize(w, instigator, child, &w2, &h2);
827 w2 += xpdfTreeIndent;
839 static Boolean needRelayout(Widget oldWidget, Widget newWidget) {
840 XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget;
841 XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
843 if (nw->tree.marginWidth != ow->tree.marginWidth ||
844 nw->tree.marginHeight != ow->tree.marginHeight) {
850 static void click(Widget widget, XEvent *event,
851 String *params, Cardinal *numParams) {
852 XPDFTreeWidget w = (XPDFTreeWidget)widget;
853 XButtonPressedEvent *bpe;
855 Boolean onExpandIcon;
856 XPDFTreeConstraint c;
857 XPDFTreeSelectCallbackStruct cbs;
859 if (event->type != ButtonPress) {
862 bpe = (XButtonPressedEvent *)event;
863 if (findPosition(w, bpe->x, bpe->y, &e, &onExpandIcon)) {
865 c = XPDFTreeCPart(e->widget);
866 w->tree.redrawY = e->widget->core.y;
867 XtVaSetValues(e->widget, XPDFNentryExpanded, !c->entryExpanded, NULL);
869 XmProcessTraversal(e->widget, XmTRAVERSE_CURRENT);
870 XtCallActionProc(widget, "ManagerGadgetActivate", event, NULL, 0);
871 cbs.reason = XmCR_ACTIVATE;
873 cbs.selectedItem = e->widget;
874 XtCallCallbackList(widget, w->tree.selectCallback, &cbs);
879 static Boolean findPosition(XPDFTreeWidget w, int x, int y,
880 XPDFTreeEntry **e, Boolean *onExpandIcon) {
883 for (e2 = w->tree.root; e2; e2 = e2->next) {
885 if (findPositionInSubtree(w, x, y, e, onExpandIcon)) {
892 // If (x,y) falls on either an expand/collapse icon or a label gadget,
893 // set *<e> and *<onExpandIcon> and return true.
894 static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y,
896 Boolean *onExpandIcon) {
898 XPDFTreeConstraint c;
902 child = (*e)->widget;
903 y1 = child->core.y + child->core.height / 2;
904 if (x >= child->core.x && x < child->core.x + child->core.width &&
905 y >= child->core.y && y < child->core.y + child->core.height) {
906 *onExpandIcon = False;
908 } else if (x >= child->core.x - 16 && x < child->core.x - 4 &&
909 y >= y1 - 6 && y < y1 + 6 &&
911 *onExpandIcon = True;
914 c = XPDFTreeCPart(child);
915 if (!c || c->entryExpanded) {
916 for (e2 = (*e)->children; e2; e2 = e2->next) {
918 if (findPositionInSubtree(w, x, y, e, onExpandIcon)) {
926 Widget XPDFCreateTree(Widget parent, char *name,
927 ArgList argList, Cardinal numArgs) {
928 return XtCreateWidget(name, xpdfTreeWidgetClass, parent, argList, numArgs);