/* This file is part of
 * ======================================================
 * 
 *           LyX, the High Level Word Processor
 * 	 
 *	    Copyright (C) 1995 Matthias Ettrich
 *
 *======================================================*/

#include "config.h"

#include <ctype.h>

#include "inset.h"
#include "lyxparagraph.h"

extern Widget toplevel;
extern char* date();


static
char* InsetNextToken(FILE* myfile, char &token_end_character)
{
   char* token = NULL;
   char c = 0;
   int i = 0;
   
   if (!feof(myfile)) {
      token = new char[100];
      do {
	 c = fgetc(myfile);
	 token[i]=c;
	 i++;
      } while (!feof(myfile) && !isspace(c));
      
      token[i-1]='\0';	       /* just the end of a command  */
   }
   token_end_character = c;
   return token;
}


/* Insets default methods */

char Inset::Deletable()
{
  return 1;
}


char Inset::DirectWrite()
{
  return 0;
}


char Inset::Editable()
{
  return 0;
}


char Inset::AutoDelete()
{
  return 0;
}


void Inset::Edit(int, int)
{
}


LyXFont Inset::ConvertFont(LyXFont font)
{
  return font;
}


char Inset::LyxCode()
{
  return LYX_NO_CODE;
}

 /* some stuff for inset locking */


void UpdatableInset::InsetButtonPress(int x, int y, int button)
{
	if (lyx_debug_level)
		fprintf(stderr,
			"Inset Button Press x=%d, y=%d, button=%d\n",
			x, y, button);
}


void UpdatableInset::InsetButtonRelease(int x, int y, int button)
{
	if (lyx_debug_level)
		fprintf(stderr,
			"Inset Button Release x=%d, y=%d, button=%d\n",
			x, y, button);
}


void UpdatableInset::InsetKeyPress(XKeyEvent *)
{
#ifdef DEBUG
  fprintf(stderr, "Inset Keypress\n");
#endif
}


void UpdatableInset::InsetMotionNotify(int x, int y, int state)
{
	if (lyx_debug_level)
		fprintf(stderr,
			"Inset Motion Notify x=%d, y=%d, state=%d\n",
			x, y, state);
}


void UpdatableInset::InsetUnlock()
{
#ifdef DEBUG
  fprintf(stderr, "Inset Unlock \n");
#endif
}


// An updatable inset is highly editable by definition
char UpdatableInset::Editable()
{
  return 2;
}


void UpdatableInset::ToggleInsetCursor()
{
  // nothing
}


/* Quotes. Used for the various quotes. German, English, French, all either
 * double or single */ 
   
InsetQuotes::InsetQuotes(char* string)
{
  kind = new char[4];
  contents = new char[2];
  ParseString(string);
}


InsetQuotes::~InsetQuotes()
{
  delete kind;
  delete contents;
}


void InsetQuotes::ParseString(char* string)
{
  if (string[0])
    kind[0]=string[0];
  else
    kind[0]=' ';
  if (string[1])
    kind[1]=string[1];
  else
    kind[1]=' ';
  if (string[2])
    kind[2]=string[2];
  else
    kind[2]=' ';
  kind[3] = '\0';
   
  switch (kind[0]) {
  case 'g':			       /* german quotes  */
    if (kind[1]=='l')
      contents[0]=',';
    else
      contents[0]='`';
    break;
  case 'f':			       /* french quotes  */
    if (kind[1]=='l')
      contents[0]='<';
    else
      contents[0]='>';
    break;
  default:			       /* english quotes  */
    if (kind[1]=='l')
      contents[0]='`';
    else
      contents[0]='\'';
    break;
  }
   
  /* single or double quotes */ 
  if (kind[2]=='s')
    contents[1]='\0';
  else
    contents[1]=contents[0];
}


int InsetQuotes::Ascent(LyXFont font)
{
  if (contents[1])
    return Maximum(LyXAscent(font, contents[0]),
		   LyXAscent(font, contents[1]));
  else
    return LyXAscent(font, contents[0]);
}


int InsetQuotes::Descent(LyXFont font)
{
  if (contents[1])
    return Maximum(LyXDescent(font, contents[0]),
		   LyXDescent(font, contents[1]));
  else
    return LyXDescent(font, contents[0]);
}


int InsetQuotes::Width(LyXFont font)
{
  int w = LyXWidth(font, contents[0]);
  
  if (contents[1])
    w += LyXWidth(font, ',');       /* double quotes are wider*/
   
  return w;
}


InsetQuotes::InsetQuotes()
{
  kind = new char[4];
  contents = new char[2];
  ParseString("eld");
}


LyXFont InsetQuotes::ConvertFont(LyXFont font)
{
  /* quotes-insets cannot be latex of any kind */
  font.latex = LYX_NO_LATEX;
  return font;
}


void InsetQuotes::Draw(LyXFont font, unsigned long  pm,
		       int baseline, float &x)
{
  /* draw it! */ 
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x, baseline,
	      contents, 1);
   
  if (contents[1]) {	       /* double quotes*/
    x += LyXWidth(font, ',');
    /* draw the second! */ 
    XDrawString(fl_display,
		pm,
		LyXGetGC(font),
		(int) x, baseline,
		contents+1, 1);      /* a little pointer hack!  */
  }
  
  /* calculate the width and set the new x position */ 
  x +=  LyXWidth(font, contents[0]);
}


