|
1 #ifndef lint |
|
2 static char Xrcsid[] = "$XConsortium: Form.c,v 1.34 89/12/13 13:51:07 kit Exp $"; |
|
3 #endif /* lint */ |
|
4 |
|
5 |
|
6 /*********************************************************** |
|
7 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts, |
|
8 and the Massachusetts Institute of Technology, Cambridge, Massachusetts. |
|
9 |
|
10 All Rights Reserved |
|
11 |
|
12 Permission to use, copy, modify, and distribute this software and its |
|
13 documentation for any purpose and without fee is hereby granted, |
|
14 provided that the above copyright notice appear in all copies and that |
|
15 both that copyright notice and this permission notice appear in |
|
16 supporting documentation, and that the names of Digital or MIT not be |
|
17 used in advertising or publicity pertaining to distribution of the |
|
18 software without specific, written prior permission. |
|
19 |
|
20 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING |
|
21 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL |
|
22 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR |
|
23 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, |
|
24 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, |
|
25 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
|
26 SOFTWARE. |
|
27 |
|
28 ******************************************************************/ |
|
29 |
|
30 #include <X11/IntrinsicP.h> |
|
31 #include <X11/StringDefs.h> |
|
32 #include <X11/Xmu/Converters.h> |
|
33 #include <X11/Xmu/CharSet.h> |
|
34 #include <./Xaw3_1XawInit.h> |
|
35 #include <./Xaw3_1FormP.h> |
|
36 |
|
37 /* Private Definitions */ |
|
38 |
|
39 static int default_value = -99999; |
|
40 |
|
41 #define Offset(field) XtOffset(FormWidget, form.field) |
|
42 static XtResource resources[] = { |
|
43 {XtNdefaultDistance, XtCThickness, XtRInt, sizeof(int), |
|
44 Offset(default_spacing), XtRImmediate, (caddr_t)4} |
|
45 }; |
|
46 #undef Offset |
|
47 |
|
48 static XtEdgeType defEdge = XtRubber; |
|
49 |
|
50 #define Offset(field) XtOffset(FormConstraints, form.field) |
|
51 static XtResource formConstraintResources[] = { |
|
52 {XtNtop, XtCEdge, XtREdgeType, sizeof(XtEdgeType), |
|
53 Offset(top), XtREdgeType, (XtPointer)&defEdge}, |
|
54 {XtNbottom, XtCEdge, XtREdgeType, sizeof(XtEdgeType), |
|
55 Offset(bottom), XtREdgeType, (XtPointer)&defEdge}, |
|
56 {XtNleft, XtCEdge, XtREdgeType, sizeof(XtEdgeType), |
|
57 Offset(left), XtREdgeType, (XtPointer)&defEdge}, |
|
58 {XtNright, XtCEdge, XtREdgeType, sizeof(XtEdgeType), |
|
59 Offset(right), XtREdgeType, (XtPointer)&defEdge}, |
|
60 {XtNhorizDistance, XtCThickness, XtRInt, sizeof(int), |
|
61 Offset(dx), XtRInt, (XtPointer) &default_value}, |
|
62 {XtNfromHoriz, XtCWidget, XtRWidget, sizeof(Widget), |
|
63 Offset(horiz_base), XtRWidget, (XtPointer)NULL}, |
|
64 {XtNvertDistance, XtCThickness, XtRInt, sizeof(int), |
|
65 Offset(dy), XtRInt, (XtPointer) &default_value}, |
|
66 {XtNfromVert, XtCWidget, XtRWidget, sizeof(Widget), |
|
67 Offset(vert_base), XtRWidget, (XtPointer)NULL}, |
|
68 {XtNresizable, XtCBoolean, XtRBoolean, sizeof(Boolean), |
|
69 Offset(allow_resize), XtRImmediate, (XtPointer) FALSE}, |
|
70 }; |
|
71 #undef Offset |
|
72 |
|
73 static void ClassInitialize(), ClassPartInitialize(), Initialize(), Resize(); |
|
74 static void ConstraintInitialize(); |
|
75 static Boolean SetValues(), ConstraintSetValues(); |
|
76 static XtGeometryResult GeometryManager(), PreferredGeometry(); |
|
77 static void ChangeManaged(); |
|
78 static Boolean Layout(); |
|
79 |
|
80 FormClassRec formClassRec = { |
|
81 { /* core_class fields */ |
|
82 /* superclass */ (WidgetClass) &constraintClassRec, |
|
83 /* class_name */ "Form", |
|
84 /* widget_size */ sizeof(FormRec), |
|
85 /* class_initialize */ ClassInitialize, |
|
86 /* class_part_init */ ClassPartInitialize, |
|
87 /* class_inited */ FALSE, |
|
88 /* initialize */ Initialize, |
|
89 /* initialize_hook */ NULL, |
|
90 /* realize */ XtInheritRealize, |
|
91 /* actions */ NULL, |
|
92 /* num_actions */ 0, |
|
93 /* resources */ resources, |
|
94 /* num_resources */ XtNumber(resources), |
|
95 /* xrm_class */ NULLQUARK, |
|
96 /* compress_motion */ TRUE, |
|
97 /* compress_exposure */ TRUE, |
|
98 /* compress_enterleave*/ TRUE, |
|
99 /* visible_interest */ FALSE, |
|
100 /* destroy */ NULL, |
|
101 /* resize */ Resize, |
|
102 /* expose */ XtInheritExpose, |
|
103 /* set_values */ SetValues, |
|
104 /* set_values_hook */ NULL, |
|
105 /* set_values_almost */ XtInheritSetValuesAlmost, |
|
106 /* get_values_hook */ NULL, |
|
107 /* accept_focus */ NULL, |
|
108 /* version */ XtVersion, |
|
109 /* callback_private */ NULL, |
|
110 /* tm_table */ NULL, |
|
111 /* query_geometry */ PreferredGeometry, |
|
112 /* display_accelerator*/ XtInheritDisplayAccelerator, |
|
113 /* extension */ NULL |
|
114 }, |
|
115 { /* composite_class fields */ |
|
116 /* geometry_manager */ GeometryManager, |
|
117 /* change_managed */ ChangeManaged, |
|
118 /* insert_child */ XtInheritInsertChild, |
|
119 /* delete_child */ XtInheritDeleteChild, |
|
120 /* extension */ NULL |
|
121 }, |
|
122 { /* constraint_class fields */ |
|
123 /* subresourses */ formConstraintResources, |
|
124 /* subresource_count */ XtNumber(formConstraintResources), |
|
125 /* constraint_size */ sizeof(FormConstraintsRec), |
|
126 /* initialize */ ConstraintInitialize, |
|
127 /* destroy */ NULL, |
|
128 /* set_values */ ConstraintSetValues, |
|
129 /* extension */ NULL |
|
130 }, |
|
131 { /* form_class fields */ |
|
132 /* layout */ Layout |
|
133 } |
|
134 }; |
|
135 |
|
136 WidgetClass formWidgetClass = (WidgetClass)&formClassRec; |
|
137 |
|
138 /**************************************************************** |
|
139 * |
|
140 * Private Procedures |
|
141 * |
|
142 ****************************************************************/ |
|
143 |
|
144 |
|
145 static XrmQuark XtQChainLeft, XtQChainRight, XtQChainTop, |
|
146 XtQChainBottom, XtQRubber; |
|
147 |
|
148 #define done(address, type) \ |
|
149 { toVal->size = sizeof(type); \ |
|
150 toVal->addr = (caddr_t) address; \ |
|
151 return; \ |
|
152 } |
|
153 |
|
154 /* ARGSUSED */ |
|
155 static void _CvtStringToEdgeType(args, num_args, fromVal, toVal) |
|
156 XrmValuePtr args; /* unused */ |
|
157 Cardinal *num_args; /* unused */ |
|
158 XrmValuePtr fromVal; |
|
159 XrmValuePtr toVal; |
|
160 { |
|
161 static XtEdgeType edgeType; |
|
162 XrmQuark q; |
|
163 char lowerName[1000]; |
|
164 |
|
165 XmuCopyISOLatin1Lowered (lowerName, (char*)fromVal->addr); |
|
166 q = XrmStringToQuark(lowerName); |
|
167 if (q == XtQChainLeft) { |
|
168 edgeType = XtChainLeft; |
|
169 done(&edgeType, XtEdgeType); |
|
170 } |
|
171 if (q == XtQChainRight) { |
|
172 edgeType = XtChainRight; |
|
173 done(&edgeType, XtEdgeType); |
|
174 } |
|
175 if (q == XtQChainTop) { |
|
176 edgeType = XtChainTop; |
|
177 done(&edgeType, XtEdgeType); |
|
178 } |
|
179 if (q == XtQChainBottom) { |
|
180 edgeType = XtChainBottom; |
|
181 done(&edgeType, XtEdgeType); |
|
182 } |
|
183 if (q == XtQRubber) { |
|
184 edgeType = XtRubber; |
|
185 done(&edgeType, XtEdgeType); |
|
186 } |
|
187 XtStringConversionWarning(fromVal->addr, "edgeType"); |
|
188 toVal->addr = NULL; |
|
189 toVal->size = 0; |
|
190 } |
|
191 |
|
192 static void ClassInitialize() |
|
193 { |
|
194 static XtConvertArgRec parentCvtArgs[] = { |
|
195 {XtBaseOffset, (caddr_t)XtOffset(Widget, core.parent), sizeof(Widget)} |
|
196 }; |
|
197 XawInitializeWidgetSet(); |
|
198 XtQChainLeft = XrmStringToQuark("chainleft"); |
|
199 XtQChainRight = XrmStringToQuark("chainright"); |
|
200 XtQChainTop = XrmStringToQuark("chaintop"); |
|
201 XtQChainBottom = XrmStringToQuark("chainbottom"); |
|
202 XtQRubber = XrmStringToQuark("rubber"); |
|
203 |
|
204 XtAddConverter( XtRString, XtREdgeType, _CvtStringToEdgeType, NULL, 0 ); |
|
205 XtAddConverter( XtRString, XtRWidget, XmuCvtStringToWidget, |
|
206 parentCvtArgs, XtNumber(parentCvtArgs) ); |
|
207 } |
|
208 |
|
209 static void ClassPartInitialize(class) |
|
210 WidgetClass class; |
|
211 { |
|
212 register FormWidgetClass c = (FormWidgetClass)class; |
|
213 |
|
214 if (c->form_class.layout == XtInheritLayout) |
|
215 c->form_class.layout = Layout; |
|
216 } |
|
217 |
|
218 |
|
219 /* ARGSUSED */ |
|
220 static void Initialize(request, new) |
|
221 Widget request, new; |
|
222 { |
|
223 FormWidget fw = (FormWidget)new; |
|
224 |
|
225 fw->form.old_width = fw->core.width; |
|
226 fw->form.old_height = fw->core.height; |
|
227 fw->form.no_refigure = False; |
|
228 fw->form.needs_relayout = False; |
|
229 fw->form.resize_in_layout = True; |
|
230 } |
|
231 |
|
232 |
|
233 static void RefigureLocations(w) |
|
234 FormWidget w; |
|
235 { |
|
236 if (w->form.no_refigure) { |
|
237 w->form.needs_relayout = True; |
|
238 } |
|
239 else { |
|
240 (*((FormWidgetClass)w->core.widget_class)->form_class.layout) |
|
241 ( w, w->core.width, w->core.height ); |
|
242 w->form.needs_relayout = False; |
|
243 } |
|
244 } |
|
245 |
|
246 /* ARGSUSED */ |
|
247 static Boolean Layout(fw, width, height) |
|
248 FormWidget fw; |
|
249 Dimension width, height; |
|
250 { |
|
251 int num_children = fw->composite.num_children; |
|
252 WidgetList children = fw->composite.children; |
|
253 Widget *childP; |
|
254 Position maxx, maxy; |
|
255 static void LayoutChild(); |
|
256 Boolean ret_val; |
|
257 |
|
258 for (childP = children; childP - children < num_children; childP++) { |
|
259 FormConstraints form = (FormConstraints)(*childP)->core.constraints; |
|
260 form->form.layout_state = LayoutPending; |
|
261 } |
|
262 |
|
263 maxx = maxy = 1; |
|
264 for (childP = children; childP - children < num_children; childP++) { |
|
265 if (XtIsManaged(*childP)) { |
|
266 Position x, y; |
|
267 LayoutChild(*childP); |
|
268 x = (*childP)->core.x + (*childP)->core.width |
|
269 + ((*childP)->core.border_width << 1); |
|
270 y = (*childP)->core.y + (*childP)->core.height |
|
271 + ((*childP)->core.border_width << 1); |
|
272 if (maxx < x) maxx = x; |
|
273 if (maxy < y) maxy = y; |
|
274 } |
|
275 } |
|
276 |
|
277 fw->form.preferred_width = (maxx += fw->form.default_spacing); |
|
278 fw->form.preferred_height = (maxy += fw->form.default_spacing); |
|
279 |
|
280 if (fw->form.resize_in_layout |
|
281 && (maxx != fw->core.width || maxy != fw->core.height)) { |
|
282 XtGeometryResult result; |
|
283 result = XtMakeResizeRequest((Widget)fw, |
|
284 (Dimension)maxx, (Dimension)maxy, |
|
285 (Dimension*)&maxx, (Dimension*)&maxy ); |
|
286 if (result == XtGeometryAlmost) |
|
287 result = XtMakeResizeRequest((Widget)fw, |
|
288 (Dimension)maxx, (Dimension)maxy, |
|
289 NULL, NULL ); |
|
290 fw->form.old_width = fw->core.width; |
|
291 fw->form.old_height = fw->core.height; |
|
292 ret_val = (result == XtGeometryYes); |
|
293 } else ret_val = False; |
|
294 |
|
295 return ret_val; |
|
296 } |
|
297 |
|
298 |
|
299 static void LayoutChild(w) |
|
300 Widget w; |
|
301 { |
|
302 FormConstraints form = (FormConstraints)w->core.constraints; |
|
303 Position x, y; |
|
304 Widget ref; |
|
305 |
|
306 switch (form->form.layout_state) { |
|
307 |
|
308 case LayoutPending: |
|
309 form->form.layout_state = LayoutInProgress; |
|
310 break; |
|
311 |
|
312 case LayoutDone: |
|
313 return; |
|
314 |
|
315 case LayoutInProgress: |
|
316 { |
|
317 String subs[2]; |
|
318 Cardinal num_subs = 2; |
|
319 subs[0] = w->core.name; |
|
320 subs[1] = w->core.parent->core.name; |
|
321 XtAppWarningMsg(XtWidgetToApplicationContext(w), |
|
322 "constraintLoop","xawFormLayout","XawToolkitError", |
|
323 "constraint loop detected while laying out child '%s' in FormWidget '%s'", |
|
324 subs, &num_subs); |
|
325 return; |
|
326 } |
|
327 } |
|
328 x = form->form.dx; |
|
329 y = form->form.dy; |
|
330 if ((ref = form->form.horiz_base) != (Widget)NULL) { |
|
331 LayoutChild(ref); |
|
332 x += ref->core.x + ref->core.width + (ref->core.border_width << 1); |
|
333 } |
|
334 if ((ref = form->form.vert_base) != (Widget)NULL) { |
|
335 LayoutChild(ref); |
|
336 y += ref->core.y + ref->core.height + (ref->core.border_width << 1); |
|
337 } |
|
338 XtMoveWidget( w, x, y ); |
|
339 form->form.layout_state = LayoutDone; |
|
340 } |
|
341 |
|
342 |
|
343 static Position TransformCoord(loc, old, new, type) |
|
344 register Position loc; |
|
345 Dimension old, new; |
|
346 XtEdgeType type; |
|
347 { |
|
348 if (type == XtRubber) { |
|
349 if ( ((int) old) > 0) |
|
350 loc = (loc * new) / old; |
|
351 } |
|
352 else if (type == XtChainBottom || type == XtChainRight) |
|
353 loc += (Position)new - (Position)old; |
|
354 |
|
355 /* I don't see any problem with returning values less than zero. */ |
|
356 |
|
357 return (loc); |
|
358 } |
|
359 |
|
360 |
|
361 static void Resize(w) |
|
362 Widget w; |
|
363 { |
|
364 FormWidget fw = (FormWidget)w; |
|
365 WidgetList children = fw->composite.children; |
|
366 int num_children = fw->composite.num_children; |
|
367 Widget *childP; |
|
368 Position x, y; |
|
369 Dimension width, height; |
|
370 |
|
371 for (childP = children; childP - children < num_children; childP++) { |
|
372 FormConstraints form = (FormConstraints)(*childP)->core.constraints; |
|
373 if (!XtIsManaged(*childP)) continue; |
|
374 x = TransformCoord( (*childP)->core.x, fw->form.old_width, |
|
375 fw->core.width, form->form.left ); |
|
376 y = TransformCoord( (*childP)->core.y, fw->form.old_height, |
|
377 fw->core.height, form->form.top ); |
|
378 |
|
379 form->form.virtual_width = |
|
380 TransformCoord((Position)((*childP)->core.x |
|
381 + form->form.virtual_width |
|
382 + 2 * (*childP)->core.border_width), |
|
383 fw->form.old_width, fw->core.width, |
|
384 form->form.right ) |
|
385 - (x + 2 * (*childP)->core.border_width); |
|
386 |
|
387 form->form.virtual_height = |
|
388 TransformCoord((Position)((*childP)->core.y |
|
389 + form->form.virtual_height |
|
390 + 2 * (*childP)->core.border_width), |
|
391 fw->form.old_height, fw->core.height, |
|
392 form->form.bottom ) |
|
393 - ( y + 2 * (*childP)->core.border_width); |
|
394 |
|
395 width = (Dimension) |
|
396 (form->form.virtual_width < 1) ? 1 : form->form.virtual_width; |
|
397 height = (Dimension) |
|
398 (form->form.virtual_height < 1) ? 1 : form->form.virtual_height; |
|
399 |
|
400 XtConfigureWidget( *childP, x, y, (Dimension)width, (Dimension)height, |
|
401 (*childP)->core.border_width ); |
|
402 } |
|
403 |
|
404 fw->form.old_width = fw->core.width; |
|
405 fw->form.old_height = fw->core.height; |
|
406 } |
|
407 |
|
408 |
|
409 /* ARGSUSED */ |
|
410 static XtGeometryResult GeometryManager(w, request, reply) |
|
411 Widget w; |
|
412 XtWidgetGeometry *request; |
|
413 XtWidgetGeometry *reply; /* RETURN */ |
|
414 { |
|
415 FormConstraints form = (FormConstraints)w->core.constraints; |
|
416 XtWidgetGeometry allowed; |
|
417 |
|
418 if ((request->request_mode & ~(XtCWQueryOnly | CWWidth | CWHeight)) || |
|
419 !form->form.allow_resize) |
|
420 return XtGeometryNo; |
|
421 |
|
422 if (request->request_mode & CWWidth) |
|
423 allowed.width = request->width; |
|
424 else |
|
425 allowed.width = w->core.width; |
|
426 |
|
427 if (request->request_mode & CWHeight) |
|
428 allowed.height = request->height; |
|
429 else |
|
430 allowed.height = w->core.height; |
|
431 |
|
432 if (allowed.width == w->core.width && allowed.height == w->core.height) |
|
433 return XtGeometryNo; |
|
434 |
|
435 if (!(request->request_mode & XtCWQueryOnly)) { |
|
436 /* reset virtual width and height. */ |
|
437 form->form.virtual_width = w->core.width = allowed.width; |
|
438 form->form.virtual_height = w->core.height = allowed.height; |
|
439 RefigureLocations( (FormWidget)w->core.parent ); |
|
440 } |
|
441 return XtGeometryYes; |
|
442 } |
|
443 |
|
444 |
|
445 |
|
446 /* ARGSUSED */ |
|
447 static Boolean SetValues(current, request, new) |
|
448 Widget current, request, new; |
|
449 { |
|
450 return( FALSE ); |
|
451 } |
|
452 |
|
453 |
|
454 /* ARGSUSED */ |
|
455 static void ConstraintInitialize(request, new) |
|
456 Widget request, new; |
|
457 { |
|
458 FormConstraints form = (FormConstraints)new->core.constraints; |
|
459 FormWidget fw = (FormWidget)new->core.parent; |
|
460 |
|
461 form->form.virtual_width = (int) new->core.width; |
|
462 form->form.virtual_height = (int) new->core.height; |
|
463 |
|
464 if (form->form.dx == default_value) |
|
465 form->form.dx = fw->form.default_spacing; |
|
466 |
|
467 if (form->form.dy == default_value) |
|
468 form->form.dy = fw->form.default_spacing; |
|
469 } |
|
470 |
|
471 /* ARGSUSED */ |
|
472 static Boolean ConstraintSetValues(current, request, new) |
|
473 Widget current, request, new; |
|
474 { |
|
475 return( FALSE ); |
|
476 } |
|
477 |
|
478 static void ChangeManaged(w) |
|
479 Widget w; |
|
480 { |
|
481 FormWidget fw = (FormWidget)w; |
|
482 FormConstraints form; |
|
483 WidgetList children, childP; |
|
484 int num_children = fw->composite.num_children; |
|
485 Widget child; |
|
486 |
|
487 /* |
|
488 * Reset virtual width and height for all children. |
|
489 */ |
|
490 |
|
491 for (children = childP = fw->composite.children ; |
|
492 childP - children < num_children; childP++) { |
|
493 child = *childP; |
|
494 if (XtIsManaged(child)) { |
|
495 form = (FormConstraints)child->core.constraints; |
|
496 |
|
497 /* |
|
498 * If the size is one (1) then we must not change the virtual sizes, as |
|
499 * they contain useful information. If someone actually wants a widget of |
|
500 * width or height one (1) in a form widget he will lose, can't win them all. |
|
501 * |
|
502 * Chris D. Peterson 2/9/89. |
|
503 */ |
|
504 |
|
505 |
|
506 if ( child->core.width != 1) |
|
507 form->form.virtual_width = (int) child->core.width; |
|
508 if ( child->core.height != 1) |
|
509 form->form.virtual_height = (int) child->core.height; |
|
510 } |
|
511 } |
|
512 RefigureLocations( (FormWidget)w ); |
|
513 } |
|
514 |
|
515 |
|
516 static XtGeometryResult PreferredGeometry( widget, request, reply ) |
|
517 Widget widget; |
|
518 XtWidgetGeometry *request, *reply; |
|
519 { |
|
520 FormWidget w = (FormWidget)widget; |
|
521 |
|
522 reply->width = w->form.preferred_width; |
|
523 reply->height = w->form.preferred_height; |
|
524 reply->request_mode = CWWidth | CWHeight; |
|
525 if ( request->request_mode & (CWWidth | CWHeight) == |
|
526 reply->request_mode & CWWidth | CWHeight |
|
527 && request->width == reply->width |
|
528 && request->height == reply->height) |
|
529 return XtGeometryYes; |
|
530 else if (reply->width == w->core.width && reply->height == w->core.height) |
|
531 return XtGeometryNo; |
|
532 else |
|
533 return XtGeometryAlmost; |
|
534 } |
|
535 |
|
536 |
|
537 /********************************************************************** |
|
538 * |
|
539 * Public routines |
|
540 * |
|
541 **********************************************************************/ |
|
542 |
|
543 /* |
|
544 * Set or reset figuring (ignored if not realized) |
|
545 */ |
|
546 |
|
547 void XawFormDoLayout(w, doit) |
|
548 Widget w; |
|
549 Boolean doit; |
|
550 { |
|
551 register FormWidget fw = (FormWidget)w; |
|
552 |
|
553 fw->form.no_refigure = !doit; |
|
554 |
|
555 if ( XtIsRealized(w) && fw->form.needs_relayout ) |
|
556 RefigureLocations( fw ); |
|
557 } |