/* 3270 Graphics Attach widget

   This widget is a sub-class of the Win3270 widget.  It is 
   used for 3277-GA windows.   					*/


#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "Ga3270P.h"

#define offset(field) XtOffset(Ga3270Widget, ga3270.field)

static void SetColor(), SetColor1(), SetColor2(), SetColor3(),
  SetColor4(), SetColor5(), SetColor6(), SetColor7(), SetColor8(),
  SetColor9(), SetColor10(), SetColor11(), SetColor12(), SetColor13(),
  SetColor14(), SetColor15(), SetRefresh();

static XtResource resources[] = {
  {XtNdrawColor, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawColor), XtRCallProc, (caddr_t) SetColor},
  {XtNdrawColor1, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[0]), XtRCallProc, (caddr_t) SetColor1},
  {XtNdrawColor2, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[1]), XtRCallProc, (caddr_t) SetColor2},
  {XtNdrawColor3, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[2]), XtRCallProc, (caddr_t) SetColor3},
  {XtNdrawColor4, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[3]), XtRCallProc, (caddr_t) SetColor4},
  {XtNdrawColor5, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[4]), XtRCallProc, (caddr_t) SetColor5},
  {XtNdrawColor6, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[5]), XtRCallProc, (caddr_t) SetColor6},
  {XtNdrawColor7, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[6]), XtRCallProc, (caddr_t) SetColor7},
  {XtNdrawColor8, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[7]), XtRCallProc, (caddr_t) SetColor8},
  {XtNdrawColor9, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[8]), XtRCallProc, (caddr_t) SetColor9},
  {XtNdrawColor10, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[9]), XtRCallProc, (caddr_t) SetColor10},
  {XtNdrawColor11, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[10]), XtRCallProc, (caddr_t) SetColor11},
  {XtNdrawColor12, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[11]), XtRCallProc, (caddr_t) SetColor12},
  {XtNdrawColor13, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[12]), XtRCallProc, (caddr_t) SetColor13},
  {XtNdrawColor14, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[13]), XtRCallProc, (caddr_t) SetColor14},
  {XtNdrawColor15, XtCDrawColor, XtRPixel, sizeof(Pixel),
     offset(drawstyle[14]), XtRCallProc, (caddr_t) SetColor15},
  {XtNrefreshColor, XtCRefreshColor, XtRPixel, sizeof(Pixel),
     offset(refreshColor), XtRCallProc, (caddr_t) SetRefresh},
  {XtNgaCursor, XtCGaCursor, XtRCursor, sizeof(Cursor),
     offset(gaCursor), XtRString, "crosshair"},
  {XtNgaTranslations, XtCTranslations, XtRTranslationTable,
     sizeof(XtTranslations), offset(gaTranslations), XtRImmediate, NULL},
};


static char newTranslations[] = 
    "<Btn1Down>:	ga3277-set-cursor() \n\
     <Btn1Motion>:	ga3277-set-cursor() \n\
     <Btn2Down>:	ga3277-clear() \n\
     <Btn3Down>:	ga3277-refresh()";


static void Initialize(), Realize(), Redisplay();
static Boolean SetValues();

