home *** CD-ROM | disk | FTP | other *** search
- /******************************************************************************
-
- MODUL
- $Id: redraw.c 1.2 1994/09/09 12:31:30 digulla Exp digulla $
-
- DESCRIPTION
- This contains all functionality that is needed to refresh
- part of the display.
-
- $Log: redraw.c $
- * Revision 1.2 1994/09/09 12:31:30 digulla
- * made local functions static
- * added new style Prototypes, DEFCMD and DEFHELP
- *
- * Revision 1.1 1994/08/19 14:03:12 digulla
- * Initial revision
- *
-
- ******************************************************************************/
-
- /**************************************
- Includes
- **************************************/
- #include <defs.h>
- #define MYDEBUG 0
- #include "debug.h"
-
-
- /**************************************
- Globale Variable
- **************************************/
-
-
- /**************************************
- 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
-
- /* 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;
- };
-
-
- /**************************************
- Interne Variable
- **************************************/
-
-
- /**************************************
- Interne Prototypes
- **************************************/
- static struct RefreshRegion * new_region (void);
- static void dispose_region (struct RefreshRegion *);
- static UWORD do_clip (struct MyRegion *, struct rect *);
- static int and_rect_region (struct RefreshRegion *, struct rect *);
- static BOOL add_rect (struct RefreshRegion *, struct rect *);
- static int clear_rect_region (struct RefreshRegion *, struct rect *);
- static void refresh_region (RP *, struct RefreshRegion *, int);
- static void print_region (struct RefreshRegion *);
-
-
- /*****************************************************************************
-
- 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.
-
- ******************************************************************************/
-
- static void print_region (struct RefreshRegion * region)
- {
- struct MyRegion * ptr;
- int t;
-
- for (t=0,ptr=GetHead(®ion->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 */
-
-
- static struct RefreshRegion * new_region (void)
- {
- struct RefreshRegion * new;
-
- if (new = AllocMem (sizeof(struct RefreshRegion), 0))
- {
- NewList ((struct List *)&new->list);
- }
-
- return (new);
- } /* new_region */
-
-
- static void dispose_region (struct RefreshRegion * region)
- {
- struct MyRegion * ptr, * next;
-
- for (ptr=GetHead(®ion->list); ptr; ptr=next)
- {
- next = GetSucc (&ptr->node);
-
- FreeMem (ptr, sizeof(struct MyRegion));
- }
-
- FreeMem (region, sizeof(struct RefreshRegion));
- } /* dispose_region */
-
-
- static 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 */
-
- static int and_rect_region (struct RefreshRegion * region, struct rect * rect)
- {
- struct MyRegion * ptr, * next;
- UWORD status;
-
- for (ptr=GetHead(®ion->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 */
-
- static struct RefreshRegion * copy_region (struct RefreshRegion * region)
- {
- struct MyRegion * ptr;
- struct RefreshRegion * copy;
-
- if (copy = new_region ())
- {
- for (ptr=GetHead(®ion->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 */
-
- static 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 ! */
-
- static 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 *)®ion->list, (struct Node *)&new->node);
- }
-
- return ((BOOL)(new != NULL));
- } /* add_rect */
-
-
- /* adjust regions that none intersects with the rect anymore */
-
- static int clear_rect_region (struct RefreshRegion * region, struct rect * rect)
- {
- struct MyRegion * ptr, * next;
- UWORD status;
-
- for (ptr=GetHead(®ion->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 */
-
-
- static 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 */
-
- static int add_block_draw_events( struct RefreshRegion *region )
- {
- Line sl, el;
-
- sl = el = ActualBlock.start_line;
- AddDrawEvent (region, sl, block_leftcolumn ( sl ), el, block_rightcolumn( el ) );
-
- sl = ActualBlock.start_line + 1;
- el = ActualBlock.end_line - 1;
- AddDrawEvent (region, sl, block_leftcolumn ( sl ), el, block_rightcolumn( el ) );
-
- sl = el = ActualBlock.end_line;
- AddDrawEvent (region, sl, block_leftcolumn ( sl ), el, block_rightcolumn( el ) );
-
- return TRUE; /* Really should check these values some day... */
- }
-
- /*****************************************************************************
-
- 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
- according to the new coordinates (force = FALSE).
-
- NOTES
-
- BUGS
-
- EXAMPLES
-
- SEE ALSO
-
- INTERNALS
-
- HISTORY
- 03. Jan 1978 ada created
-
- ******************************************************************************/
-
- Prototype void redraw_block (BOOL force, Line start_line, Column start_column, Line end_line, Column end_column);
-
- 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;
-
- // ActualBlock.flags = 0; /* Should fail; ActualBlock should be const */
-
- 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 ));
-
- if (GETF_COMLINEMODE(Ep))
- {
- text_redraw_cmdline ();
- return;
- }
-
- old = new_region ();
- new = new_region ();
- update = new_region ();
-
- if (!old || !new || !update) /* out of memory */
- return;
-
- if ( !block_ok () || ActualBlock.ep != Ep) /* no block to worry about */
- {
- 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 :-) */
- }
-
- else /* deal with the block stuff */
- /* find drawing positions. After this if, the redraw-struct is filled with
- all information to draw the new situation */
- if (force)
- {
- short part;
- Line sl, el;
- /* here, we must make sure, that start <= end ! */
- if (start_line > end_line)
- {
- SWAP (start_line, end_line );
- SWAP (start_column, end_column );
- } else if (start_line == end_line &&
- start_column > end_column )
- SWAP (start_column, end_column);
-
- /* clip end-line */
- if (end_line >= Ep->lines)
- end_line = Ep->lines-1;
-
- /* 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;
-
- /* 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
-
- */
- /* region (A) above the block */
- AddDrawEvent (update, start_line, start_column,
- ActualBlock.start_line - 1, end_column);
-
- for ( part=0; part<3; part++ )
- {
- switch (part )
- {
- case 0: sl =
- el = ActualBlock.start_line; break;
- case 1: sl = ActualBlock.start_line + 1;
- el = ActualBlock.end_line - 1; break;
- case 2: sl =
- el = ActualBlock.end_line; break;
- } /* switch(part)
-
- /* left of block */
- AddDrawEvent (update, sl, start_column, el, block_leftcolumn(el)-1 );
-
- /* right of block */
- AddDrawEvent (update, sl, block_rightcolumn(sl) + 1, el, end_column );
- }
- /* region (G) below the block */
- AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
- end_line, end_column);
-
- /* The block itself (C,D,E) */
- add_block_draw_events( new );
-
- 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 */
- {
- /* unhighlight the old block */
- add_block_draw_events( old );
-
- /* update the block coordinates */
- if ( start_line != -1 )
- set_block_start( start_line, start_column );
-
- if ( end_line != -1 )
- set_block_end( end_line, end_column );
-
- /* highlight the new block */
- add_block_draw_events( new );
-
- 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 */
-
- } /* if (force) */
-
- draw: /* jump here is all DrawEvents are correctly initialized */
-
- /* Are we allowed to draw ? */
- if (!Nsu && !GETF_ICONMODE(Ep))
- {
- /* 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 */
-
-
- static 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(®ion->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(Ep));
- else
- SetAPen (rp, TEXT_BPEN(Ep));
-
- SetWrMsk (rp, BLOCK_MASK(Ep));
- 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 );
-
- SetWrMsk (rp, ALL_MASK);
- }
-
- for ( ; start_line <= end_line; start_line ++)
- redraw_textlineseg (start_line, start_column, end_column);
- }
- } /* refresh_region */
-
-
- /******************************************************************************
- ***** ENDE redraw.c
- ******************************************************************************/
-