void InsetQuotes::Write(FILE *file)
{
  fprintf(file, "Quotes %s", kind);
}


void InsetQuotes::Read(FILE *file)
{
  char string[4];
  if (!feof(file))
    string[0] = fgetc(file);
  else
    string[0] = ' ';
  if (!feof(file))
    string[1] = fgetc(file);
  else
    string[1] = ' ';
  if (!feof(file))
    string[2] = fgetc(file);
  else
    string[2] = ' ';
  string[3]='\0';
   
  ParseString(string);
}


int InsetQuotes::Latex(FILE *file, char /*fragile*/)
{
  switch (kind[0]) {
  case 'g':			       /* german quotes  */
    fprintf(file, "\\%c%cq", kind[0], kind[1]);
    if (kind[2]!='s')
      fprintf(file, "q");
    fprintf(file,"{}");
    break;
  case 'f':			       /* french quotes  */
    fprintf(file, "\\%c%cq", kind[0], kind[1]);
    if (kind[2]!='s')
      fprintf(file, "q");
    fprintf(file,"{}");
    break;
  default:			       /* english quotes  */
    fprintf(file, "%c", contents[0]);
    if (kind[2]!='s')
      fprintf(file, "%c", contents[0]);
    break;
  }
  return 0;
}


Inset* InsetQuotes::Clone()
{
  InsetQuotes *result;
  result = new InsetQuotes(kind);
  return result;
}


char InsetQuotes::LyxCode()
{
  return LYX_QUOTE_CODE;
}


/* Latex. Used to insert Latex-Code automatically */

InsetLatex::InsetLatex(char* string)
{
  contents = StringCopy(string);
}


InsetLatex::~InsetLatex()
{
   if (contents)
      delete contents;
}


int InsetLatex::Ascent(LyXFont font)
{
  int max=0;
  int i;
  for (i=0; contents[i];i++) {
    if (LyXAscent(font, contents[i])> max)
      max = LyXAscent(font, contents[i]);
  }
  return max;
}


int InsetLatex::Descent(LyXFont font)
{
  int max=0;
  int i;
  for (i=0; contents[i];i++) {
    if (LyXDescent(font, contents[i])> max)
      max = LyXDescent(font, contents[i]);
  }
  return max;
}


int InsetLatex::Width(LyXFont font)
{
  int n;
  for (n=0; contents[n];n++);	/* get the size */
  
  int w = LyXTextWidth(font, contents, n );
   
  w +=2;
   
  return w;
}


InsetLatex::InsetLatex()
{
  contents = new char[10];
  contents[0] = '\0';
}


void InsetLatex::Draw(LyXFont font, unsigned long  pm,
		      int baseline, float &x)
{
  int n;

  for (n=0; contents[n];n++);	/* get the size */
   
  /* Latex-insets are always LaTeX, so just correct the font */ 
  if (font.latex == LYX_NO_LATEX)
    font.latex = LYX_LATEX;
   
  /* draw it! */ 
   
  x += 1;
  XFillRectangle(fl_display,
		 pm,
		 LyXGetLightedGC(),
		 (int) x, baseline- Ascent(font),
		 Width(font)-2, (Ascent(font)+Descent(font)));
		 
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x, baseline,
	      contents, n);
  
  x +=  Width(font) - 1;
}


void InsetLatex::Write(FILE *file)
{
  fprintf(file, "Latex %s\n", contents);
}


void InsetLatex::Read(FILE *file)
{
  int i = 0;
  char c='\0';
  char tmp[100];
  while (!feof(file) && (c = fgetc(file)) != '\n') {
    tmp[i]=c;
    i++;
  }
  tmp[i]='\0';
  contents = StringCopy(tmp);
}


int InsetLatex::Latex(FILE *file, char /*fragile*/)
{
  fprintf(file, "%s", contents);
  return 0;
}


char InsetLatex::Deletable()
{
  return 0;
}


Inset* InsetLatex::Clone()
{
  InsetLatex *result = new InsetLatex(contents);
  return result;
}


char InsetLatex::LyxCode()
{
  if (!strcmp(contents, "\\tableofcontents")) return LYX_TOC_CODE;
  return LYX_NO_CODE;
}


/* FormulaLatex. Used to insert FormulaLatex-Code automatically */

InsetFormulaLatex::InsetFormulaLatex(char* string)
{
  contents = StringCopy(string);
}


InsetFormulaLatex::~InsetFormulaLatex()
{
   if (contents)
      delete contents;
}


int InsetFormulaLatex::Ascent(LyXFont font)
{
  int max=0;
  int i;
  for (i=0; contents[i];i++) {
    if (LyXAscent(font, contents[i])> max)
      max = LyXAscent(font, contents[i]);
  }
  return max;
}


int InsetFormulaLatex::Descent(LyXFont font)
{
  int max=0;
  int i;
  for (i=0; contents[i];i++) {
    if (LyXDescent(font, contents[i])> max)
      max = LyXDescent(font, contents[i]);
  }
  return max;
}


int InsetFormulaLatex::Width(LyXFont font)
{
  int n;
  for (n=0; contents[n];n++);	/* get the size */

  int w = LyXTextWidth(font, contents, n );
   
  w +=2;
   
  return w;
}


