File:  [Research Unix] / researchv9 / X11 / src / X.V11R1 / lib / Xtk / VPane.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 17:22:00 2018 UTC (8 years, 1 month ago) by root
Branches: belllabs, MAIN
CVS tags: researchv9-SUN3_old, researchv9-SUN3, HEAD
researchv9-SUN3(old)

#ifndef lint
static char rcsid[] = "$Header: /var/lib/cvsd/repos/research/researchv9/X11/src/X.V11R1/lib/Xtk/VPane.c,v 1.1.1.1 2018/04/24 17:22:00 root Exp $";
#endif lint

/*
 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 * 
 *                         All Rights Reserved
 * 
 * Permission to use, copy, modify, and distribute this software and its 
 * documentation for any purpose and without fee is hereby granted, 
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in 
 * supporting documentation, and that the name of Digital Equipment
 * Corporation not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior permission.  
 * 
 * 
 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */
/*
 * VPane.c - VPane composite Widget (Converted to classing toolkit)
 *
 * Author:   Jeanne M. Rich (Original Terry Weissman)
 *           Digital Equipment Corporation
 *           Western Research Laboratory
 * Date:     Friday, Aug 28 1987
 *
 */

#include "Xlib.h"
#include "cursorfont.h"
#include "Intrinsic.h"
#include "VPaneP.h"
#include "VPane.h"
#include "Knob.h"
#include "Atoms.h"

#define offset(field) XtOffset(VPaneWidget,v_pane.field)
#define suboffset(field) XtOffset(SubWidgetPtr,field)

/**********************************************************************************
 *
 * Full instance record declaration
 *
 *********************************************************************************/

static XtResource resources[] = {
    {XtNforeground, XtCColor, XrmRPixel, sizeof(Pixel),
         offset(foreground_pixel), XrmRString, "Black"},
    {XtNknobWidth, XtCWidth, XrmRInt, sizeof(int),
         offset(knob_width), XrmRString, "9"},
    {XtNknobHeight, XtCHeight, XrmRInt, sizeof(int),
	 offset(knob_height), XrmRString, "9"},
    {XtNknobIndent, XtCKnobIndent, XrmRInt, sizeof(int),
	 offset(knob_indent), XrmRString, "16"},
    {XtNknobPixel, XtCKnobPixel, XrmRPixel, sizeof(int),
	 offset(knob_pixel), XrmRString, "Black"},
    {XtNrefigureMode, XtCRefigureMode, XrmRBoolean, sizeof(int),
         offset(refiguremode), XrmRString, "On"}
};

static XtResource subresources[] = {
    {XtNposition, XtCPosition, XrmRInt, sizeof(int),
         suboffset(position), XrmRString, "0"},
    {XtNmin, XtCMin, XrmRInt, sizeof(int),
         suboffset(min), XrmRString, "0"},
    {XtNmax, XtCMax, XrmRInt, sizeof(int),
         suboffset(max), XrmRString, "1000"},
    {XtNautoChange, XtCAutoChange, XrmRBoolean, sizeof(int),
         suboffset(autochange), XrmRString, "On"}
};

static void Initialize();
static void Realize();
static void Destroy();
static void Resize();
static void SetValues();
static XtGeometryResult GeometryManager();
static void ChangeManaged();
static void InsertChild();
static void DeleteChild();

