//===============================================================
// vMemoryDC - a memory drawing canvas - Windows
//
// 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/vmemdc.h>
#include <v/vapp.h>
//================>>> vMemoryDC::vMemoryDC <<<========================
  vMemoryDC::vMemoryDC(int width, int height)
  {
    SysDebug(Constructor,"vMemoryDC::vMemoryDC() constructor\n")
    // Mem canvases are implemented with bitmaps.
    // The idea is this. You create a bitmap (_memBM) that
    // is compatible with the canvas DC -
    // This gives the bitmap a nice color map. Then, the
    // tricky part. To use a bitmap, you have to select it into
    // a DC. So, you create a new DC (_hdc) , also compatible with
    // the canvas DC. Then you select the bitmap into the new
    // DC. Now you can draw into the new DC.
    // When you are ALL done, finally free the bitmap.

    _physHeight = width;
    _physWidth = height;

    if (_physWidth == 0)
	_physWidth = theApp->DefaultWidth();
    if (_physHeight == 0)
	_physHeight = theApp->DefaultHeight();

    _hdc = 0;
    _memBM = 0;

    // this is the contructor for the memory presentation space.  The first
    // thing to do is to create and associate the PS, then set the
    // defaults as needed.
    GetHDC();
  }
//================>>> vMemoryDC::~vMemoryDC <<<========================
  vMemoryDC::~vMemoryDC()
  {
    SysDebug(Destructor,"vMemoryDC::~vMemoryDC() destructor\n")

    if (!_memBM)
	return;

    // disassociate PS from window, then  destroy PS
    ReleaseHDC();

    GpiDeleteBitmap(_memBM);
    _memBM = 0;
  }

//====================>>> vMemoryDC::GetHDC <<<========================
  void vMemoryDC::GetHDC() VCONST
  {
    // Create the DC to draw into

    // build a memory PS compatible with calling PS
    HPS appDC = WinGetPS(theApp->winHwnd());
    HDC DevCxtComp = GpiQueryDevice(appDC);

    _DevCxtMem = DevOpenDC(theApp->AppHab(), OD_MEMORY, "*", 0L, NULL, DevCxtComp);
    SIZEL size = {_physWidth, _physHeight};
    _hdc = GpiCreatePS (theApp->AppHab(), _DevCxtMem, &size,
			PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC );

    // set the PS to RGB mode
    GpiCreateLogColorTable(_hdc, 0L, LCOLF_RGB, 0L, 0L, NULL);

    // set model space transform to put origin at upper left corner
    // since OS/2 puts the origin in the bottom left by default
/*
    MATRIXLF TransformMatrix;
    POINTL translate, origin;
    FIXED scale[2];
    translate.x = 0;
    translate.y = -_physHeight + 1;
    GpiTranslate(_hdc, &TransformMatrix, TRANSFORM_REPLACE, &translate);
    origin.x = 0; origin.y = 0;
    scale[0] = MAKEFIXED( 1,0);   // x scale
    scale[1] = MAKEFIXED(-1,0);   // y scale
    GpiScale(_hdc, &TransformMatrix, TRANSFORM_ADD, scale, &origin);
    GpiSetModelTransformMatrix(_hdc, 9, &TransformMatrix, TRANSFORM_REPLACE);
*/
    // bitmap is never scaled so set scaling to unity
    SetOS2Map(_physHeight, MAKEFIXED(1,0));

    // 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 = _physWidth;
    bmih.cy = _physHeight;
    bmih.ulColorEncoding = BCE_RGB;
    DevQueryCaps (_hdc, CAPS_COLOR_PLANES, 1, (PLONG) &bmih.cPlanes);
    DevQueryCaps (_hdc, CAPS_COLOR_BITCOUNT, 1, (PLONG) &bmih.cBitCount);
    _memBM = GpiCreateBitmap(_hdc, &bmih, 0L, NULL, NULL);

    // now we need to load the bitmap into the memory PS
    // so we can draw into the memory PS with the
    // GPI drawing API.
    GpiSetBitmap(_hdc, _memBM);

    // no need to keep the compatibility DC anymore
    WinReleasePS (appDC);
    // We are now ready to use _hdc!
    SysDebug1(Build,"vMemoryDC::GetHDC() _hdc=%u\n", _hdc);

  }