InsetFormulaLatex::InsetFormulaLatex()
{
  contents = new char[10];
  contents[0] = '\0';
}


LyXFont InsetFormulaLatex::ConvertFont(LyXFont font)
{
  /* FormulaLatex-insets are always formulas*/ 
  font.latex = LYX_FORMULA_LATEX;
  return font;
}


void InsetFormulaLatex::Draw(LyXFont font, unsigned long  pm,
			     int baseline, float &x)
{
  int n;
  for (n=0; contents[n];n++);	/* get the size */

  /* draw it! */ 
  
  x += 1;
  XFillRectangle(fl_display,
		 pm,
		 LyXGetLightedGC(),
		 (int) x, baseline- Ascent(font),
		 Width(font)-2, (Ascent(font)+Descent(font)));
		 
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x, baseline,
	      contents, n);
  
  x +=  Width(font) - 1;
}


void InsetFormulaLatex::Write(FILE *file)
{
  fprintf(file, "FormulaLatex %s\n", contents);
}


void InsetFormulaLatex::Read(FILE *file)
{
  int i = 0;
  char c='\0';
  char tmp[100];
  while (!feof(file) && (c = fgetc(file)) != '\n') {
    tmp[i]=c;
    i++;
  }
  tmp[i]='\0';
  contents = StringCopy(tmp);
}


int InsetFormulaLatex::Latex(FILE *file, char /*fragile*/)
{
  fprintf(file, "%s", contents);
  return 0;
}


char InsetFormulaLatex::Deletable()
{
  return 0;
}


Inset* InsetFormulaLatex::Clone()
{
  InsetFormulaLatex *result = new InsetFormulaLatex(contents);
  return result;
}


InsetFormulaLatexDel::InsetFormulaLatexDel(char* string)
{
  contents = StringCopy(string);
}


InsetFormulaLatexDel::~InsetFormulaLatexDel()
{
   if (contents)
      delete contents;
}


int InsetFormulaLatexDel::Ascent(LyXFont font)
{
  int max=0;
  int i;
  for (i=0; contents[i];i++) {
    if (LyXAscent(font, contents[i])> max)
      max = LyXAscent(font, contents[i]);
  }
  return max;
}


int InsetFormulaLatexDel::Descent(LyXFont font)
{
  int max=0;
  int i;
  for (i=0; contents[i];i++) {
    if (LyXDescent(font, contents[i])> max)
      max = LyXDescent(font, contents[i]);
  }
  return max;
}


int InsetFormulaLatexDel::Width(LyXFont font)
{
  int n;
  for (n=0; contents[n];n++);	/* get the size */

  int w = LyXTextWidth(font, contents, n );
   
  w +=2;
   
  return w;
}


InsetFormulaLatexDel::InsetFormulaLatexDel()
{
  contents = new char[10];
  contents[0] = '\0';
}


LyXFont InsetFormulaLatexDel::ConvertFont(LyXFont font)
{
  /* FormulaLatex-insets are always formulas*/ 
  font.latex = LYX_FORMULA_LATEX;
  return font;
}


void InsetFormulaLatexDel::Draw(LyXFont font, unsigned long  pm,
				int baseline, float &x)
{
  int n;
  for (n=0; contents[n];n++);	/* get the size */

  /* draw it! */ 
  
  x += 1;
  XFillRectangle(fl_display,
		 pm,
		 LyXGetLightedGC(),
		 (int) x, baseline- Ascent(font),
		 Width(font)-2, (Ascent(font)+Descent(font)));
		 
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x, baseline,
	      contents, n);
  
  x +=  Width(font) - 1;
}


void InsetFormulaLatexDel::Write(FILE *file)
{
  fprintf(file, "FormulaLatex %s\n", contents);
}


void InsetFormulaLatexDel::Read(FILE *file)
{
  int i = 0;
  char c='\0';
  char tmp[100];
  while (!feof(file) && (c = fgetc(file)) != '\n') {
    tmp[i]=c;
    i++;
  }
  tmp[i]='\0';
  contents = StringCopy(tmp);
}


int InsetFormulaLatexDel::Latex(FILE *file, char /*fragile*/)
{
  fprintf(file, "%s", contents);
  return 0;
}


char InsetFormulaLatexDel::Deletable()
{
  return 1;
}


Inset* InsetFormulaLatexDel::Clone()
{
  InsetFormulaLatexDel *result = new InsetFormulaLatexDel(contents);
  return result;
}



/* LatexDel. Used to insert Latex-Code automatically */

InsetLatexDel::InsetLatexDel(const char* string)
{
  contents = StringCopy(string);
}


InsetLatexDel::~InsetLatexDel()
{
   if (contents)
      delete contents;
}


int InsetLatexDel::Ascent(LyXFont font)
{
  int max=0;
  int i;

  for (i=0; contents[i];i++) {
    if (LyXAscent(font, contents[i])> max)
      max = LyXAscent(font, contents[i]);
  }

  return max;
}


int InsetLatexDel::Descent(LyXFont font)
{
  int max=0;
  int i;

  for (i=0; contents[i];i++) {
    if (LyXDescent(font, contents[i])> max)
      max = LyXDescent(font, contents[i]);
  }
  return max;
}