VPaneClassRec vPaneClassRec = {
   {
/* core class fields */
    /* superclass         */   (WidgetClass) &constraintClassRec,
    /* class name         */   "VPane",
    /* size               */   sizeof(VPaneRec),
    /* class initialize   */   NULL,
    /* class_inited       */   FALSE,
    /* initialize         */   Initialize,
    /* realize            */   Realize,
    /* actions            */   NULL,
    /* num_actions        */   0,
    /* resourses          */   resources,
    /* resource_count     */   XtNumber(resources),
    /* xrm_class          */   NULLQUARK,
    /* compress_motion    */   TRUE,
    /* compress_exposure  */   TRUE,
    /* visible_interest   */   FALSE,
    /* destroy            */   Destroy,
    /* resize             */   Resize,
    /* expose             */   NULL,
    /* set_values         */   SetValues,
    /* accept_focus       */   NULL
   }, {
/* composite class fields */
    /* geometry_manager   */   GeometryManager,
    /* change_managed     */   ChangeManaged,
    /* insert_child       */   InsertChild,
    /* delete_child       */   DeleteChild,
    /* move_focus_to_next */   NULL,
    /* move_focus_to_prev */   NULL
   }, {
/* constraint class fields */
    /* subresourses       */   subresources,
			       /* subresource_count  */   XtNumber(subresources)
   }, {
    /* mumble             */   0  /* make C compiler happy */
   }
};

static int CursorNums[4] = {0,
			    XC_sb_up_arrow,
			    XC_sb_v_double_arrow,
			    XC_sb_down_arrow};

static Boolean NeedsAdjusting(vpw)
VPaneWidget vpw;
{

   int needed, i;

   for (i = 0; i < (vpw->composite.num_children/2); i++) {
      if (vpw->composite.children[i * 2]->core.managed)
         needed += sublist[i].dheight + BORDERWIDTH;
   }
   needed -= BORDERWIDTH;
   if (needed > vpw->composite.children[i * 2]->core.height)
      return(TRUE);
   else return(FALSE);

}

static void AdjustVPaneHeight(vpw, newheight)
  VPaneWidget vpw;
  Dimension newheight;
{
    XtWidgetGeometry request, reply;
    XtGeometryResult result;
    if (newheight < 1) newheight = 1;
    request.height = newheight;
    request.request_mode = CWHeight;
    result = XtMakeGeometryRequest(vpw, &request, &reply);
    if (result == XtGeometryAlmost) {
	request = reply;
	result = XtMakeGeometryRequest(vpw, &request, &reply);
    }
    if (result == XtGeometryYes) {
	vpw->core.height = reply.height;
    }
}


static RefigureLocations(vpw, position, dir)
  VPaneWidget vpw;
  int position;
  int dir;		/* -1 = up, 1 = down, 0 = this border only */
{
    SubWidgetPtr sub, firstsub;
    WidgetList children;
    int     i, old, y, cdir, num_children, child, firstchild;

    if (vpw->composite.num_mapped_children == 0 || !vpw->v_pane.refiguremode)
	return;

    children = vpw->composite.children;
    num_children = vpw->composite.num_children / 2;
    do {
	vpw->v_pane.heightused = 0;
	for (i = 0, sub = vpw->v_pane.sublist; i < num_children; i++, sub++) {
            if (children[i * 2]->core.managed) {
	        if (sub->dheight < sub->min)
		    sub->dheight = sub->min;
	        if (sub->dheight > sub->max)
		    sub->dheight = sub->max;
	        vpw->v_pane.heightused += sub->dheight + BORDERWIDTH;
            }
	}
        vpw->v_pane.heightused -= BORDERWIDTH;
	if (dir == 0 && vpw->v_pane.heightused != vpw->core.height) {
	    for (i = 0, sub = vpw->v_pane.sublist; i < num_children; i++, sub++) {
                if (children[i * 2]->core.managed) {
		    if (sub->dheight != children[i * 2]->core.height)
		        sub->dheight += vpw->core.height - vpw->v_pane.heightused;
                }
            }
	}
    } while (dir == 0 && vpw->v_pane.heightused != vpw->core.height);

    firstsub = vpw->v_pane.sublist + position;
    firstchild = position * 2;
    sub = firstsub;
    child = firstchild;
    cdir = dir;
    while (vpw->v_pane.heightused != vpw->core.height) {
        if (children[child]->core.managed) {
	    if (sub->autochange || cdir != dir) {
	        old = sub->dheight;
	        sub->dheight = vpw->core.height - vpw->v_pane.heightused + old;
	        if (sub->dheight < sub->min)
		    sub->dheight = sub->min;
	        if (sub->dheight > sub->max)
		    sub->dheight = sub->max;
	        vpw->v_pane.heightused += (sub->dheight - old);
	    }
	    sub += cdir;
            child += (cdir * 2);
	    while (sub < vpw->v_pane.sublist ||
                  sub - vpw->v_pane.sublist == num_children) {
	        cdir = -cdir;
	        if (cdir == dir) goto triplebreak;
	        sub = firstsub + cdir;
                child = firstchild + (cdir * 2);
	    }
        }
    }
triplebreak:
    y = -BORDERWIDTH;
    for (i = 0, sub = vpw->v_pane.sublist; i < num_children; i++, sub++) {
        if (child[i * 2]->core.managed) {
	   sub->dy = y;
	   y += sub->dheight + BORDERWIDTH;
        }
    }
}


