You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5125 lines
117 KiB
5125 lines
117 KiB
//
|
|
// 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;
|
|
}
|
|
|
|
|