int InsetLatexDel::Width(LyXFont font)
{
  int n;
  for (n=0; contents[n];n++);	/* get the size */

  int w = LyXTextWidth(font, contents, n );
   
  w +=2;
   
  return w;
}


InsetLatexDel::InsetLatexDel()
{
  contents = new char[10];
  contents[0] = '\0';
}


void InsetLatexDel::Draw(LyXFont font, unsigned long  pm,
			 int baseline, float &x)
{
  int n;

  for (n=0; contents[n];n++);	/* get the size */
  
  /* Latex-insets are always LaTeX, so just correct the font */ 
  if (font.latex == LYX_NO_LATEX)
    font.latex = LYX_LATEX;

  /* draw it! */ 
  
  x += 1;
  XFillRectangle(fl_display,
		 pm,
		 LyXGetLightedGC(),
		 (int) x, baseline- Ascent(font),
		 Width(font)-2, (Ascent(font)+Descent(font)));
		 
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x, baseline,
	      contents, n);
  
  x +=  Width(font) - 1;
}


void InsetLatexDel::Write(FILE *file)
{
  fprintf(file, "LatexDel %s\n", contents);
}


void InsetLatexDel::Read(FILE *file)
{
  int i = 0;
  char c='\0';
  char tmp[100];
  while (!feof(file) && (c = fgetc(file)) != '\n') {
    tmp[i]=c;
    i++;
  }
  tmp[i]='\0';
  contents = StringCopy(tmp);
}


int InsetLatexDel::Latex(FILE *file, char /*fragile*/)
{
  fprintf(file, "%s", contents);
  return 0;
}


char InsetLatexDel::Deletable()
{
  return 1;
}


Inset* InsetLatexDel::Clone()
{
  InsetLatexDel *result = new InsetLatexDel(contents);
  return result;
}


char InsetLatexDel::LyxCode()
{
  if (!strcmp(contents, "\\tableofcontents")) return LYX_TOC_CODE;
  if (!strcmp(contents, "\\label{")) return LYX_MARK_CODE;
  if (!strcmp(contents, "\\ref{")) return LYX_REF_CODE;
  if (!strcmp(contents, "\\url{")) return LYX_URL_CODE;
  if (!strcmp(contents, "\\htmlurl{")) return LYX_HTMLURL_CODE;
  if (!strcmp(contents, "}{")) return LYX_SEPARATOR_CODE;
  if (!strcmp(contents, "}")) return LYX_ENDING_CODE;
  return LYX_NO_CODE;
}


/* LatexAccent. Proper handling of accented characters */
/* This part is done by Ivan Schreter, schreter@ccsun.tuke.sk */

InsetLatexAccent::InsetLatexAccent(char* string)
{
  contents = StringCopy(string);
  CheckContents();
}


InsetLatexAccent::~InsetLatexAccent()
{
   if (contents)
      delete contents;
}


void InsetLatexAccent::CheckContents()
        // check, if we know the modifier and can display it ok on screen
{
        int i = 2;
        char needsspace = 0, buf[64], *pcontents;

        candisp = 0;
	if (!contents) return;

	if (*contents == '{') {
		strcpy(pcontents = buf, contents+1);
		buf[strlen(buf)-1] = 0;
	} else pcontents = contents;

        if (pcontents[0] != '\\') return;
#ifdef DEBUG
        printf("Decode: [%s]\n", pcontents);
#endif
        remdot = 0; plusasc = 0; plusdesc = 0;

        switch (pcontents[1]) {
            case '\'':  // acute
                modtype = 0;    // acute
                plusasc = 1;    // at the top of character
                break;
            case '`':   // grave
                modtype = 1;    // grave
                plusasc = 1;    // at the top
                break;
            case '=':   // macron
                modtype = 2;    // macron
                plusasc = 1;    // at the top
                break;
            case '~':   // tilde
                modtype = 3;    // tilde
                plusasc = 1;    // at the top
                break;
            case 'b':   // underbar
                modtype = 4;    // underbar
                plusdesc = 1;   // at the bottom
                needsspace = 1; // needs space after mod
                break;
            case 'c':   // cedilla
                modtype = 5;    // cedilla
                plusdesc = 1;   // at the bottom
                needsspace = 1; // needs space after mod
                break;
            case 'd':   // underdot
                modtype = 6;    // underdot
                plusdesc = 1;   // at the bottom
                needsspace = 1; // needs space after mod
                break;
            case 'r':   // circle
                modtype = 7;    // circle
                plusasc = 1;    // at the top
                needsspace = 1; // needs space after mod
                break;
            case 't':   // tie
                modtype = 8;    // tie
                plusasc = 1;    // at the top
                needsspace = 1; // needs space after mod
                break;
            case 'u':   // breve
                modtype = 9;    // breve
                plusasc = 1;    // at the top
                needsspace = 1; // needs space after mod
                break;
            case 'v':   // caron
                modtype = 10;   // caron
                plusasc = 1;    // at the top
                needsspace = 1; // needs space after mod
                break;
            case 'q':   // special caron
                modtype = 11;   // special caron
                plusasc = 1;    // at the top
                needsspace = 1; // needs space after mod
                break;
            case 'H':   // hungarian umlaut
                modtype = 12;   // hungarian umlaut
                plusasc = 1;    // at the top
                needsspace = 1; // needs space after mod
                break;
            case '"':   // umlaut
                modtype = 13;   // umlaut
                plusasc = 1;    // at the top
                break;
            case '.':   // dot
                modtype = 14;   // dot
                plusasc = 1;    // at the top
                break;
            case '^':   // circumflex
                modtype = 15;   // circumflex
                plusasc = 1;    // at the top
                break;
            default:
                return;
        }

        // now decode the rest - first look for spaces
        // that while is there so that break works
        while (needsspace) {
                if (pcontents[2] == '{' || pcontents[2] == ' ') {
                        i = 3;
                        break;
                }
                if (pcontents[2] == '\\') break;
                return;
        }

        // now get the char
        ic = pcontents[i++];
        if (ic == '\\') {
                ic = pcontents[i++];
                if (ic == 'i' || ic == 'j') remdot = 1;
                        else return;
        }
        if (pcontents[i] == ' ') ++i;
        if (pcontents[i] && pcontents[i] != '}') return;

        // fine, the char is properly decoded now (hopefully)
#ifdef DEBUG
        printf("Contents: [%s], ic [%c], top: %d, bot: %d, dot: %d, mod: %d\n",
                contents, ic, plusasc, plusdesc, remdot, modtype);
#endif
        candisp = 1;
}


