XEmacs 21.4.5 "Civil Service".
[chise/xemacs-chise.git.1] / lwlib / xlwtabs.c
index 303d149..ec1502a 100644 (file)
@@ -1,25 +1,30 @@
  /* Tabs Widget for XEmacs.
     Copyright (C) 1999 Edward A. Falk
+
  This file is part of XEmacs.
+
  XEmacs is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public License as published by the
  Free Software Foundation; either version 2, or (at your option) any
  later version.
+
  XEmacs is distributed in the hope that it will be useful, but WITHOUT
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  for more details.
+
  You should have received a copy of the GNU General Public License
  along with XEmacs; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.  */
- /* Synched up with: Tabs.c 1.27 */
+
+ /* Synched up with: Tabs.c 1.27.  
+
+ #### This file contains essential XEmacs related fixes to the original
+ verison of the Tabs widget. Be VERY careful about syncing if you ever
+ update to a more recent version. In general this is probably now a
+ bad idea. */
+
  /*
  * Tabs.c - Index Tabs composite widget
  *
@@ -61,6 +66,8 @@
 #include       <X11/Xlib.h>
 #include       <X11/IntrinsicP.h>
 #include       <X11/StringDefs.h>
+
+#include       "lwlib-internal.h"
 #include       "../src/xmu.h"
 #include       "xlwtabsP.h"
 #include       "xlwgcs.h"
@@ -122,7 +129,7 @@ static      char    accelTable[] = "        #augment\n\
        <Key>KP_Down:           highlight(down) \n\
        <Key> :                 page(select)    \n\
         " ;
-static XtAccelerators  defaultAccelerators ;
+static XtAccelerators  defaultAccelerators ; /* #### Never used */
 
 #define        offset(field)   XtOffsetOf(TabsRec, tabs.field)
 static XtResource resources[] = {
@@ -139,6 +146,8 @@ static XtResource resources[] = {
        XtOffsetOf(RectObjRec,rectangle.border_width), XtRImmediate, (XtPointer)0},
   {XtNtopWidget, XtCTopWidget, XtRWidget, sizeof(Widget),
        offset(topWidget), XtRImmediate, NULL},
+  {XtNhighlightWidget, XtCHighlightWidget, XtRWidget, sizeof(Widget),
+       offset(hilight), XtRImmediate, NULL},
   {XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
        offset(callbacks), XtRCallback, NULL},
   {XtNpopdownCallback, XtCCallback, XtRCallback, sizeof(XtPointer),
@@ -262,7 +271,7 @@ static      void    DrawHighlight( TabsWidget tw, Widget child, Bool undraw) ;
 static void    UndrawTab( TabsWidget tw, Widget child) ;
 
 static void    TabWidth( Widget w) ;
-static int     TabLayout( TabsWidget, int wid, int hgt, Dimension *r_hgt,
+static int     TabLayout( TabsWidget, Dimension wid, Dimension hgt, Dimension *r_hgt,
                        Bool query_only) ;
 static void    GetPreferredSizes(TabsWidget) ;
 static void    MaxChild(TabsWidget, Widget except, Dimension, Dimension) ;
@@ -270,9 +279,9 @@ static      void    TabsShuffleRows( TabsWidget tw) ;
 static int     PreferredSize( TabsWidget,
                        Dimension *reply_width, Dimension *reply_height,
                        Dimension *reply_cw, Dimension *reply_ch) ;
-static int     PreferredSize2( TabsWidget, int cw, int ch,
+static int     PreferredSize2( TabsWidget, Dimension cw, Dimension ch,
                        Dimension *rw, Dimension *rh) ;
-static int     PreferredSize3( TabsWidget, int wid, int hgt,
+static int     PreferredSize3( TabsWidget, Dimension wid, Dimension hgt,
                        Dimension *rw, Dimension *rh) ;
 static void    MakeSizeRequest(TabsWidget) ;
 
@@ -387,21 +396,10 @@ TabsClassRec tabsClassRec = {
 
 WidgetClass tabsWidgetClass = (WidgetClass)&tabsClassRec;
 
-
-
-#ifdef DEBUG
-#ifdef __STDC__
-#define        assert(e) \
-         if(!(e)) fprintf(stderr,"yak! %s at %s:%d\n",#e,__FILE__,__LINE__)
-#else
-#define        assert(e) \
-         if(!(e)) fprintf(stderr,"yak! e at %s:%d\n",__FILE__,__LINE__)
-#endif
-#else
-#define        assert(e)
-#endif
-
-
+#define TabsNumChildren(tw) (((TabsWidget)tw)->composite.num_children)
+#define TabVisible(tab) \
+       (XtIsManaged(tab) && \
+        ((TabsConstraints)((tab)->core.constraints))->tabs.visible)
 \f
 
 /****************************************************************
@@ -430,7 +428,7 @@ TabsInit(Widget request, Widget new, ArgList args, Cardinal *num_args)
     TabsWidget newTw = (TabsWidget)new;
 
     newTw->tabs.numRows = 0 ;
-    newTw->tabs.displayChildren = 0;
+    newTw->tabs.realRows = 0;
 
     GetPreferredSizes(newTw) ;
 
@@ -486,6 +484,7 @@ TabsConstraintInitialize(Widget request, Widget new,
 {
        TabsConstraints tab = (TabsConstraints) new->core.constraints ;
        tab->tabs.greyAlloc = False ;   /* defer allocation of pixel */
+       tab->tabs.visible = False ;
 
        getBitmapInfo((TabsWidget)XtParent(new), tab) ;
        TabWidth(new) ;
@@ -530,7 +529,7 @@ TabsResize(Widget w)
        int             i ;
        int             num_children = tw->composite.num_children ;
        Widget          *childP ;
-       TabsConstraints tab ;
+       TabsConstraints tab ; /* #### unused */
        Dimension       cw,ch,bw ;
 
        /* Our size has now been dictated by the parent.  Lay out the
@@ -550,7 +549,7 @@ TabsResize(Widget w)
        {
          /* Loop through the tabs and assign rows & x positions */
          (void) TabLayout(tw, tw->core.width, tw->core.height, NULL, False) ;
-         num_children = tw->tabs.displayChildren;
+         num_children = TabsNumChildren (tw);
 
          /* assign a top widget, bring it to bottom row. */
          TabsShuffleRows(tw) ;
@@ -561,8 +560,8 @@ TabsResize(Widget w)
 
          tw->tabs.child_width = cw = tw->core.width - 2 * SHADWID ;
          tw->tabs.child_height = ch =
-                       tw->core.height - tw->tabs.tab_total - 2 * SHADWID ;
-
+           tw->core.height < (tw->tabs.tab_total + 2 * SHADWID) ? 0 :
+           tw->core.height - tw->tabs.tab_total - 2 * SHADWID ;
 
          for(i=0, childP=tw->composite.children;
                i < num_children;
@@ -571,8 +570,10 @@ TabsResize(Widget w)
            {
              tab = (TabsConstraints) (*childP)->core.constraints ;
              bw = (*childP)->core.border_width ;
-             XtConfigureWidget(*childP, SHADWID,tw->tabs.tab_total+SHADWID,
-                         cw-bw*2,ch-bw*2, bw) ;
+             /* Don't do anything if we can't see any of the child. */
+             if (ch >= bw*2 && ch > 0 && cw >= bw*2 && cw > 0)
+               XtConfigureWidget(*childP, SHADWID,tw->tabs.tab_total+SHADWID,
+                                 cw-bw*2,ch-bw*2, bw) ;
            }
          if( XtIsRealized(w) ) {
            XClearWindow(XtDisplay((Widget)tw), XtWindow((Widget)tw)) ;
@@ -651,11 +652,17 @@ TabsSetValues(Widget current, Widget request, Widget new,
        if( tw->core.sensitive != curtw->core.sensitive )
          needRedraw = True ;
 
+       /* Highlit widget changed */
+       if ( tw->tabs.hilight != curtw->tabs.hilight )
+       {
+               needRedraw = True ;
+       }
+
        /* If top widget changes, need to change stacking order, redraw tabs.
         * Window system will handle the redraws.
         */
 
-       if( tw->tabs.topWidget != curtw->tabs.topWidget ) 
+       if( tw->tabs.topWidget != curtw->tabs.topWidget )
        {
          if( XtIsRealized(tw->tabs.topWidget) )
          {
@@ -671,6 +678,7 @@ TabsSetValues(Widget current, Widget request, Widget new,
            if( tab->tabs.row != tw->tabs.numRows-1 )
              TabsShuffleRows(tw) ;
 
+               
            needRedraw = True ;
          }
          else
@@ -757,7 +765,7 @@ TabsAcceptFocus(Widget w, Time *t)
 /*
  * Return preferred size.  Happily accept anything >= our preferred size.
  * (TODO: is that the right thing to do?  Should we always return "almost"
- * if offerred more than we need?)
+ * if offered more than we need?)
  */
 
 static XtGeometryResult
@@ -864,7 +872,8 @@ TabsGeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *reply)
            myrequest.width = wid ;
            myrequest.height = hgt ;
            myrequest.request_mode = CWWidth | CWHeight ;
-
+           
+           assert (wid > 0 && hgt > 0);
            /* If child is only querying, or if we're going to have to
             * offer the child a compromise, then make this a query only.
             */
@@ -932,8 +941,8 @@ TabsGeometryManager(Widget w, XtWidgetGeometry *req, XtWidgetGeometry *reply)
              Widget    *childP = tw->composite.children ;
              int       i,bw ;
              w->core.border_width = req->border_width ;
-             for(i=tw->tabs.displayChildren; --i >= 0; ++childP)
-               if( XtIsManaged(*childP) )
+             for(i=TabsNumChildren (tw); --i >= 0; ++childP)
+               if( TabVisible(*childP) )
                {
                  bw = (*childP)->core.border_width ;
                  XtConfigureWidget(*childP, s,tw->tabs.tab_total+s,
@@ -1001,7 +1010,7 @@ TabsChangeManaged(Widget w)
        */
       if( tw->tabs.topWidget != NULL && XtIsRealized(tw->tabs.topWidget) )
       {
-       for(i=tw->tabs.displayChildren; --i >= 0; ++childP)
+       for(i=TabsNumChildren (tw); --i >= 0; ++childP)
          if( !XtIsRealized(*childP) )
            XtRealizeWidget(*childP) ;
 
@@ -1066,9 +1075,9 @@ TabsSelect(Widget w, XEvent *event, String *params, Cardinal *num_params)
         * widget to be top of stacking order with XawTabsSetTop().
         */
        for(i=0, childP=tw->composite.children;
-             i < tw->tabs.displayChildren;
+             i < TabsNumChildren (tw);
              ++i, ++childP)
-         if( XtIsManaged(*childP) )
+         if( TabVisible(*childP) )
          {
            TabsConstraints tab = (TabsConstraints)(*childP)->core.constraints;
            if( x > tab->tabs.x  &&  x < tab->tabs.x + tab->tabs.width  &&
@@ -1092,7 +1101,7 @@ TabsPage(Widget w, XEvent *event, String *params, Cardinal *num_params)
        Widget          newtop = NULL;
        Widget          *childP ;
        int             idx ;
-       int             nc = tw->tabs.displayChildren ;
+       int             nc = TabsNumChildren (tw) ;
 
        if( nc <= 0 )
          return ;
@@ -1156,7 +1165,7 @@ TabsHighlight(Widget w, XEvent *event, String *params, Cardinal *num_params)
        Widget          newhl = NULL;
        Widget          *childP ;
        int             idx ;
-       int             nc = tw->tabs.displayChildren ;
+       int             nc = TabsNumChildren (tw) ;
 
        if( nc <= 0 )
          return ;
@@ -1385,7 +1394,7 @@ DrawTabs(TabsWidget tw, Bool labels)
 
        if( !XtIsRealized((Widget)tw))
          return ;
+
        /* draw tabs and frames by row except for the top tab, which
         * is drawn last.  (This is inefficiently written, but should not
         * be too slow as long as there are not a lot of rows.)
@@ -1394,9 +1403,9 @@ DrawTabs(TabsWidget tw, Bool labels)
        y = tw->tabs.numRows == 1 ? TABDELTA : 0 ;
        for(i=0; i<tw->tabs.numRows; ++i, y += th)
        {
-         for( j=tw->tabs.displayChildren, childP=tw->composite.children;
+         for( j=TabsNumChildren (tw), childP=tw->composite.children;
              --j >= 0; ++childP )
-           if( XtIsManaged(*childP) )
+           if( TabVisible(*childP) )
            {
              tab = (TabsConstraints)(*childP)->core.constraints;
              if( tab->tabs.row == i && *childP != tw->tabs.topWidget )
@@ -1496,8 +1505,26 @@ DrawFrame(TabsWidget tw)
        GC              botgc = tw->tabs.botGC ;
        Dimension       s = SHADWID ;
        Dimension       ch = tw->tabs.child_height ;
-       Draw3dBox((Widget)tw, 0,tw->tabs.tab_total,
-               tw->core.width, ch+2*s, s, topgc, botgc) ;
+       if (ch > 0)
+         Draw3dBox((Widget)tw, 0,tw->tabs.tab_total,
+                   tw->core.width, ch+2*s, s, topgc, botgc) ;
+       else
+         {
+           Widget              w = tw->tabs.topWidget ;
+           if (w != NULL)
+             {
+               TabsConstraints tab = (TabsConstraints) w->core.constraints ;
+               Draw3dBox((Widget)tw, 0,tw->core.height - 2*s,
+                         tab->tabs.x, 2*s, s, topgc, botgc);
+               Draw3dBox((Widget)tw, tab->tabs.x + tab->tabs.width, 
+                         tw->core.height - 2*s,
+                         tw->core.width - tab->tabs.x - tab->tabs.width, 2*s, s, 
+                         topgc, botgc);
+             }
+           else
+             Draw3dBox((Widget)tw, 0,tw->core.height - 2*s,
+                       tw->core.width, 2*s, s, topgc, botgc) ;
+         }
 }
 
 
@@ -1703,18 +1730,18 @@ TabWidth(Widget w)
         */
 
 static int
-TabLayout(TabsWidget tw, int wid, int hgt, Dimension *reply_height, Bool query_only)
+TabLayout(TabsWidget tw, 
+         Dimension wid, 
+         Dimension hgt, 
+         Dimension *reply_height, Bool query_only)
 {
-       int             i, row ;
+       int             i, row, done = 0, display_rows = 0 ;
        int             num_children = tw->composite.num_children ;
        Widget          *childP ;
        Dimension       w ;
        Position        x,y ;
        TabsConstraints tab ;
 
-       if (!query_only)
-         tw->tabs.displayChildren = 0;
-
        /* Algorithm: loop through children, assign X positions.  If a tab
         * would extend beyond the right edge, start a new row.  After all
         * rows are assigned, make a second pass and assign Y positions.
@@ -1733,10 +1760,14 @@ TabLayout(TabsWidget tw, int wid, int hgt, Dimension *reply_height, Bool query_o
            {
              tab = (TabsConstraints) (*childP)->core.constraints ;
              w = tab->tabs.width ;
+
              if( x + w > wid ) {                       /* new row */
-               if (y + tw->tabs.tab_height > hgt)
-                 break;
-               ++row ;
+               if (y + tw->tabs.tab_height > hgt && !done)
+                 {
+                   display_rows = row;
+                   done = 1;
+                 }
+               ++row;
                x = INDENT ;
                y += tw->tabs.tab_height ;
              }
@@ -1746,12 +1777,14 @@ TabLayout(TabsWidget tw, int wid, int hgt, Dimension *reply_height, Bool query_o
                tab->tabs.row = row ;
              }
              x += w + SPACING ;
-             if (!query_only)
-               tw->tabs.displayChildren++;
+             if (!query_only && !done)
+               tab->tabs.visible = 1;
+
            }
-         /* If there was only one row, increse the height by TABDELTA */
-         if( ++row == 1 )
+         /* If there was only one row, increase the height by TABDELTA */
+         if( ++display_rows == 1 )
          {
+           row++;
            y = TABDELTA ;
            if( !query_only )
              for(i=num_children, childP=tw->composite.children;
@@ -1765,17 +1798,18 @@ TabLayout(TabsWidget tw, int wid, int hgt, Dimension *reply_height, Bool query_o
          y += tw->tabs.tab_height ;
        }
        else
-         row = y = 0 ;
+         display_rows = row = y = 0 ;
 
        if( !query_only ) {
          tw->tabs.tab_total = y ;
-         tw->tabs.numRows = row ;
+         tw->tabs.numRows = display_rows ;
+         tw->tabs.realRows = row;
        }
 
        if( reply_height != NULL )
          *reply_height = y ;
 
-       return row ;
+       return display_rows ;
 }
 
 
@@ -1804,7 +1838,7 @@ MaxChild(TabsWidget tw, Widget except, Dimension cw, Dimension ch)
        XtWidgetGeometry        preferred ;
 
        for(i=tw->composite.num_children; --i >=0; ++childP)
-         if( XtIsManaged(*childP)  &&  *childP != except )
+         if( TabVisible (*childP) /*XtIsManaged(*childP)*/  &&  *childP != except )
          {
            (void) XtQueryGeometry(*childP, NULL, &preferred) ;
            cw = Max(cw, preferred.width + preferred.border_width * 2 ) ;
@@ -1826,7 +1860,7 @@ TabsShuffleRows(TabsWidget tw)
 {
        TabsConstraints tab ;
        int             move ;
-       int             nrows ;
+       int             real_rows, display_rows ;
        Widget          *childP ;
        Dimension       th = tw->tabs.tab_height ;
        Position        bottom ;
@@ -1834,7 +1868,7 @@ TabsShuffleRows(TabsWidget tw)
 
        /* There must be a top widget.  If not, assign one. */
        if( tw->tabs.topWidget == NULL && tw->composite.children != NULL )
-         for(i=tw->composite.num_children, childP=tw->composite.children;
+         for(i=TabsNumChildren (tw), childP=tw->composite.children;
              --i >= 0;
              ++childP)
            if( XtIsManaged(*childP) ) {
@@ -1844,26 +1878,31 @@ TabsShuffleRows(TabsWidget tw)
 
        if( tw->tabs.topWidget != NULL )
        {
-         nrows = tw->tabs.numRows ;
-         assert( nrows > 0 ) ;
+         display_rows = tw->tabs.numRows ;
+         real_rows = tw->tabs.realRows ;
+         assert( display_rows <= real_rows ) ;
 
-         if( nrows > 1 )
+         if( real_rows > 1 )
          {
            tab = (TabsConstraints) tw->tabs.topWidget->core.constraints ;
            assert( tab != NULL ) ;
 
-           /* how far to move top row */
-           move = nrows - tab->tabs.row ;
+           /* How far to move top row. The selected tab must be on
+              the bottom row of the *visible* rows. */
+           move = (real_rows + 1 - display_rows) - tab->tabs.row ;
+           if (move < 0) 
+             move = real_rows - move;
            bottom = tw->tabs.tab_total - th ;
 
-           for(i=tw->tabs.displayChildren, childP=tw->composite.children;
+           for(i=tw->composite.num_children, childP=tw->composite.children;
                  --i >= 0;
                  ++childP)
              if( XtIsManaged(*childP) )
              {
                tab = (TabsConstraints) (*childP)->core.constraints ;
-               tab->tabs.row = (tab->tabs.row + move) % nrows ;
+               tab->tabs.row = (tab->tabs.row + move) % real_rows ;
                tab->tabs.y = bottom - tab->tabs.row * th ;
+               tab->tabs.visible = (tab->tabs.row < display_rows);
              }
          }
        }
@@ -1877,7 +1916,6 @@ TabsShuffleRows(TabsWidget tw)
         *
         * This function requires that max_cw, max_ch already be set.
         */
-
 static int
 PreferredSize(
        TabsWidget      tw,
@@ -1942,18 +1980,22 @@ PreferredSize(
 static int
 PreferredSize2(
        TabsWidget      tw,
-       int             cw,             /* child width, height */
-       int             ch,
+       Dimension       cw,             /* child width, height */
+       Dimension       ch,
        Dimension       *reply_width,   /* total widget size */
        Dimension       *reply_height)
 {
        Dimension       s = SHADWID ;
+       int ret;
 
        /* make room for shadow frame */
        cw += s*2 ;
        ch += s*2 ;
 
-       return PreferredSize3(tw, cw, ch, reply_width, reply_height) ;
+       ret = PreferredSize3(tw, cw, ch, reply_width, reply_height) ;
+
+       assert (*reply_width > 0 && *reply_height > 0);
+       return ret;
 }
 
 
@@ -1962,8 +2004,8 @@ PreferredSize2(
 static int
 PreferredSize3(
        TabsWidget      tw,
-       int             wid,            /* child width, height */
-       int             hgt,
+       Dimension       wid,            /* child width, height */
+       Dimension       hgt,
        Dimension       *reply_width,   /* total widget size */
        Dimension       *reply_height)
 {