1 /* $XConsortium: Grid.c /main/5 1995/07/15 20:40:45 drk $ */
2 /*
3 * Motif
4 *
5 * Copyright (c) 1987-2012, The Open Group. All rights reserved.
6 *
7 * These libraries and programs are free software; you can
8 * redistribute them and/or modify them under the terms of the GNU
9 * Lesser General Public License as published by the Free Software
10 * Foundation; either version 2 of the License, or (at your option)
11 * any later version.
12 *
13 * These libraries and programs are distributed in the hope that
14 * they will be useful, but WITHOUT ANY WARRANTY; without even the
15 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
16 * PURPOSE. See the GNU Lesser General Public License for more
17 * details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with these librararies and programs; if not, write
21 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
22 * Floor, Boston, MA 02110-1301 USA
23 */
24 /*
25 * HISTORY
26 */
27 /********************************** WARNING **********************************
28 *
29 * ExmGrid is a demonstration widget. OSF provides this widget
30 * solely to teach programmers how to write their own Motif widgets.
31 * OSF does not support this widget in any way
32 *********************************** WARNING *********************************/
33
34
35 /******************************************************************************
36 *
37 * Grid.c - ExmGrid widget. This widget manages its children as an MxN matrix.
38 * The ExmGrid widget demonstrates how to
39 * * create a relatively easy Motif manager widget.
40 * * install and use the XmQTspecifyRenderTable trait.
41 * * install and use the XmQTdialogShellSavvy trait.
42 * See the "OSF/Motif Widget Writer's Guide" for details.
43 *
44 ******************************************************************************/
45
46 /* Include appropriate header files. */
47 #include <Exm/GridP.h> /* private header file for the ExmGrid widget */
48 #include <Xm/GadgetP.h> /* for gadget management functions */
49 #include <Xm/TraitP.h> /* for trait access functions */
50 #include <Xm/DialogSavvyT.h> /* for XmQTdialogSavvy trait */
51 #include <Xm/SpecRenderT.h> /* for XmQTspecifyRenderTable trait */
52
53
54 /* Define macros. */
55 #define Max(x, y) (((x) > (y)) ? (x) : (y))
56 #define WARNING_TOO_MANY_ROWS "Too many rows specified for ExmGrid.\n"
57 #define WARNING_TOO_MANY_COLUMNS "Too many columns specified for ExmGrid.\n"
58
59
60 /* Declare static functions. */
61 static void GetDialogTitle(
62 Widget bb,
63 int resource,
64 XtArgVal *value) ;
65 static void ClassPartInitialize(
66 WidgetClass widgetClass);
67 static void Initialize(
68 Widget request_w,
69 Widget new_w,
70 ArgList args,
71 Cardinal *num_args );
72 static void Destroy(
73 Widget wid) ;
74 static void Resize (
75 Widget w );
76 static void Redisplay (
77 Widget w,
78 XEvent *event,
79 Region region);
80 static Boolean SetValues (
81 Widget old_w,
82 Widget request_w,
83 Widget new_w,
84 ArgList args,
85 Cardinal *num_args );
86 static void SetValuesAlmost(
87 Widget cw,
88 Widget nw,
89 XtWidgetGeometry *request,
90 XtWidgetGeometry *reply) ;
91 static XtGeometryResult QueryGeometry (
92 Widget w,
93 XtWidgetGeometry *request,
94 XtWidgetGeometry *reply);
95 static XtGeometryResult GeometryManager (
96 Widget w,
97 XtWidgetGeometry *request,
98 XtWidgetGeometry *reply);
99 static void ChangeManaged (
100 Widget w);
101 static Boolean ConstraintSetValues (
102 Widget cw,
103 Widget rw,
104 Widget nw,
105 ArgList args,
106 Cardinal *num_args);
107 static void Layout (
108 Widget wid,
109 Widget instigator);
110 static void CalcSize (
111 Widget wid,
112 Widget instigator,
113 Dimension *gridWidth,
114 Dimension *gridHeight);
115 static Boolean NeedRelayout (
116 Widget new,
117 Widget cur);
118 static void CallMapUnmap(Widget wid,
119 Boolean map_unmap) ;
120 static XmRenderTable GetTable(Widget wid,
121 XtEnum type);
122
123
124 /* No translations and no actions. */
125
126
127 /* Define the resources for the ExmGrid widget. */
128 static XtResource resources[] =
129 {
130 {
131 XmNrows,
132 XmCRows,
133 XmRShort,
134 sizeof (short),
135 XtOffsetOf( ExmGridRec, grid.rows),
136 XmRImmediate,
137 (XtPointer) 4
138 },
139 {
140 XmNcolumns,
141 XmCColumns,
142 XmRShort,
143 sizeof (short),
144 XtOffsetOf( ExmGridRec, grid.columns),
145 XmRImmediate,
146 (XtPointer) 4
147 },
148 {
149 XmNmarginWidth,
150 XmCMarginWidth,
151 XmRHorizontalDimension,
152 sizeof (Dimension),
153 XtOffsetOf( ExmGridRec, grid.margin_width),
154 XmRImmediate,
155 (XtPointer) 10
156 },
157 {
158 XmNmarginHeight,
159 XmCMarginHeight,
160 XmRVerticalDimension,
161 sizeof (Dimension),
162 XtOffsetOf(ExmGridRec, grid.margin_height),
163 XmRImmediate,
164 (XtPointer) 10
165 },
166 {
167 XmNmapCallback,
168 XmCCallback,
169 XmRCallback,
170 sizeof (XtCallbackList),
171 XtOffsetOf(ExmGridRec, grid.map_callback),
172 XmRImmediate,
173 (XtPointer) NULL
174 },
175 {
176 XmNunmapCallback,
177 XmCCallback,
178 XmRCallback,
179 sizeof (XtCallbackList),
180 XtOffsetOf(ExmGridRec, grid.unmap_callback),
181 XmRImmediate,
182 (XtPointer) NULL
183 },
184 {
185 XmNdefaultPosition,
186 XmCDefaultPosition,
187 XmRBoolean, sizeof (Boolean),
188 XtOffsetOf(ExmGridRec, grid.default_position),
189 XmRImmediate,
190 (XtPointer) True
191 },
192 {
193 XmNbuttonRenderTable,
194 XmCButtonRenderTable,
195 XmRButtonRenderTable,
196 sizeof (XmRenderTable),
197 XtOffsetOf(ExmGridRec, grid.button_render_table),
198 XmRCallProc, (XtPointer) NULL
199 },
200 {
201 XmNlabelRenderTable,
202 XmCLabelRenderTable,
203 XmRLabelRenderTable,
204 sizeof (XmRenderTable),
205 XtOffsetOf(ExmGridRec, grid.label_render_table),
206 XmRCallProc, (XtPointer) NULL
207 },
208 {
209 XmNtextRenderTable,
210 XmCTextRenderTable,
211 XmRTextRenderTable,
212 sizeof (XmRenderTable),
213 XtOffsetOf(ExmGridRec, grid.text_render_table),
214 XmRCallProc, (XtPointer) NULL
215 },
216 {
217 XmNdialogTitle,
218 XmCDialogTitle,
219 XmRXmString,
220 sizeof (XmString),
221 XtOffsetOf(ExmGridRec, grid.dialog_title),
222 XmRImmediate, (XtPointer) NULL
223 },
224
225 };
226
227 /* Three of the preceding resources will be handled as synthetic
228 resources. */
229 static XmSyntheticResource syn_resources[] =
230 {
231 {
232 XmNmarginWidth,
233 sizeof (Dimension),
234 XtOffsetOf( ExmGridRec, grid.margin_width),
235 XmeFromHorizontalPixels,
236 XmeToHorizontalPixels
237 },
238 {
239 XmNmarginHeight,
240 sizeof (Dimension),
241 XtOffsetOf( ExmGridRec, grid.margin_height),
242 XmeFromVerticalPixels,
243 XmeToVerticalPixels
244 },
245 {
246 XmNdialogTitle,
247 sizeof (XmString),
248 XtOffsetOf( ExmGridRec, grid.dialog_title),
249 GetDialogTitle,
250 NULL
251 }
252 };
253
254
255 /* Define the two constraints of ExmGrid. */
256 static XtResource constraints[] =
257 {
258 {
259 ExmNgridMarginWidthWithinCell,
260 ExmCGridMarginWidthWithinCell,
261 XmRHorizontalDimension,
262 sizeof (Dimension),
263 XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_width_within_cell),
264 XmRImmediate,
265 (XtPointer) 0
266 },
267 {
268 ExmNgridMarginHeightWithinCell,
269 ExmCGridMarginHeightWithinCell,
270 XmRVerticalDimension,
271 sizeof (Dimension),
272 XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_height_within_cell),
273 XmRImmediate,
274 (XtPointer) 0
275 },
276 };
277
278
279 /* Both of the preceding constraints will be handled as synthetic
280 constraints. */
281 static XmSyntheticResource syn_constraints[] =
282 {
283 {
284 ExmNgridMarginWidthWithinCell,
285 sizeof (Dimension),
286 XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_width_within_cell),
287 XmeFromHorizontalPixels,
288 XmeToHorizontalPixels
289 },
290 {
291 ExmNgridMarginHeightWithinCell,
292 sizeof (Dimension),
293 XtOffsetOf( ExmGridConstraintRec, grid.grid_margin_height_within_cell),
294 XmeFromVerticalPixels,
295 XmeToVerticalPixels
296 },
297 };
298
299
300
301 /* Define the widget class record. See Chapter 4 of the
302 "OSF/Motif Widget Writer's Guide" for details. */
303 externaldef(exmgridclassrec) ExmGridClassRec exmGridClassRec =
304 {
305 { /* Here is the Core class record. */
306 /* superclass */ (WidgetClass) &xmManagerClassRec,
307 /* class_name */ "ExmGrid",
308 /* widget_size */ sizeof(ExmGridRec),
309 /* class_initialize */ NULL,
310 /* class_part_initialize */ ClassPartInitialize,
311 /* class_inited */ FALSE,
312 /* initialize */ Initialize,
313 /* initialize_hook */ NULL,
314 /* realize */ XtInheritRealize,
315 /* actions */ NULL,
316 /* num_actions */ 0,
317 /* resources */ resources,
318 /* num_resources */ XtNumber(resources),
319 /* xrm_class */ NULLQUARK,
320 /* compress_motion */ TRUE,
321 /* compress_exposure */ XtExposeCompressMaximal,
322 /* compress_enterleave */ TRUE,
323 /* visible_interest */ FALSE,
324 /* destroy */ Destroy,
325 /* resize */ Resize,
326 /* expose */ Redisplay,
327 /* set_values */ SetValues,
328 /* set_values_hook */ NULL,
329 /* set_values_almost */ SetValuesAlmost,
330 /* get_values_hook */ NULL,
331 /* accept_focus */ NULL,
332 /* version */ XtVersion,
333 /* callback_private */ NULL,
334 /* tm_table */ XtInheritTranslations,
335 /* query_geometry */ QueryGeometry,
336 /* display_accelerator */ NULL,
337 /* extension */ NULL,
338 },
339 { /* Here is the Composite class record. */
340 /* geometry_manager */ GeometryManager,
341 /* change_managed */ ChangeManaged,
342 /* insert_child */ XtInheritInsertChild,
343 /* delete_child */ XtInheritDeleteChild,
344 /* extension */ NULL,
345 },
346 { /* Here is the Constaint class record. */
347 /* constraint_resources */ constraints,
348 /* constraint_num_resources */ XtNumber(constraints),
349 /* constraint_size */ sizeof(ExmGridConstraintRec),
350 /* constraint_initialize */ NULL,
351 /* constraint_destroy */ NULL,
352 /* constraint_set_values */ ConstraintSetValues,
353 /* extension */ NULL,
354 },
355 { /* Here is the XmManager class record. */
356 /* translations */ XtInheritTranslations,
357 /* syn_resources */ syn_resources,
358 /* num_syn_resources */ XtNumber(syn_resources),
359 /* syn_constraint_resources */ syn_constraints,
360 /* num_syn_constraint_resources */ XtNumber(syn_constraints),
361 /* parent_process */ XmInheritParentProcess,
362 /* extension */ NULL,
363 },
364 { /* Here is the ExmGrid class record. */
365 /* layout */ Layout,
366 /* calc_size */ CalcSize,
367 /* need_relayout */ NeedRelayout,
368 /* extension */ NULL,
369 }
370 };
371
372 /* Establish the widget class name as an externally accessible symbol.
373 Use the "externaldef" macro rather than the "extern" keyword. */
374 externaldef(exmgridwidgetclass) WidgetClass exmGridWidgetClass =
375 (WidgetClass) &exmGridClassRec;
376
377
378 /* Define trait record variables. */
379
380 /* Here is the trait record variable for the XmQTdialogSavvy trait. */
381 static XmConst XmDialogSavvyTraitRec gridDST = {
382 0, /* version */
383 CallMapUnmap, /* trait method */
384 };
385
386
387 /* Here is the trait record variable for the XmQTspecifyRenderTable trait. */
388 static XmConst XmSpecRenderTraitRec gridSRTT = {
389 0, /* version */
390 GetTable, /* trait method */
391 };
392
393
394 /****************************************************************************
395 *
396 * GetDialogTitle
397 * Copy the XmString in XmNdialogTitle before returning it to the user.
398 *
399 ****************************************************************************/
400 static void
GetDialogTitle(Widget wid,int resource,XtArgVal * value)401 GetDialogTitle(
402 Widget wid,
403 int resource,
404 XtArgVal *value)
405 {
406 *value = (XtArgVal)XmStringCopy(((ExmGridWidget) wid)->grid.dialog_title);
407 }
408
409
410 /****************************************************************************
411 *
412 * ClassPartInitialize:
413 * Called when this widget or a subclass of this widget is instantiated.
414 *
415 ****************************************************************************/
416 static void
ClassPartInitialize(WidgetClass widgetClass)417 ClassPartInitialize (
418 WidgetClass widgetClass
419 )
420 {
421 ExmGridWidgetClass wc = (ExmGridWidgetClass)widgetClass;
422 ExmGridWidgetClass sc = (ExmGridWidgetClass)wc->core_class.superclass;
423
424 /* The following code allows subclasses of ExmGrid to inherit three of
425 ExmGrid's methods. */
426 if (wc->grid_class.layout == ExmInheritLayout)
427 wc->grid_class.layout = sc->grid_class.layout;
428 if (wc->grid_class.calc_size == ExmInheritCalcSize)
429 wc->grid_class.calc_size = sc->grid_class.calc_size;
430 if (wc->grid_class.need_relayout == ExmInheritNeedRelayout)
431 wc->grid_class.need_relayout = sc->grid_class.need_relayout;
432
433 /* Install the XmQTdialogShellSavyy trait on this class and on
434 all its future subclasses. */
435 XmeTraitSet(widgetClass, XmQTdialogShellSavvy, (XtPointer) &gridDST);
436
437 /* Install the XmQTspecifyRenderTable trait on this class and on
438 all its future subclasses. */
439 XmeTraitSet(widgetClass, XmQTspecifyRenderTable, (XtPointer) &gridSRTT);
440 }
441
442
443 /**************************************************************************
444 *
445 * Initialize:
446 * Called when this widget is first instantiated.
447 *
448 ***************************************************************************/
449 static void
Initialize(Widget request_w,Widget new_w,ArgList args,Cardinal * num_args)450 Initialize (
451 Widget request_w,
452 Widget new_w,
453 ArgList args,
454 Cardinal *num_args
455 )
456 {
457 ExmGridWidget rw = (ExmGridWidget)request_w;
458 ExmGridWidget nw = (ExmGridWidget)new_w;
459
460 /* Initialize one of the internal fields of the ExmGrid widget. */
461 nw->grid.processing_constraints = False;
462
463 /* Ensure that user doesn't specify too many rows. */
464 if (rw->grid.rows > EXM_GRID_MAX_NUMBER_OF_ROWS) {
465 XmeWarning((Widget)rw, WARNING_TOO_MANY_ROWS);
466 nw->grid.rows = EXM_GRID_MAX_NUMBER_OF_ROWS;
467 }
468
469 /* Ensure that user doesn't specify too many columns. */
470 if (rw->grid.columns > EXM_GRID_MAX_NUMBER_OF_COLUMNS) {
471 XmeWarning((Widget)rw, WARNING_TOO_MANY_COLUMNS);
472 nw->grid.columns = EXM_GRID_MAX_NUMBER_OF_COLUMNS;
473 }
474
475 /* Copy in the dialog title XmString and update our shell */
476 if (nw->grid.dialog_title) {
477 nw->grid.dialog_title = XmStringCopy(rw->grid.dialog_title) ;
478 XmeSetWMShellTitle(nw->grid.dialog_title, XtParent(new_w)) ;
479 }
480 }
481
482
483 /****************************************************************************
484 *
485 * Destroy:
486 * Called when the widget is destroyed.
487 *
488 ****************************************************************************/
489 static void
Destroy(Widget wid)490 Destroy(
491 Widget wid )
492 {
493 ExmGridWidget grid = (ExmGridWidget)wid;
494
495 /* Deallocate the dynamic memory that holds the dialog_title. */
496 XmStringFree(grid->grid.dialog_title) ;
497 }
498
499
500 /****************************************************************************
501 *
502 * Resize:
503 *
504 ****************************************************************************/
505 static void
Resize(Widget w)506 Resize (
507 Widget w
508 )
509 {
510 ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(w);
511
512 /* Configure the children by calling Layout. */
513 if (gwc->grid_class.layout)
514 (*(gwc->grid_class.layout))(w, NULL);
515 else
516 Layout (w, NULL);
517 }
518
519
520
521
522 /****************************************************************************
523 *
524 * Redisplay:
525 * Called by the Intrinsics in response to an exposure event.
526 *
527 ***************************************************************************/
528 static void
Redisplay(Widget w,XEvent * event,Region region)529 Redisplay (
530 Widget w,
531 XEvent *event,
532 Region region
533 )
534 {
535 /* Pass exposure event down to gadget children. */
536 XmeRedisplayGadgets (w, event, region);
537 }
538
539
540
541 /*****************************************************************************
542 *
543 * SetValues:
544 * Called by the Intrinsics whenever any of the resource values change.
545 *
546 ****************************************************************************/
547 static Boolean
SetValues(Widget old_w,Widget request_w,Widget new_w,ArgList args,Cardinal * num_args)548 SetValues (
549 Widget old_w,
550 Widget request_w,
551 Widget new_w,
552 ArgList args,
553 Cardinal *num_args
554 )
555 {
556 ExmGridWidget cw = (ExmGridWidget)old_w;
557 ExmGridWidget rw = (ExmGridWidget)request_w;
558 ExmGridWidget nw = (ExmGridWidget)new_w;
559 Boolean redisplay = False;
560 Boolean need_relayout;
561 ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(new_w);
562
563 /* Ensure that user doesn't specify too many rows. */
564 if (rw->grid.rows > EXM_GRID_MAX_NUMBER_OF_ROWS) {
565 XmeWarning((Widget)rw, WARNING_TOO_MANY_ROWS);
566 nw->grid.rows = EXM_GRID_MAX_NUMBER_OF_ROWS;
567 }
568
569 /* Ensure that user doesn't specify too many rows. */
570 if (rw->grid.columns > EXM_GRID_MAX_NUMBER_OF_COLUMNS) {
571 XmeWarning((Widget)rw, WARNING_TOO_MANY_COLUMNS);
572 nw->grid.columns = EXM_GRID_MAX_NUMBER_OF_COLUMNS;
573 }
574
575 /* See if any class or subclass resources have changed. */
576 if (gwc->grid_class.need_relayout)
577 need_relayout = (*(gwc->grid_class.need_relayout))(old_w, new_w);
578 else
579 need_relayout = NeedRelayout (old_w, new_w);
580
581 /* If any geometry resources changed and a new size wasn't specified,
582 recalculate a new ideal size. */
583 if (need_relayout) {
584 /* Reset the widget size so that CalcSize can affect them. */
585 if (nw->core.width == cw->core.width)
586 nw->core.width = 0;
587 if (nw->core.height == cw->core.height)
588 nw->core.height = 0;
589
590 /* Call CalcSize. */
591 if (gwc->grid_class.calc_size)
592 (*(gwc->grid_class.calc_size))(new_w, NULL,
593 &nw->core.width, &nw->core.height);
594 else
595 CalcSize (new_w, NULL, &nw->core.width, &nw->core.height);
596
597
598 /* If the geometry resources have changed but the size hasn't,
599 we need to relayout manually, because Xt won't generate a
600 Resize at this point. */
601 if ((nw->core.width == cw->core.width) &&
602 (nw->core.height == cw->core.height)) {
603
604 /* Call Layout to configure the children. */
605 if (gwc->grid_class.layout)
606 (*(gwc->grid_class.layout))(new_w, NULL);
607 else
608 Layout(new_w, NULL);
609 redisplay = True ;
610 }
611 }
612
613 /* ExmGrid installs the XmQTdialogShellSavvy trait. Therefore, ExmGrid
614 has to process the Xm_DIALOG_SAVVY_FORCE_ORIGIN case, which is as
615 follows. A DialogShell always mimics the child position on itself.
616 That is, the "current" position of an ExmGrid within a DialogShell is
617 always 0. Therefore, if an application tries to set ExmGrid's x or
618 y position to 0, the Intrinsics will not detect a position change and
619 wll not trigger a geometry request. ExmGrid has to detect this special
620 request and set core.x and core.y to the special value,
621 XmDIALOG_SAVVY_FORCE_ORIGIN. That is, XmDIALOG_SAVVY_FORCE_ORIGIN
622 tells DialogShell that ExmGrid really does want to move to an x or y
623 position of 0. */
624
625 if (XmIsDialogShell(XtParent(new_w))) { /* Is parent a DialogShell? */
626 Cardinal i ;
627
628 /* We have to look in the arglist since old_w->core.x is always 0, and
629 if new_w->core.x is also set to 0, we see no change. */
630 for (i=0; i<*num_args; i++) {
631 if (strcmp (args[i].name, XmNx) == 0) {
632 if ((args[i].value == 0) && (new_w->core.x == 0))
633 new_w->core.x = XmDIALOG_SAVVY_FORCE_ORIGIN;
634 }
635 if (strcmp (args[i].name, XmNy) == 0) {
636 if ((args[i].value == 0) && (new_w->core.y == 0))
637 new_w->core.y = XmDIALOG_SAVVY_FORCE_ORIGIN;
638 }
639 } /* end for */
640 } /* end of if */
641
642 /* Update wm shell title if it has changed */
643 if(nw->grid.dialog_title != cw->grid.dialog_title ) {
644 XmStringFree(cw->grid.dialog_title) ;
645 nw->grid.dialog_title = XmStringCopy(rw->grid.dialog_title) ;
646 XmeSetWMShellTitle(nw->grid.dialog_title, XtParent(new_w)) ;
647 }
648
649 return (redisplay);
650 }
651
652
653
654 /*************************************************************************
655 *
656 * SetValuesAlmost:
657 * Called by the Intrinsics when an XtMakeGeometryRequest call
658 * returns either XmGeometryAlmost or XtGeometryNo.
659 *
660 ***************************************************************************/
661 static void
SetValuesAlmost(Widget cw,Widget nw,XtWidgetGeometry * request,XtWidgetGeometry * reply)662 SetValuesAlmost(
663 Widget cw, /* unused */
664 Widget nw,
665 XtWidgetGeometry *request,
666 XtWidgetGeometry *reply )
667 {
668 ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(nw);
669
670 /* ExmGrid's parent said XtGeometryNo to ExmGrid's geometry request.
671 Therefore, we need to relayout because this request
672 was due to a change in internal geometry resource of the ExmGrid */
673 if (!reply->request_mode) {
674 if (gwc->grid_class.layout)
675 (*(gwc->grid_class.layout))(nw, NULL);
676 else
677 Layout(nw, NULL);
678 }
679
680 *request = *reply;
681 }
682
683
684 /*************************************************************************
685 *
686 * QueryGeometry:
687 * Called by a parent of Grid when the parent needs to find out Grid's
688 * preferred size. QueryGeometry calls CalcSize to do find the
689 * preferred size.
690 *
691 ***************************************************************************/
692 static XtGeometryResult
QueryGeometry(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)693 QueryGeometry (
694 Widget w,
695 XtWidgetGeometry *request,
696 XtWidgetGeometry *reply
697 )
698 {
699 ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(w);
700
701 /* If ExmGrid's parent calls XtQueryGeometry before ExmGrid has been
702 realized, use the current size of ExmGrid as the preferred size. */
703 /* Deal with user initial size setting */
704 if (!XtIsRealized(w)) { /* Widget is not yet realized. */
705 reply->width = XtWidth(w) ; /* might be 0 */
706 reply->height = XtHeight(w) ; /* might be 0 */
707 } else { /* Widget is realized. */
708 /* always computes natural size afterwards */
709 reply->width = 0;
710 reply->height = 0;
711 }
712
713 /* Call CalcSize to figure out what the preferred size really is. */
714 if (gwc->grid_class.calc_size)
715 (*(gwc->grid_class.calc_size))(w, NULL, &reply->width, &reply->height);
716 else
717 CalcSize (w, NULL, &reply->width, &reply->height);
718
719 /* This function handles CWidth and CHeight */
720 return XmeReplyToQueryGeometry(w, request, reply) ;
721 }
722
723
724 /****************************************************************************
725 *
726 * GeometryManager:
727 * Called by Intrinsics in response to a geometry change request from
728 * one of the children of ExmGrid.
729 *
730 ***************************************************************************/
731 static XtGeometryResult
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * reply)732 GeometryManager (
733 Widget w, /* instigator */
734 XtWidgetGeometry *request,
735 XtWidgetGeometry *reply
736 )
737 {
738 ExmGridWidget gw = (ExmGridWidget) XtParent(w);
739 XtWidgetGeometry parentRequest;
740 XtGeometryResult result;
741 Dimension curWidth, curHeight, curBW;
742 ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass((Widget)gw);
743
744 /* If the request was caused by ConstraintSetValues reset the flag */
745 if (gw->grid.processing_constraints) {
746 gw->grid.processing_constraints = False;
747 /* The ConstraintSetValues added one to border_width;
748 This is the Xt trick used to fire the GM when a non core
749 geometry resource (like a constraint) changes.
750 now take it away. */
751 request->border_width -= 1;
752 }
753
754 /* Save the original child resources. */
755 curWidth = w->core.width;
756 curHeight = w->core.height;
757 curBW = w->core.border_width;
758
759 /* Deny any requests for a new position. */
760 if ((request->request_mode & CWX) || (request->request_mode & CWY))
761 return XtGeometryNo ;
762
763 if (request->request_mode & CWWidth)
764 w->core.width = request->width;
765 if (request->request_mode & CWHeight)
766 w->core.height = request->height;
767 if (request->request_mode & CWBorderWidth)
768 w->core.border_width = request->border_width;
769
770 /* Calculate a new ideal size based on these requests. */
771 /* Setting width and height to 0 tells CalcSize to override these
772 fields with the calculated width and height. */
773 parentRequest.width = 0;
774 parentRequest.height = 0;
775 if (gwc->grid_class.calc_size)
776 (*(gwc->grid_class.calc_size))((Widget)gw, w,
777 &parentRequest.width,
778 &parentRequest.height);
779 else
780 CalcSize ((Widget)gw, w, &parentRequest.width, &parentRequest.height);
781
782
783 /* Ask the Grid's parent if new calculated size is acceptable. */
784 parentRequest.request_mode = CWWidth | CWHeight;
785 if (request->request_mode & XtCWQueryOnly)
786 parentRequest.request_mode |= XtCWQueryOnly;
787 result = XtMakeGeometryRequest ((Widget)gw, &parentRequest, NULL);
788
789 /* Turn XtGeometryAlmost into XtGeometryNo. */
790 if (result == XtGeometryAlmost)
791 result = XtGeometryNo;
792
793 if (result == XtGeometryNo ||
794 request->request_mode & XtCWQueryOnly) {
795 /* Restore original geometry. */
796 w->core.width = curWidth;
797 w->core.height = curHeight;
798 w->core.border_width = curBW;
799 } else {
800 /* result == XtGeometryYes and this wasn't just a query */
801 if (gwc->grid_class.layout)
802 (*(gwc->grid_class.layout))((Widget)gw, w);
803 else
804 Layout ((Widget)gw, w); /* Layout with this child as the instigator,
805 so that we don't resize this child. */
806 }
807
808 return (result);
809 }
810
811
812
813 /**************************************************************************
814 *
815 * ChangeManaged:
816 * Called by the Intrinsics whenever either of the following happens:
817 * * a managed child becomes unmanaged.
818 * * an unmanaged child becomes managed.
819 *
820 *************************************************************************/
821 static void
ChangeManaged(Widget w)822 ChangeManaged(
823 Widget w
824 )
825 {
826 Dimension gridWidth, gridHeight;
827 ExmGridWidgetClass gwc = (ExmGridWidgetClass) XtClass(w);
828
829 /* If you get an initial (C) size from the user or application, keep it.
830 Otherwise, just force width and height to 0 so that CalcSize will
831 overwrite the appropriate fields. */
832 if (!XtIsRealized(w)) {
833 /* The first time, only attempts to change non specified sizes */
834 gridWidth = XtWidth(w) ; /* might be 0 */
835 gridHeight = XtHeight(w) ; /* might be 0 */
836 } else {
837 gridWidth = 0 ;
838 gridHeight = 0 ;
839 }
840
841 /* Determine the ideal size of Grid. */
842 if (gwc->grid_class.calc_size)
843 (*(gwc->grid_class.calc_size))(w, NULL, &gridWidth, &gridHeight);
844 else
845 CalcSize (w, NULL, &gridWidth, &gridHeight);
846
847 /* Ask parent of Grid if Grid's new size is acceptable. Keep asking until
848 parent returns either XtGeometryYes or XtGeometryNo. */
849 while (XtMakeResizeRequest (w, gridWidth, gridHeight,
850 &gridWidth, &gridHeight) == XtGeometryAlmost);
851
852 /* Now that we have a size for the Grid, we can layout the children
853 of the grid. */
854 if (gwc->grid_class.layout)
855 (*(gwc->grid_class.layout))(w, NULL);
856 else
857 Layout (w, NULL);
858
859 /* Update keyboard traversal */
860 XmeNavigChangeManaged (w);
861 }
862
863
864
865
866 /**************************************************************************
867 *
868 * ConstraintSetValues:
869 * Called by Intrinsics if there is any change in any of the constraint
870 * resources.
871 *
872 **************************************************************************/
873 static Boolean
ConstraintSetValues(Widget cw,Widget rw,Widget nw,ArgList args,Cardinal * num_args)874 ConstraintSetValues (
875 Widget cw,
876 Widget rw,
877 Widget nw,
878 ArgList args,
879 Cardinal *num_args
880 )
881 {
882 ExmGridConstraint nc;
883 ExmGridConstraint cc;
884 ExmGridWidget gw;
885
886 if (!XtIsRectObj (nw))
887 return (False);
888
889 gw = (ExmGridWidget)XtParent(nw);
890 nc = ExmGridCPart(nw);
891 cc = ExmGridCPart(cw);
892
893 /* Check for change in ExmNgridMarginWidth or ExmNgridMarginHeight */
894 if ((nc->grid_margin_width_within_cell !=
895 cc->grid_margin_width_within_cell ||
896 nc->grid_margin_height_within_cell !=
897 cc->grid_margin_height_within_cell) &&
898 XtIsManaged (nw)) {
899 /* Tell the Intrinsics and the GeometryManager method that a
900 reconfigure is needed. */
901 gw->grid.processing_constraints = True;
902 /* A trick: by altering one of the core geometry fields, Xt will
903 call the parent's geometry_manager method. */
904 nw->core.border_width += 1;
905 }
906
907 return (False);
908 }
909
910
911 /***************************************************************************
912 *
913 * Layout:
914 * Does all the placement of children.
915 * Instigator tells whether or not to resize all children.
916 *
917 *************************************************************************/
918 static void
Layout(Widget wid,Widget instigator)919 Layout (
920 Widget wid,
921 Widget instigator
922 )
923 {
924 ExmGridWidget gw = (ExmGridWidget) wid ;
925 Dimension mw = gw->grid.margin_width;
926 Dimension mh = gw->grid.margin_height;
927 Dimension TotalWidthOfGridWidget = gw->core.width;
928 Dimension TotalWidthOfGridMargins, TotalHeightOfGridMargins;
929 Dimension TotalHeightOfGridWidget = gw->core.height;
930 Dimension AvailWidthForChildren = 1, AvailHeightForChildren = 1;
931 Dimension WidthAllottedEachChild, HeightAllottedEachChild;
932 int i, row, column;
933
934 /* Lay out the children that ExmGrid is currently managing.
935 Each child will be placed somewhere on the rowxcolumn grid. */
936 TotalWidthOfGridMargins = 2 * mw;
937 if (TotalWidthOfGridWidget > TotalWidthOfGridMargins)
938 AvailWidthForChildren = TotalWidthOfGridWidget -
939 TotalWidthOfGridMargins;
940
941 WidthAllottedEachChild = AvailWidthForChildren / gw->grid.columns;
942
943 TotalHeightOfGridMargins = 2 * mh;
944 if (TotalHeightOfGridWidget > TotalHeightOfGridMargins)
945 AvailHeightForChildren = TotalHeightOfGridWidget -
946 TotalHeightOfGridMargins;
947 HeightAllottedEachChild = AvailHeightForChildren / gw->grid.rows;
948
949 /* Now that we know how much space is allotted for each child, we
950 can lay them all out. */
951 row = 0;
952 column = 0;
953 for (i = 0; i < gw->composite.num_children; i++) {
954 Widget ic = gw->composite.children[i];
955 ExmGridConstraint glc = ExmGridCPart (ic);
956 Dimension gmw = glc->grid_margin_width_within_cell;
957 Dimension gmh = glc->grid_margin_height_within_cell;
958 Position ChildsStartingX, ChildsStartingY;
959 Dimension ChildsActualWidth, ChildsActualHeight, cb;
960
961 if (!XtIsManaged(ic))
962 continue; /* ignored unmanaged children */
963
964 cb = ic->core.border_width;
965
966 /* Calculate the position and the size of the child.
967 During the layout, the children are all resized
968 to exactly fit the cell size minus the cell margin */
969
970 ChildsActualWidth = WidthAllottedEachChild - (2 * (gmw + cb));
971 ChildsStartingX = mw + (column * WidthAllottedEachChild) + gmw;
972 ChildsStartingY = mh + (row * HeightAllottedEachChild) + gmh;
973 ChildsActualHeight = HeightAllottedEachChild - 2 * (gmh + cb);
974
975 /* If layout is instigated by the GeometryManager don't
976 configure the requesting child, just set its geometry and
977 let Xt configure it. */
978 if (ic != instigator) {
979 XmeConfigureObject (ic, ChildsStartingX, ChildsStartingY,
980 ChildsActualWidth, ChildsActualHeight, cb);
981 }
982 else {
983 ic->core.x = ChildsStartingX;
984 ic->core.y = ChildsStartingY;
985 ic->core.width = ChildsActualWidth;
986 ic->core.height = ChildsActualHeight;
987 ic->core.border_width = cb;
988 }
989
990 /* Advance the column counter until we reach the right edge.
991 When we reach the right edge, reset the column
992 counter back to 0 (left edge) and advance the row counter. */
993 column += 1;
994
995 if (column == gw->grid.columns) {
996 column = 0;
997 row += 1;
998 }
999 }
1000 }
1001
1002
1003
1004 /******************************************************************************
1005 *
1006 * CalcSize:
1007 * Called by QueryGeometry, SetValues, GeometryManager, and ChangeManaged.
1008 * Calculate the ideal size of the ExmGrid widget.
1009 * Only affects the returned size if it is 0.
1010 *
1011 ****************************************************************************/
1012 static void
CalcSize(Widget wid,Widget instigator,Dimension * TotalWidthOfGridWidget,Dimension * TotalHeightOfGridWidget)1013 CalcSize (
1014 Widget wid,
1015 Widget instigator,
1016 Dimension *TotalWidthOfGridWidget,
1017 Dimension *TotalHeightOfGridWidget
1018 )
1019 {
1020 ExmGridWidget gw = (ExmGridWidget) wid ;
1021 Dimension maxWidth = 1;
1022 Dimension maxHeight = 1;
1023 int i;
1024
1025 /* Examine each of Grid's children. Find the biggest child. The
1026 ideal size of the Grid will be large enough to accomodate the
1027 largest child. */
1028 for (i = 0; i < gw->composite.num_children; i++) {
1029 Widget ic = gw->composite.children[i];
1030 ExmGridConstraint glc = ExmGridCPart (ic);
1031 Dimension width, height;
1032 Dimension cw, ch, cb;
1033 XtWidgetGeometry reply;
1034
1035 if (!XtIsManaged(ic))
1036 continue ;
1037
1038 /* Get child's preferred geometry if not the instigator. */
1039 if (ic != instigator) {
1040 XtQueryGeometry (ic, NULL, &reply);
1041 cw = (reply.request_mode & CWWidth) ? reply.width :
1042 ic->core.width;
1043 ch = (reply.request_mode & CWHeight) ? reply.height :
1044 ic->core.height;
1045 } else {
1046 cw = ic->core.width;
1047 ch = ic->core.height;
1048 }
1049 cb = ic->core.border_width;
1050
1051 width = cw + 2 * (cb + glc->grid_margin_width_within_cell);
1052 height = ch + 2 * (cb + glc->grid_margin_height_within_cell);
1053
1054 maxWidth = Max (width, maxWidth);
1055 maxHeight = Max (height, maxHeight);
1056 }
1057
1058
1059 /* The total width of the grid widget should be set to the width of
1060 the largest child widget times the number of columns. */
1061 if (!*TotalWidthOfGridWidget) {
1062 *TotalWidthOfGridWidget = maxWidth * gw->grid.columns +
1063 (2 * (gw->grid.margin_width));
1064 }
1065
1066 /* The total height of the grid widget should be set to the height of
1067 the largest child widget times the number of columns. */
1068 if (!*TotalHeightOfGridWidget) {
1069 *TotalHeightOfGridWidget = maxHeight * gw->grid.rows +
1070 (2 * (gw->grid.margin_height));
1071 }
1072 }
1073
1074
1075 /****************************************************************************
1076 *
1077 * NeedRelayout:
1078 * Called by SetValues.
1079 * Returns True if a relayout is needed.
1080 * based on this class and all superclass resources' changes.
1081 *
1082 ***************************************************************************/
1083 static Boolean
NeedRelayout(Widget old_w,Widget new_w)1084 NeedRelayout (
1085 Widget old_w,
1086 Widget new_w
1087 )
1088 {
1089 ExmGridWidget cw = (ExmGridWidget)old_w;
1090 ExmGridWidget nw = (ExmGridWidget)new_w;
1091
1092 if (nw->grid.margin_width != cw->grid.margin_width ||
1093 nw->grid.margin_height != cw->grid.margin_height ||
1094 nw->grid.rows != cw->grid.rows ||
1095 nw->grid.columns != cw->grid.columns) {
1096 return True ;
1097 } else
1098 return False ;
1099 }
1100
1101
1102
1103
1104 /*-- Trait methods --*/
1105
1106
1107 /****************************************************************
1108 *
1109 * Trait method for XmQTdialogShellSavvy trait.
1110 *
1111 **************************************************************/
1112 static void
CallMapUnmap(Widget wid,Boolean map_unmap)1113 CallMapUnmap(
1114 Widget wid,
1115 Boolean map_unmap)
1116 {
1117 ExmGridWidget grid = (ExmGridWidget) wid ;
1118 XmAnyCallbackStruct call_data;
1119
1120 call_data.reason = (map_unmap)? XmCR_MAP : XmCR_UNMAP;
1121 call_data.event = NULL;
1122
1123 if (map_unmap) {
1124 XtCallCallbackList (wid, grid->grid.map_callback,
1125 &call_data);
1126 } else {
1127 XtCallCallbackList (wid, grid->grid.unmap_callback,
1128 &call_data);
1129 }
1130 }
1131
1132 /*****************************************************************
1133 *
1134 * Trait method for XmQTspecifyRenderTable.
1135 *
1136 *****************************************************************/
1137
1138 static XmRenderTable
GetTable(Widget wid,XtEnum type)1139 GetTable(
1140 Widget wid,
1141 XtEnum type)
1142 {
1143 ExmGridWidget grid = (ExmGridWidget) wid ;
1144
1145 switch(type) {
1146 case XmLABEL_RENDER_TABLE : return grid->grid.label_render_table ;
1147 case XmBUTTON_RENDER_TABLE : return grid->grid.button_render_table ;
1148 case XmTEXT_RENDER_TABLE : return grid->grid.text_render_table ;
1149 }
1150
1151 return NULL ;
1152 }
1153
1154
1155 /*******************************************************************************
1156 *
1157 * ExmCreateGrid:
1158 * Called by an application.
1159 *
1160 ******************************************************************************/
1161 Widget
ExmCreateGrid(Widget parent,char * name,ArgList arglist,Cardinal argcount)1162 ExmCreateGrid (
1163 Widget parent,
1164 char *name,
1165 ArgList arglist,
1166 Cardinal argcount
1167 )
1168 {
1169 /* This is a convenience function to instantiate an ExmGrid widget. */
1170 return (XtCreateWidget (name, exmGridWidgetClass, parent,
1171 arglist, argcount));
1172 }
1173
1174
1175 /*******************************************************************************
1176 *
1177 * ExmCreateGridDialog
1178 * Called by an application to create an ExmGrid managed by a
1179 * DialogShell.
1180 *
1181 ******************************************************************************/
1182 Widget
ExmCreateGridDialog(Widget parent,char * name,ArgList arglist,Cardinal argcount)1183 ExmCreateGridDialog (
1184 Widget parent,
1185 char *name,
1186 ArgList arglist,
1187 Cardinal argcount
1188 )
1189 {
1190 return XmeCreateClassDialog (exmGridWidgetClass,
1191 parent, name, arglist, argcount) ;
1192
1193 }
1194