#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	CrsrText.c (CursorText)
 * Purpose:	Initialize and change states of the software cursor
 * Subroutine:	init_textcursor()		returns: void
 * Subroutine:	new_textcursor()		returns: void
 * Subroutine:	draw_textcursor()		returns: void
 * Subroutine:	reset_textcursor_coords()	returns: void
 * Subroutine:	move_textcursor()		returns: void
 * Subroutine:	textcursor_keyentry()		returns: void
 * Subroutine:	reload_textcursor()		returns: void
 * Subroutine:	save_textcursor()		returns: void
 * Copyright:	1990 Michael VanHilst
 *		You may do anything you like with this file except remove
 *		this copyright.  Michael VanHilst makes no representations
 *		about the suitability of this software for any purpose.
 *		It is provided "as is" without express or implied warranty.
 * Modified:	{0} Michael VanHilst	initial version	           1 Jan 1991
 *              {1} Paul Sydney fixed foreground assignment in 321 9 Jul 1998
 *		{n} <who> -- <does what> -- <when>
 */

#ifndef VMS
#ifdef SYSV
#include <string.h>		/*  strlen, strcat, strcpy, strrchr  */
#else
#include <strings.h>		/*  strlen, strcat, strcpy, rindex  */
#endif
#else
#include <string.h>		/*  strlen, strcat, strcpy, strrchr  */
#endif

#include <stdio.h>		/*  stderr, NULL, etc.  */
#include <X11/Xlib.h>		/*  X window stuff  */
#include <X11/Xutil.h>		/*  X window manager stuff  */
#include <X11/keysym.h>
#include <X11/keysymdef.h>
#include "hfiles/constant.h"	/*  Define codes  */
#include "hfiles/struct.h"	/*  Declare structure types  */
#include "hfiles/extern.h"	/*  Extern main parameter structures  */
#include "hfiles/define.h"	/*  Define DONT_CARE, U_DONT_CARE  */
#include "hfiles/edit.h"
#include "hfiles/region.h"	/*  regdrawRec region drawing parameters  */

struct regdrawRec rgdraw;

/*  Ammount of space for string is actually (CURSOR_MAX - 1)*sizeof(XPoint)  */
struct curText {
  int char_cnt;
  char string[CURSOR_MAX*2];
};

static EditStruct *cursor_edit;
static XFontStruct *fontstruct;
static int init = 1;


#ifdef ANSIC
/*  Exported declarations must be centralized before ANSI C can be used  */

void	    new_textcursor();
void	    clear_textcursor();
void	    save_textcursor(		XButtonEvent *xbutton);
void	    reload_textcursor();
void	    textcursor_keyentry(	XKeyEvent *xkey, KeySym keysym);
void	    draw_textcursor(		struct cursorRec *crsr, GCspec *draw);
void	    reset_textcursor_coords(	struct cursorRec *crsr);
void	    move_textcursor(		int xinc, int yinc);
static void init_textcursor();
static void draw_text_cursor_cursor(	EditStruct *edit, GC gc);
static void clear_text_area(		EditStruct *edit,
					int x, int y, int width, int height);
static void blacken_textcursor_cursor(	EditStruct *edit, int cur_x);
void	    write_text_region(		struct cursorRec *region, char* line);

#else

  XFontStruct *get_fontstruct();
  EditStruct *get_edit_struct();
  void init_edit_struct(), grab_keys_for_textcursor();
  void grab_keys_for_textcursor(), clear_edit_buf();
  void set_cursor_file_coords(), save_cursor_as_region(), disp_region();
  void store_edit_struct();
  void load_edit_string(), reset_textcursor_coords();
  void set_edit_draw_func(), unset_edit_draw_func();
  int emacs_response();
  GC set_text_gc();
  void draw_textcursor();
  static void init_textcursor(), draw_textcursor_cursor();
  static void clear_text_area(), blacken_textcursor_cursor();

#endif


/*  Subroutine:	init_textcursor
 *  Purpose:	initialize editor parameters for text cursor editing
 */
