Leaked source code of windows server 2003
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.
 
 
 
 
 
 

388 lines
16 KiB

/******************************************************************************/
/* T_CURVE.CPP: IMPLEMENTATION OF THE CCurveTool CLASS */
/* */
/* */
/******************************************************************************/
/* */
/* Methods in this file */
/* */
/* CCurve Tool Class Object */
/* CCurveTool::CCurveTool */
/* CCurveTool::~CCurveTool */
/* CCurveTool::AdjustBoundingRect */
/* CCurveTool::AddPoint */
/* CCurveTool::SetCurrentPoint */
/* CCurveTool::DrawCurve */
/* CCurveTool::AdjustPointsForConstraint */
/* CCurveTool::PreProcessPoints */
/* CCurveTool::Render */
/* CCurveTool::OnStartDrag */
/* CCurveTool::OnEndDrag */
/* CCurveTool::OnDrag */
/* CCurveTool::OnCancel */
/* CCurveTool::CanEndMultiptOperation */
/* CCurveTool::EndMultiptOperation */
/******************************************************************************/
/* */
/* Briefly, this Object draws a curve from 4 (currently) points. It generates */
/* a list of points which are placed in the array, and then calls polyline */
/* to draw line segments to build a curve. */
/* */
/* The array is divided into 2 pieces. The first piece is the anchor points, */
/* the 2nd piece is the array of points which will be passed to polyline. */
/* The anchor points are placed in the array in the following order */
/* 2,3,4,...1. See the addpoint method below for info on this order. */
/* */
/******************************************************************************/
#include "stdafx.h"
#include "global.h"
#include "pbrush.h"
#include "pbrusdoc.h"
#include "pbrusfrm.h"
#include "bmobject.h"
#include "imgsuprt.h"
#include "imgwnd.h"
#include "imgwell.h"
#include "pbrusvw.h"
#include "t_curve.h"
#ifdef _DEBUG
#undef THIS_FILE
static CHAR BASED_CODE THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CCurveTool, CRubberTool)
#include "memtrace.h"
extern CLineTool NEAR g_lineTool;
CCurveTool NEAR g_curveTool;
/******************************************************************************/
CCurveTool::CCurveTool()
{
m_nCmdID = IDMB_CURVETOOL;
m_iNumAnchorPoints = 0;
m_cRectBounding.SetRectEmpty();
}
/******************************************************************************/
CCurveTool::~CCurveTool()
{
m_cRectBounding.SetRectEmpty();
}
/******************************************************************************/
/* recalculate the bounding rectangle for the polyline/curve */
void CCurveTool::AdjustBoundingRect(void)
{
int iStrokeWidth = GetStrokeWidth();
int i;
if (m_iNumAnchorPoints >= 1)
{
//set the rect to equal the 1st value
m_cRectBounding.SetRect(m_PolyPoints[0].x, m_PolyPoints[0].y,
m_PolyPoints[0].x, m_PolyPoints[0].y);
}
for (i=1; i < m_iNumAnchorPoints; i++)
{
m_cRectBounding.SetRect( min(m_PolyPoints[i].x, m_cRectBounding.left),
min(m_PolyPoints[i].y, m_cRectBounding.top),
max(m_PolyPoints[i].x, m_cRectBounding.right),
max(m_PolyPoints[i].y, m_cRectBounding.bottom));
}
// Adjust rectangle for Windows GDI (Non-inclusive right/bottom)
m_cRectBounding.bottom++; m_cRectBounding.right++;
// Adjust for width of current drawing line/border
m_cRectBounding.OffsetRect(-(iStrokeWidth/2),-(iStrokeWidth/2));
m_cRectBounding.InflateRect(iStrokeWidth, iStrokeWidth);
}
/******************************************************************************/
// This method adds a new point into the array and increases the number of
// anchor points currently in the array. If there are no points in the
// array, it adds a point to the 1st position (index 0). If there are any
// points currently in the array, it copies the last point to the new
// location, and then adds the new point where the old last point was (1 point
// before the last point. The 1st point added is always the last point in the
// array, and the 2nd point added is always the 1st point.
// The order of the points in the array are: 2,3,4,....,1
void CCurveTool::AddPoint(POINT ptNewPoint)
{
BOOL bRC = TRUE;
if (m_iNumAnchorPoints == 0)
{
m_PolyPoints[m_iNumAnchorPoints] = ptNewPoint;
m_iNumAnchorPoints++;
}
else
{
if (m_iNumAnchorPoints < MAX_ANCHOR_POINTS)
{
m_PolyPoints[m_iNumAnchorPoints] = m_PolyPoints[m_iNumAnchorPoints-1];
m_PolyPoints[m_iNumAnchorPoints-1] = ptNewPoint;
m_iNumAnchorPoints++;
}
}
AdjustBoundingRect();
}
/******************************************************************************/
// This method changes the value of the last point in the array. If there are
// 2 points, then it modifies the 2nd point, knowing that when there are only
// 2 points, we are draing a straight line (between 2 points). If there are
// more than 2 points, it modified the second to last point in the array,
// which is actually the last point dropped/placed. See above for expl of
// order of points in the array.
void CCurveTool::SetCurrentPoint(POINT ptNewPoint)
{
if (m_iNumAnchorPoints == 2)
{
m_PolyPoints[m_iNumAnchorPoints-1] = ptNewPoint;
}
else
{
if (m_iNumAnchorPoints > 2)
{
m_PolyPoints[m_iNumAnchorPoints-2] = ptNewPoint;
}
}
AdjustBoundingRect();
}
/******************************************************************************/
BOOL CCurveTool::DrawCurve(CDC* pDC)
{
POINT ptCurve[MAX_ANCHOR_POINTS];
UINT uPoints = m_iNumAnchorPoints;
int i;
for (i=uPoints-1; i>=0; --i)
{
ptCurve[i] = m_PolyPoints[i];
}
// HACK: PolyBezier cannot handle 3 points, so repeat the middle point
if (uPoints == 3)
{
ptCurve[3] = ptCurve[2];
ptCurve[2] = ptCurve[1];
uPoints = 4;
}
PolyBezier(pDC->m_hDC, ptCurve, uPoints);
return(TRUE);
}
/******************************************************************************/
/* Call the line's adjustpointsforconstraint member function */
/* only do this if there are 2 points (i.e. drawing a straight line */
void CCurveTool::AdjustPointsForConstraint(MTI *pmti)
{
if (m_iNumAnchorPoints == 2)
{
g_lineTool.AdjustPointsForConstraint(pmti);
}
}
/******************************************************************************/
// ptDown must be anchor point for our line, not where we did mouse button down
// on a subsequent point in the multipt operation
void CCurveTool::PreProcessPoints(MTI *pmti)
{
pmti->ptDown = m_PolyPoints[0];
CRubberTool::PreProcessPoints(pmti);
}
/******************************************************************************/
/* Render sets up the pen and brush, and then calls either Render */
/* The pen and brush is set up exactly the same as the parent routine in */
/* CRubberTool. If there are only 2 points, do the standard line drawing */
/* using moveto and lineto, instead of trying to create a curve between 2 pts */
void CCurveTool::Render(CDC* pDC, CRect& rect, BOOL bDraw, BOOL bCommit, BOOL bCtrlDown)
{
// Setup Pen/Brush
SetupPenBrush( pDC->m_hDC, bDraw, TRUE, bCtrlDown );
if (m_iNumAnchorPoints == 2)
{
pDC->MoveTo( m_PolyPoints[0].x, m_PolyPoints[0].y );
pDC->LineTo( m_PolyPoints[1].x, m_PolyPoints[1].y );
}
else
{
if (m_iNumAnchorPoints > 2)
{
DrawCurve( pDC );
}
}
// Cleanup Pen/Brush
SetupPenBrush( pDC->m_hDC, bDraw, FALSE, bCtrlDown );
// Need to return the bounding rect
rect = m_cRectBounding;
}
void CCurveTool::OnActivate( BOOL bActivate )
{
if (!bActivate && m_bMultPtOpInProgress)
{
CImgWnd* pImgWnd = ((CPBView*)((CFrameWnd*)AfxGetMainWnd())->GetActiveView())->m_pImgWnd;
// Stolen from CPBView::OnEscape
// I don't think this can ever be NULL, but just in case
if (pImgWnd != NULL)
{
EndMultiptOperation( FALSE ); // end the multipt operation
Render(CDC::FromHandle(pImgWnd->m_pImg->hDC), m_cRectBounding, TRUE, TRUE, FALSE);
InvalImgRect(pImgWnd->m_pImg, &m_cRectBounding);
CommitImgRect(pImgWnd->m_pImg, &m_cRectBounding);
pImgWnd->FinishUndo(m_cRectBounding);
ClearStatusBarSize();
}
}
CRubberTool::OnActivate( bActivate );
}
/******************************************************************************/
/* On Start Drag is called on mouse button down. We basically call on Start */
/* Drag of the parent (default) class after adding in our point(s) into the */
/* array of points. If this is the first point (i.e. bMultiptOpInProgress == */
/* False, then we need 2 points in our array, and we can call the default */
/* OnStartDrag. If it is not the first point, then we just add the new point */
/* and call our OnDrag. In either case, OnDrag is called which eventually */
/* calls render to do our drawing on the mouse down */
/* We only call the parent OnStartDrag the first time, because it does some */
/* setup which we do not want done each time */
void CCurveTool::OnStartDrag( CImgWnd* pImgWnd, MTI* pmti )
{
if (m_bMultPtOpInProgress)
{
AddPoint(pmti->pt);
OnDrag(pImgWnd, pmti);
}
else
{
// must reset numAnchorPoints before calling addpoint the 1st time.
m_iNumAnchorPoints = 0;
AddPoint(pmti->pt);
m_bMultPtOpInProgress = TRUE;
// No Mult Pt In Progress => 1st Click
//
// add a 2nd point, last point is what we are draing to
// 1st point is anchor. 1st time, need 2 points to draw a line
// subsequent times, just add 1 point in array of points.
AddPoint(pmti->pt);
CRubberTool::OnStartDrag(pImgWnd, pmti);
}
}
/******************************************************************************/
/* On End Drag is sent on a mouse button up. This basically is a clone of the*/
/* CRubberTool::OnEndDrag method, except that we use our bounding rect for all*/
/* the image invalidation, and commit, and undo function calls. */
/* if we are in the middle of a multipoint operation, we do not want to call */
/* all the routines to fix the drawing (e.g. invalImgRect, CommitImgRect, */
/* FinishUndo). We just want to save the current point, render, and return */
void CCurveTool::OnEndDrag( CImgWnd* pImgWnd, MTI* pmti )
{
PreProcessPoints(pmti);
SetCurrentPoint(pmti->pt);
if (m_bMultPtOpInProgress)
{
// can't call OnDrag for this object/class, since it calls preprocesspt
// again, and then onDrag. If you call preproces again, you will lose
// bounding rectange box prev, and not be able to invalidate / repaint
// Still have to invalidate bounding rect, since if rect is larger than
// current rect, must invalidate to paint. E.g. If let off shift, then
// let off button, end point would be adjusted and bouning rect would
// also be correct, but rect calculated in CRubberTool::OnDrag is
// incorrect.
InvalImgRect(pImgWnd->m_pImg, &m_cRectBounding);
CRubberTool::OnDrag(pImgWnd, pmti);
}
else
{
OnDrag(pImgWnd, pmti); // one last time to refresh display in prep for final render
Render(CDC::FromHandle(pImgWnd->m_pImg->hDC), m_cRectBounding, pmti->fLeft, TRUE, pmti->fCtrlDown);
InvalImgRect(pImgWnd->m_pImg, &m_cRectBounding);
CommitImgRect(pImgWnd->m_pImg, &m_cRectBounding);
pImgWnd->FinishUndo(m_cRectBounding);
ClearStatusBarSize();
CImgTool::OnEndDrag(pImgWnd, pmti);
}
}
/******************************************************************************/
/* On Drag is sent when the mouse is moved with the button down. We basically*/
/* save the current point, and call the base class processing. Since the base*/
/* class processing invalidates the rect on the screen and cleans it up so we */
/* can paint a new line, we have to adjust the previous rectangle to be the */
/* bounding rectangle of our polyline. If we did not do this, our previous */
/* drawing would not get erased, and we would be drawing our new line over */
/* part of the previous line. The default processing finally calls Render */
/* which since our render is virtual, will call our render method above. */
void CCurveTool::OnDrag( CImgWnd* pImgWnd, MTI* pmti )
{
PreProcessPoints(pmti);
SetCurrentPoint(pmti->pt);
CRubberTool::OnDrag(pImgWnd, pmti);
}
/******************************************************************************/
/* On Cancel is sent when the user aborts an operation while in progress */
/* EndMultiptOperation with TRUE will do all our cleanup */
void CCurveTool::OnCancel(CImgWnd* pImgWnd)
{
EndMultiptOperation(TRUE);
CImgTool::OnCancel(pImgWnd);
}
/******************************************************************************/
/* we can only end if the number of maximum points was entered. We must stay */
/* in capture/multiptmode until we get EXACTLY the desired number of anchor */
/* points */
BOOL CCurveTool::CanEndMultiptOperation(MTI* pmti )
{
if (m_iNumAnchorPoints == MAX_ANCHOR_POINTS)
{
m_bMultPtOpInProgress = FALSE;
}
else
{
m_bMultPtOpInProgress = TRUE;
}
return (CRubberTool::CanEndMultiptOperation(pmti));
}
/******************************************************************************/
/* If bAbort is true, this means an error occurred, or the user cancelled the */
/* multipoint operation in the middle of it. We just set the num of anchor */
/* points to 0 to stop drawing and call the default endmultiptoperation */
void CCurveTool::EndMultiptOperation(BOOL bAbort)
{
if (bAbort)
{
m_iNumAnchorPoints = 0;
m_cRectBounding.SetRectEmpty();
}
CRubberTool::EndMultiptOperation();
}