int InsetLatexAccent::Ascent(LyXFont font)
{
  int max=0;
  int i;

  if (candisp) {
        max = LyXAscent(font, ic);
        if (plusasc) max += (LyXMaxAscent(font)+2) / 3;
  } else
  for (i=0; contents[i];i++) {
    if (LyXAscent(font, contents[i])> max)
      max = LyXAscent(font, contents[i]);
  }

  return max;
}


int InsetLatexAccent::Descent(LyXFont font)
{
  int max=0;
  int i;

  if (candisp) {
        if (plusdesc) max = LyXMaxDescent(font);
                else max = LyXDescent(font, ic);
  } else
  for (i=0; contents[i];i++) {
    if (LyXDescent(font, contents[i])> max)
      max = LyXDescent(font, contents[i]);
  }
  return max;
}


int InsetLatexAccent::Width(LyXFont font)
{
  int n, w;

  if (candisp) w = LyXTextWidth(font, &ic, 1);
        else {
                for (n=0; contents[n];n++);     /* get the size */
                w = LyXTextWidth(font, contents, n);
        }
   
  //w +=2;
   
  return w;
}


InsetLatexAccent::InsetLatexAccent()
{
  contents = new char[10];
  contents[0] = '\0';
  candisp = 0;
}


void InsetLatexAccent::Draw(LyXFont font,
			    unsigned long  pm,
			    int baseline, 
			    float &x)
{
  int n;

  /* Latex-insets are always LaTeX, so just correct the font */ 
  // well, in this case, we just keep the old font - it's switched
  if (font.latex != LYX_NO_LATEX)
    font.latex = LYX_NO_LATEX;

  /* draw it! */ 
  
  if (candisp) {
        int asc = Ascent(font);
        int desc = Descent(font);
        int wid = Width(font);
	int x2 = (int) x+(wid/2);
        int hg, hg35, y;
        XGCValues gcval;

        if (plusasc) {
                // mark at the top
                hg = LyXMaxDescent(font); //(LyXMaxAscent(font)+2) / 3;// space at the top
                y = baseline - asc;
                if (remdot) y += hg;            // we'll remove the dot
		if (font.shape == 1) x2 += (4*hg)/5; // italic
        } else {
                // at the bottom
                hg = desc;
                y = baseline;
        }

	hg35 = (hg*3)/5;

        GC pgc = LyXGetGC(font);
        gcval.line_width = (hg+3)/4;
	gcval.cap_style = CapRound;
        XChangeGC(fl_display, pgc, GCLineWidth | GCCapStyle, &gcval);
        // display with proper accent mark
        // first the letter
        XDrawString(fl_display, pm, pgc,
                (int) x, baseline, &ic, 1);
        if (remdot) {
                // remove the dot first
                XFillRectangle(fl_display, pm,
                 LyXGetClearGC(),
                 (int) x, y, wid - 2, hg);
        }
        // now the rest - draw within (x,y, x+wid, y+hg)
        switch (modtype) {
            case 0:     // acute
                XDrawLine(fl_display, pm, pgc, x2, y+hg35, x2+hg35, y);
                break;
            case 1:     // grave
                XDrawLine(fl_display, pm, pgc, x2, y+hg35, x2-hg35, y);
                break;
            case 2:     // macron
                XDrawLine(fl_display, pm, pgc, x2-(3*wid/7), y+(hg/2),
                        x2+(3*wid/7), y+(hg/2));
                break;
            case 3:     // tilde
		if (hg35 > 2) --hg35;
		x2 += (hg35/2);
                XDrawLine(fl_display, pm, pgc, x2-2*hg35, y+hg35, x2-hg35, y);
                XDrawLine(fl_display, pm, pgc, x2, y+hg35, x2+hg35, y);
                XDrawLine(fl_display, pm, pgc, x2, y+hg35, x2-hg35, y);
                break;
            case 4:     // underbar
                XDrawLine(fl_display, pm, pgc, x2-(3*wid/7), y+(hg/2),
                        x2+(3*wid/7), y+(hg/2));
                break;
            case 5:     // cedilla
		XDrawLine(fl_display, pm, pgc, x2, y, x2, y+(hg/3));
		XDrawLine(fl_display, pm, pgc, x2, y+(hg/3), x2+(hg/3), y+(hg/2));
		XDrawLine(fl_display, pm, pgc, x2+(hg/3), y+(hg/2), x2-(hg/4), y+hg);
                break;
            case 6:     // underdot
            case 14:    // dot
        	gcval.line_width = hg/2;
        	XChangeGC(fl_display, pgc, GCLineWidth, &gcval);
		XDrawLine(fl_display, pm, pgc, x2, y+(hg/2), x2, y+(hg/2));
                break;
            case 7:     // circle
		XDrawArc(fl_display, pm, pgc, x2-(hg/2), y, hg, hg, 0, 23039);
                break;
            case 8:     // tie
		XDrawArc(fl_display, pm, pgc, x2, y+(hg/4), hg, hg, 0, 11519);
                break;
            case 9:     // breve
		XDrawArc(fl_display, pm, pgc, x2-(hg/2), y-(hg/4), hg, hg, 0, -11519);
                break;
            case 10:    // caron
                XDrawLine(fl_display, pm, pgc, x2, y+hg35, x2+hg35, y);
                XDrawLine(fl_display, pm, pgc, x2, y+hg35, x2-hg35, y);
                break;
            case 11:    // special caron
		switch (ic) {
			case 'L': wid = 4*wid/5; break;
			case 't': y -= hg35/2; break;
		}
                XDrawLine(fl_display, pm, pgc, (int) x+wid, y+hg35+hg,
			(int) x+wid+(hg35/2), y+hg+(hg35/2));
		XDrawLine(fl_display, pm, pgc, (int) x+wid+(hg35/2),
			y+hg+(hg35/2), (int) x+wid+(hg35/2), y+hg);
                break;
            case 12:    // hung. umlaut
                XDrawLine(fl_display, pm, pgc, x2-(hg/2), y+hg35,
			x2+hg35-(hg/2), y);
                XDrawLine(fl_display, pm, pgc, x2+(hg/2), y+hg35,
			x2+hg35+(hg/2), y);
                break;
            case 13:    // umlaut
        	gcval.line_width = hg/2;
        	XChangeGC(fl_display, pgc, GCLineWidth, &gcval);
		XDrawLine(fl_display, pm, pgc, x2-(5*hg/8), y+(hg/2),
			x2-(5*hg/8), y+(hg/2));
		XDrawLine(fl_display, pm, pgc, x2+(5*hg/8), y+(hg/2),
			x2+(5*hg/8), y+(hg/2));
                break;
            case 15:    // circumflex
                XDrawLine(fl_display, pm, pgc, x2, y, x2+hg35, y+hg35);
                XDrawLine(fl_display, pm, pgc, x2, y, x2-hg35, y+hg35);
                break;
        }
  } else {               
      for (n=0; contents[n];n++);       /* get the size */
  
      XFillRectangle(fl_display,
                 pm,
                 LyXGetLightedGC(),
                 (int) x, baseline- Ascent(font),
                 Width(font), (Ascent(font)+Descent(font)));

      XDrawString(fl_display,
              pm,
              LyXGetGC(font),
              (int) x, baseline,
              contents, n);
  }
  x +=  Width(font);
}


