/*
* Motif
*
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "XmI.h"
#include <Xm/PanedP.h>
#include <Xm/SashP.h>
#include <Xm/Separator.h>
#include <Xm/ExtP.h>
typedef enum {UpLeftPane = 'U', /* Adjust panes above or to the left.*/
LowRightPane = 'L',/* Adjust panes below or the the right. */
AnyPane = 'A' } Direction;
#define NO_DELTA -99
#define NO_INDEX -100
#define BLOCK 10
#define LARGE_INC ("LargeIncr")
#define XmNisAPane "isAPane"
/************************************************************
* GLOBAL DECLARATIONS
************************************************************/
/*****************************************************************************
*
* Full instance record declaration
*
****************************************************************************/
/*
* These characters all get compiled into each application as/is, so
* the default translations table is not very readable, but is nice and small.
*/
static char defSashTranslations[] =
"<Key>osfHelp: Help()\n\
!c<Key>osfUp: SashAction(K,10,Up)\n\
None<Key>osfUp: SashAction(K,1,Up)\n\
!c<Key>osfDown: SashAction(K,10,Down)\n\
None<Key>osfDown: SashAction(K,1,Down)\n\
!c<Key>osfLeft: SashAction(K,10,Left)\n\
None<Key>osfLeft: SashAction(K,1,Left)\n\
!c<Key>osfRight: SashAction(K,10,Right)\n\
None<Key>osfRight: SashAction(K,1,Right)\n\
s~m~a<Key>Tab: PrevTabGroup()\n\
~m~a<Key>Tab: NextTabGroup()\n\
~c ~s ~m ~a <Btn1Down>: SashAction(S)\n\
~c ~s ~m ~a <Btn1Motion>: SashAction(M)\n\
~c ~s ~m ~a <BtnUp>: SashAction(C)\n\
<FocusIn>: SashFocusIn()\n\
<FocusOut>: SashFocusOut()\n\
<Unmap>: PrimitiveUnmap()\n\
<EnterWindow>: enter()\n\
<LeaveWindow>: leave()";
/* Internal (yet useful) Motif routine. */
extern void _XmBackgroundColorDefault();
/************************************************************
* Private functions.
************************************************************/
static void ClassInitialize();
static XmImportOperator ToPanedOppositePixels(Widget, int, XtArgVal *);
static XmImportOperator ToPanedChildPixels(Widget, int, XtArgVal *);
static Dimension PaneSize(Widget, Boolean);
static Dimension GetRequestInfo(XtWidgetGeometry *, Boolean);
static Pane ChoosePaneToResize(XmPanedWidget, int, Direction, Boolean);
static int GetEventLocation(XmPanedWidget, XEvent *);
static Boolean PopPaneStack(XmPanedWidget), IsPane(Widget);
static Boolean SatisfiesRule3(Pane, Boolean);
static Boolean SatisfiesRule2(Pane), SatisfiesRule1(Pane, Boolean, Direction);
static Boolean RefigureLocations(XmPanedWidget, int, Direction);
static XtGeometryResult AdjustPanedSize(XmPanedWidget, Dimension, Boolean,
Boolean, Dimension *, Dimension *);
static void ResetSize(XmPanedWidget, Boolean);
static void GetPrefSizes(XmPanedWidget, Dimension *, Dimension *);
static void FromPanedChildPixels(Widget, int, XtArgVal *);
static void FromPanedOppositePixels(Widget, int, XtArgVal *);
static void LoopAndRefigureChildren(XmPanedWidget, int, int, Dimension *);
static void CommitNewLocations(XmPanedWidget, Widget);
static void RefigureLocationsAndCommit(Widget), CreateSeparator(Widget);
static void _DrawRect(XmPanedWidget, GC, int, int, unsigned int, unsigned int);
static void _DrawTrackLines(XmPanedWidget, Boolean), ResetSash(Widget);
static void StartSashAdjustment(XmPanedWidget, Widget);
static void MoveSashAdjustment(XmPanedWidget, Widget, int);
static void CommitSashAdjustment(XmPanedWidget, Widget), ReleaseGCs(Widget);
static void ProcessKeyEvent(XtPointer, XtIntervalId *);
static void HandleSash(Widget, XtPointer, XtPointer);
static void ManageAndUnmanageSashs(XmPanedWidget), CreateSash(Widget);
static void SetChildrenPrefSizes(XmPanedWidget, Dimension, Boolean, Boolean);
static void PushPaneStack(XmPanedWidget, Pane), ClearPaneStack(XmPanedWidget);
static void GetPaneStack(XmPanedWidget, Boolean, Pane *, int *);
/************************************************************
* Semi-Public functions
************************************************************/
static Boolean SetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static Boolean PaneSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
static XtGeometryResult GeometryManager(Widget, XtWidgetGeometry *,
XtWidgetGeometry *);
static XtGeometryResult QueryGeometry(Widget, XtWidgetGeometry *,
XtWidgetGeometry *);
static void Destroy(Widget);
static void Initialize(Widget, Widget, ArgList, Cardinal*);
static void InsertChild(register Widget);
static void Realize(Widget, Mask *, XSetWindowAttributes *);
static void ConstraintDestroy(Widget), ReManageChildren(XmPanedWidget);
static void ChangeManaged(Widget), Resize(Widget);
/* Resource definitions for Subclasses of Primitive */
static Position def_pos = -10; /* negative numbers cannot be set with immed.*/
static XtResource resources[] =
{
{
XmNspacing, XmCSpacing, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedRec, paned.internal_bw),
XmRImmediate, (XtPointer) 10
},
{
XmNmarginWidth, XmCMargin, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedRec, paned.margin_width),
XmRImmediate, (XtPointer) 3
},
{
XmNmarginHeight, XmCMargin, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedRec, paned.margin_height),
XmRImmediate, (XtPointer) 3
},
{
XmNrefigureMode, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedRec, paned.refiguremode),
XmRImmediate, (XtPointer) TRUE
},
{
XmNorientation, XmCOrientation, XmROrientation,
sizeof(unsigned char), XtOffsetOf(XmPanedRec, paned.orientation),
XmRImmediate, (XtPointer) XmVERTICAL
},
{
XmNseparatorOn, XmCSeparatorOn, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedRec, paned.separator_on),
XmRImmediate, (XtPointer) TRUE
},
/* Cursors - these are used in both horiz and vertical mode. */
{
XmNcursor, XmCCursor, XmRCursor,
sizeof(Cursor), XtOffsetOf(XmPanedRec, paned.cursor),
XmRImmediate, None
},
/* Sash control resources */
{
XmNsashIndent, XmCSashIndent, XmRHorizontalPosition,
sizeof(Position), XtOffsetOf(XmPanedRec, paned.sash_indent),
XmRHorizontalPosition, (XtPointer) &def_pos
},
{
XmNsashTranslations, XmCTranslations, XmRTranslationTable,
sizeof(XtTranslations), XtOffsetOf(XmPanedRec, paned.sash_translations),
XmRString, (XtPointer)defSashTranslations
},
{
XmNsashWidth, XmCSashWidth, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedRec, paned.sash_width),
XmRImmediate, (XtPointer) 10
},
{
XmNsashHeight, XmCSashHeight, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedRec, paned.sash_height),
XmRImmediate, (XtPointer) 10
},
{
XmNsashShadowThickness, XmCShadowThickness, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedRec, paned.sash_shadow_thickness),
XmRImmediate, (XtPointer) 2
},
{
XmNallowUnusedSpace, XmCAllowUnusedSpace, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedRec, paned.allow_unused_space),
XmRImmediate, (XtPointer) TRUE
}
};
/* Definition for resources that need special processing in get values */
static XmSyntheticResource get_resources[] =
{
{
XmNmarginWidth, sizeof(Dimension),
XtOffsetOf(XmPanedRec, paned.margin_width),
XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
},
{
XmNmarginHeight, sizeof(Dimension),
XtOffsetOf(XmPanedRec, paned.margin_height),
XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
},
{
XmNspacing, sizeof(Dimension),
XtOffsetOf(XmPanedRec, paned.internal_bw),
_XmFromPanedPixels, (XmImportProc) _XmToPanedPixels
},
{
XmNsashIndent, sizeof(Position),
XtOffsetOf(XmPanedRec, paned.sash_indent),
FromPanedOppositePixels, (XmImportProc) ToPanedOppositePixels
},
{
XmNsashWidth, sizeof(Dimension),
XtOffsetOf(XmPanedRec, paned.sash_width),
XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
},
{
XmNsashHeight, sizeof(Dimension),
XtOffsetOf(XmPanedRec, paned.sash_height),
XmeFromVerticalPixels, (XmImportProc) XmeToVerticalPixels
},
{
XmNsashShadowThickness, sizeof(Dimension),
XtOffsetOf(XmPanedRec, paned.sash_shadow_thickness),
XmeFromHorizontalPixels, (XmImportProc) XmeToHorizontalPixels
}
};
static XtResource subresources[] =
{
{
XmNallowResize, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedConstraintsRec, paned.allow_resize),
XmRImmediate, (XtPointer) FALSE
},
{
XmNpaneMinimum, XmCPaneMinimum, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedConstraintsRec, paned.min),
XmRImmediate, (XtPointer) 1
},
{
XmNpaneMaximum, XmCPaneMaximum, XmRVerticalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedConstraintsRec, paned.max),
XmRImmediate, (XtPointer) 1000
},
#ifdef POSITION_IMPLEMENTED
{
XmNposition, XmCPosition, XmRInt,
sizeof(int), XtOffsetOf(XmPanedConstraintsRec, paned.position),
XmRImmediate, (XtPointer) 0
},
#endif
{
XmNpreferredPaneSize, XmCPreferredPaneSize, XmRHorizontalDimension,
sizeof(Dimension), XtOffsetOf(XmPanedConstraintsRec, paned.preferred_size),
XmRImmediate, (XtPointer) XmPanedAskChild
},
/*
* Overrides user's grip placement and go back to preferred size when
* paned window is resized or a management change happens.
*/
{
XmNresizeToPreferred, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedConstraintsRec, paned.resize_to_pref),
XmRImmediate, (XtPointer) FALSE
},
{
XmNskipAdjust, XmCBoolean, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedConstraintsRec, paned.skip_adjust),
XmRImmediate, (XtPointer) FALSE
},
{
XmNshowSash, XmCShowSash, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedConstraintsRec, paned.show_sash),
XmRImmediate, (XtPointer) TRUE
},
/*
* This is an internal constraint resources set on sashes and separators
* at start up to False, it should be True for all real panes.
*/
{
XmNisAPane, XmNisAPane, XmRBoolean,
sizeof(Boolean), XtOffsetOf(XmPanedConstraintsRec, paned.is_a_pane),
XmRImmediate, (XtPointer) TRUE
}
};
/* Definition for constraint resources that need special */
/* processing in get values */
static XmSyntheticResource get_constraint_resources[] =
{
{
XmNpaneMinimum, sizeof(Dimension),
XtOffsetOf(XmPanedConstraintsRec, paned.min),
FromPanedChildPixels, (XmImportProc) ToPanedChildPixels
},
{
XmNpaneMaximum, sizeof(Dimension),
XtOffsetOf(XmPanedConstraintsRec, paned.max),
FromPanedChildPixels, (XmImportProc) ToPanedChildPixels
},
{
XmNpreferredPaneSize, sizeof(Dimension),
XtOffsetOf(XmPanedConstraintsRec, paned.preferred_size),
FromPanedChildPixels, (XmImportProc) ToPanedChildPixels
}
};
#define SuperClass ((ConstraintWidgetClass)&xmManagerClassRec)
XmPanedClassRec xmPanedClassRec = {
{
/* core class fields */
/* superclass */ (WidgetClass) SuperClass,
/* class name */ "XmPaned",
/* size */ sizeof(XmPanedRec),
/* class_initialize */ ClassInitialize,
/* class_part init */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ Realize,
/* actions */ NULL,
/* num_actions */ 0,
/* resources */ (XtResource*)resources,
/* resource_count */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave*/ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ NULL,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ XtInheritTranslations,
/* query_geometry */ (XtGeometryHandler) QueryGeometry,
/* display_accelerator*/ XtInheritDisplayAccelerator,
/* extension */ NULL
}, {
/* composite class fields */
/* geometry_manager */ GeometryManager,
/* change_managed */ ChangeManaged,
/* insert_child */ InsertChild,
/* delete_child */ XtInheritDeleteChild,
/* extension */ NULL
}, {
/* constraint class fields */
/* subresources */ (XtResource*)subresources,
/* subresource_count */ XtNumber(subresources),
/* constraint_size */ sizeof(XmPanedConstraintsRec),
/* initialize */ NULL,
/* destroy */ ConstraintDestroy,
/* set_values */ PaneSetValues,
/* extension */ NULL
}, {
/* manager_class fields */
XtInheritTranslations, /* translations */
get_resources, /* get resources */
XtNumber(get_resources), /* num get_resources */
get_constraint_resources, /* get_cont_resources */
XtNumber(get_constraint_resources), /* num_get_cont_resources */
XmInheritParentProcess, /* parent_process */
NULL, /* extension */
}, {
/* paned_window_class fields */
NULL, /* extension */
}
};
WidgetClass xmPanedWidgetClass = (WidgetClass) &xmPanedClassRec;
/***********************************************************
*
* Private Functions.
*
************************************************************/
/*
* Function Name: ClassInitialize
* Description: Initialized XmPaned widget class
* Arguments: none
* Returns: nothing
*/
static void
ClassInitialize()
{
/* do nothing */
}
/* Function Name: AdjustPanedSize
* Description: Adjusts the size of the pane.
* Arguments: pw - the paned widget to adjust.
* off_size - the new off_size to use.
* always_compute_on_size - a self explanatory Boolean.
* query_only - perform a query_only?
* result_ret - result of query ** RETURNED **
* on_size_ret - the new on_size ** RETURNED **
* off_size_ret - the new off_size ** RETURNED **
* Returns: the amount of change in size.
*/
static XtGeometryResult
AdjustPanedSize(XmPanedWidget pw, Dimension off_size,
Boolean always_compute_on_size, Boolean query_only,
Dimension *on_size_ret, Dimension *off_size_ret)
{
Dimension old_size = PaneSize( (Widget) pw, IsVert(pw));
Dimension newsize = 0;
XtWidgetGeometry request, reply;
XtGeometryResult result;
if ((PaneSize((Widget) pw, IsVert(pw)) <= 1) || always_compute_on_size) {
GetPrefSizes(pw, &newsize, NULL);
if (newsize < 1)
newsize = 1;
}
else {
if (IsVert(pw))
newsize = pw->core.height;
else
newsize = pw->core.width;
}
if ( IsVert(pw) ) {
request.width = off_size + 2 * XmPaned_margin_width(pw);
request.height = newsize;
}
else {
request.width = newsize;
request.height = off_size + 2 * XmPaned_margin_height(pw);
}
request.request_mode = CWWidth | CWHeight;
if (query_only)
request.request_mode |= XtCWQueryOnly;
result = XtMakeGeometryRequest( (Widget) pw, &request, &reply );
if (result == XtGeometryAlmost)
{
if (query_only)
request = reply;
else
result = XtMakeGeometryRequest((Widget) pw, &reply, &request);
}
reply = request; /* simplifies things later... */
if ( result == XtGeometryNo ) {
if (on_size_ret != NULL)
*on_size_ret = old_size;
if (off_size_ret != NULL)
*off_size_ret = PaneSize((Widget) pw, !IsVert(pw));
}
else { /* result == XtGeometryYes */
if (on_size_ret != NULL)
*on_size_ret = GetRequestInfo( &reply, IsVert(pw) );
if (off_size_ret != NULL)
*off_size_ret = GetRequestInfo( &reply, !IsVert(pw) );
}
if ( IsVert(pw) ) {
if (on_size_ret != NULL)
*on_size_ret -= 2 * XmPaned_margin_height(pw);
if (off_size_ret != NULL)
*off_size_ret -= 2 * XmPaned_margin_width(pw);
}
else {
if (on_size_ret != NULL)
*on_size_ret -= 2 * XmPaned_margin_width(pw);
if (off_size_ret != NULL)
*off_size_ret -= 2 * XmPaned_margin_height(pw);
}
return(result);
}
/************************************************************
*
* Resolution Independance stuff for dealing in the face
* of orientation changes.
*
************************************************************/
/* Function Name: FromPanedPixels
* Description: Converts from pixels to current unit type
* does either horiz or vert depending on orientation.
* Arguments: widget - the paned widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
void
_XmFromPanedPixels(Widget widget, int offset, XtArgVal *value)
{
XmPanedWidget pw = (XmPanedWidget) widget;
if (IsVert(pw))
XmeFromVerticalPixels(widget, offset, value);
else
XmeFromHorizontalPixels(widget, offset, value);
}
/* Function Name: FromPanedChildPixels
* Description: Converts from pixels to current unit type
* does either horiz or vert depending on
* of the parent of this widget orientation.
* Arguments: widget - the paned widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
static void
FromPanedChildPixels(Widget widget, int offset, XtArgVal *value)
{
XmPanedWidget pw = (XmPanedWidget) XtParent(widget);
if (IsVert(pw))
XmeFromVerticalPixels(widget, offset, value);
else
XmeFromHorizontalPixels(widget, offset, value);
}
/* Function Name: ToPanedPixels
* Description: Converts to pixels from current unit type
* does either horiz or vert depending on orientation.
* Arguments: widget - the paned widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
XmImportOperator
_XmToPanedPixels(Widget widget, int offset, XtArgVal *value)
{
XmPanedWidget pw = (XmPanedWidget) widget;
if (IsVert(pw))
return(XmeToVerticalPixels(widget, offset, value));
else
return(XmeToHorizontalPixels(widget, offset, value));
}
/* Function Name: ToPanedChildPixels
* Description: Converts to pixels from current unit type
* does either horiz or vert depending on parent's
* orientation.
* Arguments: widget - the paned widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
static XmImportOperator
ToPanedChildPixels(Widget widget, int offset, XtArgVal *value)
{
XmPanedWidget pw = (XmPanedWidget) XtParent(widget);
if (IsVert(pw))
return(XmeToVerticalPixels(widget, offset, value));
else
return(XmeToHorizontalPixels(widget, offset, value));
}
/* Function Name: FromPanedOppositePixels
* Description: Converts from pixels to current unit type
* does either horiz or vert depending on orientation.
* Arguments: widget - the paned widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
static void
FromPanedOppositePixels(Widget widget, int offset, XtArgVal *value)
{
XmPanedWidget pw = (XmPanedWidget) widget;
if (IsVert(pw))
XmeFromHorizontalPixels(widget, offset, value);
else
XmeFromVerticalPixels(widget, offset, value);
}
/* Function Name: ToPanedOppositePixels
* Description: Converts to pixels from current unit type
* does either horiz or vert depending on orientation.
* Arguments: widget - the paned widget.
* offset, value - passed to correct function based
* on orientation.
* Returns: none
*/
static XmImportOperator
ToPanedOppositePixels(Widget widget, int offset, XtArgVal *value)
{
XmPanedWidget pw = (XmPanedWidget) widget;
if (IsVert(pw))
return(XmeToHorizontalPixels(widget, offset, value));
else
return(XmeToVerticalPixels(widget, offset, value));
}
/* Function Name: PaneSize
* Description: returns the width or height of the pane depending
* upon the orientation we are using.
* Arguments: w - and widget.
* vertical - TRUE if this is vertically oriented pane.
* Returns: the size requested
*
* vertical - return height
* !vertical - return width
*/
static Dimension
PaneSize(Widget w, Boolean vertical)
{
if (vertical)
return (w->core.height);
return (w->core.width);
}
/* Function Name: GetRequestInfo
* Description: returns request information.
* Arguments: geo_struct - a geometry struct to get information out of.
* vert - TRUE if this is a vertical paned widget.
* Returns: the request information.
*/
static Dimension
GetRequestInfo(XtWidgetGeometry *geo_struct, Boolean vert)
{
if (vert)
return ((Dimension) geo_struct->height);
return ((Dimension) geo_struct->width);
}
/* Function Name: ChoosePaneToResize.
* Description: This function chooses a pane to resize.
* They are chosen using the following rules:
*
* 1) size < max && size > min
* if pane is growing or has a sash.
* (keeps non sash panes from shrinking).
* 3) skip adjust == FALSE
* 4) widget not its prefered height &&
* this change will bring it closer &&
* The user has not resized this pane.
*
* If no widgets are found that fits all the rules then
* rule #3 is broken.
* If there are still no widgets found than
* rule #2 is broken.
* Rule #1 is never broken.
* If no widgets are found then NULL is returned.
*
* Arguments: pw - the paned widget.
* paneindex - the index of the current pane.
* dir - direction to search first.
* shrink - TRUE if we need to shrink a pane, FALSE otherwise.
* Returns: pane to resize or NULL.
*/
static Pane
ChoosePaneToResize(XmPanedWidget pw,
int paneindex, Direction dir, Boolean shrink)
{
Widget *childP;
int rules = 3;
Direction _dir = dir;
int _index = paneindex;
int curIndex;
if ( (paneindex == NO_INDEX) || (dir == AnyPane) ) { /* Use defaults. */
_dir = LowRightPane; /* Go up. - really. */
_index = XmPaned_num_panes(pw) - 1; /* Start the last pane, and work
backwards. */
}
childP = NthPane(pw, _index);
while(TRUE) {
register Pane pane = PaneInfo(*childP);
if ((rules < 3 || SatisfiesRule3(pane, shrink)) &&
(rules < 2 || SatisfiesRule2(pane)) &&
(SatisfiesRule1(pane, shrink, dir)) &&
((paneindex != PaneIndex(*childP)) || (dir == AnyPane)) )
{
return(pane);
}
/*
* This is counter-intuitive, but if we are resizing the pane
* above the sash we want to choose a pane below the sash to lose,
* and visa-versa.
*/
if (shrink || (dir == AnyPane)) {
if (_dir == LowRightPane)
--childP;
else
++childP;
}
else {
if (_dir == LowRightPane)
++childP;
else
--childP;
}
/*
* If we have come to and edge then reduce the rule set, and try again.
* If we are reduced the rules to none, then return NULL.
*/
curIndex = childP - NthPane(pw, 0);
if ((curIndex < 0) || (curIndex >= XmPaned_num_panes(pw))) {
if (--rules < 1) /* less strict rules. */
return(NULL);
childP = NthPane(pw, _index);
}
}
}
/* Function Name: IsPane
* Description: Returns true if this is a pane.
* Arguments: w - a child of the paned widget.
* Returns: none.
*/
static Boolean
IsPane(Widget w)
{
Pane pane = PaneInfo(w);
return ((pane != NULL) && pane->is_a_pane);
}
/* Function Name: StatisfiesRule1
* Description: check for to see if this pane satisfies rule 1.
* Arguments: pane - the pane to check.
* shrink -TRUE if we want to shrink this pane, FALSE otherwise
* rEturns: TRUE if the rule is satisfied.
*/
static Boolean
SatisfiesRule1(Pane pane, Boolean shrink, Direction dir)
{
/*
* If this pane is at its preferred size and is asked to shrink
* while having no sash then do not allow it.
*
* NOTE: If Dir == AnyPane then this is not due to a grip resize
* and this rule does not take effect.
*/
if ((dir != AnyPane) &&
shrink && (pane->sash == NULL) && (pane->size == pane->wp_size))
{
return(False);
}
return((shrink && (pane->size != pane->min)) ||
(!shrink && (pane->size != pane->max)) );
}
/* Function Name: StatisfiesRule2
* Description: check for to see if this pane satisfies rule 2.
* Arguments: pane - the pane to check.
* Returns: TRUE if the rule is satisfied.
*/
static Boolean
SatisfiesRule2(Pane pane)
{
return(!pane->skip_adjust);
}
/* Function Name: StatisfiesRule3
* Description: check for to see if this pane satisfies rule 3.
* Arguments: pane - the pane to check.
* shrink -TRUE if we want to shrink this pane, FALSE otherwise
* Returns: TRUE if the rule is satisfied.
*/
static Boolean
SatisfiesRule3(Pane pane, Boolean shrink)
{
return ((pane->size != pane->wp_size) &&
((shrink && ((int)pane->wp_size <= pane->size)) ||
(!shrink && ((int)pane->wp_size >= pane->size))) );
}
/* Function Name: LoopAndRefigureChildren.
* Description: if we are resizing either the UpleftPane or LowRight Pane
* loop through all the children to see if any will allow us
* to resize them.
* Arguments: pw - the paned widget.
* paneindex - the number of the pane border we are moving.
* dir - the pane to move (either UpLeftPane or LowRightPane).
* sizeused - current amount of space used.
* THIS VALUE IS USED AND RETURNED.
* Returns: none.
*/
static void
LoopAndRefigureChildren(XmPanedWidget pw,
int paneindex, int dir, Dimension *sizeused)
{
int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw));
Boolean shrink = ((int)(*sizeused) > (int)pane_size);
while (*sizeused != pane_size) { /* While all panes do not fit properly. */
/*
* Choose a pane to resize.
* First look on the Pane Stack, and then go hunting for another one.
* If we fail to find a pane to resize then give up.
*/
Pane pane;
int start_size;
Dimension old;
Boolean rule3_ok = FALSE, from_stack = TRUE;
GetPaneStack(pw, shrink, &pane, &start_size);
if (pane == NULL) {
pane = ChoosePaneToResize(pw, paneindex, (Direction)dir, shrink);
if (pane == NULL)
return; /* no one to resize, give up. */
rule3_ok = SatisfiesRule3(pane, shrink);
from_stack = FALSE;
PushPaneStack(pw, pane);
}
/*
* Try to resize this pane so that all panes will fit, take min and max
* into account.
*/
old = pane->size;
pane->size += pane_size - *sizeused;
if (from_stack) {
if (shrink) {
ASSIGN_MAX(pane->size, start_size);
} /* don't remove these braces. */
else
ASSIGN_MIN(pane->size, start_size);
if (pane->size == start_size) (void) PopPaneStack(pw);
}
else if (rule3_ok) {
if (shrink) {
ASSIGN_MAX(pane->size, (int) pane->wp_size);
} /* don't remove these braces. */
else
ASSIGN_MIN(pane->size, (int) pane->wp_size);
}
ASSIGN_MAX(pane->size, (int) pane->min);
ASSIGN_MIN(pane->size, (int) pane->max);
*sizeused += (pane->size - old);
}
}
/* Function Name: GetPrefSizes
* Description: Gets the preferred On Size.
* Arguments: w - the paned widget.
* RETURNED on_size, off_size;
* Returns: none.
*/
static void
GetPrefSizes(XmPanedWidget pw, Dimension *on_size, Dimension *off_size)
{
Widget *childP;
register Dimension sash_size, sizeused;
Boolean vert = IsVert(pw);
if (on_size != NULL) {
sizeused = 0;
/*
* Get an initial estimate of the size we will use.
*/
if (vert)
sash_size = XmPaned_sash_height(pw);
else
sash_size = XmPaned_sash_width(pw);
for ( childP = XmPaned_managed_children(pw);
childP < (XmPaned_managed_children(pw)
+ XmPaned_num_panes(pw));
childP++) {
register Pane pane = PaneInfo(*childP);
ASSIGN_MAX(pane->size, (int) pane->min);
ASSIGN_MIN(pane->size, (int) pane->max);
sizeused += (int) pane->size + 2 * (*childP)->core.border_width;
if (!IsLastPane(pw, childP)) {
if (HasSash(*childP))
sizeused += MAX(XmPaned_internal_bw(pw), sash_size);
else
sizeused += XmPaned_internal_bw(pw);
}
}
/*
* Get rid of extra spacing from previous 'for' loop and add in
* margin height at the top and bottom of the paned window
*/
if( vert)
sizeused += 2*XmPaned_margin_height(pw);
else
sizeused += 2*XmPaned_margin_width(pw);
*on_size = sizeused;
}
if (off_size != NULL) {
Widget *childP;
sizeused = 1;
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
Pane pane = PaneInfo(*childP);
if (XtIsManaged(*childP) && (pane->wp_off_size > sizeused))
sizeused = pane->wp_off_size;
}
*off_size = sizeused;
}
}
/* Function Name: RefigureLocations
* Description: refigures all locations of children.
* Arguments: pw - the paned widget.
* paneindex - child to start refiguring at.
* dir - direction to move from child.
* Returns: True if anything actually moved.
*
* There are special arguments to paneindex and dir, they are:
* paneindex - NO_INDEX.
* dir - AnyPane.
*
* If either of these is true then all panes may be resized and
* the choosing of panes procedes in reverse order starting with the
* last child.
*/
static Boolean
RefigureLocations(XmPanedWidget pw, int paneindex, Direction dir)
{
register Widget *childP;
int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw) );
Dimension sizeused;
Position loc = 0;
int sash_size, moved = True;
if (XmPaned_num_panes(pw) == 0)
return False;
GetPrefSizes(pw, &sizeused, NULL);
if (sizeused == pane_size)
moved = False;
else
LoopAndRefigureChildren(pw, paneindex, dir, &sizeused);
/*
* If we still are not the right size, then tell the pane that
* wanted to resize that it can't.
*/
if ( (paneindex != NO_INDEX) && (dir != AnyPane) ) {
Pane pane = PaneInfo(*NthPane(pw, paneindex));
Dimension old = pane->size;
if(pane_size != sizeused) {
moved = False;
}
pane->size += pane_size - sizeused;
ASSIGN_MAX(pane->size, (int) pane->min);
ASSIGN_MIN(pane->size, (int) pane->max);
sizeused += pane->size - old;
}
if (!XmPaned_allow_unused_space(pw))
{
if (pane_size > sizeused)
{
PaneInfo(*NthPane(pw, paneindex-1))->size += (pane_size - sizeused);
}
}
/*
* It is possible that the panes will not fit inside the vpaned widget, but
* we have tried out best.
*
* Assign each pane a location.
*/
if(IsVert(pw)) {
loc = XmPaned_margin_height(pw);
} else {
loc = XmPaned_margin_width(pw);
}
/*
* This is where we actually tell the widget where to draw the track
* lines.
*/
if (IsVert(pw))
sash_size = XmPaned_sash_height(pw);
else
sash_size = XmPaned_sash_width(pw);
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
if (LayoutIsRtoLM(pw) && !(IsVert(pw))) {
loc += PaneInfo(*childP)->size + 2 * (*childP)->core.border_width;
PaneInfo(*childP)->delta = pw->core.width - loc;
} else {
PaneInfo(*childP)->delta = loc;
loc += PaneInfo(*childP)->size + 2 * (*childP)->core.border_width;
}
if (HasSash(*childP))
loc += MAX(XmPaned_internal_bw(pw), sash_size);
else
loc += XmPaned_internal_bw(pw);
}
return moved;
}
/* Function Name: CommitNewLocations
* Description: Commits all of the previously figured locations.
* Arguments: pw - the paned widget.
* no_resize_child - child not to resize
* Returns: none.
*
* no_resize_child is only used by the geometry manager to implement an
* XtGeometryYes policy as Motif1.2 dictates.
*/
static void
CommitNewLocations(XmPanedWidget pw, Widget no_resize_child)
{
register Widget *childP;
XWindowChanges changes;
XWindowChanges sep;
int offset, sash_size;
if (!XmPaned_refiguremode(pw))
return;
if (IsVert(pw)) {
offset = XmPaned_margin_width(pw);
sash_size = XmPaned_sash_height(pw);
}
else {
offset = XmPaned_margin_height(pw);
sash_size = XmPaned_sash_width(pw);
}
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
register Pane pane = PaneInfo(*childP);
register Widget sash = pane->sash; /* may be NULL. */
register Widget separator = pane->separator; /* may be NULL. */
int internal_space;
if (HasSash(*childP))
internal_space = MAX(XmPaned_internal_bw(pw), sash_size);
else
internal_space = XmPaned_internal_bw(pw);
if (IsVert(pw)) {
if (*childP == no_resize_child) {
(*childP)->core.x = offset;
(*childP)->core.y = pane->delta;
(*childP)->core.width = (pw->core.width -
2 * (offset +
(*childP)->core.border_width));
(*childP)->core.height = pane->size;
}
else {
_XmConfigureWidget(*childP, (Position) offset, pane->delta,
pw->core.width -
2*(offset + (*childP)->core.border_width),
(Dimension) pane->size,
(Dimension) (*childP)->core.border_width);
}
if (sash != NULL) { /* Move and Display the Sash */
/*
* Motif style does - indent from right edge, pos from left
*/
if(XmPaned_sash_indent(pw) < 0) {
changes.x = (pw->core.width + XmPaned_sash_indent(pw) -
sash->core.width -
sash->core.border_width * 2);
} else {
changes.x = XmPaned_sash_indent(pw);
}
changes.y = ((*childP)->core.y + (*childP)->core.height +
2 * (*childP)->core.border_width +
internal_space/2 - sash->core.height/2 -
sash->core.border_width);
}
if (separator != NULL) {
sep.width = pw->core.width;
sep.height = XmPaned_sash_shadow_thickness(pw);
sep.x = 0;
sep.y = ((*childP)->core.y + (*childP)->core.height -
sep.height / 2 - separator->core.border_width +
internal_space / 2 +
2 * (*childP)->core.border_width);
}
} else {
if (*childP == no_resize_child) {
(*childP)->core.x = pane->delta;
(*childP)->core.y = offset;
(*childP)->core.width = pane->size;
(*childP)->core.height = (pw->core.height -
2 * (offset +
(*childP)->core.border_width));
}
else {
_XmConfigureWidget(*childP, pane->delta, (Position) offset,
(Dimension) pane->size,
pw->core.height -
2*(offset + (*childP)->core.border_width),
(Dimension) (*childP)->core.border_width);
}
if (sash != NULL) { /* Move and Display the Sash */
if (LayoutIsRtoLM(pw))
changes.x = ((*childP)->core.x -
internal_space / 2 - sash->core.width/2 -
sash->core.border_width);
else
changes.x = ((*childP)->core.x + (*childP)->core.width +
2 * (*childP)->core.border_width +
internal_space / 2 - sash->core.width/2 -
sash->core.border_width);
/* Motif style does - indent from right edge, pos from left */
if(XmPaned_sash_indent(pw) < 0) {
changes.y = pw->core.height + XmPaned_sash_indent(pw) -
sash->core.height - sash->core.border_width*2;
}
else {
changes.y = XmPaned_sash_indent(pw);
}
}
if (separator != NULL) {
sep.width = XmPaned_sash_shadow_thickness(pw);
sep.height = pw->core.height;
sep.y = 0;
if (LayoutIsRtoLM(pw))
sep.x = ((*childP)->core.x -
sep.width / 2 - separator->core.border_width -
internal_space / 2);
else
sep.x = ((*childP)->core.x + (*childP)->core.width -
sep.width / 2 - separator->core.border_width +
internal_space / 2 +
2 * (*childP)->core.border_width);
}
}
/*
* This should match XtMoveWidget, except that we're also insuring the
* sash is Raised in the same request.
*/
if(separator != NULL) {
_XmConfigureWidget(separator, sep.x, sep.y,
sep.width, sep.height,
separator->core.border_width);
}
if (sash != NULL) {
sash->core.x = changes.x;
sash->core.y = changes.y;
changes.stack_mode = Above; /* assures sash is always above sep. */
if (XtIsRealized(sash)) {
XmDropSiteStartUpdate((Widget) pw);
XConfigureWindow(XtDisplay(sash), XtWindow(sash),
CWX | CWY | CWStackMode, &changes );
XmDropSiteEndUpdate((Widget) pw);
}
}
}
ClearPaneStack(pw);
}
/* Function Name: RefigureLocationsAndCommit
* Description: Refigures all locations in a paned widget and
* commits them immediately.
* Arguments: pw - the paned widget.
* Returns: none
*
* This function does nothing if any of the following are true.
* o refiguremode is false.
* o The widget is unrealized.
* o There are no panes is the paned widget.
*
* NOTE: This is the resize Procedure for the Paned widget.
*/
static void
RefigureLocationsAndCommit(Widget w)
{
XmPanedWidget pw = (XmPanedWidget) w;
if (XmPaned_refiguremode(pw) && XtIsRealized( (Widget) pw) &&
XmPaned_num_panes(pw) > 0 )
{
RefigureLocations(pw, NO_INDEX, AnyPane);
CommitNewLocations(pw, NULL);
}
}
/* Function Name: _DrawRect
* Description: Draws a rectangle in the proper orientation.
* Arguments: pw - the paned widget.
* gc - gc to used for the draw.
* on_olc, off_loc - location of upper left corner of rect.
* on_size, off_size - size of rectangle.
* Returns: none
*/
static void
_DrawRect(XmPanedWidget pw, GC gc, int on_loc, int off_loc,
unsigned int on_size, unsigned int off_size)
{
if (IsVert(pw))
XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
off_loc, on_loc, off_size, on_size);
else
XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
on_loc, off_loc, on_size, off_size);
}
/* Function Name: _DrawTrackLines
* Description: Draws the lines that animate the pane borders when the
* sashs are moved.
* Arguments: pw - the Paned widget.
* erase - if True then just erase track lines, else
* draw them in.
* Returns: none.
*/
static void
_DrawTrackLines(XmPanedWidget pw, Boolean erase)
{
Widget *childP;
Pane pane;
int on_loc, off_loc;
unsigned int on_size, off_size;
int sash_size, internal_space;
/* Always full width of the widget accross the other dimension */
off_loc = 0;
off_size = PaneSize((Widget) pw, !IsVert(pw));
if(IsVert(pw))
sash_size = XmPaned_sash_height(pw);
else
sash_size = XmPaned_sash_width(pw);
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
pane = PaneInfo(*childP);
/*
* First child never has a track line.
*/
if ((((IsVert(pw) || !(LayoutIsRtoLM(pw))) &&
(XmPaned_managed_children(pw) != childP)) ||
(!(IsVert(pw)) && LayoutIsRtoLM(pw) &&
!(IsLastPane(pw, childP)))) &&
(erase || (pane->olddelta != pane->delta)))
{
if(IsVert(pw)) {
on_size = pane->separator ?
pane->separator->core.height : (Dimension) 2;
} else {
on_size = pane->separator ?
pane->separator->core.width: (Dimension) 2;
}
if (HasSash(*(childP - 1)))
internal_space = MAX(XmPaned_internal_bw(pw), sash_size);
else
internal_space = XmPaned_internal_bw(pw);
if (!erase && (pane->olddelta != NO_DELTA)) {
/* This formula might have to correct for border width of
* the sep in the future, but the Paned widget creates them
* with a zero width border just to make sure, so it is never
* an issue. I did not feel the need to allow users to
* specify borders around the separators because it simply
* would look stupid. -- aja
*/
on_loc = (pane->olddelta -
((int) on_size + internal_space) / 2);
_DrawRect(pw, XmPaned_flipgc(pw),
on_loc, off_loc, on_size, off_size);
}
on_loc = (pane->delta -
((int) on_size + internal_space) / 2);
_DrawRect(pw, XmPaned_flipgc(pw),
on_loc, off_loc, on_size, off_size);
}
pane->olddelta = pane->delta;
}
}
/*
* This allows good reuse of code, as well as descriptive function names.
*/
#define DrawTrackLines(pw) _DrawTrackLines((pw), FALSE);
#define EraseTrackLines(pw) _DrawTrackLines((pw), TRUE);
/* Function Name: GetEventLocation
* Description: Converts and event to an x and y location.
* Arguments: pw - the paned widget.
* event - a pointer to an event.
* Returns: if this is a vertical pane then (y) else (x).
*/
static int
GetEventLocation(XmPanedWidget pw, XEvent *event)
{
switch (event->xany.type) {
case ButtonPress:
case ButtonRelease:
return((IsVert(pw)) ? event->xbutton.y_root : event->xbutton.x_root);
case KeyPress:
case KeyRelease:
return((IsVert(pw)) ? event->xkey.y_root : event->xkey.x_root);
case MotionNotify:
return((IsVert(pw)) ? event->xmotion.y_root : event->xmotion.x_root);
default:
return((IsVert(pw)) ? XmPaned_start_loc(pw) : XmPaned_start_loc(pw));
}
}
/* Function Name: StartSashAdjustment
* Description: Starts the sash adjustment procedure.
* Arguments: pw - the paned widget.
* sash - the sash widget selected.
* Returns: none.
*/
/* ARGSUSED */
static void
StartSashAdjustment(XmPanedWidget pw, Widget sash)
{
Widget *childP;
XmPaned_repane_status(pw) = BEGAN_ADJUST;
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
PaneInfo(*childP)->olddelta = NO_DELTA;
}
}
/* Function Name: MoveSashAdjustment
* Description: This routine moves all panes around when a sash is moved.
* Arguments: pw - the paned widget.
* sash - the sash that we are moving.
* loc - location of pointer in proper direction.
* Returns: none.
*/
static void
MoveSashAdjustment(XmPanedWidget pw, Widget sash, int loc)
{
int index, diff = loc - XmPaned_start_loc(pw);
Boolean vert = IsVert(pw);
Widget w;
w = *NthPane(pw, PaneIndex(sash));
/* CR03589 CR03163 should check the sash loc is over the maximum */
if ((PaneSize(w, vert) + diff) > PaneInfo(w)->max)
diff = PaneInfo(w)->max - PaneSize(w, vert);
if (LayoutIsRtoLM(pw) && !(IsVert(pw)))
PaneInfo(w)->size = PaneSize(w, vert) - diff;
else
PaneInfo(w)->size = PaneSize(w, vert) + diff;
w = *NthPane(pw, PaneIndex(sash) + 1);
if (LayoutIsRtoLM(pw) && !(IsVert(pw)))
PaneInfo(w)->size = PaneSize(w, vert) + diff;
else
PaneInfo(w)->size = PaneSize(w, vert) - diff;
index = PaneIndex(sash);
if (diff < 0)
index += 1;
(void) RefigureLocations(pw, index,
(diff < 0) ? LowRightPane : UpLeftPane);
}
/* Function Name: CommitSashAdjustment
* Description: Commits the sash adjustment.
* Arguments: pw - the paned widget.
* Returns: none
*/
static void
CommitSashAdjustment(XmPanedWidget pw, Widget sash)
{
int i;
/*
* We only do it if we were in a sash adjustment, this prevents odd
* effects if the user binds a button up to commit, with no
* corresponding start on button down.
*/
if(XmPaned_repane_status(pw) != NO_ADJUST) {
EraseTrackLines(pw);
CommitNewLocations(pw, NULL);
XmPaned_repane_status(pw) = NO_ADJUST;
}
/*
* Set the new user preferred size of the pane above and below the sash.
*/
for (i = 0; i < 2; i++) {
Pane pane = PaneInfo(*NthPane(pw, PaneIndex(sash) + i));
pane->wp_size = pane->size;
}
}
/*************************************<->*************************************
*
* ProcessKeyEvent
*
* Description:
* -----------
* This function processes a batch of key pressed events
* so that a sash movement action via the keyboard doesn't
* get too far behind the key event actions.
*
*************************************<->***********************************/
/* ARGSUSED */
static void
ProcessKeyEvent(XtPointer client_data, XtIntervalId *id)
{
Widget sash = (Widget) client_data;
register XmPanedWidget pw = (XmPanedWidget) XtParent(sash);
Widget *childP;
int i;
/*
* NOTE: w is a sash, to get position we have
* to get index of pane associated with this sash.
*/
childP = XmPaned_managed_children(pw) + PaneIndex(sash);
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
PaneInfo(*childP)->olddelta = NO_DELTA;
}
XmPaned_start_loc(pw) = 0;
MoveSashAdjustment(pw, sash, XmPaned_increment_count(pw));
CommitNewLocations(pw, NULL);
/*
* Set the new user preferred size of the pane above and below the sash.
*/
for (i = 0; i < 2; i++) {
Pane pane = PaneInfo(*NthPane(pw, PaneIndex(sash) + i));
pane->wp_size = pane->size;
}
XmPaned_increment_count(pw) = 0;
}
/* Function Name: HandleSash
* Description: Handles the sash manipulations.
* Arguments: sash - the sash widget that has been moved.
* junk - ** NOT USED **
* call_data - data passed to us from the sash widget.
* Returns: none.
*/
/* ARGSUSED */
static void
HandleSash(Widget sash, XtPointer junk, XtPointer callData)
{
SashCallData call_data = (SashCallData)callData;
XmPanedWidget pw = (XmPanedWidget) XtParent(sash);
int loc;
char action_type;
short increment;
static String params[] = { "HandleSash" };
Cardinal num = 1;
XEvent *event = (XEvent *) call_data->event;
action_type = *call_data->params[0];
if (call_data->num_params == 0 ||
(action_type == 'C' && call_data->num_params != 1) ||
(action_type == 'K' && call_data->num_params != 3) ||
(action_type == 'M' && call_data->num_params != 1) ||
(action_type == 'S' && call_data->num_params != 1))
{
_XmWarningMsg((Widget) pw,
XmNbadActionParameters, XmNbadActionParametersMsg,
params, num);
return;
}
if (isascii(action_type) && islower(action_type))
action_type = toupper(action_type);
loc = GetEventLocation(pw, event);
if (event->xany.type == KeyPress) {
char restptr[BUFSIZ]; /* points to the rest of the string. */
/* Get movement size */
if ((increment = atoi(call_data->params[1])) == 0) {
if (streq(call_data->params[1], LARGE_INC))
increment = 10;
else
increment = 1;
}
switch(call_data->params[2][0]) {
default:
return;
case 'U': /* Up */
XmCopyISOLatin1Lowered(restptr, call_data->params[2] + 2);
if (!IsVert(pw))
increment = 0;
else
increment = -increment;
break;
case 'L': /* Left */
XmCopyISOLatin1Lowered(restptr, call_data->params[2] + 4);
if (IsVert(pw))
increment = 0;
else
increment = -increment;
break;
case 'D': /* Down */
XmCopyISOLatin1Lowered(restptr, call_data->params[2] + 4);
if (!IsVert(pw))
increment = 0;
break;
case 'R': /* Right */
XmCopyISOLatin1Lowered(restptr, call_data->params[2] + 5);
if (IsVert(pw))
increment = 0;
break;
}
/*
* Check to see if there is a string after the up/left/down/right
* and if there is then change the keyboard traversal mode.
*/
if (XmPaned_increment_count(pw) == 0) {
XmPaned_increment_count(pw) = increment;
XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) pw),
XtGetMultiClickTime(XtDisplay((Widget) pw)),
ProcessKeyEvent, (XtPointer) sash);
} else
XmPaned_increment_count(pw) += increment;
return;
}
if ((event->xany.type == ButtonPress) ||
(event->xany.type == ButtonRelease))
{
if (event->xbutton.button != 1)
return;
}
switch (action_type) {
case 'S': /* Start adjustment */
XmPaned_resize_children_to_pref(pw) = FALSE;
StartSashAdjustment(pw, sash);
DrawTrackLines(pw);
XmPaned_start_loc(pw) = loc;
break;
case 'M':
MoveSashAdjustment(pw, sash, loc);
DrawTrackLines(pw);
break;
case 'C':
CommitSashAdjustment(pw, sash);
break;
default:
{
_XmWarningMsg((Widget) pw, XmNbadActionParameters,
XmNbadActionParametersMsg, params, num);
return;
}
}
}
/* Function Name: ManageAndUnmanageSashs
* Description: This function manages and unmanages the sashs so that
* the managed state of each sash matches that of its pane.
* Arguments: pw - the paned widget.
* Returns: none.
*/
static void
ManageAndUnmanageSashs(XmPanedWidget pw)
{
WidgetList managed_sashs, unmanaged_sashs;
Widget *managedP, *unmanagedP;
WidgetList managed_seps, unmanaged_seps;
Widget *managedS, *unmanagedS;
Widget *childP;
Cardinal alloc_size;
Boolean last_child_has_sash = False;
alloc_size = (Cardinal) sizeof(Widget) * pw->composite.num_children / 2;
managedP = managed_sashs = (WidgetList) XtMalloc(alloc_size);
unmanagedP = unmanaged_sashs = (WidgetList) XtMalloc(alloc_size);
managedS = managed_seps = (WidgetList) XtMalloc(alloc_size);
unmanagedS = unmanaged_seps = (WidgetList) XtMalloc(alloc_size);
ForAllChildren(pw, childP) {
if (!IsPane(*childP))
continue;
if (HasSash(*childP)) {
last_child_has_sash = True;
if (XtIsManaged(*childP))
*managedP++ = PaneInfo(*childP)->sash;
else
*unmanagedP++ = PaneInfo(*childP)->sash;
}
else
last_child_has_sash = False;
if (HasSep(*childP)) {
if (XtIsManaged(*childP))
*managedS++ = PaneInfo(*childP)->separator;
else
*unmanagedS++ = PaneInfo(*childP)->separator;
}
}
if (managedP != managed_sashs) {
if (last_child_has_sash) {
*unmanagedP = *--managedP; /* Last sash is never managed */
unmanagedP++;
}
XtManageChildren( managed_sashs, (Cardinal)(managedP - managed_sashs) );
}
if (unmanagedP != unmanaged_sashs)
XtUnmanageChildren(unmanaged_sashs,
(Cardinal)(unmanagedP - unmanaged_sashs) );
XtFree((char *)managed_sashs);
XtFree((char *)unmanaged_sashs);
if (managedS != managed_seps) {
if (last_child_has_sash) {
*unmanagedS = *--managedS; /* Last sash is never managed */
unmanagedS++;
}
XtManageChildren( managed_seps, (Cardinal)(managedS - managed_seps) );
}
if (unmanagedS != unmanaged_seps)
XtUnmanageChildren( unmanaged_seps,
(Cardinal)(unmanagedS - unmanaged_seps) );
XtFree((char *)managed_seps);
XtFree((char *)unmanaged_seps);
}
/* Function Name: CreateSeparator
* Description: Creates a separator widget.
* Arguments: child - the child that wants a sep. to be created for it.
* Returns: none.
*/
static void
CreateSeparator(Widget child)
{
XmPanedWidget pw = (XmPanedWidget) XtParent(child);
Arg args[10];
Cardinal num_args = 0;
if (PaneInfo(child)->separator != NULL)
return;
XtSetArg(args[num_args], XmNborderWidth, 0); num_args++;
XtSetArg(args[num_args], XmNhighlightThickness, 0); num_args++;
XtSetArg(args[num_args], XmNseparatorType, XmSHADOW_ETCHED_IN); num_args++;
XtSetArg(args[num_args], XmNmargin, 0); num_args++;
XtSetArg(args[num_args], XmNnavigationType, XmNONE); num_args++;
XtSetArg(args[num_args], XmNisAPane, False); num_args++;
if (IsVert(pw)) {
XtSetArg(args[num_args], XmNorientation, XmHORIZONTAL); num_args++;
XtSetArg(args[num_args], XmNwidth, pw->core.width); num_args++;
} else {
XtSetArg(args[num_args], XmNorientation, XmVERTICAL); num_args++;
XtSetArg(args[num_args], XmNheight, pw->core.height); num_args++;
}
PaneInfo(child)->separator = XtCreateWidget("separator",
xmSeparatorWidgetClass,
(Widget)pw, args, num_args);
}
/* Function Name: CreateSash
* Description: Creates a sash widget.
* Arguments: child - the child that wants a sash to be created for it.
* Returns: none.
*/
static void
CreateSash(Widget child)
{
XmPanedWidget pw = (XmPanedWidget) XtParent(child);
Arg arglist[20];
Cardinal num_args = 0;
XtSetArg(arglist[num_args], XmNtranslations, XmPaned_sash_translations(pw));
num_args++;
XtSetArg(arglist[num_args], XmNwidth, XmPaned_sash_width(pw)); num_args++;
XtSetArg(arglist[num_args], XmNheight, XmPaned_sash_height(pw)); num_args++;
XtSetArg(arglist[num_args], XmNshadowThickness,
XmPaned_sash_shadow_thickness(pw)); num_args++;
XtSetArg(arglist[num_args], XmNtraversalOn, True); num_args++;
XtSetArg(arglist[num_args], XmNnavigationType, XmTAB_GROUP);
num_args++;
XtSetArg(arglist[num_args], XmNunitType, XmPIXELS); num_args++;
XtSetArg(arglist[num_args], XmNisAPane, False); num_args++;
PaneInfo(child)->sash = XtCreateWidget("sash", xmSashWidgetClass,
(Widget)pw, arglist, num_args);
XtAddCallback(PaneInfo(child)->sash, XmNcallback,
HandleSash, (XtPointer) child);
}
/* Function Name: GetGCs
* Description: Gets new GC's.
* Arguments: w - the paned widget.
* Returns: none.
*/
static void
GetGCs(Widget w)
{
XmPanedWidget pw = (XmPanedWidget) w;
XtGCMask valuemask;
XGCValues values;
/*
* Draw Track lines (animate pane borders) in foreground color ^ bg color.
*/
values.function = GXinvert;
values.plane_mask = pw->manager.foreground ^ pw->core.background_pixel;
values.subwindow_mode = IncludeInferiors;
valuemask = GCPlaneMask | GCFunction | GCSubwindowMode;
XmPaned_flipgc(pw) = XtGetGC(w, valuemask, &values);
}
/* Function Name: ReleaseGCs
* Description: Releases all GC's associated with this widget.
* Arguments: w - the widget.
* Returns: none.
*/
static void
ReleaseGCs(Widget w)
{
XmPanedWidget pw = (XmPanedWidget)w;
XtReleaseGC( w, XmPaned_flipgc(pw) );
}
/* Function Name: SetChildrenPrefSizes.
* Description: Sets the preferred sizes of the children.
* Arguments: pw - the paned widget.
* off_size - query children based on this off size.
* use_off_size - If False then ignore the off size.
* only set the pref size if this is a new child.
* Returns: none.
*/
static void
SetChildrenPrefSizes(XmPanedWidget pw, Dimension off_size,
Boolean use_off_size, Boolean only_if_new)
{
Widget * childP;
Boolean vert = IsVert(pw);
XtWidgetGeometry request, reply;
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
Pane pane = PaneInfo(*childP);
if (only_if_new && pane->prefs_inited)
break;
pane->prefs_inited = True;
if (XmPaned_resize_children_to_pref(pw) || (pane->size == 0) ||
(pane->resize_to_pref))
{
if (pane->preferred_size != XmPanedAskChild) {
pane->wp_size = pane->preferred_size;
if (!use_off_size) {
(void) XtQueryGeometry(*childP, NULL, &reply);
pane->wp_off_size = GetRequestInfo(&reply, !vert);
}
}
else {
request.request_mode = 0;
if (use_off_size) {
if( vert ) {
request.request_mode |= CWWidth;
request.width = off_size;
}
else {
request.request_mode |= CWHeight;
request.height = off_size;
}
}
(void) XtQueryGeometry(*childP, &request, &reply);
pane->wp_size = GetRequestInfo(&reply, vert);
if (!use_off_size)
pane->wp_off_size = GetRequestInfo(&reply, !vert);
}
pane->size = pane->wp_size;
}
else if (!use_off_size) {
(void) XtQueryGeometry(*childP, NULL, &reply);
pane->wp_off_size = GetRequestInfo(&reply, !vert);
}
}
}
/* Function Name: ResetSash
* Description: Turn on or off the sash depending on the state of
* the paned widget.
* Arguments: set - the widget this sash is associated with.
* Returns: none.
*/
static void
ResetSash(Widget set)
{
Pane pane = PaneInfo(set);
XmPanedWidget pw = (XmPanedWidget) XtParent(set);
if (HasSash(set) && (!pane->show_sash || ForceSashOff(pane))) {
XtDestroyWidget(pane->sash);
pane->sash = NULL;
}
else if (!HasSash(set) && pane->show_sash && !ForceSashOff(pane)) {
CreateSash(set);
if (XtIsRealized((Widget) pw)) {
/*
* If paned is unrealized this will happen automatically
* at realize time.
*/
if (XtIsManaged(set)) {
/*
* Since the paned is realized this will
* manage and realize the sash.
*/
XtManageChild(PaneInfo(set)->sash);
}
}
}
RefigureLocationsAndCommit((Widget) pw);
}
/************************************************************
*
* Stack Manipulation routines (Private).
*
************************************************************/
/* Function Name: PushPaneStack
* Description: Pushes a value onto the pane stack.
* Arguments: pw - the paned widget.
* pane - the pane that we are pushing.
* Returns: none.
*/
static void
PushPaneStack(XmPanedWidget pw, Pane pane)
{
PaneStack * stack = (PaneStack *) XtMalloc(sizeof(PaneStack));
stack->next = XmPaned_stack(pw);
stack->pane = pane;
stack->start_size = pane->size;
XmPaned_stack(pw) = stack;
}
/* Function Name: GetPaneStack
* Description: Gets the top value from the pane stack.
* Arguments: pw - the paned widget.
* shrink - TRUE if we want to shrink this pane,
* FALSE otherwise.
* ** RETURNED ** pane - the pane that we are popping.
* ** RETURNED ** start_size - the size that this pane started at.
* Returns: none.
*/
static void
GetPaneStack(XmPanedWidget pw, Boolean shrink, Pane *pane, int *start_size)
{
if (XmPaned_stack(pw) == NULL)
*pane = NULL;
else {
*pane = XmPaned_stack(pw)->pane;
*start_size = XmPaned_stack(pw)->start_size;
if (shrink != ((*pane)->size > *start_size))
*pane = NULL;
}
}
/* Function Name: PopPaneStack
* Description: Pops the top item off the pane stack.
* Arguments: pw - the paned widget.
* Returns: TRUE if this is not the last element on the stack.
*/
static Boolean
PopPaneStack(XmPanedWidget pw)
{
PaneStack * stack = XmPaned_stack(pw);
if (stack == NULL)
return(FALSE);
XmPaned_stack(pw) = stack->next;
XtFree((char*)stack);
return(XmPaned_stack(pw) != NULL);
}
/* Function Name: ClearPaneStack
* Description: removes all entries from the pane stack.
* Arguments: pw - the paned widget.
* Returns: none
*/
static void
ClearPaneStack(XmPanedWidget pw)
{
while(PopPaneStack(pw)) {} /* SUPPRESS 530 */
}
/************************************************************
*
* Semi-public routines.
*
************************************************************/
/* The Geometry Manager only allows changes after Realize if
* allow_resize is True in the constraints record.
*
* For vertically paned widgets:
*
* It only allows height changes, but offers the requested height
* as a compromise if both width and height changes were requested.
*
* For horizontal widgets the converse is true.
* As all good Geometry Managers should, we will return No if the
* request will have no effect; i.e. when the requestor is already
* of the desired geometry.
*/
static XtGeometryResult
GeometryManager(Widget w, XtWidgetGeometry *request, XtWidgetGeometry *reply)
{
XmPanedWidget pw = (XmPanedWidget) XtParent(w);
XtGeometryMask mask = request->request_mode;
Dimension old_size, old_wpsize, old_wp_off_size, old_paned_size;
Pane pane = PaneInfo(w);
register Boolean vert = IsVert(pw);
Dimension on_size, off_size;
XtGeometryResult result;
Boolean almost = FALSE;
/*
* If any of the following is true, disallow the geometry change.
*
* o The paned widget is realized and allow_resize is false for the pane.
* o The requested size is the same as the current size.
*/
if (!pane->is_a_pane) {
if (request->request_mode & CWWidth)
w->core.width = request->width;
if (request->request_mode & CWHeight)
w->core.height = request->height;
if (request->request_mode & CWX)
w->core.x = request->x;
if (request->request_mode & CWY)
w->core.y = request->y;
return(XtGeometryYes); /* allow any change to sashes or seps. */
}
if (!(request->request_mode & CWWidth))
request->width = w->core.width;
if (!(request->request_mode & CWHeight))
request->height = w->core.height;
if ((XtIsRealized((Widget)pw) && !pane->allow_resize) ||
((GetRequestInfo(request, vert) == PaneSize(w, vert)) &&
(GetRequestInfo(request, !vert) == PaneSize(w, !vert))))
{
return XtGeometryNo;
}
old_paned_size = PaneSize((Widget) pw, vert);
old_wpsize = pane->wp_size;
old_size = pane->size;
old_wp_off_size = pane->wp_off_size;
if (vert) {
if (mask & CWHeight)
pane->wp_size = pane->size = GetRequestInfo(request, vert);
if (mask & CWWidth)
pane->wp_off_size = GetRequestInfo(request, !vert);
}
else {
if (mask & CWWidth)
pane->wp_size = pane->size = GetRequestInfo(request, vert);
if (mask & CWHeight)
pane->wp_off_size = GetRequestInfo(request, !vert);
}
GetPrefSizes(pw, NULL, &off_size);
/*
* Ask our parent what would happen if we wanted to asked to be
* the a new size that will satisify the request of our child?
*/
result = AdjustPanedSize(pw, off_size, True, True, &on_size, &off_size);
/*
* Fool the Refigure Locations proc to thinking that we are
* a different on_size;
*/
if (result != XtGeometryNo) {
if (vert) {
pw->core.height = on_size + 2 * XmPaned_margin_height(pw);
}
else {
pw->core.width = on_size + 2 * XmPaned_margin_width(pw);
}
}
RefigureLocations(pw, PaneIndex(w), AnyPane);
/*
* Set up reply struct and reset core on_size.
*/
if (vert) {
pw->core.height = old_paned_size;
reply->width = off_size;
reply->height = pane->size;
}
else {
pw->core.width = old_paned_size;
reply->width = pane->size;
reply->height = off_size;
}
/*
* IF either of the following is true.
*
* o There was a "off_size" request and the new "off_size" is different
* from that requested.
* o There was no "off_size" request and the new "off_size" is different
*
* o The "on_size" we will allow is different from that requested.
*
* THEN: set almost
*/
if ( !((vert ? CWWidth : CWHeight) & mask))
{
if (vert)
{
request->width = w->core.width;
}
else
{
request->height = w->core.height;
}
}
almost = (mask & ~(CWWidth | CWHeight | XtCWQueryOnly));
almost |= GetRequestInfo(request, !vert) != GetRequestInfo(reply, !vert);
almost |= GetRequestInfo(request, vert) != GetRequestInfo(reply, vert);
if ( (mask & XtCWQueryOnly) || almost ) {
pane->wp_size = old_wpsize;
pane->wp_off_size = old_wp_off_size;
pane->size = old_size;
RefigureLocations(pw, PaneIndex(w), AnyPane);
reply->request_mode = CWWidth | CWHeight;
if (almost)
return XtGeometryAlmost;
}
else {
(void) AdjustPanedSize(pw, GetRequestInfo(reply, !vert),
True, False, NULL, NULL);
CommitNewLocations(pw, w); /* layout already refigured. */
}
return XtGeometryYes;
}
/* Function Name: Initialize
* Description: Called to initialize information specific
* to this widget.
* Arguments: req - what was originally requested.
* set - what will be created (our superclassed have
* already mucked with this)
* args, num_args - The arguments passed to
* the creation call.
* Returns: none.
*/
/* ARGSUSED */
static void
Initialize(Widget request, Widget set, ArgList args, Cardinal * num_args)
{
XmPanedWidget pw = (XmPanedWidget)set;
GetGCs( (Widget) pw);
XmPaned_recursively_called(pw) = False;
XmPaned_stack(pw) = NULL;
XmPaned_resize_children_to_pref(pw) = TRUE;
XmPaned_num_panes(pw) = 0;
XmPaned_increment_count(pw) = 0;
XmPaned_repane_status(pw) = NO_ADJUST;
XmPaned_num_slots(pw) = 0;
XmPaned_managed_children(pw) = NULL;
/*
* Undo the size change that XmManager did to us!!!
*/
pw->core.width = request->core.width;
pw->core.height = request->core.height;
}
/* Function Name: Realize
* Description: Called to realize this widget.
* Arguments: w - Widget to realize.
* valueMask, attributes - attributes to use when creating
* this widget's window.
* Returns: none.
*
* This overrides the Manager's frobbing with various values.
*/
static void
Realize(Widget w, Mask *valueMask, XSetWindowAttributes *attributes)
{
XmPanedWidget pw = (XmPanedWidget) w;
Widget * childP;
if (w->core.height == 0)
w->core.height = 1;
if (w->core.width == 0)
w->core.width = 1;
/*
* Set the cursor on the paned window.
*/
if ((attributes->cursor = XmPaned_cursor(pw)) != None)
*valueMask |= CWCursor;
XtCreateWindow (w, InputOutput, CopyFromParent, *valueMask, attributes);
/*
* Before we commit the new locations we need to realize all the panes and
* their sashs.
*/
for ( childP = XmPaned_managed_children(pw) ;
childP < XmPaned_managed_children(pw) + XmPaned_num_panes(pw);
childP++ ) {
XtRealizeWidget( *childP );
if (HasSash (*childP)) {
XtRealizeWidget( PaneInfo(*childP)->sash );
}
if (HasSep(*childP)) {
XtRealizeWidget( PaneInfo(*childP)->separator );
}
}
RefigureLocationsAndCommit(w);
XmPaned_resize_children_to_pref(pw) = FALSE;
} /* Realize */
/* Function Name: Destroy
* Description: Called when the widget is destroyed, cleans up.
* Arguments: w - the widget.
* Returns: none.
*/
static void
Destroy(Widget w)
{
XmPanedWidget pw = (XmPanedWidget)w;
ReleaseGCs(w);
ClearPaneStack(pw);
XtFree((XtPointer) XmPaned_managed_children(pw));
}
/* Function Name: InsertChild
* Description: called when a new child has been added to the paned window
* Arguments: w - the new child.
* Returns: none.
*/
static void
InsertChild(register Widget w)
{
XmPanedWidget pw = (XmPanedWidget) XtParent(w);
Pane pane = PaneInfo(w);
Arg arglist[10];
int num_args;
if (_XmGadgetWarning(w))
return;
/*
* Insert the child widget in the composite children list with the
* superclass insert_child routine.
*/
{
XtWidgetProc insert_child;
_XmProcessLock();
insert_child = SuperClass->composite_class.insert_child;
_XmProcessUnlock();
(*insert_child)(w);
}
/* These should be in Constraint init... */
pane->sash = NULL;
pane->separator = NULL;
pane->prefs_inited = False;
if (!IsPane(w))
return;
if(pane->min == pane->max) /* Motif behavior */
pane->show_sash = False;
/* A basic Sanity Check */
if (pane->min > pane->max)
{
/*
* This error will cause a crash later on
* lets make this error know to the programmer
* right off the bat, this will (should) never
* be "discovered" later after the thing has been used several
* times.
*/
fprintf(stderr, "XiError: XmPaned Widget resource conflict\n");
fprintf(stderr, "XmNpaneMax is less than XmNpaneMin.\n");
fprintf(stderr, "XmNpaneMax = %d XmNpaneMin = %d\n\n", pane->max, pane->min);
exit(EXIT_FAILURE);
}
/* Panes will be added in the order they are created, for now... */
if (pane->show_sash)
CreateSash(w);
if (XmPaned_separator_on(pw))
CreateSeparator(w);
pane->size = 0;
/* Motif navigation stuff */
num_args = 0;
XtSetArg(arglist[num_args], XmNnavigationType, XmTAB_GROUP);
num_args++;
XtSetValues(w, arglist, num_args);
} /* InsertChild */
/* Function Name: ConstraintDestroy
* Description: Called to clean up after child with constraints is
* destroyed.
* Arguments: w - the child that has been destroyed.
* Returns: none.
*/
static void
ConstraintDestroy(Widget w)
{
/* Remove the subwidget info and destroy the sash */
if (IsPane(w)) {
if(HasSash(w))
XtDestroyWidget(PaneInfo(w)->sash);
if(HasSep(w))
XtDestroyWidget(PaneInfo(w)->separator);
}
} /* DeleteChild */
/**********************************************************************
*
* ReManageChildren
* This procedure will be called by the ChangeManged procedure
* It will reassemble the currently managed children into the
* "paned_window.managed_children" list.
*
********************************************************************/
static void
ReManageChildren(XmPanedWidget pw)
{
int i;
XmPaned_num_panes(pw) = 0;
for (i = 0; i < pw->composite.num_children; i++) {
if(XtIsManaged(pw->composite.children[i]) &&
IsPane(pw->composite.children[i]) )
{
Pane pane = PaneInfo(pw->composite.children[i]);
/* expand our storage area if needed */
if ((XmPaned_num_panes(pw) + 1) > XmPaned_num_slots(pw)) {
XmPaned_num_slots(pw) += BLOCK;
XmPaned_managed_children(pw) = (WidgetList)
XtRealloc ((XtPointer) XmPaned_managed_children(pw),
(XmPaned_num_slots(pw) * sizeof(Widget)));
}
#ifndef POSITION_IMPLEMENTED
/*
* This is a hack to get around position change not
* being implemented yet.
*/
if (HasSash(pw->composite.children[i]))
PaneInfo(pane->sash)->position = XmPaned_num_panes(pw);
pane->position = XmPaned_num_panes(pw);
#endif
XmPaned_managed_children(pw)[XmPaned_num_panes(pw)++] =
pw->composite.children[i];
}
}
}
/* Function Name: ChangeManaged
* Description: Called when one of the children changes management state.
* Arguments: w - the paned widget.
* Returns: none.
*/
static void
ChangeManaged(Widget w)
{
XmPanedWidget pw = (XmPanedWidget)w;
if (XmPaned_recursively_called(pw)++) return;
ManageAndUnmanageSashs(pw);
XmPaned_recursively_called(pw) = False;
ReManageChildren(pw);
/*
* ForAllPanes can now be used.
*/
ResetSize(pw, PaneSize(w, IsVert(pw)) <= 1);
/* for Motif navigation */
XmeNavigChangeManaged((Widget)pw);
} /* ChangeManaged */
/* Function Name: ResetSize
* Description: Resets the size of the paned widget to its preferred.
* Checks are made on all children to attempt to size
* then to the preferred.
* Arguments: pw - the paned widget.
* recalc_off_size - If this is true the do not
* use the current off size, recalc for
* a new value.
* Returns: none.
*/
static void
ResetSize(XmPanedWidget pw, Boolean recalc_off_size)
{
Boolean test, vert = IsVert(pw);
Dimension off_size;
/*
* Must be called once before GetPrefSizes.
*/
test = !XtIsRealized((Widget) pw) || recalc_off_size;
SetChildrenPrefSizes(pw, 0, False, test);
if (recalc_off_size || XtIsRealized((Widget) pw)) {
GetPrefSizes(pw, NULL, &off_size);
}
else {
off_size = PaneSize( (Widget) pw, !vert );
if (vert)
off_size -= 2 * XmPaned_margin_width(pw);
else
off_size -= 2 * XmPaned_margin_height(pw);
}
/*
* This gets the real off size our parent will allow, may be
* quite different than what we want.
*/
if (XtIsRealized((Widget) pw))
{
(void) AdjustPanedSize(pw, off_size, True, True, NULL, &off_size);
}
/*
* Given the new off size, ask our children what size they would like
* to be, and reconfigure ourself to the new size.
*/
SetChildrenPrefSizes(pw, off_size, True, False);
(void) AdjustPanedSize(pw, off_size,
XtIsRealized((Widget) pw), False, NULL, NULL);
RefigureLocationsAndCommit((Widget) pw);
}
/* Function Name: Resize
* Description: The paned widget's resize proc.
* Arguments: w - the paned widget.
* Returns: none.
*/
static void
Resize(Widget w)
{
XmPanedWidget pw = (XmPanedWidget)w;
int size;
size = PaneSize(w, !IsVert(pw));
if (IsVert(pw))
size -= 2 * XmPaned_margin_width(pw);
else
size -= 2 * XmPaned_margin_height(pw);
SetChildrenPrefSizes((XmPanedWidget) w, size, True, False);
if (!XtIsRealized(w))
return;
RefigureLocationsAndCommit(w);
}
/* Function Name: SetValues
* Description: Called when some widget data needs to be modified on-
* the-fly.
* Arguments: old - the current (old) widget values.
* request - before superclassed have changed things.
* set - what will acutally be the new values.
* args, num_args - The arguments passed to the set
* values call.
* Returns: none
*/
/* ARGSUSED */
static Boolean
SetValues(Widget old, Widget request, Widget set,
ArgList args, Cardinal * num_args)
{
XmPanedWidget old_pw = (XmPanedWidget) old;
XmPanedWidget set_pw = (XmPanedWidget) set;
int num_panes = XmPaned_num_panes(set_pw);
register Widget *childP;
Boolean refigure = False, commit = False;
Arg sargs[3];
int num_sargs = 0;
/*
* Manager is getting in the way, fix it.
*/
if (request->core.height == 0)
set->core.height = request->core.height;
if (request->core.width == 0)
set->core.width = request->core.width;
if (request->core.border_width == 0)
set->core.border_width = request->core.border_width;
if ((XmPaned_cursor(old_pw) != XmPaned_cursor(set_pw)) && XtIsRealized(set))
XDefineCursor(XtDisplay(set), XtWindow(set), XmPaned_cursor(set_pw));
if ((old_pw->manager.foreground != set_pw->manager.foreground) ||
(old_pw->core.background_pixel != set_pw->core.background_pixel))
{
ReleaseGCs(old);
GetGCs(set);
}
/* If we change sep status we must do for all seps */
if (XmPaned_separator_on(old_pw) != XmPaned_separator_on(set_pw))
{
if (XmPaned_separator_on(set_pw)) {
WidgetList sep_children;
Cardinal num_separators = 0;
/* This should be more than enough space */
sep_children = (WidgetList) XtMalloc(num_panes * sizeof(Widget));
for ( childP = XmPaned_managed_children(set_pw) ;
childP < XmPaned_managed_children(set_pw)
+ XmPaned_num_panes(set_pw);
childP++ ) {
CreateSeparator(*childP);
sep_children[num_separators] = PaneInfo(*childP)->separator;
num_separators++;
}
XtManageChildren((WidgetList) sep_children, num_separators);
XtFree((char *)sep_children);
commit = True;
}
else {
for ( childP = XmPaned_managed_children(set_pw) ;
childP < XmPaned_managed_children(set_pw)
+ XmPaned_num_panes(set_pw);
childP++ ) {
Pane pane = PaneInfo(*childP);
if (pane->separator != NULL) {
XtDestroyWidget(pane->separator);
pane->separator = NULL;
}
}
}
}
if (IsVert(old_pw) != IsVert(set_pw)) {
Cardinal num_sep_args;
Arg sep_args[10];
num_sep_args = 0;
if (IsVert(set_pw))
XtSetArg(sep_args[num_sep_args], XmNorientation, XmHORIZONTAL);
else
XtSetArg(sep_args[num_sep_args], XmNorientation, XmVERTICAL);
num_sep_args++;
ForAllChildren(set_pw, childP) {
Pane pane = PaneInfo(*childP);
if (pane->separator != NULL) {
XtSetValues(pane->separator, sep_args, num_sep_args);
}
}
XmPaned_resize_children_to_pref(set_pw) = TRUE;
ResetSize(set_pw, TRUE);
XmPaned_resize_children_to_pref(set_pw) = FALSE;
return(TRUE);
}
/* Build an arg list for global changes to the sashs */
if (XmPaned_sash_width(old_pw) != XmPaned_sash_width(set_pw)) {
XtSetArg(sargs[num_sargs], XmNwidth, XmPaned_sash_width(set_pw));
num_sargs++;
refigure = True;
}
if (XmPaned_sash_height(old_pw) != XmPaned_sash_height(set_pw)) {
XtSetArg(sargs[num_sargs], XmNheight, XmPaned_sash_height(set_pw));
num_sargs++;
refigure = True;
}
if (XmPaned_sash_shadow_thickness(old_pw) !=
XmPaned_sash_shadow_thickness(set_pw))
{
XtSetArg(sargs[num_sargs], XmNshadowThickness,
XmPaned_sash_shadow_thickness(set_pw)); num_sargs++;
}
if (XmPaned_sash_translations(old_pw) != XmPaned_sash_translations(set_pw))
{
XmeWarning(set, XmNstaticTranslationsMsg);
XmPaned_sash_translations(set_pw) = XmPaned_sash_translations(old_pw);
}
if (num_sargs != 0) {
for ( childP = XmPaned_managed_children(set_pw) ;
childP < XmPaned_managed_children(set_pw)
+ XmPaned_num_panes(set_pw);
childP++ )
if (HasSash(*childP))
XtSetValues(PaneInfo(*childP)->sash, sargs, num_sargs);
refigure = True;
}
if ((XmPaned_internal_bw(old_pw) != XmPaned_internal_bw(set_pw)) ||
(XmPaned_margin_width(old_pw) != XmPaned_margin_width(set_pw)) ||
(XmPaned_margin_height(old_pw)!= XmPaned_margin_height(set_pw)))
{
refigure = True;
}
if ( (XmPaned_sash_indent(old_pw) != XmPaned_sash_indent(set_pw)) &&
(XtIsRealized(set)) )
{
commit = True;
}
if (refigure) {
Dimension off_size = PaneSize((Widget) old_pw, !IsVert(old_pw));
if (IsVert(old_pw))
off_size -= 2 * XmPaned_margin_width(old_pw);
else
off_size -= 2 * XmPaned_margin_height(old_pw);
(void) AdjustPanedSize(set_pw, off_size, True, False, NULL, NULL);
RefigureLocations(set_pw, NO_INDEX, AnyPane);
commit = True;
}
if (commit)
CommitNewLocations(set_pw, NULL);
return (False);
} /* SetValues */
/* Function Name: QueryGeometry
* Description: Called when my parent wants to know my preferred size.
* Arguments: w - the widget to check.
* intended - parent imposed geometry.
* preferred - what I would like.
* Returns: status.
*/
static XtGeometryResult
QueryGeometry(Widget w, XtWidgetGeometry *request,
XtWidgetGeometry *preferred)
{
XmPanedWidget pw = (XmPanedWidget) w;
Dimension on_size, off_size;
GetPrefSizes(pw, &on_size, &off_size);
if (IsVert(pw)) {
preferred->width = off_size + 2 * XmPaned_margin_width(pw);
preferred->height = on_size + 2 * XmPaned_margin_height(pw);
}
else {
preferred->width = on_size + 2 * XmPaned_margin_width(pw);
preferred->height = off_size + 2 * XmPaned_margin_height(pw);
}
return(_XmHWQuery(w, request, preferred));
}
/* Function Name: PaneSetValues
* Description: Called when some constraint data needs to be modified
* on-the-fly.
* Arguments: old - the current (old) widget values.
* request - before superclassed have changed things.
* new - what will acutally be the new values.
* args, num_args - The arguments passed to
* the child's setvalues call.
* Returns: none
*/
/* ARGSUSED */
static Boolean
PaneSetValues(Widget old, Widget request, Widget new,
ArgList args, Cardinal * num_args)
{
Pane old_pane = PaneInfo(old);
Pane new_pane = PaneInfo(new);
Boolean sash_reset = False;
/* Check for new min and max. */
if ((old_pane->min != new_pane->min) || (old_pane->max != new_pane->max)) {
if (ForceSashOff(old_pane) != ForceSashOff(new_pane))
sash_reset = True;
}
if (old_pane->show_sash != new_pane->show_sash)
sash_reset = True;
if (sash_reset)
ResetSash(new);
return(False);
}
/************************************************************
*
* Public routines.
*
************************************************************/
/* Function Name: XmPanedGetPanes
* Description: Returns the number of panes in the paned widget.
* Arguments: w - the paned widget.
* panes - the list of all panes contained in this widget.
* num - the number of panes.
* Returns: the number of panes in the paned widget.
*/
int
XmPanedGetPanes(Widget w, WidgetList *panes, int *num)
{
XmPanedWidget pw = (XmPanedWidget) w;
_XmWidgetToAppContext(w);
_XmAppLock(app);
*num = XmPaned_num_panes(pw);
*panes = XmPaned_managed_children(pw);
_XmAppUnlock(app);
return(*num);
}
/* Function Name: XmCreatePaned
* Description: Creation Routine for UIL and ADA.
* Arguments: parent - the parent widget.
* name - the name of the widget.
* args, num_args - the number and list of args.
* Returns: The created widget.
*/
Widget
XmCreatePaned(Widget parent, String name, ArgList args, Cardinal num_args)
{
return(XtCreateWidget(name, xmPanedWidgetClass, parent, args, num_args));
}