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

    MODUL
	redraw.c

    DESCRIPTION
	This contains all functionality that is needed to refresh
	part of the display.

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

/**************************************
		Includes
**************************************/
#include <defs.h>
#define MYDEBUG     0
#include "debug.h"


/**************************************
	    Globale Variable
**************************************/
Prototype void	 redraw_block		(BOOL, Line, Column, Line, Column);


/**************************************
      Interne Defines & Strukturen
**************************************/
#define SWAP(a,b)   (void)((a)^=(b),(b)^=(a),(a)^=(b))
#define MIN(a,b)    ((a) <= (b) ? (a) : (b))
#define MAX(a,b)    ((a) >= (b) ? (a) : (b))
#define CLIP(l,m,h) (((m) < (l)) ? (l) : (((m) > (h)) ? (h) : (m)))

#define BF_LINESWAP	    1L
#define BF_COLUMNSWAP	    2L


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


/**************************************
	   Interne Prototypes
**************************************/


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

    NAME
	redraw_block

    PARAMETER
	BOOL   force;		Shall I care for the difference between
				the fields in the ActualBlock or just
				redraw the block in the limits specified
				in the parameters ?
	Line   start_line;
	Column start_column;
	Line   end_line;
	Column end_column;

    RETURN
	void

    DESCRIPTION
	This function draws a block according to the type. The parameter
	force has a special meaning. If it is TRUE, you force a redraw.
	The block is newly drawn. In this case, the lines specify the
	clip-rect of text that is to be redrawn.
	    If it is FALSE, the positions specify the new start- and
	end-positions for the block. The routine gurantees that the
	start-position of the block is before the end-position after the
	call. It is valid to call the routine with -1/-1 for one position.
	In this case, you just want to move one position without touching
	the other. The routine also takes care for flipping the block.

    NOTES
	- If force is FALSE, you MUST NOT change more than one position at
	  a time. You can exchange both and change one, though.
	- The block is only redrawn, if the actual editor is the editor
	  with the block and drawing in that editor is ok !
	- After the call, the new positions are written into the ActualBlock-
	  struct if force is FALSE. It is guranteed, that the start-position
	  is before the end-position, no matter how they were when the routine
	  was called.

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

/* We note all areas that need to be drawn/erased in this structure.

    (startline<=endline && startcol<=endcol) == TRUE !
*/

#define NO_INTERSECT	    0
#define TOP_CLIP	    0x0001
#define BOTTOM_CLIP	    0x0010
#define LEFT_CLIP	    0x0100
#define RIGHT_CLIP	    0x1000
#define TOP_INTERSECT	    0x0002
#define BOTTOM_INTERSECT    0x0020
#define LEFT_INTERSECT	    0x0200
#define RIGHT_INTERSECT     0x2000

#define IS_EMPTY	    0
#define NOT_EMPTY	    1
#define MEMORY_ERROR	    2

struct RefreshRegion
{
    MLIST list; 	/* linked list of regions */
};

struct rect
{
    Line   sl;		/* line where the region starts in */
    Column sc;		/* and the column */
    Line   el;		/* same for end-pos */
    Column ec;
};


struct MyRegion
{
    MNODE  node;	/* for linking into a list */
    struct rect rect;
};


struct RefreshRegion * new_region (void);
void dispose_region (struct RefreshRegion *);
UWORD do_clip (struct MyRegion *, struct rect *);
int and_rect_region (struct RefreshRegion *, struct rect *);
BOOL add_rect (struct RefreshRegion *, struct rect *);
int clear_rect_region (struct RefreshRegion *, struct rect *);
void refresh_region (RP *, struct RefreshRegion *, int);
void print_region (struct RefreshRegion *);


void print_region (struct RefreshRegion * region)
{
    struct MyRegion * ptr;
    int t;

    for (t=0,ptr=GetHead(&region->list); ptr; ptr=GetSucc(&ptr->node),t++)
    {
	D(bug("Node %ld: (%ld/%ld) - (%ld/%ld)\n",
	    t, ptr->rect.sl, ptr->rect.sc, ptr->rect.el, ptr->rect.ec));
    }
} /* print_region */


struct RefreshRegion * new_region (void)
{
    struct RefreshRegion * new;

    if (new = AllocMem (sizeof(struct RefreshRegion), 0))
    {
	NewList ((struct List *)&new->list);
    }

    return (new);
} /* new_region */


