 /*
  * Khoros: $Id: creatework.c,v 1.3 1991/12/18 09:00:55 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: creatework.c,v 1.3 1991/12/18 09:00:55 dkhoros Exp $";
#endif

 /*
  * $Log: creatework.c,v $
 * Revision 1.3  1991/12/18  09:00:55  dkhoros
 * HellPatch3
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER 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 PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "cantata.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>								<<<<
   >>>>	    file name:  creatework.c				<<<<
   >>>>								<<<<
   >>>>   description:						<<<<
   >>>>								<<<<
   >>>>      routines:  xvl_create_workspace()			<<<<
   >>>>                 xvl_create_menuform()			<<<<
   >>>>                 xvl_create_undo_workspace()		<<<<
   >>>>                 xvl_create_grid()			<<<<
   >>>>								<<<<
   >>>> modifications						<<<<
   >>>>								<<<<
   >>>>								<<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */



/**************************************************************
*
* Routine Name: xvl_create_workspace
*
*     Purpose:	Create the cantata workspace.  This is the area in
*		which the user will layout the glyphs to "program"
*		their visual language.  The workspace creates a
*		toplevel shell widget in which the workspace will
*		be incorporated into.  The workspace can be somewhat
*		configured by the user.  The user can specify whether
*		to have a viewport, how big the workspace is to be,
*		whether they want a grid, the grid size in which the glyphs
*		will be snapped to.
*
*		The workspace is used for the main programming window,
*		but is also the same for the macros.  The macro glyph when
*		un-glyphed will yield another workspace for that macro's
*		glyphs.
*
*       Input:  menu      - the menu structure to be used with the workspace
*		name	  - the name of the workspace
*		workspace - the empty workspace structure to be filled
*
*      Output:
*
* CALLED FROM: main
*
*  Written By: Mark Young
*
*
***************************************************************/


int xvl_create_workspace(menu, name, workspace)

