00001
00002
00003
00004
00005
00006
00007 #include <stdlib.h>
00008 #include "gmem.h"
00009 #include "XPDFTreeP.h"
00010
00011
00012
00013 #define xpdfTreeIndent 16
00014
00015
00016
00017 struct _XPDFTreeEntry {
00018 Widget widget;
00019 XPDFTreeEntry *children;
00020 XPDFTreeEntry *next;
00021 };
00022
00023
00024
00025 static void classPartInitialize(WidgetClass widgetClass);
00026 static void initialize(Widget requestWidget, Widget newWidget,
00027 ArgList args, Cardinal *numArgs);
00028 static void destroy(Widget widget);
00029 static void destroySubtree(XPDFTreeEntry *e);
00030 static void resize(Widget widget);
00031 static void redisplay(Widget widget, XEvent *event, Region region);
00032 static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e,
00033 XEvent *event, Region region);
00034 static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y);
00035 static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y);
00036 static Boolean setValues(Widget oldWidget, Widget requestWidget,
00037 Widget newWidget, ArgList args, Cardinal *numArgs);
00038 static void setValuesAlmost(Widget oldWidget, Widget newWidget,
00039 XtWidgetGeometry *request,
00040 XtWidgetGeometry *reply);
00041 static XtGeometryResult queryGeometry(Widget widget,
00042 XtWidgetGeometry *request,
00043 XtWidgetGeometry *reply);
00044 static XtGeometryResult geometryManager(Widget widget,
00045 XtWidgetGeometry *request,
00046 XtWidgetGeometry *reply);
00047 static void changeManaged(Widget widget);
00048 static void initConstraint(Widget requestWidget, Widget newWidget,
00049 ArgList args, Cardinal *numArgs);
00050 static void destroyConstraint(Widget widget);
00051 static void deleteSubtree(Widget widget);
00052 static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget,
00053 Widget newWidget,
00054 ArgList args, Cardinal *numArgs);
00055 static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead);
00056 static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead);
00057 static void createGC(Widget widget);
00058 static void destroyGC(Widget widget);
00059 static void layout(Widget widget, Widget instigator);
00060 static int layoutSubtree(XPDFTreeWidget w, Widget instigator,
00061 XPDFTreeEntry *e, Position x, Position y,
00062 Boolean visible);
00063 static void calcSize(Widget widget, Widget instigator,
00064 Dimension *totalWidth,
00065 Dimension *totalHeight);
00066 static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator,
00067 XPDFTreeEntry *e,
00068 Dimension *width, Dimension *height);
00069 static Boolean needRelayout(Widget oldWidget, Widget newWidget);
00070 static void click(Widget widget, XEvent *event,
00071 String *params, Cardinal *numParams);
00072 static Boolean findPosition(XPDFTreeWidget w, int x, int y,
00073 XPDFTreeEntry **e, Boolean *onExpandIcon);
00074 static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y,
00075 XPDFTreeEntry **e,
00076 Boolean *onExpandIcon);
00077
00078
00079
00080 static XtResource resources[] = {
00081 { XmNmarginWidth, XmCMarginWidth, XmRHorizontalDimension,
00082 sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginWidth),
00083 XmRImmediate, (XtPointer)0 },
00084 { XmNmarginHeight, XmCMarginHeight, XmRVerticalDimension,
00085 sizeof(Dimension), XtOffsetOf(XPDFTreeRec, tree.marginHeight),
00086 XmRImmediate, (XtPointer)0 },
00087 { XPDFNselectionCallback, XmCCallback, XmRCallback,
00088 sizeof(XtCallbackList), XtOffsetOf(XPDFTreeRec, tree.selectCallback),
00089 XmRImmediate, (XtPointer)NULL }
00090 };
00091
00092 static XmSyntheticResource synResources[] = {
00093 { XmNmarginWidth, sizeof(Dimension),
00094 XtOffsetOf(XPDFTreeRec, tree.marginWidth),
00095 #if XmVERSION > 1
00096 XmeFromHorizontalPixels, XmeToHorizontalPixels
00097 #else
00098 _XmFromHorizontalPixels, _XmToHorizontalPixels
00099 #endif
00100 },
00101 { XmNmarginHeight, sizeof(Dimension),
00102 XtOffsetOf(XPDFTreeRec, tree.marginHeight),
00103 #if XmVERSION > 1
00104 XmeFromVerticalPixels, XmeToVerticalPixels
00105 #else
00106 _XmFromVerticalPixels, _XmToVerticalPixels
00107 #endif
00108 }
00109 };
00110
00111 static XtResource constraints[] = {
00112 { XPDFNentryParent, XPDFCentryParent, XmRWidget,
00113 sizeof(Widget), XtOffsetOf(XPDFTreeConstraintRec, tree.entryParent),
00114 XmRImmediate, (XtPointer)NULL },
00115 { XPDFNentryExpanded, XPDFCentryExpanded, XmRBoolean,
00116 sizeof(Boolean), XtOffsetOf(XPDFTreeConstraintRec, tree.entryExpanded),
00117 XmRImmediate, (XtPointer)False },
00118 { XPDFNentryPosition, XPDFCentryPosition, XmRInt,
00119 sizeof(int), XtOffsetOf(XPDFTreeConstraintRec, tree.entryPosition),
00120 XmRImmediate, (XtPointer)0 }
00121 };
00122
00123 static char defaultTranslations[] =
00124 "<Btn1Down>: XPDFTreeClick()";
00125
00126 static XtActionsRec actions[] = {
00127 { "XPDFTreeClick", click }
00128 };
00129
00130 externaldef(xpdftreeclassrec) XPDFTreeClassRec xpdfTreeClassRec = {
00131 {
00132 (WidgetClass)&xmManagerClassRec,
00133 "XPDFTree",
00134 sizeof(XPDFTreeRec),
00135 NULL,
00136 &classPartInitialize,
00137 FALSE,
00138 &initialize,
00139 NULL,
00140 XtInheritRealize,
00141 actions,
00142 XtNumber(actions),
00143 resources,
00144 XtNumber(resources),
00145 NULLQUARK,
00146 TRUE,
00147 XtExposeCompressMaximal,
00148 TRUE,
00149 FALSE,
00150 &destroy,
00151 &resize,
00152 &redisplay,
00153 &setValues,
00154 NULL,
00155 &setValuesAlmost,
00156 NULL,
00157 NULL,
00158 XtVersion,
00159 NULL,
00160 defaultTranslations,
00161 &queryGeometry,
00162 NULL,
00163 NULL
00164 },
00165 {
00166 &geometryManager,
00167 &changeManaged,
00168 XtInheritInsertChild,
00169 XtInheritDeleteChild,
00170 NULL
00171 },
00172 {
00173 constraints,
00174 XtNumber(constraints),
00175 sizeof(XPDFTreeConstraintRec),
00176 &initConstraint,
00177 &destroyConstraint,
00178 &constraintSetValues,
00179 NULL
00180 },
00181 {
00182 XtInheritTranslations,
00183 #if XmVERSION > 1
00184 synResources,
00185 XtNumber(synResources),
00186 #else
00187 NULL,
00188 0,
00189 #endif
00190 NULL,
00191 0,
00192 XmInheritParentProcess,
00193 NULL
00194 },
00195 {
00196 &createGC,
00197 &destroyGC,
00198 &layout,
00199 &calcSize,
00200 &needRelayout,
00201 NULL
00202 }
00203 };
00204
00205 externaldef(xpdftreewidgetclass) WidgetClass xpdfTreeWidgetClass =
00206 (WidgetClass)&xpdfTreeClassRec;
00207
00208
00209
00210 static void classPartInitialize(WidgetClass widgetCls) {
00211 XPDFTreeWidgetClass wc = (XPDFTreeWidgetClass)widgetCls;
00212 XPDFTreeWidgetClass sc = (XPDFTreeWidgetClass)wc->coreClass.superclass;
00213
00214
00215 if (wc->treeClass.createGC == XPDFInheritCreateGC) {
00216 wc->treeClass.createGC = sc->treeClass.createGC;
00217 }
00218 if (wc->treeClass.destroyGC == XPDFInheritDestroyGC) {
00219 wc->treeClass.destroyGC = sc->treeClass.destroyGC;
00220 }
00221 if (wc->treeClass.layout == XPDFInheritLayout) {
00222 wc->treeClass.layout = sc->treeClass.layout;
00223 }
00224 if (wc->treeClass.calcSize == XPDFInheritCalcSize) {
00225 wc->treeClass.calcSize = sc->treeClass.calcSize;
00226 }
00227 if (wc->treeClass.needRelayout == XPDFInheritNeedRelayout) {
00228 wc->treeClass.needRelayout = sc->treeClass.needRelayout;
00229 }
00230 }
00231
00232 static void initialize(Widget requestWidget, Widget newWidget,
00233 ArgList args, Cardinal *numArgs) {
00234 XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
00235 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget);
00236
00237 nw->tree.root = NULL;
00238 nw->tree.redrawY = -1;
00239 if (cls->treeClass.createGC) {
00240 (*cls->treeClass.createGC)(newWidget);
00241 } else {
00242 createGC(newWidget);
00243 }
00244 }
00245
00246 static void destroy(Widget widget) {
00247 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00248 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
00249
00250 if (w->tree.root) {
00251 destroySubtree(w->tree.root);
00252 w->tree.root = NULL;
00253 }
00254 if (cls->treeClass.destroyGC) {
00255 (*cls->treeClass.destroyGC)(widget);
00256 } else {
00257 destroyGC(widget);
00258 }
00259 }
00260
00261 static void destroySubtree(XPDFTreeEntry *e) {
00262 if (e->children) {
00263 destroySubtree(e->children);
00264 }
00265 if (e->next) {
00266 destroySubtree(e->next);
00267 }
00268 }
00269
00270 static void resize(Widget widget) {
00271 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
00272
00273 if (cls->treeClass.layout) {
00274 (*cls->treeClass.layout)(widget, NULL);
00275 } else {
00276 layout(widget, NULL);
00277 }
00278 }
00279
00280 static void redisplay(Widget widget, XEvent *event, Region region) {
00281 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00282 XPDFTreeEntry *e;
00283
00284 if (w->tree.redrawY >= 0) {
00285 XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
00286 0, w->tree.redrawY, w->core.width, w->core.height, False);
00287 w->tree.redrawY = -1;
00288 }
00289 for (e = w->tree.root; e; e = e->next) {
00290 redisplaySubtree(w, e, event, region);
00291 }
00292 }
00293
00294 static void redisplaySubtree(XPDFTreeWidget w, XPDFTreeEntry *e,
00295 XEvent *event, Region region) {
00296 XPDFTreeConstraint c;
00297 Position x, y, y2;
00298 XPDFTreeEntry *child;
00299
00300 (*XtClass(e->widget)->core_class.expose)(e->widget, event, region);
00301 c = XPDFTreeCPart(e->widget);
00302 x = e->widget->core.x;
00303 y = e->widget->core.y + e->widget->core.height / 2;
00304 if (e->children) {
00305 if (c->entryExpanded) {
00306 drawExpandedIcon(w, x - 8, y);
00307 y2 = y;
00308 for (child = e->children; child; child = child->next) {
00309 y2 = child->widget->core.y + child->widget->core.height / 2;
00310 XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC,
00311 x - 8, y2, x + 6, y2);
00312 redisplaySubtree(w, child, event, region);
00313 }
00314 XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.dottedGC,
00315 x - 8, y + 2, x - 8, y2);
00316 } else {
00317 drawCollapsedIcon(w, x - 8, y);
00318 }
00319 }
00320 }
00321
00322 static void drawExpandedIcon(XPDFTreeWidget w, Position x, Position y) {
00323 XPoint pts[4];
00324
00325 pts[0].x = x - 4; pts[0].y = y - 2;
00326 pts[1].x = x + 4; pts[1].y = y - 2;
00327 pts[2].x = x; pts[2].y = y + 2;
00328 pts[3].x = x - 4; pts[3].y = y - 2;
00329 XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC,
00330 pts, 4, CoordModeOrigin);
00331 }
00332
00333 static void drawCollapsedIcon(XPDFTreeWidget w, Position x, Position y) {
00334 XPoint pts[4];
00335
00336 pts[0].x = x - 2; pts[0].y = y - 4;
00337 pts[1].x = x - 2; pts[1].y = y + 4;
00338 pts[2].x = x + 2; pts[2].y = y;
00339 pts[3].x = x - 2; pts[3].y = y - 4;
00340 XDrawLines(XtDisplay((Widget)w), XtWindow((Widget)w), w->tree.plainGC,
00341 pts, 4, CoordModeOrigin);
00342 }
00343
00344 static Boolean setValues(Widget oldWidget, Widget requestWidget,
00345 Widget newWidget, ArgList args, Cardinal *numArgs) {
00346 XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget;
00347 XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
00348 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(nw);
00349 Boolean relayout, redisp;
00350
00351
00352 if (cls->treeClass.needRelayout) {
00353 relayout = (*cls->treeClass.needRelayout)((Widget)ow, (Widget)nw);
00354 } else {
00355 relayout = needRelayout((Widget)ow, (Widget)nw);
00356 }
00357 redisp = False;
00358 if (relayout) {
00359
00360
00361
00362 if (nw->core.width == ow->core.width) {
00363 nw->core.width = 0;
00364 }
00365 if (nw->core.height == ow->core.height) {
00366 nw->core.height = 0;
00367 }
00368 if (cls->treeClass.calcSize) {
00369 (*cls->treeClass.calcSize)((Widget)nw, NULL,
00370 &nw->core.width, &nw->core.height);
00371 } else {
00372 calcSize((Widget)nw, NULL, &nw->core.width, &nw->core.height);
00373 }
00374
00375
00376
00377 if (nw->core.width == ow->core.width &&
00378 nw->core.height == ow->core.height) {
00379 if (cls->treeClass.layout) {
00380 (*cls->treeClass.layout)((Widget)nw, NULL);
00381 } else {
00382 layout((Widget)nw, NULL);
00383 }
00384 redisp = True;
00385 }
00386 }
00387
00388 return redisp;
00389 }
00390
00391 static void setValuesAlmost(Widget oldWidget, Widget newWidget,
00392 XtWidgetGeometry *request,
00393 XtWidgetGeometry *reply) {
00394 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(newWidget);
00395
00396
00397
00398 if (!reply->request_mode) {
00399 if (cls->treeClass.layout) {
00400 (*cls->treeClass.layout)(newWidget, NULL);
00401 } else {
00402 layout(newWidget, NULL);
00403 }
00404 }
00405 *request = *reply;
00406 }
00407
00408 static XtGeometryResult queryGeometry(Widget widget,
00409 XtWidgetGeometry *request,
00410 XtWidgetGeometry *reply) {
00411 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
00412
00413 if (!XtIsRealized(widget)) {
00414 reply->width = XtWidth(widget);
00415 reply->height = XtHeight(widget);
00416 } else {
00417 reply->width = 0;
00418 reply->height = 0;
00419 }
00420 if (cls->treeClass.calcSize) {
00421 (*cls->treeClass.calcSize)(widget, NULL, &reply->width, &reply->height);
00422 } else {
00423 calcSize(widget, NULL, &reply->width, &reply->height);
00424 }
00425 #if XmVERSION > 1
00426 return XmeReplyToQueryGeometry(widget, request, reply);
00427 #else
00428 if ((request->request_mode & CWWidth) &&
00429 (request->request_mode & CWHeight) &&
00430 request->width == reply->width &&
00431 request->height == reply->height) {
00432 return XtGeometryYes;
00433 }
00434 if (reply->width == XtWidth(widget) &&
00435 reply->height == XtHeight(widget)) {
00436 return XtGeometryNo;
00437 }
00438 reply->request_mode = CWWidth | CWHeight;
00439 return XtGeometryAlmost;
00440 #endif
00441 }
00442
00443 static XtGeometryResult geometryManager(Widget widget,
00444 XtWidgetGeometry *request,
00445 XtWidgetGeometry *reply) {
00446 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget);
00447 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(w);
00448 Dimension curWidth, curHeight, curBW;
00449 XtWidgetGeometry parentReq;
00450 XtGeometryResult result;
00451
00452
00453 if ((request->request_mode & CWX) || (request->request_mode & CWY)) {
00454 return XtGeometryNo;
00455 }
00456
00457
00458 curWidth = w->core.width;
00459 curHeight = w->core.height;
00460 curBW = w->core.border_width;
00461
00462
00463 if (request->request_mode & CWWidth) {
00464 w->core.width = request->width;
00465 }
00466 if (request->request_mode & CWHeight) {
00467 w->core.height = request->height;
00468 }
00469 if (request->request_mode & CWBorderWidth) {
00470 w->core.border_width = request->border_width;
00471 }
00472
00473
00474 parentReq.width = 0;
00475 parentReq.height = 0;
00476 if (cls->treeClass.calcSize) {
00477 (*cls->treeClass.calcSize)((Widget)w, widget,
00478 &parentReq.width, &reply->height);
00479 } else {
00480 calcSize((Widget)w, widget, &parentReq.width, &reply->height);
00481 }
00482
00483
00484 parentReq.request_mode = CWWidth | CWHeight;
00485 if (request->request_mode & XtCWQueryOnly) {
00486 parentReq.request_mode |= XtCWQueryOnly;
00487 }
00488 result = XtMakeGeometryRequest((Widget)w, &parentReq, NULL);
00489 if (result == XtGeometryAlmost) {
00490 result = XtGeometryNo;
00491 }
00492
00493 if (result == XtGeometryNo || (request->request_mode & XtCWQueryOnly)) {
00494
00495 w->core.width = curWidth;
00496 w->core.height = curHeight;
00497 w->core.border_width = curBW;
00498 } else {
00499 if (cls->treeClass.layout) {
00500 (*cls->treeClass.layout)((Widget)w, widget);
00501 } else {
00502 layout((Widget)w, widget);
00503 }
00504 }
00505
00506 return result;
00507 }
00508
00509 static void changeManaged(Widget widget) {
00510 Dimension width, height;
00511 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass(widget);
00512
00513
00514 if (!XtIsRealized(widget)) {
00515 width = XtWidth(widget);
00516 height = XtHeight(widget);
00517 } else {
00518 width = 0;
00519 height = 0;
00520 }
00521 if (cls->treeClass.calcSize) {
00522 (*cls->treeClass.calcSize)(widget, NULL, &width, &height);
00523 } else {
00524 calcSize(widget, NULL, &width, &height);
00525 }
00526
00527
00528
00529 while (XtMakeResizeRequest(widget, width, height, &width, &height)
00530 == XtGeometryAlmost) ;
00531
00532
00533 if (cls->treeClass.layout) {
00534 (*cls->treeClass.layout)(widget, NULL);
00535 } else {
00536 layout(widget, NULL);
00537 }
00538
00539 #if XmVERSION > 1
00540
00541 XmeNavigChangeManaged(widget);
00542 #else
00543 _XmNavigChangeManaged(widget);
00544 #endif
00545 }
00546
00547 static void initConstraint(Widget requestWidget, Widget newWidget,
00548 ArgList args, Cardinal *numArgs) {
00549 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget);
00550 XPDFTreeConstraint c;
00551
00552 c = XPDFTreeCPart(newWidget);
00553 c->e = (XPDFTreeEntry *)gmalloc(sizeof(XPDFTreeEntry));
00554 c->e->widget = newWidget;
00555 c->e->children = NULL;
00556 c->e->next = NULL;
00557 if (c->entryParent) {
00558 insertChildOnList(c->e, &XPDFTreeCPart(c->entryParent)->e->children);
00559 } else {
00560 insertChildOnList(c->e, &w->tree.root);
00561 }
00562 }
00563
00564 static void destroyConstraint(Widget widget) {
00565 deleteSubtree(widget);
00566 }
00567
00568 static void deleteSubtree(Widget widget) {
00569 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(widget);
00570 XPDFTreeConstraint c;
00571
00572 c = XPDFTreeCPart(widget);
00573 if (!c->e) {
00574 return;
00575 }
00576 while (c->e->children) {
00577 deleteSubtree(c->e->children->widget);
00578 }
00579 if (c->entryParent) {
00580 deleteChildFromList(c->e, &XPDFTreeCPart(c->entryParent)->e->children);
00581 } else {
00582 deleteChildFromList(c->e, &w->tree.root);
00583 }
00584 gfree(c->e);
00585 c->e = NULL;
00586 }
00587
00588 static Boolean constraintSetValues(Widget oldWidget, Widget requestWidget,
00589 Widget newWidget,
00590 ArgList args, Cardinal *numArgs) {
00591 XPDFTreeWidget w = (XPDFTreeWidget)XtParent(newWidget);
00592 XPDFTreeWidgetClass cls = (XPDFTreeWidgetClass)XtClass((Widget)w);
00593 XPDFTreeConstraint oc, nc;
00594 Boolean relayout;
00595 Dimension width, height;
00596
00597 if (!XtIsManaged(newWidget)) {
00598 return False;
00599 }
00600 oc = XPDFTreeCPart(oldWidget);
00601 nc = XPDFTreeCPart(newWidget);
00602 relayout = False;
00603 if (nc->entryParent != oc->entryParent ||
00604 nc->entryPosition != oc->entryPosition) {
00605 if (oc->entryParent) {
00606 deleteChildFromList(oc->e, &XPDFTreeCPart(oc->entryParent)->e->children);
00607 } else {
00608 deleteChildFromList(oc->e, &w->tree.root);
00609 }
00610 if (nc->entryParent) {
00611 insertChildOnList(nc->e, &XPDFTreeCPart(nc->entryParent)->e->children);
00612 } else {
00613 insertChildOnList(nc->e, &w->tree.root);
00614 }
00615 relayout = True;
00616 } else if (nc->entryExpanded != oc->entryExpanded) {
00617 relayout = True;
00618 }
00619
00620 if (relayout) {
00621
00622
00623
00624 width = 0;
00625 height = 0;
00626 if (cls->treeClass.calcSize) {
00627 (*cls->treeClass.calcSize)((Widget)w, NULL, &width, &height);
00628 } else {
00629 calcSize((Widget)w, NULL, &width, &height);
00630 }
00631
00632
00633
00634 while (XtMakeResizeRequest((Widget)w, width, height, &width, &height)
00635 == XtGeometryAlmost) ;
00636
00637
00638 if (cls->treeClass.layout) {
00639 (*cls->treeClass.layout)((Widget)w, NULL);
00640 } else {
00641 layout((Widget)w, NULL);
00642 }
00643 }
00644
00645 return relayout;
00646 }
00647
00648 static void insertChildOnList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) {
00649 int pos;
00650 XPDFTreeEntry *e2;
00651
00652 pos = XPDFTreeCPart(e->widget)->entryPosition;
00653 if (!*listHead || pos < XPDFTreeCPart((*listHead)->widget)->entryPosition) {
00654 e->next = *listHead;
00655 *listHead = e;
00656 } else {
00657 for (e2 = *listHead;
00658 e2->next && pos >= XPDFTreeCPart(e2->next->widget)->entryPosition;
00659 e2 = e2->next) ;
00660 e->next = e2->next;
00661 e2->next = e;
00662 }
00663 }
00664
00665 static void deleteChildFromList(XPDFTreeEntry *e, XPDFTreeEntry **listHead) {
00666 XPDFTreeEntry **p;
00667
00668 for (p = listHead; *p; p = &(*p)->next) {
00669 if (*p == e) {
00670 *p = e->next;
00671 e->next = NULL;
00672 return;
00673 }
00674 }
00675 }
00676
00677 static void createGC(Widget widget) {
00678 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00679 XGCValues gcValues;
00680
00681 gcValues.foreground = w->manager.foreground;
00682 gcValues.line_width = 0;
00683 gcValues.line_style = LineSolid;
00684 w->tree.plainGC = XtGetGC(widget,
00685 GCForeground | GCLineWidth | GCLineStyle,
00686 &gcValues);
00687
00688 gcValues.line_style = LineOnOffDash;
00689 gcValues.dashes = 1;
00690 gcValues.dash_offset = 0;
00691 w->tree.dottedGC = XtGetGC(widget,
00692 GCForeground | GCLineWidth | GCLineStyle |
00693 GCDashList | GCDashOffset,
00694 &gcValues);
00695 }
00696
00697 static void destroyGC(Widget widget) {
00698 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00699
00700 XtReleaseGC(widget, w->tree.plainGC);
00701 XtReleaseGC(widget, w->tree.dottedGC);
00702 }
00703
00704 static void layout(Widget widget, Widget instigator) {
00705 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00706 XPDFTreeEntry *e;
00707 Position x, y;
00708
00709 x = w->tree.marginWidth + xpdfTreeIndent;
00710 y = w->tree.marginHeight;
00711 for (e = w->tree.root; e; e = e->next) {
00712 y = layoutSubtree(w, instigator, e, x, y, True);
00713 }
00714 }
00715
00716 static int layoutSubtree(XPDFTreeWidget w, Widget instigator,
00717 XPDFTreeEntry *e, Position x, Position y,
00718 Boolean visible) {
00719 Widget ew;
00720 XPDFTreeEntry *child;
00721 XPDFTreeConstraint c;
00722
00723 ew = e->widget;
00724 if (!XtIsManaged(ew)) {
00725 return y;
00726 }
00727 c = XPDFTreeCPart(ew);
00728
00729
00730 if (ew) {
00731 if (visible) {
00732 if (ew == instigator) {
00733 ew->core.x = x;
00734 ew->core.y = y;
00735 } else {
00736 #if XmVERSION > 1
00737 XmeConfigureObject(ew, x, y, ew->core.width, ew->core.height,
00738 ew->core.border_width);
00739 #else
00740 _XmConfigureObject(ew, x, y, ew->core.width, ew->core.height,
00741 ew->core.border_width);
00742 #endif
00743 }
00744 y += ew->core.height + 2 * ew->core.border_width;
00745 }
00746 }
00747
00748
00749 x += xpdfTreeIndent;
00750 for (child = e->children; child; child = child->next) {
00751 y = layoutSubtree(w, instigator, child, x, y,
00752 visible && (!c || c->entryExpanded));
00753 }
00754
00755 return y;
00756 }
00757
00758 static void calcSize(Widget widget, Widget instigator,
00759 Dimension *totalWidth,
00760 Dimension *totalHeight) {
00761 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00762 XPDFTreeEntry *e;
00763 Dimension w1, h1, w2, h2;
00764
00765 w1 = h1 = 0;
00766 for (e = w->tree.root; e; e = e->next) {
00767 calcSubtreeSize(w, instigator, e, &w2, &h2);
00768 if (w2 > w1) {
00769 w1 = w2;
00770 }
00771 h1 += h2;
00772 }
00773 w1 += xpdfTreeIndent + 2 * w->tree.marginWidth;
00774 h1 += 2 * w->tree.marginHeight;
00775 if (h1 == 0) {
00776 h1 = 1;
00777 }
00778 if (!*totalWidth) {
00779 *totalWidth = w1;
00780 }
00781 if (!*totalHeight) {
00782 *totalHeight = h1;
00783 }
00784 }
00785
00786 static void calcSubtreeSize(XPDFTreeWidget w, Widget instigator,
00787 XPDFTreeEntry *e,
00788 Dimension *width, Dimension *height) {
00789 Widget ew;
00790 XPDFTreeEntry *child;
00791 XPDFTreeConstraint c;
00792 XtWidgetGeometry geom;
00793 Dimension w1, h1, w2, h2;
00794
00795 ew = e->widget;
00796 if (!XtIsManaged(ew)) {
00797 *width = *height = 0;
00798 return;
00799 }
00800 c = XPDFTreeCPart(ew);
00801
00802
00803 if (ew) {
00804 if (!XtIsManaged(ew)) {
00805 *width = *height = 0;
00806 return;
00807 }
00808 if (ew == instigator) {
00809 w1 = ew->core.width;
00810 h1 = ew->core.height;
00811 } else {
00812 XtQueryGeometry(ew, NULL, &geom);
00813 w1 = (geom.request_mode & CWWidth) ? geom.width : ew->core.width;
00814 h1 = (geom.request_mode & CWHeight) ? geom.height : ew->core.height;
00815 }
00816 h1 += 2 * ew->core.border_width;
00817 } else {
00818
00819 w1 = 0;
00820 h1 = 0;
00821 }
00822
00823
00824 if (c->entryExpanded) {
00825 for (child = e->children; child; child = child->next) {
00826 calcSubtreeSize(w, instigator, child, &w2, &h2);
00827 w2 += xpdfTreeIndent;
00828 if (w2 > w1) {
00829 w1 = w2;
00830 }
00831 h1 += h2;
00832 }
00833 }
00834
00835 *width = w1;
00836 *height = h1;
00837 }
00838
00839 static Boolean needRelayout(Widget oldWidget, Widget newWidget) {
00840 XPDFTreeWidget ow = (XPDFTreeWidget)oldWidget;
00841 XPDFTreeWidget nw = (XPDFTreeWidget)newWidget;
00842
00843 if (nw->tree.marginWidth != ow->tree.marginWidth ||
00844 nw->tree.marginHeight != ow->tree.marginHeight) {
00845 return True;
00846 }
00847 return False;
00848 }
00849
00850 static void click(Widget widget, XEvent *event,
00851 String *params, Cardinal *numParams) {
00852 XPDFTreeWidget w = (XPDFTreeWidget)widget;
00853 XButtonPressedEvent *bpe;
00854 XPDFTreeEntry *e;
00855 Boolean onExpandIcon;
00856 XPDFTreeConstraint c;
00857 XPDFTreeSelectCallbackStruct cbs;
00858
00859 if (event->type != ButtonPress) {
00860 return;
00861 }
00862 bpe = (XButtonPressedEvent *)event;
00863 if (findPosition(w, bpe->x, bpe->y, &e, &onExpandIcon)) {
00864 if (onExpandIcon) {
00865 c = XPDFTreeCPart(e->widget);
00866 w->tree.redrawY = e->widget->core.y;
00867 XtVaSetValues(e->widget, XPDFNentryExpanded, !c->entryExpanded, NULL);
00868 } else {
00869 XmProcessTraversal(e->widget, XmTRAVERSE_CURRENT);
00870 XtCallActionProc(widget, "ManagerGadgetActivate", event, NULL, 0);
00871 cbs.reason = XmCR_ACTIVATE;
00872 cbs.event = event;
00873 cbs.selectedItem = e->widget;
00874 XtCallCallbackList(widget, w->tree.selectCallback, &cbs);
00875 }
00876 }
00877 }
00878
00879 static Boolean findPosition(XPDFTreeWidget w, int x, int y,
00880 XPDFTreeEntry **e, Boolean *onExpandIcon) {
00881 XPDFTreeEntry *e2;
00882
00883 for (e2 = w->tree.root; e2; e2 = e2->next) {
00884 *e = e2;
00885 if (findPositionInSubtree(w, x, y, e, onExpandIcon)) {
00886 return True;
00887 }
00888 }
00889 return False;
00890 }
00891
00892
00893
00894 static Boolean findPositionInSubtree(XPDFTreeWidget w, int x, int y,
00895 XPDFTreeEntry **e,
00896 Boolean *onExpandIcon) {
00897 Widget child;
00898 XPDFTreeConstraint c;
00899 XPDFTreeEntry *e2;
00900 int y1;
00901
00902 child = (*e)->widget;
00903 y1 = child->core.y + child->core.height / 2;
00904 if (x >= child->core.x && x < child->core.x + child->core.width &&
00905 y >= child->core.y && y < child->core.y + child->core.height) {
00906 *onExpandIcon = False;
00907 return True;
00908 } else if (x >= child->core.x - 16 && x < child->core.x - 4 &&
00909 y >= y1 - 6 && y < y1 + 6 &&
00910 (*e)->children) {
00911 *onExpandIcon = True;
00912 return True;
00913 }
00914 c = XPDFTreeCPart(child);
00915 if (!c || c->entryExpanded) {
00916 for (e2 = (*e)->children; e2; e2 = e2->next) {
00917 *e = e2;
00918 if (findPositionInSubtree(w, x, y, e, onExpandIcon)) {
00919 return True;
00920 }
00921 }
00922 }
00923 return False;
00924 }
00925
00926 Widget XPDFCreateTree(Widget parent, char *name,
00927 ArgList argList, Cardinal numArgs) {
00928 return XtCreateWidget(name, xpdfTreeWidgetClass, parent, argList, numArgs);
00929 }