/******************************************************************************

    MODUL
	text.c

    DESCRIPTION

    NOTES

    BUGS

    TODO

    EXAMPLES

    SEE ALSO

    INDEX

    HISTORY
	04. Oct 1992	ada created

******************************************************************************/

/**************************************
		Includes
**************************************/
#include "defs.h"


/**************************************
	    Globale Variable
**************************************/


/**************************************
      Interne Defines & Strukturen
**************************************/


/**************************************
	    Interne Variable
**************************************/


/**************************************
	   Interne Prototypes
**************************************/
Prototype ED	* uninit_init		 (ED *);
Prototype int	  setpen		 (Line, Column);
Prototype WORD	  inversemode		 (int);
Prototype void	  text_cursor		 (int);
Prototype int	  text_init		 (ED *, WIN *, struct NewWindow *);
Prototype BOOL	  text_switch		 (struct Window *);
Prototype BOOL	  text_sync		 (void);
Prototype BOOL	  text_adjust		 (BOOL);
Prototype void	  text_load		 (void);
Prototype int	  text_colno		 (void);
Prototype int	  text_lineno		 (void);
Prototype int	  text_lines		 (void);
Prototype int	  text_cols		 (void);
Prototype int	  text_imode		 (void);
Prototype int	  text_tabsize		 (void);
Prototype UBYTE * text_name		 (void);
Prototype void	  text_uninit		 (void);
Prototype void	  text_position 	 (int, int);
Prototype void	  text_redisplaycurrline (void);
Prototype void	  do_redisplay		 (void);
Prototype void	  text_redisplay	 (void);
Prototype void	  text_write		 (UBYTE *);
Prototype void	  text_displayseg	 (int, int);
Prototype void	  text_redraw_cmdline	 (void);
Prototype void	  text_redrawblock	 (BOOL);
Prototype void	  redraw_text		 (Line, Line);
Prototype void	  redraw_textlineseg	 (Line, Column, Column);
Prototype void	  redraw_lineseg	 (UBYTE *, UWORD, Column, Column);


/*****************************************************************************

    NAME
	uninit_init

    PARAMETER
	ED * ep;

    RETURN
	ED * new_ep;

    DESCRIPTION
	Resets an editor-struct.

******************************************************************************/

ED * uninit_init (ED * ep)
{
    FONT	  * font;
    BPTR	    lock   = DupLock (ep->dirlock);
    WIN 	  * win;
    struct Gadget * gadg;
    int 	    bufsiz = CONFIG_SIZE;
    char	  * buf    = malloc (bufsiz);

    /* get buffer for config */
    if (!buf)
    {
	nomemory ();

	warn ("Out of memory !");

	return (NULL);
    }

    movmem (&ep->beginconfig, buf, bufsiz);

    /* remember window, font and gadget */
    win 	= ep->win;
    font	= ep->font;
    gadg	= ep->propgad;
    ep->font	= NULL;

    /* throw anything away */
    text_uninit ();

    /* init editor */
    text_init (Ep, NULL, NULL);

    /* switch to new one */
    ep = Ep;

    /* close font if there is one */
    if (ep->font)
	CloseFont (ep->font);

    /* reset window */
    ep->win  = win;

    /* set new font */
    if (ep->font = font)
    {
	SetFont (ep->win->RPort, font);
	set_window_params ();
    }

    /* set gadget */
    ep->propgad = gadg;

    /* copy config back */
    movmem (buf, &ep->beginconfig, bufsiz);

    /* no modifications. Set cursor to beginning */
    ep->modified = 0;
    ep->line	 = ep->topline = 0;

    /* create new lock */
    UnLock (ep->dirlock);
    ep->dirlock = (long)lock;

    /* free buffer */
    free (buf);

    return (ep);
} /* uninit_init */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

/* Return: Same as is_inblock() ! */
int setpen (Line line, Column column)
{
    ED	* ep   = Ep;
    RP	* rp   = ep->win->RPort;
    WORD  test;

    test = is_inblock (line, column);

    if (test & BP_INSIDE)
    {
	SetAPen (rp,  BLOCK_FPEN);
	SetBPen (rp,  BLOCK_BPEN);
	SetWrMsk (rp, BLOCK_MASK);
    } else
    {
	SetAPen (rp,  TEXT_FPEN);
	SetBPen (rp,  TEXT_BPEN);
	SetWrMsk (rp, TEXT_MASK);
    }

    return (test);
} /* setpen */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

