|
|
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.