rebuild geeqie
[oi-userland.git] / components / x11 / libXaw4 / src / Xaw3_1Paned.c
blobac6cad8eddbf1f40b31444f0144d4f91ceeb45c2
1 #ifndef lint
2 static char Xrcsid[] = "$XConsortium: Paned.c,v 1.13 90/03/01 10:48:51 jim Exp $";
3 #endif /* lint */
6 /***********************************************************
7 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
8 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
10 All Rights Reserved
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.
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.
28 ******************************************************************/
31 * Paned.c - Paned Composite Widget.
33 * Updated and significantly modifided from the Athena VPaned Widget.
35 * Date: March 1, 1989
37 * By: Chris D. Peterson
38 * MIT X Consortium
39 * kit@expo.lcs.mit.edu
42 #include <ctype.h>
44 #include <X11/IntrinsicP.h>
45 #include <X11/cursorfont.h>
46 #include <X11/StringDefs.h>
48 #include <X11/Xmu/Misc.h>
49 #include <X11/Xmu/Converters.h>
51 #include <./Xaw3_1XawInit.h>
52 #include <./Xaw3_1Grip.h>
53 #include <./Xaw3_1PanedP.h>
55 typedef enum {UpLeftPane = 'U', LowRightPane = 'L',
56 ThisBorderOnly = 'T', AnyPane = 'A' } Direction;
58 #define NO_INDEX -100
59 #define IS_GRIP NULL
61 #define PaneInfo(w) ((Pane)(w)->core.constraints)
62 #define HasGrip(w) (PaneInfo(w)->grip != NULL)
63 #define IsPane(w) ((w)->core.widget_class != gripWidgetClass)
64 #define PaneIndex(w) (PaneInfo(w)->position)
65 #define IsVert(w) ( (w)->paned.orientation == XtorientVertical )
67 #define ForAllPanes(pw, childP) \
68 for ( (childP) = (pw)->composite.children ; \
69 (childP) < (pw)->composite.children + (pw)->paned.num_panes ; \
70 (childP)++ )
72 #define ForAllChildren(pw, childP) \
73 for ( (childP) = (pw)->composite.children ; \
74 (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
75 (childP)++ )
77 /*****************************************************************************
79 * Full instance record declaration
81 ****************************************************************************/
83 static char defGripTranslations[] =
84 "<Btn1Down>: GripAction(Start, UpLeftPane) \n\
85 <Btn2Down>: GripAction(Start, ThisBorderOnly) \n\
86 <Btn3Down>: GripAction(Start, LowRightPane) \n\
87 <Btn1Motion>: GripAction(Move, UpLeft) \n\
88 <Btn2Motion>: GripAction(Move, ThisBorder) \n\
89 <Btn3Motion>: GripAction(Move, LowRight) \n\
90 Any<BtnUp>: GripAction(Commit)";
92 #define offset(field) XtOffset(PanedWidget, paned.field)
94 static XtResource resources[] = {
95 {XtNinternalBorderColor, XtCBorderColor, XtRPixel, sizeof(Pixel),
96 offset(internal_bp), XtRString,
97 (caddr_t) "XtDefaultForeground"},
98 {XtNinternalBorderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
99 offset(internal_bw), XtRImmediate, (caddr_t) 1},
100 {XtNgripIndent, XtCGripIndent, XtRPosition, sizeof(Position),
101 offset(grip_indent), XtRImmediate, (caddr_t) 10},
102 {XtNrefigureMode, XtCBoolean, XtRBoolean, sizeof(Boolean),
103 offset(refiguremode), XtRImmediate, (caddr_t) TRUE},
104 {XtNgripTranslations, XtCTranslations, XtRTranslationTable,
105 sizeof(XtTranslations),
106 offset(grip_translations), XtRString, (caddr_t)defGripTranslations},
107 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
108 offset(orientation), XtRImmediate, (caddr_t) XtorientVertical},
110 /* Cursors - both horiz and vertical have to work. */
112 {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
113 offset(cursor), XtRImmediate, None},
114 {XtNgripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
115 offset(grip_cursor), XtRImmediate, None},
116 {XtNverticalGripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
117 offset(v_grip_cursor), XtRString, "sb_v_double_arrow"},
118 {XtNhorizontalGripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
119 offset(h_grip_cursor), XtRString, "sb_h_double_arrow"},
121 {XtNbetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
122 offset(adjust_this_cursor), XtRString, None},
123 {XtNverticalBetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
124 offset(v_adjust_this_cursor), XtRString, "sb_left_arrow"},
125 {XtNhorizontalBetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
126 offset(h_adjust_this_cursor), XtRString, "sb_up_arrow"},
128 {XtNupperCursor, XtCCursor, XtRCursor, sizeof(Cursor),
129 offset(adjust_upper_cursor), XtRString, "sb_up_arrow"},
130 {XtNlowerCursor, XtCCursor, XtRCursor, sizeof(Cursor),
131 offset(adjust_lower_cursor), XtRString, "sb_down_arrow"},
132 {XtNleftCursor, XtCCursor, XtRCursor, sizeof(Cursor),
133 offset(adjust_left_cursor), XtRString, "sb_left_arrow"},
134 {XtNrightCursor, XtCCursor, XtRCursor, sizeof(Cursor),
135 offset(adjust_right_cursor), XtRString, "sb_right_arrow"},
138 #undef offset
140 #define offset(field) XtOffset(Pane, field)
142 static XtResource subresources[] = {
143 {XtNallowResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
144 offset(allow_resize), XtRImmediate, (caddr_t) FALSE},
145 {XtNposition, XtCPosition, XtRInt, sizeof(int),
146 offset(position), XtRImmediate, (caddr_t) 0},
147 {XtNmin, XtCMin, XtRDimension, sizeof(Dimension),
148 offset(min), XtRImmediate, (caddr_t) PANED_GRIP_SIZE},
149 {XtNmax, XtCMax, XtRDimension, sizeof(Dimension),
150 offset(max), XtRImmediate, (caddr_t) ~0},
151 {XtNpreferredPaneSize, XtCPreferredPaneSize, XtRDimension,
152 sizeof(Dimension), offset(preferred_size),
153 XtRImmediate, (caddr_t) PANED_ASK_CHILD},
154 {XtNresizeToPreferred, XtCBoolean, XtRBoolean, sizeof(Boolean),
155 offset(resize_to_pref), XtRImmediate, (caddr_t) FALSE},
156 {XtNskipAdjust, XtCBoolean, XtRBoolean, sizeof(Boolean),
157 offset(skip_adjust), XtRImmediate, (caddr_t) FALSE},
158 {XtNshowGrip, XtCShowGrip, XtRBoolean, sizeof(Boolean),
159 offset(show_grip), XtRImmediate, (caddr_t) TRUE},
162 #undef offset
164 static void ClassInitialize(), Initialize();
165 static void Realize(), Resize();
166 static void Redisplay();
167 static void GetGCs(), ReleaseGCs();
168 static void RefigureLocationsAndCommit();
169 static Boolean SetValues();
170 static XtGeometryResult GeometryManager();
171 static void ChangeManaged();
172 static void InsertChild();
173 static void DeleteChild();
174 static Boolean PaneSetValues();
175 static Dimension PaneSize(), GetRequestInfo();
176 static Boolean SatisfiesRule1(), SatisfiesRule2(), SatisfiesRule3();
178 static void PushPaneStack();
179 static void GetPaneStack();
180 static Boolean PopPaneStack();
181 static void ClearPaneStack();
183 #define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
185 PanedClassRec panedClassRec = {
187 /* core class fields */
188 /* superclass */ (WidgetClass) SuperClass,
189 /* class name */ "Paned",
190 /* size */ sizeof(PanedRec),
191 /* class_initialize */ ClassInitialize,
192 /* class_part init */ NULL,
193 /* class_inited */ FALSE,
194 /* initialize */ Initialize,
195 /* initialize_hook */ NULL,
196 /* realize */ Realize,
197 /* actions */ NULL,
198 /* num_actions */ 0,
199 /* resourses */ resources,
200 /* resource_count */ XtNumber(resources),
201 /* xrm_class */ NULLQUARK,
202 /* compress_motion */ TRUE,
203 /* compress_exposure */ TRUE,
204 /* compress_enterleave*/ TRUE,
205 /* visible_interest */ FALSE,
206 /* destroy */ ReleaseGCs,
207 /* resize */ Resize,
208 /* expose */ Redisplay,
209 /* set_values */ SetValues,
210 /* set_values_hook */ NULL,
211 /* set_values_almost */ XtInheritSetValuesAlmost,
212 /* get_values_hook */ NULL,
213 /* accept_focus */ NULL,
214 /* version */ XtVersion,
215 /* callback_private */ NULL,
216 /* tm_table */ NULL,
217 /* query_geometry */ XtInheritQueryGeometry,
218 /* display_accelerator*/ XtInheritDisplayAccelerator,
219 /* extension */ NULL
220 }, {
221 /* composite class fields */
222 /* geometry_manager */ GeometryManager,
223 /* change_managed */ ChangeManaged,
224 /* insert_child */ InsertChild,
225 /* delete_child */ DeleteChild,
226 /* extension */ NULL
227 }, {
228 /* constraint class fields */
229 /* subresourses */ subresources,
230 /* subresource_count */ XtNumber(subresources),
231 /* constraint_size */ sizeof(PanedConstraintsRec),
232 /* initialize */ NULL,
233 /* destroy */ NULL,
234 /* set_values */ PaneSetValues,
235 /* extension */ NULL
239 WidgetClass panedWidgetClass = (WidgetClass) &panedClassRec;
241 /* For compatability. */
242 WidgetClass vPanedWidgetClass = (WidgetClass) &panedClassRec;
244 /***********************************************************
246 * Private Functions.
248 ************************************************************/
250 /* Function Name: AdjustPanedSize
251 * Description: Adjusts the size of the pane.
252 * Arguments: pw - the paned widget to adjust.
253 * off_size - the new off_size to use.
254 * result_ret - result of query ** RETURNED **
255 * on_size_ret - the new on_size ** RETURNED **
256 * off_size_ret - the new off_size ** RETURNED **
257 * Returns: the amount of change in size.
260 static void
261 AdjustPanedSize(pw, off_size, result_ret, on_size_ret, off_size_ret)
262 PanedWidget pw;
263 Dimension off_size;
264 XtGeometryResult * result_ret;
265 Dimension * on_size_ret, * off_size_ret;
267 Dimension old_size = PaneSize( (Widget) pw, IsVert(pw));
268 Dimension newsize = 0;
269 Widget * childP;
270 XtWidgetGeometry request, reply;
271 request.request_mode = CWWidth | CWHeight;
273 ForAllPanes(pw, childP) {
274 int size = (int) Max(PaneInfo(*childP)->size, PaneInfo(*childP)->min);
275 AssignMin(size, (int) PaneInfo(*childP)->max);
276 newsize += size + pw->paned.internal_bw;
278 newsize -= pw->paned.internal_bw;
280 if (newsize < 1) newsize = 1;
282 if ( IsVert(pw) ) {
283 request.width = off_size;
284 request.height = newsize;
286 else {
287 request.width = newsize;
288 request.height = off_size;
291 if (result_ret != NULL) {
292 request.request_mode |= XtCWQueryOnly;
294 *result_ret = XtMakeGeometryRequest( (Widget) pw, &request, &reply );
296 if ( (newsize == old_size) || (*result_ret == XtGeometryNo) ) {
297 *on_size_ret = old_size;
298 *off_size_ret = off_size;
299 return;
301 if (*result_ret != XtGeometryAlmost) {
302 *on_size_ret = GetRequestInfo( &request, IsVert(pw) );
303 *off_size_ret = GetRequestInfo( &request, !IsVert(pw) );
304 return;
306 *on_size_ret = GetRequestInfo( &reply, IsVert(pw) );
307 *off_size_ret = GetRequestInfo( &reply, !IsVert(pw) );
308 return;
311 if (newsize == old_size) return;
313 if (XtMakeGeometryRequest( (Widget) pw,
314 &request, &reply) == XtGeometryAlmost)
315 XtMakeGeometryRequest( (Widget) pw, &reply, &request);
318 /* Function Name: PaneSize
319 * Description: returns the width or height of the pane depending
320 * upon the orientation we are using.
321 * Arguments: w - and widget.
322 * vertical - TRUE if this is vertically oriented pane.
323 * Returns: the size requested
325 * vertical - return height
326 * !vertical - return width
329 static Dimension
330 PaneSize(w, vertical)
331 Widget w;
332 Boolean vertical;
334 if (vertical) return (w->core.height);
335 return (w->core.width);
338 /* Function Name: GetRequestInfo
339 * Description: returns request information.
340 * Arguments: geo_struct - a geometry struct to get information out of.
341 * vert - TRUE if this is a vertical paned widget.
342 * Returns: the request information.
345 static Dimension
346 GetRequestInfo(geo_struct, vert)
347 XtWidgetGeometry * geo_struct;
348 Boolean vert;
350 if ( vert ) return ( (Dimension) geo_struct->height);
351 return ( (Dimension) geo_struct->width);
354 /* Function Name: ChoosePaneToResize.
355 * Description: This function chooses a pane to resize.
356 * They are choosen using the following rules:
358 * 1) size < max && size > min
359 * 2) skip adjust == FALSE
360 * 3) widget not its prefered height &&
361 * this change will bring it closer &&
362 * The user has not resized this pane.
364 * If no widgets are found that fits all the rules then
365 * rule #3 is broken.
366 * If there are still no widgets found than
367 * rule #2 is broken.
368 * Rule #1 is never broken.
369 * If no widgets are found then NULL is returned.
371 * Arguments: pw - the paned widget.
372 * index - the index of the current pane.
373 * dir - direction to search first.
374 * shrink - TRUE if we need to shrink a pane, FALSE otherwise.
375 * Returns: pane to resize or NULL.
378 static Pane
379 ChoosePaneToResize(pw, index, dir, shrink)
380 PanedWidget pw;
381 int index;
382 Direction dir;
383 Boolean shrink;
385 Widget *childP;
386 int rules = 3;
387 Direction _dir = dir;
388 int _index = index;
390 if ( (index == NO_INDEX) || (dir == AnyPane) ) { /* Use defaults. */
391 _dir = LowRightPane; /* Go up. - really. */
392 _index = pw->paned.num_panes - 1; /* Start the last pane, and work
393 backwords. */
395 childP = pw->composite.children + _index;
396 while(TRUE) {
397 register Pane pane = PaneInfo(*childP);
399 if ( (rules < 3 || SatisfiesRule3(pane, shrink)) &&
400 (rules < 2 || SatisfiesRule2(pane)) &&
401 (SatisfiesRule1(pane, shrink)) &&
402 ((index != PaneIndex(*childP)) || (dir == AnyPane)) )
403 return(pane);
406 * This is counter-intiutive, but if we are resizing the pane
407 * above the grip we want to choose a pane below the grip to lose,
408 * and visa-versa.
411 if (_dir == LowRightPane) --childP; else ++childP;
414 * If we have come to and edge then reduce the rule set, and try again.
415 * If we are reduced the rules to none, then return NULL.
418 if ( (childP - pw->composite.children < 0) ||
419 (childP - pw->composite.children >= pw->paned.num_panes) ) {
420 if (--rules < 1) /* less strict rules. */
421 return(NULL);
422 childP = pw->composite.children + _index;
427 /* Function Name: StatisfiesRule1
428 * Description: check for to see if this pane satisfies rule 1.
429 * Arguments: pane - the pane to check.
430 * shrink -TRUE if we want to shrink this pane, FALSE otherwise
431 * Returns: TRUE if the rule is satisfied.
434 static Boolean
435 SatisfiesRule1(pane, shrink)
436 Pane pane;
437 Boolean shrink;
439 return( (shrink && (pane->size != pane->min)) ||
440 (!shrink && (pane->size != pane->max)) );
443 /* Function Name: StatisfiesRule2
444 * Description: check for to see if this pane satisfies rule 2.
445 * Arguments: pane - the pane to check.
446 * Returns: TRUE if the rule is satisfied.
449 static Boolean
450 SatisfiesRule2(pane)
451 Pane pane;
453 return(!pane->skip_adjust || pane->paned_adjusted_me);
456 /* Function Name: StatisfiesRule3
457 * Description: check for to see if this pane satisfies rule 3.
458 * Arguments: pane - the pane to check.
459 * shrink -TRUE if we want to shrink this pane, FALSE otherwise
460 * Returns: TRUE if the rule is satisfied.
463 static Boolean
464 SatisfiesRule3(pane, shrink)
465 Pane pane;
466 Boolean shrink;
468 return ( pane->paned_adjusted_me &&
469 ( (shrink && (pane->wp_size <= pane->size)) ||
470 (!shrink && (pane->wp_size >= pane->size))) );
473 /* Function Name: LoopAndRefigureChildren.
474 * Description: if we are resizeing either the UpleftPane or LowRight Pane
475 * loop through all the children to see if any will allow us
476 * to resize them.
477 * Arguments: pw - the paned widget.
478 * index - the number of the pane border we are moving.
479 * dir - the pane to move (either UpLeftPane or LowRightPane).
480 * sizeused - current amount of space used.
481 * THIS VALUE IS USED AND RETURNED.
482 * Returns: none.
485 static void
486 LoopAndRefigureChildren(pw, index, dir, sizeused)
487 PanedWidget pw;
488 int index, *sizeused;
489 Direction dir;
491 int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw));
492 Boolean shrink = (*sizeused > pane_size);
494 if (dir == LowRightPane) index++;
496 while (*sizeused != pane_size) { /* While all panes do not fit properly. */
498 * Choose a pane to resize.
499 * First look on the Pane Stack, and then go hunting for another one.
500 * If we fail to find a pane to resize then give up.
502 Pane pane;
503 int start_size;
504 Dimension old;
505 Boolean rule3_ok = FALSE, from_stack = TRUE;
507 GetPaneStack(pw, shrink, &pane, &start_size);
508 if (pane == NULL) {
509 pane = ChoosePaneToResize(pw, index, dir, shrink);
510 if (pane == NULL)
511 return; /* no one to resize, give up. */
513 rule3_ok = SatisfiesRule3(pane, shrink);
514 from_stack = FALSE;
515 PushPaneStack(pw, pane);
520 * Try to resize this pane so that all panes will fit, take min and max
521 * into account.
523 old = pane->size;
524 pane->size += pane_size - *sizeused;
526 if (from_stack) {
527 if (shrink) {
528 AssignMax(pane->size, start_size);
529 } /* don't remove these braces. */
530 else
531 AssignMin(pane->size, start_size);
533 if (pane->size == start_size) (void) PopPaneStack(pw);
535 else if (rule3_ok) {
536 if (shrink) {
537 AssignMax(pane->size, (int) pane->wp_size);
538 } /* don't remove these braces. */
539 else
540 AssignMin(pane->size, (int) pane->wp_size);
543 pane->paned_adjusted_me = (pane->size != pane->wp_size);
544 AssignMax(pane->size, (int) pane->min);
545 AssignMin(pane->size, (int) pane->max);
546 *sizeused += (pane->size - old);
550 /* Function Name: RefigureLocations
551 * Description: refigures all locations of children.
552 * Arguments: pw - the paned widget.
553 * index - child to start refiguring at.
554 * dir - direction to move from child.
555 * Returns: none.
557 * There are special arguements to index and dir, they are:
558 * index - NO_INDEX.
559 * dir - AnyPane.
561 * If either of these is true then all panes may be resized and
562 * the choosing of panes proceedes in reverse order starting with the
563 * last child.
566 static void
567 RefigureLocations(pw, index, dir)
568 PanedWidget pw;
569 int index;
570 Direction dir;
572 register Widget *childP;
573 int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw) );
574 int sizeused = 0;
575 Position loc = 0;
577 if (pw->paned.num_panes == 0 || !pw->paned.refiguremode) return;
580 * Get an initial estimate of the size we will use.
583 ForAllPanes(pw, childP) {
584 register Pane pane = PaneInfo(*childP);
585 AssignMax(pane->size, (int) pane->min);
586 AssignMin(pane->size, (int) pane->max);
587 sizeused += (int) pane->size + (int) pw->paned.internal_bw;
589 sizeused -= (int) pw->paned.internal_bw;
591 if ( (dir != ThisBorderOnly) && (sizeused != pane_size) )
592 LoopAndRefigureChildren(pw, index, dir, &sizeused);
595 * If we still are not the right size, then tell the pane that
596 * wanted to resize that it can't.
600 if ( (index != NO_INDEX) && (dir != AnyPane) ) {
601 Pane pane = PaneInfo(*(pw->composite.children + index));
602 Dimension old = pane->size;
604 pane->size += pane_size - sizeused;
605 AssignMax(pane->size, (int) pane->min);
606 AssignMin(pane->size, (int) pane->max);
607 sizeused += pane->size - old;
611 * It is possible that the panes will not fit inside the vpaned widget, but
612 * we have tried out best.
614 * Assign each pane a location.
617 ForAllPanes(pw, childP) {
618 PaneInfo(*childP)->delta = loc;
619 loc += PaneInfo(*childP)->size + pw->paned.internal_bw;
623 /* Function Name: CommitNewLocations
624 * Description: Commits all of the previously figured locations.
625 * Arguments: pw - the paned widget.
626 * Returns: none.
629 static void
630 CommitNewLocations(pw)
631 PanedWidget pw;
633 register Widget *childP;
634 XWindowChanges changes;
636 changes.stack_mode = Above;
638 ForAllPanes(pw, childP) {
639 register Pane pane = PaneInfo(*childP);
640 register Widget grip = pane->grip; /* may be NULL. */
642 if (IsVert(pw)) {
643 XtMoveWidget(*childP, (Position) 0, pane->delta);
644 XtResizeWidget(*childP, pw->core.width, (Dimension) pane->size,
645 (Dimension) 0);
647 if (HasGrip(*childP)) { /* Move and Display the Grip */
648 changes.x = pw->core.width - pw->paned.grip_indent -
649 grip->core.width - grip->core.border_width*2;
650 changes.y = (*childP)->core.y + (*childP)->core.height -
651 grip->core.height/2 - grip->core.border_width +
652 pw->paned.internal_bw/2;
655 else {
656 XtMoveWidget(*childP, pane->delta, (Position) 0);
657 XtResizeWidget(*childP, (Dimension) pane->size, pw->core.height,
658 (Dimension) 0);
661 if (HasGrip(*childP)) { /* Move and Display the Grip */
662 changes.x = (*childP)->core.x + (*childP)->core.width -
663 grip->core.width/2 - grip->core.border_width +
664 pw->paned.internal_bw/2;
665 changes.y = pw->core.height - pw->paned.grip_indent -
666 grip->core.height - grip->core.border_width*2;
671 * This should match XtMoveWidget, except that we're also insuring the
672 * grip is Raised in the same request.
675 if (HasGrip(*childP)) {
676 grip->core.x = changes.x;
677 grip->core.y = changes.y;
679 if (XtIsRealized(pane->grip))
680 XConfigureWindow( XtDisplay(pane->grip), XtWindow(pane->grip),
681 CWX | CWY | CWStackMode, &changes );
684 ClearPaneStack(pw);
687 /* Function Name: RefigureLocationsAndCommit
688 * Description: Refigures all locations in a paned widget and
689 * commits them immediatly.
690 * Arguments: pw - the paned widget.
691 * Returns: none
693 * This function does nothing if any of the following are true.
694 * o refiguremode is false.
695 * o The widget is unrealized.
696 * o There are no panes is the paned widget.
698 * NOTE: This is the resize Proceedure for the Paned widget.
701 static void
702 RefigureLocationsAndCommit(w)
703 Widget w;
705 PanedWidget pw = (PanedWidget) w;
706 if (pw->paned.refiguremode && XtIsRealized( (Widget) pw) &&
707 pw->paned.num_panes > 0 ) {
708 RefigureLocations(pw, NO_INDEX, AnyPane);
709 CommitNewLocations(pw);
713 /* Function Name: _DrawRect
714 * Description: Draws a rectangle in the proper orientation.
715 * Arguments: pw - the paned widget.
716 * gc - gc to used for the draw.
717 * on_olc, off_loc - location of upper left corner of rect.
718 * on_size, off_size - size of rectangle.
719 * Returns: none
722 static void
723 _DrawRect(pw, gc, on_loc, off_loc, on_size, off_size)
724 PanedWidget pw;
725 GC gc;
726 int on_loc, off_loc;
727 unsigned int on_size, off_size;
729 if (IsVert(pw))
730 XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
731 off_loc, on_loc, off_size, on_size);
732 else
733 XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
734 on_loc, off_loc, on_size, off_size);
737 /* Function Name: _DrawInternalBorders
738 * Description: Draws the internal borders into the paned widget.
739 * Arguments: pw - the paned widget.
740 * gc - the GC to use to draw the borders.
741 * Returns: none.
744 static void
745 _DrawInternalBorders(pw, gc)
746 PanedWidget pw;
747 GC gc;
749 Widget *childP;
750 int on_loc, off_loc;
751 unsigned int on_size, off_size;
754 * This is an optomization. Do not paint the internal borders if
755 * they are the same color as the background.
758 if (pw->core.background_pixel == pw->paned.internal_bp)
759 return;
761 off_loc = 0;
762 off_size = (unsigned int) PaneSize( (Widget) pw, !IsVert(pw) );
763 on_size = (unsigned int) pw->paned.internal_bw;
765 ForAllPanes(pw, childP) {
766 on_loc = IsVert(pw) ? (*childP)->core.y : (*childP)->core.x;
767 on_loc -= (int) on_size;
769 _DrawRect( pw, gc, on_loc, off_loc, on_size, off_size);
774 * This allows good reuse of code, as well as descriptive function names.
777 #define DrawInternalBorders(pw) _DrawInternalBorders((pw), (pw)->paned.normgc);
778 #define EraseInternalBorders(pw) _DrawInternalBorders((pw), (pw)->paned.invgc);
780 /* Function Name: _DrawTrackLines
781 * Description: Draws the lines that animate the pane borders when the
782 * grips are moved.
783 * Arguments: pw - the Paned widget.
784 * erase - if True then just erase track lines, else
785 * draw them in.
786 * Returns: none.
789 static void
790 _DrawTrackLines(pw, erase)
791 PanedWidget pw;
792 Boolean erase;
794 Widget *childP;
795 Pane pane;
796 int on_loc, off_loc;
797 unsigned int on_size, off_size;
799 off_loc = 0;
800 off_size = PaneSize( (Widget) pw, !IsVert(pw));
802 ForAllPanes(pw, childP) {
803 pane = PaneInfo(*childP);
804 if ( erase || (pane->olddelta != pane->delta) ) {
805 on_size = pw->paned.internal_bw;
806 if (!erase) {
807 on_loc = PaneInfo(*childP)->olddelta - (int) on_size;
809 _DrawRect( pw, pw->paned.flipgc,
810 on_loc, off_loc, on_size, off_size);
813 on_loc = PaneInfo(*childP)->delta - (int) on_size;
815 _DrawRect(pw, pw->paned.flipgc,
816 on_loc, off_loc, on_size, off_size);
818 pane->olddelta = pane->delta;
824 * This allows good reuse of code, as well as descriptive function names.
827 #define DrawTrackLines(pw) _DrawTrackLines((pw), FALSE);
828 #define EraseTrackLines(pw) _DrawTrackLines((pw), TRUE);
830 /* Function Name: GetEventLocation
831 * Description: Converts and event to an x and y locaion.
832 * Arguments: pw - the paned widget.
833 * event - a pointer to an event.
834 * Returns: if this is a vertical pane then (y) else (x).
837 static int
838 GetEventLocation(pw, event)
839 PanedWidget pw;
840 XEvent *event;
842 int x, y;
844 switch (event->xany.type) {
845 case ButtonPress:
846 case ButtonRelease:
847 x = event->xbutton.x_root;
848 y = event->xbutton.y_root;
849 break;
850 case KeyPress:
851 case KeyRelease:
852 x = event->xkey.x_root;
853 y = event->xkey.y_root;
854 break;
855 case MotionNotify:
856 x = event->xmotion.x_root;
857 y = event->xmotion.y_root;
858 break;
859 default:
860 x = pw->paned.start_loc;
861 y = pw->paned.start_loc;
863 if (IsVert(pw))
864 return(y);
865 return(x);
868 /* Function Name: StartGripAdjustment
869 * Description: Starts the grip adjustment proceedure.
870 * Arguments: pw - the paned widget.
871 * grip - the grip widget selected.
872 * dir - the direction that we are to be moving.
873 * Returns: none.
876 static void
877 StartGripAdjustment(pw, grip, dir)
878 PanedWidget pw;
879 Widget grip;
880 Direction dir;
882 Widget *childP;
883 Cursor cursor;
885 pw->paned.whichadd = pw->paned.whichsub = (Widget) NULL;
887 if (dir == ThisBorderOnly || dir == UpLeftPane)
888 pw->paned.whichadd = pw->composite.children[PaneIndex(grip)];
889 if (dir == ThisBorderOnly || dir == LowRightPane)
890 pw->paned.whichsub = pw->composite.children[PaneIndex(grip) + 1];
893 * Change the cursor.
896 if (XtIsRealized(grip)) {
897 if ( IsVert(pw) ) {
898 if (dir == UpLeftPane)
899 cursor = pw->paned.adjust_upper_cursor;
900 else if (dir == LowRightPane)
901 cursor = pw->paned.adjust_lower_cursor;
902 else {
903 if ( pw->paned.adjust_this_cursor == None)
904 cursor = pw->paned.v_adjust_this_cursor;
905 else
906 cursor = pw->paned.adjust_this_cursor;
909 else {
910 if (dir == UpLeftPane)
911 cursor = pw->paned.adjust_left_cursor;
912 else if (dir == LowRightPane)
913 cursor = pw->paned.adjust_right_cursor;
914 else {
915 if (pw->paned.adjust_this_cursor == None)
916 cursor = pw->paned.h_adjust_this_cursor;
917 else
918 cursor = pw->paned.adjust_this_cursor;
922 XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
925 EraseInternalBorders(pw);
926 ForAllPanes(pw, childP)
927 PaneInfo(*childP)->olddelta = -99;
930 /* Function Name: MoveGripAdjustment
931 * Description: This routine moves all panes around when a grip is moved.
932 * Arguments: pw - the paned widget.
933 * grip - the grip that we are moving.
934 * dir - the direction the pane we are interested is w.r.t the
935 * grip.
936 * loc - location of pointer in proper direction.
937 * Returns: none.
940 static void
941 MoveGripAdjustment(pw, grip, dir, loc)
942 PanedWidget pw;
943 Widget grip;
944 Direction dir;
945 int loc;
947 int diff, add_size = 0, sub_size = 0;
949 diff = loc - pw->paned.start_loc;
951 if (pw->paned.whichadd)
952 add_size = PaneSize(pw->paned.whichadd, IsVert(pw) ) + diff;
954 if (pw->paned.whichsub)
955 sub_size = PaneSize(pw->paned.whichsub, IsVert(pw) ) - diff;
958 * If moving this border only then do not allow either of the borders
959 * to go beyond the min or max size allowed.
962 if ( (dir == ThisBorderOnly) ) {
963 int old_add_size = add_size, old_sub_size;
965 AssignMax(add_size, (int) PaneInfo(pw->paned.whichadd)->min);
966 AssignMin(add_size, (int) PaneInfo(pw->paned.whichadd)->max);
967 if (add_size != old_add_size)
968 sub_size += old_add_size - add_size;
970 old_sub_size = sub_size;
971 AssignMax(sub_size, (int) PaneInfo(pw->paned.whichsub)->min);
972 AssignMin(sub_size, (int) PaneInfo(pw->paned.whichsub)->max);
973 if (sub_size != old_sub_size) return; /* Abort to current sizes. */
976 if (add_size != 0)
977 PaneInfo(pw->paned.whichadd)->size = add_size;
978 if (sub_size != 0)
979 PaneInfo(pw->paned.whichsub)->size = sub_size;
980 RefigureLocations(pw, PaneIndex(grip), dir);
981 DrawTrackLines(pw);
984 /* Function Name: CommitGripAdjustment
985 * Description: Commits the grip adjustment.
986 * Arguments: pw - the paned widget.
987 * Returns: none
990 CommitGripAdjustment(pw)
991 PanedWidget pw;
993 EraseTrackLines(pw);
994 CommitNewLocations(pw);
995 DrawInternalBorders(pw);
998 * Since the user selected this size then use it as the preferred size.
1001 if (pw->paned.whichadd) {
1002 Pane pane = PaneInfo(pw->paned.whichadd);
1003 pane->wp_size = pane->size;
1005 if (pw->paned.whichsub) {
1006 Pane pane = PaneInfo(pw->paned.whichsub);
1007 pane->wp_size = pane->size;
1011 /* Function Name: HandleGrip
1012 * Description: Handles the grip manipulations.
1013 * Arguments: grip - the grip widget that has been moved.
1014 * junk - ** NOT USED **
1015 * call_data - data passed to us from the grip widget.
1016 * Returns: none.
1019 /* ARGSUSED */
1020 static void
1021 HandleGrip(grip, junk, callData)
1022 Widget grip;
1023 caddr_t junk, callData;
1025 GripCallData call_data = (GripCallData)callData;
1026 PanedWidget pw = (PanedWidget) XtParent(grip);
1027 int loc;
1028 char action_type;
1029 Cursor cursor;
1030 Direction direction;
1031 Arg arglist[1];
1033 action_type = *call_data->params[0];
1035 if (call_data->num_params == 0 ||
1036 (action_type == 'C' && call_data->num_params != 1) ||
1037 (action_type != 'C' && call_data->num_params != 2))
1038 XtError( "Paned GripAction has been passed incorrect parameters." );
1040 if (islower(action_type)) action_type = toupper(action_type);
1042 loc = GetEventLocation(pw, (XEvent *) (call_data->event));
1044 if (action_type != 'C') {
1045 if ( isupper(*call_data->params[1]) )
1046 direction = (Direction) *call_data->params[1];
1047 else
1048 direction = (Direction) toupper(*call_data->params[1]);
1051 switch (action_type) {
1052 case 'S': /* Start adjustment */
1053 pw->paned.resize_children_to_pref = FALSE;
1054 StartGripAdjustment(pw, grip, direction);
1055 pw->paned.start_loc = loc;
1056 break;
1058 case 'M':
1059 MoveGripAdjustment(pw, grip, direction, loc);
1060 break;
1062 case 'C':
1063 XtSetArg(arglist[0], XtNcursor, &cursor);
1064 XtGetValues(grip, arglist, (Cardinal) 1);
1065 XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
1066 CommitGripAdjustment(pw);
1067 break;
1069 default:
1070 XtError( "Paned GripAction(); 1st parameter invalid" );
1074 /* Function Name: ResortChildren
1075 * Description: Resorts the children so that all managed children
1076 * are first.
1077 * Arguments: pw - the paned widget.
1078 * Returns: none.
1081 static void
1082 ResortChildren(pw)
1083 PanedWidget pw;
1085 Widget * unmanagedP, * childP;
1087 unmanagedP = NULL;
1088 ForAllChildren(pw, childP) {
1089 if (!IsPane(*childP) || !XtIsManaged(*childP)) {
1091 * We only keep track of the first unmanaged pane.
1093 if (unmanagedP == NULL)
1094 unmanagedP = childP;
1096 else { /* must be a managed pane */
1098 * If an earlier widget was not a managed pane, then swap
1100 if (unmanagedP != NULL) {
1101 Widget child = *unmanagedP;
1102 *unmanagedP = *childP;
1103 *childP = child;
1104 childP = unmanagedP; /* easiest to just back-track */
1105 unmanagedP = NULL; /* in case there is another managed */
1111 /* Function Name: ManageAndUnmanageGrips
1112 * Description: This function manages and unmanages the grips so that
1113 * the managed state of each grip matches that of its pane.
1114 * Arguments: pw - the paned widget.
1115 * Returns: none.
1118 static void
1119 ManageAndUnmanageGrips(pw)
1120 PanedWidget pw;
1122 WidgetList managed_grips, unmanaged_grips;
1123 Widget *managedP, *unmanagedP, *childP;
1124 Cardinal alloc_size;
1126 alloc_size = (Cardinal) sizeof(Widget) * pw->composite.num_children / 2;
1127 managedP = managed_grips = (WidgetList) XtMalloc(alloc_size);
1128 unmanagedP = unmanaged_grips = (WidgetList) XtMalloc(alloc_size);
1130 ForAllChildren(pw, childP)
1131 if (IsPane(*childP) && HasGrip(*childP))
1132 if ( XtIsManaged(*childP) )
1133 *managedP++ = PaneInfo(*childP)->grip;
1134 else
1135 *unmanagedP++ = PaneInfo(*childP)->grip;
1137 if (managedP != managed_grips) {
1138 *unmanagedP++ = *--managedP; /* Last grip is never managed */
1139 XtManageChildren( managed_grips, (Cardinal)(managedP - managed_grips) );
1142 if (unmanagedP != unmanaged_grips)
1143 XtUnmanageChildren( unmanaged_grips,
1144 (Cardinal)(unmanagedP - unmanaged_grips) );
1146 XtFree((caddr_t)managed_grips);
1147 XtFree((caddr_t)unmanaged_grips);
1150 /* Function Name: CreateGrip
1151 * Description: Creates a grip widget.
1152 * Arguments: child - the child that wants a grip to be created for it.
1153 * Returns: none.
1156 static void
1157 CreateGrip(child)
1158 Widget child;
1160 PanedWidget pw = (PanedWidget) XtParent(child);
1161 Arg arglist[2];
1162 Cardinal num_args = 0;
1163 Cursor cursor;
1165 XtSetArg(arglist[num_args], XtNtranslations, pw->paned.grip_translations);
1166 num_args++;
1167 if ( (cursor = pw->paned.grip_cursor) == None )
1168 if (IsVert(pw))
1169 cursor = pw->paned.v_grip_cursor;
1170 else
1171 cursor = pw->paned.h_grip_cursor;
1173 XtSetArg(arglist[num_args], XtNcursor, cursor);
1174 num_args++;
1175 PaneInfo(child)->grip = XtCreateWidget("grip", gripWidgetClass, (Widget)pw,
1176 arglist, num_args);
1178 XtAddCallback(PaneInfo(child)->grip, XtNcallback,
1179 (XtCallbackProc)HandleGrip, (caddr_t) child);
1182 /* Function Name: GetGCs
1183 * Description: Gets new GC's.
1184 * Arguments: w - the paned widget.
1185 * Returns: none.
1188 static void
1189 GetGCs(w)
1190 Widget w;
1192 PanedWidget pw = (PanedWidget) w;
1193 XtGCMask valuemask;
1194 XGCValues values;
1197 * Draw pane borders in internal border color.
1200 values.foreground = pw->paned.internal_bp;
1201 valuemask = GCForeground;
1202 pw->paned.normgc = XtGetGC(w, valuemask, &values);
1205 * Erase pane borders with background color.
1208 values.foreground = pw->core.background_pixel;
1209 valuemask = GCForeground;
1210 pw->paned.invgc = XtGetGC(w, valuemask, &values);
1213 * Draw Track lines (animate pane borders) in internal border color ^ bg color.
1216 values.function = GXinvert;
1217 values.plane_mask = pw->paned.internal_bp ^ pw->core.background_pixel;
1218 values.subwindow_mode = IncludeInferiors;
1219 valuemask = GCPlaneMask | GCFunction | GCSubwindowMode;
1220 pw->paned.flipgc = XtGetGC(w, valuemask, &values);
1223 /* Function Name: SetChildrenPrefSizes.
1224 * Description: Sets the preferred sizes of the children.
1225 * Arguments: pw - the paned widget.
1226 * Returns: none.
1229 static void
1230 SetChildrenPrefSizes(pw, off_size)
1231 PanedWidget pw;
1232 Dimension off_size;
1234 Widget * childP;
1235 Boolean vert = IsVert(pw);
1236 XtWidgetGeometry request, reply;
1238 ForAllPanes(pw, childP)
1239 if ( pw->paned.resize_children_to_pref ||
1240 (PaneInfo(*childP)->size == 0) ||
1241 (PaneInfo(*childP)->resize_to_pref) ) {
1243 if (PaneInfo(*childP)->preferred_size != PANED_ASK_CHILD)
1244 PaneInfo(*childP)->wp_size=PaneInfo(*childP)->preferred_size;
1245 else {
1246 if( vert ) {
1247 request.request_mode = CWWidth;
1248 request.width = off_size;
1250 else {
1251 request.request_mode = CWHeight;
1252 request.height = off_size;
1255 if ((XtQueryGeometry( *childP, &request, &reply )
1256 == XtGeometryAlmost) &&
1257 (reply.request_mode = (vert ? CWHeight : CWWidth)))
1258 PaneInfo(*childP)->wp_size = GetRequestInfo(&reply, vert);
1259 else
1260 PaneInfo(*childP)->wp_size = PaneSize(*childP, vert);
1263 PaneInfo(*childP)->size = PaneInfo(*childP)->wp_size;
1267 /* Function Name: ChangeAllGripCursors
1268 * Description: Changes all the grip cursors.
1269 * Arguments: pw - the paned widget.
1270 * Returns: none
1273 static void
1274 ChangeAllGripCursors(pw)
1275 PanedWidget pw;
1277 Widget * childP;
1279 ForAllPanes(pw, childP) {
1280 Arg arglist[1];
1281 Cursor cursor;
1283 if ( (cursor = pw->paned.grip_cursor) == None )
1284 if ( IsVert(pw) )
1285 cursor = pw->paned.v_grip_cursor;
1286 else
1287 cursor = pw->paned.h_grip_cursor;
1289 if (HasGrip (*childP)) {
1290 XtSetArg(arglist[0], XtNcursor, cursor);
1291 XtSetValues(PaneInfo(*childP)->grip, arglist, (Cardinal) 1);
1296 /************************************************************
1298 * Stack Manipulation routines (Private).
1300 ************************************************************/
1302 /* Function Name: PushPaneStack
1303 * Description: Pushes a value onto the pane stack.
1304 * Arguments: pw - the paned widget.
1305 * pane - the pane that we are pushing.
1306 * Returns: none.
1309 static void
1310 PushPaneStack(pw, pane)
1311 PanedWidget pw;
1312 Pane pane;
1314 PaneStack * stack = (PaneStack *) XtMalloc(sizeof(PaneStack));
1316 stack->next = pw->paned.stack;
1317 stack->pane = pane;
1318 stack->start_size = pane->size;
1320 pw->paned.stack = stack;
1323 /* Function Name: GetPaneStack
1324 * Description: Gets the top value from the pane stack.
1325 * Arguments: pw - the paned widget.
1326 * shrink - TRUE if we want to shrink this pane,
1327 * FALSE otherwise.
1328 * ** RETURNED ** pane - the pane that we are popping.
1329 * ** RETURNED ** start_size - the size that this pane started at.
1330 * Returns: none.
1333 static void
1334 GetPaneStack(pw, shrink, pane, start_size)
1335 PanedWidget pw;
1336 Boolean shrink;
1337 Pane * pane;
1338 int * start_size;
1340 if (pw->paned.stack == NULL) {
1341 *pane = NULL;
1342 return;
1345 *pane = pw->paned.stack->pane;
1346 *start_size = pw->paned.stack->start_size;
1348 if (shrink != ((*pane)->size > *start_size)) *pane = NULL;
1351 /* Function Name: PopPaneStack
1352 * Description: Pops the top item off the pane stack.
1353 * Arguments: pw - the paned widget.
1354 * Returns: TRUE if this is not the last element on the stack.
1357 static Boolean
1358 PopPaneStack(pw)
1359 PanedWidget pw;
1361 PaneStack * stack = pw->paned.stack;
1363 if (stack == NULL) return(FALSE);
1365 pw->paned.stack = stack->next;
1366 XtFree((char *)stack);
1368 if (pw->paned.stack == NULL) return(FALSE);
1369 return(TRUE);
1372 /* Function Name: ClearPaneStack
1373 * Description: removes all entries from the pane stack.
1374 * Arguments: pw - the paned widget.
1375 * Returns: none
1378 static void
1379 ClearPaneStack(pw)
1380 PanedWidget pw;
1382 while(PopPaneStack(pw));
1385 /************************************************************
1387 * Semi-public routines.
1389 ************************************************************/
1391 /* Function Name: ClassInitialize
1392 * Description: The Paned widgets class initialization proc.
1393 * Arguments: none.
1394 * Returns: none.
1397 static void
1398 ClassInitialize()
1400 XawInitializeWidgetSet();
1401 XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
1402 NULL, (Cardinal)0 );
1405 /* The Geometry Manager only allows changes after Realize if
1406 * allow_resize is True in the constraints record.
1408 * For vertically paned widgets:
1410 * It only allows height changes, but offers the requested height
1411 * as a compromise if both width and height changes were requested.
1413 * For horizontal widgets the coverse is true.
1414 * As all good Geometry Managers should, we will return No if the
1415 * request will have no effect; i.e. when the requestor is already
1416 * of the desired geometry.
1419 static XtGeometryResult GeometryManager(w, request, reply)
1420 Widget w;
1421 XtWidgetGeometry *request, *reply;
1423 PanedWidget pw = (PanedWidget) XtParent(w);
1424 XtGeometryMask mask = request->request_mode;
1425 Dimension old_size, old_wpsize, old_paned_size;
1426 Pane pane = PaneInfo(w);
1427 register Boolean vert = IsVert(pw);
1428 Dimension on_size, off_size;
1429 XtGeometryResult result;
1430 Boolean almost = FALSE;
1433 * If any of the following is true, disallow the geometry change.
1435 * o The paned widget is realized and allow_resize is false for the pane.
1436 * o The child did not ask to change the on_size.
1437 * o The request is not a width or height request.
1438 * o The requested size is the same as the current size.
1441 if ( (XtIsRealized((Widget)pw) && !pane->allow_resize) ||
1442 !(mask & ((vert) ? CWHeight : CWWidth)) ||
1443 (mask & ~(CWWidth | CWHeight)) ||
1444 (GetRequestInfo(request, vert) == PaneSize(w, vert)) ) {
1445 return XtGeometryNo;
1448 old_paned_size = PaneSize( (Widget) pw, vert);
1449 old_wpsize = pane->wp_size;
1450 old_size = pane->size;
1452 pane->wp_size = pane->size = GetRequestInfo(request, vert);
1454 AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), &result, &on_size,
1455 &off_size);
1458 * Fool the Refigure Locations proc to thinking that we are
1459 * a different on_size;
1462 if (result != XtGeometryNo)
1463 if (vert)
1464 pw->core.height = on_size;
1465 else
1466 pw->core.width = on_size;
1468 RefigureLocations(pw, PaneIndex(w), AnyPane);
1471 * Set up reply struct and reset core on_size.
1474 if (vert) {
1475 pw->core.height = old_paned_size;
1476 reply->height = pane->size;
1477 reply->width = off_size;
1479 else {
1480 pw->core.width = old_paned_size;
1481 reply->height = off_size;
1482 reply->width = pane->size;
1486 * IF either of the following is true.
1488 * o There was a "off_size" request and the new "off_size" is different
1489 * from that requested.
1490 * o There was no "off_size" request and the new "off_size" is different
1492 * o The "on_size" we will allow is different from that requested.
1494 * THEN: set almost
1497 if ( !((vert ? CWWidth : CWHeight) & mask))
1498 if (vert)
1499 request->width = w->core.width;
1500 else
1501 request->height = w->core.height;
1503 almost = GetRequestInfo(request, !vert) != GetRequestInfo(reply, !vert);
1504 almost |= GetRequestInfo(request, vert) != GetRequestInfo(reply, vert);
1506 if ( (mask & XtCWQueryOnly) || almost ) {
1507 pane->wp_size = old_wpsize;
1508 pane->size = old_size;
1509 RefigureLocations(pw, PaneIndex(w), AnyPane);
1510 reply->request_mode = CWWidth | CWHeight;
1511 if (almost) return XtGeometryAlmost;
1513 else {
1514 AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), NULL, NULL, NULL);
1515 CommitNewLocations( pw ); /* layout already refigured. */
1517 return XtGeometryDone;
1520 /* ARGSUSED */
1521 static void Initialize(request, new)
1522 Widget request, new;
1524 PanedWidget pw = (PanedWidget)new;
1526 GetGCs( (Widget) pw);
1528 pw->paned.recursively_called = False;
1529 pw->paned.stack = NULL;
1530 pw->paned.resize_children_to_pref = TRUE;
1531 pw->paned.num_panes = 0;
1534 static void
1535 Realize(w, valueMask, attributes)
1536 Widget w;
1537 Mask *valueMask;
1538 XSetWindowAttributes *attributes;
1540 PanedWidget pw = (PanedWidget) w;
1541 Widget * childP;
1543 if ((attributes->cursor = (pw)->paned.cursor) != None)
1544 *valueMask |= CWCursor;
1546 (*SuperClass->core_class.realize) (w, valueMask, attributes);
1549 * Before we commit the new locations we need to realize all the panes and
1550 * their grips.
1553 ForAllPanes(pw, childP) {
1554 XtRealizeWidget( *childP );
1555 if (HasGrip (*childP))
1556 XtRealizeWidget( PaneInfo(*childP)->grip );
1559 RefigureLocationsAndCommit(w);
1560 } /* Realize */
1562 static void
1563 ReleaseGCs(w)
1564 Widget w;
1566 register PanedWidget pw = (PanedWidget)w;
1568 XtReleaseGC( w, pw->paned.normgc );
1569 XtReleaseGC( w, pw->paned.invgc );
1570 XtReleaseGC( w, pw->paned.flipgc );
1573 static void InsertChild(w)
1574 register Widget w;
1576 Pane pane = PaneInfo(w);
1578 /* insert the child widget in the composite children list with the */
1579 /* superclass insert_child routine. */
1580 (*SuperClass->composite_class.insert_child)(w);
1582 if (!IsPane(w)) return;
1584 /* ||| Panes will be added in the order they are created, temporarilly */
1586 if ( pane->show_grip == TRUE ) {
1587 CreateGrip(w);
1588 if (pane->min == PANED_GRIP_SIZE)
1589 pane->min = PaneSize(pane->grip, IsVert((PanedWidget) XtParent(w)));
1591 else {
1592 if (pane->min == PANED_GRIP_SIZE)
1593 pane->min = 1;
1594 pane->grip = NULL;
1597 pane->size = 0;
1598 pane->paned_adjusted_me = FALSE;
1600 } /* InsertChild */
1602 static void DeleteChild(w)
1603 Widget w;
1605 /* remove the subwidget info and destroy the grip */
1607 if ( IsPane(w) && HasGrip(w) ) XtDestroyWidget(PaneInfo(w)->grip);
1609 /* delete the child widget in the composite children list with the */
1610 /* superclass delete_child routine. */
1611 (*SuperClass->composite_class.delete_child) (w);
1613 } /* DeleteChild */
1615 static void ChangeManaged(w)
1616 Widget w;
1618 PanedWidget pw = (PanedWidget)w;
1619 Boolean vert = IsVert(pw);
1620 Dimension size;
1621 register Widget *childP;
1623 if (pw->paned.recursively_called++) return;
1626 * If the size is zero then set it to the size of the widest or tallest pane.
1629 if ( (size = PaneSize( (Widget) pw, !vert )) == 0) {
1630 size = 1;
1631 ForAllChildren(pw, childP)
1632 if ( XtIsManaged(*childP) && (PaneSize( *childP, !vert ) > size) )
1633 size = PaneSize( *childP, !vert );
1636 ManageAndUnmanageGrips(pw);
1637 pw->paned.recursively_called = False;
1638 ResortChildren(pw);
1640 pw->paned.num_panes = 0;
1641 ForAllChildren(pw, childP)
1642 if ( IsPane(*childP) )
1643 if ( XtIsManaged(*childP) ) {
1644 Pane pane = PaneInfo(*childP);
1645 if (HasGrip(*childP))
1646 PaneInfo(pane->grip)->position = pw->paned.num_panes;
1647 pane->position = pw->paned.num_panes; /*TEMPORY -CDP 3/89 */
1648 pw->paned.num_panes++;
1650 else
1651 break; /* This list is already sorted. */
1653 SetChildrenPrefSizes( (PanedWidget) w, size);
1656 * ForAllPanes can now be used.
1659 if ( PaneSize((Widget) pw, vert) == 0 )
1660 AdjustPanedSize(pw, size, NULL, NULL, NULL);
1662 if (XtIsRealized( (Widget) pw))
1663 RefigureLocationsAndCommit( (Widget) pw);
1665 } /* ChangeManaged */
1667 /* Function Name: Resize
1668 * Description: The paned widget's resize proc.
1669 * Arguments: w - the paned widget.
1670 * Returns: none.
1673 static void
1674 Resize(w)
1675 Widget w;
1677 SetChildrenPrefSizes( (PanedWidget) w,
1678 PaneSize(w, !IsVert((PanedWidget) w)) );
1679 RefigureLocationsAndCommit(w);
1682 /* ARGSUSED */
1683 static void
1684 Redisplay(w, event, region)
1685 Widget w;
1686 XEvent * event; /* unused. */
1687 Region region; /* unused. */
1689 ((PanedWidget) w)->paned.resize_children_to_pref = FALSE;
1690 DrawInternalBorders( (PanedWidget) w);
1693 /* ARGSUSED */
1694 static Boolean
1695 SetValues(old, request, new)
1696 Widget old, request, new;
1698 PanedWidget old_pw = (PanedWidget) old;
1699 PanedWidget new_pw = (PanedWidget) new;
1700 Boolean redisplay = FALSE;
1702 if ( (old_pw->paned.cursor != new_pw->paned.cursor) && XtIsRealized(new))
1703 XDefineCursor(XtDisplay(new), XtWindow(new), new_pw->paned.cursor);
1705 if ( (old_pw->paned.internal_bp != new_pw->paned.internal_bp) ||
1706 (old_pw->core.background_pixel != new_pw->core.background_pixel) ) {
1707 ReleaseGCs(old);
1708 GetGCs(new);
1709 redisplay = TRUE;
1712 if ( (old_pw->paned.grip_cursor != new_pw->paned.grip_cursor) ||
1713 (old_pw->paned.v_grip_cursor != new_pw->paned.v_grip_cursor) ||
1714 (old_pw->paned.h_grip_cursor != new_pw->paned.h_grip_cursor) ) {
1715 ChangeAllGripCursors(new_pw);
1718 if ( IsVert(old_pw) != IsVert(new_pw)) {
1720 * We are fooling the paned widget into thinking that is needs to
1721 * fully refigure everything, which is what we want.
1723 if (IsVert(new_pw))
1724 new_pw->core.width = 0;
1725 else
1726 new_pw->core.height = 0;
1728 new_pw->paned.resize_children_to_pref = TRUE;
1729 ChangeManaged(new); /* Seems weird, but does the right thing. */
1730 new_pw->paned.resize_children_to_pref = FALSE;
1731 if (new_pw->paned.grip_cursor == None)
1732 ChangeAllGripCursors(new_pw);
1733 return(TRUE);
1736 if (old_pw->paned.internal_bw != new_pw->paned.internal_bw) {
1737 AdjustPanedSize( new_pw, PaneSize(new, !IsVert(old_pw)),
1738 NULL, NULL, NULL);
1739 RefigureLocationsAndCommit(new);
1740 return(TRUE); /* We have done a full configuration, return.*/
1743 if ( (old_pw->paned.grip_indent != new_pw->paned.grip_indent) &&
1744 (XtIsRealized(new)) ) {
1745 CommitNewLocations(new_pw);
1746 redisplay = TRUE;
1749 return (redisplay);
1750 } /* SetValues */
1753 /* ARGSUSED */
1754 static Boolean
1755 PaneSetValues(old, request, new)
1756 Widget old, request, new;
1758 Pane old_pane = PaneInfo(old);
1759 Pane new_pane = PaneInfo(new);
1760 Boolean redisplay = FALSE;
1762 /* Check for new min and max. */
1764 if (old_pane->min != new_pane->min || old_pane->max != new_pane->max)
1765 XawPanedSetMinMax(new, (int)new_pane->min, (int)new_pane->max);
1767 /* Check for change in XtNshowGrip. */
1769 if (old_pane->show_grip != new_pane->show_grip)
1770 if (new_pane->show_grip == TRUE) {
1771 CreateGrip(new);
1772 if (XtIsRealized(XtParent(new))) {
1773 if (XtIsManaged(new)) /* if paned is unrealized this will
1774 happen automatically at realize time.*/
1775 XtManageChild(PaneInfo(new)->grip); /* manage the grip. */
1776 XtRealizeWidget(PaneInfo(new)->grip); /* realize the grip. */
1777 CommitNewLocations( (PanedWidget) XtParent(new) );
1780 else if ( HasGrip(old) ) {
1781 XtDestroyWidget( old_pane->grip );
1782 new_pane->grip = NULL;
1783 redisplay = TRUE;
1786 /* ||| need to look at position changes */
1788 return(redisplay);
1791 /************************************************************
1793 * Public routines.
1795 ************************************************************/
1797 /* Function Name: XawPanedSetMinMax
1798 * Description: Sets the min and max size for a pane.
1799 * Arguments: widget - the widget that is a child of the Paned widget.
1800 * min, max - the new min and max size for the pane.
1801 * Returns: none.
1804 void
1805 XawPanedSetMinMax(widget, min, max)
1806 Widget widget;
1807 int min, max;
1809 Pane pane = PaneInfo(widget);
1811 pane->min = min;
1812 pane->max = max;
1813 RefigureLocationsAndCommit( widget->core.parent );
1816 /* Function Name: XawPanedGetMinMax
1817 * Description: Gets the min and max size for a pane.
1818 * Arguments: widget - the widget that is a child of the Paned widget.
1819 ** RETURNED ** min, max - the current min and max size for the pane.
1820 * Returns: none.
1823 void
1824 XawPanedGetMinMax(widget, min, max)
1825 Widget widget;
1826 int *min, *max;
1828 Pane pane = PaneInfo(widget);
1830 *min = pane->min;
1831 *max = pane->max;
1834 /* Function Name: XawPanedSetRefigureMode
1835 * Description: Allows a flag to be set the will inhibit
1836 * the paned widgets relayout routine.
1837 * Arguments: w - the paned widget.
1838 * mode - if FALSE then inhibit refigure.
1839 * Returns: none.
1842 void
1843 XawPanedSetRefigureMode(w, mode)
1844 Widget w;
1845 Boolean mode;
1847 ((PanedWidget) w)->paned.refiguremode = mode;
1848 RefigureLocationsAndCommit( w );
1851 /* Function Name: XawPanedGetNumSub
1852 * Description: Returns the number of panes in the paned widget.
1853 * Arguments: w - the paned widget.
1854 * Returns: the number of panes in the paned widget.
1857 int
1858 XawPanedGetNumSub(w)
1859 Widget w;
1861 return ((PanedWidget)w)->paned.num_panes;
1864 /* Function Name: XawPanedAllowResize
1865 * Description: Allows a flag to be set that determines if the paned
1866 * widget will allow geometry requests from this child
1867 * Arguments: widget - a child of the paned widget.
1868 * Returns: none.
1871 void
1872 XawPanedAllowResize(widget, allow_resize)
1873 Widget widget;
1874 Boolean allow_resize;
1876 PaneInfo(widget)->allow_resize = allow_resize;