//================>>> vMemoryDC::ReleaseHDC <<<========================
  void vMemoryDC::ReleaseHDC() VCONST
  {
    if (_hdc == 0)
	return;

    GpiSetBitmap (_hdc, NULLHANDLE);
    GpiAssociate (_hdc, NULLHANDLE);
    GpiDestroyPS (_hdc);
    DevCloseDC (_DevCxtMem);
    _hdc = 0;
  }

//=====================>>> vCanvasPaneDC::Clear <<<==========================
  void vMemoryDC::Clear(void)
  {
    // CAUTION: rc coords are inclusive/exclusive
    RECTL rc={0, 0, _physWidth, _physHeight};
    WinFillRect (_hdc, &rc, _canvasBG);

    // V to OS/2 Coord Transform Equations:
    // (os/2)  y = -(1 - height + y)  (V)
    //
    // for inclusive/inclusive (ie. Gpi)
    //         y = -(yBottom - yTop + y)
    //  where  height = yTop - yBottom + 1
    //
    // for inclusive/exclusive (ie. Win)
    //         y = -(1 + yBottom - yTop + y)
    //  where    height = yTop - yBottom
/*
    MATRIXLF TransformMatrix;
    POINTL translate, origin;
    FIXED scale[2];
    translate.x = 0;
    translate.y = (rc.yBottom - rc.yTop) + 1;
    GpiTranslate(_hdc, &TransformMatrix, TRANSFORM_REPLACE, &translate);
    origin.x = 0; origin.y = 0;
    scale[0] = MAKEFIXED( 1,0);   // x scale
    scale[1] = MAKEFIXED(-1,0);   // y scale
    GpiScale(_hdc, &TransformMatrix, TRANSFORM_ADD, scale, &origin);
    GpiSetModelTransformMatrix(_hdc, 9, &TransformMatrix, TRANSFORM_REPLACE);
*/
    // bitmap is never scaled so set scaling to unity
    SetOS2Map(rc.yTop - rc.yBottom, MAKEFIXED(1,0));

  }
//==================>>> vCanvasPaneDC::ClearRect <<<==========================
  void vMemoryDC::ClearRect(int left, int bottom, int width, int height)
  {
    SysDebug(WindowEvents,"vMemoryDC::ClearRect()\n")

    // Clear a rectangular area starting at left, bottom of width and height
    if (height == 0 || width == 0)
	return;
    RECTL rc;
    rc.yBottom = bottom; rc.xLeft = left;
    rc.yTop = bottom+height; rc.xRight = left+width;
    WinFillRect (_hdc, &rc, _canvasBG);

    // CAUTION: returned rc coords are inclusive/exclusive
    rc.yBottom = 0; rc.xLeft = 0;
    rc.yTop = _physHeight; rc.xRight = _physWidth;

    // V to OS/2 Coord Transform Equations:
    // (os/2)  y = -(1 - height + y)  (V)
    //
    // for inclusive/inclusive (ie. Gpi)
    //         y = -(yBottom - yTop + y)
    //  where  height = yTop - yBottom + 1
    //
    // for inclusive/exclusive (ie. Win)
    //         y = -(1 + yBottom - yTop + y)
    //  where    height = yTop - yBottom
/*
    MATRIXLF TransformMatrix;
    POINTL translate, origin;
    FIXED scale[2];
    translate.x = 0;
    translate.y = (rc.yBottom - rc.yTop) + 1;
    GpiTranslate(_hdc, &TransformMatrix, TRANSFORM_REPLACE, &translate);
    origin.x = 0; origin.y = 0;
    scale[0] = MAKEFIXED( 1,0);   // x scale
    scale[1] = MAKEFIXED(-1,0);   // y scale
    GpiScale(_hdc, &TransformMatrix, TRANSFORM_ADD, scale, &origin);
    GpiSetModelTransformMatrix(_hdc, 9, &TransformMatrix, TRANSFORM_REPLACE);
*/
    // bitmap is never scaled so set scaling to unity
    SetOS2Map(rc.yTop - rc.yBottom, MAKEFIXED(1,0));
  }

//================>>> vCanvasPaneDC::SetBackground <<<==========================
  void vMemoryDC::SetBackground(VCONST vColor& color)
  {
    _canvasBG = color.pixel();		// retrieve X pixel value
    GpiSetBackColor (_hdc, _canvasBG);
    Clear();
  }
//======================>>> vCanvasPaneDC::SetFont <<<===========================
  void vMemoryDC::SetFont(VCONST vFont& vf)
  {
    // Change the font associated with this window.
    _font = vf;
  }
