--- /dev/null
+#ifndef lint
+static char *RCSid() { return RCSid("$Id: wgraph.c,v 1.52.2.7 2009/03/23 23:03:25 sfeam Exp $"); }
+#endif
+
+/* GNUPLOT - win/wgraph.c */
+/*[
+ * Copyright 1992, 1993, 1998, 2004 Maurice Castro, Russell Lang
+ *
+ * Permission to use, copy, and distribute this software and its
+ * documentation for any purpose with or without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation.
+ *
+ * Permission to modify the software is granted, but not the right to
+ * distribute the complete modified source code. Modifications are to
+ * be distributed as patches to the released version. Permission to
+ * distribute binaries produced by compiling modified sources is granted,
+ * provided you
+ * 1. distribute the corresponding source modifications from the
+ * released version in the form of a patch file along with the binaries,
+ * 2. add special version identification to distinguish your version
+ * in addition to the base release version number,
+ * 3. provide your name and address as the primary contact for the
+ * support of your modified version, and
+ * 4. retain our contact information in regard to use of the base
+ * software.
+ * Permission to distribute the released version of the source code along
+ * with corresponding source modifications in the form of a patch file is
+ * granted with same provisions 2 through 4 for binary distributions.
+ *
+ * This software is provided "as is" without express or implied warranty
+ * to the extent permitted by applicable law.
+]*/
+
+/*
+ * AUTHORS
+ *
+ * Maurice Castro
+ * Russell Lang
+ */
+
+#define STRICT
+#include <windows.h>
+#include <windowsx.h>
+#if WINVER >= 0x030a
+# include <commdlg.h>
+#endif
+#ifndef __MSC__
+# include <mem.h>
+#endif
+#include <stdio.h>
+#include <string.h>
+#include "wgnuplib.h"
+#include "wresourc.h"
+#include "wcommon.h"
+#include "term_api.h" /* for enum JUSTIFY */
+#ifdef USE_MOUSE
+# include "gpexecute.h"
+# include "mouse.h"
+#endif
+# include "color.h"
+# include "getcolor.h"
+
+#ifdef USE_MOUSE
+/* Petr Mikulik, February 2001
+ * Declarations similar to src/os2/gclient.c -- see section
+ * "PM: Now variables for mouse" there in.
+ */
+
+/* If wgnuplot crashes during redrawing and mouse on, then this could help: */
+/* static char lock_mouse = 1; */
+
+/* Status of the ruler */
+static struct Ruler {
+ TBOOLEAN on; /* ruler active ? */
+ int x, y; /* ruler position */
+} ruler = {FALSE,0,0,};
+
+/* Status of the line from ruler to cursor */
+static struct RulerLineTo {
+ TBOOLEAN on; /* ruler line active ? */
+ int x, y; /* ruler line end position (previous cursor position) */
+} ruler_lineto = {FALSE,0,0,};
+
+/* Status of zoom box */
+static struct Zoombox {
+ TBOOLEAN on; /* set to TRUE during zooming */
+ POINT from, to; /* corners of the zoom box */
+ LPCSTR text1, text2; /* texts in the corners (i.e. positions) */
+} zoombox = { FALSE, {0,0}, {0,0}, NULL, NULL };
+
+/* Pointer definitions */
+HCURSOR hptrDefault, hptrCrossHair, hptrScaling, hptrRotating, hptrZooming, hptrCurrent;
+
+/* Mouse support routines */
+static void Wnd_exec_event(LPGW lpgw, LPARAM lparam, char type, int par1);
+static void Wnd_refresh_zoombox(LPGW lpgw, LPARAM lParam);
+static void Wnd_refresh_ruler_lineto(LPGW lpgw, LPARAM lParam);
+static void GetMousePosViewport(LPGW lpgw, int *mx, int *my);
+static void Draw_XOR_Text(LPGW lpgw, const char *text, size_t length, int x, int y);
+static void DisplayStatusLine(LPGW lpgw);
+static void UpdateStatusLine(LPGW lpgw, const char text[]);
+static void DrawRuler(LPGW lpgw);
+static void DrawRulerLineTo(LPGW lpgw);
+static void DrawZoomBox(LPGW lpgw);
+static void LoadCursors(LPGW lpgw);
+static void DestroyCursors(LPGW lpgw);
+#endif /* USE_MOUSE */
+
+/* ================================== */
+
+#define MAXSTR 255
+
+#define WGDEFCOLOR 15
+COLORREF wginitcolor[WGDEFCOLOR] = {
+ RGB(255,0,0), /* red */
+ RGB(0,255,0), /* green */
+ RGB(0,0,255), /* blue */
+ RGB(255,0,255), /* magenta */
+ RGB(0,0,128), /* dark blue */
+ RGB(128,0,0), /* dark red */
+ RGB(0,128,128), /* dark cyan */
+ RGB(0,0,0), /* black */
+ RGB(128,128,128), /* grey */
+ RGB(0,128,64), /* very dark cyan */
+ RGB(128,128,0), /* dark yellow */
+ RGB(128,0,128), /* dark magenta */
+ RGB(192,192,192), /* light grey */
+ RGB(0,255,255), /* cyan */
+ RGB(255,255,0), /* yellow */
+};
+#define WGDEFSTYLE 5
+int wginitstyle[WGDEFSTYLE] = {PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT};
+
+/* Maximum number of GWOPBLK arrays to be remembered. */
+/* HBB 20010218: moved here from wgnuplib.h: other parts of the program don't
+ * need to know about it */
+#define GWOPMAX 4096
+
+
+/* bitmaps for filled boxes (ULIG) */
+/* zeros represent the foreground color and ones represent the background color */
+/* FIXME HBB 20010916: *never* extern in a C source! */
+/* extern int filldensity; */
+/* extern int fillpattern; */
+
+static unsigned char halftone_bitmaps[][16] ={
+ { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, /* no fill */
+ { 0xEE, 0xEE, 0xBB, 0xBB, 0xEE, 0xEE, 0xBB, 0xBB,
+ 0xEE, 0xEE, 0xBB, 0xBB, 0xEE, 0xEE, 0xBB, 0xBB }, /* 25% pattern */
+ { 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
+ 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55 }, /* 50% pattern */
+ { 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22,
+ 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22 }, /* 75% pattern */
+ { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* solid pattern */
+};
+#define halftone_num (sizeof(halftone_bitmaps) / sizeof (*halftone_bitmaps))
+static HBRUSH halftone_brush[halftone_num];
+static BITMAP halftone_bitdata[halftone_num];
+static HBITMAP halftone_bitmap[halftone_num];
+
+static unsigned char pattern_bitmaps[][16] = {
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* no fill */
+ {0xFE, 0xFE, 0x7D, 0x7D, 0xBB, 0xBB, 0xD7, 0xD7,
+ 0xEF, 0xEF, 0xD7, 0xD7, 0xBB, 0xBB, 0x7D, 0x7D}, /* cross-hatch (1) */
+ {0x77, 0x77, 0xBB, 0xBB, 0xDD, 0xDD, 0xBB, 0xBB,
+ 0x77, 0x77, 0xBB, 0xBB, 0xDD, 0xDD, 0xBB, 0xBB}, /* double cross-hatch (2) */
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* solid fill (3) */
+ {0xFE, 0xFE, 0xFD, 0xFD, 0xFB, 0xFB, 0xF7, 0xF7,
+ 0xEF, 0xEF, 0xDF, 0xDF, 0xBF, 0xBF, 0x7F, 0x7F}, /* diagonals (4) */
+ {0x7F, 0x7F, 0xBF, 0xBF, 0xDF, 0xDF, 0xEF, 0xEF,
+ 0xF7, 0xF7, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE}, /* diagonals (5) */
+ {0xEE, 0xEE, 0xEE, 0xEE, 0xDD, 0xDD, 0xDD, 0xDD,
+ 0xBB, 0xBB, 0xBB, 0xBB, 0x77, 0x77, 0x77, 0x77}, /* steep diagonals (6) */
+ {0x77, 0x77, 0x77, 0x77, 0xBB, 0xBB, 0xBB, 0xBB,
+ 0xDD, 0xDD, 0xDD, 0xDD, 0xEE, 0xEE, 0xEE, 0xEE} /* steep diagonals (7) */
+#if (0)
+ ,{0xFC, 0xFC, 0xF3, 0xF3, 0xCF, 0xCF, 0x3F, 0x3F,
+ 0xFC, 0xFC, 0xF3, 0xF3, 0xCF, 0xCF, 0x3F, 0x3F}, /* shallow diagonals (old 5) */
+ {0x3F, 0x3F, 0xCF, 0xCF, 0xF3, 0xF3, 0xFC, 0xFC,
+ 0x3F, 0x3F, 0xCF, 0xCF, 0xF3, 0xF3, 0xFC, 0xFC} /* shallow diagonals (old 6) */
+#endif
+};
+#define pattern_num (sizeof(pattern_bitmaps)/(sizeof(*pattern_bitmaps)))
+static HBRUSH pattern_brush[pattern_num];
+static BITMAP pattern_bitdata[pattern_num];
+static HBITMAP pattern_bitmap[pattern_num];
+
+static TBOOLEAN brushes_initialized = FALSE;
+
+
+/* ================================== */
+
+/* prototypes for module-local functions */
+
+LRESULT CALLBACK WINEXPORT WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
+BOOL CALLBACK WINEXPORT LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam);
+
+static void DestroyBlocks(LPGW lpgw);
+static BOOL AddBlock(LPGW lpgw);
+static void StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle);
+static void MakePens(LPGW lpgw, HDC hdc);
+static void DestroyPens(LPGW lpgw);
+static void Wnd_GetTextSize(HDC hdc, LPCSTR str, size_t len, int *cx, int *cy);
+static void MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc);
+static void DestroyFonts(LPGW lpgw);
+static void SetFont(LPGW lpgw, HDC hdc);
+static void SelFont(LPGW lpgw);
+static void dot(HDC hdc, int xdash, int ydash);
+static void drawgraph(LPGW lpgw, HDC hdc, LPRECT rect);
+static void CopyClip(LPGW lpgw);
+static void CopyPrint(LPGW lpgw);
+static void WriteGraphIni(LPGW lpgw);
+static void ReadGraphIni(LPGW lpgw);
+static COLORREF GetColor(HWND hwnd, COLORREF ref);
+static void UpdateColorSample(HWND hdlg);
+static BOOL LineStyle(LPGW lpgw);
+
+/* ================================== */
+
+/* Helper functions for GraphOp(): */
+
+/* destroy memory blocks holding graph operations */
+static void
+DestroyBlocks(LPGW lpgw)
+{
+ struct GWOPBLK *this, *next;
+ struct GWOP FAR *gwop;
+ unsigned int i;
+
+ this = lpgw->gwopblk_head;
+ while (this != NULL) {
+ next = this->next;
+ if (!this->gwop) {
+ this->gwop = (struct GWOP FAR *)GlobalLock(this->hblk);
+ }
+ if (this->gwop) {
+ /* free all text strings within this block */
+ gwop = this->gwop;
+ for (i=0; i<GWOPMAX; i++) {
+ if (gwop->htext)
+ LocalFree(gwop->htext);
+ gwop++;
+ }
+ }
+ GlobalUnlock(this->hblk);
+ GlobalFree(this->hblk);
+ LocalFreePtr(this);
+ this = next;
+ }
+ lpgw->gwopblk_head = NULL;
+ lpgw->gwopblk_tail = NULL;
+ lpgw->nGWOP = 0;
+}
+
+
+/* add a new memory block for graph operations */
+/* returns TRUE if block allocated */
+static BOOL
+AddBlock(LPGW lpgw)
+{
+ HGLOBAL hblk;
+ struct GWOPBLK *next, *this;
+
+ /* create new block */
+ next = (struct GWOPBLK *)LocalAllocPtr(LHND, sizeof(struct GWOPBLK) );
+ if (next == NULL)
+ return FALSE;
+ hblk = GlobalAlloc(GHND, GWOPMAX*sizeof(struct GWOP));
+ if (hblk == NULL)
+ return FALSE;
+ next->hblk = hblk;
+ next->gwop = (struct GWOP FAR *)NULL;
+ next->next = (struct GWOPBLK *)NULL;
+ next->used = 0;
+
+ /* attach it to list */
+ this = lpgw->gwopblk_tail;
+ if (this == NULL) {
+ lpgw->gwopblk_head = next;
+ } else {
+ this->next = next;
+ this->gwop = (struct GWOP FAR *)NULL;
+ GlobalUnlock(this->hblk);
+ }
+ lpgw->gwopblk_tail = next;
+ next->gwop = (struct GWOP FAR *)GlobalLock(next->hblk);
+ if (next->gwop == (struct GWOP FAR *)NULL)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+void WDPROC
+GraphOp(LPGW lpgw, WORD op, WORD x, WORD y, LPCSTR str)
+{
+ if (str)
+ GraphOpSize(lpgw, op, x, y, str, _fstrlen(str)+1);
+ else
+ GraphOpSize(lpgw, op, x, y, NULL, 0);
+}
+
+
+void WDPROC
+GraphOpSize(LPGW lpgw, WORD op, WORD x, WORD y, LPCSTR str, DWORD size)
+{
+ struct GWOPBLK *this;
+ struct GWOP FAR *gwop;
+ char *npstr;
+
+ this = lpgw->gwopblk_tail;
+ if ( (this==NULL) || (this->used >= GWOPMAX) ) {
+ /* not enough space so get new block */
+ if (!AddBlock(lpgw))
+ return;
+ this = lpgw->gwopblk_tail;
+ }
+ gwop = &this->gwop[this->used];
+ gwop->op = op;
+ gwop->x = x;
+ gwop->y = y;
+ gwop->htext = 0;
+ if (str) {
+ gwop->htext = LocalAlloc(LHND, size);
+ npstr = LocalLock(gwop->htext);
+ if (gwop->htext && (npstr != (char *)NULL))
+ memcpy(npstr, str, size);
+ LocalUnlock(gwop->htext);
+ }
+ this->used++;
+ lpgw->nGWOP++;
+ return;
+}
+
+/* ================================== */
+
+/* Prepare Graph window for being displayed by windows, read wgnuplot.ini, update
+ * the window's menus and show it */
+void WDPROC
+GraphInit(LPGW lpgw)
+{
+ HMENU sysmenu;
+ WNDCLASS wndclass;
+ char buf[MAX_PATH];
+
+ if (!lpgw->hPrevInstance) {
+ wndclass.style = CS_HREDRAW | CS_VREDRAW;
+ wndclass.lpfnWndProc = WndGraphProc;
+ wndclass.cbClsExtra = 0;
+ wndclass.cbWndExtra = 2 * sizeof(void FAR *);
+ wndclass.hInstance = lpgw->hInstance;
+ wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
+ wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
+ wndclass.lpszMenuName = NULL;
+ wndclass.lpszClassName = szGraphClass;
+ RegisterClass(&wndclass);
+ }
+
+ ReadGraphIni(lpgw);
+
+ lpgw->hWndGraph = CreateWindow(szGraphClass, lpgw->Title,
+ WS_OVERLAPPEDWINDOW,
+ lpgw->Origin.x, lpgw->Origin.y,
+ lpgw->Size.x, lpgw->Size.y,
+ NULL, NULL, lpgw->hInstance, lpgw);
+
+ lpgw->hPopMenu = CreatePopupMenu();
+ AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->graphtotop ? MF_CHECKED : MF_UNCHECKED),
+ M_GRAPH_TO_TOP, "Bring to &Top");
+ AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->color ? MF_CHECKED : MF_UNCHECKED),
+ M_COLOR, "C&olor");
+ AppendMenu(lpgw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard");
+#if WINVER >= 0x030a
+ AppendMenu(lpgw->hPopMenu, MF_STRING, M_BACKGROUND, "&Background...");
+ AppendMenu(lpgw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
+ AppendMenu(lpgw->hPopMenu, MF_STRING, M_LINESTYLE, "&Line Styles...");
+#endif
+ AppendMenu(lpgw->hPopMenu, MF_STRING, M_PRINT, "&Print...");
+ if (lpgw->IniFile != (LPSTR)NULL) {
+ wsprintf(buf,"&Update %s",lpgw->IniFile);
+ AppendMenu(lpgw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
+ }
+
+ /* modify the system menu to have the new items we want */
+ sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
+ AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(sysmenu, MF_POPUP, (UINT)lpgw->hPopMenu, "&Options");
+ AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
+
+ if (!IsWindowVisible(lpgw->lptw->hWndParent)) {
+ AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
+ AppendMenu(sysmenu, MF_STRING, M_COMMANDLINE, "C&ommand Line");
+ }
+
+ ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
+}
+
+/* close a graph window */
+void WDPROC
+GraphClose(LPGW lpgw)
+{
+ /* close window */
+ if (lpgw->hWndGraph)
+ DestroyWindow(lpgw->hWndGraph);
+ TextMessage();
+ lpgw->hWndGraph = NULL;
+
+ lpgw->locked = TRUE;
+ DestroyBlocks(lpgw);
+ lpgw->locked = FALSE;
+}
+
+
+void WDPROC
+GraphStart(LPGW lpgw, double pointsize)
+{
+ lpgw->locked = TRUE;
+ DestroyBlocks(lpgw);
+ lpgw->org_pointsize = pointsize;
+ if ( !lpgw->hWndGraph || !IsWindow(lpgw->hWndGraph) )
+ GraphInit(lpgw);
+ if (IsIconic(lpgw->hWndGraph))
+ ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
+ if (lpgw->graphtotop) {
+ /* HBB NEW 20040221: avoid grabbing the keyboard focus
+ * unless mouse mode is on */
+#ifdef USE_MOUSE
+ if (mouse_setting.on) {
+ BringWindowToTop(lpgw->hWndGraph);
+ return;
+ }
+#endif /* USE_MOUSE */
+ SetWindowPos(lpgw->hWndGraph,
+ HWND_TOP, 0,0,0,0,
+ SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
+ }
+}
+
+void WDPROC
+GraphEnd(LPGW lpgw)
+{
+ RECT rect;
+
+ GetClientRect(lpgw->hWndGraph, &rect);
+ InvalidateRect(lpgw->hWndGraph, (LPRECT) &rect, 1);
+ lpgw->locked = FALSE;
+ UpdateWindow(lpgw->hWndGraph);
+#ifdef USE_MOUSE
+ gp_exec_event(GE_plotdone, 0, 0, 0, 0, 0); /* notify main program */
+#endif
+}
+
+void WDPROC
+GraphResume(LPGW lpgw)
+{
+ lpgw->locked = TRUE;
+}
+
+void WDPROC
+GraphPrint(LPGW lpgw)
+{
+ if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
+ SendMessage(lpgw->hWndGraph,WM_COMMAND,M_PRINT,0L);
+}
+
+void WDPROC
+GraphRedraw(LPGW lpgw)
+{
+ if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
+ SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
+}
+/* ================================== */
+
+/* Helper functions for bookkeeping of pens, brushes and fonts */
+
+/* Set up LOGPEN structures based on information coming from wgnuplot.ini, via
+ * ReadGraphIni() */
+static void
+StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle)
+{
+ LOGPEN FAR *plp;
+
+ plp = &lpgw->colorpen[i];
+ plp->lopnColor = ref;
+ if (colorstyle < 0) {
+ plp->lopnWidth.x = -colorstyle;
+ plp->lopnStyle = 0;
+ } else {
+ plp->lopnWidth.x = 1;
+ plp->lopnStyle = colorstyle % 5;
+ }
+ plp->lopnWidth.y = 0;
+
+ plp = &lpgw->monopen[i];
+ plp->lopnColor = RGB(0,0,0);
+ if (monostyle < 0) {
+ plp->lopnWidth.x = -monostyle;
+ plp->lopnStyle = 0;
+ } else {
+ plp->lopnWidth.x = 1;
+ plp->lopnStyle = monostyle % 5;
+ }
+ plp->lopnWidth.y = 0;
+}
+
+/* Prepare pens and brushes (--> colors) for use by the driver. Pens are (now) created
+ * on-the-fly (--> DeleteObject(SelectObject(...)) idiom), but the brushes are still
+ * all created statically, and kept until the window is closed */
+static void
+MakePens(LPGW lpgw, HDC hdc)
+{
+ int i;
+
+ if ((GetDeviceCaps(hdc,NUMCOLORS) == 2) || !lpgw->color) {
+ lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[1]); /* axis */
+ lpgw->hbrush = CreateSolidBrush(RGB(255,255,255));
+ for (i=0; i<WGNUMPENS+2; i++)
+ lpgw->colorbrush[i] = CreateSolidBrush(RGB(0,0,0));
+ } else {
+ lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[1]); /* axis */
+ lpgw->hbrush = CreateSolidBrush(lpgw->background);
+ for (i=0; i<WGNUMPENS+2; i++)
+ lpgw->colorbrush[i] = CreateSolidBrush(lpgw->colorpen[i].lopnColor);
+ }
+
+ /* build pattern brushes for filled boxes (ULIG) */
+ if( ! brushes_initialized ) {
+ int i;
+
+ for(i=0; i < halftone_num; i++) {
+ halftone_bitdata[i].bmType = 0;
+ halftone_bitdata[i].bmWidth = 16;
+ halftone_bitdata[i].bmHeight = 8;
+ halftone_bitdata[i].bmWidthBytes = 2;
+ halftone_bitdata[i].bmPlanes = 1;
+ halftone_bitdata[i].bmBitsPixel = 1;
+ halftone_bitdata[i].bmBits = halftone_bitmaps[i];
+ halftone_bitmap[i] = CreateBitmapIndirect(&halftone_bitdata[i]);
+ halftone_brush[i] = CreatePatternBrush(halftone_bitmap[i]);
+ }
+
+ for(i=0; i < pattern_num; i++) {
+ pattern_bitdata[i].bmType = 0;
+ pattern_bitdata[i].bmWidth = 16;
+ pattern_bitdata[i].bmHeight = 8;
+ pattern_bitdata[i].bmWidthBytes = 2;
+ pattern_bitdata[i].bmPlanes = 1;
+ pattern_bitdata[i].bmBitsPixel = 1;
+ pattern_bitdata[i].bmBits = pattern_bitmaps[i];
+ pattern_bitmap[i] = CreateBitmapIndirect(&pattern_bitdata[i]);
+ pattern_brush[i] = CreatePatternBrush(pattern_bitmap[i]);
+ }
+
+ brushes_initialized = TRUE;
+ }
+}
+
+/* Undo effect of MakePens(). To be called just before the window is closed. */
+static void
+DestroyPens(LPGW lpgw)
+{
+ int i;
+
+ DeleteObject(lpgw->hbrush);
+ DeleteObject(lpgw->hapen);
+ for (i=0; i<WGNUMPENS+2; i++)
+ DeleteObject(lpgw->colorbrush[i]);
+
+ /* delete brushes used for boxfilling (ULIG) */
+ if( brushes_initialized ) {
+ int i;
+
+ for( i=0; i<halftone_num; i++ ) {
+ DeleteObject(halftone_bitmap[i]);
+ DeleteObject(halftone_brush[i]);
+ }
+ for( i=0; i<pattern_num; i++ ) {
+ DeleteObject(pattern_bitmap[i]);
+ DeleteObject(pattern_brush[i]);
+ }
+ brushes_initialized = FALSE;
+ }
+}
+
+/* ================================== */
+
+/* HBB 20010218: new function. An isolated snippet from MakeFont(), now also
+ * used in Wnd_put_tmptext() to size the temporary bitmap. */
+static void
+Wnd_GetTextSize(HDC hdc, LPCSTR str, size_t len, int *cx, int *cy)
+{
+#ifdef WIN32
+ SIZE size;
+
+ GetTextExtentPoint(hdc, str, len, &size);
+ *cx = size.cx;
+ *cy = size.cy;
+#else
+ /* Hmm... if not for compatibility to Win 3.0 and earlier, we could
+ * use GetTextExtentPoint on Win16, too :-( */
+ DWORD extent;
+
+ extent = GetTextExtent(hdc, str, len);
+ *cx = LOWORD(extent);
+ *cy = HIWORD(extent);
+#endif
+}
+
+static void
+MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc)
+{
+ HFONT hfontold;
+ TEXTMETRIC tm;
+ int result;
+ char FAR *p;
+ int cx, cy;
+
+ lpgw->rotate = FALSE;
+ _fmemset(&(lpgw->lf), 0, sizeof(LOGFONT));
+ _fstrncpy(lpgw->lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
+ lpgw->lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ lpgw->lf.lfCharSet = DEFAULT_CHARSET;
+ if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
+ lpgw->lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
+ lpgw->lf.lfItalic = TRUE;
+ }
+ if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
+ lpgw->lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
+ lpgw->lf.lfWeight = FW_BOLD;
+ }
+
+ if (lpgw->hfonth == 0) {
+ lpgw->hfonth = CreateFontIndirect((LOGFONT FAR *)&(lpgw->lf));
+ }
+
+ /* we do need a 90 degree font */
+ if (lpgw->hfontv)
+ DeleteObject(lpgw->hfontv);
+ lpgw->lf.lfEscapement = 900;
+ lpgw->lf.lfOrientation = 900;
+ lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&(lpgw->lf));
+
+ /* save text size */
+ hfontold = SelectObject(hdc, lpgw->hfonth);
+ Wnd_GetTextSize(hdc, "0123456789", 10, &cx, &cy);
+ lpgw->vchar = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
+ lpgw->hchar = MulDiv(cx/10,lpgw->xmax,lprect->right - lprect->left);
+
+ /* CMW: Base tick size on character size */
+ lpgw->htic = lpgw->hchar / 2;
+ cy = MulDiv(cx/20, GetDeviceCaps(hdc, LOGPIXELSY), GetDeviceCaps(hdc, LOGPIXELSX));
+ lpgw->vtic = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
+ /* find out if we can rotate text 90deg */
+ SelectObject(hdc, lpgw->hfontv);
+ result = GetDeviceCaps(hdc, TEXTCAPS);
+ if ((result & TC_CR_90) || (result & TC_CR_ANY))
+ lpgw->rotate = TRUE;
+ GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
+ if (tm.tmPitchAndFamily & TMPF_VECTOR)
+ lpgw->rotate = TRUE; /* vector fonts can all be rotated */
+#if WINVER >=0x030a
+ if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
+ lpgw->rotate = TRUE; /* truetype fonts can all be rotated */
+#endif
+ SelectObject(hdc, hfontold);
+ return;
+}
+
+static void
+DestroyFonts(LPGW lpgw)
+{
+ if (lpgw->hfonth) {
+ DeleteObject(lpgw->hfonth);
+ lpgw->hfonth = 0;
+ }
+ if (lpgw->hfontv) {
+ DeleteObject(lpgw->hfontv);
+ lpgw->hfontv = 0;
+ }
+ return;
+}
+
+static void
+SetFont(LPGW lpgw, HDC hdc)
+{
+ if (lpgw->rotate && lpgw->angle) {
+ if (lpgw->hfontv)
+ DeleteObject(lpgw->hfontv);
+ lpgw->lf.lfEscapement = lpgw->lf.lfOrientation = lpgw->angle * 10;
+ lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&(lpgw->lf));
+ if (lpgw->hfontv)
+ SelectObject(hdc, lpgw->hfontv);
+ } else {
+ if (lpgw->hfonth)
+ SelectObject(hdc, lpgw->hfonth);
+ }
+ return;
+}
+
+static void
+SelFont(LPGW lpgw)
+{
+#if WINVER >= 0x030a
+ LOGFONT lf;
+ CHOOSEFONT cf;
+ HDC hdc;
+ char lpszStyle[LF_FACESIZE];
+ char FAR *p;
+
+ /* Set all structure fields to zero. */
+ _fmemset(&cf, 0, sizeof(CHOOSEFONT));
+ _fmemset(&lf, 0, sizeof(LOGFONT));
+ cf.lStructSize = sizeof(CHOOSEFONT);
+ cf.hwndOwner = lpgw->hWndGraph;
+ _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
+ if ((p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL) {
+ _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
+ lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
+ } else if ((p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL) {
+ _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
+ lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
+ } else {
+ _fstrcpy(lpszStyle,"Regular");
+ }
+ cf.lpszStyle = lpszStyle;
+ hdc = GetDC(lpgw->hWndGraph);
+ lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ ReleaseDC(lpgw->hWndGraph, hdc);
+ cf.lpLogFont = &lf;
+ cf.nFontType = SCREEN_FONTTYPE;
+ cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
+ if (ChooseFont(&cf)) {
+ _fstrcpy(lpgw->fontname,lf.lfFaceName);
+ lpgw->fontsize = cf.iPointSize / 10;
+ if (cf.nFontType & BOLD_FONTTYPE)
+ lstrcat(lpgw->fontname," Bold");
+ if (cf.nFontType & ITALIC_FONTTYPE)
+ lstrcat(lpgw->fontname," Italic");
+ /* set current font as default font */
+ strcpy(lpgw->deffontname,lpgw->fontname);
+ lpgw->deffontsize = lpgw->fontsize;
+ SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
+ }
+#endif
+}
+
+#ifdef USE_MOUSE
+/* ================================== */
+
+static void
+LoadCursors(LPGW lpgw)
+{
+ /* 3 of them are standard cursor shapes: */
+ hptrDefault = LoadCursor(NULL, IDC_ARROW);
+ hptrZooming = LoadCursor(NULL, IDC_SIZEALL);
+ hptrCrossHair = LoadCursor( NULL, IDC_CROSS);
+ /* the other 2 are kept in the resource file: */
+ hptrScaling = LoadCursor( lpgw->hInstance, MAKEINTRESOURCE(IDC_SCALING));
+ hptrRotating = LoadCursor( lpgw->hInstance, MAKEINTRESOURCE(IDC_ROTATING));
+
+ hptrCurrent = hptrCrossHair;
+}
+
+static void
+DestroyCursors(LPGW lpgw)
+{
+ /* No-op. Cursors from LoadCursor() don't need destroying */
+ return;
+}
+
+#endif /* USE_MOUSE */
+
+/* ================================== */
+
+
+static void
+dot(HDC hdc, int xdash, int ydash)
+{
+ MoveTo(hdc, xdash, ydash);
+ LineTo(hdc, xdash, ydash+1);
+}
+
+
+/* This one is really the heart of this module: it executes the stored set of
+ * commands, whenever it changed or a redraw is necessary */
+static void
+drawgraph(LPGW lpgw, HDC hdc, LPRECT rect)
+{
+ int xdash, ydash; /* the transformed coordinates */
+ int rr, rl, rt, rb;
+ struct GWOP FAR *curptr;
+ struct GWOPBLK *blkptr;
+ int htic, vtic;
+ int hshift, vshift;
+ unsigned int lastop=-1; /* used for plotting last point on a line */
+ int pen;
+ int polymax = 200;
+ int polyi = 0;
+ POINT *ppt;
+ unsigned int ngwop=0;
+ BOOL isColor;
+ double line_width = 1.0;
+ unsigned int fillstyle = 0.0;
+ int idx;
+
+ if (lpgw->locked)
+ return;
+
+ /* HBB 20010218: the GDI status query functions don't work on Metafile
+ * handles, so can't know whether the screen is actually showing
+ * color or not, if drawgraph() is being called from CopyClip().
+ * Solve by defaulting isColor to 1 if hdc is a metafile. */
+ isColor = (((GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc,BITSPIXEL))
+ > 2)
+ || (GetDeviceCaps(hdc, TECHNOLOGY) == DT_METAFILE));
+
+ if (lpgw->background != RGB(255,255,255) && lpgw->color && isColor) {
+ SetBkColor(hdc,lpgw->background);
+ FillRect(hdc, rect, lpgw->hbrush);
+ }
+
+ ppt = (POINT *)LocalAllocPtr(LHND, (polymax+1) * sizeof(POINT));
+
+ rr = rect->right;
+ rl = rect->left;
+ rt = rect->top;
+ rb = rect->bottom;
+
+ htic = lpgw->org_pointsize*MulDiv(lpgw->htic, rr - rl, lpgw->xmax) + 1;
+ vtic = lpgw->org_pointsize*MulDiv(lpgw->vtic, rb - rt, lpgw->ymax) + 1;
+
+ lpgw->angle = 0;
+ SetFont(lpgw, hdc);
+ SetTextAlign(hdc, TA_LEFT|TA_BASELINE);
+
+ /* calculate text shifting for horizontal text */
+ hshift = 0;
+ vshift = MulDiv(lpgw->vchar, rb - rt, lpgw->ymax)/2;
+
+ pen = 2;
+ SelectObject(hdc, lpgw->hapen);
+ SelectObject(hdc, lpgw->colorbrush[pen]);
+
+ /* do the drawing */
+ blkptr = lpgw->gwopblk_head;
+ curptr = NULL;
+ if (blkptr) {
+ if (!blkptr->gwop)
+ blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
+ if (!blkptr->gwop)
+ return;
+ curptr = (struct GWOP FAR *)blkptr->gwop;
+ }
+
+ while(ngwop < lpgw->nGWOP) {
+ /* transform the coordinates */
+ xdash = MulDiv(curptr->x, rr-rl-1, lpgw->xmax) + rl;
+ ydash = MulDiv(curptr->y, rt-rb+1, lpgw->ymax) + rb - 1;
+ if ((lastop==W_vect) && (curptr->op!=W_vect)) {
+ if (polyi >= 2) {
+ Polyline(hdc, ppt, polyi);
+ MoveTo(hdc, ppt[0].x, ppt[0].y);
+ } else if (polyi == 1)
+ LineTo(hdc, ppt[0].x, ppt[0].y);
+ polyi = 0;
+ }
+ switch (curptr->op) {
+ case 0: /* have run past last in this block */
+ break;
+ case W_move:
+ ppt[0].x = xdash;
+ ppt[0].y = ydash;
+ polyi = 1;
+ break;
+ case W_vect:
+ ppt[polyi].x = xdash;
+ ppt[polyi].y = ydash;
+ polyi++;
+ if (polyi >= polymax) {
+ Polyline(hdc, ppt, polyi);
+ ppt[0].x = xdash;
+ ppt[0].y = ydash;
+ polyi = 1;
+ }
+ break;
+ case W_line_type:
+ {
+ LOGBRUSH lb;
+ LOGPEN cur_penstruct;
+
+ short cur_pen = ((curptr->x < (WORD)(-2))
+ ? (curptr->x % WGNUMPENS) + 2
+ : curptr->x + 2);
+ /* set color only when second parameter to W_line_type equals 1 */
+ if (curptr->y != 1)
+ pen = cur_pen;
+ cur_penstruct = (lpgw->color && isColor) ?
+ lpgw->colorpen[pen] : lpgw->monopen[pen];
+ cur_penstruct.lopnColor = ((lpgw->color && isColor) ?
+ lpgw->colorpen[cur_pen] : lpgw->monopen[cur_pen]).lopnColor;
+
+ if (line_width != 1)
+ cur_penstruct.lopnWidth.x *= line_width;
+
+ /* use ExtCreatePen instead of CreatePen/CreatePenIndirect
+ * to support dashed lines if line_width > 1 */
+ lb.lbStyle = BS_SOLID;
+ lb.lbColor = cur_penstruct.lopnColor;
+
+#if 0 /* shige work-around for Windows clipboard bug */
+ lpgw->hapen = ExtCreatePen(
+ (line_width==1 ? PS_COSMETIC : PS_GEOMETRIC) | cur_penstruct.lopnStyle | PS_ENDCAP_FLAT | PS_JOIN_BEVEL,
+ cur_penstruct.lopnWidth.x, &lb, 0, 0);
+#else
+ if (line_width==1)
+ lpgw->hapen = CreatePenIndirect((LOGPEN FAR *) &cur_penstruct);
+ else
+ lpgw->hapen = ExtCreatePen(
+ PS_GEOMETRIC | cur_penstruct.lopnStyle | PS_ENDCAP_FLAT | PS_JOIN_BEVEL,
+ cur_penstruct.lopnWidth.x, &lb, 0, 0);
+#endif
+ DeleteObject(SelectObject(hdc, lpgw->hapen));
+
+ SelectObject(hdc, lpgw->colorbrush[cur_pen]);
+ /* PM 7.7.2002: support color text */
+ SetTextColor(hdc, cur_penstruct.lopnColor);
+ }
+ break;
+
+ case W_put_text:
+ {
+ char *str;
+ str = LocalLock(curptr->htext);
+ if (str) {
+ /* shift correctly for rotated text */
+ xdash += hshift;
+ ydash += vshift;
+
+ SetBkMode(hdc,TRANSPARENT);
+ TextOut(hdc,xdash,ydash,str,lstrlen(str));
+ SetBkMode(hdc,OPAQUE);
+ }
+ LocalUnlock(curptr->htext);
+ }
+ break;
+
+ case W_fillstyle:
+ /* HBB 20010916: new entry, needed to squeeze the many
+ * parameters of a filled box call through the bottlneck
+ * of the fixed number of parameters in GraphOp() and
+ * struct GWOP, respectively. */
+ fillstyle = curptr->x;
+ break;
+
+ case W_boxfill: /* ULIG */
+
+ assert (polyi == 1);
+
+ /* NOTE: the x and y passed with this call are the width and
+ * height of the box, actually. The left corner was stored into
+ * ppt[0] by a preceding W_move, and the style was memorized
+ * by a W_fillstyle call. */
+ switch(fillstyle & 0x0f) {
+ case FS_SOLID:
+ /* style == 1 --> use halftone fill pattern
+ * according to filldensity. Density is from
+ * 0..100 percent: */
+ idx = ((fillstyle >> 4) * (halftone_num - 1) / 100 );
+ if (idx < 0)
+ idx = 0;
+ if (idx > halftone_num - 1)
+ idx = halftone_num - 1;
+ SelectObject(hdc, halftone_brush[idx]);
+ break;
+ case FS_PATTERN:
+ /* style == 2 --> use fill pattern according to
+ * fillpattern. Pattern number is enumerated */
+ idx = fillstyle >> 4;
+ if (idx < 0)
+ idx = 0;
+ if (idx > pattern_num - 1)
+ idx = 0;
+ SelectObject(hdc, pattern_brush[idx]);
+ break;
+ case FS_EMPTY:
+ default:
+ /* style == 0 or unknown --> fill with background color */
+ SelectObject(hdc, halftone_brush[0]);
+ }
+ /* needs to be fixed for monochrome devices */
+ /* FIXME: probably should keep track of text color */
+ SetTextColor(hdc, lpgw->colorpen[pen].lopnColor);
+ xdash -= rl;
+ ydash -= rb - 1;
+ PatBlt(hdc, ppt[0].x, ppt[0].y, xdash, ydash, PATCOPY);
+ polyi = 0;
+ break;
+ case W_text_angle:
+ if (lpgw->angle != (short int)curptr->x) {
+ lpgw->angle = (short int)curptr->x;
+ /* correctly calculate shifting of rotated text */
+ hshift = sin(M_PI/180. * lpgw->angle) * MulDiv(lpgw->vchar, rr-rl, lpgw->xmax) / 2;
+ vshift = cos(M_PI/180. * lpgw->angle) * MulDiv(lpgw->vchar, rb-rt, lpgw->ymax) / 2;
+ SetFont(lpgw, hdc);
+ }
+ break;
+ case W_justify:
+ switch (curptr->x)
+ {
+ case LEFT:
+ SetTextAlign(hdc, TA_LEFT|TA_BASELINE);
+ break;
+ case RIGHT:
+ SetTextAlign(hdc, TA_RIGHT|TA_BASELINE);
+ break;
+ case CENTRE:
+ SetTextAlign(hdc, TA_CENTER|TA_BASELINE);
+ break;
+ }
+ break;
+ case W_font: {
+ char *font;
+
+ font = LocalLock(curptr->htext);
+ if (font) {
+ GraphChangeFont(lpgw, font, curptr->x, hdc, *rect);
+ SetFont(lpgw, hdc);
+ }
+ LocalUnlock(curptr->htext);
+ }
+ break;
+ case W_pointsize:
+ if (curptr->x != 0) {
+ double pointsize = curptr->x / 100.0;
+ htic = pointsize*MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
+ vtic = pointsize*MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
+ } else {
+ char *str;
+ str = LocalLock(curptr->htext);
+ if (str) {
+ double pointsize;
+ sscanf(str, "%lg", &pointsize);
+ htic = lpgw->org_pointsize
+ * MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
+ vtic = lpgw->org_pointsize
+ * MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
+ }
+ LocalUnlock(curptr->htext);
+ }
+ break;
+ case W_line_width:
+ /* HBB 20000813: this may look strange, but it ensures
+ * that linewidth is exactly 1 iff it's in default
+ * state */
+ line_width = curptr->x == 100 ? 1 : (curptr->x / 100.0);
+ break;
+ case W_pm3d_setcolor:
+ {
+ static HBRUSH last_pm3d_brush = NULL;
+ HBRUSH this_brush;
+ COLORREF c;
+ LOGPEN cur_penstruct;
+ LOGBRUSH lb;
+
+ /* distinguish gray values and RGB colors */
+ if (curptr->y == 0) {
+ rgb255_color rgb255;
+ rgb255maxcolors_from_gray( curptr->x / 256.0, &rgb255 );
+ c = RGB(rgb255.r, rgb255.g, rgb255.b);
+ }
+ else {
+ c = RGB(curptr->y & 0xff, (curptr->x >> 8) & 0xff, curptr->x & 0xff);
+ }
+
+ /* FIXME: always a _solid_ brush?? */
+ this_brush = CreateSolidBrush(c);
+ SelectObject(hdc, this_brush);
+ if (last_pm3d_brush != NULL)
+ DeleteObject(last_pm3d_brush);
+ last_pm3d_brush = this_brush;
+ /* create new pen, too: */
+ cur_penstruct = (lpgw->color && isColor) ?
+ lpgw->colorpen[pen] : lpgw->monopen[pen];
+ if (line_width != 1)
+ cur_penstruct.lopnWidth.x *= line_width;
+ lb.lbStyle = BS_SOLID;
+ lb.lbColor = c;
+ lpgw->hapen = ExtCreatePen(
+ (line_width==1 ? PS_COSMETIC : PS_GEOMETRIC) | cur_penstruct.lopnStyle | PS_ENDCAP_FLAT | PS_JOIN_BEVEL,
+ cur_penstruct.lopnWidth.x, &lb, 0, 0);
+ DeleteObject(SelectObject(hdc, lpgw->hapen));
+ /* finally set text color */
+ SetTextColor(hdc, c);
+ }
+ break;
+ case W_pm3d_filled_polygon_pt:
+ {
+ /* a point of the polygon is coming */
+ if (polyi >= polymax) {
+ polymax += 200;
+ ppt = (POINT *)LocalReAllocPtr(ppt, LHND, (polymax+1) * sizeof(POINT));
+ }
+ ppt[polyi].x = xdash;
+ ppt[polyi].y = ydash;
+ polyi++;
+ }
+ break;
+ case W_pm3d_filled_polygon_draw:
+ {
+ /* end of point series --> draw polygon now */
+ Polygon(hdc, ppt, polyi);
+ polyi = 0;
+ }
+ break;
+ case W_image:
+ {
+ /* Due to the structure of gwop in total 5 entries are needed.
+ These static variables help to collect all the needed information
+ */
+ static int seq = 0; /* sequence counter */
+ static POINT corners[4];
+
+ if (seq < 4) {
+ /* The first four OPs contain the `corner` array */
+ corners[seq].x = xdash;
+ corners[seq].y = ydash;
+ } else {
+ /* The last OP contains the image and it's size */
+ BITMAPINFO bmi;
+ char *image;
+ unsigned int M, N;
+ int rc;
+
+ M = curptr->x;
+ N = curptr->y;
+ image = LocalLock(curptr->htext);
+ if (image) {
+
+ /* rc = SetStretchBltMode(hdc, HALFTONE); */
+
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
+ bmi.bmiHeader.biWidth = M;
+ bmi.bmiHeader.biHeight = N;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 24;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biClrUsed = 0;
+
+ rc = StretchDIBits(hdc,
+ corners[0].x, corners[0].y,
+ corners[1].x - corners[0].x, corners[1].y - corners[0].y,
+ 0, 0,
+ M, N,
+ image, &bmi,
+ DIB_RGB_COLORS, SRCCOPY );
+ }
+ LocalUnlock(curptr->htext);
+ }
+ seq = (seq + 1) % 5;
+ }
+ break;
+ case W_dot:
+ dot(hdc, xdash, ydash);
+ break;
+ case W_plus: /* do plus */
+ MoveTo(hdc,xdash-htic,ydash);
+ LineTo(hdc,xdash+htic+1,ydash);
+ MoveTo(hdc,xdash,ydash-vtic);
+ LineTo(hdc,xdash,ydash+vtic+1);
+ break;
+ case W_cross: /* do X */
+ MoveTo(hdc,xdash-htic,ydash-vtic);
+ LineTo(hdc,xdash+htic+1,ydash+vtic+1);
+ MoveTo(hdc,xdash-htic,ydash+vtic);
+ LineTo(hdc,xdash+htic+1,ydash-vtic-1);
+ break;
+ case W_star: /* do star */
+ MoveTo(hdc,xdash-htic,ydash);
+ LineTo(hdc,xdash+htic+1,ydash);
+ MoveTo(hdc,xdash,ydash-vtic);
+ LineTo(hdc,xdash,ydash+vtic+1);
+ MoveTo(hdc,xdash-htic,ydash-vtic);
+ LineTo(hdc,xdash+htic+1,ydash+vtic+1);
+ MoveTo(hdc,xdash-htic,ydash+vtic);
+ LineTo(hdc,xdash+htic+1,ydash-vtic-1);
+ break;
+ case W_circle: /* do open circle */
+ Arc(hdc, xdash-htic, ydash-vtic, xdash+htic+1, ydash+vtic+1,
+ xdash, ydash+vtic+1, xdash, ydash+vtic+1);
+ dot(hdc, xdash, ydash);
+ break;
+ case W_fcircle: /* do filled circle */
+ Ellipse(hdc, xdash-htic, ydash-vtic,
+ xdash+htic+1, ydash+vtic+1);
+ break;
+ default: /* potentially closed figure */
+ {
+ POINT p[6];
+ int i;
+ int shape = 0;
+ int filled = 0;
+ static float pointshapes[5][10] = {
+ {-1, -1, +1, -1, +1, +1, -1, +1, 0, 0}, /* box */
+ { 0, +1, -1, 0, 0, -1, +1, 0, 0, 0}, /* diamond */
+ { 0, -4./3, -4./3, 2./3,
+ 4./3, 2./3, 0, 0}, /* triangle */
+ { 0, 4./3, -4./3, -2./3,
+ 4./3, -2./3, 0, 0}, /* inverted triangle */
+ { 0, 1, 0.95106, 0.30902, 0.58779, -0.80902,
+ -0.58779, -0.80902, -0.95106, 0.30902} /* pentagon */
+ };
+
+ switch (curptr->op) {
+ case W_box:
+ shape = 0;
+ break;
+ case W_diamond:
+ shape = 1;
+ break;
+ case W_itriangle:
+ shape = 2;
+ break;
+ case W_triangle:
+ shape = 3;
+ break;
+ case W_pentagon:
+ shape = 4;
+ break;
+ case W_fbox:
+ shape = 0;
+ filled = 1;
+ break;
+ case W_fdiamond:
+ shape = 1;
+ filled = 1;
+ break;
+ case W_fitriangle:
+ shape = 2;
+ filled = 1;
+ break;
+ case W_ftriangle:
+ shape = 3;
+ filled = 1;
+ break;
+ case W_fpentagon:
+ shape = 4;
+ filled = 1;
+ break;
+ }
+
+ for (i = 0; i < 5; ++i) {
+ if (pointshapes[shape][i * 2 + 1] == 0
+ && pointshapes[shape][i * 2] == 0)
+ break;
+ p[i].x = xdash + htic*pointshapes[shape][i*2] + 0.5;
+ p[i].y = ydash + vtic*pointshapes[shape][i*2+1] + 0.5;
+ }
+ if ( filled )
+ /* Filled polygon */
+ Polygon(hdc, p, i);
+ else {
+ /* Outline polygon */
+ p[i].x = p[0].x;
+ p[i].y = p[0].y;
+ Polyline(hdc, p, i+1);
+ dot(hdc, xdash, ydash);
+ }
+ } /* default case */
+ } /* switch(opcode) */
+ lastop = curptr->op;
+ ngwop++;
+ curptr++;
+ if ((unsigned)(curptr - blkptr->gwop) >= GWOPMAX) {
+ GlobalUnlock(blkptr->hblk);
+ blkptr->gwop = (struct GWOP FAR *)NULL;
+ if ((blkptr = blkptr->next) == NULL)
+ /* If exact multiple of GWOPMAX entries are queued,
+ * next will be NULL. Only the next GraphOp() call would
+ * have allocated a new block */
+ return;
+ if (!blkptr->gwop)
+ blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
+ if (!blkptr->gwop)
+ return;
+ curptr = (struct GWOP FAR *)blkptr->gwop;
+ }
+ }
+ if (polyi >= 2)
+ Polyline(hdc, ppt, polyi);
+ LocalFreePtr(ppt);
+}
+
+/* ================================== */
+
+/* copy graph window to clipboard --- note that the Metafile is drawn at the full
+ * virtual resolution of the Windows terminal driver (24000 x 18000 pixels), to
+ * preserve as much accuracy as remotely possible */
+static void
+CopyClip(LPGW lpgw)
+{
+ RECT rect;
+ HDC mem;
+ HBITMAP bitmap;
+ HANDLE hmf;
+ GLOBALHANDLE hGMem;
+ LPMETAFILEPICT lpMFP;
+ HWND hwnd;
+ HDC hdc;
+
+ hwnd = lpgw->hWndGraph;
+
+ /* view the window */
+ if (IsIconic(hwnd))
+ ShowWindow(hwnd, SW_SHOWNORMAL);
+ BringWindowToTop(hwnd);
+ UpdateWindow(hwnd);
+
+ /* get the context */
+ hdc = GetDC(hwnd);
+ GetClientRect(hwnd, &rect);
+
+ /* make a bitmap and copy it there */
+ mem = CreateCompatibleDC(hdc);
+ bitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left,
+ rect.bottom - rect.top);
+ if (bitmap) {
+ /* there is enough memory and the bitmaps OK */
+ SelectObject(mem, bitmap);
+ BitBlt(mem,0,0,rect.right - rect.left,
+ rect.bottom - rect.top, hdc, rect.left,
+ rect.top, SRCCOPY);
+ } else {
+ MessageBeep(MB_ICONHAND);
+ MessageBox(hwnd, "Insufficient Memory to Copy Clipboard",
+ lpgw->Title, MB_ICONHAND | MB_OK);
+ }
+ DeleteDC(mem);
+
+ /* OK, bitmap done, now create a Metafile context at full theoretical resolution
+ * of the Windows terminal (24000 x 18000 pixels), and redraw the whole
+ * plot into that. */
+ {
+ /* make copy of window's main status struct for modification */
+ GW gwclip = *lpgw;
+ int windowfontsize = MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
+ int i;
+
+ gwclip.fontsize = MulDiv(windowfontsize, lpgw->ymax, rect.bottom);
+ gwclip.hfonth = gwclip.hfontv = 0;
+
+ /* HBB 981203: scale up pens as well... */
+ for (i = 0; i < WGNUMPENS + 2; i++) {
+ if(gwclip.monopen[i].lopnWidth.x > 1)
+ gwclip.monopen[i].lopnWidth.x =
+ MulDiv(gwclip.monopen[i].lopnWidth.x,
+ gwclip.xmax, rect.right-rect.left);
+ if(gwclip.colorpen[i].lopnWidth.x > 1)
+ gwclip.colorpen[i].lopnWidth.x =
+ MulDiv(gwclip.colorpen[i].lopnWidth.x,
+ gwclip.xmax, rect.right-rect.left);
+ }
+
+ rect.right = lpgw->xmax;
+ rect.bottom = lpgw->ymax;
+
+ MakePens(&gwclip, hdc);
+ MakeFonts(&gwclip, &rect, hdc);
+
+ ReleaseDC(hwnd, hdc);
+
+ hdc = CreateMetaFile((LPSTR)NULL);
+
+/* HBB 981203: According to Petzold, Metafiles shouldn't contain SetMapMode() calls: */
+ /*SetMapMode(hdc, MM_ANISOTROPIC);*/
+#ifdef WIN32
+ SetWindowExtEx(hdc, rect.right, rect.bottom, (LPSIZE)NULL);
+#else
+ SetWindowExt(hdc, rect.right, rect.bottom);
+#endif
+ drawgraph(&gwclip, hdc, (LPRECT) &rect);
+ hmf = CloseMetaFile(hdc);
+ DestroyFonts(&gwclip);
+ DestroyPens(&gwclip);
+ }
+
+ /* Now we have the Metafile and Bitmap prepared, post their contents to
+ * the Clipboard */
+
+ hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(METAFILEPICT));
+ lpMFP = (LPMETAFILEPICT) GlobalLock(hGMem);
+ hdc = GetDC(hwnd); /* get window size */
+ GetClientRect(hwnd, &rect);
+ /* in MM_ANISOTROPIC, xExt & yExt give suggested size in 0.01mm units */
+ lpMFP->mm = MM_ANISOTROPIC;
+ lpMFP->xExt = MulDiv(rect.right-rect.left, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
+ lpMFP->yExt = MulDiv(rect.bottom-rect.top, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
+ lpMFP->hMF = hmf;
+ ReleaseDC(hwnd, hdc);
+ GlobalUnlock(hGMem);
+
+ OpenClipboard(hwnd);
+ EmptyClipboard();
+ SetClipboardData(CF_METAFILEPICT,hGMem);
+ SetClipboardData(CF_BITMAP, bitmap);
+ CloseClipboard();
+ return;
+}
+
+/* copy graph window to printer */
+static void
+CopyPrint(LPGW lpgw)
+{
+#ifdef WIN32
+ DOCINFO docInfo;
+#endif
+
+#if WINVER >= 0x030a /* If Win 3.0, this whole function does nothing at all ... */
+ HDC printer;
+#ifndef WIN32
+ DLGPROC lpfnAbortProc;
+ DLGPROC lpfnPrintDlgProc;
+#endif
+ PRINTDLG pd;
+ HWND hwnd;
+ RECT rect;
+ GP_PRINT pr;
+
+ hwnd = lpgw->hWndGraph;
+
+ _fmemset(&pd, 0, sizeof(PRINTDLG));
+ pd.lStructSize = sizeof(PRINTDLG);
+ pd.hwndOwner = hwnd;
+ pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
+
+ if (!PrintDlg(&pd))
+ return;
+ printer = pd.hDC;
+ if (NULL == printer)
+ return; /* abort */
+
+ if (!PrintSize(printer, hwnd, &rect)) {
+ DeleteDC(printer);
+ return; /* abort */
+ }
+
+ pr.hdcPrn = printer;
+ SetWindowLong(hwnd, 4, (LONG)((GP_LPPRINT)&pr));
+#ifdef WIN32
+ PrintRegister((GP_LPPRINT)&pr);
+#endif
+
+ EnableWindow(hwnd,FALSE);
+ pr.bUserAbort = FALSE;
+#ifdef WIN32
+ pr.hDlgPrint = CreateDialogParam(hdllInstance,"CancelDlgBox",hwnd,PrintDlgProc,(LPARAM)lpgw->Title);
+ SetAbortProc(printer,PrintAbortProc);
+
+ memset(&docInfo, 0, sizeof(DOCINFO));
+ docInfo.cbSize = sizeof(DOCINFO);
+ docInfo.lpszDocName = lpgw->Title;
+
+ if (StartDoc(printer, &docInfo) > 0) {
+#else /* not WIN32 */
+# ifdef __DLL__
+ lpfnPrintDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintDlgProc");
+ lpfnAbortProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintAbortProc");
+# else /* __DLL__ */
+ lpfnPrintDlgProc = (DLGPROC)MakeProcInstance((FARPROC)PrintDlgProc, hdllInstance);
+ lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)PrintAbortProc, hdllInstance);
+# endif /* __DLL__ */
+ pr.hDlgPrint = CreateDialogParam(hdllInstance,"CancelDlgBox",hwnd,lpfnPrintDlgProc,(LPARAM)lpgw->Title);
+ Escape(printer,SETABORTPROC,0,(LPSTR)lpfnAbortProc,NULL);
+ if (Escape(printer, STARTDOC, lstrlen(lpgw->Title),lpgw->Title, NULL) > 0) {
+#endif
+ SetMapMode(printer, MM_TEXT);
+ SetBkMode(printer,OPAQUE);
+#ifdef WIN32
+ StartPage(printer);
+#endif
+ DestroyFonts(lpgw);
+ MakeFonts(lpgw, (RECT FAR *)&rect, printer);
+ DestroyPens(lpgw); /* rebuild pens */
+ MakePens(lpgw, printer);
+ drawgraph(lpgw, printer, (void *) &rect);
+#ifdef WIN32
+ if (EndPage(printer) > 0)
+ EndDoc(printer);
+# else /* WIN32 */
+ if (Escape(printer,NEWFRAME,0,NULL,NULL) > 0)
+ Escape(printer,ENDDOC,0,NULL,NULL);
+# endif /* WIN32 */
+ }
+ if (!pr.bUserAbort) {
+ EnableWindow(hwnd,TRUE);
+ DestroyWindow(pr.hDlgPrint);
+ }
+#ifndef WIN32
+#ifndef __DLL__
+ FreeProcInstance((FARPROC)lpfnPrintDlgProc);
+ FreeProcInstance((FARPROC)lpfnAbortProc);
+# endif /* __DLL__ */
+#endif /* WIN32 */
+ DeleteDC(printer);
+ SetWindowLong(hwnd, 4, (LONG)(0L));
+#ifdef WIN32
+ PrintUnregister((GP_LPPRINT)&pr);
+#endif /* WIN32 */
+ /* make certain that the screen pen set is restored */
+ SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
+#endif /* WIN Version >= 3.1 */
+ return;
+}
+
+/* ================================== */
+/* INI file stuff */
+static void
+WriteGraphIni(LPGW lpgw)
+{
+ RECT rect;
+ int i;
+ char entry[32];
+ LPLOGPEN pc;
+ LPLOGPEN pm;
+ LPSTR file = lpgw->IniFile;
+ LPSTR section = lpgw->IniSection;
+ char profile[80];
+
+ if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
+ return;
+ if (IsIconic(lpgw->hWndGraph))
+ ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
+ GetWindowRect(lpgw->hWndGraph,&rect);
+ wsprintf(profile, "%d %d", rect.left, rect.top);
+ WritePrivateProfileString(section, "GraphOrigin", profile, file);
+ wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
+ WritePrivateProfileString(section, "GraphSize", profile, file);
+ wsprintf(profile, "%s,%d", lpgw->deffontname, lpgw->deffontsize);
+ WritePrivateProfileString(section, "GraphFont", profile, file);
+ wsprintf(profile, "%d", lpgw->color);
+ WritePrivateProfileString(section, "GraphColor", profile, file);
+ wsprintf(profile, "%d", lpgw->graphtotop);
+ WritePrivateProfileString(section, "GraphToTop", profile, file);
+ wsprintf(profile, "%d %d %d",GetRValue(lpgw->background),
+ GetGValue(lpgw->background), GetBValue(lpgw->background));
+ WritePrivateProfileString(section, "GraphBackground", profile, file);
+
+ /* now save pens */
+ for (i=0; i<WGNUMPENS+2; i++) {
+ if (i==0)
+ _fstrcpy(entry,"Border");
+ else if (i==1)
+ _fstrcpy(entry,"Axis");
+ else
+ wsprintf(entry,"Line%d",i-1);
+ pc = &lpgw->colorpen[i];
+ pm = &lpgw->monopen[i];
+ wsprintf(profile, "%d %d %d %d %d",GetRValue(pc->lopnColor),
+ GetGValue(pc->lopnColor), GetBValue(pc->lopnColor),
+ (pc->lopnWidth.x != 1) ? -pc->lopnWidth.x : pc->lopnStyle,
+ (pm->lopnWidth.x != 1) ? -pm->lopnWidth.x : pm->lopnStyle);
+ WritePrivateProfileString(section, entry, profile, file);
+ }
+ return;
+}
+
+static void
+ReadGraphIni(LPGW lpgw)
+{
+ LPSTR file = lpgw->IniFile;
+ LPSTR section = lpgw->IniSection;
+ char profile[81];
+ char entry[32];
+ LPSTR p;
+ int i,r,g,b,colorstyle,monostyle;
+ COLORREF ref;
+ BOOL bOKINI;
+
+ bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
+ if (!bOKINI)
+ profile[0] = '\0';
+
+ if (bOKINI)
+ GetPrivateProfileString(section, "GraphOrigin", "", profile, 80, file);
+ if ( (p = GetInt(profile, (LPINT)&lpgw->Origin.x)) == NULL)
+ lpgw->Origin.x = CW_USEDEFAULT;
+ if ( (p = GetInt(p, (LPINT)&lpgw->Origin.y)) == NULL)
+ lpgw->Origin.y = CW_USEDEFAULT;
+ if (bOKINI)
+ GetPrivateProfileString(section, "GraphSize", "", profile, 80, file);
+ if ( (p = GetInt(profile, (LPINT)&lpgw->Size.x)) == NULL)
+ lpgw->Size.x = CW_USEDEFAULT;
+ if ( (p = GetInt(p, (LPINT)&lpgw->Size.y)) == NULL)
+ lpgw->Size.y = CW_USEDEFAULT;
+
+ if (bOKINI)
+ GetPrivateProfileString(section, "GraphFont", "", profile, 80, file);
+ {
+ char FAR *size;
+ size = _fstrchr(profile,',');
+ if (size) {
+ *size++ = '\0';
+ if ( (p = GetInt(size, (LPINT)&lpgw->fontsize)) == NULL)
+ lpgw->fontsize = WINFONTSIZE;
+ }
+ _fstrcpy(lpgw->fontname, profile);
+ if (lpgw->fontsize == 0)
+ lpgw->fontsize = WINFONTSIZE;
+ if (!(*lpgw->fontname)) {
+ if (LOWORD(GetVersion()) == 3)
+ _fstrcpy(lpgw->fontname,WIN30FONT);
+ else
+ _fstrcpy(lpgw->fontname,WINFONT);
+ }
+ /* set current font as default font */
+ _fstrcpy(lpgw->deffontname, lpgw->fontname);
+ lpgw->deffontsize = lpgw->fontsize;
+ }
+
+ if (bOKINI)
+ GetPrivateProfileString(section, "GraphColor", "", profile, 80, file);
+ if ( (p = GetInt(profile, (LPINT)&lpgw->color)) == NULL)
+ lpgw->color = TRUE;
+
+ if (bOKINI)
+ GetPrivateProfileString(section, "GraphToTop", "", profile, 80, file);
+ if ( (p = GetInt(profile, (LPINT)&lpgw->graphtotop)) == NULL)
+ lpgw->graphtotop = TRUE;
+
+ lpgw->background = RGB(255,255,255);
+ if (bOKINI)
+ GetPrivateProfileString(section, "GraphBackground", "", profile, 80, file);
+ if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&g)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&b)) != NULL) )
+ lpgw->background = RGB(r,g,b);
+
+ StorePen(lpgw, 0,RGB(0,0,0),PS_SOLID,PS_SOLID);
+ if (bOKINI)
+ GetPrivateProfileString(section, "Border", "", profile, 80, file);
+ if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&g)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&b)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
+ StorePen(lpgw,0,RGB(r,g,b),colorstyle,monostyle);
+
+ StorePen(lpgw, 1,RGB(192,192,192),PS_DOT,PS_DOT);
+ if (bOKINI)
+ GetPrivateProfileString(section, "Axis", "", profile, 80, file);
+ if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&g)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&b)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
+ StorePen(lpgw,1,RGB(r,g,b),colorstyle,monostyle);
+
+ for (i=0; i<WGNUMPENS; i++)
+ {
+ ref = wginitcolor[ i%WGDEFCOLOR ];
+ colorstyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
+ monostyle = wginitstyle[ i%WGDEFSTYLE ];
+ StorePen(lpgw, i+2,ref,colorstyle,monostyle);
+ wsprintf(entry,"Line%d",i+1);
+ if (bOKINI)
+ GetPrivateProfileString(section, entry, "", profile, 80, file);
+ if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&g)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&b)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
+ ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
+ StorePen(lpgw,i+2,RGB(r,g,b),colorstyle,monostyle);
+ }
+}
+
+
+/* ================================== */
+
+/* the "Line Styles..." dialog and its support functions */
+/* FIXME HBB 20010218: this might better be delegated to a separate source file */
+
+#define LS_DEFLINE 2
+typedef struct tagLS {
+ int widtype;
+ int wid;
+ HWND hwnd;
+ int pen; /* current pen number */
+ LOGPEN colorpen[WGNUMPENS+2]; /* logical color pens */
+ LOGPEN monopen[WGNUMPENS+2]; /* logical mono pens */
+} LS;
+typedef LS FAR* LPLS;
+
+
+static COLORREF
+GetColor(HWND hwnd, COLORREF ref)
+{
+ CHOOSECOLOR cc;
+ COLORREF aclrCust[16];
+ int i;
+
+ for (i=0; i<16; i++) {
+ aclrCust[i] = RGB(0,0,0);
+ }
+ _fmemset(&cc, 0, sizeof(CHOOSECOLOR));
+ cc.lStructSize = sizeof(CHOOSECOLOR);
+ cc.hwndOwner = hwnd;
+ cc.lpCustColors = aclrCust;
+ cc.rgbResult = ref;
+ cc.Flags = CC_RGBINIT;
+ if (ChooseColor(&cc))
+ return cc.rgbResult;
+ return ref;
+}
+
+
+/* force update of owner draw button */
+static void
+UpdateColorSample(HWND hdlg)
+{
+ RECT rect;
+ POINT ptul, ptlr;
+ GetWindowRect( GetDlgItem(hdlg, LS_COLORSAMPLE), &rect);
+ ptul.x = rect.left;
+ ptul.y = rect.top;
+ ptlr.x = rect.right;
+ ptlr.y = rect.bottom;
+ ScreenToClient(hdlg, &ptul);
+ ScreenToClient(hdlg, &ptlr);
+ rect.left = ptul.x;
+ rect.top = ptul.y;
+ rect.right = ptlr.x;
+ rect.bottom = ptlr.y;
+ InvalidateRect(hdlg, &rect, TRUE);
+ UpdateWindow(hdlg);
+}
+
+/* Window handler function for the "Line Styles" dialog */
+BOOL CALLBACK WINEXPORT
+LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam)
+{
+ char buf[16];
+ LPLS lpls;
+ int i;
+ UINT pen;
+ LPLOGPEN plpm, plpc;
+ lpls = (LPLS)GetWindowLong(GetParent(hdlg), 4);
+
+ switch (wmsg) {
+ case WM_INITDIALOG:
+ pen = 2;
+ for (i=0; i<WGNUMPENS+2; i++) {
+ if (i==0)
+ _fstrcpy(buf,"Border");
+ else if (i==1)
+ _fstrcpy(buf,"Axis");
+ else
+ wsprintf(buf,"Line%d",i-1);
+ SendDlgItemMessage(hdlg, LS_LINENUM, LB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)buf));
+ }
+ SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
+
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"Solid"));
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"Dash"));
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"Dot"));
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"DashDot"));
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"DashDotDot"));
+
+ plpm = &lpls->monopen[pen];
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
+ plpm->lopnStyle, 0L);
+ wsprintf(buf,"%d",plpm->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
+
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"Solid"));
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"Dash"));
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"Dot"));
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"DashDot"));
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
+ (LPARAM)((LPSTR)"DashDotDot"));
+
+ plpc = &lpls->colorpen[pen];
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
+ plpc->lopnStyle, 0L);
+ wsprintf(buf,"%d",plpc->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
+
+ return TRUE;
+ case WM_COMMAND:
+ pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, 0, 0L);
+ plpm = &lpls->monopen[pen];
+ plpc = &lpls->colorpen[pen];
+ switch (LOWORD(wparam)) {
+ case LS_LINENUM:
+ wsprintf(buf,"%d",plpm->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
+ plpm->lopnStyle, 0L);
+ wsprintf(buf,"%d",plpc->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
+ plpc->lopnStyle, 0L);
+ UpdateColorSample(hdlg);
+ return FALSE;
+ case LS_MONOSTYLE:
+ plpm->lopnStyle =
+ (UINT)SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_GETCURSEL, 0, 0L);
+ if (plpm->lopnStyle != 0) {
+ plpm->lopnWidth.x = 1;
+ wsprintf(buf,"%d",plpm->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
+ }
+ return FALSE;
+ case LS_MONOWIDTH:
+ GetDlgItemText(hdlg, LS_MONOWIDTH, buf, 15);
+ GetInt(buf, (LPINT)&plpm->lopnWidth.x);
+ if (plpm->lopnWidth.x != 1) {
+ plpm->lopnStyle = 0;
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
+ plpm->lopnStyle, 0L);
+ }
+ return FALSE;
+ case LS_CHOOSECOLOR:
+ plpc->lopnColor = GetColor(hdlg, plpc->lopnColor);
+ UpdateColorSample(hdlg);
+ return FALSE;
+ case LS_COLORSTYLE:
+ plpc->lopnStyle =
+ (UINT)SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_GETCURSEL, 0, 0L);
+ if (plpc->lopnStyle != 0) {
+ plpc->lopnWidth.x = 1;
+ wsprintf(buf,"%d",plpc->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
+ }
+ return FALSE;
+ case LS_COLORWIDTH:
+ GetDlgItemText(hdlg, LS_COLORWIDTH, buf, 15);
+ GetInt(buf, (LPINT)&plpc->lopnWidth.x);
+ if (plpc->lopnWidth.x != 1) {
+ plpc->lopnStyle = 0;
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
+ plpc->lopnStyle, 0L);
+ }
+ return FALSE;
+ case LS_DEFAULT:
+ plpm = lpls->monopen;
+ plpc = lpls->colorpen;
+ /* border */
+ plpc->lopnColor = RGB(0,0,0);
+ plpc->lopnStyle = PS_SOLID;
+ plpc->lopnWidth.x = 1;
+ plpm->lopnStyle = PS_SOLID;
+ plpm->lopnWidth.x = 1;
+ plpc++; plpm++;
+ /* axis */
+ plpc->lopnColor = RGB(192,192,192);
+ plpc->lopnStyle = PS_DOT;
+ plpc->lopnWidth.x = 1;
+ plpm->lopnStyle = PS_DOT;
+ plpm->lopnWidth.x = 1;
+ /* LineX */
+ for (i=0; i<WGNUMPENS; i++) {
+ plpc++; plpm++;
+ plpc->lopnColor = wginitcolor[ i%WGDEFCOLOR ];
+ plpc->lopnStyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
+ plpc->lopnWidth.x = 1;
+ plpm->lopnStyle = wginitstyle[ i%WGDEFSTYLE ];
+ plpm->lopnWidth.x = 1;
+ }
+ /* update window */
+ plpm = &lpls->monopen[pen];
+ plpc = &lpls->colorpen[pen];
+ SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
+ wsprintf(buf,"%d",plpm->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
+ SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
+ plpm->lopnStyle, 0L);
+ wsprintf(buf,"%d",plpc->lopnWidth.x);
+ SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
+ SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
+ plpc->lopnStyle, 0L);
+ UpdateColorSample(hdlg);
+ return FALSE;
+ case IDOK:
+ EndDialog(hdlg, IDOK);
+ return TRUE;
+ case IDCANCEL:
+ EndDialog(hdlg, IDCANCEL);
+ return TRUE;
+ }
+ break;
+ case WM_DRAWITEM:
+ {
+ HBRUSH hBrush;
+ LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lparam;
+ pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
+ plpc = &lpls->colorpen[pen];
+ hBrush = CreateSolidBrush(plpc->lopnColor);
+ FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
+ FrameRect(lpdis->hDC, &lpdis->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
+ DeleteObject(hBrush);
+ }
+ return FALSE;
+ }
+ return FALSE;
+}
+
+
+
+/* GetWindowLong(hwnd, 4) must be available for use */
+static BOOL
+LineStyle(LPGW lpgw)
+{
+ BOOL status = FALSE;
+ LS ls;
+#ifndef WIN32
+ DLGPROC lpfnLineStyleDlgProc;
+#endif
+
+ SetWindowLong(lpgw->hWndGraph, 4, (LONG)((LPLS)&ls));
+ _fmemcpy(&ls.colorpen, &lpgw->colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
+ _fmemcpy(&ls.monopen, &lpgw->monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
+
+#ifdef WIN32
+ if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, LineStyleDlgProc)
+#else
+# ifdef __DLL__
+ lpfnLineStyleDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "LineStyleDlgProc");
+# else
+ lpfnLineStyleDlgProc = (DLGPROC)MakeProcInstance((FARPROC)LineStyleDlgProc, hdllInstance);
+# endif
+ if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, lpfnLineStyleDlgProc)
+#endif
+ == IDOK) {
+ _fmemcpy(&lpgw->colorpen, &ls.colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
+ _fmemcpy(&lpgw->monopen, &ls.monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
+ status = TRUE;
+ }
+#ifndef WIN32
+# ifndef __DLL__
+ FreeProcInstance((FARPROC)lpfnLineStyleDlgProc);
+# endif
+#endif
+ SetWindowLong(lpgw->hWndGraph, 4, (LONG)(0L));
+ return status;
+}
+
+#ifdef USE_MOUSE
+/* ================================== */
+/* HBB 20010207: new helper functions: wrapper around gp_exec_event
+ * and DoZoombox. These may vanish again, as has the original idea I
+ * invented them for... */
+
+static void
+Wnd_exec_event(LPGW lpgw, LPARAM lparam, char type, int par1)
+{
+ int mx, my;
+ static unsigned long lastTimestamp = 0;
+ unsigned long thisTimestamp = GetMessageTime();
+ int par2 = thisTimestamp - lastTimestamp;
+
+ if (type == GE_keypress)
+ par2 = 0;
+
+ GetMousePosViewport(lpgw, &mx, &my);
+ gp_exec_event(type, mx, my, par1, par2, 0);
+ lastTimestamp = thisTimestamp;
+}
+
+static void
+Wnd_refresh_zoombox(LPGW lpgw, LPARAM lParam)
+{
+ int mx, my;
+
+ GetMousePosViewport(lpgw, &mx, &my);
+ DrawZoomBox(lpgw); /* erase current zoom box */
+ zoombox.to.x = mx; zoombox.to.y = my;
+ DrawZoomBox(lpgw); /* draw new zoom box */
+}
+
+static void
+Wnd_refresh_ruler_lineto(LPGW lpgw, LPARAM lParam)
+{
+ int mx, my;
+
+ GetMousePosViewport(lpgw, &mx, &my);
+ DrawRulerLineTo(lpgw); /* erase current line */
+ ruler_lineto.x = mx; ruler_lineto.y = my;
+ DrawRulerLineTo(lpgw); /* draw new line box */
+}
+#endif /* USE_MOUSE */
+
+/* ================================== */
+
+/* The toplevel function of this module: Window handler function of the graph window */
+LRESULT CALLBACK WINEXPORT
+WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HDC hdc;
+ PAINTSTRUCT ps;
+ RECT rect;
+ LPGW lpgw;
+ HMENU sysmenu;
+ int i;
+#ifdef USE_MOUSE
+ static unsigned int last_modifier_mask = -99;
+#endif
+
+ lpgw = (LPGW)GetWindowLong(hwnd, 0);
+
+#ifdef USE_MOUSE
+ /* mouse events first */
+ if (mouse_setting.on /* AND NOT mouse_lock */ ) {
+ switch (message) {
+ case WM_MOUSEMOVE:
+#if 1
+ SetCursor(hptrCurrent);
+#else
+ SetCursor(hptrCrossHair);
+#endif
+ if (zoombox.on) {
+ Wnd_refresh_zoombox(lpgw, lParam);
+ }
+ if (ruler.on && ruler_lineto.on) {
+ Wnd_refresh_ruler_lineto(lpgw, lParam);
+ }
+ /* track (show) mouse position -- send the event to gnuplot */
+ Wnd_exec_event(lpgw, lParam, GE_motion, wParam);
+ return 0L; /* end of WM_MOUSEMOVE */
+
+ case WM_LBUTTONDOWN:
+ Wnd_exec_event(lpgw, lParam, GE_buttonpress, 1);
+ return 0L;
+
+ case WM_RBUTTONDOWN:
+ /* FIXME HBB 20010207: this collides with the right-click
+ * context menu !!! */
+ Wnd_exec_event(lpgw, lParam, GE_buttonpress, 3);
+ return 0L;
+
+ case WM_MBUTTONDOWN:
+ Wnd_exec_event(lpgw, lParam, GE_buttonpress, 2);
+ return 0L;
+
+ case WM_LBUTTONDBLCLK:
+ Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 1);
+ return 0L;
+
+ case WM_RBUTTONDBLCLK:
+ Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 3);
+ return 0L;
+
+ case WM_MBUTTONDBLCLK:
+ Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 2);
+ return 0L;
+
+#if 1
+ case WM_LBUTTONUP:
+#else
+ case WM_LBUTTONCLICK:
+#endif
+ Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 1);
+ return 0L;
+
+#if 1
+ case WM_RBUTTONUP:
+#else
+ case WM_RBUTTONCLICK:
+#endif
+ Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 3);
+ return 0L;
+
+#if 1
+ case WM_MBUTTONUP:
+#else
+ case WM_MBUTTONCLICK:
+#endif
+ Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 2);
+ return 0L;
+
+ } /* switch over mouse events */
+ }
+#endif /* USE_MOUSE */
+
+
+
+ switch(message)
+ {
+ case WM_SYSCOMMAND:
+ switch(LOWORD(wParam))
+ {
+ case M_GRAPH_TO_TOP:
+ case M_COLOR:
+ case M_CHOOSE_FONT:
+ case M_COPY_CLIP:
+ case M_LINESTYLE:
+ case M_BACKGROUND:
+ case M_PRINT:
+ case M_WRITEINI:
+ case M_REBUILDTOOLS:
+ SendMessage(hwnd, WM_COMMAND, wParam, lParam);
+ break;
+ case M_ABOUT:
+ if (lpgw->lptw)
+ AboutBox(hwnd,lpgw->lptw->AboutText);
+ return 0;
+ case M_COMMANDLINE:
+ sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
+ i = GetMenuItemCount (sysmenu);
+ DeleteMenu (sysmenu, --i, MF_BYPOSITION);
+ DeleteMenu (sysmenu, --i, MF_BYPOSITION);
+ ShowWindow (lpgw->lptw->hWndParent, SW_SHOW);
+ break;
+ }
+ break;
+ case WM_CHAR:
+ /* All 'normal' keys (letters, digits and the likes) end up
+ * here... */
+ if (wParam == VK_SPACE) {
+ /* HBB 20001023: implement the '<space> in graph returns to
+ * text window' --- feature already present in OS/2 and X11 */
+ /* Make sure the text window is visible: */
+ ShowWindow(lpgw->lptw->hWndParent, SW_SHOW);
+ /* and activate it (--> Keyboard focus goes there */
+ BringWindowToTop(lpgw->lptw->hWndParent);
+ return 0;
+ }
+#ifdef USE_MOUSE
+ Wnd_exec_event(lpgw, lParam, GE_keypress, (TCHAR)wParam);
+#endif
+ return 0L;
+#ifdef USE_MOUSE
+ /* "special" keys have to be caught from WM_KEYDOWN, as they
+ * don't generate WM_CHAR messages. */
+ /* NB: It may not be possible to catch Alt-keys, this way */
+ case WM_KEYUP:
+ {
+ /* First, look for a change in modifier status */
+ unsigned int modifier_mask = 0;
+ modifier_mask = ((GetKeyState(VK_SHIFT) < 0) ? Mod_Shift : 0 )
+ | ((GetKeyState(VK_CONTROL) < 0) ? Mod_Ctrl : 0)
+ | ((GetKeyState(VK_MENU) < 0) ? Mod_Alt : 0);
+ if (modifier_mask != last_modifier_mask) {
+ Wnd_exec_event ( lpgw, lParam, GE_modifier, modifier_mask);
+ last_modifier_mask = modifier_mask;
+ }
+ }
+ /* Ignore Key-Up events other than those of modifier keys */
+ break;
+ case WM_KEYDOWN:
+ {
+ /* First, look for a change in modifier status */
+ unsigned int modifier_mask = 0;
+ modifier_mask = ((GetKeyState(VK_SHIFT) < 0) ? Mod_Shift : 0 )
+ | ((GetKeyState(VK_CONTROL) < 0) ? Mod_Ctrl : 0)
+ | ((GetKeyState(VK_MENU) < 0) ? Mod_Alt : 0);
+ if (modifier_mask != last_modifier_mask) {
+ Wnd_exec_event ( lpgw, lParam, GE_modifier, modifier_mask);
+ last_modifier_mask = modifier_mask;
+ }
+ }
+ switch (wParam) {
+ case VK_BACK:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_BackSpace);
+ break;
+ case VK_TAB:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Tab);
+ break;
+ case VK_RETURN:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Return);
+ break;
+ case VK_PAUSE:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Pause);
+ break;
+ case VK_SCROLL:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Scroll_Lock);
+ break;
+#if 0 /* HOW_IS_THIS_FOR_WINDOWS */
+/* HBB 20010215: not at all, AFAICS... :-( */
+ case VK_SYSRQ:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Sys_Req);
+ break;
+#endif
+ case VK_ESCAPE:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Escape);
+ break;
+ case VK_DELETE:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Delete);
+ break;
+ case VK_INSERT:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_KP_Insert);
+ break;
+ case VK_HOME:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Home);
+ break;
+ case VK_LEFT:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Left);
+ break;
+ case VK_UP:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Up);
+ break;
+ case VK_RIGHT:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Right);
+ break;
+ case VK_DOWN:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Down);
+ break;
+ case VK_END:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_End);
+ break;
+ case VK_PRIOR:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_PageUp);
+ break;
+ case VK_NEXT:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_PageDown);
+ break;
+ case VK_F1:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F1);
+ break;
+ case VK_F2:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F2);
+ break;
+ case VK_F3:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F3);
+ break;
+ case VK_F4:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F4);
+ break;
+ case VK_F5:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F5);
+ break;
+ case VK_F6:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F6);
+ break;
+ case VK_F7:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F7);
+ break;
+ case VK_F8:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F8);
+ break;
+ case VK_F9:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F9);
+ break;
+ case VK_F10:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F10);
+ break;
+ case VK_F11:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F11);
+ break;
+ case VK_F12:
+ Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F12);
+ break;
+ } /* switch (wParam) */
+
+ return 0L;
+#if 0 /* DO WE NEED THIS ??? */
+ case WM_MOUSEMOVE:
+ /* set default pointer: */
+ SetCursor(hptrDefault);
+ return 0L;
+#endif
+#endif /* USE_MOUSE */
+ case WM_COMMAND:
+ switch(LOWORD(wParam))
+ {
+ case M_GRAPH_TO_TOP:
+ lpgw->graphtotop = !lpgw->graphtotop;
+ SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
+ return(0);
+ case M_COLOR:
+ lpgw->color = !lpgw->color;
+ SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
+ return(0);
+ case M_CHOOSE_FONT:
+ SelFont(lpgw);
+ return 0;
+ case M_COPY_CLIP:
+ CopyClip(lpgw);
+ return 0;
+ case M_LINESTYLE:
+ if (LineStyle(lpgw))
+ SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
+ return 0;
+ case M_BACKGROUND:
+ lpgw->background = GetColor(hwnd, lpgw->background);
+ SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
+ return 0;
+ case M_PRINT:
+ CopyPrint(lpgw);
+ return 0;
+ case M_WRITEINI:
+ WriteGraphIni(lpgw);
+ if (lpgw->lptw)
+ WriteTextIni(lpgw->lptw);
+ return 0;
+ case M_REBUILDTOOLS:
+ lpgw->resized = TRUE;
+ if (lpgw->color)
+ CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_CHECKED);
+ else
+ CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_UNCHECKED);
+ if (lpgw->graphtotop)
+ CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_CHECKED);
+ else
+ CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_UNCHECKED);
+ DestroyPens(lpgw);
+ DestroyFonts(lpgw);
+ hdc = GetDC(hwnd);
+ MakePens(lpgw, hdc);
+ GetClientRect(hwnd, &rect);
+ MakeFonts(lpgw, (LPRECT)&rect, hdc);
+ ReleaseDC(hwnd, hdc);
+ GetClientRect(hwnd, &rect);
+ InvalidateRect(hwnd, (LPRECT) &rect, 1);
+ UpdateWindow(hwnd);
+ return 0;
+ }
+ return 0;
+ case WM_RBUTTONDOWN:
+ /* HBB 20010218: note that this only works in mouse-off
+ * mode, now. You'll need to go via the System menu to
+ * access this popup, instead */
+ {
+ POINT pt;
+ pt.x = LOWORD(lParam);
+ pt.y = HIWORD(lParam);
+ ClientToScreen(hwnd,&pt);
+ TrackPopupMenu(lpgw->hPopMenu, TPM_LEFTALIGN,
+ pt.x, pt.y, 0, hwnd, NULL);
+ }
+ return(0);
+ case WM_CREATE:
+ lpgw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
+ SetWindowLong(hwnd, 0, (LONG)lpgw);
+ lpgw->hWndGraph = hwnd;
+ hdc = GetDC(hwnd);
+ MakePens(lpgw, hdc);
+#ifdef USE_MOUSE
+ LoadCursors(lpgw);
+#endif
+ GetClientRect(hwnd, &rect);
+ MakeFonts(lpgw, (LPRECT)&rect, hdc);
+ ReleaseDC(hwnd, hdc);
+#if WINVER >= 0x030a
+ {
+ WORD version = LOWORD(GetVersion());
+
+ if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
+ if ( lpgw->lptw && (lpgw->lptw->DragPre!=(LPSTR)NULL) && (lpgw->lptw->DragPost!=(LPSTR)NULL) )
+ DragAcceptFiles(hwnd, TRUE);
+ }
+#endif
+ return(0);
+ case WM_PAINT:
+ hdc = BeginPaint(hwnd, &ps);
+ SetMapMode(hdc, MM_TEXT);
+ SetBkMode(hdc,OPAQUE);
+ GetClientRect(hwnd, &rect);
+#ifdef WIN32
+ SetViewportExtEx(hdc, rect.right, rect.bottom, NULL);
+#else
+ SetViewportExt(hdc, rect.right, rect.bottom);
+#endif
+ drawgraph(lpgw, hdc, &rect);
+ EndPaint(hwnd, &ps);
+#ifdef USE_MOUSE
+ /* drawgraph() erases the plot window, so immediately after
+ * it has completed, all the 'real-time' stuff the gnuplot core
+ * doesn't know anything about has to be redrawn */
+ DrawRuler(lpgw);
+ DisplayStatusLine(lpgw);
+ DrawRulerLineTo(lpgw);
+ DrawZoomBox(lpgw);
+#endif
+ return 0;
+ case WM_SIZE:
+ /* update font sizes if graph resized */
+ if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) {
+ RECT rect;
+ SendMessage(hwnd,WM_SYSCOMMAND,M_REBUILDTOOLS,0L);
+ GetWindowRect(hwnd,&rect);
+ lpgw->Size.x = rect.right-rect.left;
+ lpgw->Size.y = rect.bottom-rect.top;
+ }
+ break;
+#if WINVER >= 0x030a
+ case WM_DROPFILES:
+ {
+ WORD version = LOWORD(GetVersion());
+ if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
+ if (lpgw->lptw)
+ DragFunc(lpgw->lptw, (HDROP)wParam);
+ }
+ break;
+#endif
+ case WM_DESTROY:
+ DestroyPens(lpgw);
+ DestroyFonts(lpgw);
+#ifdef USE_MOUSE
+ DestroyCursors(lpgw);
+#endif
+#if __TURBOC__ >= 0x410 /* Borland C++ 3.1 or later */
+ {
+ WORD version = LOWORD(GetVersion());
+ if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
+ DragAcceptFiles(hwnd, FALSE);
+ }
+#endif
+ if (lpgw->lptw && !IsWindowVisible(lpgw->lptw->hWndParent)) {
+ PostMessage (lpgw->lptw->hWndParent, WM_CLOSE, 0, 0);
+ }
+ return 0;
+ case WM_CLOSE:
+ GraphClose(lpgw);
+ return 0;
+ }
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+
+void WDPROC
+GraphChangeFont(LPGW lpgw, LPCSTR font, int fontsize, HDC hdc, RECT rect)
+{
+ int newfontsize;
+ bool remakefonts = FALSE;
+
+ newfontsize = (fontsize != 0) ? fontsize : lpgw->deffontsize;
+ if (font != NULL) {
+ remakefonts = (strcmp(lpgw->fontname, font) != 0) || (newfontsize != lpgw->fontsize);
+ } else {
+ remakefonts = (strcmp(lpgw->fontname, lpgw->deffontname) != 0) || (newfontsize != lpgw->fontsize);
+ }
+
+ if (remakefonts) {
+ lpgw->fontsize = newfontsize;
+ strcpy(lpgw->fontname, (font) ? font : lpgw->deffontname);
+
+ DestroyFonts(lpgw);
+ MakeFonts(lpgw, &rect, hdc);
+ }
+}
+
+
+#if 0
+int WDPROC
+GraphGetFontScaling(LPGW lpgw, LPCSTR font, int fontsize)
+{
+ HDC hdc;
+ RECT rect;
+ HGDIOBJ hprevfont;
+ OUTLINETEXTMETRIC otm;
+ int shift = 35;
+
+ hdc = GetDC(lpgw->hWndGraph);
+ GetClientRect(lpgw->hWndGraph, &rect);
+ GraphChangeFont(lpgw, font, fontsize, hdc, rect);
+ hprevfont = SelectObject(hdc, lpgw->hfonth);
+ if (GetOutlineTextMetrics(hdc, sizeof(otm), &otm) != 0) {
+ shift = otm.otmptSuperscriptOffset.y - otm.otmptSubscriptOffset.y;
+ shift = MulDiv(shift, GetDeviceCaps(hdc, LOGPIXELSY), 2 * 72);
+ printf( "shift: %i (%i %i)\n", shift*8, otm.otmptSuperscriptOffset.y, otm.otmptSubscriptOffset.y);
+ }
+ SelectObject(hdc, hprevfont);
+
+ return shift * 8;
+}
+#endif
+
+
+unsigned int WDPROC
+GraphGetTextLength(LPGW lpgw, LPCSTR text, LPCSTR fontname, int fontsize)
+{
+ HDC hdc;
+ RECT rect;
+ SIZE size;
+ HGDIOBJ hprevfont;
+
+ hdc = GetDC(lpgw->hWndGraph);
+ GetClientRect(lpgw->hWndGraph, &rect);
+
+ GraphChangeFont(lpgw, fontname, fontsize, hdc, rect);
+
+ hprevfont = SelectObject(hdc, lpgw->hfonth);
+ GetTextExtentPoint(hdc, text, strlen(text), &size);
+ SelectObject(hdc, hprevfont);
+
+ size.cx = MulDiv(size.cx + GetTextCharacterExtra(hdc), lpgw->xmax, rect.right-rect.left-1);
+ return size.cx;
+}
+
+
+#ifdef USE_MOUSE
+/* Implemented by Petr Mikulik, February 2001 --- the best Windows solutions
+ * come from OS/2 :-))
+ */
+
+/* ================================================================= */
+
+/* Firstly: terminal calls from win.trm */
+
+/* Note that these all take lpgw as their first argument. It's an OO-type
+ * 'this' pointer, sort of: it stores all the status information of the graph
+ * window that we need, in a single large structure. */
+
+void WDPROC
+Graph_set_cursor (LPGW lpgw, int c, int x, int y )
+{
+ switch (c) {
+ case -4: /* switch off line between ruler and mouse cursor */
+ DrawRulerLineTo(lpgw);
+ ruler_lineto.on = FALSE;
+ break;
+ case -3: /* switch on line between ruler and mouse cursor */
+ if (ruler.on && ruler_lineto.on)
+ break;
+ ruler_lineto.x = x;
+ ruler_lineto.y = y;
+ ruler_lineto.on = TRUE;
+ DrawRulerLineTo(lpgw);
+ break;
+ case -2:
+ { /* move mouse to the given point */
+ RECT rc;
+ POINT pt;
+
+ GetClientRect(lpgw->hWndGraph, &rc);
+ pt.x = MulDiv(x, rc.right - rc.left, lpgw->xmax);
+ pt.y = rc.bottom - MulDiv(y, rc.bottom - rc.top, lpgw->ymax);
+
+ MapWindowPoints(lpgw->hWndGraph, HWND_DESKTOP, &pt, 1);
+ SetCursorPos(pt.x, pt.y);
+ }
+ break;
+ case -1: /* start zooming; zooming cursor */
+ zoombox.on = TRUE;
+ zoombox.from.x = zoombox.to.x = x;
+ zoombox.from.y = zoombox.to.y = y;
+ break;
+ case 0: /* standard cross-hair cursor */
+ SetCursor( (hptrCurrent = mouse_setting.on ? hptrCrossHair : hptrDefault) );
+ break;
+ case 1: /* cursor during rotation */
+ SetCursor(hptrCurrent = hptrRotating);
+ break;
+ case 2: /* cursor during scaling */
+ SetCursor(hptrCurrent = hptrScaling);
+ break;
+ case 3: /* cursor during zooming */
+ SetCursor(hptrCurrent = hptrZooming);
+ break;
+ }
+ if (c>=0 && zoombox.on) { /* erase zoom box */
+ DrawZoomBox(lpgw);
+ zoombox.on = FALSE;
+ }
+ if (c>=0 && ruler_lineto.on) { /* erase ruler line */
+ DrawRulerLineTo(lpgw);
+ ruler_lineto.on = FALSE;
+ }
+}
+
+/* set_ruler(int x, int y) term API: x<0 switches ruler off. */
+void WDPROC
+Graph_set_ruler (LPGW lpgw, int x, int y )
+{
+ DrawRuler(lpgw); /* remove previous drawing, if any */
+ DrawRulerLineTo(lpgw);
+ if (x < 0) {
+ ruler.on = FALSE;
+ return;
+ }
+ ruler.on = TRUE;
+ ruler.x = x; ruler.y = y;
+ DrawRuler(lpgw); /* draw ruler at new positions */
+ DrawRulerLineTo(lpgw);
+}
+
+/* put_tmptext(int i, char c[]) term API
+ * i: 0..at statusline
+ * 1, 2: at corners of zoom box with \r separating text
+ */
+void WDPROC
+Graph_put_tmptext (LPGW lpgw, int where, LPCSTR text )
+{
+ /* Position of the annotation string (mouse movement) or zoom box
+ * text or whatever temporary text added...
+ */
+ switch (where) {
+ case 0:
+ UpdateStatusLine(lpgw, text);
+ break;
+ case 1:
+ DrawZoomBox(lpgw);
+ if (zoombox.text1) {
+ free((char*)zoombox.text1);
+ }
+ zoombox.text1 = strdup(text);
+ DrawZoomBox(lpgw);
+ break;
+ case 2:
+ DrawZoomBox(lpgw);
+ if (zoombox.text2) {
+ free((char*)zoombox.text2);
+ }
+ zoombox.text2 = strdup(text);
+ DrawZoomBox(lpgw);
+ break;
+ default:
+ ; /* should NEVER happen */
+ }
+}
+
+void WDPROC
+Graph_set_clipboard (LPGW lpgw, LPCSTR s)
+{
+ size_t length;
+ HGLOBAL memHandle;
+ LPSTR clipText;
+
+ /* check: no string --> nothing to do */
+ if (!s || !s[0])
+ return;
+
+ /* Transport the string into a system-global storage area. In case
+ * of (unlikely) allocation failures, fail silently */
+ length = strlen(s);
+ if ( (memHandle = GlobalAlloc(GHND, length + 1)) == NULL)
+ return;
+ if ( (clipText = GlobalLock(memHandle)) == NULL) {
+ GlobalFree(memHandle);
+ return;
+ }
+ strcpy(clipText, s);
+ GlobalUnlock(memHandle);
+
+ /* Now post that memory area to the Clipboard */
+ OpenClipboard(lpgw->hWndGraph);
+ EmptyClipboard();
+ SetClipboardData(CF_TEXT, memHandle);
+ CloseClipboard();
+}
+
+/* ================================================================= */
+
+/* Secondly, support routines that implement direct mouse reactions. */
+
+/* This routine gets the mouse/pointer position in the current window and
+ * recalculates it to the viewport coordinates. */
+static void
+GetMousePosViewport (LPGW lpgw, int *mx, int *my)
+{
+ POINT pt;
+ RECT rc;
+
+ GetClientRect(lpgw->hWndGraph,&rc);
+
+ /* HBB: has to be done this way. The simpler method by taking apart LPARM
+ * only works for mouse, but not for keypress events. */
+ GetCursorPos(&pt);
+ ScreenToClient(lpgw->hWndGraph,&pt);
+ *mx = pt.x;
+ *my = pt.y;
+
+ /* px=px(mx); mouse=>gnuplot driver coordinates */
+ /* FIXME: classically, this would use MulDiv() call, and no floating point */
+ *mx = (int)((*mx - rc.left) * lpgw->xmax / (rc.right - rc.left) + 0.5);
+ *my = (int)((rc.bottom - *my) * lpgw->ymax / (rc.bottom -rc.top) + 0.5);
+}
+
+/* HBB 20010218: Newly separated function: Draw text string in XOR mode.
+ * That is surprisingly difficult using the Windows API: have to draw text
+ * into a background bitmap, first, and then blit that onto the screen.
+ *
+ * x and y give the bottom-left corner of the bounding box into which the
+ * text will be drawn */
+static void
+Draw_XOR_Text(LPGW lpgw, const char *text, size_t length, int x, int y)
+{
+ HDC hdc, tempDC;
+ HBITMAP bitmap;
+ int cx, cy;
+
+ if (!text || !text[0])
+ return; /* no text to be displayed */
+
+ hdc = GetDC(lpgw->hWndGraph);
+
+ /* Prepare background image buffer of the necessary size */
+ Wnd_GetTextSize(hdc, text, length, &cx, &cy);
+ bitmap = CreateCompatibleBitmap(hdc, cx, cy);
+ /* ... and a DeviceContext to access it by */
+ tempDC = CreateCompatibleDC(hdc);
+ DeleteObject(SelectObject(tempDC, bitmap));
+
+ /* Print inverted text, so the second inversion done by SRCINVERT ends
+ * up printing the right way round... */
+ /* FIXME HBB 20010218: find out the real ROP3 code for operation
+ * "target = target XOR (NOT source)" and use that, instead. It's the
+ * one with MSByte = 0x99, but without VC++ or MSDN, I can't seem to
+ * find out what the full code is. */
+ SetTextColor(tempDC, GetBkColor(hdc));
+ SetBkColor(tempDC, GetTextColor(hdc));
+ TextOut(tempDC, 0, 0, text, length);
+
+ /* Copy printed string to the screen window by XORing, so the
+ * repetition of this same operation will delete it again */
+ BitBlt(hdc, x, y - cy, cx, cy, tempDC, 0, 0, SRCINVERT);
+
+ /* Clean up behind ourselves */
+ DeleteDC(tempDC);
+ DeleteObject(bitmap);
+ ReleaseDC(lpgw->hWndGraph, hdc);
+}
+
+
+/* ================================== */
+
+/* Status line routines. */
+
+/* Saved text currently contained in status line */
+static char *sl_curr_text = NULL;
+
+/* Display the status line by the text (and remove it again by calling this
+ * same routine a second time --- thanks to XOR mode) */
+static void
+DisplayStatusLine (LPGW lpgw)
+{
+ RECT rc;
+
+ if (!sl_curr_text || !sl_curr_text[0])
+ return; /* no text to be displayed */
+
+ GetClientRect(lpgw->hWndGraph, &rc);
+ Draw_XOR_Text(lpgw, sl_curr_text, strlen(sl_curr_text), 0, rc.bottom);
+}
+
+
+/*
+ * Update the status line by the text; firstly erase the previous text
+ */
+static void
+UpdateStatusLine (LPGW lpgw, const char text[] )
+{
+ DisplayStatusLine(lpgw); /* erase previous text */
+ free(sl_curr_text);
+ if (!text || !*text) {
+ sl_curr_text = 0;
+ } else { /* display new text */
+ sl_curr_text = strdup(text);
+ DisplayStatusLine(lpgw);
+ }
+}
+
+/* Draw the ruler.
+ */
+static void
+DrawRuler (LPGW lpgw)
+{
+ HDC hdc;
+ int iOldRop;
+ RECT rc;
+ long rx, ry;
+
+ if (!ruler.on || ruler.x < 0)
+ return;
+
+ hdc = GetDC(lpgw->hWndGraph);
+ GetClientRect(lpgw->hWndGraph, &rc);
+
+ rx = MulDiv(ruler.x, rc.right - rc.left, lpgw->xmax);
+ ry = rc.bottom - MulDiv(ruler.y, rc.bottom - rc.top, lpgw->ymax);
+
+ iOldRop = SetROP2(hdc, R2_NOT);
+ MoveTo(hdc, rc.left, ry);
+ LineTo(hdc, rc.right, ry);
+ MoveTo(hdc, rx, rc.top);
+ LineTo(hdc, rx, rc.bottom);
+ SetROP2(hdc, iOldRop);
+ ReleaseDC(lpgw->hWndGraph, hdc);
+}
+
+/* Draw the ruler line to cursor position.
+ */
+static void
+DrawRulerLineTo (LPGW lpgw)
+{
+ HDC hdc;
+ int iOldRop;
+ RECT rc;
+ long rx, ry, rlx, rly;
+
+ if (!ruler.on || !ruler_lineto.on || ruler.x < 0 || ruler_lineto.x < 0)
+ return;
+
+ hdc = GetDC(lpgw->hWndGraph);
+ GetClientRect(lpgw->hWndGraph, &rc);
+
+ rx = MulDiv(ruler.x, rc.right - rc.left, lpgw->xmax);
+ ry = rc.bottom - MulDiv(ruler.y, rc.bottom - rc.top, lpgw->ymax);
+ rlx = MulDiv(ruler_lineto.x, rc.right - rc.left, lpgw->xmax);
+ rly = rc.bottom - MulDiv(ruler_lineto.y, rc.bottom - rc.top, lpgw->ymax);
+
+ iOldRop = SetROP2(hdc, R2_NOT);
+ MoveTo(hdc, rx, ry);
+ LineTo(hdc, rlx, rly);
+ SetROP2(hdc, iOldRop);
+ ReleaseDC(lpgw->hWndGraph, hdc);
+}
+
+/* Draw the zoom box.
+ */
+static void
+DrawZoomBox (LPGW lpgw)
+{
+ HDC hdc;
+ long fx, fy, tx, ty, text_y;
+ int OldROP2;
+ RECT rc;
+ HPEN OldPen;
+
+ if (!zoombox.on)
+ return;
+
+ hdc = GetDC(lpgw->hWndGraph);
+ GetClientRect(lpgw->hWndGraph, &rc);
+
+ fx = MulDiv(zoombox.from.x, rc.right - rc.left, lpgw->xmax);
+ fy = rc.bottom - MulDiv(zoombox.from.y, rc.bottom - rc.top, lpgw->ymax);
+ tx = MulDiv(zoombox.to.x, rc.right - rc.left, lpgw->xmax);
+ ty = rc.bottom - MulDiv(zoombox.to.y, rc.bottom - rc.top, lpgw->ymax);
+ text_y = MulDiv(lpgw->vchar, rc.bottom - rc.top, lpgw->ymax);
+
+ OldROP2 = SetROP2(hdc, R2_NOTXORPEN);
+ OldPen = SelectObject(hdc, CreatePenIndirect(
+ (lpgw->color ? lpgw->colorpen : lpgw->monopen) + 1));
+ Rectangle(hdc, fx, fy, tx, ty);
+ DeleteObject(SelectObject(hdc, OldPen));
+ SetROP2(hdc, OldROP2);
+
+ ReleaseDC(lpgw->hWndGraph, hdc);
+
+ if (zoombox.text1) {
+ char *separator = strchr(zoombox.text1, '\r');
+
+ if (separator) {
+ Draw_XOR_Text(lpgw, zoombox.text1, separator - zoombox.text1, fx, fy);
+ Draw_XOR_Text(lpgw, separator + 1, strlen(separator + 1), fx, fy + text_y);
+ } else {
+ Draw_XOR_Text(lpgw, zoombox.text1, strlen(zoombox.text1), fx, fy + lpgw->vchar / 2);
+ }
+ }
+ if (zoombox.text2) {
+ char *separator = strchr(zoombox.text2, '\r');
+
+ if (separator) {
+ Draw_XOR_Text(lpgw, zoombox.text2, separator - zoombox.text2, tx, ty);
+ Draw_XOR_Text(lpgw, separator + 1, strlen(separator + 1), tx, ty + text_y);
+ } else {
+ Draw_XOR_Text(lpgw, zoombox.text2, strlen(zoombox.text2), tx, ty + lpgw->vchar / 2);
+ }
+ }
+}
+
+#endif /* USE_MOUSE */
+
+/* eof wgraph.c */
+