|
|
1.1 ! root 1: /* $Header: Form.c,v 1.1 87/09/11 07:58:23 toddb Exp $ */ ! 2: #ifndef lint ! 3: static char *sccsid = "@(#)Form.c 1.17 5/18/87"; ! 4: #endif lint ! 5: /* ! 6: * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. ! 7: * ! 8: * All Rights Reserved ! 9: * ! 10: * Permission to use, copy, modify, and distribute this software and its ! 11: * documentation for any purpose and without fee is hereby granted, ! 12: * provided that the above copyright notice appear in all copies and that ! 13: * both that copyright notice and this permission notice appear in ! 14: * supporting documentation, and that the name of Digital Equipment ! 15: * Corporation not be used in advertising or publicity pertaining to ! 16: * distribution of the software without specific, written prior permission. ! 17: * ! 18: * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 19: * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 20: * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 21: * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 22: * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 23: * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 24: * SOFTWARE. ! 25: */ ! 26: ! 27: #include "Xlib.h" ! 28: #include "Intrinsic.h" ! 29: #include "Form.h" ! 30: #include "Atoms.h" ! 31: ! 32: ! 33: /* Private Definitions */ ! 34: ! 35: ! 36: typedef struct SubWidgetDataRec { ! 37: Window w; /* Window id for this subwidget. */ ! 38: struct WidgetDataRec *data; /* Pointer to form widget data. */ ! 39: XtEdgeType top, bottom, left, right; ! 40: /* Where to drag things on resize. */ ! 41: int dx; /* Desired initial horiz offset. */ ! 42: Window fromhoriz; /* Other subwidget to base dx off of. ! 43: (NULL if form edge.) */ ! 44: int dy; /* Desired initial vertical offset. */ ! 45: Window fromvert; /* Other subwidget to base dy off of. ! 46: (NULL if form edge.) */ ! 47: Boolean allowresize; /* TRUE if we allow the subwidget to resize ! 48: itself. */ ! 49: WindowBox wb; /* Current coordinates. */ ! 50: } SubWidgetDataRec, *SubWidgetData; ! 51: ! 52: ! 53: static SubWidgetDataRec subglob; ! 54: static SubWidgetDataRec subinit = {0}; ! 55: ! 56: typedef struct WidgetDataRec { ! 57: Display *dpy; /* Display connection for the form widget */ ! 58: Window mywin; /* Window ID of form widget. */ ! 59: WindowBox wb; /* Coordinates of form widget. */ ! 60: SubWidgetData *sub; /* Array of subwidgets. */ ! 61: int numsub; /* Number of subwidgets. */ ! 62: Pixel background; /* Background color. */ ! 63: Pixel border; /* Border color. */ ! 64: int defaultdistance; /* Default distance between widgets. */ ! 65: int dontrefigure; /* Nonzero if we don't want to recalc. */ ! 66: Boolean needsrefigure; /* TRUE if we need to recalc. */ ! 67: } WidgetDataRec, *WidgetData; ! 68: ! 69: /* !!! STATIC !!! */ ! 70: static WidgetDataRec globaldata; ! 71: static WidgetDataRec globalinit = {0}; ! 72: ! 73: /* Private Data */ ! 74: ! 75: static Resource resources[] = { ! 76: {XtNwindow, XtCWindow, XrmRWindow, sizeof(Window), ! 77: (caddr_t)&globaldata.mywin, (caddr_t)NULL}, ! 78: {XtNborderWidth, XtCBorderWidth, XrmRInt, sizeof(int), ! 79: (caddr_t)&globaldata.wb.borderWidth, (caddr_t)NULL}, ! 80: {XtNx, XtCX, XrmRInt, sizeof(int), ! 81: (caddr_t)&globaldata.wb.x, (caddr_t)NULL}, ! 82: {XtNy, XtCY, XrmRInt, sizeof(int), ! 83: (caddr_t)&globaldata.wb.y, (caddr_t)NULL}, ! 84: {XtNwidth, XtCWidth, XrmRInt, sizeof(int), ! 85: (caddr_t)&globaldata.wb.width, (caddr_t)NULL}, ! 86: {XtNheight, XtCHeight, XrmRInt, sizeof(int), ! 87: (caddr_t)&globaldata.wb.height, (caddr_t)NULL}, ! 88: {XtNbackground, XtCColor, XrmRPixel, sizeof(Pixel), ! 89: (caddr_t)&globaldata.background, (caddr_t)&XtDefaultBGPixel}, ! 90: {XtNborder, XtCColor, XrmRPixel, sizeof(Pixel), ! 91: (caddr_t)&globaldata.border,(caddr_t)&XtDefaultFGPixel}, ! 92: {XtNdefaultDistance, XtCThickness, XrmRInt, ! 93: sizeof(int), (caddr_t)&globaldata.defaultdistance, (caddr_t)NULL}, ! 94: }; ! 95: ! 96: static XtEdgeType defEdge = XtRubber; ! 97: ! 98: static Resource subresources[] = { ! 99: {XtNtop, XtCEdge, XtRJustify, sizeof(XtEdgeType), ! 100: (caddr_t)&subglob.top, (caddr_t)&defEdge}, ! 101: {XtNbottom, XtCEdge, XtRJustify, sizeof(XtEdgeType), ! 102: (caddr_t)&subglob.bottom, (caddr_t)&defEdge}, ! 103: {XtNleft, XtCEdge, XtRJustify, sizeof(XtEdgeType), ! 104: (caddr_t)&subglob.left, (caddr_t)&defEdge}, ! 105: {XtNright, XtCEdge, XtRJustify, sizeof(XtEdgeType), ! 106: (caddr_t)&subglob.right, (caddr_t)&defEdge}, ! 107: {XtNfromHoriz, XtCWindow, XrmRWindow, sizeof(Window), ! 108: (caddr_t)&subglob.fromhoriz, (caddr_t)NULL}, ! 109: {XtNfromVert, XtCWindow, XrmRWindow, sizeof(Window), ! 110: (caddr_t)&subglob.fromvert, (caddr_t)NULL}, ! 111: {XtNhorizDistance, XtCThickness, XrmRInt, sizeof(int), ! 112: (caddr_t)&subglob.dx, (caddr_t)NULL}, ! 113: {XtNvertDistance, XtCThickness, XrmRInt, sizeof(int), ! 114: (caddr_t)&subglob.dy, (caddr_t)NULL}, ! 115: {XtNresizable, XtCBoolean, XrmRBoolean, sizeof(Boolean), ! 116: (caddr_t)&subglob.allowresize, (caddr_t) NULL} ! 117: }; ! 118: ! 119: ! 120: static XContext formContext; ! 121: static XContext subContext; ! 122: ! 123: /**************************************************************** ! 124: * ! 125: * Private Procedures ! 126: * ! 127: ****************************************************************/ ! 128: ! 129: static Boolean initialized = FALSE; ! 130: ! 131: static void Initialize () ! 132: { ! 133: if (initialized) ! 134: return; ! 135: initialized = TRUE; ! 136: ! 137: subinit.top = subinit.bottom = subinit.left = subinit.right = XtRubber; ! 138: subinit.wb.x = subinit.wb.y = -1; ! 139: ! 140: globalinit.wb.width = globalinit.wb.height = 10; ! 141: globalinit.wb.x = globalinit.wb.y = 0; ! 142: globalinit.defaultdistance = 4; ! 143: globalinit.wb.borderWidth = 1; ! 144: ! 145: formContext = XUniqueContext(); ! 146: subContext = XUniqueContext(); ! 147: } ! 148: ! 149: ! 150: static WidgetData DataFromWindow(dpy, w) ! 151: Display *dpy; ! 152: Window w; ! 153: { ! 154: WidgetData result; ! 155: if (XFindContext(dpy, w, formContext, (caddr_t *)&result)) ! 156: return NULL; ! 157: return result; ! 158: } ! 159: ! 160: static SubWidgetData SubFromWindow(dpy, w) ! 161: Display *dpy; ! 162: Window w; ! 163: { ! 164: SubWidgetData result; ! 165: if (XFindContext(dpy, w, subContext, (caddr_t *)&result)) ! 166: return NULL; ! 167: return result; ! 168: } ! 169: ! 170: static void RefigureLocations(data) ! 171: WidgetData data; ! 172: { ! 173: int i; ! 174: Position x, y, maxx, maxy; ! 175: SubWidgetData sub, sub2; ! 176: WindowBox reqBox, replBox; ! 177: XtGeometryReturnCode result; ! 178: if (data->dontrefigure) { ! 179: data->needsrefigure = TRUE; ! 180: return; ! 181: } ! 182: maxx = maxy = 0; ! 183: for (i=0 ; i<data->numsub ; i++) { ! 184: sub = data->sub[i]; ! 185: x = sub->dx; ! 186: y = sub->dy; ! 187: if (sub->fromhoriz && (sub2 = SubFromWindow(data->dpy, sub->fromhoriz))) ! 188: x += sub2->wb.x + sub2->wb.width; ! 189: if (sub->fromvert && (sub2 = SubFromWindow(data->dpy, sub->fromvert))) ! 190: y += sub2->wb.y + sub2->wb.height; ! 191: if (x != sub->wb.x || y != sub->wb.y) { ! 192: XMoveWindow(data->dpy, sub->w, x, y); ! 193: sub->wb.x = x; ! 194: sub->wb.y = y; ! 195: } ! 196: if (maxx < x + sub->wb.width) maxx = x + sub->wb.width; ! 197: if (maxy < y + sub->wb.height) maxy = y + sub->wb.height; ! 198: } ! 199: maxx += data->defaultdistance; ! 200: maxy += data->defaultdistance; ! 201: if (maxx != data->wb.width || maxy != data->wb.height) { ! 202: reqBox.width = maxx; ! 203: reqBox.height = maxy; ! 204: result = XtMakeGeometryRequest(data->dpy, data->mywin, XtgeometryResize, ! 205: &reqBox, &replBox); ! 206: if (result == XtgeometryAlmost) { ! 207: replBox = reqBox; ! 208: result = XtMakeGeometryRequest(data->dpy, data->mywin, XtgeometryResize, ! 209: &reqBox, &replBox); ! 210: } ! 211: if (result == XtgeometryYes) { ! 212: data->wb.width = reqBox.width; ! 213: data->wb.height = reqBox.height; ! 214: } ! 215: } ! 216: data->needsrefigure = FALSE; ! 217: } ! 218: ! 219: ! 220: static int MoveEdge(loc, old, new, type) ! 221: int loc, old, new; ! 222: XtEdgeType type; ! 223: { ! 224: if (type == XtRubber) ! 225: return loc * new / old; ! 226: if (type == XtChainTop || type == XtChainLeft) ! 227: return loc; ! 228: return loc + new - old; ! 229: } ! 230: ! 231: static void ChangeSize(data, newwidth, newheight) ! 232: WidgetData data; ! 233: int newwidth, newheight; ! 234: { ! 235: int i; ! 236: SubWidgetData sub; ! 237: WindowBox wb; ! 238: for (i=0 ; i<data->numsub ; i++) { ! 239: sub = data->sub[i]; ! 240: wb.borderWidth = sub->wb.borderWidth; ! 241: wb.x = MoveEdge(sub->wb.x, (int)data->wb.width, newwidth, sub->left); ! 242: wb.y = MoveEdge(sub->wb.y, (int)data->wb.height, newheight, sub->top); ! 243: wb.width = ! 244: MoveEdge((int)(sub->wb.x + sub->wb.width), ! 245: (int)data->wb.width, newwidth, sub->right) - wb.x; ! 246: wb.height = MoveEdge((int)(sub->wb.y + sub->wb.height), ! 247: (int)data->wb.height, newheight, sub->bottom) ! 248: - wb.y; ! 249: if (wb.width < 1) wb.width = 1; ! 250: if (wb.height < 1) wb.height = 1; ! 251: if (wb.x != sub->wb.x || wb.y != sub->wb.y || ! 252: wb.width != sub->wb.width || wb.height != sub->wb.height) { ! 253: XMoveResizeWindow(data->dpy, sub->w, wb.x, wb.y, ! 254: wb.width, wb.height); ! 255: (void) XtSendConfigureNotify(data->dpy, sub->w, &wb); ! 256: sub->wb = wb; ! 257: } ! 258: } ! 259: data->wb.width = newwidth; ! 260: data->wb.height = newheight; ! 261: } ! 262: ! 263: ! 264: /* ARGSUSED */ ! 265: static XtGeometryReturnCode FormGeometryHandler(dpy, w, req, reqBox, replBox) ! 266: Display *dpy; ! 267: Window w; ! 268: XtGeometryRequest req; ! 269: WindowBox *reqBox; ! 270: WindowBox *replBox; /* RETURN */ ! 271: { ! 272: SubWidgetData sub; ! 273: sub = SubFromWindow(dpy, w); ! 274: if (sub && req == XtgeometryResize && sub->allowresize) { ! 275: XResizeWindow(sub->data->dpy, sub->w, reqBox->width, reqBox->height); ! 276: *replBox = *reqBox; ! 277: sub->wb.width = reqBox->width; ! 278: sub->wb.height = reqBox->height; ! 279: (void) XtSendConfigureNotify(sub->data->dpy, w, &(sub->wb)); ! 280: RefigureLocations(sub->data); ! 281: return XtgeometryYes; ! 282: } ! 283: return XtgeometryNo; ! 284: } ! 285: ! 286: ! 287: /* ! 288: * ! 289: * Destroy the widget ! 290: * ! 291: */ ! 292: ! 293: static void Destroy(data) ! 294: WidgetData data; ! 295: { ! 296: int i; ! 297: for (i=0 ; i<data->numsub; i++) { ! 298: (void) XDeleteContext(data->dpy, data->sub[i]->w, subContext); ! 299: (void) XtSendDestroyNotify(data->dpy, data->sub[i]->w); ! 300: } ! 301: XtClearEventHandlers(data->dpy, data->mywin); ! 302: (void) XDeleteContext(data->dpy, data->mywin, formContext); ! 303: XtFree((char *) data->sub); ! 304: XtFree((char *) data); ! 305: } ! 306: ! 307: ! 308: /* ! 309: * ! 310: * Generic widget event handler ! 311: * ! 312: */ ! 313: ! 314: static XtEventReturnCode EventHandler(event, eventdata) ! 315: XEvent *event; ! 316: caddr_t eventdata; ! 317: { ! 318: WidgetData data = (WidgetData ) eventdata; ! 319: int newwidth, newheight; ! 320: ! 321: switch (event->type) { ! 322: case ConfigureNotify: ! 323: newwidth = event->xconfigure.width; ! 324: newheight = event->xconfigure.height; ! 325: if (newwidth != data->wb.width || newheight != data->wb.height) ! 326: ChangeSize(data, newwidth, newheight); ! 327: break; ! 328: ! 329: case DestroyNotify: ! 330: Destroy(data); ! 331: break; ! 332: ! 333: } ! 334: return (XteventHandled); ! 335: } ! 336: ! 337: /* ! 338: * Handle events in subwidgets. ! 339: */ ! 340: ! 341: static XtEventReturnCode SubEventHandler(event, sub) ! 342: XEvent *event; ! 343: SubWidgetData sub; ! 344: { ! 345: if (event->type == DestroyNotify) { ! 346: XtFormRemoveWidget(sub->data->dpy, sub->data->mywin, sub->w); ! 347: return XteventHandled; ! 348: } ! 349: return XteventNotHandled; ! 350: } ! 351: ! 352: /**************************************************************** ! 353: * ! 354: * Public Procedures ! 355: * ! 356: ****************************************************************/ ! 357: ! 358: Window XtFormCreate(dpy, parent, args, argCount) ! 359: Display *dpy; ! 360: Window parent; ! 361: ArgList args; ! 362: int argCount; ! 363: { ! 364: WidgetData data; ! 365: XrmNameList names; ! 366: XrmClassList classes; ! 367: if (!initialized) ! 368: Initialize (); ! 369: ! 370: data = (WidgetData) XtMalloc(sizeof(WidgetDataRec)); ! 371: ! 372: /* Set Default Values */ ! 373: globaldata = globalinit; ! 374: globaldata.dpy = dpy; ! 375: XtGetResources(dpy, resources, XtNumber(resources), args, argCount, parent, ! 376: "form", "Form", &names, &classes); ! 377: *data = globaldata; ! 378: ! 379: data->numsub = 0; ! 380: data->sub = (SubWidgetData *)XtMalloc(sizeof(SubWidgetData)); ! 381: if (data->mywin != NULL) { ! 382: XWindowAttributes wi; ! 383: /* set global data from window parameters */ ! 384: if (! XGetWindowAttributes(data->dpy, data->mywin, &wi)) { ! 385: data->mywin = NULL; ! 386: } else { ! 387: data->wb.borderWidth = wi.border_width; ! 388: data->wb.width = wi.width; ! 389: data->wb.height = wi.height; ! 390: data->wb.x = wi.x; ! 391: data->wb.y = wi.y; ! 392: } ! 393: } ! 394: if (data->mywin == NULL) { ! 395: /* create the Form window */ ! 396: data->mywin = XCreateSimpleWindow(data->dpy, parent, data->wb.x, ! 397: data->wb.y, data->wb.width, data->wb.height, ! 398: data->wb.borderWidth, ! 399: data->border, data->background); ! 400: } ! 401: ! 402: XtSetNameAndClass(data->dpy, data->mywin, names, classes); ! 403: XrmFreeNameList(names); ! 404: XrmFreeClassList(classes); ! 405: (void) XSaveContext(data->dpy, data->mywin, formContext, (caddr_t)data); ! 406: ! 407: /* set handler for resize, and message events */ ! 408: ! 409: XtSetEventHandler (data->dpy, data->mywin, (XtEventHandler)EventHandler, ! 410: StructureNotifyMask, (caddr_t)data); ! 411: ! 412: return (data->mywin); ! 413: } ! 414: ! 415: /* ! 416: * ! 417: * Get Attributes ! 418: * ! 419: */ ! 420: ! 421: void XtFormGetValues (dpy, w, args, argCount) ! 422: Display *dpy; ! 423: Window w; ! 424: ArgList args; ! 425: int argCount; ! 426: { ! 427: WidgetData data; ! 428: ! 429: if ((data = DataFromWindow(dpy, w)) == NULL) ! 430: return; ! 431: globaldata = *data; ! 432: XtGetValues(resources, XtNumber(resources), args, argCount); ! 433: } ! 434: ! 435: /* ! 436: * ! 437: * Set Values ! 438: * ! 439: */ ! 440: ! 441: void XtFormSetValues (dpy, w, args, argCount) ! 442: Display *dpy; ! 443: Window w; ! 444: ArgList args; ! 445: int argCount; ! 446: { ! 447: WidgetData data; ! 448: ! 449: if ((data = DataFromWindow(dpy, w)) == NULL) ! 450: return; ! 451: globaldata = *data; ! 452: XtSetValues(resources, XtNumber(resources), args, argCount); ! 453: *data = globaldata; ! 454: } ! 455: ! 456: ! 457: /* ! 458: * Add a new widget to the form. ! 459: */ ! 460: ! 461: void XtFormAddWidget(dpy, mywin, w, args, argCount) ! 462: Display *dpy; ! 463: Window mywin, w; ! 464: ArgList args; ! 465: int argCount; ! 466: { ! 467: WidgetData data; ! 468: SubWidgetData sub; ! 469: XrmNameList names; ! 470: XrmClassList classes; ! 471: XWindowAttributes info; ! 472: if ((data = DataFromWindow(dpy, mywin)) == NULL) return; ! 473: if ((sub = SubFromWindow(dpy, w)) == NULL) { ! 474: data->sub = (SubWidgetData *) ! 475: XtRealloc((char *) data->sub, ! 476: (unsigned) sizeof(SubWidgetData) * ++data->numsub); ! 477: sub = data->sub[data->numsub - 1] = ! 478: (SubWidgetData) XtMalloc(sizeof(SubWidgetDataRec)); ! 479: (void)XSaveContext(dpy, w, subContext, (caddr_t)sub); ! 480: *sub = subinit; ! 481: sub->data = data; ! 482: sub->w = w; ! 483: sub->dx = sub->dy = data->defaultdistance; ! 484: (void) XGetWindowAttributes(data->dpy, w, &info); /* %%% Icky-poo. */ ! 485: sub->wb.width = info.width; ! 486: sub->wb.height = info.height; ! 487: sub->wb.borderWidth = info.border_width; ! 488: (void) XtSetGeometryHandler(dpy, w, (XtGeometryHandler) FormGeometryHandler); ! 489: (void) XtSetEventHandler(dpy, w, (XtEventHandler)SubEventHandler, ! 490: StructureNotifyMask, (caddr_t)sub); ! 491: } ! 492: subglob = *sub; ! 493: XtGetResources(dpy, subresources, XtNumber(subresources), args, argCount, ! 494: w, "ignore", "Ignore", &names, &classes); ! 495: *sub = subglob; ! 496: XrmFreeNameList(names); ! 497: XrmFreeClassList(classes); ! 498: RefigureLocations(data); ! 499: XMapWindow(data->dpy, w); ! 500: } ! 501: ! 502: ! 503: /* ! 504: * Remove a subwidget from a form. Doesn't delete the subwidget. ! 505: */ ! 506: ! 507: void XtFormRemoveWidget(dpy, mywin, w) ! 508: Display *dpy; ! 509: Window mywin, w; ! 510: { ! 511: WidgetData data; ! 512: SubWidgetData sub; ! 513: Boolean found; ! 514: int i; ! 515: if ((data = DataFromWindow(dpy, mywin)) == NULL || ! 516: (sub = SubFromWindow(dpy, w)) == NULL) return; ! 517: found = FALSE; ! 518: for (i=0 ; i<data->numsub ; i++) { ! 519: if (data->sub[i]->fromhoriz == w) ! 520: data->sub[i]->fromhoriz = sub->fromhoriz; ! 521: if (data->sub[i]->fromvert == w) ! 522: data->sub[i]->fromvert = sub->fromvert; ! 523: if (!found) found = (data->sub[i] == sub); ! 524: if (found) data->sub[i] = data->sub[i+1]; ! 525: } ! 526: if (found) (data->numsub)--; ! 527: XtSetEventHandler(dpy, w, (XtEventHandler) SubEventHandler, ! 528: (unsigned long) 0, (caddr_t) NULL); ! 529: (void) XtClearGeometryHandler(dpy, w); ! 530: (void) XDeleteContext(dpy, w, subContext); ! 531: XtFree((char *)sub); ! 532: } ! 533: ! 534: ! 535: ! 536: /* ! 537: * Set or reset figuring ! 538: */ ! 539: ! 540: void XtFormDoLayout(dpy, mywin, doit) ! 541: Display *dpy; ! 542: Window mywin; ! 543: Boolean doit; ! 544: { ! 545: WidgetData data; ! 546: if ((data = DataFromWindow(dpy, mywin)) == NULL) ! 547: return; ! 548: if (doit && data->dontrefigure > 0) data->dontrefigure--; ! 549: else data->dontrefigure++; ! 550: if (data->needsrefigure) RefigureLocations(data); ! 551: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.