/* SPIM S20 MIPS simulator.
   X interface to SPIM
   Copyright (C) 1990 by James Larus (larus@cs.wisc.edu), James R. Goodman,
   and Alan Yuen-wui Siow.

   SPIM is free software; you can redistribute it and/or modify it
   under the terms of the GNU General Public License as published by the
   Free Software Foundation; either version 1, or (at your option) any
   later version.

   SPIM is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   for more details.

   You should have received a copy of the GNU General Public License
   along with GNU CC; see the file COPYING.  If not, write to James R.
   Larus, Computer Sciences Department, University of Wisconsin--Madison,
   1210 West Dayton Street, Madison, WI 53706, USA or to the Free
   Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */


/* $Header: /u/l/a/larus/Software/SPIM/src/RCS/textact.c,v 3.1 1990/10/02 15:03:19 larus Exp $
 */


#include <stdio.h>
#include <ctype.h>

#include <X11/Xatom.h>
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <X11/Xmu/Atoms.h>
#include <X11/Xmu/Misc.h>
#include <X11/Xaw/TextP.h>

#define SrcScan                XawTextSourceScan
#define FindDist               XawTextSinkFindDistance
#define FindPos                XawTextSinkFindPosition


/* Exported functions: */

void InsertChar ();
void InsertNewLine ();


/* Local functions: */

static void AutoFill ();
static void EndAction ();
static int InsertNewLineAndBackupInternal ();
static int LocalInsertNewLine ();
static void StartAction ();


/* Imported functions: */

/*
 * These are defined in TextPop.c
 */
void _XawTextInsertFileAction(), _XawTextInsertFile(), _XawTextSearch();
void _XawTextSearch(), _XawTextDoSearchAction(), _XawTextDoReplaceAction();
void _XawTextSetField(), _XawTextPopdownSearchAction();

/*
 * These are defined in Text.c
 */
char * _XawTextGetText();
void _XawTextBuildLineTable(), _XawTextAlterSelection(), _XawTextVScroll();
void _XawTextSetSelection(), _XawTextCheckResize(), _XawTextExecuteUpdate();
void _XawTextSetScrollBars(), _XawTextClearAndCenterDisplay();
Atom * _XawTextSelectionList();



static void
StartAction (ctx, event)
     TextWidget ctx;
     XEvent *event;
{
  _XawTextPrepareToUpdate (ctx);
  if (event != NULL)
    {
      switch (event->type)
	{
	case ButtonPress:
	case ButtonRelease:
	  ctx->text.time = event->xbutton.time;
	  ctx->text.ev_x = event->xbutton.x;
	  ctx->text.ev_y = event->xbutton.y;
	  break;
	case KeyPress:
	case KeyRelease:
	  ctx->text.time = event->xkey.time;
	  ctx->text.ev_x = event->xkey.x;
	  ctx->text.ev_y = event->xkey.y;
	  break;
	case MotionNotify:
	  ctx->text.time = event->xmotion.time;
	  ctx->text.ev_x = event->xmotion.x;
	  ctx->text.ev_y = event->xmotion.y;
	  break;
	case EnterNotify:
	case LeaveNotify:
	  ctx->text.time = event->xcrossing.time;
	  ctx->text.ev_x = event->xcrossing.x;
	  ctx->text.ev_y = event->xcrossing.y;
	}
    }
}


static void
EndAction (ctx)
     TextWidget ctx;
{
  _XawTextCheckResize (ctx);
  _XawTextExecuteUpdate (ctx);
  ctx->text.mult = 1;
}


struct _SelectionList
{
  String *params;
  Cardinal count;
  Time time;
};


static XComposeStatus compose_status = {NULL, 0};


/*	Function Name: AutoFill
 *	Description: Breaks the line at the previous word boundry when
 *                   called inside InsertChar.
 *	Arguments: ctx - The text widget.
 *	Returns: none
 */


