home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / wp_dtp / xdme1821.lha / XDME / redraw.c < prev    next >
C/C++ Source or Header  |  1993-03-25  |  27KB  |  1,089 lines

  1. /******************************************************************************
  2.  
  3.     MODUL
  4.     redraw.c
  5.  
  6.     DESCRIPTION
  7.     This contains all functionality that is needed to refresh
  8.     part of the display.
  9.  
  10. ******************************************************************************/
  11.  
  12. /**************************************
  13.         Includes
  14. **************************************/
  15. #include <defs.h>
  16. #define MYDEBUG     0
  17. #include "debug.h"
  18.  
  19.  
  20. /**************************************
  21.         Globale Variable
  22. **************************************/
  23. Prototype void     redraw_block        (BOOL, Line, Column, Line, Column);
  24.  
  25.  
  26. /**************************************
  27.       Interne Defines & Strukturen
  28. **************************************/
  29. #define SWAP(a,b)   (void)((a)^=(b),(b)^=(a),(a)^=(b))
  30. #define MIN(a,b)    ((a) <= (b) ? (a) : (b))
  31. #define MAX(a,b)    ((a) >= (b) ? (a) : (b))
  32. #define CLIP(l,m,h) (((m) < (l)) ? (l) : (((m) > (h)) ? (h) : (m)))
  33.  
  34. #define BF_LINESWAP        1L
  35. #define BF_COLUMNSWAP        2L
  36.  
  37.  
  38. /**************************************
  39.         Interne Variable
  40. **************************************/
  41.  
  42.  
  43. /**************************************
  44.        Interne Prototypes
  45. **************************************/
  46.  
  47.  
  48. /*****************************************************************************
  49.  
  50.     NAME
  51.     redraw_block
  52.  
  53.     PARAMETER
  54.     BOOL   force;        Shall I care for the difference between
  55.                 the fields in the ActualBlock or just
  56.                 redraw the block in the limits specified
  57.                 in the parameters ?
  58.     Line   start_line;
  59.     Column start_column;
  60.     Line   end_line;
  61.     Column end_column;
  62.  
  63.     RETURN
  64.     void
  65.  
  66.     DESCRIPTION
  67.     This function draws a block according to the type. The parameter
  68.     force has a special meaning. If it is TRUE, you force a redraw.
  69.     The block is newly drawn. In this case, the lines specify the
  70.     clip-rect of text that is to be redrawn.
  71.         If it is FALSE, the positions specify the new start- and
  72.     end-positions for the block. The routine gurantees that the
  73.     start-position of the block is before the end-position after the
  74.     call. It is valid to call the routine with -1/-1 for one position.
  75.     In this case, you just want to move one position without touching
  76.     the other. The routine also takes care for flipping the block.
  77.  
  78.     NOTES
  79.     - If force is FALSE, you MUST NOT change more than one position at
  80.       a time. You can exchange both and change one, though.
  81.     - The block is only redrawn, if the actual editor is the editor
  82.       with the block and drawing in that editor is ok !
  83.     - After the call, the new positions are written into the ActualBlock-
  84.       struct if force is FALSE. It is guranteed, that the start-position
  85.       is before the end-position, no matter how they were when the routine
  86.       was called.
  87.  
  88. ******************************************************************************/
  89.  
  90. /* We note all areas that need to be drawn/erased in this structure.
  91.  
  92.     (startline<=endline && startcol<=endcol) == TRUE !
  93. */
  94.  
  95. #define NO_INTERSECT        0
  96. #define TOP_CLIP        0x0001
  97. #define BOTTOM_CLIP        0x0010
  98. #define LEFT_CLIP        0x0100
  99. #define RIGHT_CLIP        0x1000
  100. #define TOP_INTERSECT        0x0002
  101. #define BOTTOM_INTERSECT    0x0020
  102. #define LEFT_INTERSECT        0x0200
  103. #define RIGHT_INTERSECT     0x2000
  104.  
  105. #define IS_EMPTY        0
  106. #define NOT_EMPTY        1
  107. #define MEMORY_ERROR        2
  108.  
  109. struct RefreshRegion
  110. {
  111.     MLIST list;     /* linked list of regions */
  112. };
  113.  
  114. struct rect
  115. {
  116.     Line   sl;        /* line where the region starts in */
  117.     Column sc;        /* and the column */
  118.     Line   el;        /* same for end-pos */
  119.     Column ec;
  120. };
  121.  
  122.  
  123. struct Region
  124. {
  125.     MNODE  node;    /* for linking into a list */
  126.     struct rect rect;
  127. };
  128.  
  129.  
  130. struct RefreshRegion * new_region (void);
  131. void dispose_region (struct RefreshRegion *);
  132. USHORT do_clip (struct Region *, struct rect *);
  133. int and_rect_region (struct RefreshRegion *, struct rect *);
  134. BOOL add_rect (struct RefreshRegion *, struct rect *);
  135. int clear_rect_region (struct RefreshRegion *, struct rect *);
  136. void refresh_region (RP *, struct RefreshRegion *, int);
  137. void print_region (struct RefreshRegion *);
  138.  
  139.  
  140. void print_region (struct RefreshRegion * region)
  141. {
  142.     struct Region * ptr;
  143.     int t;
  144.  
  145.     for (t=0,ptr=GetHead(®ion->list); ptr; ptr=GetSucc(&ptr->node),t++)
  146.     {
  147.     D(bug("Node %ld: (%ld/%ld) - (%ld/%ld)\n",
  148.         t, ptr->rect.sl, ptr->rect.sc, ptr->rect.el, ptr->rect.ec));
  149.     }
  150. } /* print_region */
  151.  
  152.  
  153. struct RefreshRegion * new_region (void)
  154. {
  155.     struct RefreshRegion * new;
  156.  
  157.     if (new = AllocMem (sizeof(struct RefreshRegion), 0))
  158.     {
  159.     NewList ((struct List *)&new->list);
  160.     }
  161.  
  162.     return (new);
  163. } /* new_region */
  164.  
  165.  
  166. void dispose_region (struct RefreshRegion * region)
  167. {
  168.     struct Region * ptr, * next;
  169.  
  170.     for (ptr=GetHead(®ion->list); ptr; ptr=next)
  171.     {
  172.     next = GetSucc (&ptr->node);
  173.  
  174.     FreeMem (ptr, sizeof(struct Region));
  175.     }
  176.  
  177.     FreeMem (region, sizeof(struct RefreshRegion));
  178. } /* dispose_region */
  179.  
  180.  
  181. USHORT do_clip (struct Region * region, struct rect * rect)
  182. {
  183.     USHORT test = NO_INTERSECT;
  184.  
  185.     if (!(  (region->rect.sl > rect->el) || (region->rect.el < rect->sl) ||
  186.         (region->rect.sc > rect->ec) || (region->rect.ec < rect->sc) ) )
  187.     {
  188.     if (region->rect.sl < rect->sl)
  189.         test |= TOP_CLIP;
  190.  
  191.     if (region->rect.el > rect->el)
  192.         test |= BOTTOM_CLIP;
  193.  
  194.     if (region->rect.sc < rect->sc)
  195.         test |= LEFT_CLIP;
  196.  
  197.     if (region->rect.ec > rect->ec)
  198.         test |= RIGHT_CLIP;
  199.  
  200.     if (region->rect.sl <= rect->el)
  201.         test |= TOP_INTERSECT;
  202.  
  203.     if (region->rect.el >= rect->sl)
  204.         test |= BOTTOM_INTERSECT;
  205.  
  206.     if (region->rect.sc <= rect->ec)
  207.         test |= LEFT_INTERSECT;
  208.  
  209.     if (region->rect.ec >= rect->sc)
  210.         test |= RIGHT_INTERSECT;
  211.     }
  212.  
  213.     /* D(bug("clip %04lx\n", test)); */
  214.  
  215.     return (test);
  216. } /* do_clip */
  217.  
  218.  
  219. /* clip regions */
  220.  
  221. int and_rect_region (struct RefreshRegion * region, struct rect * rect)
  222. {
  223.     struct Region * ptr, * next;
  224.     USHORT status;
  225.  
  226.     for (ptr=GetHead(®ion->list); ptr; ptr=next)
  227.     {
  228.     USHORT common;
  229.  
  230.     next = GetSucc (&ptr->node);
  231.  
  232.     if ((common = do_clip (ptr, rect)) != NO_INTERSECT)
  233.     {
  234.         if (common & TOP_CLIP)
  235.         ptr->rect.sl = rect->sl;
  236.  
  237.         if (common & BOTTOM_CLIP)
  238.         ptr->rect.el = rect->el;
  239.  
  240.         if (common & LEFT_CLIP)
  241.         ptr->rect.sc = rect->sc;
  242.  
  243.         if (common & RIGHT_CLIP)
  244.         ptr->rect.ec = rect->ec;
  245.     }
  246.     else
  247.     {
  248.         /* if they do not intersect, remove the Region */
  249.  
  250.         Remove ((struct Node *)&ptr->node);
  251.  
  252.         FreeMem (ptr, sizeof(struct Region));
  253.     }
  254.     }
  255.  
  256.     if (!GetHead(region))
  257.     status = IS_EMPTY;
  258.     else
  259.     status = NOT_EMPTY;
  260.  
  261.     return (status);
  262. } /* and_rect_region */
  263.  
  264.  
  265. /* make a copy of a region */
  266.  
  267. struct RefreshRegion * copy_region (struct RefreshRegion * region)
  268. {
  269.     struct Region * ptr;
  270.     struct RefreshRegion * copy;
  271.  
  272.     if (copy = new_region ())
  273.     {
  274.     for (ptr=GetHead(®ion->list); ptr; ptr=GetSucc(&ptr->node))
  275.     {
  276.         if (!(add_rect (copy, &ptr->rect)) )
  277.         {
  278.         dispose_region (copy);
  279.  
  280.         return (NULL);
  281.         }
  282.     }
  283.     }
  284.  
  285.     return (copy);
  286. } /* copy_region */
  287.  
  288.  
  289. /* make erase all common areas between two regions */
  290.  
  291. void clip_region (struct RefreshRegion * region, struct RefreshRegion * clip)
  292. {
  293.     struct Region * ptr;
  294.  
  295.     for (ptr=GetHead(&clip->list); ptr; ptr=GetSucc(&ptr->node))
  296.     {
  297.     clear_rect_region (region, &ptr->rect);
  298.     }
  299. } /* clip_region */
  300.  
  301.  
  302. /* create a new Region and add it to the RefreshRegion. This routine
  303.    must not be called with a rect that intersects with any of the
  304.    Regions that are already in the RefreshRegion ! */
  305.  
  306. BOOL add_rect (struct RefreshRegion * region, struct rect * rect)
  307. {
  308.     struct Region * new;
  309.  
  310.     if (new = AllocMem (sizeof(struct Region), 0))
  311.     {
  312.     movmem (rect, &new->rect, sizeof (struct rect));
  313.  
  314.     /* AddHead because we might be editing the list right now :-) */
  315.     AddHead ((struct List *)®ion->list, (struct Node *)&new->node);
  316.     }
  317.  
  318.     return ((new != NULL));
  319. } /* add_rect */
  320.  
  321.  
  322. /* adjust regions that none intersects with the rect anymore */
  323.  
  324. int clear_rect_region (struct RefreshRegion * region, struct rect * rect)
  325. {
  326.     struct Region * ptr, * next;
  327.     USHORT status;
  328.  
  329.     for (ptr=GetHead(®ion->list); ptr; ptr=next)
  330.     {
  331.     USHORT common;
  332.     struct rect new_rect;
  333.  
  334.     next = GetSucc (&ptr->node);
  335.  
  336.     /* do something only if we have an intersection */
  337.  
  338.     if ((common = do_clip (ptr, rect)) != NO_INTERSECT)
  339.     {
  340.         /* if both intersect, we make sure we don't have any areas left
  341.            that are in two Regions */
  342.  
  343.         if (common & TOP_CLIP)
  344.         {
  345.         /* if we have a TOP_CLIP, there must be some new Region
  346.            above. */
  347.  
  348.         new_rect.sl = ptr->rect.sl;
  349.         new_rect.el = rect->sl - 1;    /* this is the intersection */
  350.         new_rect.sc = ptr->rect.sc;
  351.         new_rect.ec = ptr->rect.ec;
  352.  
  353.         /* is this a valid rect anyway ?? */
  354.         if (new_rect.sl <= new_rect.el)
  355.         {
  356.             if (!add_rect (region, &new_rect))
  357.             return (MEMORY_ERROR);
  358.             else
  359.             ptr->rect.sl = rect->sl;   /* new topline */
  360.         } /* valid rect ? */
  361.         } /* type of intersect */
  362.  
  363.         if (common & BOTTOM_CLIP)
  364.         {
  365.         /* if we have a BOTTOM_CLIP, there must be some new Region
  366.            below. */
  367.  
  368.         new_rect.sl = rect->el + 1;    /* clipping */
  369.         new_rect.el = ptr->rect.el;
  370.         new_rect.sc = ptr->rect.sc;
  371.         new_rect.ec = ptr->rect.ec;
  372.  
  373.         /* is this a valid rect anyway ?? */
  374.         if (new_rect.sl <= new_rect.el)
  375.         {
  376.             if (!add_rect (region, &new_rect))
  377.             return (MEMORY_ERROR);
  378.             else
  379.             ptr->rect.el = rect->el;
  380.         } /* valid rect ? */
  381.         } /* type of intersect */
  382.  
  383.         if (common & LEFT_CLIP)
  384.         {
  385.         /* if we have a LEFT_CLIP, there must be some new Region
  386.            below. */
  387.  
  388.         new_rect.sl = ptr->rect.sl;
  389.         new_rect.el = ptr->rect.el;
  390.         new_rect.sc = ptr->rect.sc;
  391.         new_rect.ec = rect->sc - 1;    /* clipping */
  392.  
  393.         /* is this a valid rect anyway ?? */
  394.         if (new_rect.sc <= new_rect.ec)
  395.         {
  396.             if (!add_rect (region, &new_rect))
  397.             return (MEMORY_ERROR);
  398.  
  399.             /* we do not need any ELSE here since RIGHT_CLIP
  400.                doesn't care about the left border. */
  401.  
  402.         } /* valid rect ? */
  403.         } /* type of intersect */
  404.  
  405.         if (common & RIGHT_CLIP)
  406.         {
  407.         /* if we have a RIGHT_CLIP, there must be some new Region
  408.            below. */
  409.  
  410.         new_rect.sl = ptr->rect.sl;
  411.         new_rect.el = ptr->rect.el;
  412.         new_rect.sc = rect->ec + 1;    /* clipping */
  413.         new_rect.ec = ptr->rect.ec;
  414.  
  415.         /* is this a valid rect anyway ?? */
  416.         if (new_rect.sc <= new_rect.ec)
  417.         {
  418.             if (!add_rect (region, &new_rect))
  419.             return (MEMORY_ERROR);
  420.         } /* valid rect ? */
  421.         } /* type of intersect */
  422.  
  423.         /* remove old area */
  424.         Remove ((struct Node *)&ptr->node);
  425.  
  426.         FreeMem (ptr, sizeof (struct Region));
  427.     } /* intersection */
  428.     }
  429.  
  430.     if (!GetHead(region))
  431.     status = IS_EMPTY;
  432.     else
  433.     status = NOT_EMPTY;
  434.  
  435.     return (status);
  436. } /* clear_rect_region */
  437.  
  438.  
  439. int AddDrawEvent (struct RefreshRegion * region, Line sl, Column sc,
  440.         Line el, Column ec)
  441. {
  442.     struct rect new_rect;
  443.  
  444.     if (el < sl || ec < sc) /* don't add invalid blocks */
  445.     return (TRUE);
  446.  
  447.     new_rect.sl = sl;
  448.     new_rect.el = el;
  449.     new_rect.sc = sc;
  450.     new_rect.ec = ec;
  451.  
  452.     return (add_rect (region, &new_rect));
  453. } /* AddDrawEvent */
  454.  
  455.  
  456. /*****************************************************************************
  457.  
  458.     NAME
  459.     redraw_block
  460.  
  461.     PARAMETER
  462.     BOOL   force;
  463.     Line   start_line;
  464.     Column start_column;
  465.     Line   end_line;
  466.     Column end_column;
  467.  
  468.     RESULT
  469.  
  470.     RETURN
  471.     void
  472.  
  473.     DESCRIPTION
  474.     Draws part of the text (force = TRUE) or adjust the block
  475.     accurding to the new coordinates (force = FALSE).
  476.  
  477.     NOTES
  478.  
  479.     BUGS
  480.  
  481.     EXAMPLES
  482.  
  483.     SEE ALSO
  484.  
  485.     INTERNALS
  486.  
  487.     HISTORY
  488.     03. Jan 1978    ada created
  489.  
  490. ******************************************************************************/
  491.  
  492. void redraw_block (BOOL force, Line start_line, Column start_column,
  493.            Line end_line, Column end_column)
  494. {
  495.     RP * rp;
  496.     struct RefreshRegion * old,     /* the old block that has to be erased */
  497.              * new,     /* the new block that has to be drawn */
  498.              * update,  /* region where we have to redraw the
  499.                        text */
  500.              * copy;    /* and a copy of old for removing common
  501.                        areas. */
  502.     struct rect new_rect;
  503.  
  504.     D(bug("----> redraw_block\nforce:%ld    start:%3ld/%3ld  end:%3ld/%3ld\n",
  505.         force,
  506.         start_line+1, start_column+1,
  507.         end_line+1, end_column+1 ));
  508.  
  509.     old    = new_region ();
  510.     new    = new_region ();
  511.     update = new_region ();
  512.  
  513.     if (!old || !new || !update)    /* out of memory */
  514.     return;
  515.  
  516.     if (block_ok () && ActualBlock.ep == Ep) /* do this only if there really is a block */
  517.     {
  518.     if (ActualBlock.start_line > ActualBlock.end_line)
  519.     {
  520.         SWAP (ActualBlock.start_line, ActualBlock.end_line);
  521.  
  522.         ActualBlock.flags ^= BF_LINESWAP;
  523.  
  524.         if (    ActualBlock.type == BT_NORMAL ||
  525.             ActualBlock.start_column > ActualBlock.end_column)
  526.         {
  527.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  528.  
  529.         ActualBlock.flags ^= BF_COLUMNSWAP;
  530.         }
  531.     } else if ((ActualBlock.type == BT_VERTICAL ||
  532.         (ActualBlock.start_line == ActualBlock.end_line &&
  533.             ActualBlock.type == BT_NORMAL)) &&
  534.             ActualBlock.start_column > ActualBlock.end_column)
  535.     {
  536.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  537.  
  538.         ActualBlock.flags ^= BF_COLUMNSWAP;
  539.     }
  540.     }
  541.     else    /* no matter what we have to do: it cannot be something that
  542.            has to do with a block. So we just redraw the current area. */
  543.     {
  544. update_only:         /* jump here if we are sure there is no block to draw */
  545.  
  546.     D(bug("Update only\n"));
  547.  
  548.     if (end_line < start_line)
  549.         SWAP(start_line,end_line);
  550.  
  551.     if (end_column < start_column)
  552.         SWAP(start_column,end_column);
  553.  
  554.     AddDrawEvent (update, start_line, start_column,
  555.         end_line, end_column);
  556.  
  557.     goto draw;    /* I really don't like goto but I also don't
  558.                want to indent all that crap below :-) */
  559.     }
  560.  
  561.     /* find drawing positions. After this if, the redraw-struct is filled with
  562.        all information to draw the new situation */
  563.     if (force)
  564.     {
  565.     /* here, we must make sure, that start <= end ! */
  566.     if (start_line > end_line)
  567.     {
  568.         SWAP (start_line, end_line);
  569.  
  570.         if (ActualBlock.type == BT_NORMAL)
  571.         SWAP (start_column, end_column);
  572.         else if (ActualBlock.type == BT_VERTICAL &&
  573.                start_column > end_column)
  574.         SWAP (start_column, end_column);
  575.     } else if (((start_line == end_line && ActualBlock.type == BT_NORMAL) ||
  576.            ActualBlock.type == BT_VERTICAL) &&
  577.            start_column > end_column)
  578.         SWAP (start_column, end_column);
  579.  
  580.     /* clip end-line */
  581.     if (end_line >= Ep->lines)
  582.         end_line = Ep->lines-1;
  583.  
  584.     if (globalflags.Comlinemode)
  585.     {
  586.         text_redraw_cmdline ();
  587.         return;
  588.     } else {
  589.         /* clip all areas against the draw-area */
  590.         new_rect.sl = start_line;
  591.         new_rect.el = end_line;
  592.         new_rect.sc = start_column;
  593.         new_rect.ec = end_column;
  594.  
  595.         switch (ActualBlock.type)
  596.         {
  597.         case BT_LINE:
  598.         {
  599.         AddDrawEvent (update, start_line, start_column,
  600.             ActualBlock.start_line - 1, end_column);
  601.         AddDrawEvent (new,
  602.             ActualBlock.start_line, start_column,
  603.             ActualBlock.end_line, end_column);
  604.         AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
  605.             end_line, end_column);
  606.         }
  607.         break;
  608.  
  609.         case BT_VERTICAL:
  610.         {
  611.         /* this is something like this:
  612.  
  613.           +---------------------+
  614.           |       (A)          |
  615.           +-----+-------+-------+
  616.           | (B) |  (C)  |  (D)  |
  617.           +-----+-------+-------+
  618.           |       (E)          |
  619.           +---------------------+
  620.         */
  621.  
  622.         AddDrawEvent (update, start_line, start_column,
  623.             ActualBlock.start_line - 1, end_column);
  624.         AddDrawEvent (update,
  625.             ActualBlock.start_line, start_column,
  626.             ActualBlock.end_line, ActualBlock.start_column - 1);
  627.         AddDrawEvent (new,
  628.             ActualBlock.start_line, ActualBlock.start_column,
  629.             ActualBlock.end_line, ActualBlock.end_column);
  630.         AddDrawEvent (update,
  631.             ActualBlock.start_line, ActualBlock.end_column + 1,
  632.             ActualBlock.end_line, end_column);
  633.         AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
  634.             end_line, end_column);
  635.  
  636.         }
  637.         break;
  638.  
  639.         case BT_NORMAL:
  640.         {
  641.         Column scol, ecol;
  642.         int start_len, end_len;
  643.  
  644.         /* The situation is like this :
  645.  
  646.           +-----------------------+
  647.           |         (A)          |   (A)  The area above the block
  648.           |         +------------+   (B)  The area in the line where
  649.           |  (B)     |     (C)    |        the block starts BEFORE the
  650.           +----------+------------+       block
  651.           |        (D)           |   (C)  The area inside the block in
  652.           +-------------+---------+       the line where the block
  653.           |    (E)      |   (F)   |        begins
  654.           +-------------+      |   (D)  the main body
  655.           |         (G)          |   (E)  the rest of the block in the
  656.           +-----------------------+       last line
  657.                           (F)  the rest of this line
  658.                           (G)  anything below the block
  659.  
  660.         */
  661.  
  662.         start_len = LINELEN(Ep,ActualBlock.start_line);
  663.  
  664.         if (start_len <= ActualBlock.start_column)
  665.             scol = start_len;
  666.         else
  667.             scol = ActualBlock.start_column;
  668.  
  669.         AddDrawEvent (update, start_line, start_column,
  670.             ActualBlock.start_line-1, end_column);
  671.  
  672.         end_len = LINELEN(Ep,ActualBlock.end_line);
  673.  
  674.         if (end_len <= ActualBlock.end_column)
  675.             ecol = end_column;
  676.         else
  677.             ecol = ActualBlock.end_column;
  678.  
  679.         if (ActualBlock.start_line != ActualBlock.end_line)
  680.         {
  681.             /* (B) (C) */
  682.             AddDrawEvent (update,
  683.             ActualBlock.start_line, start_column,
  684.             ActualBlock.start_line, scol-1);
  685.             AddDrawEvent (new,
  686.             ActualBlock.start_line, scol,
  687.             ActualBlock.start_line, end_column);
  688.  
  689.             /* (D) */
  690.             AddDrawEvent (new,
  691.             ActualBlock.start_line+1, start_column,
  692.             ActualBlock.end_line-1, end_column);
  693.  
  694.             /* (E) (F) */
  695.             AddDrawEvent (new,
  696.             ActualBlock.end_line, start_column,
  697.             ActualBlock.end_line, ecol);
  698.             AddDrawEvent (update,
  699.             ActualBlock.end_line, ecol+1,
  700.             ActualBlock.end_line, end_column);
  701.         } else
  702.         {
  703.             AddDrawEvent (update,
  704.             ActualBlock.start_line, start_column,
  705.             ActualBlock.start_line, scol-1);
  706.  
  707.             AddDrawEvent (new,
  708.             ActualBlock.start_line, scol,
  709.             ActualBlock.start_line, ecol);
  710.  
  711.             AddDrawEvent (update,
  712.             ActualBlock.start_line, ecol+1,
  713.             ActualBlock.start_line, end_column);
  714.         }
  715.  
  716.         /* (G) */
  717.         AddDrawEvent (update, ActualBlock.end_line+1, start_column,
  718.             end_line, end_column);
  719.  
  720.         if (start_len <= ActualBlock.start_column)
  721.             start_column = start_len;
  722.  
  723.         if (end_len <= ActualBlock.end_column)
  724.             end_column = end_len;
  725.         }
  726.         break;
  727.         } /* switch */
  728.  
  729.         and_rect_region (update, &new_rect);
  730.         and_rect_region (new, &new_rect);
  731.  
  732.         /* D(bug("Update :\n")); print_region (update);
  733.         D(bug("new :\n")); print_region (new); */
  734.     }
  735.     } else /* force == FALSE */
  736.     {
  737.     Line   top, bottom;
  738.     Column left, right;
  739.  
  740.     D(bug("Flags %ld\n", ActualBlock.flags));
  741.  
  742.     top    = ActualBlock.start_line;
  743.     bottom = ActualBlock.end_line;
  744.     left   = ActualBlock.start_column;
  745.     right  = ActualBlock.end_column;
  746.  
  747.     if (ActualBlock.flags & BF_LINESWAP)
  748.         SWAP (top, bottom);
  749.  
  750.     if (ActualBlock.flags & BF_COLUMNSWAP)
  751.         SWAP (left, right);
  752.  
  753.     if (start_line == -1)   /* find correct start-pos */
  754.     {
  755.         start_line     = top;
  756.         start_column = left;
  757.     } else if (end_line == -1) /* find correct end-pos */
  758.     {
  759.         end_line   = bottom;
  760.         end_column = right;
  761.     }
  762.  
  763.     D(bug("Drawing:   start:%3ld/%3ld  end:%3ld/%3ld\n",
  764.         start_line+1,
  765.         start_column+1,
  766.         end_line+1,
  767.         end_column+1
  768.         ));
  769.     D(bug("(old)      start:%3ld/%3ld  end:%3ld/%3ld\n",
  770.         ActualBlock.start_line+1,
  771.         ActualBlock.start_column+1,
  772.         ActualBlock.end_line+1,
  773.         ActualBlock.end_column+1
  774.         ));
  775.  
  776.     left   = Ep->topcolumn;
  777.     top    = Ep->topline;
  778.     right  = left + Columns - 1;
  779.     bottom = top + Lines - 1;
  780.  
  781.     /* all these routines work basically the same way. First,
  782.        we copy the start- and end-pos. Then we make sure that
  783.        the start-pos is before to end-pos. Now we check if the new
  784.        block is visible.
  785.  
  786.        We have 2 versions of every positions, one normal and one
  787.        clipped against the window-borders.
  788.        The sl/el/sc/ec-coords are the sorted new positions, csl/cel/...
  789.        are the clipped version, the old positions are in ActualBlock.xx
  790.        and the clipped version in osl/sel/...
  791.     */
  792.  
  793.     switch (ActualBlock.type)
  794.     {
  795.     case BT_LINE:
  796.     {
  797.         Line   sl, el;
  798.  
  799.         sl = start_line;
  800.         el = end_line;
  801.  
  802.         if (el < sl)
  803.         SWAP(sl,el);
  804.  
  805.         AddDrawEvent (old, ActualBlock.start_line, left,
  806.             ActualBlock.end_line, right);
  807.         AddDrawEvent (new, sl, left, el, right);
  808.     }
  809.     break;
  810.  
  811.     case BT_NORMAL:
  812.     {
  813.         Line   sl, el;
  814.         Column sc, ec, scol, ecol;
  815.         int    slen, elen;
  816.         USHORT flags;
  817.  
  818.         sl = start_line;
  819.         el = end_line;
  820.         sc = start_column;
  821.         ec = end_column;
  822.  
  823.         flags = 0;
  824.  
  825.         if (el < sl)
  826.         {
  827.         SWAP (sl, el);
  828.         SWAP (sc, ec);
  829.  
  830.         flags |= BF_LINESWAP | BF_COLUMNSWAP;
  831.         } else if (sl == el && ec < sc)
  832.         {
  833.         SWAP (sc, ec);
  834.  
  835.         flags |= BF_COLUMNSWAP;
  836.         }
  837.  
  838.         slen = LINELEN(Ep,ActualBlock.start_line);
  839.  
  840.         if (slen <= ActualBlock.start_column)
  841.         scol = slen;
  842.         else
  843.         scol = ActualBlock.start_column;
  844.  
  845.         elen = LINELEN(Ep,ActualBlock.end_line);
  846.  
  847.         if (elen <= ActualBlock.end_column)
  848.         ecol = right;
  849.         else
  850.         ecol = ActualBlock.end_column;
  851.  
  852.         if (ActualBlock.start_line != ActualBlock.end_line)
  853.         {
  854.         AddDrawEvent (old,
  855.             ActualBlock.start_line, scol,
  856.             ActualBlock.start_line, right);
  857.  
  858.         AddDrawEvent (old,
  859.             ActualBlock.start_line+1, left,
  860.             ActualBlock.end_line-1, right);
  861.  
  862.         AddDrawEvent (old,
  863.             ActualBlock.end_line, left,
  864.             ActualBlock.end_line, ecol);
  865.         }
  866.         else
  867.         AddDrawEvent (old,
  868.             ActualBlock.start_line, scol,
  869.             ActualBlock.start_line, ecol);
  870.  
  871.         slen = LINELEN(Ep,sl);
  872.  
  873.         if (slen <= sc)
  874.         scol = slen;
  875.         else
  876.         scol = sc;
  877.  
  878.         elen = LINELEN(Ep,el);
  879.  
  880.         if (elen <= ec)
  881.         ecol = right;
  882.         else
  883.         ecol = ec;
  884.  
  885.         if (sl != el)
  886.         {
  887.         AddDrawEvent (new, sl, scol, sl, right);
  888.         AddDrawEvent (new, sl+1, left, el-1, right);
  889.         AddDrawEvent (new, el, left, el, ecol);
  890.         }
  891.         else
  892.         AddDrawEvent (new, sl, scol, sl, ecol);
  893.  
  894.         if (slen <= sc)
  895.         sc = slen;
  896.  
  897.         if (elen <= ec)
  898.         ec = elen;
  899.  
  900.         if (flags & BF_COLUMNSWAP)
  901.         SWAP(sc,ec);
  902.  
  903.         start_column = sc;
  904.         end_column     = ec;
  905.     }
  906.     break;
  907.  
  908.     case BT_VERTICAL:
  909.     {
  910.         Line   sl, el;
  911.         Column sc, ec;
  912.  
  913.         /* create sorted coords for new block */
  914.         sl = start_line;
  915.         el = end_line;
  916.         sc = start_column;
  917.         ec = end_column;
  918.  
  919.         if (el < sl) SWAP(sl,el);
  920.         if (ec < sc) SWAP(sc,ec);
  921.  
  922.         AddDrawEvent (old,
  923.             ActualBlock.start_line, ActualBlock.start_column,
  924.             ActualBlock.end_line, ActualBlock.end_column);
  925.         AddDrawEvent (new, sl, sc, el, ec);
  926.  
  927.         /* that's all folx ! */
  928.     }
  929.     break;
  930.     } /* switch (ActualBlock.type) */
  931.  
  932.     copy = copy_region (old);       /* make a copy of the old block */
  933.  
  934.     clip_region (old, new);         /* clear all common areas in old */
  935.     clip_region (new, copy);        /* clear all common areas in new */
  936.  
  937.     dispose_region (copy);          /* free copy */
  938.  
  939.     /* undo swap drawing-positions accordingly to blockflags */
  940.     /* if (ActualBlock.flags & BF_LINESWAP)
  941.         SWAP (start_line, end_line);
  942.  
  943.     if (ActualBlock.flags & BF_COLUMNSWAP)
  944.         SWAP (start_column, end_column); */
  945.  
  946.     D(bug("copy:      start:%3ld/%3ld  end:%3ld/%3ld\n",
  947.         start_line+1,
  948.         start_column+1,
  949.         end_line+1,
  950.         end_column+1
  951.         ));
  952.  
  953.     /* copy new positions */
  954.     ActualBlock.start_line     = start_line;
  955.     ActualBlock.start_column = start_column;
  956.     ActualBlock.end_line     = end_line;
  957.     ActualBlock.end_column     = end_column;
  958.  
  959.     ActualBlock.flags &= ~(BF_LINESWAP | BF_COLUMNSWAP);
  960.  
  961.     /* reset flags */
  962.     if (ActualBlock.start_line > ActualBlock.end_line)
  963.     {
  964.         SWAP (ActualBlock.start_line, ActualBlock.end_line);
  965.  
  966.         ActualBlock.flags |= BF_LINESWAP;
  967.  
  968.         if (ActualBlock.type == BT_NORMAL)
  969.         {
  970.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  971.  
  972.         ActualBlock.flags |= BF_COLUMNSWAP;
  973.         } else if (ActualBlock.type == BT_VERTICAL)
  974.         {
  975.         if (ActualBlock.start_column > ActualBlock.end_column)
  976.         {
  977.             SWAP (ActualBlock.start_column, ActualBlock.end_column);
  978.  
  979.             ActualBlock.flags |= BF_COLUMNSWAP;
  980.         }
  981.         }
  982.     } else if (ActualBlock.start_column > ActualBlock.end_column &&
  983.            (    (ActualBlock.type == BT_VERTICAL) ||
  984.             (ActualBlock.type == BT_NORMAL &&
  985.              ActualBlock.start_line == ActualBlock.end_line)
  986.            )
  987.           )
  988.     {
  989.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  990.  
  991.         ActualBlock.flags |= BF_COLUMNSWAP;
  992.     }
  993.  
  994.     /* D(bug("NEW:       start:%3ld/%3ld  end:%3ld/%3ld\n",
  995.         ActualBlock.start_line+1,
  996.         ActualBlock.start_column+1,
  997.         ActualBlock.end_line+1,
  998.         ActualBlock.end_column+1
  999.         )); */
  1000.  
  1001.     D(bug("Flags %ld\n", ActualBlock.flags));
  1002.     } /* if (force) */
  1003.  
  1004. draw:        /* jump here is all DrawEvents are correctly initialized */
  1005.  
  1006.     /* Are we allowed to draw ? */
  1007.     if (!Nsu && !Ep->iconmode)
  1008.     {
  1009.     /* init rastport */
  1010.     rp = Ep->win->RPort;
  1011.  
  1012.     /* clip the update-region */
  1013.     new_rect.sl = Ep->topline;
  1014.     new_rect.el = new_rect.sl + Lines - 1;
  1015.     new_rect.sc = Ep->topcolumn;
  1016.     new_rect.ec = new_rect.sc + Columns - 1;
  1017.  
  1018.     /* make sure we don't get below the last line */
  1019.     if (new_rect.el >= Ep->lines)
  1020.         new_rect.el = Ep->lines - 1;
  1021.  
  1022.     /* clip away everything that exceeds the displayable area */
  1023.     and_rect_region (update, &new_rect);
  1024.     and_rect_region (old, &new_rect);
  1025.     and_rect_region (new, &new_rect);
  1026.  
  1027.     refresh_region (rp, update, 2);
  1028.     refresh_region (rp, old, 0);
  1029.     refresh_region (rp, new, 1);
  1030.  
  1031.     dispose_region (update);
  1032.     dispose_region (old);
  1033.     dispose_region (new);
  1034.     }
  1035. } /* redraw_block */
  1036.  
  1037.  
  1038. void refresh_region (RP * rp, struct RefreshRegion * region, int mode)
  1039. {
  1040.     struct Region * ptr;
  1041.     int t;
  1042.     Line start_line, end_line;
  1043.     Column start_column, end_column;
  1044.  
  1045.     t=0;
  1046.  
  1047.     for (ptr=GetHead(®ion->list); ptr; ptr=GetSucc(&ptr->node))
  1048.     {
  1049.     start_line   = ptr->rect.sl;
  1050.     end_line     = ptr->rect.el;
  1051.     start_column = ptr->rect.sc;
  1052.     end_column   = ptr->rect.ec + 1;
  1053.  
  1054.     D(bug("Draw %ld: %ld (%2ld,%2ld) - (%2ld/%2ld)\n", t ++,
  1055.         mode, start_line+1, start_column+1, end_line+1, end_column+1));
  1056.  
  1057.     if (start_line > end_line ||
  1058.         start_column >= end_column)
  1059.     {
  1060.         D(bug("ERROR !!!!\n"));
  1061.         continue;
  1062.     }
  1063.  
  1064.     if (mode != 2)
  1065.     {
  1066.         if (mode == 1)
  1067.         SetAPen (rp, BLOCK_BPEN);
  1068.         else
  1069.         SetAPen (rp, TEXT_BPEN);
  1070.  
  1071.         SetWrMsk (rp, BLOCK_MASK);
  1072.         SetDrMd (rp, JAM2);
  1073.  
  1074.         RectFill (rp, COL(start_column - Ep->topcolumn),
  1075.             ROW(start_line - Ep->topline),
  1076.             COL(end_column - Ep->topcolumn)-1,
  1077.             ROW(end_line + 1 - Ep->topline)-1 );
  1078.     }
  1079.  
  1080.     for ( ; start_line <= end_line; start_line ++)
  1081.         redraw_textlineseg (start_line, start_column, end_column);
  1082.     }
  1083. } /* refresh_region */
  1084.  
  1085.  
  1086. /******************************************************************************
  1087. *****  ENDE redraw.c
  1088. ******************************************************************************/
  1089.