Paned.c

Go to the documentation of this file.
00001 /* $XConsortium: Paned.c,v 1.27 94/04/17 20:12:28 kaleb Exp $ */
00002 
00003 /***********************************************************
00004 
00005 Copyright (c) 1987, 1988, 1994  X Consortium
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023 
00024 Except as contained in this notice, the name of the X Consortium shall not be
00025 used in advertising or otherwise to promote the sale, use or other dealings
00026 in this Software without prior written authorization from the X Consortium.
00027 
00028 
00029 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
00030 
00031                         All Rights Reserved
00032 
00033 Permission to use, copy, modify, and distribute this software and its 
00034 documentation for any purpose and without fee is hereby granted, 
00035 provided that the above copyright notice appear in all copies and that
00036 both that copyright notice and this permission notice appear in 
00037 supporting documentation, and that the name of Digital not be
00038 used in advertising or publicity pertaining to distribution of the
00039 software without specific, written prior permission.  
00040 
00041 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00042 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00043 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00044 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00045 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00046 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00047 SOFTWARE.
00048 
00049 ******************************************************************/
00050 
00051 /*
00052  * Paned.c - Paned Composite Widget.
00053  *
00054  * Updated and significantly modified from the Athena VPaned Widget.
00055  *
00056  * Date:    March 1, 1989
00057  *
00058  * By:      Chris D. Peterson
00059  *          MIT X Consortium
00060  *          kit@expo.lcs.mit.edu
00061  */
00062 
00063 #include <X11/IntrinsicP.h>
00064 #include <X11/cursorfont.h>
00065 #include <X11/StringDefs.h>
00066 
00067 #include <X11/Xmu/Misc.h>
00068 #include <X11/Xmu/Converters.h>
00069 
00070 #include <X11/Xaw3d/XawInit.h>
00071 #include <X11/Xaw3d/Grip.h>
00072 #include <X11/Xaw3d/PanedP.h>
00073 
00074 /* I don't know why Paned.c calls _XawImCallVendorShellExtResize, but... */
00075 #include <X11/Xaw3d/XawImP.h> 
00076 
00077 #include <ctype.h>
00078 
00079 typedef enum {UpLeftPane = 'U', LowRightPane = 'L', 
00080               ThisBorderOnly = 'T', AnyPane = 'A' } Direction;
00081 
00082 #define NO_INDEX -100
00083 #define IS_GRIP  NULL
00084 
00085 #define PaneInfo(w)     ((Pane)(w)->core.constraints)
00086 #define HasGrip(w)      (PaneInfo(w)->grip != NULL)
00087 #define IsPane(w)       ((w)->core.widget_class != gripWidgetClass)
00088 #define PaneIndex(w)    (PaneInfo(w)->position)
00089 #define IsVert(w)       ( (w)->paned.orientation == XtorientVertical )
00090 
00091 #define ForAllPanes(pw, childP) \
00092   for ( (childP) = (pw)->composite.children ; \
00093         (childP) < (pw)->composite.children + (pw)->paned.num_panes ; \
00094         (childP)++ )
00095 
00096 #define ForAllChildren(pw, childP) \
00097   for ( (childP) = (pw)->composite.children ; \
00098         (childP) < (pw)->composite.children + (pw)->composite.num_children ; \
00099         (childP)++ )
00100 
00101 /*****************************************************************************
00102  *
00103  * Full instance record declaration
00104  *
00105  ****************************************************************************/
00106 
00107 static char defGripTranslations[] =
00108     "<Btn1Down>:                GripAction(Start, UpLeftPane) \n\
00109      <Btn2Down>:                GripAction(Start, ThisBorderOnly) \n\
00110      <Btn3Down>:                GripAction(Start, LowRightPane) \n\
00111      <Btn1Motion>:              GripAction(Move, UpLeft) \n\
00112      <Btn2Motion>:              GripAction(Move, ThisBorder) \n\
00113      <Btn3Motion>:              GripAction(Move, LowRight) \n\
00114      Any<BtnUp>:                GripAction(Commit)";
00115 
00116 #define offset(field) XtOffsetOf(PanedRec, paned.field)
00117 
00118 static XtResource resources[] = {
00119     {XtNinternalBorderColor, XtCBorderColor, XtRPixel, sizeof(Pixel),
00120          offset(internal_bp), XtRString, 
00121          (XtPointer) XtDefaultForeground},
00122     {XtNinternalBorderWidth, XtCBorderWidth, XtRDimension, sizeof(Dimension),
00123          offset(internal_bw), XtRImmediate, (XtPointer) 1},
00124     {XtNgripIndent, XtCGripIndent, XtRPosition, sizeof(Position),
00125          offset(grip_indent), XtRImmediate, (XtPointer) 10},
00126     {XtNrefigureMode, XtCBoolean, XtRBoolean, sizeof(Boolean),
00127          offset(refiguremode), XtRImmediate, (XtPointer) TRUE},
00128     {XtNgripTranslations, XtCTranslations, XtRTranslationTable,
00129          sizeof(XtTranslations),
00130          offset(grip_translations), XtRString, (XtPointer)defGripTranslations},
00131     {XtNorientation,  XtCOrientation, XtROrientation, sizeof(XtOrientation),
00132          offset(orientation), XtRImmediate, (XtPointer) XtorientVertical},
00133 
00134     /* Cursors - both horiz and vertical have to work. */
00135 
00136     {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
00137          offset(cursor), XtRImmediate, None},
00138     {XtNgripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00139          offset(grip_cursor), XtRImmediate, None},
00140     {XtNverticalGripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00141          offset(v_grip_cursor), XtRString, "sb_v_double_arrow"},
00142     {XtNhorizontalGripCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00143          offset(h_grip_cursor), XtRString, "sb_h_double_arrow"},
00144 
00145     {XtNbetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00146          offset(adjust_this_cursor), XtRString, None},
00147     {XtNverticalBetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00148          offset(v_adjust_this_cursor), XtRString, "sb_left_arrow"},
00149     {XtNhorizontalBetweenCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00150          offset(h_adjust_this_cursor), XtRString, "sb_up_arrow"},
00151 
00152     {XtNupperCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00153          offset(adjust_upper_cursor), XtRString, "sb_up_arrow"},
00154     {XtNlowerCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00155          offset(adjust_lower_cursor), XtRString, "sb_down_arrow"},
00156     {XtNleftCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00157          offset(adjust_left_cursor), XtRString, "sb_left_arrow"},
00158     {XtNrightCursor, XtCCursor, XtRCursor, sizeof(Cursor),
00159          offset(adjust_right_cursor), XtRString, "sb_right_arrow"},
00160 };
00161 
00162 #undef offset
00163 
00164 #define offset(field) XtOffsetOf(PanedConstraintsRec, paned.field)
00165 
00166 static XtResource subresources[] = {
00167     {XtNallowResize, XtCBoolean, XtRBoolean, sizeof(Boolean),
00168          offset(allow_resize), XtRImmediate, (XtPointer) FALSE},
00169     {XtNposition, XtCPosition, XtRInt, sizeof(int),
00170          offset(position), XtRImmediate, (XtPointer) 0},
00171     {XtNmin, XtCMin, XtRDimension, sizeof(Dimension),
00172          offset(min), XtRImmediate, (XtPointer) PANED_GRIP_SIZE},
00173     {XtNmax, XtCMax, XtRDimension, sizeof(Dimension),
00174          offset(max), XtRImmediate, (XtPointer) ~0},
00175     {XtNpreferredPaneSize, XtCPreferredPaneSize, XtRDimension,
00176          sizeof(Dimension), offset(preferred_size), 
00177          XtRImmediate, (XtPointer) PANED_ASK_CHILD},
00178     {XtNresizeToPreferred, XtCBoolean, XtRBoolean, sizeof(Boolean),
00179          offset(resize_to_pref), XtRImmediate, (XtPointer) FALSE},
00180     {XtNskipAdjust, XtCBoolean, XtRBoolean, sizeof(Boolean),
00181          offset(skip_adjust), XtRImmediate, (XtPointer) FALSE},
00182     {XtNshowGrip, XtCShowGrip, XtRBoolean, sizeof(Boolean),
00183          offset(show_grip), XtRImmediate, (XtPointer) TRUE},
00184 };
00185 
00186 #undef offset
00187 
00188 static void ClassInitialize(), Initialize();
00189 static void Realize(), Resize();
00190 static void Redisplay();
00191 static void GetGCs(), ReleaseGCs();
00192 static void RefigureLocationsAndCommit();
00193 static Boolean SetValues();
00194 static XtGeometryResult GeometryManager();
00195 static void ChangeManaged();
00196 static void InsertChild();
00197 static void DeleteChild();
00198 static Boolean PaneSetValues();
00199 static Dimension PaneSize(), GetRequestInfo();
00200 static Boolean SatisfiesRule1(), SatisfiesRule2(), SatisfiesRule3();
00201 
00202 static void PushPaneStack();
00203 static void GetPaneStack();
00204 static Boolean PopPaneStack();
00205 static void ClearPaneStack();
00206 
00207 #define SuperClass ((ConstraintWidgetClass)&constraintClassRec)
00208 
00209 PanedClassRec panedClassRec = {
00210    {
00211 /* core class fields */
00212     /* superclass         */   (WidgetClass) SuperClass,
00213     /* class name         */   "Paned",
00214     /* size               */   sizeof(PanedRec),
00215     /* class_initialize   */   ClassInitialize,
00216     /* class_part init    */   NULL,
00217     /* class_inited       */   FALSE,
00218     /* initialize         */   Initialize,
00219     /* initialize_hook    */   NULL,
00220     /* realize            */   Realize,
00221     /* actions            */   NULL,
00222     /* num_actions        */   0,
00223     /* resources          */   resources,
00224     /* resource_count     */   XtNumber(resources),
00225     /* xrm_class          */   NULLQUARK,
00226     /* compress_motion    */   TRUE,
00227     /* compress_exposure  */   TRUE,
00228     /* compress_enterleave*/   TRUE,
00229     /* visible_interest   */   FALSE,
00230     /* destroy            */   ReleaseGCs,
00231     /* resize             */   Resize,
00232     /* expose             */   Redisplay,
00233     /* set_values         */   SetValues,
00234     /* set_values_hook    */   NULL,
00235     /* set_values_almost  */   XtInheritSetValuesAlmost,
00236     /* get_values_hook    */   NULL,
00237     /* accept_focus       */   NULL,
00238     /* version            */   XtVersion,
00239     /* callback_private   */   NULL,
00240     /* tm_table           */   NULL,
00241     /* query_geometry     */   XtInheritQueryGeometry,
00242     /* display_accelerator*/   XtInheritDisplayAccelerator,
00243     /* extension          */   NULL
00244    }, {
00245 /* composite class fields */
00246     /* geometry_manager   */   GeometryManager,
00247     /* change_managed     */   ChangeManaged,
00248     /* insert_child       */   InsertChild,
00249     /* delete_child       */   DeleteChild,
00250     /* extension          */   NULL
00251    }, {
00252 /* constraint class fields */
00253     /* subresources       */   subresources,
00254     /* subresource_count  */   XtNumber(subresources),
00255     /* constraint_size    */   sizeof(PanedConstraintsRec),
00256     /* initialize         */   NULL,
00257     /* destroy            */   NULL,
00258     /* set_values         */   PaneSetValues,
00259     /* extension          */   NULL
00260    }
00261 };
00262 
00263 WidgetClass panedWidgetClass = (WidgetClass) &panedClassRec;
00264 
00265 /* For compatibility. */
00266 WidgetClass vPanedWidgetClass = (WidgetClass) &panedClassRec;
00267 
00268 /***********************************************************
00269  *
00270  * Private Functions.
00271  *
00272  ************************************************************/
00273 
00274 /*      Function Name: AdjustPanedSize
00275  *      Description: Adjusts the size of the pane.
00276  *      Arguments: pw - the paned widget to adjust.
00277  *                 off_size - the new off_size to use.
00278  *                 result_ret - result of query ** RETURNED **
00279  *                 on_size_ret - the new on_size ** RETURNED **
00280  *                 off_size_ret - the new off_size ** RETURNED **
00281  *      Returns: the amount of change in size.
00282  */
00283 
00284 static void
00285 AdjustPanedSize(pw, off_size, result_ret, on_size_ret, off_size_ret)
00286 PanedWidget pw;
00287 Dimension off_size;
00288 XtGeometryResult * result_ret;
00289 Dimension * on_size_ret, * off_size_ret;
00290 {
00291     Dimension old_size = PaneSize( (Widget) pw, IsVert(pw));
00292     Dimension newsize = 0;
00293     Widget * childP;
00294     XtWidgetGeometry request, reply;
00295     request.request_mode = CWWidth | CWHeight;
00296 
00297     ForAllPanes(pw, childP) {
00298         int size = Max(PaneInfo(*childP)->size, (int)PaneInfo(*childP)->min);
00299         AssignMin(size, (int) PaneInfo(*childP)->max);
00300         newsize += size + pw->paned.internal_bw;
00301     }
00302     newsize -= pw->paned.internal_bw;
00303 
00304     if (newsize < 1) newsize = 1;
00305 
00306     if ( IsVert(pw) ) {
00307         request.width = off_size;
00308         request.height = newsize;
00309     }
00310     else {
00311         request.width = newsize;
00312         request.height = off_size;
00313     }
00314 
00315     if (result_ret != NULL) {
00316       request.request_mode |= XtCWQueryOnly;
00317 
00318       *result_ret = XtMakeGeometryRequest( (Widget) pw, &request, &reply );
00319       _XawImCallVendorShellExtResize( (Widget) pw );
00320 
00321       if ( (newsize == old_size) || (*result_ret == XtGeometryNo) ) {
00322           *on_size_ret = old_size;
00323           *off_size_ret = off_size;
00324           return;
00325       }
00326       if (*result_ret != XtGeometryAlmost) {
00327           *on_size_ret = GetRequestInfo( &request, IsVert(pw) );
00328           *off_size_ret = GetRequestInfo( &request, !IsVert(pw) );
00329           return;
00330       }
00331       *on_size_ret = GetRequestInfo( &reply, IsVert(pw) );
00332       *off_size_ret = GetRequestInfo( &reply, !IsVert(pw) );
00333       return;
00334     }
00335 
00336     if (newsize == old_size) return;
00337 
00338     if (XtMakeGeometryRequest( (Widget) pw,
00339                               &request, &reply) == XtGeometryAlmost)
00340         XtMakeGeometryRequest( (Widget) pw, &reply, &request);
00341 }
00342 
00343 /*      Function Name: PaneSize
00344  *      Description: returns the width or height of the pane depending
00345  *                   upon the orientation we are using.
00346  *      Arguments: w - and widget.
00347  *                 vertical - TRUE if this is vertically oriented pane.
00348  *      Returns: the size requested
00349  *
00350  *      vertical  - return height
00351  *      !vertical - return width
00352  */
00353 
00354 static Dimension
00355 PaneSize(w, vertical)
00356 Widget w;
00357 Boolean vertical;
00358 {
00359     if (vertical) return (w->core.height);
00360     return (w->core.width);
00361 }
00362 
00363 /*      Function Name: GetRequestInfo
00364  *      Description: returns request information.
00365  *      Arguments:  geo_struct - a geometry struct to get information out of.
00366  *                  vert - TRUE if this is a vertical paned widget.
00367  *      Returns: the request information.
00368  */
00369 
00370 static Dimension
00371 GetRequestInfo(geo_struct, vert)
00372 XtWidgetGeometry * geo_struct;
00373 Boolean vert;
00374 {
00375     if ( vert ) return ( (Dimension) geo_struct->height);
00376     return ( (Dimension) geo_struct->width);
00377 }
00378 
00379 /*      Function Name: ChoosePaneToResize.
00380  *      Description: This function chooses a pane to resize.
00381  *                   They are chosen using the following rules:
00382  *
00383  *                   1) size < max && size > min
00384  *                   2) skip adjust == FALSE
00385  *                   3) widget not its prefered height &&
00386  *                      this change will bring it closer &&
00387  *                      The user has not resized this pane.
00388  *           
00389  *                   If no widgets are found that fits all the rules then
00390  *                      rule #3 is broken.
00391  *                   If there are still no widgets found than
00392  *                      rule #2 is broken.
00393  *                   Rule #1 is never broken.
00394  *                   If no widgets are found then NULL is returned.
00395  * 
00396  *      Arguments: pw - the paned widget.
00397  *                 paneindex - the index of the current pane.
00398  *                 dir - direction to search first.
00399  *                 shrink - TRUE if we need to shrink a pane, FALSE otherwise.
00400  *      Returns: pane to resize or NULL.
00401  */
00402 
00403 static Pane
00404 ChoosePaneToResize(pw, paneindex, dir, shrink)
00405 PanedWidget pw;
00406 int paneindex;
00407 Direction dir;
00408 Boolean shrink;
00409 {
00410     Widget *childP;
00411     int rules = 3;
00412     Direction _dir = dir;
00413     int _index = paneindex;
00414 
00415     if ( (paneindex == NO_INDEX) || (dir == AnyPane) ) {  /* Use defaults. */
00416       _dir = LowRightPane;              /* Go up. - really. */
00417       _index = pw->paned.num_panes - 1; /* Start the last pane, and work
00418                                            backwards. */
00419     }
00420     childP = pw->composite.children + _index;
00421 
00422     /* CONSTCOND */
00423     while(TRUE) {
00424         Pane pane = PaneInfo(*childP);
00425         
00426         if ( (rules < 3 || SatisfiesRule3(pane, shrink)) &&
00427              (rules < 2 || SatisfiesRule2(pane))         &&
00428              (SatisfiesRule1(pane, shrink))              &&
00429              ((paneindex != PaneIndex(*childP)) || (dir == AnyPane)) )
00430             return(pane);
00431 
00432 /*
00433  * This is counter-intuitive, but if we are resizing the pane
00434  * above the grip we want to choose a pane below the grip to lose,
00435  * and visa-versa.
00436  */
00437 
00438         if (_dir == LowRightPane) --childP; else ++childP;
00439 
00440 /*
00441  * If we have come to and edge then reduce the rule set, and try again.
00442  * If we are reduced the rules to none, then return NULL.
00443  */
00444         
00445         if ( (childP - pw->composite.children < 0) ||
00446              (childP - pw->composite.children >= pw->paned.num_panes) ) {
00447             if (--rules < 1)  /* less strict rules. */
00448               return(NULL);
00449             childP = pw->composite.children + _index;
00450         }
00451     }
00452 }
00453 
00454 /*      Function Name: StatisfiesRule1
00455  *      Description: check for to see if this pane satisfies rule 1.
00456  *      Arguments: pane - the pane to check.
00457  *                 shrink -TRUE if we want to shrink this pane, FALSE otherwise
00458  *      Returns: TRUE if the rule is satisfied.
00459  */
00460 
00461 static Boolean
00462 SatisfiesRule1(pane, shrink)
00463 Pane pane;
00464 Boolean shrink;
00465 {
00466   return( (shrink && (pane->size != pane->min)) ||
00467           (!shrink && (pane->size != pane->max)) );
00468 }
00469  
00470 /*      Function Name: StatisfiesRule2
00471  *      Description: check for to see if this pane satisfies rule 2.
00472  *      Arguments: pane - the pane to check.
00473  *      Returns: TRUE if the rule is satisfied.
00474  */
00475 
00476 static Boolean
00477 SatisfiesRule2(pane)
00478 Pane pane;
00479 {
00480   return(!pane->skip_adjust || pane->paned_adjusted_me);
00481 }
00482  
00483 /*      Function Name: StatisfiesRule3
00484  *      Description: check for to see if this pane satisfies rule 3.
00485  *      Arguments: pane - the pane to check.
00486  *                 shrink -TRUE if we want to shrink this pane, FALSE otherwise
00487  *      Returns: TRUE if the rule is satisfied.
00488  */
00489 
00490 static Boolean
00491 SatisfiesRule3(pane, shrink)
00492 Pane pane;
00493 Boolean shrink;
00494 {
00495   return ( pane->paned_adjusted_me &&
00496            ( (shrink && ((int)pane->wp_size <= pane->size)) ||
00497              (!shrink && ((int)pane->wp_size >= pane->size))) );
00498 }
00499 
00500 /*      Function Name: LoopAndRefigureChildren.
00501  *      Description: if we are resizing either the UpleftPane or LowRight Pane
00502  *                   loop through all the children to see if any will allow us
00503  *                   to resize them.
00504  *      Arguments: pw - the paned widget.
00505  *                 paneindex - the number of the pane border we are moving.
00506  *                 dir - the pane to move (either UpLeftPane or LowRightPane).
00507  *                 sizeused - current amount of space used. 
00508  *                            THIS VALUE IS USED AND RETURNED.
00509  *      Returns: none.
00510  */
00511 
00512 static void
00513 LoopAndRefigureChildren(pw, paneindex, dir, sizeused)
00514 PanedWidget pw;
00515 int paneindex, *sizeused;
00516 Direction dir;
00517 {
00518     int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw));
00519     Boolean shrink = (*sizeused > pane_size);
00520 
00521     if (dir == LowRightPane) paneindex++;
00522 
00523     while (*sizeused != pane_size) { /* While all panes do not fit properly. */
00524 /*
00525  * Choose a pane to resize.
00526  * First look on the Pane Stack, and then go hunting for another one.
00527  * If we fail to find a pane to resize then give up.
00528  */
00529         Pane pane;
00530         int start_size;
00531         Dimension old;
00532         Boolean rule3_ok = FALSE, from_stack = TRUE;
00533 
00534         GetPaneStack(pw, shrink, &pane, &start_size);
00535         if (pane == NULL) {
00536             pane = ChoosePaneToResize(pw, paneindex, dir, shrink);
00537             if (pane == NULL) 
00538                 return; /* no one to resize, give up. */
00539 
00540             rule3_ok = SatisfiesRule3(pane, shrink);
00541             from_stack = FALSE;
00542             PushPaneStack(pw, pane);
00543         }
00544 
00545 
00546 /*
00547  * Try to resize this pane so that all panes will fit, take min and max
00548  * into account.
00549  */
00550         old = pane->size;
00551         pane->size += pane_size - *sizeused;
00552 
00553         if (from_stack) {
00554             if (shrink) {
00555                 AssignMax(pane->size, start_size);
00556             }                   /* don't remove these braces. */
00557             else
00558                 AssignMin(pane->size, start_size);
00559 
00560             if (pane->size == start_size) (void) PopPaneStack(pw);
00561         }
00562         else if (rule3_ok) {
00563             if (shrink) {
00564                 AssignMax(pane->size, (int) pane->wp_size);
00565             }                   /* don't remove these braces. */
00566             else
00567                 AssignMin(pane->size, (int) pane->wp_size);
00568         }
00569 
00570         pane->paned_adjusted_me = (pane->size != pane->wp_size);
00571         AssignMax(pane->size, (int) pane->min);
00572         AssignMin(pane->size, (int) pane->max);
00573         *sizeused += (pane->size - old);
00574     }
00575 }
00576 
00577 /*      Function Name: RefigureLocations
00578  *      Description: refigures all locations of children.
00579  *      Arguments: pw - the paned widget.
00580  *                 paneindex - child to start refiguring at.
00581  *                 dir - direction to move from child.
00582  *      Returns: none.
00583  *
00584  *      There are special arguments to paneindex and dir, they are:
00585  *      paneindex - NO_INDEX.
00586  *      dir   - AnyPane.
00587  *
00588  *      If either of these is true then all panes may be resized and
00589  *      the choosing of panes procedes in reverse order starting with the
00590  *      last child.
00591  */
00592 
00593 static void 
00594 RefigureLocations(pw, paneindex, dir)
00595 PanedWidget pw;
00596 int paneindex;
00597 Direction dir;
00598 {
00599     Widget *childP;
00600     int pane_size = (int) PaneSize( (Widget) pw, IsVert(pw) );
00601     int sizeused = 0;
00602     Position loc = 0;
00603 
00604     if (pw->paned.num_panes == 0 || !pw->paned.refiguremode) return;
00605 
00606 /*
00607  * Get an initial estimate of the size we will use.
00608  */
00609 
00610     ForAllPanes(pw, childP) {
00611         Pane pane = PaneInfo(*childP);
00612         AssignMax(pane->size, (int) pane->min);
00613         AssignMin(pane->size, (int) pane->max);
00614         sizeused += (int) pane->size + (int) pw->paned.internal_bw;
00615     }
00616     sizeused -= (int) pw->paned.internal_bw;
00617 
00618     if ( (dir != ThisBorderOnly) && (sizeused != pane_size) ) 
00619       LoopAndRefigureChildren(pw, paneindex, dir, &sizeused);
00620 
00621 /* 
00622  * If we still are not the right size, then tell the pane that
00623  * wanted to resize that it can't.
00624  */
00625 
00626 
00627     if ( (paneindex != NO_INDEX) && (dir != AnyPane) ) {
00628         Pane pane = PaneInfo(*(pw->composite.children + paneindex));
00629         Dimension old = pane->size;
00630 
00631         pane->size += pane_size - sizeused;
00632         AssignMax(pane->size, (int) pane->min);
00633         AssignMin(pane->size, (int) pane->max);
00634         sizeused += pane->size - old;
00635     }
00636     
00637 /*
00638  * It is possible that the panes will not fit inside the vpaned widget, but
00639  * we have tried out best.
00640  *
00641  * Assign each pane a location.
00642  */
00643 
00644     ForAllPanes(pw, childP) {
00645         PaneInfo(*childP)->delta = loc;
00646         loc += PaneInfo(*childP)->size + pw->paned.internal_bw;
00647     }
00648 }
00649 
00650 /*      Function Name: CommitNewLocations
00651  *      Description: Commits all of the previously figured locations.
00652  *      Arguments: pw - the paned widget.
00653  *      Returns: none.
00654  */
00655 
00656 static void 
00657 CommitNewLocations(pw)
00658 PanedWidget pw;
00659 {
00660     Widget *childP;
00661     XWindowChanges changes;
00662 
00663     changes.stack_mode = Above;
00664 
00665     ForAllPanes(pw, childP) {
00666         Pane pane = PaneInfo(*childP);
00667         Widget grip = pane->grip; /* may be NULL. */
00668 
00669         if (IsVert(pw)) {
00670             XtMoveWidget(*childP, (Position) 0, pane->delta);
00671             XtResizeWidget(*childP, pw->core.width, (Dimension) pane->size,
00672                            (Dimension) 0);
00673 
00674             if (HasGrip(*childP)) {         /* Move and Display the Grip */
00675                 changes.x = pw->core.width - pw->paned.grip_indent -
00676                             grip->core.width - grip->core.border_width*2;
00677                 changes.y = (*childP)->core.y + (*childP)->core.height -
00678                             grip->core.height/2 - grip->core.border_width + 
00679                             pw->paned.internal_bw/2;
00680             }
00681         }
00682         else {
00683             XtMoveWidget(*childP, pane->delta, (Position) 0);
00684             XtResizeWidget(*childP, (Dimension) pane->size, pw->core.height,
00685                            (Dimension) 0);
00686 
00687 
00688             if (HasGrip(*childP)) {         /* Move and Display the Grip */
00689                 changes.x = (*childP)->core.x + (*childP)->core.width -
00690                             grip->core.width/2 - grip->core.border_width + 
00691                             pw->paned.internal_bw/2;
00692                 changes.y = pw->core.height - pw->paned.grip_indent -
00693                             grip->core.height - grip->core.border_width*2;
00694             }
00695         }
00696 
00697 /*
00698  * This should match XtMoveWidget, except that we're also insuring the 
00699  * grip is Raised in the same request.
00700  */
00701 
00702         if (HasGrip(*childP)) {
00703             grip->core.x = changes.x;
00704             grip->core.y = changes.y;
00705 
00706             if (XtIsRealized(pane->grip))
00707                 XConfigureWindow( XtDisplay(pane->grip), XtWindow(pane->grip),
00708                                   CWX | CWY | CWStackMode, &changes );
00709         }
00710     }
00711     ClearPaneStack(pw);
00712 }
00713 
00714 /*      Function Name: RefigureLocationsAndCommit
00715  *      Description: Refigures all locations in a paned widget and
00716  *                   commits them immediately.
00717  *      Arguments: pw - the paned widget.
00718  *      Returns: none
00719  *
00720  *      This function does nothing if any of the following are true.
00721  *      o refiguremode is false.
00722  *      o The widget is unrealized.
00723  *      o There are no panes is the paned widget.
00724  *
00725  *      NOTE: This is the resize Procedure for the Paned widget.
00726  */
00727 
00728 static void 
00729 RefigureLocationsAndCommit(w)
00730 Widget w;
00731 {
00732     PanedWidget pw = (PanedWidget) w;
00733     if (pw->paned.refiguremode && XtIsRealized( (Widget) pw) &&
00734         pw->paned.num_panes > 0 ) {
00735         RefigureLocations(pw, NO_INDEX, AnyPane);
00736         CommitNewLocations(pw);
00737     }
00738 }
00739 
00740 /*      Function Name: _DrawRect
00741  *      Description: Draws a rectangle in the proper orientation.
00742  *      Arguments: pw - the paned widget.
00743  *                 gc - gc to used for the draw.
00744  *                 on_olc, off_loc - location of upper left corner of rect.
00745  *                 on_size, off_size - size of rectangle.
00746  *      Returns: none
00747  */
00748 
00749 static void
00750 _DrawRect(pw, gc, on_loc, off_loc, on_size, off_size)
00751 PanedWidget pw;
00752 GC gc;
00753 int on_loc, off_loc;
00754 unsigned int on_size, off_size;
00755 {
00756   if (IsVert(pw)) 
00757     XFillRectangle(XtDisplay(pw), XtWindow(pw), gc, 
00758                    off_loc, on_loc, off_size, on_size);
00759   else
00760     XFillRectangle(XtDisplay(pw), XtWindow(pw), gc,
00761                    on_loc, off_loc, on_size, off_size);
00762 }
00763 
00764 /*      Function Name: _DrawInternalBorders
00765  *      Description: Draws the internal borders into the paned widget.
00766  *      Arguments: pw - the paned widget.
00767  *                 gc - the GC to use to draw the borders.
00768  *      Returns: none.
00769  */
00770 
00771 static void
00772 _DrawInternalBorders(pw, gc)
00773 PanedWidget pw;
00774 GC gc;
00775 {
00776     Widget *childP;
00777     int on_loc, off_loc;
00778     unsigned int on_size, off_size;
00779 
00780 /*
00781  * This is an optimization.  Do not paint the internal borders if
00782  * they are the same color as the background.
00783  */
00784 
00785     if (pw->core.background_pixel == pw->paned.internal_bp)
00786         return;
00787 
00788     off_loc = 0; 
00789     off_size = (unsigned int) PaneSize( (Widget) pw, !IsVert(pw) );
00790     on_size = (unsigned int) pw->paned.internal_bw;
00791 
00792     ForAllPanes(pw, childP) {
00793         on_loc = IsVert(pw) ? (*childP)->core.y : (*childP)->core.x;
00794         on_loc -= (int) on_size;
00795 
00796         _DrawRect( pw, gc, on_loc, off_loc, on_size, off_size);
00797     }
00798 }
00799 
00800 /* 
00801  * This allows good reuse of code, as well as descriptive function names.
00802  */
00803 
00804 #define DrawInternalBorders(pw) _DrawInternalBorders((pw), (pw)->paned.normgc);
00805 #define EraseInternalBorders(pw) _DrawInternalBorders((pw), (pw)->paned.invgc);
00806 
00807 /*      Function Name: _DrawTrackLines
00808  *      Description: Draws the lines that animate the pane borders when the
00809  *                   grips are moved.
00810  *      Arguments: pw - the Paned widget.
00811  *                 erase - if True then just erase track lines, else
00812  *                         draw them in.
00813  *      Returns: none.
00814  */
00815 
00816 static void
00817 _DrawTrackLines(pw, erase)
00818 PanedWidget pw;
00819 Boolean erase;
00820 {
00821     Widget *childP;
00822     Pane pane;
00823     int on_loc, off_loc;
00824     unsigned int on_size, off_size;
00825 
00826     off_loc = 0;
00827     off_size = PaneSize( (Widget) pw, !IsVert(pw));
00828 
00829     ForAllPanes(pw, childP) {
00830         pane = PaneInfo(*childP);
00831         if ( erase || (pane->olddelta != pane->delta) ) {
00832             on_size = pw->paned.internal_bw; 
00833             if (!erase) {
00834                 on_loc = PaneInfo(*childP)->olddelta - (int) on_size;
00835 
00836                 _DrawRect( pw, pw->paned.flipgc,
00837                           on_loc, off_loc, on_size, off_size);
00838             }
00839 
00840             on_loc = PaneInfo(*childP)->delta - (int) on_size;
00841 
00842             _DrawRect(pw, pw->paned.flipgc,
00843                       on_loc, off_loc, on_size, off_size);
00844 
00845             pane->olddelta = pane->delta;
00846         }
00847     }
00848 }
00849 
00850 /* 
00851  * This allows good reuse of code, as well as descriptive function names.
00852  */
00853 
00854 #define DrawTrackLines(pw) _DrawTrackLines((pw), FALSE);
00855 #define EraseTrackLines(pw) _DrawTrackLines((pw), TRUE);
00856 
00857 /*      Function Name: GetEventLocation
00858  *      Description: Converts and event to an x and y location.
00859  *      Arguments: pw - the paned widget.
00860  *                 event - a pointer to an event.
00861  *      Returns: if this is a vertical pane then (y) else (x).
00862  */
00863 
00864 static int
00865 GetEventLocation(pw, event)
00866 PanedWidget pw;
00867 XEvent *event;
00868 {
00869     int x, y;
00870 
00871     switch (event->xany.type) {
00872         case ButtonPress:
00873         case ButtonRelease: 
00874             x = event->xbutton.x_root;
00875             y = event->xbutton.y_root;
00876             break;
00877         case KeyPress:
00878         case KeyRelease:    
00879             x = event->xkey.x_root;
00880             y = event->xkey.y_root;
00881             break;
00882         case MotionNotify:  
00883             x = event->xmotion.x_root;
00884             y = event->xmotion.y_root;
00885             break;
00886         default:            
00887             x = pw->paned.start_loc;
00888             y = pw->paned.start_loc;
00889     }
00890     if (IsVert(pw)) 
00891         return(y);
00892     return(x);
00893 }
00894 
00895 /*      Function Name: StartGripAdjustment
00896  *      Description: Starts the grip adjustment procedure.
00897  *      Arguments: pw - the paned widget.
00898  *                 grip - the grip widget selected.
00899  *                 dir - the direction that we are to be moving.
00900  *      Returns: none.
00901  */
00902 
00903 static void
00904 StartGripAdjustment(pw, grip, dir)
00905 PanedWidget pw;
00906 Widget grip;
00907 Direction dir;
00908 {
00909     Widget *childP;
00910     Cursor cursor;
00911 
00912     pw->paned.whichadd = pw->paned.whichsub = (Widget) NULL;
00913 
00914     if (dir == ThisBorderOnly || dir == UpLeftPane)
00915       pw->paned.whichadd = pw->composite.children[PaneIndex(grip)];
00916     if (dir == ThisBorderOnly || dir == LowRightPane)
00917       pw->paned.whichsub = pw->composite.children[PaneIndex(grip) + 1];
00918 
00919 /*
00920  * Change the cursor.
00921  */
00922 
00923     if (XtIsRealized(grip)) {
00924         if ( IsVert(pw) ) {
00925             if (dir == UpLeftPane) 
00926                 cursor = pw->paned.adjust_upper_cursor;
00927             else if (dir == LowRightPane) 
00928                 cursor = pw->paned.adjust_lower_cursor;
00929             else {
00930                 if ( pw->paned.adjust_this_cursor == None)
00931                     cursor = pw->paned.v_adjust_this_cursor;
00932                 else
00933                     cursor = pw->paned.adjust_this_cursor;
00934             }
00935         }
00936         else {
00937             if (dir == UpLeftPane) 
00938                 cursor = pw->paned.adjust_left_cursor;
00939             else if (dir == LowRightPane) 
00940                 cursor = pw->paned.adjust_right_cursor;
00941             else {
00942                 if (pw->paned.adjust_this_cursor == None)
00943                     cursor = pw->paned.h_adjust_this_cursor;
00944                 else
00945                     cursor = pw->paned.adjust_this_cursor;
00946             }
00947         }
00948     
00949         XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
00950     }
00951 
00952     EraseInternalBorders(pw);
00953     ForAllPanes(pw, childP) 
00954         PaneInfo(*childP)->olddelta = -99;
00955 }
00956 
00957 /*      Function Name: MoveGripAdjustment
00958  *      Description: This routine moves all panes around when a grip is moved. 
00959  *      Arguments: pw - the paned widget.
00960  *                 grip - the grip that we are moving.
00961  *                 dir - the direction the pane we are interested is w.r.t the
00962  *                       grip.
00963  *                 loc - location of pointer in proper direction.
00964  *      Returns: none.
00965  */
00966 
00967 static void
00968 MoveGripAdjustment(pw, grip, dir, loc)
00969 PanedWidget pw;
00970 Widget grip;
00971 Direction dir;
00972 int loc;
00973 {
00974     int diff, add_size = 0, sub_size = 0;
00975 
00976     diff = loc - pw->paned.start_loc;
00977 
00978     if (pw->paned.whichadd) 
00979         add_size = PaneSize(pw->paned.whichadd, IsVert(pw) ) + diff;
00980 
00981     if (pw->paned.whichsub) 
00982         sub_size = PaneSize(pw->paned.whichsub, IsVert(pw) ) - diff;
00983 
00984 /*
00985  * If moving this border only then do not allow either of the borders
00986  * to go beyond the min or max size allowed.
00987  */
00988 
00989     if ( (dir == ThisBorderOnly) ) {
00990       int old_add_size = add_size, old_sub_size;
00991 
00992       AssignMax(add_size, (int) PaneInfo(pw->paned.whichadd)->min);
00993       AssignMin(add_size, (int) PaneInfo(pw->paned.whichadd)->max);
00994       if (add_size != old_add_size) 
00995           sub_size += old_add_size - add_size;
00996 
00997       old_sub_size = sub_size;
00998       AssignMax(sub_size, (int) PaneInfo(pw->paned.whichsub)->min);
00999       AssignMin(sub_size, (int) PaneInfo(pw->paned.whichsub)->max);
01000       if (sub_size != old_sub_size) return; /* Abort to current sizes. */
01001     }
01002 
01003     if (add_size != 0)
01004         PaneInfo(pw->paned.whichadd)->size = add_size;
01005     if (sub_size != 0)
01006         PaneInfo(pw->paned.whichsub)->size = sub_size;
01007     RefigureLocations(pw, PaneIndex(grip), dir);
01008     DrawTrackLines(pw);
01009 }
01010 
01011 /*      Function Name: CommitGripAdjustment
01012  *      Description: Commits the grip adjustment.
01013  *      Arguments: pw - the paned widget.
01014  *      Returns: none
01015  */
01016 
01017 static void
01018 CommitGripAdjustment(pw)
01019 PanedWidget pw;
01020 {
01021     EraseTrackLines(pw);
01022     CommitNewLocations(pw);
01023     DrawInternalBorders(pw);
01024            
01025 /*
01026  * Since the user selected this size then use it as the preferred size. 
01027  */
01028 
01029     if (pw->paned.whichadd) {
01030         Pane pane = PaneInfo(pw->paned.whichadd);
01031         pane->wp_size = pane->size;
01032     }
01033     if (pw->paned.whichsub) {
01034         Pane pane = PaneInfo(pw->paned.whichsub);
01035         pane->wp_size = pane->size;
01036     }
01037 }
01038 
01039 /*      Function Name: HandleGrip
01040  *      Description: Handles the grip manipulations.
01041  *      Arguments: grip - the grip widget that has been moved.
01042  *                 junk - ** NOT USED **
01043  *                 call_data - data passed to us from the grip widget.
01044  *      Returns: none.
01045  */
01046 
01047 /* ARGSUSED */
01048 static void
01049 HandleGrip(grip, junk, callData)
01050 Widget grip;
01051 XtPointer junk, callData;
01052 {
01053     XawGripCallData call_data = (XawGripCallData)callData;
01054     PanedWidget pw = (PanedWidget) XtParent(grip);
01055     int loc;
01056     char action_type;
01057     Cursor cursor;
01058     Direction direction = 0;
01059     Arg arglist[1];
01060 
01061     action_type = *call_data->params[0];
01062 
01063     if (call_data->num_params == 0                             ||
01064         (action_type == 'C' && call_data->num_params != 1)      ||
01065         (action_type != 'C' && call_data->num_params != 2))
01066         XtError( "Paned GripAction has been passed incorrect parameters." );
01067 
01068     if (islower(action_type)) action_type = toupper(action_type);
01069 
01070     loc = GetEventLocation(pw, (XEvent *) (call_data->event));
01071 
01072     if (action_type != 'C') {
01073         if ( isupper(*call_data->params[1]) )
01074           direction = (Direction) *call_data->params[1];
01075         else
01076           direction = (Direction) toupper(*call_data->params[1]);
01077     }
01078 
01079     switch (action_type) {
01080         case 'S':               /* Start adjustment */
01081             pw->paned.resize_children_to_pref = FALSE;
01082             StartGripAdjustment(pw, grip, direction);
01083             pw->paned.start_loc = loc;  
01084             break;
01085 
01086         case 'M': 
01087             MoveGripAdjustment(pw, grip, direction, loc);
01088             break;
01089 
01090         case 'C':
01091             XtSetArg(arglist[0], XtNcursor, &cursor);
01092             XtGetValues(grip, arglist, (Cardinal) 1);
01093             XDefineCursor(XtDisplay(grip), XtWindow(grip), cursor);
01094             CommitGripAdjustment(pw);
01095             break;
01096 
01097         default:
01098             XtError( "Paned GripAction(); 1st parameter invalid" );
01099      }
01100 }
01101 
01102 /*      Function Name: ResortChildren
01103  *      Description: Resorts the children so that all managed children
01104  *                   are first.
01105  *      Arguments: pw - the paned widget.
01106  *      Returns: none.
01107  */
01108 
01109 static void
01110 ResortChildren(pw)
01111 PanedWidget pw;
01112 {
01113     Widget * unmanagedP, * childP;
01114 
01115     unmanagedP = NULL;
01116     ForAllChildren(pw, childP) {
01117        if (!IsPane(*childP) || !XtIsManaged(*childP)) {
01118            /*
01119             * We only keep track of the first unmanaged pane.
01120             */
01121            if (unmanagedP == NULL)    
01122                unmanagedP = childP;
01123        }
01124        else {                        /* must be a managed pane */
01125            /*
01126             * If an earlier widget was not a managed pane, then swap 
01127             */
01128            if (unmanagedP != NULL) {       
01129                Widget child = *unmanagedP;
01130                *unmanagedP = *childP;
01131                *childP = child;
01132                childP = unmanagedP;  /* easiest to just back-track */
01133                unmanagedP = NULL;    /* in case there is another managed */
01134            }
01135        }
01136    }
01137 }
01138 
01139 /*      Function Name: ManageAndUnmanageGrips
01140  *      Description: This function manages and unmanages the grips so that
01141  *                   the managed state of each grip matches that of its pane.
01142  *      Arguments: pw - the paned widget.
01143  *      Returns: none.
01144  */
01145 
01146 static void   
01147 ManageAndUnmanageGrips(pw)
01148 PanedWidget pw;
01149 {
01150    WidgetList managed_grips, unmanaged_grips;
01151    Widget *managedP, *unmanagedP, *childP;
01152    Cardinal alloc_size;
01153 
01154    alloc_size = (Cardinal) sizeof(Widget) * pw->composite.num_children / 2;
01155    managedP = managed_grips = (WidgetList) XtMalloc(alloc_size);
01156    unmanagedP = unmanaged_grips = (WidgetList) XtMalloc(alloc_size);
01157 
01158    ForAllChildren(pw, childP) 
01159        if (IsPane(*childP) && HasGrip(*childP))
01160            if ( XtIsManaged(*childP) ) 
01161                *managedP++ = PaneInfo(*childP)->grip;
01162            else
01163                *unmanagedP++ = PaneInfo(*childP)->grip;
01164    
01165    if (managedP != managed_grips) {
01166        *unmanagedP++ = *--managedP;   /* Last grip is never managed */
01167        XtManageChildren( managed_grips, (Cardinal)(managedP - managed_grips) );
01168    }
01169 
01170    if (unmanagedP != unmanaged_grips)
01171        XtUnmanageChildren( unmanaged_grips,
01172                            (Cardinal)(unmanagedP - unmanaged_grips) );
01173 
01174    XtFree((char *)managed_grips);
01175    XtFree((char *)unmanaged_grips);
01176 }
01177 
01178 /*      Function Name: CreateGrip
01179  *      Description: Creates a grip widget.
01180  *      Arguments: child - the child that wants a grip to be created for it.
01181  *      Returns: none.
01182  */
01183 
01184 static void
01185 CreateGrip(child)
01186 Widget child;
01187 {
01188     PanedWidget pw = (PanedWidget) XtParent(child);
01189     Arg arglist[2];
01190     Cardinal num_args = 0;
01191     Cursor cursor;
01192      
01193     XtSetArg(arglist[num_args], XtNtranslations, pw->paned.grip_translations);
01194     num_args++;
01195     if ( (cursor = pw->paned.grip_cursor) == None )
01196         if (IsVert(pw))
01197             cursor = pw->paned.v_grip_cursor;
01198         else
01199             cursor = pw->paned.h_grip_cursor;
01200 
01201     XtSetArg(arglist[num_args], XtNcursor, cursor);
01202     num_args++;
01203     PaneInfo(child)->grip = XtCreateWidget("grip", gripWidgetClass, (Widget)pw,
01204                                            arglist, num_args);
01205     
01206     XtAddCallback(PaneInfo(child)->grip, XtNcallback, 
01207                   HandleGrip, (XtPointer) child);
01208 }
01209 
01210 /*      Function Name: GetGCs
01211  *      Description: Gets new GC's.
01212  *      Arguments: w - the paned widget.
01213  *      Returns: none.
01214  */
01215 
01216 static void
01217 GetGCs(w)
01218 Widget w;
01219 {
01220     PanedWidget pw = (PanedWidget) w;
01221     XtGCMask valuemask;
01222     XGCValues values;
01223 
01224 /*
01225  * Draw pane borders in internal border color. 
01226  */
01227 
01228     values.foreground = pw->paned.internal_bp;  
01229     valuemask = GCForeground;
01230     pw->paned.normgc = XtGetGC(w, valuemask, &values);
01231 
01232 /*
01233  * Erase pane borders with background color. 
01234  */
01235 
01236     values.foreground = pw->core.background_pixel;      
01237     valuemask = GCForeground;
01238     pw->paned.invgc = XtGetGC(w, valuemask, &values);
01239 
01240 /*
01241  * Draw Track lines (animate pane borders) in internal border color ^ bg color.
01242  */
01243 
01244     values.function = GXinvert;
01245     values.plane_mask = pw->paned.internal_bp ^ pw->core.background_pixel;
01246     values.subwindow_mode = IncludeInferiors; 
01247     valuemask = GCPlaneMask | GCFunction | GCSubwindowMode;
01248     pw->paned.flipgc = XtGetGC(w, valuemask, &values);
01249 }
01250 
01251 /*      Function Name: SetChildrenPrefSizes.
01252  *      Description: Sets the preferred sizes of the children.
01253  *      Arguments: pw - the paned widget.
01254  *      Returns: none.
01255  */
01256 
01257 static void
01258 SetChildrenPrefSizes(pw, off_size)
01259 PanedWidget pw;
01260 Dimension off_size;
01261 {
01262     Widget * childP;
01263     Boolean vert = IsVert(pw);
01264     XtWidgetGeometry request, reply;
01265 
01266     ForAllPanes(pw, childP)
01267         if ( pw->paned.resize_children_to_pref          ||
01268              (PaneInfo(*childP)->size == 0)             ||
01269              (PaneInfo(*childP)->resize_to_pref) ) {
01270 
01271             if (PaneInfo(*childP)->preferred_size != PANED_ASK_CHILD) 
01272                 PaneInfo(*childP)->wp_size=PaneInfo(*childP)->preferred_size;
01273             else {
01274                 if( vert ) {
01275                     request.request_mode = CWWidth;
01276                     request.width = off_size;
01277                 }
01278                 else {
01279                     request.request_mode = CWHeight;
01280                     request.height = off_size;
01281                 }
01282 
01283                 if ((XtQueryGeometry( *childP, &request, &reply ) 
01284                                                  == XtGeometryAlmost) &&
01285                     (reply.request_mode = (vert ? CWHeight : CWWidth)))
01286                     PaneInfo(*childP)->wp_size = GetRequestInfo(&reply, vert);
01287                 else
01288                     PaneInfo(*childP)->wp_size = PaneSize(*childP, vert);
01289             } 
01290 
01291             PaneInfo(*childP)->size = PaneInfo(*childP)->wp_size;
01292           }
01293 }
01294 
01295 /*      Function Name: ChangeAllGripCursors
01296  *      Description: Changes all the grip cursors.
01297  *      Arguments: pw - the paned widget.
01298  *      Returns: none
01299  */
01300 
01301 static void
01302 ChangeAllGripCursors(pw)
01303 PanedWidget pw;
01304 {
01305     Widget * childP;
01306 
01307     ForAllPanes(pw, childP) {
01308         Arg arglist[1];
01309         Cursor cursor;
01310       
01311         if ( (cursor = pw->paned.grip_cursor) == None )
01312             if ( IsVert(pw) )
01313                 cursor = pw->paned.v_grip_cursor;
01314             else
01315                 cursor = pw->paned.h_grip_cursor;
01316 
01317         if (HasGrip (*childP)) {
01318             XtSetArg(arglist[0], XtNcursor, cursor);
01319             XtSetValues(PaneInfo(*childP)->grip, arglist, (Cardinal) 1);
01320         }
01321     }
01322 }
01323       
01324 /************************************************************
01325  *
01326  * Stack Manipulation routines (Private).
01327  *
01328  ************************************************************/
01329 
01330 /*      Function Name: PushPaneStack
01331  *      Description: Pushes a value onto the pane stack.
01332  *      Arguments: pw - the paned widget.
01333  *                 pane - the pane that we are pushing.
01334  *      Returns: none.
01335  */
01336 
01337 static void
01338 PushPaneStack(pw, pane)
01339 PanedWidget pw;
01340 Pane pane;
01341 {
01342   PaneStack * stack = (PaneStack *) XtMalloc(sizeof(PaneStack));
01343 
01344   stack->next = pw->paned.stack;
01345   stack->pane = pane;
01346   stack->start_size = pane->size;
01347 
01348   pw->paned.stack = stack;
01349 }
01350 
01351 /*      Function Name: GetPaneStack
01352  *      Description: Gets the top value from the pane stack.
01353  *      Arguments: pw - the paned widget.
01354  *                 shrink - TRUE if we want to shrink this pane,
01355  *                          FALSE otherwise.
01356  * ** RETURNED **  pane - the pane that we are popping.
01357  * ** RETURNED **  start_size - the size that this pane started at. 
01358  *      Returns: none.
01359  */
01360 
01361 static void
01362 GetPaneStack(pw, shrink, pane, start_size)
01363 PanedWidget pw;
01364 Boolean shrink;
01365 Pane * pane;
01366 int * start_size;
01367 {
01368   if (pw->paned.stack == NULL) { 
01369     *pane = NULL; 
01370     return;
01371   }
01372 
01373   *pane = pw->paned.stack->pane;
01374   *start_size = pw->paned.stack->start_size;
01375 
01376   if (shrink != ((*pane)->size > *start_size)) *pane = NULL;
01377 }
01378 
01379 /*      Function Name: PopPaneStack
01380  *      Description: Pops the top item off the pane stack.
01381  *      Arguments: pw - the paned widget.
01382  *      Returns: TRUE if this is not the last element on the stack.
01383  */
01384 
01385 static Boolean
01386 PopPaneStack(pw)
01387 PanedWidget pw;
01388 {
01389   PaneStack * stack = pw->paned.stack;
01390 
01391   if (stack == NULL) return(FALSE);
01392 
01393   pw->paned.stack = stack->next;
01394   XtFree((char*)stack);
01395 
01396   if (pw->paned.stack == NULL) return(FALSE);
01397   return(TRUE);
01398 }
01399 
01400 /*      Function Name: ClearPaneStack
01401  *      Description: removes all entries from the pane stack.
01402  *      Arguments: pw - the paned widget.
01403  *      Returns: none
01404  */
01405 
01406 static void
01407 ClearPaneStack(pw)
01408 PanedWidget pw;
01409 {
01410   while(PopPaneStack(pw));
01411 }
01412 
01413 /************************************************************
01414  *
01415  * Semi-public routines. 
01416  *
01417  ************************************************************/
01418 
01419 /*      Function Name: ClassInitialize
01420  *      Description: The Paned widgets class initialization proc.
01421  *      Arguments: none.
01422  *      Returns: none.
01423  */
01424 
01425 static void 
01426 ClassInitialize()
01427 {
01428     XawInitializeWidgetSet();
01429     XtAddConverter( XtRString, XtROrientation, XmuCvtStringToOrientation,
01430                     (XtConvertArgList)NULL, (Cardinal)0 );
01431 }
01432 
01433 /* The Geometry Manager only allows changes after Realize if
01434  * allow_resize is True in the constraints record.  
01435  * 
01436  * For vertically paned widgets:
01437  *
01438  * It only allows height changes, but offers the requested height
01439  * as a compromise if both width and height changes were requested.
01440  *
01441  * For horizontal widgets the converse is true.
01442  * As all good Geometry Managers should, we will return No if the
01443  * request will have no effect; i.e. when the requestor is already
01444  * of the desired geometry.
01445  */
01446 
01447 static XtGeometryResult GeometryManager(w, request, reply)
01448 Widget w;
01449 XtWidgetGeometry *request, *reply;
01450 {
01451     PanedWidget pw = (PanedWidget) XtParent(w);
01452     XtGeometryMask mask = request->request_mode;
01453     Dimension old_size, old_wpsize, old_paned_size;
01454     Pane pane = PaneInfo(w);
01455     Boolean vert = IsVert(pw);
01456     Dimension on_size, off_size;
01457     XtGeometryResult result;
01458     Boolean almost = FALSE;
01459 
01460 /*
01461  * If any of the following is true, disallow the geometry change.
01462  *
01463  * o The paned widget is realized and allow_resize is false for the pane.
01464  * o The child did not ask to change the on_size.
01465  * o The request is not a width or height request.
01466  * o The requested size is the same as the current size.
01467  */
01468 
01469     if ( (XtIsRealized((Widget)pw) && !pane->allow_resize)        ||
01470          !(mask & ((vert) ? CWHeight : CWWidth))                  ||
01471          (mask & ~(CWWidth | CWHeight))                           ||
01472          (GetRequestInfo(request, vert) ==  PaneSize(w, vert)) ) {
01473         return XtGeometryNo;
01474     }
01475 
01476     old_paned_size = PaneSize( (Widget) pw, vert);
01477     old_wpsize = pane->wp_size;
01478     old_size = pane->size;
01479 
01480     pane->wp_size = pane->size = GetRequestInfo(request, vert);
01481 
01482     AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), &result, &on_size,
01483                     &off_size);
01484 
01485 /*
01486  * Fool the Refigure Locations proc to thinking that we are
01487  * a different on_size;
01488  */
01489 
01490     if (result != XtGeometryNo) 
01491         if (vert) 
01492             pw->core.height = on_size;
01493         else 
01494             pw->core.width = on_size;
01495     
01496     RefigureLocations(pw, PaneIndex(w), AnyPane);
01497 
01498 /* 
01499  * Set up reply struct and reset core on_size.
01500  */
01501     
01502     if (vert) {
01503         pw->core.height = old_paned_size;
01504         reply->height = pane->size;
01505         reply->width = off_size;
01506     }
01507     else {
01508         pw->core.width = old_paned_size;
01509         reply->height = off_size;
01510         reply->width = pane->size;
01511     }    
01512 
01513 /*
01514  * IF either of the following is true.
01515  *
01516  * o There was a "off_size" request and the new "off_size" is different
01517  *   from that requested.
01518  * o There was no "off_size" request and the new "off_size" is different
01519  * 
01520  * o The "on_size" we will allow is different from that requested.
01521  * 
01522  * THEN: set almost
01523  */
01524 
01525     if ( !((vert ? CWWidth : CWHeight) & mask))
01526         if (vert) 
01527             request->width = w->core.width;
01528         else
01529             request->height = w->core.height;
01530 
01531     almost = GetRequestInfo(request, !vert) != GetRequestInfo(reply, !vert);
01532     almost |= (GetRequestInfo(request, vert) != GetRequestInfo(reply, vert));
01533 
01534     if ( (mask & XtCWQueryOnly) || almost ) {
01535         pane->wp_size = old_wpsize;
01536         pane->size = old_size;
01537         RefigureLocations(pw, PaneIndex(w), AnyPane);
01538         reply->request_mode = CWWidth | CWHeight;
01539         if (almost) return XtGeometryAlmost;
01540     }
01541     else {
01542         AdjustPanedSize(pw, PaneSize((Widget) pw, !vert), 
01543                         (XtGeometryResult *)NULL, 
01544                         (Dimension *)NULL, (Dimension *)NULL);
01545         CommitNewLocations( pw );       /* layout already refigured. */
01546     }
01547     return XtGeometryDone;
01548 }
01549 
01550 /* ARGSUSED */
01551 static void Initialize(request, new, args, num_args)
01552 Widget request, new;
01553 ArgList args;
01554 Cardinal *num_args;
01555 {
01556     PanedWidget pw = (PanedWidget)new;
01557 
01558     GetGCs( (Widget) pw);
01559 
01560     pw->paned.recursively_called = False;
01561     pw->paned.stack = NULL;
01562     pw->paned.resize_children_to_pref = TRUE;
01563     pw->paned.num_panes = 0;
01564 }
01565 
01566 static void 
01567 Realize(w, valueMask, attributes)
01568 Widget w;
01569 Mask *valueMask;
01570 XSetWindowAttributes *attributes;
01571 {
01572     PanedWidget pw = (PanedWidget) w;
01573     Widget * childP;
01574 
01575     if ((attributes->cursor = (pw)->paned.cursor) != None)
01576         *valueMask |= CWCursor;
01577 
01578     (*SuperClass->core_class.realize) (w, valueMask, attributes);
01579 
01580 /*
01581  * Before we commit the new locations we need to realize all the panes and
01582  * their grips.
01583  */
01584 
01585     ForAllPanes(pw, childP) {
01586         XtRealizeWidget( *childP );
01587         if (HasGrip (*childP))
01588             XtRealizeWidget( PaneInfo(*childP)->grip );
01589     }
01590 
01591     RefigureLocationsAndCommit(w);
01592     pw->paned.resize_children_to_pref = FALSE;
01593 } /* Realize */
01594 
01595 static void 
01596 ReleaseGCs(w)
01597 Widget w;
01598 {
01599     PanedWidget pw = (PanedWidget)w;
01600 
01601     XtReleaseGC( w, pw->paned.normgc );
01602     XtReleaseGC( w, pw->paned.invgc );
01603     XtReleaseGC( w, pw->paned.flipgc );
01604 } 
01605 
01606 static void InsertChild(w)
01607 Widget w;
01608 {
01609    Pane pane = PaneInfo(w);
01610 
01611    /* insert the child widget in the composite children list with the */
01612    /* superclass insert_child routine.                                */
01613    (*SuperClass->composite_class.insert_child)(w);
01614 
01615    if (!IsPane(w)) return;
01616 
01617    /* ||| Panes will be added in the order they are created, temporarily */
01618 
01619    if ( pane->show_grip == TRUE ) {
01620        CreateGrip(w);
01621        if (pane->min == PANED_GRIP_SIZE) 
01622            pane->min = PaneSize(pane->grip, IsVert((PanedWidget) XtParent(w)));
01623    }
01624    else {
01625        if (pane->min == PANED_GRIP_SIZE)
01626            pane->min = 1;
01627        pane->grip = NULL;
01628    }
01629 
01630    pane->size = 0;
01631    pane->paned_adjusted_me = FALSE;
01632 
01633 } /* InsertChild */
01634 
01635 static void DeleteChild(w)
01636 Widget w;
01637 {
01638     /* remove the subwidget info and destroy the grip */
01639    
01640     if ( IsPane(w) && HasGrip(w) ) XtDestroyWidget(PaneInfo(w)->grip);
01641 
01642     /* delete the child widget in the composite children list with the */
01643     /* superclass delete_child routine.                                */
01644     (*SuperClass->composite_class.delete_child) (w);
01645 
01646 } /* DeleteChild */
01647 
01648 static void ChangeManaged(w)
01649    Widget w;
01650 {
01651    PanedWidget pw = (PanedWidget)w;
01652    Boolean vert = IsVert(pw);
01653    Dimension size;
01654    Widget *childP;
01655 
01656    if (pw->paned.recursively_called++) return;
01657 
01658 /*
01659  * If the size is zero then set it to the size of the widest or tallest pane.
01660  */
01661 
01662    if ( (size = PaneSize( (Widget) pw, !vert )) == 0) {
01663        size = 1;
01664        ForAllChildren(pw, childP)
01665            if ( XtIsManaged(*childP) && (PaneSize( *childP, !vert ) > size) )
01666                size = PaneSize( *childP, !vert );
01667    }
01668 
01669    ManageAndUnmanageGrips(pw);
01670    pw->paned.recursively_called = False;
01671    ResortChildren(pw);          
01672 
01673    pw->paned.num_panes = 0;
01674    ForAllChildren(pw, childP) 
01675        if ( IsPane(*childP) )
01676            if ( XtIsManaged(*childP) ) {
01677                Pane pane = PaneInfo(*childP);
01678                if (HasGrip(*childP))
01679                    PaneInfo(pane->grip)->position = pw->paned.num_panes;
01680                pane->position = pw->paned.num_panes; /*TEMPORY -CDP 3/89 */
01681                pw->paned.num_panes++;
01682            }
01683            else
01684                break;           /* This list is already sorted. */
01685 
01686    SetChildrenPrefSizes( (PanedWidget) w, size);
01687 
01688 /*
01689  * ForAllPanes can now be used. 
01690  */
01691 
01692    if ( PaneSize((Widget) pw, vert) == 0 ) 
01693        AdjustPanedSize(pw, size, (XtGeometryResult *)NULL, 
01694                         (Dimension *)NULL, (Dimension *)NULL);
01695 
01696    if (XtIsRealized( (Widget) pw)) 
01697        RefigureLocationsAndCommit( (Widget) pw); 
01698 
01699 } /* ChangeManaged */
01700 
01701 /*      Function Name: Resize
01702  *      Description: The paned widget's resize proc.
01703  *      Arguments: w - the paned widget.
01704  *      Returns: none.
01705  */
01706 
01707 static void
01708 Resize(w)
01709 Widget w;
01710 {
01711     SetChildrenPrefSizes( (PanedWidget) w,
01712                           PaneSize(w, !IsVert((PanedWidget) w)) );
01713     RefigureLocationsAndCommit(w);
01714 }
01715 
01716 /* ARGSUSED */
01717 static void
01718 Redisplay(w, event, region)
01719 Widget w;
01720 XEvent * event;                 /* unused. */
01721 Region region;                  /* unused. */
01722 {
01723     DrawInternalBorders( (PanedWidget) w);
01724 }
01725 
01726 /* ARGSUSED */
01727 static Boolean 
01728 SetValues(old, request, new, args, num_args)
01729 Widget old, request, new;
01730 ArgList args;
01731 Cardinal *num_args;
01732 {
01733     PanedWidget old_pw = (PanedWidget) old;
01734     PanedWidget new_pw = (PanedWidget) new;
01735     Boolean redisplay = FALSE;
01736 
01737     if ( (old_pw->paned.cursor != new_pw->paned.cursor) && XtIsRealized(new))
01738         XDefineCursor(XtDisplay(new), XtWindow(new), new_pw->paned.cursor);
01739 
01740     if ( (old_pw->paned.internal_bp != new_pw->paned.internal_bp) ||
01741          (old_pw->core.background_pixel != new_pw->core.background_pixel) ) {
01742         ReleaseGCs(old);
01743         GetGCs(new);
01744         redisplay = TRUE;
01745     }
01746 
01747     if ( (old_pw->paned.grip_cursor != new_pw->paned.grip_cursor)     ||
01748          (old_pw->paned.v_grip_cursor != new_pw->paned.v_grip_cursor) ||
01749          (old_pw->paned.h_grip_cursor != new_pw->paned.h_grip_cursor) ) {
01750         ChangeAllGripCursors(new_pw);
01751     }
01752         
01753     if ( IsVert(old_pw) != IsVert(new_pw)) {
01754 /*
01755  * We are fooling the paned widget into thinking that is needs to
01756  * fully refigure everything, which is what we want.
01757  */
01758         if (IsVert(new_pw))
01759             new_pw->core.width = 0;
01760         else
01761             new_pw->core.height = 0;
01762 
01763         new_pw->paned.resize_children_to_pref = TRUE;
01764         ChangeManaged(new);     /* Seems weird, but does the right thing. */
01765         new_pw->paned.resize_children_to_pref = FALSE;
01766         if (new_pw->paned.grip_cursor == None)
01767             ChangeAllGripCursors(new_pw);
01768         return(TRUE);
01769     }
01770 
01771     if (old_pw->paned.internal_bw != new_pw->paned.internal_bw) {
01772         AdjustPanedSize( new_pw, PaneSize(new, !IsVert(old_pw)),
01773                          (XtGeometryResult *)NULL, 
01774                          (Dimension *)NULL, (Dimension *)NULL);
01775         RefigureLocationsAndCommit(new);
01776         return(TRUE);           /* We have done a full configuration, return.*/
01777     }
01778     
01779     if ( (old_pw->paned.grip_indent != new_pw->paned.grip_indent) &&
01780          (XtIsRealized(new)) ) {
01781         CommitNewLocations(new_pw);
01782         redisplay = TRUE;
01783     }
01784 
01785     return (redisplay);
01786 } /* SetValues */
01787 
01788 
01789 /* ARGSUSED */
01790 static Boolean 
01791 PaneSetValues(old, request, new, args, num_args)
01792 Widget old, request, new;
01793 ArgList args;
01794 Cardinal *num_args;
01795 {
01796     Pane old_pane = PaneInfo(old);
01797     Pane new_pane = PaneInfo(new);
01798     Boolean redisplay = FALSE;
01799 
01800     /* Check for new min and max. */
01801 
01802     if (old_pane->min != new_pane->min || old_pane->max != new_pane->max)
01803         XawPanedSetMinMax(new, (int)new_pane->min, (int)new_pane->max);
01804 
01805     /* Check for change in XtNshowGrip. */
01806 
01807     if (old_pane->show_grip != new_pane->show_grip)
01808         if (new_pane->show_grip == TRUE) {
01809             CreateGrip(new);
01810             if (XtIsRealized(XtParent(new))) {
01811                 if (XtIsManaged(new)) /* if paned is unrealized this will
01812                                        happen automatically at realize time.*/
01813                     XtManageChild(PaneInfo(new)->grip); /* manage the grip. */
01814                 XtRealizeWidget(PaneInfo(new)->grip); /* realize the grip. */
01815                 CommitNewLocations( (PanedWidget) XtParent(new) );
01816             }
01817         }
01818         else if ( HasGrip(old) ) {
01819             XtDestroyWidget( old_pane->grip );
01820             new_pane->grip = NULL;
01821             redisplay = TRUE;
01822         }
01823 
01824   /* ||| need to look at position changes */
01825 
01826     return(redisplay);
01827 }
01828 
01829 /************************************************************
01830  *
01831  * Public routines. 
01832  *
01833  ************************************************************/
01834 
01835 /*      Function Name: XawPanedSetMinMax
01836  *      Description: Sets the min and max size for a pane.
01837  *      Arguments: widget - the widget that is a child of the Paned widget.
01838  *                 min, max - the new min and max size for the pane.
01839  *      Returns: none.
01840  */
01841 
01842 void 
01843 #if NeedFunctionPrototypes
01844 XawPanedSetMinMax(Widget widget, int min, int max)
01845 #else
01846 XawPanedSetMinMax(widget, min, max)
01847 Widget widget;
01848 int min, max;
01849 #endif
01850 {
01851     Pane pane = PaneInfo(widget);
01852 
01853     pane->min = min;
01854     pane->max = max;
01855     RefigureLocationsAndCommit( widget->core.parent );
01856 }
01857 
01858 /*      Function Name: XawPanedGetMinMax
01859  *      Description: Gets the min and max size for a pane.
01860  *      Arguments: widget - the widget that is a child of the Paned widget.
01861  ** RETURNED **    min, max - the current min and max size for the pane.
01862  *      Returns: none.
01863  */
01864 
01865 void 
01866 #if NeedFunctionPrototypes
01867 XawPanedGetMinMax(Widget widget, int *min, int *max)
01868 #else
01869 XawPanedGetMinMax(widget, min, max)
01870 Widget widget;
01871 int    *min, *max;
01872 #endif
01873 {
01874     Pane pane = PaneInfo(widget);
01875 
01876     *min = pane->min;
01877     *max = pane->max;
01878 }
01879 
01880 /*      Function Name: XawPanedSetRefigureMode
01881  *      Description: Allows a flag to be set the will inhibit 
01882  *                   the paned widgets relayout routine.
01883  *      Arguments: w - the paned widget.
01884  *                 mode - if FALSE then inhibit refigure.
01885  *      Returns: none.
01886  */
01887 
01888 void 
01889 #if NeedFunctionPrototypes
01890 XawPanedSetRefigureMode(Widget w,
01891 #if NeedWidePrototypes
01892                         int mode)
01893 #else
01894                         Boolean mode)
01895 #endif
01896 #else
01897 XawPanedSetRefigureMode(w, mode)
01898 Widget w;
01899 Boolean mode;
01900 #endif
01901 {
01902     ((PanedWidget) w)->paned.refiguremode = mode;
01903     RefigureLocationsAndCommit( w );
01904 }
01905 
01906 /*      Function Name: XawPanedGetNumSub
01907  *      Description: Returns the number of panes in the paned widget.
01908  *      Arguments: w - the paned widget.
01909  *      Returns: the number of panes in the paned widget.
01910  */
01911 
01912 int 
01913 #if NeedFunctionPrototypes
01914 XawPanedGetNumSub(Widget w)
01915 #else
01916 XawPanedGetNumSub(w)
01917 Widget w;
01918 #endif
01919 {
01920     return ((PanedWidget)w)->paned.num_panes;
01921 }
01922 
01923 /*      Function Name: XawPanedAllowResize
01924  *      Description: Allows a flag to be set that determines if the paned
01925  *                   widget will allow geometry requests from this child
01926  *      Arguments: widget - a child of the paned widget.
01927  *      Returns: none.
01928  */
01929 
01930 void 
01931 #if NeedFunctionPrototypes
01932 XawPanedAllowResize(Widget widget,
01933 #if NeedWidePrototypes
01934                     int allow_resize)
01935 #else
01936                     Boolean allow_resize)
01937 #endif
01938 #else
01939 XawPanedAllowResize(widget, allow_resize)
01940 Widget widget;
01941 Boolean allow_resize;
01942 #endif
01943 {
01944     PaneInfo(widget)->allow_resize = allow_resize;
01945 }

Generated on Sun Mar 4 15:03:55 2007 for Scilab [trunk] by  doxygen 1.5.1