WORD  inversemode (int n)
{
    RP	* rp = Ep->win->RPort;
    WORD  test;
    UBYTE fgpen;
    UBYTE bgpen;

    test = setpen (Ep->line, Ep->column);

    if (n)
    {
	fgpen = ~rp->FgPen;
	bgpen = ~rp->BgPen;

	SetAPen (rp, bgpen);
	SetBPen (rp, fgpen);
	SetDrMd (rp, JAM2|INVERSVID);
    } else
	SetDrMd (rp, JAM2);

    SetWrMsk (rp, 0xFF);

    return ((WORD)(test & BP_INSIDE));
} /* inversemode */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_init (ED * oldep, WIN * win, struct NewWindow * nw)
{
    ED * ep;

    if (!(ep = (ED *)allocb (sizeof(ED))) )
	return (0);

    setmem (ep, sizeof(ED), 0);
    ep->win = win;

    if (oldep)
    {
	ep->dirlock = (long)DupLock (oldep->dirlock);

	movmem (&oldep->beginconfig, &ep->beginconfig, CONFIG_SIZE);

	if (oldep->font)
	{
	    ep->font = oldep->font;
	    ep->font->tf_Accessors ++;

	    if (win)
		SetFont (win->RPort, ep->font);
	}

	/* change oldep to "last editor" to have the iconified window
	   positioned right */
	oldep = GetTail ((LIST *)&DBase);

	if (oldep->iconmode)
	{
	    ep->config.iwinx = oldep->win->LeftEdge;
	    ep->config.iwiny = oldep->win->TopEdge;
	} else
	{
	    ep->config.iwinx = oldep->config.iwinx;
	    ep->config.iwiny = oldep->config.iwiny;
	}

	ep->config.iwinx += TextLength (oldep->win->RPort, oldep->name,
			    strlen (oldep->name)) + 60;

	if (ep->config.iwinx > oldep->win->WScreen->Width)
	{
	    ep->config.iwinx = 0;

	    if(Ep->win->WScreen->Font != NULL)
		/* height */
		ep->config.iwiny += oldep->win->WScreen->Font->ta_YSize + 3;
	    else
		ep->config.iwiny += GfxBase->DefaultFont->tf_YSize + 3;
	}
    }
    else
    {
	PROC * proc = (PROC *)FindTask (NULL);

	ep->dirlock = (long)DupLock (proc->pr_CurrentDir);

	loadconfig (ep);
    }

    ep->lines	  = 1;
    ep->maxlines  = 32;
    ep->list	  = (UBYTE **)alloclptr (ep->maxlines);
    SETLINE(ep,0,allocline (1));

    Current[0] = Clen = 0;

    AddTail ((LIST *)&DBase, (NODE *)ep);
    ep->node.ln_Name = ep->name;
    ep->keytable  = currenthash ();      /* PATCH_NULL [01 Feb 1993] : added */
    ep->menustrip = currentmenu ();      /* PATCH_NULL [01 Feb 1993] : added */

    strcpy ((char *)ep->name, "unnamed");
    Ep = ep;	/* no switch_ed() here ! */

    strcpy (ep->wtitle, "  OK  ");

    if (win)
	text_cursor (1);

    if (nw)
    {
	if (!ep->iconmode && ep->win)
	{
	    nw->LeftEdge = ep->win->LeftEdge;
	    nw->TopEdge  = ep->win->TopEdge;
	    nw->Width	 = ep->win->Width;
	    nw->Height	 = ep->win->Height;
	} else
	{
	    if (ep->config.winwidth && ep->config.winheight)
	    {
		nw->LeftEdge = ep->config.winx;
		nw->TopEdge  = ep->config.winy;
		nw->Width    = ep->config.winwidth;
		nw->Height   = ep->config.winheight;
	    } else
	    {
		nw->LeftEdge = 0;
		nw->TopEdge  = 0;
		nw->Width    = 640;
		nw->Height   = 200;
	    }
	}

	nw->DetailPen = TEXT_BPEN;
	nw->BlockPen  = TEXT_FPEN;
    }

    return (1);
} /* text_init */


