home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 22 gnu
/
22-gnu.zip
/
spmio10.zip
/
gcc2
/
pmio
/
textwin.cc
< prev
next >
Wrap
C/C++ Source or Header
|
1994-06-21
|
11KB
|
456 lines
#include <stdlib.h>
#include <string.h>
#include "textwin.h"
class TextWindowAux
{
public:
static void setdirty (TextWindow *tw, int x, int y);
static void putc (TextWindow *tw, char c);
static void linefeed (TextWindow *tw);
static void carriage_return (TextWindow *tw);
static int window_position_to_index (const TextWindow *tw, int x, int y);
};
inline int TextWindowAux::window_position_to_index (const TextWindow *tw,
int x, int y)
{
const int sx = x + tw->window_x_offset;
const int sy = y + tw->window_y_offset;
return sy * tw->screen_width + sx;
}
inline void TextWindowAux::setdirty (TextWindow *tw, int x, int y)
{
const int index = window_position_to_index (tw, x, y);
if (0 <= index && index < tw->screen_width * tw->screen_height)
tw->current_dirt[index] = 1;
}
TextWindow::TextWindow (int init_width, int init_height)
: current_text(0), current_attr(0), current_dirt(0)
{
set_attr (0xFF);
set_screen_size (init_width, init_height);
}
void TextWindow::set_screen_size (int width, int height)
{
const int size = width * height;
if (width <= 0 || height <= 0 || size <= 0)
return;
if (current_text)
free (current_text);
if (current_attr)
free (current_attr);
if (current_dirt)
free (current_dirt);
current_text =
(typeof (current_text)) malloc (sizeof (current_text[0]) * size);
current_attr =
(typeof (current_attr)) malloc (sizeof (current_attr[0]) * size);
current_dirt =
(typeof (current_dirt)) malloc (sizeof (current_dirt[0]) * size);
screen_width = width;
screen_height = height;
unset_window ();
clrscr ();
}
void TextWindow::set_width (int width)
{
set_screen_size (width, screen_height);
}
void TextWindow::set_height (int height)
{
set_screen_size (screen_width, height);
}
int TextWindow::get_screen_width () const
{
return screen_width;
}
int TextWindow::get_screen_height () const
{
return screen_height;
}
void TextWindow::set_attr (unsigned char attr)
{
text_attr = attr;
}
void TextWindow::set_fg (unsigned char fg_color)
{
set_attr ((text_attr & 0xF0) | (fg_color & 0x0F));
}
void TextWindow::set_bg (unsigned char bg_color)
{
set_attr ((text_attr & 0x0F) | (bg_color << 4));
}
int TextWindow::getx () const
{
return cx;
}
int TextWindow::gety () const
{
return cy;
}
int TextWindow::get_screen_x () const
{
return window_x_offset + cx;
}
int TextWindow::get_screen_y () const
{
return window_y_offset + cy;
}
void TextWindow::gotoxy (int x, int y)
{
if (0 <= x && x < window_width
&& 0 <= y && y < window_height)
{
TextWindowAux::setdirty (this, cx, cy);
cx = x;
cy = y;
TextWindowAux::setdirty (this, cx, cy);
}
}
inline void TextWindowAux::putc (TextWindow *tw, char c)
{
// Calculate the index into the screen array for the current position
const int cell_index = window_position_to_index (tw, tw->cx, tw->cy);
// Set the current cell to the requested character
tw->current_text[cell_index] = c;
tw->current_attr[cell_index] = tw->text_attr;
tw->current_dirt[cell_index] = 1;
// Advance the cursor
tw->cx++;
if (tw->cx >= tw->window_width)
{
tw->cx = 0;
linefeed (tw);
}
TextWindowAux::setdirty (tw, tw->cx, tw->cy);
}
inline void TextWindowAux::linefeed (TextWindow *tw)
{
tw->cy++;
if (tw->cy >= tw->window_height)
{
tw->cy--;
tw->scroll_window (1);
}
TextWindowAux::setdirty (tw, tw->cx, tw->cy);
}
inline void TextWindowAux::carriage_return (TextWindow *tw)
{
setdirty (tw, tw->cx, tw->cy);
tw->cx = 0;
setdirty (tw, tw->cx, tw->cy);
}
void TextWindow::put_raw (int len, const char *text)
{
int i;
for (i=0; i < len; i++)
TextWindowAux::putc (this, text[i]);
}
void TextWindow::put_tty (int len, const char *text)
{
int i;
for (i=0; i < len; i++)
switch (text[i])
{
case '\t':
put_raw (8 - (cx & 7), " ");
break;
case '\n':
TextWindowAux::linefeed (this);
break;
case '\r':
TextWindowAux::carriage_return (this);
break;
default:
TextWindowAux::putc (this, text[i]);
}
}
void TextWindow::put_std (int len, const char *text)
{
int i;
for (i=0; i < len; i++)
switch (text[i])
{
case '\t':
put_raw (8 - (cx & 7), " ");
break;
case '\n':
TextWindowAux::carriage_return (this);
TextWindowAux::linefeed (this);
break;
case '\r':
TextWindowAux::carriage_return (this);
break;
default:
TextWindowAux::putc (this, text[i]);
}
}
void TextWindow::set_cells (int len, const char *text)
{
int x = cx;
int y = cy;
int i;
for (i = 0; i < len; i++)
{
const int cell_index =
TextWindowAux::window_position_to_index (this, cx, cy);
current_text[cell_index] = text[i];
current_attr[cell_index] = text_attr;
current_dirt[cell_index] = 1;
if (++x > window_width)
{
x = 0;
if (++y > window_height)
return;
}
}
}
void TextWindow::clrscr ()
{
gotoxy (0, 0);
int y;
for (y=0; y < window_height; y++)
{
gotoxy (0, y);
clreol ();
}
gotoxy (0, 0);
}
void TextWindow::clreol ()
{
// Calculate the index into the screen array for the current position
const int cell_index =
TextWindowAux::window_position_to_index (this, cx, cy);
// Calculate the amount of screen to be altered
const run_length = window_width - cx;
if (run_length <= 0)
return;
// Then alter it
int i;
for (i=0; i < run_length; i++)
{
int j = i + cell_index;
current_text[j] = ' ';
current_attr[j] = text_attr;
current_dirt[j] = 1;
}
}
void TextWindow::scroll_window (int scroll_distance)
{
if (scroll_distance == 0)
return;
// Determines the number of lines involved
int lines_to_scroll;
if (scroll_distance > 0)
lines_to_scroll = window_height - scroll_distance;
else
lines_to_scroll = window_height + scroll_distance;
// If blanking the window is easier, go for it
if (lines_to_scroll >= window_height)
{
clrscr ();
return;
}
// Otherwise, determine how many lines to blank and how many to move
const int lines_to_blank = window_height - lines_to_scroll;
const int lines_to_move = lines_to_scroll;
// Calculate how wide a line is
const int line_width = window_width;
// Move the stuff to move
int line;
for (line = 0; line < lines_to_move; line++)
{
const int source_line = (scroll_distance > 0)
? (line + scroll_distance)
: (lines_to_move - line - 1);
const int dest_line = source_line - scroll_distance;
const int source_index =
TextWindowAux::window_position_to_index (this, 0, source_line);
const int dest_index =
TextWindowAux::window_position_to_index (this, 0, dest_line);
memcpy (current_text + dest_index, current_text + source_index,
sizeof (current_text[0]) * line_width);
memcpy (current_attr + dest_index, current_attr + source_index,
sizeof (current_attr[0]) * line_width);
memcpy (current_dirt + dest_index, current_dirt + source_index,
sizeof (current_dirt[0]) * line_width);
}
// See if a derived class has provided a faster way of scrolling...
// if so, we don't have to mark the moved lines as dirty
int physical_scroll =
scroll_region_draw (scroll_distance,
window_x_offset, window_y_offset,
window_x_offset + window_width - 1,
window_y_offset + window_height - 1);
// Blank the new lines
for (line = 0; line < lines_to_blank; line++)
{
if (scroll_distance > 0)
gotoxy (0, window_height - 1 - line);
else
gotoxy (0, line);
clreol ();
}
// Mark the moved lines as dirty
if (physical_scroll)
return;
for (line = 0; line < lines_to_move; line++)
{
const int source_line = (scroll_distance > 0)
? (line + scroll_distance)
: (lines_to_move - line - 1);
const int dest_line = source_line - scroll_distance;
const int dest_index =
TextWindowAux::window_position_to_index (this, 0, dest_line);
memset (current_dirt + dest_index, 1,
sizeof (current_dirt[0]) * line_width);
}
}
int TextWindow::scroll_region_draw (int, int, int, int, int)
{
return 0;
}
void TextWindow::get_dirt (int y, int *left, int *right)
{
// Calculate the position in the array of this line
const int position = y * screen_width;
// Find the leftmost dirt
int i;
for (i = 0; i < screen_width; i++)
if (current_dirt[position + i])
break;
// Give up if no dirt
if (i >= screen_width)
{
*left = -1;
*right = -1;
return;
}
// Setup the leftmost dirt
*left = i;
// Clear dirt while searching for rightmost
int rightmost = i;
current_dirt[position + i++] = 0;
for (; i < screen_width; i++)
if (current_dirt[position + i])
{
rightmost = i;
current_dirt[position + i] = 0;
}
*right = rightmost;
}
int TextWindow::repaint_needed ()
{
int i;
for (i = 0; i < screen_width * screen_height; i++)
if (current_dirt[i])
return 1;
return 0;
}
const char *TextWindow::get_text (int x, int y) const
{
return current_text + y * screen_width + x;
}
const unsigned char *TextWindow::get_attr (int x, int y) const
{
return current_attr + y * screen_width + x;
}
void TextWindow::set_window (int x1, int y1, int x2, int y2)
{
if (0 <= x1 && x1 < x2 && x2 < screen_width
&& 0 <= y1 && y1 < y2 && y2 < screen_height)
{
TextWindowAux::setdirty (this, cx, cy);
window_width = x2 - x1 + 1;
window_height = y2 - y1 + 1;
window_x_offset = x1;
window_y_offset = y1;
gotoxy (0, 0);
}
}
void TextWindow::unset_window ()
{
set_window (0, 0, screen_width-1, screen_height-1);
}
typedef struct
{
int screen_width;
int screen_height;
char *text;
char *attr;
} SaveRecord;
void *TextWindow::save_screen_content ()
{
SaveRecord *saverec = (SaveRecord *) malloc (sizeof (SaveRecord));
if (saverec == 0)
return 0;
saverec->screen_width = screen_width;
saverec->screen_height = screen_height;
const int cell_count = screen_width * screen_height;
saverec->text = (char *) malloc (cell_count);
saverec->attr = (char *) malloc (cell_count);
if (saverec->text == 0 || saverec->attr == 0)
return 0;
memcpy (saverec->text, current_text, cell_count);
memcpy (saverec->attr, current_attr, cell_count);
return saverec;
}
void TextWindow::restore_screen_content (void *p)
{
if (p == 0)
return;
SaveRecord * const saverec = (SaveRecord *) p;
if (saverec->text == 0 || saverec->attr == 0)
return;
if (saverec->screen_width != screen_width
|| saverec->screen_height != screen_height)
return;
const int cell_count = screen_width * screen_height;
memcpy (current_text, saverec->text, cell_count);
memcpy (current_attr, saverec->attr, cell_count);
free (saverec->text);
free (saverec->attr);
free (saverec);
memset (current_dirt, 1, cell_count);
}