/* * @OPENGROUP_COPYRIGHT@ * COPYRIGHT NOTICE * Copyright (c) 1990, 1991, 1992, 1993 Open Software Foundation, Inc. * Copyright (c) 1996, 1997, 1998, 1999, 2000 The Open Group * ALL RIGHTS RESERVED (MOTIF). See the file named COPYRIGHT.MOTIF for * the full copyright text. * * This software is subject to an open license. It may only be * used on, with or for operating systems which are themselves open * source systems. You must contact The Open Group for a license * allowing distribution and sublicensing of this software on, with, * or for operating systems which are not Open Source programs. * * See http://www.opengroup.org/openmotif/license for full * details of the license agreement. Any use, reproduction, or * distribution of the program constitutes recipient's acceptance of * this agreement. * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS * PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT LIMITATION, ANY * WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY * OR FITNESS FOR A PARTICULAR PURPOSE * * EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT * NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE * EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ /* * HISTORY */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "CareVisualTI.h" #include "ColorI.h" #include "GeoUtilsI.h" #include "GMUtilsI.h" #include "MessagesI.h" #include "RegionI.h" #include "RepTypeI.h" #include "ScrollFramTI.h" #include "XmI.h" #define MESSAGE0 _XmMMsgNotebook_0000 #define MESSAGE1 _XmMMsgMotif_0001 /* Under SunOS /usr/include/sys/sysmacros.h (included by types.h) */ /* thoughtfully grabs part of our name space. */ #ifdef major #undef major #endif #ifdef minor #undef minor #endif /***************************************************************************** * * * constants & useful macros * * * *****************************************************************************/ /* names of notebook internal children */ #define MAJOR_TAB_NEXT_NAME "MajorTabScrollerNext" #define MAJOR_TAB_PREV_NAME "MajorTabScrollerPrevious" #define MINOR_TAB_NEXT_NAME "MinorTabScrollerNext" #define MINOR_TAB_PREV_NAME "MinorTabScrollerPrevious" #define PAGE_SCROLLER_NAME "PageScroller" #define NB_TEXT_FIELD_NAME "NBTextField" /* status values for notebook.scroller_status */ #define DEFAULT_NONE 0 /* default is not created yet */ #define DEFAULT_CREATE 1 /* default being created */ #define DEFAULT_USED 2 /* default is being used */ #define DEFAULT_GONE 3 /* default is destroyed */ /* Notebook position value */ #define LEFT 0 #define RIGHT 1 #define TOP 2 #define BOTTOM 4 /* tab traversal value */ #define _HOME 0 #define _END 1 #define _NEXT 2 #define _PREVIOUS 3 #define _FIRST_VISIBLE 4 /* For KNextTab/KPrevTab, scrolling */ #define _LAST_VISIBLE 5 /* For tab scrolling */ #define _CURRENT_VISIBLE 6 /* For tab group traversal */ /* status values for drawing minor tabs */ #define TAB_DRAW 0 /* tab is to be drawn */ #define TAB_DRAWING 1 /* tab is being drawn */ #define TAB_DRAWN 2 /* tab has been drawn */ /* XmNotebook default values */ #define FIRST_PAGE_NUMBER_DEFAULT 1 #define BACK_PAGE_NUMBER_DEFAULT 2 #define BACK_PAGE_SIZE_DEFAULT 8 #define BINDING_WIDTH_DEFAULT 25 #define MARGIN_WIDTH_DEFAULT 0 #define MARGIN_HEIGHT_DEFAULT 0 #define MAJOR_TAB_SPACING_DEFAULT 3 #define MINOR_TAB_SPACING_DEFAULT 3 #define TAB_SCROLLER_WIDTH_DEFAULT 20 #define TAB_SCROLLER_HEIGHT_DEFAULT 20 #define NOTEBOOK_MINIMUM_WIDTH 16 #define NOTEBOOK_MINIMUM_HEIGHT 16 #define MIN_DRAWABLE_SPIRAL_SIZE 6 /* macros */ #define NB_IS_CHILD_NONE(x) \ ((unsigned char)x == XmNONE) #define NB_IS_CHILD_PAGE(x) \ ((unsigned char)x == XmPAGE) #define NB_IS_CHILD_MAJOR(x) \ ((unsigned char)x == XmMAJOR_TAB) #define NB_IS_CHILD_MINOR(x) \ ((unsigned char)x == XmMINOR_TAB) #define NB_IS_CHILD_TAB(x) \ (((unsigned char)x == XmMAJOR_TAB) \ || ((unsigned char)x == XmMINOR_TAB)) #define NB_IS_CHILD_STATUS(x) \ ((unsigned char)x == XmSTATUS_AREA) #define NB_IS_CHILD_PAGE_SCROLLER(x) \ ((unsigned char)x == XmPAGE_SCROLLER) #define NB_IS_CHILD_MAJOR_SCROLLER(x) \ (((unsigned char)x == XmMAJOR_TAB_SCROLLER) \ || ((unsigned char)x == XmTAB_SCROLLER)) #define NB_IS_CHILD_MINOR_SCROLLER(x) \ (((unsigned char)x == XmMINOR_TAB_SCROLLER) \ || ((unsigned char)x == XmTAB_SCROLLER)) /* Layout defines */ #define NB_IS_VISIBLE(w) \ ((XtIsManaged(w) && \ ((w)->core.x > -(int)((w)->core.width + (w)->core.border_width * 2)) && \ ((w)->core.y > -(int)((w)->core.height + (w)->core.border_width * 2)))) #define NB_IS_HIDDEN(w) \ (((w)->core.x <= -(int)((w)->core.width + (w)->core.border_width * 2)) && \ ((w)->core.y <= -(int)((w)->core.height + (w)->core.border_width * 2))) #define NB_ENFORCE_SIGN(s,x) ((s) > 0 ? (x) : -(x)) /* Fixed placement of non-top minor tabs */ #define NB_MINOR_TAB_STEP(x) ((x) /2) /* Max dimension of major tab area, i.e., max of tab and tab scroller dimension */ #define NB_MAJOR_MAX(n,x,y) (MAX((x), (y))) /* MAX(0, (n)->notebook.shadow_thickness - (n)->notebook.back_page_size)) */ /* Max dimension of minor tab area, i.e., max of tab (minus fixed placement) and tab scroller dimension */ #define NB_MINOR_MAX(n,x,y) \ (MAX((int)((x) - NB_MINOR_TAB_STEP((n)->notebook.back_page_size)),(int)(y))) /* MAX(0, (n)->notebook.shadow_thickness - (n)->notebook.back_page_size)) */ /* Retrieve trait defines */ #define NB_SCROLL_FRAME(x) \ ((XmScrollFrameTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \ XmQTscrollFrame)) #define NB_ACTIVATABLE(x) \ ((XmActivatableTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \ XmQTactivatable)) #define NB_NAVIGATOR(x) \ ((XmNavigatorTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \ XmQTnavigator)) #define NB_JOINSIDE(x) \ ((XmJoinSideTrait)XmeTraitGet((XtPointer)XtClass((Widget)(x)), \ XmQTjoinSide)) /* Is trait defines */ #define NB_IS_CHILD_ACTIVATABLE(x) \ (((XmeTraitGet((XtPointer)XtClass(x),XmQTactivatable)) != NULL) \ ? True : False) #define NB_IS_CHILD_NAVIGATOR(x) \ (((XmeTraitGet((XtPointer)XtClass(x),XmQTnavigator)) != NULL) \ ? True : False) #define NB_IS_CHILD_JOINSIDE(x) \ (((XmeTraitGet((XtPointer)XtClass(x),XmQTjoinSide)) != NULL) \ ? True : False) #define NB_IS_CHILD_ACCESSTEXTUAL(x) \ (((XmeTraitGet((XtPointer)XtClass(x),XmQTaccessTextual)) != NULL) \ ? True : False) #define NotebookConstraint(w) \ (&((XmNotebookConstraintPtr) (w)->core.constraints)->notebook) /* If the original dimension is negative, then offset the original position by that negative amount and make it the new position. Also make the new dimension be the positive original dimension. So for instance, if the x value is 20 and the width is -10, then make the x value be 10 and the width be positive 10. If the original dimension is not negative, then just set the new values to be the same as the old values. */ #define ADJUST_NEGATIVE_DIMENSION(orig_pos, orig_dim, new_pos, new_dim) \ if (orig_dim < 0) \ { \ new_pos = orig_pos + orig_dim; \ new_dim = (Dimension) (orig_dim * -1) ; \ } \ else \ { \ new_pos = orig_pos; \ new_dim = (Dimension) orig_dim; \ } #define manager_translations _XmNotebook_manager_translations /***************************************************************************** * * * global variables * * * *****************************************************************************/ static XtAccelerators TabAcceleratorsParsed; /***************************************************************************** * * * Static function declarations * * * *****************************************************************************/ /* synthetic hook */ static void GetDefaultFrameBackground( Widget g, int offset, XrmValue *value) ; static void GetDefaultBackPageBackground( Widget g, int offset, XrmValue *value) ; static void GetDefaultBackPagePos( Widget w, int offset, XrmValue *value) ; static void FromOrientationPixels( Widget w, int offset, XtArgVal *value) ; static XmImportOperator ToOrientationPixels( Widget w, int offset, XtArgVal *value) ; static void FromOrientationOppositePixels( Widget w, int offset, XtArgVal *value) ; static XmImportOperator ToOrientationOppositePixels( Widget w, int offset, XtArgVal *value) ; /* core class method */ static void ClassInitialize ( void) ; static void ClassPartInitialize( WidgetClass wc) ; static void Initialize( Widget rw, Widget nw, ArgList args, Cardinal *num) ; static void Destroy( Widget w) ; static void Resize( Widget w) ; static void Redisplay( Widget w, XEvent *e, Region region) ; static Boolean SetValues( Widget ow, Widget rw, Widget nw, ArgList args, Cardinal *num) ; static XtGeometryResult QueryGeometry( Widget w, XtWidgetGeometry *intended, XtWidgetGeometry *desired) ; static XtGeometryResult GeometryManager( Widget instigator, XtWidgetGeometry *desired, XtWidgetGeometry *reply) ; static void ChangeManaged( Widget w) ; static void InsertChild( Widget child) ; static void DeleteChild( Widget child) ; static void ConstraintInitialize( Widget req, Widget new_w, ArgList args, Cardinal *num) ; static void CreateTabScrollers( XmNotebookWidget nb) ; static void SetVisualConfig( XmNotebookWidget nb) ; static Boolean UpdateJoinSide( XmNotebookWidget nb, Widget child, unsigned char child_type, Dimension shadow_thickness) ; static void UpdateJoinSideChildren( XmNotebookWidget nb, Dimension shadow_thickness) ; static void SetPageScroller( XmNotebookWidget nb) ; static void LayoutChildren( XmNotebookWidget nb, Widget instigator) ; static void LayoutPages( XmNotebookWidget nb, Widget instigator) ; static void LayoutMajorTabs( XmNotebookWidget nb, Widget instigator) ; static void LayoutMinorTabs( XmNotebookWidget nb, Widget instigator) ; static void ResetTopPointers( XmNotebookWidget nb, unsigned char reason, int scroll) ; static void GetFrameGCs( XmNotebookWidget nb) ; static void GetBackpageGCs( XmNotebookWidget nb) ; static void DrawBinding( XmNotebookWidget nb, XExposeEvent *event, Region region) ; static void MakeSpiralPixmap( XmNotebookWidget nb, Dimension width, Dimension height) ; static void DrawPixmapBinding( XmNotebookWidget nb, Dimension x, Dimension y, Dimension width, Dimension height, Pixmap pixmap) ; static void DrawFrameShadow( XmNotebookWidget nb, XExposeEvent *event, Region region) ; static void DrawBackPages( XmNotebookWidget nb, XExposeEvent *event, Region region) ; static Boolean NewPreferredGeometry( XmNotebookWidget nb, Widget instigator, XtWidgetGeometry *desired, XtWidgetGeometry *preferred) ; static void AdjustGeometry( XmNotebookWidget nb, Widget instigator, XtWidgetGeometry *desired) ; static Boolean SetLastPageNumber ( XmNotebookWidget nb, int last_page_number) ; static Boolean AssignDefaultPageNumber( XmNotebookWidget nb) ; static Boolean ConstraintSetValues( Widget old_w, Widget req, Widget new_w, ArgList args, Cardinal *num) ; static void SetActiveChildren( XmNotebookWidget nb) ; static void RepositionChild( XmNotebookWidget nb, Widget child) ; static void SortChildren( XmNotebookWidget nb) ; static int GetNextAvailPageNum( XmNotebookWidget nb, int last) ; static Widget GetChildWidget( XmNotebookWidget nb, int page_number, unsigned char child_type) ; static void GotoPage( XmNotebookWidget nb, int page_number, XEvent *event, int reason) ; static void ShowChild( Widget child, Widget instigator, int x, int y, int width, int height) ; static void HideChild( Widget child, Widget instigator) ; static void HideShadowedTab( XmNotebookWidget nb, Widget child) ; static void FlipTabs( Widget w, XtPointer data, XtPointer call_data) ; static void TabPressed( Widget w, XtPointer data, XtPointer call_data) ; static void TraverseTab( Widget w, XEvent *event, String *params, Cardinal *num_params) ; static Widget GetNextTab( XmNotebookWidget nb, unsigned char child_type, int page_number, unsigned char direction) ; static Boolean MaxIsRightUp( XmNotebookWidget nb, unsigned char child_type) ; static void ScrollFrameInit( Widget w, XtCallbackProc moveCB, Widget scrollable) ; static Boolean ScrollFrameGetInfo( Widget w, Cardinal *dimension, Widget **nav_list, Cardinal *num_nav_list) ; static void AddNavigator( Widget w, Widget nav, Mask dimMask) ; static void RemoveNavigator( Widget w, Widget nav) ; static void PageMove( Widget w, XtPointer data, XtPointer call_data) ; static Widget RedirectTraversal( Widget old_focus, Widget new_focus, unsigned int focus_policy, XmTraversalDirection direction, unsigned int pass) ; static void UpdateNavigators( XmNotebookWidget nb) ; static GC GetUnhighlightGC( Widget w, Widget child) ; static unsigned char GetDefaultBackPagePosAgain( Widget w); /***************************************************************************** * * * Action Records * * * *****************************************************************************/ static XtActionsRec tab_actions_list[] = { {"TraverseTab", TraverseTab}, }; /***************************************************************************** * * * Resources * * * *****************************************************************************/ static XtResource resources[] = { { XmNcurrentPageNumber, XmCCurrentPageNumber, XmRInt, sizeof(int), XtOffsetOf(XmNotebookRec, notebook.current_page_number), XmRImmediate, (XtPointer)XmUNSPECIFIED_PAGE_NUMBER }, { XmNfirstPageNumber, XmCFirstPageNumber, XmRInt, sizeof(int), XtOffsetOf(XmNotebookRec, notebook.first_page_number), XmRImmediate, (XtPointer)FIRST_PAGE_NUMBER_DEFAULT, }, { XmNlastPageNumber, XmCLastPageNumber, XmRInt, sizeof(int), XtOffsetOf(XmNotebookRec, notebook.last_page_number), XmRImmediate, (XtPointer)XmUNSPECIFIED_PAGE_NUMBER }, { XmNorientation, XmCOrientation, XmROrientation, sizeof(unsigned char), XtOffsetOf(XmNotebookRec, notebook.orientation), XmRImmediate, (XtPointer)XmHORIZONTAL }, { XmNframeBackground, XmCFrameBackground, XmRPixel, sizeof(Pixel), XtOffsetOf(XmNotebookRec, notebook.frame_background), XmRCallProc, (XtPointer) GetDefaultFrameBackground }, { XmNbackPagePlacement, XmCBackPagePlacement, XmRScrollBarPlacement, sizeof(unsigned char), XtOffsetOf(XmNotebookRec, notebook.back_page_pos), XmRCallProc, (XtPointer)GetDefaultBackPagePos }, { XmNbackPageNumber, XmCBackPageNumber, XmRCardinal, sizeof(Cardinal), XtOffsetOf(XmNotebookRec, notebook.back_page_number), XmRImmediate, (XtPointer)BACK_PAGE_NUMBER_DEFAULT }, { XmNbackPageSize, XmCBackPageSize, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.back_page_size), XmRImmediate, (XtPointer)BACK_PAGE_SIZE_DEFAULT }, { XmNbackPageForeground, XmCBackPageForeground, XmRPixel, sizeof(Pixel), XtOffsetOf(XmNotebookRec, notebook.back_page_foreground), XmRCallProc, (XtPointer)_XmForegroundColorDefault }, { XmNbackPageBackground, XmCBackPageBackground, XmRPixel, sizeof(Pixel), XtOffsetOf(XmNotebookRec, notebook.back_page_background), XmRCallProc, (XtPointer)GetDefaultBackPageBackground }, { XmNbindingType, XmCBindingType, XmRBindingType, sizeof(unsigned char), XtOffsetOf(XmNotebookRec, notebook.binding_type), XmRImmediate, (XtPointer)XmSPIRAL }, { XmNbindingPixmap, XmCBindingPixmap, XmRDynamicPixmap, sizeof(Pixmap), XtOffsetOf(XmNotebookRec, notebook.binding_pixmap), XmRImmediate, (XtPointer)XmUNSPECIFIED_PIXMAP }, { XmNbindingWidth, XmCBindingWidth, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.binding_width), XmRImmediate, (XtPointer)BINDING_WIDTH_DEFAULT }, { XmNinnerMarginWidth, XmCInnerMarginWidth, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.margin_width), XmRImmediate, (XtPointer)MARGIN_WIDTH_DEFAULT }, { XmNinnerMarginHeight, XmCInnerMarginHeight, XmRVerticalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.margin_height), XmRImmediate, (XtPointer)MARGIN_HEIGHT_DEFAULT }, { XmNmajorTabSpacing, XmCMajorTabSpacing, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.major_spacing), XmRImmediate, (XtPointer)MAJOR_TAB_SPACING_DEFAULT }, { XmNminorTabSpacing, XmCMinorTabSpacing, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.minor_spacing), XmRImmediate, (XtPointer)MINOR_TAB_SPACING_DEFAULT }, { XmNframeShadowThickness, XmCShadowThickness, XmRHorizontalDimension, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.shadow_thickness), XmRCallProc, (XtPointer) _XmSetThickness }, { XmNpageChangedCallback, XmCCallback, XmRCallback, sizeof(XtCallbackList), XtOffsetOf(XmNotebookRec, notebook.page_change_callback), XmRPointer, (XtPointer)NULL } }; static XtResource constraint_resources[] = { { XmNnotebookChildType, XmCNotebookChildType, XmRNotebookChildType, sizeof(unsigned char), XtOffsetOf(XmNotebookConstraintRec, notebook.child_type), XmRImmediate, (XtPointer)XmNONE }, { XmNpageNumber, XmCPageNumber, XmRInt, sizeof(int), XtOffsetOf(XmNotebookConstraintRec, notebook.page_number), XmRImmediate, (XtPointer)XmUNSPECIFIED_PAGE_NUMBER }, { XmNresizable, XmCResizable, XmRBoolean, sizeof(Boolean), XtOffsetOf(XmNotebookConstraintRec, notebook.resizable), XmRImmediate, (XtPointer)True } }; static XmSyntheticResource syn_resources[] = { { XmNbackPageSize, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.back_page_size), XmeFromHorizontalPixels,XmeToHorizontalPixels }, { XmNbindingWidth, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.binding_width), FromOrientationPixels,ToOrientationPixels }, { XmNinnerMarginWidth, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.margin_width), XmeFromHorizontalPixels,XmeToHorizontalPixels }, { XmNinnerMarginHeight, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.margin_height), XmeFromVerticalPixels,XmeToVerticalPixels }, { XmNmajorTabSpacing, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.major_spacing), FromOrientationOppositePixels,ToOrientationOppositePixels }, { XmNminorTabSpacing, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.minor_spacing), FromOrientationPixels,ToOrientationPixels }, { XmNframeShadowThickness, sizeof(Dimension), XtOffsetOf(XmNotebookRec, notebook.shadow_thickness), XmeFromHorizontalPixels,XmeToHorizontalPixels } }; /***************************************************************************** * * * Notebook class record definition * * * *****************************************************************************/ externaldef(xmnotebookclassrec) XmNotebookClassRec xmNotebookClassRec = { /* core class record */ { (WidgetClass)&xmManagerClassRec, /* superclass */ "XmNotebook", /* class_name */ sizeof(XmNotebookRec), /* widget_size */ ClassInitialize, /* class_initialize */ ClassPartInitialize, /* class_part_initialize */ FALSE, /* class_inited */ Initialize, /* initialize */ NULL, /* initialize_hook */ XtInheritRealize, /* realize */ tab_actions_list, /* actions */ XtNumber(tab_actions_list), /* num_actions */ resources, /* resources */ XtNumber(resources), /* num_resources */ NULLQUARK, /* xrm_class */ TRUE, /* compress_motion */ XtExposeCompressMaximal, /* compress_exposure */ TRUE, /* compress enterleave */ TRUE, /* visible_interest */ Destroy, /* destroy */ Resize, /* resize */ Redisplay, /* expose */ SetValues, /* set_values */ NULL, /* set_values_hook */ XtInheritSetValuesAlmost, /* set_value_almost */ NULL, /* get_values_hook */ NULL, /* accept focus */ XtVersion, /* current version */ NULL, /* callback private */ XtInheritTranslations, /* translation table */ QueryGeometry, /* query_geometry */ NULL, /* display_accelerator */ NULL /* extension */ }, /* Composite class record */ { GeometryManager, /* childrens geometry_manager */ ChangeManaged, /* change_managed */ InsertChild, /* insert_child */ DeleteChild, /* delete_child */ NULL /* extension */ }, /* Constraint class record */ { constraint_resources, /* constraint resource */ XtNumber(constraint_resources), /* number of constraints */ sizeof(XmNotebookConstraintRec), /* size of constraint */ ConstraintInitialize, /* initialization */ NULL, /* destroy proc */ ConstraintSetValues, /* set_values proc */ NULL /* extension */ }, /* Manager class record */ { manager_translations, /* translations */ syn_resources, /* syn_resources */ XtNumber(syn_resources), /* num_syn_resources */ NULL, /* get_cont_resources */ 0, /* num_get_cont_resources */ XmInheritParentProcess, /* parent_process */ NULL /* extension */ }, /* Notebook class record */ { NULL /* unused */ } }; externaldef(xmnotebookwidgetclass) WidgetClass xmNotebookWidgetClass = (WidgetClass) &xmNotebookClassRec; /* Trait record for Notebook scrollFrame */ static XmConst XmScrollFrameTraitRec notebookSFT = { 1, /* version */ ScrollFrameInit, /* initialize */ ScrollFrameGetInfo, /* get trait info */ AddNavigator, /* add navigator method */ RemoveNavigator, /* remove navigator method */ NULL /* update original geometry */ }; /* Trait record for Notebook traversalControl */ static XmConst XmTraversalControlTraitRec notebookTCT = { 0, /* version */ RedirectTraversal /* redirect */ }; /* Trait record for Notebook specifyUnhighlight */ static XmConst XmSpecifyUnhighlightTraitRec notebookSUT = { 0, /* version */ GetUnhighlightGC /* getUnhighlightGC */ }; /***************************************************************************** * * * Core method functions * * * *****************************************************************************/ /*- ClassInitialize --------------------------------------------------------- This routine is invoked only once. -----------------------------------------------------------------------------*/ static void ClassInitialize(void) { /* Parse the default accelerator table */ TabAcceleratorsParsed = XtParseAcceleratorTable( _XmNotebook_TabAccelerators ); } /*- ClassPartInitialize ----------------------------------------------------- Set up the fast subclassing for the widget and install traits -----------------------------------------------------------------------------*/ static void ClassPartInitialize ( WidgetClass wc) { _XmFastSubclassInit(wc, XmNOTEBOOK_BIT); XmeTraitSet((XtPointer)wc,XmQTscrollFrame,(XtPointer)¬ebookSFT); XmeTraitSet((XtPointer)wc,XmQTtraversalControl,(XtPointer)¬ebookTCT); XmeTraitSet((XtPointer)wc,XmQTspecifyUnhighlight,(XtPointer)¬ebookSUT); } /*- Initialize -------------------------------------------------------------- Initialize method -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void Initialize ( Widget rw, /* unused */ Widget nw, ArgList args, /* unused */ Cardinal *num) /* unused */ { XmNotebookWidget new_w = (XmNotebookWidget)nw; XmScrollFrameTrait scroll_frameT; /* XmNaccelerators */ new_w->core.accelerators = TabAcceleratorsParsed; /* XmNorientation */ if (!XmRepTypeValidValue(XmRID_ORIENTATION,new_w->notebook.orientation,nw)) new_w->notebook.orientation = XmHORIZONTAL; /* XmNbackPagePlacement */ if (!XmRepTypeValidValue(XmRID_SCROLL_BAR_PLACEMENT, new_w->notebook.back_page_pos, nw)) new_w->notebook.back_page_pos = GetDefaultBackPagePosAgain(nw); /* XmNbindingType */ if (!XmRepTypeValidValue(XmRID_BINDING_TYPE, new_w->notebook.binding_type, nw)) new_w->notebook.binding_type = XmSOLID; /* set tab and binding positions */ SetVisualConfig(new_w); /* page number resources */ if (new_w->notebook.current_page_number == XmUNSPECIFIED_PAGE_NUMBER) new_w->notebook.current_page_number = new_w->notebook.first_page_number; if (new_w->notebook.last_page_number == XmUNSPECIFIED_PAGE_NUMBER) { new_w->notebook.last_page_number = new_w->notebook.first_page_number; new_w->notebook.dynamic_last_page_num = True; } else new_w->notebook.dynamic_last_page_num = False; new_w->notebook.last_alloc_num = new_w->notebook.first_page_number; /* intialize variables for layouting tabs */ new_w->notebook.first_major = NULL; new_w->notebook.old_top_major = NULL; new_w->notebook.top_major = NULL; new_w->notebook.last_major = NULL; new_w->notebook.first_minor = NULL; new_w->notebook.old_top_minor = NULL; new_w->notebook.top_minor = NULL; new_w->notebook.last_minor = NULL; new_w->notebook.constraint_child = NULL; /* shadow thickness state for current page major and minor tab */ new_w->notebook.major_shadow_thickness = (Dimension) 0; new_w->notebook.minor_shadow_thickness = (Dimension) 0; new_w->notebook.in_setshadow = False; new_w->notebook.major_shadow_child = NULL; new_w->notebook.minor_shadow_child = NULL; /* other misc. variables */ new_w->notebook.which_tab = XmMAJOR_TAB; new_w->notebook.scroller_status = DEFAULT_NONE; new_w->notebook.need_scroller = XmNONE; new_w->notebook.scroller = NULL; new_w->notebook.scroller_child = NULL; new_w->notebook.in_callback = False; new_w->notebook.frame_gc = NULL; new_w->notebook.binding_gc = NULL; new_w->notebook.background_gc = NULL; new_w->notebook.foreground_gc = NULL; new_w->notebook.spiral_pixmap = XmUNSPECIFIED_PIXMAP; /* initialize the scroll_frame and change_managed flags */ new_w->notebook.scroll_frame_data = NULL; new_w->notebook.first_change_managed = True; /* initialize the scrollFrame with move callback (subclass trait check) */ if (((scroll_frameT=NB_SCROLL_FRAME(nw)) != NULL) && (scroll_frameT->init != NULL) ) scroll_frameT->init(nw, PageMove, nw); /* creating GCs */ GetFrameGCs(new_w); GetBackpageGCs(new_w); /* create tab scrollers */ CreateTabScrollers(new_w); SetPageScroller(new_w); } /*- Destroy ----------------------------------------------------------------- Destroy the widget and its children -----------------------------------------------------------------------------*/ static void Destroy ( Widget w) { XmNotebookWidget nb = (XmNotebookWidget)w; /* release all GCs */ if (nb->notebook.frame_gc) XtReleaseGC(w, nb->notebook.frame_gc); if (nb->notebook.binding_gc) XtReleaseGC(w,nb->notebook.binding_gc); if (nb->notebook.foreground_gc) XtReleaseGC(w,nb->notebook.foreground_gc); if (nb->notebook.background_gc) XtReleaseGC(w,nb->notebook.background_gc); /* release spiral pixmap */ if (nb->notebook.spiral_pixmap != XmUNSPECIFIED_PIXMAP && nb->notebook.spiral_pixmap != XmNONE) XFreePixmap(XtDisplay(w), nb->notebook.spiral_pixmap); /* release scroll frame data */ if (nb->notebook.scroll_frame_data != NULL) XtFree((char*)nb->notebook.scroll_frame_data); } /*- Resize ----------------------------------------------------------------- Resize the widget -----------------------------------------------------------------------------*/ static void Resize ( Widget w) { XmNotebookWidget nb = (XmNotebookWidget)w; /* Adjust notebook children sizes based on notebook size */ AdjustGeometry(nb, NULL, NULL); /* Layout children based on notebook sizes */ LayoutChildren(nb, NULL); if (XtIsRealized(w)) XClearArea(XtDisplay(w),XtWindow(w),0,0,0,0,True); } /*- Redisplay --------------------------------------------------------------- Method for expose event -----------------------------------------------------------------------------*/ static void Redisplay ( Widget w, XEvent *e, Region region) { XmNotebookWidget nb = (XmNotebookWidget)w; XExposeEvent *event = (XExposeEvent *)e; Widget child; /* fix for CR8959, hack for CR9805 */ int i; /* fix for CR8959, hack for CR9805 */ int total_major_tabs,total_minor_tabs; XmNotebookConstraint nc; total_major_tabs = 0; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (NB_IS_CHILD_MAJOR(nc->child_type)) total_major_tabs++; } if (total_major_tabs > 0 ) { XtManageChild(nb->notebook.prev_major); XtManageChild(nb->notebook.next_major); } else { XtUnmanageChild(nb->notebook.prev_major); XtUnmanageChild(nb->notebook.next_major); } total_minor_tabs = 0; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (NB_IS_CHILD_MAJOR(nc->child_type)) total_minor_tabs++; } if (total_minor_tabs > 0 ) { XtManageChild(nb->notebook.prev_minor); XtManageChild(nb->notebook.next_minor); } else { XtUnmanageChild(nb->notebook.prev_minor); XtUnmanageChild(nb->notebook.next_minor); } /* draw the background */ DrawBackPages(nb, event, region); DrawBinding(nb, event, region); DrawFrameShadow(nb, event, region); /* display gadgets */ XmeRedisplayGadgets(w,e,region); /* Work-around due to PushBG not updating border highlight -- to be removed when PushBG is fixed, see CR9805 */ for (i=0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; if ( (NB_IS_CHILD_TAB(NotebookConstraint(child)->child_type)) && (NotebookConstraint(child)->active) && (XmIsPushButtonGadget((child)))) { (*(xmPushButtonGadgetClassRec.gadget_class.border_unhighlight))((child)); } } } /*- SetValues --------------------------------------------------------------- Set notebook widget resources -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static Boolean SetValues ( Widget ow, Widget rw, /* unused */ Widget nw, ArgList args, /* unused */ Cardinal *num) /* unused */ { XmNotebookWidget old = (XmNotebookWidget) ow; XmNotebookWidget new_w = (XmNotebookWidget) nw; Boolean redraw = False; Boolean updateJoin = False; Boolean updateVisual = False; Boolean relayout = False; Mask visualFlag = NoVisualChange; /* XmNorientation */ if (new_w->notebook.orientation != old->notebook.orientation) { if (!XmRepTypeValidValue(XmRID_ORIENTATION, new_w->notebook.orientation, nw)) new_w->notebook.orientation = old->notebook.orientation; } /* XmNbackPagePlacement */ if (new_w->notebook.back_page_pos != old->notebook.back_page_pos) { if (!XmRepTypeValidValue(XmRID_SCROLL_BAR_PLACEMENT, new_w->notebook.back_page_pos, nw)) new_w->notebook.back_page_pos = old->notebook.back_page_pos; } /* XmNbindingType */ if (new_w->notebook.binding_type != old->notebook.binding_type) { if (!XmRepTypeValidValue(XmRID_BINDING_TYPE, new_w->notebook.binding_type, nw)) new_w->notebook.binding_type = old->notebook.binding_type; } /* XmNcurrentPageNumber */ /* current page must be in the page number range */ ASSIGN_MAX(new_w->notebook.current_page_number, new_w->notebook.first_page_number); ASSIGN_MIN(new_w->notebook.current_page_number, new_w->notebook.last_page_number); /* XmNlastPageNumber */ /* set static last page number, if the last page number is set */ if (new_w->notebook.last_page_number != old->notebook.last_page_number) new_w->notebook.dynamic_last_page_num = False; /* XmNfirstPageNumber */ /* re-determine active children, if page number range has been changed */ if (new_w->notebook.first_page_number != old->notebook.first_page_number || new_w->notebook.last_page_number != old->notebook.last_page_number) { /* Update navigators, unless GotoPage() will */ if (new_w->notebook.current_page_number == old->notebook.current_page_number) UpdateNavigators(new_w); SetActiveChildren(new_w); } /* if XmNcurrentPageNumber is changed, go to the new page */ if (new_w->notebook.current_page_number != old->notebook.current_page_number) { int page_number; page_number = new_w->notebook.current_page_number; new_w->notebook.current_page_number = old->notebook.current_page_number; GotoPage(new_w, page_number, NULL, XmCR_NONE); } /* * Notebook visuals */ /* XmNorientation, XmNbackPagePlacement */ if (new_w->notebook.orientation != old->notebook.orientation || new_w->notebook.back_page_pos != old->notebook.back_page_pos) { updateVisual = True; updateJoin = True; } /* XmNframeShadowThickness */ if (new_w->notebook.shadow_thickness != old->notebook.shadow_thickness) updateJoin = True; /* XmNbackPageNumber */ if (new_w->notebook.back_page_number != old->notebook.back_page_number) { /* set the real back page number */ new_w->notebook.real_back_page_number = new_w->notebook.back_page_number; ASSIGN_MIN(new_w->notebook.real_back_page_number, (Dimension)(new_w->notebook.back_page_size /2)); ASSIGN_MAX(new_w->notebook.real_back_page_number, 1); if (new_w->notebook.real_back_page_number != old->notebook.real_back_page_number) redraw = True; } /* XmNframeBackground */ if (new_w->notebook.frame_background != old->notebook.frame_background || new_w->manager.foreground != old->manager.foreground) { GetFrameGCs(new_w); visualFlag |= (VisualHighlightColor|VisualHighlightPixmap); } /* XmNbackPageBackground, XmNbackPageForeground */ if (new_w->notebook.back_page_background != old->notebook.back_page_background || new_w->notebook.back_page_foreground != old->notebook.back_page_foreground) GetBackpageGCs(new_w); /* Set new size, if necessary */ if (XtIsRealized((Widget)new_w) && (new_w->notebook.orientation != old->notebook.orientation || new_w->notebook.back_page_pos != old->notebook.back_page_pos || new_w->notebook.back_page_size != old->notebook.back_page_size || new_w->notebook.binding_type != old->notebook.binding_type || new_w->notebook.binding_width != old->notebook.binding_width || new_w->notebook.first_page_number != old->notebook.first_page_number || new_w->notebook.last_page_number != old->notebook.last_page_number || new_w->notebook.margin_width != old->notebook.margin_width || new_w->notebook.margin_height != old->notebook.margin_height || new_w->notebook.major_spacing != old->notebook.major_spacing || new_w->notebook.minor_spacing != old->notebook.minor_spacing || new_w->notebook.shadow_thickness != old->notebook.shadow_thickness)) { relayout = True; redraw = True; } /* if visual is changed, redraw */ if (new_w->notebook.frame_background != old->notebook.frame_background || new_w->notebook.binding_pixmap != old->notebook.binding_pixmap || new_w->notebook.back_page_foreground != old->notebook.back_page_foreground || new_w->notebook.back_page_background != old->notebook.back_page_background) { redraw = True; } if (updateVisual) SetVisualConfig(new_w); if (updateJoin) UpdateJoinSideChildren (new_w, (Dimension) 0); if (relayout) { Dimension save_width, save_height; XtWidgetGeometry preferred_geo; /* Store new w/h, restore old w/h, and adjust geometry to the old */ save_width = XtWidth(new_w); save_height = XtHeight(new_w); XtWidth(new_w) = XtWidth(old); XtHeight(new_w) = XtHeight(old); /* Adjust notebook's children type sizes to old size */ AdjustGeometry(new_w, NULL, NULL); /* Layout Children based on old notebook sizes */ LayoutChildren(new_w, NULL); /* Get preferred size unless app changed both width & height */ if ((XtWidth(old) == save_width) || (XtHeight(old) == save_height)) NewPreferredGeometry(new_w, NULL, NULL, &preferred_geo); /* App request for width takes precedence over NewPreferredGeometry */ if (XtWidth(old) != save_width) XtWidth(new_w) = save_width; else XtWidth(new_w) = preferred_geo.width; /* App request for height takes precedence over NewPreferredGeometry */ if (XtHeight(old) != save_height) XtHeight(new_w) = save_height; else XtHeight(new_w) = preferred_geo.height; } if (visualFlag) redraw |= _XmNotifyChildrenVisual (ow, nw, visualFlag); return(redraw); } /*- QueryGeometry ----------------------------------------------------------- Method for the composite widget's QueryGeometry Returns: preferred size if realized, else user/application w/h values -----------------------------------------------------------------------------*/ static XtGeometryResult QueryGeometry ( Widget w, XtWidgetGeometry *intended, XtWidgetGeometry *desired) { /* Get the preferred w/h based on children preferred sizes */ NewPreferredGeometry((XmNotebookWidget)w, NULL, NULL, desired); /* Handle user initial size setting */ if (!XtIsRealized(w)) { if (XtWidth(w)) desired->width = XtWidth(w); if (XtHeight(w)) desired->height = XtHeight(w); } /* Return result, XmeReplyToQueryGeometry will set CWidth and CHeight */ return(XmeReplyToQueryGeometry(w, intended, desired)); } /***************************************************************************** * * * Composite Class Methods * * * *****************************************************************************/ /*- GeometryManager --------------------------------------------------------- Method for the composite widget's GeometryManager -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static XtGeometryResult GeometryManager ( Widget instigator, XtWidgetGeometry *desired, XtWidgetGeometry *reply) /* unused */ { XmNotebookWidget nb = (XmNotebookWidget)XtParent(instigator); XmNotebookConstraint nc = NotebookConstraint(instigator); XtGeometryResult result = XtGeometryNo; XtWidgetGeometry myrequest, myallowed; /* handle changes during ConstraintSetValues layout */ if ( (nb->notebook.constraint_child == instigator) && ((IsX(desired)) && (IsY(desired)))) { nb->notebook.constraint_child = NULL; XtX(instigator) = desired->x; XtY(instigator) = desired->y; if (IsWidth(desired)) XtWidth(instigator) = desired->width; if (IsHeight(desired)) XtHeight(instigator) = desired->height; return XtGeometryYes; } /* only for resizing request */ if (nc->resizable && (desired->request_mode & (CWWidth|CWHeight|CWBorderWidth)) && !nb->notebook.in_setshadow) { /* Determine preferred geometry based on instigator preferrences */ NewPreferredGeometry(nb, instigator, desired, &myrequest); /* * Prepare resize request (as needed) to the parent */ myrequest.request_mode = 0; if (IsQueryOnly(desired)) myrequest.request_mode |= XtCWQueryOnly; if (IsWidth(desired) && XtWidth(nb) != myrequest.width) myrequest.request_mode |= CWWidth; if (IsHeight(desired) && XtHeight(nb) != myrequest.height) myrequest.request_mode |= CWHeight; if (IsBorder(desired) && XtBorderWidth(nb) != myrequest.border_width) myrequest.border_width |= CWBorderWidth; /* ask parent, only if notebook resize request is needed */ if (myrequest.request_mode) { result = XtMakeGeometryRequest((Widget)nb, &myrequest, &myallowed); /* Parent unable to completely fulfill request */ if (result == XtGeometryAlmost) result = XtGeometryNo; } /* Update the geometry, if necessary */ if (result == XtGeometryYes && !IsQueryOnly(desired)) { /* Adjust notebook's children type sizes to new size */ AdjustGeometry(nb, instigator, desired); /* Layout Children based on new notebook size */ LayoutChildren(nb, instigator); if (XtIsRealized((Widget)nb)) XClearArea(XtDisplay((Widget)nb),XtWindow((Widget)nb), 0,0,0,0,True); } } return result; } /*- ChangeManaged ----------------------------------------------------------- Method for the composite widget's ChangeManaged Something changed in the set of managed children, so place the children and change the form widget size to reflect new size, if possible. -----------------------------------------------------------------------------*/ static void ChangeManaged ( Widget w) { XmNotebookWidget nb = (XmNotebookWidget)w; XtWidgetGeometry preferred; /* ChangeManaged recursively called by SetPageScroller; return */ if (nb->notebook.scroller_status == DEFAULT_CREATE) return; /* if this is the first time through, set the page scroller */ if (nb->notebook.scroller_status == DEFAULT_NONE) { SetPageScroller(nb); UpdateNavigators(nb); } /* assign default page number to those who don't have */ AssignDefaultPageNumber(nb); /* invoke XmNpageChangedCallback for initial setting of current page */ if (nb->notebook.first_change_managed && XtHasCallbacks(w, XmNpageChangedCallback) == XtCallbackHasSome) { XmNotebookCallbackStruct cbs; cbs.reason = XmCR_NONE; cbs.event = NULL; cbs.page_number = nb->notebook.current_page_number; cbs.page_widget = GetChildWidget(nb, nb->notebook.current_page_number, XmPAGE); cbs.prev_page_number = XmUNSPECIFIED_PAGE_NUMBER; cbs.prev_page_widget = NULL; /* Mark that the callback is being called and when it finishes */ nb->notebook.in_callback = True; XtCallCallbackList(w, nb->notebook.page_change_callback, &cbs); nb->notebook.in_callback = False; } /* sort children by their page number and update their activity */ SortChildren(nb); /* * Determine preferred notebook size based on new managed child */ /* Check if current size is the preferred size */ if (NewPreferredGeometry(nb, NULL, NULL, &preferred)) { /* Prepare parent geometry request */ preferred.request_mode = 0; if (XtIsRealized((Widget)nb) || XtWidth(nb) == 0) preferred.request_mode |= CWWidth; if (XtIsRealized((Widget)nb) || XtHeight(nb) == 0) preferred.request_mode |= CWHeight; /* Make parent geometry request, if necessary */ if (preferred.request_mode) _XmMakeGeometryRequest((Widget)nb, &preferred); /* Clear notebook area otherwise binder and backpage don't update. */ if (XtIsRealized((Widget)nb) && !nb->notebook.first_change_managed) XClearArea(XtDisplay(nb), XtWindow(nb), 0, 0, 0, 0, True); } /* Adjust notebook's children type sizes (based on notebook size) */ AdjustGeometry(nb, NULL, NULL); /* Layout Children (based on notebook size) */ LayoutChildren(nb, NULL); XmeNavigChangeManaged(w); nb->notebook.first_change_managed = False; } /*- InsertChild ------------------------------------------------------------- Method for the composite widget's InsertChild -----------------------------------------------------------------------------*/ static void InsertChild ( Widget child) { XmNotebookWidget nb = (XmNotebookWidget)XtParent(child); XmNotebookConstraint nc = NotebookConstraint(child); XmScrollFrameTrait scroll_frameT; XtWidgetProc insert_child; /* check if trying to insert an invalid object */ if (!XtIsRectObj(child)) return; /* call manager's InsertChild method */ _XmProcessLock(); insert_child = ((XmManagerWidgetClass)xmManagerWidgetClass) ->composite_class.insert_child; _XmProcessUnlock(); (*insert_child)(child); /* add some keyboard traversal stuff */ switch (nc->child_type) { case XmPAGE_SCROLLER: /* First: take care of previous page scroller */ /* default page scroller not yet made, so just put this one in */ if (nb->notebook.scroller_status == DEFAULT_NONE) nb->notebook.scroller_status = DEFAULT_GONE; /* remove previously created default page scroller */ else if (nb->notebook.scroller_status == DEFAULT_USED) { nb->notebook.scroller_status = DEFAULT_CREATE; /* remove navigator, if page scroller is a navigator */ if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller)) { if ((scroll_frameT=NB_SCROLL_FRAME(nb)) != NULL && scroll_frameT->removeNavigator != NULL) scroll_frameT->removeNavigator((Widget) nb, nb->notebook.scroller); } XtDestroyWidget(nb->notebook.scroller); nb->notebook.scroller_status = DEFAULT_GONE; } /* remove previously created non-default page scroller */ else if (nb->notebook.scroller_status == DEFAULT_GONE && nb->notebook.scroller != NULL) { nb->notebook.scroller_status = DEFAULT_CREATE; /* remove navigator, if page scroller is a navigator */ if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller)) { if ((scroll_frameT=NB_SCROLL_FRAME(nb)) != NULL && scroll_frameT->removeNavigator != NULL) scroll_frameT->removeNavigator((Widget)nb, nb->notebook.scroller); } XtUnmanageChild(nb->notebook.scroller); nb->notebook.scroller_status = DEFAULT_GONE; } /* Second: take care of this new page scroller */ /* update scroller's translation table */ nb->notebook.scroller = child; /* add navigator, if page scroller has navigator trait */ if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller)) { if ((scroll_frameT = NB_SCROLL_FRAME(nb)) != NULL && scroll_frameT->addNavigator != NULL) scroll_frameT->addNavigator((Widget)nb, child, NavigDimensionX); } /* update navigators so this one get initial info */ UpdateNavigators(nb); break; case XmPAGE: case XmSTATUS_AREA: XtVaSetValues(child, XmNnavigationType, XmTAB_GROUP, NULL); break; case XmMAJOR_TAB: case XmMINOR_TAB: /* Install activiation callback */ { XmActivatableTrait activeT; if ((activeT=NB_ACTIVATABLE(child)) != NULL && activeT->changeCB != NULL) activeT->changeCB(child, TabPressed, (XtPointer)(unsigned long)(NB_IS_CHILD_MAJOR(nc->child_type) ? XmCR_MAJOR_TAB : XmCR_MINOR_TAB), True); } /* Update JoinSide information */ (void) UpdateJoinSide(nb, child, nc->child_type, (Dimension) 0); /* Install accelerators */ if (!XmIsGadget(child)) XtInstallAccelerators(child, (Widget)nb); break; } } /*- DeleteChild ------------------------------------------------------------- Method for the composite widget's DeleteChild -----------------------------------------------------------------------------*/ static void DeleteChild ( Widget child) { XmNotebookWidget nb = (XmNotebookWidget)XtParent(child); XmNotebookConstraint nc = NotebookConstraint(child); XmScrollFrameTrait scroll_frameT; XtWidgetProc delete_child; /* clear child pointers in Notebook */ switch (nc->child_type) { case XmPAGE_SCROLLER: if (nb->notebook.scroller == child) { /* remove navigator */ if (NB_IS_CHILD_NAVIGATOR(nb->notebook.scroller)) { if ((scroll_frameT=NB_SCROLL_FRAME(nb)) != NULL && scroll_frameT->removeNavigator != NULL) scroll_frameT->removeNavigator((Widget)nb, nb->notebook.scroller); } /* Mark that no page scroller is established */ nb->notebook.scroller = NULL; nb->notebook.scroller_status = DEFAULT_GONE; } break; case XmMAJOR_TAB_SCROLLER: nb->notebook.next_major = NULL; nb->notebook.prev_major = NULL; break; case XmMINOR_TAB_SCROLLER: nb->notebook.next_minor = NULL; nb->notebook.prev_minor = NULL; break; } /* call manager's DeleteChild method */ _XmProcessLock(); delete_child = ((XmManagerWidgetClass)xmManagerWidgetClass) ->composite_class.delete_child; _XmProcessUnlock(); (*delete_child)(child); } /***************************************************************************** * * * Constraint Class Methods * * * *****************************************************************************/ /*- ConstraintInitialize ---------------------------------------------------- Initialize method for Notebook's constraint class A default page number will be provided when the widget is managed. -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void ConstraintInitialize ( Widget req, /* unused */ Widget new_w, ArgList args, /* unused */ Cardinal *num) /* unused */ { XmNotebookConstraint nc = NotebookConstraint(new_w); /* check for invalid object */ if (!XtIsRectObj(new_w)) return; /* validate the child type */ if (nc->child_type != XmMAJOR_TAB_SCROLLER && nc->child_type != XmMINOR_TAB_SCROLLER && !XmRepTypeValidValue(XmRID_NB_CHILD_TYPE, nc->child_type, new_w)) nc->child_type = XmNONE; /* convert to internal */ if (nc->child_type == XmNONE) { if (NB_IS_CHILD_ACTIVATABLE(new_w)) nc->child_type = XmMAJOR_TAB; else if (NB_IS_CHILD_ACCESSTEXTUAL(new_w)) nc->child_type = XmSTATUS_AREA; else if (NB_IS_CHILD_NAVIGATOR(new_w)) nc->child_type = XmPAGE_SCROLLER; else nc->child_type = XmPAGE; } } /*- ConstraintSetValues ----------------------------------------------------- SetValue method for notebook's constraint class -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static Boolean ConstraintSetValues ( Widget old_w, Widget req, /* unused */ Widget new_w, ArgList args, /* unused */ Cardinal *num) /* unused */ { XmNotebookWidget nb = (XmNotebookWidget)XtParent(new_w); XmNotebookConstraint old_nc = NotebookConstraint(old_w); XmNotebookConstraint new_nc = NotebookConstraint(new_w); Boolean redraw = False; Boolean need_reset = False; /* check for invalid object */ if (!XtIsRectObj(new_w)) return False; /* XmNnotebookChildType is only CG, not Settable */ if (new_nc->child_type != old_nc->child_type) { new_nc->child_type = old_nc->child_type; XmeWarning(new_w, MESSAGE0); } /* if the page number is changed, sort again */ /* by just repositioning that child */ if (new_nc->page_number != old_nc->page_number) { /* check for last page number change */ if (nb->notebook.dynamic_last_page_num) { if (new_nc->page_number > nb->notebook.last_page_number && XtIsManaged(new_w) && (NB_IS_CHILD_PAGE(new_nc->child_type) || NB_IS_CHILD_TAB(new_nc->child_type) || NB_IS_CHILD_STATUS(new_nc->child_type))) need_reset = SetLastPageNumber(nb, new_nc->page_number); else if (old_nc->page_number == nb->notebook.last_page_number) need_reset = AssignDefaultPageNumber(nb); } /* re-sort and check child list */ RepositionChild(nb, new_w); SetActiveChildren(nb); /* check for changes that affect layout */ if (!nb->notebook.in_callback) { switch(new_nc->child_type) { case XmPAGE: case XmSTATUS_AREA: if (nb->notebook.current_page_number == old_nc->page_number || nb->notebook.current_page_number == new_nc->page_number) { if (need_reset) ResetTopPointers(nb, XmNONE, 0); nb->notebook.constraint_child = new_w; LayoutPages(nb, NULL); redraw = True; } break; case XmMAJOR_TAB: ResetTopPointers(nb, XmNONE, 0); nb->notebook.constraint_child = new_w; LayoutMajorTabs(nb, NULL); LayoutMinorTabs(nb, NULL); redraw = True; break; case XmMINOR_TAB: ResetTopPointers(nb, XmNONE, 0); nb->notebook.constraint_child = new_w; LayoutMinorTabs(nb, NULL); redraw = True; break; } /* switch */ } /* if */ } /* if */ return(redraw); } /***************************************************************************** * * * Initializing & Resource Managing * * * *****************************************************************************/ /*- GetDefaultBackPagePos --------------------------------------------------- Get the default back page position -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void GetDefaultFrameBackground( Widget w, int offset, /* unused */ XrmValue *value) { value->addr = (XtPointer) &w->core.background_pixel; } /*ARGSUSED*/ static void GetDefaultBackPageBackground( Widget w, int offset, /* unused */ XrmValue *value) { XmNotebookWidget nb = (XmNotebookWidget)w; static Pixel pixel; value->addr = (XtPointer) &pixel; XmGetColors(XtScreen(w), nb->core.colormap, nb->notebook.frame_background, NULL, NULL, NULL, &pixel); } /*ARGSUSED*/ static void GetDefaultBackPagePos ( Widget w, int offset, /* unused */ XrmValue *value) { static unsigned char back_page_pos; XmNotebookWidget nb = (XmNotebookWidget)w; /* initialize the notebook layout default */ if (LayoutIsRtoLM(w)) { if (nb->notebook.orientation == XmVERTICAL) /* RIGHT_TO_LEFT and VERTICAL */ back_page_pos = XmBOTTOM_LEFT; else /* RIGHT_TO_LEFT and HORIZONTAL */ back_page_pos = XmBOTTOM_LEFT; } else { if (nb->notebook.orientation == XmVERTICAL) /* LEFT_TO_RIGHT and VERTICAL */ back_page_pos = XmBOTTOM_RIGHT; else /* LEFT_TO_RIGHT and HORIZONTAL */ back_page_pos = XmBOTTOM_RIGHT; } /* * This will have to change when BOTTOM_TO_TOP is supported for * XmNlayoutDirection. */ value->addr = (XPointer) &back_page_pos; } /* Same logic as the GetDefaultBackPagePos default proc ... rewritten * without the static variable - for use from the Initialize proc . */ static unsigned char GetDefaultBackPagePosAgain ( Widget w) { unsigned char back_page_pos; XmNotebookWidget nb = (XmNotebookWidget)w; if (LayoutIsRtoLM(w)) { if (nb->notebook.orientation == XmVERTICAL) /* RIGHT_TO_LEFT and VERTICAL */ back_page_pos = XmBOTTOM_LEFT; else /* RIGHT_TO_LEFT and HORIZONTAL */ back_page_pos = XmBOTTOM_LEFT; } else { if (nb->notebook.orientation == XmVERTICAL) /* LEFT_TO_RIGHT and VERTICAL */ back_page_pos = XmBOTTOM_RIGHT; else /* LEFT_TO_RIGHT and HORIZONTAL */ back_page_pos = XmBOTTOM_RIGHT; } return back_page_pos; } /*- FromOrientationPixels --------------------------------------------------- Determines orientation and calls appropriate converter. -----------------------------------------------------------------------------*/ static void FromOrientationPixels ( Widget w, int offset, XtArgVal *value) { XmNotebookWidget nb = (XmNotebookWidget)w; if ((int)(*value) < 0) *value = 0; if (nb->notebook.orientation == XmHORIZONTAL) XmeFromHorizontalPixels(w, offset, value); else XmeFromVerticalPixels(w, offset, value); } /*- ToOrientationPixels ---------------------------------------------------- Determines orientation and calls appropriate converter. -----------------------------------------------------------------------------*/ static XmImportOperator ToOrientationPixels ( Widget w, int offset, XtArgVal *value) { XmNotebookWidget nb = (XmNotebookWidget)w; if (nb->notebook.orientation == XmHORIZONTAL) return(XmeToHorizontalPixels(w, offset, value)); else return(XmeToVerticalPixels(w, offset, value)); } /*- FromOrientationOppositePixels ------------------------------------------- Determines orientation and calls appropriate converter. -----------------------------------------------------------------------------*/ static void FromOrientationOppositePixels ( Widget w, int offset, XtArgVal *value) { XmNotebookWidget nb = (XmNotebookWidget)w; if ((int)(*value) < 0) *value = 0; if (nb->notebook.orientation == XmHORIZONTAL) XmeFromVerticalPixels(w, offset, value); else XmeFromHorizontalPixels(w, offset, value); } /*- ToOrientationOppositePixels -------------------------------------------- Determines orientation and calls appropriate converter. -----------------------------------------------------------------------------*/ static XmImportOperator ToOrientationOppositePixels ( Widget w, int offset, XtArgVal *value) { XmNotebookWidget nb = (XmNotebookWidget)w; if (nb->notebook.orientation == XmHORIZONTAL) return(XmeToVerticalPixels(w, offset, value)); else return(XmeToHorizontalPixels(w, offset, value)); } /*- CreateTabScrollers ----------------------------------------------------- Create Notebook's tab scrollers -----------------------------------------------------------------------------*/ static void CreateTabScrollers ( XmNotebookWidget nb) { /* creating major tab scrollers */ nb->notebook.next_major = XtVaCreateManagedWidget(MAJOR_TAB_NEXT_NAME, xmArrowButtonGadgetClass, (Widget)nb, XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT, XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT, XmNnotebookChildType, XmMAJOR_TAB_SCROLLER, XmNtraversalOn, False, NULL); ((XmActivatableTrait)XmeTraitGet((XtPointer) XtClass((Widget)nb->notebook.next_major),XmQTactivatable))-> changeCB(nb->notebook.next_major,FlipTabs,NULL,True); nb->notebook.prev_major = XtVaCreateManagedWidget(MAJOR_TAB_PREV_NAME, xmArrowButtonGadgetClass, (Widget)nb, XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT, XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT, XmNnotebookChildType, XmMAJOR_TAB_SCROLLER, XmNtraversalOn, False, NULL); ((XmActivatableTrait)XmeTraitGet((XtPointer) XtClass((Widget)nb->notebook.prev_major),XmQTactivatable))-> changeCB(nb->notebook.prev_major,FlipTabs,NULL,True); /* creating minor tab scrollers */ nb->notebook.next_minor = XtVaCreateManagedWidget(MINOR_TAB_NEXT_NAME, xmArrowButtonGadgetClass, (Widget)nb, XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT, XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT, XmNnotebookChildType, XmMINOR_TAB_SCROLLER, XmNtraversalOn, False, NULL); ((XmActivatableTrait)XmeTraitGet((XtPointer) XtClass((Widget)nb->notebook.next_minor),XmQTactivatable))-> changeCB(nb->notebook.next_minor,FlipTabs,NULL,True); nb->notebook.prev_minor = XtVaCreateManagedWidget(MINOR_TAB_PREV_NAME, xmArrowButtonGadgetClass, (Widget)nb, XmNwidth, TAB_SCROLLER_WIDTH_DEFAULT, XmNheight, TAB_SCROLLER_HEIGHT_DEFAULT, XmNnotebookChildType, XmMINOR_TAB_SCROLLER, XmNtraversalOn, False, NULL); ((XmActivatableTrait)XmeTraitGet((XtPointer) XtClass((Widget)nb->notebook.prev_minor),XmQTactivatable))-> changeCB(nb->notebook.prev_minor,FlipTabs,NULL,True); } /*- SetVisualConfig --------------------------------------------------------- Sets Notebook visual configuration private variables. -----------------------------------------------------------------------------*/ static void SetVisualConfig ( XmNotebookWidget nb) { /* set tab and binding position variables */ if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { nb->notebook.major_pos = RIGHT; nb->notebook.minor_pos = BOTTOM; nb->notebook.binding_pos = LEFT; } else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmVERTICAL) { nb->notebook.major_pos = BOTTOM; nb->notebook.minor_pos = RIGHT; nb->notebook.binding_pos = TOP; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmHORIZONTAL) { nb->notebook.major_pos = LEFT; nb->notebook.minor_pos = BOTTOM; nb->notebook.binding_pos = RIGHT; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmVERTICAL) { nb->notebook.major_pos = BOTTOM; nb->notebook.minor_pos = LEFT; nb->notebook.binding_pos = TOP; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { nb->notebook.major_pos = RIGHT; nb->notebook.minor_pos = TOP; nb->notebook.binding_pos = LEFT; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmVERTICAL) { nb->notebook.major_pos = TOP; nb->notebook.minor_pos = RIGHT; nb->notebook.binding_pos = BOTTOM; } else if (nb->notebook.back_page_pos == XmTOP_LEFT && nb->notebook.orientation == XmHORIZONTAL) { nb->notebook.major_pos = LEFT; nb->notebook.minor_pos = TOP; nb->notebook.binding_pos = RIGHT; } else if (nb->notebook.back_page_pos == XmTOP_LEFT && nb->notebook.orientation == XmVERTICAL) { nb->notebook.major_pos = TOP; nb->notebook.minor_pos = LEFT; nb->notebook.binding_pos = BOTTOM; } } /*- UpdateJoinSide ------------------------------------------------------------ Update tab's JoinSide Trait to match current visual configuration. Uses instance state: major_pos minor_pos Returns True, if the child is major or minor tab and holds the JoinSide trait. Otherwise, returns False. -----------------------------------------------------------------------------*/ static Boolean UpdateJoinSide ( XmNotebookWidget nb, Widget child, unsigned char child_type, Dimension shadow_thickness) { XmJoinSideTrait joinsideT; /* child JoinSide trait */ unsigned char side_of_book; /* side of notebook tab is on */ unsigned char side_to_join; /* side to join */ /* Determine side of nookbook tabs reside */ if (NB_IS_CHILD_MAJOR(child_type)) side_of_book = nb->notebook.major_pos; else if (NB_IS_CHILD_MINOR(child_type)) side_of_book = nb->notebook.minor_pos; else return(False); /* Update JoinSide trait infomation, unless trait not found */ if ((joinsideT=NB_JOINSIDE(child)) != NULL && joinsideT->setValue != NULL) { /* Convert notebook position to JoinSide position */ switch (side_of_book) { case RIGHT: side_to_join = XmLEFT; break; case BOTTOM: side_to_join = XmTOP; break; case LEFT: side_to_join = XmRIGHT; break; case TOP: side_to_join = XmBOTTOM; break; } /* Invoke JoinSideSetValues */ joinsideT->setValue(child, side_to_join, shadow_thickness); return(True); } return(False); } /*- UpdateJoinSideChildren -------------------------------------------------- Update JoinSide aware children of new shadow_thickness or JoinSide. -----------------------------------------------------------------------------*/ static void UpdateJoinSideChildren ( XmNotebookWidget nb, Dimension shadow_thickness) { Widget cw; /* child widget */ unsigned char ct; /* child constraint type */ int i; for (i=0; i < nb->composite.num_children; i++) { cw = nb->composite.children[i]; ct = NotebookConstraint(cw)->child_type; if (NB_IS_CHILD_TAB(ct)) (void) UpdateJoinSide(nb, cw, ct, shadow_thickness); } } /*- SetPageScroller --------------------------------------------------------- Set the visual configuration of the page scroller. It creates the default page scroller if no page scroller is created yet (consisting of a SpinBox with TextField child). -----------------------------------------------------------------------------*/ static void SetPageScroller ( XmNotebookWidget nb) { /* Only create default page scroller if none currently exists */ if (nb->notebook.scroller_status != DEFAULT_NONE) return; /* Mark that we are in the process of creating the default */ nb->notebook.scroller_status = DEFAULT_CREATE; nb->notebook.scroller = XtVaCreateManagedWidget(PAGE_SCROLLER_NAME, xmSpinBoxWidgetClass, (Widget)nb, XmNarrowLayout, XmARROWS_SPLIT, XmNnotebookChildType, XmPAGE_SCROLLER, NULL); nb->notebook.scroller_child = XtVaCreateManagedWidget(NB_TEXT_FIELD_NAME, xmTextFieldWidgetClass, nb->notebook.scroller, XmNspinBoxChildType, XmNUMERIC, XmNcolumns, 6, XmNmarginHeight, 2, XmNcursorPositionVisible, False, XmNeditable, False, XmNtraversalOn, True, NULL); /* Mark that the default page scroller has been established */ nb->notebook.scroller_status = DEFAULT_USED; } /***************************************************************************** * * * Child Layout Functions * * * *****************************************************************************/ /*- LayoutChildren ---------------------------------------------------------- Function to layout Notebook's children -----------------------------------------------------------------------------*/ static void LayoutChildren ( XmNotebookWidget nb, Widget instigator) { /* reset top pointers of tabs */ ResetTopPointers(nb, XmNONE, 0); /* layout children */ LayoutPages(nb, instigator); LayoutMajorTabs(nb, instigator); LayoutMinorTabs(nb, instigator); } /*- LayoutPages ------------------------------------------------------------- Function to layout Page, Status, and Page Scroller. Uses instance state: current_page_number, orientation, and precalculated sizes of each child type. Called from: LayoutChildren(), when performing complete relayout ConstraintSetValues(), when child page number changes GotoPage(), when notebook.current_page_number changes -----------------------------------------------------------------------------*/ static void LayoutPages ( XmNotebookWidget nb, Widget instigator) { XmNotebookConstraint nc; Widget child; int i; Dimension x, y, x1, y1, x2; /* get the page's x, y position */ x = nb->notebook.margin_width + nb->notebook.shadow_thickness + 1; y = nb->notebook.margin_height + nb->notebook.shadow_thickness + 1; if (nb->notebook.binding_pos == LEFT) x += nb->notebook.real_binding_width; else if (nb->notebook.binding_pos == TOP) y += nb->notebook.real_binding_width; if (nb->notebook.major_pos == LEFT) x += NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) + nb->notebook.back_page_size; else if (nb->notebook.major_pos == TOP) y += NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) + nb->notebook.back_page_size; if (nb->notebook.minor_pos == LEFT) x += NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) + nb->notebook.back_page_size; else if (nb->notebook.minor_pos == TOP) y += NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) + nb->notebook.back_page_size; /* get the status area and the page scroller's position */ y1 = y + nb->notebook.page_height + nb->notebook.margin_height; if (nb->notebook.back_page_pos == XmTOP_RIGHT || nb->notebook.back_page_pos == XmBOTTOM_RIGHT) { x1 = x; x2 = x + nb->notebook.page_width - nb->notebook.scroller_width; } else { x1 = x + nb->notebook.page_width - nb->notebook.status_width; x2 = x; } /* resize pages & status */ for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if ( NB_IS_CHILD_PAGE(nc->child_type) || NB_IS_CHILD_STATUS(nc->child_type) ) { if (nc->active && nc->page_number == nb->notebook.current_page_number) { if (NB_IS_CHILD_PAGE(nc->child_type)) ShowChild(child, instigator, x, y, nb->notebook.page_width, nb->notebook.page_height); else if (NB_IS_CHILD_STATUS(nc->child_type)) ShowChild(child, instigator, x1, y1, nb->notebook.status_width, nb->notebook.status_height); } else { /* This is to get HideChild to function properly on widgets such as Form which fail to properly set default width/height to a non-zero value */ if (nb->notebook.first_change_managed && (!XtWidth(child) && !XtHeight(child))) { XtWidth(child) = 10; XtHeight(child) = 10; HideChild(child, instigator); XtWidth(child) = 0; XtHeight(child) = 0; } else HideChild(child, instigator); } } } /* Show the page scroller */ if (nb->notebook.scroller != NULL) { child = nb->notebook.scroller; ShowChild(child, instigator, x2, y1, nb->notebook.scroller_width, nb->notebook.scroller_height); } } /*- LayoutMajorTabs --------------------------------------------------------- Function to layout major tabs -----------------------------------------------------------------------------*/ static void LayoutMajorTabs ( XmNotebookWidget nb, Widget instigator) { XmNotebookConstraint nc; /* constraint pointer */ Widget child; /* a major tab widget */ Widget join_child = NULL; /* top major and joinSide tab */ int x, y, tmpx, tmpy; /* tab's geometry */ int tab_count; /* # of tabs shown */ int margin_w, margin_h; /* temporary margin value */ int sx1, sy1, sx2, sy2; /* tab scroller position */ int fixed; /* back page fixed position */ int limit; /* the last possible position */ int delta, spacing; /* major tab spacing */ int first_major, top_major; /* page# of first and top major tabs */ unsigned char prev, next; /* for tab scroller arrow direction */ Boolean gray_prev, gray_next; /* True if need to gray out scrollers */ int i; unsigned char direction; int total_major_tabs, top_tab_count, current_tab = 0; /* * Initialize */ first_major = nb->notebook.first_major ? NotebookConstraint(nb->notebook.first_major)->page_number : nb->notebook.first_page_number - 1; top_major = nb->notebook.top_major ? NotebookConstraint(nb->notebook.top_major)->page_number : nb->notebook.first_page_number - 1; gray_prev = gray_next = True; sx1 = sy1 = sx2 = sy2 = 0; /* * Determine tab margin spacing and tab staggering */ spacing = MAX(nb->notebook.major_spacing, nb->notebook.shadow_thickness); delta = nb->notebook.back_page_size / nb->notebook.real_back_page_number; /* * Determine tab positions */ if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ x = nb->notebook.real_binding_width + nb->notebook.frame_width; y = nb->notebook.back_page_size; fixed = x + nb->notebook.back_page_size; limit = nb->notebook.frame_height - nb->notebook.major_height - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = fixed; sy1 = y; sy2 = sy1 + nb->notebook.frame_height - nb->notebook.major_scroller_height; limit = nb->notebook.frame_height - MAX(0, (int)(nb->notebook.major_scroller_height - nb->notebook.back_page_size)) - nb->notebook.major_height - nb->notebook.shadow_thickness; y += nb->notebook.major_scroller_height + spacing; } else y += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_UP; next = XmARROW_DOWN; } else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmVERTICAL) { /* set starting position */ x = nb->notebook.back_page_size; y = nb->notebook.real_binding_width + nb->notebook.frame_height; fixed = y + nb->notebook.back_page_size; limit = nb->notebook.frame_width - nb->notebook.major_width - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = fixed; sx1 = x; sx2 = sx1 + nb->notebook.frame_width - nb->notebook.major_scroller_width; limit = nb->notebook.frame_width - MAX(0, (int)(nb->notebook.major_scroller_width - nb->notebook.back_page_size)) - nb->notebook.major_width - nb->notebook.shadow_thickness; x += nb->notebook.major_scroller_width + spacing; } else x += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_LEFT; next = XmARROW_RIGHT; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) +1; x = margin_w + nb->notebook.back_page_size - nb->notebook.major_width; y = nb->notebook.back_page_size; fixed = x - nb->notebook.back_page_size; limit = nb->notebook.frame_height - nb->notebook.major_height - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width; sy1 = y; sy2 = y + nb->notebook.frame_height - nb->notebook.major_scroller_height; limit = nb->notebook.frame_height - MAX(0, (int)(nb->notebook.major_scroller_height - nb->notebook.back_page_size)) - nb->notebook.major_height - nb->notebook.shadow_thickness; y += nb->notebook.major_scroller_height + spacing; } else y += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_UP; next = XmARROW_DOWN; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmVERTICAL) { /* set starting position */ margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width); x = margin_w + nb->notebook.frame_width - nb->notebook.major_width; y = nb->notebook.real_binding_width + nb->notebook.frame_height; fixed = y + nb->notebook.back_page_size; limit = margin_w + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = fixed; sx1 = margin_w + nb->notebook.frame_width - nb->notebook.major_scroller_width; sx2 = margin_w; limit = margin_w + MAX(nb->notebook.back_page_size, nb->notebook.major_scroller_width) + nb->notebook.shadow_thickness; x -= nb->notebook.major_scroller_width + spacing; } else x -= spacing; /* set arrow direction resource */ prev = XmARROW_RIGHT; next = XmARROW_LEFT; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height); x = nb->notebook.real_binding_width + nb->notebook.frame_width; y = margin_h + nb->notebook.frame_height - nb->notebook.major_height; fixed = x + nb->notebook.back_page_size; limit = margin_h + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = fixed; sy1 = margin_h + nb->notebook.frame_height - nb->notebook.minor_scroller_height; sy2 = margin_h; limit = margin_h + MAX(nb->notebook.back_page_size, nb->notebook.major_scroller_height) + nb->notebook.shadow_thickness; y -= nb->notebook.major_scroller_height + spacing; } else y -= spacing; /* set arrow direction resource */ prev = XmARROW_DOWN; next = XmARROW_UP; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmVERTICAL) { /* set starting position */ margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) +1; x = nb->notebook.back_page_size; y = margin_h + nb->notebook.back_page_size - nb->notebook.major_height; fixed = margin_h - nb->notebook.major_height; limit = nb->notebook.frame_width - nb->notebook.major_width - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = margin_h - nb->notebook.major_scroller_height; sx1 = x; sx2 = nb->notebook.frame_width + nb->notebook.back_page_size - nb->notebook.major_scroller_width; limit = nb->notebook.frame_width - MAX(0, (int)(nb->notebook.major_scroller_width - nb->notebook.back_page_size)) - nb->notebook.major_width - nb->notebook.shadow_thickness; x += nb->notebook.major_scroller_width + spacing; } else x += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_LEFT; next = XmARROW_RIGHT; } else if (nb->notebook.back_page_pos == XmTOP_LEFT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) +1; margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) +1; x = margin_w + nb->notebook.back_page_size - nb->notebook.major_width; y = margin_h + nb->notebook.frame_height - nb->notebook.major_height; fixed = x - nb->notebook.back_page_size; limit = margin_h + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width; sy1 = margin_h + nb->notebook.frame_height - nb->notebook.major_scroller_height; sy2 = margin_h; limit = margin_h + MAX(nb->notebook.back_page_size, nb->notebook.major_scroller_height) + nb->notebook.shadow_thickness; y -= nb->notebook.major_scroller_height + spacing; } else y -= spacing; /* set arrow direction resource */ prev = XmARROW_DOWN; next = XmARROW_UP; } else { /* set starting position */ margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) +1; margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) +1; x = margin_w + nb->notebook.frame_width - nb->notebook.major_width; y = margin_h + nb->notebook.back_page_size - nb->notebook.major_height; fixed = y - nb->notebook.back_page_size; limit = margin_w + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = margin_h - nb->notebook.major_scroller_height; sx1 = margin_w + nb->notebook.frame_width - nb->notebook.major_scroller_width; sx2 = margin_w; limit = margin_w + MAX(nb->notebook.back_page_size, nb->notebook.major_scroller_width) + nb->notebook.shadow_thickness; x -= nb->notebook.major_scroller_width + spacing; } else x -= spacing; /* set arrow direction resource */ prev = XmARROW_RIGHT; next = XmARROW_LEFT; } /* * Deal with previous top and current top tab shadowing */ /* Inform old top major to restore shadow_thickness */ if (nb->notebook.old_top_major != NULL && nb->notebook.old_top_major != nb->notebook.top_major) { /* Protect against geometry requests during join changes */ nb->notebook.in_setshadow = True; /* Inform join-aware tab else restore shadow thickness */ if (!UpdateJoinSide(nb, nb->notebook.old_top_major, XmMAJOR_TAB, (Dimension)0)) { /* Hide the old top major shadow */ HideShadowedTab(nb, nb->notebook.old_top_major); /* Restore child shadow thickness */ XtVaSetValues(nb->notebook.old_top_major, XmNshadowThickness, nb->notebook.major_shadow_thickness, NULL); } /* Release protection against geometry requests */ nb->notebook.in_setshadow = False; } /* Store & set new top major's shadow */ if (nb->notebook.top_major != NULL) { /* Hide the top major shadow, as it may be moving (shown or hidden) */ HideShadowedTab(nb, nb->notebook.top_major); /* Protect against geometry requests during join changes */ nb->notebook.in_setshadow = True; /* Set shadow thickness of new top tab */ if (!UpdateJoinSide(nb, nb->notebook.top_major, XmMAJOR_TAB, nb->notebook.shadow_thickness)) { /* Save shadow_thickness of top tab, unless we already have */ if (nb->notebook.top_major != nb->notebook.major_shadow_child) { XtVaGetValues(nb->notebook.top_major, XmNshadowThickness, &(nb->notebook.major_shadow_thickness), NULL); nb->notebook.major_shadow_child = nb->notebook.top_major; } else { /* CR 9903: The application may have set shadow_thickness. */ Dimension current = 0; XtVaGetValues(nb->notebook.top_major, XmNshadowThickness, ¤t, NULL); if (current != 0) nb->notebook.major_shadow_thickness = current; } /* Notebook will draw shadow for non-JoinSide trait tabs */ XtVaSetValues(nb->notebook.top_major, XmNshadowThickness, 0, NULL); } else join_child = nb->notebook.top_major; /* Release protection against geometry requests */ nb->notebook.in_setshadow = False; } else /* There is no top tab so advance to the first back page line */ { if (nb->notebook.major_pos == RIGHT) x += delta; else if (nb->notebook.major_pos == LEFT) x -= delta; else if (nb->notebook.major_pos == BOTTOM) y += delta; else /* if (nb->notebook.major_pos == TOP) */ y -= delta; } /* * FIX for CDExc23791 */ total_major_tabs = 0; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (NB_IS_CHILD_MAJOR(nc->child_type)) total_major_tabs++; if ( child == nb->notebook.top_major) top_tab_count = total_major_tabs; } /* * Layout major tabs */ tab_count = 0; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (NB_IS_CHILD_MAJOR(nc->child_type)) { if (!nc->active) HideChild(child, instigator); else if (nc->page_number < first_major) { HideChild(child, instigator); gray_prev = False; } else if ((nb->notebook.minor_pos == BOTTOM && y > limit) || (nb->notebook.minor_pos == TOP && y < limit) || (nb->notebook.minor_pos == RIGHT && x > limit) || (nb->notebook.minor_pos == LEFT && x < limit)) { HideChild(child, instigator); gray_next = False; } else { /* Display the tab */ if ( current_tab < top_tab_count - 1 ) { /* * FIX for CDExc23791 */ if (nb->notebook.orientation == XmHORIZONTAL) { if (nb->notebook.major_pos == RIGHT) tmpx = x + ( total_major_tabs + 1 - top_tab_count + current_tab) * delta; else tmpx = x - ( total_major_tabs + 1 - top_tab_count + current_tab) * delta; tmpy = y; } else { tmpx = x; if (nb->notebook.major_pos == TOP) tmpy = y - (total_major_tabs + 1 - top_tab_count + current_tab) * delta; else tmpy = y + (total_major_tabs + 1 - top_tab_count + current_tab) * delta; } } else { tmpx = x; tmpy = y; } if (/*(nb->notebook.orientation == XmHORIZONTAL && nc->page_number < top_major) ||*/ (nb->notebook.major_pos == RIGHT && tmpx > fixed) || (nb->notebook.major_pos == LEFT && tmpx < fixed)) { tmpx = fixed; } else if (/*(nb->notebook.orientation == XmVERTICAL && nc->page_number < top_major) ||*/ (nb->notebook.major_pos == BOTTOM && tmpy > fixed) || (nb->notebook.major_pos == TOP && tmpy < fixed)) { tmpy = fixed; } /* move joinSide top tab over to align with frame */ if ((join_child && (join_child == child)) || (nb->notebook.top_major && (nb->notebook.top_major == child))) { if (nb->notebook.major_pos == LEFT) tmpx = tmpx + nb->notebook.shadow_thickness; else if (nb->notebook.major_pos == RIGHT) tmpx = tmpx - nb->notebook.shadow_thickness; else if (nb->notebook.major_pos == TOP) tmpy = tmpy + nb->notebook.shadow_thickness; else /* (nb->notebook.major_pos == BOTTOM) */ tmpy = tmpy - nb->notebook.shadow_thickness; } /* Make tab visible */ ShowChild(child, instigator, tmpx, tmpy, nb->notebook.major_width, nb->notebook.major_height); tab_count++; /* Calculate the next position */ if (nb->notebook.minor_pos == BOTTOM) y += nb->notebook.major_height + spacing; else if (nb->notebook.minor_pos == TOP) y -= nb->notebook.major_height + spacing; else if (nb->notebook.minor_pos == RIGHT) x += nb->notebook.major_width + spacing; else /* (nb->notebook.minor_pos == LEFT) */ x -= nb->notebook.major_width + spacing; } /* to the next back page line */ if (nc->page_number >= top_major) { if (nb->notebook.major_pos == RIGHT) x += delta; else if (nb->notebook.major_pos == LEFT) x -= delta; else if (nb->notebook.major_pos == BOTTOM) y += delta; else y -= delta; } current_tab++; } /* if */ } /* for */ /* * Display the tab scrolling tab, if neccessary */ if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller) && tab_count) { /* set scroller's arrow directions */ XtVaGetValues(nb->notebook.prev_major, XmNarrowDirection, &direction, NULL); if (direction != prev) XtVaSetValues(nb->notebook.prev_major, XmNarrowDirection, prev, NULL); XtVaGetValues(nb->notebook.next_major, XmNarrowDirection, &direction, NULL); if (direction != next) XtVaSetValues(nb->notebook.next_major, XmNarrowDirection, next, NULL); /* Gray out scrollers, if necessary */ if (gray_prev) XtSetSensitive(nb->notebook.prev_major, False); else XtSetSensitive(nb->notebook.prev_major, True); if (gray_next) XtSetSensitive(nb->notebook.next_major, False); else XtSetSensitive(nb->notebook.next_major, True); /* show the scrollers */ ShowChild(nb->notebook.prev_major, instigator, sx1, sy1, nb->notebook.major_scroller_width, nb->notebook.major_scroller_height); ShowChild(nb->notebook.next_major, instigator, sx2, sy2, nb->notebook.major_scroller_width, nb->notebook.major_scroller_height); } else { HideChild(nb->notebook.prev_major, instigator); HideChild(nb->notebook.next_major, instigator); } } /*- LayoutMinorTabs --------------------------------------------------------- Function to layout minor tabs -----------------------------------------------------------------------------*/ static void LayoutMinorTabs ( XmNotebookWidget nb, Widget instigator) { XmNotebookConstraint nc; /* constraint pointer */ Widget child; /* a major tab widget */ Widget join_child = NULL; /* top minor and joinSide tab */ int x, y, tmpx, tmpy; /* tab's geometry */ int tab_count; /* # of tabs shown */ int backpage_h; /* temporary backpage value */ int margin_w, margin_h; /* temporary margin value */ int sx1, sy1, sx2, sy2; /* tab scroller position */ int fixed; /* back page fixed position */ int limit; /* the last possible position */ int spacing; /* major tab spacing */ int status; /* minor tab drawing status */ int top_major; /* page# of the top major tab */ int first_minor, top_minor; /* page# of first and top minor tabs */ unsigned char prev, next; /* for tab scroller arrow direction */ Boolean gray_prev, gray_next; /* True if need to gray out scrollers */ int i; unsigned char direction; int offset = 0; /* * Initialize */ top_major = nb->notebook.top_major ? NotebookConstraint(nb->notebook.top_major)->page_number : nb->notebook.first_page_number - 1; first_minor = nb->notebook.first_minor ? NotebookConstraint(nb->notebook.first_minor)->page_number : nb->notebook.first_page_number - 1; top_minor = nb->notebook.top_minor ? NotebookConstraint(nb->notebook.top_minor)->page_number : nb->notebook.first_page_number - 1; gray_prev = gray_next = True; sx1 = sy1 = sx2 = sy2 = 0; if ( nb->notebook.shadow_thickness == 0 ) offset = 1; /* * Determine tap spacing */ spacing = MAX(nb->notebook.minor_spacing, nb->notebook.shadow_thickness); /* * Determine tab positions */ if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ x = MAX((nb->notebook.real_binding_width + 1 + offset), nb->notebook.back_page_size); y = nb->notebook.frame_height; fixed = y + NB_MINOR_TAB_STEP(nb->notebook.back_page_size); limit = nb->notebook.real_binding_width + nb->notebook.frame_width - nb->notebook.minor_width - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = y + nb->notebook.back_page_size; sx1 = x; sx2 = nb->notebook.real_binding_width + nb->notebook.frame_width + nb->notebook.back_page_size - nb->notebook.minor_scroller_width; limit = nb->notebook.real_binding_width + nb->notebook.frame_width - nb->notebook.minor_width - nb->notebook.shadow_thickness - MAX(0, (int)(nb->notebook.minor_scroller_width - nb->notebook.back_page_size)); x += nb->notebook.minor_scroller_width + spacing; } else x += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_LEFT; next = XmARROW_RIGHT; } else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmVERTICAL) { /* set starting position */ backpage_h = 1; if (nb->notebook.back_page_size > nb->notebook.real_binding_width) backpage_h = nb->notebook.back_page_size - nb->notebook.real_binding_width; x = nb->notebook.frame_width; y = nb->notebook.real_binding_width + backpage_h + offset; fixed = x + NB_MINOR_TAB_STEP(nb->notebook.back_page_size); limit = nb->notebook.real_binding_width + nb->notebook.frame_height - nb->notebook.minor_height - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = x + nb->notebook.back_page_size; sy1 = y; sy2 = nb->notebook.real_binding_width + nb->notebook.frame_height + nb->notebook.back_page_size - nb->notebook.minor_scroller_height; limit = nb->notebook.real_binding_width + nb->notebook.frame_height - MAX(0, (int)(nb->notebook.minor_scroller_height - nb->notebook.back_page_size)) - nb->notebook.minor_height - nb->notebook.shadow_thickness; y += nb->notebook.minor_scroller_height + spacing; } else y += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_UP; next = XmARROW_DOWN; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width); x = margin_w + nb->notebook.back_page_size + nb->notebook.frame_width - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - nb->notebook.minor_width - offset; y = nb->notebook.frame_height; fixed = y + NB_MINOR_TAB_STEP(nb->notebook.back_page_size); limit = margin_w + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = y + nb->notebook.back_page_size; sx1 = margin_w + nb->notebook.back_page_size + nb->notebook.frame_width - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - nb->notebook.minor_scroller_width; sx2 = margin_w; limit = margin_w + MAX(nb->notebook.minor_scroller_width, nb->notebook.back_page_size) + nb->notebook.shadow_thickness; x -= nb->notebook.minor_scroller_width + spacing; } else x -= nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_RIGHT; next = XmARROW_LEFT; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmVERTICAL) { /* set starting position */ margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) +1; x = margin_w + nb->notebook.back_page_size - nb->notebook.minor_width; y = MAX((nb->notebook.real_binding_width + 1 + offset), nb->notebook.back_page_size); fixed = margin_w + NB_MINOR_TAB_STEP(nb->notebook.back_page_size) - nb->notebook.minor_width; limit = nb->notebook.real_binding_width + nb->notebook.frame_height - nb->notebook.minor_height - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width; sy1 = y; sy2 = nb->notebook.real_binding_width + nb->notebook.frame_height + nb->notebook.back_page_size - nb->notebook.minor_scroller_height; limit = nb->notebook.real_binding_width + nb->notebook.frame_height - MAX(0, (int)(nb->notebook.minor_scroller_height - nb->notebook.back_page_size)) - nb->notebook.minor_height - nb->notebook.shadow_thickness; y += nb->notebook.minor_scroller_height + spacing; } else y += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_UP; next = XmARROW_DOWN; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) + 1; x = MAX((nb->notebook.real_binding_width + 1 + offset), nb->notebook.back_page_size); y = margin_h + nb->notebook.back_page_size - nb->notebook.minor_height; fixed = margin_h + NB_MINOR_TAB_STEP(nb->notebook.back_page_size) - nb->notebook.minor_height; limit = nb->notebook.real_binding_width + nb->notebook.frame_width - nb->notebook.minor_width - nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = margin_h - nb->notebook.minor_scroller_height; sx1 = x; sx2 = nb->notebook.real_binding_width + nb->notebook.frame_width + nb->notebook.back_page_size - nb->notebook.minor_scroller_width; limit = nb->notebook.real_binding_width + nb->notebook.frame_width - MAX(0, (int)(nb->notebook.minor_scroller_width - nb->notebook.back_page_size)) - nb->notebook.minor_width - nb->notebook.shadow_thickness; x += nb->notebook.minor_scroller_width + spacing; } else x += nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_LEFT; next = XmARROW_RIGHT; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmVERTICAL) { /* set starting position */ backpage_h = 0; if (nb->notebook.back_page_size > nb->notebook.real_binding_width) backpage_h = nb->notebook.back_page_size - nb->notebook.real_binding_width; margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height); x = nb->notebook.frame_width; y = margin_h + nb->notebook.back_page_size + nb->notebook.frame_height - nb->notebook.minor_height - backpage_h - offset; fixed = x + NB_MINOR_TAB_STEP(nb->notebook.back_page_size); limit = margin_h + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = x + nb->notebook.back_page_size; sy1 = margin_h + nb->notebook.back_page_size + nb->notebook.frame_height - nb->notebook.minor_scroller_height - backpage_h; sy2 = margin_h; limit = margin_h + MAX(nb->notebook.back_page_size, nb->notebook.minor_scroller_height) + nb->notebook.shadow_thickness; y -= (nb->notebook.minor_scroller_height + spacing); } else y -= nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_DOWN; next = XmARROW_UP; } else if (nb->notebook.back_page_pos == XmTOP_LEFT && nb->notebook.orientation == XmHORIZONTAL) { /* set starting position */ margin_w = NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width); margin_h = NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) +1; x = margin_w + nb->notebook.back_page_size + nb->notebook.frame_width - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - nb->notebook.minor_width - offset; y = margin_h + nb->notebook.back_page_size - nb->notebook.minor_height; fixed = y - NB_MINOR_TAB_STEP(nb->notebook.back_page_size); limit = margin_w + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sy1 = sy2 = margin_h - nb->notebook.minor_scroller_height; sx1 = margin_w + nb->notebook.back_page_size + nb->notebook.frame_width - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - nb->notebook.minor_scroller_width; sx2 = margin_w; limit = margin_w + MAX(nb->notebook.minor_scroller_width, nb->notebook.back_page_size) + nb->notebook.shadow_thickness; x -= nb->notebook.minor_scroller_width + spacing; } else x -= nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_RIGHT; next = XmARROW_LEFT; } else /* if (nb->notebook.back_page_pos == XmTOP_LEFT && nb->notebook.orientation == XmVERTICAL) */ { /* set starting position */ margin_w = NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) + 1; margin_h = NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height); x = margin_w + nb->notebook.back_page_size - nb->notebook.minor_width; y = margin_h + nb->notebook.back_page_size + nb->notebook.frame_height - nb->notebook.minor_height - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - offset; fixed = x - NB_MINOR_TAB_STEP(nb->notebook.back_page_size); limit = margin_h + nb->notebook.back_page_size + nb->notebook.shadow_thickness; if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller)) { sx1 = sx2 = margin_w - nb->notebook.minor_scroller_width; sy1 = margin_h + nb->notebook.back_page_size + nb->notebook.frame_height - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - nb->notebook.minor_scroller_height; sy2 = margin_h; limit = margin_h + MAX(nb->notebook.back_page_size, nb->notebook.minor_scroller_height) + nb->notebook.shadow_thickness; y -= nb->notebook.minor_scroller_height + spacing; } else y -= nb->notebook.shadow_thickness; /* set arrow direction resource */ prev = XmARROW_DOWN; next = XmARROW_UP; } /* * Deal with previous top and current top tab shadowing */ /* Inform old top minor to restore shadow_thickness */ if (nb->notebook.old_top_minor != NULL && nb->notebook.old_top_minor != nb->notebook.top_minor) { /* Protect against geometry requests during join changes */ nb->notebook.in_setshadow = True; /* Inform join-aware tab else restore shadow thickness */ if (!UpdateJoinSide(nb, nb->notebook.old_top_minor, XmMINOR_TAB, (Dimension)0)) { /* Hide the old top minor shadow */ HideShadowedTab(nb, nb->notebook.old_top_minor); /* Restore the old top minor shadow thickness */ XtVaSetValues(nb->notebook.old_top_minor, XmNshadowThickness, nb->notebook.minor_shadow_thickness, NULL); } /* Release protection against geometry requests */ nb->notebook.in_setshadow = False; } /* Store & set new top minor's shadow */ if (nb->notebook.top_minor != NULL) { /* Hide the top minor shadow, as it may be moving (shown or hidden) */ HideShadowedTab(nb, nb->notebook.top_minor); /* Protect against geometry requests during join changes */ nb->notebook.in_setshadow = True; /* Set shadow thickness of new top tab */ if (!UpdateJoinSide(nb, nb->notebook.top_minor, XmMINOR_TAB, nb->notebook.shadow_thickness)) { /* Save shadow_thickness of top tab, unless we already have */ if (nb->notebook.top_minor != nb->notebook.minor_shadow_child) { /* Save shadow_thickness of top tab, unless already saved */ XtVaGetValues(nb->notebook.top_minor, XmNshadowThickness, &(nb->notebook.minor_shadow_thickness), NULL); nb->notebook.minor_shadow_child = nb->notebook.top_minor; } else { /* CR 9903: The application may have set shadow_thickness. */ Dimension current = 0; XtVaGetValues(nb->notebook.top_minor, XmNshadowThickness, ¤t, NULL); if (current != 0) nb->notebook.minor_shadow_thickness = current; } /* Notebook will draw shadow */ XtVaSetValues(nb->notebook.top_minor, XmNshadowThickness, 0, NULL); } else join_child = nb->notebook.top_minor; /* Release protection against geometry requests */ nb->notebook.in_setshadow = False; } /* * Layout major tabs */ status = TAB_DRAW; tab_count = 0; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (first_minor < nb->notebook.first_page_number || (nc->active && NB_IS_CHILD_MAJOR(nc->child_type) && (status == TAB_DRAWING || nc->page_number > first_minor))) status = TAB_DRAWN; if (NB_IS_CHILD_MINOR(nc->child_type)) { if (!nc->active || status == TAB_DRAWN) HideChild(child, instigator); else if (nc->page_number < first_minor) { if (nc->page_number >= top_major) gray_prev = False; HideChild(child, instigator); } else if ((nb->notebook.binding_pos == LEFT && x > limit) || (nb->notebook.binding_pos == RIGHT && x < limit) || (nb->notebook.binding_pos == TOP && y > limit) || (nb->notebook.binding_pos == BOTTOM && y < limit)) { gray_next = False; HideChild(child, instigator); } else { /* Display the tab */ status = TAB_DRAWING; tmpx = x; tmpy = y; if (nc->page_number != top_minor) { if (nb->notebook.orientation == XmHORIZONTAL) tmpy = fixed; else tmpx = fixed; } /* move joinSide top tab over to align with frame */ if ((join_child && (join_child == child)) || (nb->notebook.top_minor && (nb->notebook.top_minor == child))) { if (nb->notebook.minor_pos == LEFT) tmpx = tmpx + nb->notebook.shadow_thickness; else if (nb->notebook.minor_pos == RIGHT) tmpx = tmpx - nb->notebook.shadow_thickness; else if (nb->notebook.minor_pos == TOP) tmpy = tmpy + nb->notebook.shadow_thickness; else if (nb->notebook.minor_pos == BOTTOM) tmpy = tmpy - nb->notebook.shadow_thickness; } /* Make tab visible */ ShowChild(child, instigator, tmpx, tmpy, nb->notebook.minor_width, nb->notebook.minor_height); tab_count++; /* Calculate the next position */ if (nb->notebook.binding_pos == LEFT) x += nb->notebook.minor_width + spacing; else if (nb->notebook.binding_pos == RIGHT) x -= nb->notebook.minor_width + spacing; else if (nb->notebook.binding_pos == TOP) y += nb->notebook.minor_height + spacing; else y -= nb->notebook.minor_height + spacing; } } } /* display the tab scrolling tab if neccessary */ if (NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller) && tab_count) { /* set scroller's arrow directions */ XtVaGetValues(nb->notebook.prev_minor, XmNarrowDirection, &direction, NULL); if (direction != prev) XtVaSetValues(nb->notebook.prev_minor, XmNarrowDirection, prev, NULL); XtVaGetValues(nb->notebook.next_minor, XmNarrowDirection, &direction, NULL); if (direction != next) XtVaSetValues(nb->notebook.next_minor, XmNarrowDirection, next, NULL); /* gray out scrollers if necessary */ if (gray_prev) XtSetSensitive(nb->notebook.prev_minor, False); else XtSetSensitive(nb->notebook.prev_minor, True); if (gray_next) XtSetSensitive(nb->notebook.next_minor, False); else XtSetSensitive(nb->notebook.next_minor, True); /* show the scrollers */ ShowChild(nb->notebook.prev_minor, instigator, sx1, sy1, nb->notebook.minor_scroller_width, nb->notebook.minor_scroller_height); ShowChild(nb->notebook.next_minor, instigator, sx2, sy2, nb->notebook.minor_scroller_width, nb->notebook.minor_scroller_height); } else { HideChild(nb->notebook.prev_minor, instigator); HideChild(nb->notebook.next_minor, instigator); } } /*- ResetTopPointers -------------------------------------------------------- Function to calculate and update needed information to perform layout for major and minor tabs, and the tab scroller. Uses instance state: notebook.current_page_number Updates instance state: notebook.first_major - page# of the first visible major tab notebook.first_minor - page# of the first visible minor tab notebook.top_major - page# of the currently active major tab notebook.top_minor - page# of the currently active minor tab notebook.need_scroller - tab scroller necessary, where XmNONE indicates none, XmMAJOR_TAB_SCROLLER indicates major only, XmMINOR_TAB_SCROLLER indicates minor only, XmTAB_SCROLLER indicates both are needed. Called from: LayoutChildren(), when performing layout GotoPage(), when changing the top pages FlipTabs(), when tab scrolling are activated TraverseTab(), when tab traverse actions are activated Parameters: IN reason - Why was this routine called? where XmNONE = reset all information XmPAGE = reset due to a page navigation (general) XmPAGE_SCROLLER = reset due to navigating via the page scroller XmMAJOR_TAB = reset due to activating a minor tab XmMINOR_TAB = reset due to activating a major tab XmMAJOR_TAB_SCROLLER = reset due to major scroller activation XmMINOR_TAB_SCROLLER = reset due to minor scroller activation IN scroll - What type of scrolling where _NEXT = scroll to the next major/minor tab _PREV = scroll to the previous major/minor tab _HOME = scroll to the first major/minor tab _END = scroll to the last major/minor tab (only used for reason == NB_IS_CHILD_MAJOR_SCROLLER or NB_IS_CHILD_MINOR_SCROLLER) -----------------------------------------------------------------------------*/ static void ResetTopPointers ( XmNotebookWidget nb, unsigned char reason, int scroll) { XmNotebookConstraint nc; /* constraint pointer */ Widget child; /* a tab widget */ int i; /* index */ int spacing; /* tab spacing */ int half; int count; /* temporary counting */ Dimension frame_dim, tab_dim, scroller_dim; /* temporary w/h */ /* major tab information */ Widget start_major; /* the very first major tab */ Widget top_major; /* the currently major tab */ Widget next_major; /* the next major tab of first_major */ Widget prev_major; /* the prev major tab of first_major */ int first_major_page; /* page# of the first visible major tab */ int top_major_page; /* page# of the current major tab */ int top_major_idx; /* top major tab's index in the child array */ int num_major; /* # of major tabs */ int num_visible_major; /* # of visible major tabs */ int num_rest_major; /* # of next major tabs of the current page */ int num_next_major; /* # of next major tabs of first_major */ int num_prev_major; /* # of prev major tabs of first_major */ /* minor tab information */ Widget start_minor; /* the first minor tab in the current major */ Widget top_minor; /* the current minor tab */ Widget next_minor; /* the next minor tab of first_minor */ Widget prev_minor; /* the prev minor tab of first_minor */ int first_minor_page; /* page# of the first visible minor tab */ int top_minor_page; /* page# of the current minor tab */ int top_minor_idx; /* top minor tab's index in the child array */ int start_minor_idx; /* start minor tab's index in the child array */ int end_minor_idx; /* end minor tab's index in the child array */ int num_minor; /* # of minor tabs */ int num_visible_minor; /* # of visible minor tabs */ int num_rest_minor; /* # of next minor tabs of the current page */ int num_next_minor; /* # of next minor tabs of first_minor */ int num_prev_minor; /* # of prev minor tabs of first_minor */ /* * Calculate general tab information, based on the current_page_number. */ /* Major tab */ first_major_page = nb->notebook.first_major ? NotebookConstraint(nb->notebook.first_major)->page_number : nb->notebook.first_page_number - 1; top_major_page = nb->notebook.first_page_number - 1; top_major_idx = -1; start_major = top_major = next_major = prev_major = NULL; num_major = num_rest_major = num_next_major = num_prev_major = 0; for (i=0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->active && NB_IS_CHILD_MAJOR(nc->child_type)) { if (!start_major) /* Mark the very first tab */ start_major = child; if (nc->page_number <= nb->notebook.current_page_number) { /* Mark the closest tab to the current page */ top_major = child; top_major_page = nc->page_number; top_major_idx = i; } else /* Count of tabs past the current page */ num_rest_major++; if (nc->page_number < first_major_page) { /* Mark the closest previous tab to the first visible tab */ prev_major = child; /* Count of tabs prior to the current page */ num_prev_major++; } else if (nc->page_number > first_major_page) { if (!num_next_major) /* Mark the closest next tab to the current page */ next_major = child; /* Count of tabs after the current page */ num_next_major++; } /* Count of all tabs */ num_major++; } } /* Minor tab */ first_minor_page = nb->notebook.first_minor ? NotebookConstraint(nb->notebook.first_minor)->page_number : nb->notebook.first_page_number - 1; top_minor_page = nb->notebook.first_page_number - 1; top_minor_idx = -1; start_minor_idx = end_minor_idx = -1; start_minor = top_minor = next_minor = prev_minor = NULL; num_minor = num_rest_minor = num_next_minor = num_prev_minor = 0; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->active) { /* Break out when next major tab section is reached */ if ( nc->page_number > top_major_page && NB_IS_CHILD_MAJOR(nc->child_type) ) break; /* This minor tab is in the current major tab section */ if ( nc->page_number >= top_major_page && NB_IS_CHILD_MINOR(nc->child_type) ) { if (!num_minor) { /* Mark the first tab in this section */ start_minor = child; start_minor_idx = i; } if (nc->page_number <= nb->notebook.current_page_number) { /* Mark the closest tab to the current page */ top_minor = child; top_minor_page = nc->page_number; top_minor_idx = i; } else { /* Count of tabs past the current page */ num_rest_minor++; } if (nc->page_number < first_minor_page) { /* Mark the closest previous tab to the first visible tab */ prev_minor = child; num_prev_minor++; } else if (nc->page_number > first_minor_page) { if (!num_next_minor) { /* Mark the closest next tab to the current page */ next_minor = child; } /* Count of tabs after the current page */ num_next_minor++; } end_minor_idx = i; num_minor++; } } } /* * Find the number of possibly visible tabs (num_visible_xxx), and * find whether the tab scroller is needed (notebook.need_scroller) */ nb->notebook.need_scroller = XmNONE; /* Major tab */ if (nb->notebook.orientation == XmHORIZONTAL) { frame_dim = nb->notebook.frame_height; tab_dim = MAX(nb->notebook.major_height, 1); /* Avoid div 0 */ scroller_dim = nb->notebook.major_scroller_height; } else /* (nb->notebook.orientation == XmVERTICAL) */ { frame_dim = nb->notebook.frame_width; tab_dim = MAX(nb->notebook.major_width, 1); /* Avoid div 0 */ scroller_dim = nb->notebook.major_scroller_width; } spacing = MAX(nb->notebook.major_spacing, nb->notebook.shadow_thickness); num_visible_major = (int)(frame_dim - nb->notebook.back_page_size - nb->notebook.shadow_thickness) / (int)(tab_dim + spacing); if (num_visible_major < num_major) { nb->notebook.need_scroller = XmMAJOR_TAB_SCROLLER; num_visible_major = (int)(frame_dim - nb->notebook.back_page_size - scroller_dim - MAX(0, (int)(scroller_dim - nb->notebook.back_page_size)) - nb->notebook.shadow_thickness ) / (int)(tab_dim + spacing); } /* Minor tab */ if (nb->notebook.orientation == XmHORIZONTAL) { frame_dim = nb->notebook.frame_width; tab_dim = MAX(nb->notebook.minor_width, 1); /* Avoid div 0 */ scroller_dim = nb->notebook.minor_scroller_width; } else /* (nb->notebook.orientation == XmVERTICAL) */ { frame_dim = nb->notebook.frame_height; tab_dim = MAX(nb->notebook.minor_height, 1); /* Avoid div 0 */ scroller_dim = nb->notebook.minor_scroller_height; } spacing = MAX(nb->notebook.minor_spacing, nb->notebook.shadow_thickness); num_visible_minor = (int)(frame_dim - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - nb->notebook.shadow_thickness) / (int)(tab_dim + spacing); if (num_visible_minor < num_minor) { if (NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller)) nb->notebook.need_scroller = XmTAB_SCROLLER; else nb->notebook.need_scroller = XmMINOR_TAB_SCROLLER; num_visible_minor = (int)(frame_dim - MAX(0, (int)(nb->notebook.back_page_size - nb->notebook.real_binding_width)) - scroller_dim - MAX(0, (int)(scroller_dim - nb->notebook.back_page_size)) - nb->notebook.shadow_thickness) / (int)(tab_dim + spacing); } /* * If tab scrolling, then determine first tab but leave top tab alone. */ /* Major tab */ if (NB_IS_CHILD_MAJOR_SCROLLER(reason)) { if (scroll == _NEXT) { /* If there is a next non-visible tab(s), move up one */ if (num_next_major >= num_visible_major) nb->notebook.first_major = next_major; } else if (scroll == _PREVIOUS) { /* If there is a prev non-visible tab(s), move back one */ if (num_prev_major > 0) nb->notebook.first_major = prev_major; } else if (scroll == _HOME) { /* If there is a starting tab, move to it */ if (start_major) nb->notebook.first_major = start_major; } else if (scroll == _END) { /* Back up from the last tab "num_visible_major" tabs */ for (count = num_visible_major,i = nb->composite.num_children -1; i >= 0 && count > 0; i--) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->active && NB_IS_CHILD_MAJOR(nc->child_type)) { nb->notebook.first_major = child; count--; } } } return; } /* Minor tab */ if (NB_IS_CHILD_MINOR_SCROLLER(reason)) { if (scroll == _NEXT) { if (num_next_minor >= num_visible_minor) nb->notebook.first_minor = next_minor; } else if (scroll == _PREVIOUS) { if (num_prev_minor > 0) nb->notebook.first_minor = prev_minor; } else if (scroll == _HOME) { nb->notebook.first_minor = start_minor; } else if (scroll == _END) { for (count = num_visible_minor,i = end_minor_idx; i >= 0 && i >= start_minor_idx && count > 0; i--) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->active && NB_IS_CHILD_MINOR(nc->child_type)) { nb->notebook.first_minor = child; count--; } } } return; } /* * If going to a new page, then determine if we need to scroll * the tabs to make the top major/minor tabs visible */ if (NB_IS_CHILD_PAGE(reason) || NB_IS_CHILD_PAGE_SCROLLER(reason) || NB_IS_CHILD_MAJOR(reason) || NB_IS_CHILD_MINOR(reason)) { if (top_major && (top_major != nb->notebook.top_major)) { if (NB_IS_VISIBLE(top_major)) reason = XmMAJOR_TAB; } else if (top_minor && (top_minor != nb->notebook.top_minor)) { if (NB_IS_VISIBLE(top_minor)) reason = XmMINOR_TAB; } } /* * Set new top major/minor tabs */ nb->notebook.old_top_major = nb->notebook.top_major; nb->notebook.top_major = top_major; nb->notebook.old_top_minor = nb->notebook.top_minor; nb->notebook.top_minor = top_minor; /* * Determine new first tab for the new top tab. * If apparently activated by a minor tab, we don't need to do anything * because the top major and minor must be visible . * If apparently activated by a major tab, we don't need to do anything. */ /* A page change NOT caused by a major tab activiation */ if (!NB_IS_CHILD_MAJOR(reason) && !NB_IS_CHILD_MINOR(reason)) { /* Set the first tab to the starting tab, if we do not need a page scroller or if the calculated top tab page number is less than the first page number */ if (!NB_IS_CHILD_MAJOR_SCROLLER(nb->notebook.need_scroller) || (top_major_page <= nb->notebook.first_page_number)) nb->notebook.first_major = start_major; /* Set the first tab to the calculated top tab, if it is the only one that might be visible */ else if (num_visible_major <= 1) nb->notebook.first_major = top_major; /* Set the first tab so that the top tab is near the center of the visible tabs */ else { half = num_visible_major /2; half += MAX(((num_visible_major - 1) /2) - num_rest_major, 0); nb->notebook.first_major = top_major; for (i = top_major_idx - 1; i >= 0 && half > 0; i--) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->active && NB_IS_CHILD_MAJOR(nc->child_type)) { nb->notebook.first_major = child; half--; } } } } /* Minor tab */ if (!(NB_IS_CHILD_MINOR(reason))) { /* Set the first tab to the starting tab in this tab section, if we do not need a page scroller or if the calculated top tab page number is less than the first page number */ if (!NB_IS_CHILD_MINOR_SCROLLER(nb->notebook.need_scroller) || (top_minor_page <= nb->notebook.first_page_number)) nb->notebook.first_minor = start_minor; /* Set the first tab to the calculated top tab, if it is the only one that might be visible */ else if (num_visible_minor <= 1) nb->notebook.first_minor = top_minor; /* Set the first tab so that the top tab is near the center of the visible tabs */ else { half = num_visible_minor /2; half += MAX(((num_visible_minor - 1) /2) - num_rest_minor, 0); nb->notebook.first_minor = top_minor; for (i = top_minor_idx - 1; i >= 0 && half > 0; i--) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->active) { if (NB_IS_CHILD_MAJOR(nc->child_type)) break; else if (NB_IS_CHILD_MINOR(nc->child_type)) { nb->notebook.first_minor = child; half--; } } } } } } /***************************************************************************** * * * Drawing Functions * * * *****************************************************************************/ /*- GetFrameGCs ------------------------------------------------------------- Get the GC's for drawing notebook frame and binding -----------------------------------------------------------------------------*/ static void GetFrameGCs ( XmNotebookWidget nb) { XGCValues values; XtGCMask mask, dynamicMask; if (nb->notebook.frame_gc) XtReleaseGC((Widget)nb, nb->notebook.frame_gc); if (nb->notebook.binding_gc) XtReleaseGC((Widget)nb, nb->notebook.binding_gc); dynamicMask = GCForeground; mask = GCForeground | GCBackground | GCLineWidth; values.foreground = nb->manager.foreground; values.background = nb->notebook.frame_background; values.line_width = 1; nb->notebook.frame_gc = XtAllocateGC((Widget)nb, 0, mask, &values, dynamicMask, 0); mask = GCForeground | GCBackground; dynamicMask = (GCFillStyle | GCTile | GCStipple | GCTileStipXOrigin | GCTileStipYOrigin); values.foreground = nb->manager.foreground; values.background = nb->notebook.frame_background; nb->notebook.binding_gc = XtAllocateGC((Widget)nb, 0, mask, &values, dynamicMask, 0); } /*- GetBackpageGCs --------------------------------------------------------- Get the GC's for drawing notebook backpages. These two may be shared with other widgets. -----------------------------------------------------------------------------*/ static void GetBackpageGCs ( XmNotebookWidget nb) { XGCValues values; XtGCMask mask, dynamicMask, unusedMask; if (nb->notebook.foreground_gc) XtReleaseGC((Widget)nb, nb->notebook.foreground_gc); if (nb->notebook.background_gc) XtReleaseGC((Widget)nb, nb->notebook.background_gc); /* Will often be the same as HighlightGC in List */ mask = GCForeground; dynamicMask = (GCLineWidth | GCLineStyle | GCClipMask | GCClipXOrigin | GCClipYOrigin); unusedMask = GCBackground | GCDashList; values.foreground = nb->notebook.back_page_foreground; nb->notebook.foreground_gc = XtAllocateGC((Widget)nb, 0, mask, &values, dynamicMask, unusedMask); /* Will often be the same as InverseGC in List */ mask |= GCGraphicsExposures; dynamicMask = GCClipMask | GCClipXOrigin | GCClipYOrigin; unusedMask = GCBackground | GCFont; values.foreground = nb->notebook.back_page_background; values.graphics_exposures = FALSE; nb->notebook.background_gc = XtAllocateGC((Widget)nb, 0, mask, &values, dynamicMask, unusedMask); } /*- MakeSpiralPixmap ------------------------------------------------------- Makes a spiral binding pixmap. Uses instance state: binding placement (XmNorientation and XmNbackPagePlacement) Updates instance state: spiral_pixmap Parameters: IN width - binding area width IN height - binding area height -----------------------------------------------------------------------------*/ static void MakeSpiralPixmap ( XmNotebookWidget nb, Dimension width, Dimension height) { int rx, ry, rw, rh; /* rectangle values for binding surface */ int sx, sy, sw, sh, sd; /* spiral values */ int a1, a2, a3, a4; /* spiral angle values */ int hx, hy, hd; /* hole values */ int lx1, ly1, lx2, ly2; /* line values for binding edge */ int pw, ph; /* pixmap size */ int gap; /* gap between spirals */ int div; /* division of binding width */ int i; Pixmap pixmap; /* check binding width for reasonable values */ if (width < MIN_DRAWABLE_SPIRAL_SIZE || height < MIN_DRAWABLE_SPIRAL_SIZE) return; /* * Determine spiral component values */ if (nb->notebook.binding_pos == LEFT) { div = width / 3; gap = div / 2; pw = width; ph = div + gap; sx = 0; sy = gap / 2; sw = div * 2; sh = div; sd = sh / 4; a1 = 270 - 20; a2 = -270; a3 = 90 - 20; a4 = 110; hx = sx + sw - sd; hy = sy + (sh / 2) - sd +1; hd = MIN(div, sd * 2); rx = div; ry = 0; rw = width - div; rh = ph; lx1 = div; ly1 = 0; lx2 = lx1; ly2 = ph; } else if (nb->notebook.binding_pos == RIGHT) { div = width / 3; gap = div / 2; pw = width; ph = div + gap; sx = div - 1; sy = gap / 2; sw = div * 2; sh = div; sd = sh / 4; a1 = 275; a2 = 270; a3 = 90 - 10; a4 = 100; hx = sx - (sd / 2); hy = sy + (sh / 2) - sd +1; hd = MIN(div, sd * 2); rx = 0; ry = 0; rw = pw - div; rh = ph; lx1 = pw - div; ly1 = 0; lx2 = lx1; ly2 = rh; } else if (nb->notebook.binding_pos == TOP) { div = height / 3; gap = div / 2; pw = div + gap; ph = height; sx = gap / 2; sy = 0; sw = div; sh = div * 2; sd = sw / 4; a1 = 0 + 15; a2 = 270; a3 = 90; a4 = 110; hx = sx + (sw / 2) - sd +1; hy = sh - sd; hd = MIN(div, sd * 2); rx = 0; ry = div; rw = pw; rh = height - div; lx1 = 0; ly1 = div; lx2 = pw; ly2 = ly1; } else if (nb->notebook.binding_pos == BOTTOM) { div = height / 3; gap = div / 2; pw = div + gap; ph = height; sx = gap / 2; sy = div -1; sw = div; sh = (div * 2); sd = sw / 4; a1 = 360 - 5; a2 = -295; a3 = 90 + 8; a4 = 110; hx = sx + (sw / 2); hy = sy; hd = MIN(div, sd * 2); rx = 0; ry = 0; rw = pw; rh = ph - div; lx1 = 0; ly1 = ph - div; lx2 = pw; ly2 = ly1; } /* * Create spiral pixmap, if previous one exists destroy it */ if (nb->notebook.spiral_pixmap != XmUNSPECIFIED_PIXMAP && nb->notebook.spiral_pixmap != XmNONE) XFreePixmap(XtDisplay(nb), nb->notebook.spiral_pixmap); pixmap = nb->notebook.spiral_pixmap = XCreatePixmap(XtDisplay(nb), XtWindow(nb), pw, ph, nb->core.depth); /* * Scribble in spiral pixmap */ /* Fill pixmap with notebook background */ XFillRectangle(XtDisplay(nb), pixmap, nb->manager.background_GC, 0, 0, pw, ph); /* draw binding surface */ XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->notebook.frame_background); XFillRectangle(XtDisplay(nb), pixmap, nb->notebook.frame_gc, rx, ry, rw, rh); /* draw line along binding surface */ XSetClipMask(XtDisplay(nb), nb->notebook.foreground_gc, None); XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 1, LineSolid, CapRound, JoinMiter); XDrawLine(XtDisplay(nb), pixmap, nb->notebook.foreground_gc, lx1, ly1, lx2, ly2); /* draw hole in binding surface with top/bottom shadows */ XFillArc(XtDisplay(nb), pixmap, nb->manager.background_GC, hx, hy, hd, hd, 0, 360 * 64); XDrawArc(XtDisplay(nb), pixmap, nb->manager.bottom_shadow_GC, hx, hy, hd, hd, 225 * 64, -180 * 64); XDrawArc(XtDisplay(nb), pixmap, nb->manager.top_shadow_GC, hx, hy, hd, hd, 45 * 64, -180 * 64); /* draw spiral with top/bottom shadows */ XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->manager.foreground); XSetLineAttributes(XtDisplay(nb), nb->notebook.frame_gc, 1, LineSolid, CapRound, JoinMiter); for(i=1; i < sd; i++) XDrawArc(XtDisplay(nb), pixmap, nb->notebook.frame_gc, sx +i, sy +i, sw -i, sh -i, a1 * 64, a2 * 64); XSetLineAttributes(XtDisplay(nb), nb->notebook.frame_gc, MAX(0,sd -2), LineSolid, CapRound, JoinMiter); XDrawArc(XtDisplay(nb), pixmap, nb->notebook.frame_gc, sx +(sd/2), sy +(sd/2), sw, sh, a3 * 64, a4 * 64); XDrawArc(XtDisplay(nb), pixmap, nb->manager.top_shadow_GC, sx, sy, sw, sh, a1 * 64, a2 * 64); XDrawArc(XtDisplay(nb), pixmap, nb->manager.bottom_shadow_GC, sx +sd, sy +sd, sw -sd, sh -sd, a1 * 64, a2 * 64); } /*- DrawBinding ------------------------------------------------------------- Draw the Notebook binding -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void DrawBinding ( XmNotebookWidget nb, XExposeEvent *event, /* unused */ Region region) { Dimension x, y, width, height; /* check binding type resource and binding width */ if (nb->notebook.binding_type == XmNONE || nb->notebook.real_binding_width <= 0) return; /* get the binding area */ x = y = 0; if (nb->notebook.major_pos == LEFT) x += NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) + nb->notebook.back_page_size + nb->notebook.frame_width; else if (nb->notebook.major_pos == TOP) y += NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) + nb->notebook.back_page_size + nb->notebook.frame_height; if (nb->notebook.minor_pos == LEFT) x += NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) + nb->notebook.back_page_size; else if (nb->notebook.minor_pos == TOP) y += NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) + nb->notebook.back_page_size; if (nb->notebook.orientation == XmHORIZONTAL) { width = nb->notebook.real_binding_width; height = nb->notebook.frame_height - 1; y += 1; } else { width = nb->notebook.frame_width - 1; height = nb->notebook.real_binding_width; x += 1; } /* draw the binding if applicable */ if (XRectInRegion(region, x, y, width, height)) { switch (nb->notebook.binding_type) { case XmSOLID: XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->manager.foreground); XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc, x, y, width, height); break; case XmSPIRAL: MakeSpiralPixmap (nb, width, height); DrawPixmapBinding(nb, x, y, width, height, nb->notebook.spiral_pixmap); break; case XmPIXMAP: DrawPixmapBinding(nb, x, y, width, height, nb->notebook.binding_pixmap); break; case XmPIXMAP_OVERLAP_ONLY: DrawPixmapBinding(nb, x, y, width, height, nb->notebook.binding_pixmap); break; } /* switch */ } /* if */ } /*- DrawPixmapBinding ------------------------------------------------------- Draw the pixmap binding -----------------------------------------------------------------------------*/ static void DrawPixmapBinding ( XmNotebookWidget nb, Dimension x, Dimension y, Dimension width, Dimension height, Pixmap pixmap) { int depth; int x_origin, y_origin; XGCValues values; XtGCMask mask; /* no pixmap? don't draw */ if (pixmap == XmUNSPECIFIED_PIXMAP || pixmap == XmNONE) return; /* get Pixmap depth */ XmeGetPixmapData(XtScreen(nb), pixmap, NULL, &depth, NULL, NULL, NULL, NULL, NULL, NULL); /* creating the gc */ if (depth == 1) { mask = GCFillStyle | GCStipple; values.fill_style = FillStippled; values.stipple = pixmap; } else { mask = GCFillStyle | GCTile; values.fill_style = FillTiled; values.tile = pixmap; } XChangeGC(XtDisplay(nb), nb->notebook.binding_gc, mask, &values); /* * set TSOrigin */ if (nb->notebook.binding_pos == LEFT || nb->notebook.binding_pos == TOP) x_origin = x, y_origin = y; else if (nb->notebook.binding_pos == RIGHT) x_origin = x + width - 1, y_origin = y; else /* if (nb->notebook.binding_pos == BOTTOM) */ x_origin = x, y_origin = y + height; XSetTSOrigin(XtDisplay(nb), nb->notebook.binding_gc, x_origin, y_origin); /* display the pixmap binding */ XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.binding_gc, x, y, width -1, height - 1); } /*- DrawFrameShadow --------------------------------------------------------- Draw the Notebook frame shadow -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void DrawFrameShadow ( XmNotebookWidget nb, XExposeEvent *event, /* unused */ Region region) /* unused */ { Dimension x, y, width, height; Region shadow_region; XRectangle rect; /* get the page's x, y position */ x = y = 1; if (nb->notebook.binding_pos == LEFT) x += nb->notebook.real_binding_width; else if (nb->notebook.binding_pos == TOP) y += nb->notebook.real_binding_width; if (nb->notebook.major_pos == LEFT) x += NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) + nb->notebook.back_page_size; else if (nb->notebook.major_pos == TOP) y += NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) + nb->notebook.back_page_size; if (nb->notebook.minor_pos == LEFT) x += NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) + nb->notebook.back_page_size; else if (nb->notebook.minor_pos == TOP) y += NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) + nb->notebook.back_page_size; width = nb->notebook.frame_width - 2; height = nb->notebook.frame_height - 2; XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->notebook.frame_background); /* draw the frame shadow */ if (nb->notebook.shadow_thickness) { /* draw the shadow */ /* creating the shadow region */ shadow_region = XCreateRegion(); /* adding the frame area to the shadow region */ rect.x = x; rect.y = y; rect.width = width; rect.height = height; XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc, x, y, width + 1, height + 1); XUnionRectWithRegion(&rect, shadow_region, shadow_region); /* adding the top major tab area to the shadow region */ if (nb->notebook.top_major && NB_IS_VISIBLE(nb->notebook.top_major) && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_major)) { rect.x = nb->notebook.top_major->core.x - nb->notebook.shadow_thickness; rect.y = nb->notebook.top_major->core.y - nb->notebook.shadow_thickness; rect.width = nb->notebook.top_major->core.width + nb->notebook.shadow_thickness * 2 - 1; rect.height = nb->notebook.top_major->core.height + nb->notebook.shadow_thickness * 2 - 1; /* ensure x/y of rect does not go negative */ /* this can be removed when _XmRegionDrawShadow is fixed to allow negative y values */ if( rect.x < 0) { rect.width -= rect.x; rect.x = 0; } if( rect.y < 0) { rect.height -= rect.y; rect.y = 0; } XUnionRectWithRegion(&rect, shadow_region, shadow_region); } /* adding the top minor tab area to the shadow region */ if (nb->notebook.top_minor && NB_IS_VISIBLE(nb->notebook.top_minor) && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_minor)) { rect.x = nb->notebook.top_minor->core.x - nb->notebook.shadow_thickness; rect.y = nb->notebook.top_minor->core.y - nb->notebook.shadow_thickness; rect.width = nb->notebook.top_minor->core.width + nb->notebook.shadow_thickness * 2 - 1; rect.height = nb->notebook.top_minor->core.height + nb->notebook.shadow_thickness * 2 - 1; /* ensure x/y of rect does not go negative */ /* this can be removed when _XmRegionDrawShadow is fixed to allow negative y values */ if( rect.x < 0) { rect.width -= rect.x; rect.x = 0; } if( rect.y < 0) { rect.height -= rect.y; rect.y = 0; } XUnionRectWithRegion(&rect, shadow_region, shadow_region); } /* draw the shadow */ _XmRegionDrawShadow(XtDisplay(nb), XtWindow(nb), nb->manager.top_shadow_GC, nb->manager.bottom_shadow_GC, (XmRegion)shadow_region, nb->core.border_width, nb->notebook.shadow_thickness, XmSHADOW_OUT); XDestroyRegion(shadow_region); } else { XFillRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc, x, y, width, height); XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->manager.foreground); XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc, x, y, width, height); if (nb->notebook.top_major && NB_IS_VISIBLE(nb->notebook.top_major) && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_major)) { rect.x = nb->notebook.top_major->core.x - 1; rect.y = nb->notebook.top_major->core.y - 1; rect.width = nb->notebook.top_major->core.width + 1; rect.height = nb->notebook.top_major->core.height + 1; /* ensure x/y of rect does not go negative */ /* this can be removed when _XmRegionDrawShadow is fixed to allow negative y values */ if( rect.x < 0) { rect.width -= rect.x; rect.x = 0; } if( rect.y < 0) { rect.height -= rect.y; rect.y = 0; } XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc, rect.x, rect.y, rect.width, rect.height); } /* adding the top minor tab area to the shadow region */ if (nb->notebook.top_minor && NB_IS_VISIBLE(nb->notebook.top_minor) && !NB_IS_CHILD_JOINSIDE(nb->notebook.top_minor)) { rect.x = nb->notebook.top_minor->core.x - 1; rect.y = nb->notebook.top_minor->core.y - 1; rect.width = nb->notebook.top_minor->core.width + 1; rect.height = nb->notebook.top_minor->core.height + 1; /* ensure x/y of rect does not go negative */ /* this can be removed when _XmRegionDrawShadow is fixed to allow negative y values */ if( rect.x < 0) { rect.width -= rect.x; rect.x = 0; } if( rect.y < 0) { rect.height -= rect.y; rect.y = 0; } XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.frame_gc, rect.x, rect.y, rect.width, rect.height); } } } /*- DrawBackPages ----------------------------------------------------------- Draw Notebook back pages -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void DrawBackPages ( XmNotebookWidget nb, XExposeEvent *event, /* unused */ Region region) { int delta, back; /* backpage foreground & background deltas */ int binding_width; /* the real binding width */ int dx, dy; /* delta-x and delta-y */ int mx, my; /* maximum delta-x and delta-y */ int x, y, limit; /* temporary variables */ XPoint p[5]; /* foreground line pattern */ XPoint q[3]; /* background line pattern */ /* * initialize */ delta = nb->notebook.back_page_size / nb->notebook.real_back_page_number; /* draw backpages on the frame, which is not necessarily along the entire binding */ if (nb->notebook.binding_type == XmPIXMAP) binding_width = MAX(nb->notebook.real_binding_width, nb->notebook.binding_width); else binding_width = MIN(nb->notebook.real_binding_width, nb->notebook.binding_width); /* find back page line pattern */ if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { p[1].x = nb->notebook.real_binding_width - binding_width; p[1].y = nb->notebook.frame_height; p[2].x = binding_width + nb->notebook.frame_width; p[2].y = 0; p[3].x = 0; p[3].y = - nb->notebook.frame_height; p[4].x = - delta; p[4].y = 0; p[0].x = p[1].x; p[0].y = p[1].y - delta; x = 0; y = delta; dx = dy = delta; mx = my = nb->notebook.back_page_size; } else if (nb->notebook.back_page_pos == XmBOTTOM_RIGHT && nb->notebook.orientation == XmVERTICAL) { p[1].x = nb->notebook.frame_width; p[1].y = nb->notebook.real_binding_width - binding_width; p[2].x = 0; p[2].y = binding_width + nb->notebook.frame_height; p[3].x = - nb->notebook.frame_width; p[3].y = 0; p[4].x = 0; p[4].y = - delta; p[0].x = p[1].x - delta; p[0].y = p[1].y; x = delta; y = 0; dx = dy = delta; mx = my = nb->notebook.back_page_size; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmHORIZONTAL) { p[1].x = NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) + nb->notebook.back_page_size + nb->notebook.frame_width + binding_width - 1; p[1].y = nb->notebook.frame_height; p[2].x = - (nb->notebook.frame_width + binding_width); p[2].y = 0; p[3].x = 0; p[3].y = - nb->notebook.frame_height; p[4].x = delta; p[4].y = 0; p[0].x = p[1].x; p[0].y = p[1].y - delta; x = 0; y = delta; dx = - delta; dy = delta; mx = - nb->notebook.back_page_size; my = nb->notebook.back_page_size; } else if (nb->notebook.back_page_pos == XmBOTTOM_LEFT && nb->notebook.orientation == XmVERTICAL) { p[1].x = nb->notebook.back_page_size + NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) - 1; p[1].y = nb->notebook.real_binding_width - binding_width; p[2].x = 0; p[2].y = binding_width + nb->notebook.frame_height; p[3].x = nb->notebook.frame_width; p[3].y = 0; p[4].x = 0; p[4].y = - delta; p[0].x = p[1].x + delta; p[0].y = p[1].y; x = - delta; y = 0; dx = - delta; dy = delta; mx = - nb->notebook.back_page_size; my = nb->notebook.back_page_size; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmHORIZONTAL) { p[1].x = nb->notebook.real_binding_width - binding_width; p[1].y = nb->notebook.back_page_size + NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) - 1; p[2].x = binding_width + nb->notebook.frame_width; p[2].y = 0; p[3].x = 0; p[3].y = nb->notebook.frame_height; p[4].x = - delta; p[4].y = 0; p[0].x = p[1].x; p[0].y = p[1].y + delta; x = 0; y = - delta; dx = delta; dy = - delta; mx = nb->notebook.back_page_size; my = - nb->notebook.back_page_size; } else if (nb->notebook.back_page_pos == XmTOP_RIGHT && nb->notebook.orientation == XmVERTICAL) { p[1].x = nb->notebook.frame_width; p[1].y = nb->notebook.back_page_size + nb->notebook.frame_height + binding_width + NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) - 1; p[2].x = 0; p[2].y = - (binding_width + nb->notebook.frame_height); p[3].x = - nb->notebook.frame_width; p[3].y = 0; p[4].x = 0; p[4].y = delta; p[0].x = p[1].x - delta; p[0].y = p[1].y; x = delta; y = 0; dx = delta; dy = - delta; mx = nb->notebook.back_page_size; my = - nb->notebook.back_page_size; } else if (nb->notebook.back_page_pos == XmTOP_LEFT && nb->notebook.orientation == XmHORIZONTAL) { p[1].x = nb->notebook.back_page_size + nb->notebook.frame_width + binding_width + NB_MAJOR_MAX(nb, nb->notebook.major_width, nb->notebook.major_scroller_width) - 1; p[1].y = nb->notebook.back_page_size + NB_MINOR_MAX(nb, nb->notebook.minor_height, nb->notebook.minor_scroller_height) - 1; p[2].x = - (binding_width + nb->notebook.frame_width); p[2].y = 0; p[3].x = 0; p[3].y = nb->notebook.frame_height; p[4].x = delta; p[4].y = 0; p[0].x = p[1].x; p[0].y = p[1].y + delta; x = 0; y = - delta; dx = - delta; dy = - delta; mx = - nb->notebook.back_page_size; my = - nb->notebook.back_page_size; } else { p[1].x = nb->notebook.back_page_size + NB_MINOR_MAX(nb, nb->notebook.minor_width, nb->notebook.minor_scroller_width) - 1; p[1].y = nb->notebook.back_page_size + nb->notebook.frame_height + binding_width + NB_MAJOR_MAX(nb, nb->notebook.major_height, nb->notebook.major_scroller_height) -1; p[2].x = 0; p[2].y = - (binding_width + nb->notebook.frame_height); p[3].x = nb->notebook.frame_width; p[3].y = 0; p[4].x = 0; p[4].y = delta; p[0].x = p[1].x + delta; p[0].y = p[1].y; x = - delta; y = 0; dx = - delta; dy = - delta; mx = - nb->notebook.back_page_size; my = - nb->notebook.back_page_size; } /* set the clipping region if necessary */ XSetRegion(XtDisplay(nb), nb->notebook.foreground_gc, region); XSetRegion(XtDisplay(nb), nb->notebook.background_gc, region); XSetClipOrigin(XtDisplay(nb), nb->notebook.foreground_gc, 0, 0); XSetClipOrigin(XtDisplay(nb), nb->notebook.background_gc, 0, 0); /* draw the first page outline */ XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 1, LineSolid, CapButt, JoinMiter); if (nb->notebook.binding_type == XmSPIRAL || nb->notebook.binding_type == XmPIXMAP || nb->notebook.binding_type == XmSOLID || nb->notebook.binding_type == XmNONE || nb->notebook.binding_type == XmPIXMAP_OVERLAP_ONLY) { Dimension width, height; Position x, y; /* We can't pass a negative width or height to the draw call. Since it appears that draw functions later in the code need the p values set as above, let's check whether the height and width here are negative and adjust the draw coordinates as appropriate. */ if (nb->notebook.orientation == XmHORIZONTAL) { ADJUST_NEGATIVE_DIMENSION(p[1].x, p[2].x, x, width); ADJUST_NEGATIVE_DIMENSION(p[1].y, p[3].y, y, height); XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc, x, y, width, height); } else { ADJUST_NEGATIVE_DIMENSION(p[1].x, p[3].x, x, width); ADJUST_NEGATIVE_DIMENSION(p[1].y, p[2].y, y, height); XDrawRectangle(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc, x, y, width, height); } } /* for XmSOLID, XmPIXMAP, and XmPIXMAP_OVERLAP_ONLY */ if (nb->notebook.binding_type == XmSOLID || nb->notebook.binding_type == XmPIXMAP || nb->notebook.binding_type == XmPIXMAP_OVERLAP_ONLY) { /* draw back page lines */ x = p[1].x; y = p[1].y; limit = nb->notebook.back_page_size; while (limit > 0) { /* draw backpage foreground */ XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc, &(p[1]), 4, CoordModePrevious); /* draw backpage background */ if (delta >= 2 && limit > delta - 2) { back = delta - 1; q[0].x = p[1].x; q[0].y = p[1].y; q[1].x = p[2].x; q[1].y = p[2].y; q[2].x = p[3].x; q[2].y = p[3].y; q[0].x += NB_ENFORCE_SIGN(dx, 1); q[0].y += NB_ENFORCE_SIGN(dy, 1); if (q[2].x) q[2].x += dx; if (q[2].y) q[2].y += dy; while (back > 0) { XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.background_gc, q, 3, CoordModePrevious); q[0].y += NB_ENFORCE_SIGN(dy, 1); q[0].x += NB_ENFORCE_SIGN(dx, 1); if (q[2].x) q[2].x -= NB_ENFORCE_SIGN(dx, 1); if (q[2].y) q[2].y -= NB_ENFORCE_SIGN(dy, 1); back--; } } p[1].x += dx; p[1].y += dy; limit -= delta; } /* draw the last page line */ p[0].x = x; p[0].y = y; p[1].x = mx; p[1].y = my; XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 2, LineSolid, CapButt, JoinMiter); XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc, p, 5, CoordModePrevious); } /* for XmNONE and XmSPIRAL */ else { /* draw back page lines */ p[1].x = x; p[1].y = y; x = p[0].x; y = p[0].y; limit = nb->notebook.back_page_size; while (limit > 0) { /* draw backpage foreground */ XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc, p, 5, CoordModePrevious); /* draw backpage background */ if (delta >= 2 && limit > delta - 2) { back = delta - 1; q[0].x = p[0].x + p[1].x; q[0].y = p[0].y + p[1].y; q[1].x = p[2].x; q[1].y = p[2].y; q[2].x = p[3].x; q[2].y = p[3].y; q[0].x += NB_ENFORCE_SIGN(dx, 1); q[0].y += NB_ENFORCE_SIGN(dy, 1); if (q[1].x) { q[0].x += dx; q[1].x -= dx; } if (q[1].y) { q[0].y += dy; q[1].y -= dy; } if (q[2].x) q[2].x += dx; if (q[2].y) q[2].y += dy; while (back > 0) { XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.background_gc, q, 3, CoordModePrevious); if (q[1].x) { q[0].y += NB_ENFORCE_SIGN(dy, 1); q[1].x += NB_ENFORCE_SIGN(dx, 1); } if (q[1].y) { q[0].x += NB_ENFORCE_SIGN(dx, 1); q[1].y += NB_ENFORCE_SIGN(dy, 1); } if (q[2].x) q[2].x -= NB_ENFORCE_SIGN(dx, 1); if (q[2].y) q[2].y -= NB_ENFORCE_SIGN(dy, 1); back--; } } p[0].x += dx; p[0].y += dy; limit -= delta; } /* draw the last page line */ p[0].x = x + mx; p[0].y = y + my; XSetLineAttributes(XtDisplay(nb), nb->notebook.foreground_gc, 2, LineSolid, CapButt, JoinMiter); XDrawLines(XtDisplay(nb), XtWindow(nb), nb->notebook.foreground_gc, p, 5, CoordModePrevious); } } /***************************************************************************** * * * Geometry Functions * * * *****************************************************************************/ /*- CalcGeoInfo ------------------------------------------------------------ Calculate Notebook's preferred geometry. Updates instance state: page_width page_height status_width status_height major_width major_height minor_width minor_height scroller_width scroller_height major_scroller_width major_scroller_height minor_scroller_width minor_scroller_height frame_width frame_height real_binding_width real_back_page_number, if adjust is True Parameters: IN instigator - child widget requesting geo request IN desired - instigator's requested geometry IN adjust - flag to indicate whether instance geometry variables used for layout should be set. OUT preferred_width, OUT preferred_height - notebook w/h based on children sizes -----------------------------------------------------------------------------*/ static void CalcGeoInfo ( XmNotebookWidget nb, Widget instigator, XtWidgetGeometry *desired, Dimension *preferred_width, Dimension *preferred_height, Boolean adjust) { XmNotebookConstraint nc; Dimension width, height; Widget child; XtWidgetGeometry preferred; int i; unsigned int w, h; Dimension page_width = 0,page_height = 0; Dimension status_width = 0,status_height = 0; Dimension major_width = 0,major_height = 0; Dimension minor_width = 0,minor_height = 0; Dimension scroller_width = 0,scroller_height = 0; Dimension major_scroller_width = 0,major_scroller_height = 0; Dimension minor_scroller_width = 0,minor_scroller_height = 0; Dimension frame_width,frame_height; Dimension real_binding_width,real_back_page_number; /* get width and height of children */ for (i = 0; i < nb->composite.num_children; i++) { /* ask preferred size */ child = nb->composite.children[i]; if (child == instigator) { width = IsWidth(desired) ? desired->width : XtWidth(instigator); width += (IsBorder(desired) ? desired->border_width : XtBorderWidth(instigator)) * 2; height = IsHeight(desired) ? desired->height : XtHeight(instigator); height += (IsBorder(desired) ? desired->border_width : XtBorderWidth(instigator)) * 2; } else { XtQueryGeometry(child, NULL, &preferred); width = (preferred.request_mode & CWWidth) ? preferred.width : XtWidth(child) + child->core.border_width*2; height = (preferred.request_mode & CWHeight) ? preferred.height : XtHeight(child) + child->core.border_width*2; } /* get the maximum */ if (XtIsManaged(child)) { nc = NotebookConstraint(child); switch (nc->child_type) { case XmPAGE: ASSIGN_MAX(page_width, width); ASSIGN_MAX(page_height, height); break; case XmSTATUS_AREA: ASSIGN_MAX(status_width, width); ASSIGN_MAX(status_height, height); break; case XmMAJOR_TAB: ASSIGN_MAX(major_width, width); ASSIGN_MAX(major_height, height); break; case XmMINOR_TAB: ASSIGN_MAX(minor_width, width); ASSIGN_MAX(minor_height, height); break; case XmPAGE_SCROLLER: ASSIGN_MAX(scroller_width, width); ASSIGN_MAX(scroller_height, height); break; case XmMAJOR_TAB_SCROLLER: ASSIGN_MAX(major_scroller_width, width); ASSIGN_MAX(major_scroller_height, height); break; case XmMINOR_TAB_SCROLLER: ASSIGN_MAX(minor_scroller_width, width); ASSIGN_MAX(minor_scroller_height, height); break; } } } /* adjust page's width */ page_width = MAX((int)page_width, (int)(status_width + nb->notebook.margin_width + scroller_width)); /* set the real binding width */ real_binding_width = nb->notebook.binding_width; switch (nb->notebook.binding_type) { case XmNONE: real_binding_width = 0; break; case XmSPIRAL: real_binding_width = ((int)(nb->notebook.binding_width * 3))/2; break; case XmPIXMAP: if (nb->notebook.binding_pixmap != XmUNSPECIFIED_PIXMAP && nb->notebook.binding_pixmap != XmNONE) { w = h = 0; XmeGetPixmapData(XtScreen(nb),nb->notebook.binding_pixmap, NULL,NULL,NULL,NULL,NULL,NULL,&w,&h); if (nb->notebook.orientation == XmHORIZONTAL) { ASSIGN_MAX(real_binding_width, w); } else { ASSIGN_MAX(real_binding_width, h); } } break; /* Note: in case of XmPIXMAP_OVERLAP_ONLY binding_width is used so we don't care about the Pixmap size here */ } /* Calculate the real back page number */ real_back_page_number = nb->notebook.back_page_number; ASSIGN_MIN(real_back_page_number, (Dimension)(nb->notebook.back_page_size /2)); ASSIGN_MAX(real_back_page_number, 1); /* Calculate status w/h based on page,margin,& scroller w/h */ status_width = MAX(0,(int) (page_width - nb->notebook.margin_width - scroller_width)); status_height = scroller_height = MAX(status_height,scroller_height); /* Calculate the notebook frame size based on page size,shadows,& margins*/ frame_width = page_width + (nb->notebook.shadow_thickness * 2) + (nb->notebook.margin_width * 2) + 1; frame_height = page_height + status_height + (nb->notebook.shadow_thickness * 2) + (nb->notebook.margin_height * 3) + 1; /* * Return calculated notebook's preferred size */ /* add frame and back pages area */ *preferred_width = frame_width + nb->notebook.back_page_size; *preferred_height = frame_height + nb->notebook.back_page_size; /* add binding and tab area */ if (nb->notebook.orientation == XmHORIZONTAL) { *preferred_width += real_binding_width + NB_MAJOR_MAX(nb, major_width, major_scroller_width); *preferred_height += NB_MINOR_MAX(nb, minor_height, minor_scroller_height); } else { *preferred_width += NB_MINOR_MAX(nb, minor_width, minor_scroller_width); *preferred_height += real_binding_width + NB_MAJOR_MAX(nb, major_height, major_scroller_height); } /* * Set notebook geometry, if adjusting */ if (adjust) { nb->notebook.page_width = page_width; nb->notebook.page_height = page_height; nb->notebook.status_width = status_width; nb->notebook.status_height = status_height; nb->notebook.major_width = major_width; nb->notebook.major_height = major_height; nb->notebook.minor_width = minor_width; nb->notebook.minor_height = minor_height; nb->notebook.scroller_width = scroller_width; nb->notebook.scroller_height = scroller_height; nb->notebook.major_scroller_width = major_scroller_width; nb->notebook.major_scroller_height = major_scroller_height; nb->notebook.minor_scroller_width = minor_scroller_width; nb->notebook.minor_scroller_height = minor_scroller_height; nb->notebook.frame_width = frame_width; nb->notebook.frame_height = frame_height; nb->notebook.real_binding_width = real_binding_width; nb->notebook.real_back_page_number = real_back_page_number; } } /*- NewPreferredGeometry ---------------------------------------------------- Get Notebook's preferred geometry Parameters: IN instigator - child widget requesting geo request IN desired - instigator's requested geometry OUT preferred - w/h based on child's preferred sizes -----------------------------------------------------------------------------*/ static Boolean NewPreferredGeometry ( XmNotebookWidget nb, Widget instigator, XtWidgetGeometry *desired, XtWidgetGeometry *preferred) { Dimension preferred_width, preferred_height; /* calculate preferred geometry information */ CalcGeoInfo(nb, instigator, desired, &preferred_width, &preferred_height, FALSE); preferred->width = preferred_width; preferred->height = preferred_height; preferred->request_mode = CWHeight | CWWidth; return(!((preferred->width == nb->core.width) && (preferred->height == nb->core.height))); } /*- AdjustGeometry ---------------------------------------------------------- Adjust notebook's children sizes based on the Notebook's width and height. The minimum width needed is determined by the following: 1. page and status are minimized until they reach XmNbackPageWidth 2. binding is minimized 3. major tabs are minimized 4. page scroller is minimized 5. back pages and frame are clipped The minimum height needed is determined by the following: 1. page is minimized 2. status and page scroller are minimized 3. minor tabs are minimized 4. back pages and frame are clipped -----------------------------------------------------------------------------*/ static void AdjustGeometry ( XmNotebookWidget nb, Widget instigator, XtWidgetGeometry *desired) { Dimension ideal_width,ideal_height; /* the value min is the minimum width/height that the Notebook can be after a component is reduced to its minimum */ Dimension min; /* calculate preferred geometry information */ CalcGeoInfo(nb, instigator, desired, &ideal_width, &ideal_height, TRUE); /* adjust children's width */ /* Notebook's width is bigger than ideal width */ if (nb->core.width > ideal_width) nb->notebook.page_width += nb->core.width - ideal_width; /* Notebook's width is smaller than ideal width */ else if (nb->core.width < ideal_width) { /* minimize the page area */ min = ideal_width - nb->notebook.page_width + nb->notebook.scroller_width; if (nb->core.width >= min) nb->notebook.page_width = nb->core.width - (min - nb->notebook.scroller_width); else if (nb->core.width < min) { nb->notebook.page_width = nb->notebook.scroller_width; if (nb->notebook.orientation == XmHORIZONTAL) { /* minimize the binding area */ min -= nb->notebook.real_binding_width; if (nb->core.width >= min) nb->notebook.real_binding_width = nb->core.width - min; else { /* minimize major tabs */ nb->notebook.real_binding_width = 0; min -= nb->notebook.major_width; if (nb->core.width > min) nb->notebook.major_width = nb->core.width - min; else nb->notebook.major_width = 0; } } else { /* minimize minor tabs */ min -= nb->notebook.minor_width; if (nb->core.width > min) nb->notebook.minor_width = nb->core.width - min; else nb->notebook.minor_width = 0; } } } /* adjust children's height */ /* Notebook's height is bigger than ideal height */ if (nb->core.height > ideal_height) nb->notebook.page_height += nb->core.height - ideal_height; /* Notebook's height is smaller than ideal height */ else if (nb->core.height < ideal_height) { /* minimize the page area */ min = ideal_height - nb->notebook.page_height; if (nb->core.height >= min) nb->notebook.page_height = nb->core.height - min; else if (nb->core.height < min) { /* minimize the page scroller area */ nb->notebook.page_height = 0; min -= nb->notebook.scroller_height; if (nb->core.height >= min) nb->notebook.scroller_height = nb->notebook.status_height = nb->core.height - min; else { nb->notebook.scroller_height = nb->notebook.status_height = 0; if (nb->notebook.orientation == XmVERTICAL) { /* minimize the binding area */ min -= nb->notebook.real_binding_width; if (nb->core.height >= min) nb->notebook.real_binding_width = nb->core.height - min; else { /* minimize major tabs */ nb->notebook.real_binding_width = 0; min -= nb->notebook.major_height; if (nb->core.height > min) nb->notebook.major_height = nb->core.height - min; else nb->notebook.major_height = 0; } } else { /* minimize minor tabs */ min -= nb->notebook.minor_height; if (nb->core.height > min) nb->notebook.minor_height = nb->core.height - min; else nb->notebook.minor_height = 0; } } } } /* Calculate status w/h based on page,margin,& scroller w/h */ nb->notebook.status_width = MAX(0,(int)(nb->notebook.page_width - nb->notebook.margin_width - nb->notebook.scroller_width)); nb->notebook.status_height = nb->notebook.scroller_height = MAX(nb->notebook.status_height, nb->notebook.scroller_height); /* Calculate the notebook frame size based on page size,shadows,& margins*/ nb->notebook.frame_width = nb->notebook.page_width + (nb->notebook.shadow_thickness * 2) + (nb->notebook.margin_width * 2) + 1; nb->notebook.frame_height = nb->notebook.page_height + nb->notebook.status_height + (nb->notebook.shadow_thickness * 2) + (nb->notebook.margin_height * 3) + 1; } /***************************************************************************** * * * Child Managing Functions * * * *****************************************************************************/ /*- SetLastPageNumber ---------------------------------------------------- Sets XmNlastPageNumber if no explicit last page number was set, and updates navigators. Uses instance state: dynamic_last_page_num ,True, if no explicit setting Called from: AssignDefaultPageNumber ,when children are managed ConstraintSetValues ,when a child page # is changed Return: True, if last_page_number changed. Otherwise, False. -----------------------------------------------------------------------------*/ static Boolean SetLastPageNumber ( XmNotebookWidget nb, int last_page_number) { if (nb->notebook.dynamic_last_page_num && last_page_number > nb->notebook.last_page_number) { nb->notebook.last_page_number = last_page_number; UpdateNavigators(nb); return(True); } return(False); } /*- AssignDefaultPageNumber ------------------------------------------------- assign a default page number to those children who did not get from the application. When a page is managed without a page number, the Notebook provides the page with the smallest unallocated page number that is greater than or equal to the first page number and is greater than the last allocated page number. When a tab or a status area is managed without a page number, the widget gets the page number of the most recently managed page that does not have the same type of child. If the page does have the same type of child, however, the Notebook associates the child with the next page whose page number is one greater than the most recently managed one. The Notebook, then, assumes the new page number is occupied. The next subsequent page without a page number will not receive this number. The default page number that the Notebook generates can exceed the last page number, which makes those page inaccessable by the user. -----------------------------------------------------------------------------*/ static Boolean AssignDefaultPageNumber ( XmNotebookWidget nb) { XmNotebookConstraint nc; Widget child; int i, last_page_number; /* initialize */ last_page_number = nb->notebook.first_page_number; /* for all children */ for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); /* for all managed children */ if (XtIsManaged(child)) { /* assign a default page number */ if (nc->page_number == XmUNSPECIFIED_PAGE_NUMBER) { if (NB_IS_CHILD_PAGE(nc->child_type)) { nc->page_number = GetNextAvailPageNum(nb, i); nb->notebook.last_alloc_num = nc->page_number; } else if (NB_IS_CHILD_MAJOR(nc->child_type) || NB_IS_CHILD_MINOR(nc->child_type) || NB_IS_CHILD_STATUS(nc->child_type)) { if (GetChildWidget(nb, nb->notebook.last_alloc_num, nc->child_type)) { nc->page_number = GetNextAvailPageNum(nb, i); nb->notebook.last_alloc_num = nc->page_number; } else nc->page_number = nb->notebook.last_alloc_num; } } else nb->notebook.last_alloc_num = nc->page_number; /* update the last_page_number */ if (NB_IS_CHILD_PAGE(nc->child_type) || NB_IS_CHILD_TAB(nc->child_type) || NB_IS_CHILD_STATUS(nc->child_type)) { ASSIGN_MAX(last_page_number, nc->page_number); } } /* if */ } /* for */ return(SetLastPageNumber(nb, last_page_number)); } /*- SetActiveChildren ------------------------------------------------------ Determine which children should be active. Active children are all managed scrollers and managed pages, status areas, and tabs which are within the page number range and not duplicated or later matched ones if duplicated. Uses instance state: first_page_number last_page_number Updates child constraint "active" field FALSE, if child is NOT managed or child page # less than notebook.first_page_number or child page # greater than notebook.last_page_number or child page # duplicated by a child of the same type TRUE, otherwise -----------------------------------------------------------------------------*/ static void SetActiveChildren ( XmNotebookWidget nb) { Widget child; XmNotebookConstraint nc; XmNotebookConstraint last = NULL; /* initial previous child */ unsigned char type = XmNONE; /* initial previous type */ int num = XmUNSPECIFIED_PAGE_NUMBER; /* initial previous page */ int i; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (XtIsManaged(child) && nc->page_number >= nb->notebook.first_page_number && nc->page_number <= nb->notebook.last_page_number) { if (last) last->active = !(nc->child_type == type && nc->page_number == num); last = nc; type = nc->child_type; num = nc->page_number; } else /* NOT managed or NOT (1st page) <= (page #) <= (last page #) */ { nc->active = False; } } if (last) last->active = True; } /*- CompareChildren --------------------------------------------------------- Compares children, used for qsort() in SortChildren. -----------------------------------------------------------------------------*/ static int CompareChildren ( XmConst void *a, XmConst void *b) { XmNotebookConstraint ac = NotebookConstraint(*((Widget *)a)); XmNotebookConstraint bc = NotebookConstraint(*((Widget *)b)); int cmp; /* Compare page numbers */ cmp = ac->page_number - bc->page_number; /* Compare child types, if page numbers are same */ if (!cmp) cmp = ac->child_type - bc->child_type; /* Compare position in the array, if child types are the same */ if (!cmp) cmp = (unsigned long)a - (unsigned long)b; return cmp; } /*- SortChildren ------------------------------------------------------------ Sorts children by page number and type. Assumptions: Previously created children are already sorted, and newly created children are at the end of the composite.children list. -----------------------------------------------------------------------------*/ static void SortChildren ( XmNotebookWidget nb) { qsort(nb->composite.children, nb->composite.num_children, sizeof(Widget), CompareChildren); SetActiveChildren(nb); } /*- RepositionChild --------------------------------------------------------- Repositions a childs position in composite array using an insertion method. -----------------------------------------------------------------------------*/ static void RepositionChild ( XmNotebookWidget nb, Widget child) { XmNotebookConstraint rnc = NotebookConstraint(child); XmNotebookConstraint nc; /* temp comparator value */ Widget w; /* temp comparator value */ int cmp; /* temp comparator value */ int cur_pos = -1; /* position of changing child */ int ins_pos = -1; /* position to insert child */ int i; /* counter */ /* nothing to do, if there is only one child in array */ if (nb->composite.num_children == 1) return; for (i = 0; i < nb->composite.num_children; i++) { w = nb->composite.children[i]; nc = NotebookConstraint(w); if (rnc == nc) cur_pos = i; else if (ins_pos < 0) { cmp = rnc->page_number - nc->page_number; if (!cmp) cmp = rnc->child_type - nc->child_type; if (!cmp) cmp = (unsigned long)child - (unsigned long)w; if (cmp < 0) ins_pos = i; /* should be inserted before this element */ } } /* for */ /* error, unable to locate repositioning child in array??? */ if (cur_pos < 0) return; /* found no one less than, move others down, and insert at last position */ if (ins_pos < 0) { for (i = cur_pos; i < nb->composite.num_children -1; i++) nb->composite.children[i] = nb->composite.children[i+1]; nb->composite.children[nb->composite.num_children -1] = child; } /* found new position above, move others down, and then insert */ else if (cur_pos < ins_pos) { for (i = cur_pos; i < ins_pos -1; i++) nb->composite.children[i] = nb->composite.children[i+1]; nb->composite.children[ins_pos -1] = child; } /* found new position below, move others up, and then insert */ else if (cur_pos > ins_pos) { for (i = cur_pos; i > ins_pos; i--) nb->composite.children[i] = nb->composite.children[i-1]; nb->composite.children[ins_pos] = child; } } /*- GetNextAvailPageNum ----------------------------------------------------- Finds out the next available page number for allocating it to a newly created page or other child. -----------------------------------------------------------------------------*/ static int GetNextAvailPageNum( XmNotebookWidget nb, int last) { XmNotebookConstraint nc; Widget child; int i, avail; avail = nb->notebook.last_alloc_num; for (i = 0; i < last; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (XtIsManaged(child) && nc->page_number == avail) avail++; } return avail; } /*- GetChildWidget --------------------------------------------------------- Finds the later matched child widget of the specified type. It returns NULL if not found. -----------------------------------------------------------------------------*/ static Widget GetChildWidget( XmNotebookWidget nb, int page_number, unsigned char child_type) { XmNotebookConstraint nc; Widget child, this_w; int i; this_w = NULL; for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->page_number == page_number && nc->child_type == child_type) { this_w = child; } else { /* Skip remaining array once last matching child is found */ if (this_w) break; } } return this_w; } /*- GotoPage --------------------------------------------------------------- Places the specified page on top. If the specified page IS currently on top nothing is done. Otherwise, - the XmNpageChangedCallback is called. During which notebook.in_callback is set to True. This is checked in XmNotebook:ConstraintSetValues() to avoid performing layout at that time. - navigators are updated - relayout is performed Called from: SetValues(), when notebook.current_page_number is set TabPressed(), when tabs are activated PageMove(), when ScrollFrame trait navigation is triggered -----------------------------------------------------------------------------*/ static void GotoPage( XmNotebookWidget nb, int page_number, XEvent *event, int reason) { XmNotebookCallbackStruct call_value; Dimension save_width, save_height; Widget old_top_major, old_first_major; Widget old_top_minor, old_first_minor; int prev_page = nb->notebook.current_page_number; /* Don't bother when the page number is out of the page number range, or if it is same as the old page number */ if ( page_number == nb->notebook.current_page_number || page_number < nb->notebook.first_page_number || page_number > nb->notebook.last_page_number) return; /* Save the notebook's size before invoking the callback */ save_width = XtWidth(nb); save_height = XtHeight(nb); /* Set the NEW current page number */ nb->notebook.current_page_number = page_number; /* Invoke the XmNpageChangedCallback, if any exist */ if ((XtHasCallbacks((Widget)nb, XmNpageChangedCallback) == XtCallbackHasSome)) { call_value.reason = reason; call_value.event = event; call_value.page_number = page_number; call_value.page_widget = GetChildWidget(nb, page_number, XmPAGE); call_value.prev_page_number = prev_page; call_value.prev_page_widget = GetChildWidget(nb, prev_page, XmPAGE); /* Mark that the callback is being called and when it finishes */ nb->notebook.in_callback = True; XtCallCallbackList((Widget)nb, nb->notebook.page_change_callback, &call_value); nb->notebook.in_callback = False; } /* Tell all navigators about our page change */ UpdateNavigators(nb); /* If there is any visual change caused by the callback then relayout and redisplay children */ if (save_width != XtWidth(nb) || save_height != XtHeight(nb)) { LayoutChildren(nb, NULL); if (XtIsRealized((Widget)nb)) XClearArea(XtDisplay(nb),XtWindow(nb),0,0,0,0,True); } /* Otherwise just relayout children */ else { /* Save top tab pointers */ old_top_major = nb->notebook.top_major; old_first_major = nb->notebook.first_major; old_top_minor = nb->notebook.top_minor; old_first_minor = nb->notebook.first_minor; /* Reset tab pointers */ ResetTopPointers(nb, XmPAGE, 0); /* Layout children */ LayoutPages(nb, NULL); if ( old_top_major != nb->notebook.top_major || old_first_major != nb->notebook.first_major) LayoutMajorTabs(nb, NULL); if ( old_top_minor != nb->notebook.top_minor || old_first_minor != nb->notebook.first_minor) LayoutMinorTabs(nb, NULL); } } /***************************************************************************** * * * utility functions * * * *****************************************************************************/ /*- ShowChild --------------------------------------------------------------- Change the dimensional aspects of a child, and display it. -----------------------------------------------------------------------------*/ static void ShowChild ( Widget child, Widget instigator, int x, int y, int width, int height) { int border_width; /* adjust width and height and calculate border_width */ border_width = child->core.border_width; width -= border_width * 2; height -= border_width * 2; /* Since width and height can potentially be 0, need to check that they aren't negative after subtracting the border */ if (width <= 0) width = 1, border_width = 0; if (height <= 0) height = 1, border_width = 0; /* Configure the object */ if (child == instigator) { /* if this child is making a geometry request */ XtX(child) = x; XtY(child) = y; XtWidth(child) = width; XtHeight(child) = height; } else { /* otherwise, configure the child */ XmeConfigureObject(child, (Position)x, (Position)y, (Dimension)width, (Dimension)height, (Dimension)border_width); } } /*- HideChild --------------------------------------------------------------- Hide a child by placing it to invisible place. -----------------------------------------------------------------------------*/ static void HideChild ( Widget child, Widget instigator) { int x = - (int)(child->core.width + child->core.border_width * 2); int y = - (int)(child->core.height + child->core.border_width * 2); /* if the child is already invisible, don't bother */ if (!NB_IS_VISIBLE(child)) return; /* place the child to (x, y) */ if (child == instigator) { /* if child is making a geometry request */ XtX(child) = (Position)x; XtY(child) = (Position)y; } else { /* otherwise, configure the child */ XmeConfigureObject(child, (Position)x, (Position)y, child->core.width, child->core.height, child->core.border_width); } } /*- HideShadowedTab --------------------------------------------------------- Clear tab child and its surrounding frame shadow -----------------------------------------------------------------------------*/ static void HideShadowedTab ( XmNotebookWidget nb, Widget child) { int x, y, width, height; if (XtIsRealized((Widget)nb) && child && NB_IS_VISIBLE(child)) { x = child->core.x - nb->notebook.shadow_thickness; y = child->core.y - nb->notebook.shadow_thickness; width = child->core.width + nb->notebook.shadow_thickness * 2 + 1; height = child->core.height + nb->notebook.shadow_thickness * 2 + 1; if ( nb->notebook.shadow_thickness ) XClearArea(XtDisplay(nb), XtWindow(nb), x, y, width, height, True); else XClearArea(XtDisplay(nb), XtWindow(nb), x - 1 , y - 1, width + 1, height + 1, True); } } /***************************************************************************** * * * callback functions * * * *****************************************************************************/ /*- FlipTabs ---------------------------------------------------------------- callback function for events for tab scrolling -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void FlipTabs ( Widget w, XtPointer data, /* unused */ XtPointer call_data) /* unused */ { XmNotebookWidget nb = (XmNotebookWidget)XtParent(w); Widget old_first_major, old_first_minor; Widget cfw = XmGetFocusWidget((Widget)nb); /* save tab pointers */ old_first_major = nb->notebook.first_major; old_first_minor = nb->notebook.first_minor; /* request to reset notebook.first_major */ if (w == nb->notebook.next_major) ResetTopPointers(nb, XmMAJOR_TAB_SCROLLER, _NEXT); else if (w == nb->notebook.prev_major) ResetTopPointers(nb, XmMAJOR_TAB_SCROLLER, _PREVIOUS); else if (w == nb->notebook.next_minor) ResetTopPointers(nb, XmMINOR_TAB_SCROLLER, _NEXT); else if (w == nb->notebook.prev_minor) ResetTopPointers(nb, XmMINOR_TAB_SCROLLER, _PREVIOUS); /* redraw tabs if necessary */ if (old_first_major != nb->notebook.first_major) LayoutMajorTabs(nb, NULL); if (old_first_minor != nb->notebook.first_minor) LayoutMinorTabs(nb, NULL); /* * If focus was a tab widget that is now hidden due to tab scrolling then * move focus to the next visible tab */ if (cfw && XtParent(cfw) == (Widget)nb) { unsigned char ct = NotebookConstraint(cfw)->child_type; if (NB_IS_HIDDEN(cfw) && NB_IS_CHILD_TAB(ct)) { if ((w == nb->notebook.next_major) && NB_IS_CHILD_MAJOR(ct)) XmProcessTraversal( (Widget) GetNextTab(nb, XmMAJOR_TAB, 0, _FIRST_VISIBLE), XmTRAVERSE_CURRENT); else if (w == nb->notebook.prev_major && NB_IS_CHILD_MAJOR(ct)) XmProcessTraversal( (Widget) GetNextTab(nb, XmMAJOR_TAB, 0, _LAST_VISIBLE), XmTRAVERSE_CURRENT); else if (w == nb->notebook.next_minor && NB_IS_CHILD_MINOR(ct)) XmProcessTraversal( (Widget) GetNextTab(nb, XmMINOR_TAB, 0, _FIRST_VISIBLE), XmTRAVERSE_CURRENT); else if (w == nb->notebook.prev_minor && NB_IS_CHILD_MINOR(ct)) XmProcessTraversal( (Widget) GetNextTab(nb, XmMINOR_TAB, 0, _LAST_VISIBLE), XmTRAVERSE_CURRENT); } } } /*- TabPressed -------------------------------------------------------------- callback function for events for tab push-buttons. -----------------------------------------------------------------------------*/ static void TabPressed ( Widget w, XtPointer data, XtPointer call_data) { XmNotebookWidget nb = (XmNotebookWidget)XtParent(w); XmNotebookConstraint nc = NotebookConstraint(w); XmAnyCallbackStruct *cbs = (XmAnyCallbackStruct *)call_data; int reason = (unsigned long)data; /* move to the selected page */ GotoPage(nb, nc->page_number, cbs->event, reason); } /***************************************************************************** * * * Keyboard Traversal Functions & Action Procs * * * *****************************************************************************/ /*- TraverseTab ------------------------------------------------------------- action for moving the focus on tabs -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void TraverseTab ( Widget w, XEvent *event, /* unused */ String *params, Cardinal *num_params) { XmNotebookWidget nb = (XmNotebookWidget)w; XmNotebookConstraint nc; Widget first, last, next, prev, child = NULL; int traverse_to; /* Check error conditions */ if (nb && XmIsNotebook(nb)) child = XmGetFocusWidget(w); else while (nb && !(XmIsNotebook(nb))) { child = (Widget)nb; nb = (XmNotebookWidget)XtParent(child); } if (!nb || !child) return; if (!num_params || (*num_params != 1) || !params) { XmeWarning(w, MESSAGE1); return; } /* Only valid for major or minor tabs */ if (!(nc = NotebookConstraint(child)) || !(NB_IS_CHILD_MAJOR(nc->child_type) || NB_IS_CHILD_MINOR(nc->child_type))) return; if (_XmConvertActionParamToRepTypeId((Widget) nb, XmRID_NOTEBOOK_TRAVERSE_TAB_ACTION_PARAMS, params[0], False, &traverse_to) == False) traverse_to = _HOME; /* * Make the traversal */ if (traverse_to == _HOME) { /* Major HOME traversal */ first = GetNextTab(nb,nc->child_type,nc->page_number,_HOME); if ((first) && NB_IS_HIDDEN(first)) { if (NB_IS_CHILD_MAJOR(nc->child_type)) { ResetTopPointers(nb,XmMAJOR_TAB_SCROLLER,_HOME); LayoutMajorTabs(nb, NULL); } else { ResetTopPointers(nb,XmMINOR_TAB_SCROLLER,_HOME); LayoutMinorTabs(nb, NULL); } } if (first) XmProcessTraversal(first,XmTRAVERSE_CURRENT); } else if (traverse_to == _END) { last = GetNextTab(nb,nc->child_type,nc->page_number,_END); if ((last) && NB_IS_HIDDEN(last)) { if (NB_IS_CHILD_MAJOR(nc->child_type)) { ResetTopPointers(nb,XmMAJOR_TAB_SCROLLER,_END); LayoutMajorTabs(nb, NULL); } else { ResetTopPointers(nb,XmMINOR_TAB_SCROLLER,_END); LayoutMinorTabs(nb, NULL); } } if (last) XmProcessTraversal(last,XmTRAVERSE_CURRENT); } else if (traverse_to == _PREVIOUS) { prev = GetNextTab(nb,nc->child_type,nc->page_number,_PREVIOUS); if ((prev) && NB_IS_HIDDEN(prev)) { if (NB_IS_CHILD_MAJOR(nc->child_type)) FlipTabs( (MaxIsRightUp(nb,nc->child_type)) ? nb->notebook.prev_major : nb->notebook.next_major, NULL,NULL); else FlipTabs( (MaxIsRightUp(nb,nc->child_type)) ? nb->notebook.prev_minor : nb->notebook.next_minor, NULL,NULL); } if (prev) XmProcessTraversal(prev, XmTRAVERSE_CURRENT); } else if (traverse_to == _NEXT) { next = GetNextTab(nb,nc->child_type,nc->page_number,_NEXT); if ((next) && NB_IS_HIDDEN(next)) { if (NB_IS_CHILD_MAJOR(nc->child_type)) FlipTabs( (MaxIsRightUp(nb,nc->child_type)) ? nb->notebook.next_major : nb->notebook.prev_major, NULL,NULL); else FlipTabs( (MaxIsRightUp(nb,nc->child_type)) ? nb->notebook.next_minor : nb->notebook.prev_minor, NULL,NULL); } if (next) XmProcessTraversal(next, XmTRAVERSE_CURRENT); } } /*- RedirectTraversal ------------------------------------------------------- redirect traversal control trait Focus From Focus To Focus Request NEXT_TAB_GROUP MINOR _CURRENT_VISIBLE MAJOR MAJOR _CURRENT_VISIBLE MINOR PREV_TAB_GROUP MAJOR _CURRENT_VISIBLE MINOR MINOR _CURRENT_VISIBLE MAJOR -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static Widget RedirectTraversal( Widget old_focus, Widget new_focus, unsigned int focus_policy, XmTraversalDirection direction, unsigned int pass) /* unused */ { unsigned char to_type, from_type; Widget to_child, from_child; Widget to_parent, from_parent; Widget new_focus_widget; /* If we're in pointer focus mode there's nothing to be done. */ if ((focus_policy != XmEXPLICIT) || ((direction != XmTRAVERSE_NEXT_TAB_GROUP) && (direction != XmTRAVERSE_PREV_TAB_GROUP))) return new_focus; /* Determine nearest notebook parent for the target. */ to_parent = NULL; if (to_child=new_focus) { if ((to_parent=XtParent(to_child)) == NULL) return new_focus; while (!XmIsNotebook(to_parent)) { to_child = to_parent; if ((to_parent=XtParent(to_child)) == NULL) break; } } /* Determine target child type. */ if (to_parent) to_type = NotebookConstraint(to_child)->child_type; /* Determine nearest notebook parent for the source. */ from_parent = NULL; if (from_child=old_focus) { if ((from_parent = XtParent(from_child)) == NULL) return new_focus; while (!XmIsNotebook(from_parent)) { from_child = from_parent; if ((from_parent=XtParent(from_child)) == NULL) break; } } /* Determine source child type. */ if (from_parent) from_type = NotebookConstraint(from_child)->child_type; /* * Determine if we need to force traversal between major and * minor tabs (traverse to nearest tab to the current page) * * Note: If TO is NULL, then it is assumed that there is only * one TAB GROUP i.e., the Major/Minor tabs TAB GROUP */ new_focus_widget = NULL; if (direction == XmTRAVERSE_NEXT_TAB_GROUP) { /* If FROM Minor with a NULL TO then GOTO Major */ if (to_child == NULL && (from_parent && (from_type == XmMINOR_TAB))) new_focus_widget = GetNextTab((XmNotebookWidget)from_parent, XmMAJOR_TAB,0,_CURRENT_VISIBLE); /* If FROM Major with any TO then GOTO Minor */ else if (from_parent && (from_type == XmMAJOR_TAB)) new_focus_widget = GetNextTab((XmNotebookWidget)from_parent, XmMINOR_TAB,0,_CURRENT_VISIBLE); /* If *NOT* FROM Major and TO Minor then GOTO Major */ else if (to_parent && (to_type == XmMINOR_TAB)) new_focus_widget = GetNextTab((XmNotebookWidget)to_parent, XmMAJOR_TAB,0,_CURRENT_VISIBLE); /* If TO Major with any FROM then GOTO Major */ else if (to_parent && (to_type == XmMAJOR_TAB)) new_focus_widget = GetNextTab((XmNotebookWidget)to_parent, XmMAJOR_TAB,0,_CURRENT_VISIBLE); } else /* if (direction == XmTRAVERSE_PREV_TAB_GROUP) */ { /* If FROM Major with a NULL TO then GOTO Minor */ if (to_child == NULL && (from_parent && (from_type == XmMAJOR_TAB))) new_focus_widget = GetNextTab((XmNotebookWidget)from_parent, XmMINOR_TAB,0,_CURRENT_VISIBLE); /* If FROM Minor with any TO and then GOTO Major */ else if (from_parent && (from_type == XmMINOR_TAB)) new_focus_widget = GetNextTab((XmNotebookWidget)from_parent, XmMAJOR_TAB,0,_CURRENT_VISIBLE); /* If *NOT* FROM Minor with TO Major then GOTO Major */ else if (to_parent && (to_type == XmMAJOR_TAB)) new_focus_widget = GetNextTab((XmNotebookWidget)to_parent, XmMINOR_TAB,0,_CURRENT_VISIBLE); /* If to a Minor then traverse to a Minor nearest the current page */ else if (to_parent && (to_type == XmMINOR_TAB)) new_focus_widget = GetNextTab((XmNotebookWidget)to_parent, XmMINOR_TAB,0,_CURRENT_VISIBLE); } if (new_focus_widget && XmIsTraversable(new_focus_widget)) return new_focus_widget; return new_focus; } /*- GetNextTab -------------------------------------------------------------- Get next tab to set focus to. In Parameters: child_type XmMAJOR_TAB or XmMINOR_TAB page_number page number of interest direction traversal direction returns next major || minor tab (can be NULL) -----------------------------------------------------------------------------*/ static Widget GetNextTab ( XmNotebookWidget nb, unsigned char child_type, int page_number, unsigned char direction) { XmNotebookConstraint nc; Widget child; int i; Widget target; unsigned char target_dir; unsigned char target_child_type; Boolean target_found; int top_major_page; if (NB_IS_CHILD_MAJOR(child_type) || NB_IS_CHILD_MINOR(child_type)) target_child_type = child_type; else return(NULL); /* Bad parameter */ if (MaxIsRightUp(nb,target_child_type)) target_dir = direction; else switch(direction) { case _PREVIOUS: target_dir = _NEXT; break; case _NEXT: target_dir = _PREVIOUS; break; default: target_dir = direction; } /* * Attempt to return top tab */ if (target_dir == _CURRENT_VISIBLE) { if (NB_IS_CHILD_MAJOR(child_type)) { if ( (nb->notebook.top_major != NULL) && (NB_IS_VISIBLE(nb->notebook.top_major))) return nb->notebook.top_major; else target_dir = _FIRST_VISIBLE; } else if (NB_IS_CHILD_MINOR(child_type)) { if ( (nb->notebook.top_minor != NULL) && (NB_IS_VISIBLE(nb->notebook.top_minor))) return nb->notebook.top_minor; else target_dir = _FIRST_VISIBLE; } } i = 0; target = NULL; target_found = False; if (NB_IS_CHILD_MAJOR(target_child_type)) { while((!target_found) && (i < nb->composite.num_children)) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if ((nc->active) && (NB_IS_CHILD_MAJOR(nc->child_type))) switch (target_dir) { case _HOME: target = child; target_found = True; break; case _FIRST_VISIBLE: if (NB_IS_VISIBLE(child)) { target = child; target_found = True; } break; case _LAST_VISIBLE: if (NB_IS_VISIBLE(child)) { target = child; } break; case _PREVIOUS: if (nc->page_number < page_number) target = child; else target_found = True; break; case _NEXT: if (nc->page_number > page_number) { target = child; target_found = True; } break; case _END: target = child; } /* switch */ i++; } /* while */ } /* if */ else /* NB_IS_CHILD_MINOR(target_child_type) */ { top_major_page = nb->notebook.top_major ? NotebookConstraint(nb->notebook.top_major)->page_number : nb->notebook.first_page_number - 1; while((!target_found) && (i < nb->composite.num_children)) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (NB_IS_CHILD_MAJOR(nc->child_type) && (nc->page_number > top_major_page)) target_found = True; else if ((nc->active) && (NB_IS_CHILD_MINOR(nc->child_type)) && (nc->page_number >= top_major_page)) switch (target_dir) { case _HOME: target = child; target_found = True; break; case _FIRST_VISIBLE: if (NB_IS_VISIBLE(child)) { target = child; target_found = True; } break; case _LAST_VISIBLE: if (NB_IS_VISIBLE(child)) { target = child; } break; case _PREVIOUS: if (nc->page_number < page_number) target = child; else target_found = True; break; case _NEXT: if (nc->page_number > page_number) { target = child; target_found = True; } break; case _END: target = child; } /* switch */ i++; } /* while */ } /* else */ return(target); } /*- MaxIsRightUp ------------------------------------------------------------ returns True, if "osfRight" and "osfDown" mean "next" and "osfLeft" and "osfUp" mean "prev" False, if "osfLeft" and "osfUp" mean "next" and "osfRight" and "osfDown" mean "prev" -----------------------------------------------------------------------------*/ static Boolean MaxIsRightUp ( XmNotebookWidget nb, unsigned char child_type) { return( ( (NB_IS_CHILD_MAJOR(child_type)) && ( (nb->notebook.back_page_pos == XmBOTTOM_RIGHT) || ( (nb->notebook.back_page_pos == XmBOTTOM_LEFT) && (nb->notebook.orientation == XmHORIZONTAL)) || ( (nb->notebook.back_page_pos == XmTOP_RIGHT) && (nb->notebook.orientation == XmVERTICAL)))) || ( (NB_IS_CHILD_MINOR(child_type)) && ( (nb->notebook.back_page_pos == XmBOTTOM_RIGHT) || ( (nb->notebook.back_page_pos == XmBOTTOM_LEFT) && (nb->notebook.orientation == XmVERTICAL)) || ( (nb->notebook.back_page_pos == XmTOP_RIGHT) && (nb->notebook.orientation == XmHORIZONTAL))))); } /***************************************************************************** * * * Trait Stuff * * * *****************************************************************************/ /*- ScrollFrameInit --------------------------------------------------------- ScrollFrame init trait method -----------------------------------------------------------------------------*/ static void ScrollFrameInit ( Widget w, XtCallbackProc moveCB, Widget scrollable) { XmNotebookWidget nb = (XmNotebookWidget)w; if (nb->notebook.scroll_frame_data != NULL) return; nb->notebook.scroll_frame_data = (XmScrollFrameData) XtMalloc(sizeof(XmScrollFrameDataRec)); nb->notebook.scroll_frame_data->num_nav_list = 0 ; nb->notebook.scroll_frame_data->nav_list = NULL ; nb->notebook.scroll_frame_data->num_nav_slots = 0 ; nb->notebook.scroll_frame_data->move_cb = moveCB ; nb->notebook.scroll_frame_data->scrollable = scrollable ; } /*- ScrollFrameGetInfo ------------------------------------------------------ ScrollFrame getInfo trait method Notebook is a 1 dimensional frame. -----------------------------------------------------------------------------*/ static Boolean ScrollFrameGetInfo ( Widget w, Cardinal *dimension, Widget **nav_list, Cardinal *num_nav_list) { XmNotebookWidget nb = (XmNotebookWidget)w; if (dimension) *dimension = 1; /* one dimensional frame */ if (nb->notebook.scroll_frame_data != NULL) { if (nav_list) *nav_list = nb->notebook.scroll_frame_data->nav_list; if (num_nav_list) *num_nav_list = nb->notebook.scroll_frame_data->num_nav_list; } return( nb->notebook.scroll_frame_data != NULL ); } /*- AddNavigator ------------------------------------------------------------ ScrollFrame addNavigator trait method -----------------------------------------------------------------------------*/ static void AddNavigator ( Widget w, Widget nav, Mask dimMask) { XmNotebookWidget nb = (XmNotebookWidget)w; if (nb->notebook.scroll_frame_data != NULL) _XmSFAddNavigator(w, nav, dimMask, nb->notebook.scroll_frame_data); } /*- RemoveNavigator --------------------------------------------------------- ScrollFrame removeNavigator trait method -----------------------------------------------------------------------------*/ static void RemoveNavigator ( Widget w, Widget nav) { XmNotebookWidget nb = (XmNotebookWidget)w; if (nb->notebook.scroll_frame_data != NULL) _XmSFRemoveNavigator(w, nav, nb->notebook.scroll_frame_data); } /*- PageMove ---------------------------------------------------------------- Callback for the value changes of navigators. -----------------------------------------------------------------------------*/ /*ARGSUSED*/ static void PageMove ( Widget w, XtPointer data, XtPointer call_data) /* unused */ { /* w is a navigator widget */ XmNotebookWidget nb = (XmNotebookWidget)data; XmNavigatorDataRec nav_data; XmNavigatorTrait navigatorT; int reason; /* Get the new navigator value using the trait getValue */ nav_data.valueMask = NavValue; /* Check to ensure navigator is ok */ if ((navigatorT=NB_NAVIGATOR(w)) == NULL || navigatorT->getValue == NULL) return; navigatorT->getValue(w, &nav_data); /* Determine the callback reason */ if (nav_data.value.x > nb->notebook.current_page_number) reason = XmCR_PAGE_SCROLLER_INCREMENT; else if (nav_data.value.x < nb->notebook.current_page_number) reason = XmCR_PAGE_SCROLLER_DECREMENT; else reason = XmCR_NONE; /* Look at the kind of navigator and make the appropriate move */ if ((nav_data.dimMask & NavigDimensionX) && (reason != XmCR_NONE)) GotoPage(nb, nav_data.value.x, NULL, reason); } /*- UpdateNavigators -------------------------------------------------------- Update navigators due to page change -----------------------------------------------------------------------------*/ static void UpdateNavigators ( XmNotebookWidget nb) { XmNavigatorDataRec nav_data; /* update navigators */ nav_data.value.x = nb->notebook.current_page_number; nav_data.minimum.x = nb->notebook.first_page_number; nav_data.maximum.x = nb->notebook.last_page_number + 1; nav_data.slider_size.x = 1; nav_data.increment.x = 1; nav_data.page_increment.x = 1; nav_data.dimMask = NavigDimensionX; nav_data.valueMask = NavValue | NavMinimum | NavMaximum | NavSliderSize | NavIncrement | NavPageIncrement; _XmSFUpdateNavigatorsValue((Widget)nb, &nav_data, True); /* Control arrow sensitivity if using default page scroller */ if (nb->notebook.scroller_status == DEFAULT_USED) { if ((nb->notebook.current_page_number ==nb->notebook.last_page_number) && (nb->notebook.current_page_number ==nb->notebook.first_page_number)) XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity, XmARROWS_INSENSITIVE, NULL); else if (nb->notebook.current_page_number == nb->notebook.last_page_number) XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity, XmARROWS_DECREMENT_SENSITIVE, NULL); else if (nb->notebook.current_page_number == nb->notebook.first_page_number) XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity, XmARROWS_INCREMENT_SENSITIVE, NULL); else XtVaSetValues(nb->notebook.scroller_child,XmNarrowSensitivity, XmARROWS_SENSITIVE, NULL); } } /*- GetUnhighlightGC -------------------------------------------------------- ScrollFrame removeNavigator trait method -----------------------------------------------------------------------------*/ static GC GetUnhighlightGC ( Widget w, Widget child) { XmNotebookWidget nb = (XmNotebookWidget)w; XmNotebookConstraint nc; GC background_GC = NULL; if (child) { nc = NotebookConstraint(child); switch (nc->child_type) { case XmMAJOR_TAB: if (nb->notebook.top_major == child) { XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->notebook.frame_background); background_GC = nb->notebook.frame_gc; } else background_GC = nb->manager.background_GC; break; case XmMINOR_TAB: if (nb->notebook.top_minor == child) { XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->notebook.frame_background); background_GC = nb->notebook.frame_gc; } else background_GC = nb->manager.background_GC; break; case XmPAGE: case XmPAGE_SCROLLER: case XmSTATUS_AREA: XSetForeground(XtDisplay(nb), nb->notebook.frame_gc, nb->notebook.frame_background); background_GC = nb->notebook.frame_gc; break; case XmMAJOR_TAB_SCROLLER: case XmMINOR_TAB_SCROLLER: background_GC = nb->manager.background_GC; break; } } return(background_GC); } /***************************************************************************** * * * Public Functions * * * *****************************************************************************/ XmNotebookPageStatus XmNotebookGetPageInfo ( Widget notebook, int page_number, XmNotebookPageInfo *page_info) { XmNotebookWidget nb = (XmNotebookWidget)notebook; XmNotebookConstraint nc; Widget child; Widget page, status, major_tab, minor_tab; XmNotebookPageStatus result; int i; _XmWidgetToAppContext(notebook); _XmAppLock(app); /* initialize */ page = status = major_tab = minor_tab = NULL; result = XmPAGE_EMPTY; /* searching for the page */ for (i = 0; i < nb->composite.num_children; i++) { child = nb->composite.children[i]; nc = NotebookConstraint(child); if (nc->page_number > page_number) break; switch (nc->child_type) { case XmPAGE: if (nc->page_number == page_number) { if (nc->active) { page = child; if (result == XmPAGE_EMPTY) result = XmPAGE_FOUND; } else result = XmPAGE_DUPLICATED; } break; case XmSTATUS_AREA: if ((nc->active) && (nc->page_number == page_number)) status = child; break; case XmMAJOR_TAB: if (nc->active) major_tab = child; break; case XmMINOR_TAB: if (nc->active) minor_tab = child; break; } } /* see if the page number is invalid */ if (page_number < nb->notebook.first_page_number || page_number > nb->notebook.last_page_number) result = XmPAGE_INVALID; /* fill the XmNotebookPageInfo struct */ page_info->page_number = page_number; page_info->page_widget = page; page_info->status_area_widget = status; page_info->major_tab_widget = major_tab; page_info->minor_tab_widget = minor_tab; _XmAppUnlock(app); return result; } Widget XmCreateNotebook( Widget parent, String name, ArgList arglist, Cardinal argcount) { /* * Create an instance of a notebook and return the widget id. */ return(XtCreateWidget(name,xmNotebookWidgetClass,parent,arglist,argcount)); } /* End of Notebook.c */