| Current Path : /var/www/html/prashantkr/TurboC/TCWIN45/SOURCE/OWL/ |
| Current File : /var/www/html/prashantkr/TurboC/TCWIN45/SOURCE/OWL/BUTTONGA.CPP |
//----------------------------------------------------------------------------
// ObjectWindows
// (C) Copyright 1992, 1994 by Borland International, All Rights Reserved
//
// Implementation of class TButtonGadget.
//----------------------------------------------------------------------------
#include <owl/owlpch.h>
#include <owl/buttonga.h>
#include <owl/gadgetwi.h>
#include <owl/celarray.h>
//
// make the monochrome bitmap large enough to hold any possible bitmap
//
#define GLYPH_MASK_WIDTH 128
#define GLYPH_MASK_HEIGHT 128
const long RopPSDPxax = 0x00B8074AL; //
const long RopDSPDxax = 0x00E20746L; //
//
// local 'class' vars
//
static THatch8x8Brush ditherBrush(THatch8x8Brush::Hatch11F1,
::GetSysColor(COLOR_BTNHIGHLIGHT),
::GetSysColor(COLOR_BTNHIGHLIGHT));
static TBitmap glyphMask(GLYPH_MASK_WIDTH, GLYPH_MASK_HEIGHT, 1, 1, 0);
//
// command enabler for button gadgets
//
class _OWLCLASS TButtonGadgetEnabler : public TCommandEnabler {
public:
TButtonGadgetEnabler(HWND hWndReceiver, TButtonGadget* g)
: TCommandEnabler(g->GetId(), hWndReceiver) {
Gadget = g;
}
//
// override member functions of TCommandEnabler
//
void Enable(bool);
void SetText(const char far*);
void SetCheck(int);
protected:
TButtonGadget* Gadget;
};
void
TButtonGadgetEnabler::Enable(bool enable)
{
TCommandEnabler::Enable(enable);
Gadget->SetEnabled(enable);
}
void
TButtonGadgetEnabler::SetText(const char far*)
{
# pragma warn -ccc
CHECK(false);
# pragma warn .ccc
}
void
TButtonGadgetEnabler::SetCheck(int state)
{
Gadget->SetButtonState(TButtonGadget::TState(state));
}
TButtonGadget::TButtonGadget(TResId bmpResId,
int id,
TType type,
bool enabled,
TState state,
bool repeat)
:
TGadget(id, Plain)
{
ResId = bmpResId.IsString() ? strnewdup(bmpResId) : (char far*)bmpResId;
CelArray = 0;
BitmapOrigin.x = BitmapOrigin.y = 0;
Type = type;
Repeat = repeat;
TrackMouse = true;
State = state;
NotchCorners = true;
Pressed = false;
SetEnabled(enabled);
SetShadowStyle(DoubleShadow);
SetAntialiasEdges(true);
}
TButtonGadget::~TButtonGadget()
{
delete CelArray;
if (ResId.IsString())
delete (char far*)ResId;
}
void
TButtonGadget::SetShadowStyle(TShadowStyle shadowStyle)
{
TBorders borders;
ShadowStyle = shadowStyle;
borders.Left = borders.Top = 2;
borders.Right = borders.Bottom = ShadowStyle + 1;
SetBorders(borders);
}
void
TButtonGadget::CommandEnable()
{
// Must send, not post here, since a ptr to a temp is passed
//
Window->Parent->HandleMessage(
WM_COMMAND_ENABLE,
0,
(LPARAM)&TButtonGadgetEnabler(*Window->Parent, this)
);
}
void
TButtonGadget::SysColorChange()
{
ditherBrush.Reconstruct(THatch8x8Brush::Hatch11F1,
::GetSysColor(COLOR_BTNHIGHLIGHT),
::GetSysColor(COLOR_BTNHIGHLIGHT));
BuildCelArray();
}
void
TButtonGadget::CheckExclusively()
{
if (State != Down) {
if (Window) {
TGadget* g = Window->FirstGadget();
TButtonGadget* first = 0;
TButtonGadget* last = this;
//
// look for the start of the group in which the receiver is located
//
while (g != this) {
TButtonGadget* bg = TYPESAFE_DOWNCAST(g, TButtonGadget);
if (!bg || bg->Type != Exclusive)
first = 0;
else if (!first)
first = bg;
g = g->NextGadget();
}
if (!first)
first = this;
// Look for the end of the group in which the receiver is located
//
while (last->NextGadget()) {
TButtonGadget* bg = TYPESAFE_DOWNCAST(last->NextGadget(), TButtonGadget);
if (!bg || bg->Type != Exclusive)
break;
else
last = bg;
}
while (true) {
CHECK(first); // Already know they are buttons, but just in case...
if (first->State == Down) {
first->State = Up;
first->Invalidate();
first->Update();
}
if (first == last)
break;
first = TYPESAFE_DOWNCAST(first->NextGadget(), TButtonGadget);
}
}
State = Down;
}
}
void
TButtonGadget::SetButtonState(TState state)
{
if (state != State) {
if (Type == Exclusive && state == Down)
CheckExclusively();
State = state;
Invalidate();
Update();
}
}
void
TButtonGadget::SetBounds(TRect& bounds)
{
TRect innerRect;
TSize bitmapSize = CelArray->CelSize();
TGadget::SetBounds(bounds);
// Center the glyph within the inner bounds
//
GetInnerRect(innerRect);
BitmapOrigin.x = innerRect.left + (innerRect.Width() - bitmapSize.cx) / 2;
BitmapOrigin.y = innerRect.top + (innerRect.Height() - bitmapSize.cy) / 2;
}
void
TButtonGadget::GetDesiredSize(TSize& size)
{
TGadget::GetDesiredSize(size);
if (!CelArray)
BuildCelArray();
size += CelArray->CelSize();
}
//
// determines the parts of "r1" that do not lie within "r2"
//
// returns the resulting number of rectangles which will be in the
// range "0 .. 4" inclusive
//
uint
Subtract(TRect& r1, TRect& r2, TRect result[4])
{
if (!r1.Touches(r2)) {
result[0] = r1;
return 1;
}
else {
uint i = 0;
if (r2.top > r1.top) {
result[i].left = r1.left;
result[i].top = r1.top;
result[i].right = r1.right;
result[i].bottom = r2.top;
i++;
}
if (r2.bottom < r1.bottom) {
result[i].left = r1.left;
result[i].top = r2.bottom;
result[i].right = r1.right;
result[i].bottom = r1.bottom;
i++;
}
if (r2.left > r1.left) {
result[i].left = r1.left;
result[i].top = max(r1.top, r2.top);
result[i].right = r2.left;
result[i].bottom = min(r1.bottom, r2.bottom);
i++;
}
if (r2.right < r1.right) {
result[i].left = r2.right;
result[i].top = max(r1.top, r2.top);
result[i].right = r1.right;
result[i].bottom = min(r1.bottom, r2.bottom);
i++;
}
return i;
}
}
//
// build a monochrome mask bitmap for the glyph that has 1's where
// COLOR_BTNFACE is and 0's everywhere else. assumes glyphDC is already setup
//
static void
BuildMask(TDC& maskDC, TRect& maskRect, TDC& glyphDC, TRect& glyphRect)
{
maskDC.PatBlt(0, 0, maskRect.Width(), maskRect.Height(), WHITENESS);
glyphDC.SetBkColor(GetSysColor(COLOR_BTNFACE)); // btnface to white
maskDC.BitBlt(maskRect.left, maskRect.top, glyphRect.Width(), glyphRect.Height(),
glyphDC, glyphRect.left, glyphRect.top, SRCCOPY);
}
//
// tiles the rectangle with a even dithered (checkerboard) pattern
//
// maskDC determines the stencil area of dither
//
static void
DitherBackground(TDC& dc, TDC& maskDC, TRect& rect)
{
dc.SelectObject(HBRUSH(ditherBrush));
dc.SetTextColor(RGB(0, 0, 0)); // 0 to black
dc.SetBkColor(RGB(255, 255, 255)); // 1 to white
dc.BitBlt(rect, maskDC, TPoint(0, 0), RopDSPDxax);
}
//
// virtual function responsible for supplying glyphdib. Can be overriden to
// get dib from elsewhere, cache it, map colors differently, etc.
//
TDib*
TButtonGadget::GetGlyphDib()
{
TDib* glyph = new TDib(*Window->GetModule(), ResId);
glyph->MapUIColors(
TDib::MapFace | TDib::MapText | TDib::MapShadow | TDib::MapHighlight
);
return glyph;
}
//
// virtual function responsible for releasing glyph dib as needed based on how
// GetGlyphDib() got it (if different from new/delete).
//
void
TButtonGadget::ReleaseGlyphDib(TDib* glyph)
{
delete glyph;
}
//
// Build the CelArray member using the resource bitmap as the base glyph
// CelArray may contain an existing cel array that should be deleted if
// replaced
//
void
TButtonGadget::BuildCelArray()
{
//
// Get the base glyph as a dib, & map the colors to current SysColors.
//
TDib* glyph = GetGlyphDib();
TSize celSize = glyph->Size();
//
// Create a TCelArray if we don't already have one, else use existing one.
//
if (!CelArray) {
TBitmap* bitmap = new TBitmap(TScreenDC(), celSize.cx*CelsTotal,
celSize.cy);
CelArray = new TCelArray(bitmap, CelsTotal);
}
TMemoryDC maskDC;
maskDC.SelectObject(glyphMask);
TRect maskRect(0,0, celSize.cx, celSize.cy);
TMemoryDC celDC;
celDC.SelectObject(*CelArray);
//
// CelArray[CelNormal]: normal appearance, blit directly from the glyph dib
//
TRect nrmlCelRect = CelArray->CelRect(CelNormal);
celDC.StretchDIBits(nrmlCelRect, maskRect, *glyph);
ReleaseGlyphDib(glyph);
//
// CelArray[CelDisabled]: disabled variant of glyph
//
TRect celRect = CelArray->CelRect(CelDisabled);
//
// make sure area under highlight color ends up face color
//
BuildMask(maskDC, maskRect, celDC, nrmlCelRect);
celDC.TextRect(celRect, GetSysColor(COLOR_BTNFACE));
//
// inactivate mask--convert the highlight color to 1's on existing mask
//
celDC.SetBkColor(GetSysColor(COLOR_BTNHIGHLIGHT));
maskDC.BitBlt(maskRect, celDC, nrmlCelRect.TopLeft(), SRCPAINT);
//
// make the image look embossed--highlight color offset down & right
//
celDC.SetTextColor(RGB(0, 0, 0)); // 0 to black
celDC.SetBkColor(RGB(255, 255, 255)); // 1 to white
TBrush hiliteBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
celDC.SelectObject(hiliteBrush); // 0 -> highlight color
celDC.BitBlt(celRect.left + 1, celRect.top + 1,
celRect.Width() - 1, celRect.Height() - 1,
maskDC, 0, 0, RopPSDPxax);
//
// fade the image by replacing the button text color with the button
// shadow color
//
TBrush shadowBrush(GetSysColor(COLOR_BTNSHADOW));
celDC.SelectObject(shadowBrush); // 0 -> shadow
celDC.BitBlt(celRect, maskDC, TPoint(0, 0), RopPSDPxax);
//
// CelArray[CelIndeterm]: Indeterminate variant of glyph
//
celRect = CelArray->CelRect(CelIndeterm);
//
// fade the image by replacing the button text color with the button
// shadow color
//
celDC.SelectObject(shadowBrush); // 0 -> shadow
celDC.BitBlt(celRect, maskDC, TPoint(0, 0), RopPSDPxax);
//
// dither the background everywhere except where the glyph is
//
DitherBackground(celDC, maskDC, celRect);
//
// CelArray[CelDown]: Down (but not Pressed) variant of glyph
//
celRect = CelArray->CelRect(CelDown);
celDC.BitBlt(celRect, celDC, CelArray->CelRect(CelNormal).TopLeft(), SRCCOPY);
//
// dither the background everywhere except where the glyph is
//
BuildMask(maskDC, maskRect, celDC, celRect);
DitherBackground(celDC, maskDC, celRect);
maskDC.RestoreBitmap();
celDC.RestoreBitmap();
celDC.RestoreBitmap();
celDC.RestoreBrush();
}
//
//
//
void
TButtonGadget::Paint(TDC& dc)
{
int cxBorder = GetSystemMetrics(SM_CXBORDER);
int cyBorder = GetSystemMetrics(SM_CYBORDER);
TPoint bitmapOrigin = BitmapOrigin;
TRect innerRect(cxBorder, cyBorder,
Bounds.Width()-cxBorder, Bounds.Height()-cyBorder);
PaintBorder(dc); // Assumes Plain border--other styles will be overpainted
TBrush faceBrush(GetSysColor(COLOR_BTNFACE));
TBrush hiliteBrush(GetSysColor(COLOR_BTNHIGHLIGHT));
TBrush shadowBrush(GetSysColor(COLOR_BTNSHADOW));
//
// draw top and left
//
int shadow = Pressed && Type != Command ? 2 : 1;
dc.SelectObject(Pressed || State == Down ? shadowBrush : hiliteBrush);
dc.PatBlt(innerRect.left, innerRect.top,
innerRect.Width(), shadow * cyBorder, PATCOPY);
dc.PatBlt(innerRect.left, innerRect.top,
shadow * cxBorder, innerRect.Height(), PATCOPY);
if (Pressed || State == Down) {
innerRect.left += shadow * cxBorder;
innerRect.top += shadow * cyBorder;
}
else {
int i = 0;
//
// draw right and bottom
//
dc.SelectObject(shadowBrush);
innerRect.bottom -= cyBorder;
innerRect.right -= cxBorder;
while (true) {
dc.PatBlt(innerRect.left, innerRect.bottom,
innerRect.Width() + cxBorder, cyBorder, PATCOPY);
dc.PatBlt(innerRect.right, innerRect.top,
cxBorder, innerRect.Height(), PATCOPY);
if (++i == ShadowStyle)
break;
innerRect.Inflate(-cxBorder, -cyBorder);
}
}
if (NotchCorners || AntialiasEdges && State == Up && !Pressed) {
dc.SelectObject(faceBrush);
if (NotchCorners) {
dc.PatBlt(0, 0, cxBorder, cyBorder);
dc.PatBlt(Bounds.Width() - cxBorder, 0, cxBorder, cyBorder);
dc.PatBlt(0, Bounds.Height() - cyBorder, cxBorder, cyBorder);
dc.PatBlt(Bounds.Width() - cxBorder, Bounds.Height() - cyBorder,
cxBorder, cyBorder);
}
if (AntialiasEdges && State == Up && !Pressed) {
TRect edge(0, 0, Bounds.Width(), Bounds.Height());
for (int i = 0; i <= shadow; i++) {
edge.Inflate(-cxBorder,-cyBorder);
dc.PatBlt(edge.right-cxBorder, edge.top, cxBorder, cyBorder);
dc.PatBlt(edge.left, edge.bottom-cyBorder, cxBorder, cyBorder);
}
}
dc.RestoreBrush();
}
//
// adjust the bitmap origin based on the state
//
if (Pressed || State == Down)
bitmapOrigin.Offset(shadow * cxBorder, shadow * cyBorder);
TRect bitmapRect(bitmapOrigin, CelArray->CelSize());
TMemoryDC celDC;
celDC.SelectObject(*CelArray);
//
// blit the appropriate cel at the calculated origin
//
if (!GetEnabled() || State == Indeterminate) {
if (!GetEnabled())
dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelDisabled).TopLeft());
else //(State == Indeterminate)
dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelIndeterm).TopLeft());
}
else {
TRect dirtyRects[4];
int numRects = Subtract(innerRect, bitmapRect, dirtyRects);
if (numRects) {
dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
while (numRects--)
dc.TextRect(dirtyRects[numRects]);
}
if (State == Down && !Pressed)
dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelDown).TopLeft());
else //(State == Up || Pressed)
dc.BitBlt(bitmapRect, celDC, CelArray->CelRect(CelNormal).TopLeft());
}
celDC.RestoreBitmap();
dc.RestoreBrush();
}
void
TButtonGadget::Invalidate()
{
TRect r(0, 0, Bounds.Width(), Bounds.Height());
r.Inflate(-GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
InvalidateRect(r, false);
}
//
// Begin button pressed state, repaint & enter menuselect state
//
void
TButtonGadget::BeginPressed(TPoint&)
{
Pressed = true;
Invalidate();
Update();
if (Window->GetHintMode() == TGadgetWindow::PressHints)
Window->SetHintCommand(GetId());
}
//
// Cancel pressed state, repaint & end menuselect state
//
void
TButtonGadget::CancelPressed(TPoint&)
{
Pressed = false;
Invalidate();
Update();
if (Window->GetHintMode() == TGadgetWindow::PressHints)
Window->SetHintCommand(-1);
}
void
TButtonGadget::Activate(TPoint& pt)
{
switch (Type) {
case Exclusive:
if (State != Down)
CheckExclusively();
break;
case NonExclusive:
State = State == Up ? Down : Up;
break;
}
CancelPressed(pt);
if (!(Type == Exclusive && State != Down) && GetEnabled())
Window->Parent->PostMessage(WM_COMMAND, GetId());
}
void
TButtonGadget::LButtonDown(uint modKeys, TPoint& pt)
{
TGadget::LButtonDown(modKeys, pt);
BeginPressed(pt);
}
void
TButtonGadget::MouseMove(uint modKeys, TPoint& pt)
{
TGadget::MouseMove(modKeys, pt);
bool hit = PtIn(pt);
if (Pressed) {
if (!hit)
CancelPressed(pt);
}
else if (hit) {
BeginPressed(pt);
}
}
void
TButtonGadget::MouseEnter(uint modKeys, TPoint& pt)
{
TGadget::MouseEnter(modKeys, pt);
if (Window->GetHintMode() == TGadgetWindow::EnterHints)
Window->SetHintCommand(GetId());
}
void
TButtonGadget::MouseLeave(uint modKeys, TPoint& pt)
{
TGadget::MouseLeave(modKeys, pt);
if (Window->GetHintMode() == TGadgetWindow::EnterHints)
Window->SetHintCommand(-1);
}
void
TButtonGadget::LButtonUp(uint modKeys, TPoint& pt)
{
TGadget::LButtonUp(modKeys, pt);
if (Pressed)
Activate(pt);
}