/*****************************************************************************

    NAME
	text_switch

    PARAMETER
	WIN * win;	    The window to switch to.

    RETURN
	BOOL found;	    Was the change successful ?

    DESCRIPTION
	Searches for the specified window and makes the editor with that
	window active.

******************************************************************************/

BOOL text_switch (WIN * win)
{
    ED * ep;

    /* look for that window */

    for (ep=(ED *)GetHead(&DBase); ep; ep=(ED *)GetSucc((struct Node *)ep))
    {
	if (ep->win == win)
	    break;
    }

    return (switch_ed (ep));
} /* text_switch */


/*****************************************************************************

    NAME
	text_sync

    PARAMETER
	void

    RETURN
	BOOL redraw;		Did text_sync() a screen-refresh ?

    DESCRIPTION
	copy current line to list of lines and say, if screen-update
	is neccessary. Furthermore, Current is filled with spaces upto
	the current column.

******************************************************************************/

BOOL text_sync (void)
{
    ED	  * ep	   = Ep;
//    char    redraw = 0;
    WORD    len;
    UBYTE * ptr;
    UBYTE * line;

    /* remove trailing spaces */
    len = strlen ((char *)Current)-1;
    ptr = Current + len;

    while (len && *ptr == ' ')
    {
	len --;
	ptr --;
    }

    if (*ptr == ' ')
	*ptr = 0;
    else
    {
	ptr[1] = 0;
	len ++;
    }

    /* Line length */
    Clen = len;

    if (!globalflags.Comlinemode)
    {
	WORD  len_in_blocks, clen_in_blocks;

	line = GETTEXT(ep,ep->line);
	len = strlen ((char *)line);

	/* Find out how many blocks (*8) we use and how many we need */
	len_in_blocks  =  (len + 8) & ~7;
	clen_in_blocks = (Clen + 8) & ~7;

	/* This was highly wasting memory. OS is always padding Alloc's
	   to 8 Bytes. If the length of the line is still within one
	   block but has changed we freed and allocated new memory.
	   This guranteed to fragment memory.

	   Just use the old version and edit some large text. Use avail,
	   save & reload text and "avail" again. The you'll see what I mean.
	   This is fixed now. */

	/* I must not use strcpy() if the line was empty since empty
	   lines are handled differently, i.e. they use static memory.
	   Only allocate new, if the line was empty or if the size in
	   blocks has changed, i.e. we need one more or less block of
	   memory (see AllocMem() in Amiga-ROM-Kernel-Ref.-Manual about
	   blocks). */
	if ((!len && Clen) || len_in_blocks != clen_in_blocks)
	{
	    if (ptr = allocline(Clen+1))
	    {

#ifdef DEBUG_MEM_H
    printf ("Allocated at %08x\n", ptr);
#endif

		ep->modified = 1;
		globalflags.Overide = 0;

		freeline (line);
		SETLINE(ep,ep->line,(LINE)ptr);

		strcpy ((char *)ptr, (char *)Current);
	    } else
	    {
		nomemory ();
		strcpy ((char *)Current, (char *)line);
	    }
	} else
	{ /* Within one block ... */
	    UBYTE * ptr1, * ptr2;

	    ptr1 = line;
	    ptr2 = Current;

	    /* We need not to copy stuff that's equal ! */
	    while (*ptr1 == *ptr2)
	    {
		if (!*ptr1)
		    break;

		ptr1 ++;
		ptr2 ++;
	    }

	    if (*ptr1 != *ptr2)
	    {
		ep->modified = 1;
		globalflags.Overide = 0;

/*printf ("Lines \nOld `%s'\nNew `%s'\ndiffer at\n%s\n%s", line, Current, ptr1, ptr2); */

		strcpy ((char *)ptr1, (char *)ptr2);
/*printf ("New Line `%s'\n", line);*/
	    } /* Any changes ? */
	} /* Old block length != new block length */
    } /* if (!Comlinemode) */

error:
    return ((BOOL)text_adjust (FALSE));
} /* text_sync */