void InsetLatexAccent::Write(FILE *file)
{
  fprintf(file, "\\i %s\n", contents);
}


void InsetLatexAccent::Read(FILE *file)
{
  int i = 0;
  char c='\0';
  char tmp[100];
  while (!feof(file) && (c = fgetc(file)) != '\n') {
    tmp[i]=c;
    i++;
  }
  tmp[i]='\0';
  contents = StringCopy(tmp);
  CheckContents();
}


int InsetLatexAccent::Latex(FILE *file, char /*fragile*/)
{
  fprintf(file, "%s", contents);
  return 0;
}


char InsetLatexAccent::Deletable()
{
  return 1;
}


char InsetLatexAccent::DirectWrite()
{
  return 1;
}


Inset* InsetLatexAccent::Clone()
{
  InsetLatexAccent *result = new InsetLatexAccent(contents);
  return result;
}


char InsetLatexAccent::LyxCode()
{
  return LYX_ACCENT_CODE;
}


Bool InsetLatexAccent::IsEqual(Inset* other)
{
  if (other && other->LyxCode() == LYX_ACCENT_CODE){
    InsetLatexAccent* otheraccent = (InsetLatexAccent*) other;
    return StringEqual(contents, otheraccent->contents);
  }
  return False;
}


/* Error, used for the LaTeX-Error Messages */

InsetError::InsetError(const char* string)
{
  contents = StringCopy(string);
}


InsetError::~InsetError()
{
   if (contents)
      delete contents;
}


int InsetError::Ascent(LyXFont font)
{
  return LyXAscent(font, 'E')+3;
}


int InsetError::Descent(LyXFont font)
{
  return LyXDescent(font, 'E')+3;
}


int InsetError::Width(LyXFont font)
{
  int w = LyXTextWidth(font, "Error", 5 );
   
  w +=6;
   
  return w;
}


