home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 June / SIMTEL_0692.cdr / msdos / turbo_c / turbbook.arc / TWINDOW.C < prev    next >
Text File  |  1987-10-22  |  14KB  |  641 lines

  1. /* ----------------------- twindow.c --------------------- */
  2.  
  3. #include <stdio.h>
  4. #include <ctype.h>
  5. #include <stdarg.h>
  6. #include <dos.h>
  7. #include <alloc.h>
  8. #include <stdlib.h>
  9. #include <string.h>
  10. #include "twindow.h"
  11. #include "keys.h"
  12.  
  13. #define TABS 4
  14. #define SCRNHT 25
  15. #define SCRNWIDTH 80
  16. #define ON  1
  17. #define OFF 0
  18. #define ERROR -1
  19.  
  20. /* -------- local prototypes ---------- */
  21. redraw(WINDOW *wnd);
  22. wframe(WINDOW *wnd);
  23. dtitle(WINDOW *wnd);
  24. int *waddr(WINDOW *wnd, int x, int y);
  25. vswap(WINDOW *wnd);
  26. vsave(WINDOW *wnd);
  27. vrstr(WINDOW *wnd);
  28. add_list(WINDOW *wnd);
  29. beg_list(WINDOW *wnd);
  30. remove_list(WINDOW *wnd);
  31. insert_list(WINDOW *w1, WINDOW *w2);
  32. #ifndef FASTWINDOWS
  33. int dget(WINDOW *wnd, int x, int y);
  34. verify_wnd(WINDOW **w1);
  35. #endif
  36. /*page*/
  37. /* ---- array of border character sets ------ */
  38. struct {
  39.     int nw, ne, se, sw, side, line;
  40. } wcs[] = {
  41.     {218,191,217,192,179,196},    /* single line */
  42.     {201,187,188,200,186,205},    /* double line */
  43.     {214,183,189,211,186,196},    /* single top, double side */
  44.     {213,184,190,212,179,205},    /* double top, single side */
  45.     {194,194,217,192,179,196}    /* pop-down menu */
  46. };
  47.  
  48. /* ---- window structure linked list head & tail ---- */
  49. WINDOW *listhead = NULL;
  50. WINDOW *listtail = NULL;
  51. int VSG;    /* video segment address */
  52.  
  53. /* ----------- establish a new window -------------- */
  54. WINDOW *establish_window(x, y, h, w)
  55. {
  56.     WINDOW *wnd;
  57.  
  58.     VSG = (vmode() == 7 ? 0xb000 : 0xb800);
  59.     if ((wnd = (WINDOW *) malloc(sizeof (WINDOW))) == NULL)
  60.         return NULL;
  61.     /* ------- adjust for out-of bounds parameters ------- */
  62.     WTITLE = "";
  63.     HEIGHT = min(h, SCRNHT);
  64.     WIDTH = min(w, SCRNWIDTH);
  65.     COL = max(0, min(x, SCRNWIDTH-WIDTH));
  66.     ROW = max(0, min(y, SCRNHT-HEIGHT));
  67.     WCURS = 0;
  68.     SCROLL = 0;
  69.     SELECT = 1;
  70.     BTYPE = 0;
  71.     VISIBLE = HIDDEN = 0;
  72.     PREV = NEXT = NULL;
  73.     FHEAD = FTAIL = NULL;
  74.     WBORDER=WNORMAL=PNORMAL=WTITLEC =
  75.                 clr(BLACK, WHITE, BRIGHT);
  76.     WACCENT = clr(WHITE, BLACK, DIM);
  77.     if ((SAV = malloc(WIDTH * HEIGHT * 2)) == (char *) 0)
  78.         return NULL;
  79.     add_list(wnd);
  80. #ifndef FASTWINDOWS
  81.     clear_window(wnd);
  82.     wframe(wnd);
  83. #endif
  84.     return wnd;
  85. }
  86.  
  87. /* ------ set the window's border --------- */
  88. void set_border(WINDOW *wnd, int btype)
  89. {
  90.     if (verify_wnd(&wnd))    {
  91.         BTYPE = btype;
  92.         redraw(wnd);
  93.     }
  94. }
  95.  
  96. /* ------- set colors ----------- */
  97. void set_colors(WINDOW *wnd,int area,int bg,int fg,int inten)
  98. {
  99.     if (vmode() == 7)    {
  100.         if (bg != WHITE && bg != BLACK)
  101.             return;
  102.         if (fg != WHITE && fg != BLACK)
  103.             return;
  104.     }
  105.     if (verify_wnd(&wnd))    {
  106.         if (area == ALL)
  107.             while (area)
  108.                 WCOLOR [--area] = clr(bg, fg, inten);
  109.         else
  110.             WCOLOR [area] = clr(bg, fg, inten);
  111.         redraw(wnd);
  112.     }
  113. }
  114. /*page*/
  115. /* ----- set the intensity of a window ------ */
  116. void set_intensity(WINDOW *wnd, int inten)
  117. {
  118.     int area = ALL;
  119.  
  120.     if (verify_wnd(&wnd))    {
  121.         while (area)    {
  122.             WCOLOR [--area] &= ~BRIGHT;
  123.             WCOLOR [area] |= inten;
  124.         }
  125.         redraw(wnd);
  126.     }
  127. }
  128.  
  129. /* -------- set title ------------- */
  130. void set_title(WINDOW *wnd, char *title)
  131. {
  132.     if (verify_wnd(&wnd))    {
  133.         WTITLE = title;
  134.         redraw(wnd);
  135.     }
  136. }
  137.  
  138. /* ------ redraw a window when an attribute changes ----- */
  139. static redraw(WINDOW *wnd)
  140. {
  141. #ifndef FASTWINDOWS
  142.     int x, y, chat, atr;
  143.  
  144.     for (y = 1; y < HEIGHT-1; y++)
  145.         for (x = 1; x < WIDTH-1; x++)    {
  146.             chat = dget(wnd, x, y);
  147.             atr = (((chat>>8)&255) ==
  148.                 PNORMAL ? WNORMAL : WACCENT);
  149.             displ(wnd, x, y, chat&255, atr);
  150.         }
  151.     wframe(wnd);
  152. #endif
  153.     PNORMAL = WNORMAL;
  154. }
  155.  
  156. /* ------------ display an established window ------------ */
  157. void display_window(WINDOW *wnd)
  158. {
  159.     if (verify_wnd(&wnd) && !VISIBLE)    {
  160.         VISIBLE = 1;
  161. #ifdef FASTWINDOWS
  162.         if (HIDDEN)    {
  163.             HIDDEN = 0;
  164.             vrstr(wnd);
  165.         }
  166.         else    {
  167.             vsave(wnd);
  168.             clear_window(wnd);
  169.             wframe(wnd);
  170.         }
  171. #else
  172.         vswap(wnd);
  173. #endif
  174.     }
  175. }
  176.  
  177. /* ---------- close all windows -------------- */
  178. void close_all()
  179. {
  180.     WINDOW *sav, *wnd = listtail;
  181.  
  182.     while (wnd)    {
  183.         sav = PREV;
  184.         delete_window(wnd);
  185.         wnd = sav;
  186.     }
  187. }
  188. /*page*/
  189. /* ------------ remove a window ------------------ */
  190. void delete_window(WINDOW *wnd)
  191. {
  192.     if (verify_wnd(&wnd))        {
  193.         hide_window(wnd);
  194.         free(SAV);
  195.         remove_list(wnd);    /* remove window from list */
  196.         free(wnd);
  197.     }
  198. }
  199.  
  200. /* ----------- hide a window --------------- */
  201. void hide_window(WINDOW *wnd)
  202. {
  203.     if (verify_wnd(&wnd) && VISIBLE)    {
  204. #ifndef FASTWINDOWS
  205.         vswap(wnd);
  206. #else
  207.         vrstr(wnd);
  208. #endif
  209.         HIDDEN = 1;
  210.         VISIBLE = 0;
  211.     }
  212. }
  213. /*page*/
  214. #ifndef FASTWINDOWS
  215. /* ------ reposition the window in its 3-axis plane ------ */
  216. void repos_wnd(WINDOW *wnd, int x, int y, int z)
  217. {
  218.     WINDOW *twnd;
  219.     int x1, y1, chat;
  220.     if (!verify_wnd(&wnd))
  221.         return;
  222.     twnd = establish_window(x+COL, y+ROW, HEIGHT, WIDTH);
  223.     twnd->_tl = WTITLE;
  224.     twnd->btype = BTYPE;
  225.     twnd->wcolor[BORDER] = WBORDER;
  226.     twnd->wcolor[TITLE] = WTITLEC;
  227.     twnd->wcolor[ACCENT] = WACCENT;
  228.     twnd->wcolor[NORMAL] = WNORMAL;
  229.     twnd->_wsp = SCROLL;
  230.     twnd->_cr = WCURS;
  231.     if (z != 1)    {
  232.         remove_list(twnd);
  233.         if (z == 0)
  234.             insert_list(twnd, wnd);
  235.         else
  236.             beg_list(twnd);
  237.     }
  238.     for (y1 = 0; y1 < twnd->_wh; y1++)
  239.         for (x1 = 0; x1 < twnd->_ww; x1++)    {
  240.             chat = dget(wnd, x1, y1);
  241.             displ(twnd, x1, y1, chat&255, (chat>>8)&255);
  242.         }
  243.     twnd->_wv = 1;
  244.     vswap(twnd);
  245.     hide_window(wnd);
  246.     free(SAV);
  247.     remove_list(wnd);
  248.     *wnd = *twnd;
  249.     insert_list(wnd, twnd);
  250.     remove_list(twnd);
  251.     free(twnd);
  252. }
  253. #endif
  254.  
  255. /* ----------- clear the window area -------------- */
  256. void clear_window(WINDOW *wnd)
  257. {
  258.     register int x1, y1;
  259.  
  260.     if (verify_wnd(&wnd))
  261.         for (y1 = 1; y1 < HEIGHT-1; y1++)
  262.             for (x1 = 1; x1 < WIDTH-1; x1++)
  263.                 displ(wnd,x1, y1, ' ', WNORMAL);
  264. }
  265.  
  266. /* ------------ draw the window frame --------------- */
  267. static wframe(WINDOW *wnd)
  268. {
  269.     register int x1, y1;
  270.  
  271.     if (!verify_wnd(&wnd))
  272.         return;
  273.     /* --------- window title -------------- */
  274.     displ(wnd,0, 0, NW, WBORDER);
  275.     dtitle(wnd);
  276.     displ(wnd,WIDTH-1, 0, NE, WBORDER);
  277.     /* ------------ window sides ----------------- */
  278.     for (y1 = 1; y1 < HEIGHT-1; y1++)    {
  279.         displ(wnd,0, y1, SIDE, WBORDER);
  280.         displ(wnd,WIDTH-1, y1, SIDE, WBORDER);
  281.     }
  282.     /* --------------- bottom of frame ---------------- */
  283.     displ(wnd,0, y1, SW, WBORDER);
  284.     for (x1 = 1; x1 < WIDTH-1; x1++)
  285.         displ(wnd,x1, y1, LINE, WBORDER);
  286.     displ(wnd,x1, y1, SE, WBORDER);
  287. }
  288. /*page*/
  289. /* ------------- displ the window title -------------------- */
  290. static dtitle(WINDOW *wnd)
  291. {
  292.     int x1 = 1, i, ln;
  293.     char *s = WTITLE;
  294.  
  295.     if (!verify_wnd(&wnd))
  296.         return;
  297.     if (s)    {
  298.         ln = strlen(s);
  299.         if (ln > WIDTH-2)
  300.             i = 0;
  301.         else
  302.             i = ((WIDTH-2-ln) / 2);
  303.         if (i > 0)
  304.             while (i--)
  305.                 displ(wnd, x1++, 0, LINE, WBORDER);
  306.         while (*s && x1 < WIDTH-1)
  307.             displ(wnd, x1++, 0, *s++, WTITLEC);
  308.     }
  309.     while (x1 < WIDTH-1)
  310.         displ(wnd, x1++, 0, LINE, WBORDER);
  311. }
  312.  
  313. /* ------------- window-oriented printf ---------------- */
  314. void wprintf(WINDOW *wnd, char *ln, ...)
  315. {
  316.     char dlin [100], *dl = dlin;
  317.  
  318.     if (verify_wnd(&wnd))        {
  319.         va_list ap;
  320.         va_start(ap, ln);
  321.         vsprintf(dlin, ln, ap);
  322.         va_end(ap);
  323.         while (*dl)
  324.             wputchar(wnd, *dl++);
  325.     }
  326. }
  327. /*page*/
  328. /* ------------ write a character to the window ---------- */
  329. void wputchar(WINDOW *wnd, int c)
  330. {
  331.     if (!verify_wnd(&wnd))
  332.         return;
  333.     switch (c)    {
  334.         case '\n':
  335.             if (SCROLL == HEIGHT-3)
  336.                 scroll(wnd, UP);
  337.             else
  338.                 SCROLL++;
  339.             WCURS = 0;
  340.             break;
  341.         case '\t':
  342.             do displ(wnd,(WCURS++)+3,SCROLL+1,' ',WNORMAL);
  343.                 while ((WCURS%TABS) && (WCURS+1) < WIDTH-1);
  344.             break;
  345.         default:
  346.             if ((WCURS+1) < WIDTH-1)    {
  347.                 displ(wnd, WCURS+1, SCROLL+1, c, WNORMAL);
  348.                 WCURS++;
  349.             }
  350.             break;
  351.     }
  352. }
  353.  
  354. /* ------- set window cursor --------- */
  355. void wcursor(WINDOW *wnd, int x, int y)
  356. {
  357.     if (verify_wnd(&wnd) && x < WIDTH-1 && y < HEIGHT-1)    {
  358.         WCURS = x;
  359.         SCROLL = y;
  360.         cursor(COL+x+1, ROW+y+1);
  361.     }
  362. }
  363. /*page*/
  364. /* ------ allow the user to make a window selection ------ */
  365. int get_selection(WINDOW *wnd, int s, char *keys)
  366. {
  367.     int c = 0, ky;
  368.     if (!verify_wnd(&wnd))
  369.         return 0;
  370.     SELECT = s;
  371.     while (c != ESC && c != '\r' && c != BS && c != FWD)    {
  372.         accent(wnd);
  373.         c = get_char();
  374.         deaccent(wnd);
  375.         switch (c)        {
  376.             case UP:    if (SELECT >  1)
  377.                             SELECT--;
  378.                         else
  379.                             SELECT = SCROLL+1;
  380.                         break;
  381.             case DN:    if (SELECT < SCROLL+1)
  382.                             SELECT++;
  383.                         else 
  384.                             SELECT = 1;
  385.                         break;
  386.             case '\r':
  387.             case ESC:
  388.             case FWD:
  389.             case BS:    break;
  390.             default:    if (keys)    {
  391.                             ky = 0;
  392.                             while (*(keys + ky))    {
  393.                                 if (*(keys+ky)==toupper(c) ||
  394.                                     *(keys+ky)==tolower(c))
  395.                                     return ky + 1;
  396.                                 ky++;
  397.                             }
  398.                         }
  399.                         break;
  400.         }
  401.     }
  402.     return     c == '\r' ? SELECT : c == ESC ? 0 : c;
  403. }
  404.  
  405. union REGS rg;
  406.  
  407. /* ------- scroll a window's contents up or down --------- */
  408. void scroll(WINDOW *wnd, int dir)
  409. {
  410.     int row = HEIGHT-1, col, chat;
  411.  
  412.     if (!verify_wnd(&wnd))
  413.         return;
  414.     if (NEXT == NULL && HEIGHT > 3 && VISIBLE)    {
  415.         rg.h.ah = dir == UP ? 6 : 7;
  416.         rg.h.al = 1;
  417.         rg.h.bh = WNORMAL;
  418.         rg.h.cl = COL + 1;
  419.         rg.h.ch = ROW + 1;
  420.         rg.h.dl = COL + WIDTH - 2;
  421.         rg.h.dh = ROW + HEIGHT - 2;
  422.         int86(16, &rg, &rg);
  423.         return;
  424.     }
  425.     if (dir == UP)    {
  426.         for (row = 2; row < HEIGHT-1; row++)
  427.             for (col = 1; col < WIDTH-1; col++)    {
  428.                 chat = dget(wnd, col, row);
  429.                 displ(wnd,col,row-1,chat&255,(chat>>8)&255);
  430.             }
  431.         for (col = 1; col < WIDTH-1; col++)
  432.             displ(wnd, col, row-1, ' ', WNORMAL);
  433.     }
  434.     else    {
  435.         for (row = HEIGHT-2; row > 1; --row)
  436.             for (col = 1; col < WIDTH-1; col++)    {
  437.                 chat = dget(wnd, col, row);
  438.                 displ(wnd,col,row+1,chat&255,(chat>>8)&255);
  439.             }
  440.         for (col = 1; col < WIDTH-1; col++)
  441.             displ(wnd, col, row+1, ' ', WNORMAL);
  442.     }
  443. }
  444. /*page*/
  445. #ifndef FASTWINDOWS
  446. /* --- compute address of a window's display character --- */
  447. static int *waddr(WINDOW *wnd, int x, int y)
  448. {
  449.     WINDOW *nxt = NEXT;
  450.     int *vp;
  451.  
  452.     if (!VISIBLE)
  453.         return (int *) (SAV+y*(WIDTH*2)+x*2);
  454.     x += COL;
  455.     y += ROW;
  456.     while (nxt)    {
  457.         if (nxt->_wv)
  458.             if (x >= nxt->_wx && x <= nxt->_wx + nxt->_ww-1)
  459.                 if (y >= nxt->_wy &&
  460.                         y <= nxt->_wy + nxt->_wh-1)    {
  461.                     x -= nxt->_wx;
  462.                     y -= nxt->_wy;
  463.                     vp = (int *)
  464.                         ((nxt->_ws) +y*(nxt->_ww*2)+x*2);
  465.                     return vp;
  466.                 }
  467.         nxt = nxt->_nx;
  468.     }
  469.     return NULL;
  470. }
  471.  
  472. /* ---------- display a character to a window --------- */
  473. void displ(WINDOW *wnd, int x, int y, int ch, int at)
  474. {
  475.     int *vp;
  476.     int vch = (ch&255)|(at<<8);
  477.  
  478.     if ((vp = waddr(wnd, x, y)) != NULL)
  479.         *vp = vch;
  480.     else
  481.         vpoke(VSG,vad(x+COL,y+ROW),vch);
  482. }
  483. /*page*/
  484. /* ----- get a displayed character from a window ----- */
  485. static int dget(WINDOW *wnd, int x, int y)
  486. {
  487.     int *vp;
  488.  
  489.     if ((vp = waddr(wnd, x, y)) != NULL)
  490.         return *vp;
  491.     return vpeek(VSG,vad(x+COL,y+ROW));
  492. }
  493.  
  494. /* ------------- low-level video functions --------------- */
  495.  
  496. /* ------- swap the video image with the save buffer ----- */
  497. static vswap(WINDOW *wnd)
  498. {
  499.     int x, y, chat;
  500.     int *bf = (int *) SAV;
  501.  
  502.     for (y = 0; y < HEIGHT; y++)
  503.         for (x = 0; x < WIDTH; x++)    {
  504.             chat = *bf;
  505.             *bf++ = dget(wnd, x, y);
  506.             displ(wnd, x, y, chat&255, (chat>>8)&255);
  507.         }
  508. }
  509.  
  510. #else
  511.  
  512. /* -------- save video memory into the save buffer ---- */
  513. static vsave(WINDOW *wnd)
  514. {
  515.     int x, y;
  516.     int *bf = (int *) SAV;
  517.  
  518.     for (y = 0; y < HEIGHT; y++)
  519.         for (x = 0; x < WIDTH; x++)
  520.             *bf++ = vpeek(VSG, vad(x+COL, y+ROW));
  521. }
  522. /*page*/
  523. /* ----- restore video memory from the save buffer ----- */
  524. static vrstr(WINDOW *wnd)
  525. {
  526.     int x, y;
  527.     int *bf = (int *) SAV;
  528.  
  529.     for (y = 0; y < HEIGHT; y++)
  530.         for (x = 0; x < WIDTH; x++)
  531.             vpoke(VSG,vad(x+COL,y+ROW), *bf++);
  532. }
  533. #endif
  534.  
  535. /* ----- (de)accent the line where SELECT points ------- */
  536. void acline(WINDOW *wnd, int set)
  537. {
  538.     int x, ch;
  539.  
  540.     if (!verify_wnd(&wnd))
  541.         return;
  542.     for (x = 1; x < WIDTH - 1; x++)    {
  543.         ch = dget(wnd, x, SELECT) & 255;
  544.         displ(wnd, x, SELECT, ch, set);
  545.     }
  546. }
  547.  
  548. /* ---------- linked list functions --------- */
  549.  
  550. /* ----- add a window to the end of the list ------ */
  551. static add_list(WINDOW *wnd)
  552. {
  553.     if (listtail)    {
  554.         PREV = listtail;
  555.         listtail->_nx = wnd;
  556.     }
  557.     listtail = wnd;
  558.     if (!listhead)
  559.         listhead = wnd;
  560. }
  561. /*page*/
  562. /* ----- add a window to the beginning of the list ------ */
  563. static beg_list(WINDOW *wnd)
  564. {
  565.     if (listhead)    {
  566.         NEXT = listhead;
  567.         listhead->_pv = wnd;
  568.     }
  569.     listhead = wnd;
  570.     if (!listtail)
  571.         listtail = wnd;
  572. }
  573.  
  574. /* --------- remove a window from the list -------- */
  575. static remove_list(WINDOW *wnd)
  576. {
  577.     if (NEXT)
  578.         NEXT->_pv = PREV;
  579.     if (PREV)
  580.         PREV->_nx = NEXT;
  581.     if (listhead == wnd)
  582.         listhead = NEXT;
  583.     if (listtail == wnd)
  584.         listtail = PREV;
  585.     NEXT = PREV = NULL;
  586. }
  587.  
  588. /* ----- insert w1 after w2 ------ */
  589. static insert_list(WINDOW *w1, WINDOW *w2)
  590. {
  591.     w1->_pv = w2;
  592.     w1->_nx = w2->_nx;
  593.     w2->_nx = w1;
  594.     if (w1->_nx == NULL)
  595.         listtail = w1;
  596.     else
  597.         w1->_nx->_pv = w1;
  598. }
  599. /*page*/
  600. #ifndef FASTWINDOWS
  601. /* ---- verify the presence of a window in the list ----- */
  602. static verify_wnd(WINDOW **w1)
  603. {
  604.     WINDOW *wnd;
  605.  
  606.     if (*w1 == NULL)
  607.         *w1 = listtail;
  608.     else    {
  609.         wnd = listhead;
  610.         while (wnd != NULL)    {
  611.             if (*w1 == wnd)
  612.                 break;
  613.             wnd = NEXT;
  614.         }
  615.     }
  616.     return *w1 != NULL;
  617. }
  618. #endif
  619.  
  620. WINDOW *ewnd = NULL;
  621.  
  622. /* ------- error messages ------- */
  623. void error_message(char *s)
  624. {
  625.     ewnd = establish_window(50, 22, 3, max(10, strlen(s)+2));
  626.     set_colors(ewnd, ALL, RED, YELLOW, BRIGHT);
  627.     set_title(ewnd, " ERROR! ");
  628.     display_window(ewnd);
  629.     wprintf(ewnd, s);
  630.     putchar(BELL);
  631. }
  632.  
  633. void clear_message()
  634. {
  635.     if (ewnd)
  636.         delete_window(ewnd);
  637.     ewnd = NULL;
  638. }
  639.  
  640.  
  641.