diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/dsl/screen.cpp	Sat Dec 22 17:52:45 2007 -0500
@@ -0,0 +1,396 @@
+/*****
+
+ 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, &regs, &regs);
+    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, &regs, &regs);
+  }
+};
+
+// 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;
+}