void dispose_region (struct RefreshRegion * region)
{
    struct MyRegion * ptr, * next;

    for (ptr=GetHead(&region->list); ptr; ptr=next)
    {
	next = GetSucc (&ptr->node);

	FreeMem (ptr, sizeof(struct MyRegion));
    }

    FreeMem (region, sizeof(struct RefreshRegion));
} /* dispose_region */


UWORD do_clip (struct MyRegion * region, struct rect * rect)
{
    UWORD test = NO_INTERSECT;

    if (!(  (region->rect.sl > rect->el) || (region->rect.el < rect->sl) ||
	    (region->rect.sc > rect->ec) || (region->rect.ec < rect->sc) ) )
    {
	if (region->rect.sl < rect->sl)
	    test |= TOP_CLIP;

	if (region->rect.el > rect->el)
	    test |= BOTTOM_CLIP;

	if (region->rect.sc < rect->sc)
	    test |= LEFT_CLIP;

	if (region->rect.ec > rect->ec)
	    test |= RIGHT_CLIP;

	if (region->rect.sl <= rect->el)
	    test |= TOP_INTERSECT;

	if (region->rect.el >= rect->sl)
	    test |= BOTTOM_INTERSECT;

	if (region->rect.sc <= rect->ec)
	    test |= LEFT_INTERSECT;

	if (region->rect.ec >= rect->sc)
	    test |= RIGHT_INTERSECT;
    }

    /* D(bug("clip %04lx\n", test)); */

    return (test);
} /* do_clip */


/* clip regions */

int and_rect_region (struct RefreshRegion * region, struct rect * rect)
{
    struct MyRegion * ptr, * next;
    UWORD status;

    for (ptr=GetHead(&region->list); ptr; ptr=next)
    {
	UWORD common;

	next = GetSucc (&ptr->node);

	if ((common = do_clip (ptr, rect)) != NO_INTERSECT)
	{
	    if (common & TOP_CLIP)
		ptr->rect.sl = rect->sl;

	    if (common & BOTTOM_CLIP)
		ptr->rect.el = rect->el;

	    if (common & LEFT_CLIP)
		ptr->rect.sc = rect->sc;

	    if (common & RIGHT_CLIP)
		ptr->rect.ec = rect->ec;
	}
	else
	{
	    /* if they do not intersect, remove the Region */

	    Remove ((struct Node *)&ptr->node);

	    FreeMem (ptr, sizeof(struct MyRegion));
	}
    }

    if (!GetHead(region))
	status = IS_EMPTY;
    else
	status = NOT_EMPTY;

    return (status);
} /* and_rect_region */


/* make a copy of a region */

struct RefreshRegion * copy_region (struct RefreshRegion * region)
{
    struct MyRegion * ptr;
    struct RefreshRegion * copy;

    if (copy = new_region ())
    {
	for (ptr=GetHead(&region->list); ptr; ptr=GetSucc(&ptr->node))
	{
	    if (!(add_rect (copy, &ptr->rect)) )
	    {
		dispose_region (copy);

		return (NULL);
	    }
	}
    }

    return (copy);
} /* copy_region */


/* make erase all common areas between two regions */

void clip_region (struct RefreshRegion * region, struct RefreshRegion * clip)
{
    struct MyRegion * ptr;

    for (ptr=GetHead(&clip->list); ptr; ptr=GetSucc(&ptr->node))
    {
	clear_rect_region (region, &ptr->rect);
    }
} /* clip_region */


/* create a new Region and add it to the RefreshRegion. This routine
   must not be called with a rect that intersects with any of the
   Regions that are already in the RefreshRegion ! */

BOOL add_rect (struct RefreshRegion * region, struct rect * rect)
{
    struct MyRegion * new;

    if (new = AllocMem (sizeof(struct MyRegion), 0))
    {
	movmem (rect, &new->rect, sizeof (struct rect));

	/* AddHead because we might be editing the list right now :-) */
	AddHead ((struct List *)&region->list, (struct Node *)&new->node);
    }

    return ((BOOL)(new != NULL));
} /* add_rect */


/* adjust regions that none intersects with the rect anymore */