/*****************************************************************************

    NAME
	text_adjust

    PARAMETER
	BOOL force;		TRUE: Redraw screen even if the cursor
				      is visible.
				FALSE: Draw only, if cursor is not visible.

    RETURN
	BOOL did_redraw;

    DESCRIPTION
	Make sure the current cursor position is visible.

******************************************************************************/

BOOL text_adjust (BOOL force)
{
    if (!Nsu)
    {
	if (Ep->column - Ep->topcolumn >= Columns || Ep->column < Ep->topcolumn)
	{
	    force = 1;

	    Ep->topcolumn = Ep->column - (Columns>>1);

	    if (Ep->topcolumn < 0)
		Ep->topcolumn = 0;
	}

	if (Ep->line - Ep->topline >= Lines || Ep->line < Ep->topline)
	{
	    force = 1;

	    Ep->topline = Ep->line - (Lines>>1);

	    if (Ep->topline < 0)
		Ep->topline = 0;
	}

	/* need I redraw ?? */
	if (force)
	    text_redisplay ();
    }

    /* pad line with spaces upto cursor */
    while (Ep->column > Clen)
	Current[Clen++] = ' ';

    Current[Clen] = '\0';

    return (force);
} /* text_adjust */


/*****************************************************************************

    NAME
	text_load

    PARAMETER
	void

    RETURN
	void

    DESCRIPTION
	Load current line into Current. Current is padded with spaces
	if the cursor is to the left.

******************************************************************************/


void text_load (void)
{
    if (globalflags.Comlinemode)
	return;

    strcpy ((char *)Current, GETTEXT(Ep,Ep->line));

    Clen = strlen ((char *)Current);

    while (Ep->column > Clen)
	Current[Clen++] = ' ';

    Current[Clen] = '\0';
} /* text_load */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_colno (void)
{
    return((int)Ep->column);
} /* text_colno */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_lineno (void)
{
    return((int)Ep->line+1);
} /* text_lineno */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_lines (void)
{
    return((int)Ep->lines);
} /* text_lines */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_cols (void)
{
    return((int)Clen);
} /* text_cols */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_imode (void)
{
    return((int)Ep->config.insertmode);
} /* text_imode */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

int text_tabsize (void)
{
    return((int)Ep->config.tabstop);
} /* text_tabsize */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

UBYTE * text_name (void)
{
    return(Ep->name);
} /* text_name */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

void text_uninit (void)
{
    ED * ep = Ep;

    if (ep)
    {
	markerkill (ep);
	check_stack (ep);

	freelist (ep->list, ep->lines);
	FreeMem (ep->list, ep->maxlines * sizeof(LINE));

	DelAllVarsFromTree((void **)&ep->textvars); /* PATCH_NULL: local vars have to be freed */

	if (ActualBlock.ep == ep)
	{
	    ActualBlock.type = BT_NONE;
	    ActualBlock.ep = NULL;
	}

	Remove ((NODE *)ep);

	if (ep->font)
	{
	    SetFont (ep->win->RPort, ep->win->WScreen->RastPort.Font);
	    CloseFont (ep->font);
	}

	UnLock (ep->dirlock);
	FreeMem (ep, sizeof(ED));

	if (ep = (ED *)GetHead (&DBase))
	{
	    Ep = NULL;

	    switch_ed (ep);

	    text_load ();
	} else
	    Ep = NULL;
    }
} /* text_uninit */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

void text_cursor (int n)
{
    ED	* ep   = Ep;
    RP	* rp   = ep->win->RPort;

    if (Ep->iconmode || Nsu)
	return;

    movetocursor ();
    inversemode (n);

    if (Current[ep->column])
    {
	Text (rp, Current + ep->column, 1);
    } else
    {
	Text (rp, (STRPTR)" ", 1);
    }

    if (n && globalflags.FollowCursor)
	do_makecursorvisible ();

    inversemode (0);

    /* SetBPen (rp, TEXT_BPEN);
    SetWrMsk (rp, -1); */
} /* text_cursor */


/*****************************************************************************

    NAME

    PARAMETER

    RETURN

    DESCRIPTION

******************************************************************************/

