home *** CD-ROM | disk | FTP | other *** search
- #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 */
-
-