2 static char *RCSid() { return RCSid("$Id: wgraph.c,v 1.52.2.7 2009/03/23 23:03:25 sfeam Exp $"); }
5 /* GNUPLOT - win/wgraph.c */
7 * Copyright 1992, 1993, 1998, 2004 Maurice Castro, Russell Lang
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.
15 * Permission to modify the software is granted, but not the right to
16 * distribute the complete modified source code. Modifications are to
17 * be distributed as patches to the released version. Permission to
18 * distribute binaries produced by compiling modified sources is granted,
20 * 1. distribute the corresponding source modifications from the
21 * released version in the form of a patch file along with the binaries,
22 * 2. add special version identification to distinguish your version
23 * in addition to the base release version number,
24 * 3. provide your name and address as the primary contact for the
25 * support of your modified version, and
26 * 4. retain our contact information in regard to use of the base
28 * Permission to distribute the released version of the source code along
29 * with corresponding source modifications in the form of a patch file is
30 * granted with same provisions 2 through 4 for binary distributions.
32 * This software is provided "as is" without express or implied warranty
33 * to the extent permitted by applicable law.
57 #include "term_api.h" /* for enum JUSTIFY */
59 # include "gpexecute.h"
63 # include "getcolor.h"
66 /* Petr Mikulik, February 2001
67 * Declarations similar to src/os2/gclient.c -- see section
68 * "PM: Now variables for mouse" there in.
71 /* If wgnuplot crashes during redrawing and mouse on, then this could help: */
72 /* static char lock_mouse = 1; */
74 /* Status of the ruler */
76 TBOOLEAN on; /* ruler active ? */
77 int x, y; /* ruler position */
78 } ruler = {FALSE,0,0,};
80 /* Status of the line from ruler to cursor */
81 static struct RulerLineTo {
82 TBOOLEAN on; /* ruler line active ? */
83 int x, y; /* ruler line end position (previous cursor position) */
84 } ruler_lineto = {FALSE,0,0,};
86 /* Status of zoom box */
87 static struct Zoombox {
88 TBOOLEAN on; /* set to TRUE during zooming */
89 POINT from, to; /* corners of the zoom box */
90 LPCSTR text1, text2; /* texts in the corners (i.e. positions) */
91 } zoombox = { FALSE, {0,0}, {0,0}, NULL, NULL };
93 /* Pointer definitions */
94 HCURSOR hptrDefault, hptrCrossHair, hptrScaling, hptrRotating, hptrZooming, hptrCurrent;
96 /* Mouse support routines */
97 static void Wnd_exec_event(LPGW lpgw, LPARAM lparam, char type, int par1);
98 static void Wnd_refresh_zoombox(LPGW lpgw, LPARAM lParam);
99 static void Wnd_refresh_ruler_lineto(LPGW lpgw, LPARAM lParam);
100 static void GetMousePosViewport(LPGW lpgw, int *mx, int *my);
101 static void Draw_XOR_Text(LPGW lpgw, const char *text, size_t length, int x, int y);
102 static void DisplayStatusLine(LPGW lpgw);
103 static void UpdateStatusLine(LPGW lpgw, const char text[]);
104 static void DrawRuler(LPGW lpgw);
105 static void DrawRulerLineTo(LPGW lpgw);
106 static void DrawZoomBox(LPGW lpgw);
107 static void LoadCursors(LPGW lpgw);
108 static void DestroyCursors(LPGW lpgw);
109 #endif /* USE_MOUSE */
111 /* ================================== */
115 #define WGDEFCOLOR 15
116 COLORREF wginitcolor[WGDEFCOLOR] = {
117 RGB(255,0,0), /* red */
118 RGB(0,255,0), /* green */
119 RGB(0,0,255), /* blue */
120 RGB(255,0,255), /* magenta */
121 RGB(0,0,128), /* dark blue */
122 RGB(128,0,0), /* dark red */
123 RGB(0,128,128), /* dark cyan */
124 RGB(0,0,0), /* black */
125 RGB(128,128,128), /* grey */
126 RGB(0,128,64), /* very dark cyan */
127 RGB(128,128,0), /* dark yellow */
128 RGB(128,0,128), /* dark magenta */
129 RGB(192,192,192), /* light grey */
130 RGB(0,255,255), /* cyan */
131 RGB(255,255,0), /* yellow */
134 int wginitstyle[WGDEFSTYLE] = {PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT};
136 /* Maximum number of GWOPBLK arrays to be remembered. */
137 /* HBB 20010218: moved here from wgnuplib.h: other parts of the program don't
138 * need to know about it */
142 /* bitmaps for filled boxes (ULIG) */
143 /* zeros represent the foreground color and ones represent the background color */
144 /* FIXME HBB 20010916: *never* extern in a C source! */
145 /* extern int filldensity; */
146 /* extern int fillpattern; */
148 static unsigned char halftone_bitmaps[][16] ={
149 { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
150 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }, /* no fill */
151 { 0xEE, 0xEE, 0xBB, 0xBB, 0xEE, 0xEE, 0xBB, 0xBB,
152 0xEE, 0xEE, 0xBB, 0xBB, 0xEE, 0xEE, 0xBB, 0xBB }, /* 25% pattern */
153 { 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55,
154 0xAA, 0xAA, 0x55, 0x55, 0xAA, 0xAA, 0x55, 0x55 }, /* 50% pattern */
155 { 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22,
156 0x88, 0x88, 0x22, 0x22, 0x88, 0x88, 0x22, 0x22 }, /* 75% pattern */
157 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* solid pattern */
160 #define halftone_num (sizeof(halftone_bitmaps) / sizeof (*halftone_bitmaps))
161 static HBRUSH halftone_brush[halftone_num];
162 static BITMAP halftone_bitdata[halftone_num];
163 static HBITMAP halftone_bitmap[halftone_num];
165 static unsigned char pattern_bitmaps[][16] = {
166 {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
167 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, /* no fill */
168 {0xFE, 0xFE, 0x7D, 0x7D, 0xBB, 0xBB, 0xD7, 0xD7,
169 0xEF, 0xEF, 0xD7, 0xD7, 0xBB, 0xBB, 0x7D, 0x7D}, /* cross-hatch (1) */
170 {0x77, 0x77, 0xBB, 0xBB, 0xDD, 0xDD, 0xBB, 0xBB,
171 0x77, 0x77, 0xBB, 0xBB, 0xDD, 0xDD, 0xBB, 0xBB}, /* double cross-hatch (2) */
172 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
173 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* solid fill (3) */
174 {0xFE, 0xFE, 0xFD, 0xFD, 0xFB, 0xFB, 0xF7, 0xF7,
175 0xEF, 0xEF, 0xDF, 0xDF, 0xBF, 0xBF, 0x7F, 0x7F}, /* diagonals (4) */
176 {0x7F, 0x7F, 0xBF, 0xBF, 0xDF, 0xDF, 0xEF, 0xEF,
177 0xF7, 0xF7, 0xFB, 0xFB, 0xFD, 0xFD, 0xFE, 0xFE}, /* diagonals (5) */
178 {0xEE, 0xEE, 0xEE, 0xEE, 0xDD, 0xDD, 0xDD, 0xDD,
179 0xBB, 0xBB, 0xBB, 0xBB, 0x77, 0x77, 0x77, 0x77}, /* steep diagonals (6) */
180 {0x77, 0x77, 0x77, 0x77, 0xBB, 0xBB, 0xBB, 0xBB,
181 0xDD, 0xDD, 0xDD, 0xDD, 0xEE, 0xEE, 0xEE, 0xEE} /* steep diagonals (7) */
183 ,{0xFC, 0xFC, 0xF3, 0xF3, 0xCF, 0xCF, 0x3F, 0x3F,
184 0xFC, 0xFC, 0xF3, 0xF3, 0xCF, 0xCF, 0x3F, 0x3F}, /* shallow diagonals (old 5) */
185 {0x3F, 0x3F, 0xCF, 0xCF, 0xF3, 0xF3, 0xFC, 0xFC,
186 0x3F, 0x3F, 0xCF, 0xCF, 0xF3, 0xF3, 0xFC, 0xFC} /* shallow diagonals (old 6) */
189 #define pattern_num (sizeof(pattern_bitmaps)/(sizeof(*pattern_bitmaps)))
190 static HBRUSH pattern_brush[pattern_num];
191 static BITMAP pattern_bitdata[pattern_num];
192 static HBITMAP pattern_bitmap[pattern_num];
194 static TBOOLEAN brushes_initialized = FALSE;
197 /* ================================== */
199 /* prototypes for module-local functions */
201 LRESULT CALLBACK WINEXPORT WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
202 BOOL CALLBACK WINEXPORT LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam);
204 static void DestroyBlocks(LPGW lpgw);
205 static BOOL AddBlock(LPGW lpgw);
206 static void StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle);
207 static void MakePens(LPGW lpgw, HDC hdc);
208 static void DestroyPens(LPGW lpgw);
209 static void Wnd_GetTextSize(HDC hdc, LPCSTR str, size_t len, int *cx, int *cy);
210 static void MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc);
211 static void DestroyFonts(LPGW lpgw);
212 static void SetFont(LPGW lpgw, HDC hdc);
213 static void SelFont(LPGW lpgw);
214 static void dot(HDC hdc, int xdash, int ydash);
215 static void drawgraph(LPGW lpgw, HDC hdc, LPRECT rect);
216 static void CopyClip(LPGW lpgw);
217 static void CopyPrint(LPGW lpgw);
218 static void WriteGraphIni(LPGW lpgw);
219 static void ReadGraphIni(LPGW lpgw);
220 static COLORREF GetColor(HWND hwnd, COLORREF ref);
221 static void UpdateColorSample(HWND hdlg);
222 static BOOL LineStyle(LPGW lpgw);
224 /* ================================== */
226 /* Helper functions for GraphOp(): */
228 /* destroy memory blocks holding graph operations */
230 DestroyBlocks(LPGW lpgw)
232 struct GWOPBLK *this, *next;
233 struct GWOP FAR *gwop;
236 this = lpgw->gwopblk_head;
237 while (this != NULL) {
240 this->gwop = (struct GWOP FAR *)GlobalLock(this->hblk);
243 /* free all text strings within this block */
245 for (i=0; i<GWOPMAX; i++) {
247 LocalFree(gwop->htext);
251 GlobalUnlock(this->hblk);
252 GlobalFree(this->hblk);
256 lpgw->gwopblk_head = NULL;
257 lpgw->gwopblk_tail = NULL;
262 /* add a new memory block for graph operations */
263 /* returns TRUE if block allocated */
268 struct GWOPBLK *next, *this;
270 /* create new block */
271 next = (struct GWOPBLK *)LocalAllocPtr(LHND, sizeof(struct GWOPBLK) );
274 hblk = GlobalAlloc(GHND, GWOPMAX*sizeof(struct GWOP));
278 next->gwop = (struct GWOP FAR *)NULL;
279 next->next = (struct GWOPBLK *)NULL;
282 /* attach it to list */
283 this = lpgw->gwopblk_tail;
285 lpgw->gwopblk_head = next;
288 this->gwop = (struct GWOP FAR *)NULL;
289 GlobalUnlock(this->hblk);
291 lpgw->gwopblk_tail = next;
292 next->gwop = (struct GWOP FAR *)GlobalLock(next->hblk);
293 if (next->gwop == (struct GWOP FAR *)NULL)
301 GraphOp(LPGW lpgw, WORD op, WORD x, WORD y, LPCSTR str)
304 GraphOpSize(lpgw, op, x, y, str, _fstrlen(str)+1);
306 GraphOpSize(lpgw, op, x, y, NULL, 0);
311 GraphOpSize(LPGW lpgw, WORD op, WORD x, WORD y, LPCSTR str, DWORD size)
313 struct GWOPBLK *this;
314 struct GWOP FAR *gwop;
317 this = lpgw->gwopblk_tail;
318 if ( (this==NULL) || (this->used >= GWOPMAX) ) {
319 /* not enough space so get new block */
322 this = lpgw->gwopblk_tail;
324 gwop = &this->gwop[this->used];
330 gwop->htext = LocalAlloc(LHND, size);
331 npstr = LocalLock(gwop->htext);
332 if (gwop->htext && (npstr != (char *)NULL))
333 memcpy(npstr, str, size);
334 LocalUnlock(gwop->htext);
341 /* ================================== */
343 /* Prepare Graph window for being displayed by windows, read wgnuplot.ini, update
344 * the window's menus and show it */
352 if (!lpgw->hPrevInstance) {
353 wndclass.style = CS_HREDRAW | CS_VREDRAW;
354 wndclass.lpfnWndProc = WndGraphProc;
355 wndclass.cbClsExtra = 0;
356 wndclass.cbWndExtra = 2 * sizeof(void FAR *);
357 wndclass.hInstance = lpgw->hInstance;
358 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
359 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
360 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
361 wndclass.lpszMenuName = NULL;
362 wndclass.lpszClassName = szGraphClass;
363 RegisterClass(&wndclass);
368 lpgw->hWndGraph = CreateWindow(szGraphClass, lpgw->Title,
370 lpgw->Origin.x, lpgw->Origin.y,
371 lpgw->Size.x, lpgw->Size.y,
372 NULL, NULL, lpgw->hInstance, lpgw);
374 lpgw->hPopMenu = CreatePopupMenu();
375 AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->graphtotop ? MF_CHECKED : MF_UNCHECKED),
376 M_GRAPH_TO_TOP, "Bring to &Top");
377 AppendMenu(lpgw->hPopMenu, MF_STRING | (lpgw->color ? MF_CHECKED : MF_UNCHECKED),
379 AppendMenu(lpgw->hPopMenu, MF_STRING, M_COPY_CLIP, "&Copy to Clipboard");
381 AppendMenu(lpgw->hPopMenu, MF_STRING, M_BACKGROUND, "&Background...");
382 AppendMenu(lpgw->hPopMenu, MF_STRING, M_CHOOSE_FONT, "Choose &Font...");
383 AppendMenu(lpgw->hPopMenu, MF_STRING, M_LINESTYLE, "&Line Styles...");
385 AppendMenu(lpgw->hPopMenu, MF_STRING, M_PRINT, "&Print...");
386 if (lpgw->IniFile != (LPSTR)NULL) {
387 wsprintf(buf,"&Update %s",lpgw->IniFile);
388 AppendMenu(lpgw->hPopMenu, MF_STRING, M_WRITEINI, (LPSTR)buf);
391 /* modify the system menu to have the new items we want */
392 sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
393 AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
394 AppendMenu(sysmenu, MF_POPUP, (UINT)lpgw->hPopMenu, "&Options");
395 AppendMenu(sysmenu, MF_STRING, M_ABOUT, "&About");
397 if (!IsWindowVisible(lpgw->lptw->hWndParent)) {
398 AppendMenu(sysmenu, MF_SEPARATOR, 0, NULL);
399 AppendMenu(sysmenu, MF_STRING, M_COMMANDLINE, "C&ommand Line");
402 ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
405 /* close a graph window */
407 GraphClose(LPGW lpgw)
411 DestroyWindow(lpgw->hWndGraph);
413 lpgw->hWndGraph = NULL;
417 lpgw->locked = FALSE;
422 GraphStart(LPGW lpgw, double pointsize)
426 lpgw->org_pointsize = pointsize;
427 if ( !lpgw->hWndGraph || !IsWindow(lpgw->hWndGraph) )
429 if (IsIconic(lpgw->hWndGraph))
430 ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
431 if (lpgw->graphtotop) {
432 /* HBB NEW 20040221: avoid grabbing the keyboard focus
433 * unless mouse mode is on */
435 if (mouse_setting.on) {
436 BringWindowToTop(lpgw->hWndGraph);
439 #endif /* USE_MOUSE */
440 SetWindowPos(lpgw->hWndGraph,
442 SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE);
451 GetClientRect(lpgw->hWndGraph, &rect);
452 InvalidateRect(lpgw->hWndGraph, (LPRECT) &rect, 1);
453 lpgw->locked = FALSE;
454 UpdateWindow(lpgw->hWndGraph);
456 gp_exec_event(GE_plotdone, 0, 0, 0, 0, 0); /* notify main program */
461 GraphResume(LPGW lpgw)
467 GraphPrint(LPGW lpgw)
469 if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
470 SendMessage(lpgw->hWndGraph,WM_COMMAND,M_PRINT,0L);
474 GraphRedraw(LPGW lpgw)
476 if (lpgw->hWndGraph && IsWindow(lpgw->hWndGraph))
477 SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
479 /* ================================== */
481 /* Helper functions for bookkeeping of pens, brushes and fonts */
483 /* Set up LOGPEN structures based on information coming from wgnuplot.ini, via
486 StorePen(LPGW lpgw, int i, COLORREF ref, int colorstyle, int monostyle)
490 plp = &lpgw->colorpen[i];
491 plp->lopnColor = ref;
492 if (colorstyle < 0) {
493 plp->lopnWidth.x = -colorstyle;
496 plp->lopnWidth.x = 1;
497 plp->lopnStyle = colorstyle % 5;
499 plp->lopnWidth.y = 0;
501 plp = &lpgw->monopen[i];
502 plp->lopnColor = RGB(0,0,0);
504 plp->lopnWidth.x = -monostyle;
507 plp->lopnWidth.x = 1;
508 plp->lopnStyle = monostyle % 5;
510 plp->lopnWidth.y = 0;
513 /* Prepare pens and brushes (--> colors) for use by the driver. Pens are (now) created
514 * on-the-fly (--> DeleteObject(SelectObject(...)) idiom), but the brushes are still
515 * all created statically, and kept until the window is closed */
517 MakePens(LPGW lpgw, HDC hdc)
521 if ((GetDeviceCaps(hdc,NUMCOLORS) == 2) || !lpgw->color) {
522 lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->monopen[1]); /* axis */
523 lpgw->hbrush = CreateSolidBrush(RGB(255,255,255));
524 for (i=0; i<WGNUMPENS+2; i++)
525 lpgw->colorbrush[i] = CreateSolidBrush(RGB(0,0,0));
527 lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[1]); /* axis */
528 lpgw->hbrush = CreateSolidBrush(lpgw->background);
529 for (i=0; i<WGNUMPENS+2; i++)
530 lpgw->colorbrush[i] = CreateSolidBrush(lpgw->colorpen[i].lopnColor);
533 /* build pattern brushes for filled boxes (ULIG) */
534 if( ! brushes_initialized ) {
537 for(i=0; i < halftone_num; i++) {
538 halftone_bitdata[i].bmType = 0;
539 halftone_bitdata[i].bmWidth = 16;
540 halftone_bitdata[i].bmHeight = 8;
541 halftone_bitdata[i].bmWidthBytes = 2;
542 halftone_bitdata[i].bmPlanes = 1;
543 halftone_bitdata[i].bmBitsPixel = 1;
544 halftone_bitdata[i].bmBits = halftone_bitmaps[i];
545 halftone_bitmap[i] = CreateBitmapIndirect(&halftone_bitdata[i]);
546 halftone_brush[i] = CreatePatternBrush(halftone_bitmap[i]);
549 for(i=0; i < pattern_num; i++) {
550 pattern_bitdata[i].bmType = 0;
551 pattern_bitdata[i].bmWidth = 16;
552 pattern_bitdata[i].bmHeight = 8;
553 pattern_bitdata[i].bmWidthBytes = 2;
554 pattern_bitdata[i].bmPlanes = 1;
555 pattern_bitdata[i].bmBitsPixel = 1;
556 pattern_bitdata[i].bmBits = pattern_bitmaps[i];
557 pattern_bitmap[i] = CreateBitmapIndirect(&pattern_bitdata[i]);
558 pattern_brush[i] = CreatePatternBrush(pattern_bitmap[i]);
561 brushes_initialized = TRUE;
565 /* Undo effect of MakePens(). To be called just before the window is closed. */
567 DestroyPens(LPGW lpgw)
571 DeleteObject(lpgw->hbrush);
572 DeleteObject(lpgw->hapen);
573 for (i=0; i<WGNUMPENS+2; i++)
574 DeleteObject(lpgw->colorbrush[i]);
576 /* delete brushes used for boxfilling (ULIG) */
577 if( brushes_initialized ) {
580 for( i=0; i<halftone_num; i++ ) {
581 DeleteObject(halftone_bitmap[i]);
582 DeleteObject(halftone_brush[i]);
584 for( i=0; i<pattern_num; i++ ) {
585 DeleteObject(pattern_bitmap[i]);
586 DeleteObject(pattern_brush[i]);
588 brushes_initialized = FALSE;
592 /* ================================== */
594 /* HBB 20010218: new function. An isolated snippet from MakeFont(), now also
595 * used in Wnd_put_tmptext() to size the temporary bitmap. */
597 Wnd_GetTextSize(HDC hdc, LPCSTR str, size_t len, int *cx, int *cy)
602 GetTextExtentPoint(hdc, str, len, &size);
606 /* Hmm... if not for compatibility to Win 3.0 and earlier, we could
607 * use GetTextExtentPoint on Win16, too :-( */
610 extent = GetTextExtent(hdc, str, len);
611 *cx = LOWORD(extent);
612 *cy = HIWORD(extent);
617 MakeFonts(LPGW lpgw, LPRECT lprect, HDC hdc)
625 lpgw->rotate = FALSE;
626 _fmemset(&(lpgw->lf), 0, sizeof(LOGFONT));
627 _fstrncpy(lpgw->lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
628 lpgw->lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
629 lpgw->lf.lfCharSet = DEFAULT_CHARSET;
630 if ( (p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL ) {
631 lpgw->lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
632 lpgw->lf.lfItalic = TRUE;
634 if ( (p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL ) {
635 lpgw->lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
636 lpgw->lf.lfWeight = FW_BOLD;
639 if (lpgw->hfonth == 0) {
640 lpgw->hfonth = CreateFontIndirect((LOGFONT FAR *)&(lpgw->lf));
643 /* we do need a 90 degree font */
645 DeleteObject(lpgw->hfontv);
646 lpgw->lf.lfEscapement = 900;
647 lpgw->lf.lfOrientation = 900;
648 lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&(lpgw->lf));
651 hfontold = SelectObject(hdc, lpgw->hfonth);
652 Wnd_GetTextSize(hdc, "0123456789", 10, &cx, &cy);
653 lpgw->vchar = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
654 lpgw->hchar = MulDiv(cx/10,lpgw->xmax,lprect->right - lprect->left);
656 /* CMW: Base tick size on character size */
657 lpgw->htic = lpgw->hchar / 2;
658 cy = MulDiv(cx/20, GetDeviceCaps(hdc, LOGPIXELSY), GetDeviceCaps(hdc, LOGPIXELSX));
659 lpgw->vtic = MulDiv(cy,lpgw->ymax,lprect->bottom - lprect->top);
660 /* find out if we can rotate text 90deg */
661 SelectObject(hdc, lpgw->hfontv);
662 result = GetDeviceCaps(hdc, TEXTCAPS);
663 if ((result & TC_CR_90) || (result & TC_CR_ANY))
665 GetTextMetrics(hdc,(TEXTMETRIC FAR *)&tm);
666 if (tm.tmPitchAndFamily & TMPF_VECTOR)
667 lpgw->rotate = TRUE; /* vector fonts can all be rotated */
669 if (tm.tmPitchAndFamily & TMPF_TRUETYPE)
670 lpgw->rotate = TRUE; /* truetype fonts can all be rotated */
672 SelectObject(hdc, hfontold);
677 DestroyFonts(LPGW lpgw)
680 DeleteObject(lpgw->hfonth);
684 DeleteObject(lpgw->hfontv);
691 SetFont(LPGW lpgw, HDC hdc)
693 if (lpgw->rotate && lpgw->angle) {
695 DeleteObject(lpgw->hfontv);
696 lpgw->lf.lfEscapement = lpgw->lf.lfOrientation = lpgw->angle * 10;
697 lpgw->hfontv = CreateFontIndirect((LOGFONT FAR *)&(lpgw->lf));
699 SelectObject(hdc, lpgw->hfontv);
702 SelectObject(hdc, lpgw->hfonth);
714 char lpszStyle[LF_FACESIZE];
717 /* Set all structure fields to zero. */
718 _fmemset(&cf, 0, sizeof(CHOOSEFONT));
719 _fmemset(&lf, 0, sizeof(LOGFONT));
720 cf.lStructSize = sizeof(CHOOSEFONT);
721 cf.hwndOwner = lpgw->hWndGraph;
722 _fstrncpy(lf.lfFaceName,lpgw->fontname,LF_FACESIZE);
723 if ((p = _fstrstr(lpgw->fontname," Bold")) != (LPSTR)NULL) {
724 _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
725 lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
726 } else if ((p = _fstrstr(lpgw->fontname," Italic")) != (LPSTR)NULL) {
727 _fstrncpy(lpszStyle,p+1,LF_FACESIZE);
728 lf.lfFaceName[ (unsigned int)(p-lpgw->fontname) ] = '\0';
730 _fstrcpy(lpszStyle,"Regular");
732 cf.lpszStyle = lpszStyle;
733 hdc = GetDC(lpgw->hWndGraph);
734 lf.lfHeight = -MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
735 ReleaseDC(lpgw->hWndGraph, hdc);
737 cf.nFontType = SCREEN_FONTTYPE;
738 cf.Flags = CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT | CF_USESTYLE;
739 if (ChooseFont(&cf)) {
740 _fstrcpy(lpgw->fontname,lf.lfFaceName);
741 lpgw->fontsize = cf.iPointSize / 10;
742 if (cf.nFontType & BOLD_FONTTYPE)
743 lstrcat(lpgw->fontname," Bold");
744 if (cf.nFontType & ITALIC_FONTTYPE)
745 lstrcat(lpgw->fontname," Italic");
746 /* set current font as default font */
747 strcpy(lpgw->deffontname,lpgw->fontname);
748 lpgw->deffontsize = lpgw->fontsize;
749 SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
755 /* ================================== */
758 LoadCursors(LPGW lpgw)
760 /* 3 of them are standard cursor shapes: */
761 hptrDefault = LoadCursor(NULL, IDC_ARROW);
762 hptrZooming = LoadCursor(NULL, IDC_SIZEALL);
763 hptrCrossHair = LoadCursor( NULL, IDC_CROSS);
764 /* the other 2 are kept in the resource file: */
765 hptrScaling = LoadCursor( lpgw->hInstance, MAKEINTRESOURCE(IDC_SCALING));
766 hptrRotating = LoadCursor( lpgw->hInstance, MAKEINTRESOURCE(IDC_ROTATING));
768 hptrCurrent = hptrCrossHair;
772 DestroyCursors(LPGW lpgw)
774 /* No-op. Cursors from LoadCursor() don't need destroying */
778 #endif /* USE_MOUSE */
780 /* ================================== */
784 dot(HDC hdc, int xdash, int ydash)
786 MoveTo(hdc, xdash, ydash);
787 LineTo(hdc, xdash, ydash+1);
791 /* This one is really the heart of this module: it executes the stored set of
792 * commands, whenever it changed or a redraw is necessary */
794 drawgraph(LPGW lpgw, HDC hdc, LPRECT rect)
796 int xdash, ydash; /* the transformed coordinates */
798 struct GWOP FAR *curptr;
799 struct GWOPBLK *blkptr;
802 unsigned int lastop=-1; /* used for plotting last point on a line */
807 unsigned int ngwop=0;
809 double line_width = 1.0;
810 unsigned int fillstyle = 0.0;
816 /* HBB 20010218: the GDI status query functions don't work on Metafile
817 * handles, so can't know whether the screen is actually showing
818 * color or not, if drawgraph() is being called from CopyClip().
819 * Solve by defaulting isColor to 1 if hdc is a metafile. */
820 isColor = (((GetDeviceCaps(hdc, PLANES) * GetDeviceCaps(hdc,BITSPIXEL))
822 || (GetDeviceCaps(hdc, TECHNOLOGY) == DT_METAFILE));
824 if (lpgw->background != RGB(255,255,255) && lpgw->color && isColor) {
825 SetBkColor(hdc,lpgw->background);
826 FillRect(hdc, rect, lpgw->hbrush);
829 ppt = (POINT *)LocalAllocPtr(LHND, (polymax+1) * sizeof(POINT));
836 htic = lpgw->org_pointsize*MulDiv(lpgw->htic, rr - rl, lpgw->xmax) + 1;
837 vtic = lpgw->org_pointsize*MulDiv(lpgw->vtic, rb - rt, lpgw->ymax) + 1;
841 SetTextAlign(hdc, TA_LEFT|TA_BASELINE);
843 /* calculate text shifting for horizontal text */
845 vshift = MulDiv(lpgw->vchar, rb - rt, lpgw->ymax)/2;
848 SelectObject(hdc, lpgw->hapen);
849 SelectObject(hdc, lpgw->colorbrush[pen]);
852 blkptr = lpgw->gwopblk_head;
856 blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
859 curptr = (struct GWOP FAR *)blkptr->gwop;
862 while(ngwop < lpgw->nGWOP) {
863 /* transform the coordinates */
864 xdash = MulDiv(curptr->x, rr-rl-1, lpgw->xmax) + rl;
865 ydash = MulDiv(curptr->y, rt-rb+1, lpgw->ymax) + rb - 1;
866 if ((lastop==W_vect) && (curptr->op!=W_vect)) {
868 Polyline(hdc, ppt, polyi);
869 MoveTo(hdc, ppt[0].x, ppt[0].y);
870 } else if (polyi == 1)
871 LineTo(hdc, ppt[0].x, ppt[0].y);
874 switch (curptr->op) {
875 case 0: /* have run past last in this block */
883 ppt[polyi].x = xdash;
884 ppt[polyi].y = ydash;
886 if (polyi >= polymax) {
887 Polyline(hdc, ppt, polyi);
896 LOGPEN cur_penstruct;
898 short cur_pen = ((curptr->x < (WORD)(-2))
899 ? (curptr->x % WGNUMPENS) + 2
901 /* set color only when second parameter to W_line_type equals 1 */
904 cur_penstruct = (lpgw->color && isColor) ?
905 lpgw->colorpen[pen] : lpgw->monopen[pen];
906 cur_penstruct.lopnColor = ((lpgw->color && isColor) ?
907 lpgw->colorpen[cur_pen] : lpgw->monopen[cur_pen]).lopnColor;
910 cur_penstruct.lopnWidth.x *= line_width;
912 /* use ExtCreatePen instead of CreatePen/CreatePenIndirect
913 * to support dashed lines if line_width > 1 */
914 lb.lbStyle = BS_SOLID;
915 lb.lbColor = cur_penstruct.lopnColor;
917 #if 0 /* shige work-around for Windows clipboard bug */
918 lpgw->hapen = ExtCreatePen(
919 (line_width==1 ? PS_COSMETIC : PS_GEOMETRIC) | cur_penstruct.lopnStyle | PS_ENDCAP_FLAT | PS_JOIN_BEVEL,
920 cur_penstruct.lopnWidth.x, &lb, 0, 0);
923 lpgw->hapen = CreatePenIndirect((LOGPEN FAR *) &cur_penstruct);
925 lpgw->hapen = ExtCreatePen(
926 PS_GEOMETRIC | cur_penstruct.lopnStyle | PS_ENDCAP_FLAT | PS_JOIN_BEVEL,
927 cur_penstruct.lopnWidth.x, &lb, 0, 0);
929 DeleteObject(SelectObject(hdc, lpgw->hapen));
931 SelectObject(hdc, lpgw->colorbrush[cur_pen]);
932 /* PM 7.7.2002: support color text */
933 SetTextColor(hdc, cur_penstruct.lopnColor);
940 str = LocalLock(curptr->htext);
942 /* shift correctly for rotated text */
946 SetBkMode(hdc,TRANSPARENT);
947 TextOut(hdc,xdash,ydash,str,lstrlen(str));
948 SetBkMode(hdc,OPAQUE);
950 LocalUnlock(curptr->htext);
955 /* HBB 20010916: new entry, needed to squeeze the many
956 * parameters of a filled box call through the bottlneck
957 * of the fixed number of parameters in GraphOp() and
958 * struct GWOP, respectively. */
959 fillstyle = curptr->x;
962 case W_boxfill: /* ULIG */
966 /* NOTE: the x and y passed with this call are the width and
967 * height of the box, actually. The left corner was stored into
968 * ppt[0] by a preceding W_move, and the style was memorized
969 * by a W_fillstyle call. */
970 switch(fillstyle & 0x0f) {
972 /* style == 1 --> use halftone fill pattern
973 * according to filldensity. Density is from
975 idx = ((fillstyle >> 4) * (halftone_num - 1) / 100 );
978 if (idx > halftone_num - 1)
979 idx = halftone_num - 1;
980 SelectObject(hdc, halftone_brush[idx]);
983 /* style == 2 --> use fill pattern according to
984 * fillpattern. Pattern number is enumerated */
985 idx = fillstyle >> 4;
988 if (idx > pattern_num - 1)
990 SelectObject(hdc, pattern_brush[idx]);
994 /* style == 0 or unknown --> fill with background color */
995 SelectObject(hdc, halftone_brush[0]);
997 /* needs to be fixed for monochrome devices */
998 /* FIXME: probably should keep track of text color */
999 SetTextColor(hdc, lpgw->colorpen[pen].lopnColor);
1002 PatBlt(hdc, ppt[0].x, ppt[0].y, xdash, ydash, PATCOPY);
1006 if (lpgw->angle != (short int)curptr->x) {
1007 lpgw->angle = (short int)curptr->x;
1008 /* correctly calculate shifting of rotated text */
1009 hshift = sin(M_PI/180. * lpgw->angle) * MulDiv(lpgw->vchar, rr-rl, lpgw->xmax) / 2;
1010 vshift = cos(M_PI/180. * lpgw->angle) * MulDiv(lpgw->vchar, rb-rt, lpgw->ymax) / 2;
1018 SetTextAlign(hdc, TA_LEFT|TA_BASELINE);
1021 SetTextAlign(hdc, TA_RIGHT|TA_BASELINE);
1024 SetTextAlign(hdc, TA_CENTER|TA_BASELINE);
1031 font = LocalLock(curptr->htext);
1033 GraphChangeFont(lpgw, font, curptr->x, hdc, *rect);
1036 LocalUnlock(curptr->htext);
1040 if (curptr->x != 0) {
1041 double pointsize = curptr->x / 100.0;
1042 htic = pointsize*MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
1043 vtic = pointsize*MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
1046 str = LocalLock(curptr->htext);
1049 sscanf(str, "%lg", &pointsize);
1050 htic = lpgw->org_pointsize
1051 * MulDiv(lpgw->htic, rr-rl, lpgw->xmax) + 1;
1052 vtic = lpgw->org_pointsize
1053 * MulDiv(lpgw->vtic, rb-rt, lpgw->ymax) + 1;
1055 LocalUnlock(curptr->htext);
1059 /* HBB 20000813: this may look strange, but it ensures
1060 * that linewidth is exactly 1 iff it's in default
1062 line_width = curptr->x == 100 ? 1 : (curptr->x / 100.0);
1064 case W_pm3d_setcolor:
1066 static HBRUSH last_pm3d_brush = NULL;
1069 LOGPEN cur_penstruct;
1072 /* distinguish gray values and RGB colors */
1073 if (curptr->y == 0) {
1074 rgb255_color rgb255;
1075 rgb255maxcolors_from_gray( curptr->x / 256.0, &rgb255 );
1076 c = RGB(rgb255.r, rgb255.g, rgb255.b);
1079 c = RGB(curptr->y & 0xff, (curptr->x >> 8) & 0xff, curptr->x & 0xff);
1082 /* FIXME: always a _solid_ brush?? */
1083 this_brush = CreateSolidBrush(c);
1084 SelectObject(hdc, this_brush);
1085 if (last_pm3d_brush != NULL)
1086 DeleteObject(last_pm3d_brush);
1087 last_pm3d_brush = this_brush;
1088 /* create new pen, too: */
1089 cur_penstruct = (lpgw->color && isColor) ?
1090 lpgw->colorpen[pen] : lpgw->monopen[pen];
1091 if (line_width != 1)
1092 cur_penstruct.lopnWidth.x *= line_width;
1093 lb.lbStyle = BS_SOLID;
1095 lpgw->hapen = ExtCreatePen(
1096 (line_width==1 ? PS_COSMETIC : PS_GEOMETRIC) | cur_penstruct.lopnStyle | PS_ENDCAP_FLAT | PS_JOIN_BEVEL,
1097 cur_penstruct.lopnWidth.x, &lb, 0, 0);
1098 DeleteObject(SelectObject(hdc, lpgw->hapen));
1099 /* finally set text color */
1100 SetTextColor(hdc, c);
1103 case W_pm3d_filled_polygon_pt:
1105 /* a point of the polygon is coming */
1106 if (polyi >= polymax) {
1108 ppt = (POINT *)LocalReAllocPtr(ppt, LHND, (polymax+1) * sizeof(POINT));
1110 ppt[polyi].x = xdash;
1111 ppt[polyi].y = ydash;
1115 case W_pm3d_filled_polygon_draw:
1117 /* end of point series --> draw polygon now */
1118 Polygon(hdc, ppt, polyi);
1124 /* Due to the structure of gwop in total 5 entries are needed.
1125 These static variables help to collect all the needed information
1127 static int seq = 0; /* sequence counter */
1128 static POINT corners[4];
1131 /* The first four OPs contain the `corner` array */
1132 corners[seq].x = xdash;
1133 corners[seq].y = ydash;
1135 /* The last OP contains the image and it's size */
1143 image = LocalLock(curptr->htext);
1146 /* rc = SetStretchBltMode(hdc, HALFTONE); */
1148 memset(&bmi, 0, sizeof(bmi));
1149 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
1150 bmi.bmiHeader.biWidth = M;
1151 bmi.bmiHeader.biHeight = N;
1152 bmi.bmiHeader.biPlanes = 1;
1153 bmi.bmiHeader.biBitCount = 24;
1154 bmi.bmiHeader.biCompression = BI_RGB;
1155 bmi.bmiHeader.biClrUsed = 0;
1157 rc = StretchDIBits(hdc,
1158 corners[0].x, corners[0].y,
1159 corners[1].x - corners[0].x, corners[1].y - corners[0].y,
1163 DIB_RGB_COLORS, SRCCOPY );
1165 LocalUnlock(curptr->htext);
1167 seq = (seq + 1) % 5;
1171 dot(hdc, xdash, ydash);
1173 case W_plus: /* do plus */
1174 MoveTo(hdc,xdash-htic,ydash);
1175 LineTo(hdc,xdash+htic+1,ydash);
1176 MoveTo(hdc,xdash,ydash-vtic);
1177 LineTo(hdc,xdash,ydash+vtic+1);
1179 case W_cross: /* do X */
1180 MoveTo(hdc,xdash-htic,ydash-vtic);
1181 LineTo(hdc,xdash+htic+1,ydash+vtic+1);
1182 MoveTo(hdc,xdash-htic,ydash+vtic);
1183 LineTo(hdc,xdash+htic+1,ydash-vtic-1);
1185 case W_star: /* do star */
1186 MoveTo(hdc,xdash-htic,ydash);
1187 LineTo(hdc,xdash+htic+1,ydash);
1188 MoveTo(hdc,xdash,ydash-vtic);
1189 LineTo(hdc,xdash,ydash+vtic+1);
1190 MoveTo(hdc,xdash-htic,ydash-vtic);
1191 LineTo(hdc,xdash+htic+1,ydash+vtic+1);
1192 MoveTo(hdc,xdash-htic,ydash+vtic);
1193 LineTo(hdc,xdash+htic+1,ydash-vtic-1);
1195 case W_circle: /* do open circle */
1196 Arc(hdc, xdash-htic, ydash-vtic, xdash+htic+1, ydash+vtic+1,
1197 xdash, ydash+vtic+1, xdash, ydash+vtic+1);
1198 dot(hdc, xdash, ydash);
1200 case W_fcircle: /* do filled circle */
1201 Ellipse(hdc, xdash-htic, ydash-vtic,
1202 xdash+htic+1, ydash+vtic+1);
1204 default: /* potentially closed figure */
1210 static float pointshapes[5][10] = {
1211 {-1, -1, +1, -1, +1, +1, -1, +1, 0, 0}, /* box */
1212 { 0, +1, -1, 0, 0, -1, +1, 0, 0, 0}, /* diamond */
1213 { 0, -4./3, -4./3, 2./3,
1214 4./3, 2./3, 0, 0}, /* triangle */
1215 { 0, 4./3, -4./3, -2./3,
1216 4./3, -2./3, 0, 0}, /* inverted triangle */
1217 { 0, 1, 0.95106, 0.30902, 0.58779, -0.80902,
1218 -0.58779, -0.80902, -0.95106, 0.30902} /* pentagon */
1221 switch (curptr->op) {
1259 for (i = 0; i < 5; ++i) {
1260 if (pointshapes[shape][i * 2 + 1] == 0
1261 && pointshapes[shape][i * 2] == 0)
1263 p[i].x = xdash + htic*pointshapes[shape][i*2] + 0.5;
1264 p[i].y = ydash + vtic*pointshapes[shape][i*2+1] + 0.5;
1267 /* Filled polygon */
1270 /* Outline polygon */
1273 Polyline(hdc, p, i+1);
1274 dot(hdc, xdash, ydash);
1276 } /* default case */
1277 } /* switch(opcode) */
1278 lastop = curptr->op;
1281 if ((unsigned)(curptr - blkptr->gwop) >= GWOPMAX) {
1282 GlobalUnlock(blkptr->hblk);
1283 blkptr->gwop = (struct GWOP FAR *)NULL;
1284 if ((blkptr = blkptr->next) == NULL)
1285 /* If exact multiple of GWOPMAX entries are queued,
1286 * next will be NULL. Only the next GraphOp() call would
1287 * have allocated a new block */
1290 blkptr->gwop = (struct GWOP FAR *)GlobalLock(blkptr->hblk);
1293 curptr = (struct GWOP FAR *)blkptr->gwop;
1297 Polyline(hdc, ppt, polyi);
1301 /* ================================== */
1303 /* copy graph window to clipboard --- note that the Metafile is drawn at the full
1304 * virtual resolution of the Windows terminal driver (24000 x 18000 pixels), to
1305 * preserve as much accuracy as remotely possible */
1314 LPMETAFILEPICT lpMFP;
1318 hwnd = lpgw->hWndGraph;
1320 /* view the window */
1322 ShowWindow(hwnd, SW_SHOWNORMAL);
1323 BringWindowToTop(hwnd);
1326 /* get the context */
1328 GetClientRect(hwnd, &rect);
1330 /* make a bitmap and copy it there */
1331 mem = CreateCompatibleDC(hdc);
1332 bitmap = CreateCompatibleBitmap(hdc, rect.right - rect.left,
1333 rect.bottom - rect.top);
1335 /* there is enough memory and the bitmaps OK */
1336 SelectObject(mem, bitmap);
1337 BitBlt(mem,0,0,rect.right - rect.left,
1338 rect.bottom - rect.top, hdc, rect.left,
1341 MessageBeep(MB_ICONHAND);
1342 MessageBox(hwnd, "Insufficient Memory to Copy Clipboard",
1343 lpgw->Title, MB_ICONHAND | MB_OK);
1347 /* OK, bitmap done, now create a Metafile context at full theoretical resolution
1348 * of the Windows terminal (24000 x 18000 pixels), and redraw the whole
1349 * plot into that. */
1351 /* make copy of window's main status struct for modification */
1353 int windowfontsize = MulDiv(lpgw->fontsize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
1356 gwclip.fontsize = MulDiv(windowfontsize, lpgw->ymax, rect.bottom);
1357 gwclip.hfonth = gwclip.hfontv = 0;
1359 /* HBB 981203: scale up pens as well... */
1360 for (i = 0; i < WGNUMPENS + 2; i++) {
1361 if(gwclip.monopen[i].lopnWidth.x > 1)
1362 gwclip.monopen[i].lopnWidth.x =
1363 MulDiv(gwclip.monopen[i].lopnWidth.x,
1364 gwclip.xmax, rect.right-rect.left);
1365 if(gwclip.colorpen[i].lopnWidth.x > 1)
1366 gwclip.colorpen[i].lopnWidth.x =
1367 MulDiv(gwclip.colorpen[i].lopnWidth.x,
1368 gwclip.xmax, rect.right-rect.left);
1371 rect.right = lpgw->xmax;
1372 rect.bottom = lpgw->ymax;
1374 MakePens(&gwclip, hdc);
1375 MakeFonts(&gwclip, &rect, hdc);
1377 ReleaseDC(hwnd, hdc);
1379 hdc = CreateMetaFile((LPSTR)NULL);
1381 /* HBB 981203: According to Petzold, Metafiles shouldn't contain SetMapMode() calls: */
1382 /*SetMapMode(hdc, MM_ANISOTROPIC);*/
1384 SetWindowExtEx(hdc, rect.right, rect.bottom, (LPSIZE)NULL);
1386 SetWindowExt(hdc, rect.right, rect.bottom);
1388 drawgraph(&gwclip, hdc, (LPRECT) &rect);
1389 hmf = CloseMetaFile(hdc);
1390 DestroyFonts(&gwclip);
1391 DestroyPens(&gwclip);
1394 /* Now we have the Metafile and Bitmap prepared, post their contents to
1397 hGMem = GlobalAlloc(GMEM_MOVEABLE, (DWORD)sizeof(METAFILEPICT));
1398 lpMFP = (LPMETAFILEPICT) GlobalLock(hGMem);
1399 hdc = GetDC(hwnd); /* get window size */
1400 GetClientRect(hwnd, &rect);
1401 /* in MM_ANISOTROPIC, xExt & yExt give suggested size in 0.01mm units */
1402 lpMFP->mm = MM_ANISOTROPIC;
1403 lpMFP->xExt = MulDiv(rect.right-rect.left, 2540, GetDeviceCaps(hdc, LOGPIXELSX));
1404 lpMFP->yExt = MulDiv(rect.bottom-rect.top, 2540, GetDeviceCaps(hdc, LOGPIXELSY));
1406 ReleaseDC(hwnd, hdc);
1407 GlobalUnlock(hGMem);
1409 OpenClipboard(hwnd);
1411 SetClipboardData(CF_METAFILEPICT,hGMem);
1412 SetClipboardData(CF_BITMAP, bitmap);
1417 /* copy graph window to printer */
1419 CopyPrint(LPGW lpgw)
1425 #if WINVER >= 0x030a /* If Win 3.0, this whole function does nothing at all ... */
1428 DLGPROC lpfnAbortProc;
1429 DLGPROC lpfnPrintDlgProc;
1436 hwnd = lpgw->hWndGraph;
1438 _fmemset(&pd, 0, sizeof(PRINTDLG));
1439 pd.lStructSize = sizeof(PRINTDLG);
1440 pd.hwndOwner = hwnd;
1441 pd.Flags = PD_PRINTSETUP | PD_RETURNDC;
1446 if (NULL == printer)
1449 if (!PrintSize(printer, hwnd, &rect)) {
1454 pr.hdcPrn = printer;
1455 SetWindowLong(hwnd, 4, (LONG)((GP_LPPRINT)&pr));
1457 PrintRegister((GP_LPPRINT)&pr);
1460 EnableWindow(hwnd,FALSE);
1461 pr.bUserAbort = FALSE;
1463 pr.hDlgPrint = CreateDialogParam(hdllInstance,"CancelDlgBox",hwnd,PrintDlgProc,(LPARAM)lpgw->Title);
1464 SetAbortProc(printer,PrintAbortProc);
1466 memset(&docInfo, 0, sizeof(DOCINFO));
1467 docInfo.cbSize = sizeof(DOCINFO);
1468 docInfo.lpszDocName = lpgw->Title;
1470 if (StartDoc(printer, &docInfo) > 0) {
1471 #else /* not WIN32 */
1473 lpfnPrintDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintDlgProc");
1474 lpfnAbortProc = (DLGPROC)GetProcAddress(hdllInstance, "PrintAbortProc");
1475 # else /* __DLL__ */
1476 lpfnPrintDlgProc = (DLGPROC)MakeProcInstance((FARPROC)PrintDlgProc, hdllInstance);
1477 lpfnAbortProc = (DLGPROC)MakeProcInstance((FARPROC)PrintAbortProc, hdllInstance);
1478 # endif /* __DLL__ */
1479 pr.hDlgPrint = CreateDialogParam(hdllInstance,"CancelDlgBox",hwnd,lpfnPrintDlgProc,(LPARAM)lpgw->Title);
1480 Escape(printer,SETABORTPROC,0,(LPSTR)lpfnAbortProc,NULL);
1481 if (Escape(printer, STARTDOC, lstrlen(lpgw->Title),lpgw->Title, NULL) > 0) {
1483 SetMapMode(printer, MM_TEXT);
1484 SetBkMode(printer,OPAQUE);
1489 MakeFonts(lpgw, (RECT FAR *)&rect, printer);
1490 DestroyPens(lpgw); /* rebuild pens */
1491 MakePens(lpgw, printer);
1492 drawgraph(lpgw, printer, (void *) &rect);
1494 if (EndPage(printer) > 0)
1497 if (Escape(printer,NEWFRAME,0,NULL,NULL) > 0)
1498 Escape(printer,ENDDOC,0,NULL,NULL);
1501 if (!pr.bUserAbort) {
1502 EnableWindow(hwnd,TRUE);
1503 DestroyWindow(pr.hDlgPrint);
1507 FreeProcInstance((FARPROC)lpfnPrintDlgProc);
1508 FreeProcInstance((FARPROC)lpfnAbortProc);
1509 # endif /* __DLL__ */
1512 SetWindowLong(hwnd, 4, (LONG)(0L));
1514 PrintUnregister((GP_LPPRINT)&pr);
1516 /* make certain that the screen pen set is restored */
1517 SendMessage(lpgw->hWndGraph,WM_COMMAND,M_REBUILDTOOLS,0L);
1518 #endif /* WIN Version >= 3.1 */
1522 /* ================================== */
1523 /* INI file stuff */
1525 WriteGraphIni(LPGW lpgw)
1532 LPSTR file = lpgw->IniFile;
1533 LPSTR section = lpgw->IniSection;
1536 if ((file == (LPSTR)NULL) || (section == (LPSTR)NULL))
1538 if (IsIconic(lpgw->hWndGraph))
1539 ShowWindow(lpgw->hWndGraph, SW_SHOWNORMAL);
1540 GetWindowRect(lpgw->hWndGraph,&rect);
1541 wsprintf(profile, "%d %d", rect.left, rect.top);
1542 WritePrivateProfileString(section, "GraphOrigin", profile, file);
1543 wsprintf(profile, "%d %d", rect.right-rect.left, rect.bottom-rect.top);
1544 WritePrivateProfileString(section, "GraphSize", profile, file);
1545 wsprintf(profile, "%s,%d", lpgw->deffontname, lpgw->deffontsize);
1546 WritePrivateProfileString(section, "GraphFont", profile, file);
1547 wsprintf(profile, "%d", lpgw->color);
1548 WritePrivateProfileString(section, "GraphColor", profile, file);
1549 wsprintf(profile, "%d", lpgw->graphtotop);
1550 WritePrivateProfileString(section, "GraphToTop", profile, file);
1551 wsprintf(profile, "%d %d %d",GetRValue(lpgw->background),
1552 GetGValue(lpgw->background), GetBValue(lpgw->background));
1553 WritePrivateProfileString(section, "GraphBackground", profile, file);
1556 for (i=0; i<WGNUMPENS+2; i++) {
1558 _fstrcpy(entry,"Border");
1560 _fstrcpy(entry,"Axis");
1562 wsprintf(entry,"Line%d",i-1);
1563 pc = &lpgw->colorpen[i];
1564 pm = &lpgw->monopen[i];
1565 wsprintf(profile, "%d %d %d %d %d",GetRValue(pc->lopnColor),
1566 GetGValue(pc->lopnColor), GetBValue(pc->lopnColor),
1567 (pc->lopnWidth.x != 1) ? -pc->lopnWidth.x : pc->lopnStyle,
1568 (pm->lopnWidth.x != 1) ? -pm->lopnWidth.x : pm->lopnStyle);
1569 WritePrivateProfileString(section, entry, profile, file);
1575 ReadGraphIni(LPGW lpgw)
1577 LPSTR file = lpgw->IniFile;
1578 LPSTR section = lpgw->IniSection;
1582 int i,r,g,b,colorstyle,monostyle;
1586 bOKINI = (file != (LPSTR)NULL) && (section != (LPSTR)NULL);
1591 GetPrivateProfileString(section, "GraphOrigin", "", profile, 80, file);
1592 if ( (p = GetInt(profile, (LPINT)&lpgw->Origin.x)) == NULL)
1593 lpgw->Origin.x = CW_USEDEFAULT;
1594 if ( (p = GetInt(p, (LPINT)&lpgw->Origin.y)) == NULL)
1595 lpgw->Origin.y = CW_USEDEFAULT;
1597 GetPrivateProfileString(section, "GraphSize", "", profile, 80, file);
1598 if ( (p = GetInt(profile, (LPINT)&lpgw->Size.x)) == NULL)
1599 lpgw->Size.x = CW_USEDEFAULT;
1600 if ( (p = GetInt(p, (LPINT)&lpgw->Size.y)) == NULL)
1601 lpgw->Size.y = CW_USEDEFAULT;
1604 GetPrivateProfileString(section, "GraphFont", "", profile, 80, file);
1607 size = _fstrchr(profile,',');
1610 if ( (p = GetInt(size, (LPINT)&lpgw->fontsize)) == NULL)
1611 lpgw->fontsize = WINFONTSIZE;
1613 _fstrcpy(lpgw->fontname, profile);
1614 if (lpgw->fontsize == 0)
1615 lpgw->fontsize = WINFONTSIZE;
1616 if (!(*lpgw->fontname)) {
1617 if (LOWORD(GetVersion()) == 3)
1618 _fstrcpy(lpgw->fontname,WIN30FONT);
1620 _fstrcpy(lpgw->fontname,WINFONT);
1622 /* set current font as default font */
1623 _fstrcpy(lpgw->deffontname, lpgw->fontname);
1624 lpgw->deffontsize = lpgw->fontsize;
1628 GetPrivateProfileString(section, "GraphColor", "", profile, 80, file);
1629 if ( (p = GetInt(profile, (LPINT)&lpgw->color)) == NULL)
1633 GetPrivateProfileString(section, "GraphToTop", "", profile, 80, file);
1634 if ( (p = GetInt(profile, (LPINT)&lpgw->graphtotop)) == NULL)
1635 lpgw->graphtotop = TRUE;
1637 lpgw->background = RGB(255,255,255);
1639 GetPrivateProfileString(section, "GraphBackground", "", profile, 80, file);
1640 if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1641 ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1642 ((p = GetInt(p, (LPINT)&b)) != NULL) )
1643 lpgw->background = RGB(r,g,b);
1645 StorePen(lpgw, 0,RGB(0,0,0),PS_SOLID,PS_SOLID);
1647 GetPrivateProfileString(section, "Border", "", profile, 80, file);
1648 if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1649 ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1650 ((p = GetInt(p, (LPINT)&b)) != NULL) &&
1651 ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
1652 ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
1653 StorePen(lpgw,0,RGB(r,g,b),colorstyle,monostyle);
1655 StorePen(lpgw, 1,RGB(192,192,192),PS_DOT,PS_DOT);
1657 GetPrivateProfileString(section, "Axis", "", profile, 80, file);
1658 if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1659 ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1660 ((p = GetInt(p, (LPINT)&b)) != NULL) &&
1661 ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
1662 ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
1663 StorePen(lpgw,1,RGB(r,g,b),colorstyle,monostyle);
1665 for (i=0; i<WGNUMPENS; i++)
1667 ref = wginitcolor[ i%WGDEFCOLOR ];
1668 colorstyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
1669 monostyle = wginitstyle[ i%WGDEFSTYLE ];
1670 StorePen(lpgw, i+2,ref,colorstyle,monostyle);
1671 wsprintf(entry,"Line%d",i+1);
1673 GetPrivateProfileString(section, entry, "", profile, 80, file);
1674 if ( ((p = GetInt(profile, (LPINT)&r)) != NULL) &&
1675 ((p = GetInt(p, (LPINT)&g)) != NULL) &&
1676 ((p = GetInt(p, (LPINT)&b)) != NULL) &&
1677 ((p = GetInt(p, (LPINT)&colorstyle)) != NULL) &&
1678 ((p = GetInt(p, (LPINT)&monostyle)) != NULL) )
1679 StorePen(lpgw,i+2,RGB(r,g,b),colorstyle,monostyle);
1684 /* ================================== */
1686 /* the "Line Styles..." dialog and its support functions */
1687 /* FIXME HBB 20010218: this might better be delegated to a separate source file */
1689 #define LS_DEFLINE 2
1690 typedef struct tagLS {
1694 int pen; /* current pen number */
1695 LOGPEN colorpen[WGNUMPENS+2]; /* logical color pens */
1696 LOGPEN monopen[WGNUMPENS+2]; /* logical mono pens */
1698 typedef LS FAR* LPLS;
1702 GetColor(HWND hwnd, COLORREF ref)
1705 COLORREF aclrCust[16];
1708 for (i=0; i<16; i++) {
1709 aclrCust[i] = RGB(0,0,0);
1711 _fmemset(&cc, 0, sizeof(CHOOSECOLOR));
1712 cc.lStructSize = sizeof(CHOOSECOLOR);
1713 cc.hwndOwner = hwnd;
1714 cc.lpCustColors = aclrCust;
1716 cc.Flags = CC_RGBINIT;
1717 if (ChooseColor(&cc))
1718 return cc.rgbResult;
1723 /* force update of owner draw button */
1725 UpdateColorSample(HWND hdlg)
1729 GetWindowRect( GetDlgItem(hdlg, LS_COLORSAMPLE), &rect);
1732 ptlr.x = rect.right;
1733 ptlr.y = rect.bottom;
1734 ScreenToClient(hdlg, &ptul);
1735 ScreenToClient(hdlg, &ptlr);
1738 rect.right = ptlr.x;
1739 rect.bottom = ptlr.y;
1740 InvalidateRect(hdlg, &rect, TRUE);
1744 /* Window handler function for the "Line Styles" dialog */
1745 BOOL CALLBACK WINEXPORT
1746 LineStyleDlgProc(HWND hdlg, UINT wmsg, WPARAM wparam, LPARAM lparam)
1752 LPLOGPEN plpm, plpc;
1753 lpls = (LPLS)GetWindowLong(GetParent(hdlg), 4);
1758 for (i=0; i<WGNUMPENS+2; i++) {
1760 _fstrcpy(buf,"Border");
1762 _fstrcpy(buf,"Axis");
1764 wsprintf(buf,"Line%d",i-1);
1765 SendDlgItemMessage(hdlg, LS_LINENUM, LB_ADDSTRING, 0,
1766 (LPARAM)((LPSTR)buf));
1768 SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
1770 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1771 (LPARAM)((LPSTR)"Solid"));
1772 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1773 (LPARAM)((LPSTR)"Dash"));
1774 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1775 (LPARAM)((LPSTR)"Dot"));
1776 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1777 (LPARAM)((LPSTR)"DashDot"));
1778 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_ADDSTRING, 0,
1779 (LPARAM)((LPSTR)"DashDotDot"));
1781 plpm = &lpls->monopen[pen];
1782 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1783 plpm->lopnStyle, 0L);
1784 wsprintf(buf,"%d",plpm->lopnWidth.x);
1785 SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1787 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1788 (LPARAM)((LPSTR)"Solid"));
1789 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1790 (LPARAM)((LPSTR)"Dash"));
1791 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1792 (LPARAM)((LPSTR)"Dot"));
1793 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1794 (LPARAM)((LPSTR)"DashDot"));
1795 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_ADDSTRING, 0,
1796 (LPARAM)((LPSTR)"DashDotDot"));
1798 plpc = &lpls->colorpen[pen];
1799 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1800 plpc->lopnStyle, 0L);
1801 wsprintf(buf,"%d",plpc->lopnWidth.x);
1802 SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1806 pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, 0, 0L);
1807 plpm = &lpls->monopen[pen];
1808 plpc = &lpls->colorpen[pen];
1809 switch (LOWORD(wparam)) {
1811 wsprintf(buf,"%d",plpm->lopnWidth.x);
1812 SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1813 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1814 plpm->lopnStyle, 0L);
1815 wsprintf(buf,"%d",plpc->lopnWidth.x);
1816 SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1817 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1818 plpc->lopnStyle, 0L);
1819 UpdateColorSample(hdlg);
1823 (UINT)SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_GETCURSEL, 0, 0L);
1824 if (plpm->lopnStyle != 0) {
1825 plpm->lopnWidth.x = 1;
1826 wsprintf(buf,"%d",plpm->lopnWidth.x);
1827 SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1831 GetDlgItemText(hdlg, LS_MONOWIDTH, buf, 15);
1832 GetInt(buf, (LPINT)&plpm->lopnWidth.x);
1833 if (plpm->lopnWidth.x != 1) {
1834 plpm->lopnStyle = 0;
1835 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1836 plpm->lopnStyle, 0L);
1839 case LS_CHOOSECOLOR:
1840 plpc->lopnColor = GetColor(hdlg, plpc->lopnColor);
1841 UpdateColorSample(hdlg);
1845 (UINT)SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_GETCURSEL, 0, 0L);
1846 if (plpc->lopnStyle != 0) {
1847 plpc->lopnWidth.x = 1;
1848 wsprintf(buf,"%d",plpc->lopnWidth.x);
1849 SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1853 GetDlgItemText(hdlg, LS_COLORWIDTH, buf, 15);
1854 GetInt(buf, (LPINT)&plpc->lopnWidth.x);
1855 if (plpc->lopnWidth.x != 1) {
1856 plpc->lopnStyle = 0;
1857 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1858 plpc->lopnStyle, 0L);
1862 plpm = lpls->monopen;
1863 plpc = lpls->colorpen;
1865 plpc->lopnColor = RGB(0,0,0);
1866 plpc->lopnStyle = PS_SOLID;
1867 plpc->lopnWidth.x = 1;
1868 plpm->lopnStyle = PS_SOLID;
1869 plpm->lopnWidth.x = 1;
1872 plpc->lopnColor = RGB(192,192,192);
1873 plpc->lopnStyle = PS_DOT;
1874 plpc->lopnWidth.x = 1;
1875 plpm->lopnStyle = PS_DOT;
1876 plpm->lopnWidth.x = 1;
1878 for (i=0; i<WGNUMPENS; i++) {
1880 plpc->lopnColor = wginitcolor[ i%WGDEFCOLOR ];
1881 plpc->lopnStyle = wginitstyle[ (i/WGDEFCOLOR) % WGDEFSTYLE ];
1882 plpc->lopnWidth.x = 1;
1883 plpm->lopnStyle = wginitstyle[ i%WGDEFSTYLE ];
1884 plpm->lopnWidth.x = 1;
1887 plpm = &lpls->monopen[pen];
1888 plpc = &lpls->colorpen[pen];
1889 SendDlgItemMessage(hdlg, LS_LINENUM, LB_SETCURSEL, pen, 0L);
1890 wsprintf(buf,"%d",plpm->lopnWidth.x);
1891 SetDlgItemText(hdlg, LS_MONOWIDTH, buf);
1892 SendDlgItemMessage(hdlg, LS_MONOSTYLE, CB_SETCURSEL,
1893 plpm->lopnStyle, 0L);
1894 wsprintf(buf,"%d",plpc->lopnWidth.x);
1895 SetDlgItemText(hdlg, LS_COLORWIDTH, buf);
1896 SendDlgItemMessage(hdlg, LS_COLORSTYLE, CB_SETCURSEL,
1897 plpc->lopnStyle, 0L);
1898 UpdateColorSample(hdlg);
1901 EndDialog(hdlg, IDOK);
1904 EndDialog(hdlg, IDCANCEL);
1911 LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lparam;
1912 pen = (UINT)SendDlgItemMessage(hdlg, LS_LINENUM, LB_GETCURSEL, (WPARAM)0, (LPARAM)0);
1913 plpc = &lpls->colorpen[pen];
1914 hBrush = CreateSolidBrush(plpc->lopnColor);
1915 FillRect(lpdis->hDC, &lpdis->rcItem, hBrush);
1916 FrameRect(lpdis->hDC, &lpdis->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
1917 DeleteObject(hBrush);
1926 /* GetWindowLong(hwnd, 4) must be available for use */
1928 LineStyle(LPGW lpgw)
1930 BOOL status = FALSE;
1933 DLGPROC lpfnLineStyleDlgProc;
1936 SetWindowLong(lpgw->hWndGraph, 4, (LONG)((LPLS)&ls));
1937 _fmemcpy(&ls.colorpen, &lpgw->colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1938 _fmemcpy(&ls.monopen, &lpgw->monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1941 if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, LineStyleDlgProc)
1944 lpfnLineStyleDlgProc = (DLGPROC)GetProcAddress(hdllInstance, "LineStyleDlgProc");
1946 lpfnLineStyleDlgProc = (DLGPROC)MakeProcInstance((FARPROC)LineStyleDlgProc, hdllInstance);
1948 if (DialogBox (hdllInstance, "LineStyleDlgBox", lpgw->hWndGraph, lpfnLineStyleDlgProc)
1951 _fmemcpy(&lpgw->colorpen, &ls.colorpen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1952 _fmemcpy(&lpgw->monopen, &ls.monopen, (WGNUMPENS + 2) * sizeof(LOGPEN));
1957 FreeProcInstance((FARPROC)lpfnLineStyleDlgProc);
1960 SetWindowLong(lpgw->hWndGraph, 4, (LONG)(0L));
1965 /* ================================== */
1966 /* HBB 20010207: new helper functions: wrapper around gp_exec_event
1967 * and DoZoombox. These may vanish again, as has the original idea I
1968 * invented them for... */
1971 Wnd_exec_event(LPGW lpgw, LPARAM lparam, char type, int par1)
1974 static unsigned long lastTimestamp = 0;
1975 unsigned long thisTimestamp = GetMessageTime();
1976 int par2 = thisTimestamp - lastTimestamp;
1978 if (type == GE_keypress)
1981 GetMousePosViewport(lpgw, &mx, &my);
1982 gp_exec_event(type, mx, my, par1, par2, 0);
1983 lastTimestamp = thisTimestamp;
1987 Wnd_refresh_zoombox(LPGW lpgw, LPARAM lParam)
1991 GetMousePosViewport(lpgw, &mx, &my);
1992 DrawZoomBox(lpgw); /* erase current zoom box */
1993 zoombox.to.x = mx; zoombox.to.y = my;
1994 DrawZoomBox(lpgw); /* draw new zoom box */
1998 Wnd_refresh_ruler_lineto(LPGW lpgw, LPARAM lParam)
2002 GetMousePosViewport(lpgw, &mx, &my);
2003 DrawRulerLineTo(lpgw); /* erase current line */
2004 ruler_lineto.x = mx; ruler_lineto.y = my;
2005 DrawRulerLineTo(lpgw); /* draw new line box */
2007 #endif /* USE_MOUSE */
2009 /* ================================== */
2011 /* The toplevel function of this module: Window handler function of the graph window */
2012 LRESULT CALLBACK WINEXPORT
2013 WndGraphProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
2022 static unsigned int last_modifier_mask = -99;
2025 lpgw = (LPGW)GetWindowLong(hwnd, 0);
2028 /* mouse events first */
2029 if (mouse_setting.on /* AND NOT mouse_lock */ ) {
2033 SetCursor(hptrCurrent);
2035 SetCursor(hptrCrossHair);
2038 Wnd_refresh_zoombox(lpgw, lParam);
2040 if (ruler.on && ruler_lineto.on) {
2041 Wnd_refresh_ruler_lineto(lpgw, lParam);
2043 /* track (show) mouse position -- send the event to gnuplot */
2044 Wnd_exec_event(lpgw, lParam, GE_motion, wParam);
2045 return 0L; /* end of WM_MOUSEMOVE */
2047 case WM_LBUTTONDOWN:
2048 Wnd_exec_event(lpgw, lParam, GE_buttonpress, 1);
2051 case WM_RBUTTONDOWN:
2052 /* FIXME HBB 20010207: this collides with the right-click
2053 * context menu !!! */
2054 Wnd_exec_event(lpgw, lParam, GE_buttonpress, 3);
2057 case WM_MBUTTONDOWN:
2058 Wnd_exec_event(lpgw, lParam, GE_buttonpress, 2);
2061 case WM_LBUTTONDBLCLK:
2062 Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 1);
2065 case WM_RBUTTONDBLCLK:
2066 Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 3);
2069 case WM_MBUTTONDBLCLK:
2070 Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 2);
2076 case WM_LBUTTONCLICK:
2078 Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 1);
2084 case WM_RBUTTONCLICK:
2086 Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 3);
2092 case WM_MBUTTONCLICK:
2094 Wnd_exec_event(lpgw, lParam, GE_buttonrelease, 2);
2097 } /* switch over mouse events */
2099 #endif /* USE_MOUSE */
2106 switch(LOWORD(wParam))
2108 case M_GRAPH_TO_TOP:
2116 case M_REBUILDTOOLS:
2117 SendMessage(hwnd, WM_COMMAND, wParam, lParam);
2121 AboutBox(hwnd,lpgw->lptw->AboutText);
2124 sysmenu = GetSystemMenu(lpgw->hWndGraph,0);
2125 i = GetMenuItemCount (sysmenu);
2126 DeleteMenu (sysmenu, --i, MF_BYPOSITION);
2127 DeleteMenu (sysmenu, --i, MF_BYPOSITION);
2128 ShowWindow (lpgw->lptw->hWndParent, SW_SHOW);
2133 /* All 'normal' keys (letters, digits and the likes) end up
2135 if (wParam == VK_SPACE) {
2136 /* HBB 20001023: implement the '<space> in graph returns to
2137 * text window' --- feature already present in OS/2 and X11 */
2138 /* Make sure the text window is visible: */
2139 ShowWindow(lpgw->lptw->hWndParent, SW_SHOW);
2140 /* and activate it (--> Keyboard focus goes there */
2141 BringWindowToTop(lpgw->lptw->hWndParent);
2145 Wnd_exec_event(lpgw, lParam, GE_keypress, (TCHAR)wParam);
2149 /* "special" keys have to be caught from WM_KEYDOWN, as they
2150 * don't generate WM_CHAR messages. */
2151 /* NB: It may not be possible to catch Alt-keys, this way */
2154 /* First, look for a change in modifier status */
2155 unsigned int modifier_mask = 0;
2156 modifier_mask = ((GetKeyState(VK_SHIFT) < 0) ? Mod_Shift : 0 )
2157 | ((GetKeyState(VK_CONTROL) < 0) ? Mod_Ctrl : 0)
2158 | ((GetKeyState(VK_MENU) < 0) ? Mod_Alt : 0);
2159 if (modifier_mask != last_modifier_mask) {
2160 Wnd_exec_event ( lpgw, lParam, GE_modifier, modifier_mask);
2161 last_modifier_mask = modifier_mask;
2164 /* Ignore Key-Up events other than those of modifier keys */
2168 /* First, look for a change in modifier status */
2169 unsigned int modifier_mask = 0;
2170 modifier_mask = ((GetKeyState(VK_SHIFT) < 0) ? Mod_Shift : 0 )
2171 | ((GetKeyState(VK_CONTROL) < 0) ? Mod_Ctrl : 0)
2172 | ((GetKeyState(VK_MENU) < 0) ? Mod_Alt : 0);
2173 if (modifier_mask != last_modifier_mask) {
2174 Wnd_exec_event ( lpgw, lParam, GE_modifier, modifier_mask);
2175 last_modifier_mask = modifier_mask;
2180 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_BackSpace);
2183 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Tab);
2186 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Return);
2189 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Pause);
2192 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Scroll_Lock);
2194 #if 0 /* HOW_IS_THIS_FOR_WINDOWS */
2195 /* HBB 20010215: not at all, AFAICS... :-( */
2197 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Sys_Req);
2201 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Escape);
2204 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Delete);
2207 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_KP_Insert);
2210 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Home);
2213 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Left);
2216 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Up);
2219 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Right);
2222 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_Down);
2225 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_End);
2228 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_PageUp);
2231 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_PageDown);
2234 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F1);
2237 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F2);
2240 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F3);
2243 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F4);
2246 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F5);
2249 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F6);
2252 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F7);
2255 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F8);
2258 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F9);
2261 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F10);
2264 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F11);
2267 Wnd_exec_event(lpgw, lParam, GE_keypress, GP_F12);
2269 } /* switch (wParam) */
2272 #if 0 /* DO WE NEED THIS ??? */
2274 /* set default pointer: */
2275 SetCursor(hptrDefault);
2278 #endif /* USE_MOUSE */
2280 switch(LOWORD(wParam))
2282 case M_GRAPH_TO_TOP:
2283 lpgw->graphtotop = !lpgw->graphtotop;
2284 SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
2287 lpgw->color = !lpgw->color;
2288 SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
2297 if (LineStyle(lpgw))
2298 SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
2301 lpgw->background = GetColor(hwnd, lpgw->background);
2302 SendMessage(hwnd,WM_COMMAND,M_REBUILDTOOLS,0L);
2308 WriteGraphIni(lpgw);
2310 WriteTextIni(lpgw->lptw);
2312 case M_REBUILDTOOLS:
2313 lpgw->resized = TRUE;
2315 CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_CHECKED);
2317 CheckMenuItem(lpgw->hPopMenu, M_COLOR, MF_BYCOMMAND | MF_UNCHECKED);
2318 if (lpgw->graphtotop)
2319 CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_CHECKED);
2321 CheckMenuItem(lpgw->hPopMenu, M_GRAPH_TO_TOP, MF_BYCOMMAND | MF_UNCHECKED);
2325 MakePens(lpgw, hdc);
2326 GetClientRect(hwnd, &rect);
2327 MakeFonts(lpgw, (LPRECT)&rect, hdc);
2328 ReleaseDC(hwnd, hdc);
2329 GetClientRect(hwnd, &rect);
2330 InvalidateRect(hwnd, (LPRECT) &rect, 1);
2335 case WM_RBUTTONDOWN:
2336 /* HBB 20010218: note that this only works in mouse-off
2337 * mode, now. You'll need to go via the System menu to
2338 * access this popup, instead */
2341 pt.x = LOWORD(lParam);
2342 pt.y = HIWORD(lParam);
2343 ClientToScreen(hwnd,&pt);
2344 TrackPopupMenu(lpgw->hPopMenu, TPM_LEFTALIGN,
2345 pt.x, pt.y, 0, hwnd, NULL);
2349 lpgw = ((CREATESTRUCT FAR *)lParam)->lpCreateParams;
2350 SetWindowLong(hwnd, 0, (LONG)lpgw);
2351 lpgw->hWndGraph = hwnd;
2353 MakePens(lpgw, hdc);
2357 GetClientRect(hwnd, &rect);
2358 MakeFonts(lpgw, (LPRECT)&rect, hdc);
2359 ReleaseDC(hwnd, hdc);
2360 #if WINVER >= 0x030a
2362 WORD version = LOWORD(GetVersion());
2364 if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
2365 if ( lpgw->lptw && (lpgw->lptw->DragPre!=(LPSTR)NULL) && (lpgw->lptw->DragPost!=(LPSTR)NULL) )
2366 DragAcceptFiles(hwnd, TRUE);
2371 hdc = BeginPaint(hwnd, &ps);
2372 SetMapMode(hdc, MM_TEXT);
2373 SetBkMode(hdc,OPAQUE);
2374 GetClientRect(hwnd, &rect);
2376 SetViewportExtEx(hdc, rect.right, rect.bottom, NULL);
2378 SetViewportExt(hdc, rect.right, rect.bottom);
2380 drawgraph(lpgw, hdc, &rect);
2381 EndPaint(hwnd, &ps);
2383 /* drawgraph() erases the plot window, so immediately after
2384 * it has completed, all the 'real-time' stuff the gnuplot core
2385 * doesn't know anything about has to be redrawn */
2387 DisplayStatusLine(lpgw);
2388 DrawRulerLineTo(lpgw);
2393 /* update font sizes if graph resized */
2394 if ((wParam == SIZE_MAXIMIZED) || (wParam == SIZE_RESTORED)) {
2396 SendMessage(hwnd,WM_SYSCOMMAND,M_REBUILDTOOLS,0L);
2397 GetWindowRect(hwnd,&rect);
2398 lpgw->Size.x = rect.right-rect.left;
2399 lpgw->Size.y = rect.bottom-rect.top;
2402 #if WINVER >= 0x030a
2405 WORD version = LOWORD(GetVersion());
2406 if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
2408 DragFunc(lpgw->lptw, (HDROP)wParam);
2416 DestroyCursors(lpgw);
2418 #if __TURBOC__ >= 0x410 /* Borland C++ 3.1 or later */
2420 WORD version = LOWORD(GetVersion());
2421 if ((LOBYTE(version)*100 + HIBYTE(version)) >= 310)
2422 DragAcceptFiles(hwnd, FALSE);
2425 if (lpgw->lptw && !IsWindowVisible(lpgw->lptw->hWndParent)) {
2426 PostMessage (lpgw->lptw->hWndParent, WM_CLOSE, 0, 0);
2433 return DefWindowProc(hwnd, message, wParam, lParam);
2438 GraphChangeFont(LPGW lpgw, LPCSTR font, int fontsize, HDC hdc, RECT rect)
2441 bool remakefonts = FALSE;
2443 newfontsize = (fontsize != 0) ? fontsize : lpgw->deffontsize;
2445 remakefonts = (strcmp(lpgw->fontname, font) != 0) || (newfontsize != lpgw->fontsize);
2447 remakefonts = (strcmp(lpgw->fontname, lpgw->deffontname) != 0) || (newfontsize != lpgw->fontsize);
2451 lpgw->fontsize = newfontsize;
2452 strcpy(lpgw->fontname, (font) ? font : lpgw->deffontname);
2455 MakeFonts(lpgw, &rect, hdc);
2462 GraphGetFontScaling(LPGW lpgw, LPCSTR font, int fontsize)
2467 OUTLINETEXTMETRIC otm;
2470 hdc = GetDC(lpgw->hWndGraph);
2471 GetClientRect(lpgw->hWndGraph, &rect);
2472 GraphChangeFont(lpgw, font, fontsize, hdc, rect);
2473 hprevfont = SelectObject(hdc, lpgw->hfonth);
2474 if (GetOutlineTextMetrics(hdc, sizeof(otm), &otm) != 0) {
2475 shift = otm.otmptSuperscriptOffset.y - otm.otmptSubscriptOffset.y;
2476 shift = MulDiv(shift, GetDeviceCaps(hdc, LOGPIXELSY), 2 * 72);
2477 printf( "shift: %i (%i %i)\n", shift*8, otm.otmptSuperscriptOffset.y, otm.otmptSubscriptOffset.y);
2479 SelectObject(hdc, hprevfont);
2487 GraphGetTextLength(LPGW lpgw, LPCSTR text, LPCSTR fontname, int fontsize)
2494 hdc = GetDC(lpgw->hWndGraph);
2495 GetClientRect(lpgw->hWndGraph, &rect);
2497 GraphChangeFont(lpgw, fontname, fontsize, hdc, rect);
2499 hprevfont = SelectObject(hdc, lpgw->hfonth);
2500 GetTextExtentPoint(hdc, text, strlen(text), &size);
2501 SelectObject(hdc, hprevfont);
2503 size.cx = MulDiv(size.cx + GetTextCharacterExtra(hdc), lpgw->xmax, rect.right-rect.left-1);
2509 /* Implemented by Petr Mikulik, February 2001 --- the best Windows solutions
2510 * come from OS/2 :-))
2513 /* ================================================================= */
2515 /* Firstly: terminal calls from win.trm */
2517 /* Note that these all take lpgw as their first argument. It's an OO-type
2518 * 'this' pointer, sort of: it stores all the status information of the graph
2519 * window that we need, in a single large structure. */
2522 Graph_set_cursor (LPGW lpgw, int c, int x, int y )
2525 case -4: /* switch off line between ruler and mouse cursor */
2526 DrawRulerLineTo(lpgw);
2527 ruler_lineto.on = FALSE;
2529 case -3: /* switch on line between ruler and mouse cursor */
2530 if (ruler.on && ruler_lineto.on)
2534 ruler_lineto.on = TRUE;
2535 DrawRulerLineTo(lpgw);
2538 { /* move mouse to the given point */
2542 GetClientRect(lpgw->hWndGraph, &rc);
2543 pt.x = MulDiv(x, rc.right - rc.left, lpgw->xmax);
2544 pt.y = rc.bottom - MulDiv(y, rc.bottom - rc.top, lpgw->ymax);
2546 MapWindowPoints(lpgw->hWndGraph, HWND_DESKTOP, &pt, 1);
2547 SetCursorPos(pt.x, pt.y);
2550 case -1: /* start zooming; zooming cursor */
2552 zoombox.from.x = zoombox.to.x = x;
2553 zoombox.from.y = zoombox.to.y = y;
2555 case 0: /* standard cross-hair cursor */
2556 SetCursor( (hptrCurrent = mouse_setting.on ? hptrCrossHair : hptrDefault) );
2558 case 1: /* cursor during rotation */
2559 SetCursor(hptrCurrent = hptrRotating);
2561 case 2: /* cursor during scaling */
2562 SetCursor(hptrCurrent = hptrScaling);
2564 case 3: /* cursor during zooming */
2565 SetCursor(hptrCurrent = hptrZooming);
2568 if (c>=0 && zoombox.on) { /* erase zoom box */
2572 if (c>=0 && ruler_lineto.on) { /* erase ruler line */
2573 DrawRulerLineTo(lpgw);
2574 ruler_lineto.on = FALSE;
2578 /* set_ruler(int x, int y) term API: x<0 switches ruler off. */
2580 Graph_set_ruler (LPGW lpgw, int x, int y )
2582 DrawRuler(lpgw); /* remove previous drawing, if any */
2583 DrawRulerLineTo(lpgw);
2589 ruler.x = x; ruler.y = y;
2590 DrawRuler(lpgw); /* draw ruler at new positions */
2591 DrawRulerLineTo(lpgw);
2594 /* put_tmptext(int i, char c[]) term API
2595 * i: 0..at statusline
2596 * 1, 2: at corners of zoom box with \r separating text
2599 Graph_put_tmptext (LPGW lpgw, int where, LPCSTR text )
2601 /* Position of the annotation string (mouse movement) or zoom box
2602 * text or whatever temporary text added...
2606 UpdateStatusLine(lpgw, text);
2610 if (zoombox.text1) {
2611 free((char*)zoombox.text1);
2613 zoombox.text1 = strdup(text);
2618 if (zoombox.text2) {
2619 free((char*)zoombox.text2);
2621 zoombox.text2 = strdup(text);
2625 ; /* should NEVER happen */
2630 Graph_set_clipboard (LPGW lpgw, LPCSTR s)
2636 /* check: no string --> nothing to do */
2640 /* Transport the string into a system-global storage area. In case
2641 * of (unlikely) allocation failures, fail silently */
2643 if ( (memHandle = GlobalAlloc(GHND, length + 1)) == NULL)
2645 if ( (clipText = GlobalLock(memHandle)) == NULL) {
2646 GlobalFree(memHandle);
2649 strcpy(clipText, s);
2650 GlobalUnlock(memHandle);
2652 /* Now post that memory area to the Clipboard */
2653 OpenClipboard(lpgw->hWndGraph);
2655 SetClipboardData(CF_TEXT, memHandle);
2659 /* ================================================================= */
2661 /* Secondly, support routines that implement direct mouse reactions. */
2663 /* This routine gets the mouse/pointer position in the current window and
2664 * recalculates it to the viewport coordinates. */
2666 GetMousePosViewport (LPGW lpgw, int *mx, int *my)
2671 GetClientRect(lpgw->hWndGraph,&rc);
2673 /* HBB: has to be done this way. The simpler method by taking apart LPARM
2674 * only works for mouse, but not for keypress events. */
2676 ScreenToClient(lpgw->hWndGraph,&pt);
2680 /* px=px(mx); mouse=>gnuplot driver coordinates */
2681 /* FIXME: classically, this would use MulDiv() call, and no floating point */
2682 *mx = (int)((*mx - rc.left) * lpgw->xmax / (rc.right - rc.left) + 0.5);
2683 *my = (int)((rc.bottom - *my) * lpgw->ymax / (rc.bottom -rc.top) + 0.5);
2686 /* HBB 20010218: Newly separated function: Draw text string in XOR mode.
2687 * That is surprisingly difficult using the Windows API: have to draw text
2688 * into a background bitmap, first, and then blit that onto the screen.
2690 * x and y give the bottom-left corner of the bounding box into which the
2691 * text will be drawn */
2693 Draw_XOR_Text(LPGW lpgw, const char *text, size_t length, int x, int y)
2699 if (!text || !text[0])
2700 return; /* no text to be displayed */
2702 hdc = GetDC(lpgw->hWndGraph);
2704 /* Prepare background image buffer of the necessary size */
2705 Wnd_GetTextSize(hdc, text, length, &cx, &cy);
2706 bitmap = CreateCompatibleBitmap(hdc, cx, cy);
2707 /* ... and a DeviceContext to access it by */
2708 tempDC = CreateCompatibleDC(hdc);
2709 DeleteObject(SelectObject(tempDC, bitmap));
2711 /* Print inverted text, so the second inversion done by SRCINVERT ends
2712 * up printing the right way round... */
2713 /* FIXME HBB 20010218: find out the real ROP3 code for operation
2714 * "target = target XOR (NOT source)" and use that, instead. It's the
2715 * one with MSByte = 0x99, but without VC++ or MSDN, I can't seem to
2716 * find out what the full code is. */
2717 SetTextColor(tempDC, GetBkColor(hdc));
2718 SetBkColor(tempDC, GetTextColor(hdc));
2719 TextOut(tempDC, 0, 0, text, length);
2721 /* Copy printed string to the screen window by XORing, so the
2722 * repetition of this same operation will delete it again */
2723 BitBlt(hdc, x, y - cy, cx, cy, tempDC, 0, 0, SRCINVERT);
2725 /* Clean up behind ourselves */
2727 DeleteObject(bitmap);
2728 ReleaseDC(lpgw->hWndGraph, hdc);
2732 /* ================================== */
2734 /* Status line routines. */
2736 /* Saved text currently contained in status line */
2737 static char *sl_curr_text = NULL;
2739 /* Display the status line by the text (and remove it again by calling this
2740 * same routine a second time --- thanks to XOR mode) */
2742 DisplayStatusLine (LPGW lpgw)
2746 if (!sl_curr_text || !sl_curr_text[0])
2747 return; /* no text to be displayed */
2749 GetClientRect(lpgw->hWndGraph, &rc);
2750 Draw_XOR_Text(lpgw, sl_curr_text, strlen(sl_curr_text), 0, rc.bottom);
2755 * Update the status line by the text; firstly erase the previous text
2758 UpdateStatusLine (LPGW lpgw, const char text[] )
2760 DisplayStatusLine(lpgw); /* erase previous text */
2762 if (!text || !*text) {
2764 } else { /* display new text */
2765 sl_curr_text = strdup(text);
2766 DisplayStatusLine(lpgw);
2773 DrawRuler (LPGW lpgw)
2780 if (!ruler.on || ruler.x < 0)
2783 hdc = GetDC(lpgw->hWndGraph);
2784 GetClientRect(lpgw->hWndGraph, &rc);
2786 rx = MulDiv(ruler.x, rc.right - rc.left, lpgw->xmax);
2787 ry = rc.bottom - MulDiv(ruler.y, rc.bottom - rc.top, lpgw->ymax);
2789 iOldRop = SetROP2(hdc, R2_NOT);
2790 MoveTo(hdc, rc.left, ry);
2791 LineTo(hdc, rc.right, ry);
2792 MoveTo(hdc, rx, rc.top);
2793 LineTo(hdc, rx, rc.bottom);
2794 SetROP2(hdc, iOldRop);
2795 ReleaseDC(lpgw->hWndGraph, hdc);
2798 /* Draw the ruler line to cursor position.
2801 DrawRulerLineTo (LPGW lpgw)
2806 long rx, ry, rlx, rly;
2808 if (!ruler.on || !ruler_lineto.on || ruler.x < 0 || ruler_lineto.x < 0)
2811 hdc = GetDC(lpgw->hWndGraph);
2812 GetClientRect(lpgw->hWndGraph, &rc);
2814 rx = MulDiv(ruler.x, rc.right - rc.left, lpgw->xmax);
2815 ry = rc.bottom - MulDiv(ruler.y, rc.bottom - rc.top, lpgw->ymax);
2816 rlx = MulDiv(ruler_lineto.x, rc.right - rc.left, lpgw->xmax);
2817 rly = rc.bottom - MulDiv(ruler_lineto.y, rc.bottom - rc.top, lpgw->ymax);
2819 iOldRop = SetROP2(hdc, R2_NOT);
2820 MoveTo(hdc, rx, ry);
2821 LineTo(hdc, rlx, rly);
2822 SetROP2(hdc, iOldRop);
2823 ReleaseDC(lpgw->hWndGraph, hdc);
2826 /* Draw the zoom box.
2829 DrawZoomBox (LPGW lpgw)
2832 long fx, fy, tx, ty, text_y;
2840 hdc = GetDC(lpgw->hWndGraph);
2841 GetClientRect(lpgw->hWndGraph, &rc);
2843 fx = MulDiv(zoombox.from.x, rc.right - rc.left, lpgw->xmax);
2844 fy = rc.bottom - MulDiv(zoombox.from.y, rc.bottom - rc.top, lpgw->ymax);
2845 tx = MulDiv(zoombox.to.x, rc.right - rc.left, lpgw->xmax);
2846 ty = rc.bottom - MulDiv(zoombox.to.y, rc.bottom - rc.top, lpgw->ymax);
2847 text_y = MulDiv(lpgw->vchar, rc.bottom - rc.top, lpgw->ymax);
2849 OldROP2 = SetROP2(hdc, R2_NOTXORPEN);
2850 OldPen = SelectObject(hdc, CreatePenIndirect(
2851 (lpgw->color ? lpgw->colorpen : lpgw->monopen) + 1));
2852 Rectangle(hdc, fx, fy, tx, ty);
2853 DeleteObject(SelectObject(hdc, OldPen));
2854 SetROP2(hdc, OldROP2);
2856 ReleaseDC(lpgw->hWndGraph, hdc);
2858 if (zoombox.text1) {
2859 char *separator = strchr(zoombox.text1, '\r');
2862 Draw_XOR_Text(lpgw, zoombox.text1, separator - zoombox.text1, fx, fy);
2863 Draw_XOR_Text(lpgw, separator + 1, strlen(separator + 1), fx, fy + text_y);
2865 Draw_XOR_Text(lpgw, zoombox.text1, strlen(zoombox.text1), fx, fy + lpgw->vchar / 2);
2868 if (zoombox.text2) {
2869 char *separator = strchr(zoombox.text2, '\r');
2872 Draw_XOR_Text(lpgw, zoombox.text2, separator - zoombox.text2, tx, ty);
2873 Draw_XOR_Text(lpgw, separator + 1, strlen(separator + 1), tx, ty + text_y);
2875 Draw_XOR_Text(lpgw, zoombox.text2, strlen(zoombox.text2), tx, ty + lpgw->vchar / 2);
2880 #endif /* USE_MOUSE */