static void init_textcursor()
{
  /*  Get same font used for region labels  */
  fontstruct = get_fontstruct(1);
  /*  Allocate text editor struct space  */
  cursor_edit = get_edit_struct((CURSOR_MAX-1)*4);
  /*  Initialize text editor parameters  */
  init_edit_struct(dispbox.display, dispbox.ID, cursor_edit, fontstruct,
		   cursor.draw->foreground, cursor.draw->background);
  cursor_edit->y = cursor.win.y;
  cursor_edit->x = cursor.win.x;
  cursor_edit->max_pixlen = 512;
  cursor_edit->area_y =
    cursor_edit->y - cursor_edit->fontstruct->max_bounds.ascent;
  /*  Set this value initially so position cursor will appear  */
  cursor_edit->pixlen[1] = XTextWidth(cursor_edit->fontstruct, "e", 1);
}


/*  Subroutine:	new_textcursor()
 *  Purpose:	set up cursor struct for text cursor interactions
 */
void new_textcursor()
{
  struct curText *curtext;

  if( init ) {
    init_textcursor();
    init = 0;
  }
  curtext = (struct curText *)cursor.points;
  curtext->char_cnt = 0;
  curtext->string[0] = '\0';
  cursor.point_cnt = 2;
  grab_keys_for_textcursor(1);
}


/*  Subroutine:	clear_textcursor
 *  Purpose:	empty text cursor buffer and ungrab keyboard input
 */
void clear_textcursor()
{
  grab_keys_for_textcursor(0);
  clear_edit_buf(cursor_edit);
}


/*  Subroutine:	save_textcursor
 *  Purpose:	save string in editor on region save event
 */
#ifdef ANSIC
void save_textcursor ( XButtonEvent *xbutton )
#else
void save_textcursor ( xbutton )
     XButtonEvent *xbutton;
#endif
{
  struct curText *curtext;

  /*  Force file coordinates into agreement with window coordinates  */
  set_cursor_file_coords(&cursor, &coord.disptofile, 1);
  /*  Save cursor as a region  */
  if( xbutton->button == Button2 )
    save_cursor_as_region(&cursor, 1);
  else
    save_cursor_as_region(&cursor, 0);
  cursor.index = cursor.next_region->index;
  disp_region(cursor.next_region);
  store_edit_struct(cursor_edit);
  curtext = (struct curText *)cursor.next_region->points;
  --(curtext->char_cnt);
  curtext->string[curtext->char_cnt] = '\0';
}


/*  Subroutine:	reload_textcursor
 *  Purpose:	Put cursor string into editor buffer
 */
void reload_textcursor()
{
  struct curText *curtext;

  curtext = (struct curText *)cursor.points;
  load_edit_string(cursor_edit, curtext->string, curtext->char_cnt);
  reset_textcursor_coords(&cursor);
}


/*  Subroutine:	textcursor_keyentry
 *  Purpose:	Respond to key entry while in textcursor mode
 */
#ifdef ANSIC
void textcursor_keyentry ( XKeyEvent *xkey, KeySym keysym )
#else
void textcursor_keyentry ( xkey, keysym )
     XKeyEvent *xkey;
     KeySym keysym;
