home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / magazine / drdobbs / 1991 / 08 / c_prog.asc < prev    next >
Text File  |  1991-07-23  |  33KB  |  922 lines

  1. _C PROGRAMMING COLUMN_
  2. by Al Stevens
  3.  
  4.  
  5.  
  6. [LISTING ONE]
  7.  
  8. /* ------------- dflat.h ----------- */
  9. #ifndef WINDOW_H
  10. #define WINDOW_H
  11.  
  12. #define VERSION "Version 3 Beta"
  13. #define TRUE 1
  14. #define FALSE 0
  15.  
  16. #include "system.h"
  17. #include "config.h"
  18. #include "rect.h"
  19. #include "menu.h"
  20. #include "keys.h"
  21. #include "commands.h"
  22. #include "config.h"
  23. #include "dialbox.h"
  24.  
  25. /* ------ integer type for message parameters ----- */
  26. typedef long PARAM;
  27. #define TE(m) m
  28. typedef enum window_class    {
  29. #include "classes.h"
  30. } CLASS;
  31. typedef struct window {
  32.     CLASS class;           /* window class                  */
  33.     char *title;           /* window title                  */
  34.     struct window *parent; /* parent window                 */
  35.     int (*wndproc)
  36.         (struct window *, enum messages, PARAM, PARAM);
  37.     /* ---------------- window dimensions ----------------- */
  38.     RECT rc;               /* window coordinates (0/0 to 79/24)  */
  39.     int ht, wd;            /* window height and width       */
  40.     RECT RestoredRC;       /* restored condition rect       */
  41.     /* -------------- linked list pointers ---------------- */
  42.     struct window *next;        /* next window on screen    */
  43.     struct window *prev;        /* previous window on screen*/
  44.     struct window *nextbuilt;   /* next window built        */
  45.     struct window *prevbuilt;   /* previous window built    */
  46.     int attrib;                 /* Window attributes        */
  47.     char *videosave;            /* video save buffer        */
  48.     int condition;              /* Restored, Maximized, Minimized */
  49.     int restored_attrib;        /* attributes when restored */
  50.     void *extension;            /* -> menus, dialog box, etc*/
  51.     struct window *PrevMouse;
  52.     struct window *PrevKeyboard;
  53.     /* ----------------- text box fields ------------------ */
  54.     int wlines;     /* number of lines of text              */
  55.     int wtop;       /* text line that is on the top display */
  56.     char *text;     /* window text                          */
  57.     int textlen;    /* text length                          */
  58.     int wleft;      /* left position in window viewport     */
  59.     int textwidth;  /* width of longest line in textbox     */
  60.     int BlkBegLine; /* beginning line of marked block       */
  61.     int BlkBegCol;  /* beginning column of marked block     */
  62.     int BlkEndLine; /* ending line of marked block          */
  63.     int BlkEndCol;  /* ending column of marked block        */
  64.     int HScrollBox; /* position of horizontal scroll box    */
  65.     int VScrollBox; /* position of vertical scroll box      */
  66.     /* ----------------- list box fields ------------------ */
  67.     int selection;  /* current selection                    */
  68.     int AddMode;    /* adding extended selections mode      */
  69.     int AnchorPoint;/* anchor point for extended selections */
  70.     int SelectCount;/* count of selected items              */
  71.     /* ----------------- edit box fields ------------------ */
  72.     int CurrCol;    /* Current column                       */
  73.     int CurrLine;   /* Current line                         */
  74.     int WndRow;     /* Current window row                   */
  75.     int TextChanged; /* TRUE if text has changed            */
  76.     char *DeletedText; /* for undo                          */
  77.     int DeletedLength; /*  "   "                            */
  78.     /* ---------------- dialog box fields ----------------- */
  79.     struct window *dFocus; /* control that has the focus    */
  80.     int ReturnCode;        /* return code from a dialog box */
  81. } * WINDOW;
  82. #include "message.h"
  83. #include "classdef.h"
  84. #include "video.h"
  85. enum Condition     {
  86.     ISRESTORED, ISMINIMIZED, ISMAXIMIZED
  87. };
  88. void LogMessages (WINDOW, MESSAGE, PARAM, PARAM);
  89. void MessageLog(WINDOW);
  90. /* ------- window methods ----------- */
  91. #define WindowHeight(w)      ((w)->ht)
  92. #define WindowWidth(w)       ((w)->wd)
  93. #define BorderAdj(w)         (TestAttribute(w,HASBORDER)?1:0)
  94. #define TopBorderAdj(w)      ((TestAttribute(w,TITLEBAR) &&   \
  95.                               TestAttribute(w,HASMENUBAR)) ?  \
  96.                               2 : (TestAttribute(w,TITLEBAR | \
  97.                               HASMENUBAR | HASBORDER) ? 1 : 0))
  98. #define ClientWidth(w)       (WindowWidth(w)-BorderAdj(w)*2)
  99. #define ClientHeight(w)      (WindowHeight(w)-TopBorderAdj(w)-\
  100.                               BorderAdj(w))
  101. #define WindowRect(w)        ((w)->rc)
  102. #define GetTop(w)            (RectTop(WindowRect(w)))
  103. #define GetBottom(w)         (RectBottom(WindowRect(w)))
  104. #define GetLeft(w)           (RectLeft(WindowRect(w)))
  105. #define GetRight(w)          (RectRight(WindowRect(w)))
  106. #define GetClientTop(w)      (GetTop(w)+TopBorderAdj(w))
  107. #define GetClientBottom(w)   (GetBottom(w)-BorderAdj(w))
  108. #define GetClientLeft(w)     (GetLeft(w)+BorderAdj(w))
  109. #define GetClientRight(w)    (GetRight(w)-BorderAdj(w))
  110. #define GetParent(w)         ((w)->parent)
  111. #define GetTitle(w)          ((w)->title)
  112. #define NextWindow(w)        ((w)->next)
  113. #define PrevWindow(w)        ((w)->prev)
  114. #define NextWindowBuilt(w)   ((w)->nextbuilt)
  115. #define PrevWindowBuilt(w)   ((w)->prevbuilt)
  116. #define GetClass(w)          ((w)->class)
  117. #define GetAttribute(w)      ((w)->attrib)
  118. #define AddAttribute(w,a)    (GetAttribute(w) |= a)
  119. #define ClearAttribute(w,a)  (GetAttribute(w) &= ~(a))
  120. #define TestAttribute(w,a)   (GetAttribute(w) & (a))
  121. #define isVisible(w)         (GetAttribute(w) & VISIBLE)
  122. #define SetVisible(w)        (GetAttribute(w) |= VISIBLE)
  123. #define ClearVisible(w)      (GetAttribute(w) &= ~VISIBLE)
  124. #define gotoxy(w,x,y) cursor(w->rc.lf+(x)+1,w->rc.tp+(y)+1)
  125. WINDOW CreateWindow(CLASS,char *,int,int,int,int,void*,WINDOW,
  126.        int (*)(struct window *,enum messages,PARAM,PARAM),int);
  127. void AddTitle(WINDOW, char *);
  128. void InsertTitle(WINDOW, char *);
  129. void DisplayTitle(WINDOW, RECT *);
  130. void RepaintBorder(WINDOW, RECT *);
  131. void ClearWindow(WINDOW, RECT *, int);
  132. #ifdef INCLUDE_SYSTEM_MENUS
  133. void clipline(WINDOW, int, char *);
  134. #else
  135. #define clipline(w,x,c) /**/
  136. #endif
  137. void writeline(WINDOW, char *, int, int, int);
  138. void writefull(WINDOW, char *, int);
  139. void SetNextFocus(WINDOW,int);
  140. void SetPrevFocus(WINDOW,int);
  141. void PutWindowChar(WINDOW, int, int, int);
  142. void GetVideoBuffer(WINDOW);
  143. void RestoreVideoBuffer(WINDOW);
  144. void CreatePath(char *, char *, int, int);
  145. int LineLength(char *);
  146. RECT AdjustRectangle(WINDOW, RECT);
  147. #define DisplayBorder(wnd) RepaintBorder(wnd, NULL)
  148. #define DefaultWndProc(wnd,msg,p1,p2)    \
  149.     (*classdefs[FindClass(wnd->class)].wndproc)(wnd,msg,p1,p2)
  150. #define BaseWndProc(class,wnd,msg,p1,p2)    \
  151.     (*classdefs[DerivedClass(class)].wndproc)(wnd,msg,p1,p2)
  152. #define NULLWND ((WINDOW) 0)
  153. struct LinkedList    {
  154.     WINDOW FirstWindow;
  155.     WINDOW LastWindow;
  156. };
  157. extern struct LinkedList Focus;
  158. extern struct LinkedList Built;
  159. extern WINDOW inFocus;
  160. extern WINDOW CaptureMouse;
  161. extern WINDOW CaptureKeyboard;
  162. extern int foreground, background;
  163. extern int WindowMoving;
  164. extern int WindowSizing;
  165. extern int TextMarking;
  166. extern char *Clipboard;
  167. extern WINDOW SystemMenuWnd;
  168. /* --------------- border characters ------------- */
  169. #define FOCUS_NW       '\xc9'
  170. #define FOCUS_NE       '\xbb'
  171. #define FOCUS_SE       '\xbc'
  172. #define FOCUS_SW       '\xc8'
  173. #define FOCUS_SIDE     '\xba'
  174. #define FOCUS_LINE     '\xcd'
  175. #define NW             '\xda'
  176. #define NE             '\xbf'
  177. #define SE             '\xd9'
  178. #define SW             '\xc0'
  179. #define SIDE           '\xb3'
  180. #define LINE           '\xc4'
  181. #define LEDGE          '\xc3'
  182. #define REDGE          '\xb4'
  183. /* ------------- scroll bar characters ------------ */
  184. #define UPSCROLLBOX    '\x1e'
  185. #define DOWNSCROLLBOX  '\x1f'
  186. #define LEFTSCROLLBOX  '\x11'
  187. #define RIGHTSCROLLBOX '\x10'
  188. #define SCROLLBARCHAR  176 
  189. #define SCROLLBOXCHAR  178
  190. #define CHECKMARK      251      /* menu item toggle         */
  191. /* ----------------- title bar characters ----------------- */
  192. #define CONTROLBOXCHAR '\xf0'
  193. #define MAXPOINTER     24      /* maximize token            */
  194. #define MINPOINTER     25      /* minimize token            */
  195. #define RESTOREPOINTER 18      /* restore token             */
  196. /* --------------- text control characters ---------------- */
  197. #define APPLCHAR     176    /* fills application window     */
  198. #define SHORTCUTCHAR '~'    /* prefix: shortcut key display */
  199. #define CHANGECOLOR  174    /* prefix to change colors      */
  200. #define RESETCOLOR   175    /* reset colors to default      */
  201. #define LISTSELECTOR   4    /* selected list box entry      */
  202. /* ---- standard window message processing prototypes ----- */
  203. int ApplicationProc(WINDOW, MESSAGE, PARAM, PARAM);
  204. int NormalProc(WINDOW, MESSAGE, PARAM, PARAM);
  205. int TextBoxProc(WINDOW, MESSAGE, PARAM, PARAM);
  206. int ListBoxProc(WINDOW, MESSAGE, PARAM, PARAM);
  207. int EditBoxProc(WINDOW, MESSAGE, PARAM, PARAM);
  208. int MenuBarProc(WINDOW, MESSAGE, PARAM, PARAM);
  209. int PopDownProc(WINDOW, MESSAGE, PARAM, PARAM);
  210. int ButtonProc(WINDOW, MESSAGE, PARAM, PARAM);
  211. int DialogProc(WINDOW, MESSAGE, PARAM, PARAM);
  212. int SystemMenuProc(WINDOW, MESSAGE, PARAM, PARAM);
  213. int HelpBoxProc(WINDOW, MESSAGE, PARAM, PARAM);
  214. int MessageBoxProc(WINDOW, MESSAGE, PARAM, PARAM);
  215. /* ------------- normal box prototypes ------------- */
  216. int isWindow(WINDOW);
  217. WINDOW inWindow(int, int);
  218. int WndForeground(WINDOW);
  219. int WndBackground(WINDOW);
  220. int FrameForeground(WINDOW);
  221. int FrameBackground(WINDOW);
  222. int SelectForeground(WINDOW);
  223. int SelectBackground(WINDOW);
  224. void SetStandardColor(WINDOW);
  225. void SetReverseColor(WINDOW);
  226. void SetClassColors(CLASS);
  227. WINDOW GetFirstChild(WINDOW);
  228. WINDOW GetNextChild(WINDOW);
  229. WINDOW GetLastChild(WINDOW);
  230. WINDOW GetPrevChild(WINDOW);
  231. #define HitControlBox(wnd, p1, p2)     \
  232.     (TestAttribute(wnd, TITLEBAR)   && \
  233.      TestAttribute(wnd, CONTROLBOX) && \
  234.      p1 == 2 && p2 == 0)
  235. /* -------- text box prototypes ---------- */
  236. #define TextLine(wnd, sel) \
  237.       (wnd->text + *((int *)(wnd->extension) + sel))
  238. void WriteTextLine(WINDOW, RECT *, int, int);
  239. void SetAnchor(WINDOW, int, int);
  240. #define BlockMarked(wnd) (  wnd->BlkBegLine ||    \
  241.                             wnd->BlkEndLine ||    \
  242.                             wnd->BlkBegCol  ||    \
  243.                             wnd->BlkEndCol)
  244. #define ClearBlock(wnd) wnd->BlkBegLine = wnd->BlkEndLine =  \
  245.                         wnd->BlkBegCol  = wnd->BlkEndCol = 0;
  246. #define GetText(w)        ((w)->text)
  247. void ClearTextPointers(WINDOW);
  248. void BuildTextPointers(WINDOW);
  249. /* --------- menu prototypes ---------- */
  250. int CopyCommand(char *, char *, int, int);
  251. void PrepOptionsMenu(void *, struct Menu *);
  252. void PrepEditMenu(void *, struct Menu *);
  253. void PrepWindowMenu(void *, struct Menu *);
  254. void BuildSystemMenu(WINDOW);
  255. int isActive(MENU *, int);
  256. void ActivateCommand(MENU *,int);
  257. void DeactivateCommand(MENU *,int);
  258. int GetCommandToggle(MENU *,int);
  259. void SetCommandToggle(MENU *,int);
  260. void ClearCommandToggle(MENU *,int);
  261. void InvertCommandToggle(MENU *,int);
  262. /* ------------- list box prototypes -------------- */
  263. int ItemSelected(WINDOW, int);
  264. /* ------------- edit box prototypes ----------- */
  265. #ifdef INCLUDE_MULTILINE
  266. #define isMultiLine(wnd)     TestAttribute(wnd, MULTILINE)
  267. #else
  268. #define isMultiLine(wnd)     FALSE
  269. #endif
  270. /* --------- message box prototypes -------- */
  271. void MessageBox(char *, char *);
  272. void ErrorMessage(char *);
  273. int TestErrorMessage(char *);
  274. int YesNoBox(char *);
  275. int MsgHeight(char *);
  276. int MsgWidth(char *);
  277.  
  278. #ifdef INCLUDE_DIALOG_BOXES
  279. /* ------------- dialog box prototypes -------------- */
  280. int DialogBox(WINDOW,DBOX *,int(*)(struct window *,enum messages,PARAM,PARAM));
  281. int DlgOpenFile(char *, char *);
  282. int DlgSaveAs(char *);
  283. void GetDlgListText(WINDOW, char *, enum commands);
  284. int DlgDirList(WINDOW, char *, enum commands, enum commands, unsigned);
  285. int RadioButtonSetting(DBOX *, enum commands);
  286. void PushRadioButton(DBOX *, enum commands);
  287. void PutItemText(WINDOW, enum commands, char *);
  288. void GetItemText(WINDOW, enum commands, char *, int);
  289. void SetCheckBox(DBOX *, enum commands);
  290. void ClearCheckBox(DBOX *, enum commands);
  291. int CheckBoxSetting(DBOX *, enum commands);
  292. WINDOW ControlWindow(DBOX *, enum commands);
  293. CTLWINDOW *ControlBox(DBOX *, WINDOW);
  294. #endif
  295. /* ------------- help box prototypes ------------- */
  296. void HelpFunction(void);
  297. void LoadHelpFile(void);
  298. #define swap(a,b){int x=a;a=b;b=x;}
  299.  
  300. #endif
  301.  
  302.  
  303.  
  304.  
  305. [LISTING TWO]
  306.  
  307. /* ---------------- config.h -------------- */
  308.  
  309. #ifndef CONFIG_H
  310. #define CONFIG_H
  311.  
  312. #define DFLAT_APPLICATION "MEMOPAD"
  313.  
  314. #ifdef BUILD_FULL_DFLAT
  315. #define INCLUDE_SYSTEM_MENUS
  316. #define INCLUDE_CLOCK
  317. #define INCLUDE_MULTIDOCS
  318. #define INCLUDE_SCROLLBARS
  319. #define INCLUDE_SHADOWS
  320. #define INCLUDE_DIALOG_BOXES
  321. #define INCLUDE_CLIPBOARD
  322. #define INCLUDE_MULTILINE
  323. #define INCLUDE_LOGGING
  324. #endif
  325.  
  326. struct colors {
  327.     /* ------------ colors ------------ */
  328.     char ApplicationFG,  ApplicationBG;
  329.     char NormalFG,       NormalBG;
  330.     char ButtonFG,       ButtonBG;
  331.     char ButtonSelFG,    ButtonSelBG;
  332.     char DialogFG,       DialogBG;
  333.     char ErrorBoxFG,     ErrorBoxBG;
  334.     char MessageBoxFG,   MessageBoxBG;
  335.     char HelpBoxFG,      HelpBoxBG;
  336.     char InFocusTitleFG, InFocusTitleBG;
  337.     char TitleFG,        TitleBG;
  338.     char DummyFG,        DummyBG;
  339.     char TextBoxFG,      TextBoxBG;
  340.     char TextBoxSelFG,   TextBoxSelBG;
  341.     char TextBoxFrameFG, TextBoxFrameBG;
  342.     char ListBoxFG,      ListBoxBG;
  343.     char ListBoxSelFG,   ListBoxSelBG;
  344.     char ListBoxFrameFG, ListBoxFrameBG;
  345.     char EditBoxFG,      EditBoxBG;
  346.     char EditBoxSelFG,   EditBoxSelBG;
  347.     char EditBoxFrameFG, EditBoxFrameBG;
  348.     char MenuBarFG,      MenuBarBG;
  349.     char MenuBarSelFG,   MenuBarSelBG;
  350.     char PopDownFG,      PopDownBG;
  351.     char PopDownSelFG,   PopDownSelBG;
  352.     char InactiveSelFG;
  353.     char ShortCutFG;
  354. };
  355. /* ----------- configuration parameters ----------- */
  356. typedef struct config {
  357.     char version[sizeof DFLAT_APPLICATION + sizeof VERSION];
  358.     char mono;         /* 0=color, 1=mono, 2=reverse mono    */
  359.     int InsertMode;    /* Editor insert mode                 */
  360.     int Tabs;          /* Editor tab stops                   */
  361.     int WordWrap;      /* True to word wrap editor           */
  362.     int Border;        /* True for application window border */
  363.     int Title;         /* True for application window title  */
  364.     int Texture;       /* True for textured appl window      */
  365.     int ScreenLines;   /* Number of screen lines (25/43/50)  */
  366.     struct colors clr; /* Colors                             */
  367. } CONFIG;
  368. extern CONFIG cfg;
  369. extern struct colors color, bw, reverse;
  370. int LoadConfig(void);
  371. void SaveConfig(void);
  372.  
  373. #endif
  374.  
  375.  
  376.  
  377.  
  378.  
  379. [LISTING THREE]
  380.  
  381. /* ---------- window.c ------------- */
  382. #include <stdio.h>
  383. #include <conio.h>
  384. #include <stdlib.h>
  385. #include <string.h>
  386. #include <dos.h>
  387. #include "dflat.h"
  388.  
  389. WINDOW inFocus = NULLWND;
  390.  
  391. int foreground, background;   /* current video colors */
  392. static void TopLine(WINDOW, int, RECT);
  393.  
  394. /* --------- create a window ------------ */
  395. WINDOW CreateWindow(
  396.     CLASS class,              /* class of this window       */
  397.     char *ttl,                /* title or NULL              */
  398.     int left, int top,        /* upper left coordinates     */
  399.     int height, int width,    /* dimensions                 */
  400.     void *extension,          /* pointer to additional data */
  401.     WINDOW parent,            /* parent of this window      */
  402.     int (*wndproc)(struct window *,enum messages,PARAM,PARAM),
  403.     int attrib)               /* window attribute           */
  404. {
  405.     WINDOW wnd = malloc(sizeof(struct window));
  406.     get_videomode();
  407.     if (wnd != NULLWND)    {
  408.         int base;
  409.         /* ----- height, width = -1: fill the screen ------- */
  410.         if (height == -1)
  411.             height = SCREENHEIGHT;
  412.         if (width == -1)
  413.             width = SCREENWIDTH;
  414.         /* ----- coordinates -1, -1 = center the window ---- */
  415.         if (left == -1)
  416.             wnd->rc.lf = (SCREENWIDTH-width)/2;
  417.         else
  418.             wnd->rc.lf = left;
  419.         if (top == -1)
  420.             wnd->rc.tp = (SCREENHEIGHT-height)/2;
  421.         else
  422.             wnd->rc.tp = top;
  423.         wnd->attrib = attrib;
  424.         if (ttl != NULL)
  425.             AddAttribute(wnd, TITLEBAR);
  426.         if (wndproc == NULL)
  427.             wnd->wndproc = classdefs[FindClass(class)].wndproc;
  428.         else
  429.             wnd->wndproc = wndproc;
  430.         /* ---- derive attributes of base classes ---- */
  431.         base = class;
  432.         while (base != -1)    {
  433.             int tclass = FindClass(base);
  434.             AddAttribute(wnd, classdefs[tclass].attrib);
  435.             base = classdefs[tclass].base;
  436.         }
  437.         if (parent && !TestAttribute(wnd, NOCLIP))    {
  438.             /* -- keep upper left within borders of parent - */
  439.             wnd->rc.lf = max(wnd->rc.lf,GetClientLeft(parent));
  440.             wnd->rc.tp = max(wnd->rc.tp,GetClientTop(parent));
  441.         }
  442.         wnd->class = class;
  443.         wnd->extension = extension;
  444.         wnd->rc.rt = GetLeft(wnd)+width-1;
  445.         wnd->rc.bt = GetTop(wnd)+height-1;
  446.         wnd->ht = height;
  447.         wnd->wd = width;
  448.         wnd->title = NULL;
  449.         if (ttl != NULL)
  450.             InsertTitle(wnd, ttl);
  451.         wnd->next = wnd->prev = wnd->dFocus = NULLWND;
  452.         wnd->parent = parent;
  453.         wnd->videosave = NULL;
  454.         wnd->condition = ISRESTORED;
  455.         wnd->restored_attrib = 0;
  456.         wnd->RestoredRC = wnd->rc;
  457.         wnd->PrevKeyboard = wnd->PrevMouse = NULL;
  458.         wnd->DeletedText = NULL;
  459.         SendMessage(wnd, CREATE_WINDOW, 0, 0);
  460.         if (isVisible(wnd))
  461.             SendMessage(wnd, SHOW_WINDOW, 0, 0);
  462.     }
  463.     return wnd;
  464. }
  465. /* -------- add a title to a window --------- */
  466. void AddTitle(WINDOW wnd, char *ttl)
  467. {
  468.     InsertTitle(wnd, ttl);
  469.     SendMessage(wnd, BORDER, 0, 0);
  470. }
  471. /* ----- insert a title into a window ---------- */
  472. void InsertTitle(WINDOW wnd, char *ttl)
  473. {
  474.     if ((wnd->title=realloc(wnd->title,strlen(ttl)+1)) != NULL)
  475.         strcpy(wnd->title, ttl);
  476. }
  477. /* ------- write a character to a window area at x,y ------- */
  478. void PutWindowChar(WINDOW wnd, int x, int y, int c)
  479. {
  480.     int x1 = GetLeft(wnd)+x;
  481.     int y1 = GetTop(wnd)+y;
  482.     if (isVisible(wnd))    {
  483.         if (!TestAttribute(wnd, NOCLIP))    {
  484.             WINDOW wnd1 = GetParent(wnd);
  485.             while (wnd1 != NULLWND)    {
  486.                 /* --- clip character to parent's borders -- */
  487.                 if (x1 < GetClientLeft(wnd1)   ||
  488.                     x1 > GetClientRight(wnd1)  ||
  489.                     y1 > GetClientBottom(wnd1) ||
  490.                     y1 < GetClientTop(wnd1))
  491.                         return;
  492.                 wnd1 = GetParent(wnd1);
  493.             }
  494.         }
  495.         if (x1 < SCREENWIDTH && y1 < SCREENHEIGHT)
  496.             wputch(wnd, c, x, y);
  497.     }
  498. }
  499. static char line[161];
  500. #ifdef INCLUDE_SYSTEM_MENUS
  501. /* ----- clip line if it extends below the bottom of parent window ------ */
  502. static int clipbottom(WINDOW wnd, int y)
  503. {
  504.     if (!TestAttribute(wnd, NOCLIP))    {
  505.         WINDOW wnd1 = GetParent(wnd);
  506.         while (wnd1 != NULLWND)    {
  507.             if (GetClientTop(wnd)+y > GetClientBottom(wnd1)+1)
  508.                 return TRUE;
  509.             wnd1 = GetParent(wnd1);
  510.         }
  511.     }
  512.     return GetTop(wnd)+y > SCREENHEIGHT;
  513. }
  514. /* -- clip portion of line that extends past right margin of parent window-- */
  515. void clipline(WINDOW wnd, int x, char *ln)
  516. {
  517.     WINDOW pwnd = GetParent(wnd);
  518.     int x1 = strlen(ln);
  519.     int i = 0;
  520.     if (!TestAttribute(wnd, NOCLIP))    {
  521.         while (pwnd != NULLWND)    {
  522.             x1 = GetClientRight(pwnd) - GetLeft(wnd) - x + 1;
  523.             pwnd = GetParent(pwnd);
  524.         }
  525.     }
  526.     else if (GetLeft(wnd) + x > SCREENWIDTH)
  527.         x1 = SCREENWIDTH-GetLeft(wnd) - x;
  528.     /* --- adjust the clipping offset for color controls --- */
  529.     if (x1 < 0)
  530.         x1 = 0;
  531.     while (i < x1)    {
  532.         if ((unsigned char) ln[i] == CHANGECOLOR)
  533.             i += 3, x1 += 3;
  534.         else if ((unsigned char) ln[i] == RESETCOLOR)
  535.             i++, x1++;
  536.         else 
  537.             i++;
  538.     }
  539.     ln[x1] = '\0';
  540. }
  541. #else
  542. #define clipbottom(w,y) FALSE
  543. #endif
  544. /* ------ write a line to video window client area ------ */
  545. void writeline(WINDOW wnd, char *str, int x, int y, int pad)
  546. {
  547.     static char wline[120];
  548.     if (!clipbottom(wnd, y))
  549.     {
  550.         char *cp;
  551.         int len;
  552.         int dif;
  553.         memset(wline, 0, sizeof wline);
  554.         len = LineLength(str);
  555.         dif = strlen(str) - len;
  556.         strncpy(wline, str, ClientWidth(wnd) + dif);
  557.         if (pad)    {
  558.             cp = wline+strlen(wline);
  559.             while (len++ < ClientWidth(wnd)-x)
  560.                 *cp++ = ' ';
  561.         }
  562.         clipline(wnd, x, wline);
  563.         wputs(wnd, wline, x, y);
  564.     }
  565. }
  566. /* -- write a line to video window (including the border) -- */
  567. void writefull(WINDOW wnd, char *str, int y)
  568. {
  569.     if (!clipbottom(wnd, y))    {
  570.         strcpy(line, str);
  571.         clipline(wnd, 0, line);
  572.         wputs(wnd, line, 0, y);
  573.     }
  574. }
  575. RECT AdjustRectangle(WINDOW wnd, RECT rc)
  576. {
  577.     /* -------- adjust the rectangle ------- */
  578.     if (TestAttribute(wnd, HASBORDER))    {
  579.         if (RectLeft(rc) == 0)
  580.             --rc.rt;
  581.         else if (RectLeft(rc) < RectRight(rc) &&
  582.                 RectLeft(rc) < WindowWidth(wnd)+1)
  583.             --rc.lf;
  584.     }
  585.     if (TestAttribute(wnd, HASBORDER | TITLEBAR))    {
  586.         if (RectTop(rc) == 0)
  587.             --rc.bt;
  588.         else if (RectTop(rc) < RectBottom(rc) &&
  589.                 RectTop(rc) < WindowHeight(wnd)+1)
  590.             --rc.tp;
  591.     }
  592.     RectRight(rc) = max(RectLeft(rc),min(RectRight(rc),WindowWidth(wnd)));
  593.     RectBottom(rc) = max(RectTop(rc),min(RectBottom(rc),WindowHeight(wnd)));
  594.     return rc;
  595. }
  596. /* -------- display a window's title --------- */
  597. void DisplayTitle(WINDOW wnd, RECT *rcc)
  598. {
  599.     int tlen = min(strlen(wnd->title), WindowWidth(wnd)-2);
  600.     int tend = WindowWidth(wnd)-3-BorderAdj(wnd);
  601.     RECT rc;
  602.     if (rcc == NULL)
  603.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  604.     else
  605.         rc = *rcc;
  606.     rc = AdjustRectangle(wnd, rc);
  607.     if (SendMessage(wnd, TITLE, LPARAM(rcc), 0))    {
  608.         if (wnd == inFocus)    {
  609.             foreground = cfg.clr.InFocusTitleFG;
  610.             background = cfg.clr.InFocusTitleBG;
  611.         }
  612.         else    {
  613.             foreground = cfg.clr.TitleFG;
  614.             background = cfg.clr.TitleBG;
  615.         }
  616.         memset(line,' ',WindowWidth(wnd));
  617.         if (wnd->condition != ISMINIMIZED)
  618.             strncpy(line + ((WindowWidth(wnd)-2 - tlen) / 2),
  619.                 wnd->title, tlen);
  620.         if (TestAttribute(wnd, CONTROLBOX))
  621.             line[2-BorderAdj(wnd)] = CONTROLBOXCHAR;
  622. #ifdef INCLUDE_SYSTEM_MENUS
  623.         if (TestAttribute(wnd, MINMAXBOX))    {
  624.             switch (wnd->condition)    {
  625.                 case ISRESTORED:
  626.                     line[tend+1] = MAXPOINTER;
  627.                     line[tend]   = MINPOINTER;
  628.                     break;
  629.                 case ISMINIMIZED:
  630.                     line[tend+1] = MAXPOINTER;
  631.                     break;
  632.                 case ISMAXIMIZED:
  633.                     line[tend]   = MINPOINTER;
  634.                     line[tend+1] = RESTOREPOINTER;
  635.                     break;
  636.                 default:
  637.                     break;
  638.             }
  639.         }
  640. #endif
  641.         line[RectRight(rc)+1] = line[tend+3] = '\0';
  642.         writeline(wnd, line+RectLeft(rc),
  643.                        RectLeft(rc)+BorderAdj(wnd),
  644.                        0,
  645.                        FALSE);
  646.     }
  647. }
  648. #ifdef INCLUDE_SHADOWS
  649. /* --- display right border shadow character of a window --- */
  650. static void near shadow_char(WINDOW wnd, int y)
  651. {
  652.     int fg = foreground;
  653.     int bg = background;
  654.     int x = WindowWidth(wnd);
  655.     int c = videochar(GetLeft(wnd)+x, GetTop(wnd)+y);
  656.  
  657.     if (TestAttribute(wnd, SHADOW) == 0)
  658.         return;
  659.     foreground = DARKGRAY;
  660.     background = BLACK;
  661.     PutWindowChar(wnd, x, y, c);
  662.     foreground = fg;
  663.     background = bg;
  664. }
  665. /* --- display the bottom border shadow line for a window -- */
  666. static void near shadowline(WINDOW wnd, RECT rc)
  667. {
  668.     int i;
  669.     int y = GetBottom(wnd)+1;
  670.  
  671.     if ((TestAttribute(wnd, SHADOW)) == 0)
  672.         return;
  673.     if (!clipbottom(wnd, WindowHeight(wnd)))    {
  674.         int fg = foreground;
  675.         int bg = background;
  676.         for (i = 0; i < WindowWidth(wnd)+1; i++)
  677.             line[i] = videochar(GetLeft(wnd)+i, y);
  678.         line[i] = '\0';
  679.         foreground = DARKGRAY;
  680.         background = BLACK;
  681.         clipline(wnd, 1, line);
  682.         line[RectRight(rc)+1] = '\0';
  683.         if (RectLeft(rc) == 0)
  684.             rc.lf++;
  685.         wputs(wnd, line+RectLeft(rc), RectLeft(rc),WindowHeight(wnd));
  686.         foreground = fg;
  687.         background = bg;
  688.     }
  689. }
  690. #endif
  691. /* ------- display a window's border ----- */
  692. void RepaintBorder(WINDOW wnd, RECT *rcc)
  693. {
  694.     int y;
  695.     int lin, side, ne, nw, se, sw;
  696.     RECT rc, clrc;
  697.     if (!TestAttribute(wnd, HASBORDER))
  698.         return;
  699.     if (rcc == NULL)    {
  700.         rc = RelativeWindowRect(wnd, WindowRect(wnd));
  701. #ifdef INCLUDE_SHADOWS
  702.         if (TestAttribute(wnd, SHADOW))    {
  703.             rc.rt++;
  704.             rc.bt++;
  705.         }
  706. #endif
  707.     }
  708.     else
  709.         rc = *rcc;
  710.     clrc = AdjustRectangle(wnd, rc);
  711.     if (wnd == inFocus)    {
  712.         lin  = FOCUS_LINE;
  713.         side = FOCUS_SIDE;
  714.         ne   = FOCUS_NE;
  715.         nw   = FOCUS_NW;
  716.         se   = FOCUS_SE;
  717.         sw   = FOCUS_SW;
  718.     }
  719.     else    {
  720.         lin  = LINE;
  721.         side = SIDE;
  722.         ne   = NE;
  723.         nw   = NW;
  724.         se   = SE;
  725.         sw   = SW;
  726.     }
  727.     line[WindowWidth(wnd)] = '\0';
  728.     /* ---------- window title ------------ */
  729.     if (TestAttribute(wnd, TITLEBAR))
  730.         if (RectTop(rc) == 0)
  731.             if (RectLeft(rc) < WindowWidth(wnd)-BorderAdj(wnd))
  732.                 DisplayTitle(wnd, &rc);
  733.     foreground = FrameForeground(wnd);
  734.     background = FrameBackground(wnd);
  735.     /* -------- top frame corners --------- */
  736.     if (RectTop(rc) == 0)    {
  737.         if (RectLeft(rc) == 0)
  738.             PutWindowChar(wnd, 0, 0, nw);
  739.         if (RectLeft(rc) < WindowWidth(wnd))    {
  740.             if (RectRight(rc) >= WindowWidth(wnd)-1)
  741.                 PutWindowChar(wnd, WindowWidth(wnd)-1, 0, ne);
  742.             TopLine(wnd, lin, rc);
  743.         }
  744.     }
  745.     /* ----------- window body ------------ */
  746.     for (y = RectTop(rc); y <= RectBottom(rc); y++)    {
  747.         int ch;
  748.         if (y == 0 || y >= WindowHeight(wnd)-1)
  749.             continue;
  750.         if (RectLeft(rc) == 0)
  751.             PutWindowChar(wnd, 0, y, side);
  752.         if (RectLeft(rc) < WindowWidth(wnd) &&
  753.                 RectRight(rc) >= WindowWidth(wnd)-1)    {
  754. #ifdef INCLUDE_SCROLLBARS
  755.             if (TestAttribute(wnd, VSCROLLBAR))
  756.                 ch = (    y == 1 ? UPSCROLLBOX       :
  757.                             y == WindowHeight(wnd)-2  ?
  758.                                 DOWNSCROLLBOX       :
  759.                             y-1 == wnd->VScrollBox    ?
  760.                                 SCROLLBOXCHAR       :
  761.                                 SCROLLBARCHAR );
  762.             else
  763. #endif
  764.                 ch = side;
  765.             PutWindowChar(wnd, WindowWidth(wnd)-1, y, ch);
  766.         }
  767. #ifdef INCLUDE_SHADOWS
  768.         if (RectRight(rc) == WindowWidth(wnd))
  769.             shadow_char(wnd, y);
  770. #endif
  771.     }
  772.     if (RectTop(rc) <= WindowHeight(wnd)-1 &&
  773.             RectBottom(rc) >= WindowHeight(wnd)-1)    {
  774.         /* -------- bottom frame corners ---------- */
  775.         if (RectLeft(rc) == 0)
  776.             PutWindowChar(wnd, 0, WindowHeight(wnd)-1, sw);
  777.         if (RectLeft(rc) < WindowWidth(wnd) &&
  778.                 RectRight(rc) >= WindowWidth(wnd)-1)
  779.             PutWindowChar(wnd, WindowWidth(wnd)-1,
  780.                 WindowHeight(wnd)-1, se);
  781.         /* ----------- bottom line ------------- */
  782.         memset(line,lin,WindowWidth(wnd)-1);
  783. #ifdef INCLUDE_SCROLLBARS
  784.         if (TestAttribute(wnd, HSCROLLBAR))    {
  785.             line[0] = LEFTSCROLLBOX;
  786.             line[WindowWidth(wnd)-3] = RIGHTSCROLLBOX;
  787.             memset(line+1, SCROLLBARCHAR, WindowWidth(wnd)-4);
  788.             line[wnd->HScrollBox] = SCROLLBOXCHAR;
  789.         }
  790. #endif
  791.         line[WindowWidth(wnd)-2] = line[RectRight(rc)] = '\0';
  792.         if (RectLeft(rc) != RectRight(rc) ||
  793.            (RectLeft(rc) && RectLeft(rc) < WindowWidth(wnd)-1))
  794.             writeline(wnd,
  795.                 line+(RectLeft(clrc)),
  796.                 RectLeft(clrc)+1,
  797.                 WindowHeight(wnd)-1,
  798.                 FALSE);
  799. #ifdef INCLUDE_SHADOWS
  800.         if (RectRight(rc) == WindowWidth(wnd))
  801.             shadow_char(wnd, WindowHeight(wnd)-1);
  802. #endif
  803.     }
  804. #ifdef INCLUDE_SHADOWS
  805.     if (RectBottom(rc) == WindowHeight(wnd))
  806.         /* ---------- bottom shadow ------------- */
  807.         shadowline(wnd, rc);
  808. #endif
  809. }
  810. static void TopLine(WINDOW wnd, int lin, RECT rc)
  811. {
  812.     if (TestAttribute(wnd, TITLEBAR | HASMENUBAR))
  813.         return;
  814.     if (RectLeft(rc) < RectRight(rc))    {
  815.         /* ----------- top line ------------- */
  816.         memset(line,lin,WindowWidth(wnd)-1);
  817.         line[RectRight(rc)] = '\0';
  818.         writeline(wnd, line+RectLeft(rc),
  819.             RectLeft(rc)+1, 0, FALSE);
  820.     }
  821. }
  822. /* ------ clear the data space of a window -------- */
  823. void ClearWindow(WINDOW wnd, RECT *rcc, int clrchar)
  824. {
  825.     if (isVisible(wnd))    {
  826.         int y;
  827.         RECT rc;
  828.         if (rcc == NULL)
  829.             rc = RelativeWindowRect(wnd, WindowRect(wnd));
  830.         else
  831.             rc = *rcc;
  832.         if (RectLeft(rc) == 0)
  833.             RectLeft(rc) = BorderAdj(wnd);
  834.         if (RectRight(rc) > WindowWidth(wnd)-1)
  835.             RectRight(rc) = WindowWidth(wnd)-1;
  836.         SetStandardColor(wnd);
  837.         memset(line, clrchar, sizeof line);
  838.         line[RectRight(rc)+1] = '\0';
  839.         for (y = RectTop(rc); y <= RectBottom(rc); y++)    {
  840.             if (y < TopBorderAdj(wnd) ||
  841.                     y >= WindowHeight(wnd)-1)
  842.                 continue;
  843.             writeline(wnd,
  844.                 line+(RectLeft(rc)),
  845.                 RectLeft(rc),
  846.                 y,
  847.                 FALSE);
  848.         }
  849.     }
  850. }
  851. /* -- adjust a window's rectangle to clip it to its parent -- */
  852. static RECT near ClipRect(WINDOW wnd)
  853. {
  854.     RECT rc;
  855.     rc = wnd->rc;
  856. #ifdef INCLUDE_SHADOWS
  857.     if (TestAttribute(wnd, SHADOW))    {
  858.         RectBottom(rc)++;
  859.         RectRight(rc)++;
  860.     }
  861. #endif
  862.     if (!TestAttribute(wnd, NOCLIP))    {
  863.         WINDOW pwnd = GetParent(wnd);
  864.         if (pwnd != NULLWND)    {
  865.             RectTop(rc) = max(RectTop(rc),
  866.                         GetClientTop(pwnd));
  867.             RectLeft(rc) = max(RectLeft(rc),
  868.                         GetClientLeft(pwnd));
  869.             RectRight(rc) = min(RectRight(rc),
  870.                         GetClientRight(pwnd));
  871.             RectBottom(rc) = min(RectBottom(rc),
  872.                         GetClientBottom(pwnd));
  873.         }
  874.     }
  875.     RectRight(rc) = min(RectRight(rc), SCREENWIDTH-1);
  876.     RectBottom(rc) = min(RectBottom(rc), SCREENHEIGHT-1);
  877.     RectLeft(rc) = min(RectLeft(rc), SCREENWIDTH-1);
  878.     RectTop(rc) = min(RectTop(rc), SCREENHEIGHT-1);
  879.     return rc;
  880. }
  881. /* -- get the video memory that is to be used by a window -- */
  882. void GetVideoBuffer(WINDOW wnd)
  883. {
  884.     RECT rc;
  885.     int ht;
  886.     int wd;
  887.     rc = ClipRect(wnd);
  888.     ht = RectBottom(rc) - RectTop(rc) + 1;
  889.     wd = RectRight(rc) - RectLeft(rc) + 1;
  890.     wnd->videosave = realloc(wnd->videosave, (ht * wd * 2));
  891.     get_videomode();
  892.     if (wnd->videosave != NULL)
  893.         getvideo(rc, wnd->videosave);
  894. }
  895. /* --- restore the video memory that was used by a window -- */
  896. void RestoreVideoBuffer(WINDOW wnd)
  897. {
  898.     if (wnd->videosave != NULL)    {
  899.         RECT rc;
  900.         rc = ClipRect(wnd);
  901.         storevideo(rc, wnd->videosave);
  902.         free(wnd->videosave);
  903.         wnd->videosave = NULL;
  904.     }
  905. }
  906. /* ------ compute the logical line length of a window ------ */
  907. int LineLength(char *ln)
  908. {
  909.     int len = strlen(ln);
  910.     char *cp = ln;
  911.     while ((cp = strchr(cp, CHANGECOLOR)) != NULL)    {
  912.         cp++;
  913.         len -= 3;
  914.     }
  915.     cp = ln;
  916.     while ((cp = strchr(cp, RESETCOLOR)) != NULL)    {
  917.         cp++;
  918.         --len;
  919.     }
  920.     return len;
  921. }
  922.