InsetError::InsetError()
{
  contents = new char[10];
  contents[0] = '\0';
}


void InsetError::Draw(LyXFont font, unsigned long  pm,
		      int baseline, float &x)
{
  /* Latex-insets are always LaTeX, so just correct the font */ 
   
  font.latex = LYX_LATEX;
   
  /* draw it! */ 
   
  x += 1;
  XFillRectangle(fl_display,
		 pm,
		 LyXGetLightedGC(),
		 (int) x, baseline- Ascent(font),
		 Width(font)-2, (Ascent(font)+Descent(font)));
   
  XDrawRectangle(fl_display,
		 pm,
		 LyXGetCopyGC(),
		 (int) x-1, baseline- Ascent(font)-1,
		 Width(font)-1, (Ascent(font)+Descent(font))+1);
   
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x+3, baseline,
	      "Error", 5);
   
  x +=  Width(font) - 1;
}


void InsetError::Write(FILE *)
{
}


void InsetError::Read(FILE *)
{
}


int InsetError::Latex(FILE *, char /*fragile*/)
{
  return 0;
}


char InsetError::AutoDelete()
{
  return 1;
}


char InsetError::Editable()
{
  return 1;
}


static
void CloseErrorCB(FL_OBJECT *, long data)
{
   FL_FORM *form = (FL_FORM*) data;
   if (form)
     fl_hide_form(form);
}


FL_FORM* InsetError::form = NULL;
FL_OBJECT* InsetError::strobj = NULL;

void InsetError::Edit(int, int)
{
  if (!form) {
    FL_OBJECT *obj;
    form = fl_bgn_form(FL_UP_BOX,400,140);
    strobj = fl_add_box(FL_FRAME_BOX,10,140-50-80,380,80,"");
    fl_set_object_color(strobj,FL_MCOL,FL_MCOL);
    obj = fl_add_button(FL_RETURN_BUTTON,160,140-10-30,120,30,"OK");
    fl_set_object_callback(obj, CloseErrorCB, (long)form);
    fl_end_form();
  }
  fl_set_object_label(strobj, contents);
  if (form->visible) {
	  fl_raise_form(form);
  } else
    fl_show_form(form,FL_PLACE_MOUSE | FL_FREE_SIZE, FL_FULLBORDER, 
		 "LaTeX-Error");
}


Inset* InsetError::Clone()
{
  InsetError *result = new InsetError(contents);
  return result;
}


/* Info, used for the Info boxes */

InsetInfo::InsetInfo()
{
   form = NULL;
   strobj = NULL;
   contents = new char[10];
   contents[0] = '\0';
}


InsetInfo::~InsetInfo()
{
   if (contents)
      delete contents;
   if (form){
      fl_hide_form(form);
      fl_free_form(form);
      form = NULL;
   }
}


int InsetInfo::Ascent(LyXFont font)
{
  return LyXAscent(font, 'E')+3;
}


int InsetInfo::Descent(LyXFont font)
{
  return LyXDescent(font, 'E')+3;
}


int InsetInfo::Width(LyXFont font)
{
  int w = LyXTextWidth(font, "Note", 5 );
   
  w +=6;
   
  return w;
}


void InsetInfo::Draw(LyXFont font, unsigned long  pm,
		     int baseline, float &x)
{
   
  /* Latex-insets are never LaTeX, so just correct the font */ 
   
  font.latex = LYX_NO_LATEX;
   
  /* draw it! */ 
   
  x += 1;
  XFillRectangle(fl_display,
		 pm,
		 LyXGetInsetGC(),
		 (int) x, baseline- Ascent(font),
		 Width(font)-2, (Ascent(font)+Descent(font)));
   
  XDrawRectangle(fl_display,
		 pm,
		 LyXGetCopyGC(),
		 (int) x-1, baseline- Ascent(font)-1,
		 Width(font)-1, (Ascent(font)+Descent(font))+1);
   
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x+3, baseline,
	      "Note", 5);
   
  x +=  Width(font) - 1;
}


void InsetInfo::Write(FILE *file)
{
   fprintf(file, "Info %s\n", contents);
}


void InsetInfo::Read(FILE *file)
{
   char* token;
   char c;
   char token_end_character;
   LyXParagraph *par = new LyXParagraph();
   int pos = 0;
   int i;
   c = fgetc(file);
   while (!feof(file)) {
      /* is it a lyx command? */ 
      if (c=='\\') {
	 token = InsetNextToken(file, token_end_character);
	 if (StringEqual(token, "end_inset")) {
	    par->InsertChar(pos - 1, '\0');   /* the - 1 deletes the newline
					       * before end_preamble*/
	    Set(par->text);
	    delete par;
	    return;
	 }
	 else {
	    par->InsertChar(pos, '\\');
	    pos++;
	    for (i = 0; token[i]; i++) {
	       par->InsertChar(pos, token[i]);
	       pos++;
	    }
	    par->InsertChar(pos, token_end_character);
	    pos++;
	 }
	 delete token;
      }
      else {
	 /* simple text */
	 par->InsertChar(pos, c);
	 pos++;
      }
      c = fgetc(file);
   }
}
      

int InsetInfo::Latex(FILE *, char /*fragile*/)
{
  return 0;
}


char InsetInfo::Editable()
{
  return 1;
}