#endif
{
  struct curText *curtext;
  int old_end_x, old_cur_x;

  /*  Always use latest func, mask, and background  */
  if( cursor.draw->mask != AllPlanes ) {
    old_end_x = 0;
    old_cur_x = -1;
    draw_textcursor(&cursor, &color.gcset.undraw);
  } else {
    old_end_x = cursor_edit->pixlen[cursor_edit->char_cnt];
    old_cur_x = cursor_edit->pixlen[cursor_edit->active_position];
  }
  /*  Intercept Linefeed so editor won't act on it  */
  if( (keysym == XK_Linefeed) || (keysym == XK_Return) ) {
    /*  Do a save and move cursor for next line on a carriage return  */
    if( keysym == XK_Return )
      ascii_region(&control.event.xkey, XK_s);
    else
      ascii_region(&control.event.xkey, XK_e);
    /*  Move line done hight of text and set float coordinate as well  */
    if( (cursor.win.y += cursor_edit->area_height) < 0 )
      cursor.win.Y = (double)cursor.win.y - 0.5;
    else
      cursor.win.Y = (double)cursor.win.y + 0.5;
    curtext = (struct curText *)cursor.points;
    curtext->string[0] = '\0';
    curtext->string[1] = '\0';
    curtext->char_cnt = 0;
    cursor.point_cnt = 2;
    load_edit_string(cursor_edit, curtext->string, 0);
    cursor_edit->active_position = 0;
    reset_textcursor_coords(&cursor);
    /*  Redraw the display window to clean things up and show new positions  */
    disp_dispbox();
    return;
  } else {
    /*  Suppress drawing by the editor (we do it here)  */
    set_edit_draw_func(cursor.draw->func, 0);
    (void)emacs_response(xkey, cursor_edit);
    /*  Update cursor string to account for changes (incl. space on end)  */
    curtext = (struct curText *)cursor.points;
#ifdef ANSIC
    (void)strncpy(curtext->string, cursor_edit->string,
		  (size_t)(cursor_edit->char_cnt + 1));
#else
    strncpy(curtext->string, cursor_edit->string, cursor_edit->char_cnt + 1);
#endif
    curtext->string[cursor_edit->char_cnt + 1] = '\0';
    curtext->char_cnt = cursor_edit->char_cnt;
    /*  Restore the default editor string drawing functions  */
    unset_edit_draw_func();
  }
  /*  Use point count to reserve space for one byte more than string  */
  /*  Point count is used by save cursor to copy bytes to region record  */
  cursor.point_cnt = ((curtext->char_cnt + 1) / sizeof(XPoint)) + 2;
  /*  If string got shorter and not erasing, blank stuff no longer covered  */
  if( old_end_x > cursor_edit->pixlen[cursor_edit->char_cnt] ) {
    int new_end_x;
    GC gc;

    new_end_x = cursor_edit->pixlen[cursor_edit->char_cnt];
    clear_text_area(cursor_edit, cursor_edit->x + new_end_x,
		    cursor_edit->y
		     - cursor_edit->fontstruct->max_bounds.ascent,
		    old_end_x - new_end_x,
		    cursor_edit->area_height);
  }
  /*  If cursor was or will not be erased, set it to background color  */
  if( old_cur_x >= old_end_x )
    blacken_textcursor_cursor(cursor_edit, old_cur_x);
  /*  Draw new string  */
  draw_textcursor(&cursor, cursor.draw);
}


/*  Subroutine:	draw_textcursor
 *  Purpose:	draw a cursor, using only cursorRec info
 */
#ifdef ANSIC
void draw_textcursor ( struct cursorRec *crsr, GCspec *draw )
#else
void draw_textcursor ( crsr, draw )
     struct cursorRec *crsr;
     GCspec *draw;
#endif
{
  struct curText *curtext;
  GC gc;


  curtext = (struct curText *)crsr->points;
  if( draw == NULL )
    draw = crsr->draw;
  /*  Make sure info is available  */
  if( init ) {
    init_textcursor();
    init = 0;
  }
  /*  Stencil chars if tracking the string or not having a background  */
  if( (draw->func == GXxor) ||
      (draw->mask != AllPlanes) ) {
    gc = set_text_gc(cursor_edit->font, draw->foreground, U_DONT_CARE,
		     draw->func, draw->mask);
    XDrawString(crsr->win.display, crsr->win.ID, gc, crsr->win.x,
		crsr->win.y, curtext->string, curtext->char_cnt);
    if( crsr == &cursor ) {
      /*  Update coords (cursor may have been moved in non-text mode)  */
      cursor_edit->x = cursor.win.x;
      cursor_edit->y = cursor.win.y;
      draw_textcursor_cursor(cursor_edit, gc);
    }
  } else {
    unsigned long foreground, background; /*  Text and background colors */

    /*  These backgrounds don't work with overlays, should use image dark  */
    foreground = draw->foreground;
    if( draw == &color.gcset.incl ) {
      /*  Include is ALWAYS yellow or white on black  */
      background = color.hard.true_black;
      /*  This must be keyed to what disppsct.c does for hardcopy  */
      if( foreground == color.hard.std_black )
	foreground = color.hard.true_white;
    } else if( draw == &color.gcset.excl ) {
      /*  Exclude is ALWAYS red or black on white  */
      background = color.hard.true_white;
      /*  This must be keyed to what disppsct.c does for hardcopy  */
      if( foreground == color.hard.std_white )
	foreground = color.hard.true_black;
    } else if( draw->foreground == color.hard.true_black )
      background = color.hard.true_white;
    else
      background = color.hard.true_black;
    gc = set_text_gc(cursor_edit->font, foreground, background,
		     draw->func, draw->mask);
    XDrawImageString(cursor_edit->display, cursor_edit->ID, gc, crsr->win.x,
		     crsr->win.y, curtext->string, curtext->char_cnt);
    if( crsr == &cursor ) {
      cursor_edit->background = background;
      /*  Update coords (cursor may have been moved in non-text mode)  */
      cursor_edit->x = cursor.win.x;
      cursor_edit->y = cursor.win.y;
      draw_textcursor_cursor(cursor_edit, gc);
    }
  }
}


