home *** CD-ROM | disk | FTP | other *** search
/ Amiga Elysian Archive / AmigaElysianArchive.iso / wp_dtp / xdme1820.lha / XDME / redraw.c < prev    next >
C/C++ Source or Header  |  1993-02-28  |  26KB  |  1,057 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. void redraw_block (Bool force, Line start_line, Column start_column,
  457.            Line end_line, Column end_column)
  458. {
  459.     RP * rp;
  460.     struct RefreshRegion * old,     /* the old block that has to be erased */
  461.              * new,     /* the new block that has to be drawn */
  462.              * update,  /* region where we have to redraw the
  463.                        text */
  464.              * copy;    /* and a copy of old for removing common
  465.                        areas. */
  466.     struct rect new_rect;
  467.  
  468.     D(bug("----> redraw_block\nforce:%ld    start:%3ld/%3ld  end:%3ld/%3ld\n",
  469.         force,
  470.         start_line+1, start_column+1,
  471.         end_line+1, end_column+1 ));
  472.  
  473.     old    = new_region ();
  474.     new    = new_region ();
  475.     update = new_region ();
  476.  
  477.     if (!old || !new || !update)    /* out of memory */
  478.     return;
  479.  
  480.     if (block_ok () && ActualBlock.ep == Ep) /* do this only if there really is a block */
  481.     {
  482.     if (ActualBlock.start_line > ActualBlock.end_line)
  483.     {
  484.         SWAP (ActualBlock.start_line, ActualBlock.end_line);
  485.  
  486.         ActualBlock.flags ^= BF_LINESWAP;
  487.  
  488.         if (    ActualBlock.type == BT_NORMAL ||
  489.             ActualBlock.start_column > ActualBlock.end_column)
  490.         {
  491.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  492.  
  493.         ActualBlock.flags ^= BF_COLUMNSWAP;
  494.         }
  495.     } else if ((ActualBlock.type == BT_VERTICAL ||
  496.         (ActualBlock.start_line == ActualBlock.end_line &&
  497.             ActualBlock.type == BT_NORMAL)) &&
  498.             ActualBlock.start_column > ActualBlock.end_column)
  499.     {
  500.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  501.  
  502.         ActualBlock.flags ^= BF_COLUMNSWAP;
  503.     }
  504.     }
  505.     else    /* no matter what we have to do: it cannot be something that
  506.            has to do with a block. So we just redraw the current area. */
  507.     {
  508. update_only:         /* jump here if we are sure there is no block to draw */
  509.  
  510.     D(bug("Update only\n"));
  511.  
  512.     if (force)
  513.     {
  514.         if (end_line < start_line)
  515.         SWAP(start_line,end_line);
  516.  
  517.         if (end_column < start_column)
  518.         SWAP(start_column,end_column);
  519.  
  520.         AddDrawEvent (update, start_line, start_column,
  521.             end_line, end_column);
  522.  
  523.     }
  524.  
  525.     goto draw;    /* I really don't like goto but I also don't
  526.                want to indent all those mush below :-) */
  527.     }
  528.  
  529.     /* find drawing positions. After this if, the redraw-struct is filled with
  530.        all information to draw the new situation */
  531.     if (force)
  532.     {
  533.     /* here, we must make sure, that start <= end ! */
  534.     if (start_line > end_line)
  535.     {
  536.         SWAP (start_line, end_line);
  537.  
  538.         if (ActualBlock.type == BT_NORMAL)
  539.         SWAP (start_column, end_column);
  540.         else if (ActualBlock.type == BT_VERTICAL &&
  541.                start_column > end_column)
  542.         SWAP (start_column, end_column);
  543.     } else if (((start_line == end_line && ActualBlock.type == BT_NORMAL) ||
  544.            ActualBlock.type == BT_VERTICAL) &&
  545.            start_column > end_column)
  546.         SWAP (start_column, end_column);
  547.  
  548.     /* clip end-line */
  549.     if (end_line >= Ep->lines)
  550.         end_line = Ep->lines-1;
  551.  
  552.     if (globalflags.Comlinemode)
  553.     {
  554.         text_redraw_cmdline ();
  555.         return;
  556.     } else {
  557.         /* clip all areas against the draw-area */
  558.         new_rect.sl = start_line;
  559.         new_rect.el = end_line;
  560.         new_rect.sc = start_column;
  561.         new_rect.ec = end_column;
  562.  
  563.         switch (ActualBlock.type)
  564.         {
  565.         case BT_LINE:
  566.         {
  567.         AddDrawEvent (update, start_line, start_column,
  568.             ActualBlock.start_line - 1, end_column);
  569.         AddDrawEvent (new,
  570.             ActualBlock.start_line, start_column,
  571.             ActualBlock.end_line, end_column);
  572.         AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
  573.             end_line, end_column);
  574.         }
  575.         break;
  576.  
  577.         case BT_VERTICAL:
  578.         {
  579.         /* this is something like this:
  580.  
  581.           +---------------------+
  582.           |       (A)          |
  583.           +-----+-------+-------+
  584.           | (B) |  (C)  |  (D)  |
  585.           +-----+-------+-------+
  586.           |       (E)          |
  587.           +---------------------+
  588.         */
  589.  
  590.         AddDrawEvent (update, start_line, start_column,
  591.             ActualBlock.start_line - 1, end_column);
  592.         AddDrawEvent (update,
  593.             ActualBlock.start_line, start_column,
  594.             ActualBlock.end_line, ActualBlock.start_column - 1);
  595.         AddDrawEvent (new,
  596.             ActualBlock.start_line, ActualBlock.start_column,
  597.             ActualBlock.end_line, ActualBlock.end_column);
  598.         AddDrawEvent (update,
  599.             ActualBlock.start_line, ActualBlock.end_column + 1,
  600.             ActualBlock.end_line, end_column);
  601.         AddDrawEvent (update, ActualBlock.end_line + 1, start_column,
  602.             end_line, end_column);
  603.  
  604.         }
  605.         break;
  606.  
  607.         case BT_NORMAL:
  608.         {
  609.         Column scol, ecol;
  610.         int start_len, end_len;
  611.  
  612.         /* The situation is like this :
  613.  
  614.           +-----------------------+
  615.           |         (A)          |   (A)  The area above the block
  616.           |         +------------+   (B)  The area in the line where
  617.           |  (B)     |     (C)    |        the block starts BEFORE the
  618.           +----------+------------+       block
  619.           |        (D)           |   (C)  The area inside the block in
  620.           +-------------+---------+       the line where the block
  621.           |    (E)      |   (F)   |        begins
  622.           +-------------+      |   (D)  the main body
  623.           |         (G)          |   (E)  the rest of the block in the
  624.           +-----------------------+       last line
  625.                           (F)  the rest of this line
  626.                           (G)  anything below the block
  627.  
  628.         */
  629.  
  630.         start_len = LINELEN(Ep,ActualBlock.start_line);
  631.  
  632.         if (start_len <= ActualBlock.start_column)
  633.             scol = start_len;
  634.         else
  635.             scol = ActualBlock.start_column;
  636.  
  637.         AddDrawEvent (update, start_line, start_column,
  638.             ActualBlock.start_line-1, end_column);
  639.  
  640.         end_len = LINELEN(Ep,ActualBlock.end_line);
  641.  
  642.         if (end_len <= ActualBlock.end_column)
  643.             ecol = end_column;
  644.         else
  645.             ecol = ActualBlock.end_column;
  646.  
  647.         if (ActualBlock.start_line != ActualBlock.end_line)
  648.         {
  649.             /* (B) (C) */
  650.             AddDrawEvent (update,
  651.             ActualBlock.start_line, start_column,
  652.             ActualBlock.start_line, scol-1);
  653.             AddDrawEvent (new,
  654.             ActualBlock.start_line, scol,
  655.             ActualBlock.start_line, end_column);
  656.  
  657.             /* (D) */
  658.             AddDrawEvent (new,
  659.             ActualBlock.start_line+1, start_column,
  660.             ActualBlock.end_line-1, end_column);
  661.  
  662.             /* (E) (F) */
  663.             AddDrawEvent (new,
  664.             ActualBlock.end_line, start_column,
  665.             ActualBlock.end_line, ecol);
  666.             AddDrawEvent (update,
  667.             ActualBlock.end_line, ecol+1,
  668.             ActualBlock.end_line, end_column);
  669.         } else
  670.         {
  671.             AddDrawEvent (update,
  672.             ActualBlock.start_line, start_column,
  673.             ActualBlock.start_line, scol-1);
  674.  
  675.             AddDrawEvent (new,
  676.             ActualBlock.start_line, scol,
  677.             ActualBlock.start_line, ecol);
  678.  
  679.             AddDrawEvent (update,
  680.             ActualBlock.start_line, ecol+1,
  681.             ActualBlock.start_line, end_column);
  682.         }
  683.  
  684.         /* (G) */
  685.         AddDrawEvent (update, ActualBlock.end_line+1, start_column,
  686.             end_line, end_column);
  687.  
  688.         if (start_len <= ActualBlock.start_column)
  689.             start_column = start_len;
  690.  
  691.         if (end_len <= ActualBlock.end_column)
  692.             end_column = end_len;
  693.         }
  694.         break;
  695.         } /* switch */
  696.  
  697.         and_rect_region (update, &new_rect);
  698.         and_rect_region (new, &new_rect);
  699.  
  700.         /* D(bug("Update :\n")); print_region (update);
  701.         D(bug("new :\n")); print_region (new); */
  702.     }
  703.     } else /* force == FALSE */
  704.     {
  705.     Line   top, bottom;
  706.     Column left, right;
  707.  
  708.     D(bug("Flags %ld\n", ActualBlock.flags));
  709.  
  710.     top    = ActualBlock.start_line;
  711.     bottom = ActualBlock.end_line;
  712.     left   = ActualBlock.start_column;
  713.     right  = ActualBlock.end_column;
  714.  
  715.     if (ActualBlock.flags & BF_LINESWAP)
  716.         SWAP (top, bottom);
  717.  
  718.     if (ActualBlock.flags & BF_COLUMNSWAP)
  719.         SWAP (left, right);
  720.  
  721.     if (start_line == -1)   /* find correct start-pos */
  722.     {
  723.         start_line     = top;
  724.         start_column = left;
  725.     } else if (end_line == -1) /* find correct end-pos */
  726.     {
  727.         end_line   = bottom;
  728.         end_column = right;
  729.     }
  730.  
  731.     D(bug("Drawing:   start:%3ld/%3ld  end:%3ld/%3ld\n",
  732.         start_line+1,
  733.         start_column+1,
  734.         end_line+1,
  735.         end_column+1
  736.         ));
  737.     D(bug("(old)      start:%3ld/%3ld  end:%3ld/%3ld\n",
  738.         ActualBlock.start_line+1,
  739.         ActualBlock.start_column+1,
  740.         ActualBlock.end_line+1,
  741.         ActualBlock.end_column+1
  742.         ));
  743.  
  744.     left   = Ep->topcolumn;
  745.     top    = Ep->topline;
  746.     right  = left + Columns - 1;
  747.     bottom = top + Lines - 1;
  748.  
  749.     /* all these routines work basically the same way. First,
  750.        we copy the start- and end-pos. Then we make sure that
  751.        the start-pos is before to end-pos. Now we check if the new
  752.        block is visible.
  753.  
  754.        We have 2 versions of every positions, one normal and one
  755.        clipped against the window-borders.
  756.        The sl/el/sc/ec-coords are the sorted new positions, csl/cel/...
  757.        are the clipped version, the old positions are in ActualBlock.xx
  758.        and the clipped version in osl/sel/...
  759.     */
  760.  
  761.     switch (ActualBlock.type)
  762.     {
  763.     case BT_LINE:
  764.     {
  765.         Line   sl, el;
  766.  
  767.         sl = start_line;
  768.         el = end_line;
  769.  
  770.         if (el < sl)
  771.         SWAP(sl,el);
  772.  
  773.         AddDrawEvent (old, ActualBlock.start_line, left,
  774.             ActualBlock.end_line, right);
  775.         AddDrawEvent (new, sl, left, el, right);
  776.     }
  777.     break;
  778.  
  779.     case BT_NORMAL:
  780.     {
  781.         Line   sl, el;
  782.         Column sc, ec, scol, ecol;
  783.         int    slen, elen;
  784.         USHORT flags;
  785.  
  786.         sl = start_line;
  787.         el = end_line;
  788.         sc = start_column;
  789.         ec = end_column;
  790.  
  791.         flags = 0;
  792.  
  793.         if (el < sl)
  794.         {
  795.         SWAP (sl, el);
  796.         SWAP (sc, ec);
  797.  
  798.         flags |= BF_LINESWAP | BF_COLUMNSWAP;
  799.         } else if (sl == el && ec < sc)
  800.         {
  801.         SWAP (sc, ec);
  802.  
  803.         flags |= BF_COLUMNSWAP;
  804.         }
  805.  
  806.         slen = LINELEN(Ep,ActualBlock.start_line);
  807.  
  808.         if (slen <= ActualBlock.start_column)
  809.         scol = slen;
  810.         else
  811.         scol = ActualBlock.start_column;
  812.  
  813.         elen = LINELEN(Ep,ActualBlock.end_line);
  814.  
  815.         if (elen <= ActualBlock.end_column)
  816.         ecol = right;
  817.         else
  818.         ecol = ActualBlock.end_column;
  819.  
  820.         if (ActualBlock.start_line != ActualBlock.end_line)
  821.         {
  822.         AddDrawEvent (old,
  823.             ActualBlock.start_line, scol,
  824.             ActualBlock.start_line, right);
  825.  
  826.         AddDrawEvent (old,
  827.             ActualBlock.start_line+1, left,
  828.             ActualBlock.end_line-1, right);
  829.  
  830.         AddDrawEvent (old,
  831.             ActualBlock.end_line, left,
  832.             ActualBlock.end_line, ecol);
  833.         }
  834.         else
  835.         AddDrawEvent (old,
  836.             ActualBlock.start_line, scol,
  837.             ActualBlock.start_line, ecol);
  838.  
  839.         slen = LINELEN(Ep,sl);
  840.  
  841.         if (slen <= sc)
  842.         scol = slen;
  843.         else
  844.         scol = sc;
  845.  
  846.         elen = LINELEN(Ep,el);
  847.  
  848.         if (elen <= ec)
  849.         ecol = right;
  850.         else
  851.         ecol = ec;
  852.  
  853.         if (sl != el)
  854.         {
  855.         AddDrawEvent (new, sl, scol, sl, right);
  856.         AddDrawEvent (new, sl+1, left, el-1, right);
  857.         AddDrawEvent (new, el, left, el, ecol);
  858.         }
  859.         else
  860.         AddDrawEvent (new, sl, scol, sl, ecol);
  861.  
  862.         if (slen <= sc)
  863.         sc = slen;
  864.  
  865.         if (elen <= ec)
  866.         ec = elen;
  867.  
  868.         if (flags & BF_COLUMNSWAP)
  869.         SWAP(sc,ec);
  870.  
  871.         start_column = sc;
  872.         end_column     = ec;
  873.     }
  874.     break;
  875.  
  876.     case BT_VERTICAL:
  877.     {
  878.         Line   sl, el;
  879.         Column sc, ec;
  880.  
  881.         /* create sorted coords for new block */
  882.         sl = start_line;
  883.         el = end_line;
  884.         sc = start_column;
  885.         ec = end_column;
  886.  
  887.         if (el < sl) SWAP(sl,el);
  888.         if (ec < sc) SWAP(sc,ec);
  889.  
  890.         AddDrawEvent (old,
  891.             ActualBlock.start_line, ActualBlock.start_column,
  892.             ActualBlock.end_line, ActualBlock.end_column);
  893.         AddDrawEvent (new, sl, sc, el, ec);
  894.  
  895.         /* that's all folx ! */
  896.     }
  897.     break;
  898.     } /* switch (ActualBlock.type) */
  899.  
  900.     copy = copy_region (old);       /* make a copy of the old block */
  901.  
  902.     clip_region (old, new);         /* clear all common areas in old */
  903.     clip_region (new, copy);        /* clear all common areas in new */
  904.  
  905.     dispose_region (copy);          /* free copy */
  906.  
  907.     /* undo swap drawing-positions accordingly to blockflags */
  908.     /* if (ActualBlock.flags & BF_LINESWAP)
  909.         SWAP (start_line, end_line);
  910.  
  911.     if (ActualBlock.flags & BF_COLUMNSWAP)
  912.         SWAP (start_column, end_column); */
  913.  
  914.     D(bug("copy:      start:%3ld/%3ld  end:%3ld/%3ld\n",
  915.         start_line+1,
  916.         start_column+1,
  917.         end_line+1,
  918.         end_column+1
  919.         ));
  920.  
  921.     /* copy new positions */
  922.     ActualBlock.start_line     = start_line;
  923.     ActualBlock.start_column = start_column;
  924.     ActualBlock.end_line     = end_line;
  925.     ActualBlock.end_column     = end_column;
  926.  
  927.     ActualBlock.flags &= ~(BF_LINESWAP | BF_COLUMNSWAP);
  928.  
  929.     /* reset flags */
  930.     if (ActualBlock.start_line > ActualBlock.end_line)
  931.     {
  932.         SWAP (ActualBlock.start_line, ActualBlock.end_line);
  933.  
  934.         ActualBlock.flags |= BF_LINESWAP;
  935.  
  936.         if (ActualBlock.type == BT_NORMAL)
  937.         {
  938.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  939.  
  940.         ActualBlock.flags |= BF_COLUMNSWAP;
  941.         } else if (ActualBlock.type == BT_VERTICAL)
  942.         {
  943.         if (ActualBlock.start_column > ActualBlock.end_column)
  944.         {
  945.             SWAP (ActualBlock.start_column, ActualBlock.end_column);
  946.  
  947.             ActualBlock.flags |= BF_COLUMNSWAP;
  948.         }
  949.         }
  950.     } else if (ActualBlock.start_column > ActualBlock.end_column &&
  951.            (    (ActualBlock.type == BT_VERTICAL) ||
  952.             (ActualBlock.type == BT_NORMAL &&
  953.              ActualBlock.start_line == ActualBlock.end_line)
  954.            )
  955.           )
  956.     {
  957.         SWAP (ActualBlock.start_column, ActualBlock.end_column);
  958.  
  959.         ActualBlock.flags |= BF_COLUMNSWAP;
  960.     }
  961.  
  962.     /* D(bug("NEW:       start:%3ld/%3ld  end:%3ld/%3ld\n",
  963.         ActualBlock.start_line+1,
  964.         ActualBlock.start_column+1,
  965.         ActualBlock.end_line+1,
  966.         ActualBlock.end_column+1
  967.         )); */
  968.  
  969.     D(bug("Flags %ld\n", ActualBlock.flags));
  970.     } /* if (force) */
  971.  
  972. draw:        /* jump here is all DrawEvents are correctly initialized */
  973.  
  974.     /* Are we allowed to draw ? */
  975.     if (!Nsu && !Ep->iconmode)
  976.     {
  977.     /* init rastport */
  978.     rp = Ep->win->RPort;
  979.  
  980.     /* clip the update-region */
  981.     new_rect.sl = Ep->topline;
  982.     new_rect.el = new_rect.sl + Lines - 1;
  983.     new_rect.sc = Ep->topcolumn;
  984.     new_rect.ec = new_rect.sc + Columns - 1;
  985.  
  986.     /* make sure we don't get below the last line */
  987.     if (new_rect.el >= Ep->lines)
  988.         new_rect.el = Ep->lines - 1;
  989.  
  990.     /* clip away everything that exceeds the displayable area */
  991.     and_rect_region (update, &new_rect);
  992.     and_rect_region (old, &new_rect);
  993.     and_rect_region (new, &new_rect);
  994.  
  995.     refresh_region (rp, update, 2);
  996.     refresh_region (rp, old, 0);
  997.     refresh_region (rp, new, 1);
  998.  
  999.     dispose_region (update);
  1000.     dispose_region (old);
  1001.     dispose_region (new);
  1002.     }
  1003. } /* redraw_block */
  1004.  
  1005.  
  1006. void refresh_region (RP * rp, struct RefreshRegion * region, int mode)
  1007. {
  1008.     struct Region * ptr;
  1009.     int t;
  1010.     Line start_line, end_line;
  1011.     Column start_column, end_column;
  1012.  
  1013.     t=0;
  1014.  
  1015.     for (ptr=GetHead(®ion->list); ptr; ptr=GetSucc(&ptr->node))
  1016.     {
  1017.     start_line   = ptr->rect.sl;
  1018.     end_line     = ptr->rect.el;
  1019.     start_column = ptr->rect.sc;
  1020.     end_column   = ptr->rect.ec + 1;
  1021.  
  1022.     D(bug("Draw %ld: %ld (%2ld,%2ld) - (%2ld/%2ld)\n", t ++,
  1023.         mode, start_line+1, start_column+1, end_line+1, end_column+1));
  1024.  
  1025.     if (start_line > end_line ||
  1026.         start_column >= end_column)
  1027.     {
  1028.         D(bug("ERROR !!!!\n"));
  1029.         continue;
  1030.     }
  1031.  
  1032.     if (mode != 2)
  1033.     {
  1034.         if (mode == 1)
  1035.         SetAPen (rp, BLOCK_BPEN);
  1036.         else
  1037.         SetAPen (rp, TEXT_BPEN);
  1038.  
  1039.         SetWrMsk (rp, BLOCK_MASK);
  1040.         SetDrMd (rp, JAM2);
  1041.  
  1042.         RectFill (rp, COL(start_column - Ep->topcolumn),
  1043.             ROW(start_line - Ep->topline),
  1044.             COL(end_column - Ep->topcolumn)-1,
  1045.             ROW(end_line + 1 - Ep->topline)-1 );
  1046.     }
  1047.  
  1048.     for ( ; start_line <= end_line; start_line ++)
  1049.         redraw_textlineseg (start_line, start_column, end_column);
  1050.     }
  1051. } /* refresh_region */
  1052.  
  1053.  
  1054. /******************************************************************************
  1055. *****  ENDE redraw.c
  1056. ******************************************************************************/
  1057.