static
void CloseInfoCB(FL_OBJECT *, long data)
{
   InsetInfo *inset = (InsetInfo*) data;
   char *tmp=StringCopy(fl_get_input(inset->strobj));
   inset->Set(tmp);
   delete tmp;
   fl_hide_form(inset->form);
   fl_free_form(inset->form);
   inset->form = NULL;
}


void InsetInfo::Edit(int, int)
{
  if (!form) {
    FL_OBJECT *obj;
    form = fl_bgn_form(FL_UP_BOX,400,180);
    strobj = obj = fl_add_input(FL_MULTILINE_INPUT,10,180-50-120,380,120,"");
    fl_set_object_color(obj,FL_MCOL,FL_MCOL);
    fl_set_object_resize(obj, FL_RESIZE_ALL);
    fl_set_object_gravity(obj, NorthWestGravity, SouthEastGravity);
    obj = fl_add_button(FL_NORMAL_BUTTON,160,180-10-30,120,30,"OK");
    fl_set_object_resize(obj, FL_RESIZE_ALL);
    fl_set_object_gravity(obj, SouthWestGravity, SouthEastGravity);
    fl_set_object_callback(obj, CloseInfoCB, (long)this);
    fl_set_object_shortcut(obj, "#O#o", (long)this);
    fl_end_form();
  }
  fl_set_input(strobj, contents);
  if (form->visible) {
	  fl_raise_form(form);
  } else
    fl_show_form(form,FL_PLACE_MOUSE | FL_FREE_SIZE, FL_FULLBORDER, 
		 "Note");
}


void InsetInfo::Set(char* string)
{
   if (contents)
      delete contents;
   contents = StringCopy(string);
}


Inset* InsetInfo::Clone()
{
   InsetInfo *result = new InsetInfo();
   result->Set(contents);
   return result;
}


char InsetInfo::LyxCode()
{
   return LYX_IGNORE_CODE;
}


/* Label. Used to insert a label automatically */

InsetLabel::InsetLabel(char* string)
{
  label = StringCopy(string);
  int i;
  for (i=0; label[i]; i++);
  contents = new char [i+20];
  sprintf(contents, "\\label{%s}", label);
}


InsetLabel::~InsetLabel()
{
   if (label)
      delete label;
   if (contents)
      delete contents;
}


int InsetLabel::Ascent(LyXFont font)
{
  int max=0;
  int i;

  for (i=0; label[i];i++) {
    if (LyXAscent(font, label[i])> max)
      max = LyXAscent(font, label[i]);
  }

  return max;
}


int InsetLabel::Descent(LyXFont font)
{
  int max=0;
  int i;

  for (i=0; label[i];i++) {
    if (LyXDescent(font, label[i])> max)
      max = LyXDescent(font, label[i]);
  }
  return max;
}


int InsetLabel::Width(LyXFont font)
{
  int n;
  for (n=0; label[n];n++);	/* get the size */

  int w = LyXTextWidth(font, label, n );
   
  w += 6;
   
  return w;
}


InsetLabel::InsetLabel()
{
  contents = new char[10];
  contents[0] = '\0';
  label = new char[10];
  label[0] = '\0';

}


void InsetLabel::Draw(LyXFont font, unsigned long  pm,
		      int baseline, float &x)
{
  int n;

  for (n=0; label[n];n++);	/* get the size */
  
  /* Latex-insets are always LaTeX, so just correct the font */ 
  //  if (font.latex == LYX_NO_LATEX)
  //  font.latex = LYX_LATEX;

  /* draw it! */ 
  
  x += 1;

  XDrawRectangle(fl_display,
		 pm,
		 LyXGetCopyGC(),
		 (int) x-1, baseline- Ascent(font)-3,
		 Width(font)-1, (Ascent(font)+Descent(font))+5);
		 
  XFillRectangle(fl_display,
		 pm,
		 LyXGetLightedGC(),
		 (int) x, baseline- Ascent(font)-2,
		 Width(font)-2, (Ascent(font)+Descent(font))+4);          
		 
  XDrawString(fl_display,
	      pm,
	      LyXGetGC(font),
	      (int) x+2, baseline,
	      label, n);
  
  x +=  Width(font) - 1;
}


void InsetLabel::Write(FILE *file)
{
  fprintf(file, "Label %s\n", label);
}


void InsetLabel::Read(FILE *file)
{
  int i = 0;
  char c='\0';
  char tmp[100];
  while (!feof(file) && (c = fgetc(file)) != '\n') {
    tmp[i]=c;
    i++;
  }
  tmp[i]='\0';
  label = StringCopy(tmp);
  for (i=0; label[i]; i++);
  contents = new char [i+20];
  sprintf(contents, "\\label{%s}", label);
}


int InsetLabel::Latex(FILE *file, char /*fragile*/)
{
  fprintf(file, "%s", contents);
  return 0;
}


char InsetLabel::Deletable()
{
  return 1;
}


Inset* InsetLabel::Clone()
{
  InsetLabel *result = new InsetLabel(label);
  return result;
}


char InsetLabel::LyxCode()
{
  return LYX_LABEL_CODE;
}

int InsetLabel::GetNumberOfLabels()
{
  return 1;
}


const char* InsetLabel::GetLabel(int)
{
  return label;
}