int clear_rect_region (struct RefreshRegion * region, struct rect * rect)
{
    struct MyRegion * ptr, * next;
    UWORD status;

    for (ptr=GetHead(&region->list); ptr; ptr=next)
    {
	UWORD common;
	struct rect new_rect;

	next = GetSucc (&ptr->node);

	/* do something only if we have an intersection */

	if ((common = do_clip (ptr, rect)) != NO_INTERSECT)
	{
	    /* if both intersect, we make sure we don't have any areas left
	       that are in two Regions */

	    if (common & TOP_CLIP)
	    {
		/* if we have a TOP_CLIP, there must be some new Region
		   above. */

		new_rect.sl = ptr->rect.sl;
		new_rect.el = rect->sl - 1;    /* this is the intersection */
		new_rect.sc = ptr->rect.sc;
		new_rect.ec = ptr->rect.ec;

		/* is this a valid rect anyway ?? */
		if (new_rect.sl <= new_rect.el)
		{
		    if (!add_rect (region, &new_rect))
			return (MEMORY_ERROR);
		    else
			ptr->rect.sl = rect->sl;   /* new topline */
		} /* valid rect ? */
	    } /* type of intersect */

	    if (common & BOTTOM_CLIP)
	    {
		/* if we have a BOTTOM_CLIP, there must be some new Region
		   below. */

		new_rect.sl = rect->el + 1;    /* clipping */
		new_rect.el = ptr->rect.el;
		new_rect.sc = ptr->rect.sc;
		new_rect.ec = ptr->rect.ec;

		/* is this a valid rect anyway ?? */
		if (new_rect.sl <= new_rect.el)
		{
		    if (!add_rect (region, &new_rect))
			return (MEMORY_ERROR);
		    else
			ptr->rect.el = rect->el;
		} /* valid rect ? */
	    } /* type of intersect */

	    if (common & LEFT_CLIP)
	    {
		/* if we have a LEFT_CLIP, there must be some new Region
		   below. */

		new_rect.sl = ptr->rect.sl;
		new_rect.el = ptr->rect.el;
		new_rect.sc = ptr->rect.sc;
		new_rect.ec = rect->sc - 1;    /* clipping */

		/* is this a valid rect anyway ?? */
		if (new_rect.sc <= new_rect.ec)
		{
		    if (!add_rect (region, &new_rect))
			return (MEMORY_ERROR);

		    /* we do not need any ELSE here since RIGHT_CLIP
		       doesn't care about the left border. */

		} /* valid rect ? */
	    } /* type of intersect */

	    if (common & RIGHT_CLIP)
	    {
		/* if we have a RIGHT_CLIP, there must be some new Region
		   below. */

		new_rect.sl = ptr->rect.sl;
		new_rect.el = ptr->rect.el;
		new_rect.sc = rect->ec + 1;    /* clipping */
		new_rect.ec = ptr->rect.ec;

		/* is this a valid rect anyway ?? */
		if (new_rect.sc <= new_rect.ec)
		{
		    if (!add_rect (region, &new_rect))
			return (MEMORY_ERROR);
		} /* valid rect ? */
	    } /* type of intersect */

	    /* remove old area */
	    Remove ((struct Node *)&ptr->node);

	    FreeMem (ptr, sizeof (struct MyRegion));
	} /* intersection */
    }

    if (!GetHead(region))
	status = IS_EMPTY;
    else
	status = NOT_EMPTY;

    return (status);
} /* clear_rect_region */


int AddDrawEvent (struct RefreshRegion * region, Line sl, Column sc,
	    Line el, Column ec)
{
    struct rect new_rect;

    if (el < sl || ec < sc) /* don't add invalid blocks */
	return (TRUE);

    new_rect.sl = sl;
    new_rect.el = el;
    new_rect.sc = sc;
    new_rect.ec = ec;

    return (add_rect (region, &new_rect));
} /* AddDrawEvent */


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

    NAME
	redraw_block

    PARAMETER
	BOOL   force;
	Line   start_line;
	Column start_column;
	Line   end_line;
	Column end_column;

    RESULT

    RETURN
	void

    DESCRIPTION
	Draws part of the text (force = TRUE) or adjust the block
	accurding to the new coordinates (force = FALSE).

    NOTES

    BUGS

    EXAMPLES

    SEE ALSO

    INTERNALS

    HISTORY
	03. Jan 1978	ada created

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

