#ifdef SCCS
static char sccsid[]="@(#)ui_x.c	1.10 Oki Electric Industry Co., Ltd. 93/05/24";
#endif
/*
	This file is under sccs control at Stardent in:
	/nfs/sole/root/sccs1.p/X11R5/mit/demos/pexdraw/s.ui_x.c
*/
/*
 *			Copyright (c) 1992 by
 *			Oki Electric Industry Co., Ltd.
 *			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 Oki not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission. Oki
 * makes no representations about the suitability of this software for any
 * purpose.  It is provided "as is" without express or implied warranty.
 *
 * This supercedes the Stardent copyright granting the same rights that
 * appeared in the pdraw predecessor to pexdraw.
 *
 *************************************************************************
 *
 *                         P E X D R A W
 *
 *  A PEX drawing program based on PDRAW,
 *
 *   This is the NO_MOTIF version of the "user interface".
 *
 *  This implements the following routines: InitUserInterface(),
 *    MainLoop() and AddWorkProc();
 *
 *************************************************************************/

#include <stdio.h>

#include <math.h>

#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <X11/Xutil.h>
#include <X11/Xatom.h>

#include <X11/PEX5/PEXlib.h>
#include "pexdraw.h"


static int (*theWorker)();
static char *theInfo;

PEXVector  theVPN = { 0.0, 0.0, 1.0 };
PEXVector  theVUP = { 0.0, 1.0, 1.0 };
int theDBFlag = 1;

int activate(
#if NeedFunctionPrototypes
	     KeySym  /* k */
#endif
);

/*************************************************************************
 *
 */
void
InitUserInterface( argc, argv )
     int argc;
     char *argv[];
{
    XVisualInfo 	template;
    XVisualInfo 	*visinfo;
    Visual   		*visual; 
    int			nitems;
    XSizeHints		sizehints;
    int	i;

    char *displayString = (char *)0;
    int direct = 0;
    char *winstr;
    int vis = -1;
    int wind_x, wind_y, wind_w = 500, wind_h = 500;

    for ( i = 1; i<argc; i++ ) {
      if ((strncmp(argv[i],"-geometry",strlen(argv[i]))) == 0) {
	printf("found -geom\n");
      } else if ((strncmp(argv[i],"-display",strlen(argv[i]))) == 0) {
	if (++i > argc) { printf("not enough args"); exit(1); }
	displayString = argv[i];
      } else if ((strncmp(argv[i],"-pmdb",strlen(argv[i]))) == 0) {
	thePMDBFlag = 1; 
      } else if ((strncmp(argv[i],"-wks",strlen(argv[i]))) == 0) {
	theForceWKSFlag = 1; 
      } else if ((strncmp(argv[i],"-direct",strlen(argv[i]))) == 0) {
	vis = 1;
	direct = 1;
      } else if ((strncmp(argv[i],"-true",strlen(argv[i]))) == 0) {
	vis = 1;
	direct = 0;
      }
    }

  theDisplay = XOpenDisplay(displayString);
  if (!theDisplay) { printf(" cannot open display %s\n",displayString); exit(1);}

    wind_x = (1280-wind_w)/2;
    wind_y = (1024-wind_h)/2;

  if ( vis = -1 ) {
    theWindow = XCreateSimpleWindow( theDisplay, DefaultRootWindow(theDisplay), 
				 wind_x,wind_y,
				 wind_w,wind_h,
				 2,
				 BlackPixel(theDisplay,DefaultScreen(theDisplay)),
				 WhitePixel(theDisplay,DefaultScreen(theDisplay)));
/*    thePixelDepth = DefaultDepth(theDisplay, DefaultScreen(theDisplay)); */
  } else {

    /* Get the visual info for a visual of the type we want */
    if (direct) {
      template.class = DirectColor;
      winstr = "DirectColor";
    } else {
      template.class = TrueColor;
      winstr = "TrueColor";
    }
    visinfo = XGetVisualInfo(theDisplay, VisualClassMask, &template, &nitems);
    if (visinfo == NULL) 
    {   fprintf(stderr,"Can't create %s window",winstr);
	exit(-1);
    }
    /* This is the visual that we will use */
    visual = visinfo->visual;
    theWindow = XCreateWindow(theDisplay,
			   DefaultRootWindow(theDisplay),
			   wind_x,wind_y,
			   wind_w,wind_h,
			   2,
			   visinfo->depth,
			   InputOutput,	
			   visual,
			   0,0);
/*    thePixelDepth = visinfo->depth; */
  }
    sizehints.x = wind_x;
    sizehints.y = wind_y;
    sizehints.width = sizehints.max_width = wind_w;
    sizehints.height = sizehints.max_height = wind_h;
    sizehints.flags = USSize | USPosition;
    XSetNormalHints(theDisplay,theWindow,&sizehints);

    XMapWindow(theDisplay,theWindow);

    XSelectInput(theDisplay,theWindow,
		 ButtonMotionMask|ButtonPressMask|ButtonReleaseMask|
		 KeyPressMask|
		 ExposureMask|StructureNotifyMask);
    XFlush(theDisplay);

  /* iquire what the default too is and ... */
  set_tool_line();

  theDynGC = CreateDynGC();

  theWorker = 0;
}

