home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Plotting / aa_Intel_Only / Gnuplot / Unused / win / wgraph.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-12  |  39.3 KB  |  1,487 lines

  1. #ifndef lint
  2. static char *RCSid = "$Id: wgraph.c%v 3.38.2.74 1993/02/19 01:16:40 woo Exp woo $";
  3. #endif
  4.  
  5. /* GNUPLOT - win/wgraph.c */
  6. /*
  7.  * Copyright (C) 1992   Maurice Castro, Russell Lang
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted, 
  11.  * provided that the above copyright notice appear in all copies and 
  12.  * that both that copyright notice and this permission notice appear 
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the modified code.  Modifications are to be distributed 
  17.  * as patches to released version.
  18.  *  
  19.  * This software is provided "as is" without express or implied warranty.
  20.  * 
  21.  *
  22.  * AUTHORS
  23.  * 
  24.  *   Maurice Castro
  25.  *   Russell Lang
  26.  * 
  27.  * Send your comments or suggestions to 
  28.  *  info-gnuplot@dartmouth.edu.
  29.  * This is a mailing list; to join it send a note to 
  30.  *  info-gnuplot-request@dartmouth.edu.  
  31.  * Send bug reports to
  32.  *  bug-gnuplot@dartmouth.edu.
  33.  */
  34.  
  35. #define STRICT
  36. #include <windows.h>
  37. #include <windowsx.h>
  38. #if WINVER >= 0x030a
  39. #include <commdlg.h>
  40. #endif
  41. #ifndef __MSC__
  42. #include <mem.h>
  43. #endif
  44. #include <string.h>
  45. #include "wgnuplib.h"
  46. #include "wresourc.h"
  47. #include "wcommon.h"
  48.  
  49. LRESULT CALLBACK _export WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  50. void ReadGraphIni(LPGW lpgw);
  51.  
  52. /* ================================== */
  53.  
  54. #define MAXSTR 255
  55.  
  56. #define WGDEFCOLOR 15
  57. COLORREF wginitcolor[WGDEFCOLOR] =  {
  58.     RGB(0,0,255),    /* blue */
  59.     RGB(0,255,0),    /* green */
  60.     RGB(255,0,0),    /* red */
  61.     RGB(255,0,255), /* magenta */
  62.     RGB(0,0,128),    /* dark blue */
  63.     RGB(128,0,0),    /* dark red */
  64.     RGB(0,128,128),    /* dark cyan */
  65.     RGB(0,0,0),    /* black */
  66.     RGB(128,128,128), /* grey */
  67.     RGB(0,128,64),    /* very dark cyan */
  68.     RGB(128,128,0), /* dark yellow */
  69.     RGB(128,0,128),    /* dark magenta */
  70.     RGB(192,192,192), /* light grey */
  71.     RGB(0,255,255),    /* cyan */
  72.     RGB(255,255,0),    /* yellow */
  73. };
  74. #define WGDEFSTYLE 5
  75. int wginitstyle[WGDEFSTYLE] = {PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT};
  76.  
  77. /* ================================== */
  78.  
  79. /* destroy memory blocks holding graph operations */
  80. void
  81. DestroyBlocks(LPGW lpgw)
  82. {
  83.     struct GWOPBLK *this, *next;
  84.     struct GWOP FAR *gwop;
  85.     unsigned int i;
  86.  
  87.     this = lpgw->gwopblk_head;
  88.     while (this != NULL) {
  89.         next = this->next;
  90.         if (!this->gwop) {
  91.             this->gwop = (struct GWOP FAR *)GlobalLock(this->hblk);
  92.         }
  93.         if (this->gwop) {
  94.             /* free all text strings within this block */
  95.             gwop = this->gwop;
  96.             for (i=0; i<GWOPMAX; i++) {
  97.                 if (gwop->htext)
  98.                     LocalFree(gwop->htext);
  99.                 gwop++;
  100.             }
  101.         }
  102.         GlobalUnlock(this->hblk);
  103.         GlobalFree(this->hblk);
  104.         LocalFreePtr(this);
  105.         this = next;
  106.     }
  107.     lpgw->gwopblk_head = NULL;
  108.     lpgw->gwopblk_tail = NULL;
  109.     lpgw->nGWOP = 0;
  110. }
  111.         
  112.     
  113. /* add a new memory block for graph operations */
  114. /* returns TRUE if block allocated */
  115. BOOL 
  116. AddBlock(LPGW lpgw)
  117. {
  118. HGLOBAL hblk;
  119. struct GWOPBLK *next, *this;
  120.  
  121.     /* create new block */
  122.     next = (struct GWOPBLK *)LocalAllocPtr(LHND, sizeof(struct GWOPBLK) );
  123.     if (next == NULL)
  124.         return FALSE;
  125.     hblk = GlobalAlloc(GHND, GWOPMAX*sizeof(struct GWOP));
  126.     if (hblk == NULL)
  127.         return FALSE;
  128.     next->hblk = hblk;
  129.     next->gwop = (struct GWOP FAR *)NULL;
  130.     next->next = (struct GWOPBLK *)NULL;
  131.     next->used = 0;
  132.     
  133.     /* attach it to list */
  134.     this = lpgw->gwopblk_tail;
  135.     if (this == NULL) {
  136.         lpgw->gwopblk_head = next;
  137.     }
  138.     else {
  139.         this->next = next;
  140.         this->gwop = (struct GWOP FAR *)NULL;
  141.         GlobalUnlock(this->hblk);
  142.     }
  143.     lpgw->gwopblk_tail = next;
  144.     next->gwop = (struct GWOP FAR *)GlobalLock(next->hblk);
  145.     if (next->gwop == (struct GWOP FAR *)NULL)
  146.         return FALSE;
  147.         
  148.     return TRUE;
  149. }
  150.  
  151.  
  152. void WDPROC
  153. GraphOp(LPGW lpgw, WORD op, WORD x, WORD y, LPSTR str)
  154. {
  155.     struct GWOPBLK *this;
  156.     struct GWOP FAR *gwop;
  157.     char *npstr;
  158.     
  159.     this = lpgw->gwopblk_tail;
  160.     if ( (this==NULL) || (this->used >= GWOPMAX) ) {
  161.         /* not enough space so get new block */
  162.         if (!AddBlock(lpgw))
  163.             return;
  164.         this = lpgw->gwopblk_tail;
  165.     }
  166.     gwop = &this->gwop[this->used];
  167.     gwop->op = op;
  168.     gwop->x = x;
  169.     gwop->y = y;
  170.     gwop->htext = 0;
  171.     if (str) {
  172.         gwop->htext = LocalAlloc(LHND, _fstrlen(str)+1);
  173.         npstr = LocalLock(gwop->htext);
  174.         if (gwop->htext && (npstr != (char *)NULL))
  175.             lstrcpy(npstr, str);
  176.         LocalUnlock(gwop->htext);
  177.     }
  178.     this->used++;
  179.     lpgw->nGWOP++;
  180.     return;
  181. }
  182.  
  183. /* ================================== */
  184.  
  185. void WDPROC
  186. GraphInit(LPGW lpgw)
  187. {
  188.     HMENU sysmenu;
  189.     WNDCLASS wndclass;
  190.     char buf[80];
  191.  
  192.     if (!lpgw->hPrevInstance) {
  193.         wndclass.style = CS_HREDRAW | CS_VREDRAW;
  194.         wndclass.lpfnWndProc = WndGraphProc;
  195.         wndclass.cbClsExtra = 0;
  196.         wndclass.cbWndExtra = 2 * sizeof(void FAR *);
  197.         wndclass.hInstance = lpgw->hInstance;
  198.         wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  199.         wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  200.         wndclass.hbrBackground = GetStockBrush(WHITE_BRUSH);
  201.         wndclass.lpszMenuName = NULL;
  202.         wndclass.lpszClassName = szGraphClass;
  203.         RegisterClass(&wndclass);
  204.     }
  205.  
  206.     ReadGraphIni(lpgw);
  207.  
  208.     lpgw->hWndGraph = CreateWindow(szGraphClass, lpgw->Title,
  209.         WS_OVERLAPPEDWINDOW,
  210.         lpgw->Origin.x, lpgw->Origin.y,
  211.         lpgw->Size.x, lpgw->Size.y,
  212.         NULL, NULL, lpgw->hInstance, lpgw);
  213.  
  214.     lpgw->hPopMenu = CreatePopupMenu();
  215.     AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->graphtotop ? MF_CHECKED : MF_UNCHECKED), 
  216.         M_GRAPH_TO_TOP, "Bring to &Top");
  217.     AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->color ? MF_CHECKED : MF_UNCHECKED), 
  218.         M_COLOR, "C&olor");
  219.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard");
  220. #if WINVER >= 0x030a
  221.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_BACKGROUND, "&Background...");
  222.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
  223.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_LINESTYLE, "&Line Styles...");
  224. #endif
  225.     AppendMenu(lpgw->hPopMenu, MF_STRING, M_PRINT, "&Print...");
  226.     if (lpgw->IniFile != (LPSTR)NULL) {
  227.         wsprintf(buf,"&Update %s",lpgw->IniFile);
  228.         AppendMenu(lpgw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
  229.     }
  230.  
  231.     /* modify the system menu to have the new items we want */
  232.     sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
  233.     AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
  234.     AppendMenu(sysmenu, MF_POPUP, (UINT)lpgw->hPopMenu, "&Options");
  235.     AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
  236.  
  237.     ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
  238. }
  239.  
  240. /* close a graph window */
  241. void WDPROC
  242. GraphClose(LPGW lpgw)
  243. {
  244.     /* close window */
  245.     if (lpgw->hWndGraph)
  246.         DestroyWindow(lpgw->hWndGraph);
  247.     TextMessage();
  248.     lpgw->hWndGraph = NULL;
  249.  
  250.     lpgw->locked = TRUE;
  251.     DestroyBlocks(lpgw);
  252.     lpgw->locked = FALSE;
  253.  
  254. }
  255.     
  256.  
  257. void WDPROC
  258. GraphStart(LPGW lpgw)
  259. {
  260.     lpgw->locked = TRUE;
  261.     DestroyBlocks(lpgw);
  262.     if ( !lpgw->hWndGraph || !IsWindow(lpgw->hWndGraph) )
  263.         GraphInit(lpgw);
  264.     if (IsIconic(lpgw->hWndGraph))
  265.         ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
  266.     if (lpgw->graphtotop)
  267.         BringWindowToTop(lpgw->hWndGraph);
  268. }
  269.         
  270. void WDPROC
  271. GraphEnd(LPGW lpgw)
  272. {
  273. RECT rect;
  274.     GetClientRect(lpgw->hWndGraph, &rect);
  275.     InvalidateRect(lpgw->hWndGraph, (LPRECT) &rect, 1);
  276.     lpgw->locked = FALSE;
  277.     UpdateWindow(lpgw->hWndGraph);
  278. }
  279.  
  280. void WDPROC
  281. GraphPrint(LPGW lpgw)
  282. {
  283.     if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
  284.         SendMessage(lpgw->hWndGraph,WM_COMMAND,M_PRINT,0L);
  285. }
  286.  
  287. void WDPROC
  288. GraphRedraw(LPGW lpgw)
  289. {
  290.     if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
  291.         SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
  292. }
  293. /* ================================== */
  294.  
  295. void
  296. StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle)
  297. {
  298.     LOGPEN FAR *plp;
  299.  
  300.     plp = &lpgw->colorpen[i];
  301.     plp->lopnColor = ref;
  302.     if (colorstyle < 0) {
  303.         plp->lopnWidth.x = -colorstyle;
  304.         plp->lopnStyle = 0;
  305.     }
  306.     else {
  307.         plp->lopnWidth.x = 1;
  308.         plp->lopnStyle = colorstyle % 5;
  309.     }
  310.     plp->lopnWidth.y = 0;
  311.  
  312.     plp = &lpgw->monopen[i];
  313.     plp->lopnColor = RGB(0,0,0);
  314.     if (monostyle < 0) {
  315.         plp->lopnWidth.x = -monostyle;
  316.             plp->lopnStyle = 0;
  317.     }
  318.     else {
  319.         plp->lopnWidth.x = 1;
  320.         plp->lopnStyle = monostyle % 5;
  321.     }
  322.     plp->lopnWidth.y = 0;
  323. }
  324.  
  325. void
  326. MakePens(LPGW lpgw, HDC hdc)
  327. {
  328.     int i;
  329.  
  330.     if ((GetDeviceCaps(hdc,NUMCOLORS) == 2) || !lpgw->color) {
  331.         /* Monochrome Device */
  332.         /* create border pens */
  333.         lpgw->hbpen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[0]);    /* border */
  334.         lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[1]);     /* axis */
  335.         /* create drawing pens */
  336.         for (i=0; i<WGNUMPENS; i++)
  337.         {
  338.             lpgw->hpen[i] = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[i+2]);
  339.             }
  340.         /* find number of solid, unit width line styles */
  341.         for (i=0; i<WGNUMPENS && lpgw->monopen[i+2].lopnStyle==PS_SOLID
  342.             && lpgw->monopen[i+2].lopnWidth.x==1; i++) ;
  343.         lpgw->numsolid = i ? i : 1;    /* must be at least 1 */
  344.         lpgw->hbrush = CreateSolidBrush(RGB(255,255,255));
  345.     }
  346.     else {
  347.         /* Color Device */
  348.         /* create border pens */
  349.         lpgw->hbpen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[0]);    /* border */
  350.         lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[1]);     /* axis */
  351.         /* create drawing pens */
  352.         for (i=0; i<WGNUMPENS; i++)
  353.         {
  354.             lpgw->hpen[i] = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[i+2]);
  355.             }
  356.         /* find number of solid, unit width line styles */
  357.         for (i=0; i<WGNUMPENS && lpgw->colorpen[i+2].lopnStyle==PS_SOLID
  358.             && lpgw->colorpen[i+2].lopnWidth.x==1; i++) ;
  359.         lpgw->numsolid = i ? i : 1;    /* must be at least 1 */
  360.         lpgw->hbrush = CreateSolidBrush(lpgw->background);
  361.     }
  362. }
  363.  
  364. void
  365. DestroyPens(LPGW lpgw)
  366. {
  367.     int i;
  368.  
  369.     DeleteBrush(lpgw->hbrush);
  370.     DeletePen(lpgw->hbpen);
  371.     DeletePen(lpgw->hapen);
  372.     for (i=0; i<WGNUMPENS; i++)
  373.         DeletePen(lpgw->hpen[i]);
  374. }
  375.  
  376. /* ================================== */
  377.  
  378. void
  379. MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc)
  380. {
  381.     LOGFONT lf;
  382.     HFONT hfontold;
  383.     TEXTMETRIC tm;
  384.     int result;
  385.     char FAR *p;
  386.     int cx, cy;
  387.  
  388.     lpgw->rotate = FALSE;
  389.     _fmemset(&lf, 0, sizeof(LOGFONT));
  390.     _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
  391.     lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  392.     lf.lfCharSet = DEFAULT_CHARSET;
  393.     if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
  394.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  395.         lf.lfItalic = TRUE;
  396.     }
  397.     if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
  398.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  399.         lf.lfWeight = FW_BOLD;
  400.     }
  401.  
  402.     if (lpgw->hfonth == 0) {
  403.         lpgw->hfonth = CreateFontIndirect((LOGFONT FAR *)&lf);
  404.     }
  405.  
  406.     if (lpgw->hfontv == 0) {
  407.         lf.lfEscapement = 900;
  408.         lf.lfOrientation = 900;
  409.         lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&lf);
  410.     }
  411.  
  412.     /* save text size */
  413.     hfontold = SelectFont(hdc, lpgw->hfonth);
  414. #ifdef WIN32
  415.     {
  416.     SIZE size;
  417.     GetTextExtentPoint(hdc,"0123456789",10, (LPSIZE)&size);
  418.     cx = size.cx;
  419.     cy = size.cy;
  420.     }
  421. #else
  422.     {
  423.     DWORD extent;
  424.     extent = GetTextExtent(hdc,"0123456789",10);
  425.     cx = LOWORD(extent);
  426.     cy = HIWORD(extent);
  427.     }
  428. #endif
  429.     lpgw->vchar = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
  430.     lpgw->hchar = MulDiv(cx/10,lpgw->xmax,lprect->right - lprect->left);
  431.     /* find out if we can rotate text 90deg */
  432.     SelectFont(hdc, lpgw->hfontv);
  433.     result = GetDeviceCaps(hdc, TEXTCAPS);
  434.     if ((result & TC_CR_90) || (result & TC_CR_ANY))
  435.         lpgw->rotate = 1;
  436.     GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
  437.     if (tm.tmPitchAndFamily & TMPF_VECTOR)
  438.         lpgw->rotate = 1;    /* vector fonts can all be rotated */
  439. #if WINVER >=0x030a
  440.     if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
  441.         lpgw->rotate = 1;    /* truetype fonts can all be rotated */
  442. #endif
  443.     SelectFont(hdc, hfontold);
  444.     return;
  445. }
  446.  
  447. void
  448. DestroyFonts(LPGW lpgw)
  449. {
  450.     if (lpgw->hfonth) {
  451.         DeleteFont(lpgw->hfonth);
  452.         lpgw->hfonth = 0;
  453.     }
  454.     if (lpgw->hfontv) {
  455.         DeleteFont(lpgw->hfontv);
  456.         lpgw->hfontv = 0;
  457.     }
  458.     return;
  459. }
  460.  
  461. void
  462. SetFont(LPGW lpgw, HDC hdc)
  463. {
  464.     if (lpgw->rotate && lpgw->angle) {
  465.         if (lpgw->hfontv)
  466.             SelectFont(hdc, lpgw->hfontv);
  467.     }
  468.     else {
  469.         if (lpgw->hfonth)
  470.             SelectFont(hdc, lpgw->hfonth);
  471.     }
  472.     return;
  473. }
  474.  
  475. void
  476. SelFont(LPGW lpgw) {
  477. #if WINVER >= 0x030a
  478.     LOGFONT lf;
  479.     CHOOSEFONT cf;
  480.     HDC hdc;
  481.     char lpszStyle[LF_FACESIZE]; 
  482.     char FAR *p;
  483.  
  484.     /* Set all structure fields to zero. */
  485.     _fmemset(&cf, 0, sizeof(CHOOSEFONT));
  486.     _fmemset(&lf, 0, sizeof(LOGFONT));
  487.     cf.lStructSize = sizeof(CHOOSEFONT);
  488.     cf.hwndOwner = lpgw->hWndGraph;
  489.     _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
  490.     if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
  491.         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
  492.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  493.     }
  494.     else if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
  495.         _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
  496.         lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
  497.     }
  498.     else
  499.         _fstrcpy(lpszStyle,"Regular");
  500.     cf.lpszStyle = lpszStyle;
  501.     hdc = GetDC(lpgw->hWndGraph);
  502.     lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
  503.     ReleaseDC(lpgw->hWndGraph, hdc);
  504.     cf.lpLogFont = &lf;
  505.     cf.nFontType = SCREEN_FONTTYPE;
  506.     cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
  507.     if (ChooseFont(&cf)) {
  508.         _fstrcpy(lpgw->fontname,lf.lfFaceName);
  509.         lpgw->fontsize = cf.iPointSize / 10;
  510.         if (cf.nFontType & BOLD_FONTTYPE)
  511.             lstrcat(lpgw->fontname," Bold");
  512.         if (cf.nFontType & ITALIC_FONTTYPE)
  513.             lstrcat(lpgw->fontname," Italic");
  514.         SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
  515.     }
  516. #endif
  517. }
  518.  
  519. /* ================================== */
  520.  
  521. void
  522. drawgraph(LPGW lpgw, HDC hdc, LPRECT rect)
  523. {
  524.     int xdash, ydash;            /* the transformed coordinates */
  525.     int rr, rl, rt, rb;
  526.     struct GWOP FAR *curptr;
  527.     struct GWOPBLK *blkptr;
  528.     int htic, vtic, vshift;
  529.     unsigned int lastop=-1;        /* used for plotting last point on a line */
  530.     int pen, numsolid;
  531.     int polymax = 200;
  532.     int polyi = 0;
  533.     POINT *ppt;
  534.     unsigned int ngwop=0;
  535.  
  536.     if (lpgw->locked) 
  537.         return;
  538.  
  539.     if (lpgw->background != RGB(255,255,255) && lpgw->color
  540.       && (GetDeviceCaps(hdc,NUMCOLORS) > 2)) {
  541.         SetBkColor(hdc,lpgw->background);
  542.         FillRect(hdc, rect, lpgw->hbrush);
  543.     }
  544.  
  545.     ppt = (POINT *)LocalAllocPtr(LHND, (polymax+1) * sizeof(POINT));
  546.  
  547.     rr = rect->right;
  548.     rl = rect->left;
  549.     rt = rect->top;
  550.     rb = rect->bottom;
  551.  
  552.     htic = MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
  553.     vtic = MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
  554.  
  555.     lpgw->angle = 0;
  556.     SetFont(lpgw, hdc);
  557.     SetTextAlign(hdc, TA_LEFT|TA_BOTTOM);
  558.     vshift = MulDiv(lpgw->vchar, rb-rt, lpgw->ymax)/2;
  559.  
  560.     pen = 0;
  561.     SelectPen(hdc, lpgw->hpen[pen]);
  562.     numsolid = lpgw->numsolid;
  563.  
  564.     /* do the drawing */
  565.     blkptr = lpgw->gwopblk_head;
  566.     curptr = NULL;
  567.     if (blkptr) {
  568.         if (!blkptr->gwop)
  569.             blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
  570.         if (!blkptr->gwop)
  571.             return;
  572.         curptr = (struct GWOP FAR *)blkptr->gwop;
  573.     }
  574.     while(ngwop < lpgw->nGWOP)
  575.        {
  576.         /* transform the coordinates */
  577.         xdash = MulDiv(curptr->x, rr-rl-1, lpgw->xmax) + rl;
  578.         ydash = MulDiv(curptr->y, rt-rb+1, lpgw->ymax) + rb - 1;
  579.         if ((lastop==W_vect) && (curptr->op!=W_vect)) {
  580.             if (polyi >= 2)
  581.                 Polyline(hdc, ppt, polyi);
  582.             polyi = 0;
  583.         }
  584.         switch (curptr->op) {
  585.             case 0:    /* have run past last in this block */
  586.                 break;
  587.             case W_move:
  588.                 ppt[0].x = xdash;
  589.                 ppt[0].y = ydash;
  590.                 polyi = 1;;
  591.                 break;
  592.             case W_vect:
  593.                 ppt[polyi].x = xdash;
  594.                 ppt[polyi].y = ydash;
  595.                 polyi++;
  596.                 if (polyi >= polymax) {
  597.                     Polyline(hdc, ppt, polyi);
  598.                     ppt[0].x = xdash;
  599.                     ppt[0].y = ydash;
  600.                     polyi = 1;;
  601.                 }
  602.                 break;
  603.             case W_line_type:
  604.                 switch (curptr->x)
  605.                 {
  606.                     case -2:            /* black 2 pixel wide */
  607.                         SelectPen(hdc, lpgw->hbpen);
  608.                         break;
  609.                     case -1:            /* black 1 pixel wide doted */
  610.                         SelectPen(hdc, lpgw->hapen);
  611.                         break;
  612.                     default:
  613.                         SelectPen(hdc, lpgw->hpen[(curptr->x)%WGNUMPENS]);
  614.                     }
  615.                 pen = curptr->x;
  616.                 break;
  617.             case W_put_text:
  618.                 {char *str;
  619.                 str = LocalLock(curptr->htext);
  620.                 if (str) {
  621.                     ydash += vshift;
  622.                     SetBkMode(hdc,TRANSPARENT);
  623.                     TextOut(hdc,xdash,ydash,str,lstrlen(str));
  624.                     SetBkMode(hdc,OPAQUE);
  625.                 }
  626.                 LocalUnlock(curptr->htext);
  627.                 }
  628.                 break;
  629.             case W_text_angle:
  630.                 lpgw->angle = curptr->x;
  631.                 SetFont(lpgw,hdc);
  632.                 break;
  633.             case W_justify:
  634.                 switch (curptr->x)
  635.                 {
  636.                     case LEFT:
  637.                         SetTextAlign(hdc, TA_LEFT|TA_BOTTOM);
  638.                         break;
  639.                     case RIGHT:
  640.                         SetTextAlign(hdc, TA_RIGHT|TA_BOTTOM);
  641.                         break;
  642.                     case CENTRE:
  643.                         SetTextAlign(hdc, TA_CENTER|TA_BOTTOM);
  644.                         break;
  645.                     }
  646.                 break;
  647.             case W_dot:
  648.                 if (pen >= numsolid) {
  649.                     pen %= numsolid;    /* select solid pen */
  650.                     SelectPen(hdc, lpgw->hpen[pen]);
  651.                 }
  652.                 MoveTo(hdc,xdash,ydash);
  653.                 LineTo(hdc,xdash+1,ydash);
  654.                 break;
  655.             case W_diamond: /* do diamond */ 
  656.                 if (pen >= numsolid) {
  657.                     pen %= numsolid;
  658.                     SelectPen(hdc, lpgw->hpen[pen]);
  659.                 }
  660.                 MoveTo(hdc,xdash-htic,ydash);
  661.                 LineTo(hdc,xdash,ydash-vtic);
  662.                 LineTo(hdc,xdash+htic,ydash);
  663.                 LineTo(hdc,xdash,ydash+vtic);
  664.                 LineTo(hdc,xdash-htic,ydash);
  665.                 MoveTo(hdc,xdash,ydash);
  666.                 LineTo(hdc,xdash+1,ydash);
  667.                 break;
  668.             case W_plus: /* do plus */ 
  669.                 if (pen >= numsolid) {
  670.                     pen %= numsolid;
  671.                     SelectPen(hdc, lpgw->hpen[pen]);
  672.                 }
  673.                 MoveTo(hdc,xdash-htic,ydash);
  674.                 LineTo(hdc,xdash+htic+1,ydash);
  675.                 MoveTo(hdc,xdash,ydash-vtic);
  676.                 LineTo(hdc,xdash,ydash+vtic+1);
  677.                 break;
  678.             case W_box: /* do box */ 
  679.                 if (pen >= numsolid) {
  680.                     pen %= numsolid;
  681.                     SelectPen(hdc, lpgw->hpen[pen]);
  682.                 }
  683.                 MoveTo(hdc,xdash-htic,ydash-vtic);
  684.                 LineTo(hdc,xdash+htic,ydash-vtic);
  685.                 LineTo(hdc,xdash+htic,ydash+vtic);
  686.                 LineTo(hdc,xdash-htic,ydash+vtic);
  687.                 LineTo(hdc,xdash-htic,ydash-vtic);
  688.                 MoveTo(hdc,xdash,ydash);
  689.                 LineTo(hdc,xdash+1,ydash);
  690.                 break;
  691.             case W_cross: /* do X */ 
  692.                 if (pen >= numsolid) {
  693.                     pen %= numsolid;
  694.                     SelectPen(hdc, lpgw->hpen[pen]);
  695.                 }
  696.                 MoveTo(hdc,xdash-htic,ydash-vtic);
  697.                 LineTo(hdc,xdash+htic+1,ydash+vtic+1);
  698.                 MoveTo(hdc,xdash-htic,ydash+vtic);
  699.                 LineTo(hdc,xdash+htic+1,ydash-vtic-1);
  700.                 break;
  701.             case W_triangle: /* do triangle */ 
  702.                 if (pen >= numsolid) {
  703.                     pen %= numsolid;
  704.                     SelectPen(hdc, lpgw->hpen[pen]);
  705.                 }
  706.                 MoveTo(hdc,xdash,ydash-(4*vtic/3));
  707.                 LineTo(hdc,xdash-(4*htic/3),ydash+(2*vtic/3));
  708.                 LineTo(hdc,xdash+(4*htic/3),ydash+(2*vtic/3));
  709.                 LineTo(hdc,xdash,ydash-(4*vtic/3));
  710.                 MoveTo(hdc,xdash,ydash);
  711.                 LineTo(hdc,xdash+1,ydash);
  712.                 break;
  713.             case W_star: /* do star */ 
  714.                 if (pen >= numsolid) {
  715.                     pen %= numsolid;
  716.                     SelectPen(hdc, lpgw->hpen[pen]);
  717.                 }
  718.                 MoveTo(hdc,xdash-htic,ydash);
  719.                 LineTo(hdc,xdash+htic+1,ydash);
  720.                 MoveTo(hdc,xdash,ydash-vtic);
  721.                 LineTo(hdc,xdash,ydash+vtic+1);
  722.                 MoveTo(hdc,xdash-htic,ydash-vtic);
  723.                 LineTo(hdc,xdash+htic+1,ydash+vtic+1);
  724.                 MoveTo(hdc,xdash-htic,ydash+vtic);
  725.                 LineTo(hdc,xdash+htic+1,ydash-vtic-1);
  726.                 break;
  727.         }
  728.         lastop = curptr->op;
  729.         ngwop++;
  730.         curptr++;
  731.         if ((unsigned)(curptr - blkptr->gwop) >= GWOPMAX) {
  732.             GlobalUnlock(blkptr->hblk);
  733.             blkptr->gwop = (struct GWOP FAR *)NULL;
  734.             blkptr = blkptr->next;
  735.             if (!blkptr->gwop)
  736.                 blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
  737.             if (!blkptr->gwop)
  738.                     return;
  739.                 curptr = (struct GWOP FAR *)blkptr->gwop;
  740.         }
  741.     }
  742.     if (polyi >= 2)
  743.         Polyline(hdc, ppt, polyi);
  744.     LocalFreePtr(ppt);
  745. }
  746.  
  747. /* ================================== */
  748.  
  749. /* copy graph window to clipboard */
  750. void
  751. CopyClip(LPGW lpgw)
  752. {
  753.     RECT rect;
  754.     HDC mem;
  755.     HBITMAP bitmap;
  756.     HANDLE hmf;
  757.     GLOBALHANDLE hGMem;
  758.     LPMETAFILEPICT lpMFP;
  759.     HWND hwnd;
  760.     HDC hdc;
  761.  
  762.     hwnd = lpgw->hWndGraph;
  763.  
  764.     /* view the window */
  765.     if (IsIconic(hwnd))
  766.         ShowWindow(hwnd, SW_SHOWNORMAL);
  767.     BringWindowToTop(hwnd);
  768.     UpdateWindow(hwnd);
  769.  
  770.     /* get the context */
  771.     hdc = GetDC(hwnd);
  772.     GetClientRect(hwnd, &rect);
  773.     /* make a bitmap and copy it there */
  774.     mem = CreateCompatibleDC(hdc);
  775.     bitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left,
  776.             rect.bottom - rect.top);
  777.     if (bitmap) {
  778.         /* there is enough memory and the bitmaps OK */
  779.         SelectBitmap(mem, bitmap);
  780.         BitBlt(mem,0,0,rect.right - rect.left, 
  781.             rect.bottom - rect.top, hdc, rect.left,
  782.             rect.top, SRCCOPY);
  783.     }
  784.     else {
  785.         MessageBeep(MB_ICONHAND);
  786.         MessageBox(hwnd, "Insufficient Memory to Copy Clipboard", 
  787.             lpgw->Title, MB_ICONHAND | MB_OK);
  788.     }
  789.     DeleteDC(mem);
  790.     ReleaseDC(hwnd, hdc);
  791.  
  792.     hdc = CreateMetaFile((LPSTR)NULL);
  793.     SetMapMode(hdc, MM_ANISOTROPIC);
  794. #ifdef WIN32
  795.     SetWindowExtEx(hdc, rect.right, rect.bottom, (LPSIZE)NULL);
  796. #else
  797.     SetWindowExt(hdc, rect.right, rect.bottom);
  798. #endif
  799.     drawgraph(lpgw, hdc, (void *) &rect);
  800.     hmf = CloseMetaFile(hdc);
  801.  
  802.     hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(METAFILEPICT));
  803.     lpMFP = (LPMETAFILEPICT) GlobalLock(hGMem);
  804.     hdc = GetDC(hwnd);    /* get window size */
  805.     GetClientRect(hwnd, &rect);
  806.     /* in MM_ANISOTROPIC, xExt & yExt give suggested size in 0.01mm units */
  807.     lpMFP->mm = MM_ANISOTROPIC;
  808.     lpMFP->xExt = MulDiv(rect.right-rect.left, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
  809.     lpMFP->yExt = MulDiv(rect.bottom-rect.top, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
  810.     lpMFP->hMF = hmf;
  811.     ReleaseDC(hwnd, hdc);
  812.     GlobalUnlock(hGMem);
  813.  
  814.     OpenClipboard(hwnd);
  815.     EmptyClipboard();
  816.     SetClipboardData(CF_METAFILEPICT,hGMem);
  817.     SetClipboardData(CF_BITMAP, bitmap);
  818.     CloseClipboard();
  819.     return;
  820. }
  821.  
  822. /* copy graph window to printer */
  823. void
  824. CopyPrint(LPGW lpgw)
  825. {
  826. #if WINVER >= 0x030a
  827.     HDC printer;
  828.     DLGPROC lpfnAbortProc;
  829.     DLGPROC lpfnPrintDlgProc;
  830.     PRINTDLG pd;
  831.     HWND hwnd;
  832.     RECT rect;
  833.     PRINT pr;
  834.     UINT widabort;
  835.  
  836.     hwnd = lpgw->hWndGraph;
  837.  
  838.     _fmemset(&pd, 0, sizeof(PRINTDLG));
  839.     pd.lStructSize = sizeof(PRINTDLG);
  840.     pd.hwndOwner = hwnd;
  841.     pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
  842.  
  843.     if (!PrintDlg(&pd))
  844.         return;
  845.     printer = pd.hDC;
  846.     if (NULL == printer)
  847.         return;    /* abort */
  848.  
  849.     if (!PrintSize(printer, hwnd, &rect)) {
  850.         DeleteDC(printer);
  851.         return; /* abort */
  852.     }
  853.  
  854.     pr.hdcPrn = printer;
  855.     SetWindowLong(hwnd, 4, (LONG)((LPPRINT)&pr));
  856.     PrintRegister((LPPRINT)&pr);
  857.  
  858.     EnableWindow(hwnd,FALSE);
  859.     pr.bUserAbort = FALSE;
  860. #ifdef __DLL__
  861.     lpfnPrintDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintDlgProc");
  862.     lpfnAbortProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintAbortProc");
  863. #else
  864.     lpfnPrintDlgProc = (DLGPROC)MakeProcInstance((FARPROC)PrintDlgProc, hdllInstance);
  865.     lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)PrintAbortProc, hdllInstance);
  866. #endif
  867.     pr.hDlgPrint = CreateDialogParam(hdllInstance,"PrintDlgBox",hwnd,lpfnPrintDlgProc,(LPARAM)lpgw->Title);
  868.     Escape(printer,SETABORTPROC,0,(LPSTR)lpfnAbortProc,NULL);  
  869.     if (Escape(printer, STARTDOC, lstrlen(lpgw->Title),lpgw->Title, NULL) > 0) {
  870.         SetMapMode(printer, MM_TEXT);
  871.         SetBkMode(printer,OPAQUE);
  872.         DestroyFonts(lpgw);
  873.         MakeFonts(lpgw, (RECT FAR *)&rect, printer);
  874.         DestroyPens(lpgw);    /* rebuild pens */
  875.         MakePens(lpgw, printer);
  876.         drawgraph(lpgw, printer, (void *) &rect);
  877.         if (Escape(printer,NEWFRAME,0,NULL,NULL) > 0)
  878.             Escape(printer,ENDDOC,0,NULL,NULL);
  879.     }
  880.     if (!pr.bUserAbort) {
  881.         EnableWindow(hwnd,TRUE);
  882.         DestroyWindow(pr.hDlgPrint);
  883.     }
  884. #ifndef __DLL__
  885.     FreeProcInstance((FARPROC)lpfnPrintDlgProc);
  886.     FreeProcInstance((FARPROC)lpfnAbortProc);
  887. #endif
  888.     DeleteDC(printer);
  889.     SetWindowLong(hwnd, 4, (LONG)(0L));
  890.     PrintUnregister((LPPRINT)&pr);
  891.     /* make certain that the screen pen set is restored */
  892.     SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
  893. #endif
  894.     return;
  895. }
  896.  
  897. /* ================================== */
  898. /*  INI file stuff */
  899. void
  900. WriteGraphIni(LPGW lpgw)
  901. {
  902.     RECT rect;
  903.     int i;
  904.     char entry[32];
  905.     LPLOGPEN pc;
  906.     LPLOGPEN pm;
  907.     LPSTR file = lpgw->IniFile;
  908.     LPSTR section = lpgw->IniSection;
  909.     char profile[80];
  910.  
  911.     if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
  912.         return;
  913.     if (IsIconic(lpgw->hWndGraph))
  914.         ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
  915.     GetWindowRect(lpgw->hWndGraph,&rect);
  916.     wsprintf(profile, "%d %d", rect.left, rect.top);
  917.     WritePrivateProfileString(section, "GraphOrigin", profile, file);
  918.     wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
  919.     WritePrivateProfileString(section, "GraphSize", profile, file);
  920.     wsprintf(profile, "%s,%d", lpgw->fontname, lpgw->fontsize);
  921.     WritePrivateProfileString(section, "GraphFont", profile, file);
  922.     wsprintf(profile, "%d", lpgw->color);
  923.     WritePrivateProfileString(section, "GraphColor", profile, file);
  924.     wsprintf(profile, "%d", lpgw->graphtotop);
  925.     WritePrivateProfileString(section, "GraphToTop", profile, file);
  926.     wsprintf(profile, "%d %d %d",GetRValue(lpgw->background),
  927.             GetGValue(lpgw->background), GetBValue(lpgw->background));
  928.     WritePrivateProfileString(section, "GraphBackground", profile, file);
  929.  
  930.     /* now save pens */
  931.     for (i=0; i<WGNUMPENS+2; i++) {
  932.         if (i==0)
  933.             _fstrcpy(entry,"Border");
  934.         else if (i==1)
  935.             _fstrcpy(entry,"Axis");
  936.         else
  937.              wsprintf(entry,"Line%d",i-1);
  938.         pc = &lpgw->colorpen[i];
  939.         pm = &lpgw->monopen[i];
  940.         wsprintf(profile, "%d %d %d %d %d",GetRValue(pc->lopnColor),
  941.             GetGValue(pc->lopnColor), GetBValue(pc->lopnColor),
  942.             (pc->lopnWidth.x != 1) ? -pc->lopnWidth.x : pc->lopnStyle, 
  943.             (pm->lopnWidth.x != 1) ? -pm->lopnWidth.x : pm->lopnStyle);
  944.         WritePrivateProfileString(section, entry, profile, file);
  945.     }
  946.     return;
  947. }
  948.  
  949. void
  950. ReadGraphIni(LPGW lpgw)
  951. {
  952.     LPSTR file = lpgw->IniFile;
  953.     LPSTR section = lpgw->IniSection;
  954.     char profile[81];
  955.     char entry[32];
  956.     LPSTR p;
  957.     int i,r,g,b,colorstyle,monostyle;
  958.     COLORREF ref;
  959.     BOOL bOKINI;
  960.  
  961.     bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
  962.     if (!bOKINI)
  963.         profile[0] = '\0';
  964.  
  965.     if (bOKINI)
  966.       GetPrivateProfileString(section, "GraphOrigin", "", profile, 80, file);
  967.     if ( (p = GetInt(profile, &lpgw->Origin.x)) == NULL)
  968.         lpgw->Origin.x = CW_USEDEFAULT;
  969.     if ( (p = GetInt(p, &lpgw->Origin.y)) == NULL)
  970.         lpgw->Origin.y = CW_USEDEFAULT;
  971.     if (bOKINI)
  972.       GetPrivateProfileString(section, "GraphSize", "", profile, 80, file);
  973.     if ( (p = GetInt(profile, &lpgw->Size.x)) == NULL)
  974.         lpgw->Size.x = CW_USEDEFAULT;
  975.     if ( (p = GetInt(p, &lpgw->Size.y)) == NULL)
  976.         lpgw->Size.y = CW_USEDEFAULT;
  977.  
  978.     if (bOKINI)
  979.       GetPrivateProfileString(section, "GraphFont", "", profile, 80, file);
  980.     {
  981.         char FAR *size;
  982.         size = _fstrchr(profile,',');
  983.         if (size) {
  984.             *size++ = '\0';
  985.             if ( (p = GetInt(size, &lpgw->fontsize)) == NULL)
  986.                 lpgw->fontsize = WINFONTSIZE;
  987.         }
  988.         _fstrcpy(lpgw->fontname, profile);
  989.         if (lpgw->fontsize == 0)
  990.             lpgw->fontsize = WINFONTSIZE;
  991.         if (!(*lpgw->fontname))
  992.             if (LOWORD(GetVersion()) == 3)
  993.                 _fstrcpy(lpgw->fontname,WIN30FONT);
  994.             else
  995.                 _fstrcpy(lpgw->fontname,WINFONT);
  996.     }
  997.  
  998.     if (bOKINI)
  999.       GetPrivateProfileString(section, "GraphColor", "", profile, 80, file);
  1000.         if ( (p = GetInt(profile, &lpgw->color)) == NULL)
  1001.             lpgw->color = TRUE;
  1002.  
  1003.     if (bOKINI)
  1004.       GetPrivateProfileString(section, "GraphToTop", "", profile, 80, file);
  1005.         if ( (p = GetInt(profile, &lpgw->graphtotop)) == NULL)
  1006.             lpgw->graphtotop = TRUE;
  1007.  
  1008.     lpgw->background = RGB(255,255,255);
  1009.     if (bOKINI)
  1010.       GetPrivateProfileString(section, "GraphBackground", "", profile, 80, file);
  1011.     if ( ((p = GetInt(profile, &r)) != NULL) &&
  1012.          ((p = GetInt(p, &g)) != NULL) &&
  1013.          ((p = GetInt(p, &b)) != NULL) )
  1014.             lpgw->background = RGB(r,g,b);
  1015.  
  1016.     StorePen(lpgw, 0,RGB(0,0,0),PS_SOLID,PS_SOLID);
  1017.     if (bOKINI)
  1018.       GetPrivateProfileString(section, "Border", "", profile, 80, file);
  1019.     if ( ((p = GetInt(profile, &r)) != NULL) &&
  1020.          ((p = GetInt(p, &g)) != NULL) &&
  1021.          ((p = GetInt(p, &b)) != NULL) &&
  1022.          ((p = GetInt(p, &colorstyle)) != NULL) &&
  1023.          ((p = GetInt(p, &monostyle)) != NULL) )
  1024.             StorePen(lpgw,0,RGB(r,g,b),colorstyle,monostyle);
  1025.  
  1026.     StorePen(lpgw, 1,RGB(192,192,192),PS_DOT,PS_DOT);
  1027.     if (bOKINI)
  1028.       GetPrivateProfileString(section, "Axis", "", profile, 80, file);
  1029.     if ( ((p = GetInt(profile, &r)) != NULL) &&
  1030.          ((p = GetInt(p, &g)) != NULL) &&
  1031.          ((p = GetInt(p, &b)) != NULL) &&
  1032.          ((p = GetInt(p, &colorstyle)) != NULL) &&
  1033.          ((p = GetInt(p, &monostyle)) != NULL) )
  1034.             StorePen(lpgw,1,RGB(r,g,b),colorstyle,monostyle);
  1035.  
  1036.     for (i=0; i<WGNUMPENS; i++)
  1037.     {
  1038.         ref = wginitcolor[ i%WGDEFCOLOR ];
  1039.         colorstyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
  1040.         monostyle  = wginitstyle[ i%WGDEFSTYLE ];
  1041.         StorePen(lpgw, i+2,ref,colorstyle,monostyle);
  1042.         wsprintf(entry,"Line%d",i+1);
  1043.         if (bOKINI)
  1044.           GetPrivateProfileString(section, entry, "", profile, 80, file);
  1045.         if ( ((p = GetInt(profile, &r)) != NULL) &&
  1046.              ((p = GetInt(p, &g)) != NULL) &&
  1047.              ((p = GetInt(p, &b)) != NULL) &&
  1048.              ((p = GetInt(p, &colorstyle)) != NULL) &&
  1049.              ((p = GetInt(p, &monostyle)) != NULL) )
  1050.                 StorePen(lpgw,i+2,RGB(r,g,b),colorstyle,monostyle);
  1051.     }
  1052. }
  1053.  
  1054.  
  1055. /* ================================== */
  1056.  
  1057. #define LS_DEFLINE 2
  1058. typedef struct tagLS {
  1059.     int    widtype;
  1060.     int    wid;
  1061.     HWND    hwnd;
  1062.     int    pen;            /* current pen number */
  1063.     LOGPEN    colorpen[WGNUMPENS+2];    /* logical color pens */
  1064.     LOGPEN    monopen[WGNUMPENS+2];    /* logical mono pens */
  1065. } LS;
  1066. typedef LS FAR*  LPLS;
  1067.     
  1068.  
  1069. COLORREF
  1070. GetColor(HWND hwnd, COLORREF ref)
  1071. {
  1072. CHOOSECOLOR cc;
  1073. COLORREF aclrCust[16];
  1074. int i;
  1075.  
  1076.     for (i=0; i<16; i++) {
  1077.         aclrCust[i] = RGB(0,0,0);
  1078.     }
  1079.     _fmemset(&cc, 0, sizeof(CHOOSECOLOR));
  1080.     cc.lStructSize = sizeof(CHOOSECOLOR);
  1081.     cc.hwndOwner = hwnd;
  1082.     cc.lpCustColors = aclrCust;
  1083.     cc.rgbResult = ref;
  1084.     cc.Flags = CC_RGBINIT;
  1085.     if (ChooseColor(&cc))
  1086.         return cc.rgbResult;
  1087.     return ref;
  1088. }
  1089.  
  1090.  
  1091. /* force update of owner draw button */
  1092. void
  1093. UpdateColorSample(HWND hdlg)
  1094. {
  1095.     RECT rect;
  1096.     POINT ptul, ptlr;
  1097.     GetWindowRect( GetDlgItem(hdlg, LS_COLORSAMPLE), &rect);
  1098.     ptul.x = rect.left;
  1099.     ptul.y = rect.top;
  1100.     ptlr.x = rect.right;
  1101.     ptlr.y = rect.bottom;
  1102.     ScreenToClient(hdlg, &ptul);
  1103.     ScreenToClient(hdlg, &ptlr);
  1104.     rect.left   = ptul.x;
  1105.     rect.top    = ptul.y;
  1106.     rect.right  = ptlr.x;
  1107.     rect.bottom = ptlr.y;
  1108.     InvalidateRect(hdlg, &rect, TRUE);
  1109.     UpdateWindow(hdlg);
  1110. }
  1111.  
  1112. BOOL CALLBACK _export
  1113. LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam)
  1114. {
  1115.     char buf[16];
  1116.     LPLS lpls;
  1117.     int i;
  1118.     UINT pen;
  1119.     LPLOGPEN plpm, plpc;
  1120.     lpls = (LPLS)GetWindowLong(GetParent(hdlg), 4);
  1121.  
  1122.     switch (wmsg) {
  1123.         case WM_INITDIALOG:
  1124.             pen = 2;
  1125.             for (i=0; i<WGNUMPENS+2; i++) {
  1126.                 if (i==0)
  1127.                     _fstrcpy(buf,"Border");
  1128.                 else if (i==1)
  1129.                     _fstrcpy(buf,"Axis");
  1130.                 else
  1131.                      wsprintf(buf,"Line%d",i-1);
  1132.                 SendDlgItemMessage(hdlg, LS_LINENUM, LB_ADDSTRING, 0, 
  1133.                     (LPARAM)((LPSTR)buf));
  1134.             }
  1135.             SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
  1136.  
  1137.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1138.                 (LPARAM)((LPSTR)"Solid"));
  1139.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1140.                 (LPARAM)((LPSTR)"Dash"));
  1141.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1142.                 (LPARAM)((LPSTR)"Dot"));
  1143.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1144.                 (LPARAM)((LPSTR)"DashDot"));
  1145.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0, 
  1146.                 (LPARAM)((LPSTR)"DashDotDot"));
  1147.  
  1148.             plpm = &lpls->monopen[pen];
  1149.             SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1150.                 plpm->lopnStyle, 0L);
  1151.             wsprintf(buf,"%d",plpm->lopnWidth.x);
  1152.             SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1153.  
  1154.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1155.                 (LPARAM)((LPSTR)"Solid"));
  1156.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1157.                 (LPARAM)((LPSTR)"Dash"));
  1158.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1159.                 (LPARAM)((LPSTR)"Dot"));
  1160.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1161.                 (LPARAM)((LPSTR)"DashDot"));
  1162.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0, 
  1163.                 (LPARAM)((LPSTR)"DashDotDot"));
  1164.  
  1165.             plpc = &lpls->colorpen[pen];
  1166.             SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1167.                 plpc->lopnStyle, 0L);
  1168.             wsprintf(buf,"%d",plpc->lopnWidth.x);
  1169.             SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1170.  
  1171.             return TRUE;
  1172.         case WM_COMMAND:
  1173.             pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, 0, 0L);
  1174.             plpm = &lpls->monopen[pen];
  1175.             plpc = &lpls->colorpen[pen];
  1176.             switch (LOWORD(wparam)) {
  1177.                 case LS_LINENUM:
  1178.                     wsprintf(buf,"%d",plpm->lopnWidth.x);
  1179.                     SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1180.                     SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1181.                         plpm->lopnStyle, 0L);
  1182.                     wsprintf(buf,"%d",plpc->lopnWidth.x);
  1183.                     SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1184.                     SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1185.                         plpc->lopnStyle, 0L);
  1186.                     UpdateColorSample(hdlg);
  1187.                     return FALSE;
  1188.                 case LS_MONOSTYLE:
  1189.                     plpm->lopnStyle = 
  1190.                         (UINT)SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_GETCURSEL, 0, 0L);
  1191.                     if (plpm->lopnStyle != 0) {
  1192.                         plpm->lopnWidth.x = 1;
  1193.                         wsprintf(buf,"%d",plpm->lopnWidth.x);
  1194.                         SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1195.                     }
  1196.                     return FALSE;
  1197.                 case LS_MONOWIDTH:
  1198.                     GetDlgItemText(hdlg, LS_MONOWIDTH, buf, 15);
  1199.                     GetInt(buf, &plpm->lopnWidth.x);
  1200.                     if (plpm->lopnWidth.x != 1) {
  1201.                         plpm->lopnStyle = 0;
  1202.                         SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1203.                             plpm->lopnStyle, 0L);
  1204.                     }
  1205.                     return FALSE;
  1206.                 case LS_CHOOSECOLOR:
  1207.                     plpc->lopnColor = GetColor(hdlg, plpc->lopnColor);
  1208.                     UpdateColorSample(hdlg);
  1209.                     return FALSE;
  1210.                 case LS_COLORSTYLE:
  1211.                     plpc->lopnStyle = 
  1212.                         (UINT)SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_GETCURSEL, 0, 0L);
  1213.                     if (plpc->lopnStyle != 0) {
  1214.                         plpc->lopnWidth.x = 1;
  1215.                         wsprintf(buf,"%d",plpc->lopnWidth.x);
  1216.                         SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1217.                     }
  1218.                     return FALSE;
  1219.                 case LS_COLORWIDTH:
  1220.                     GetDlgItemText(hdlg, LS_COLORWIDTH, buf, 15);
  1221.                     GetInt(buf, &plpc->lopnWidth.x);
  1222.                     if (plpc->lopnWidth.x != 1) {
  1223.                         plpc->lopnStyle = 0;
  1224.                         SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1225.                             plpc->lopnStyle, 0L);
  1226.                     }
  1227.                     return FALSE;
  1228.                 case LS_DEFAULT:
  1229.                     plpm = lpls->monopen;
  1230.                     plpc = lpls->colorpen;
  1231.                     /* border */
  1232.                     plpc->lopnColor   = RGB(0,0,0);
  1233.                     plpc->lopnStyle   = PS_SOLID;
  1234.                     plpc->lopnWidth.x = 1;
  1235.                     plpm->lopnStyle   = PS_SOLID;
  1236.                     plpm->lopnWidth.x = 1;
  1237.                     plpc++; plpm++;
  1238.                     /* axis */
  1239.                     plpc->lopnColor   = RGB(192,192,192);
  1240.                     plpc->lopnStyle   = PS_DOT;
  1241.                     plpc->lopnWidth.x = 1;
  1242.                     plpm->lopnStyle   = PS_DOT;
  1243.                     plpm->lopnWidth.x = 1;
  1244.                     /* LineX */
  1245.                     for (i=0; i<WGNUMPENS; i++) {
  1246.                         plpc++; plpm++;
  1247.                         plpc->lopnColor   = wginitcolor[ i%WGDEFCOLOR ];
  1248.                         plpc->lopnStyle   = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
  1249.                         plpc->lopnWidth.x = 1;
  1250.                         plpm->lopnStyle   = wginitstyle[ i%WGDEFSTYLE ];
  1251.                         plpm->lopnWidth.x = 1;
  1252.                     }
  1253.                     /* update window */
  1254.                     plpm = &lpls->monopen[pen];
  1255.                     plpc = &lpls->colorpen[pen];
  1256.                     SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
  1257.                     wsprintf(buf,"%d",plpm->lopnWidth.x);
  1258.                     SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
  1259.                     SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL, 
  1260.                         plpm->lopnStyle, 0L);
  1261.                     wsprintf(buf,"%d",plpc->lopnWidth.x);
  1262.                     SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
  1263.                     SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL, 
  1264.                         plpc->lopnStyle, 0L);
  1265.                     UpdateColorSample(hdlg);
  1266.                     return FALSE;
  1267.                 case IDOK:
  1268.                     EndDialog(hdlg, IDOK);
  1269.                     return TRUE;
  1270.                 case IDCANCEL:
  1271.                     EndDialog(hdlg, IDCANCEL);
  1272.                     return TRUE;
  1273.             }
  1274.             break;
  1275.         case WM_DRAWITEM:
  1276.             {
  1277.             HBRUSH hBrush;
  1278.             LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lparam;
  1279.             pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
  1280.             plpc = &lpls->colorpen[pen];
  1281.             hBrush = CreateSolidBrush(plpc->lopnColor);
  1282.             FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
  1283.             FrameRect(lpdis->hDC, &lpdis->rcItem, GetStockBrush(BLACK_BRUSH));
  1284.             DeleteBrush(hBrush);
  1285.             }
  1286.             return FALSE;
  1287.     }
  1288.     return FALSE;
  1289. }
  1290.  
  1291.  
  1292.  
  1293. /* GetWindowLong(hwnd, 4) must be available for use */
  1294. BOOL
  1295. LineStyle(LPGW lpgw)
  1296. {
  1297. DLGPROC lpfnLineStyleDlgProc ;
  1298. BOOL status = FALSE;
  1299. LS ls;
  1300.     
  1301.     SetWindowLong(lpgw->hWndGraph, 4, (LONG)((LPLS)&ls));
  1302.     _fmemcpy(&ls.colorpen, &lpgw->colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1303.     _fmemcpy(&ls.monopen, &lpgw->monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1304.  
  1305. #ifdef __DLL__
  1306.     lpfnLineStyleDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "LineStyleDlgProc");
  1307. #else
  1308.     lpfnLineStyleDlgProc = (DLGPROC)MakeProcInstance((FARPROC)LineStyleDlgProc, hdllInstance);
  1309. #endif
  1310.     if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, lpfnLineStyleDlgProc)
  1311.         == IDOK) {
  1312.         _fmemcpy(&lpgw->colorpen, &ls.colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1313.         _fmemcpy(&lpgw->monopen, &ls.monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
  1314.         status = TRUE;
  1315.     }
  1316. #ifndef __DLL__
  1317.     FreeProcInstance((FARPROC)lpfnLineStyleDlgProc);
  1318. #endif
  1319.     SetWindowLong(lpgw->hWndGraph, 4, (LONG)(0L));
  1320.     return status;
  1321. }
  1322.  
  1323. /* ================================== */
  1324.  
  1325. LRESULT CALLBACK _export
  1326. WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  1327. {
  1328.     HDC hdc;
  1329.     PAINTSTRUCT ps;
  1330.     RECT rect;
  1331.     LPGW lpgw;
  1332.  
  1333.     lpgw = (LPGW)GetWindowLong(hwnd, 0);
  1334.  
  1335.     switch(message)
  1336.     {
  1337.         case WM_SYSCOMMAND:
  1338.             switch(LOWORD(wParam))
  1339.             {
  1340.                 case M_GRAPH_TO_TOP:
  1341.                 case M_COLOR:
  1342.                 case M_CHOOSE_FONT:
  1343.                 case M_COPY_CLIP:
  1344.                 case M_LINESTYLE:
  1345.                 case M_PRINT:
  1346.                 case M_WRITEINI:
  1347.                 case M_REBUILDTOOLS:
  1348.                     SendMessage(hwnd, WM_COMMAND, wParam, lParam);
  1349.                     break;
  1350.                 case M_ABOUT:
  1351.                     if (lpgw->lptw)
  1352.                         AboutBox(hwnd,lpgw->lptw->AboutText);
  1353.                     return 0;
  1354.             }
  1355.             break;
  1356.         case WM_COMMAND:
  1357.             switch(LOWORD(wParam))
  1358.             {
  1359.                 case M_GRAPH_TO_TOP:
  1360.                     lpgw->graphtotop = !lpgw->graphtotop;
  1361.                     SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1362.                     return(0);
  1363.                 case M_COLOR:
  1364.                     lpgw->color = !lpgw->color;
  1365.                     SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1366.                     return(0);
  1367.                 case M_CHOOSE_FONT:
  1368.                     SelFont(lpgw);
  1369.                     return 0;
  1370.                 case M_COPY_CLIP:
  1371.                     CopyClip(lpgw);
  1372.                     return 0;
  1373.                 case M_LINESTYLE:
  1374.                     if (LineStyle(lpgw))
  1375.                         SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1376.                     return 0;
  1377.                 case M_BACKGROUND:
  1378.                     lpgw->background = GetColor(hwnd, lpgw->background);
  1379.                     SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
  1380.                     return 0;
  1381.                 case M_PRINT:
  1382.                     CopyPrint(lpgw);
  1383.                     return 0;
  1384.                 case M_WRITEINI:
  1385.                     WriteGraphIni(lpgw);
  1386.                     if (lpgw->lptw)
  1387.                         WriteTextIni(lpgw->lptw);
  1388.                     return 0;
  1389.                 case M_REBUILDTOOLS:
  1390.                     lpgw->resized = TRUE;
  1391.                     if (lpgw->color) 
  1392.                         CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_CHECKED);
  1393.                     else
  1394.                         CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_UNCHECKED);
  1395.                     if (lpgw->graphtotop) 
  1396.                         CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_CHECKED);
  1397.                     else
  1398.                         CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_UNCHECKED);
  1399.                     DestroyPens(lpgw);
  1400.                     DestroyFonts(lpgw);
  1401.                     hdc = GetDC(hwnd);
  1402.                     MakePens(lpgw, hdc);
  1403.                     GetClientRect(hwnd, &rect);
  1404.                     MakeFonts(lpgw, (LPRECT)&rect, hdc);
  1405.                     ReleaseDC(hwnd, hdc);
  1406.                     GetClientRect(hwnd, &rect);
  1407.                     InvalidateRect(hwnd, (LPRECT) &rect, 1);
  1408.                     UpdateWindow(hwnd);
  1409.                     return 0;
  1410.             }
  1411.             return 0;
  1412.         case WM_RBUTTONDOWN:
  1413.             {
  1414.             POINT pt;
  1415.             pt.x = LOWORD(lParam);
  1416.             pt.y = HIWORD(lParam);
  1417.             ClientToScreen(hwnd,&pt);
  1418.             TrackPopupMenu(lpgw->hPopMenu, TPM_LEFTALIGN, 
  1419.                 pt.x, pt.y, 0, hwnd, NULL);
  1420.             }
  1421.             return(0);
  1422.         case WM_CREATE:
  1423.             lpgw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
  1424.             SetWindowLong(hwnd, 0, (LONG)lpgw);
  1425.             lpgw->hWndGraph = hwnd;
  1426.             hdc = GetDC(hwnd);
  1427.             MakePens(lpgw, hdc);
  1428.             GetClientRect(hwnd, &rect);
  1429.             MakeFonts(lpgw, (LPRECT)&rect, hdc);
  1430.             ReleaseDC(hwnd, hdc);
  1431. #if WINVER >= 0x030a
  1432.             {
  1433.             WORD version = LOWORD(GetVersion());
  1434.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1435.                 if ( lpgw->lptw && (lpgw->lptw->DragPre!=(LPSTR)NULL) && (lpgw->lptw->DragPost!=(LPSTR)NULL) )
  1436.                     DragAcceptFiles(hwnd, TRUE);
  1437.             }
  1438. #endif
  1439.             return(0);
  1440.         case WM_PAINT:
  1441.             hdc = BeginPaint(hwnd, &ps);
  1442.             SetMapMode(hdc, MM_TEXT);
  1443.             SetBkMode(hdc,OPAQUE);
  1444.             GetClientRect(hwnd, &rect);
  1445.             SetViewportExt(hdc, rect.right, rect.bottom);
  1446.             drawgraph(lpgw, hdc, (void *) &rect);
  1447.             EndPaint(hwnd, &ps);
  1448.             return 0;
  1449.         case WM_SIZE:
  1450.             /* update font sizes if graph resized */
  1451.             if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) {
  1452.                 RECT rect;
  1453.                 SendMessage(hwnd,WM_SYSCOMMAND,M_REBUILDTOOLS,0L);
  1454.                 GetWindowRect(hwnd,&rect);
  1455.                 lpgw->Size.x = rect.right-rect.left;
  1456.                 lpgw->Size.y = rect.bottom-rect.top;
  1457.             }
  1458.             break;
  1459. #if WINVER >= 0x030a
  1460.         case WM_DROPFILES:
  1461.             {
  1462.             WORD version = LOWORD(GetVersion());
  1463.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1464.                 if (lpgw->lptw)
  1465.                     DragFunc(lpgw->lptw, (HDROP)wParam);
  1466.             }
  1467.             break;
  1468. #endif
  1469.         case WM_DESTROY:
  1470.             DestroyPens(lpgw);
  1471.             DestroyFonts(lpgw);
  1472. #if __TURBOC__ >= 0x410    /* Borland C++ 3.1 or later */
  1473.             {
  1474.             WORD version = LOWORD(GetVersion());
  1475.             if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
  1476.                 DragAcceptFiles(hwnd, FALSE);
  1477.             }
  1478. #endif
  1479.             return 0;
  1480.         case WM_CLOSE:
  1481.             GraphClose(lpgw);
  1482.             return 0;
  1483.         }
  1484.     return DefWindowProc(hwnd, message, wParam, lParam);
  1485. }
  1486.  
  1487.