home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The World of Computer Software
/
World_Of_Computer_Software-02-385-Vol-1of3.iso
/
d
/
dots151.zip
/
GRAPHSRC.ZIP
/
WINDOW.C
< prev
next >
Wrap
C/C++ Source or Header
|
1990-06-16
|
34KB
|
1,445 lines
#define SHRINK
/*
wint - implement graphics mode menus for Turbo C
*/
#include <dos.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include "g.h"
#include "scr_ci.h"
#include "window.h"
#ifndef SHRINK
#include "mif.h"
#endif
#define MAXCHARS 38 /* # characters in queue (where mouse-
generated characters are saved) */
#define MAXMSG 20 /* maximum # messages in message queue */
static CurVis = 0; /* nonzero if mouse cursor is visible */
/* ------------- general purpose programs ---------------------------- */
/*
queued_chars[chHead] is where the next character will be placed
queued_chars[chTail] has the next character to be delivered
chHead == chTail when the queue is empty
*/
static int chHead, chTail;
static char queued_chars[MAXCHARS];
static key_avail() /* return nonzero if a keyboard char is available */
{
union REGS regs;
regs.h.ah = 0xb;
regs.x.dx = 0;
return (chHead - chTail) || intdos(®s, ®s);
}
static min(a, b) int a, b;
{ if(a < b) return a;
return b;
}
static max(a, b) int a, b;
{ if(a > b) return a;
return b;
}
ungets(s) char *s;
{ int i;
while(*s)
{i = chHead + 1;
if(i >= MAXCHARS) i = 0;
if(i == chTail) return;
queued_chars[chHead] = *s++;
chHead = i;
}
}
static key_in()
{ int ch;
#ifdef __TURBOC__
union REGS regs;
#endif
while(1)
{
deliver(); /* deliver one message from queue */
if(chHead != chTail)
{ch = queued_chars[chTail];
if(++chTail >= MAXCHARS) chTail = 0;
return ch;
}
#ifdef _DESMET_
if(_os(0xb, 0))
#else
#ifdef __TURBOC__
regs.h.ah = 0xb;
regs.x.dx = 0;
if(intdos(®s, ®s))
#endif /* __TURBOC__ */
#endif /* _DESMET_ */
return scr_ci();
}
}
static char *gmem(num) int num;
{ char *mp, *malloc();
mp = malloc(num);
if(!mp)
{
#ifndef SHRINK
fprintf(stderr, "out of memory\n");
#endif
exit(1);
}
return mp;
}
/* get string, edit */
getse(s, appending, x, y, w, norm, high)
char *s;
int appending, x, y, w, norm, high;
{ int ch, i, j, n, maxn, inserting;
inserting = 0;
if(79*char_width > w) maxn = w/char_width;
else maxn = 79; /* assume the input buffer is 80 bytes long */
maxn -= 2; /* allow for the two spaces printed after the string */
n = strlen(s);
if(n > maxn) n = maxn;
s[n] = 0;
if(appending) i = n;
else i = 0;
set_color(norm & 0x0f);
set_background_color(norm >> 4);
gotoxy(x, y);
(*draw_text)(s);
gotoxy(x + n*char_width, y);
(*draw_text)(" ");
set_color(high & 0x0f);
set_background_color(high >> 4);
gotoxy(x + i*char_width, y);
(*draw_char)(i < n ? s[i] : ' ');
ch = key_in();
if(!appending)
{switch(ch)
{case 3:
case ESC:
case 0x0d:
case ctrl_right_char:
case ctrl_left_char:
case right_char:
case up_char:
case down_char:
case ins_char:
case del_char:
case end_char:
case home_char:
break;
default:
for (i = 0; i < n; i++) s[i] = ' ';
set_color(norm & 0x0f);
set_background_color(norm >> 4);
gotoxy(x, y);
(*draw_text)(s);
s[0] = i = n = 0;
}
}
while(1)
{switch(ch)
{case 3:
case ESC:
return 0; /* abnormal return */
case RETURN:
case up_char:
case down_char:
return ch; /* normal return */
case left_char:
{if(i) i--;
break;
}
case BS:
{if (i == 0) break;
i--;
/* fall into... */
}
case del_char:
{if (i == n) break;
for (j = i; j < n; j++) s[j] = s[j + 1];
n--;
break;
}
case ins_char:
{inserting ^= 1;
break;
}
case ctrl_right_char:
{while(i < n && s[i] != ' ') i++;
while(i < n && s[i] == ' ') i++;
break;
}
case ctrl_left_char:
{while(i && s[i-1] == ' ') i--;
while(i && s[i-1] != ' ') i--;
break;
}
case right_char:
{if(i < n && i < maxn) i++;
break;
}
case end_char:
{i = n;
break;
}
case home_char:
{i = 0;
break;
}
default:
{if(ch < ' ' || ch > 0x7f) break;
if(inserting)
if(n >= maxn) break;
else
for (j = n++; j >= i; j--)
s[j + 1] = s[j];
else if(i == n)
if(n >= maxn) break;
else s[++n] = 0;
s[i++] = ch;
break;
}
}
set_color(norm & 0x0f);
set_background_color(norm >> 4);
gotoxy(x, y);
(*draw_text)(s);
gotoxy(x + n*char_width, y);
(*draw_text)(" ");
set_color(high & 0x0f);
set_background_color(high >> 4);
gotoxy(x + i*char_width, y);
(*draw_char)(i < n ? s[i] : ' ');
ch = key_in();
}
}
/* ------------- window programs ------------------------------------- */
#define WINMAX 30
WINDOW *WinStack[WINMAX];
int WinVis = 0;
static x0, y0, xp, yp, b_left, b_right, b_up, b_down,
ShowingBox = 0, ShowingCross = 0;
static CURSOR CursorShape;
CURSOR DragShape = BOX;
WINDOW *CreateWindow(text, x, y, extra)
char *text; /* displayed at the top of this window */
int x, y; /* upper left corner of window */
int extra; /* extra bytes to allocate at end of this WINDOW */
{ WINDOW *pw;
int nb, bx, by, thisw, maxw;
pw = (WINDOW *)gmem(sizeof(WINDOW) + extra);
pw->text = text;
pw->accept = MsgWindow;
pw->x = x;
pw->y = y;
pw->w = strlen(text) * char_width;
pw->h = char_height;
pw->window_style = 1;
pw->border_style = 1;
/* 0 -> white */
pw->norm = (max_color&0x0f)<<4; /* background in high order nibble, */
pw->high = max_color&0x0f; /* forground in low order */
pw->vis = 0;
return pw;
}
#define RR(x) /* \
{FILE *buf; \
buf = fopen("debug", "a"); \
fprintf x; \
fclose(buf); \
} /**/
void MsgWindow(msg, data, pw) MESSAGE msg; int *data; WINDOW *pw;
{ int bx, by, i, j, restore;
char buf[100];
switch(msg)
{
case REDRAW:
if(pw->vis == 0)
{
if(WinVis >= WINMAX) break;
WinStack[WinVis++] = pw; pw->vis = 1;
/*
{FILE *dfile;
dfile = fopen("c:debug", "a");
fprintf(dfile, "adding window: WinVis = %d, WinStack[WinVis-1] = %04x\n",
WinVis, WinStack[WinVis-1]);
fclose(dfile);
}
*/
}
/*
{FILE *dfile;
dfile = fopen("c:debug", "a");
fprintf(dfile, " redrawing window: WinVis = %d, WinStack[WinVis-1] = %04x\n",
WinVis, WinStack[WinVis-1]);
fclose(dfile);
}
*/
bx = pw->x; by = pw->y;
#ifndef SHRINK
if(restore = CurVis) HideMouseCursor();
#endif /* SHRINK */
set_background_color(pw->norm >> 4);
ClearBox(bx, by, bx + pw->w, by + pw->h + 1);
if(strlen(pw->text))
{
gotoxy(bx, by + char_height);
set_color(pw->norm & 0x0f);
(*draw_text)(pw->text);
}
set_color(pw->norm & 0x0f);
if(pw->border_style == 1)
box(bx - 1, by - 1, bx + pw->w, by + pw->h);
#ifndef SHRINK
if(restore) ShowMouseCursor();
#endif /* SHRINK */
break;
#ifndef SHRINK
case DRAG:
SetHorizontalLimits(0, pixels_wide - 1); /* release cursor */
SetVerticalLimits(0, pixels_high - 1);
bx = data[0] - b_left;
if(bx <= 0) bx = 1;
if(bx + pw->w >= pixels_wide) bx = pixels_wide - pw->w - 1;
by = data[1] - b_up;
if(by < 0) by = 0;
if(by + pw->h >= pixels_high) by = pixels_high - pw->h - 1;
data[0] = bx;
data[1] = by;
(*pw->accept)(MOVETO, data, pw);
break;
#endif /* SHRINK */
case CLEAR:
if(pw->vis)
{
/*
{FILE *dfile;
dfile = fopen("c:debug", "a");
fprintf(dfile, "clearing window: WinVis = %d, WinStack[0] = %04x\n",
WinVis, WinStack[0]);
fclose(dfile);
}
*/
for (i = j = 0; i < WinVis; i++)
if(WinStack[i] != pw) WinStack[j++] = WinStack[i];
WinVis = j;
pw->vis = 0;
}
case HIDE:
bx = pw->x; by = pw->y;
#ifndef SHRINK
if(restore = CurVis) HideMouseCursor();
#endif /* SHRINK */
set_background_color(pw->norm >> 4);
RR((buf, "msg = %d (%s)\n", msg, msg==CLEAR?"CLEAR":(msg==HIDE?"HIDE":"?") ))
if((pw->norm >> 4) == max_color && bx == 0 && by == 0 &&
pw->w == pixels_wide-1 && pw->h == pixels_high-1)
{
RR((buf, "clearing screen (%d*%d window)\n", pw->w, pw->h))
clear_graphics();
}
else
{
RR((buf, "clearing box.. color %d!=%d, %d*%d window starting at (%d,%d)\n", pw->norm>>4, max_color, pw->w, pw->h, bx, by))
ClearBox(max(0, bx - 1), max(0, by - 1),
min(pixels_wide - 1, bx + pw->w + 1),
min(pixels_high - 1, by + pw->h + 1));
}
#ifndef SHRINK
if(restore) ShowMouseCursor();
#endif /* SHRINK */
break;
case START_DRAGGING:
DragShape = BORDER;
b_left = xp - pw->x + 1;
b_up = yp - pw->y;
b_right = pw->w - b_left;
b_down = pw->h - b_up;
/* cage cursor */
#ifndef SHRINK
SetHorizontalLimits(b_left, pixels_wide - b_right - 1);
SetVerticalLimits(b_up, pixels_high - b_down - 1);
#endif /* SHRINK */
break;
case MOVETO:
bx = data[0];
if(bx < 1) bx = 1;
if(bx + pw->w >= pixels_wide) bx = pixels_wide - 1 - pw->w;
by = data[1];
if(by < 0) by = 0;
if(by + pw->h >= pixels_high) by = pixels_high - 1 - pw->h;
pw->x = bx;
pw->y = by;
break;
case RESIZE:
bx = data[0];
if(bx < 1) bx = 1;
if(bx + pw->x >= pixels_wide) bx = pixels_wide - 1 - pw->x;
by = data[1];
if(by < 0) by = 0;
if(by + pw->y >= pixels_high) by = pixels_high - 1 - pw->y;
pw->w = bx;
pw->h = by;
break;
default:
;
/* nothing */
}
}
WinCovers(pw1, pw2) WINDOW *pw1, *pw2;
{ return (pw1->x <= pw2->x &&
pw1->y <= pw2->y &&
pw1->x + pw1->w >= pw2->x + pw2->w &&
pw1->y + pw1->h >= pw2->y + pw2->h);
}
WinOverlaps(pw1, pw2) WINDOW *pw1, *pw2;
{ return (pw2->x < pw1->x + pw1->w &&
pw2->x + pw2->w > pw1->x &&
pw2->y < pw1->y + pw1->h &&
pw2->y + pw2->h > pw1->y);
}
WinShowString(s, x, y, pw) char *s; int x, y; WINDOW *pw;
{
if(pw->vis == 0)(*pw->accept)(REDRAW, NULL, pw);
set_color(pw->norm & 0x0f);
set_background_color(pw->norm >> 4);
gotoxy(pw->x + x, pw->y + y);
(*draw_text)(s);
}
WinGetString(query, s, appending, x, y, pw)
char *query, *s;
int appending, x, y;
WINDOW *pw;
{
pw->text = query;
(*pw->accept)(REDRAW, NULL, pw);
return getse(s, appending, pw->x + x, pw->y + y, pw->w - x, pw->norm,
pw->high);
}
/*
queued message i has three parts:
qm_msg[i] message number
qm_data[i] the associated data (four integers)
qm_pw[i] pointer to the addressee (a window)
xx[msgHead] is where the next message will be placed
xx[msgTail] has the next message to be delivered
(where xx is one of the above three arrays)
When msgHead == msgTail, the queue is empty. xx[msgHead] is
always unused, but when (msgHead + 1)%MAXMSG == msgTail, the
queue is full.
A collection of arrays is used rather than the more intuitive
array of structures because the latter doesn't work when
DS != SS (i.e. when messages are being deposited by the mouse
event handler).
*/
static int msgHead, msgTail;
static MESSAGE qm_msg[MAXMSG];
static int qm_data[MAXMSG][4];
static WINDOW *qm_pw[MAXMSG];
deposit(msg, data, pw) MESSAGE msg; int data[]; WINDOW *pw;
{ int i, j;
i = msgHead + 1;
if(i >= MAXMSG) i = 0;
if(i == msgTail) return; /* queue is full - drop the message */
qm_msg[chHead] = msg;
for (j = 0; j < 4; j++) qm_data[chHead][j] = data[j];
qm_pw[chHead] = pw;
msgHead = i;
}
deliver()
{
if(msgHead != msgTail)
{
(*qm_pw[chTail]->accept)(qm_msg[chTail], qm_data[chTail],
qm_pw[chTail]);
if(++msgTail >= MAXMSG) msgTail = 0;
}
}
/* ------------- menu programs --------------------------------------- */
MENU *CreateVMenu(text, pb, x, y, extra)
char *text; /* displayed at the top of this menu */
BUTTON *pb; /* an array of buttons */
int x, y; /* upper left corner of menu */
int extra; /* extra bytes to allocate at end of this MENU */
{ MENU *pm;
int nb, bx, by, thisw, maxw;
pm = (MENU *)CreateWindow(text, x, y,
sizeof(MENU) - sizeof(WINDOW) + extra);
pm->w_accept = pm->accept;
pm->accept = MsgMenu;
pm->pab = pb;
bx = 0; by = 0;
maxw = strlen(text);
if(strlen(text)) by += char_height; /* leave room for text */
for (nb = 0; (pb + nb)->text; nb++)
{thisw = strlen((pb + nb)->text); /* find longest text string */
if(maxw < thisw) maxw = thisw;
}
maxw *= char_width;
while(pb->text)
{
pb->pm = 0;
if(pb->accept == NULL) pb->accept = MsgButton;
pb->norm = pm->norm;
pb->high = pm->high;
pb->x = bx;
pb->y = by;
pb->w = maxw;
pb->h = char_height + 1;
by += char_height + 1;
pb++;
}
if(char_h_adjusted) pm->x = x;
else pm->x = (x/char_width)*char_width;
if(char_v_adjusted) pm->y = y;
else pm->y = (y/char_height)*char_height;
pm->w = maxw + 1;
pm->h = by + 1;
pm->menu_style = 0;
pm->sel = 0;
pm->cButtons = nb;
return pm;
}
MENU *CreateHMenu(pb, x, y, extra)
BUTTON *pb; /* an array of buttons */
int x, y; /* upper left corner of menu */
int extra; /* extra bytes to allocate at end of this MENU */
{ MENU *pm;
int nb, bx, by, thisw, maxw;
static char dummy[] = "";
pm = (MENU *)CreateWindow(dummy, x, y,
sizeof(MENU) - sizeof(WINDOW) + extra);
pm->w_accept = pm->accept;
pm->accept = MsgMenu;
pm->pab = pb;
nb = 0; bx = 0; by = 1;
while(pb->text)
{
pb->pm = 0;
if(pb->accept == NULL) pb->accept = MsgButton;
pb->norm = pm->norm;
pb->high = pm->high;
pb->x = bx;
pb->y = by;
pb->w = char_width*strlen(pb->text);
pb->h = char_height + 1;
bx += pb->w;
if(by >= pixels_wide) break; /* the entries won't fit on the screen */
pb++;
nb++;
}
pm->w = bx;
pm->h = char_height + 1;
if(char_h_adjusted) pm->x = x;
else pm->x = (x/char_width)*char_width;
if(char_v_adjusted) pm->y = y;
else pm->y = (y/char_height)*char_height;
pm->menu_style = 1;
pm->sel = 0;
pm->cButtons = nb;
return pm;
}
void MsgMenu(msg, data, pm) MESSAGE msg; int *data; MENU *pm;
{ int i, x, y, dx, dy, bx, by, origin[2], restore;
BUTTON *pb, *pbc;
MENU *pm2;
pbc = pb = pm->pab;
x = data[0] - pm->x;
y = data[1] - pm->y; /* get mouse location wrt menu origin */
for (i = 0; i < pm->cButtons; i++)
{
if(inside(x, y, pbc->x, pbc->y, pbc->w, pbc->h))
break;
pbc++;
}
if(pbc - pb >= pm->cButtons) pbc = 0;
switch(msg)
{
case MOVETO:
if(restore = pm->vis) (*pm->accept)(HIDE, data, pm);
bx = data[0];
if(bx < char_width) bx = char_width;
if(bx + pm->w >= pixels_wide) bx = pixels_wide - pm->w - 1;
if(!char_h_adjusted) bx -= bx%char_width;
by = data[1];
if(by < 0) by = 0;
if(by + pm->h >= pixels_high) by = pixels_high - pm->h - 1;
if(!char_v_adjusted) by -= by%char_height;
dx = bx - pm->x;
dy = by - pm->y;
data[0] = bx;
data[1] = by;
(*pm->w_accept)(MOVETO, data, pm);
if(restore) (*pm->accept)(REDRAW, data, pm);
pbc = pm->pab;
for (i = 0; i < pm->cButtons; i++)
{
if(pm2 = pbc->pm)
{data[0] = pm2->x + dx;
data[1] = pm2->y + dy;
(*pm2->accept)(MOVETO, data, pm2);
}
pbc++;
}
/**/
break;
case MOVE:
x = data[0] - pm->x;
y = data[1] - pm->y; /* get location wrt menu origin */
if(pbc)
{if(inside(x, y, pbc->x, pbc->y, pbc->w, pbc->h))
break; /* no change */
(*pbc->accept)(NORMALIZE, data, pbc);
}
pm->sel = -1;
origin[0] = pm->x;
origin[1] = pm->y;
for (i = 0; i < pm->cButtons; i++)
{pbc = pb + i;
if(inside(x, y, pbc->x, pbc->y, pbc->w, pbc->h))
{(*pbc->accept)(HIGHLIGHT, origin, pbc);
pm->sel = i;
break;
}
}
break;
case CLICK:
case RELEASE:
if(pbc)
(*pbc->accept)(msg, data, pbc);
break;
case REDRAW:
(*pm->w_accept)(msg, data, (WINDOW *)pm);
origin[0] = pm->x;
origin[1] = pm->y;
if(restore = CurVis) HideMouseCursor();
for (i = 0; i < pm->cButtons; i++)
{pbc = pb + i;
(*pbc->accept)((i == pm->sel) ? HIGHLIGHT : NORMALIZE,
origin, pbc);
}
if(restore) ShowMouseCursor();
break;
default:
(*pm->w_accept)(msg, data, (WINDOW *)pm);
}
}
inside(x, y, x1, y1, w, h) int x, y, x1, y1, w, h;
{ return x1 <= x && x <= x1 + w && y1 <= y && y <= y1 + h;
}
void MsgButton(msg, data, pb) MESSAGE msg; int *data; BUTTON *pb;
{ int attrib, restore;
switch(msg)
{
case NORMALIZE:
attrib = pb->norm;
goto DISPLAY_BUTTON;
case HIGHLIGHT:
attrib = pb->high;
DISPLAY_BUTTON:
if(restore = CurVis) HideMouseCursor();
gotoxy(data[0] + pb->x, data[1] + pb->y + char_height);
set_color(attrib&0x0f);
set_background_color(attrib >> 4);
(*draw_text)(pb->text);
if(restore) ShowMouseCursor();
break;
case CLICK:
ungets(pb->val);
break;
default:
;
}
}
/* return value of chosen item, or zero */
MenuResponse(pm) MENU *pm;
{
int cmd, current, k, next, prev, origin[4];
/*
note we set origin immediately before each use, since the user
may have dragged the menu since the function was called.
*/
BUTTON *pb, *pbc;
if(pm->menu_style == 0) /* vertical menu */
{next = down_char;
prev = up_char;
}
else
{next = right_char;
prev = left_char;
}
pb = pm->pab;
current = pm->sel;
if(current < 0 || current >= pm->cButtons) pm->sel = current = 0;
(*pm->accept)(REDRAW, NULL, pm);
while(1)
{
if(current != pm->sel)
{ /* display current option */
origin[0] = pm->x;
origin[1] = pm->y;
pbc = pb + pm->sel;
(*pbc->accept)(NORMALIZE, origin, pbc);
pbc = pb + current;
(*pbc->accept)(HIGHLIGHT, origin, pbc);
pm->sel = current; /* save key for next time */
}
cmd = key_in();
if(pm->menu_style == 1) /* special keys for horizontal menus */
{if(cmd == down_char)
cmd = RETURN;
else if(cmd == up_char)
cmd = ESC;
}
else if(pm->menu_style == 0) /* special keys for vertical menus */
{if(cmd == pgup_char)
cmd = home_char;
else if(cmd == pgdn_char)
cmd = end_char;
}
if(cmd == next)
{if (++current >= pm->cButtons)
current = 0;
}
else if (cmd == prev)
{if (--current<0)
current = pm->cButtons-1;
}
else
{switch(cmd)
{case ESC: /* ESCAPE */
return 0;
case RETURN: /* CARRIAGE RETURN */
/* return current selection */
return pb[current].val[0];
case home_char:
current = 0;
break;
case end_char:
current = pm->cButtons-1;
break;
default:
cmd = tolower(cmd);
for (k = 0; k < pm->cButtons; k++)
{if (cmd == tolower(pb[k].trigger[0]))
{if(k != pm->sel)
{
/* highlight selected option */
/* (*pm->accept)(REDRAW, NULL, pm); */
origin[0] = pm->x;
origin[1] = pm->y;
pbc = pb + pm->sel;
(*pbc->accept)(NORMALIZE, origin, pbc);
pbc = pb + k;
(*pbc->accept)(HIGHLIGHT, origin, pbc);
pm->sel = k; /* save key for next time */
}
return pb[k].val[0];
}
}
}
}
}
}
/* ------------- mouse programs -------------------------------------- */
extern unsigned _rax, _rbx, _rcx, _rdx;
typedef enum
{START, PRESSED, DRAGGING
} MOUSE_STATE;
MOUSE_STATE state = START;
static mouseInstalled = 0;
HideMouseCursor()
{
#ifndef SHRINK
if(mouseInstalled) HideCursor();
CurVis = 0;
#endif
}
ShowMouseCursor()
{
#ifndef SHRINK
if(mouseInstalled)
{ShowCursor();
CurVis = 1;
}
#endif
}
#ifndef __TURBOC__
int IsMouse()
{ unsigned int_offset, int_segment;
char instruction;
#ifndef SHRINK
_lmove(2, 0x33*4, 0, &int_offset, _showds());
_lmove(2, 0x33*4 + 2, 0, &int_segment, _showds());
if(int_offset == 0 && int_segment == 0) return 0;
_lmove(1, int_offset, int_segment, &instruction, _showds());
if(instruction == 0xcf) return 0;
_rax = 0;
_doint(0x33);
if(_rax == 0)
#endif
return 0;
#ifndef SHRINK
return mouseInstalled = _rbx;
#endif
}
#endif
HideMouse()
{
#ifndef SHRINK
switch(CursorShape)
{case CROSS: flip_cross(xp, yp); break;
case BORDER: flip_box(xp - b_left, yp - b_up,
xp + b_right, yp + b_down);
break;
case BOX: flip_box(x0, y0, xp, yp); break;
case LINE: (*flip_line)(x0, y0, xp, yp); break;
default: HideMouseCursor();
}
#endif
}
ShowMouse()
{
#ifndef SHRINK
switch(CursorShape)
{case CROSS: flip_cross(xp, yp); break;
case BORDER: flip_box(xp - b_left, yp - b_up,
xp + b_right, yp + b_down);
break;
case BOX: flip_box(x0, y0, xp, yp); break;
case LINE: (*flip_line)(x0, y0, xp, yp); break;
default: ShowMouseCursor();
}
#endif
}
#ifndef SHRINK
/*
This mouse handler is called by the mouse driver (MOUSE.COM or
MOUSE.SYS). Since it is in effect an interrupt handler, it cannot
use most DOS services since DOS isn't reentrant. In addition, the
mouse driver assumes it is calling a large model program, whereas
this is a small model program. The assembly language interface
reset DS and CS and uses a near CALL rather than a far CALL, but DS
and SS are still different. This means that this program and any
program it calls can use statics, locals, and pointers to statics,
but not pointers to locals (since pointers are always dereferenced
using DS). This also means local arrays can't be passed to a
function.
*/
void far MouseHandler(trigger, status, hor, ver) int trigger, status, hor, ver;
{ static int data[4], flag = 0;
int i, x1, y1;
/* char buf[80]; */
MESSAGE msg;
WINDOW *pw;
flag++;
if(flag > 1) /* don't permit multiple simultaneous invocations */
{flag--; return;
}
msg = INVALID;
if(trigger & 2) /* press left button */
{state = PRESSED;
x0 = hor; y0 = ver;
}
else if(trigger & 4) /* release left button */
{if(state == DRAGGING)
{
SetHorizontalLimits(0, pixels_wide - 1); /* release cursor */
SetVerticalLimits(0, pixels_high - 1);
if(abs(x0 - xp) + abs(y0 - yp) > 3)
{msg = DRAG;
data[2] = x0; data[3] = y0;
}
else
{msg = CLICK;
data[0] = x0; data[1] = y0;
}
HideMouse();
CursorShape = NORMAL;
DragShape = BOX;
ShowMouseCursor();
}
else if(state == PRESSED) msg = CLICK;
state = START;
}
else if(trigger & 8) ungets("\033"); /* right button generates ESC */
else if(trigger & 1) /* moving */
{if(state == PRESSED)
{state = DRAGGING;
xp = hor; yp = ver;
HideMouse();
CursorShape = DragShape;
msg = START_DRAGGING;
ShowMouse();
}
else if(state == DRAGGING)
{HideMouse();
xp = hor; yp = ver;
CursorShape = DragShape;
ShowMouse();
}
}
/*
{if(ShowingCross)
{flip_cross(xp, yp); ShowingCross = 0;
x0 = xp = hor;
y0 = yp = ver;
ShowingBox = 1;
}
else if(ShowingBox)
{flip_box(x0, y0, xp, yp); ShowingBox = 0;
ShowMouseCursor();
}
else
{HideMouseCursor();
xp = hor; yp = ver;
flip_cross(xp, yp); ShowingCross = 1;
}
}
if(trigger & 1) msg = MOVE;
if(trigger & 2) msg = PRESS;
if(trigger & 4) msg = RELEASE;
if(trigger & 8) msg = PRESSR;
if(trigger & 16) msg = RELEASER;
*/
data[0] = hor; data[1] = ver;
if(msg != INVALID)
{
if(msg == DRAG || msg == START_DRAGGING) {x1 = x0; y1 = y0;}
else {x1 = hor; y1 = ver;}
for (i = WinVis; i--; )
{pw = WinStack[i];
if(inside(x1, y1, pw->x, pw->y, pw->w, pw->h))
{
deposit(msg, data, pw);
break;
}
}
}
flag--;
}
#endif /* SHRINK */
/*
SetEventHandler (mask, handler)
int mask;
mask weight meaning
0 1 change cursor position
1 2 press left button
2 4 release left button
3 8 press right button
4 16 release right button
5-15 not used
int *handler()
called as: (*handler)(trigger, buttonStatus, horizontal, vertical)
trigger = mask with condition bit set that triggered call
buttonStatus = button state (bit 0 = left, bit 1 = right)
horizontal = horizontal cursor position
vertical = vertical cursor position
*/
/* ------------- graphics programs ----------------------------------- */
box(x0, y0, x1, y1) int x0, y0, x1, y1;
{
(*draw_line)(x0, y0, x0, y1);
(*draw_line)(x1, y1, x0, y1);
(*draw_line)(x1, y1, x1, y0);
(*draw_line)(x0, y0, x1, y0);
}
flip_cross(x, y) int x, y;
{
(*flip_line)(0, y, pixels_wide-1, y);
(*flip_line)(x, 0, x, pixels_high-1);
}
flip_box(x0, y0, x1, y1) int x0, y0, x1, y1;
{
#ifndef SHRINK
HideMouseCursor();
(*flip_line)(x0, y0, x0, y1);
(*flip_line)(x1, y1, x0, y1);
(*flip_line)(x1, y1, x1, y0);
(*flip_line)(x0, y0, x1, y0);
ShowMouseCursor();
#endif
}
ClearBox(x1, y1, x2, y2) int x1, y1, x2, y2;
{ int t;
if (y2 < y1) {t = y1; y1 = y2; y2 = t;}
while(y1 < y2) {(*erase_line)(x1, y1, x2, y1); y1++;}
}
/* ------------- test program ---------------------------------------- */
#ifdef MAIN
show_window(pw) WINDOW *pw;
{ printf("window...\n");
printf(" text \"%s\"\n", pw->text);
printf("message handler at %04x\n", pw->accept);
printf(" origin (%3d,%3d)\n", pw->x, pw->y);
printf(" size (%3d,%3d)\n", pw->w, pw->h);
printf("window style %d\n", pw->window_style);
printf("border style %d\n", pw->border_style);
printf(" norm %02x\n", pw->norm);
printf(" high %02x\n", pw->high);
}
show_button(pb) BUTTON *pb;
{ printf("button...\n");
printf(" text \"%0.20s\"\n", pb->text);
printf(" trigger \"%0.20s\"\n", pb->trigger);
printf(" val \"%0.20s\"\n", pb->val);
printf("message handler at %04x\n", pb->accept);
printf(" child at %04x\n", pb->pm);
printf(" high %02x\n", pb->high);
printf(" norm %02x\n", pb->norm);
printf(" origin (%d,%d)\n", pb->x, pb->y);
printf(" size (%d,%d)\n", pb->w, pb->h);
}
show_menu(pm) MENU *pm;
{ BUTTON *pb;
show_window(pm);
printf("%20s %4s %4s %4s %5s %4s %4s %9s %9s\n",
"text", "trig", "val", "hand", "child", "high", "norm", "origin", "size");
for (pb = pm->pab; *(int *)pb; pb++)
{printf("%20.20s %4.4s %4.4s %04x %04x %02x %02x (%3d,%3d) (%3d,%3d)\n",
pb->text, pb->trigger, pb->val, pb->accept, pb->pm,
pb->high, pb->norm, pb->x, pb->y, pb->w, pb->h);
}
}
char *msg_label[]={"INVALID","REDRAW","CLEAR","RESIZE","MOVETO","MOVE","CLICK",
"CLICKR","DRAG","RELEASE","HIGHLIGHT","NORMALIZE"};
BUTTON astuff[] =
{
{" file ", "f", "f"},
{" big ", "b", "b"},
{" edit ", "e", "e"},
{" view ", "v", "v"},
{" quit ", "q", "q"},
{0}
};
BUTTON fButtons[] =
{
{" save ", "s", "s"},
{" load ", "l", "l"},
{" new ", "n", "n"},
{" quit ", "q", "q"},
{" beep ", "b", "b"},
{0}
};
BUTTON bButtons[] =
{
{" at astra per aspera ", "a", "a"},
{" be prepared ","b", "b"},
{" don't tread on me ", "d", "d"},
{" I shall return ", "i", "i"},
{" if anything can go wrong, it will ", "i", "i"},
{" live free or die ", "l", "l"},
{" mind your own business ", "m", "m"},
{" Murphy was an optimist ", "u", "u"},
{" old soldiers never die ", "o", "o"},
{" there's no such thing as a free lunch ", "t", "t"},
{" use it or lose it ", "u", "u"},
{0}
};
BUTTON eButtons[] =
{
{" cross ", "c", "c"},
{" replace ", "r", "r"},
{" delete ", "d", "d"},
{" box ", "b", "b"},
{" line ", "l", "l"},
{0}
};
BUTTON vButtons[] =
{
{" zoom ", "z", "z"},
{" pan ", "p", "p"},
{0}
};
MENU *amen, *fmen, *bmen, *emen, *vmen, stack_array[30], **mstack = &stack_array[30];
WINDOW *bwin;
AddLine(msg, data, pw) MESSAGE msg; int *data; WINDOW *pw;
{
if(msg == DRAG)
{
#ifndef SHRINK
HideMouseCursor();
#endif /* SHRINK */
(*draw_line)(data[0], data[1], data[2], data[3]);
#ifndef SHRINK
ShowMouseCursor();
SetHorizontalLimits(0, pixels_wide - 1);
SetVerticalLimits(0, pixels_high - 1);
#endif /* SHRINK */
}
else if(msg == START_DRAGGING)
DragShape = LINE;
else MsgWindow(msg, data, pw);
}
AddBox(msg, data, pw) MESSAGE msg; int *data; WINDOW *pw;
{
if(msg == DRAG)
{
#ifndef SHRINK
HideMouseCursor();
#endif /* SHRINK */
box(data[0], data[1], data[2], data[3]);
#ifndef SHRINK
ShowMouseCursor();
SetHorizontalLimits(0, pixels_wide - 1);
SetVerticalLimits(0, pixels_high - 1);
#endif /* SHRINK */
}
else if(msg == START_DRAGGING)
DragShape = BOX;
else MsgWindow(msg, data, pw);
}
edit_menu()
{
int ch;
while(ch = MenuResponse(emen))
{switch(ch)
{case 'b':
bwin->accept = AddBox;
DragShape = BOX;
break;
case 'l':
bwin->accept = AddLine;
DragShape = LINE;
break;
case 'c':
bwin->accept = AddBox;
DragShape = CROSS;
break;
}
}
(*emen->accept)(CLEAR, NULL, emen);
}
view_menu()
{
int ch;
while(ch = MenuResponse(vmen))
{
}
(*vmen->accept)(CLEAR, NULL, vmen);
}
file_menu()
{
int ch;
while(ch = MenuResponse(fmen))
{
if(ch == 'b') putchar(7);
}
(*fmen->accept)(CLEAR, NULL, fmen);
}
big_menu()
{
int ch;
while(ch = MenuResponse(bmen))
{
if(ch == 'b') putchar(7);
}
(*bmen->accept)(CLEAR, NULL, bmen);
}
background()
{ int x0;
for (x0 = 0; x0 < pixels_wide; x0 += 10)
(*draw_line)(x0, 0, x0, pixels_high - 1);
}
main()
{ BUTTON *pb;
WINDOW *qwin, *dwin;
int status, hor, ver, left, right, middle, numButtons, i;
int data[2], ch;
char buf[128];
init_graphics();
#ifndef SHRINK
IsMouse();
if(mouseInstalled)
{
FlagReset(&status, &numButtons);
/* SetEventHandler(1 + 2 + 4 + 8, MouseHandler); */
ShowCursor();
getchar();
HideCursor();
getchar();
ShowCursor();
getchar();
HideCursor();
getchar();
}
#endif /* SHRINK */
data[0] = data[1] = 0;
bwin = CreateWindow("background", char_width, 0, 0);
bwin->w = 400;
bwin->h = 200;
bwin->accept = AddLine;
bwin->border_style = 0; /* no border */
/* amen = CreateHMenu(astuff, 20, 35, 0); */
amen = CreateVMenu("", astuff, 20, 35, 0);
pb = amen->pab;
pb->pm = fmen = CreateVMenu("", fButtons, amen->x + pb->x + char_width,
amen->y + pb->y + pb->h, 0);
pb++;
pb->pm = bmen = CreateVMenu("", bButtons, amen->x + pb->x + char_width,
amen->y + pb->y + pb->h, 0);
pb++;
pb->pm = emen = CreateVMenu("", eButtons, amen->x + pb->x + char_width,
amen->y + pb->y + pb->h, 0);
pb++;
pb->pm = vmen = CreateVMenu("", vButtons, amen->x + pb->x + char_width,
amen->y + pb->y + pb->h, 0);
*--mstack = 0; /* signals the bottom of the menu stack */
/*
show_menu(amen); getchar();
show_menu(fmen); getchar();
show_menu(bmen); getchar();
show_menu(emen); getchar();
show_menu(vmen); getchar();
*/
/*
{FILE *dfile;
dfile = fopen("c:debug", "a");
fprintf(dfile, "amen = %04x\n", amen);
fprintf(dfile, "fmen = %04x\n", fmen);
fprintf(dfile, "bmen = %04x\n", bmen);
fprintf(dfile, "emen = %04x\n", emen);
fprintf(dfile, "vmen = %04x\n", vmen);
fclose(dfile);
}
set_intensity(1.);
set_background_intensity(0.);
*/
background();
qwin = CreateWindow("query window", 6*char_width, 17*char_height, 0);
qwin->w = 40*char_width;
qwin->h = 2*char_height;
dwin = CreateWindow("display window", 6*char_width, 20*char_height, 0);
dwin->w = 40*char_width;
dwin->h = 2*char_height;
/*
strcpy(buf, "2.718281828");
WinGetString("string, no appending", buf, 0, char_width, 2*char_height, qwin);
(*qwin->accept)(CLEAR, NULL, qwin);
WinShowString(buf, char_width, 2*char_height, dwin);
getchar();
(*dwin->accept)(CLEAR, NULL, dwin);
strcpy(buf, "3.1417");
WinGetString("string, appending", buf, 1, char_width, 2*char_height, qwin);
(*qwin->accept)(CLEAR, NULL, qwin);
WinShowString(buf, char_width, 2*char_height, dwin);
getchar();
(*dwin->accept)(CLEAR, NULL, dwin);
*/
/*
if(mouseInstalled)
WinShowString("mouse present", char_width, 2*char_height, dwin);
else
WinShowString("mouse absent", char_width, 2*char_height, dwin);
getchar();
(*dwin->accept)(CLEAR, NULL, dwin);
*/
#ifndef SHRINK
if(mouseInstalled)
{
FlagReset(&status, &numButtons);
SetEventHandler(1 + 2 + 4 + 8, MouseHandler);
ShowMouseCursor();
sprintf(buf, "CurVis=%d", CurVis);
WinShowString(buf, char_width, 2*char_height, dwin);
getchar();
ShowCursor(); putchar(7);
WinShowString("ShowCursor() called", char_width, 2*char_height, dwin);
getchar();
(*dwin->accept)(CLEAR, NULL, dwin);
}
#endif
(*bwin->accept)(REDRAW, NULL, bwin);
while(ch = MenuResponse(amen))
{if(ch == 'q') break;
if(ch == 'f') file_menu();
if(ch == 'b') big_menu();
if(ch == 'e') edit_menu();
if(ch == 'v') view_menu();
}
(*amen->accept)(CLEAR, NULL, amen);
#ifndef SHRINK
if(mouseInstalled)
{
SetEventHandler(0, MouseHandler);
HideMouse();
}
#endif
gotoxy(200,100);
set_color(0);
set_background_color(max_color);
sprintf(buf, "character returned was %3d = %02x = '%c' ",
ch, ch, isprint(ch)?ch:'.');
(*draw_text)(buf);
getchar();
finish_graphics();
if(!mouseInstalled) printf("there is no mouse installed");
printf("\nbye!");
}
#endif /* MAIN */