void redraw_block (BOOL force, Line start_line, Column start_column,
		   Line end_line, Column end_column)
{
    RP * rp;
    struct RefreshRegion * old,     /* the old block that has to be erased */
			 * new,     /* the new block that has to be drawn */
			 * update,  /* region where we have to redraw the
				       text */
			 * copy;    /* and a copy of old for removing common
				       areas. */
    struct rect new_rect;

    D(bug("----> redraw_block\nforce:%ld    start:%3ld/%3ld  end:%3ld/%3ld\n",
	    force,
	    start_line+1, start_column+1,
	    end_line+1, end_column+1 ));

    old    = new_region ();
    new    = new_region ();
    update = new_region ();

    if (!old || !new || !update)    /* out of memory */
	return;

    if (block_ok () && ActualBlock.ep == Ep) /* do this only if there really is a block */
    {
	if (ActualBlock.start_line > ActualBlock.end_line)
	{
	    SWAP (ActualBlock.start_line, ActualBlock.end_line);

	    ActualBlock.flags ^= BF_LINESWAP;

	    if (    ActualBlock.type == BT_NORMAL ||
		    ActualBlock.start_column > ActualBlock.end_column)
	    {
		SWAP (ActualBlock.start_column, ActualBlock.end_column);

		ActualBlock.flags ^= BF_COLUMNSWAP;
	    }
	} else if ((ActualBlock.type == BT_VERTICAL ||
		(ActualBlock.start_line == ActualBlock.end_line &&
		    ActualBlock.type == BT_NORMAL)) &&
		    ActualBlock.start_column > ActualBlock.end_column)
	{
	    SWAP (ActualBlock.start_column, ActualBlock.end_column);

	    ActualBlock.flags ^= BF_COLUMNSWAP;
	}
    }
    else    /* no matter what we have to do: it cannot be something that
	       has to do with a block. So we just redraw the current area. */
    {
update_only:	     /* jump here if we are sure there is no block to draw */

	D(bug("Update only\n"));

	if (end_line < start_line)
	    SWAP(start_line,end_line);

	if (end_column < start_column)
	    SWAP(start_column,end_column);

	AddDrawEvent (update, start_line, start_column,
		end_line, end_column);

	goto draw;	/* I really don't like goto but I also don't
			   want to indent all those mush below :-) */
    }

    /* find drawing positions. After this if, the redraw-struct is filled with
       all information to draw the new situation */
    if (force)
    {
	/* here, we must make sure, that start <= end ! */
	if (start_line > end_line)
	{
	    SWAP (start_line, end_line);

	    if (ActualBlock.type == BT_NORMAL)
		SWAP (start_column, end_column);
	    else if (ActualBlock.type == BT_VERTICAL &&
		       start_column > end_column)
		SWAP (start_column, end_column);
	} else if (((start_line == end_line && ActualBlock.type == BT_NORMAL) ||
		   ActualBlock.type == BT_VERTICAL) &&
		   start_column > end_column)
	    SWAP (start_column, end_column);

	/* clip end-line */
	if (end_line >= Ep->lines)
	    end_line = Ep->lines-1;

	if (globalflags.Comlinemode)
	{
	    text_redraw_cmdline ();
	    return;
	} else {
	    /* clip all areas against the draw-area */
	    new_rect.sl = start_line;
	    new_rect.el = end_line;
	    new_rect.sc = start_column;
	    new_rect.ec = end_column;

	    switch (ActualBlock.type)
	    {
	    case BT_LINE:
	    {
		AddDrawEvent (update, start_line, start_column,
			ActualBlock.start_line - 1, end_column);
		AddDrawEvent (new,
			ActualBlock.start_line, start_column,
			ActualBlock.end_line, end_column);
		AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
			end_line, end_column);
	    }
	    break;

	    case BT_VERTICAL:
	    {
		/* this is something like this:

		  +---------------------+
		  |	   (A)          |
		  +-----+-------+-------+
		  | (B) |  (C)  |  (D)  |
		  +-----+-------+-------+
		  |	   (E)          |
		  +---------------------+
		*/

		AddDrawEvent (update, start_line, start_column,
			ActualBlock.start_line - 1, end_column);
		AddDrawEvent (update,
			ActualBlock.start_line, start_column,
			ActualBlock.end_line, ActualBlock.start_column - 1);
		AddDrawEvent (new,
			ActualBlock.start_line, ActualBlock.start_column,
			ActualBlock.end_line, ActualBlock.end_column);
		AddDrawEvent (update,
			ActualBlock.start_line, ActualBlock.end_column + 1,
			ActualBlock.end_line, end_column);
		AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
			end_line, end_column);

	    }
	    break;

	    case BT_NORMAL:
	    {
		Column scol, ecol;
		int start_len, end_len;

		/* The situation is like this :

		  +-----------------------+
		  |	     (A)          |   (A)  The area above the block
		  |	     +------------+   (B)  The area in the line where
		  |  (B)     |     (C)    |        the block starts BEFORE the
		  +----------+------------+	   block
		  |	    (D)           |   (C)  The area inside the block in
		  +-------------+---------+	   the line where the block
		  |    (E)      |   (F)   |        begins
		  +-------------+	  |   (D)  the main body
		  |	     (G)          |   (E)  the rest of the block in the
		  +-----------------------+	   last line
					      (F)  the rest of this line
					      (G)  anything below the block

		*/

		start_len = LINELEN(Ep,ActualBlock.start_line);

		if (start_len <= ActualBlock.start_column)
		    scol = start_len;
		else
		    scol = ActualBlock.start_column;

		AddDrawEvent (update, start_line, start_column,
			ActualBlock.start_line-1, end_column);

		end_len = LINELEN(Ep,ActualBlock.end_line);

		if (end_len <= ActualBlock.end_column)
		    ecol = end_column;
		else
		    ecol = ActualBlock.end_column;

		if (ActualBlock.start_line != ActualBlock.end_line)
		{
		    /* (B) (C) */
		    AddDrawEvent (update,
			ActualBlock.start_line, start_column,
			ActualBlock.start_line, scol-1);
		    AddDrawEvent (new,
			ActualBlock.start_line, scol,
			ActualBlock.start_line, end_column);

		    /* (D) */
		    AddDrawEvent (new,
			ActualBlock.start_line+1, start_column,
			ActualBlock.end_line-1, end_column);

		    /* (E) (F) */
		    AddDrawEvent (new,
			ActualBlock.end_line, start_column,
			ActualBlock.end_line, ecol);
		    AddDrawEvent (update,
			ActualBlock.end_line, ecol+1,
			ActualBlock.end_line, end_column);
		} else
		{
		    AddDrawEvent (update,
			ActualBlock.start_line, start_column,
			ActualBlock.start_line, scol-1);

		    AddDrawEvent (new,
			ActualBlock.start_line, scol,
			ActualBlock.start_line, ecol);

		    AddDrawEvent (update,
			ActualBlock.start_line, ecol+1,
			ActualBlock.start_line, end_column);
		}

		/* (G) */
		AddDrawEvent (update, ActualBlock.end_line+1, start_column,
			end_line, end_column);

		/* if (start_len <= ActualBlock.start_column)
		    start_column = start_len;

		if (end_len <= ActualBlock.end_column)
		    end_column = end_len; dead assign */
	    }
	    break;
	    } /* switch */

	    and_rect_region (update, &new_rect);
	    and_rect_region (new, &new_rect);

	    /* D(bug("Update :\n")); print_region (update);
	    D(bug("new :\n")); print_region (new); */
	}
    } else /* force == FALSE */
    {
	Line   top, bottom;
	Column left, right;

	D(bug("Flags %ld\n", ActualBlock.flags));

	top    = ActualBlock.start_line;
	bottom = ActualBlock.end_line;
	left   = ActualBlock.start_column;
	right  = ActualBlock.end_column;

	if (ActualBlock.flags & BF_LINESWAP)
	    SWAP (top, bottom);

	if (ActualBlock.flags & BF_COLUMNSWAP)
	    SWAP (left, right);

	if (start_line == -1)   /* find correct start-pos */
	{
	    start_line	 = top;
	    start_column = left;
	} else if (end_line == -1) /* find correct end-pos */
	{
	    end_line   = bottom;
	    end_column = right;
	}

	D(bug("Drawing:   start:%3ld/%3ld  end:%3ld/%3ld\n",
	    start_line+1,
	    start_column+1,
	    end_line+1,
	    end_column+1
	    ));
	D(bug("(old)      start:%3ld/%3ld  end:%3ld/%3ld\n",
	    ActualBlock.start_line+1,
	    ActualBlock.start_column+1,
	    ActualBlock.end_line+1,
	    ActualBlock.end_column+1
	    ));

	left   = Ep->topcolumn;
	/* top	  = Ep->topline; dead assign */
	right  = left + Columns - 1;
	/* bottom = top + Lines - 1; dead assign */

	/* all these routines work basically the same way. First,
	   we copy the start- and end-pos. Then we make sure that
	   the start-pos is before to end-pos. Now we check if the new
	   block is visible.

	   We have 2 versions of every positions, one normal and one
	   clipped against the window-borders.
	   The sl/el/sc/ec-coords are the sorted new positions, csl/cel/...
	   are the clipped version, the old positions are in ActualBlock.xx
	   and the clipped version in osl/sel/...
	*/

	switch (ActualBlock.type)
	{
	case BT_LINE:
	{
	    Line   sl, el;

	    sl = start_line;
	    el = end_line;

	    if (el < sl)
		SWAP(sl,el);

	    AddDrawEvent (old, ActualBlock.start_line, left,
		    ActualBlock.end_line, right);
	    AddDrawEvent (new, sl, left, el, right);
	}
	break;

	case BT_NORMAL:
	{
	    Line   sl, el;
	    Column sc, ec, scol, ecol;
	    int    slen, elen;
	    UWORD  flags;

	    sl = start_line;
	    el = end_line;
	    sc = start_column;
	    ec = end_column;

	    flags = 0;

	    if (el < sl)
	    {
		SWAP (sl, el);
		SWAP (sc, ec);

		flags |= BF_LINESWAP | BF_COLUMNSWAP;
	    } else if (sl == el && ec < sc)
	    {
		SWAP (sc, ec);

		flags |= BF_COLUMNSWAP;
	    }

	    slen = LINELEN(Ep,ActualBlock.start_line);

	    if (slen <= ActualBlock.start_column)
		scol = slen;
	    else
		scol = ActualBlock.start_column;

	    elen = LINELEN(Ep,ActualBlock.end_line);

	    if (elen <= ActualBlock.end_column)
		ecol = right;
	    else
		ecol = ActualBlock.end_column;

	    if (ActualBlock.start_line != ActualBlock.end_line)
	    {
		AddDrawEvent (old,
		    ActualBlock.start_line, scol,
		    ActualBlock.start_line, right);

		AddDrawEvent (old,
		    ActualBlock.start_line+1, left,
		    ActualBlock.end_line-1, right);

		AddDrawEvent (old,
		    ActualBlock.end_line, left,
		    ActualBlock.end_line, ecol);
	    }
	    else
		AddDrawEvent (old,
		    ActualBlock.start_line, scol,
		    ActualBlock.start_line, ecol);

	    slen = LINELEN(Ep,sl);

	    if (slen <= sc)
		scol = slen;
	    else
		scol = sc;

	    elen = LINELEN(Ep,el);

	    if (elen <= ec)
		ecol = right;
	    else
		ecol = ec;

	    if (sl != el)
	    {
		AddDrawEvent (new, sl, scol, sl, right);
		AddDrawEvent (new, sl+1, left, el-1, right);
		AddDrawEvent (new, el, left, el, ecol);
	    }
	    else
		AddDrawEvent (new, sl, scol, sl, ecol);

	    if (slen <= sc)
		sc = slen;

	    if (elen <= ec)
		ec = elen;

	    if (flags & BF_COLUMNSWAP)
		SWAP(sc,ec);

	    start_column = sc;
	    end_column	 = ec;
	}
	break;

	case BT_VERTICAL:
	{
	    Line   sl, el;
	    Column sc, ec;

	    /* create sorted coords for new block */
	    sl = start_line;
	    el = end_line;
	    sc = start_column;
	    ec = end_column;

	    if (el < sl) SWAP(sl,el);
	    if (ec < sc) SWAP(sc,ec);

	    AddDrawEvent (old,
		    ActualBlock.start_line, ActualBlock.start_column,
		    ActualBlock.end_line, ActualBlock.end_column);
	    AddDrawEvent (new, sl, sc, el, ec);

	    /* that's all folx ! */
	}
	break;
	} /* switch (ActualBlock.type) */

	copy = copy_region (old);       /* make a copy of the old block */

	clip_region (old, new);         /* clear all common areas in old */
	clip_region (new, copy);        /* clear all common areas in new */

	dispose_region (copy);          /* free copy */

	/* undo swap drawing-positions accordingly to blockflags */
	/* if (ActualBlock.flags & BF_LINESWAP)
	    SWAP (start_line, end_line);

	if (ActualBlock.flags & BF_COLUMNSWAP)
	    SWAP (start_column, end_column); */

	D(bug("copy:      start:%3ld/%3ld  end:%3ld/%3ld\n",
	    start_line+1,
	    start_column+1,
	    end_line+1,
	    end_column+1
	    ));

	/* copy new positions */
	ActualBlock.start_line	 = start_line;
	ActualBlock.start_column = start_column;
	ActualBlock.end_line	 = end_line;
	ActualBlock.end_column	 = end_column;

	ActualBlock.flags &= ~(BF_LINESWAP | BF_COLUMNSWAP);

	/* reset flags */
	if (ActualBlock.start_line > ActualBlock.end_line)
	{
	    SWAP (ActualBlock.start_line, ActualBlock.end_line);

	    ActualBlock.flags |= BF_LINESWAP;

	    if (ActualBlock.type == BT_NORMAL)
	    {
		SWAP (ActualBlock.start_column, ActualBlock.end_column);

		ActualBlock.flags |= BF_COLUMNSWAP;
	    } else if (ActualBlock.type == BT_VERTICAL)
	    {
		if (ActualBlock.start_column > ActualBlock.end_column)
		{
		    SWAP (ActualBlock.start_column, ActualBlock.end_column);

		    ActualBlock.flags |= BF_COLUMNSWAP;
		}
	    }
	} else if (ActualBlock.start_column > ActualBlock.end_column &&
		   (    (ActualBlock.type == BT_VERTICAL) ||
			(ActualBlock.type == BT_NORMAL &&
			 ActualBlock.start_line == ActualBlock.end_line)
		   )
		  )
	{
	    SWAP (ActualBlock.start_column, ActualBlock.end_column);

	    ActualBlock.flags |= BF_COLUMNSWAP;
	}

	/* D(bug("NEW:       start:%3ld/%3ld  end:%3ld/%3ld\n",
	    ActualBlock.start_line+1,
	    ActualBlock.start_column+1,
	    ActualBlock.end_line+1,
	    ActualBlock.end_column+1
	    )); */

	D(bug("Flags %ld\n", ActualBlock.flags));
    } /* if (force) */

