home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / spmio10.zip / gcc2 / pmio / textwin.cc < prev    next >
C/C++ Source or Header  |  1994-06-21  |  11KB  |  456 lines

  1. #include <stdlib.h>
  2. #include <string.h>
  3.  
  4. #include "textwin.h"
  5.  
  6. class TextWindowAux
  7. {
  8. public:
  9.   static void setdirty (TextWindow *tw, int x, int y);
  10.   static void putc (TextWindow *tw, char c);
  11.   static void linefeed (TextWindow *tw);
  12.   static void carriage_return (TextWindow *tw);
  13.   static int window_position_to_index (const TextWindow *tw, int x, int y);
  14. };
  15.  
  16. inline int TextWindowAux::window_position_to_index (const TextWindow *tw,
  17.                             int x, int y)
  18. {
  19.   const int sx = x + tw->window_x_offset;
  20.   const int sy = y + tw->window_y_offset;
  21.   return sy * tw->screen_width + sx;
  22. }
  23.  
  24. inline void TextWindowAux::setdirty (TextWindow *tw, int x, int y)
  25. {
  26.   const int index = window_position_to_index (tw, x, y);
  27.   if (0 <= index && index < tw->screen_width * tw->screen_height)
  28.     tw->current_dirt[index] = 1;
  29. }
  30.  
  31.  
  32. TextWindow::TextWindow (int init_width, int init_height)
  33. : current_text(0), current_attr(0), current_dirt(0)
  34. {
  35.   set_attr (0xFF);
  36.   set_screen_size (init_width, init_height);
  37. }
  38.  
  39. void TextWindow::set_screen_size (int width, int height)
  40. {
  41.   const int size = width * height;
  42.   if (width <= 0 || height <= 0 || size <= 0)
  43.     return;
  44.   if (current_text)
  45.     free (current_text);
  46.   if (current_attr)
  47.     free (current_attr);
  48.   if (current_dirt)
  49.     free (current_dirt);
  50.   current_text =
  51.     (typeof (current_text)) malloc (sizeof (current_text[0]) * size);
  52.   current_attr =
  53.     (typeof (current_attr)) malloc (sizeof (current_attr[0]) * size);
  54.   current_dirt =
  55.     (typeof (current_dirt)) malloc (sizeof (current_dirt[0]) * size);
  56.   screen_width = width;
  57.   screen_height = height;
  58.   unset_window ();
  59.   clrscr ();
  60. }
  61.  
  62. void TextWindow::set_width (int width)
  63. {
  64.   set_screen_size (width, screen_height);
  65. }
  66.  
  67. void TextWindow::set_height (int height)
  68. {
  69.   set_screen_size (screen_width, height);
  70. }
  71.  
  72. int TextWindow::get_screen_width () const
  73. {
  74.   return screen_width;
  75. }
  76.  
  77. int TextWindow::get_screen_height () const
  78. {
  79.   return screen_height;
  80. }
  81.  
  82. void TextWindow::set_attr (unsigned char attr)
  83. {
  84.   text_attr = attr;
  85. }
  86.  
  87. void TextWindow::set_fg (unsigned char fg_color)
  88. {
  89.   set_attr ((text_attr & 0xF0) | (fg_color & 0x0F));
  90. }
  91.  
  92. void TextWindow::set_bg (unsigned char bg_color)
  93. {
  94.   set_attr ((text_attr & 0x0F) | (bg_color << 4));
  95. }
  96.  
  97. int TextWindow::getx () const
  98. {
  99.   return cx;
  100. }
  101.  
  102. int TextWindow::gety () const
  103. {
  104.   return cy;
  105. }
  106.  
  107. int TextWindow::get_screen_x () const
  108. {
  109.   return window_x_offset + cx;
  110. }
  111.  
  112. int TextWindow::get_screen_y () const
  113. {
  114.   return window_y_offset + cy;
  115. }
  116.  
  117. void TextWindow::gotoxy (int x, int y)
  118. {
  119.   if (0 <= x && x < window_width
  120.       && 0 <= y && y < window_height)
  121.     {
  122.       TextWindowAux::setdirty (this, cx, cy);
  123.       cx = x;
  124.       cy = y;
  125.       TextWindowAux::setdirty (this, cx, cy);
  126.     }
  127. }
  128.  
  129.  
  130. inline void TextWindowAux::putc (TextWindow *tw, char c)
  131. {
  132.   // Calculate the index into the screen array for the current position
  133.   const int cell_index = window_position_to_index (tw, tw->cx, tw->cy);
  134.   // Set the current cell to the requested character
  135.   tw->current_text[cell_index] = c;
  136.   tw->current_attr[cell_index] = tw->text_attr;
  137.   tw->current_dirt[cell_index] = 1;
  138.   // Advance the cursor
  139.   tw->cx++;
  140.   if (tw->cx >= tw->window_width)
  141.     {
  142.       tw->cx = 0;
  143.       linefeed (tw);
  144.     }
  145.   TextWindowAux::setdirty (tw, tw->cx, tw->cy);
  146. }
  147.  
  148. inline void TextWindowAux::linefeed (TextWindow *tw)
  149. {
  150.   tw->cy++;
  151.   if (tw->cy >= tw->window_height)
  152.     {
  153.       tw->cy--;
  154.       tw->scroll_window (1);
  155.     }
  156.   TextWindowAux::setdirty (tw, tw->cx, tw->cy);
  157. }
  158.  
  159. inline void TextWindowAux::carriage_return (TextWindow *tw)
  160. {
  161.   setdirty (tw, tw->cx, tw->cy);
  162.   tw->cx = 0;
  163.   setdirty (tw, tw->cx, tw->cy);
  164. }
  165.  
  166. void TextWindow::put_raw (int len, const char *text)
  167. {
  168.   int i;
  169.   for (i=0; i < len; i++)
  170.     TextWindowAux::putc (this, text[i]);
  171. }
  172.  
  173. void TextWindow::put_tty (int len, const char *text)
  174. {
  175.   int i;
  176.   for (i=0; i < len; i++)
  177.     switch (text[i])
  178.       {
  179.       case '\t':
  180.     put_raw (8 - (cx & 7), "        ");
  181.     break;
  182.       case '\n':
  183.     TextWindowAux::linefeed (this);
  184.     break;
  185.       case '\r':
  186.     TextWindowAux::carriage_return (this);
  187.     break;
  188.       default:
  189.     TextWindowAux::putc (this, text[i]);
  190.       }
  191. }
  192.  
  193. void TextWindow::put_std (int len, const char *text)
  194. {
  195.   int i;
  196.   for (i=0; i < len; i++)
  197.     switch (text[i])
  198.       {
  199.       case '\t':
  200.     put_raw (8 - (cx & 7), "        ");
  201.     break;
  202.       case '\n':
  203.     TextWindowAux::carriage_return (this);
  204.     TextWindowAux::linefeed (this);
  205.     break;
  206.       case '\r':
  207.     TextWindowAux::carriage_return (this);
  208.     break;
  209.       default:
  210.     TextWindowAux::putc (this, text[i]);
  211.       }
  212. }
  213.  
  214. void TextWindow::set_cells (int len, const char *text)
  215. {
  216.   int x = cx;
  217.   int y = cy;
  218.   int i;
  219.   for (i = 0; i < len; i++)
  220.     {
  221.       const int cell_index =
  222.     TextWindowAux::window_position_to_index (this, cx, cy);
  223.       current_text[cell_index] = text[i];
  224.       current_attr[cell_index] = text_attr;
  225.       current_dirt[cell_index] = 1;
  226.       if (++x > window_width)
  227.     {
  228.       x = 0;
  229.       if (++y > window_height)
  230.         return;
  231.     }
  232.     }
  233. }
  234.  
  235. void TextWindow::clrscr ()
  236. {
  237.   gotoxy (0, 0);
  238.   int y;
  239.   for (y=0; y < window_height; y++)
  240.     {
  241.       gotoxy (0, y);
  242.       clreol ();
  243.     }
  244.   gotoxy (0, 0);
  245. }
  246.  
  247. void TextWindow::clreol ()
  248. {
  249.   // Calculate the index into the screen array for the current position
  250.   const int cell_index =
  251.     TextWindowAux::window_position_to_index (this, cx, cy);
  252.   // Calculate the amount of screen to be altered
  253.   const run_length = window_width - cx;
  254.   if (run_length <= 0)
  255.     return;
  256.   // Then alter it
  257.   int i;
  258.   for (i=0; i < run_length; i++)
  259.     {
  260.       int j = i + cell_index;
  261.       current_text[j] = ' ';
  262.       current_attr[j] = text_attr;
  263.       current_dirt[j] = 1;
  264.     }
  265. }
  266.  
  267. void TextWindow::scroll_window (int scroll_distance)
  268. {
  269.   if (scroll_distance == 0)
  270.     return;
  271.               
  272.   // Determines the number of lines involved
  273.   int lines_to_scroll;
  274.   if (scroll_distance > 0)
  275.     lines_to_scroll = window_height - scroll_distance;
  276.   else
  277.     lines_to_scroll = window_height + scroll_distance;
  278.   // If blanking the window is easier, go for it
  279.   if (lines_to_scroll >= window_height)
  280.     {
  281.       clrscr ();
  282.       return;
  283.     }
  284.   // Otherwise, determine how many lines to blank and how many to move
  285.   const int lines_to_blank = window_height - lines_to_scroll;
  286.   const int lines_to_move = lines_to_scroll;
  287.   // Calculate how wide a line is
  288.   const int line_width = window_width;
  289.   // Move the stuff to move
  290.   int line;
  291.   for (line = 0; line < lines_to_move; line++)
  292.     {
  293.       const int source_line = (scroll_distance > 0)
  294.     ? (line + scroll_distance)
  295.       : (lines_to_move - line - 1);
  296.       const int dest_line = source_line - scroll_distance;
  297.       const int source_index =
  298.     TextWindowAux::window_position_to_index (this, 0, source_line);
  299.       const int dest_index =
  300.     TextWindowAux::window_position_to_index (this, 0, dest_line);
  301.       memcpy (current_text + dest_index, current_text + source_index,
  302.           sizeof (current_text[0]) * line_width);
  303.       memcpy (current_attr + dest_index, current_attr + source_index,
  304.           sizeof (current_attr[0]) * line_width);
  305.       memcpy (current_dirt + dest_index, current_dirt + source_index,
  306.           sizeof (current_dirt[0]) * line_width);
  307.     }
  308.   // See if a derived class has provided a faster way of scrolling...
  309.   // if so, we don't have to mark the moved lines as dirty
  310.   int physical_scroll =
  311.     scroll_region_draw (scroll_distance,
  312.             window_x_offset, window_y_offset,
  313.             window_x_offset + window_width - 1,
  314.             window_y_offset + window_height - 1);
  315.   // Blank the new lines
  316.   for (line = 0; line < lines_to_blank; line++)
  317.     {
  318.       if (scroll_distance > 0)
  319.     gotoxy (0, window_height - 1 - line);
  320.       else
  321.     gotoxy (0, line);
  322.       clreol ();
  323.     }
  324.   // Mark the moved lines as dirty
  325.   if (physical_scroll)
  326.     return;
  327.   for (line = 0; line < lines_to_move; line++)
  328.     {
  329.       const int source_line = (scroll_distance > 0)
  330.     ? (line + scroll_distance)
  331.       : (lines_to_move - line - 1);
  332.       const int dest_line = source_line - scroll_distance;
  333.       const int dest_index =
  334.     TextWindowAux::window_position_to_index (this, 0, dest_line);
  335.       memset (current_dirt + dest_index, 1,
  336.           sizeof (current_dirt[0]) * line_width);
  337.     }
  338. }
  339.  
  340. int TextWindow::scroll_region_draw (int, int, int, int, int)
  341. {
  342.   return 0;
  343. }
  344.  
  345. void TextWindow::get_dirt (int y, int *left, int *right)
  346. {
  347.   // Calculate the position in the array of this line
  348.   const int position = y * screen_width;
  349.   // Find the leftmost dirt
  350.   int i;
  351.   for (i = 0; i < screen_width; i++)
  352.     if (current_dirt[position + i])
  353.       break;
  354.   // Give up if no dirt
  355.   if (i >= screen_width)
  356.     {
  357.       *left = -1;
  358.       *right = -1;
  359.       return;
  360.     }
  361.   // Setup the leftmost dirt
  362.   *left = i;
  363.   // Clear dirt while searching for rightmost
  364.   int rightmost = i;
  365.   current_dirt[position + i++] = 0;
  366.   for (; i < screen_width; i++)
  367.     if (current_dirt[position + i])
  368.       {
  369.     rightmost = i;
  370.     current_dirt[position + i] = 0;
  371.       }
  372.   *right = rightmost;
  373. }
  374.  
  375. int TextWindow::repaint_needed ()
  376. {
  377.   int i;
  378.   for (i = 0; i < screen_width * screen_height; i++)
  379.     if (current_dirt[i])
  380.       return 1;
  381.   return 0;
  382. }
  383.  
  384. const char *TextWindow::get_text (int x, int y) const
  385. {
  386.   return current_text + y * screen_width + x;
  387. }
  388.  
  389. const unsigned char *TextWindow::get_attr (int x, int y) const
  390. {
  391.   return current_attr + y * screen_width + x;
  392. }
  393.  
  394. void TextWindow::set_window (int x1, int y1, int x2, int y2)
  395. {
  396.   if (0 <= x1 && x1 < x2 && x2 < screen_width
  397.       && 0 <= y1 && y1 < y2 && y2 < screen_height)
  398.     {
  399.       TextWindowAux::setdirty (this, cx, cy);
  400.       window_width = x2 - x1 + 1;
  401.       window_height = y2 - y1 + 1;
  402.       window_x_offset = x1;
  403.       window_y_offset = y1;
  404.       gotoxy (0, 0);
  405.     }
  406. }
  407.  
  408. void TextWindow::unset_window ()
  409. {
  410.   set_window (0, 0, screen_width-1, screen_height-1);
  411. }
  412.  
  413. typedef struct
  414. {
  415.   int screen_width;
  416.   int screen_height;
  417.   char *text;
  418.   char *attr;
  419. } SaveRecord;
  420.  
  421. void *TextWindow::save_screen_content ()
  422. {
  423.   SaveRecord *saverec = (SaveRecord *) malloc (sizeof (SaveRecord));
  424.   if (saverec == 0)
  425.     return 0;
  426.   saverec->screen_width = screen_width;
  427.   saverec->screen_height = screen_height;
  428.   const int cell_count = screen_width * screen_height;
  429.   saverec->text = (char *) malloc (cell_count);
  430.   saverec->attr = (char *) malloc (cell_count);
  431.   if (saverec->text == 0 || saverec->attr == 0)
  432.     return 0;
  433.   memcpy (saverec->text, current_text, cell_count);
  434.   memcpy (saverec->attr, current_attr, cell_count);
  435.   return saverec;
  436. }
  437.  
  438. void TextWindow::restore_screen_content (void *p)
  439. {
  440.   if (p == 0)
  441.     return;
  442.   SaveRecord * const saverec = (SaveRecord *) p;
  443.   if (saverec->text == 0 || saverec->attr == 0)
  444.     return;
  445.   if (saverec->screen_width != screen_width
  446.       || saverec->screen_height != screen_height)
  447.     return;
  448.   const int cell_count = screen_width * screen_height;
  449.   memcpy (current_text, saverec->text, cell_count);
  450.   memcpy (current_attr, saverec->attr, cell_count);
  451.   free (saverec->text);
  452.   free (saverec->attr);
  453.   free (saverec);
  454.   memset (current_dirt, 1, cell_count);
  455. }
  456.