#ifndef lint
static char *RCSid() { return RCSid("$Id: wgraph.c,v 1.67 2009/03/23 23:12:50 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
#include
#if WINVER >= 0x030a
# include
#endif
#ifndef __MSC__
# include
#endif
#include
#include
#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; ihtext)
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];
HDC hdc;
TEXTMETRIC metric;
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);
/* determine height of status line */
hdc = GetDC(lpgw->hWndGraph);
GetTextMetrics(hdc, &metric);
lpgw->statuslineheight = metric.tmHeight * 1.2;
ReleaseDC(lpgw->hWndGraph, hdc);
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)
{
/* Pass it through mouse handling to check for "bind Close" */
Wnd_exec_event(lpgw, (LPARAM)0, GE_reset, 0);
/* close window */
if (lpgw->hWndGraph)
DestroyWindow(lpgw->hWndGraph);
#ifndef WGP_CONSOLE
TextMessage();
#endif
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
}
/* shige */
void WDPROC
GraphChangeTitle(LPGW lpgw)
{
SetWindowText(lpgw->hWndGraph,lpgw->Title);
}
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; icolorbrush[i] = CreateSolidBrush(RGB(0,0,0));
} else {
lpgw->hapen = CreatePenIndirect((LOGPEN FAR *)&lpgw->colorpen[1]); /* axis */
lpgw->hbrush = CreateSolidBrush(lpgw->background);
for (i=0; icolorbrush[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; icolorbrush[i]);
/* delete brushes used for boxfilling (ULIG) */
if( brushes_initialized ) {
int i;
for( i=0; ibottom -= lpgw->statuslineheight; /* leave some room for the status line */
if (rect->bottom < rect->top) rect->bottom = rect->top;
}
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);
/* Bastian's proposed new fix */
MoveTo(hdc, ppt[0].x, ppt[0].y);
}
else if (polyi == 1)
/* Bastian's earlier fix */
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:
case FS_TRANSPARENT_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:
case FS_TRANSPARENT_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 / (double)WIN_PAL_COLORS, &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);
GetPlotRect(lpgw, &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 */
GetPlotRect(lpgw, &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; icolorpen[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; ilopnWidth.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; ilopnColor = 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... */
#ifndef DISABLE_SPACE_RAISES_CONSOLE
if (wParam == VK_SPACE) {
/* HBB 20001023: implement the ' 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;
}
#endif /* DISABLE_SPACE_RAISES_CONSOLE */
#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);
GetPlotRect(lpgw, &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
GetPlotRect(lpgw, &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);
GetPlotRect(lpgw, &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);
GetPlotRect(lpgw, &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);
GetPlotRect(lpgw, &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;
GetPlotRect(lpgw, &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 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;
GetPlotRect(lpgw, &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 text */
static void
DisplayStatusLine(LPGW lpgw)
{
RECT rc;
HDC hdc;
if (!sl_curr_text || !sl_curr_text[0])
return; /* no text to be displayed */
hdc = GetDC(lpgw->hWndGraph);
SetBkMode(hdc, OPAQUE);
GetClientRect(lpgw->hWndGraph, &rc);
TextOut(hdc, 0, rc.bottom - lpgw->statuslineheight, sl_curr_text, strlen(sl_curr_text));
ReleaseDC(lpgw->hWndGraph, hdc);
}
/*
* Update the status line by the text; erase the previous text
*/
static void
UpdateStatusLine (LPGW lpgw, const char text[])
{
RECT rc;
HDC hdc;
SIZE size, size2;
hdc = GetDC(lpgw->hWndGraph);
GetClientRect(lpgw->hWndGraph, &rc);
/* determine length of previous text */
size.cx = 0;
if (sl_curr_text) {
GetTextExtentPoint(hdc, sl_curr_text, strlen(sl_curr_text), &size);
free(sl_curr_text);
}
/* determine length of new text */
if (!text || !*text) {
sl_curr_text = 0;
size2.cx = 0;
} else {
sl_curr_text = strdup(text);
GetTextExtentPoint(hdc, sl_curr_text, strlen(sl_curr_text), &size2);
/* overwrite previous text */
SetBkMode(hdc, OPAQUE);
TextOut(hdc, 0, rc.bottom - lpgw->statuslineheight, sl_curr_text, strlen(sl_curr_text));
}
/* erase the rest */
if (size.cx > size2.cx) {
rc.left = size2.cx;
rc.right = size.cx;
rc.top = rc.bottom - lpgw->statuslineheight;
FillRect(hdc, &rc, (HBRUSH) (COLOR_WINDOW+1));
}
ReleaseDC(lpgw->hWndGraph, hdc);
}
/* 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);
GetPlotRect(lpgw, &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);
GetPlotRect(lpgw, &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);
GetPlotRect(lpgw, &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 */