Menu		*menu;
char		*name;
Workspace	*workspace;
{
	Position  x, y;
	int	  w, h;
	Arg	  arg[20];
	Dimension width, height;
	int	  i, flag, xpos, ypos;
	Workspace *attributes;


	/*
	 *  Load the workspace default workspace attributes.
	 */
	xvl_load_attributes(workspace);

	/*
	 *  width  = geometry of (workspace->geometry);
	 *  height = geometry of (workspace->geometry);
	 */
	flag = XGeometry(display, XDefaultScreen(display), workspace->geometry,
			  NULL, 0, 1, 1, 0, 0, &xpos, &ypos, &w, &h);

	if (!(flag & XValue) || !(flag & YValue) || !workspace->auto_placement)
	   xpos = ypos = -1;

	if (!(flag & WidthValue))
	   width = 0;
	else
	   width = w;

	if (!(flag & HeightValue))
	   height = 0;
	else
	   height = h;

	/*
	 *  Create the user interface menu (menuform).  Then see if that form
	 *  contained a specification for a workspace.  If not or the attached
	 *  canvas is set to false then we will create a toplevel widget of
	 *  our own.
	 */
	if (!xvl_create_menuform(menu, workspace, xpos, ypos))
	   return(False);

	workspace->toplevel = xvl_change_workspace(workspace->menuform, name,
			width, height);
	if (workspace->attach_canvas && workspace->toplevel)
	{
	   xvl_query_widget(workspace->toplevel, &x, &y, &width, &height);
	}
	else
	{
	   if (width  == 0) width = 500;
	   if (height == 0) height = 500;

	   i = 0;
	   XtSetArg(arg[i], XtNscreen, DefaultScreenOfDisplay(display)); i++;
	   XtSetArg(arg[i], XtNargc, ac); 				 i++;
	   XtSetArg(arg[i], XtNargv, av);				 i++;
	   XtSetArg(arg[i], XtNinput, True);				 i++;
	   XtSetArg(arg[i], XtNtitle, name);				 i++;
	   XtSetArg(arg[i], XtNx, (Position) xpos);			 i++;
	   XtSetArg(arg[i], XtNy, (Position) ypos);			 i++;
	   XtSetArg(arg[i], XtNheight, height);				 i++;
	   XtSetArg(arg[i], XtNmappedWhenManaged, False);		 i++;
	   if (workspace->auto_placement)
	   {
	      XtSetArg(arg[i], XtNgeometry, workspace->geometry);	 i++;
	   }
	   XtSetArg(arg[i], XtNwidth, width);				 i++;
	   workspace->toplevel = XtAppCreateShell(name, name,
			applicationShellWidgetClass, display, arg, i);
	   XtRealizeWidget(workspace->toplevel);
	   XtMapWidget(workspace->toplevel);
	}


	if (workspace->view_port)
	{

	   /* create viewport widget to manage the glyphs */
	   i = 0;
	   XtSetArg(arg[i], XtNwidth, width);			i++;
	   XtSetArg(arg[i], XtNheight, height);			i++;
	   XtSetArg(arg[i], XtNallowVert, True);		i++;
	   XtSetArg(arg[i], XtNallowHoriz, True);		i++;
	   XtSetArg(arg[i], XtNuseBottom, True);		i++;
	   XtSetArg(arg[i], XtNuseRight, True);			i++;
	   XtSetArg(arg[i], XtNforceBars, True);		i++;
	   workspace->viewport = XtCreateManagedWidget("viewport",
			viewportWidgetClass, workspace->toplevel, arg, i);

	   width  *= workspace->width_factor;
	   height *= workspace->height_factor;
	}
	else
	{
	   workspace->viewport = workspace->toplevel;
	}

	/* create form widget to manage the glyphs */
	i = 0;
	XtSetArg(arg[i], XtNwidth,  width);			i++;
	XtSetArg(arg[i], XtNheight, height);			i++;
	workspace->back = XtCreateManagedWidget("line_back", formWidgetClass,
			workspace->viewport, arg, i);

	if (wresource.fg == ~0L)
	   xvl_init_color(workspace->toplevel, NULL, &wresource.fg, NULL);
	if (wresource.bg == ~0L)
	   xvl_init_color(workspace->toplevel, &wresource.bg, NULL, NULL);
	if (wresource.grid_color == ~0L)
	   xvl_init_color(workspace->toplevel, NULL,NULL,&wresource.grid_color);

	i = 0;
	XtSetArg(arg[i], XtNwidth,  width);			i++;
	XtSetArg(arg[i], XtNheight, height);			i++;
	XtSetArg(arg[i], XtNborderWidth,   0);			i++;
	XtSetArg(arg[i], XtNhorizDistance, 0);			i++;
	XtSetArg(arg[i], XtNvertDistance,  0);			i++;
	XtSetArg(arg[i], XtNleft,   XtChainLeft);		i++;
	XtSetArg(arg[i], XtNright,  XtChainLeft);		i++;
	XtSetArg(arg[i], XtNtop,    XtChainTop);		i++;
	XtSetArg(arg[i], XtNbottom, XtChainTop);		i++;
	XtSetArg(arg[i], XtNforeground, wresource.fg);		i++;
	attributes = xvl_get_attributes(workspace);
	if (attributes->show_grid == False)
	{
	   XtSetArg(arg[i], XtNbackground, wresource.bg);	i++;
	}
	workspace->draw = XtCreateManagedWidget("draw_wid", simpleWidgetClass,
			workspace->back, arg, i);


	XtAddEventHandler(workspace->draw, ExposureMask, True, xvl_exposure_cb,
			 (caddr_t) workspace);
	XtAddEventHandler(workspace->draw, ButtonPressMask, False,
			  xvl_connection_cb, (caddr_t) workspace);
	XtAddEventHandler(workspace->draw, ButtonMotionMask | ButtonPressMask |
			  ButtonReleaseMask | PointerMotionHintMask, False,
			  xvl_select_cb, (caddr_t) workspace);

	xvl_create_clipboard(workspace);
	xvl_create_undo_workspace(workspace);
	xvl_init_environment(workspace, workspace->menuform, cantata);
	return(True);
}



/**************************************************************
*
*Routine Name: xvl_create_menuform
*
*     Purpose: Create the toplevel menu form in which the user
*	       will be able to create glyphs and program from.
*
*       Input:  menu             - the menu structure to be used
*		workspace        - the workspace for which we will be creating
*			           menu form.
*		x & y	         - the initial x & y position
*
*      Output:  loads the "workspace" attributes part of the structure.
*
* CALLED FROM: main
*
*  Written By: Mark Young
*
*
***************************************************************/

int xvl_create_menuform(menu, workspace, x, y)

Menu		*menu;
Workspace	*workspace;
int		x, y;
{
	char	**database;

        /*
	 *  go throughout database to create an array needed for naming
         *  each widget independently
	 */
	/* create cantata menu form */
	database = xvf_copy_database(menu->db);
	workspace->menuform = xvf_build_form(database, menu->num, menu->size,
			av, ac, SIMPLE, NULL, x, y);
	if (workspace->menuform == NULL)
	{
	   fprintf(stderr, "\nxvl_create_menuform:\n");
	   fprintf(stderr, "unable to create menu for workspace\n");
	   return(False);
	}
	workspace->glyphform = xvf_begin_form();
	workspace->glyphs    =
	workspace->frontlist = NULL;
	workspace->autorun   = False;
	workspace->var_name  = NULL;

	xvf_change_routine(workspace->menuform, menu->routine,
			(caddr_t) workspace);
	xvf_change_routine(workspace->glyphform, xvl_glyph_menu_cb,
			(caddr_t) workspace);
	return(True);
}