Ga3270ClassRec ga3270ClassRec = {
  /* Core fields */
  { /* superclass		*/	(WidgetClass) &win3270ClassRec,
    /* class_name		*/	"Ga3270",
    /* widget_size		*/	sizeof(Ga3270Rec),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize	  	*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	Realize,
    /* actions			*/	NULL,
    /* num_actions		*/	0,
    /* resources		*/	resources,
    /* num_resources		*/	XtNumber(resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	NULL,
    /* resize			*/	XtInheritResize,
    /* 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			*/	XtInheritTranslations,
    /* query_geometry		*/	NULL,
    /* display_accelerator      */      XtInheritDisplayAccelerator,
    /* extension                */      NULL,
  },
  /* Win3270 fields */
  { /* empty			*/	0 },
  /* Ga3270 fields */
  { /* empty			*/	0 }
};

WidgetClass ga3270WidgetClass = (WidgetClass) &ga3270ClassRec;


#define g(field) xw->ga3270.field


/* The default color values are set dynamically.  Since they aren't
   used on a monochrome display, they are set to "XtDefaultForeground".
   Otherwise, the Toolkit would print warning messages about not being
   able to allocate colormap entries.  */

#define setc(func, colorval) \
  static void func(widget, closure, value)				\
       Widget widget; int closure; XrmValue *value;			\
  {									\
    XrmValue fromval;							\
    fromval.addr = CellsOfScreen(XtScreen(widget)) > 2 ?		\
                     colorval : "XtDefaultForeground";			\
    fromval.size = strlen(fromval.addr) + 1;				\
    XtConvert(widget, XtRString, &fromval, XtRPixel, value);		\
  }

setc (SetColor,   "White")
setc (SetColor1,  "White")
setc (SetColor2,  "Blue")
setc (SetColor3,  "Green")
setc (SetColor4,  "Red")
setc (SetColor5,  "Cyan")
setc (SetColor6,  "Magenta")
setc (SetColor7,  "Brown")
setc (SetColor8,  "Orange")
setc (SetColor9,  "Grey")
setc (SetColor10, "Pink")
setc (SetColor11, "LightBlue")
setc (SetColor12, "Yellow")
setc (SetColor13, "Aquamarine")
setc (SetColor14, "Sienna")
setc (SetColor15, "Black")
setc (SetRefresh, "Cyan")


/*ARGSUSED*/ static void Initialize(request, new)
     Widget request, new;
{
  Ga3270Widget xw = (Ga3270Widget) new;

  /* Substitute GA cursor for text cursor */
  xw->win3270.cursor = g(gaCursor);

  /* If size wasn't specified, pick some reasonable values */
  if (xw->core.width == 0) xw->core.width = 512;
  if (xw->core.height == 0) xw->core.height = 512 * 3200 / 4096;

  /* Add Ga3270-specific translations */
  XtOverrideTranslations(new, XtParseTranslationTable(newTranslations));

  /* Add any user-specified translations.  It would be nice if this
     could be done using the "*ga3270.translations" resource, but
     that would be overriden by newTranslations.  Therefore, a new
     "*ga3270.gaTranslations" resource was defined.  */

  if (g(gaTranslations))
    XtOverrideTranslations(new, g(gaTranslations));
}


static void Realize(w, value_mask, attributes)
     Widget w;
     Mask *value_mask;
     XSetWindowAttributes *attributes;
{
  Ga3270Widget xw = (Ga3270Widget) w;
  XColor fcolor, bcolor;
  Pixel planes[5], pixval;
  XtGCMask gcmask;
  XGCValues gcv;

  /* Call realize procedure of superclass */
  (*(((Win3270WidgetClass) XtSuperclass(w))->core_class.realize))
   (w, value_mask, attributes);

  /* Set cursor color to the proper value */
  fcolor.pixel = xw->win3270.mouseColor;
  XQueryColor(XtDisplay(w), xw->core.colormap, &fcolor);
  bcolor.pixel = xw->core.background_pixel;
  XQueryColor(XtDisplay(w), xw->core.colormap, &bcolor);
  XRecolorCursor(XtDisplay(w), g(gaCursor), &fcolor, &bcolor);

  /* Try to get some color planes */
  g(colormode) = (PlanesOfScreen(XtScreen(w)) > 1);
  if (g(colormode))
    {
      g(lottaplanes) = True;
      if (!XAllocColorCells(XtDisplay(w), xw->core.colormap, False,
			    planes, 5, &pixval, 1))
	{
	  /* If we can't get five planes, try for two */
	  g(lottaplanes) = False;
	  if (!XAllocColorCells(XtDisplay(w), xw->core.colormap, False,
				planes, 2, &pixval, 1))

	    /* Can't even get two planes, so forget color mode */
	    g(colormode) = False;
	}
    }
  
  if (g(colormode))
    {
      /* Convert pixels to RGB and load into the new cells */
      if (g(lottaplanes))
	{
	  /* +---------------------------------------+ */
	  /* | Color assignments:                    | */
	  /* |                                       | */
	  /* | 0         Background                  | */
	  /* | 1 to 15   Normal drawing colors       | */
	  /* | 16        Refresh over background     | */
	  /* | 17 to 31  Refresh over drawing colors | */
	  /* +---------------------------------------+ */

	  register int i, j;
	  g(colors[0].pixel) = xw->core.background_pixel;
	  for (i = 1; i < 16; i++)
	    g(colors[i].pixel) = g(drawstyle[i - 1]);
	  g(colors[16].pixel) = g(refreshColor);
	  XQueryColors(XtDisplay(w), xw->core.colormap, &g(colors[0]), 17);

	  for (i = 0; i < 32; i++)
	    {
	      g(colors[i].flags) = DoRed | DoGreen | DoBlue;
	      g(colors[i].pixel) = pixval;
	      if (i > 16)
		{
		  g(colors[i].red) = g(colors[16].red);
		  g(colors[i].green) = g(colors[16].green);
		  g(colors[i].blue) = g(colors[16].blue);
		}
	      for (j = 0; j < 5; j++)
		if (i & (1 << j)) g(colors[i].pixel) |= planes[j];
	    }
	  XStoreColors(XtDisplay(w), xw->core.colormap, g(colors), 32);
	}
      else
	{
	  /* Background color */
	  g(colors[0].pixel) = xw->core.background_pixel;
	  XQueryColor(XtDisplay(w), xw->core.colormap, &g(colors[0]));
	  g(colors[0].pixel) = pixval;
	  g(colors[0].flags) = DoRed | DoGreen | DoBlue;

	  /* Normal drawing color */
	  g(colors[1].pixel) = g(drawColor);
	  XQueryColor(XtDisplay(w), xw->core.colormap, &g(colors[1]));
	  g(colors[1].pixel) = pixval | planes[0];
	  g(colors[1].flags) = DoRed | DoGreen | DoBlue;

	  /* Refresh drawing over background */
	  g(colors[2].pixel) = g(refreshColor);
	  XQueryColor(XtDisplay(w), xw->core.colormap, &g(colors[2]));
	  g(colors[2].pixel) = pixval | planes[1];
	  g(colors[2].flags) = DoRed | DoGreen | DoBlue;

	  /* Refresh drawing over normal color */
	  g(colors[3].red) = g(colors[2].red);
	  g(colors[3].green) = g(colors[2].green);
	  g(colors[3].blue) = g(colors[2].blue);
	  g(colors[3].pixel) = pixval | planes[0] | planes[1];
	  g(colors[3].flags) = DoRed | DoGreen | DoBlue;

	  XStoreColors(XtDisplay(w), xw->core.colormap, g(colors), 4);
	}

      /* Create graphics contexts for drawing and clearing */
      gcmask = GCPlaneMask | GCForeground | GCBackground;
      gcv.background = pixval;

      if (g(lottaplanes))
	{
	  gcv.plane_mask = pixval | planes[0] | planes[1] | planes[2] |
	    planes[3];
	  gcv.foreground = g(colors[1].pixel); /* Default color */
	  g(draw_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);

	  gcv.plane_mask = planes[4];
	  gcv.foreground = g(colors[16].pixel); /* Refresh color */
	  g(ref_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);

	  gcv.plane_mask = planes[4];
	  gcv.foreground = g(colors[0].pixel); /* Background color */
	  g(refclear_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);
	}
      else
	{
	  gcv.plane_mask = planes[0];
	  gcv.foreground = g(colors[1].pixel);
	  g(draw_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);

	  gcv.plane_mask = planes[1];
	  gcv.foreground = g(colors[2].pixel);
	  g(ref_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);

	  gcv.plane_mask = planes[1];
	  gcv.foreground = g(colors[0].pixel);
	  g(refclear_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);
	}

      /* Set new background pixel value */
      xw->core.background_pixel = pixval;
      XSetWindowBackground(XtDisplay(w), XtWindow(w), pixval);
    }

  /* Use XOR on monochrome displays or when colormap is exhausted */
  else
    {
      gcv.background = xw->core.background_pixel;
      if (PlanesOfScreen(XtScreen(w)) > 1)
        gcv.foreground = g(drawColor);
      else
        gcv.foreground = xw->win3270.foreground;

      gcmask = GCFunction | GCForeground | GCBackground;
      gcv.function = GXcopy;
      g(draw_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);

      gcv.foreground = gcv.foreground ^ gcv.background;
      gcv.function = GXxor;
      g(ref_gc) = XCreateGC(XtDisplay(w), XtWindow(w), gcmask, &gcv);
    }
  g(oldgc) = 0;
  g(oldtype) = g(oldinten) = -1;
}


/*ARGSUSED*/ static void Redisplay(w, event, region)
     Widget w;
     XEvent *event;
     Region region;
{
  Ga3270Widget xw = (Ga3270Widget) w;

  /* Make sure XOR refresh drawing stays in sync no matter what */
  if (!g(colormode) && XtIsRealized(w))
     XClearArea(XtDisplay(w), XtWindow(w), 0, 0, 0, 0, False);

  XtCallCallbacks(w, XtNexposeProc, event);
}


/*ARGSUSED*/ static Boolean SetValues(current, request, new)
     Widget current, request, new;
{
  return False;
}



/*** Public routines ***/


/* Draw a line */
XtGa3270DrawLine(w, dt, ltype, inten, x1, y1, x2, y2)
     Widget w;
     enum draw_types dt;
     int ltype, inten, x1, y1, x2, y2;
{
  Ga3270Widget xw = (Ga3270Widget) w;
  GC gc;

  if (!XtIsRealized(w)) return 0;

  /* Select the proper graphics context based on drawing type */
  gc = g(draw_gc);
  switch (dt)
    {
    case dt_draw:
      gc = g(draw_gc);
      break;
    case dt_refresh:
      gc = g(ref_gc);
      break;
    case dt_refclear:
      if (g(colormode)) gc = g(refclear_gc);
      else gc = g(ref_gc);
      break;
    }

  /* If line type or intensity is different from last time, set new value */
  if (dt == dt_draw && g(lottaplanes) && ltype != g(oldtype))
    {
      XSetForeground(XtDisplay(w), gc, g(colors[ltype+1].pixel));
      g(oldtype) = ltype;
    }
  if (g(oldinten) != inten || gc != g(oldgc))
    {
      XSetLineAttributes(XtDisplay(w), gc, inten, LineSolid,
			 CapButt, JoinMiter);
      g(oldinten) = inten;
    }
  g(oldgc) = gc;

  /* Draw the line */
  XDrawLine(XtDisplay(w), XtWindow(w), gc, x1, y1, x2, y2);
  return 0;
}
