1 /*
2  * Motif
3  *
4  * Copyright (c) 1987-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 /************************************************************
26 *	INCLUDE FILES
27 *************************************************************/
28 #include <stdio.h>
29 
30 #include "XmI.h"
31 #include <Xm/IconBoxP.h>
32 #include <Xm/ExtP.h>
33 
34 /************************************************************
35 *	TYPEDEFS AND DEFINES
36 *************************************************************/
37 
38 #define SUPERCLASS ((WidgetClass) &xmManagerClassRec)
39 
40 /************************************************************
41 *	MACROS
42 *************************************************************/
43 #define GetIconInfo(w) ((IconInfo*) \
44            &(((XmIconBoxConstraintsRec*)((char*)((w)->core.constraints)))->icon))
45 
46 
47 /************************************************************
48 *	GLOBAL DECLARATIONS
49 *************************************************************/
50 
51 /************************************************************
52 *	STATIC FUNCTION DECLARATIONS
53 *************************************************************/
54 
55 static void ClassInitialize();
56 static void ClassPartInitialize(WidgetClass w_class);
57 static void Realize(Widget, Mask *, XSetWindowAttributes *);
58 static void Resize(Widget), ChangeManaged(Widget), InsertChild(Widget);
59 static void Initialize(Widget, Widget, ArgList, Cardinal *);
60 static void ConstraintInitialize(Widget, Widget, ArgList, Cardinal *);
61 static Boolean ConstraintSetValues(Widget, Widget, Widget, ArgList, Cardinal*);
62 
63 static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
64 
65 static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
66 					XtWidgetGeometry *);
67 static XtGeometryResult QueryGeometry(Widget,
68 				      XtWidgetGeometry *, XtWidgetGeometry *);
69 
70 /************************
71  * Actions and callbacks.
72  ************************/
73 
74 /*********************
75  * Internal Routines.
76  *********************/
77 
78 static void FindNearestCellLocation(Widget, Position *, Position *);
79 static void GetMinCells(Widget, Cardinal *, Cardinal *);
80 static void PlaceChildren(Widget, Widget);
81 static void GetMaxCellSize(Widget, Widget, Dimension *, Dimension *);
82 static void GetCellFromXY(Widget, Position, Position, Position *, Position *);
83 static void GetXYFromCell(Widget, IconInfo *, Position *, Position *);
84 static void CalcCellSizes(Widget, Widget,
85 			  Boolean, Boolean, Dimension *, Dimension *);
86 
87 static Boolean SetToEmptyCell(Widget);
88 
89 /************************************************************
90 *	STATIC DECLARATIONS
91 *************************************************************/
92 
93 static XtResource resources[] =
94 {
95   {
96     XmNminimumVerticalCells, XmCDefaultCells, XmRDimension,
97     sizeof(Dimension), XtOffsetOf(XmIconBoxRec, box.min_v_cells),
98     XmRImmediate, (XtPointer) 2
99   },
100   {
101     XmNminimumHorizontalCells, XmCDefaultCells, XmRHorizontalDimension,
102     sizeof(Dimension), XtOffsetOf(XmIconBoxRec, box.min_h_cells),
103     XmRImmediate, (XtPointer) 2
104   },
105 
106   {
107     XmNminimumCellWidth, XmCMinimumCellSize, XmRHorizontalDimension,
108     sizeof(Dimension), XtOffsetOf(XmIconBoxRec, box.min_cell_width),
109     XmRImmediate, (XtPointer) 20
110   },
111 
112   {
113     XmNminimumCellHeight, XmCMinimumCellSize, XmRDimension,
114     sizeof(Dimension), XtOffsetOf(XmIconBoxRec, box.min_cell_height),
115     XmRImmediate, (XtPointer) 10
116   },
117 
118   {
119     XmNverticalMargin, XmCMargin, XmRVerticalDimension,
120     sizeof(Dimension), XtOffsetOf(XmIconBoxRec, box.v_margin),
121     XmRImmediate, (XtPointer) 4
122   },
123 
124   {
125     XmNhorizontalMargin, XmCMargin, XmRHorizontalDimension,
126     sizeof(Dimension), XtOffsetOf(XmIconBoxRec, box.h_margin),
127     XmRImmediate, (XtPointer) 4
128   }
129 };
130 
131 static XmSyntheticResource get_resources[] =
132 {
133   {
134     XmNhorizontalMargin, sizeof(Dimension),
135     XtOffsetOf(XmIconBoxRec, box.h_margin),
136     XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
137   },
138 
139   {
140     XmNverticalMargin, sizeof(Dimension),
141     XtOffsetOf(XmIconBoxRec, box.v_margin),
142     XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
143   },
144 
145   {
146     XmNminimumCellWidth, sizeof(Dimension),
147     XtOffsetOf(XmIconBoxRec, box.min_cell_width),
148     XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
149   },
150 
151   {
152     XmNminimumCellHeight, sizeof(Dimension),
153     XtOffsetOf(XmIconBoxRec, box.min_cell_height),
154     XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
155   }
156 };
157 
158 static short G_any_cell = XmIconBoxAnyCell;
159 
160 static XtResource constraints[] =
161 {
162   {
163     XmNcellX, XmCCellX, XmRShort,
164     sizeof(short), XtOffsetOf(XmIconBoxConstraintsRec, icon.cell_x),
165     XmRShort, (XtPointer) &G_any_cell
166   },
167 
168   {
169     XmNcellY, XmCCellY, XmRShort,
170     sizeof(short), XtOffsetOf(XmIconBoxConstraintsRec, icon.cell_y),
171     XmRShort, (XtPointer) &G_any_cell
172   }
173 };
174 
175 XmIconBoxClassRec xmIconBoxClassRec = {
176   { /* core fields */
177     /* superclass		*/	SUPERCLASS,
178     /* class_name		*/	"XmIconBox",
179     /* widget_size		*/	sizeof(XmIconBoxRec),
180     /* class_initialize		*/	ClassInitialize,
181     /* class_part_initialize	*/	ClassPartInitialize,
182     /* class_inited		*/	FALSE,
183     /* initialize		*/	Initialize,
184     /* initialize_hook		*/	NULL,
185     /* realize			*/	Realize,
186     /* actions			*/	NULL,
187     /* num_actions		*/	0,
188     /* resources		*/	(XtResource*)resources,
189     /* num_resources		*/	XtNumber(resources),
190     /* xrm_class		*/	NULLQUARK,
191     /* compress_motion		*/	TRUE,
192     /* compress_exposure	*/	TRUE,
193     /* compress_enterleave	*/	TRUE,
194     /* visible_interest		*/	FALSE,
195     /* destroy			*/	NULL,
196     /* resize			*/	Resize,
197     /* expose			*/	NULL,
198     /* set_values		*/	SetValues,
199     /* set_values_hook		*/	NULL,
200     /* set_values_almost	*/	XtInheritSetValuesAlmost,
201     /* get_values_hook		*/	NULL,
202     /* accept_focus		*/	NULL,
203     /* version			*/	XtVersion,
204     /* callback_private		*/	NULL,
205     /* tm_table			*/	XtInheritTranslations,
206     /* query_geometry		*/	(XtGeometryHandler) QueryGeometry,
207     /* display_accelerator	*/	XtInheritDisplayAccelerator,
208     /* extension		*/	NULL
209   },
210    {		/* composite_class fields */
211     /* geometry_manager   */      GeometryManager,
212     /* change_managed     */      ChangeManaged,
213     /* insert_child       */      InsertChild,
214     /* delete_child       */      XtInheritDeleteChild,
215     /* extension          */      NULL,
216    },
217    {		/* constraint_class fields */
218     /* resource list        */         (XtResource*)constraints,
219     /* num resources        */         XtNumber(constraints),
220     /* constraint size      */         sizeof(XmIconBoxConstraintsRec),
221     /* init proc            */         ConstraintInitialize,
222     /* destroy proc         */         NULL,
223     /* set values proc      */         ConstraintSetValues,
224     /* extension            */         NULL,
225    },
226    {		/* manager_class fields */
227     /* default translations   */      XtInheritTranslations,
228     /* syn_resources          */      get_resources,
229     /* num_syn_resources      */      XtNumber(get_resources),
230     /* syn_cont_resources     */      NULL,
231     /* num_syn_cont_resources */      0,
232     /* parent_process         */      XmInheritParentProcess,
233     /* extension	      */      NULL,
234    },
235   { /* Icon Box fields */
236       NULL                      /* extension          */
237   }
238 };
239 
240 WidgetClass xmIconBoxWidgetClass = (WidgetClass)&xmIconBoxClassRec;
241 
242 /************************************************************
243 *	STATIC CODE
244 *************************************************************/
245 
246 /*	Function Name: Initialize
247  *	Description:   Called to initialize information specific
248  *                     to this widget.
249  *	Arguments:     req - what was originally requested.
250  *                     set - what will be created (our superclassed have
251  *                           already mucked with this)
252  *                     args, num_args - The arguments passed to
253  *                                      the creation call.
254  *	Returns:       none.
255  */
256 
257 
258 static void
ClassInitialize()259 ClassInitialize()
260 {
261   /* do nothing */
262 }
263 
264 /*ARGSUSED*/
265 static void
Initialize(Widget req,Widget set,ArgList args,Cardinal * num_args)266 Initialize(Widget req, Widget set, ArgList args, Cardinal * num_args)
267 {
268     XmIconBoxWidget ibw = (XmIconBoxWidget) set;
269 
270     /*
271      * This is needed so that the right thing happens if an icon box is
272      * created w/o any children.
273      */
274 
275     CalcCellSizes(set, NULL, FALSE, FALSE,
276 		  &(XmIconBox_cell_width(ibw)), &(XmIconBox_cell_height(ibw)));
277 }
278 
279 /*	Function Name: Realize
280  *	Description:   Called to realize this widget.
281  *	Arguments:     w - Widget to realize.
282  *                     valueMask, attributes - attributes to use when creating
283  *                     this widget's window.
284  *	Returns:       none.
285  *
286  * This overrides the Manager's frobbing with various values.
287  */
288 
289 static void
Realize(Widget w,Mask * valueMask,XSetWindowAttributes * attributes)290 Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
291 {
292     XtCreateWindow (w, InputOutput, CopyFromParent, *valueMask, attributes);
293 }
294 
295 /*	Function Name: Resize
296  *	Description:   Called when this widget has been resized.
297  *	Arguments:     w - the widget to resize.
298  *	Returns:       none.
299  */
300 
301 static void
Resize(Widget w)302 Resize(Widget w)
303 {
304     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
305 
306     CalcCellSizes(w, NULL, TRUE, FALSE,
307 		  &(XmIconBox_cell_width(ibw)), &(XmIconBox_cell_height(ibw)));
308     PlaceChildren(w, NULL);
309 }
310 
311 /*	Function Name: SetValues
312  *	Description:   Called when some widget data needs to be modified on-
313  *                     the-fly.
314  *	Arguments:     current - the current (old) widget values.
315  *                     request - before superclassed have changed things.
316  *                     set - what will acutally be the set values.
317  *                     args, num_args - the arguments in the list.
318  *	Returns:       none
319  */
320 
321 /*ARGSUSED*/
322 static Boolean
SetValues(Widget current,Widget request,Widget set,ArgList args,Cardinal * num_args)323 SetValues(Widget current, Widget request, Widget set,
324 	  ArgList args, Cardinal * num_args)
325 {
326     XmIconBoxWidget old_ibw = (XmIconBoxWidget) current;
327     XmIconBoxWidget set_ibw = (XmIconBoxWidget) set;
328 
329     if ((XmIconBox_min_v_cells(old_ibw) != XmIconBox_min_v_cells(set_ibw))           ||
330 	(XmIconBox_min_h_cells(old_ibw) != XmIconBox_min_h_cells(set_ibw))           ||
331 	(XmIconBox_min_cell_width(old_ibw) != XmIconBox_min_cell_width(set_ibw))     ||
332 	(XmIconBox_min_cell_height(old_ibw) != XmIconBox_min_cell_height(set_ibw))   ||
333 	(XmIconBox_v_margin(old_ibw) != XmIconBox_v_margin(set_ibw))                 ||
334 	(XmIconBox_h_margin(old_ibw) != XmIconBox_h_margin(set_ibw)) )
335     {
336 	CalcCellSizes(set, NULL, FALSE, FALSE,
337 		      &(XmIconBox_cell_width(set_ibw)), &(XmIconBox_cell_height(set_ibw)));
338 	PlaceChildren(set, NULL);
339     }
340 
341     return(FALSE);
342 }
343 
344 /*	Function Name: QueryGeometry
345  *	Description:   Called when my parent wants to know what size
346  *                     I would like to be.
347  *	Arguments:     w - the widget to check.
348  *                     indended - constriants imposed by the parent.
349  *                     preferred - what I would like.
350  *	Returns:       See Xt Manual.
351  */
352 
353 static XtGeometryResult
QueryGeometry(Widget w,XtWidgetGeometry * intended,XtWidgetGeometry * preferred)354 QueryGeometry(Widget w,XtWidgetGeometry *intended, XtWidgetGeometry *preferred)
355 {
356     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
357     Cardinal min_x, min_y;
358     Dimension max_w, max_h;
359 
360     GetMinCells(w, &min_x, &min_y);
361     GetMaxCellSize(w, NULL, &max_w, &max_h);
362 
363     min_x++;
364     min_y++;
365 
366     preferred->width = XmIconBox_h_margin(ibw) + min_x * (max_w + XmIconBox_h_margin(ibw));
367     preferred->height= XmIconBox_v_margin(ibw) + min_y * (max_h + XmIconBox_v_margin(ibw));
368 
369     return(_XmHWQuery(w, intended, preferred));
370 }
371 
372 /************************************************************
373  *
374  * Composite and Constraint Information.
375  *
376  ************************************************************/
377 
378 /*	Function Name: GeometryManager
379  *	Description:   handles requests from children for a size change.
380  *	Arguments:     child - the child to change.
381  *                     request - the geometry that the child wants.
382  *                     return - what we will allow if this is an almost.
383  *	Returns:       status.
384  */
385 
386 /*ARGSUSED*/
387 static XtGeometryResult
GeometryManager(Widget w,XtWidgetGeometry * request,XtWidgetGeometry * result)388 GeometryManager(Widget w, XtWidgetGeometry * request,
389 		XtWidgetGeometry * result)
390 {
391     Dimension cwidth, cheight;
392     XmIconBoxWidget ibw = (XmIconBoxWidget) XtParent(w);
393     IconInfo * info = GetIconInfo(w);
394     Boolean w_req = (request->request_mode & CWWidth);
395     Boolean h_req = (request->request_mode & CWHeight);
396     Boolean x_req = (request->request_mode & CWX);
397     Boolean y_req = (request->request_mode & CWY);
398 
399     if (!(request->request_mode & (CWWidth | CWHeight | CWX | CWY)))
400 	return(XtGeometryNo);
401 
402     result->request_mode = 0;
403 
404     if (w_req || h_req) {
405 	CalcCellSizes((Widget) ibw, w, FALSE, TRUE, &cwidth, &cheight);
406 
407 	if(w_req)
408 	    ASSIGN_MAX(cwidth, request->width);
409 	else
410 	    ASSIGN_MAX(cwidth, w->core.width);
411 
412 	if(h_req)
413 	    ASSIGN_MAX(cheight, request->height);
414 	else
415 	    ASSIGN_MAX(cheight, w->core.height);
416 
417 	/*
418 	 * Do not allow an x, y width and height request at the same time.
419 	 * since it is unclear what this would mean.  I want to place the
420 	 * widget in the cell the center of it is over.  With a multiple
421 	 * request like this is it tough to find out which cell to use
422 	 * since there are two reasonable values for height and width.
423 	 */
424 
425 	result->x = w->core.x;
426 	result->y = w->core.y;
427 	result->width  = cwidth;
428 	result->height = cheight;
429 	result->request_mode |= CWX | CWY | CWHeight | CWWidth;
430     }
431     else if ( x_req || y_req ) {
432 	Position x, y;
433 	short cell_x, cell_y;
434 
435 	if (x_req)
436 	    x = request->x;
437 	else
438 	    x = w->core.x;
439 
440 	if (y_req)
441 	    y = request->y;
442 	else
443 	    y = w->core.y;
444 
445 	FindNearestCellLocation((Widget) ibw, &x, &y);
446 
447 	GetCellFromXY((Widget) ibw, x, y, &cell_x, &cell_y);
448 	if (XmIconBoxIsCellEmpty((Widget) ibw, cell_x, cell_y, w)) {
449 	    result->x = x;
450 	    result->y = y;
451 	    result->request_mode |= CWX | CWY;
452 	}
453 	else			/* Cell is full, return NO. */
454 	    return(XtGeometryNo);
455     }
456 
457     if (((request->x == result->x) || !x_req) &&
458 	((request->y == result->y) || !y_req) &&
459 	((request->width == result->width) || !w_req) &&
460 	((request->height == result->height) || !h_req))
461     {
462 	if (request->request_mode &
463 	    (CWBorderWidth | CWStackMode | CWSibling))
464 	{
465 	    return(XtGeometryAlmost);
466 	}
467 
468 	if (request->request_mode & XtCWQueryOnly)
469 	    return(XtGeometryYes);
470 
471 	if (w_req || h_req) {
472 	    if (w_req)
473 		info->pref_width = w->core.width = request->width;
474 
475 	    if (h_req)
476 		info->pref_height = w->core.height = request->height;
477 	}
478 	else {
479 	    /*
480 	     * NOTE: We are assuming here that the cell height/width
481 	     * did not change.  This is valid because this code is
482 	     * only executed if w_req and h_req are false.
483 	     */
484 
485 	    GetCellFromXY((Widget) ibw, result->x, result->y,
486 			  &(info->cell_x), &(info->cell_y));
487 	}
488 
489 	CalcCellSizes((Widget) ibw, NULL, FALSE, FALSE,
490 		      &(XmIconBox_cell_width(ibw)), &(XmIconBox_cell_height(ibw)));
491 
492 	PlaceChildren((Widget) ibw, w);
493 	return(XtGeometryYes);
494     }
495 
496     info->pref_width = info->pref_height = 0; /* invalidate cache. */
497 
498     if (((request->x == result->x) || !x_req)         ||
499 	((request->y == result->y) || !y_req)         ||
500 	((request->width == result->width) || !w_req) ||
501 	((request->height == result->height) || !h_req))
502     {
503 	return(XtGeometryAlmost);
504     }
505     else
506 	return(XtGeometryNo);
507 }
508 
509 /*	Function Name: InsertChild
510  *	Description: called when a new child is to be added.
511  *	Arguments: w - the new child.
512  *	Returns: none.
513  *
514  * This routine simply makes sure that no gadgets are added.
515  */
516 
517 static void
InsertChild(Widget w)518 InsertChild(Widget w)
519 {
520    if (_XmGadgetWarning(w))
521        return;
522 
523    {
524       XtWidgetProc insert_child;
525 
526       _XmProcessLock();
527       insert_child = ( (CompositeWidgetClass) SUPERCLASS)->composite_class.insert_child;
528       _XmProcessUnlock();
529 
530       (*insert_child)(w);
531    }
532 }
533 
534 /*	Function Name: ChangeManaged
535  *	Description:   When a management change has occured...
536  *	Arguments:     w - the icon box widget.
537  *	Returns:       none.
538  */
539 
540 static void
ChangeManaged(Widget w)541 ChangeManaged(Widget w)
542 {
543     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
544     Widget * childp;
545 
546     CalcCellSizes(w, NULL, FALSE, TRUE,
547 		  &(XmIconBox_cell_width(ibw)), &(XmIconBox_cell_height(ibw)));
548 
549     ForAllChildren(ibw, childp) {
550 	IconInfo * info = GetIconInfo(*childp);
551 
552 	if ((info->cell_x != XmIconBoxAnyCell) &&
553 	    (info->cell_y != XmIconBoxAnyCell) &&
554 	    !XmIconBoxIsCellEmpty((Widget) ibw,
555 				  info->cell_x, info->cell_y, *childp))
556 	{
557 	    static String params[1];
558 	    Cardinal num = 1;
559 	    char buf[BUFSIZ];
560 
561 	    params[0] = buf;
562 	    snprintf(buf, BUFSIZ, "(%d, %d)", info->cell_x, info->cell_y);
563 
564 	    _XmWarningMsg(w, XmNcellNotEmpty,
565 		    XmNcellNotEmptyMsg, params, num);
566 	    /*
567 	     * tell it to reset this to an empty cell.
568 	     */
569 
570 	    info->cell_y = XmIconBoxAnyCell;
571 	}
572 
573 	if ((info->cell_x == XmIconBoxAnyCell) ||
574 	    (info->cell_y == XmIconBoxAnyCell))
575 	{
576 	    Position x = (*childp)->core.x;
577 	    Position y = (*childp)->core.y;
578 	    Position cell_x, cell_y;
579 
580 	    /*
581 	     * If the cell location is not specified try to find the
582 	     * cell nearest the X and Y coords specified.
583 	     */
584 
585 	    FindNearestCellLocation((Widget) ibw, &x, &y);
586 	    GetCellFromXY((Widget) ibw, x, y, &cell_x, &cell_y);
587 
588 	    if (XmIconBoxIsCellEmpty((Widget) ibw, cell_x, cell_y, w))
589 	    {
590 		info->cell_x = cell_x;
591 		info->cell_y = cell_y;
592 	    }
593 	    /*
594 	     * If this cell is full the just find any empty cell.
595 	     */
596 	    else if (!SetToEmptyCell(*childp)) {
597 		XmeWarning(w, XmNnoEmptyCellsMsg);
598 	    }
599 	}
600     }
601 
602     CalcCellSizes(w, NULL, FALSE, FALSE,
603 		  &(XmIconBox_cell_width(ibw)), &(XmIconBox_cell_height(ibw)));
604 
605     PlaceChildren(w, NULL);
606 
607    XmeNavigChangeManaged(w);	/* For Motif navigation */
608 }
609 
610 /*
611  * ClassPartInitialize sets up the fast subclassing for the widget.
612  */
613 static void
614 #ifdef _NO_PROTO
ClassPartInitialize(w_class)615 ClassPartInitialize(w_class)
616         WidgetClass w_class ;
617 #else
618 ClassPartInitialize(WidgetClass w_class)
619 #endif /* _NO_PROTO */
620 {
621     _XmFastSubclassInit (w_class, XmICONBOX_BIT);
622 }
623 
624 
625 /*	Function Name: ConstraintInitialize
626  *	Description:   Called when a childs constriaints need initializing.
627  *	Arguments:     req - the widget being requested.
628  *                     set - what this will become.
629  *                     args, num_args - the argument list.
630  *	Returns:       none.
631  */
632 
633 /*ARGSUSED*/
634 static void
ConstraintInitialize(Widget req,Widget set,ArgList args,Cardinal * num_args)635 ConstraintInitialize(Widget req, Widget set, ArgList args, Cardinal * num_args)
636 {
637     IconInfo * info = GetIconInfo(set);
638 
639     info->pref_width = req->core.width;
640     info->pref_height = req->core.height;
641 }
642 
643 /*	Function Name: ConstraintSetValues
644  *	Description:   Called when some constraint data needs to be modified
645  *                     on-the-fly.
646  *	Arguments:     current - the current (old) widget values.
647  *                     request - before superclassed have changed things.
648  *                     set - what will acutally be the new values.
649  *                     args, num_args - the arguments in the list.
650  *	Returns:       none
651  */
652 
653 /*ARGSUSED*/
654 static Boolean
ConstraintSetValues(Widget current,Widget request,Widget set,ArgList args,Cardinal * num_args)655 ConstraintSetValues(Widget current, Widget request, Widget set,
656 		    ArgList args, Cardinal * num_args)
657 {
658     IconInfo * set_info = GetIconInfo(set);
659     IconInfo * old_info = GetIconInfo(current);
660 
661     if (set->core.width != set_info->pref_width)
662 	set_info->pref_width = 0;
663 
664     if (set->core.height != set_info->pref_height)
665 	set_info->pref_height = 0;
666 
667     if ((set_info->cell_x != old_info->cell_x) ||
668 	(set_info->cell_y != old_info->cell_y))
669     {
670 	if ( XmIconBoxIsCellEmpty(XtParent(set),
671 				  set_info->cell_x, set_info->cell_y, set))
672 	{
673 	    GetXYFromCell(XtParent(set),
674 			  set_info, &(set->core.x), &(set->core.y));
675 	}
676 	else {
677 	    static String params[1];
678 	    Cardinal num = 1;
679 	    char buf[BUFSIZ];
680 
681 	    params[0] = buf;
682 	    snprintf(buf, BUFSIZ, "(%d, %d)", set_info->cell_x, set_info->cell_y);
683 
684 	    _XmWarningMsg(set, XmNcellNotEmpty,
685 		    XmNcellNotEmptyMsg, params, num);
686 
687 	    set_info->cell_x = old_info->cell_x;
688 	    set_info->cell_y = old_info->cell_y;
689 	}
690     }
691 
692     return(False);
693 }
694 
695 /************************************************************
696  *
697  * Actions and Callbacks.
698  *
699  ************************************************************/
700 
701 /************************************************************
702  *
703  * Internal routines.
704  *
705  ************************************************************/
706 
707 /*	Function Name: GetCellFromXY
708  *	Description:   Gets the cell located at this location.
709  *	Arguments:     w - the icon box.
710  *                     x, y - the coordinates in X space.
711  * RETURNED            cell_x, cell_y - the corrdinates in cell space.
712  *	Returns:       none.
713  */
714 
715 static void
GetCellFromXY(Widget w,Position x,Position y,Position * cell_x,Position * cell_y)716 GetCellFromXY(Widget w,
717 	      Position x, Position y, Position * cell_x, Position * cell_y)
718 {
719     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
720 
721     *cell_x = (int)x / (int)(XmIconBox_cell_width(ibw) + XmIconBox_h_margin(ibw));
722     *cell_y = (int)y / (int)(XmIconBox_cell_height(ibw) + XmIconBox_v_margin(ibw));
723 }
724 
725 /*	Function Name: Find Nearest Cell Location
726  *	Description: Finds the nearest cell
727  *	Arguments: ibw - the icon box widget.
728  * IN/OUT          x, y - Used as an input for the current location
729  *                        is output with the new location.
730  *	Returns: none
731  */
732 
733 static void
FindNearestCellLocation(Widget w,Position * x,Position * y)734 FindNearestCellLocation(Widget w, Position *x, Position *y)
735 {
736     IconInfo temp;
737     Dimension width, height;
738     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
739 
740     width = XmIconBox_cell_width(ibw);
741     height = XmIconBox_cell_height(ibw);
742 
743     GetCellFromXY(w, *x + width/2,
744 		  *y + height/2, &(temp.cell_x), &(temp.cell_y));
745 
746     GetXYFromCell(w, &temp, x, y);
747 }
748 
749 /*	Function Name: GetXYFromCell
750  *	Description:   Gets the X and Y position for this cell.
751  *	Arguments:     info - the cell info.
752  * RETURNED            x, y - the coordinates in X space.
753  *	Returns:       none.
754  */
755 
756 static void
GetXYFromCell(Widget w,IconInfo * info,Position * x,Position * y)757 GetXYFromCell(Widget w, IconInfo * info, Position * x, Position * y)
758 {
759     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
760     Position x_temp = (info->cell_x < 0) ? 0 : info->cell_x;
761     Position y_temp = (info->cell_y < 0) ? 0 : info->cell_y;
762 
763     *x = XmIconBox_h_margin(ibw) +
764 	 x_temp * (XmIconBox_cell_width(ibw) + XmIconBox_h_margin(ibw));
765 
766     *y = XmIconBox_v_margin(ibw) +
767 	 y_temp * (XmIconBox_cell_height(ibw) + XmIconBox_v_margin(ibw));
768 }
769 
770 /*	Function Name: PlaceChildren
771  *	Description:   Places all managed children correctly.
772  *	Arguments:     w - the icon box widget.
773  *                     child - set attributes rather than configure this child.
774  *	Returns:       none.
775  */
776 
777 static void
PlaceChildren(Widget w,Widget child)778 PlaceChildren(Widget w, Widget child)
779 {
780     Widget * childp;
781     Position x, y;
782     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
783 
784     ForAllChildren(ibw, childp) {
785 	if (!XtIsManaged(*childp))
786 	    continue;
787 
788 	GetXYFromCell(w, GetIconInfo(*childp), &x, &y);
789 
790 	if (*childp == child) {
791 	    child->core.x = x;
792 	    child->core.y = y;
793 	    child->core.width = XmIconBox_cell_width(ibw);
794 	    child->core.height = XmIconBox_cell_height(ibw);
795 	}
796 	else {
797 	    _XmConfigureWidget(*childp, x, y,
798 			       XmIconBox_cell_width(ibw), XmIconBox_cell_height(ibw),
799 			       (*childp)->core.border_width);
800 	}
801     }
802 }
803 
804 /*	Function Name: CalcCellSizes
805  *	Description:   Calculates the height and width of each cell.
806  *	Arguments:     w - the icon box widget.
807  *                     ignore - ignore this child when calculating cell sizes.
808  *                     noresize - If true then never attempt a resize.
809  *                     query_only - only ask, don't change anything.
810  *                     cell_width, cell_height - new size of each cell.
811  *	Returns:       none.
812  */
813 
814 static void
CalcCellSizes(Widget w,Widget ignore,Boolean noresize,Boolean query_only,Dimension * cell_width,Dimension * cell_height)815 CalcCellSizes(Widget w, Widget ignore, Boolean noresize, Boolean query_only,
816 	      Dimension * cell_width, Dimension * cell_height)
817 {
818     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
819 
820     Cardinal min_x, min_y;
821     Dimension max_w, max_h, d_width, d_height, width, height;
822 
823     GetMinCells(w, &min_x, &min_y);
824     GetMaxCellSize(w, ignore, &max_w, &max_h);
825 
826     min_x++;
827     min_y++;
828 
829     d_width = XmIconBox_h_margin(ibw) + min_x * (max_w + XmIconBox_h_margin(ibw));
830     d_height = XmIconBox_v_margin(ibw) + min_y * (max_h + XmIconBox_v_margin(ibw));
831 
832     if (noresize ||
833 	(_XmRequestNewSize(w, query_only, d_width, d_height,
834 			   &width, &height) != XtGeometryYes))
835     {
836 	if (noresize) {
837 	    width = w->core.width;
838 	    height = w->core.height;
839 	}
840 
841 	/*
842 	 * We may need to adjust the cell size.
843 	 */
844 
845 	if (width < d_width)
846 	    max_w = (width - XmIconBox_h_margin(ibw))/ min_x - XmIconBox_h_margin(ibw);
847 	if (height < d_height)
848 	    max_h = (height - XmIconBox_v_margin(ibw))/ min_y - XmIconBox_v_margin(ibw);
849     }
850 
851     *cell_width = max_w;
852     *cell_height = max_h;
853 }
854 
855 /*	Function Name: GetMinCells
856  *	Description:   Returns the minimum number of cells that should
857  *                     be displayed in each direction.
858  *	Arguments:     w - the Icon Box widget.
859  * RETURN              min_x, min_y - minimum number of cells needed
860  *                                    in each direction.
861  *
862  *	Returns:
863  */
864 
865 static void
GetMinCells(Widget w,Cardinal * min_x,Cardinal * min_y)866 GetMinCells(Widget w, Cardinal * min_x, Cardinal * min_y)
867 {
868     Widget * childp;
869     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
870 
871     *min_x = XmIconBox_min_h_cells(ibw) - 1;
872     *min_y = XmIconBox_min_v_cells(ibw) - 1;
873 
874     ForAllChildren(ibw, childp) {
875 	Position x, y;
876 	IconInfo * info;
877 
878 	if (!XtIsManaged(*childp))
879 	    continue;
880 
881 	info = GetIconInfo(*childp);
882 
883 	x = (info->cell_x < 0) ? 0 : info->cell_x;
884 	y = (info->cell_y < 0) ? 0 : info->cell_y;
885 
886 	if (x > *min_x)
887 	    *min_x = x;
888 
889 	if (y > *min_y)
890 	    *min_y = y;
891     }
892 }
893 
894 /*	Function Name: GetMaxCellSize
895  *	Description:   Gets the maximum size of each cell.
896  *	Arguments:     w - the Icon Box widget.
897  *                     ignore - ignore this child.
898  *                     max_w, max_h - the maximum size of each cell.
899  *	Returns:       none.
900  */
901 
902 static void
GetMaxCellSize(Widget w,Widget ignore,Dimension * max_w,Dimension * max_h)903 GetMaxCellSize(Widget w, Widget ignore, Dimension * max_w, Dimension * max_h)
904 {
905     Widget * childp;
906     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
907     XtWidgetGeometry preferred;
908     register Dimension temp;
909 
910     *max_w = XmIconBox_min_cell_width(ibw);
911     *max_h = XmIconBox_min_cell_height(ibw);
912 
913     ForAllChildren(ibw, childp) {
914 	IconInfo * info = GetIconInfo(*childp);
915 
916 	if (!XtIsManaged(*childp) || (*childp == ignore))
917 	    continue;
918 
919 	if ((info->pref_width != 0) && (info->pref_height != 0)) {
920 	    preferred.width = info->pref_width;
921 	    preferred.height = info->pref_height;
922 	    preferred.border_width = (*childp)->core.border_width;
923 	}
924 	else {
925 	    (void) XtQueryGeometry(*childp, NULL, &preferred);
926 	    info->pref_width = preferred.width;
927 	    info->pref_height = preferred.height;
928 	}
929 
930 	temp = preferred.width + 2 * preferred.border_width;
931 	ASSIGN_MAX(*max_w, temp);
932 
933 	temp = preferred.height + 2 * preferred.border_width;
934 	ASSIGN_MAX(*max_h, temp);
935     }
936 }
937 
938 /*	Function Name: SetToEmptyCell
939  *	Description:   Puts the widget passed into an empty node as
940  *                     close to 0, 0 as possible.
941  *	Arguments:     child - the child.
942  *	Returns:       True if an empty cell was found.
943  */
944 
945 static Boolean
SetToEmptyCell(Widget child)946 SetToEmptyCell(Widget child)
947 {
948     XmIconBoxWidget ibw = (XmIconBoxWidget) XtParent(child);
949 
950     register Position x, y, cur_x, cur_y;
951     register unsigned long square, cur_square;
952     Cardinal max_x, max_y;
953 
954     GetMinCells((Widget) ibw, &max_x, &max_y);
955 
956     cur_x = cur_y = XmIconBoxAnyCell;
957     cur_square = max_x * max_x + max_y * max_y;
958 
959     for (y = 0; y <= max_y; y++)
960 	for (x = 0; x <= max_x; x++) {
961 	    square = x * x + y * y;
962 
963 	    if (square <= cur_square &&
964 		XmIconBoxIsCellEmpty(XtParent(child), x, y, NULL)) {
965 		cur_square = square;
966 		cur_x = x;
967 		cur_y = y;
968 		break;
969 	    }
970 	    else if (square >= cur_square)
971 		continue;
972 	}
973 
974     if (cur_x == XmIconBoxAnyCell) {
975 	IconInfo * info = GetIconInfo(child);
976 
977 	info->cell_x = 0;
978 	info->cell_y = max_y + 1;
979     }
980     else {
981 	IconInfo * info = GetIconInfo(child);
982 
983 	info->cell_x = cur_x;
984 	info->cell_y = cur_y;
985     }
986 
987     return(TRUE);
988 }
989 
990 /************************************************************
991  *
992  * Public Functions.
993  *
994  ************************************************************/
995 
996 /*	Function Name: XmIconBoxIsCellEmpty
997  *	Description:   Returns true if this cell is unused.
998  *	Arguments:     w - the icon box.
999  *                     x, y - cell to check.
1000  *                     ignore - ignore this widget when checking.
1001  *	Returns:       Returns true if this cell is unused.
1002  */
1003 
1004 Boolean
XmIconBoxIsCellEmpty(Widget w,Position x,Position y,Widget ignore)1005 XmIconBoxIsCellEmpty(Widget w, Position x, Position y, Widget ignore)
1006 {
1007     XmIconBoxWidget ibw = (XmIconBoxWidget) w;
1008     Widget * childp;
1009 
1010     _XmWidgetToAppContext(w);
1011     _XmAppLock(app);
1012 
1013     ForAllChildren(ibw, childp) {
1014 	IconInfo * info;
1015 
1016 	if (!XtIsManaged(*childp) ||
1017 	    (*childp == ignore) || (*childp)->core.being_destroyed)
1018 	{
1019 	    continue;
1020 	}
1021 
1022 	info = GetIconInfo(*childp);
1023 	if ((x == info->cell_x) && (y == info->cell_y))
1024 	  {
1025 	    _XmAppUnlock(app);
1026 	    return(False);
1027 	  }
1028     }
1029 
1030     _XmAppUnlock(app);
1031     return(True);
1032 }
1033 
1034 /*	Function Name: XmCreateIconBox
1035  *	Description: Creation Routine for UIL and ADA.
1036  *	Arguments: parent - the parent widget.
1037  *                 name - the name of the widget.
1038  *                 args, num_args - the number and list of args.
1039  *	Returns: The created widget.
1040  */
1041 
1042 Widget
XmCreateIconBox(Widget parent,String name,ArgList args,Cardinal num_args)1043 XmCreateIconBox(Widget parent, String name,
1044 		ArgList args, Cardinal num_args)
1045 {
1046     return(XtCreateWidget(name, xmIconBoxWidgetClass, parent, args, num_args));
1047 }
1048