//-------------------------------------------------------------------
// OWL Extensions (OWLEXT) Class Library
// Copyright(c) 1996 by Manic Software.
// All rights reserved.
//
// TPictDecorator: Decorator-pattern-based class to add bitmap-backgrounds
//    to any OWL client window
//-------------------------------------------------------------------
#include <owlext\pch.h>
#pragma hdrstop
 
#include <owlext/pictdeco.h>
 
using namespace owl;
 
namespace OwlExt {
 
//
// Diagnostic group declarations/definitions
//
DIAG_DEFINE_GROUP_INIT(OWL_INI, OwlexPictDecor, 1, 0);
DIAG_DECLARE_GROUP(OwlMsg);
 
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//                                                                    TPictDialog
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TPictDecorator::TPictDecorator(TDib* dib, TWindow& decorated)
:
TWindow(decorated.GetHandle()),
pDib(dib)
{
  TRACEX(OwlexPictDecor, 1, "TPictDecorator constructed @ " << (void*)this);
  TRACEX(OwlexPictDecor, 2, "dib = " << (void*)dib << ", decorated = " << (void*)&decorated);
}
TPictDecorator::~TPictDecorator()
{
  TRACEX(OwlexPictDecor, 1, "TPictDecorator @ " << (void*)this << " destructed");
 
  // Note that we assume *no* responsibility for the TDib* by this method; we
  // probably should, but that's another issue.
}
 
 
DEFINE_RESPONSE_TABLE1(TPictDecorator, TWindow)
EV_WM_ERASEBKGND,
EV_WM_SIZE,
END_RESPONSE_TABLE;
 
bool TPictDecorator::EvEraseBkgnd(HDC hdc)
{
  TRACEX(OwlexPictDecor, 2, "TPictDecorator::EvEraseBkgnd entered");
 
  // Call back up the chain, in case the DIB doesn't cover the entire window
  //
  DefaultProcessing();
 
  // create a TDC based off of the DC handed to us
  //
  TDC dc(hdc);
 
  // From here on, code copied almost verbatim from TPictWindow
  //
 
  // Check if the DC supports palettes, and if so, select the DIB's into it
  //
  TPointer<TPalette> palette(0);
  bool hasPalette = ToBool(dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE);
  TDib* dib = pDib();
  // We could just use the op() form of TProperty<> everywhere we reference
  // 'dib' in the code below, but for speed reasons (which are pretty slim), I
  // choose to capture the pointer stored in the TProperty into a local var and
  // use that, instead.
 
  if (dib){
    if (hasPalette){
      TRACEX(OwlexPictDecor, 3, "TPictDecorator::EvEraseBkgnd: DC supports palettes; "
        "selecting and realizing DIB palette");
      palette = new TPalette(*dib);
      dc.SelectObject(*palette);
      dc.RealizePalette();
    }
 
    // figure out upper left corner of the client area
    //
    TRect clientRect(GetClientRect());
    TPoint sourcePoint(0, 0);
    TRACEX(OwlexPictDecor, 3, "TPictDecorator::EvEraseBkgnd: clientRect = " << clientRect);
 
    // determine offsets
    //
    int offsetX = abs(dib->Width() - clientRect.Width()) / 2;
    if (dib->Width() > clientRect.Width())
      sourcePoint.x += offsetX;
    else
      clientRect.Offset(offsetX, 0);
 
    int offsetY = abs(dib->Height() - clientRect.Height()) / 2;
    if (dib->Height() > clientRect.Height())
      sourcePoint.y += offsetY;
    else
      clientRect.Offset(0, offsetY);
 
    // adjust the lower right corner
    //
    clientRect.bottom = clientRect.top + dib->Height();
    clientRect.right  = clientRect.left + dib->Width();
 
    // if the picture is larger than screen dimensions,
    // adjust the upper left corner.
    //
    clientRect.top   -= sourcePoint.y;
    clientRect.left  -= sourcePoint.x;
 
    // display the dib
    //
    TRACEX(OwlexPictDecor, 3, "TPictDecorator::EvEraseBkgnd: Displaying dib;"
      " clientRect = " << clientRect << ", sourcePoint = " << sourcePoint);
    dc.SetDIBitsToDevice(clientRect, sourcePoint, *dib);
 
    // restore the DC to what it was
    //
    dc.RestoreObjects();
  } // if (dib)
 
  TRACEX(OwlexPictDecor, 2, "TPictDecorator::EvEraseBkgnd exited");
  return true;
}
void TPictDecorator::EvSize(uint /*sizeType*/, const TSize& /*size*/)
{
  // Because Windows 4.0 sends WM_SIZE messages to the window *as* the window
  // is being resized, the background pict can be drawn in weird ways, esp. if
  // the pict doesn't cover the entire size of the window. To help with this, I
  // force the entire background to be redrawn on each WM_SIZE message. This has
  // the unfortunate effect of causing some flicker in the redrawing process, but
  // if you care not to see that flicker, just comment out this entire event-handler
  // (and its corresponding macro in the TPictDecorator event-table) and you'll
  // see no flicker. I only recommend this for non-Windows 4.0 apps.
  //
  Invalidate();
 
  // Call back to the decorated window for help
  //
  DefaultProcessing();
}
 
 
} // OwlExt namespace
 
 
#ifdef TEST_THE_CODE
 
// Core
//
#include <owl/owlcore.h>
 
using namespace OwlExt;
 
int OwlMain(int, char* [])
{
  // Kick off default app with default frame window
  //
  GetApplicationObject()->Start();  //??????????????????????????????????????????
 
  // Create a vanilla TWindow with a TPictDecorator wrapped around it
  //
  TWindow* window = new TWindow(GetApplicationObject()->GetMainWindow());
  window->Create();
  // TPictDecorator requires an HWND it can subclass, so Create() window before
  // handing it off to TPictDecorator.
  TPictDecorator* pictDecor = new TPictDecorator(new TDib("CLOUDS.BMP"), *window);
  // pictDecor will be delete'd in the normal course of things, by TApplication
  // when it shuts down, so pictDecor *must* be a heap-allocated object!
 
  // Set the pictDecor to be the client window
  //
  GetApplicationObject()->GetMainWindow()->SetClientWindow(window);
 
  // Let 'er rip
  //
  return GetApplicationObject()->Run();
}
 
#endif

V821 Decreased performance. The 'palette' variable can be constructed in a lower level scope.