static CommitNewLocations(vpw)
VPaneWidget vpw;
{
    int i, kx, ky, num_children;
    WidgetList children;
    KnobWidget lastknob;
    SubWidgetPtr sub;

    num_children = vpw->composite.num_children / 2;
    children = vpw->composite.children
    lastknob = NULL:

    /* First unmap all the knobs that are not managed */
    for (i = 0; i < vpw_composite.num_children; i+2)
       if (children[i]->core.managed == FALSE) {
          if (children[i + 1]->core.managed == TRUE) {
             XtUnmapWidget(children[i + 1]);
             children[i + 1]->core.managed = FALSE;
          }
       }
    }

    for (i = 0, sub = vpw->v_pane.sublist; i < num_children; i++, sub++) {
        if (children[i * 2]->core.managed) {

            /* see if the widget needs to be moved */
            if (sub->dy != children[i * 2]->core.y) 
                XtMoveWidget(children[i * 2], sub->dy, -BORDERWIDTH);
 
            /* see if the widget needs to be resized */
            if ((sub->dheight != children[i * 2]->core.height) ||
                (children[i * 2]->core.width != vpw->core.width) ||
                (children[i * 2]->core.borderwidth != BORDERWIDTH)) 
                XtResizeWidget(children[i * 2], vpw->core.height, sub->dheight,
                        BORDERWIDTH);

            /* Move and Display the Knob */
	    kx = vpw->core.width - vpw->v_pane.knobindent;
	    ky = children[i * 2]->core.y +  children[i * 2]->core.height -
                  (vpw->v_pane.knobheight/2)+1;
            XtMoveWidget(sub->knob, kx, ky);
            if (sub->knob->core.managed == FALSE) {
                XtMapWidget(sub->knob);
                sub->knob->core.managed = TRUE;
            }
            XRaiseWindow(XtDisplay(sub->knob), XtWindow(sub->knob));
            lastknob = sub->knob;
            
	}
    }

    if (lastknob != NULL) {
        XtUnMapWidget(lastknob);
        lastknob->core.managed = FALSE;
    }
}


static RefigureLocationsAndCommit(vpw, position, dir)
  VPaneWidget data;
  int position, dir;
{
    RefigureLocations(vpw, position, dir);
    CommitNewLocations(vpw);
}