void
MainLoop()
{
  XEvent event;
  int done = 0;
  int button, length;
  KeySym keysym;
  char buf[42]; /* why ask why? */
  XComposeStatus cs;
  XWindowAttributes winAttrs;

  while (!done) {
    if (!XPending(theDisplay)) {
      if (theWorker) if (theWorker(theInfo)) theWorker = 0;
    } else {
      XNextEvent(theDisplay,&event);
      switch (event.type) {
	
      case Expose:
	theRenderProcs.ReDraw();
	break;
	
      case ConfigureNotify:
	theWinHeight = event.xconfigure.height;
	ResizeWindow( theWindow, event.xconfigure.width, event.xconfigure.height );
	theRenderProcs.ReDraw();
	break;
	
      case ButtonPress:
	if (event.xbutton.button < 1 || event.xbutton.button > 3) break;
	thePressHandlerTable[event.xbutton.button-1](&event);
	break;
	
      case  ButtonRelease:
	if (event.xbutton.button < 1 || event.xbutton.button > 3) break;
	theReleaseHandlerTable[event.xbutton.button-1](&event);
	break;
	
      case MotionNotify:
	if ( event.xmotion.state == Button1MotionMask ) {
	  button = 0;
	} else if ( event.xmotion.state == Button2MotionMask ) {
	  button = 1;
	} else if ( event.xmotion.state == Button3MotionMask ) {
	  button = 2;
	} else {
	  return;
	}
	
	theMotionHandlerTable[button](&event);
	break;
	
      case KeyPress:
	length = XLookupString(&event.xkey, buf, 42, &keysym, &cs );
	done = activate(keysym);
	break;
	
      default:
	printf("got weird event!!! type = %x\n", event.type);
      }
    }
  }

}

int activate(k)
     KeySym k;
{
  switch (k) {

  case XK_question:
  case XK_h:
  case XK_H: /*  k_tool_pointer */
    printf("You are in NO_MOTIF mode!, h & ? get this message\n");
    printf(" tool selection l - line, p - pointer, t - triangle, v -view\n");
    printf(" d - dump strux, k - kill element, a - delete all \n");
    printf(" s - spin, i - interior style solid, r - refresh\n");
    break;

  case XK_p:
  case XK_P: /*  k_tool_pointer */
    set_tool_pointer();
    break;

  case XK_l:
  case XK_L: /*  k_tool_line */
    set_tool_line();
    break;

  case XK_v:
  case XK_V: /*  k_tool_view */
    set_tool_view();
    break;

  case XK_t:
  case XK_T: /*  k_tool_tristrip */
    set_tool_tristrip();
    break;

  case XK_d:
  case XK_D: /*  k_dump_strux */
    DumpStruxCmd(1);
    break;

  case XK_r:
  case XK_R: /*  k_refresh */
    theRenderProcs.ReDraw();
    break;

  case XK_k:
  case XK_K: /*  k_delete */
    DeleteSelected();
    break;

  case XK_i:
  case XK_I: /*  k_make_solid */
    InteriorStyleCmd(PEXInteriorStyleSolid);
    break;

  case XK_s:
  case XK_S: /*  k_spin_slowly */ {
    PEXStructure sid;
    
    if ( theSelectedElement != -1 ) {
      sid = theSelectedStrux;
    } else if (theNewStrux != 0) {
      sid = theNewStrux;
    } else break;

    if (!StartSpinning(sid)) { /* could not start, must be spinning */
      StopSpinning(sid);
    }}

  case XK_a:
  case XK_A: /*  k_delete_all */
    StopSpinning((PEXStructure)-1);
    PEXRotate(PEXXAxis, 0.0, theMCMatrix.matrix );
    theMCMatrix.seqNo = 0;
    theRenderProcs.DeleteAll();
    break;

  case XK_q:
  case XK_Q: /*  k_delete_all */
    return (1);
    break;

  default:
    break;
  }
  return (0);
}

