ftp.nice.ch/pub/next/unix/developer/pcn.2.0.s.tar.gz#/contrib/gauge/Xsw/MyList.c

This is MyList.c in view mode; [Download] [Up]

#if ( !defined(lint) && !defined(SABER))
  static char PCN_rcsid[] = "$Header: /ufs/comp/mei/PROJ_PCN/onprofile/IFModel/Xsw/RCS/MyList.c,v 1.1 1992/04/17 18:26:10 mei Exp $";
#endif

/******************************************************************************
*									      *
*	Copyright (C) The Aerospace Corporation 1991			      *
*									      *
*	This software was developed by The Aerospace Corporation as a 	      *
*	research endeavor for the United States Air Force 		      *
*	Space Systems Division.  The current version of the Gauge	      *
*	computer program is available for  release to you for		      *
*	educational and research purposes only.  It is not 		      *
*	to be used for commercial purposes.				      *
*									      *
*	In addition, the following conditions shall apply.		      *
*									      *
*	1) The computer software and documentation were designed to	      *
*	satisfy internal Aerospace requirements only.			      *
*	The software is provided ``as is,'' and The Aerospace Corporation     *
*	makes no warranty, expressed or implied, as to it accuracy,	      *
*	functioning, or fitness for a particular purpose.		      *
*									      *
*	2) The Aerospace Corporation and its personnel are not		      *
*	responsible for providing technical support or general assistance     *
*	with respect to the software.					      *
*									      *
*	3) Neither The Aerospace Corporation nor its personnel shall be	      *
*	liable for claims, losses, or damages arising out of or connected     *
*	with the use of this software.					      *
*	Your sole and exclusive remedy shall be to request a replacement      *
*	copy of the program.						      *
*									      *
******************************************************************************/

#include <X11/IntrinsicP.h>
#include "Xsw.h"
#include "MyListP.h"
#include "Patterns.h"

#define DIMENSION(widget) ( (widget->myList.vertical) ? (widget->core.height) : (widget->core.width) )

#define FONTWIDTH(font) ((font)->max_bounds.rbearing-(font)->max_bounds.lbearing)


static XtResource resources[] = {
#define offset(field) XtOffset(MyListWidget, myList.field)
  { XtNcallback, XtCCallback, XtRCallback, sizeof(XPointer),
	offset(callback), XtRCallback, NULL },
   { XtNlongest, XtCLongest, XtRInt, sizeof(int),
	  offset(longest), XtRString, "0" },
    { XtNmaxChars, XtCMaxChars, XtRInt, sizeof(int),
	  offset(max_chars), XtRString, "0" },
    { XtNnumberStrings, XtCNumberStrings, XtRInt, sizeof(int),
	  offset(nitems), XtRString, "0" },
    { XtNfont, XtCFont, XtRFontStruct, sizeof(XtPointer),
	offset(font), XtRString, XtDefaultFont },
    { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
	offset(foreground), XtRString, XtDefaultForeground },
    { XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
	offset(highlight), XtRString, XtDefaultForeground },
    { XtNlist, XtCList, XtRPointer, sizeof(XtPointer),
	offset(list), XtRString, NULL },
    { XtNspacing, XtCSpacing, XtRDimension, sizeof(Dimension),
	offset(space), XtRString, "1" },
    { XtNtopItem, XtCItem, XtRInt, sizeof(int),
	offset(top_item), XtRString, "0" },
    { XtNvertical, XtCVertical, XtRBoolean, sizeof(Boolean),
	offset(vertical), XtRString, "True" },
    { XtNrotate, XtCRotate, XtRBoolean, sizeof(Boolean),
	offset(rotate), XtRString, "False" },
    { XtNrigidZoom, XtCRigidZoom, XtRBoolean, sizeof(Boolean),
	offset(rigid_zoom), XtRString, "False" },
    { XtNzoom, XtCZoom, XtRBoolean, sizeof(Boolean),
	offset(zoom), XtRString, "True" },
#undef offset
};

static void Initialize();
static void Redisplay();
static void Resize();
static void Destroy();
static Boolean SetValues();
static void DrawItem();

