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 >
C/C++ Source or Header  |  1999-03-03  |  43KB  |  1,310 lines

  1. //===============================================================
  2. // vWinDC - Windows Base DC
  3. //
  4. // Copyright (C) 1995,1996,1997,1998  Bruce E. Wampler
  5. //
  6. // This file is part of the V C++ GUI Framework, and is covered
  7. // under the terms of the GNU Library General Public License,
  8. // Version 2. This library has NO WARRANTY. See the source file
  9. // vapp.cxx for more complete information about license terms.
  10. //===============================================================
  11.  
  12. #include <v/vos2.h>            // for OS/2 stuff
  13. extern "C"
  14. {
  15.   #include <math.h>
  16. }
  17. #include <v/vwindc.h>
  18. #include <v/vmemdc.h>
  19. #include <v/vapp.h>            // need access to the app
  20. #include <v/vcanvas.h>         // our own canvas widget
  21. #include <v/vicon.h>
  22.  
  23. //-----------------------------------------------------------------------
  24. //================>>> vWinDC::vWinDC <<<========================
  25.   vWinDC::vWinDC()
  26.   {
  27.     SysDebug(Constructor,"vWinDC::vWinDC() constructor\n")
  28.  
  29.     _font = theApp->GetDefaultFont();  // Use the default fixed font by default!
  30.     _hdc = 0;
  31.  
  32.     // set some defaults
  33.     _canvasBG = SETRGB(255,255,255);    // white
  34.     _hpen = _pen.GetHPEN();            // Get the default pen
  35.     _hbrush = _brush.GetHBRUSH();       // Get the default brush
  36. //    _hpen = 0;                          // no pen for now
  37. //    _hbrush = 0;                        // no brush for now
  38.     _isPrinterDC = 0;                  // Assume not printer
  39.   }
  40.  
  41. //================>>> vWinDC::~vWinDC <<<========================
  42.   vWinDC::~vWinDC()
  43.   {
  44.     SysDebug(Destructor,"vWinDC::~vWinDC() destructor\n")
  45.   }
  46. //================>>> vWinDC::CopyFromMemoryDC <<<=======================
  47.   void vWinDC::CopyFromMemoryDC(vMemoryDC* vmemdc, int destX, int destY,
  48.        int srcX, int srcY, int srcW, int srcH) // V:1.13
  49.   {
  50.     BeginPaint();
  51.     int ch = vmemdc->_physHeight;
  52.     int cw = vmemdc->_physWidth;
  53.     int cx = 0;
  54.     int cy = 0;
  55.  
  56.     if (srcX > 0)               // Fixed: 10/11/96
  57.       cx = srcX;
  58.     if (srcY > 0)
  59.       cy = srcY;
  60.     if (srcW > 0)
  61.       cw = srcW;
  62.     if (srcH > 0)
  63.       ch = srcH;
  64.  
  65.     if ((cw + cx) > vmemdc->_physWidth && _physWidth > 0)       // only copy what will fi
  66.       cw = vmemdc->_physWidth - cx;
  67.     if ((ch + cy) > vmemdc->_physHeight && _physHeight > 0)
  68.       ch = vmemdc->_physHeight - cy;
  69.  
  70.     if ((cw + destX) > _physWidth && _physWidth > 0)
  71.       cw = _physWidth - destX;
  72.     if ((ch + destY) > _physHeight && _physHeight > 0)
  73.       ch = _physHeight - destY;
  74.  
  75.  
  76.     if (cw > _physWidth && _physWidth > 0)     // only copy what will fit
  77.       cw = _physWidth;
  78.     if (ch > _physHeight && _physHeight > 0)
  79.       ch = _physHeight;
  80.  
  81.     POINTL cPoints[3] = {destX, destY,              // lower left targ
  82.                          destX+cw, destY+ch,        // upper right targ
  83.                          cx, cy };                  // lower left src
  84.  
  85.     HPS memDC = vmemdc->_hdc;
  86.     SysDebug1(Constructor,"vWinDC::CopyFromMemoryDC() memDC = %d\n", memDC)
  87.  
  88. #define BITBLT
  89. #ifdef BITBLT
  90.     // we need to convert the target coords which are in World Space
  91.     // to Device Space since GpiBitBlt expects device coords
  92. //    GpiConvert(_hdc, CVTC_WORLD, CVTC_DEVICE, 1, &cPoints[0]);
  93. //    GpiConvert(_hdc, CVTC_WORLD, CVTC_DEVICE, 1, &cPoints[1]);
  94.     MapToOS2(&cPoints[0]);
  95.     MapToOS2(&cPoints[1]);
  96.     GpiBitBlt(_hdc, memDC, 3, cPoints, ROP_SRCCOPY, BBO_IGNORE);
  97. #else
  98.     // register COLORREF color, cout;
  99.     register ULONG color, cout;
  100.     POINTL cPoint;
  101.     LINEBUNDLE Pen;
  102.     for (int row = 0 ; row < ch ; ++row)
  103.       for (int col = 0 ; col < cw ; ++col)
  104.       {
  105.         cPoint.x = row;
  106.         cPoint.y = col;
  107.         MapToOS2(&cPoint);
  108.  
  109.         color = GpiQueryPel (memDC, cPoint);
  110.         cout = GpiQueryAttrs (_hdc, PRIM_LINE, LBB_COLOR, &Pen);
  111.         Pen.lColor = color;
  112.         GpiSetAttrs (_hdc, PRIM_LINE, LBB_COLOR, 0, &Pen);
  113.         GpiSetPel (_hdc, cPoint);
  114.         Pen.lColor = cout;
  115.         GpiSetAttrs (_hdc, PRIM_LINE, LBB_COLOR, 0, &Pen);
  116.       }
  117. #endif
  118.     EndPaint();
  119.    }
  120.  
  121. //====================>>> vWinDC::DrawIcon <<<==========================
  122.   void vWinDC::DrawIcon(int x, int y, VCONST vIcon& icon)
  123.   {
  124.     BeginPaint();
  125.     int xx = Scale(x+_tx);
  126.     int yy = Scale(y+_ty);
  127.     // Now, draw the icon
  128.     HBITMAP hbm = icon.GetIconHBM(_hdc);    // get the bitmap
  129.     SysDebug1(Build,"vWinDC::DrawIcon() hbm=%u\n", hbm)
  130.  
  131.     // Now BitBlt the icon BMP into the drawing canvas, leaving
  132.     // background untouched, and the pen color to draw 1 bits
  133.     // (Note: Target is in World Coords, and Source is in Device Coords)
  134.     POINTL cPoints[4] = {xx, yy,                             // lower left targ
  135.              xx+icon.width-1, yy+icon.height-1,  // upper right targ
  136.              0, 0,                               // lower left src
  137.              icon.width, icon.height};           // upper right src
  138.  
  139.     // Map to OS/2 coord system before calling
  140.     // (only need to map World Coords)
  141.     MapToOS2(&cPoints[0]);
  142.     MapToOS2(&cPoints[1]);
  143.  
  144.     // set ownership of bitmap to canvas
  145.     HBITMAP hbmr = GpiSetBitmap(_hdc, hbm);
  146.     // now reset the original bitmap if there was one
  147.     GpiSetBitmap(_hdc, hbmr);
  148.  
  149.     if (icon.iType == Transparent)
  150.     {
  151.       // for transparent icons, we set the canvas background
  152.       // color to the icon transparent color and then set
  153.       // the background mix mode to BM_SRCTRANSPARENT, OS/2
  154.       // takes care of the rest (compare with the windoze code! :-) )
  155.       IMAGEBUNDLE himage;
  156.       himage.lColor = _pen.GetColor().pixel();  // use pen color
  157.       himage.lBackColor = icon.GetTransparentColor();
  158.       GpiSetAttrs(_hdc, PRIM_IMAGE, IBB_BACK_COLOR | IBB_COLOR, 0, &himage);
  159.       GpiSetBackMix(_hdc,BM_SRCTRANSPARENT);
  160.  
  161.       // blit the image to the canvas
  162.       GpiWCBitBlt(_hdc, hbm, 4, cPoints, ROP_SRCCOPY, BBO_IGNORE);
  163.  
  164.       // restore defaults
  165.       himage.lColor = _pen.GetColor().pixel();  // use pen color
  166.       himage.lBackColor = _canvasBG;            // use background color
  167.       GpiSetAttrs(_hdc, PRIM_IMAGE, IBB_BACK_COLOR | IBB_COLOR, 0, &himage);
  168.       GpiSetBackMix(_hdc,BM_DEFAULT);
  169.     }
  170.     else
  171.     {
  172.       // for monochrome bitmaps, we can control the
  173.       // target colors using the image bundle
  174.       IMAGEBUNDLE himage;
  175.       himage.lColor = _pen.GetColor().pixel();  // use pen color
  176.       himage.lBackColor = _canvasBG;            // use background color
  177.       GpiSetAttrs(_hdc, PRIM_IMAGE, IBB_COLOR | IBB_BACK_COLOR, 0, &himage);
  178.  
  179.       // blit the image to the canvas
  180.       GpiWCBitBlt(_hdc, hbm, 4, cPoints, ROP_SRCCOPY, BBO_IGNORE);
  181.     }
  182.     EndPaint();
  183.   }
  184.  
  185. //#define DRAWARC
  186. #ifdef DRAWARC
  187. //====================>>> vWinDC::DrawArc <<<==========================
  188. // This function is experimental
  189. //  (xx1, yy1) start of arc
  190. //  (xx2, yy2) end of arc
  191. //  (xxc, yyc) centre of arc
  192.  
  193.   void vWinDC::DrawArc(int xx1, int yy1, int xx2, int yy2,
  194.     int xxc, int yyc)
  195.   {
  196.     double dx = xx1 - xxc;
  197.     double dy = yy1 - yyc;
  198.     double radius = sqrt(dx * dx + dy * dy);
  199.     const double PIx2 = 6.283185;
  200.     double angle1, angle2;    // angles of points wrt center
  201.  
  202.     BeginPaint();
  203.     if (xx1 == xx2 && yy1 == yy2)
  204.     {
  205.       angle1 = 0.0;
  206.       angle2 = 360.0;
  207.     }
  208.     else if (radius == 0.0)
  209.       angle1 = angle2 = 0.0;
  210.     else
  211.     {
  212.       if (xx1 - xxc == 0)
  213.       {
  214.         if (yy1 - yyc < 0)
  215.           angle1 = 90.0;
  216.         else
  217.           angle1 = -90.0;
  218.       }
  219.       else
  220.         angle1 = -atan2 ((double) (yy1 - yyc), (double) (xx1 - xxc)) * 360.0 / PIx2;
  221.  
  222.       if (xx2 - xxc == 0)
  223.       {
  224.         if (yy2 - yyc < 0)
  225.           angle2 = 90.0;
  226.         else
  227.           angle2 = -90.0;
  228.       }
  229.       else
  230.         angle2 = -atan2 ((double) (yy2 - yyc), (double) (xx2 - xxc)) * 360.0 / PIx2;
  231.     }
  232.  
  233.     POINTL posc = {xxc, yyc};
  234.     POINTL pos1 = {xx1, yy1};
  235.     MapToOS2(&posc);
  236.     MapToOS2(&pos1);
  237.  
  238.     ARCPARAMS arc;
  239.     double ri, Scale;
  240.  
  241.     ri = floor(radius);   // radius always >= 0
  242.     Scale = radius/ri;
  243.     arc.lP = (LONG) ri;
  244.     arc.lQ = (LONG) ri;
  245.     arc.lR = 0L;
  246.     arc.lS = 0L;
  247.     GpiSetArcParams(_hdc, &arc);
  248.  
  249.     // compute start and sweep angles (must be >= 0)
  250.     double start = angle1;
  251.     double sweep = fabs(angle2 - angle1);
  252.     while (start < 0)
  253.       start += 360;
  254.     // set pen attributes and draw arc
  255.     _hpen = _pen.GetHPEN();            // Get the pen
  256.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH, 0, _hpen);
  257.  
  258.     GpiMove(_hdc, &pos1);
  259.     GpiPartialArc(_hdc, &posc, DBLTOFX(Scale), DBLTOFX(start), DBLTOFX(sweep));
  260.     EndPaint();
  261.   }
  262. #endif
  263.  
  264. //====================>>> vWinDC::DrawEllipse <<<==========================
  265. // (x,y) lower left corner ellipse bounding box
  266.   void vWinDC::DrawEllipse(int x, int y, int width, int height)
  267.   {
  268.     if (height == 0 || width == 0)
  269.       return;
  270.  
  271.     BeginPaint();
  272.     // coords for GPI functions are inclusive/inclusive
  273.     // right = left + width -1
  274.     // top = bottom + height -1
  275.     int x1 = Scale(x+_tx);
  276.     int y1 = Scale(y+_ty);
  277.     int width1 = Scale(width-1);
  278.     int height1 = Scale(height-1);
  279.  
  280.     _hpen = _pen.GetHPEN();            // Get the pen
  281.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  282.       0, _hpen);
  283.  
  284.     _hbrush = _brush.GetHBRUSH();
  285.     GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
  286.  
  287.     // coords for GPI functions are inclusive/inclusive
  288.     // right = left + width -1
  289.     // top = bottom + height -1
  290.     // set arc params at 2x scale
  291.     ARCPARAMS arc;
  292.     arc.lP = width1;
  293.     arc.lQ = height1;
  294.     arc.lR = 0;
  295.     arc.lS = 0;
  296.     GpiSetArcParams(_hdc , &arc);
  297.  
  298.     // compute center of ellipse
  299.     POINTL posc = {x1+(width1/2), y1+(height1/2)};
  300.     MapToOS2(&posc);
  301.  
  302.     if (_hpen->usType == LINETYPE_SOLID)
  303.     {
  304.       GpiSetCurrentPosition (_hdc, &posc);
  305.       GpiFullArc (_hdc, DRO_FILL, MAKEFIXED(0,0x8000));   // scale by 1/2
  306.       GpiBeginPath(_hdc, 1L);
  307.       GpiFullArc (_hdc, DRO_OUTLINE, MAKEFIXED(0,0x8000));   // scale by 1/2
  308.       GpiEndPath(_hdc);
  309.  
  310.       AREABUNDLE hlinebrush;
  311.       hlinebrush.lColor = _hpen->lColor;
  312.       hlinebrush.usSymbol = PATSYM_SOLID;
  313.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &hlinebrush);
  314.       GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  315.     }
  316.     else
  317.     {
  318.       GpiSetCurrentPosition (_hdc, &posc);    // move to start point
  319.       GpiFullArc (_hdc, DRO_OUTLINEFILL, MAKEFIXED(0,0x8000));   // scale by 1/2
  320.     }
  321.     EndPaint();
  322.   }
  323.  
  324. //====================>>> vWinDC::DrawLine <<<==========================
  325.   void vWinDC::DrawLine(int x, int y, int xend, int yend)
  326.   {
  327.     BeginPaint();
  328.     // Draw a line from x,y to xend,yend
  329.     // This method has the typical sequence of code for drawing. All other
  330.     // drawing methods are modeled using this approach
  331.     // First, do the required scaling
  332.     int xx = Scale(x+_tx);
  333.     int yy = Scale(y+_ty);
  334.     int xe = Scale(xend+_tx);
  335.     int ye = Scale(yend+_ty);
  336.  
  337.     //  OS/2 can define a presentation space when the window
  338.     // is created, and we can use it until the window is
  339.     // destroyed.  This saves us from needing to constantly
  340.     // get and destroy the DC (unlike the windows code) while the user program is
  341.     // drawing stuff interactively (usually in response to mouse input).
  342.     // For Redraw, the canvas redraw event will issue a WinBeginPaint
  343.     // and WinEndPaint, which will bracket all drawing.  We feed
  344.     // WinBeginPaint our presentation space for the window so it
  345.     // doesn't create a separate cached micro-PS like it normally would do.
  346.     // This allows us to retain any attributes of the PS for the
  347.     // life of the window.
  348.  
  349.     _hpen = _pen.GetHPEN();         // Get the pen
  350.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  351.        0, _hpen);
  352.  
  353.     // Shapes will do a similar sequence for brushes as well
  354.     // Now the code to actually do the drawing
  355.     POINTL poss = {xx, yy};  // start point
  356.     POINTL pose = {xe, ye};  // end point
  357.     MapToOS2(&poss);
  358.     MapToOS2(&pose);
  359.  
  360.     GpiBeginPath(_hdc, 1L);
  361.     GpiSetCurrentPosition (_hdc, &poss);
  362.     GpiLine (_hdc , &pose);
  363.     GpiEndPath(_hdc);
  364.  
  365.     // it turns out that to get a line of variable thickness it must be
  366.     // stroked.  However, such lines do not support linetypes other
  367.     // than type solid. So to get dots and dashed lines we need to
  368.     // use outlines, but then the width is ignored (dohh!).
  369.     // This behavior is also true for windows though,
  370.     // so I'm not going to worry about it.  The major pain though is
  371.     // that the stroked line color is set to the area fill color, which
  372.     // is why I have to do the nonsense with the hlinebrush.
  373.  
  374.     if (_hpen->usType == LINETYPE_SOLID)
  375.     {
  376.       // for Geometric lines, the fill color is used (what a debacle!)
  377.       AREABUNDLE hlinebrush;
  378.       hlinebrush.lColor = _hpen->lColor;              // for stroked lines
  379.       hlinebrush.usSymbol = PATSYM_SOLID;
  380.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &hlinebrush);
  381.       GpiStrokePath(_hdc, 1L, 0L);   // solid lines can be stroked
  382.     }
  383.     else
  384.       GpiOutlinePath(_hdc, 1L, 0L);  // other lines need to be outlined
  385.  
  386.     EndPaint();
  387.   }
  388.  
  389. //====================>>> vWinDC::DrawLines <<<==========================
  390.   void vWinDC::DrawLines(vLine* lineList, int count)
  391.   {
  392.     if (count < 1 || lineList == 0)
  393.       return;
  394.  
  395.     BeginPaint();
  396.     _hpen = _pen.GetHPEN();         // Get the pen
  397.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  398.       0, _hpen);
  399.  
  400.     vLine* lp = lineList ;
  401.     POINTL poss;   // start point
  402.     POINTL pose;   // end point
  403.  
  404.     GpiBeginPath(_hdc, 1L);
  405.     for (int num = 0 ; num < count ; ++lp, ++num)
  406.     {
  407.       poss.x = Scale(lp->x+_tx);
  408.       poss.y = Scale(lp->y+_ty);
  409.       pose.x = Scale(lp->xend+_tx);
  410.       pose.y = Scale(lp->yend+_ty);
  411.       MapToOS2(&poss);
  412.       MapToOS2(&pose);
  413.  
  414.       GpiSetCurrentPosition (_hdc, &poss);
  415.       GpiLine (_hdc , &pose);
  416.     }
  417.     GpiEndPath(_hdc);
  418.     if (_hpen->usType == LINETYPE_SOLID)
  419.     {
  420.       // for Geometric lines, the fill color is used (what a debacle!)
  421.       AREABUNDLE linebrush;
  422.       linebrush.lColor = _hpen->lColor;               // for stroked lines
  423.       linebrush.usSymbol = PATSYM_SOLID;
  424.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  425.       GpiStrokePath(_hdc, 1L, 0L);   // solid lines can be stroked
  426.     }
  427.     else
  428.       GpiOutlinePath(_hdc, 1L, 0L);  // other lines need to be outlined
  429.  
  430.     EndPaint();
  431.   }
  432.  
  433. //==================>>> vWinDC::DrawColorPoints <<<======================
  434.   void vWinDC::DrawColorPoints(int x, int y, int nPoints, vColor* pointList)
  435.   {
  436.     // Draw a bunch of color points.
  437.     if (nPoints < 1 || pointList == 0)
  438.       return;
  439.  
  440.     BeginPaint();
  441.  
  442.     int xx = Scale(x+_tx);
  443.     int yy = Scale(y+_ty);
  444.     if (yy < 0)
  445.       return;                         // row not displayed
  446.  
  447. #define BITBLT
  448. #ifdef BITBLT
  449.     // performance was bad with GpiSetPel so  do this with
  450.     // a line bitmap blitted to the canvas
  451.  
  452.     // bitmap data structures
  453.     PVBYTE bmbits;
  454.     PBITMAPINFO2 pbmi;
  455.  
  456.     // build a memory PS compatible with calling PS
  457.     HDC DevCxtComp = GpiQueryDevice(_hdc);
  458.     HDC DevCxtMem = DevOpenDC(theApp->AppHab(), OD_MEMORY, "*", 0L, NULL, DevCxtComp);
  459.     SIZEL size = {nPoints, 1};
  460.     HPS hdcMem = GpiCreatePS (theApp->AppHab(), DevCxtMem, &size,
  461.       PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );
  462.  
  463.     // set the PS to RGB mode
  464.     GpiCreateLogColorTable(hdcMem, 0L, LCOLF_RGB, 0L, 0L, NULL);
  465.  
  466.     // First, create a blank bitmap compatible with the
  467.     // current context that is size of bitmap.
  468.     BITMAPINFOHEADER2 bmih;
  469.     memset(&bmih, 0, sizeof(BITMAPINFOHEADER2));
  470.     bmih.cbFix = sizeof(BITMAPINFOHEADER2);
  471.     bmih.cx = nPoints;
  472.     bmih.cy = 1;
  473.     bmih.ulColorEncoding = BCE_RGB;
  474.     bmih.cPlanes = 1;         // always 1 for OS/2
  475.     bmih.cBitCount = 24;      // bits of color per pixel
  476.  
  477.     HBITMAP hbm = GpiCreateBitmap(hdcMem, &bmih, 0L, NULL, NULL);
  478.     // now we need to load the bitmap with data by associating
  479.     // with a memory PS and setting each pel
  480.     GpiSetBitmap(hdcMem, hbm);
  481.  
  482.     // We first need to create the bitmapinfo structure
  483.     // (a color table is not needed for 24 bit bitmaps)
  484.     // allocate space for header
  485.     pbmi=(PBITMAPINFO2) new VBYTE [sizeof(BITMAPINFOHEADER2)];
  486.  
  487.     // copy the header to the bitmap info structure
  488.     memcpy(pbmi, &bmih, sizeof(BITMAPINFOHEADER2));
  489.     pbmi->cclrUsed = 0 ;         // no color table needed
  490.     pbmi->cbImage = nPoints*3;   // image size (bytes)
  491.  
  492.     // Now need to copy pixel data over from pointList
  493.     int rowwords = ((nPoints*3)+3) / 4;   // number of words (for OS/2 bitmap data)
  494.     bmbits = new VBYTE[rowwords*4];         // allocate space
  495.     PVBYTE to = bmbits;                    // set to first pixel
  496.  
  497.     int col;
  498.     for (col = 0 ; col < nPoints ; ++col)   // do each V pixel per row
  499.     {
  500.       // R G B
  501.       *to++ = pointList[col].r();
  502.       *to++ = pointList[col].g();
  503.       *to++ = pointList[col].b();
  504.     }
  505.  
  506.     // Finished a row, need to pad to a word boundary
  507.     while ( (col*3)<(4*rowwords) )
  508.     {
  509.       *to++ = 0x00;           // pad with 0's
  510.       col++;
  511.     }
  512.  
  513.     // Now, create the bitmap
  514.     GpiSetBitmapBits(hdcMem, 0L, pbmi->cy, (PBYTE) bmbits, pbmi);
  515.     // free up resources and we are done
  516.     delete [] bmbits;
  517.     delete [] pbmi;
  518.  
  519.     GpiSetBitmap (hdcMem, NULLHANDLE);
  520.     GpiAssociate (hdcMem, NULLHANDLE);
  521.     GpiDestroyPS (hdcMem);
  522.     DevCloseDC (DevCxtMem);
  523.  
  524.     POINTL cPoints[4] = {xx, yy,                 // lower left targ
  525.                          xx+nPoints-1, yy,       // upper right targ
  526.                          0, 0,                   // lower left src
  527.                          nPoints, 1};            // upper right src
  528.     MapToOS2(&cPoints[0]);
  529.     MapToOS2(&cPoints[1]);
  530.  
  531.     // set ownership of bitmap to canvas
  532.     HBITMAP hbmr = GpiSetBitmap(_hdc, hbm);
  533.     // now reset the original bitmap if there was one
  534.     GpiSetBitmap(_hdc, hbmr);
  535.     // blit the image to the canvas
  536.     GpiWCBitBlt(_hdc, hbm, 4, cPoints, ROP_SRCCOPY, BBO_IGNORE);
  537.     // destroy the bitmap
  538.     if (hbm != 0)
  539.       GpiDeleteBitmap(hbm);
  540.  
  541. #else
  542.     // this is the slow but straightforward way using GpiSetPel
  543.     LINEBUNDLE pen;
  544.     POINTL Point, os2Point;
  545.     Point.x = xx;
  546.     Point.y = yy;
  547.  
  548.     if (xx < 0)                                // need to check every time
  549.     {
  550.       for (int ix = 0 ; ix < nPoints ; ++ix)
  551.       {
  552.         if (xx+ix < 0)
  553.           continue;                       // this one not displayed
  554.         pen.lColor = pointList[ix].pixel();
  555.         GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, &pen);
  556.         Point.x = xx+ix;
  557.         os2Point.x = Point.x;
  558.         os2Point.y = Point.y;
  559.         MapToOS2(&os2Point);
  560.         GpiSetPel (_hdc, &os2Point);
  561.       }
  562.     }
  563.     else                               // don't need xx check
  564.     {
  565.       for (int ix = 0 ; ix < nPoints ; ++ix)
  566.       {
  567.         pen.lColor = pointList[ix].pixel();
  568.         GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, &pen);
  569.         Point.x = xx+ix;
  570.         os2Point.x = Point.x;
  571.         os2Point.y = Point.y;
  572.         MapToOS2(&os2Point);
  573.         GpiSetPel (_hdc, &os2Point);
  574.       }
  575.     }
  576. #endif
  577.     EndPaint();
  578.  }
  579.  
  580. //==================>>> vWinDC::DrawPoint <<<======================
  581.   void vWinDC::DrawPoint(int x, int y)
  582.   {
  583.     BeginPaint();
  584.     // First, do the required scaling
  585.     int xx = Scale(x+_tx);
  586.     int yy = Scale(y+_ty);
  587.  
  588.     POINTL Point;
  589.     Point.x = xx;
  590.     Point.y = yy;
  591.     MapToOS2(&Point);
  592.  
  593.  
  594.     _hpen = _pen.GetHPEN();            // Get the pen
  595.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, _hpen);
  596.  
  597.     // Now the code to actually do the drawing
  598.     GpiSetPel (_hdc, &Point);
  599.     EndPaint();
  600.   }
  601.  
  602. //==================>>> vWinDC::DrawPoints <<<======================
  603.   void vWinDC::DrawPoints(vPoint* pointList, int count)
  604.   {
  605.     POINTL Point;
  606.  
  607.     if (count < 1 || pointList == 0)
  608.       return;
  609.  
  610.     BeginPaint();
  611.     _hpen = _pen.GetHPEN();            // Get the pen
  612.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR, 0, _hpen);
  613.  
  614.     // Now the code to actually do the drawing
  615.     vPoint* pl = pointList ;
  616.     for (int num = 0 ; num < count ; ++pl, ++num)
  617.     {
  618.       Point.x = Scale(pl->x+_tx);
  619.       Point.y = Scale(pl->y+_ty);
  620.       MapToOS2(&Point);
  621.  
  622.       GpiSetPel (_hdc, &Point);
  623.     }
  624.     EndPaint();
  625.   }
  626.  
  627. //==================>>> vWinDC::DrawPolygon <<<======================
  628.   void vWinDC::DrawPolygon(int n, vPoint points[], int fillStyle)
  629.   {
  630.     // draw a complete polygon (starting point specified twice!)
  631.     BeginPaint();
  632.     if (_hasScale || _tx != 0 || _ty != 0)     // If we have to scale, then we need to copy
  633.     {
  634.       for (int i = 0; i < n; i++)
  635.       {
  636.         points[i].x = ((points[i].x+_tx) * _Mult) / _Div;   // scale
  637.         points[i].y = ((points[i].y+_ty) * _Mult) / _Div;
  638.       }
  639.     }
  640.  
  641.     // we need to be careful here, since we are actually changing the
  642.     // data in the users own structure here.  We will need to put things
  643.     // back the way they were when we are done!
  644.     for (int i = 0; i < n; i++)
  645.     {
  646.       MapToOS2(&points[i]);
  647.     }
  648.  
  649.     _hpen = _pen.GetHPEN();            // Get the pen
  650.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  651.       0, _hpen);
  652.  
  653.     _hbrush = _brush.GetHBRUSH();
  654.     GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
  655.  
  656.     // fill the outline
  657.     GpiBeginPath(_hdc, 1L);
  658.     GpiSetCurrentPosition (_hdc , &points[0]);   // move to first point
  659.     GpiPolyLine(_hdc, n-1, &points[1]);           // draw the outline polygon
  660.     GpiEndPath(_hdc);
  661.  
  662.     GpiFillPath(_hdc, 1L, (fillStyle == vAlternate) ? FPATH_ALTERNATE : FPATH_WINDING);
  663.  
  664.     // draw the outline
  665.     GpiBeginPath(_hdc, 1L);
  666.     GpiSetCurrentPosition (_hdc , &points[0]);   // move to last point
  667.     GpiPolyLine(_hdc, n-1, &points[1]);               // draw the outline polygon
  668.     GpiEndPath(_hdc);
  669.  
  670.     if (_hpen->usType == LINETYPE_SOLID)
  671.     {
  672.        // for Geometric lines, the fill color is used (what a debacle!)
  673.        AREABUNDLE linebrush;
  674.        linebrush.lColor = _hpen->lColor;               // for stroked lines
  675.        linebrush.usSymbol = PATSYM_SOLID;
  676.        GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  677.        GpiStrokePath(_hdc, 1L, 0L);   // solid lines can be stroked
  678.     }
  679.     else
  680.       GpiOutlinePath(_hdc, 1L, 0L);  // other lines need to be outlined
  681.  
  682.     // restore the user's points data back to the original values
  683.     for (i = 0; i < n; i++)
  684.     {
  685.       MapFromOS2(&points[i]);
  686.     }
  687.  
  688.     EndPaint();
  689. }
  690.  
  691. //==================>>> vWinDC::DrawRectangle <<<======================
  692.   void vWinDC::DrawRectangle(int x, int y, int width, int height)
  693.   {
  694.     if (height == 0 || width == 0)
  695.       return;
  696.  
  697.     BeginPaint();
  698.     POINTL poss, pose;
  699.     AREABUNDLE linebrush;
  700.  
  701.     // coords for GPI functions are inclusive/inclusive
  702.     // right = left + width -1
  703.     // top = bottom + height -1
  704.     poss.x = Scale(x+_tx);
  705.     poss.y = Scale(y+_ty);
  706.     pose.x = Scale(x+width-1+_tx);
  707.     pose.y = Scale(y+height-1+_ty);
  708.     MapToOS2(&poss);
  709.     MapToOS2(&pose);
  710.  
  711.     _hpen = _pen.GetHPEN();            // Get the pen
  712.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  713.       0, _hpen);
  714.  
  715.     _hbrush = _brush.GetHBRUSH();
  716.     GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
  717.  
  718.     if (_hpen->usType == LINETYPE_SOLID)
  719.     {
  720.       GpiSetCurrentPosition (_hdc, &poss);
  721.       GpiBox(_hdc, DRO_FILL, &pose, 0, 0);
  722.       GpiBeginPath(_hdc, 1L);
  723.       GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
  724.       GpiEndPath(_hdc);
  725.  
  726.       linebrush.lColor = _hpen->lColor;
  727.       linebrush.usSymbol = PATSYM_SOLID;
  728.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  729.       GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  730.     }
  731.     else
  732.     {
  733.       GpiSetCurrentPosition (_hdc, &poss);    // move to start point
  734.       GpiBox(_hdc, DRO_OUTLINEFILL, &pose, 0, 0);
  735.     }
  736.     EndPaint();
  737.   }
  738.  
  739. //==================>>> vWinDC::DrawRectangles <<<======================
  740.   void vWinDC::DrawRectangles(vRect* rectList, int count)
  741.   {
  742.     if (count < 1 || !rectList)
  743.       return;
  744.  
  745.     POINTL poss, pose;
  746.  
  747.     BeginPaint();
  748.     _hpen = _pen.GetHPEN();            // Get the pen
  749.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  750.       0, _hpen);
  751.  
  752.     _hbrush = _brush.GetHBRUSH();
  753.     GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
  754.  
  755.     vRect* rp = rectList ;
  756.     for (int num=0 ; num < count ; ++rp, ++num)
  757.     {
  758.       // coords for GPI functions are inclusive/inclusive
  759.       // right = left + width -1
  760.       // top = bottom + height -1
  761.       poss.x = Scale(rp->x+_tx);
  762.       poss.y = Scale(rp->y+_ty);
  763.       pose.x = Scale(rp->x+rp->w-1+_tx);
  764.       pose.y = Scale(rp->y+rp->h-1+_ty);
  765.       if (rp->h == 0 && rp->w == 0)
  766.         continue;
  767.       MapToOS2(&poss);
  768.       MapToOS2(&pose);
  769.  
  770.       // if solid line then we can support variable line widths
  771.       if (_hpen->usType == LINETYPE_SOLID)
  772.       {
  773.         GpiSetCurrentPosition (_hdc, &poss);
  774.         GpiBox(_hdc, DRO_FILL, &pose, 0, 0);
  775.         GpiBeginPath(_hdc, 1L);
  776.         GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
  777.         GpiEndPath(_hdc);
  778.  
  779.         AREABUNDLE linebrush;
  780.         linebrush.lColor = _hpen->lColor;
  781.         linebrush.usSymbol = PATSYM_SOLID;
  782.         GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  783.         GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  784.         // don't forget to reset the brush back to what it was
  785.  
  786.         GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
  787.       }
  788.       else
  789.       // otherwise, we only support single pel width lines
  790.       {
  791.         GpiSetCurrentPosition (_hdc, &poss);    // move to start point
  792.         GpiBox(_hdc, DRO_OUTLINEFILL, &pose, 0, 0);
  793.       }
  794.     }
  795.     EndPaint();
  796.   }
  797.  
  798. //================>>> vWinDC::DrawRoundedRectangle <<<===================
  799.   void vWinDC::DrawRoundedRectangle(int x, int y,
  800.     int width, int height, int radius)
  801.   {
  802.     if (height == 0 || width == 0)
  803.       return;
  804.  
  805.     BeginPaint();
  806.     // coords for GPI functions are inclusive/inclusive
  807.     // right = left + width -1
  808.     // top = bottom + height -1
  809.     POINTL poss, pose;
  810.     poss.x = Scale(x+_tx);
  811.     poss.y = Scale(y+_ty);
  812.     pose.x = Scale(x+width-1+_tx);
  813.     pose.y = Scale(y+height-1+_ty);
  814.     MapToOS2(&poss);
  815.     MapToOS2(&pose);
  816.  
  817.     int r;
  818.     if (radius < 0)
  819.     {
  820.       // Negative radius means divide average of height and width
  821.       // by this
  822.       r = (Scale(width+height)/(-2 * radius));
  823.     }
  824.     else
  825.       r = Scale(radius);
  826.  
  827.     _hpen = _pen.GetHPEN();            // Get the pen
  828.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  829.       0, _hpen);
  830.  
  831.     _hbrush = _brush.GetHBRUSH();
  832.     GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, _hbrush);
  833.  
  834.     if (_hpen->usType == LINETYPE_SOLID)
  835.     {
  836.       GpiSetCurrentPosition (_hdc, &poss);
  837.       GpiBox(_hdc, DRO_FILL, &pose, 2*r, 2*r);
  838.       GpiBeginPath(_hdc, 1L);
  839.       GpiBox(_hdc, DRO_OUTLINE, &pose, 2*r, 2*r);
  840.       GpiEndPath(_hdc);
  841.  
  842.       AREABUNDLE linebrush;
  843.       linebrush.lColor = _hpen->lColor;
  844.       linebrush.usSymbol = PATSYM_SOLID;
  845.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  846.       GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  847.     }
  848.     else
  849.     {
  850.       GpiSetCurrentPosition (_hdc, &poss);    // move to start point
  851.       GpiBox(_hdc, DRO_OUTLINEFILL, &pose, 2*r, 2*r);
  852.     }
  853.     EndPaint();
  854.   }
  855.  
  856. //==================>>> vWinDC::DrawRubberEllipse<<<===================
  857.   void vWinDC::DrawRubberEllipse(int x, int y, int width, int height)
  858.   {
  859.     if (height == 0 || width == 0)
  860.       return;
  861.  
  862.     BeginPaint();
  863.     // coords for GPI functions are inclusive/inclusive
  864.     // right = left + width -1
  865.     // top = bottom + height -1
  866.     int x1 = Scale(x+_tx);
  867.     int y1 = Scale(y+_ty);
  868.     int width1 = Scale(width-1);
  869.     int height1 = Scale(height-1);
  870.  
  871.     _hpen = _pen.GetHPEN();             // Get the pen
  872.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH, 0, _hpen);
  873.  
  874.     // set arc params at 2x scale
  875.     ARCPARAMS arc;
  876.     arc.lP = width1;
  877.     arc.lQ = height1;
  878.     arc.lR = 0;
  879.     arc.lS = 0;
  880.     GpiSetArcParams(_hdc , &arc);
  881.  
  882.     // compute center of ellipse
  883.     POINTL posc = {x1+(width1/2), y1+(height1/2)};
  884.     MapToOS2(&posc);
  885.  
  886.     if (_hpen->usType == LINETYPE_SOLID)
  887.     {
  888.       // save the original brush values
  889.       LONG orgColor = _hbrush->lColor;
  890.       USHORT orgMix = _hbrush->usMixMode;
  891.  
  892.       GpiSetCurrentPosition (_hdc, &posc);
  893.       GpiBeginPath(_hdc, 1L);
  894.       GpiFullArc (_hdc, DRO_OUTLINE, MAKEFIXED(0,0x8000));   // scale by 1/2
  895.       GpiEndPath(_hdc);
  896.  
  897.       AREABUNDLE linebrush;
  898.       linebrush.lColor = SETRGB(255,255,255);
  899.       linebrush.usMixMode = FM_XOR;           // draw in XOR
  900.       linebrush.usSymbol = PATSYM_SOLID;
  901.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  902.       GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  903.  
  904.       // restore the original brush values
  905.       linebrush.lColor = orgColor;
  906.       linebrush.usMixMode = orgMix;
  907.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR, 0, &linebrush);
  908.     }
  909.     else
  910.     {
  911.       // save the original pen values
  912.       LONG orgColor = _hpen->lColor;
  913.       USHORT orgMix = _hpen->usMixMode;
  914.  
  915.       // change pen for rubber line
  916.       _hpen->lColor = SETRGB(255,255,255);  // set pen color to white
  917.       _hpen->usMixMode = FM_XOR;            // draw in XOR
  918.       GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  919.  
  920.       GpiFullArc (_hdc, DRO_OUTLINE, MAKEFIXED(0,0x8000));   // scale by 1/2
  921.       // restore the original pen values
  922.       _hpen->lColor = orgColor;
  923.       _hpen->usMixMode = orgMix;
  924.       GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  925.     EndPaint();
  926.     }
  927.  }
  928.  
  929. //==================>>> vWinDC::DrawRubberLine <<<======================
  930.   void vWinDC::DrawRubberLine(int x, int y, int xend, int yend)
  931.   {
  932.     BeginPaint();
  933.     // Draw a rubber-band line from x,y to xend,yend. Redrawing
  934.     // over the same with will erase it.
  935.     int xx = Scale(x+_tx);
  936.     int yy = Scale(y+_ty);
  937.     int xe = Scale(xend+_tx);
  938.     int ye = Scale(yend+_ty);
  939.  
  940.     _hpen = _pen.GetHPEN();            // Get the pen
  941.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH, 0, _hpen);
  942.  
  943.     // Shapes will do a similar sequence for brushes as well
  944.     // Now the code to actually do the drawing
  945.  
  946.     POINTL poss = {xx, yy};  // start point
  947.     POINTL pose = {xe, ye};  // end point
  948.     MapToOS2(&poss);
  949.     MapToOS2(&pose);
  950.  
  951.     if (_hpen->usType == LINETYPE_SOLID)
  952.     {
  953.       // save the original brush values
  954.       LONG orgColor = _hbrush->lColor;
  955.       USHORT orgMix = _hbrush->usMixMode;
  956.  
  957.       GpiBeginPath(_hdc, 1L);
  958.       GpiSetCurrentPosition (_hdc, &poss);
  959.       GpiLine (_hdc , &pose);
  960.       GpiEndPath(_hdc);
  961.  
  962.       AREABUNDLE linebrush;
  963.       linebrush.lColor = SETRGB(255,255,255);
  964.       linebrush.usMixMode = FM_XOR;           // draw in XOR
  965.       linebrush.usSymbol = PATSYM_SOLID;
  966.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  967.       GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  968.  
  969.       // restore the original brush values
  970.       linebrush.lColor = orgColor;
  971.       linebrush.usMixMode = orgMix;
  972.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR, 0, &linebrush);
  973.     }
  974.     else
  975.     {
  976.       // save the original pen values
  977.       LONG orgColor = _hpen->lColor;
  978.       USHORT orgMix = _hpen->usMixMode;
  979.  
  980.       // change pen for rubber line
  981.       _hpen->lColor = SETRGB(255,255,255);  // set pen color to white
  982.       _hpen->usMixMode = FM_XOR;            // draw in XOR
  983.       GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  984.       GpiSetCurrentPosition (_hdc, &poss);
  985.       GpiLine (_hdc , &pose);
  986.  
  987.       // restore the original pen values
  988.       _hpen->lColor = orgColor;
  989.       _hpen->usMixMode = orgMix;
  990.       GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  991.     }
  992.     EndPaint();
  993.   }
  994.  
  995. //==================>>> vWinDC::DrawRubberPoint <<<======================
  996.   void vWinDC::DrawRubberPoint(int x, int y)
  997.   {
  998.     BeginPaint();
  999.     // First, do the required scaling
  1000.     int xx = Scale(x+_tx);
  1001.     int yy = Scale(y+_ty);
  1002.  
  1003.     POINTL Point;
  1004.     Point.x = xx;
  1005.     Point.y = yy;
  1006.     MapToOS2(&Point);
  1007.  
  1008.     _hpen = _pen.GetHPEN();            // Get the pen
  1009.     // save the original pen values
  1010.     LONG orgColor = _hpen->lColor;
  1011.     USHORT orgMix = _hpen->usMixMode;
  1012.     // change pen for rubber line
  1013.     _hpen->lColor = SETRGB(255,255,255);  // set pen color to white
  1014.     _hpen->usMixMode = FM_XOR;            // draw in XOR
  1015.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  1016.     GpiSetPel (_hdc, &Point);
  1017.  
  1018.     // restore the original pen values
  1019.     _hpen->lColor = orgColor;
  1020.     _hpen->usMixMode = orgMix;
  1021.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  1022.     EndPaint();
  1023.  }
  1024.  
  1025. //==================>>> vWinDC::DrawRubberRectangle <<<==================
  1026.   void vWinDC::DrawRubberRectangle(int x, int y, int width, int height)
  1027.   {
  1028.     if (height == 0 || width == 0)
  1029.       return;
  1030.  
  1031.     BeginPaint();
  1032.     POINTL poss, pose;
  1033.     AREABUNDLE linebrush;
  1034.     // coords for GPI functions are inclusive/inclusive
  1035.     // right = left + width -1
  1036.     // top = bottom + height -1
  1037.     poss.x = Scale(x+_tx);
  1038.     poss.y = Scale(y+_ty);
  1039.     pose.x = Scale(x+width-1+_tx);
  1040.     pose.y = Scale(y+height-1+_ty);
  1041.     MapToOS2(&poss);
  1042.     MapToOS2(&pose);
  1043.  
  1044.     _hpen = _pen.GetHPEN();            // Get the pen
  1045.     GpiSetAttrs(_hdc, PRIM_LINE, LBB_COLOR | LBB_TYPE | LBB_WIDTH | LBB_GEOM_WIDTH,
  1046.       0, _hpen);
  1047.  
  1048.     if (_hpen->usType == LINETYPE_SOLID)
  1049.     {
  1050.       // save the original brush values
  1051.       LONG orgColor = _hbrush->lColor;
  1052.       USHORT orgMix = _hbrush->usMixMode;
  1053.  
  1054.       GpiSetCurrentPosition (_hdc, &poss);
  1055.       GpiBeginPath(_hdc, 1L);
  1056.       GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
  1057.       GpiEndPath(_hdc);
  1058.  
  1059.       linebrush.lColor = SETRGB(255,255,255);
  1060.       linebrush.usMixMode = FM_XOR;           // draw in XOR
  1061.       linebrush.usSymbol = PATSYM_SOLID;
  1062.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR | ABB_SYMBOL, 0, &linebrush);
  1063.       GpiStrokePath(_hdc, 1L, 0L);   // thick lines need to be stroked
  1064.  
  1065.       // restore the original brush values
  1066.       linebrush.lColor = orgColor;
  1067.       linebrush.usMixMode = orgMix;
  1068.       GpiSetAttrs(_hdc, PRIM_AREA, ABB_MIX_MODE | ABB_COLOR, 0, &linebrush);
  1069.     }
  1070.     else
  1071.     {
  1072.       // save the original pen values
  1073.       LONG orgColor = _hpen->lColor;
  1074.       USHORT orgMix = _hpen->usMixMode;
  1075.       // change pen for rubber line
  1076.       _hpen->lColor = SETRGB(255,255,255);  // set pen color to white
  1077.       _hpen->usMixMode = FM_XOR;            // draw in XOR
  1078.       GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  1079.  
  1080.       GpiSetCurrentPosition (_hdc, &poss);    // move to start point
  1081.       GpiBox(_hdc, DRO_OUTLINE, &pose, 0, 0);
  1082.  
  1083.       // restore the original pen values
  1084.       _hpen->lColor = orgColor;
  1085.       _hpen->usMixMode = orgMix;
  1086.       GpiSetAttrs(_hdc, PRIM_LINE, LBB_MIX_MODE | LBB_COLOR, 0, _hpen);
  1087.     }
  1088.     EndPaint();
  1089.   }
  1090.  
  1091. //=====================>>> vWinDC::DrawAttrText <<<==========================
  1092.   void vWinDC::DrawAttrText(int x, int y, VCONST char* text, const ChrAttr attr)
  1093.   {
  1094.     // Draw text with attributes at given x, y.
  1095.     static int mapColor[] =
  1096.     {
  1097.       vC_Black, vC_Blue, vC_Green, vC_Cyan,
  1098.       vC_Red, vC_Magenta, vC_Yellow, vC_White,
  1099.       vC_DarkGray, vC_DimBlue, vC_DimGreen, vC_DimCyan,
  1100.       vC_DimRed, vC_DimMagenta, vC_DimYellow, vC_MedGray
  1101.     };
  1102.  
  1103.     BeginPaint();
  1104.     POINTL poss;
  1105.     poss.x = Scale(x+_tx);
  1106.     poss.y = Scale(y+_ty);
  1107.     MapToOS2(&poss);
  1108.  
  1109.     _font.LoadFont(_hdc);              // need to setup font!
  1110.     _htext = _font.GetHFONT();
  1111.     _htext->usTextAlign = TA_BOTTOM | TA_LEFT;
  1112.  
  1113.     // we get the charbundle to control font color
  1114.     // we use the current pen to define text colors
  1115.     ULONG orgfgc = _pen.GetColor().pixel();
  1116.     ULONG orgbgc = _canvasBG;
  1117.  
  1118.     if (attr & ChHighlight)
  1119.     {
  1120.       _htext->usBackMixMode = BM_OVERPAINT;
  1121.       _htext->lBackColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_HILITEBACKGROUND, 0L);
  1122.       _htext->lColor = WinQuerySysColor(HWND_DESKTOP, SYSCLR_HILITEFOREGROUND, 0L);
  1123.       _htext->usTextAlign = TA_BOTTOM | TA_LEFT;
  1124.     }
  1125.     else if (attr & ChReverse)
  1126.     {
  1127.       // default backmixmode is BM_LEAVEALONE, the windows version of V
  1128.       // overpaints background so we will do accordingly
  1129.       _htext->usBackMixMode = BM_OVERPAINT;
  1130.       _htext->lBackColor = orgfgc;
  1131.       _htext->lColor = orgbgc;
  1132.       _htext->usTextAlign = TA_BOTTOM | TA_LEFT;
  1133.     }
  1134.     else
  1135.     {
  1136.       _htext->usBackMixMode = BM_OVERPAINT;
  1137. //      _htext->usBackMixMode = BM_LEAVEALONE;
  1138.       _htext->lBackColor = orgbgc;
  1139.       _htext->lColor = orgfgc;
  1140.       _htext->usTextAlign = TA_BOTTOM | TA_LEFT;
  1141.     }
  1142.  
  1143.     if (attr & 0xF0)           // A color overide
  1144.     {
  1145.       _htext->lColor = vStdColors[ mapColor[((attr & 0xF0) >> 4)] ].pixel();
  1146.     }
  1147.  
  1148.     GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_BACK_MIX_MODE | CBB_COLOR | CBB_TEXT_ALIGN,
  1149.       0, _htext);
  1150.  
  1151.     // Now the code to actually do the drawing
  1152.     if (_isPrinterDC)
  1153.     {
  1154.       GpiCharStringAt (_hdc, &poss, strlen(text), text);
  1155.     }
  1156.     else
  1157.     {
  1158.       // need to turn off cursor during screen update
  1159.       GpiCharStringAt (_hdc, &poss, strlen(text), text);
  1160.     }
  1161.  
  1162.     if ((attr & ChReverse) || (attr & ChHighlight))
  1163.     {
  1164.       _htext->usBackMixMode = BM_LEAVEALONE;
  1165.       _htext->lBackColor = orgbgc;
  1166.       _htext->lColor = orgfgc;
  1167.       GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_BACK_MIX_MODE | CBB_COLOR, 0, _htext);
  1168.     }
  1169.     else
  1170.     {
  1171.       _htext->usBackMixMode = BM_LEAVEALONE;
  1172.       GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_MIX_MODE, 0, _htext);
  1173.     }
  1174.  
  1175.     EndPaint();
  1176.   }
  1177.  
  1178. //=====================>>> vWinDC::DrawText <<<==========================
  1179.   void vWinDC::DrawText(int x, int y, VCONST char* text)
  1180.   {
  1181.     // simple draw text at given x, y
  1182.     // First, do the required scaling
  1183.     if (!text || !*text)
  1184.       return;
  1185.  
  1186.     BeginPaint();
  1187.     POINTL poss;
  1188.     poss.x = Scale(x+_tx);
  1189.     poss.y = Scale(y+_ty);
  1190.     MapToOS2(&poss);
  1191.  
  1192.     _font.LoadFont(_hdc);              // need to setup font!
  1193.     _htext = _font.GetHFONT();
  1194.  
  1195.     _htext->lColor = _pen.GetColor().pixel();
  1196.     _htext->lBackColor = _canvasBG;
  1197.     _htext->usBackMixMode = BM_OVERPAINT;
  1198.     _htext->usTextAlign = TA_BOTTOM | TA_LEFT;
  1199.     GpiSetAttrs(_hdc, PRIM_CHAR,
  1200.       CBB_BACK_COLOR | CBB_COLOR | CBB_TEXT_ALIGN | CBB_BACK_MIX_MODE, 0, _htext);
  1201.  
  1202.     // Now the code to actually do the drawing
  1203.     // We fudge the y position to accomodate the
  1204.     // model transform that puts the origin at the top left.
  1205.     if (_isPrinterDC)
  1206.     {
  1207. //      poss.y = poss.y + _font.GetPointSize();
  1208.       GpiCharStringAt (_hdc, &poss, strlen(text), text);
  1209.     }
  1210.     else
  1211.     {
  1212.       // need to turn off cursor during screen update
  1213.       GpiCharStringAt (_hdc, &poss, strlen(text), text);
  1214.     }
  1215.  
  1216.     // restore to deafult mix mode
  1217.     _htext->usBackMixMode = BM_LEAVEALONE;
  1218.     GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_MIX_MODE, 0, _htext);
  1219.  
  1220.     EndPaint();
  1221.   }
  1222.  
  1223. //=====================>>> vWinDC::SetBrush <<<============================
  1224.   void vWinDC::SetBrush(VCONST vBrush& brush)
  1225.   {
  1226.     _brush = brush;
  1227.   }
  1228.  
  1229. //=====================>>> vWinDC::SetPen <<<============================
  1230.   void vWinDC::SetPen(VCONST vPen& pen)
  1231.   {
  1232.     _pen = pen;
  1233.   }
  1234.  
  1235. //====================>>> vWinDC::TextHeight <<<=============================
  1236.   int vWinDC::TextHeight(int& asc, int& des) VCONST
  1237.   {
  1238.     // Return total height of this font. V will use total height, which
  1239.     // is most often made up of ascent + descent.  This is too much
  1240.     // detail for the kind of apps V will support.
  1241.     _font.LoadFont(_hdc);              // need to setup font!
  1242.     _htext = _font.GetHFONT();
  1243.     _htext->usTextAlign = TA_BOTTOM | TA_LEFT;
  1244.     GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_COLOR | CBB_TEXT_ALIGN, 0, _htext);
  1245.  
  1246.     FONTMETRICS fm;
  1247.     int a = 5, d = 3;                  // something reasonable?
  1248.     GpiQueryFontMetrics (_hdc, sizeof(FONTMETRICS), &fm);
  1249.     a = fm.lMaxAscender;
  1250.     d = fm.lMaxDescender;
  1251.  
  1252.     asc = a ; des = d;
  1253.  
  1254.     if (_isPrinterDC)  // need to correct for the scaling of the print canvas
  1255.     {
  1256.       return ((a+d)*65536/_OS2Scale);
  1257.     }
  1258.     else
  1259.     {
  1260.       return (a+d);
  1261.     }
  1262.   }
  1263.  
  1264. //========================>>> vvWinDC::TextWidth <<<==========================
  1265.   int vWinDC::TextWidth(char* str) VCONST
  1266.   {
  1267.     _font.LoadFont(_hdc);              // need to setup font!
  1268.     _htext = _font.GetHFONT();
  1269.     GpiSetAttrs(_hdc, PRIM_CHAR, CBB_BACK_COLOR | CBB_COLOR, 0, _htext);
  1270.  
  1271.     POINTL box[TXTBOX_COUNT];
  1272.     GpiQueryTextBox (_hdc, strlen(str), str, TXTBOX_COUNT, box);
  1273.  
  1274.     int width = box[TXTBOX_TOPRIGHT].x - box[TXTBOX_TOPLEFT].x;
  1275.  
  1276.     if (_isPrinterDC)  // need to correct for the scaling of the print canvas
  1277.     {
  1278.       return (width*65536/_OS2Scale);
  1279.     }
  1280.     else
  1281.     {
  1282.       return (width);
  1283.     }
  1284.   }
  1285.  
  1286. //========================>>> vvWinDC::MapToOS2 <<<===========================
  1287.   void vWinDC::MapToOS2(PPOINTL in)
  1288.   {
  1289.     // we use the OS/2 FIXED data type to handle fractional
  1290.     // scaling while retaining integer math
  1291.     ULONG m, f;
  1292.  
  1293.     m = HIUSHORT(_OS2Scale);
  1294.     f = LOUSHORT(_OS2Scale);
  1295.     in->y = -(1-_OS2Height + in->y);
  1296.     in->y = (in->y * m) + (in->y * f/65536);
  1297.     in->x = (in->x * m) + (in->x * f/65536);
  1298.   }
  1299.  
  1300. //========================>>> vvWinDC::MapFromOS2 <<<=========================
  1301.   void vWinDC::MapFromOS2(PPOINTL in)
  1302.   {
  1303.     // we use the OS/2 FIXED data type to handle fractional
  1304.     // scaling while retaining integer math
  1305.     in->y = -(1-_OS2Height + (in->y * 65536/_OS2Scale) );
  1306.     in->x = in->x * 65536/_OS2Scale;
  1307.   }
  1308.  
  1309.  
  1310.