void
AddWorkProc(worker,info)
     int (*worker)();
     char *info;
{
  theWorker = worker;
  theInfo = info;
}

int
applyViewSet( viewNumber)
     int viewNumber;
{
  PEXCoord  vrp;  /* view reference point */
  PEXVector  vpn;  /* view plane normal    */
  PEXVector  vup;  /* view up vector       */
  
  PEXViewRep vrep;                           /*  view structure */

  PEXCoord2D          frame[2];
  PEXNPCSubVolume     viewport;
  int                 perspective;
  PEXCoord            prp;
  float               view_plane, back_plane, front_plane;
 
  int err;

  int persp;


  persp = 0;

  vrp.x = 0;
  vrp.y = 0;
  vrp.z = 0;
  
  err = PEXViewOrientationMatrix( &vrp, &theVPN, &theVUP,
				 vrep.view.orientation);
  if (err != 0) {
    printf( "view orientation error %d\n",err); return (1);
  }


frame[0].x = -3;
frame[1].x = 3;
frame[0].y = -3;
frame[1].y = 3;
viewport.min.x = 0;
viewport.max.x = 1;
viewport.min.y = 0;
viewport.max.y = 1;
viewport.min.z = 0;
viewport.max.z = 1;
prp.x = 0;
prp.y = 0;
prp.z = 10;
view_plane = 0;
back_plane = -5;
front_plane = 5;

  err = PEXViewMappingMatrix( frame, &viewport, persp, &prp,
		       view_plane, back_plane, front_plane,
		       vrep.view.mapping);
  
  if (err != 0) { printf( "view mapping error %d\n",err); return (1); }
  
  vrep.view.clip_limits.min.x = viewport.min.x;
  vrep.view.clip_limits.min.y = viewport.min.y;
  vrep.view.clip_limits.min.z = viewport.min.z;
  vrep.view.clip_limits.max.x = viewport.max.x;
  vrep.view.clip_limits.max.y = viewport.max.y;
  vrep.view.clip_limits.max.z = viewport.max.z;
  vrep.view.clip_flags = PEXClipXY | PEXClipBack | PEXClipFront;
  vrep.index = viewNumber;

  theRenderProcs.SetView( 1, &vrep.view );

  bcopy((char *)&vrep.view.orientation, (char *)&theMatOri,sizeof(PEXMatrix));
  bcopy((char *)&vrep.view.mapping, (char *)&theMatMap, sizeof(PEXMatrix));

  theRenderProcs.ReDraw();

  return (0);
}

/*************************************************************************
 * CreateDynGC - create an X GC Resource for Dynamics.
 *
 * Got the rubberbanding methodology from contrib/clients/xfig/w_drawPrim.c
 * But just the idea, no code was copied, hence no copyright.
 *
 * The idea is to xor ( exclusive or ) the foreground and the background
 * together. When it is xor'd with the background it produces the foreground.
 */
GC CreateDynGC()
{
  XGCValues values;
  unsigned long fg, bg;
  GC tGC;

  if (theWimpyWindow) {
    values.foreground = -1;
    values.background = 0;
  } else {
  bg = BlackPixel(theDisplay,DefaultScreen(theDisplay));
  fg = WhitePixel(theDisplay,DefaultScreen(theDisplay));

  values.foreground = fg ^ bg;
  values.background = bg;
  }
  values.function = GXxor;
  tGC = XCreateGC(theDisplay, theWindow,
		  GCFunction | GCForeground | GCBackground, &values );
  return (tGC);
}

void GetVPN( viewNumber, vpn )
     int viewNumber;
     PEXVector  *vpn;
{
  *vpn = theVPN;
}

void SetVPN( viewNumber, vpn )
     int viewNumber;
     PEXVector  *vpn;
{
  theVPN = *vpn;
}


void GetVUP( viewNumber, vup )
     int viewNumber;
     PEXVector  *vup;
{
  *vup = theVUP;
}

void SetVUP( viewNumber, vup )
     int viewNumber;
     PEXVector  *vup;
{
  theVUP = *vup;
}

GetSomeTextFromUI( x, y, length, charStr, flags )
     int x;
     int y;
     int *length;
     char **charStr;
     int *flags;
{
  *length = strlen("hello world");
  *charStr = malloc(*length+1);
  strcpy(*charStr, "hello world");
  *flags = 0;
}

