/* ----------------------- twindow.c --------------------- */ #include #include #include #include #include #include #include #include "twindow.h" #include "keys.h" #define TABS 4 #define SCRNHT 25 #define SCRNWIDTH 80 #define ON 1 #define OFF 0 #define ERROR -1 /* -------- local prototypes ---------- */ static void redraw(WINDOW *wnd); static void wframe(WINDOW *wnd); static void dtitle(WINDOW *wnd); static int *waddr(WINDOW *wnd, int x, int y); static void vswap(WINDOW *wnd); static void vsave(WINDOW *wnd); static void vrstr(WINDOW *wnd); static void add_list(WINDOW *wnd); static void beg_list(WINDOW *wnd); static void remove_list(WINDOW *wnd); static void insert_list(WINDOW *w1, WINDOW *w2); #ifndef FASTWINDOWS static int verify_wnd(WINDOW **w1); static int dget(WINDOW *wnd, int x, int y); #endif /*page*/ /* ---- array of border character sets ------ */ struct { int nw, ne, se, sw, side, line; } wcs[] = { {218,191,217,192,179,196}, /* single line */ {201,187,188,200,186,205}, /* double line */ {214,183,189,211,186,196}, /* single top, double side */ {213,184,190,212,179,205}, /* double top, single side */ {194,194,217,192,179,196} /* pop-down menu */ }; /* ---- window structure linked list head & tail ---- */ WINDOW *listhead = NULL; WINDOW *listtail = NULL; int VSG; /* video segment address */ /* ----------- establish a new window -------------- */ WINDOW *establish_window(x, y, h, w) { WINDOW *wnd; VSG = (vmode() == 7 ? 0xb000 : 0xb800); if ((wnd = (WINDOW *) malloc(sizeof (WINDOW))) == NULL) return NULL; /* ------- adjust for out-of bounds parameters ------- */ WTITLE = ""; HEIGHT = min(h, SCRNHT); WIDTH = min(w, SCRNWIDTH); COL = max(0, min(x, SCRNWIDTH-WIDTH)); ROW = max(0, min(y, SCRNHT-HEIGHT)); WCURS = 0; SCROLL = 0; SELECT = 1; BTYPE = 0; VISIBLE = HIDDEN = 0; PREV = NEXT = NULL; FHEAD = FTAIL = NULL; WBORDER=WNORMAL=PNORMAL=WTITLEC = clr(BLACK, WHITE, BRIGHT); WACCENT = clr(WHITE, BLACK, DIM); if ((SAV = malloc(WIDTH * HEIGHT * 2)) == (char *) 0) return NULL; add_list(wnd); #ifndef FASTWINDOWS clear_window(wnd); wframe(wnd); #endif return wnd; } /* ------ set the window's border --------- */ void set_border(WINDOW *wnd, int btype) { if (verify_wnd(&wnd)) { BTYPE = btype; redraw(wnd); } } /* ------- set colors ----------- */ void set_colors(WINDOW *wnd,int area,int bg,int fg,int inten) { if (vmode() == 7) { if (bg != WHITE && bg != BLACK) return; if (fg != WHITE && fg != BLACK) return; } if (verify_wnd(&wnd)) { if (area == ALL) while (area) WCOLOR [--area] = clr(bg, fg, inten); else WCOLOR [area] = clr(bg, fg, inten); redraw(wnd); } } /*page*/ /* ----- set the intensity of a window ------ */ void set_intensity(WINDOW *wnd, int inten) { int area = ALL; if (verify_wnd(&wnd)) { while (area) { WCOLOR [--area] &= ~BRIGHT; WCOLOR [area] |= inten; } redraw(wnd); } } /* -------- set title ------------- */ void set_title(WINDOW *wnd, char *title) { if (verify_wnd(&wnd)) { WTITLE = title; redraw(wnd); } } /* ------ redraw a window when an attribute changes ----- */ static void redraw(WINDOW *wnd) { #ifndef FASTWINDOWS int x, y, chat, atr; for (y = 1; y < HEIGHT-1; y++) for (x = 1; x < WIDTH-1; x++) { chat = dget(wnd, x, y); atr = (((chat>>8)&255) == PNORMAL ? WNORMAL : WACCENT); displ(wnd, x, y, chat&255, atr); } wframe(wnd); #endif PNORMAL = WNORMAL; } /* ------------ display an established window ------------ */ void display_window(WINDOW *wnd) { if (verify_wnd(&wnd) && !VISIBLE) { VISIBLE = 1; #ifdef FASTWINDOWS if (HIDDEN) { HIDDEN = 0; vrstr(wnd); } else { vsave(wnd); clear_window(wnd); wframe(wnd); } #else vswap(wnd); #endif } } /* ---------- close all windows -------------- */ void close_all() { WINDOW *sav, *wnd = listtail; while (wnd) { sav = PREV; delete_window(wnd); wnd = sav; } } /*page*/ /* ------------ remove a window ------------------ */ void delete_window(WINDOW *wnd) { if (verify_wnd(&wnd)) { hide_window(wnd); free(SAV); remove_list(wnd); /* remove window from list */ free(wnd); } } /* ----------- hide a window --------------- */ void hide_window(WINDOW *wnd) { if (verify_wnd(&wnd) && VISIBLE) { #ifndef FASTWINDOWS vswap(wnd); #else vrstr(wnd); #endif HIDDEN = 1; VISIBLE = 0; } } /*page*/ #ifndef FASTWINDOWS /* ------ reposition the window in its 3-axis plane ------ */ void repos_wnd(WINDOW *wnd, int x, int y, int z) { WINDOW *twnd; int x1, y1, chat; if (!verify_wnd(&wnd)) return; twnd = establish_window(x+COL, y+ROW, HEIGHT, WIDTH); twnd->_tl = WTITLE; twnd->btype = BTYPE; twnd->wcolor[BORDER] = WBORDER; twnd->wcolor[TITLE] = WTITLEC; twnd->wcolor[ACCENT] = WACCENT; twnd->wcolor[NORMAL] = WNORMAL; twnd->_wsp = SCROLL; twnd->_cr = WCURS; if (z != 1) { remove_list(twnd); if (z == 0) insert_list(twnd, wnd); else beg_list(twnd); } for (y1 = 0; y1 < twnd->_wh; y1++) for (x1 = 0; x1 < twnd->_ww; x1++) { chat = dget(wnd, x1, y1); displ(twnd, x1, y1, chat&255, (chat>>8)&255); } twnd->_wv = 1; vswap(twnd); hide_window(wnd); free(SAV); remove_list(wnd); *wnd = *twnd; insert_list(wnd, twnd); remove_list(twnd); free(twnd); } #endif /* ----------- clear the window area -------------- */ void clear_window(WINDOW *wnd) { register int x1, y1; if (verify_wnd(&wnd)) for (y1 = 1; y1 < HEIGHT-1; y1++) for (x1 = 1; x1 < WIDTH-1; x1++) displ(wnd,x1, y1, ' ', WNORMAL); } /* ------------ draw the window frame --------------- */ static void wframe(WINDOW *wnd) { register int x1, y1; if (!verify_wnd(&wnd)) return; /* --------- window title -------------- */ displ(wnd,0, 0, NW, WBORDER); dtitle(wnd); displ(wnd,WIDTH-1, 0, NE, WBORDER); /* ------------ window sides ----------------- */ for (y1 = 1; y1 < HEIGHT-1; y1++) { displ(wnd,0, y1, SIDE, WBORDER); displ(wnd,WIDTH-1, y1, SIDE, WBORDER); } /* --------------- bottom of frame ---------------- */ displ(wnd,0, y1, SW, WBORDER); for (x1 = 1; x1 < WIDTH-1; x1++) displ(wnd,x1, y1, LINE, WBORDER); displ(wnd,x1, y1, SE, WBORDER); } /*page*/ /* ------------- displ the window title -------------------- */ static void dtitle(WINDOW *wnd) { int x1 = 1, i, ln; char *s = WTITLE; if (!verify_wnd(&wnd)) return; if (s) { ln = strlen(s); if (ln > WIDTH-2) i = 0; else i = ((WIDTH-2-ln) / 2); if (i > 0) while (i--) displ(wnd, x1++, 0, LINE, WBORDER); while (*s && x1 < WIDTH-1) displ(wnd, x1++, 0, *s++, WTITLEC); } while (x1 < WIDTH-1) displ(wnd, x1++, 0, LINE, WBORDER); } /* ------------- window-oriented printf ---------------- */ void wprintf(WINDOW *wnd, char *ln, ...) { char dlin [100], *dl = dlin; if (verify_wnd(&wnd)) { va_list ap; va_start(ap, ln); vsprintf(dlin, ln, ap); va_end(ap); while (*dl) wputchar(wnd, *dl++); } } /*page*/ /* ------------ write a character to the window ---------- */ void wputchar(WINDOW *wnd, int c) { if (!verify_wnd(&wnd)) return; switch (c) { case '\n': if (SCROLL == HEIGHT-3) scroll(wnd, UP); else SCROLL++; WCURS = 0; break; case '\t': do displ(wnd,(WCURS++)+3,SCROLL+1,' ',WNORMAL); while ((WCURS%TABS) && (WCURS+1) < WIDTH-1); break; default: if ((WCURS+1) < WIDTH-1) { displ(wnd, WCURS+1, SCROLL+1, c, WNORMAL); WCURS++; } break; } } /* ------- set window cursor --------- */ void wcursor(WINDOW *wnd, int x, int y) { if (verify_wnd(&wnd) && x < WIDTH-1 && y < HEIGHT-1) { WCURS = x; SCROLL = y; cursor(COL+x+1, ROW+y+1); } } /*page*/ /* ------ allow the user to make a window selection ------ */ int get_selection(WINDOW *wnd, int s, char *keys) { int c = 0, ky; if (!verify_wnd(&wnd)) return 0; SELECT = s; while (c != ESC && c != '\r' && c != BS && c != FWD) { accent(wnd); c = get_char(); deaccent(wnd); switch (c) { case UP: if (SELECT > 1) SELECT--; else SELECT = SCROLL+1; break; case DN: if (SELECT < SCROLL+1) SELECT++; else SELECT = 1; break; case '\r': case ESC: case FWD: case BS: break; default: if (keys) { ky = 0; while (*(keys + ky)) { if (*(keys+ky)==toupper(c) || *(keys+ky)==tolower(c)) return ky + 1; ky++; } } break; } } return c == '\r' ? SELECT : c == ESC ? 0 : c; } union REGS rg; /* ------- scroll a window's contents up or down --------- */ void scroll(WINDOW *wnd, int dir) { int row = HEIGHT-1, col, chat; if (!verify_wnd(&wnd)) return; if (NEXT == NULL && HEIGHT > 3 && VISIBLE) { rg.h.ah = dir == UP ? 6 : 7; rg.h.al = 1; rg.h.bh = WNORMAL; rg.h.cl = COL + 1; rg.h.ch = ROW + 1; rg.h.dl = COL + WIDTH - 2; rg.h.dh = ROW + HEIGHT - 2; int86(16, &rg, &rg); return; } if (dir == UP) { for (row = 2; row < HEIGHT-1; row++) for (col = 1; col < WIDTH-1; col++) { chat = dget(wnd, col, row); displ(wnd,col,row-1,chat&255,(chat>>8)&255); } for (col = 1; col < WIDTH-1; col++) displ(wnd, col, row-1, ' ', WNORMAL); } else { for (row = HEIGHT-2; row > 1; --row) for (col = 1; col < WIDTH-1; col++) { chat = dget(wnd, col, row-1); displ(wnd,col,row,chat&255,(chat>>8)&255); } for (col = 1; col < WIDTH-1; col++) displ(wnd, col, row, ' ', WNORMAL); } } /*page*/ #ifndef FASTWINDOWS /* --- compute address of a window's display character --- */ static int *waddr(WINDOW *wnd, int x, int y) { WINDOW *nxt = NEXT; int *vp; if (!VISIBLE) return (int *) (SAV+y*(WIDTH*2)+x*2); x += COL; y += ROW; while (nxt) { if (nxt->_wv) if (x >= nxt->_wx && x <= nxt->_wx + nxt->_ww-1) if (y >= nxt->_wy && y <= nxt->_wy + nxt->_wh-1) { x -= nxt->_wx; y -= nxt->_wy; vp = (int *) ((nxt->_ws) +y*(nxt->_ww*2)+x*2); return vp; } nxt = nxt->_nx; } return NULL; } /* ---------- display a character to a window --------- */ void displ(WINDOW *wnd, int x, int y, int ch, int at) { int *vp; int vch = (ch&255)|(at<<8); if ((vp = waddr(wnd, x, y)) != NULL) *vp = vch; else vpoke(VSG,vad(x+COL,y+ROW),vch); } /*page*/ /* ----- get a displayed character from a window ----- */ static int dget(WINDOW *wnd, int x, int y) { int *vp; if ((vp = waddr(wnd, x, y)) != NULL) return *vp; return vpeek(VSG,vad(x+COL,y+ROW)); } /* ------------- low-level video functions --------------- */ /* ------- swap the video image with the save buffer ----- */ static void vswap(WINDOW *wnd) { int x, y, chat; int *bf = (int *) SAV; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) { chat = *bf; *bf++ = dget(wnd, x, y); displ(wnd, x, y, chat&255, (chat>>8)&255); } } #else /* -------- save video memory into the save buffer ---- */ static void vsave(WINDOW *wnd) { int x, y; int *bf = (int *) SAV; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) *bf++ = vpeek(VSG, vad(x+COL, y+ROW)); } /*page*/ /* ----- restore video memory from the save buffer ----- */ static void vrstr(WINDOW *wnd) { int x, y; int *bf = (int *) SAV; for (y = 0; y < HEIGHT; y++) for (x = 0; x < WIDTH; x++) vpoke(VSG,vad(x+COL,y+ROW), *bf++); } #endif /* ----- (de)accent the line where SELECT points ------- */ void acline(WINDOW *wnd, int set) { int x, ch; if (!verify_wnd(&wnd)) return; for (x = 1; x < WIDTH - 1; x++) { ch = dget(wnd, x, SELECT) & 255; displ(wnd, x, SELECT, ch, set); } } /* ---------- linked list functions --------- */ /* ----- add a window to the end of the list ------ */ static void add_list(WINDOW *wnd) { if (listtail) { PREV = listtail; listtail->_nx = wnd; } listtail = wnd; if (!listhead) listhead = wnd; } /*page*/ /* ----- add a window to the beginning of the list ------ */ static void beg_list(WINDOW *wnd) { if (listhead) { NEXT = listhead; listhead->_pv = wnd; } listhead = wnd; if (!listtail) listtail = wnd; } /* --------- remove a window from the list -------- */ static void remove_list(WINDOW *wnd) { if (NEXT) NEXT->_pv = PREV; if (PREV) PREV->_nx = NEXT; if (listhead == wnd) listhead = NEXT; if (listtail == wnd) listtail = PREV; NEXT = PREV = NULL; } /* ----- insert w1 after w2 ------ */ static void insert_list(WINDOW *w1, WINDOW *w2) { w1->_pv = w2; w1->_nx = w2->_nx; w2->_nx = w1; if (w1->_nx == NULL) listtail = w1; else w1->_nx->_pv = w1; } /*page*/ #ifndef FASTWINDOWS /* ---- verify the presence of a window in the list ----- */ static int verify_wnd(WINDOW **w1) { WINDOW *wnd; wnd = listhead; if (*w1 == NULL) *w1 = listtail; else { while (wnd != NULL) { if (*w1 == wnd) break; wnd = NEXT; } } return wnd != NULL; } #endif WINDOW *ewnd = NULL; /* ------- error messages ------- */ void error_message(char *s) { ewnd = establish_window(50, 22, 3, max(10, strlen(s)+2)); set_colors(ewnd, ALL, RED, YELLOW, BRIGHT); set_title(ewnd, " ERROR! "); display_window(ewnd); wprintf(ewnd, s); putchar(BELL); } void clear_message() { if (ewnd) delete_window(ewnd); ewnd = NULL; }