home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
vos2-121.zip
/
v
/
srcos2
/
vwindc.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1999-03-03
|
43KB
|
1,310 lines
//===============================================================
// vWinDC - Windows Base DC
//
// Copyright (C) 1995,1996,1997,1998 Bruce E. Wampler
//
// This file is part of the V C++ GUI Framework, and is covered
// under the terms of the GNU Library General Public License,
// Version 2. This library has NO WARRANTY. See the source file
// vapp.cxx for more complete information about license terms.
//===============================================================
#include <v/vos2.h> // for OS/2 stuff
extern "C"
{
#include <math.h>
}
#include <v/vwindc.h>
#include <v/vmemdc.h>
#include <v/vapp.h> // need access to the app
#include <v/vcanvas.h> // our own canvas widget
#include <v/vicon.h>
//-----------------------------------------------------------------------
//================>>> vWinDC::vWinDC <<<========================
vWinDC::vWinDC()
{
SysDebug(Constructor,"vWinDC::vWinDC() constructor\n")
_font = theApp->GetDefaultFont(); // Use the default fixed font by default!
_hdc = 0;
// set some defaults
_canvasBG = SETRGB(255,255,255); // white
_hpen = _pen.GetHPEN(); // Get the default pen
_hbrush = _brush.GetHBRUSH(); // Get the default brush
// _hpen = 0; // no pen for now
// _hbrush = 0; // no brush for now
_isPrinterDC = 0; // Assume not printer
}
//================>>> vWinDC::~vWinDC <<<========================
vWinDC::~vWinDC()
{
SysDebug(Destructor,"vWinDC::~vWinDC() destructor\n")
}
//================>>> vWinDC::CopyFromMemoryDC <<<=======================
void vWinDC::CopyFromMemoryDC(vMemoryDC* vmemdc, int destX, int destY,
int srcX, int srcY, int srcW, int srcH) // V:1.13
{
BeginPaint();
int ch = vmemdc->_physHeight;
int cw = vmemdc->_physWidth;
int cx = 0;
int cy = 0;
if (srcX > 0) // Fixed: 10/11/96
cx = srcX;
if (srcY > 0)
cy = srcY;
if (srcW > 0)
cw = srcW;
if (srcH > 0)
ch = srcH;
if ((cw + cx) > vmemdc->_physWidth && _physWidth > 0) // only copy what will fi
cw = vmemdc->_physWidth - cx;
if ((ch + cy) > vmemdc->_physHeight && _physHeight > 0)
ch = vmemdc->_physHeight - cy;
if ((cw + destX) > _physWidth && _physWidth > 0)
cw = _physWidth - destX;
if ((ch + destY) > _physHeight && _physHeight > 0)
ch = _physHeight - destY;
if (cw > _physWidth && _physWidth > 0) // only copy what will fit
cw = _physWidth;
if (ch > _physHeight && _physHeight > 0)
ch = _physHeight;
POINTL cPoints[3] = {destX, destY, // lower left targ
destX+cw, destY+ch, // upper right targ
cx, cy }; // lower left src
HPS memDC = vmemdc->_hdc;
SysDebug1(Constructor,"vWinDC::CopyFromMemoryDC() memDC = %d\n", memDC)
#define BITBLT
#ifdef BITBLT
// we need to convert the target coords which are in World Space
// to Device Space since GpiBitBlt expects device coords
// GpiConvert(_hdc, CVTC_WORLD, CVTC_DEVICE, 1, &cPoints[0]);
// GpiConvert(_hdc, CVTC_WORLD, CVTC_DEVICE, 1, &cPoints[1]);
MapToOS2(&cPoints[0]);
MapToOS2(&cPoints[1]);
GpiBitBlt(_hdc, memDC, 3, cPoints, ROP_SRCCOPY, BBO_IGNORE);
#else
// register COLORREF color, cout;
register ULONG color, cout;
POINTL cPoint;
LINEBUNDLE Pen;
for (int row = 0 ; row < ch ; ++row)
for (int col = 0 ; col < cw ; ++col)
{
cPoint.x = row;
cPoint.y = col;
MapToOS2(&cPoint);
color = GpiQueryPel (memDC, cPoint);
cout = GpiQueryAttrs (_hdc, PRIM_LINE, LBB_COLOR, &Pen);
Pen.lColor = color;
GpiSetAttrs (_hdc, PRIM_LINE, LBB_COLOR, 0, &Pen);
GpiSetPel (_hdc, cPoint);
Pen.lColor = cout;
GpiSetAttrs (_hdc, PRIM_LINE, LBB_COLOR, 0, &Pen);
}
#endif
EndPaint();
}
//====================>>> vWinDC::DrawIcon <<<==========================
void vWinDC::DrawIcon(int x, int y, VCONST vIcon& icon)
{
BeginPaint();
int xx = Scale(x+_tx);
int yy = Scale(y+_ty);
// Now, draw the icon
HBITMAP hbm = icon.GetIconHBM(_hdc); // get the bitmap
SysDebug1(Build,"vWinDC::DrawIcon() hbm=%u\n", hbm)
// Now BitBlt the icon BMP into the drawing canvas, leaving
// background untouched, and the pen color to draw 1 bits
// (Note: Target is in World Coords, and Source is in Device Coords)
POINTL cPoints[4] = {xx, yy, // lower left targ
xx+icon.width-1, yy+icon.height-1, // upper right targ
0, 0, // lower left src
icon.width, icon.height}; // upper right src
// Map to OS/2 coord system before calling
// (only need to map World Coords)
MapToOS2(&cPoints[0]);
MapToOS2(&cPoints[1]);
// set ownership of bitmap to canvas
HBITMAP hbmr = GpiSetBitmap(_hdc, hbm);
// now reset the original bitmap if there was one
GpiSetBitmap(_hdc, hbmr);
if (icon.iType == Transparent)
{
// for transparent icons, we set the canvas background
// color to the icon transparent color and then set
// the background mix mode to BM_SRCTRANSPARENT, OS/2
// takes care of the rest (compare with the windoze code! :-) )
IMAGEBUNDLE himage;
himage.lColor = _pen.GetColor().pixel(); // use pen color
himage.lBackColor = icon.GetTransparentColor();
GpiSetAttrs(_hdc, PRIM_IMAGE, IBB_BACK_COLOR | IBB_COLOR, 0, &himage);
GpiSetBackMix(_hdc,BM_SRCTRANSPARENT);
// blit the image to the canvas
GpiWCBitBlt(_hdc, hbm, 4, cPoints, ROP_SRCCOPY, BBO_IGNORE);
// restore defaults
himage.lColor = _pen.GetColor().pixel(); // use pen color
himage.lBackColor = _canvasBG; // use background color
GpiSetAttrs(_hdc, PRIM_IMAGE, IBB_BACK_COLOR | IBB_COLOR, 0, &himage);
GpiSetBackMix(_hdc,BM_DEFAULT);
}
else
{
// for monochrome bitmaps, we can control the
// target colors using the image bundle
IMAGEBUNDLE himage;
himage.lColor = _pen.GetColor().pixel(); // use pen color
himage.lBackColor = _canvasBG; // use background color
GpiSetAttrs(_hdc, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR, 0, &himage);
// blit the image to the canvas
GpiWCBitBlt(_hdc, hbm, 4, cPoints, ROP_SRCCOPY, BBO_IGNORE);
}
EndPaint();
}
//#define DRAWARC
#ifdef DRAWARC
//====================>>> vWinDC::DrawArc <<<==========================
// This function is experimental
// (xx1, yy1) start of arc
// (xx2, yy2) end of arc
// (xxc, yyc) centre of arc
void vWinDC::DrawArc(int xx1, int yy1, int xx2, int yy2,
int xxc, int yyc)
{
double dx = xx1 - xxc;
double dy = yy1 - yyc;
double radius = sqrt(dx * dx + dy * dy);
const double PIx2 = 6.283185;
double angle1, angle2; // angles of points wrt center
BeginPaint();
if (xx1 == xx2 && yy1 == yy2)
{
angle1 = 0.0;
angle2 = 360.0;
}
else if (radius == 0.0)
angle1 = angle2 = 0.0;
else
{
if (xx1 - xxc == 0)
{
if (yy1 - yyc < 0)
angle1 = 90.0;
else
angle1 = -90.0;
}
else
angle1 = -atan2 ((double) (yy1 - yyc), (double) (xx1 - xxc)) * 360.0 / PIx2;
if (xx2 - xxc == 0)
{
if (yy2 - yyc < 0)
angle2 = 90.0;
else
angle2 = -90.0;
}
else
angle2 = -atan2 ((double) (yy2 - yyc), (double) (xx2 - xxc)) * 360.0 / PIx2;
}
POINTL posc = {xxc, yyc};
POINTL pos1 = {xx1, yy1};
MapToOS2(&posc);
MapToOS2(&pos1);
ARCPARAMS arc;
double ri, Scale;
ri = floor(radius); // radius always >= 0
Scale = radius/ri;
arc.lP = (LONG) ri;
arc.lQ = (LONG) ri;
arc.lR = 0L;
arc.lS = 0L;
GpiSetArcParams(_hdc, &arc);
// compute start and sweep angles (must be >= 0)
double start = angle1;
double sweep = fabs(angle2 - angle1);
while (start < 0)
start += 360;
// set pen attributes and draw arc
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH, 0, _hpen);
GpiMove(_hdc, &pos1);
GpiPartialArc(_hdc, &posc, DBLTOFX(Scale), DBLTOFX(start), DBLTOFX(sweep));
EndPaint();
}
#endif
//====================>>> vWinDC::DrawEllipse <<<==========================
// (x,y) lower left corner ellipse bounding box
void vWinDC::DrawEllipse(int x, int y, int width, int height)
{
if (height == 0 || width == 0)
return;
BeginPaint();
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
int x1 = Scale(x+_tx);
int y1 = Scale(y+_ty);
int width1 = Scale(width-1);
int height1 = Scale(height-1);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
_hbrush = _brush.GetHBRUSH();
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
// set arc params at 2x scale
ARCPARAMS arc;
arc.lP = width1;
arc.lQ = height1;
arc.lR = 0;
arc.lS = 0;
GpiSetArcParams(_hdc , &arc);
// compute center of ellipse
POINTL posc = {x1+(width1/2), y1+(height1/2)};
MapToOS2(&posc);
if (_hpen->usType == LINETYPE_SOLID)
{
GpiSetCurrentPosition (_hdc, &posc);
GpiFullArc (_hdc, DRO_FILL, MAKEFIXED(0,0x8000)); // scale by 1/2
GpiBeginPath(_hdc, 1L);
GpiFullArc (_hdc, DRO_OUTLINE, MAKEFIXED(0,0x8000)); // scale by 1/2
GpiEndPath(_hdc);
AREABUNDLE hlinebrush;
hlinebrush.lColor = _hpen->lColor;
hlinebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &hlinebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
}
else
{
GpiSetCurrentPosition (_hdc, &posc); // move to start point
GpiFullArc (_hdc, DRO_OUTLINEFILL, MAKEFIXED(0,0x8000)); // scale by 1/2
}
EndPaint();
}
//====================>>> vWinDC::DrawLine <<<==========================
void vWinDC::DrawLine(int x, int y, int xend, int yend)
{
BeginPaint();
// Draw a line from x,y to xend,yend
// This method has the typical sequence of code for drawing. All other
// drawing methods are modeled using this approach
// First, do the required scaling
int xx = Scale(x+_tx);
int yy = Scale(y+_ty);
int xe = Scale(xend+_tx);
int ye = Scale(yend+_ty);
// OS/2 can define a presentation space when the window
// is created, and we can use it until the window is
// destroyed. This saves us from needing to constantly
// get and destroy the DC (unlike the windows code) while the user program is
// drawing stuff interactively (usually in response to mouse input).
// For Redraw, the canvas redraw event will issue a WinBeginPaint
// and WinEndPaint, which will bracket all drawing. We feed
// WinBeginPaint our presentation space for the window so it
// doesn't create a separate cached micro-PS like it normally would do.
// This allows us to retain any attributes of the PS for the
// life of the window.
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
// Shapes will do a similar sequence for brushes as well
// Now the code to actually do the drawing
POINTL poss = {xx, yy}; // start point
POINTL pose = {xe, ye}; // end point
MapToOS2(&poss);
MapToOS2(&pose);
GpiBeginPath(_hdc, 1L);
GpiSetCurrentPosition (_hdc, &poss);
GpiLine (_hdc , &pose);
GpiEndPath(_hdc);
// it turns out that to get a line of variable thickness it must be
// stroked. However, such lines do not support linetypes other
// than type solid. So to get dots and dashed lines we need to
// use outlines, but then the width is ignored (dohh!).
// This behavior is also true for windows though,
// so I'm not going to worry about it. The major pain though is
// that the stroked line color is set to the area fill color, which
// is why I have to do the nonsense with the hlinebrush.
if (_hpen->usType == LINETYPE_SOLID)
{
// for Geometric lines, the fill color is used (what a debacle!)
AREABUNDLE hlinebrush;
hlinebrush.lColor = _hpen->lColor; // for stroked lines
hlinebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &hlinebrush);
GpiStrokePath(_hdc, 1L, 0L); // solid lines can be stroked
}
else
GpiOutlinePath(_hdc, 1L, 0L); // other lines need to be outlined
EndPaint();
}
//====================>>> vWinDC::DrawLines <<<==========================
void vWinDC::DrawLines(vLine* lineList, int count)
{
if (count < 1 || lineList == 0)
return;
BeginPaint();
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
vLine* lp = lineList ;
POINTL poss; // start point
POINTL pose; // end point
GpiBeginPath(_hdc, 1L);
for (int num = 0 ; num < count ; ++lp, ++num)
{
poss.x = Scale(lp->x+_tx);
poss.y = Scale(lp->y+_ty);
pose.x = Scale(lp->xend+_tx);
pose.y = Scale(lp->yend+_ty);
MapToOS2(&poss);
MapToOS2(&pose);
GpiSetCurrentPosition (_hdc, &poss);
GpiLine (_hdc , &pose);
}
GpiEndPath(_hdc);
if (_hpen->usType == LINETYPE_SOLID)
{
// for Geometric lines, the fill color is used (what a debacle!)
AREABUNDLE linebrush;
linebrush.lColor = _hpen->lColor; // for stroked lines
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // solid lines can be stroked
}
else
GpiOutlinePath(_hdc, 1L, 0L); // other lines need to be outlined
EndPaint();
}
//==================>>> vWinDC::DrawColorPoints <<<======================
void vWinDC::DrawColorPoints(int x, int y, int nPoints, vColor* pointList)
{
// Draw a bunch of color points.
if (nPoints < 1 || pointList == 0)
return;
BeginPaint();
int xx = Scale(x+_tx);
int yy = Scale(y+_ty);
if (yy < 0)
return; // row not displayed
#define BITBLT
#ifdef BITBLT
// performance was bad with GpiSetPel so do this with
// a line bitmap blitted to the canvas
// bitmap data structures
PVBYTE bmbits;
PBITMAPINFO2 pbmi;
// build a memory PS compatible with calling PS
HDC DevCxtComp = GpiQueryDevice(_hdc);
HDC DevCxtMem = DevOpenDC(theApp->AppHab(), OD_MEMORY, "*", 0L, NULL, DevCxtComp);
SIZEL size = {nPoints, 1};
HPS hdcMem = GpiCreatePS (theApp->AppHab(), DevCxtMem, &size,
PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
// set the PS to RGB mode
GpiCreateLogColorTable(hdcMem, 0L, LCOLF_RGB, 0L, 0L, NULL);
// First, create a blank bitmap compatible with the
// current context that is size of bitmap.
BITMAPINFOHEADER2 bmih;
memset(&bmih, 0, sizeof(BITMAPINFOHEADER2));
bmih.cbFix = sizeof(BITMAPINFOHEADER2);
bmih.cx = nPoints;
bmih.cy = 1;
bmih.ulColorEncoding = BCE_RGB;
bmih.cPlanes = 1; // always 1 for OS/2
bmih.cBitCount = 24; // bits of color per pixel
HBITMAP hbm = GpiCreateBitmap(hdcMem, &bmih, 0L, NULL, NULL);
// now we need to load the bitmap with data by associating
// with a memory PS and setting each pel
GpiSetBitmap(hdcMem, hbm);
// We first need to create the bitmapinfo structure
// (a color table is not needed for 24 bit bitmaps)
// allocate space for header
pbmi=(PBITMAPINFO2) new VBYTE [sizeof(BITMAPINFOHEADER2)];
// copy the header to the bitmap info structure
memcpy(pbmi, &bmih, sizeof(BITMAPINFOHEADER2));
pbmi->cclrUsed = 0 ; // no color table needed
pbmi->cbImage = nPoints*3; // image size (bytes)
// Now need to copy pixel data over from pointList
int rowwords = ((nPoints*3)+3) / 4; // number of words (for OS/2 bitmap data)
bmbits = new VBYTE[rowwords*4]; // allocate space
PVBYTE to = bmbits; // set to first pixel
int col;
for (col = 0 ; col < nPoints ; ++col) // do each V pixel per row
{
// R G B
*to++ = pointList[col].r();
*to++ = pointList[col].g();
*to++ = pointList[col].b();
}
// Finished a row, need to pad to a word boundary
while ( (col*3)<(4*rowwords) )
{
*to++ = 0x00; // pad with 0's
col++;
}
// Now, create the bitmap
GpiSetBitmapBits(hdcMem, 0L, pbmi->cy, (PBYTE) bmbits, pbmi);
// free up resources and we are done
delete [] bmbits;
delete [] pbmi;
GpiSetBitmap (hdcMem, NULLHANDLE);
GpiAssociate (hdcMem, NULLHANDLE);
GpiDestroyPS (hdcMem);
DevCloseDC (DevCxtMem);
POINTL cPoints[4] = {xx, yy, // lower left targ
xx+nPoints-1, yy, // upper right targ
0, 0, // lower left src
nPoints, 1}; // upper right src
MapToOS2(&cPoints[0]);
MapToOS2(&cPoints[1]);
// set ownership of bitmap to canvas
HBITMAP hbmr = GpiSetBitmap(_hdc, hbm);
// now reset the original bitmap if there was one
GpiSetBitmap(_hdc, hbmr);
// blit the image to the canvas
GpiWCBitBlt(_hdc, hbm, 4, cPoints, ROP_SRCCOPY, BBO_IGNORE);
// destroy the bitmap
if (hbm != 0)
GpiDeleteBitmap(hbm);
#else
// this is the slow but straightforward way using GpiSetPel
LINEBUNDLE pen;
POINTL Point, os2Point;
Point.x = xx;
Point.y = yy;
if (xx < 0) // need to check every time
{
for (int ix = 0 ; ix < nPoints ; ++ix)
{
if (xx+ix < 0)
continue; // this one not displayed
pen.lColor = pointList[ix].pixel();
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, &pen);
Point.x = xx+ix;
os2Point.x = Point.x;
os2Point.y = Point.y;
MapToOS2(&os2Point);
GpiSetPel (_hdc, &os2Point);
}
}
else // don't need xx check
{
for (int ix = 0 ; ix < nPoints ; ++ix)
{
pen.lColor = pointList[ix].pixel();
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, &pen);
Point.x = xx+ix;
os2Point.x = Point.x;
os2Point.y = Point.y;
MapToOS2(&os2Point);
GpiSetPel (_hdc, &os2Point);
}
}
#endif
EndPaint();
}
//==================>>> vWinDC::DrawPoint <<<======================
void vWinDC::DrawPoint(int x, int y)
{
BeginPaint();
// First, do the required scaling
int xx = Scale(x+_tx);
int yy = Scale(y+_ty);
POINTL Point;
Point.x = xx;
Point.y = yy;
MapToOS2(&Point);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, _hpen);
// Now the code to actually do the drawing
GpiSetPel (_hdc, &Point);
EndPaint();
}
//==================>>> vWinDC::DrawPoints <<<======================
void vWinDC::DrawPoints(vPoint* pointList, int count)
{
POINTL Point;
if (count < 1 || pointList == 0)
return;
BeginPaint();
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, _hpen);
// Now the code to actually do the drawing
vPoint* pl = pointList ;
for (int num = 0 ; num < count ; ++pl, ++num)
{
Point.x = Scale(pl->x+_tx);
Point.y = Scale(pl->y+_ty);
MapToOS2(&Point);
GpiSetPel (_hdc, &Point);
}
EndPaint();
}
//==================>>> vWinDC::DrawPolygon <<<======================
void vWinDC::DrawPolygon(int n, vPoint points[], int fillStyle)
{
// draw a complete polygon (starting point specified twice!)
BeginPaint();
if (_hasScale || _tx != 0 || _ty != 0) // If we have to scale, then we need to copy
{
for (int i = 0; i < n; i++)
{
points[i].x = ((points[i].x+_tx) * _Mult) / _Div; // scale
points[i].y = ((points[i].y+_ty) * _Mult) / _Div;
}
}
// we need to be careful here, since we are actually changing the
// data in the users own structure here. We will need to put things
// back the way they were when we are done!
for (int i = 0; i < n; i++)
{
MapToOS2(&points[i]);
}
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
_hbrush = _brush.GetHBRUSH();
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
// fill the outline
GpiBeginPath(_hdc, 1L);
GpiSetCurrentPosition (_hdc , &points[0]); // move to first point
GpiPolyLine(_hdc, n-1, &points[1]); // draw the outline polygon
GpiEndPath(_hdc);
GpiFillPath(_hdc, 1L, (fillStyle == vAlternate) ? FPATH_ALTERNATE : FPATH_WINDING);
// draw the outline
GpiBeginPath(_hdc, 1L);
GpiSetCurrentPosition (_hdc , &points[0]); // move to last point
GpiPolyLine(_hdc, n-1, &points[1]); // draw the outline polygon
GpiEndPath(_hdc);
if (_hpen->usType == LINETYPE_SOLID)
{
// for Geometric lines, the fill color is used (what a debacle!)
AREABUNDLE linebrush;
linebrush.lColor = _hpen->lColor; // for stroked lines
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // solid lines can be stroked
}
else
GpiOutlinePath(_hdc, 1L, 0L); // other lines need to be outlined
// restore the user's points data back to the original values
for (i = 0; i < n; i++)
{
MapFromOS2(&points[i]);
}
EndPaint();
}
//==================>>> vWinDC::DrawRectangle <<<======================
void vWinDC::DrawRectangle(int x, int y, int width, int height)
{
if (height == 0 || width == 0)
return;
BeginPaint();
POINTL poss, pose;
AREABUNDLE linebrush;
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
poss.x = Scale(x+_tx);
poss.y = Scale(y+_ty);
pose.x = Scale(x+width-1+_tx);
pose.y = Scale(y+height-1+_ty);
MapToOS2(&poss);
MapToOS2(&pose);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
_hbrush = _brush.GetHBRUSH();
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
if (_hpen->usType == LINETYPE_SOLID)
{
GpiSetCurrentPosition (_hdc, &poss);
GpiBox(_hdc, DRO_FILL, &pose, 0, 0);
GpiBeginPath(_hdc, 1L);
GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
GpiEndPath(_hdc);
linebrush.lColor = _hpen->lColor;
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
}
else
{
GpiSetCurrentPosition (_hdc, &poss); // move to start point
GpiBox(_hdc, DRO_OUTLINEFILL, &pose, 0, 0);
}
EndPaint();
}
//==================>>> vWinDC::DrawRectangles <<<======================
void vWinDC::DrawRectangles(vRect* rectList, int count)
{
if (count < 1 || !rectList)
return;
POINTL poss, pose;
BeginPaint();
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
_hbrush = _brush.GetHBRUSH();
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
vRect* rp = rectList ;
for (int num=0 ; num < count ; ++rp, ++num)
{
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
poss.x = Scale(rp->x+_tx);
poss.y = Scale(rp->y+_ty);
pose.x = Scale(rp->x+rp->w-1+_tx);
pose.y = Scale(rp->y+rp->h-1+_ty);
if (rp->h == 0 && rp->w == 0)
continue;
MapToOS2(&poss);
MapToOS2(&pose);
// if solid line then we can support variable line widths
if (_hpen->usType == LINETYPE_SOLID)
{
GpiSetCurrentPosition (_hdc, &poss);
GpiBox(_hdc, DRO_FILL, &pose, 0, 0);
GpiBeginPath(_hdc, 1L);
GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
GpiEndPath(_hdc);
AREABUNDLE linebrush;
linebrush.lColor = _hpen->lColor;
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
// don't forget to reset the brush back to what it was
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
}
else
// otherwise, we only support single pel width lines
{
GpiSetCurrentPosition (_hdc, &poss); // move to start point
GpiBox(_hdc, DRO_OUTLINEFILL, &pose, 0, 0);
}
}
EndPaint();
}
//================>>> vWinDC::DrawRoundedRectangle <<<===================
void vWinDC::DrawRoundedRectangle(int x, int y,
int width, int height, int radius)
{
if (height == 0 || width == 0)
return;
BeginPaint();
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
POINTL poss, pose;
poss.x = Scale(x+_tx);
poss.y = Scale(y+_ty);
pose.x = Scale(x+width-1+_tx);
pose.y = Scale(y+height-1+_ty);
MapToOS2(&poss);
MapToOS2(&pose);
int r;
if (radius < 0)
{
// Negative radius means divide average of height and width
// by this
r = (Scale(width+height)/(-2 * radius));
}
else
r = Scale(radius);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
_hbrush = _brush.GetHBRUSH();
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
if (_hpen->usType == LINETYPE_SOLID)
{
GpiSetCurrentPosition (_hdc, &poss);
GpiBox(_hdc, DRO_FILL, &pose, 2*r, 2*r);
GpiBeginPath(_hdc, 1L);
GpiBox(_hdc, DRO_OUTLINE, &pose, 2*r, 2*r);
GpiEndPath(_hdc);
AREABUNDLE linebrush;
linebrush.lColor = _hpen->lColor;
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
}
else
{
GpiSetCurrentPosition (_hdc, &poss); // move to start point
GpiBox(_hdc, DRO_OUTLINEFILL, &pose, 2*r, 2*r);
}
EndPaint();
}
//==================>>> vWinDC::DrawRubberEllipse<<<===================
void vWinDC::DrawRubberEllipse(int x, int y, int width, int height)
{
if (height == 0 || width == 0)
return;
BeginPaint();
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
int x1 = Scale(x+_tx);
int y1 = Scale(y+_ty);
int width1 = Scale(width-1);
int height1 = Scale(height-1);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH, 0, _hpen);
// set arc params at 2x scale
ARCPARAMS arc;
arc.lP = width1;
arc.lQ = height1;
arc.lR = 0;
arc.lS = 0;
GpiSetArcParams(_hdc , &arc);
// compute center of ellipse
POINTL posc = {x1+(width1/2), y1+(height1/2)};
MapToOS2(&posc);
if (_hpen->usType == LINETYPE_SOLID)
{
// save the original brush values
LONG orgColor = _hbrush->lColor;
USHORT orgMix = _hbrush->usMixMode;
GpiSetCurrentPosition (_hdc, &posc);
GpiBeginPath(_hdc, 1L);
GpiFullArc (_hdc, DRO_OUTLINE, MAKEFIXED(0,0x8000)); // scale by 1/2
GpiEndPath(_hdc);
AREABUNDLE linebrush;
linebrush.lColor = SETRGB(255,255,255);
linebrush.usMixMode = FM_XOR; // draw in XOR
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
// restore the original brush values
linebrush.lColor = orgColor;
linebrush.usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR, 0, &linebrush);
}
else
{
// save the original pen values
LONG orgColor = _hpen->lColor;
USHORT orgMix = _hpen->usMixMode;
// change pen for rubber line
_hpen->lColor = SETRGB(255,255,255); // set pen color to white
_hpen->usMixMode = FM_XOR; // draw in XOR
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
GpiFullArc (_hdc, DRO_OUTLINE, MAKEFIXED(0,0x8000)); // scale by 1/2
// restore the original pen values
_hpen->lColor = orgColor;
_hpen->usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
EndPaint();
}
}
//==================>>> vWinDC::DrawRubberLine <<<======================
void vWinDC::DrawRubberLine(int x, int y, int xend, int yend)
{
BeginPaint();
// Draw a rubber-band line from x,y to xend,yend. Redrawing
// over the same with will erase it.
int xx = Scale(x+_tx);
int yy = Scale(y+_ty);
int xe = Scale(xend+_tx);
int ye = Scale(yend+_ty);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH, 0, _hpen);
// Shapes will do a similar sequence for brushes as well
// Now the code to actually do the drawing
POINTL poss = {xx, yy}; // start point
POINTL pose = {xe, ye}; // end point
MapToOS2(&poss);
MapToOS2(&pose);
if (_hpen->usType == LINETYPE_SOLID)
{
// save the original brush values
LONG orgColor = _hbrush->lColor;
USHORT orgMix = _hbrush->usMixMode;
GpiBeginPath(_hdc, 1L);
GpiSetCurrentPosition (_hdc, &poss);
GpiLine (_hdc , &pose);
GpiEndPath(_hdc);
AREABUNDLE linebrush;
linebrush.lColor = SETRGB(255,255,255);
linebrush.usMixMode = FM_XOR; // draw in XOR
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
// restore the original brush values
linebrush.lColor = orgColor;
linebrush.usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR, 0, &linebrush);
}
else
{
// save the original pen values
LONG orgColor = _hpen->lColor;
USHORT orgMix = _hpen->usMixMode;
// change pen for rubber line
_hpen->lColor = SETRGB(255,255,255); // set pen color to white
_hpen->usMixMode = FM_XOR; // draw in XOR
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
GpiSetCurrentPosition (_hdc, &poss);
GpiLine (_hdc , &pose);
// restore the original pen values
_hpen->lColor = orgColor;
_hpen->usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
}
EndPaint();
}
//==================>>> vWinDC::DrawRubberPoint <<<======================
void vWinDC::DrawRubberPoint(int x, int y)
{
BeginPaint();
// First, do the required scaling
int xx = Scale(x+_tx);
int yy = Scale(y+_ty);
POINTL Point;
Point.x = xx;
Point.y = yy;
MapToOS2(&Point);
_hpen = _pen.GetHPEN(); // Get the pen
// save the original pen values
LONG orgColor = _hpen->lColor;
USHORT orgMix = _hpen->usMixMode;
// change pen for rubber line
_hpen->lColor = SETRGB(255,255,255); // set pen color to white
_hpen->usMixMode = FM_XOR; // draw in XOR
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
GpiSetPel (_hdc, &Point);
// restore the original pen values
_hpen->lColor = orgColor;
_hpen->usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
EndPaint();
}
//==================>>> vWinDC::DrawRubberRectangle <<<==================
void vWinDC::DrawRubberRectangle(int x, int y, int width, int height)
{
if (height == 0 || width == 0)
return;
BeginPaint();
POINTL poss, pose;
AREABUNDLE linebrush;
// coords for GPI functions are inclusive/inclusive
// right = left + width -1
// top = bottom + height -1
poss.x = Scale(x+_tx);
poss.y = Scale(y+_ty);
pose.x = Scale(x+width-1+_tx);
pose.y = Scale(y+height-1+_ty);
MapToOS2(&poss);
MapToOS2(&pose);
_hpen = _pen.GetHPEN(); // Get the pen
GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
0, _hpen);
if (_hpen->usType == LINETYPE_SOLID)
{
// save the original brush values
LONG orgColor = _hbrush->lColor;
USHORT orgMix = _hbrush->usMixMode;
GpiSetCurrentPosition (_hdc, &poss);
GpiBeginPath(_hdc, 1L);
GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
GpiEndPath(_hdc);
linebrush.lColor = SETRGB(255,255,255);
linebrush.usMixMode = FM_XOR; // draw in XOR
linebrush.usSymbol = PATSYM_SOLID;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
GpiStrokePath(_hdc, 1L, 0L); // thick lines need to be stroked
// restore the original brush values
linebrush.lColor = orgColor;
linebrush.usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR, 0, &linebrush);
}
else
{
// save the original pen values
LONG orgColor = _hpen->lColor;
USHORT orgMix = _hpen->usMixMode;
// change pen for rubber line
_hpen->lColor = SETRGB(255,255,255); // set pen color to white
_hpen->usMixMode = FM_XOR; // draw in XOR
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
GpiSetCurrentPosition (_hdc, &poss); // move to start point
GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
// restore the original pen values
_hpen->lColor = orgColor;
_hpen->usMixMode = orgMix;
GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
}
EndPaint();
}
//=====================>>> vWinDC::DrawAttrText <<<==========================
void vWinDC::DrawAttrText(int x, int y, VCONST char* text, const ChrAttr attr)
{
// Draw text with attributes at given x, y.
static int mapColor[] =
{
vC_Black, vC_Blue, vC_Green, vC_Cyan,
vC_Red, vC_Magenta, vC_Yellow, vC_White,
vC_DarkGray, vC_DimBlue, vC_DimGreen, vC_DimCyan,
vC_DimRed, vC_DimMagenta, vC_DimYellow, vC_MedGray
};
BeginPaint();
POINTL poss;
poss.x = Scale(x+_tx);
poss.y = Scale(y+_ty);
MapToOS2(&poss);
_font.LoadFont(_hdc); // need to setup font!
_htext = _font.GetHFONT();
_htext->usTextAlign = TA_BOTTOM | TA_LEFT;
// we get the charbundle to control font color
// we use the current pen to define text colors
ULONG orgfgc = _pen.GetColor().pixel();
ULONG orgbgc = _canvasBG;
if (attr & ChHighlight)
{
_htext->usBackMixMode = BM_OVERPAINT;
_htext->lBackColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_HILITEBACKGROUND, 0L);
_htext->lColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_HILITEFOREGROUND, 0L);
_htext->usTextAlign = TA_BOTTOM | TA_LEFT;
}
else if (attr & ChReverse)
{
// default backmixmode is BM_LEAVEALONE, the windows version of V
// overpaints background so we will do accordingly
_htext->usBackMixMode = BM_OVERPAINT;
_htext->lBackColor = orgfgc;
_htext->lColor = orgbgc;
_htext->usTextAlign = TA_BOTTOM | TA_LEFT;
}
else
{
_htext->usBackMixMode = BM_OVERPAINT;
// _htext->usBackMixMode = BM_LEAVEALONE;
_htext->lBackColor = orgbgc;
_htext->lColor = orgfgc;
_htext->usTextAlign = TA_BOTTOM | TA_LEFT;
}
if (attr & 0xF0) // A color overide
{
_htext->lColor = vStdColors[ mapColor[((attr & 0xF0) >> 4)] ].pixel();
}
GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_BACK_MIX_MODE | CBB_COLOR | CBB_TEXT_ALIGN,
0, _htext);
// Now the code to actually do the drawing
if (_isPrinterDC)
{
GpiCharStringAt (_hdc, &poss, strlen(text), text);
}
else
{
// need to turn off cursor during screen update
GpiCharStringAt (_hdc, &poss, strlen(text), text);
}
if ((attr & ChReverse) || (attr & ChHighlight))
{
_htext->usBackMixMode = BM_LEAVEALONE;
_htext->lBackColor = orgbgc;
_htext->lColor = orgfgc;
GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_BACK_MIX_MODE | CBB_COLOR, 0, _htext);
}
else
{
_htext->usBackMixMode = BM_LEAVEALONE;
GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_MIX_MODE, 0, _htext);
}
EndPaint();
}
//=====================>>> vWinDC::DrawText <<<==========================
void vWinDC::DrawText(int x, int y, VCONST char* text)
{
// simple draw text at given x, y
// First, do the required scaling
if (!text || !*text)
return;
BeginPaint();
POINTL poss;
poss.x = Scale(x+_tx);
poss.y = Scale(y+_ty);
MapToOS2(&poss);
_font.LoadFont(_hdc); // need to setup font!
_htext = _font.GetHFONT();
_htext->lColor = _pen.GetColor().pixel();
_htext->lBackColor = _canvasBG;
_htext->usBackMixMode = BM_OVERPAINT;
_htext->usTextAlign = TA_BOTTOM | TA_LEFT;
GpiSetAttrs(_hdc, PRIM_CHAR,
CBB_BACK_COLOR | CBB_COLOR | CBB_TEXT_ALIGN | CBB_BACK_MIX_MODE, 0, _htext);
// Now the code to actually do the drawing
// We fudge the y position to accomodate the
// model transform that puts the origin at the top left.
if (_isPrinterDC)
{
// poss.y = poss.y + _font.GetPointSize();
GpiCharStringAt (_hdc, &poss, strlen(text), text);
}
else
{
// need to turn off cursor during screen update
GpiCharStringAt (_hdc, &poss, strlen(text), text);
}
// restore to deafult mix mode
_htext->usBackMixMode = BM_LEAVEALONE;
GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_MIX_MODE, 0, _htext);
EndPaint();
}
//=====================>>> vWinDC::SetBrush <<<============================
void vWinDC::SetBrush(VCONST vBrush& brush)
{
_brush = brush;
}
//=====================>>> vWinDC::SetPen <<<============================
void vWinDC::SetPen(VCONST vPen& pen)
{
_pen = pen;
}
//====================>>> vWinDC::TextHeight <<<=============================
int vWinDC::TextHeight(int& asc, int& des) VCONST
{
// Return total height of this font. V will use total height, which
// is most often made up of ascent + descent. This is too much
// detail for the kind of apps V will support.
_font.LoadFont(_hdc); // need to setup font!
_htext = _font.GetHFONT();
_htext->usTextAlign = TA_BOTTOM | TA_LEFT;
GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_COLOR | CBB_TEXT_ALIGN, 0, _htext);
FONTMETRICS fm;
int a = 5, d = 3; // something reasonable?
GpiQueryFontMetrics (_hdc, sizeof(FONTMETRICS), &fm);
a = fm.lMaxAscender;
d = fm.lMaxDescender;
asc = a ; des = d;
if (_isPrinterDC) // need to correct for the scaling of the print canvas
{
return ((a+d)*65536/_OS2Scale);
}
else
{
return (a+d);
}
}
//========================>>> vvWinDC::TextWidth <<<==========================
int vWinDC::TextWidth(char* str) VCONST
{
_font.LoadFont(_hdc); // need to setup font!
_htext = _font.GetHFONT();
GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_COLOR, 0, _htext);
POINTL box[TXTBOX_COUNT];
GpiQueryTextBox (_hdc, strlen(str), str, TXTBOX_COUNT, box);
int width = box[TXTBOX_TOPRIGHT].x - box[TXTBOX_TOPLEFT].x;
if (_isPrinterDC) // need to correct for the scaling of the print canvas
{
return (width*65536/_OS2Scale);
}
else
{
return (width);
}
}
//========================>>> vvWinDC::MapToOS2 <<<===========================
void vWinDC::MapToOS2(PPOINTL in)
{
// we use the OS/2 FIXED data type to handle fractional
// scaling while retaining integer math
ULONG m, f;
m = HIUSHORT(_OS2Scale);
f = LOUSHORT(_OS2Scale);
in->y = -(1-_OS2Height + in->y);
in->y = (in->y * m) + (in->y * f/65536);
in->x = (in->x * m) + (in->x * f/65536);
}
//========================>>> vvWinDC::MapFromOS2 <<<=========================
void vWinDC::MapFromOS2(PPOINTL in)
{
// we use the OS/2 FIXED data type to handle fractional
// scaling while retaining integer math
in->y = -(1-_OS2Height + (in->y * 65536/_OS2Scale) );
in->x = in->x * 65536/_OS2Scale;
}