void text_position (int col, int row)
{
    ED	* ep	 = Ep;
    WORD  column,
	  line;

    text_sync ();

    column = ep->topcolumn + col;

    if (column > MAXLINELEN-1)
	column = MAXLINELEN-1;

    if (column < 0)
	column = 0;

    line = ep->topline + row;

    if (line >= ep->lines)
	line = ep->lines - 1;

    if (line < 0)
	line = 0;

    ep->column = column;
    ep->line = line;

    text_load ();
    text_adjust (FALSE);
} /* text_position */


/*****************************************************************************

    NAME
	text_displayseg

    PARAMETER
	int start;
	int lines;

    RETURN
	void

    DESCRIPTION

******************************************************************************/

void text_displayseg (int start, int lines)
{
    ED * ep = Ep;

    if (Nsu || ep->iconmode) return;

    if (globalflags.Comlinemode)
    {
	text_redraw_cmdline ();
    } else
    {
	Line   start_line;

	start_line = start + ep->topline;

	redraw_block (TRUE, start_line, ep->topcolumn,
			start_line + lines-1, ep->topcolumn + Columns-1);

	prop_adj ();
    } /* !Comlinemode */
} /* text_displayseg */


/*****************************************************************************

    NAME
	text_redraw_cmdline

    PARAMETER
	void

    RETURN
	void

    DESCRIPTION

******************************************************************************/

void text_redraw_cmdline (void)
{
    RP * rp = Ep->win->RPort;
    int  len;
    int  topline = Ep->line - Ep->topline;

    /* Clear back */
    SetAPen  (rp, TEXT_BPEN);
    SetWrMsk (rp, 0xFF);
    RectFill (rp, Xbase, ROW(topline), Xpixs, Ypixs);

    /* Write text */
    SetAPen (rp, TEXT_FPEN);
    SetBPen (rp, TEXT_BPEN);

    len = Clen - Ep->topcolumn;

    if (len > 0)
    {
	Move (rp, XTbase, ROWT(topline));
	Text (rp, Current + Ep->topcolumn, (len > Columns) ? Columns : len);
    }
} /* text_redraw_cmdline */


/*****************************************************************************

    NAME
	do_redisplay

    PARAMETER
	void

    RETURN
       void

    DESCRIPTION

******************************************************************************/

void do_redisplay (void)
{
    text_adjust (TRUE);
} /* do_redisplay */


/*****************************************************************************

    NAME
	text_redisplay

    PARAMETER
	void

    RETURN
	void

    DESCRIPTION

******************************************************************************/

void text_redisplay (void)
{
    ED * ep = Ep;
    RP * rp = ep->win->RPort;

    if (!Nsu)
    {
	if (!globalflags.Comlinemode)
	{
	    SetAPen (rp, TEXT_BPEN);
	    SetWrMsk (rp, 0xFF);

	    RectFill (rp, Xbase, Ybase, Xpixs, Ypixs);
	}

	text_displayseg (0, Lines);
    }
} /* text_redisplay */


/*****************************************************************************

    NAME
	text_redisplaycurrline

    PARAMETER
	void

    RETURN
	void

    DESCRIPTION
	Redrenders the current line.

******************************************************************************/

void text_redisplaycurrline (void)
{
    ED * ep  = Ep;
    RP * rp  = ep->win->RPort;
    int  row = ep->line - ep->topline;

    if (!Nsu)
    {
	if (globalflags.Comlinemode)
	{
	    text_displayseg (0, Lines);
	} else {
	    SetAPen (rp, TEXT_BPEN);
	    SetWrMsk (rp, 0xFF);
	    RectFill (rp, Xbase, ROW(row), Xpixs, ROW(row+1)-1);

	    redraw_block (TRUE, ep->line, ep->topcolumn, ep->line,
		    ep->topcolumn + Columns - 1);
	}
    }
} /* text_redisplaycurrline */


/*****************************************************************************

    NAME
	text_write

    PARAMETER
	UBYTE * str;

    RETURN
	void

    DESCRIPTION
	Inserts the string str into the text.

******************************************************************************/