static void SelectItem();
static void ManyItems();

void SetItem();

static XtActionsRec actions[] =
{
    {"SelectItem", SelectItem},
    {"ManyItems", ManyItems},
};

static char translations[] =
"<Btn1Down>:		SelectItem()	\n\
 <Btn1Motion>:          ManyItems()     \n\
";

/* definition in MyList.h */
static MyListItemInfo info;

MyListClassRec myListClassRec = {
  { /* core fields */
    /* superclass		*/	(WidgetClass) &coreClassRec,
    /* class_name		*/	"MyList",
    /* widget_size		*/	sizeof(MyListRec),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	XtInheritRealize,
    /* actions			*/	actions,
    /* num_actions		*/	XtNumber(actions),
    /* resources		*/	resources,
    /* num_resources		*/	XtNumber(resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	Destroy,
    /* resize			*/	Resize,
    /* expose			*/	Redisplay,
    /* set_values		*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	translations,
    /* query_geometry		*/	XtInheritQueryGeometry,
    /* display_accelerator	*/	XtInheritDisplayAccelerator,
    /* extension		*/	NULL
  },
  { /* template fields */
    /* empty			*/	0
  }
};

WidgetClass myListWidgetClass = (WidgetClass)&myListClassRec;

static void
GetAllGC(cw)
MyListWidget cw;
{
  XGCValues values;
  XtGCMask mask = GCForeground | GCBackground | GCFont |
    GCFillStyle;

  values.foreground = cw->core.background_pixel;
  values.background = cw->core.background_pixel;
  values.font = cw->myList.font->fid;
  values.fill_style = FillSolid;
  cw->myList.cleargc = XtGetGC((Widget) cw, mask, &values);


  if ((cw->myList.highlight == cw->myList.foreground) ||
      (cw->myList.highlight == cw->core.background_pixel)) {
    values.background = cw->myList.foreground;
    values.foreground = cw->core.background_pixel;
    values.fill_style = FillOpaqueStippled;
    mask = mask | GCStipple;
    values.stipple = 
      XCreateBitmapFromData(XtDisplay(cw),
			    RootWindow(XtDisplay(cw),
				       DefaultScreen(XtDisplay(cw))),
			    zero,
			    PAT_WIDTH, PAT_HEIGHT);
    
  } else {
    values.foreground = cw->myList.highlight;
  }
    
  cw->myList.revgc = XtGetGC((Widget) cw, mask, &values);  

  values.foreground = cw->myList.foreground;
  values.background = cw->core.background_pixel;
  cw->myList.normgc = XtGetGC((Widget) cw, mask, &values);

}

static void FillSlot(cw, gc, i, pos)
MyListWidget cw;
GC gc;
int i, pos;
{ 
  int x, y;
  unsigned int w, h;
  Boolean text;

  if (cw->myList.vertical) {
    if (cw->myList.space >= FONTHEIGHT(cw->myList.font))
      { y = pos; x = 0; text = True; }
    else {
      y = pos-cw->myList.space; x = 0;
      h = cw->myList.space-1; w = cw->core.width;
      text = False;
    }
  }
  else { 
    if (cw->myList.space >= ((cw->myList.rotate) ? FONTWIDTH(cw->myList.font) : cw->myList.longest)) { 
      y = cw->myList.font->max_bounds.ascent; x = pos; text = True; 
    } else {
      y = 0; x = pos-cw->myList.space;
      h = cw->core.height; w = cw->myList.space-1;
      text = False;
    }
  }
  if (!text) 
    XFillRectangle(XtDisplay(cw), XtWindow(cw), gc,
		   x, y, w, h);
  else if (cw->myList.rotate) {
    char buff[2];
    char *sPtr = cw->myList.list[i].label;
    char *cPtr = sPtr + strlen(cw->myList.list[i].label);
    
    y += (cw->myList.max_chars - 1) * FONTHEIGHT(cw->myList.font);
    buff[1] = '\0';
    while ( --cPtr >= sPtr) {
      buff[0] = *cPtr;
      XDrawImageString(XtDisplay(cw), XtWindow(cw), gc, x, y, buff, 1);
      y -= cw->myList.font->max_bounds.ascent;
    } 
  } else
    XDrawImageString(XtDisplay(cw), XtWindow(cw), gc,
		     x, y, cw->myList.list[i].label,
		     strlen(cw->myList.list[i].label));
}

static Boolean
IsVisible(w, pos)
MyListWidget w;
int pos;
{
  Boolean result = True;

  if (!w->myList.zoom)
    if (w->myList.vertical) {
      if (pos >= w->core.height/w->myList.space+w->myList.top_item)
	result = False;
    } else {
      if (pos >= w->core.width/w->myList.space+w->myList.top_item)
	 result = False;
    }
  if ((pos < w->myList.top_item) || (pos >= w->myList.nitems))
    result = False;

  return result;
}

static void ShowList(cw)
MyListWidget cw;
{
  int i;

  if ((XtWindow(cw) != (Window) NULL) && 
           (cw->myList.list != (ListElement *)NULL)) {
    i = cw->myList.top_item;
    while (IsVisible(cw, i)) {
      DrawItem(cw, i);
      i++;
    }
  }
 /* This is the efficient but inelegant method    
    boundary = DIMENSION(cw);
    if (cw->myList.vertical) {
      if (cw->myList.space >= FONTHEIGHT(cw->myList.font))
	offset = cw->myList.font->max_bounds.descent +
	  ((cw->myList.space - FONTHEIGHT(cw->myList.font))/2);
    }

    while ((cw->myList.list[i].label != (String)NULL) &&
	   ((int)coord <= boundary)) {
      if (!(cw->myList.vertical)) {
	if (cw->myList.space >= cw->myList.longest) {
	  offset = (cw->myList.space + 
		    XTextWidth(cw->myList.font,
			       cw->myList.list[i].label,
			       strlen(cw->myList.list[i].label)))/2;
	  if (offset > cw->myList.space) offset = cw->myList.space;
	}
	else offset = 0;
      }
      if (cw->myList.list[i].state)
	FillSlot(cw, cw->myList.revgc, i, (int)coord - offset);
      else
	FillSlot(cw, cw->myList.normgc, i, (int)coord - offset);
      i++;
      coord += space;
    }
  }
  */
}


/* ARGSUSED */
static void
Initialize(request, new)
MyListWidget request, new;
{

  GetAllGC(new);

  if (new->myList.list[0].label == NULL)
    new->myList.list[0].label = new->core.name;

  new->myList.save_space = new->myList.space;

  if (new->myList.vertical) new->myList.rotate = 0;

  if ((new->myList.longest == 0) || (new->myList.nitems == 0) ||
      (new->myList.max_chars == 0)) {
    int longest = 0;
    int max_chars = 0;
    int nitems = 0;
    int length;
    while (new->myList.list[nitems].label != (String)NULL) {
      length = XTextWidth(new->myList.font, 
			  new->myList.list[nitems].label,
			  strlen(new->myList.list[nitems].label));
      if (length > longest) 
	longest = length;
      length = strlen(new->myList.list[nitems].label);
      if (length > max_chars) 
	max_chars = length;
      nitems++;
    }
    if (new->myList.longest == 0) new->myList.longest = longest;
    if (new->myList.max_chars == 0) new->myList.max_chars = max_chars;
    if (new->myList.nitems == 0) new->myList.nitems = nitems;
  }

  if (new->myList.vertical) {
    new->core.width = new->myList.longest;
    new->core.height = new->myList.nitems*new->myList.space;
  } else if (new->myList.rotate) {
    new->core.width = FONTWIDTH(new->myList.font)*new->myList.nitems;
    new->core.height = new->myList.max_chars * FONTHEIGHT(new->myList.font);
  } else {
    new->core.width = new->myList.longest*new->myList.nitems;
    new->core.height = FONTHEIGHT(new->myList.font);
  }    
  

  if ((new->myList.vertical) && 
      (new->myList.space < FONTHEIGHT(new->myList.font))) {
    new->core.width = new->myList.space;
  }
  if (!(new->myList.vertical) && !(new->myList.rotate) &&
      (new->myList.space < new->myList.longest)) {
    new->core.height = new->myList.space;
  }
  if (!(new->myList.vertical) && new->myList.rotate &&
      (new->myList.space < FONTWIDTH(new->myList.font))) {
    new->core.height = new->myList.space;
  }

  new->myList.tog_state = True;
  new->myList.save_top = new->myList.top_item;
}

void XswListRedisplay(w)
MyListWidget w;
{
  if (!XtIsRealized((Widget) w))
    return;
  else
    ShowList(w);
}


static void
Redisplay(cw, event)
MyListWidget cw;
XExposeEvent *event;
{
  
  int pos, max;

  if (!XtIsRealized((Widget) cw))
    return;
  
  if (event) {  /* called from btn-event or expose */
    if (cw->myList.zoom && (!cw->myList.rigid_zoom)) {
      pos = (cw->myList.vertical ? event->y : event->x) / 
	((double)DIMENSION(cw)/(double)cw->myList.nitems);
      max = (cw->myList.vertical ? 
	     event->y+event->height : event->x+event->width) / 
	((double)DIMENSION(cw)/(double)cw->myList.nitems);
    } else {
      if (cw->myList.vertical) {
	pos = cw->myList.top_item + event->y / cw->myList.space;
	max = cw->myList.top_item + 
	  (event->height+event->y)/cw->myList.space + 1;
      } else {
	pos = cw->myList.top_item + event->x / cw->myList.space;
	max = cw->myList.top_item + 
	  (event->width+event->x)/cw->myList.space + 1;
      }
    }
    if (max > cw->myList.nitems)
      max = cw->myList.nitems;
    max = MIN(max, ((double)DIMENSION(cw)/(double)cw->myList.space) + 
	      cw->myList.top_item);
    if (pos < 0) pos = 0;
    
    if ((max == cw->myList.nitems) && (pos == 0))
      ShowList(cw);
    else
      for( ; pos<max; pos++)
	DrawItem(cw, pos);
  }
  else {        /* called because complete redraw */
    ShowList(cw);
  }
}

static void ScrollList(cw, p0, p1)
MyListWidget cw;
int p0, p1;
{
  int pos;
  unsigned int size, cover, excess;
  XExposeEvent fake_event;

  pos = (p1 - p0) * cw->myList.space;

  if (cw->myList.zoom && !cw->myList.rigid_zoom) {
    excess = 0;
  } else {
    excess = DIMENSION(cw) % cw->myList.space;
  }
  
  if (pos > 0) {
    p0 = pos;
    p1 = 0;
    size = DIMENSION(cw) - pos - excess;
    pos = size;
    cover = p0;
    fake_event.y = fake_event.x = size;
    fake_event.height = fake_event.width = p0;
  } else {
    p0 = 0;
    p1 = -pos;
    size = DIMENSION(cw) + pos - excess;
    pos = 0;
    cover = p1;
    fake_event.y = fake_event.x = 0;
    fake_event.height = fake_event.width = p1;
  }

  if (size > DIMENSION(cw)) {
    XFillRectangle(XtDisplay(cw), XtWindow(cw), cw->myList.cleargc,
		   0, 0, cw->core.width, cw->core.height);
    ShowList(cw);
  } else {
    if (cw->myList.vertical) { 
      XCopyArea(XtDisplay(cw), XtWindow(cw), XtWindow(cw),
		cw->myList.normgc, 0, p0, cw->core.width,
		size, 0, p1);
      XFillRectangle(XtDisplay(cw), XtWindow(cw), cw->myList.cleargc,
		     0, pos, cw->core.width, cover);
    } else {
      XCopyArea(XtDisplay(cw), XtWindow(cw), XtWindow(cw),
		cw->myList.normgc, p0, 0, size,
		cw->core.height, p1, 0);
      XFillRectangle(XtDisplay(cw), XtWindow(cw), cw->myList.cleargc,
		     pos, 0, cover, cw->core.height);
    }
    Redisplay(cw, &fake_event);
  }
}
 
/* ARGSUSED */
static Boolean
SetValues(current, request, new)
Widget current, request, new;
{
  MyListWidget curcw = (MyListWidget) current;
  MyListWidget newcw = (MyListWidget) new;
  Boolean redisplay = False;
  Boolean change_stats = False;
  Arg arg[2];

  if ((curcw->myList.foreground != newcw->myList.foreground) ||
      (curcw->myList.highlight != newcw->myList.highlight)) {
    if (newcw->myList.normgc)
      XtReleaseGC((Widget) newcw, newcw->myList.normgc);
    if (newcw->myList.revgc)
      XtReleaseGC((Widget) newcw, newcw->myList.revgc);
    if (newcw->myList.cleargc)
      XtReleaseGC((Widget) newcw, newcw->myList.cleargc);
    GetAllGC(newcw);
    redisplay = True;
  }

  if (curcw->myList.zoom != newcw->myList.zoom) {
    if (newcw->myList.zoom) {
      newcw->myList.save_top = newcw->myList.top_item;
      newcw->myList.top_item = 0;
    } else {
      newcw->myList.top_item = newcw->myList.save_top;
    }
  }
   
  if ((curcw->myList.space != newcw->myList.space) ||
      (curcw->myList.zoom != newcw->myList.zoom)) {
    newcw->myList.space = newcw->myList.save_space;
    Resize(newcw, NULL);
    redisplay = True;
  }

  if ((curcw->myList.list != newcw->myList.list) ||
      (curcw->myList.nitems != newcw->myList.nitems) ||
      (curcw->myList.longest != newcw->myList.longest)) {
    change_stats = True;
    redisplay = True;
  }

  if ((curcw->myList.rotate != newcw->myList.rotate)) {
    XtSetArg(arg[0], XtNheight,
	     (Dimension) (newcw->myList.rotate ? 
			  newcw->myList.longest :
			  newcw->myList.max_chars * FONTHEIGHT(newcw->myList.font)));
    XtSetValues((Widget) newcw, arg, 1);    
  }

  if (curcw->myList.top_item != newcw->myList.top_item) {
    while ((newcw->myList.top_item > 0) &&
	   (newcw->myList.space *
	    (newcw->myList.nitems-newcw->myList.top_item) < 
	    DIMENSION(newcw) -
	    (DIMENSION(newcw) % newcw->myList.space)))
      newcw->myList.top_item--;
    
    if (newcw->myList.top_item < 0) newcw->myList.top_item = 0;

    ScrollList(newcw, curcw->myList.top_item,
	       newcw->myList.top_item);
  }
 
  if (change_stats) {
    if ((newcw->myList.longest == 0) || (newcw->myList.nitems == 0)
	|| (newcw->myList.max_chars)) {
      int longest = 0;
      int max_chars = 0;
      int nitems = 0;
      int length;
      while (newcw->myList.list[nitems].label != (String)NULL) {
	length = XTextWidth(newcw->myList.font, 
			    newcw->myList.list[nitems].label,
			    strlen(newcw->myList.list[nitems].label));
	if (length > longest) 
	  longest = length;
	length = strlen(newcw->myList.list[nitems].label);
	if (length > max_chars) 
	  max_chars = length;
	nitems++;
      }
      if (newcw->myList.longest == 0) newcw->myList.longest = longest;
      if (newcw->myList.max_chars == 0) newcw->myList.max_chars = max_chars;
      if (newcw->myList.nitems == 0) newcw->myList.nitems = nitems;
      Resize(newcw, NULL);
    }
    if (newcw->myList.vertical) 
      XtVaSetValues((Widget)newcw, XtNwidth, (Dimension)newcw->myList.longest,NULL);
    
  }
  
  return redisplay;
}


/* ARGSUSED */
static void
Resize(cw, event)
MyListWidget cw;
XExposeEvent *event;
{
  if (cw->myList.zoom) {
    /* 
     * Calculate the maximum spacing that will allow the
     * entire list to be displayed.
     */
    cw->myList.space = DIMENSION(cw) / cw->myList.nitems;
  } else {
    while ((cw->myList.top_item > 0) &&
	   (cw->myList.space *
	    (cw->myList.nitems-cw->myList.top_item) < 
	    cw->core.height -
	    (cw->core.height % cw->myList.space)))
      cw->myList.top_item--;
  }
}

static void Destroy(cw)
MyListWidget cw;
{
  if (cw->myList.normgc)
    XtReleaseGC((Widget) cw, cw->myList.normgc);
  if (cw->myList.revgc)
    XtReleaseGC((Widget) cw, cw->myList.revgc);
  if (cw->myList.cleargc)
    XtReleaseGC((Widget) cw, cw->myList.cleargc);
}


void XswListSetItem(w, pos, state)
MyListWidget w;
int pos;
Boolean state;
{
  

  if (w->myList.list[pos].state != state) {
    w->myList.list[pos].state = state;
    if (IsVisible(w, pos))
      DrawItem(w, pos);
  }
}  

static Boolean
GetCoord(w, event, nPtr)
MyListWidget w;
XButtonEvent *event;
int * nPtr;
{
  if ((w->myList.zoom) && (!w->myList.rigid_zoom)) {
    *nPtr = (w->myList.vertical ? event->y : event->x) / 
      ((double)DIMENSION(w)/(double)w->myList.nitems);
  } else {
    if (w->myList.vertical) {
      *nPtr = w->myList.top_item + event->y / w->myList.space;
    } else {
      *nPtr = w->myList.top_item + event->x / w->myList.space;
    }
  }

  if (!IsVisible(w, *nPtr)) return False;
  else return True;
}

static void
SelectItem(w, event)
MyListWidget w;
XButtonEvent *event;
{
  int new;

  if (!GetCoord(w, event, &new)) return;
  
  w->myList.list[new].state =
    !w->myList.list[new].state;

  w->myList.tog_state = w->myList.list[new].state;

  DrawItem(w, new);
  info.item = new;
  info.state = w->myList.tog_state;
  XtCallCallbacks((Widget) w, XtNcallback, &info);
}

static void
ManyItems(w, event)
MyListWidget w;
XButtonEvent *event;
{
  int new;

  if (!GetCoord(w, event, &new)) return;

  if (w->myList.list[new].state != w->myList.tog_state) {
    w->myList.list[new].state = w->myList.tog_state;
    DrawItem(w, new);
    info.item = new;
    info.state = w->myList.tog_state;
    XtCallCallbacks((Widget) w, XtNcallback, &info);
  }
}


static void
DrawItem(cw, i)
MyListWidget cw;
int i;
{
  int y;
  int offset = 0;

  if (cw->myList.zoom && (!cw->myList.rigid_zoom)) 
    y = (double)(i + 1) *
      (double)((double)DIMENSION(cw)/(double)cw->myList.nitems);
  else 
    y = (i - cw->myList.top_item + 1) * cw->myList.space;
  if (cw->myList.vertical) {
    if (cw->myList.space >= FONTHEIGHT(cw->myList.font))
      offset = cw->myList.font->max_bounds.descent +
	((cw->myList.space - FONTHEIGHT(cw->myList.font))/2);
  } else if (cw->myList.rotate) {
    if (cw->myList.space >= FONTWIDTH(cw->myList.font)) {
/* Fprototyping .. hui 4/15, very odd
      offset = (cw->myList.space + 
		XTextWidth(cw->myList.font,
			   cw->myList.list[i].label + strlen(cw->myList.list[i]) - 1,
                           1))/2;
   maybe like the following */
      offset = (cw->myList.space + 
		XTextWidth(cw->myList.font,
			   cw->myList.list[i].label,strlen(cw->myList.list[i].label))
                           - 1)/2;
    }
  } else {
    if (cw->myList.space >= cw->myList.longest) {
      offset = (cw->myList.space + 
		XTextWidth(cw->myList.font,
			   cw->myList.list[i].label,
			   strlen(cw->myList.list[i].label)))/2;
      if (offset > cw->myList.space) offset = cw->myList.space;
    }
  }

  if (cw->myList.list[i].state)
    FillSlot(cw, cw->myList.revgc, i, y-offset);
  else 
    FillSlot(cw, cw->myList.normgc, i, y-offset);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.