eigenmath/window.cpp

432 lines
7.5 KiB
C++

#include "stdafx.h"
#include "defs.h"
// total_h sum of the heights of all the items in the display queue
//
// display_y the display queue y coordinate that maps to the screen
//
// maxy_y the maximum value that display_y can have
//
// total_w the maximum width including right and left margins
extern int line_height;
extern int left_margin;
extern int right_margin;
extern int display_x;
extern int display_y;
extern int display_height;
extern int display_width;
extern int max_x;
extern int max_y;
extern int total_w;
extern int total_h;
extern int update_display_request;
extern int text_width(int, char *);
#define SMALL_FONT 1
#define DEFAULT_FONT 2
#define DRAW_HRULE 20
#define DRAW_LEFT_BRACKET 21
#define DRAW_RIGHT_BRACKET 22
#define DRAW_LINE 23
#define DRAW_POINT 24
#define DRAW_BOX 25
#define DRAW_LABEL 26
#define MAXHIST 10001
extern int test_flag;
int term_flag;
// type
//
// 0 print string
//
// 1 display
struct {
unsigned char type, attr;
int w, h;
union {
char *s;
unsigned char *d;
} u;
} term[MAXHIST];
static int head, tail, len;
static char buf[1000];
#define OUTBUFLEN 10000
char out_buf[OUTBUFLEN + 1];
int out_count;
static void printcharf(int);
static void advance(void);
void
printchar_nowrap(int c)
{
if (c == '\n' || len < 80)
printchar(c);
}
static int
breaking_char(int c)
{
switch (c) {
case ' ':
case '+':
case '-':
case '*':
case '/':
case ',':
case '(':
return 1;
}
return 0;
}
void
printchar(int c)
{
if (test_flag && out_count < OUTBUFLEN)
out_buf[out_count++] = c;
printcharf(c);
// try not to break tokens but must break at 80 in case it's a huge number
if (len >= 60 && breaking_char(c) || len >= 80)
printcharf('\n');
}
static void
printcharf(int c)
{
char *s;
if (c == '\n') {
s = (char *) malloc(len + 1);
if (s == NULL)
return;
buf[len] = 0;
strcpy(s, buf);
len = 0;
term[tail].type = 0;
term[tail].attr = term_flag;
term[tail].u.s = s;
term[tail].w = text_width(DEFAULT_FONT, s);
term[tail].h = line_height;
total_h += line_height;
if (total_h - max_y > display_height)
max_y = total_h - display_height;
display_y = max_y;
advance();
return;
}
if (len < (int) sizeof buf)
buf[len++] = c;
}
void
printstr(char *s)
{
while (*s)
printchar(*s++);
}
void
clear_term(void)
{
while (head != tail) {
free(term[head].u.s);
head = (head + 1) % MAXHIST;
}
head = 0;
tail = 0;
display_x = 0;
display_y = 0;
max_x = 0;
max_y = 0;
total_w = 0;
total_h = 0;
update_display_request = 1;
}
void
shipout(unsigned char *d, int w, int h)
{
term[tail].type = 1;
term[tail].attr = 0;
term[tail].u.d = d;
term[tail].w = w;
term[tail].h = h + line_height;
total_h += h + line_height;
if (total_h - max_y > display_height)
max_y = total_h - display_height;
display_y = max_y;
advance();
}
static void
advance(void)
{
int h;
tail = (tail + 1) % MAXHIST;
if (tail == head) {
h = term[head].h;
free(term[head].u.s);
head = (head + 1) % MAXHIST;
total_h -= h;
max_y -= h;
display_y -= h;
if (max_y < 0)
max_y = 0;
if (display_y < 0)
display_y = 0;
}
update_display_request = 1;
}
extern void drawstring(int, int, char *, int);
extern void drawpixel(int, int, int, int);
extern void draw_left_bracket(int, int, int, int);
extern void draw_right_bracket(int, int, int, int);
extern void draw_line(int, int, int, int);
static int find_start_index(void);
static void draw(int);
static int yy;
void
draw_display(void)
{
int i;
update_display_request = 0;
i = find_start_index();
total_w = 0;
while (i != tail && yy < display_height) {
draw(i);
i = (i + 1) % MAXHIST;
}
max_x = total_w - display_width;
if (max_x < display_x)
max_x = display_x;
}
// find the top of the term
static int
find_start_index(void)
{
int indx, y;
indx = tail;
// back up until y <= display_y
y = total_h;
while (1) {
if (y <= display_y)
break;
if (indx == head)
break;
indx = (indx + MAXHIST - 1) % MAXHIST;
y -= term[indx].h;
}
// if too tall then negative start_y
if (y - display_y < 0)
yy = y - display_y;
else
yy = 0;
return indx;
}
extern void draw_text(int, int, int, char *, int);
extern void draw_hrule(int, int, int);
extern void draw_point(int, int);
extern void draw_box(int, int, int, int);
extern void use_graph_pen(void);
extern void use_normal_pen(void);
#define N(x) (((int) d[k + x] << 24) | ((int) d[k + x + 1] << 16) | ((int) d[k + x + 2]) << 8 | ((int) d[k + x + 3]))
static void
draw(int i)
{
int cmd, h, k, len, w, xx, x, x1, x2, y, y1, y2;
unsigned char *d;
w = term[i].w;
switch (term[i].type) {
case 0:
if (term[i].u.s[0]) {
xx = left_margin;
if (xx + w + right_margin > total_w)
total_w = xx + w + right_margin;
xx -= display_x;
len = (int) strlen(term[i].u.s);
draw_text(DEFAULT_FONT, xx, yy, term[i].u.s, len);
}
yy += line_height;
break;
case 1:
yy += line_height / 2;
d = term[i].u.d;
xx = (display_width - w) / 2; // center it
if (xx < left_margin)
xx = left_margin;
if (xx + w + right_margin > total_w)
total_w = xx + w + right_margin;
xx -= display_x;
k = 0;
while (1) {
cmd = d[k];
if (cmd == 0)
break;
switch (cmd) {
case 1:
use_normal_pen();
x = 256 * d[k + 1] + d[k + 2];
y = 256 * d[k + 3] + d[k + 4];
if (x > 32767)
x -= 65536;
if (y > 32767)
y -= 65536;
len = d[k + 5];
draw_text(SMALL_FONT, xx + x, yy + y, (char *) d + k + 6, len); // small font
k = k + 6 + len;
break;
case 2: // default font
case 3:
case 4:
case 5:
case 6:
case 7:
case 8:
case 9:
case 10:
use_normal_pen();
x = N(1);
y = N(5);
len = N(9);
draw_text(cmd, xx + x, yy + y, (char *) d + k + 13, len);
k = k + 13 + len;
break;
case DRAW_HRULE:
use_normal_pen();
x = N(1);
y = N(5);
w = N(9);
h = N(13);
draw_hrule(xx + x, yy + y, w);
k += 17;
break;
case DRAW_LEFT_BRACKET:
use_normal_pen();
x = N(1);
y = N(5);
w = N(9);
h = N(13);
draw_left_bracket(xx + x, yy + y, w, h);
k += 17;
break;
case DRAW_RIGHT_BRACKET:
use_normal_pen();
x = N(1);
y = N(5);
w = N(9);
h = N(13);
draw_right_bracket(xx + x, yy + y, w, h);
k += 17;
break;
case DRAW_LINE:
use_normal_pen();
x1 = 256 * d[k + 1] + d[k + 2];
y1 = 256 * d[k + 3] + d[k + 4];
x2 = 256 * d[k + 5] + d[k + 6];
y2 = 256 * d[k + 7] + d[k + 8];
draw_line(xx + x1, yy + y1, xx + x2, yy + y2);
k += 9;
break;
case DRAW_POINT:
use_graph_pen();
x = 256 * d[k + 1] + d[k + 2];
y = 256 * d[k + 3] + d[k + 4];
draw_point(xx + x, yy + y);
k += 5;
break;
case DRAW_BOX:
x1 = 256 * d[k + 1] + d[k + 2];
y1 = 256 * d[k + 3] + d[k + 4];
x2 = 256 * d[k + 5] + d[k + 6];
y2 = 256 * d[k + 7] + d[k + 8];
draw_box(xx + x1, yy + y1, xx + x2, yy + y2);
k += 9;
break;
default:
d[4] = 0; // error, force stop
k = 4;
break;
}
}
// 1/2 line_height above and below display
yy -= line_height / 2;
yy += term[i].h;
use_normal_pen();
break;
}
}
char *
get_tty_buf(void)
{
int i, j, n;
char *s;
i = head;
n = 0;
while (i != tail) {
if (term[i].type == 0)
n += (int) strlen(term[i].u.s) + 1;
i = (i + 1) % MAXHIST;
}
s = (char *) malloc(n + 1);
if (s == NULL)
return s;
i = head;
j = 0;
while (i != tail) {
if (term[i].type == 0) {
strcpy(s + j, term[i].u.s);
j += (int) strlen(term[i].u.s);
s[j++] = '\n';
}
i = (i + 1) % MAXHIST;
}
s[j] = 0;
return s;
}