EraseInternalBorders(data)
  WidgetData data;
{
    int     i;
    for (i = 1; i < data->numsubwindows; i++)
	XFillRectangle(data->dpy, data->window, data->invgc,
		       0, data->sub[i].y, data->width, BORDERWIDTH);
}
/*

DrawInternalBorders(data)
  WidgetData data;
{
    int     i;
    for (i = 1; i < data->numsubwindows; i++)
	XFillRectangle(data->dpy, data->window, data->normgc,
		       0, data->sub[i].y, data->width, BORDERWIDTH);
}


static DrawTrackLines(data)
  WidgetData data;
{
    int     i;
    SubWindowPtr sub;
    for (i = 1, sub = data->sub + 1; i < data->numsubwindows; i++, sub++) {
	if (sub->olddy != sub->dy) {
	    XDrawLine(data->dpy, data->window, data->flipgc,
		  0, sub->olddy, (Position) data->width, sub->olddy);
	    XDrawLine(data->dpy, data->window, data->flipgc,
		  0, sub->dy, (Position) data->width, sub->dy);
	    sub->olddy = sub->dy;
	}
    }
}

static EraseTrackLines(data)
  WidgetData data;
{
    int     i;
    SubWindowPtr sub;
    for (i = 1, sub = data->sub + 1; i < data->numsubwindows; i++, sub++)
	XDrawLine(data->dpy, data->window, data->flipgc,
	      0, sub->olddy, (Position) data->width, sub->olddy);
}

static XtEventReturnCode HandleKnob(event)
  XEvent *event;
{
    WidgetData data;
    int     position, diff, y, i;

    data = DataFromWindow(event->xbutton.display, event->xbutton.window);
    if (!data) return XteventNotHandled;
    switch (event->type) {
	case ButtonPress: 
	    y = event->xbutton.y;
	    if (data->whichtracking != -1)
		return XteventNotHandled;
	    for (position = 0; position < data->numsubwindows; position++)
		if (data->sub[position].knob == event->xbutton.window)
		    break;
	    if (position >= data->numsubwindows)
		return XteventNotHandled;
	    
	    (void) XGrabPointer(data->dpy, event->xbutton.window, FALSE,
				(unsigned int)PointerMotionMask | ButtonReleaseMask,
				GrabModeAsync, GrabModeAsync, None,
				XtGetCursor(data->dpy,
					    CursorNums[event->xbutton.button]),
				CurrentTime);
	    data->whichadd = data->whichsub = NULL;
	    data->whichdirection = 2 - event->xbutton.button; * Hack! *
	    data->starty = y;
	    if (data->whichdirection >= 0) {
		data->whichadd = data->sub + position;
		while (data->whichadd->max == data->whichadd->min &&
			data->whichadd > data->sub)
		    (data->whichadd)--;
	    }
	    if (data->whichdirection <= 0) {
		data->whichsub = data->sub + position + 1;
		while (data->whichsub->max == data->whichsub->min &&
			data->whichsub < data->sub + data->numsubwindows - 1)
		    (data->whichsub)++;
	    }
	    data->whichtracking = position;
	    if (data->whichdirection == 1)
		(data->whichtracking)++;
	    EraseInternalBorders(data);
	    for (i = 0; i < data->numsubwindows; i++)
		data->sub[i].olddy = -99;
	* Fall through *

	case MotionNotify: 
	case ButtonRelease:
	    if (event->type == MotionNotify) y = event->xmotion.y;
	    else y = event->xbutton.y;
	    if (data->whichtracking == -1)
		return XteventNotHandled;
	    for (i = 0; i < data->numsubwindows; i++)
		data->sub[i].dheight = data->sub[i].height;
	    diff = y - data->starty;
	    if (data->whichadd)
		data->whichadd->dheight = data->whichadd->height + diff;
	    if (data->whichsub)
		data->whichsub->dheight = data->whichsub->height - diff;
	    RefigureLocations(data, data->whichtracking, data->whichdirection);

	    if (event->type != ButtonRelease) {
		DrawTrackLines(data); * Draw new borders *
		return XteventHandled;
	    }
	    XUngrabPointer(data->dpy, CurrentTime);
	    EraseTrackLines(data);
	    CommitNewLocations(data);
	    DrawInternalBorders(data);
	    data->whichtracking = -1;
	    return XteventHandled;
    }
    return XteventNotHandled;
}
*/

/* Semi-public routines. */

static XtGeometryReturnCode GeometryManager(w, request, reply)
Widget w;
WidgetGeometry *request, *reply;
{

   return(XtgeometryNo);

}

