windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/msconfwb/grobj.cpp
2020-09-26 16:20:57 +08:00

5125 lines
112 KiB
C++
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// GROBJ.CPP
// Graphic Objects
//
// Copyright Microsoft 1998-
//
// PRECOMP
#include "precomp.h"
#define DECIMAL_PRECISION 10000
//
// Local macros
//
#define min4(x1,x2,x3,x4) min((min((x1),(x2))),(min((x3),(x4))))
#define max4(x1,x2,x3,x4) max((max((x1),(x2))),(max((x3),(x4))))
//
// CircleHit()
//
// Checks for overlap between circle at PcxPcy with uRadius and
// lpHitRect. If overlap TRUE is returned, otherwise FALSE.
//
BOOL CircleHit( LONG Pcx, LONG Pcy, UINT uRadius, LPCRECT lpHitRect,
BOOL bCheckPt )
{
RECT hr = *lpHitRect;
RECT ellipse;
ellipse.left = Pcx - uRadius;
ellipse.right= Pcx + uRadius;
ellipse.bottom = Pcy + uRadius;
ellipse.top = Pcy - uRadius;
// check the easy thing first (don't use PtInRect)
if( bCheckPt &&(lpHitRect->left >= ellipse.left)&&(ellipse.right >= lpHitRect->right)&&
(lpHitRect->top >= ellipse.top)&&(ellipse.bottom >= lpHitRect->bottom))
{
return( TRUE );
}
//
// The circle is just a boring ellipse
//
return EllipseHit(&ellipse, bCheckPt, uRadius, lpHitRect );
}
//
// EllipseHit()
//
// Checks for overlap between ellipse defined by lpEllipseRect and
// lpHitRect. If overlap TRUE is returned, otherwise FALSE.
//
BOOL EllipseHit(LPCRECT lpEllipseRect, BOOL bBorderHit, UINT uPenWidth,
LPCRECT lpHitRect )
{
RECT hr = *lpHitRect;
// Check easy thing first. If lpEllipseRect is inside lpHitRect
// then we have a hit (no duh...)
if( (hr.left <= lpEllipseRect->left)&&(hr.right >= lpEllipseRect->right)&&
(hr.top <= lpEllipseRect->top)&&(hr.bottom >= lpEllipseRect->bottom) )
return( TRUE );
// If this is an ellipse....
//
// * * ^
// * | b | Y
// * | a +-------> X
// *-------+--------
// |
//
//
// Look for the ellipse hit. (x/a)^2 + (y/b)^2 = 1
// If it is > 1 than the point is outside the ellipse
// If it is < 1 it is inside
//
LONG a,b,aOuter, bOuter, x, y, xCenter, yCenter;
BOOL bInsideOuter = FALSE;
BOOL bOutsideInner = FALSE;
//
// Calculate a and b
//
a = (lpEllipseRect->right - lpEllipseRect->left)/2;
b = (lpEllipseRect->bottom - lpEllipseRect->top)/2;
//
// Get the center of the ellipse
//
xCenter = lpEllipseRect->left + a;
yCenter = lpEllipseRect->top + b;
//
// a and b generates a inner ellipse
// aOuter and bOuter generates a outer ellipse
//
aOuter = a + uPenWidth + 1;
bOuter = b + uPenWidth + 1;
a = a - 1;
b = b - 1;
//
// Make our coordinates relative to the center of the ellipse
//
y = abs(hr.bottom - yCenter);
x = abs(hr.right - xCenter);
//
// Be carefull not to divide by 0
//
if((a && b && aOuter && bOuter) == 0)
{
return FALSE;
}
//
// We are using LONG instead of double and we need to have some precision
// that is why we multiply the equation of the ellipse
// ((x/a)^2 + (y/b)^2 = 1) by DECIMAL_PRECISION
// Note that the multiplication has to be done before the division, if we didn't do that
// we will always get 0 or 1 for x/a
//
if(x*x*DECIMAL_PRECISION/(aOuter*aOuter) + y*y*DECIMAL_PRECISION/(bOuter*bOuter) <= DECIMAL_PRECISION)
{
bInsideOuter = TRUE;
}
if(x*x*DECIMAL_PRECISION/(a*a)+ y*y*DECIMAL_PRECISION/(b*b) >= DECIMAL_PRECISION)
{
bOutsideInner = TRUE;
}
//
// If we are checking for border hit,
// we need to be inside the outer ellipse and inside the inner
//
if( bBorderHit )
{
return( bInsideOuter & bOutsideInner );
}
// just need to be inside the outer ellipse
else
{
return( bInsideOuter );
}
}
//
// LineHit()
//
// Checks for overlap (a "hit") between lpHitRect and the line
// P1P2 accounting for line width. If bCheckP1End or bCheckP2End is
// TRUE then a circle of radius 0.5 * uPenWidth is also checked for
// a hit to account for the rounded ends of wide lines.
//
// If a hit is found TRUE is returned, otherwise FALSE.
//
BOOL LineHit( LONG P1x, LONG P1y, LONG P2x, LONG P2y, UINT uPenWidth,
BOOL bCheckP1End, BOOL bCheckP2End,
LPCRECT lpHitRect )
{
LONG uHalfPenWidth = uPenWidth/2;
LONG a,b,x,y;
x = lpHitRect->left + (lpHitRect->right - lpHitRect->left)/2;
y = lpHitRect->bottom + (lpHitRect->top - lpHitRect->bottom)/2;
if( (P1x == P2x)&&(P1y == P2y) )
{
// just check one end point's circle
return( CircleHit( P1x, P1y, uHalfPenWidth, lpHitRect, TRUE ) );
}
// check rounded end at P1
if( bCheckP1End && CircleHit( P1x, P1y, uHalfPenWidth, lpHitRect, FALSE ) )
return( TRUE );
// check rounded end at P2
if( bCheckP2End && CircleHit( P2x, P2y, uHalfPenWidth, lpHitRect, FALSE ) )
return( TRUE );
//
// The function of a line is Y = a.X + b
//
// a = (Y1-Y2)/(X1 -X2)
// if we found a we get b = y1 -a.X1
//
if(P1x == P2x)
{
a=0;
b = DECIMAL_PRECISION*P1x;
}
else
{
a = (P1y - P2y)*DECIMAL_PRECISION/(P1x - P2x);
b = DECIMAL_PRECISION*P1y - a*P1x;
}
//
// Paralel to Y
//
if(P1x == P2x && ((x >= P1x - uHalfPenWidth) && x <= P1x + uHalfPenWidth))
{
return TRUE;
}
//
// Paralel to X
//
if(P1y == P2y && ((y >= P1y - uHalfPenWidth) && y <= P1y + uHalfPenWidth))
{
return TRUE;
}
//
// General line
//
return(( y*DECIMAL_PRECISION <= a*x + b + DECIMAL_PRECISION*uHalfPenWidth) &
( y*DECIMAL_PRECISION >= a*x + b - DECIMAL_PRECISION*uHalfPenWidth));
}
//
//
// Function: ConstructGraphic
//
// Purpose: Construct a graphic from a page and handle
//
//
DCWbGraphic* DCWbGraphic::ConstructGraphic(WB_PAGE_HANDLE hPage,
WB_GRAPHIC_HANDLE hGraphic)
{
PWB_GRAPHIC pHeader;
DCWbGraphic* pGraphic;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ConstructGraphic(page, handle)");
// Get a pointer to the external graphic data
// (Throws an exception if any errors occur)
pHeader = PG_GetData(hPage, hGraphic);
// Construct the graphic
pGraphic = DCWbGraphic::ConstructGraphic(pHeader);
// If we got the graphic, set its page and handle
if (pGraphic != NULL)
{
pGraphic->m_hPage = hPage;
pGraphic->m_hGraphic = hGraphic;
}
g_pwbCore->WBP_GraphicRelease(hPage, hGraphic, pHeader);
return pGraphic;
}
DCWbGraphic* DCWbGraphic::ConstructGraphic(WB_PAGE_HANDLE hPage,
WB_GRAPHIC_HANDLE hGraphic,
PWB_GRAPHIC pHeader)
{
DCWbGraphic* pGraphic;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ConstructGraphic(page, pHeader)");
pGraphic = DCWbGraphic::ConstructGraphic(pHeader);
// If we got the graphic, set its page and handle
if (pGraphic != NULL)
{
pGraphic->m_hPage = hPage;
pGraphic->m_hGraphic = hGraphic;
}
return pGraphic;
}
DCWbGraphic* DCWbGraphic::ConstructGraphic(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ConstructGraphic(data)");
TRACE_DEBUG(("Constructing graphic of type %hd", pHeader->type));
TRACE_DEBUG(("Length of graphic = %ld", pHeader->length));
TRACE_DEBUG(("Data offset = %hd", pHeader->dataOffset));
// Construct the internal representation of the graphic
DCWbGraphic* pGraphic = NULL;
if (pHeader == NULL)
{
return NULL;
}
switch (pHeader->type)
{
case TYPE_GRAPHIC_LINE:
pGraphic = new DCWbGraphicLine(pHeader);
break;
case TYPE_GRAPHIC_FREEHAND:
pGraphic = new DCWbGraphicFreehand(pHeader);
break;
case TYPE_GRAPHIC_RECTANGLE:
pGraphic = new DCWbGraphicRectangle(pHeader);
break;
case TYPE_GRAPHIC_FILLED_RECTANGLE:
pGraphic = new DCWbGraphicFilledRectangle(pHeader);
break;
case TYPE_GRAPHIC_ELLIPSE:
pGraphic = new DCWbGraphicEllipse(pHeader);
break;
case TYPE_GRAPHIC_FILLED_ELLIPSE:
pGraphic = new DCWbGraphicFilledEllipse(pHeader);
break;
case TYPE_GRAPHIC_TEXT:
pGraphic = new DCWbGraphicText(pHeader);
break;
case TYPE_GRAPHIC_DIB:
pGraphic = new DCWbGraphicDIB(pHeader);
break;
default:
// Do nothing, the object pointer is already set to NULL
break;
}
if (!pGraphic)
{
ERROR_OUT(("ConstructGraphic failing; can't allocate object of type %d",
pHeader->type));
}
return pGraphic;
}
//
//
// Function: CopyGraphic
//
// Purpose: Construct a graphic from a pointer. This function makes a
// complete internal copy of the graphic data.
//
//
DCWbGraphic* DCWbGraphic::CopyGraphic(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::CopyGraphic(PWB_GRAPHIC)");
// Construct the graphic
DCWbGraphic* pGraphic = DCWbGraphic::ConstructGraphic(pHeader);
// Copy the extra data
if (pGraphic != NULL)
{
pGraphic->CopyExtra(pHeader);
}
return pGraphic;
}
//
//
// Function: DCWbGraphic constructor
//
// Purpose: Construct a new graphic object.
//
//
DCWbGraphic::DCWbGraphic(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::DCWbGraphic");
// Do basic initialization
Initialize();
// Convert the external data header to the internal member variables
if (pHeader != NULL)
{
ReadHeader(pHeader);
// Convert the extra data for the specific object
// (not all objects have extra data).
ReadExtra(pHeader);
}
}
DCWbGraphic::DCWbGraphic(WB_PAGE_HANDLE hPage, WB_GRAPHIC_HANDLE hGraphic)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::DCWbGraphic");
// Do the basic initialization
Initialize();
ASSERT(hPage != WB_PAGE_HANDLE_NULL);
m_hPage = hPage;
ASSERT(hGraphic != NULL);
m_hGraphic = hGraphic;
// Read the header data
ReadExternal();
}
DCWbGraphic::~DCWbGraphic( void )
{
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphic::ReadExternal
//
// Purpose: Read the graphic data from an externally stored graphic.
// The external graphic to be used is specified by the
// hGraphic member.
//
//
void DCWbGraphic::ReadExternal(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ReadExternal");
ASSERT(m_hPage != WB_PAGE_HANDLE_NULL);
ASSERT(m_hGraphic != NULL);
// Lock the object data in the page
PWB_GRAPHIC pHeader = PG_GetData(m_hPage, m_hGraphic);
// Convert the external data header to the internal member variables
ReadHeader(pHeader);
// Convert the extra data for the specific object
// (not all objects have extra data).
ReadExtra(pHeader);
// Release the data in the page
g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, pHeader);
// Show that we are no longer changed since last read/write
m_bChanged = FALSE;
}
//
//
// Function: DCWbGraphic::ReadHeader
//
// Purpose: Convert the external representation of the graphic's header
// to the internal format.
//
//
void DCWbGraphic::ReadHeader(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ReadHeader");
// Get the length of the object
m_dwExternalLength = pHeader->length;
// Convert the external data header to the internal member variables
// Bounding rectangle
m_boundsRect.left = pHeader->rectBounds.left;
m_boundsRect.top = pHeader->rectBounds.top;
m_boundsRect.right = pHeader->rectBounds.right;
m_boundsRect.bottom = pHeader->rectBounds.bottom;
// Defining rectangle
m_rect.left = pHeader->rect.left;
m_rect.top = pHeader->rect.top;
m_rect.right = pHeader->rect.right;
m_rect.bottom = pHeader->rect.bottom;
// Pen color
m_clrPenColor = RGB(pHeader->color.red,
pHeader->color.green,
pHeader->color.blue);
m_clrPenColor = SET_PALETTERGB( m_clrPenColor ); // make it do color matching
// Pen width
m_uiPenWidth = pHeader->penWidth;
// Pen style
m_iPenStyle = pHeader->penStyle;
// Raster operation
m_iPenROP = pHeader->rasterOp;
// Get the lock indication
m_uiLockState = pHeader->locked;
// Get the drawing tool type
if (pHeader->toolType == WBTOOL_TEXT)
m_toolType = TOOLTYPE_TEXT;
else
m_toolType = TOOLTYPE_PEN;
}
//
//
// Function: DCWbGraphic::WriteExternal
//
// Purpose: Write the graphic's details to a flat WB_GRAPHIC structure
//
//
void DCWbGraphic::WriteExternal(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::WriteExternal");
// Write the header
WriteHeader(pHeader);
// Write the extra data
WriteExtra(pHeader);
}
//
//
// Function: DCWbGraphic::WriteHeader
//
// Purpose: Write the graphic's header details to a flat WB_GRAPHIC
// structure.
//
//
void DCWbGraphic::WriteHeader(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::WriteHeader");
// Convert the internal data to the external header format
// Init struct
FillMemory(pHeader, sizeof (WB_GRAPHIC), 0 );
// Calculate the external length
pHeader->length = CalculateExternalLength();
// Set the type of graphic
pHeader->type = (TSHR_UINT16)Type();
// Assume that there is no extra data
pHeader->dataOffset = sizeof(WB_GRAPHIC);
// Bounding rectangle
pHeader->rectBounds.left = (short)m_boundsRect.left;
pHeader->rectBounds.top = (short)m_boundsRect.top;
pHeader->rectBounds.right = (short)m_boundsRect.right;
pHeader->rectBounds.bottom = (short)m_boundsRect.bottom;
// Defining rectangle
pHeader->rect.left = (short)m_rect.left;
pHeader->rect.top = (short)m_rect.top;
pHeader->rect.right = (short)m_rect.right;
pHeader->rect.bottom = (short)m_rect.bottom;
// Pen color
pHeader->color.red = GetRValue(m_clrPenColor);
pHeader->color.green = GetGValue(m_clrPenColor);
pHeader->color.blue = GetBValue(m_clrPenColor);
// Pen width
pHeader->penWidth = (TSHR_UINT16)m_uiPenWidth;
// Pen style
pHeader->penStyle = (TSHR_UINT16)m_iPenStyle;
// Raster operation
pHeader->rasterOp = (TSHR_UINT16)m_iPenROP;
// Set the lock indicator
pHeader->locked = (BYTE) m_uiLockState;
// Set the drawing method
pHeader->smoothed = FALSE;
// Set the drawing tool type
if (m_toolType == TOOLTYPE_TEXT)
pHeader->toolType = WBTOOL_TEXT;
else
pHeader->toolType = WBTOOL_PEN;
}
//
//
// Function: Initialize
//
// Purpose: Initialize the member variables
//
//
void DCWbGraphic::Initialize(void)
{
m_hPage = WB_PAGE_HANDLE_NULL;
m_hGraphic = NULL;
m_bChanged = TRUE;
m_uiLockState = WB_GRAPHIC_LOCK_NONE;
//
// Set default graphic attributes
//
::SetRectEmpty(&m_boundsRect);
::SetRectEmpty(&m_rect);
m_clrPenColor = RGB(0, 0, 0); // Black pen color
m_uiPenWidth = 1; // One unit width
m_iPenROP = R2_COPYPEN; // Standard drawing ROP
m_iPenStyle = PS_INSIDEFRAME; // Solid pen to be used
m_toolType = TOOLTYPE_PEN;
}
//
//
// Function: Copy
//
// Purpose: Return a copy of the graphic. The graphic returned has all
// its data read into local memory. The returned graphic has
// the same page as the copied graphic, but a NULL handle.
//
//
DCWbGraphic* DCWbGraphic::Copy(void) const
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Copy");
// Get a pointer to the external graphic data
// (Throws an exception if any errors occur)
PWB_GRAPHIC pHeader = PG_GetData(m_hPage, m_hGraphic);
// Construct the graphic
DCWbGraphic* pGraphic = DCWbGraphic::CopyGraphic(pHeader);
// If we got the graphic, set its page and handle
if (pGraphic != NULL)
{
pGraphic->m_hPage = m_hPage;
pGraphic->m_hGraphic = NULL;
}
// Release the data
g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, pHeader);
return pGraphic;
}
//
//
// Function: DCWbGraphic::SetBoundsRect
//
// Purpose: Set the bounding rectangle of the object
//
//
void DCWbGraphic::SetBoundsRect(LPCRECT lprc)
{
m_boundsRect = *lprc;
}
//
//
// Function: DCWbGraphic::SetRect
//
// Purpose: Set the defining rectangle of the object
//
//
void DCWbGraphic::SetRect(LPCRECT lprc)
{
m_rect = *lprc;
NormalizeRect(&m_rect);
// Show that we have been changed
m_bChanged = TRUE;
}
void DCWbGraphic::SetRectPts(POINT point1, POINT point2)
{
RECT rc;
rc.left = point1.x;
rc.top = point1.y;
rc.right = point2.x;
rc.bottom = point2.y;
SetRect(&rc);
}
//
//
// Function: DCWbGraphic::PointInBounds
//
// Purpose: Return TRUE if the specified point lies in the bounding
// rectangle of the graphic object.
//
//
BOOL DCWbGraphic::PointInBounds(POINT point)
{
return(::PtInRect(&m_boundsRect, point));
}
//
//
// Function: DCWbGraphic::MoveBy
//
// Purpose: Translate the object by the offset specified
//
//
void DCWbGraphic::MoveBy(int cx, int cy)
{
// Move the bounding rectangle
::OffsetRect(&m_boundsRect, cx, cy);
// Show that we have been changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphic::MoveTo
//
// Purpose: Move the object to an absolute position
//
//
void DCWbGraphic::MoveTo(int x, int y)
{
// Calculate the offset needed to translate the object from its current
// position to the required position.
x -= m_boundsRect.left;
y -= m_boundsRect.top;
MoveBy(x, y);
}
//
//
// Function: DCWbGraphic::GetPosition
//
// Purpose: Return the top left corner of the object's bounding
// rectangle
//
//
void DCWbGraphic::GetPosition(LPPOINT lppt)
{
lppt->x = m_boundsRect.left;
lppt->y = m_boundsRect.top;
}
//
//
// Function: DCWbGraphic::NormalizeRect
//
// Purpose: Normalize a rectangle ensuring that the top left is above
// and to the left of the bottom right.
//
//
void DCWbGraphic::NormalizeRect(LPRECT lprc)
{
int tmp;
if (lprc->right < lprc->left)
{
tmp = lprc->left;
lprc->left = lprc->right;
lprc->right = tmp;
}
if (lprc->bottom < lprc->top)
{
tmp = lprc->top;
lprc->top = lprc->bottom;
lprc->bottom = tmp;
}
}
//
//
// Function: DCWbGraphic::SetColor
//
// Purpose: Set the object color.
//
//
void DCWbGraphic::SetColor(COLORREF color)
{
color = SET_PALETTERGB( color ); // make it use color matching
if (m_clrPenColor != color)
{
// Save the new color
m_clrPenColor = color;
// Show that we have been changed
m_bChanged = TRUE;
}
}
//
//
// Function: DCWbGraphic::SetROP
//
// Purpose: Set the object raster operation
//
//
void DCWbGraphic::SetROP(int iPenROP)
{
// If the new ROP is different
if (m_iPenROP != iPenROP)
{
// Save the new ROP
m_iPenROP = iPenROP;
// Show that we have been changed
m_bChanged = TRUE;
}
}
//
//
// Function: DCWbGraphic::SetPenStyle
//
// Purpose: Set the object pen style
//
//
void DCWbGraphic::SetPenStyle(int iPenStyle)
{
// If the new style is different
if (m_iPenStyle != iPenStyle)
{
// Save the new pen style
m_iPenStyle = iPenStyle;
// Show that the graphic has been changed
m_bChanged = TRUE;
}
}
//
//
// Function: DCWbGraphic::SetPenWidth
//
// Purpose: Set the pen width for the object.
//
//
void DCWbGraphic::SetPenWidth(UINT uiWidth)
{
// If the new width is different
if (m_uiPenWidth != uiWidth)
{
// Save the width given
m_uiPenWidth = uiWidth;
// Update the bounding rectangle
CalculateBoundsRect();
// Show that we have been changed
m_bChanged = TRUE;
}
}
//
//
// Function: IsTopmost
//
// Purpose: Return TRUE if this graphic is topmost on its page
//
//
BOOL DCWbGraphic::IsTopmost(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::IsTopmost");
ASSERT(m_hGraphic != NULL);
return PG_IsTopmost(m_hPage, this);
}
//
//
// Function: AddToPageLast
//
// Purpose: Add the graphic to the specified page
//
//
void DCWbGraphic::AddToPageLast(WB_PAGE_HANDLE hPage)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::AddToPageLast");
ASSERT(m_hGraphic == NULL);
// Get the length of the flat representation
DWORD length = CalculateExternalLength();
// Allocate memory for the graphic
PWB_GRAPHIC pHeader = PG_AllocateGraphic(hPage, length);
if(pHeader == NULL)
{
return;
}
// Write the graphic details to the memory
WriteExternal(pHeader);
// Add the flat representation to the page
WB_GRAPHIC_HANDLE hGraphic = NULL;
UINT uiReturn;
uiReturn = g_pwbCore->WBP_GraphicAddLast(hPage, pHeader, &hGraphic);
if (uiReturn != 0)
{
DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
return;
}
// Show that we have not changed since the last write
m_bChanged = FALSE;
// Save the page to which this graphic now belongs
m_hPage = hPage;
m_hGraphic = hGraphic;
}
//
//
// Function: ForceReplace
//
// Purpose: Write the object to external storage, replacing what is
// already there, even if the object hasn't changed.
//
//
void DCWbGraphic::ForceReplace(void)
{
if( Type() != 0 )
{
m_bChanged = TRUE;
this->Replace();
}
}
//
//
// Function: Replace
//
// Purpose: Write the object to external storage, replacing what is
// already there.
//
//
void DCWbGraphic::Replace(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Replace");
ASSERT(m_hGraphic != NULL);
// Only do the replace if we have been changed
if (m_bChanged == TRUE)
{
TRACE_MSG(("Replacing the graphic in the page"));
// Get the length of the flat representation
DWORD length = CalculateExternalLength();
// Allocate memory for the graphic
PWB_GRAPHIC pHeader = PG_AllocateGraphic(m_hPage, length);
if(pHeader == NULL)
{
return;
}
// Write the graphic details to the memory
WriteExternal(pHeader);
// Replace the graphic
PG_GraphicReplace(m_hPage, &m_hGraphic, pHeader);
// Show that we have not changed since the last update
m_bChanged = FALSE;
}
}
//
//
// Function: ReplaceConfirm
//
// Purpose: Confirm the replace of the graphic
//
//
void DCWbGraphic::ReplaceConfirm(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ReplaceConfirm");
ASSERT(m_hGraphic != NULL);
// Confirm the update
g_pwbCore->WBP_GraphicReplaceConfirm(m_hPage, m_hGraphic);
// Read the new details
ReadExternal();
}
void DCWbGraphic::ForceUpdate(void)
{
if ((Type() != 0) && m_hGraphic)
{
m_bChanged = TRUE;
this->Update();
}
}
//
//
// Function: Update
//
// Purpose: Write the header of the graphic to external storage
//
//
void DCWbGraphic::Update(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Update");
ASSERT(m_hGraphic != NULL);
// Only make the update if the graphic has changed
if (m_bChanged)
{
// Allocate memory for the update graphic
TRACE_MSG(("Graphic has changed"));
DWORD length = sizeof(WB_GRAPHIC);
PWB_GRAPHIC pHeader;
if( (pHeader = PG_AllocateGraphic(m_hPage, length)) != NULL )
{
// Write the header details to the allocated memory
pHeader->type = (TSHR_UINT16)Type();
WriteHeader(pHeader);
// Update the header in the page
PG_GraphicUpdate(m_hPage, &m_hGraphic, pHeader);
}
// Show that we have not changed since the last update
m_bChanged = FALSE;
}
}
//
//
// Function: UpdateConfirm
//
// Purpose: Confirm the update of the graphic
//
//
void DCWbGraphic::UpdateConfirm(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::UpdateConfirm");
ASSERT(m_hGraphic != NULL);
// Confirm the update
g_pwbCore->WBP_GraphicUpdateConfirm(m_hPage, m_hGraphic);
// Read the new details
ReadExternal();
}
//
//
// Function: Delete
//
// Purpose: Remove the graphic from its page
//
//
void DCWbGraphic::Delete(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Delete");
ASSERT(m_hPage != WB_PAGE_HANDLE_NULL);
ASSERT(m_hGraphic != NULL);
// Delete the graphic
PG_GraphicDelete(m_hPage, *this);
// Reset the handles for this graphic - it is now deleted
m_hPage = WB_PAGE_HANDLE_NULL;
m_hGraphic = NULL;
// Show that we have changed (an add is required to save the graphic)
m_bChanged = TRUE;
}
//
//
// Function: DeleteConfirm
//
// Purpose: Confirm the delete of the graphic
//
//
void DCWbGraphic::DeleteConfirm(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::DeleteConfirm");
ASSERT(m_hGraphic != NULL);
// Confirm the update
g_pwbCore->WBP_GraphicDeleteConfirm(m_hPage, m_hGraphic);
// Reset the graphic page and handle (they are no longer useful)
m_hPage = WB_PAGE_HANDLE_NULL;
m_hGraphic = NULL;
}
//
//
// Function: Lock
//
// Purpose: Lock the graphic
//
//
void DCWbGraphic::Lock(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Lock");
// If we are not already locked
if( Type() != 0 )
{
if (m_uiLockState == WB_GRAPHIC_LOCK_NONE)
{
m_bChanged = TRUE;
m_uiLockState = WB_GRAPHIC_LOCK_LOCAL;
}
}
}
//
//
// Function: Unlock
//
// Purpose: Unlock the graphic
//
//
void DCWbGraphic::Unlock(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Unlock");
// If we are currently locked
if( Type() != 0 )
{
if (m_uiLockState == WB_GRAPHIC_LOCK_LOCAL)
{
// Lock & release
PWB_GRAPHIC pHeader = PG_GetData(m_hPage, m_hGraphic);
g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, pHeader);
m_uiLockState = WB_GRAPHIC_LOCK_NONE;
g_pwbCore->WBP_GraphicUnlock(m_hPage, m_hGraphic);
}
}
}
//
//
// Function: DCWbGraphicMarker::DCWbGraphicMarker
//
// Purpose: Constructors for marker objects
//
//
DCWbGraphicMarker::DCWbGraphicMarker()
{
HBITMAP hBmpMarker;
// Set up a checked pattern to draw the marker rect with
WORD bits[] = {204, 204, 51, 51, 204, 204, 51, 51};
// Create the brush to be used to draw the marker rectangle
hBmpMarker = ::CreateBitmap(8, 8, 1, 1, bits);
m_hMarkerBrush = ::CreatePatternBrush(hBmpMarker);
::DeleteBitmap(hBmpMarker);
MarkerList.EmptyList();
::SetRectEmpty(&m_rect);
m_bMarkerPresent = FALSE;
}
DCWbGraphicMarker::~DCWbGraphicMarker()
{
if (m_hMarkerBrush != NULL)
{
DeleteBrush(m_hMarkerBrush);
m_hMarkerBrush = NULL;
}
}
//
//
// Function: DCWbGraphicMarker::SetRect
//
// Purpose: Set the rectangle for the object
//
//
BOOL DCWbGraphicMarker::SetRect(LPCRECT lprc,
DCWbGraphic *pGraphic,
BOOL bRedraw,
BOOL bLockObject )
{
DCWbGraphic *pMarker;
BOOL bGraphicAdded = FALSE;
LPRECT pmMarker;
// Save the new rectangle
m_rect = *lprc;
NormalizeRect(&m_rect);
// Calculate the new bounding rectangle of the entire marker
CalculateBoundsRect();
// Calculate the marker rectangles
CalculateMarkerRectangles();
if( (pMarker = HasAMarker( pGraphic )) != NULL )
delete pMarker;
// allow select only if object is not locked - bug 2185
if( !pGraphic->Locked())
{
// add/replace pGraphic|markerrect pair to list
pmMarker = new RECT;
if (!pmMarker)
{
ERROR_OUT(("Failed to create RECT object"));
}
else
{
*pmMarker = m_markerRect;
MarkerList.SetAt( (void *)pGraphic, pmMarker);
ASSERT(g_pDraw);
DrawRect(g_pDraw->GetCachedDC(), pmMarker, FALSE, NULL );
bGraphicAdded = TRUE;
}
if( bLockObject )
{
// lock the object if we don't already have it locked
// to keep anybody else from selecting it
if( !pGraphic->GotLock() )
{
pGraphic->Lock();
if( pGraphic->Handle() != NULL )
pGraphic->ForceUpdate(); // if valid object force lock NOW
}
}
}
if( bRedraw && m_bMarkerPresent )
{
ASSERT(g_pDraw);
::UpdateWindow(g_pDraw->m_hwnd);
}
// set m_boundsRect to real bounds
GetBoundsRect(&m_boundsRect);
return( bGraphicAdded );
}
//
//
// Function: DCWbGraphicMarker::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the object
//
//
void DCWbGraphicMarker::CalculateBoundsRect(void)
{
// Generate the new bounding rectangle
m_boundsRect = m_rect;
NormalizeRect(&m_boundsRect);
::InflateRect(&m_boundsRect, m_uiPenWidth, m_uiPenWidth);
}
//
//
// Function: DCWbGraphicMarker::CalculateMarkerRectangles
//
// Purpose: Calculate the rectangles for the marker handles
//
//
void DCWbGraphicMarker::CalculateMarkerRectangles(void)
{
m_markerRect = m_boundsRect;
::InflateRect(&m_markerRect, 1-m_uiPenWidth, 1-m_uiPenWidth);
}
//
//
// Function: DCWbGraphicMarker::PointInMarker
//
// Purpose: Calculate whether the given point is in one of the marker
// rectangles.
//
//
int DCWbGraphicMarker::PointInMarker(POINT point)
{
return(NO_HANDLE);
}
void DCWbGraphicMarker::DrawRect
(
HDC hDC,
LPCRECT pMarkerRect,
BOOL bDrawObject,
DCWbGraphic * pGraphic
)
{
int nOldROP;
COLORREF crOldTextColor;
COLORREF crOldBkColor;
nOldROP = ::SetROP2(hDC, R2_COPYPEN);
crOldTextColor = ::SetTextColor(hDC, RGB(0, 0, 0));
ASSERT(g_pDraw);
crOldBkColor = ::SetBkColor(hDC, ::GetSysColor(COLOR_WINDOW));
if (pMarkerRect != NULL)
{
if( bDrawObject )
pGraphic->Draw(hDC ); // draw object instead of rect
else
::FrameRect(hDC, pMarkerRect, m_hMarkerBrush); // draw rect
}
::SetROP2(hDC, nOldROP);
::SetTextColor(hDC, crOldTextColor);
::SetBkColor(hDC, crOldBkColor);
}
//
//
// Function: DCWbGraphicMarker::Draw
//
// Purpose: Draw the marker object
//
//
void DCWbGraphicMarker::Draw(HDC hDC, BOOL bDrawObjects)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
// if marker is not up, do nuthin
if( !m_bMarkerPresent )
return;
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext, (void *&)pGraphic, (void *&)pMarkerRect );
DrawRect(hDC, pMarkerRect, bDrawObjects, pGraphic );
}
}
void DCWbGraphicMarker::UndrawRect
(
HDC hDC,
WbDrawingArea * pDrawingArea,
LPCRECT pMarkerRect
)
{
int nOldROP;
COLORREF crOldTextColor;
COLORREF crOldBkColor;
if (pMarkerRect != NULL)
{
// set up context to erase marker rect
nOldROP = ::SetROP2(hDC, R2_COPYPEN);
ASSERT(g_pDraw);
crOldTextColor = ::SetTextColor(hDC, ::GetSysColor(COLOR_WINDOW));
crOldBkColor = ::SetBkColor(hDC, ::GetSysColor(COLOR_WINDOW));
::FrameRect(hDC, pMarkerRect, m_hMarkerBrush);
UndrawMarker( pMarkerRect ); // invalidate so underlying objects will repair window
::SetROP2(hDC, nOldROP);
::SetTextColor(hDC, crOldTextColor);
::SetBkColor(hDC, crOldBkColor);
}
}
//
//
// Function: DCWbGraphicMarker::Undraw
//
// Purpose: Undraw the marker object
//
//
void DCWbGraphicMarker::Undraw(HDC hDC, WbDrawingArea * pDrawingArea)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext, (void *&)pGraphic, (void *&)pMarkerRect );
UndrawRect(hDC, pDrawingArea, pMarkerRect);
}
}
void DCWbGraphicMarker::DeleteAllMarkers( DCWbGraphic *pLastSelectedGraphic,
BOOL bLockLastSelectedGraphic )
{
POSITION posFirst;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
BOOL bAddLastBack = FALSE;
if( MarkerList.IsEmpty() )
return; // nuthin to do
// let each object clean itself up
posFirst = MarkerList.GetHeadPosition();
while( posFirst != NULL )
{
MarkerList.GetNextAssoc( posFirst,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
if( pGraphic == pLastSelectedGraphic )
{
// have to put this one back since somebody up there needs it
bAddLastBack = TRUE;
// delete key but don't delete object
DeleteMarker( pGraphic );
}
else
{
// obj will call DeleteMarker()
delete pGraphic;
}
}
else
{
// nobody home, remove key ourselves
DeleteMarker( pGraphic );
}
}
// put last selected object back if needed
if( bAddLastBack && (pLastSelectedGraphic != NULL) )
{
RECT rcT;
pLastSelectedGraphic->GetBoundsRect(&rcT);
SetRect(&rcT, pLastSelectedGraphic, FALSE, bLockLastSelectedGraphic );
}
// if marker is not up, don't redraw immediately
if( !m_bMarkerPresent )
return;
ASSERT(g_pDraw);
if (g_pDraw->m_hwnd != NULL )
::UpdateWindow(g_pDraw->m_hwnd);
}
//
// Deletes DCWbGraphic/LPRECT pair corresponding to pGraphic
//
void DCWbGraphicMarker::DeleteMarker( DCWbGraphic *pGraphic )
{
LPRECT pMarkerRect;
if( MarkerList.IsEmpty() )
return;
if( MarkerList.Lookup( (void *)pGraphic, (void *&)pMarkerRect ) )
{
if( pMarkerRect != NULL )
{
ASSERT(g_pDraw);
UndrawRect(g_pDraw->GetCachedDC(), g_pDraw, pMarkerRect );
delete pMarkerRect;
}
MarkerList.RemoveKey( (void *)pGraphic );
// set m_boundsRect to real bounds
GetBoundsRect(&m_boundsRect);
// pGraphic should be locked by us since it was selected
// but check to be sure since this might be coming from
// another user that beat us to the lock.
if( pGraphic->GotLock() )
{
pGraphic->Unlock();
if( pGraphic->Handle() != NULL )
pGraphic->ForceUpdate();
}
}
// if marker is not up, don't redraw immediately
if( !m_bMarkerPresent )
return;
}
//
// Sees if pGraphic->Handle() is in marker list and returns obj
//
DCWbGraphic *DCWbGraphicMarker::HasAMarker( DCWbGraphic *pGraphic )
{
POSITION posNext;
DCWbGraphic *pSearchGraphic;
LPRECT pMarkerRect;
if( MarkerList.IsEmpty() )
return( NULL );
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pSearchGraphic, (void *&)pMarkerRect );
if( (pSearchGraphic != NULL)&&
(pSearchGraphic->Handle() == pGraphic->Handle()) )
{
return( pSearchGraphic );
}
}
return( NULL );
}
//
// Gets last marker
//
DCWbGraphic *DCWbGraphicMarker::LastMarker( void )
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
pGraphic = NULL;
if( !MarkerList.IsEmpty() )
{
// this isn't eactly right, just return head of list for now
posNext = MarkerList.GetHeadPosition();
if( posNext != NULL )
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
}
return( pGraphic );
}
void DCWbGraphicMarker::UndrawMarker(LPCRECT pMarkerRect )
{
RECT rect;
ASSERT(g_pDraw);
if( (pMarkerRect != NULL) && (g_pDraw->m_hwnd != NULL) )
{
rect = *pMarkerRect;
g_pDraw->SurfaceToClient(&rect);
::InvalidateRect(g_pDraw->m_hwnd, &rect, FALSE);
}
}
int DCWbGraphicMarker::GetNumMarkers( void )
{
int count = 0;
POSITION pos;
pos = MarkerList.GetHeadPosition();
while(pos)
{
count ++;
MarkerList.GetNext(pos);
}
return count;
}
void DCWbGraphicMarker::MoveBy(int cx, int cy)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call MoveBy for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
pGraphic->MoveBy(cx, cy);
}
}
}
DCWbGraphic::MoveBy(cx, cy); // move marker too
}
void DCWbGraphicMarker::Update( void )
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
pGraphic->Update();
}
}
}
BOOL DCWbGraphicMarker::PointInBounds(POINT pt)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
RECT rectHit;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
MAKE_HIT_RECT(rectHit, pt );
if( pGraphic->PointInBounds(pt)&&
pGraphic->CheckReallyHit( &rectHit )
)
return( TRUE );
}
}
}
return( FALSE );
}
//
// Returns a rect that is the union of all the items in the marker
//
void DCWbGraphicMarker::GetBoundsRect(LPRECT lprc)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
RECT rc;
::SetRectEmpty(lprc);
if( !MarkerList.IsEmpty())
{
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
pGraphic->GetBoundsRect(&rc);
::UnionRect(lprc, lprc, &rc);
}
}
}
}
void DCWbGraphicMarker::SetColor(COLORREF color)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
pGraphic->SetColor( color );
}
}
}
void DCWbGraphicMarker::SetPenWidth(UINT uiWidth)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
pGraphic->SetPenWidth(uiWidth);
}
}
}
void DCWbGraphicMarker::SetSelectionFont(HFONT hFont)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( (pGraphic != NULL)&&
pGraphic->IsGraphicTool() == enumGraphicText)
{
// Change the font of the object
((DCWbGraphicText*)pGraphic)->SetFont(hFont);
// Replace the object
pGraphic->Replace();
}
}
}
}
//
// Deletes each marker obj for all connections
//
void DCWbGraphicMarker::DeleteSelection( void )
{
POSITION posNext;
DCWbGraphic *pGraphic;
DCWbGraphic *pGraphicCopy;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
// make a copy for trash can
pGraphicCopy = pGraphic->Copy();
// throw in trash
if( pGraphicCopy != NULL )
{
g_pMain->m_LastDeletedGraphic.CollectTrash( pGraphicCopy );
}
// delete obj
g_pDraw->DeleteGraphic( pGraphic );
}
}
DeleteAllMarkers( NULL );
}
}
//
// Brings eaach marker obj to top
//
void DCWbGraphicMarker::BringToTopSelection( void )
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
// move obj to top
UINT uiReturn;
uiReturn = g_pwbCore->WBP_GraphicMove(g_pDraw->Page(),
pGraphic->Handle(), LAST);
if (uiReturn != 0)
{
DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
return;
}
}
}
}
}
//
// Sends each marker object to back
//
void DCWbGraphicMarker::SendToBackSelection( void )
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
if( !MarkerList.IsEmpty() )
{
// Call Update for each selected obj
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( pGraphic != NULL )
{
UINT uiReturn;
// move obj to top
uiReturn = g_pwbCore->WBP_GraphicMove(g_pDraw->Page(),
pGraphic->Handle(), FIRST);
if (uiReturn != 0)
{
DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
return;
}
}
}
}
}
//
// Copy marker to clipboard using CLIPBOARD_PRIVATE_MULTI_OBJ format:
// [ RECT : marker rect ]
// [ DWORD : number of objects ]
// [ DWORD : byte length of 1st object ]
// [ WB_GRAPHIC : header data for first object ]
// [ DWORD : byte length of 2nd object ]
// [ WB_GRAPHIC : header data for 2nd object ]
// :
// :
// [ DWORD : byte length of last object ]
// [ WB_GRAPHIC : header data for last object ]
// [ DWORD : 0 (marks end of object data) ]
//
BOOL DCWbGraphicMarker::RenderPrivateMarkerFormat( void )
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
DWORD nBufSize;
DWORD nObjSize;
DWORD nNumObjs;
BYTE *buf;
BYTE *pbuf;
HANDLE hbuf;
PWB_GRAPHIC pHeader;
WB_GRAPHIC_HANDLE hGraphic;
if( MarkerList.IsEmpty() )
return( TRUE ); // nuthin to do
// Have to make two passes. The first one figures out how much
// data we have, the second copies the data.
// figure out how much data we've got
nBufSize = sizeof (RECT) + sizeof (DWORD); // marker rect and object
// count are first
nNumObjs = 0;
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( (pGraphic != NULL)&&
((hGraphic = pGraphic->Handle()) != NULL)&&
((pHeader = PG_GetData(pGraphic->Page(), hGraphic )) != NULL) )
{
nBufSize += (DWORD)(pHeader->length + sizeof(DWORD));
g_pwbCore->WBP_GraphicRelease(pGraphic->Page(), hGraphic, pHeader);
// count objects instead of using MarkerList.GetCount()
// in case we have an error or something (bad object,
// leaky core, who knows...)
nNumObjs++;
}
}
// Add one more DWORD at end. This will be set to 0 below
// to mark the end of the buffer.
nBufSize += sizeof(DWORD);
// Make object buffer. Use GlobalDiddle instead of new so we
// can pass a mem handle to the clipboard later.
hbuf = ::GlobalAlloc( GHND, nBufSize );
if( hbuf == NULL )
return( FALSE ); // couldn't make room
buf = (BYTE *)::GlobalLock( hbuf );
if( buf == NULL )
{
::GlobalFree( hbuf );
return( FALSE ); // couldn't find the room
}
pbuf = buf;
// set marker rect
CopyMemory(pbuf, &m_boundsRect, sizeof(RECT));
pbuf += sizeof (RECT);
// set number of objects
*((DWORD *)pbuf) = nNumObjs;
pbuf += sizeof (DWORD);
// copy each obj to buf + a length DWORD
posNext = MarkerList.GetHeadPosition();
while( posNext != NULL )
{
MarkerList.GetNextAssoc( posNext,
(void *&)pGraphic, (void *&)pMarkerRect );
if( (pGraphic != NULL)&&
((hGraphic = pGraphic->Handle()) != NULL)&&
((pHeader = PG_GetData(pGraphic->Page(), hGraphic )) != NULL) )
{
// save length of this obj first
nObjSize = (DWORD)pHeader->length;
*((DWORD *)pbuf) = nObjSize;
pbuf += sizeof (DWORD);
// copy obj to buf
CopyMemory( pbuf, (CONST VOID *)pHeader, nObjSize );
// make sure copy isn't "locked" (bug 474)
((PWB_GRAPHIC)pbuf)->locked = WB_GRAPHIC_LOCK_NONE;
// set up for next obj
pbuf += nObjSize;
g_pwbCore->WBP_GraphicRelease(pGraphic->Page(), hGraphic, pHeader );
}
}
// cork it up
*((DWORD *)pbuf) = 0;
// give it to the clipboard
::GlobalUnlock( hbuf );
if( ::SetClipboardData(
g_ClipboardFormats[ CLIPBOARD_PRIVATE_MULTI_OBJ ], hbuf
)
== NULL )
{
// clipboard choked, clean up mess
::GlobalFree( hbuf );
return( FALSE );
}
// zillions of shared clipboards all over the planet are receiving this
// thing about now...
return( TRUE );
}
//
// Decodes CLIPBOARD_PRIVATE_MULTI_OBJ format and pastes objects
// to Whiteboard. See DCWbGraphicMarker::RenderPrivateMarkerFormat
// for details of format.
//
void DCWbGraphicMarker::Paste( HANDLE handle )
{
BYTE *pbuf;
DWORD nNumObjs;
DWORD nObjSize;
DCWbGraphic *pGraphic;
DCWbGraphic *pSelectedGraphic;
SIZE PasteOffset;
RECT rectMarker;
// blow off current selection
g_pMain->m_drawingArea.RemoveMarker(NULL);
DeleteAllMarkers( NULL );
pSelectedGraphic = NULL;
// get data
pbuf = (BYTE *)::GlobalLock( handle );
if( pbuf == NULL )
return; // can't get the door open
// get marker's original coords and figure offset
CopyMemory( &rectMarker, (CONST VOID *)pbuf, sizeof (RECT) );
pbuf += sizeof (RECT);
RECT rcVis;
g_pMain->m_drawingArea.GetVisibleRect(&rcVis);
PasteOffset.cx = rcVis.left - rectMarker.left;
PasteOffset.cy = rcVis.top - rectMarker.top;
// get num objects
nNumObjs = *((DWORD *)pbuf);
pbuf += sizeof (DWORD);
// get each object
while( (nObjSize = *((DWORD *)pbuf)) != 0 )
{
pbuf += sizeof (DWORD);
// Add the object to the page and current selection
pGraphic = DCWbGraphic::CopyGraphic( (PWB_GRAPHIC)pbuf );
pbuf += nObjSize;
if( pGraphic != NULL )
{
pGraphic->MoveBy( PasteOffset.cx, PasteOffset.cy );
pGraphic->AddToPageLast( g_pMain->GetCurrentPage() );
g_pMain->m_drawingArea.SelectGraphic( pGraphic, TRUE, TRUE );
}
}
::GlobalUnlock( handle );
GetBoundsRect(&m_boundsRect);
}
DCWbGraphicLine::~DCWbGraphicLine( void )
{
// Have to make sure marker is cleaned up before we vanish
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphicLine::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the line
//
//
void DCWbGraphicLine::CalculateBoundsRect()
{
// Create the basic bounding rectangle from the start and end points
m_boundsRect = m_rect;
NormalizeRect(&m_boundsRect);
// Expand the rectangle by the pen width used for drawing
int iInflate = (m_uiPenWidth + 1) / 2;
::InflateRect(&m_boundsRect, iInflate, iInflate);
}
//
//
// Function: DCWbGraphicLine::SetStart
//
// Purpose: Set the start point of the line
//
//
void DCWbGraphicLine::SetStart(POINT pointFrom)
{
// Only do anything if the start point has changed
if (!EqualPoint(*((LPPOINT)&m_rect.left), pointFrom))
{
// Save the new start point
m_rect.left = pointFrom.x;
m_rect.top = pointFrom.y;
// Show that the graphic has changed
m_bChanged = TRUE;
}
// Update the bounding rectangle
CalculateBoundsRect();
}
//
//
// Function: DCWbGraphicLine::SetEnd
//
// Purpose: Set the start point of the line
//
//
void DCWbGraphicLine::SetEnd(POINT pointTo)
{
// Only do anything if the end point has changed
if (!EqualPoint(*((LPPOINT)&m_rect.right), pointTo))
{
// Save the new end point
m_rect.right = pointTo.x;
m_rect.bottom = pointTo.y;
// Show that the graphic has changed
m_bChanged = TRUE;
}
// Update the bounding rectangle
CalculateBoundsRect();
}
//
//
// Function: DCWbGraphicLine::Draw
//
// Purpose: Draw the line.
//
//
void DCWbGraphicLine::Draw(HDC hDC)
{
HPEN hPen;
HPEN hOldPen;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicLine::Draw");
// Select the required pen
hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
hOldPen = SelectPen(hDC, hPen);
if (hOldPen != NULL)
{
// Select the raster operation
int iOldROP = ::SetROP2(hDC, m_iPenROP);
// Draw the line
::MoveToEx(hDC, m_rect.left, m_rect.top, NULL);
::LineTo(hDC, m_rect.right, m_rect.bottom);
// De-select the pen and ROP
::SetROP2(hDC, iOldROP);
SelectPen(hDC, hOldPen);
}
if (hPen != NULL)
{
::DeletePen(hPen);
}
}
//
//
// Function: DCWbGraphicLine::MoveBy
//
// Purpose: Move the line.
//
//
void DCWbGraphicLine::MoveBy(int cx, int cy)
{
// Move the start and end points
::OffsetRect(&m_rect, cx, cy);
// Move the other object attributes
DCWbGraphic::MoveBy(cx, cy);
}
//
// Checks object for an actual overlap with pRectHit. Assumes m_boundsRect
// has already been compared.
//
BOOL DCWbGraphicLine::CheckReallyHit(LPCRECT pRectHit)
{
return(LineHit(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom,
m_uiPenWidth, TRUE, TRUE, pRectHit));
}
//
//
// Function: DCWbGraphicFreehand::DCWbGraphicFreehand
//
// Purpose: Constructor
//
//
DCWbGraphicFreehand::DCWbGraphicFreehand(void) : DCWbGraphic()
{
}
DCWbGraphicFreehand::DCWbGraphicFreehand(PWB_GRAPHIC pHeader)
: DCWbGraphic()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::DCWbGraphicFreehand");
// Note that we do everything in this constructor because of the
// call to ReadExternal. If we let the DCWbGraphic base constructor
// do it the wrong version of ReadExtra will be called (the one
// in DCWbGraphic instead of the one in DCWbGraphicFreehand);
// Do the basic initialization
Initialize();
// Set up the page and graphic handle
ASSERT(pHeader != NULL);
// Read the header data
ReadHeader(pHeader);
// Read the extra data
ReadExtra(pHeader);
}
DCWbGraphicFreehand::DCWbGraphicFreehand
(
WB_PAGE_HANDLE hPage,
WB_GRAPHIC_HANDLE hGraphic
) : DCWbGraphic()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::DCWbGraphicFreehand");
// Note that we do everything in this constructor because of the
// call to ReadExternal. If we let the DCWbGraphic base constructor
// do it the wrong version of ReadExtra will be called (the one
// in DCWbGraphic instead of the one in DCWbGraphicFreehand);
// Do the basic initialization
Initialize();
ASSERT(hPage != WB_PAGE_HANDLE_NULL);
m_hPage = hPage;
ASSERT(hGraphic != NULL);
m_hGraphic = hGraphic;
// Read the header data
ReadExternal();
}
DCWbGraphicFreehand::~DCWbGraphicFreehand( void )
{
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphicFreehand::MoveBy
//
// Purpose: Move the polyline.
//
//
void DCWbGraphicFreehand::MoveBy(int cx, int cy)
{
// Move the base point of the freehand object
m_rect.left += cx;
m_rect.top += cy;
// Move the other object attributes
DCWbGraphic::MoveBy(cx, cy);
}
//
//
// Function: DCWbGraphicFreehand::Draw
//
// Purpose: Draw the polyline.
//
//
void DCWbGraphicFreehand::Draw(HDC hDC)
{
RECT clipBox;
int iOldROP;
HPEN hPen;
HPEN hOldPen;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand:Draw");
// NFC, SFR 5922. Check the return code from GetClipBox.
// If we fail to get it, just draw everything
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
// Select the required pen
hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
hOldPen = SelectPen(hDC, hPen);
// Select the raster operation
iOldROP = ::SetROP2(hDC, m_iPenROP);
if (hOldPen != NULL)
{
// All points are relative to the first point in the list.
// We update the origin of the DC temporarily to account for this.
POINT origin;
::GetWindowOrgEx(hDC, &origin);
::SetWindowOrgEx(hDC, origin.x - m_rect.left, origin.y - m_rect.top, NULL);
// Call the appropriate drawing function, according to whether
// we're smooth or not
DrawUnsmoothed(hDC);
// Restore the origin
::SetWindowOrgEx(hDC, origin.x, origin.y, NULL);
::SetROP2(hDC, iOldROP);
SelectPen(hDC, hOldPen);
}
if (hPen != NULL)
{
::DeletePen(hPen);
}
}
//
//
// Function: DCWbGraphicFreehand::DrawUnsmoothed
//
// Purpose: Draw the complete graphic, not using smoothing.
//
//
void DCWbGraphicFreehand::DrawUnsmoothed(HDC hDC)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehandDrawUnsmoothed");
// Set up the count and pointer to the points data. We use the
// external data if we have a handle, otherwise internal data is used.
int iCount = points.GetSize();
if (iCount < 2)
{
POINT point;
point.x = points[0]->x;
point.y = points[0]->y;
points.Add(point);
iCount = points.GetSize();
}
RECT clipBox;
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
// Draw all the line segments stored
::MoveToEx(hDC, points[0]->x, points[0]->y, NULL);
for ( int iIndex = 1; iIndex < iCount; iIndex++)
{
// Draw the line
::LineTo(hDC, points[iIndex]->x, points[iIndex]->y);
}
}
//
//
// Function: DCWbGraphicFreehand::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the line
//
//
void DCWbGraphicFreehand::CalculateBoundsRect(void)
{
// Reset the bounds rectangle
::SetRectEmpty(&m_boundsRect);
// Add each of the points in the line to the bounding rectangle
int iCount = points.GetSize();
for ( int iIndex = 0; iIndex < iCount; iIndex++)
{
AddPointToBounds(points[iIndex]->x, points[iIndex]->y);
}
//
// Since the points are inclusive, we need to add one to the top &
// bottom sides.
//
::InflateRect(&m_boundsRect, 0, 1);
::OffsetRect(&m_boundsRect, m_rect.left, m_rect.top);
}
//
//
// Function: DCWbGraphicFreehand::AddPointToBounds
//
// Purpose: Add a single point into the bounding rectangle. The point is
// expected to be in surface co-ordinates.
//
//
void DCWbGraphicFreehand::AddPointToBounds(int x, int y)
{
// Create a rectangle containing the point just added (expanded
// by the width of the pen being used).
RECT rect;
int iInflate = (m_uiPenWidth + 1) / 2;
rect.left = x - iInflate;
rect.top = y - iInflate;
rect.right = x + iInflate;
rect.bottom = y + iInflate;
::UnionRect(&m_boundsRect, &m_boundsRect, &rect);
}
//
//
// Function: DCWbGraphicFreehand::AddPoint
//
// Purpose: Add a point to the poly line, returning BOOL indicating
// success.
//
//
BOOL DCWbGraphicFreehand::AddPoint(POINT point)
{
BOOL bSuccess = TRUE;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::AddPoint");
// if we've reached the maximum number of points then quit with failure
if (points.GetSize() >= MAX_FREEHAND_POINTS)
{
bSuccess = FALSE;
TRACE_MSG(("Maximum number of points for freehand object reached."));
return(bSuccess);
}
// If this is the first point - all others are taken relative to it.
if (points.GetSize() == 0)
{
// Save the first point here.
m_rect.left = point.x;
m_rect.top = point.y;
}
// Add the new point to the array - surround with exception handler
// to catch memory errors
POINT newpoint;
newpoint.x = point.x - m_rect.left;
newpoint.y = point.y - m_rect.top;
points.Add((newpoint));
// Add the new point into the accumulated bounds rectangle.
AddPointToBounds(point.x, point.y);
// Show that the graphic has changed
m_bChanged = TRUE;
return(bSuccess);
}
//
//
// Function: DCWbGraphicFreehand::CalculateExternalLength
//
// Purpose: Return the length of the external representation of the
// graphic.
//
//
DWORD DCWbGraphicFreehand::CalculateExternalLength(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::CalculateExternalLength");
// Calculate the total length of the flat representation of the graphic
return (DWORD) ( sizeof(WB_GRAPHIC_FREEHAND)
+ (points.GetSize() * sizeof(POINT)));
}
//
//
// Function: DCWbGraphicFreehand::WriteExtra
//
// Purpose: Write the extra (non-header) data to the flat representation
// of the graphic.
//
//
void DCWbGraphicFreehand::WriteExtra(PWB_GRAPHIC pHeader)
{
// Allocate the memory
PWB_GRAPHIC_FREEHAND pFreehand = (PWB_GRAPHIC_FREEHAND) pHeader;
// Copy the extra details into place
pFreehand->pointCount = (TSHR_UINT16)points.GetSize();
for ( int iIndex = 0; iIndex < pFreehand->pointCount; iIndex++)
{
pFreehand->points[iIndex].x = (short)points[iIndex]->x;
pFreehand->points[iIndex].y = (short)points[iIndex]->y;
}
}
//
//
// Function: DCWbGraphicFreehand::ReadExtra
//
// Purpose: Read the extra (non-header) data from the flat
// representation of the graphic.
//
//
void DCWbGraphicFreehand::ReadExtra(PWB_GRAPHIC pHeader)
{
// Allocate the memory
PWB_GRAPHIC_FREEHAND pFreehand = (PWB_GRAPHIC_FREEHAND) pHeader;
// Get the number of points
int iCount = pFreehand->pointCount;
// Set the size of the points array
points.SetSize(iCount);
// Copy the points from the external memory to internal
int iPointIndex = 0;
while (iPointIndex < iCount)
{
points[iPointIndex]->x = pFreehand->points[iPointIndex].x;
points[iPointIndex]->y = pFreehand->points[iPointIndex].y;
iPointIndex++;
}
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicFreehand::CheckReallyHit(LPCRECT pRectHit)
{
POINT *lpPoints;
int iCount;
int i;
POINT ptLast;
UINT uRadius;
RECT rectHit;
iCount = points.GetSize();
lpPoints = (POINT *)points.GetBuffer();
if( iCount == 0 )
return( FALSE );
// addjust hit rect to lpPoints coord space.
rectHit = *pRectHit;
::OffsetRect(&rectHit, -m_rect.left, -m_rect.top);
if( (iCount > 0)&&(iCount < 2) )
{
// only one point, just hit check it
uRadius = m_uiPenWidth >> 1; // m_uiPenWidth/2
return(
CircleHit( lpPoints->x, lpPoints->y, uRadius, &rectHit, TRUE )
);
}
// look for a hit on each line segment body
ptLast = *lpPoints++;
for( i=1; i<iCount; i++ )
{
if( LineHit( ptLast.x, ptLast.y,
lpPoints->x, lpPoints->y, m_uiPenWidth,
FALSE, FALSE,
&rectHit )
)
return( TRUE ); // got a hit
ptLast = *lpPoints++;
}
// now, look for a hit on the line endpoints if m_uiPenWidth > 1
if( m_uiPenWidth > 1 )
{
uRadius = m_uiPenWidth >> 1; // m_uiPenWidth/2
lpPoints = (POINT *)points.GetBuffer();
for( i=0; i<iCount; i++, lpPoints++ )
{
if( CircleHit( lpPoints->x, lpPoints->y, uRadius, &rectHit, FALSE )
)
return( TRUE ); // got a hit
}
}
return( FALSE ); // no hits
}
DCWbGraphicRectangle::~DCWbGraphicRectangle( void )
{
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphicRectangle::SetRect
//
// Purpose: Set the rectangle size/position
//
//
void DCWbGraphicRectangle::SetRect(LPCRECT lprect)
{
DCWbGraphic::SetRect(lprect);
// Generate the new bounding rectangle
CalculateBoundsRect();
}
//
//
// Function: DCWbGraphicRectangle::MoveBy
//
// Purpose: Move the rectangle
//
//
void DCWbGraphicRectangle::MoveBy(int cx, int cy)
{
// Move the rectangle
::OffsetRect(&m_rect, cx, cy);
// Move the other object attributes
DCWbGraphic::MoveBy(cx, cy);
}
//
//
// Function: DCWbGraphicRectangle::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the object
//
//
void DCWbGraphicRectangle::CalculateBoundsRect(void)
{
// Generate the new bounding rectangle
m_boundsRect = m_rect;
NormalizeRect(&m_boundsRect);
::InflateRect(&m_boundsRect, m_uiPenWidth, m_uiPenWidth);
}
//
//
// Function: DCWbGraphicRectangle::Draw
//
// Purpose: Draw the rectangle
//
//
void DCWbGraphicRectangle::Draw(HDC hDC)
{
int iOldROP;
RECT clipBox;
HPEN hPen;
HPEN hOldPen;
HBRUSH hOldBrush;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicRectangle::Draw");
// Only draw anything if the bounding rectangle intersects
// the current clip box.
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
// Select the pen
hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
hOldPen = SelectPen(hDC, hPen);
hOldBrush = SelectBrush(hDC, ::GetStockObject(NULL_BRUSH));
// Select the raster operation
iOldROP = ::SetROP2(hDC, m_iPenROP);
// Draw the rectangle
::Rectangle(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
m_boundsRect.bottom);
::SetROP2(hDC, iOldROP);
SelectPen(hDC, hOldPen);
if (hPen != NULL)
{
::DeletePen(hPen);
}
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicRectangle::CheckReallyHit(LPCRECT pRectHit)
{
RECT rectEdge;
RECT rectHit;
// check left edge
rectEdge.left = m_rect.left - m_uiPenWidth;
rectEdge.top = m_rect.top - m_uiPenWidth;
rectEdge.right = m_rect.left;
rectEdge.bottom = m_rect.bottom + m_uiPenWidth;
if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
return( TRUE );
// check right edge
rectEdge.left = m_rect.right;
rectEdge.right = m_rect.right + m_uiPenWidth;
if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
return( TRUE );
// check top edge
rectEdge.left = m_rect.left;
rectEdge.right = m_rect.right;
rectEdge.bottom = m_rect.top;
if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
return( TRUE );
// check bottom edge
rectEdge.top = m_rect.bottom;
rectEdge.bottom = m_rect.bottom + m_uiPenWidth;
if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
return( TRUE );
return( FALSE );
}
DCWbGraphicFilledRectangle::~DCWbGraphicFilledRectangle( void )
{
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphicFilledRectangle::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the object
//
//
void DCWbGraphicFilledRectangle::CalculateBoundsRect(void)
{
// Generate the new bounding rectangle
// This is one greater than the rectangle to include the drawing rectangle
m_boundsRect = m_rect;
NormalizeRect(&m_boundsRect);
::InflateRect(&m_boundsRect, 1, 1);
}
//
//
// Function: DCWbGraphicFilledRectangle::Draw
//
// Purpose: Draw the rectangle
//
//
void DCWbGraphicFilledRectangle::Draw(HDC hDC)
{
HPEN hPen;
HPEN hOldPen;
HBRUSH hBrush;
HBRUSH hOldBrush;
int iOldROP;
RECT clipBox;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFilledRectangle::Draw");
// Only draw anything if the bounding rectangle intersects
// the current clip box.
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
// Select the pen
hPen = ::CreatePen(m_iPenStyle, 2, m_clrPenColor);
hOldPen = SelectPen(hDC, hPen);
hBrush = ::CreateSolidBrush(m_clrPenColor);
hOldBrush = SelectBrush(hDC, hBrush);
// Select the raster operation
iOldROP = ::SetROP2(hDC, m_iPenROP);
// Draw the rectangle
::Rectangle(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
m_boundsRect.bottom);
// Restore the ROP mode
::SetROP2(hDC, iOldROP);
SelectBrush(hDC, hOldBrush);
if (hBrush != NULL)
{
::DeleteBrush(hBrush);
}
SelectPen(hDC, hOldPen);
if (hPen != NULL)
{
::DeletePen(hPen);
}
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicFilledRectangle::CheckReallyHit(LPCRECT pRectHit)
{
return( TRUE );
}
//
// Draws a tracking rect for every marker obj in marker
// (DCWbGraphicSelectTrackingRectangle is a friend of DCWbGraphicMarker
// and WbDrawingArea)
//
void DCWbGraphicSelectTrackingRectangle::Draw(HDC hDC)
{
POSITION posNext;
DCWbGraphic *pGraphic;
LPRECT pMarkerRect;
RECT rectTracker;
CPtrToPtrList *pMList;
// don't draw at start point or XOR will get out of sync
if( (m_Offset.cx == 0)&&(m_Offset.cy == 0) )
return;
ASSERT(g_pDraw);
pMList = &(g_pDraw->m_pMarker->MarkerList);
if( pMList->IsEmpty() )
return;
posNext = pMList->GetHeadPosition();
while( posNext != NULL )
{
pMList->GetNextAssoc( posNext, (void *&)pGraphic, (void *&)pMarkerRect );
if( pMarkerRect != NULL )
{
rectTracker = *pMarkerRect;
::OffsetRect(&rectTracker, m_Offset.cx, m_Offset.cy);
SetRect(&rectTracker);
DCWbGraphicRectangle::Draw(hDC);
}
}
}
void DCWbGraphicSelectTrackingRectangle::MoveBy(int cx, int cy)
{
m_Offset.cx += cx;
m_Offset.cy += cy;
}
DCWbGraphicEllipse::~DCWbGraphicEllipse( void )
{
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphicEllipse::SetRect
//
// Purpose: Set the ellipse size/position
//
//
void DCWbGraphicEllipse::SetRect(LPCRECT lprc)
{
DCWbGraphic::SetRect(lprc);
// Generate the new bounding rectangle
CalculateBoundsRect();
}
//
//
// Function: DCWbGraphicEllipse::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the object
//
//
void DCWbGraphicEllipse::CalculateBoundsRect(void)
{
// Generate the new bounding rectangle
// This includes all the line, since we draw inside the bounds
m_boundsRect = m_rect;
NormalizeRect(&m_boundsRect);
::InflateRect(&m_boundsRect, m_uiPenWidth, m_uiPenWidth);
}
//
//
// Function: DCWbGraphicEllipse::MoveBy
//
// Purpose: Move the ellipse
//
//
void DCWbGraphicEllipse::MoveBy(int cx, int cy)
{
// Move the ellipse
::OffsetRect(&m_rect, cx, cy);
// Move the other object attributes
DCWbGraphic::MoveBy(cx, cy);
}
//
//
// Function: DCWbGraphicEllipse::Draw
//
// Purpose: Draw the ellipse
//
//
void DCWbGraphicEllipse::Draw(HDC hDC)
{
HPEN hPen;
HPEN hOldPen;
HBRUSH hOldBrush;
int iOldROP;
RECT clipBox;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicEllipse::Draw");
// Only draw anything if the bounding rectangle intersects
// the current clip box.
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
// Select the pen
hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
hOldPen = SelectPen(hDC, hPen);
hOldBrush = SelectBrush(hDC, ::GetStockObject(NULL_BRUSH));
// Select the raster operation
iOldROP = ::SetROP2(hDC, m_iPenROP);
// Draw the rectangle
::Ellipse(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
m_boundsRect.bottom);
::SetROP2(hDC, iOldROP);
SelectBrush(hDC, hOldBrush);
SelectPen(hDC, hOldPen);
if (hPen != NULL)
{
::DeletePen(hPen);
}
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicEllipse::CheckReallyHit(LPCRECT pRectHit)
{
return( EllipseHit( &m_rect, TRUE, m_uiPenWidth, pRectHit ) );
}
DCWbGraphicFilledEllipse::~DCWbGraphicFilledEllipse( void )
{
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
}
//
//
// Function: DCWbGraphicFilledEllipse::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the object
//
//
void DCWbGraphicFilledEllipse::CalculateBoundsRect(void)
{
// Generate the new bounding rectangle
// This is one greater than the rectangle to include the drawing rectangle
m_boundsRect = m_rect;
NormalizeRect(&m_boundsRect);
::InflateRect(&m_boundsRect, 1, 1);
}
//
//
// Function: DCWbGraphicFilledEllipse::Draw
//
// Purpose: Draw the ellipse
//
//
void DCWbGraphicFilledEllipse::Draw(HDC hDC)
{
RECT clipBox;
HPEN hPen;
HPEN hOldPen;
HBRUSH hBrush;
HBRUSH hOldBrush;
int iOldROP;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFilledEllipse::Draw");
// Only draw anything if the bounding rectangle intersects
// the current clip box.
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
// Select the pen
hPen = ::CreatePen(m_iPenStyle, 2, m_clrPenColor);
hOldPen = SelectPen(hDC, hPen);
hBrush = ::CreateSolidBrush(m_clrPenColor);
hOldBrush = SelectBrush(hDC, hBrush);
// Select the raster operation
iOldROP = ::SetROP2(hDC, m_iPenROP);
// Draw the rectangle
::Ellipse(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
m_boundsRect.bottom);
::SetROP2(hDC, iOldROP);
SelectBrush(hDC, hOldBrush);
if (hBrush != NULL)
{
::DeleteBrush(hBrush);
}
SelectPen(hDC, hOldPen);
if (hPen != NULL)
{
::DeletePen(hPen);
}
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicFilledEllipse::CheckReallyHit(LPCRECT pRectHit)
{
return( EllipseHit( &m_rect, FALSE, 0, pRectHit ) );
}
//
//
// Function: DCWbGraphicText::DCWbGraphicText
//
// Purpose: Initialize a new drawn text object.
//
//
DCWbGraphicText::DCWbGraphicText(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::DCWbGraphicText");
m_hFontThumb = NULL;
m_hFont = ::CreateFont(0,0,0,0,FW_NORMAL,0,0,0,0,OUT_TT_PRECIS,
CLIP_DFA_OVERRIDE,
DRAFT_QUALITY,
FF_SWISS,NULL);
// Add an empty line to the text array
strTextArray.Add(_T(""));
// Show that the graphic has not changed
m_bChanged = FALSE;
m_nKerningOffset = 0; // added for bug 469
}
DCWbGraphicText::DCWbGraphicText(PWB_GRAPHIC pHeader)
: DCWbGraphic()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::DCWbGraphicText");
ASSERT(pHeader != NULL);
m_hFont = NULL;
m_hFontThumb = NULL;
// Note that we do everything in this constructor because of the
// calls to ReadHeader and ReadExtra. If we let the DCWbGraphic base
// constructor do it the wrong version of ReadExtra will be called
// (the one in DCWbGraphic instead of the one in DCWbGraphicText).
// Add an empty line to the text array
strTextArray.Add(_T(""));
// Read the data
ReadHeader(pHeader);
ReadExtra(pHeader);
// Show that the graphic has not changed
m_bChanged = FALSE;
}
DCWbGraphicText::DCWbGraphicText
(
WB_PAGE_HANDLE hPage,
WB_GRAPHIC_HANDLE hGraphic
) : DCWbGraphic()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::DCWbGraphicText");
// Note that we do everything in this constructor because of the
// call to ReadExternal. If we let the DCWbGraphic base constructor
// do it the wrong version of ReadExtra will be called (the one
// in DCWbGraphic instead of the one in DCWbGraphicText);
// Set up the page and graphic handle
ASSERT(hPage != WB_PAGE_HANDLE_NULL);
m_hPage = hPage;
ASSERT(hGraphic != NULL);
m_hGraphic = hGraphic;
m_hFont = NULL;
m_hFontThumb = NULL;
// Add an empty line to the text array
strTextArray.Add(_T(""));
// Read the data
ReadExternal();
// Show that the graphic has not changed
m_bChanged = FALSE;
}
//
//
// Function: DCWbGraphicText:: ~DCWbGraphicText
//
// Purpose: Destruct a text object
//
//
DCWbGraphicText::~DCWbGraphicText()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::~DCWbGraphicText");
// don't know if we are selected or not so just delete anyway
if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
// Ensure that the DC does not contain our fonts
if(g_pDraw != NULL)
{
g_pDraw->UnPrimeFont(g_pDraw->GetCachedDC());
}
if (m_hFontThumb != NULL)
{
::DeleteFont(m_hFontThumb);
m_hFontThumb = NULL;
}
if (m_hFont != NULL)
{
::DeleteFont(m_hFont);
m_hFont = NULL;
}
}
StrCspn(char * string, char * control)
{
char *str = string;
char *ctrl = control;
unsigned char map[32];
int count;
/* Clear out bit map */
for (count=0; count<32; count++)
map[count] = 0;
/* Set bits in control map */
while (*ctrl)
{
map[*ctrl >> 3] |= (1 << (*ctrl & 7));
ctrl++;
}
count=0;
map[0] |= 1; /* null chars not considered */
while (!(map[*str >> 3] & (1 << (*str & 7))))
{
count++;
str++;
}
return(count);
}
//
//
// Function: DCWbGraphicText::SetText
//
// Purpose: Set the text of the object
//
//
void DCWbGraphicText::SetText(TCHAR * strText)
{
// Remove all the current stored text
strTextArray.RemoveAll();
// Scan the text for carriage return and new-line characters
int iNext = 0;
int iLast = 0;
int textSize = lstrlen(strText);
TCHAR savedChar[1];
//
// In this case, we don't know how many lines there will be. So we
// use Add() from the StrArray class.
//
while (iNext < textSize)
{
// Find the next carriage return or line feed
iNext += StrCspn(strText + iNext, "\r\n");
// Extract the text before the terminator
// and add it to the current list of text lines.
savedChar[0] = strText[iNext];
strText[iNext] = 0;
strTextArray.Add((strText+iLast));
strText[iNext] = savedChar[0];
if (iNext < textSize)
{
// Skip the carriage return
if (strText[iNext] == '\r')
iNext++;
// Skip a following new line (if there is one)
if (strText[iNext] == '\n')
iNext++;
// Update the index of the start of the next line
iLast = iNext;
}
}
// Calculate the bounding rectangle for the new text
CalculateBoundsRect();
// Show that the graphic has not changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphicText::SetText
//
// Purpose: Set the text of the object
//
//
void DCWbGraphicText::SetText(const StrArray& _strTextArray)
{
// Scan the text for carriage return and new-line characters
int iSize = _strTextArray.GetSize();
//
// In this case we know how many lines, so set that # then use SetAt()
// to stick text there.
//
strTextArray.RemoveAll();
strTextArray.SetSize(iSize);
int iNext = 0;
for ( ; iNext < iSize; iNext++)
{
strTextArray.SetAt(iNext, _strTextArray[iNext]);
}
// Calculate the new bounding rectangle
CalculateBoundsRect();
// Show that the graphic has changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphicText::SetFont
//
// Purpose: Set the font to be used for drawing
//
//
void DCWbGraphicText::SetFont(HFONT hFont)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::SetFont");
// Get the font details
LOGFONT lfont;
::GetObject(hFont, sizeof(LOGFONT), &lfont);
//
// Pass the logical font into the SetFont() function
//
SetFont(&lfont);
}
//
//
// Function: DCWbGraphicText::SetFont(metrics)
//
// Purpose: Set the font to be used for drawing
//
//
void DCWbGraphicText::SetFont(LOGFONT *pLogFont, BOOL bReCalc )
{
HFONT hOldFont;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::SetFont");
// Ensure that the font can be resized by the zoom function
// (proof quality prevents font scaling).
pLogFont->lfQuality = DRAFT_QUALITY;
//zap FontAssociation mode (bug 3258)
pLogFont->lfClipPrecision |= CLIP_DFA_OVERRIDE;
// Always work in cell coordinates to get scaling right
TRACE_MSG(("Setting font height %d, width %d, face %s, family %d, precis %d",
pLogFont->lfHeight,pLogFont->lfWidth,pLogFont->lfFaceName,
pLogFont->lfPitchAndFamily, pLogFont->lfOutPrecision));
hOldFont = m_hFont;
m_hFont = ::CreateFontIndirect(pLogFont);
if (!m_hFont)
{
// Could not create the font
ERROR_OUT(("Failed to create font"));
DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
return;
}
// Calculate the line height for this font
if(g_pDraw != NULL)
{
HDC hDC = g_pDraw->GetCachedDC();
g_pDraw->PrimeFont(hDC, m_hFont, &m_textMetrics);
}
// We are now guaranteed to be able to delete the old font
if (hOldFont != NULL)
{
::DeleteFont(hOldFont);
}
// Set up the thumbnail font, forcing truetype if not currently TT
if (!(m_textMetrics.tmPitchAndFamily & TMPF_TRUETYPE))
{
pLogFont->lfFaceName[0] = 0;
pLogFont->lfOutPrecision = OUT_TT_PRECIS;
TRACE_MSG(("Non-True type font"));
}
if (m_hFontThumb != NULL)
{
::DeleteFont(m_hFontThumb);
}
m_hFontThumb = ::CreateFontIndirect(pLogFont);
if (!m_hFontThumb)
{
// Could not create the font
ERROR_OUT(("Failed to create thumbnail font"));
DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
return;
}
// Calculate the bounding rectangle, accounting for the new font
if( bReCalc )
CalculateBoundsRect();
// Show that the graphic has changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphicText::GetTextABC
//
// Purpose: Calculate the ABC numbers for a string of text
//
// COMMENT BY RAND: The abc returned is for the whole string, not just one
// char. I.e, ABC.abcA is the offset to the first glyph in
// the string, ABC.abcB is the sum of all of the glyphs and
// ABC.abcC is the trailing space after the last glyph.
// ABC.abcA + ABC.abcB + ABC.abcC is the total rendered
// length including overhangs.
//
// Note - we never use the A spacing so it is always 0
//
ABC DCWbGraphicText::GetTextABC( LPCTSTR pText,
int iStartX,
int iStopX)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::GetTextABC");
ABC abcResult;
HDC hDC;
BOOL rc = FALSE;
ABC abcFirst;
ABC abcLast;
BOOL zoomed = g_pDraw->Zoomed();
int nCharLast;
int i;
LPCTSTR pScanStr;
ZeroMemory( (PVOID)&abcResult, sizeof abcResult );
ZeroMemory( (PVOID)&abcFirst, sizeof abcFirst );
ZeroMemory( (PVOID)&abcLast, sizeof abcLast );
// Get the standard size measure of the text
LPCTSTR pABC = (pText + iStartX);
int pABCLength = iStopX - iStartX;
hDC = g_pDraw->GetCachedDC();
g_pDraw->PrimeFont(hDC, m_hFont, &m_textMetrics);
//
// We must temporarily unzoom if we are currently zoomed since the
// weird Windows font handling will not give us the same answer for
// the text extent in zoomed mode for some TrueType fonts
//
if (zoomed)
{
::ScaleViewportExtEx(hDC, 1, g_pDraw->ZoomFactor(), 1, g_pDraw->ZoomFactor(), NULL);
}
DWORD size = ::GetTabbedTextExtent(hDC, pABC, pABCLength, 0, NULL);
// We now have the advance width of the text
abcResult.abcB = LOWORD(size);
TRACE_MSG(("Basic text width is %d",abcResult.abcB));
// Allow for C space (or overhang)
if (iStopX > iStartX)
{
if (m_textMetrics.tmPitchAndFamily & TMPF_TRUETYPE)
{
if(GetSystemMetrics( SM_DBCSENABLED ))
{
// have to handle DBCS on both ends
if( IsDBCSLeadByte( (BYTE)pABC[0] ) )
{
// pack multi byte char into a WORD for GetCharABCWidths
WORD wMultiChar = MAKEWORD( pABC[1], pABC[0] );
rc = ::GetCharABCWidths(hDC, wMultiChar, wMultiChar, &abcFirst);
}
else
{
// first char is SBCS
rc = ::GetCharABCWidths(hDC, pABC[0], pABC[0], &abcFirst );
}
// Check for DBCS as last char. Have to scan whole string to be sure
pScanStr = pABC;
nCharLast = 0;
for( i=0; i<pABCLength; i++, pScanStr++ )
{
nCharLast = i;
if( IsDBCSLeadByte( (BYTE)*pScanStr ) )
{
i++;
pScanStr++;
}
}
if( IsDBCSLeadByte( (BYTE)pABC[nCharLast] ) )
{
// pack multi byte char into a WORD for GetCharABCWidths
ASSERT( (nCharLast+1) < pABCLength );
WORD wMultiChar = MAKEWORD( pABC[nCharLast+1], pABC[nCharLast] );
rc = ::GetCharABCWidths(hDC, wMultiChar, wMultiChar, &abcLast);
}
else
{
// last char is SBCS
rc = ::GetCharABCWidths(hDC, pABC[nCharLast], pABC[nCharLast], &abcLast );
}
}
else
{
// SBCS, no special fiddling, just call GetCharABCWidths()
rc = ::GetCharABCWidths(hDC, pABC[0], pABC[0], &abcFirst );
nCharLast = pABCLength-1;
rc = rc && ::GetCharABCWidths(hDC, pABC[nCharLast], pABC[nCharLast], &abcLast );
}
TRACE_MSG(("abcFirst: rc=%d, a=%d, b=%d, c=%d",
rc, abcFirst.abcA, abcFirst.abcB, abcFirst.abcC) );
TRACE_MSG(("abcLast: rc=%d, a=%d, b=%d, c=%d",
rc, abcLast.abcA, abcLast.abcB, abcLast.abcC) );
}
if( rc )
{
// The text was trutype and we got good abcwidths
// Give the C space of the last characters from
// the string as the C space of the text.
abcResult.abcA = abcFirst.abcA;
abcResult.abcC = abcLast.abcC;
}
else
{
//
// Mock up C value for a non TT font by taking some of overhang as
// the negative C value.
//
//TRACE_MSG(("Using overhang -%d as C space",m_textMetrics.tmOverhang/2));
// Adjust B by -overhang to make update rect schoot
// far enough to the left so that the toes of italic cap A's
// don't get clipped. Ignore comment above.
abcResult.abcB -= m_textMetrics.tmOverhang;
}
}
//
// If we temporarily unzoomed then restore it now
//
if (zoomed)
{
::ScaleViewportExtEx(hDC, g_pDraw->ZoomFactor(), 1, g_pDraw->ZoomFactor(), 1, NULL);
}
TRACE_MSG(("Final text width is %d, C space %d",abcResult.abcB,abcResult.abcC));
return abcResult;
}
//
//
// Function: DCWbGraphicText::GetTextRectangle
//
// Purpose: Calculate the bounding rectangle of a portion of the object
//
//
void DCWbGraphicText::GetTextRectangle(int iStartY,
int iStartX,
int iStopX,
LPRECT lprc)
{
// ABC structures for text sizing
ABC abcText1;
ABC abcText2;
int iLeftOffset = 0;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::GetTextRect");
// Here we calculate the width of the text glyphs in which we
// are interested. In case there are tabs involved we must start
// with position 0 and get two lengths then subtract them
abcText1 = GetTextABC(strTextArray[iStartY], 0, iStopX);
if (iStartX > 0)
{
// The third param used to be iStartX-1 which is WRONG. It
// has to point to the first char pos past the string
// we are using.
abcText2 = GetTextABC(strTextArray[iStartY], 0, iStartX);
// Just use B part for offset. Adding A snd/or C to it moves the update
// rectangle too far to the right and clips the char
iLeftOffset = abcText2.abcB;
}
else
{
ZeroMemory( &abcText2, sizeof abcText2 );
}
//
// We need to allow for A and C space in the bounding rectangle. Use
// ABS function just to make sure we get a large enough rectangle.
//
// Move A and C from original offset calc to here for width of update
// rectangle. Add in tmOverhang (non zero for non-tt fonts) to compensate
// for the kludge in GetTextABC()....THIS EDITBOX CODE HAS GOT TO GO...
abcText1.abcB = abcText1.abcB - iLeftOffset +
abs(abcText2.abcA) + abs(abcText2.abcC) +
abs(abcText1.abcA) + abs(abcText1.abcC) +
m_textMetrics.tmOverhang;
TRACE_DEBUG(("Left offset %d",iLeftOffset));
TRACE_DEBUG(("B width now %d",abcText1.abcB));
// Build the result rectangle.
// Note that we never return an empty rectangle. This allows for the
// fact that the Windows rectangle functions will ignore empty
// rectangles completely. This would cause the bounding rectangle
// calculation (for instance) to go wrong if the top or bottom lines
// in a text object were empty.
int iLineHeight = m_textMetrics.tmHeight + m_textMetrics.tmExternalLeading;
lprc->left = 0;
lprc->top = 0;
lprc->right = max(1, abcText1.abcB);
lprc->bottom = iLineHeight;
::OffsetRect(lprc, iLeftOffset, iLineHeight * iStartY);
// rect is the correct width at this point but it might need to be schooted to
// the left a bit to allow for kerning of 1st letter (bug 469)
if( abcText1.abcA < 0 )
{
::OffsetRect(lprc, abcText1.abcA, 0);
m_nKerningOffset = -abcText1.abcA;
}
else
m_nKerningOffset = 0;
POINT pt;
GetPosition(&pt);
::OffsetRect(lprc, pt.x, pt.y);
}
//
//
// Function: DCWbGraphicText::CalculateRect
//
// Purpose: Calculate the bounding rectangle of a portion of the object
//
//
void DCWbGraphicText::CalculateRect(int iStartX,
int iStartY,
int iStopX,
int iStopY,
LPRECT lprcResult)
{
RECT rcResult;
RECT rcT;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::CalculateRect");
//
// NOTE:
// We must use an intermediate rectangle, so as not to disturb the
// contents of the passed-in one until done. lprcResult may be pointing
// to the current bounds rect, and we call functions from here that
// may need its current value.
//
// Initialize the result rectangle
::SetRectEmpty(&rcResult);
// Allow for special limit values and ensure that the start and stop
// character positions are in range.
if (iStopY == LAST_LINE)
{
iStopY = strTextArray.GetSize() - 1;
}
iStopY = min(iStopY, strTextArray.GetSize() - 1);
iStopY = max(iStopY, 0);
if (iStopX == LAST_CHAR)
{
iStopX = lstrlen(strTextArray[iStopY]);
}
iStopX = min(iStopX, lstrlen(strTextArray[iStopY]));
iStopX = max(iStopX, 0);
// Loop through the text strings, adding each to the rectangle
for (int iIndex = iStartY; iIndex <= iStopY; iIndex++)
{
int iLeftX = ((iIndex == iStartY) ? iStartX : 0);
int iRightX = ((iIndex == iStopY)
? iStopX : lstrlen(strTextArray[iIndex]));
GetTextRectangle(iIndex, iLeftX, iRightX, &rcT);
::UnionRect(&rcResult, &rcResult, &rcT);
}
*lprcResult = rcResult;
}
//
//
// Function: DCWbGraphicText::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the object
//
//
void DCWbGraphicText::CalculateBoundsRect(void)
{
// Set the new bounding rectangle
CalculateRect(0, 0, LAST_CHAR, LAST_LINE, &m_boundsRect);
}
//
//
// Function: DCWbGraphicText::Draw
//
// Purpose : Draw the object onto the specified DC
//
//
void DCWbGraphicText::Draw(HDC hDC, BOOL thumbNail)
{
RECT clipBox;
BOOL dbcsEnabled = GetSystemMetrics(SM_DBCSENABLED);
INT *tabArray;
UINT ch;
int i,j;
BOOL zoomed = g_pDraw->Zoomed();
int oldBkMode = 0;
int iIndex = 0;
POINT pointPos;
int nLastTab;
ABC abc;
int iLength;
TCHAR * strLine;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::Draw");
//
// Only draw anything if the bounding rectangle intersects the current
// clip box.
//
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
//
// Select the font.
//
if (thumbNail)
{
TRACE_MSG(("Using thumbnail font"));
g_pDraw->PrimeFont(hDC, m_hFontThumb, &m_textMetrics);
}
else
{
TRACE_MSG(("Using standard font"));
g_pDraw->PrimeFont(hDC, m_hFont, &m_textMetrics);
}
//
// Set the color and mode for drawing.
//
::SetTextColor(hDC, m_clrPenColor);
//
// Set the background to be transparent
//
oldBkMode = ::SetBkMode(hDC, TRANSPARENT);
//
// Calculate the bounding rectangle, accounting for the new font.
//
CalculateBoundsRect();
//
// Get the start point for the text.
//
pointPos.x = m_boundsRect.left + m_nKerningOffset;
pointPos.y = m_boundsRect.top;
//
// Loop through the text strings drawing each as we go.
//
for (iIndex = 0; iIndex < strTextArray.GetSize(); iIndex++)
{
//
// Get a reference to the line to be printed for convenience.
//
strLine = (LPTSTR)strTextArray[iIndex];
iLength = lstrlen(strLine);
//
// Only draw the line if there are any characters in it.
//
if (iLength > 0)
{
if (zoomed)
{
// if new fails just skip it
tabArray = new INT[iLength+1];
if( tabArray == NULL )
{
ERROR_OUT(("Failed to allocate tabArray"));
continue;
}
// We are zoomed. Must calculate char spacings
// ourselfs so that they end up proportionally
// in the right places. TabbedTextOut will not
// do this right so we have to use ExtTextOut with
// a tab array.
// figure out tab array
j = 0;
nLastTab = 0;
for (i=0; i < iLength; i++)
{
ch = strLine[(int)i]; //Don't worry about DBCS here...
abc = GetTextABC(strLine, 0, i);
if( j > 0 )
tabArray[j-1] = abc.abcB - nLastTab;
nLastTab = abc.abcB;
j++;
}
// Now, strip out any tab chars so they don't interact
// in an obnoxious manner with the tab array we just
// made and so they don't make ugly little
// blocks when they are drawn.
for (i=0; i < iLength; i++)
{
ch = strLine[(int)i];
if ((dbcsEnabled) && (IsDBCSLeadByte((BYTE)ch)))
i++;
else
if(strLine[(int)i] == '\t')
strLine[i] = ' '; // blow off tab, tab array
// will compensate for this
}
// do it
::ExtTextOut(hDC, pointPos.x,
pointPos.y,
0,
NULL,
strLine,
iLength,
tabArray);
delete tabArray;
}
else
{
POINT ptPos;
GetPosition(&ptPos);
// Not zoomed, just do it
::TabbedTextOut(hDC, pointPos.x,
pointPos.y,
strLine,
iLength,
0,
NULL,
ptPos.x);
}
}
//
// Move to the next line.
//
pointPos.y += (m_textMetrics.tmHeight);
}
//
// Restore the old background mode.
//
::SetBkMode(hDC, oldBkMode);
g_pDraw->UnPrimeFont(hDC);
}
//
//
// Function: DCWbGraphicText::CalculateExternalLength
//
// Purpose: Return the length of the external representation of the
// graphic.
//
//
DWORD DCWbGraphicText::CalculateExternalLength(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::CalculateExternalLength");
// Loop through the text strings, adding the size of each as we go
DWORD length = sizeof(WB_GRAPHIC_TEXT);
int iCount = strTextArray.GetSize();
for (int iIndex = 0; iIndex < iCount; iIndex++)
{
// Allow extra bytes per string for NULL term
length += lstrlen(strTextArray[iIndex]) + 2;
}
return length;
}
//
//
// Function: DCWbGraphicText::WriteExtra
//
// Purpose: Write the extra (non-header) data to the flat representation
// of the graphic.
//
//
void DCWbGraphicText::WriteExtra(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::WriteExtra");
// Allocate the memory
PWB_GRAPHIC_TEXT pText = (PWB_GRAPHIC_TEXT) pHeader;
// Get the font face name
LOGFONT lfont;
::GetObject(m_hFont, sizeof(LOGFONT), &lfont);
// Copy the face name into the flat object representation
// The other information comes from the logical font details
TRACE_MSG(("Font details height %d, avwidth %d, family %d, face %s",
lfont.lfHeight,
lfont.lfWidth,
lfont.lfPitchAndFamily,
lfont.lfFaceName));
_tcscpy(pText->faceName, lfont.lfFaceName);
pText->charHeight = (short)lfont.lfHeight;
pText->averageCharWidth = (short)lfont.lfWidth;
pText->strokeWeight = (short)lfont.lfWeight;
pText->italic = lfont.lfItalic;
pText->underline = lfont.lfUnderline;
pText->strikeout = lfont.lfStrikeOut;
pText->pitch = lfont.lfPitchAndFamily;
//COMMENT BY RAND
// Original DCL apps ignore WB_GRAPHIC_TEXT::codePage. I am using it here
// to pass around the fonts script (character set). This might change later.
// Apps that ignore this have set it to 0 which will be interpreted as an
// ANSI_CHARSET.
pText->codePage = lfont.lfCharSet;
// Loop through the text strings, adding each as we go
char* pDest = pText->text;
int iCount = strTextArray.GetSize();
for (int iIndex = 0; iIndex < iCount; iIndex++)
{
_tcscpy(pDest, strTextArray[iIndex]);
pDest += lstrlen(strTextArray[iIndex]);
// Add the null terminator
*pDest++ = '\0';
}
// Save the number of strings
pText->stringCount = (TSHR_UINT16)iCount;
}
//
//
// Function: DCWbGraphicText::ReadExtra
//
// Purpose: Read the extra (non-header) data from the flat
// representation of the graphic.
//
//
void DCWbGraphicText::ReadExtra(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::ReadExtra");
// Allocate the memory
PWB_GRAPHIC_TEXT pText = (PWB_GRAPHIC_TEXT) pHeader;
// Get the font details
LOGFONT lfont;
lfont.lfHeight = (short)pText->charHeight;
//
lfont.lfWidth = pText->averageCharWidth;
lfont.lfEscapement = 0;
lfont.lfOrientation = 0;
lfont.lfWeight = pText->strokeWeight;
lfont.lfItalic = pText->italic;
lfont.lfUnderline = pText->underline;
lfont.lfStrikeOut = pText->strikeout;
//COMMENT BY RAND
// Original DCL apps ignore WB_GRAPHIC_TEXT::codePage. I am using it here
// to pass around the fonts script (character set). This might change later.
// Apps that ignore this have set it to 0 which will be interpreted as an
// ANSI_CHARSET.
lfont.lfCharSet = (BYTE)pText->codePage;
lfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS | CLIP_DFA_OVERRIDE;
lfont.lfQuality = DRAFT_QUALITY;
lfont.lfPitchAndFamily = pText->pitch;
_tcscpy(lfont.lfFaceName, pText->faceName);
TRACE_MSG(("Setting height to %d, width %d, pitch %d, face %s",
pText->charHeight, pText->averageCharWidth, pText->pitch, pText->faceName));
// Loop through the text strings, retrieving each as we go
TCHAR* pString = pText->text;
int iCount = pText->stringCount;
// Remove all the current stored text
strTextArray.RemoveAll();
strTextArray.SetSize(iCount);
for (int iIndex = 0; iIndex < iCount; iIndex++)
{
strTextArray.SetAt(iIndex, pString);
pString += lstrlen(pString);
// Skip the null terminator
pString++;
}
// Set the current font
SetFont(&lfont);
}
//
//
// Function: InvalidateMetrics
//
// Purpose: Mark the metrics need retrieving again
//
//
void DCWbGraphicText::InvalidateMetrics(void)
{
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicText::CheckReallyHit(LPCRECT pRectHit )
{
return( TRUE );
}
// version of Position() that compensates for kerning (bug 469)
void DCWbGraphicText::GetPosition(LPPOINT lppt)
{
lppt->x = m_boundsRect.left + m_nKerningOffset;
lppt->y = m_boundsRect.top;
}
//
//
// Function: DCWbGraphicDIB::DCWbGraphicDIB
//
// Purpose: Initialize a new drawn bitmap object.
//
//
DCWbGraphicDIB::DCWbGraphicDIB(void)
{
// Show that we have no internal image
m_lpbiImage = NULL;
}
DCWbGraphicDIB::DCWbGraphicDIB(PWB_GRAPHIC pHeader)
: DCWbGraphic(pHeader)
{
// Show that we have no internal image
m_lpbiImage = NULL;
}
DCWbGraphicDIB::DCWbGraphicDIB
(
WB_PAGE_HANDLE hPage,
WB_GRAPHIC_HANDLE hGraphic
) : DCWbGraphic(hPage, hGraphic)
{
// Show that we have no internal image
m_lpbiImage = NULL;
}
//
//
// Function: DCWbGraphicDIB::~DCWbGraphicDIB
//
// Purpose: Destruct a drawn bitmap object.
//
//
DCWbGraphicDIB::~DCWbGraphicDIB(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::~DCWbGraphicDIB");
// don't know if we are selected or not so just delete anyway
if(g_pDraw->m_pMarker != NULL)
{
g_pDraw->m_pMarker->DeleteMarker( this );
}
DeleteImage();
}
//
//
// Function: DCWbGraphicDIB::SetImage
//
// Purpose: Set the image of the object
//
//
void DCWbGraphicDIB::SetImage(LPBITMAPINFOHEADER lpbi)
{
// Delete any current bits
DeleteImage();
// Save the DIB bits--this is a COPY we now own
m_lpbiImage = lpbi;
// Update the bounds rectangle
CalculateBoundsRect();
// Show that the graphic has changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphicDIB::CalculateBoundsRect
//
// Purpose: Calculate the bounding rectangle of the bitmap
//
//
void DCWbGraphicDIB::CalculateBoundsRect()
{
// If there is no bitmap set up, the bounding rectangle is empty
if (m_lpbiImage == NULL)
{
::SetRectEmpty(&m_boundsRect);
}
else
{
// Calculate the bounding rectangle from the size of the bitmap
m_boundsRect.right = m_boundsRect.left + m_lpbiImage->biWidth;
m_boundsRect.bottom = m_boundsRect.top + m_lpbiImage->biHeight;
}
}
//
//
// Function: DCWbGraphicDIB::CalculateExternalLength
//
// Purpose: Return the length of the external representation of the
// graphic.
//
//
DWORD DCWbGraphicDIB::CalculateExternalLength(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::CalculateExternalLength");
// Use the internal representation to calculate the external length.
DWORD dwLength = sizeof(WB_GRAPHIC_DIB);
if (m_lpbiImage != NULL)
{
dwLength += DIB_TotalLength(m_lpbiImage);
}
else
{
// If we have got an external form already, use its length
if (m_hGraphic != NULL)
{
dwLength = m_dwExternalLength;
}
}
return dwLength;
}
//
//
// Function: DCWbGraphicDIB::WriteExtra
//
// Purpose: Write the data above and beyond the header to the pointer
// passed.
//
//
void DCWbGraphicDIB::WriteExtra(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::WriteExtra");
// Nothing more to do if we do not have an image
if (m_lpbiImage != NULL)
{
// Copy the data into place
memcpy(((BYTE *) pHeader) + pHeader->dataOffset, m_lpbiImage,
DIB_TotalLength(m_lpbiImage));
}
}
//
//
// Function: DCWbGraphicDIB::ReadExtra
//
// Purpose: Read the data above and beyond the header to the pointer
// passed.
//
//
//
// DCWbGraphicDIB does not have a ReadExtra function. The Draw function
// uses the external data (if there is any) and the local data if there is
// not.
//
//
//
// Function: DCWbGraphicDIB::CopyExtra
//
// Purpose: Copy the data above and beyond the header into this object.
//
//
void DCWbGraphicDIB::CopyExtra(PWB_GRAPHIC pHeader)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::CopyExtra");
// Get a pointer to the DIB data
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER) (((BYTE *) pHeader) + pHeader->dataOffset);
// Make a DIB copy
ASSERT(m_lpbiImage == NULL);
m_lpbiImage = DIB_Copy(lpbi);
// Show that the graphic has changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphicDIB::FromScreenArea
//
// Purpose: Set the content of the object from an area of the screen
//
//
void DCWbGraphicDIB::FromScreenArea(LPCRECT lprcScreen)
{
LPBITMAPINFOHEADER lpbiNew;
lpbiNew = DIB_FromScreenArea(lprcScreen);
if (lpbiNew != NULL)
{
// Set this as our current bits
SetImage(lpbiNew);
}
else
{
::Message(NULL, (UINT)IDS_MSG_CAPTION, (UINT)IDS_CANTGETBMP, (UINT)MB_OK );
}
}
//
//
// Function: DCWbGraphicDIB::DeleteImage
//
// Purpose: Delete the internal image
//
//
void DCWbGraphicDIB::DeleteImage(void)
{
// If we have DIB bits, delete
if (m_lpbiImage != NULL)
{
::GlobalFree((HGLOBAL)m_lpbiImage);
m_lpbiImage = NULL;
}
// Show our contents have changed
m_bChanged = TRUE;
}
//
//
// Function: DCWbGraphicDIB::GetDIBData
//
// Purpose: Return a pointer to the DIB data
//
//
BOOL DCWbGraphicDIB::GetDIBData(HOLD_DATA& hold)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::GetDIBData");
// Pointer to image data (set up below depending on whether
// we have an internal or external image).
hold.lpbi = NULL;
hold.pHeader = NULL;
// Draw depending on whether the DIB data is internal or external
if (m_hGraphic == NULL)
{
// Do nothing if we do not have an image at all
if (m_lpbiImage != NULL)
{
hold.lpbi = m_lpbiImage;
}
}
else
{
// Lock the object data in the page
hold.pHeader = (PWB_GRAPHIC) PG_GetData(m_hPage, m_hGraphic);
if (hold.pHeader != NULL)
{
hold.lpbi = (LPBITMAPINFOHEADER) (((BYTE *) hold.pHeader)
+ hold.pHeader->dataOffset);
}
}
return (hold.lpbi != NULL);
}
//
//
// Function: DCWbGraphicDIB::ReleaseDIBData
//
// Purpose: Release DIB data previously obtained with GetDIBData
//
//
void DCWbGraphicDIB::ReleaseDIBData(HOLD_DATA& hold)
{
if ((m_hGraphic != NULL) && (hold.pHeader != NULL))
{
// Release external memory
g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, hold.pHeader);
hold.pHeader = NULL;
}
// Reset the hold bitmap info pointer
hold.lpbi = NULL;
}
//
//
// Function: DCWbGraphicDIB::Draw
//
// Purpose: Draw the object onto the specified DC
//
//
void DCWbGraphicDIB::Draw(HDC hDC)
{
RECT clipBox;
MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::Draw");
// Only draw anything if the bounding rectangle intersects
// the current clip box.
if (::GetClipBox(hDC, &clipBox) == ERROR)
{
WARNING_OUT(("Failed to get clip box"));
}
else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
{
TRACE_MSG(("No clip/bounds intersection"));
return;
}
// Pointer to image data (set up below depending on whether
// we have an internal or external image.
HOLD_DATA hold;
if (GetDIBData(hold))
{
// Set the stretch mode to be used so that scan lines are deleted
// rather than combined. This will tend to preserve color better.
int iOldStretchMode = ::SetStretchBltMode(hDC, STRETCH_DELETESCANS);
// Draw the bitmap
BOOL bResult = ::StretchDIBits(hDC,
m_boundsRect.left,
m_boundsRect.top,
m_boundsRect.right - m_boundsRect.left,
m_boundsRect.bottom - m_boundsRect.top,
0,
0,
(UINT) hold.lpbi->biWidth,
(UINT) hold.lpbi->biHeight,
(VOID FAR *) DIB_Bits(hold.lpbi),
(LPBITMAPINFO)hold.lpbi,
DIB_RGB_COLORS,
SRCCOPY);
// Restore the stretch mode
::SetStretchBltMode(hDC, iOldStretchMode);
// Release external memory
ReleaseDIBData(hold);
}
}
//
// Checks object for an actual overlap with pRectHit. This
// function assumes that the boundingRect has already been
// compared with pRectHit.
//
BOOL DCWbGraphicDIB::CheckReallyHit(LPCRECT pRectHit)
{
return( TRUE );
}
ObjectTrashCan::~ObjectTrashCan(void)
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::~ObjectTrashCan");
BurnTrash();
}
BOOL ObjectTrashCan::GotTrash( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::GotTrash");
return(!Trash.IsEmpty());
}
void ObjectTrashCan::BurnTrash( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::BurnTrash");
int nObjects;
int i;
// zap objects
POSITION pos = Trash.GetHeadPosition();
while (pos != NULL)
{
delete Trash.GetNext(pos);
}
// zap pointers
EmptyTrash();
}
void ObjectTrashCan::CollectTrash( DCWbGraphic *pGObj )
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::CollectTrash");
Trash.AddTail(pGObj); // stuff it in the sack
m_hPage = pGObj->Page();
}
void
ObjectTrashCan::EmptyTrash( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::EmptyTrash");
// zap pointers but leave objects scattered about the room
Trash.EmptyList();
}
void ObjectTrashCan::AddToPageLast
(
WB_PAGE_HANDLE hPage
)
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::AddToPageLast");
int nObjects;
int i;
POSITION posNext = Trash.GetHeadPosition();
while( posNext != NULL )
{
((DCWbGraphic *)(Trash.GetNext(posNext)))->AddToPageLast(hPage);
}
}
void
ObjectTrashCan::SelectTrash( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::SelectTrash");
int nObjects;
int i;
BOOL bForceAdd;
DCWbGraphic *pGObj;
// Zap current selection with first object and then add remaining
// objects to current selection
bForceAdd = FALSE;
POSITION posNext = Trash.GetHeadPosition();
while( posNext != NULL )
{
pGObj = (DCWbGraphic *)(Trash.GetNext(posNext));
g_pMain->m_drawingArea.SelectGraphic( pGObj, TRUE, bForceAdd );
bForceAdd = TRUE;
}
}
CPtrToPtrList::CPtrToPtrList( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::CPtrToPtrList");
}// CPtrToPtrList::CPtrToPtrList
CPtrToPtrList::~CPtrToPtrList( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::~CPtrToPtrList");
RemoveAll();
}// CPtrToPtrList::~CPtrToPtrList
void
CPtrToPtrList::RemoveAll( void )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::RemoveAll");
POSITION pos;
stPtrPair *pPp;
// clean up pairs
pos = GetHeadPosition();
while( pos != NULL )
{
pPp = (stPtrPair *)GetNext( pos );
if( pPp != NULL )
delete pPp;
}
COBLIST::EmptyList();
}// CPtrToPtrList::~CPtrToPtrList
void
CPtrToPtrList::SetAt( void *key, void *newValue )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::SetAt");
stPtrPair *pPp;
// see if key is already there
pPp = FindMainThingPair( key, NULL );
if( pPp != NULL )
{
// it's there, we're just updating its value
pPp->pRelatedThing = newValue;
}
else
{
// this is a new entry
pPp = new stPtrPair;
if( pPp != NULL )
{
pPp->pMainThing = key;
pPp->pRelatedThing = newValue;
AddTail(pPp);
}
else
{
ERROR_OUT( ("CPtrToPtrList: can't alloc stPtrPair") );
}
}
}// CPtrToPtrList::SetAt
BOOL
CPtrToPtrList::RemoveKey( void *key )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::RemoveKey");
POSITION pos;
stPtrPair *pPp;
pPp = FindMainThingPair( key, &pos );
if( pPp != NULL )
{
RemoveAt( pos );
delete pPp;
return( TRUE );
}
else
return( FALSE );
}// CPtrToPtrList::RemoveKey
void
CPtrToPtrList::GetNextAssoc( POSITION &rNextPosition, void *&rKey, void *&rValue )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::GetNextAssoc");
stPtrPair *pPp;
pPp = (stPtrPair *)GetNext( rNextPosition );
if( pPp != NULL )
{
rKey = pPp->pMainThing;
rValue = pPp->pRelatedThing;
}
else
{
rKey = NULL;
rValue = NULL;
}
}// CPtrToPtrList::GetNextAssoc
BOOL
CPtrToPtrList::Lookup( void *key, void *&rValue )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::Lookup");
stPtrPair *pPp;
pPp = FindMainThingPair( key, NULL );
if( pPp != NULL )
{
rValue = pPp->pRelatedThing;
return( TRUE );
}
else
{
rValue = NULL;
return( FALSE );
}
}// CPtrToPtrList::Lookup
CPtrToPtrList::stPtrPair *
CPtrToPtrList::FindMainThingPair( void *pMainThing, POSITION *pPos )
{
MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::FindMainThingPair");
POSITION pos;
POSITION lastpos;
stPtrPair *pPp;
if( pPos != NULL )
*pPos = NULL;
// look for pair containing pMainThing
pos = GetHeadPosition();
while( pos != NULL )
{
lastpos = pos;
pPp = (stPtrPair *)GetNext( pos );
if( pPp->pMainThing == pMainThing )
{
if( pPos != NULL )
*pPos = lastpos;
return( pPp );
}
}
// didn't find it
return( NULL );
}// CPtrToPtrList::FindMainThingPair
#define ARRAY_INCREMENT 0x200
DCDWordArray::DCDWordArray()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCDWordArray::DCDWordArray");
m_Size = 0;
m_MaxSize = ARRAY_INCREMENT;
m_pData = new POINT[ARRAY_INCREMENT];
if (!m_pData)
{
ERROR_OUT(("Failed to allocate m_pData POINT array"));
}
}
DCDWordArray::~DCDWordArray()
{
MLZ_EntryOut(ZONE_FUNCTION, "DCDWordArray::~DCDWordArray");
delete[] m_pData;
}
//
// We need to increase the size of the array
//
BOOL DCDWordArray::ReallocateArray(void)
{
POINT *pOldArray = m_pData;
m_pData = new POINT[m_MaxSize];
if(m_pData)
{
TRACE_DEBUG((">>>>>Increasing size of array to hold %d points", m_MaxSize));
// copy new data from old
memcpy( m_pData, pOldArray, (m_Size) * sizeof(POINT));
TRACE_DEBUG(("Deleting array of points %x", pOldArray));
delete[] pOldArray;
return TRUE;
}
else
{
ERROR_OUT(("Failed to allocate new POINT array of size %d", m_MaxSize));
m_pData = pOldArray;
return FALSE;
}
}
//
// Add a new point to the array
//
void DCDWordArray::Add(POINT point)
{
MLZ_EntryOut(ZONE_FUNCTION, "DCDWordArray::Add");
TRACE_DEBUG(("Adding point(%d,%d) at %d", point.x, point.y, m_Size));
TRACE_DEBUG(("Adding point at %x", &m_pData[m_Size]));
if(m_pData == NULL)
{
return;
}
m_pData[m_Size].x = point.x;
m_pData[m_Size].y = point.y;
m_Size++;
//
// if we want more points, we need to re allocate the array
//
if(m_Size == m_MaxSize)
{
m_MaxSize +=ARRAY_INCREMENT;
if(ReallocateArray() == FALSE)
{
m_Size--;
}
}
}
//
// Return the number of points in the array
//
UINT DCDWordArray::GetSize(void)
{
return m_Size;
}
//
// Sets the size of the array
//
void DCDWordArray::SetSize(UINT size)
{
int newSize;
//
// if we want more points, we need to re allocate the array
//
if (size > m_MaxSize)
{
m_MaxSize= ((size/ARRAY_INCREMENT)+1)*ARRAY_INCREMENT;
if(ReallocateArray() == FALSE)
{
return;
}
}
m_Size = size;
}