xvl_create_undo_workspace(workspace)

Workspace *workspace;
{
	Workspace *undo_workspace;


	workspace->undo =  xvl_find_undo_button(workspace->menuform);
	undo_workspace = (Workspace *) XtCalloc(1, sizeof(Workspace));
	workspace->undo_workspace = undo_workspace;
	undo_workspace->glyphform = xvf_begin_form();

	xvl_update_undo(workspace);
}

/**************************************************************
*
* Routine Name: xvl_create_grid
*
*     Purpose:  This routine is used to create an arbitary sized 
*		grid.  The grid is a pixmap of sizexsize.  A dashed
*		line is drawn from (0,0) to (size,0) and from (0,0)
*		to (0,size).
*
*		This pattern will be set to the window's background.
*		Thus, the background will be tiled with the pixmap
*		giving us the effect of a grid.  The real advantage
*		is that having a tiled background means the server 
*		will take care of maintaining it.
*
*       Input:  widget -  widget in which the pixmap will be used.
*
*      Output:  
*
* CALLED FROM: main
*
*  Written By: Mark Young
*
*
***************************************************************/


xvl_create_grid(workspace)

Workspace	*workspace;
{
	GC	      gc;
	XGCValues     xgcv;
	Window	      root;
	unsigned long mask;
	Pixmap	      grid;
	int	      x, y, size;
	unsigned int  width, height, depth, border_width;
	Workspace     *attributes;

	static char dotted[] = { 1, 1 };
	static int  length   = 2;




	if (XtWindow(workspace->draw) == NULL)
	{
	   fprintf(stderr,"Couldn't creaate large window to draw glyph");
	   fprintf(stderr," connections on\n");
	   exit(1);
	}
	else if (!XGetGeometry(display, XtWindow(workspace->draw), &root, &x,
			  &y, &width, &height, &border_width, &depth))
	{
	   fprintf(stderr,"xvl_create_grid:  Cannot stat widget in which to \
place the grid.\nNo grid will be created!\n");
	   return;
	}

	attributes = xvl_get_attributes(workspace);

	if (attributes->show_grid)
	{
	   size = attributes->grid_size;
	   grid = XCreatePixmap(display, XtWindow(workspace->draw), size, size,
			       depth);
	   if (!XGetGeometry(display, grid, &root, &x, &y, &width,
			   &height, &border_width, &depth))
	   {
	      fprintf(stderr,"xvl_create_grid:  Cannot create grid. No grid \
will be used!\n");
	      return;
	   }

	   /*
	    *  Set the GC to use LineDoubleDash.
	    */
	   xgcv.line_width	    = 1;
	   xgcv.join_style	    = JoinRound;
	   xgcv.cap_style           = CapNotLast;
	   xgcv.line_style	    = LineDoubleDash;
	   xgcv.foreground	    = wresource.bg;
	   xgcv.background	    = wresource.grid_color;

	   mask = GCLineWidth | GCCapStyle | GCLineStyle | GCJoinStyle |
	          GCForeground | GCBackground;
	   gc = XCreateGC(display, XtWindow(workspace->draw), mask, &xgcv);
	   XSetDashes(display, gc, 0, dotted, length);

	   /*
	    *  The grid will be accomplished by drawing a line from (0,0) to
	    *  (size,0)  and (0,0) to (0,size).  This pattern will be set to
	    *  the window's background.  Thus, the background will be tiled
	    *  with the pixmap giving us the effect of a grid.  The real
	    *  advantage is that having a tiled background means the server
	    *  will take care of maintaining it.
	    */
	   XFillRectangle(display, grid, gc, 0, 0, size, size);
	   XDrawLine(display, grid, gc, 0, 0, size, 0);
	   XDrawLine(display, grid, gc, 0, 0, 0, size);

	   XFreeGC(display, gc);
	   XSetWindowBackgroundPixmap(display, XtWindow(workspace->draw), grid);
	   XClearWindow(display, XtWindow(workspace->draw));
	   XFreePixmap(display, grid);
	}
	else
	{
	   XSetWindowBackgroundPixmap(display, XtWindow(workspace->draw), None);
	   XSetWindowBackground(display, XtWindow(workspace->draw),
				wresource.bg);
	   XClearWindow(display, XtWindow(workspace->draw));
	}
}