static void Initialize(w)
Widget w;
{

    VPaneWidget vpw = (VPaneWidget) w;
    unsigned long valuemask;
    XGCValues values;

    values.foreground = vpw->v_pane.foreground_pixel;
    values.function = GXcopy;
    values.plane_mask = ~0;
    values.fill_style = FillSolid;
    values.fill_rule = EvenOddRule;
    values.subwindow_mode = IncludeInferiors;
    valuemask = GCForeground | GCFunction | GCPlaneMask | GCFillStyle
	| GCFillRule | GCSubwindowMode;
    vpw->v_pane.normgc = XtGetGC(vpw->core.display, vpw->core.window, valuemask,
                                   &values);
    values.foreground = vpw->core.background_pixel;
    vpw->v_pane.invgc = XtGetGC(vpw->core.display, vpw->core.window, valuemask,
                                  &values);
    values.function = GXinvert;
#if BORDERWIDTH == 1
    values.line_width = 0;	/* Take advantage of fast server lines. */
#else
    values.line_width = BORDERWIDTH;
#endif
    values.line_style = LineSolid;
    valuemask |= GCLineWidth | GCLineStyle;
    vpw->v_pane.flipgc = XtGetGC(vpw->core.display, vpw->core.window, valuemask,
                                 &values);
    vpw->v_pane.heightused = 0;
    vpw->v_pane.sublist = NULL;
    vpw->v_pane.whichtracking = -1;
    vpw->v_pane.refiguremode = TRUE;
}


static void Realize(w, valueMask, attributes)
register Widget w;
Mask valueMask;
XSetWindowAttributes *attributes;

{

    attributes->bit_gravity = NorthWestGravity;
    valueMask |= CWBitGravity;

    w->core.window = 
          XCreateWindow(w->core.display, w->core.parent, w->core.x, w->core.y,
                        w->core.width, w->core.height, w_core.border_width,
                        0, InputOutput, (Visual *)CopyFromParent, valueMask,
                        attributes);
} /* Realize */

static void Destroy(vpw)
register VPaneWidget vpw;
{

   XtFree((char *) vpw->v_pane.sublist);

} /* Destroy */


static void InsertChild(w, args, argcount)
register Widget w;
ArgList args;
int argcount;
{

   static Arg knobargs[] = {
      {XtNwidth, (XtArgVal) 0},
      {XtNheight, (XtArgVal) 0},
      {XtNbackground, (XtArgVal) "Black"}
   };

   Cardinal     position;
   VPaneWidgetClass  myclass;
   ConstraintWidgetClass superclass;
   ConstraintWidget cw;
   SubWidgetPtr sub;
   int i;

   myclass = (VPaneWidgetClass) vPaneWidgetClass;
   superclass = (ConstraintWidgetClass) myclass->core_class.superclass;

   /* insert the child widget in the composite children list with the */
   /* superclass insert_child routine.                                */
   superclass->composite_class.insert_child(w, args, argcount);

   if (!XtIsSubclass(w, KnobWidgetClass)) {
      cw = w->core.parent;

      /* ||| Panes will be added in the order they are created, temporarilly */
      /* they are also managed at creation time.                             */

      /* will normally get the position from the insert position routine */
      position = cw->composite_widget.num_children / 2;
      cw->v_pane.sublist =
         (SubWidgetPtr) XtRealloc((caddr_t) cw->v_pane.sublist,
         ((cw->composite_widget.num_children/2 + 1) * sizeof(SubWidgetInfo)));

      /* shift up pane info then position new pane info */
      for (i = cw->composite_widget.num_children/2; i > position; i++)
         cw->v_pane.sublist[i] = cw->v_pane.sublist[i - 1];

      /* set the desired height of the pane */
      cw->v_pane.sublist[position].dheight = w->core.height;

      /* Get the subresources for this child widget */
      sub = &(cw->v_pane.sublist[position]);
      XtGetSubResources(cw, sub, w->core.name,
         w->core.widget_class->core_class.class_name,
         subresources, XtNumber(subresources), args, argcount);

      /* Create the Knob Widget */
      knobargs[0].value = (XtArgVal) cw->v_pane.knob_width;
      knobargs[1].value = (XtArgVal) cw->v_pane.knob_height;
      knobargs[2].value = (XtArgVal) cw->v_pane.knob_pixel;
      sub->knob = XtCreateWidget("Knob", KnobWidgetClass, (CompositeWidget) cw,
              knobargs, XtNumber(knobargs));
/*
      XtSetEventHandler(sub->knob,
          ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, FALSE, HandleKnob,
          (caddr_t) NULL);
*/

      XDefineCursor(XtDisplay(sub->knob), sub->knob,
                    XtGetCursor(XtDisplay(sub->knob), XC_double_arrow));

   }

} /* InsertChild */