draw:	    /* jump here is all DrawEvents are correctly initialized */

    /* Are we allowed to draw ? */
    if (!Nsu && !Ep->iconmode)
    {
	/* init rastport */
	rp = Ep->win->RPort;

	/* clip the update-region */
	new_rect.sl = Ep->topline;
	new_rect.el = new_rect.sl + Lines - 1;
	new_rect.sc = Ep->topcolumn;
	new_rect.ec = new_rect.sc + Columns - 1;

	/* make sure we don't get below the last line */
	if (new_rect.el >= Ep->lines)
	    new_rect.el = Ep->lines - 1;

	/* clip away everything that exceeds the displayable area */
	and_rect_region (update, &new_rect);
	and_rect_region (old, &new_rect);
	and_rect_region (new, &new_rect);

	refresh_region (rp, update, 2);
	refresh_region (rp, old, 0);
	refresh_region (rp, new, 1);

	dispose_region (update);
	dispose_region (old);
	dispose_region (new);
    }
} /* redraw_block */


void refresh_region (RP * rp, struct RefreshRegion * region, int mode)
{
    struct MyRegion * ptr;
    Line start_line, end_line;
    Column start_column, end_column;
    D(int t=0);

    for (ptr=GetHead(&region->list); ptr; ptr=GetSucc(&ptr->node))
    {
	start_line   = ptr->rect.sl;
	end_line     = ptr->rect.el;
	start_column = ptr->rect.sc;
	end_column   = ptr->rect.ec + 1;

	D(bug("Draw %ld: %ld (%2ld,%2ld) - (%2ld/%2ld)\n", t ++,
	    mode, start_line+1, start_column+1, end_line+1, end_column+1));

	if (start_line > end_line ||
	    start_column >= end_column)
	{
	    D(bug("ERROR !!!!\n"));
	    continue;
	}

	if (mode != 2)
	{
	    if (mode == 1)
		SetAPen (rp, BLOCK_BPEN);
	    else
		SetAPen (rp, TEXT_BPEN);

	    SetWrMsk (rp, BLOCK_MASK);
	    SetDrMd (rp, JAM2);

	    RectFill (rp, COL(start_column - Ep->topcolumn),
			ROW(start_line - Ep->topline),
			COL(end_column - Ep->topcolumn)-1,
			ROW(end_line + 1 - Ep->topline)-1 );
	}

	for ( ; start_line <= end_line; start_line ++)
	    redraw_textlineseg (start_line, start_column, end_column);
    }
} /* refresh_region */


/******************************************************************************
*****  ENDE redraw.c
******************************************************************************/
