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.

599 lines
22 KiB

  1. /******************************************************************************/
  2. /* T_POLY.CPP: IMPLEMENTATION OF THE CPolygonTool CLASS */
  3. /* */
  4. /* */
  5. /******************************************************************************/
  6. /* */
  7. /* Methods in this file */
  8. /* */
  9. /* Polygon Tool Class Object */
  10. /* CPolygonTool::CPolygonTool */
  11. /* CPolygonTool::~CPolygonTool */
  12. /* CPolygonTool::DeleteArrayContents */
  13. /* CPolygonTool::AdjustBoundingRect */
  14. /* CPolygonTool::CopyPointsToMemArray */
  15. /* CPolygonTool::AddPoint */
  16. /* CPolygonTool::SetCurrentPoint */
  17. /* CPolygonTool::RenderInProgress */
  18. /* CPolygonTool::RenderFinal */
  19. /* CPolygonTool::SetupPenBrush */
  20. /* CPolygonTool::AdjustPointsForConstraint */
  21. /* CPolygonTool::PreProcessPoints */
  22. /* CPolygonTool::Render */
  23. /* CPolygonTool::OnStartDrag */
  24. /* CPolygonTool::OnEndDrag */
  25. /* CPolygonTool::OnDrag */
  26. /* CPolygonTool::OnCancel */
  27. /* CPolygonTool::CanEndMultiptOperation */
  28. /* CPolygonTool::EndMultiptOperation */
  29. /******************************************************************************/
  30. /* */
  31. /* Briefly, This object stores the points of the polygon in a CObArray of */
  32. /* CPoint Objects. For the in progress drawing, it calls PolyLine. When the */
  33. /* polygon is closed or completed (by the user doubleclicking => asking us to */
  34. /* close it), Polygon is called on the same points. */
  35. /* */
  36. /* The last point in the array of points is always the point the current line */
  37. /* is being drawn to. The first time 2 points are added (the Anchor/first */
  38. /* point, and the point the line is being drawn to) It does happen that this */
  39. /* first time, they are the same point. It is necessary that the first time */
  40. /* 2 points are added, since subsequent times, new points are not added, but */
  41. /* the last point is reset. */
  42. /* */
  43. /******************************************************************************/
  44. #include "stdafx.h"
  45. #include "global.h"
  46. #include "pbrush.h"
  47. #include "pbrusdoc.h"
  48. #include "pbrusfrm.h"
  49. #include "bmobject.h"
  50. #include "imgsuprt.h"
  51. #include "imgwnd.h"
  52. #include "imgwell.h"
  53. #include "t_poly.h"
  54. #ifdef _DEBUG
  55. #undef THIS_FILE
  56. static CHAR BASED_CODE THIS_FILE[] = __FILE__;
  57. #endif
  58. IMPLEMENT_DYNAMIC(CPolygonTool, CClosedFormTool)
  59. #include "memtrace.h"
  60. extern CLineTool NEAR g_lineTool;
  61. CPolygonTool NEAR g_polygonTool;
  62. extern MTI NEAR mti;
  63. /******************************************************************************/
  64. CPolygonTool::CPolygonTool()
  65. {
  66. m_nCmdID = IDMB_POLYGONTOOL;
  67. m_cRectBounding.SetRectEmpty();
  68. m_bMultPtOpInProgress = FALSE;
  69. m_nStrokeWidth = 1;
  70. }
  71. /******************************************************************************/
  72. CPolygonTool::~CPolygonTool()
  73. {
  74. m_cRectBounding.SetRectEmpty();
  75. DeleteArrayContents();
  76. }
  77. /******************************************************************************/
  78. /* delete all cpoint objects allocated and stored in the array */
  79. /* also free any memory associated with the array */
  80. void CPolygonTool::DeleteArrayContents(void)
  81. {
  82. int iSize = (int)m_cObArrayPoints.GetSize();
  83. CPoint *pcPoint;
  84. for (int i = 0; i < iSize; i++)
  85. {
  86. pcPoint= (CPoint *)m_cObArrayPoints.GetAt( i );
  87. delete pcPoint;
  88. }
  89. m_cObArrayPoints.RemoveAll();
  90. }
  91. /******************************************************************************/
  92. /* recalculate the bounding rectangle for the polyline/polygon */
  93. void CPolygonTool::AdjustBoundingRect(void)
  94. {
  95. int iSize = (int)m_cObArrayPoints.GetSize();
  96. CPoint *pcPoint;
  97. int iStrokeWidth = GetStrokeWidth();
  98. int i;
  99. if (iSize >= 1)
  100. {
  101. pcPoint= (CPoint*)m_cObArrayPoints.GetAt( 0 );
  102. //set the rect to equal the 1st value
  103. m_cRectBounding.SetRect(pcPoint->x, pcPoint->y, pcPoint->x, pcPoint->y);
  104. }
  105. for (i = 1; i < iSize; i++)
  106. {
  107. pcPoint = (CPoint *)m_cObArrayPoints.GetAt( i );
  108. m_cRectBounding.SetRect( min( pcPoint->x, m_cRectBounding.left ),
  109. min( pcPoint->y, m_cRectBounding.top ),
  110. max( pcPoint->x, m_cRectBounding.right ),
  111. max( pcPoint->y, m_cRectBounding.bottom ) );
  112. }
  113. // Adjust for width of current drawing line/border
  114. m_cRectBounding.OffsetRect ( -(iStrokeWidth / 2), -(iStrokeWidth / 2) );
  115. m_cRectBounding.InflateRect( iStrokeWidth , iStrokeWidth);
  116. }
  117. /******************************************************************************/
  118. /* This method will copy the CObArray structure of CPoints to a contiguous */
  119. /* memory block of CPoint Structures */
  120. BOOL CPolygonTool::CopyPointsToMemArray(CPoint **pcPoint, int *piNumElements)
  121. {
  122. BOOL bRC = TRUE;
  123. int i;
  124. int iSize = (int)m_cObArrayPoints.GetSize();
  125. if (! iSize)
  126. {
  127. *piNumElements = 0;
  128. *pcPoint = NULL;
  129. return TRUE;
  130. }
  131. TRY
  132. {
  133. *pcPoint = new CPoint[iSize];
  134. if (*pcPoint == NULL)
  135. {
  136. AfxThrowMemoryException();
  137. }
  138. for (i=0; i < iSize; i++)
  139. {
  140. (*pcPoint)[i] = *((CPoint*) (m_cObArrayPoints[i]));
  141. }
  142. *piNumElements = iSize;
  143. }
  144. CATCH(CMemoryException,e)
  145. {
  146. *piNumElements = 0;
  147. bRC = FALSE;
  148. }
  149. END_CATCH
  150. return bRC;
  151. }
  152. /******************************************************************************/
  153. /* This routine can Throw a CMemoryException!! */
  154. /* It adds a new point to the end of the array, possibly increasing the size */
  155. void CPolygonTool::AddPoint(POINT ptNewPoint)
  156. {
  157. CPoint *pcPoint;
  158. pcPoint = new CPoint(ptNewPoint);
  159. if (pcPoint == NULL)
  160. {
  161. AfxThrowMemoryException();
  162. }
  163. m_cObArrayPoints.Add((CObject *)pcPoint);
  164. AdjustBoundingRect();
  165. }
  166. /******************************************************************************/
  167. /* This method changes the value of the last point in the array. It does not */
  168. /* remove the point and add a new one. It just modifies it in place */
  169. void CPolygonTool::SetCurrentPoint(POINT ptNewPoint)
  170. {
  171. int iLast = (int)m_cObArrayPoints.GetUpperBound();
  172. if (iLast >= 0)
  173. {
  174. CPoint *pcPoint = (CPoint *) m_cObArrayPoints[iLast];
  175. pcPoint->x = ptNewPoint.x;
  176. pcPoint->y = ptNewPoint.y;
  177. AdjustBoundingRect();
  178. }
  179. }
  180. /******************************************************************************/
  181. /* Render In Progress is called for all drawing during the multi-pt operation */
  182. /* The only difference between this method and RenderFinal is that it calls */
  183. /* polyline and RenderFinal calls polygon. */
  184. void CPolygonTool::RenderInProgress(CDC* pDC)
  185. {
  186. CPoint *pcPointArray = 0;
  187. int iNumElements;
  188. if (CopyPointsToMemArray( &pcPointArray, &iNumElements ) && pcPointArray != NULL)
  189. {
  190. pDC->Polyline(pcPointArray, iNumElements);
  191. delete [] pcPointArray;
  192. }
  193. }
  194. /******************************************************************************/
  195. /* Render Final is called at the end of the multi-pt drawing mode. The only */
  196. /* difference between this method and RenderInProgress is that it calls */
  197. /* polygon and RenderInProgress calls polyline. */
  198. void CPolygonTool::RenderFinal(CDC* pDC)
  199. {
  200. CPoint *pcPointArray = 0;
  201. int iNumElements;
  202. if (CopyPointsToMemArray(&pcPointArray, &iNumElements) && pcPointArray != NULL)
  203. {
  204. // Remove RIP with only 2 points
  205. if (iNumElements > 2)
  206. pDC->Polygon(pcPointArray, iNumElements);
  207. delete [] pcPointArray;
  208. }
  209. }
  210. /******************************************************************************/
  211. /* This routine is called before rendering onto the DC. It basically, calls */
  212. /* the default setup to setup the pen and brush, and then overrides the Pen if*/
  213. /* drawing in progress and drawing without any border. This case is necessary*/
  214. /* since if you do not have a border, you need to see something during the in */
  215. /* progress drawing mode. It uses the inverse (not) of the screen color as */
  216. /* the border in this mode. */
  217. BOOL CPolygonTool::SetupPenBrush(HDC hDC, BOOL bLeftButton, BOOL bSetup, BOOL bCtrlDown)
  218. {
  219. static int iOldROP2Code;
  220. static BOOL bCurrentlySetup = FALSE;
  221. BOOL bRC = CClosedFormTool::SetupPenBrush(hDC, bLeftButton, bSetup, bCtrlDown);
  222. // for multipt operations in progress (e.g. drawing outline, not fill yet
  223. // if there is no border, use the not of the screen color for the border.
  224. // When bMultiptopinprogress == FALSE, final drawing, we will use a null
  225. // pen and thus have no border.
  226. if (m_bMultPtOpInProgress)
  227. {
  228. if (bSetup)
  229. {
  230. if (! bCurrentlySetup)
  231. {
  232. bCurrentlySetup = TRUE;
  233. // if no border, draw inprogress border as inverse of screen color
  234. if (! m_bBorder)
  235. iOldROP2Code = SetROP2(hDC, R2_NOT);
  236. }
  237. else
  238. // Error: Will lose allocated Brush/Pen
  239. bRC = FALSE;
  240. }
  241. else
  242. {
  243. if (bCurrentlySetup)
  244. {
  245. bCurrentlySetup = FALSE;
  246. // if no border, restore drawing mode
  247. if (! m_bBorder)
  248. SetROP2(hDC, iOldROP2Code);
  249. }
  250. else
  251. // Error: Cannot Free/cleanup Brush/Pen -- Never allocated.
  252. bRC = FALSE;
  253. }
  254. }
  255. return bRC;
  256. }
  257. /******************************************************************************/
  258. /* Call the line's adjustpointsforconstraint member function */
  259. void CPolygonTool::AdjustPointsForConstraint(MTI *pmti)
  260. {
  261. g_lineTool.AdjustPointsForConstraint(pmti);
  262. }
  263. /******************************************************************************/
  264. // ptDown must be anchor point for our line, not where we did mouse button down
  265. void CPolygonTool::PreProcessPoints(MTI *pmti)
  266. {
  267. int iLast = (int)m_cObArrayPoints.GetUpperBound();
  268. if (iLast > 0)
  269. iLast--;
  270. CPoint* pcPoint;
  271. if (iLast >= 0)
  272. {
  273. pcPoint = (CPoint *)m_cObArrayPoints[iLast];
  274. pmti->ptDown = *pcPoint;
  275. }
  276. CClosedFormTool::PreProcessPoints(pmti);
  277. }
  278. /******************************************************************************/
  279. /* Render sets up the pen and brush, and then calls either RenderInProgress */
  280. /* or RenderFinal. RenderInProgress is called if in the middle of a multipt */
  281. /* operation, and RenderFinal is called when a multipt operation is complete */
  282. /* The pen and brush is set up exactly the same as the parent routine in */
  283. /* CRubberTool */
  284. void CPolygonTool::Render(CDC* pDC, CRect& rect, BOOL bDraw, BOOL bCommit, BOOL bCtrlDown)
  285. {
  286. // Setup Pen/Brush
  287. SetupPenBrush(pDC->m_hDC, bDraw, TRUE, bCtrlDown);
  288. if (m_bMultPtOpInProgress)
  289. {
  290. RenderInProgress(pDC);
  291. }
  292. else
  293. {
  294. RenderFinal(pDC);
  295. }
  296. // Cleanup Pen/Brush
  297. SetupPenBrush(pDC->m_hDC, bDraw, FALSE, bCtrlDown);
  298. // Need to return the bounding rect
  299. rect = m_cRectBounding;
  300. }
  301. /******************************************************************************/
  302. void CPolygonTool::OnActivate( BOOL bActivate )
  303. {
  304. if (! bActivate && m_bMultPtOpInProgress)
  305. {
  306. if (m_pImgWnd != NULL)
  307. if (m_cObArrayPoints.GetSize() > 1)
  308. {
  309. OnStartDrag( m_pImgWnd, &m_MTI );
  310. OnEndDrag ( m_pImgWnd, &m_MTI );
  311. m_MTI.ptPrev = m_MTI.pt;
  312. EndMultiptOperation(); // end the multipt operation
  313. OnEndDrag( m_pImgWnd, &m_MTI );
  314. mti.fLeft = FALSE;
  315. mti.fRight = FALSE;
  316. }
  317. else
  318. OnCancel( m_pImgWnd );
  319. else
  320. EndMultiptOperation( TRUE );
  321. }
  322. m_pImgWnd = NULL;
  323. if (bActivate)
  324. {
  325. m_nStrokeWidth = g_nStrokeWidth;
  326. }
  327. else
  328. {
  329. g_nStrokeWidth = m_nStrokeWidth;
  330. }
  331. CImgTool::OnActivate( bActivate );
  332. }
  333. /******************************************************************************/
  334. void CPolygonTool::OnEnter( CImgWnd* pImgWnd, MTI* pmti )
  335. {
  336. m_pImgWnd = NULL;
  337. }
  338. /******************************************************************************/
  339. void CPolygonTool::OnLeave( CImgWnd* pImgWnd, MTI* pmti )
  340. {
  341. m_pImgWnd = pImgWnd;
  342. }
  343. /******************************************************************************/
  344. /* On Start Drag is called on mouse button down. We basically call on Start */
  345. /* Drag of the parent (default) class after adding in our point(s) into the */
  346. /* array of points. If this is the first point (i.e. bMultiptOpInProgress == */
  347. /* False, then we need 2 points in our array, and we can call the default */
  348. /* OnStartDrag. If it is not the first point, then we just add the new point */
  349. /* and call our OnDrag. In either case, OnDrag is called which eventually */
  350. /* calls render to do our drawing on the mouse down */
  351. void CPolygonTool::OnStartDrag( CImgWnd* pImgWnd, MTI* pmti )
  352. {
  353. TRY {
  354. if (m_bMultPtOpInProgress)
  355. {
  356. CRect rect;
  357. CPoint pt = pmti->pt;
  358. pImgWnd->ImageToClient( pt );
  359. pImgWnd->GetClientRect( &rect );
  360. if (rect.PtInRect( pt ))
  361. {
  362. AddPoint( pmti->pt );
  363. OnDrag( pImgWnd, pmti );
  364. }
  365. }
  366. else
  367. {
  368. DeleteArrayContents();
  369. m_cRectBounding.SetRectEmpty();
  370. AddPoint( pmti->pt );
  371. // must set m_bmultptopinprogress prior to calling onstartdrag
  372. // since that calls render,and render will call renderinprogress
  373. // or renderfinal depending on the sate of this variable.
  374. m_bMultPtOpInProgress = TRUE;
  375. // No Mult Pt In Progress => 1st Click
  376. //
  377. // add a 2nd point, last point is what we are draing to
  378. // 1st point is anchor. 1st time, need 2 points to draw a line
  379. // subsequent times, just re-use last point as anchor and only one
  380. // more point is added (above outside test for m_bmultptopinprogress)
  381. AddPoint( pmti->pt );
  382. CClosedFormTool::OnStartDrag( pImgWnd, pmti );
  383. }
  384. }
  385. CATCH(CMemoryException,e)
  386. {
  387. }
  388. END_CATCH
  389. }
  390. /******************************************************************************/
  391. /* On End Drag is sent on a mouse button up. This basically is a clone of the*/
  392. /* CRubberTool::OnEndDrag method, except that we use our bounding rect for all*/
  393. /* the image invalidation, and commit, and undo function calls. */
  394. /* if we are in the middle of a multipoint operation, we do not want to call */
  395. /* all the routines to fix the drawing (e.g. invalImgRect, CommitImgRect, */
  396. /* FinishUndo). We just want to save the current point, render, and return */
  397. void CPolygonTool::OnEndDrag( CImgWnd* pImgWnd, MTI* pmti )
  398. {
  399. PreProcessPoints(pmti);
  400. SetCurrentPoint(pmti->pt);
  401. if (m_bMultPtOpInProgress)
  402. {
  403. m_MTI = *pmti;
  404. // can't call OnDrag for this object/class, since it calls preprocesspt
  405. // again, and then onDrag. If you call preproces again, you will lose
  406. // bounding rectange box prev, and not be able to invalidate / repaint
  407. // Still have to invalidate bounding rect, since if rect is larger than
  408. // current rect, must invalidate to paint. E.g. If let off shift, then
  409. // let off button, end point would be adjusted and bouning rect would
  410. // also be correct, but rect calculated in CClosedFormTool::OnDrag is
  411. // incorrect.
  412. InvalImgRect(pImgWnd->m_pImg, &m_cRectBounding);
  413. CClosedFormTool::OnDrag(pImgWnd, pmti);
  414. return;
  415. }
  416. if (! m_cObArrayPoints.GetSize())
  417. return;
  418. OnDrag(pImgWnd, pmti); // one last time to refresh display in prep for final render
  419. Render(CDC::FromHandle(pImgWnd->m_pImg->hDC), m_cRectBounding, pmti->fLeft, TRUE, pmti->fCtrlDown);
  420. InvalImgRect(pImgWnd->m_pImg, &m_cRectBounding);
  421. CommitImgRect(pImgWnd->m_pImg, &m_cRectBounding);
  422. pImgWnd->FinishUndo(m_cRectBounding);
  423. ClearStatusBarSize();
  424. CImgTool::OnEndDrag(pImgWnd, pmti);
  425. }
  426. /******************************************************************************/
  427. /* On Drag is sent when the mouse is moved with the button down. We basically*/
  428. /* save the current point, and call the base class processing. Since the base*/
  429. /* class processing invalidates the rect on the screen and cleans it up so we */
  430. /* can paint a new line, we have to adjust the previous rectangle to be the */
  431. /* bounding rectangle of our polyline. If we did not do this, our previous */
  432. /* drawing would not get erased, and we would be drawing our new line over */
  433. /* part of the previous line. The default processing finally calls Render */
  434. /* which since our render is virtual, will call our render method above. */
  435. void CPolygonTool::OnDrag( CImgWnd* pImgWnd, MTI* pmti )
  436. {
  437. PreProcessPoints ( pmti );
  438. SetCurrentPoint ( pmti->pt );
  439. SetStatusBarPosition( pmti->pt );
  440. SetStatusBarSize ( m_cRectBounding.Size() );
  441. CClosedFormTool::OnDrag(pImgWnd, pmti);
  442. }
  443. /******************************************************************************/
  444. /* On Cancel is sent when the user aborts an operation while in progress */
  445. /* EndMultiptOperation with TRUE will do all our cleanup */
  446. void CPolygonTool::OnCancel(CImgWnd* pImgWnd)
  447. {
  448. InvalImgRect( pImgWnd->m_pImg, &m_cRectBounding );
  449. EndMultiptOperation(TRUE);
  450. CClosedFormTool::OnCancel(pImgWnd);
  451. }
  452. /******************************************************************************/
  453. /* If point is on 1st point (i.e. closes the polygon) then can end is true */
  454. // Use the stroke width to determine the width of the line and whether the */
  455. /* end point touches the beginning point because of the line thickness */
  456. BOOL CPolygonTool::CanEndMultiptOperation(MTI* pmti )
  457. {
  458. CPoint *pcPoint = (CPoint *) m_cObArrayPoints[0];
  459. CSize cSizeDiff = (*pcPoint) - pmti->pt;
  460. int iStrokeWidth = GetStrokeWidth() * 2;
  461. m_bMultPtOpInProgress = ! ((abs( cSizeDiff.cx ) <= iStrokeWidth)
  462. && (abs( cSizeDiff.cy ) <= iStrokeWidth));
  463. return ( TRUE );
  464. }
  465. /******************************************************************************/
  466. /* If bAbort is true, this means an error occurred, or the user cancelled the */
  467. /* multipoint operation in the middle of it. We need to clean up the */
  468. /* allocated memory in our array of points. */
  469. void CPolygonTool::EndMultiptOperation( BOOL bAbort )
  470. {
  471. if (bAbort)
  472. {
  473. DeleteArrayContents();
  474. }
  475. CClosedFormTool::EndMultiptOperation();
  476. }
  477. /******************************************************************************/
  478. void CPolygonTool::OnUpdateColors( CImgWnd* pImgWnd )
  479. {
  480. if (m_cObArrayPoints.GetSize() && m_bMultPtOpInProgress)
  481. {
  482. OnStartDrag( pImgWnd, &m_MTI );
  483. OnEndDrag ( pImgWnd, &m_MTI );
  484. }
  485. }
  486. /******************************************************************************/
  487.