/************************************************************
 *
 * Insertion Routines.
 *
 ************************************************************/

static int
InsertNewLineAndBackupInternal (ctx)
     TextWidget ctx;
{
  int count, error = XawEditDone;
  XawTextBlock text;
  char *buf, *ptr;

  ptr = buf = XtMalloc (sizeof (char) * ctx->text.mult);
  for (count = 0; count < ctx->text.mult; count++, ptr++)
    ptr[0] = '\n';

  text.length = ctx->text.mult;
  text.ptr = buf;
  text.firstPos = 0;
  text.format = FMT8BIT;

  if (_XawTextReplace (ctx, ctx->text.insertPos, ctx->text.insertPos, &text))
    {
      XBell (XtDisplay (ctx), 50);
      error = XawEditError;
    }
  else
    ctx->text.showposition = TRUE;

  XtFree (buf);
  return (error);
}

static int
LocalInsertNewLine (ctx, event)
TextWidget ctx;
XEvent *event;
{
  StartAction (ctx, event);
  if (InsertNewLineAndBackupInternal (ctx) == XawEditError)
    return (XawEditError);
  ctx->text.insertPos = SrcScan (ctx->text.source, ctx->text.insertPos,
				 XawstPositions, XawsdRight, ctx->text.mult,
				 TRUE);
  EndAction (ctx);
  _XawTextSetScrollBars (ctx);
  return (XawEditDone);
}


void
InsertNewLine (w, event)
     Widget w;
     XEvent *event;
{
  (void) LocalInsertNewLine ((TextWidget) w, event);
}


static void
AutoFill (ctx)
     TextWidget ctx;
{
  int width, height, x, line_num, max_width;
  XawTextPosition ret_pos;
  XawTextBlock text;

  if (!((ctx->text.auto_fill) && (ctx->text.mult == 1)))
    return;

  for (line_num = 0; line_num < ctx->text.lt.lines ; line_num++)
    if (ctx->text.lt.info[line_num].position >= ctx->text.insertPos)
      break;
  line_num--;			/* backup a line. */

  max_width = Max (0, ctx->core.width - HMargins (ctx));

  x = ctx->text.margin.left;
  XawTextSinkFindPosition (ctx->text.sink,
			   ctx->text.lt.info[line_num].position,
			   x, max_width, TRUE, &ret_pos, &width, &height);

  if (ret_pos >= ctx->text.insertPos)
    return;

  text.ptr = "\n";
  text.length = 1;
  text.firstPos = 0;
  text.format = FMT8BIT;

  _XawTextReplace (ctx, ret_pos - 1, ret_pos, &text);
}


void
InsertChar (w, event)
Widget w;
XEvent *event;
{
  TextWidget ctx = (TextWidget) w;
  char *ptr, strbuf[BUFSIZ];
  int count, error;
  KeySym keysym;
  XawTextBlock text;

  if ((text.length = XLookupString (&event->xkey, strbuf, BUFSIZ,
				     &keysym, &compose_status)) == 0)
    return;

  text.ptr = ptr = XtMalloc (sizeof (char) * text.length * ctx->text.mult);
  for (count = 0 ; count < ctx->text.mult ; count++)
    {
      strncpy (ptr, strbuf, text.length);
      ptr += text.length;
    }

  text.length = text.length * ctx->text.mult;
  text.firstPos = 0;
  text.format = FMT8BIT;

  StartAction (ctx, event);

  error = _XawTextReplace (ctx, ctx->text.insertPos, ctx->text.insertPos,
			   &text);

  if (error == XawEditDone)
    {
      ctx->text.insertPos =
	SrcScan (ctx->text.source, ctx->text.insertPos,
		 XawstPositions, XawsdRight, text.length, TRUE);
      AutoFill (ctx);
    }
  else
    XBell (XtDisplay (ctx), 50);

  XtFree (text.ptr);
  EndAction (ctx);
  _XawTextSetScrollBars (ctx);
}
