Mercurial > ~dholland > hg > ag > index.cgi
view examples/dsl/screen.cpp @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children | aab9ff6af791 |
line wrap: on
line source
/***** AnaGram Programming Examples A Dos Script Language Screen Display Module Copyright 1993 Parsifal Software. All Rights Reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. *****/ #include "screen.h" #include "pair.h" #include <assert.h> #include "util.h" #ifdef __MSDOS__ #include <dos.h> #else /* This is only meant to compile, not run. (Unix, Windows) */ #define far union REGS { struct { unsigned short ah, bh, dl, dh; } h; }; void INT(unsigned long, union REGS *, union REGS *) {} #endif /***** Video display class This class is defined to provide screen initialization and access to the screen. It is not used outside this module. *****/ class video_display_class { public: char_cell far *base; pair <int> size; video_display_class() : base((char_cell *)(COLOR_ADAPTER_ADDRESS)) , size(80,25) {} // Access a particular char_cell in the display char_cell &operator[] (pair<int> p) { assert(p < size); return base[p.x + size.x * p.y]; } pair<int> get_cursor(void) { union REGS regs; regs.h.ah = 3; regs.h.bh = 0; INT(0x10, ®s, ®s); return pair<int>(regs.h.dl, regs.h.dh); } void set_cursor(pair<int> cp) { union REGS regs; regs.h.ah = 2; regs.h.bh = 0; regs.h.dl = (char) cp.x; regs.h.dh = (char) cp.y; INT(0x10, ®s, ®s); } }; // This should be the only instance of a video display class static video_display_class display; // Protect display class exists to save and restore screen protect_display::protect_display() { n = display.size.x * display.size.y; p = new char_cell[n]; copy(p,display.base,n); cursor_position = display.get_cursor(); } protect_display::~protect_display() { copy(display.base, p, n); delete [] p; display.set_cursor(cursor_position); } // Screen Rectangle class // Set cursor in a screen rectangle screen_rect &screen_rect::set_cursor(const int x, const int y) { assert (x < size.x && y < size.y); pair<int> where(pos.x + x, pos.y + y); display.set_cursor(where); return *this; } /***** Create a screen rectangle at a particular location in the display Rectangle consists of entire screen below and to the right of the specified coordinates. *****/ screen_rect at(int x, int y, int jm) { screen_rect r; r.pos = pair<int>(x,y); assert(r.pos < display.size); r.size = display.size - r.pos; r.jm.x = (jm/10) & 3; r.jm.y = (jm%10) & 3; return r; } screen_rect screen_rect::at(int x, int y, int jm) { screen_rect r = *this; r.pos = pos + pair<int>(x,y); assert(r.pos < pos + size); r.size = size - pair<int>(x,y); r.jm.x = (jm/10) & 3; r.jm.y = (jm%10) & 3; return r; } screen_rect screen_rect::rect(int w, int d, int jm) { screen_rect b = *this; pair <int> p = b.pos; pair <int> q = b.pos; int jmy = (jm % 10) & 3; int jmx = (jm / 10) & 3; if (w < b.size.x) b.size.x = w; if (d < b.size.y) b.size.y = d; b.pos.x += (size.x - b.size.x)*jmx/2; b.pos.y += (size.y - b.size.y)*jmy/2; return b; } screen_rect box(screen_rect r){ screen_rect b = r; pair <int> p = b.pos; pair <int> q = b.pos; q.y += b.size.y - 1; display[p] = 218; display[q] = 192; q.x++; p.x++; while (p.x < b.pos.x + b.size.x - 1) { display[p] = 196; display[q] = 196; p.x++; q.x++; } display[p] = 191; display[q] = 217; p = b.pos; p.y++; q = p; q.x += b.size.x - 1; while (p.y < b.pos.y + b.size.y - 1) { display[p] = 179; display[q] = 179; p.y++; q.y++; } b.size.x -= 4; b.size.y -= 2; b.pos.x += 2; b.pos.y++; return b; } screen_rect line(int x, int y, int w, int jm) { screen_rect r; char_cell p; if (w + x > display.size.x) w = display.size.x - x; r.pos = pair<int>(x,y); r.size = pair<int>(w,1); r.jm.x = (jm/10) & 3; r.jm.y = (jm%10) & 3; assert(r.pos + r.size <= display.size); return r; } screen_rect screen_rect::line(int x, int y, int w, int jm) const { screen_rect r; char_cell p; if (w + x > size.x) w = size.x - x; r.pos = pos + pair<int>(x,y); r.size = pair<int>(w,1); r.jm.x = (jm/10) & 3; r.jm.y = (jm%10) & 3; assert(r.pos + r.size <= display.size); return r; } /***** Set all char_cells in a rectangle to a given value *****/ screen_rect &screen_rect:: operator << (const char_cell &p) { pair<int> limit = pos + size; pair<int> i = pos; pair<int> j = pos; while (i.y < limit.y) { j = i; while (j.x < limit.x) display[j] = p, j.x++; i.y++; } return *this; } /***** Set all char_cells in a rectangle to a given color *****/ screen_rect &screen_rect::tint(int color) { pair<int> limit = pos + size; pair<int> i = pos; pair<int> j = pos; while (i.y < limit.y) { j = i; while (j.x < limit.x) display[j].color = (char) color, j.x++; i.y++; } return *this; } screen_rect &screen_rect::tint(int fg, int bg) { tint(COLOR(fg,bg)); return *this; } /***** Set all display characters within a rectangle to a given value *****/ screen_rect &screen_rect::operator << (const int c) { pair<int> limit = pos + size; pair<int> i = pos; pair<int> j = pos; while (i.y < limit.y) { j = i; while (j.x < limit.x) display[j].data = (char) c, j.x++; i.y++; } return *this; } /***** Write a string into a screen rectangle, taking account of desired justification mode. string_size returns the size (width x height) of the string. str_size adjusts this down, if necesary, to the size of the rectangle white is the amount of white space, horizontal and vertical to be distributed. loc is the position where the string display should begin limit is the location where the string should be clipped *****/ static int n_lines(const char *s) { int n = 0; if (s == NULL) return 0; while (*s) { while (*s && *s != '\n') s++; if (*s == '\n') s++; n++; } return n; } static int line_width(const char *s) { int n = 0; while (*s && *s != '\n') n++, s++; return n; } screen_rect &screen_rect ::operator << (const char *s) { pair<int> loc = pos; pair<int> limit = pos + size; int string_height = n_lines(s); int blank_lines = size.y > string_height ? size.y - string_height : 0; screen_rect r = *this; // Blank lines at top of rectangle r.size.y = blank_lines*jm.y/2; r << ' '; // Text segment loc.y += r.size.y; if (s != NULL) while (*s && loc.y < limit.y) { pair<int> p = loc; int width = line_width(s); int n = (size.x > width ? size.x - width : 0) * jm.x / 2; // Leading blanks while (n--) { display[p].data = ' '; p.x++; } // Text while ( *s && *s != '\n' && p.x < limit.x) { display[p].data = *s++; p.x++; } // Trailing blanks while (p.x < limit.x) { display[p].data = ' '; p.x++; } // Skip to end of line in string while (*s && *s != '\n') s++; if (*s == '\n') s++; loc.y++; } // Blank lines at bottom of rectangle r.pos = loc; r.size = limit - r.pos; r << ' '; return *this; } char_cell *contents(const screen_rect &r) { char_cell *c = new char_cell[r.size.x*r.size.y]; pair<int> pos = r.pos; pair<int> limit = r.pos + r.size; int k = 0; while (pos.y < limit.y) { pair<int> p = pos; while (p.x < limit.x) { c[k++] = display[p]; p.x++; } pos.y++; } return c; } screen_rect &screen_rect::operator << (const char_cell *c) { pair<int> rpos = pos; pair<int> limit = pos + size; int k = 0; while (rpos.y < limit.y) { pair<int> p = rpos; while (p.x < limit.x) { display[p] = c[k++]; p.x++; } rpos.y++; } return *this; }