static void DeleteChild(w)
Widget w;
{

   Cardinal     position;
   VPaneWidgetClass  myclass;
   ConstraintWidgetClass superclass;
   ConstraintWidget cw;
   SubWidgetPtr sub;

   /* remove the subwidget info and destroy the knob */
   if (!XtIsSubClass(w, KnobWidgetClass)) {
      cw = w->core.parent;

      /* find out the postion of the widget */
      for (position = 0; position < cw->composite.num_children; position++) {
         if (cw->composite.children[position] == w)
            break;
      }
      position = position/2;

      /* Destroy the knob */
      XtDestroyWidget(cw->v_pane.sublist[position].knob);

      /* Ripple the subwidget info down, over the deleted pane */
      for (i = position; i < cw->composite.num_children/2; i++)
         cw->v_pane.sublist[i] = cw->v_pane.sublist[i + 1];

   } 

   myclass = (VPaneWidgetClass) vPaneWidgetClass;
   superclass = (ConstraintWidgetClass) myclass->core_class.superclass;

   /* delete the child widget in the composite children list with the */
   /* superclass delete_child routine.                                */
   superclass->composite_class.delete_child(w);

} /* DeleteChild */

static void ChangeManaged(vpw)
VPaneWidget vpw;
{

   /* see if the height of the VPane needs to be adjusted to fit all the panes */
   if (NeedsAdjusting(vpw))
      AdjustVPaneHeight(vpw);
   RefigureLocationsAndCommit(vpw, 0, 1);

} /* ChangeManaged */

static void Resize(vpw)
VPaneWidget vpw;
{

   RefigureLocationsAndCommit(vpw, 0, 1);

} /* Resize */

static void SetValues(oldvpw, newvpw)
VPaneWidget oldvpw, newvpw;
{
} /* SetValues */


/* Change the min and max size of the given sub window. */

void XtVPanedSetMinMax(vpw, paneWidget, min, max)
VPaneWidget vpw;
Widget paneWidget;
int    min, max;
{

    int i;

    for (i = 0; i < vpw->composite.num_children; i + 2) {
	if (vpw->composite.children[i] == paneWidget) {
	    vpw->v_pane.sublist[i / 2].min = min;
	    vpw->v_pane.sublist[i / 2].max = max;
	    RefigureLocationsAndCommit(vpw, i/2, 1);
	    return;
	}
    }
}


/* Get the min and max size of the given sub window. */

void XtVPanedGetMinMax(vpw, paneWidget, min, max)
VPaneWidget vpw;
Widget paneWindow;
int    *min, *max;
{

    int i;

    for (i = 0; i < vpw->composite.num_children; i + 2) {
	if (vpw->composite.children[i] == paneWidget) {
	    *min = vpw->v_pane.sublist[i / 2].min;
	    *max = vpw->v_pane.sublist[i / 2].max;
	    return;
	}
    }
}

int XtVPanedGetNumSub(vpw)
VPaneWidget vpw;
{

   int i, num_sub_widgets;

   num_sub_widgets = 0;

   for (i = 0; i < vpw->composite.num_children; i + 2) {
      if (vpw->composite.children[i]->core.managed)
          num_sub_widgets++;
   }

   return(num_sub_widgets);
}




void XtVPanedRefigureMode(vpw, mode)
  VPaneWidget vpw;
  Boolean  mode;
{
    vpw->v_pane.refiguremode = mode;
	if (mode)
	    RefigureLocationsAndCommit(vpw, vpw->composite.num_children/2 - 1, -1);
    }
}

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.