home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 06 / dflat3 / window.c < prev   
Text File  |  1991-05-19  |  18KB  |  587 lines

  1. /* ---------- window.c ------------- */
  2.  
  3. #include <stdio.h>
  4. #include <conio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <dos.h>
  8. #include "dflat.h"
  9.  
  10. WINDOW inFocus = NULLWND;
  11.  
  12. int foreground, background;   /* current video colors */
  13.  
  14. static void TopLine(WINDOW, int, RECT);
  15.  
  16. /* --------- create a window ------------ */
  17. WINDOW CreateWindow(
  18.     CLASS class,              /* class of this window       */
  19.     char *ttl,                /* title or NULL              */
  20.     int left, int top,        /* upper left coordinates     */
  21.     int height, int width,    /* dimensions                 */
  22.     void *extension,          /* pointer to additional data */
  23.     WINDOW parent,            /* parent of this window      */
  24.     int (*wndproc)(struct window *,enum messages,PARAM,PARAM),
  25.     int attrib)               /* window attribute           */
  26. {
  27.     WINDOW wnd = malloc(sizeof(struct window));
  28.     get_videomode();
  29.     if (wnd != NULLWND)    {
  30.         int base;
  31.         /* ----- height, width = -1: fill the screen ------- */
  32.         if (height == -1)
  33.             height = SCREENHEIGHT;
  34.         if (width == -1)
  35.             width = SCREENWIDTH;
  36.         /* ----- coordinates -1, -1 = center the window ---- */
  37.         if (left == -1)
  38.             wnd->rc.lf = (SCREENWIDTH-width)/2;
  39.         else
  40.             wnd->rc.lf = left;
  41.         if (top == -1)
  42.             wnd->rc.tp = (SCREENHEIGHT-height)/2;
  43.         else
  44.             wnd->rc.tp = top;
  45.         wnd->attrib = attrib;
  46.         if (ttl != NULL)
  47.             AddAttribute(wnd, TITLEBAR);
  48.         if (wndproc == NULL)
  49.             wnd->wndproc = classdefs[FindClass(class)].wndproc;
  50.         else
  51.             wnd->wndproc = wndproc;
  52.         /* ---- derive attributes of base classes ---- */
  53.         base = class;
  54.         while (base != -1)    {
  55.             int tclass = FindClass(base);
  56.             AddAttribute(wnd, classdefs[tclass].attrib);
  57.             base = classdefs[tclass].base;
  58.         }
  59.         if (parent && !TestAttribute(wnd, NOCLIP))    {
  60.             /* -- keep upper left within borders of parent - */
  61.             wnd->rc.lf = max(wnd->rc.lf,GetClientLeft(parent));
  62.             wnd->rc.tp = max(wnd->rc.tp,GetClientTop(parent));
  63.         }
  64.         wnd->class = class;
  65.         wnd->extension = extension;
  66.         wnd->rc.rt = GetLeft(wnd)+width-1;
  67.         wnd->rc.bt = GetTop(wnd)+height-1;
  68.         wnd->ht = height;
  69.         wnd->wd = width;
  70.         wnd->title = NULL;
  71.         if (ttl != NULL)
  72.             InsertTitle(wnd, ttl);
  73.         wnd->next = wnd->prev = wnd->dFocus = NULLWND;
  74.         wnd->parent = parent;
  75.         wnd->videosave = NULL;
  76.         wnd->condition = ISRESTORED;
  77.         wnd->restored_attrib = 0;
  78.         wnd->RestoredRC = wnd->rc;
  79.         wnd->PrevKeyboard = wnd->PrevMouse = NULL;
  80.         wnd->DeletedText = NULL;
  81.         SendMessage(wnd, CREATE_WINDOW, 0, 0);
  82.         if (isVisible(wnd))
  83.             SendMessage(wnd, SHOW_WINDOW, 0, 0);
  84.     }
  85.     return wnd;
  86. }
  87.  
  88. /* -------- add a title to a window --------- */
  89. void AddTitle(WINDOW wnd, char *ttl)
  90. {
  91.     InsertTitle(wnd, ttl);
  92.     SendMessage(wnd, BORDER, 0, 0);
  93. }
  94.  
  95. /* ----- insert a title into a window ---------- */
  96. void InsertTitle(WINDOW wnd, char *ttl)
  97. {
  98.     if ((wnd->title=realloc(wnd->title,strlen(ttl)+1)) != NULL)
  99.         strcpy(wnd->title, ttl);
  100. }
  101.  
  102. /* ------- write a character to a window area at x,y ------- */
  103. void PutWindowChar(WINDOW wnd, int x, int y, int c)
  104. {
  105.     int x1 = GetLeft(wnd)+x;
  106.     int y1 = GetTop(wnd)+y;
  107.  
  108.     if (isVisible(wnd))    {
  109.         if (!TestAttribute(wnd, NOCLIP))    {
  110.             WINDOW wnd1 = GetParent(wnd);
  111.             while (wnd1 != NULLWND)    {
  112.                 /* --- clip character to parent's borders -- */
  113.                 if (x1 < GetClientLeft(wnd1)   ||
  114.                     x1 > GetClientRight(wnd1)  ||
  115.                     y1 > GetClientBottom(wnd1) ||
  116.                     y1 < GetClientTop(wnd1))
  117.                         return;
  118.                 wnd1 = GetParent(wnd1);
  119.             }
  120.         }
  121.         if (x1 < SCREENWIDTH && y1 < SCREENHEIGHT)
  122.             wputch(wnd, c, x, y);
  123.     }
  124. }
  125.  
  126. static char line[161];
  127.  
  128. #ifdef INCLUDE_SYSTEM_MENUS
  129.  
  130. /* ----- clip line if it extends below the bottom of the
  131.              parent window ------ */
  132. static int clipbottom(WINDOW wnd, int y)
  133. {
  134.     if (!TestAttribute(wnd, NOCLIP))    {
  135.         WINDOW wnd1 = GetParent(wnd);
  136.         while (wnd1 != NULLWND)    {
  137.             if (GetClientTop(wnd)+y > GetClientBottom(wnd1)+1)
  138.                 return TRUE;
  139.             wnd1 = GetParent(wnd1);
  140.         }
  141.     }
  142.     return GetTop(wnd)+y > SCREENHEIGHT;
  143. }
  144.  
  145. /* ------ clip the portion of a line that extends past the
  146.                      right margin of the parent window ----- */
  147. void clipline(WINDOW wnd, int x, char *ln)
  148. {
  149.     WINDOW pwnd = GetParent(wnd);
  150.     int x1 = strlen(ln);
  151.     int i = 0;
  152.  
  153.     if (!TestAttribute(wnd, NOCLIP))    {
  154.         while (pwnd != NULLWND)    {
  155.             x1 = GetClientRight(pwnd) - GetLeft(wnd) - x + 1;
  156.             pwnd = GetParent(pwnd);
  157.         }
  158.     }
  159.     else if (GetLeft(wnd) + x > SCREENWIDTH)
  160.         x1 = SCREENWIDTH-GetLeft(wnd) - x;
  161.     /* --- adjust the clipping offset for color controls --- */
  162.     if (x1 < 0)
  163.         x1 = 0;
  164.     while (i < x1)    {
  165.         if ((unsigned char) ln[i] == CHANGECOLOR)
  166.             i += 3, x1 += 3;
  167.         else if ((unsigned char) ln[i] == RESETCOLOR)
  168.             i++, x1++;
  169.         else 
  170.             i++;
  171.     }
  172.     ln[x1] = '\0';
  173. }
  174. #else
  175. #define clipbottom(w,y) FALSE
  176. #endif
  177.  
  178. /* ------ write a line to video window client area ------ */
  179. void writeline(WINDOW wnd, char *str, int x, int y, int pad)
  180. {
  181.     static char wline[120];
  182.  
  183.     if (!clipbottom(wnd, y))
  184.     {
  185.         char *cp;
  186.         int len;
  187.         int dif;
  188.  
  189.         memset(wline, 0, sizeof wline);
  190.         len = LineLength(str);
  191.         dif = strlen(str) - len;
  192.         strncpy(wline, str, ClientWidth(wnd) + dif);
  193.         if (pad)    {
  194.             cp = wline+strlen(wline);
  195.             while (len++ < ClientWidth(wnd)-x)
  196.                 *cp++ = ' ';
  197.         }
  198.         clipline(wnd, x, wline);
  199.         wputs(wnd, wline, x, y);
  200.     }
  201. }
  202.  
  203. /* -- write a line to video window (including the border) -- */
  204. void writefull(WINDOW wnd, char *str, int y)
  205. {
  206.     if (!clipbottom(wnd, y))    {
  207.         strcpy(line, str);
  208.         clipline(wnd, 0, line);
  209.         wputs(wnd, line, 0, y);
  210.     }
  211. }
  212.  
  213. RECT AdjustRectangle(WINDOW wnd, RECT rc)
  214. {
  215.     /* -------- adjust the rectangle ------- */
  216.     if (TestAttribute(wnd, HASBORDER))    {
  217.         if (RectLeft(rc) == 0)
  218.             --rc.rt;
  219.         else if (RectLeft(rc) < RectRight(rc) &&
  220.                 RectLeft(rc) < WindowWidth(wnd)+1)
  221.             --rc.lf;
  222.     }
  223.     if (TestAttribute(wnd, HASBORDER | TITLEBAR))    {
  224.         if (RectTop(rc) == 0)
  225.             --rc.bt;
  226.         else if (RectTop(rc) < RectBottom(rc) &&
  227.                 RectTop(rc) < WindowHeight(wnd)+1)
  228.             --rc.tp;
  229.     }
  230.     RectRight(rc) = max(RectLeft(rc),
  231.                         min(RectRight(rc),WindowWidth(wnd)));
  232.     RectBottom(rc) = max(RectTop(rc),
  233.                         min(RectBottom(rc),WindowHeight(wnd)));
  234.     return rc;
  235. }
  236.  
  237. /* -------- display a window's title --------- */
  238. void DisplayTitle(WINDOW wnd, RECT *rcc)
  239. {
  240.     int tlen = min(strlen(wnd->title), WindowWidth(wnd)-2);
  241.     int tend = WindowWidth(wnd)-3-BorderAdj(wnd);
  242.     RECT rc;
  243.  
  244.     if (rcc == NULL)
  245.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  246.     else
  247.         rc = *rcc;
  248.     rc = AdjustRectangle(wnd, rc);
  249.  
  250.     if (SendMessage(wnd, TITLE, LPARAM(rcc), 0))    {
  251.         if (wnd == inFocus)    {
  252.             foreground = cfg.clr.InFocusTitleFG;
  253.             background = cfg.clr.InFocusTitleBG;
  254.         }
  255.         else    {
  256.             foreground = cfg.clr.TitleFG;
  257.             background = cfg.clr.TitleBG;
  258.         }
  259.         memset(line,' ',WindowWidth(wnd));
  260.         if (wnd->condition != ISMINIMIZED)
  261.             strncpy(line + ((WindowWidth(wnd)-2 - tlen) / 2),
  262.                 wnd->title, tlen);
  263.         if (TestAttribute(wnd, CONTROLBOX))
  264.             line[2-BorderAdj(wnd)] = CONTROLBOXCHAR;
  265. #ifdef INCLUDE_SYSTEM_MENUS
  266.         if (TestAttribute(wnd, MINMAXBOX))    {
  267.             switch (wnd->condition)    {
  268.                 case ISRESTORED:
  269.                     line[tend+1] = MAXPOINTER;
  270.                     line[tend]   = MINPOINTER;
  271.                     break;
  272.                 case ISMINIMIZED:
  273.                     line[tend+1] = MAXPOINTER;
  274.                     break;
  275.                 case ISMAXIMIZED:
  276.                     line[tend]   = MINPOINTER;
  277.                     line[tend+1] = RESTOREPOINTER;
  278.                     break;
  279.                 default:
  280.                     break;
  281.             }
  282.         }
  283. #endif
  284.         line[RectRight(rc)+1] = line[tend+3] = '\0';
  285.         writeline(wnd, line+RectLeft(rc),
  286.                        RectLeft(rc)+BorderAdj(wnd),
  287.                        0,
  288.                        FALSE);
  289.     }
  290. }
  291.  
  292. #ifdef INCLUDE_SHADOWS
  293. /* --- display right border shadow character of a window --- */
  294. static void near shadow_char(WINDOW wnd, int y)
  295. {
  296.     int fg = foreground;
  297.     int bg = background;
  298.     int x = WindowWidth(wnd);
  299.     int c = videochar(GetLeft(wnd)+x, GetTop(wnd)+y);
  300.  
  301.     if (TestAttribute(wnd, SHADOW) == 0)
  302.         return;
  303.     foreground = DARKGRAY;
  304.     background = BLACK;
  305.     PutWindowChar(wnd, x, y, c);
  306.     foreground = fg;
  307.     background = bg;
  308. }
  309.  
  310. /* --- display the bottom border shadow line for a window -- */
  311. static void near shadowline(WINDOW wnd, RECT rc)
  312. {
  313.     int i;
  314.     int y = GetBottom(wnd)+1;
  315.  
  316.     if ((TestAttribute(wnd, SHADOW)) == 0)
  317.         return;
  318.     if (!clipbottom(wnd, WindowHeight(wnd)))    {
  319.         int fg = foreground;
  320.         int bg = background;
  321.         for (i = 0; i < WindowWidth(wnd)+1; i++)
  322.             line[i] = videochar(GetLeft(wnd)+i, y);
  323.         line[i] = '\0';
  324.         foreground = DARKGRAY;
  325.         background = BLACK;
  326.         clipline(wnd, 1, line);
  327.         line[RectRight(rc)+1] = '\0';
  328.         if (RectLeft(rc) == 0)
  329.             rc.lf++;
  330.         wputs(wnd, line+RectLeft(rc), RectLeft(rc),
  331.             WindowHeight(wnd));
  332.         foreground = fg;
  333.         background = bg;
  334.     }
  335. }
  336. #endif
  337.  
  338. /* ------- display a window's border ----- */
  339. void RepaintBorder(WINDOW wnd, RECT *rcc)
  340. {
  341.     int y;
  342.     int lin, side, ne, nw, se, sw;
  343.     RECT rc, clrc;
  344.  
  345.     if (!TestAttribute(wnd, HASBORDER))
  346.         return;
  347.     if (rcc == NULL)    {
  348.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  349. #ifdef INCLUDE_SHADOWS
  350.         if (TestAttribute(wnd, SHADOW))    {
  351.             rc.rt++;
  352.             rc.bt++;
  353.         }
  354. #endif
  355.     }
  356.     else
  357.         rc = *rcc;
  358.  
  359.     clrc = AdjustRectangle(wnd, rc);
  360.  
  361.     if (wnd == inFocus)    {
  362.         lin  = FOCUS_LINE;
  363.         side = FOCUS_SIDE;
  364.         ne   = FOCUS_NE;
  365.         nw   = FOCUS_NW;
  366.         se   = FOCUS_SE;
  367.         sw   = FOCUS_SW;
  368.     }
  369.     else    {
  370.         lin  = LINE;
  371.         side = SIDE;
  372.         ne   = NE;
  373.         nw   = NW;
  374.         se   = SE;
  375.         sw   = SW;
  376.     }
  377.     line[WindowWidth(wnd)] = '\0';
  378.     /* ---------- window title ------------ */
  379.     if (TestAttribute(wnd, TITLEBAR))
  380.         if (RectTop(rc) == 0)
  381.             if (RectLeft(rc) < WindowWidth(wnd)-BorderAdj(wnd))
  382.                 DisplayTitle(wnd, &rc);
  383.     foreground = FrameForeground(wnd);
  384.     background = FrameBackground(wnd);
  385.     /* -------- top frame corners --------- */
  386.     if (RectTop(rc) == 0)    {
  387.         if (RectLeft(rc) == 0)
  388.             PutWindowChar(wnd, 0, 0, nw);
  389.         if (RectLeft(rc) < WindowWidth(wnd))    {
  390.             if (RectRight(rc) >= WindowWidth(wnd)-1)
  391.                 PutWindowChar(wnd, WindowWidth(wnd)-1, 0, ne);
  392.             TopLine(wnd, lin, rc);
  393.         }
  394.     }
  395.  
  396.     /* ----------- window body ------------ */
  397.     for (y = RectTop(rc); y <= RectBottom(rc); y++)    {
  398.         int ch;
  399.         if (y == 0 || y >= WindowHeight(wnd)-1)
  400.             continue;
  401.         if (RectLeft(rc) == 0)
  402.             PutWindowChar(wnd, 0, y, side);
  403.         if (RectLeft(rc) < WindowWidth(wnd) &&
  404.                 RectRight(rc) >= WindowWidth(wnd)-1)    {
  405. #ifdef INCLUDE_SCROLLBARS
  406.             if (TestAttribute(wnd, VSCROLLBAR))
  407.                 ch = (    y == 1 ? UPSCROLLBOX       :
  408.                             y == WindowHeight(wnd)-2  ?
  409.                                 DOWNSCROLLBOX       :
  410.                             y-1 == wnd->VScrollBox    ?
  411.                                 SCROLLBOXCHAR       :
  412.                                 SCROLLBARCHAR );
  413.             else
  414. #endif
  415.                 ch = side;
  416.             PutWindowChar(wnd, WindowWidth(wnd)-1, y, ch);
  417.         }
  418. #ifdef INCLUDE_SHADOWS
  419.         if (RectRight(rc) == WindowWidth(wnd))
  420.             shadow_char(wnd, y);
  421. #endif
  422.     }
  423.  
  424.     if (RectTop(rc) <= WindowHeight(wnd)-1 &&
  425.             RectBottom(rc) >= WindowHeight(wnd)-1)    {
  426.         /* -------- bottom frame corners ---------- */
  427.         if (RectLeft(rc) == 0)
  428.             PutWindowChar(wnd, 0, WindowHeight(wnd)-1, sw);
  429.         if (RectLeft(rc) < WindowWidth(wnd) &&
  430.                 RectRight(rc) >= WindowWidth(wnd)-1)
  431.             PutWindowChar(wnd, WindowWidth(wnd)-1,
  432.                 WindowHeight(wnd)-1, se);
  433.  
  434.  
  435.         /* ----------- bottom line ------------- */
  436.         memset(line,lin,WindowWidth(wnd)-1);
  437. #ifdef INCLUDE_SCROLLBARS
  438.         if (TestAttribute(wnd, HSCROLLBAR))    {
  439.             line[0] = LEFTSCROLLBOX;
  440.             line[WindowWidth(wnd)-3] = RIGHTSCROLLBOX;
  441.             memset(line+1, SCROLLBARCHAR, WindowWidth(wnd)-4);
  442.             line[wnd->HScrollBox] = SCROLLBOXCHAR;
  443.         }
  444. #endif
  445.         line[WindowWidth(wnd)-2] = line[RectRight(rc)] = '\0';
  446.         if (RectLeft(rc) != RectRight(rc) ||
  447.            (RectLeft(rc) && RectLeft(rc) < WindowWidth(wnd)-1))
  448.             writeline(wnd,
  449.                 line+(RectLeft(clrc)),
  450.                 RectLeft(clrc)+1,
  451.                 WindowHeight(wnd)-1,
  452.                 FALSE);
  453. #ifdef INCLUDE_SHADOWS
  454.         if (RectRight(rc) == WindowWidth(wnd))
  455.             shadow_char(wnd, WindowHeight(wnd)-1);
  456. #endif
  457.     }
  458. #ifdef INCLUDE_SHADOWS
  459.     if (RectBottom(rc) == WindowHeight(wnd))
  460.         /* ---------- bottom shadow ------------- */
  461.         shadowline(wnd, rc);
  462. #endif
  463. }
  464.  
  465. static void TopLine(WINDOW wnd, int lin, RECT rc)
  466. {
  467.     if (TestAttribute(wnd, TITLEBAR | HASMENUBAR))
  468.         return;
  469.  
  470.     if (RectLeft(rc) < RectRight(rc))    {
  471.         /* ----------- top line ------------- */
  472.         memset(line,lin,WindowWidth(wnd)-1);
  473.         line[RectRight(rc)] = '\0';
  474.         writeline(wnd, line+RectLeft(rc),
  475.             RectLeft(rc)+1, 0, FALSE);
  476.     }
  477. }
  478.  
  479. /* ------ clear the data space of a window -------- */
  480. void ClearWindow(WINDOW wnd, RECT *rcc, int clrchar)
  481. {
  482.     if (isVisible(wnd))    {
  483.         int y;
  484.         RECT rc;
  485.  
  486.         if (rcc == NULL)
  487.             rc = RelativeWindowRect(wnd, WindowRect(wnd));
  488.         else
  489.             rc = *rcc;
  490.  
  491.         if (RectLeft(rc) == 0)
  492.             RectLeft(rc) = BorderAdj(wnd);
  493.         if (RectRight(rc) > WindowWidth(wnd)-1)
  494.             RectRight(rc) = WindowWidth(wnd)-1;
  495.         SetStandardColor(wnd);
  496.         memset(line, clrchar, sizeof line);
  497.         line[RectRight(rc)+1] = '\0';
  498.         for (y = RectTop(rc); y <= RectBottom(rc); y++)    {
  499.             if (y < TopBorderAdj(wnd) ||
  500.                     y >= WindowHeight(wnd)-1)
  501.                 continue;
  502.             writeline(wnd,
  503.                 line+(RectLeft(rc)),
  504.                 RectLeft(rc),
  505.                 y,
  506.                 FALSE);
  507.         }
  508.     }
  509. }
  510.  
  511. /* -- adjust a window's rectangle to clip it to its parent - */
  512. static RECT near ClipRect(WINDOW wnd)
  513. {
  514.     RECT rc;
  515.     rc = wnd->rc;
  516. #ifdef INCLUDE_SHADOWS
  517.     if (TestAttribute(wnd, SHADOW))    {
  518.         RectBottom(rc)++;
  519.         RectRight(rc)++;
  520.     }
  521. #endif
  522.     if (!TestAttribute(wnd, NOCLIP))    {
  523.         WINDOW pwnd = GetParent(wnd);
  524.         if (pwnd != NULLWND)    {
  525.             RectTop(rc) = max(RectTop(rc),
  526.                         GetClientTop(pwnd));
  527.             RectLeft(rc) = max(RectLeft(rc),
  528.                         GetClientLeft(pwnd));
  529.             RectRight(rc) = min(RectRight(rc),
  530.                         GetClientRight(pwnd));
  531.             RectBottom(rc) = min(RectBottom(rc),
  532.                         GetClientBottom(pwnd));
  533.         }
  534.     }
  535.     RectRight(rc) = min(RectRight(rc), SCREENWIDTH-1);
  536.     RectBottom(rc) = min(RectBottom(rc), SCREENHEIGHT-1);
  537.     RectLeft(rc) = min(RectLeft(rc), SCREENWIDTH-1);
  538.     RectTop(rc) = min(RectTop(rc), SCREENHEIGHT-1);
  539.     return rc;
  540. }
  541.  
  542. /* -- get the video memory that is to be used by a window -- */
  543. void GetVideoBuffer(WINDOW wnd)
  544. {
  545.     RECT rc;
  546.     int ht;
  547.     int wd;
  548.  
  549.     rc = ClipRect(wnd);
  550.     ht = RectBottom(rc) - RectTop(rc) + 1;
  551.     wd = RectRight(rc) - RectLeft(rc) + 1;
  552.     wnd->videosave = realloc(wnd->videosave, (ht * wd * 2));
  553.     get_videomode();
  554.     if (wnd->videosave != NULL)
  555.         getvideo(rc, wnd->videosave);
  556. }
  557.  
  558. /* --- restore the video memory that was used by a window -- */
  559. void RestoreVideoBuffer(WINDOW wnd)
  560. {
  561.     if (wnd->videosave != NULL)    {
  562.         RECT rc;
  563.         rc = ClipRect(wnd);
  564.         storevideo(rc, wnd->videosave);
  565.         free(wnd->videosave);
  566.         wnd->videosave = NULL;
  567.     }
  568. }
  569.  
  570. /* ------ compute the logical line length of a window ------ */
  571. int LineLength(char *ln)
  572. {
  573.     int len = strlen(ln);
  574.     char *cp = ln;
  575.     while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  576.         cp++;
  577.         len -= 3;
  578.     }
  579.     cp = ln;
  580.     while ((cp = strchr(cp, RESETCOLOR)) != NULL)    {
  581.         cp++;
  582.         --len;
  583.     }
  584.     return len;
  585. }
  586.  
  587.