void text_write (UBYTE * str)
{
    WORD  len = strlen ((char *)str);
    WORD  i;
    ED	* ep  = Ep;
    RP	* rp  = ep->win->RPort;

    if (Clen + len >= MAXLINELEN-1)
    {
	text_sync ();
	text_load ();
    }

    if (!ep->config.insertmode)
    {
	UWORD line, column_start, column_end;

	if (ep->column + len >= MAXLINELEN-1)
	    goto fail;

	movmem (str, Current + ep->column, len);

	/* clear area */
	line = ep->line - ep->topline;
	column_start = ep->column - ep->topcolumn;
	column_end = column_start + len;

	/* only draw, if we need to (otherwise the screen is refreshed !) */
	if (column_end < Columns)
	{
	    SetAPen (rp, TEXT_BPEN);
	    SetWrMsk (rp, TEXT_MASK);       /* don't write over block */

	    /* clear area */
	    RectFill (rp, COL(column_start), ROW(line),
		    COL(column_end)-1, ROW(line+1)-1);

	    /* refresh block */
	    redraw_block (TRUE, ep->line, ep->column, ep->line,
			    ep->column + len - 1);

	    setpen (ep->line, ep->column);
	}

	if (ep->column + len >= Clen)
	    Clen = ep->column + len;

	Current[Clen] = 0;
    } else
    {
	if (Clen + len >= MAXLINELEN-1)
	    goto fail;

	movmem (Current + ep->column, Current + ep->column + len,
		Clen+1-ep->column);
	movmem (str, Current + ep->column, len);
	Clen += len;

	if (len < Columns - (ep->column - ep->topcolumn))
	{
	    i = ep->line - ep->topline;

	    setpen (ep->line, ep->column);

	    ScrollRaster (rp, -len * Xsize, 0 ,
		COL(ep->column - ep->topcolumn),
		ROW(i),
		Xpixs,
		ROW(i + 1) - 1);

	    if (Ep->win->WLayer->Flags & LAYERREFRESH)
		OptimizedRefresh (Ep);
	}

	/* update block */
	if (ActualBlock.type == BT_NORMAL &&
		(is_inblock (ep->line, ep->column) & BP_INSIDE))
	{
	    ActualBlock.end_column += len;
	}
    }

    i = ep->column;
    redraw_lineseg (Current, ROWT(ep->line - ep->topline), i, i+len);

    ep->column += len;

    if (ep->column - ep->topcolumn >= Columns)
    {
	text_sync ();
	text_adjust (FALSE);
    }

fail:
    if (!globalflags.Comlinemode)
    {
	if (ep->config.wordwrap)
	    do_reformat(0);
	else if (ep->config.autosplit)
	{
	    WORD  thislen;	    /* Length of this line */
//	      WORD  nextlen;	      /* Length of next line */
	    WORD  wordlen;	    /* Length of word */
	    char * ptr;

	    /* Check if we have to break */
	    thislen = strlen ((char *)Current);

	    if (thislen > ep->config.margin && ep->column == thislen)
	    {
		/* Well, lets start.
		   This algorithm is very simple for now. It does work only,
		   when the cursor is the end of the line and copies the last
		   word in the next line.
		*/
		wordlen = thislen - 1;
		ptr = (char *)Current + wordlen;

		while (*ptr != ' ' && wordlen)
		{
		    ptr --;
		    wordlen --;
		}

		/* If we found a space, we are 1 char wrong */
		if (wordlen)
		{
		    /* ptr ++; dead assign */
		    wordlen ++;
		}

		/* Calc. length of last word */
		wordlen = thislen - wordlen;

		/* Do nothing if this word won't fit in the next line */
		if (wordlen < ep->config.margin)
		{
		    /* Set cursor at the beginning of the word,
		       split line there, go down and go to last
		       char in this line. */
		    ep->column -= wordlen;
		    do_split ();
		    do_down ();
		    do_lastcolumn ();
		} /* if does word fit */
	    } /* if "Do we have to split ?" */
	} /* if Autosplit */
    } /* if !Comlinemode */
} /* text_write */


/*****************************************************************************

    NAME
	text_redrawblock

    PARAMETER
	BOOL on;	Turn block on (TRUE) or off (FALSE)

    RETURN
	void

    DESCRIPTION
	Redraw the block.

******************************************************************************/