/*  Subroutine:	draw_textcursor_cursor
 *  Xlib calls:	XDrawImageString()
 */
#ifdef ANSIC
static void draw_textcursor_cursor ( EditStruct *edit, GC gc )
#else
static void draw_textcursor_cursor ( edit, gc )
     EditStruct *edit;
     GC gc;
#endif
{
  int x;

  x = edit->x + edit->pixlen[edit->active_position] -
    edit->pixlen[edit->first_char_shown];
  XDrawLine(edit->display, edit->ID, gc, x, edit->y + 1,
	    x + edit->pixlen[1] - 1, edit->y + 1);
}


/*  Subroutine:	reset_textcursor_coords
 */
#ifdef ANSIC
void reset_textcursor_coords( struct cursorRec *crsr )
#else
void reset_textcursor_coords( crsr )
     struct cursorRec *crsr;
#endif
{
  if( crsr == &cursor ) {
    cursor_edit->x = cursor.win.x;
    cursor_edit->y = cursor.win.y;
    cursor_edit->area_y =
      cursor_edit->y - cursor_edit->fontstruct->max_bounds.ascent;
    cursor_edit->active_position = cursor_edit->char_cnt;
  }
}


/*  Subroutine:	move_textcursor
 *  Purpose:	Move the text drawing coords when text cursor is moved
 */
#ifdef ANSIC
void move_textcursor ( int xinc, int yinc )
#else
void move_textcursor ( xinc, yinc )
     int xinc, yinc;
#endif
{
  cursor_edit->x += xinc;
  cursor_edit->y += yinc;
  cursor_edit->area_y += yinc;
}


/*  Subroutine:	clear_text_area
 *  Purpose:	Clear area around edit string, mindful of mask in use
 *  Note:	Assumes only called with GXcopy, AllPlanes, ImageString cursor
 */
#ifdef ANSIC
static void clear_text_area ( EditStruct *edit,
			      int x, int y, int width, int height )
#else
static void clear_text_area ( edit, x, y, width, height )
     EditStruct *edit;
     int x, y, width, height;
#endif
{
  GC gc;

  gc = set_text_gc(edit->font, edit->background, U_DONT_CARE,
		   GXcopy, AllPlanes);
  XFillRectangle(edit->display, edit->ID, gc, x, y,
		 (unsigned int)width, (unsigned int)height);
}


/*  Subroutine:	blacken_textcursor_cursor
 *  Xlib calls:	XDrawImageString()
 */
#ifdef ANSIC
static void blacken_textcursor_cursor ( EditStruct *edit, int cur_x )
#else
static void blacken_textcursor_cursor ( edit, cur_x )
     EditStruct *edit;
     int cur_x;
#endif
{
  int x;
  GC gc;

  gc = set_text_gc(edit->font, edit->background, U_DONT_CARE,
		   GXcopy, AllPlanes);
  x = edit->x + cur_x - edit->pixlen[edit->first_char_shown];
  XDrawLine(edit->display, edit->ID, gc, x, edit->y + 1,
	    x + edit->pixlen[1] - 1, edit->y + 1);
}


/*  Subroutine:	write_text_region
 *  Purpose:	Write detail part of region file line for a text cursor
 */
#ifdef ANSIC
void write_text_region ( struct cursorRec *region, char* line )
#else
void write_text_region ( region, line )
     struct cursorRec *region;
     char* line;
#endif
{
  struct curText *curtext;
  int len;

  curtext = (struct curText *)region->points;
  curtext->string[curtext->char_cnt] = '\0';
  len = strlen(line);
  (void)sprintf(&line[len], ",%1d,\"%s\")",
		curtext->char_cnt, curtext->string);
}


syntax highlighted by Code2HTML, v. 0.9.1