void text_redrawblock (BOOL on)
{
    ED * saveed = NULL;

    /* if there is a block that belongs to an editor */

    if (ActualBlock.ep)
    {
	/* change the actual editor, if the editor the block is in and the
	   actual one are not the same */

	if (ActualBlock.ep != Ep)
	{
	    saveed = Ep;
	    switch_ed (ActualBlock.ep);
	}

	/* redraw the block */

	displayblock (on);

	/* if we changed the editor, undo it */

	if (saveed)
	    switch_ed (saveed);
    } else if (!on)
    {
	/* if we want to turn the block off, do it here */

	ActualBlock.type = BT_NONE;
    }
} /* text_redrawblock */


/*****************************************************************************

    NAME
	redraw_text

    PARAMETER
	Line start_line;    Line to start with
	Line end_line;	    Line to end in (not included)

    RETURN
	void

    DESCRIPTION
	Redraws some lines of text. Only the start-line is included in the
	update.

******************************************************************************/

void redraw_text (Line start_line, Line end_line)
{
    if (start_line < Ep->topline)
	start_line = Ep->topline;

    if (end_line > Ep->topline + Lines)
	end_line = Ep->topline + Lines;
    if (end_line > Ep->lines)
	end_line = Ep->lines;

    for ( ; start_line < end_line; start_line ++)
	redraw_textline (start_line);
} /* redraw_text */


/*****************************************************************************

    NAME
	redraw_textline

    PARAMETER
	Line line;

    RETURN
	void

    DESCRIPTION
	Redraws one complete lines of text.

    NOTES
	- line must be a valid line from the text.
	- THIS IS A MACRO !

******************************************************************************/


/*****************************************************************************

    NAME
	redraw_textlineseg

    PARAMETER
	Line   line;		The line
	Column start_column;	The column to start in
	Column end_column;	The column to end with (not included)

    RETURN
	void

    DESCRIPTION
	Redraws part of a lines in the text. We redraw all text between
	start_column and end_column including only the former.

    NOTE
	If used to update text that traverses a block-border, the colors
	of the drawn text will be wrong.

******************************************************************************/

void redraw_textlineseg (Line line, Column start_column, Column end_column)
{
    setpen (line, start_column);

    if (line == Ep->line)
	redraw_lineseg (Current, ROWT(line - Ep->topline),
		start_column, end_column);
    else
	redraw_lineseg (GETTEXT(Ep,line), ROWT(line - Ep->topline),
		start_column, end_column);
} /* redraw_textlineseg */


/*****************************************************************************

    NAME
	redraw_lineseg

    PARAMETER
	UBYTE * text;		The contents of the line
	UWORD  y;	       y-position to draw at
	Column	start_column;	The column to start in
	Column	end_column;	The column to end with (not included)

    RETURN
	void

    DESCRIPTION
	Redraws part of a lines in the text. We redraw all text between
	start_column and end_column including only the former.

******************************************************************************/

void redraw_lineseg (UBYTE * text, UWORD y, Column start_column, Column end_column)
{
    RP *   rp	     = Ep->win->RPort;
    int    len;

    if (Nsu) return;

    /* start-column visible ? */

    if (start_column < Ep->topcolumn)
	start_column = Ep->topcolumn;

    /* end-column visible ? */

    if (end_column > Ep->topcolumn + Columns)
	end_column = Ep->topcolumn + Columns;

    /* outside screen ? */

    if (start_column > end_column)
	return;

    /* get length of line beyond the start-column */

    len = strlen (text);

    if (len > end_column)
	len = end_column;

    len -= start_column;

    /* if there is still text ... */

    if (len > 0)
    {
	/* get contents of line at offset */
	text += start_column;

	while (*text == ' ' && len)
	{
	    text ++;
	    len --;
	    start_column ++;
	}

	/* draw any text that is still to draw */

	if (len)
	{
	    /* set gfxcursor */

	    Move (rp, COLT(start_column - Ep->topcolumn), y);

	    /* draw text */

	    Text (rp, text, len);
	}
    }
} /* redraw_lineseg */


/******************************************************************************
*****  ENDE text.c
******************************************************************************/
