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.

5124 lines
117 KiB

  1. //
  2. // GROBJ.CPP
  3. // Graphic Objects
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. #define DECIMAL_PRECISION 10000
  10. //
  11. // Local macros
  12. //
  13. #define min4(x1,x2,x3,x4) min((min((x1),(x2))),(min((x3),(x4))))
  14. #define max4(x1,x2,x3,x4) max((max((x1),(x2))),(max((x3),(x4))))
  15. //
  16. // CircleHit()
  17. //
  18. // Checks for overlap between circle at PcxPcy with uRadius and
  19. // lpHitRect. If overlap TRUE is returned, otherwise FALSE.
  20. //
  21. BOOL CircleHit( LONG Pcx, LONG Pcy, UINT uRadius, LPCRECT lpHitRect,
  22. BOOL bCheckPt )
  23. {
  24. RECT hr = *lpHitRect;
  25. RECT ellipse;
  26. ellipse.left = Pcx - uRadius;
  27. ellipse.right= Pcx + uRadius;
  28. ellipse.bottom = Pcy + uRadius;
  29. ellipse.top = Pcy - uRadius;
  30. // check the easy thing first (don't use PtInRect)
  31. if( bCheckPt &&(lpHitRect->left >= ellipse.left)&&(ellipse.right >= lpHitRect->right)&&
  32. (lpHitRect->top >= ellipse.top)&&(ellipse.bottom >= lpHitRect->bottom))
  33. {
  34. return( TRUE );
  35. }
  36. //
  37. // The circle is just a boring ellipse
  38. //
  39. return EllipseHit(&ellipse, bCheckPt, uRadius, lpHitRect );
  40. }
  41. //
  42. // EllipseHit()
  43. //
  44. // Checks for overlap between ellipse defined by lpEllipseRect and
  45. // lpHitRect. If overlap TRUE is returned, otherwise FALSE.
  46. //
  47. BOOL EllipseHit(LPCRECT lpEllipseRect, BOOL bBorderHit, UINT uPenWidth,
  48. LPCRECT lpHitRect )
  49. {
  50. RECT hr = *lpHitRect;
  51. // Check easy thing first. If lpEllipseRect is inside lpHitRect
  52. // then we have a hit (no duh...)
  53. if( (hr.left <= lpEllipseRect->left)&&(hr.right >= lpEllipseRect->right)&&
  54. (hr.top <= lpEllipseRect->top)&&(hr.bottom >= lpEllipseRect->bottom) )
  55. return( TRUE );
  56. // If this is an ellipse....
  57. //
  58. // * * ^
  59. // * | b | Y
  60. // * | a +-------> X
  61. // *-------+--------
  62. // |
  63. //
  64. //
  65. // Look for the ellipse hit. (x/a)^2 + (y/b)^2 = 1
  66. // If it is > 1 than the point is outside the ellipse
  67. // If it is < 1 it is inside
  68. //
  69. LONG a,b,aOuter, bOuter, x, y, xCenter, yCenter;
  70. BOOL bInsideOuter = FALSE;
  71. BOOL bOutsideInner = FALSE;
  72. //
  73. // Calculate a and b
  74. //
  75. a = (lpEllipseRect->right - lpEllipseRect->left)/2;
  76. b = (lpEllipseRect->bottom - lpEllipseRect->top)/2;
  77. //
  78. // Get the center of the ellipse
  79. //
  80. xCenter = lpEllipseRect->left + a;
  81. yCenter = lpEllipseRect->top + b;
  82. //
  83. // a and b generates a inner ellipse
  84. // aOuter and bOuter generates a outer ellipse
  85. //
  86. aOuter = a + uPenWidth + 1;
  87. bOuter = b + uPenWidth + 1;
  88. a = a - 1;
  89. b = b - 1;
  90. //
  91. // Make our coordinates relative to the center of the ellipse
  92. //
  93. y = abs(hr.bottom - yCenter);
  94. x = abs(hr.right - xCenter);
  95. //
  96. // Be carefull not to divide by 0
  97. //
  98. if((a && b && aOuter && bOuter) == 0)
  99. {
  100. return FALSE;
  101. }
  102. //
  103. // We are using LONG instead of double and we need to have some precision
  104. // that is why we multiply the equation of the ellipse
  105. // ((x/a)^2 + (y/b)^2 = 1) by DECIMAL_PRECISION
  106. // Note that the multiplication has to be done before the division, if we didn't do that
  107. // we will always get 0 or 1 for x/a
  108. //
  109. if(x*x*DECIMAL_PRECISION/(aOuter*aOuter) + y*y*DECIMAL_PRECISION/(bOuter*bOuter) <= DECIMAL_PRECISION)
  110. {
  111. bInsideOuter = TRUE;
  112. }
  113. if(x*x*DECIMAL_PRECISION/(a*a)+ y*y*DECIMAL_PRECISION/(b*b) >= DECIMAL_PRECISION)
  114. {
  115. bOutsideInner = TRUE;
  116. }
  117. //
  118. // If we are checking for border hit,
  119. // we need to be inside the outer ellipse and inside the inner
  120. //
  121. if( bBorderHit )
  122. {
  123. return( bInsideOuter & bOutsideInner );
  124. }
  125. // just need to be inside the outer ellipse
  126. else
  127. {
  128. return( bInsideOuter );
  129. }
  130. }
  131. //
  132. // LineHit()
  133. //
  134. // Checks for overlap (a "hit") between lpHitRect and the line
  135. // P1P2 accounting for line width. If bCheckP1End or bCheckP2End is
  136. // TRUE then a circle of radius 0.5 * uPenWidth is also checked for
  137. // a hit to account for the rounded ends of wide lines.
  138. //
  139. // If a hit is found TRUE is returned, otherwise FALSE.
  140. //
  141. BOOL LineHit( LONG P1x, LONG P1y, LONG P2x, LONG P2y, UINT uPenWidth,
  142. BOOL bCheckP1End, BOOL bCheckP2End,
  143. LPCRECT lpHitRect )
  144. {
  145. LONG uHalfPenWidth = uPenWidth/2;
  146. LONG a,b,x,y;
  147. x = lpHitRect->left + (lpHitRect->right - lpHitRect->left)/2;
  148. y = lpHitRect->bottom + (lpHitRect->top - lpHitRect->bottom)/2;
  149. if( (P1x == P2x)&&(P1y == P2y) )
  150. {
  151. // just check one end point's circle
  152. return( CircleHit( P1x, P1y, uHalfPenWidth, lpHitRect, TRUE ) );
  153. }
  154. // check rounded end at P1
  155. if( bCheckP1End && CircleHit( P1x, P1y, uHalfPenWidth, lpHitRect, FALSE ) )
  156. return( TRUE );
  157. // check rounded end at P2
  158. if( bCheckP2End && CircleHit( P2x, P2y, uHalfPenWidth, lpHitRect, FALSE ) )
  159. return( TRUE );
  160. //
  161. // The function of a line is Y = a.X + b
  162. //
  163. // a = (Y1-Y2)/(X1 -X2)
  164. // if we found a we get b = y1 -a.X1
  165. //
  166. if(P1x == P2x)
  167. {
  168. a=0;
  169. b = DECIMAL_PRECISION*P1x;
  170. }
  171. else
  172. {
  173. a = (P1y - P2y)*DECIMAL_PRECISION/(P1x - P2x);
  174. b = DECIMAL_PRECISION*P1y - a*P1x;
  175. }
  176. //
  177. // Paralel to Y
  178. //
  179. if(P1x == P2x && ((x >= P1x - uHalfPenWidth) && x <= P1x + uHalfPenWidth))
  180. {
  181. return TRUE;
  182. }
  183. //
  184. // Paralel to X
  185. //
  186. if(P1y == P2y && ((y >= P1y - uHalfPenWidth) && y <= P1y + uHalfPenWidth))
  187. {
  188. return TRUE;
  189. }
  190. //
  191. // General line
  192. //
  193. return(( y*DECIMAL_PRECISION <= a*x + b + DECIMAL_PRECISION*uHalfPenWidth) &
  194. ( y*DECIMAL_PRECISION >= a*x + b - DECIMAL_PRECISION*uHalfPenWidth));
  195. }
  196. //
  197. //
  198. // Function: ConstructGraphic
  199. //
  200. // Purpose: Construct a graphic from a page and handle
  201. //
  202. //
  203. DCWbGraphic* DCWbGraphic::ConstructGraphic(WB_PAGE_HANDLE hPage,
  204. WB_GRAPHIC_HANDLE hGraphic)
  205. {
  206. PWB_GRAPHIC pHeader;
  207. DCWbGraphic* pGraphic;
  208. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ConstructGraphic(page, handle)");
  209. // Get a pointer to the external graphic data
  210. // (Throws an exception if any errors occur)
  211. pHeader = PG_GetData(hPage, hGraphic);
  212. // Construct the graphic
  213. pGraphic = DCWbGraphic::ConstructGraphic(pHeader);
  214. // If we got the graphic, set its page and handle
  215. if (pGraphic != NULL)
  216. {
  217. pGraphic->m_hPage = hPage;
  218. pGraphic->m_hGraphic = hGraphic;
  219. }
  220. g_pwbCore->WBP_GraphicRelease(hPage, hGraphic, pHeader);
  221. return pGraphic;
  222. }
  223. DCWbGraphic* DCWbGraphic::ConstructGraphic(WB_PAGE_HANDLE hPage,
  224. WB_GRAPHIC_HANDLE hGraphic,
  225. PWB_GRAPHIC pHeader)
  226. {
  227. DCWbGraphic* pGraphic;
  228. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ConstructGraphic(page, pHeader)");
  229. pGraphic = DCWbGraphic::ConstructGraphic(pHeader);
  230. // If we got the graphic, set its page and handle
  231. if (pGraphic != NULL)
  232. {
  233. pGraphic->m_hPage = hPage;
  234. pGraphic->m_hGraphic = hGraphic;
  235. }
  236. return pGraphic;
  237. }
  238. DCWbGraphic* DCWbGraphic::ConstructGraphic(PWB_GRAPHIC pHeader)
  239. {
  240. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ConstructGraphic(data)");
  241. TRACE_DEBUG(("Constructing graphic of type %hd", pHeader->type));
  242. TRACE_DEBUG(("Length of graphic = %ld", pHeader->length));
  243. TRACE_DEBUG(("Data offset = %hd", pHeader->dataOffset));
  244. // Construct the internal representation of the graphic
  245. DCWbGraphic* pGraphic = NULL;
  246. if (pHeader == NULL)
  247. {
  248. return NULL;
  249. }
  250. switch (pHeader->type)
  251. {
  252. case TYPE_GRAPHIC_LINE:
  253. pGraphic = new DCWbGraphicLine(pHeader);
  254. break;
  255. case TYPE_GRAPHIC_FREEHAND:
  256. pGraphic = new DCWbGraphicFreehand(pHeader);
  257. break;
  258. case TYPE_GRAPHIC_RECTANGLE:
  259. pGraphic = new DCWbGraphicRectangle(pHeader);
  260. break;
  261. case TYPE_GRAPHIC_FILLED_RECTANGLE:
  262. pGraphic = new DCWbGraphicFilledRectangle(pHeader);
  263. break;
  264. case TYPE_GRAPHIC_ELLIPSE:
  265. pGraphic = new DCWbGraphicEllipse(pHeader);
  266. break;
  267. case TYPE_GRAPHIC_FILLED_ELLIPSE:
  268. pGraphic = new DCWbGraphicFilledEllipse(pHeader);
  269. break;
  270. case TYPE_GRAPHIC_TEXT:
  271. pGraphic = new DCWbGraphicText(pHeader);
  272. break;
  273. case TYPE_GRAPHIC_DIB:
  274. pGraphic = new DCWbGraphicDIB(pHeader);
  275. break;
  276. default:
  277. // Do nothing, the object pointer is already set to NULL
  278. break;
  279. }
  280. if (!pGraphic)
  281. {
  282. ERROR_OUT(("ConstructGraphic failing; can't allocate object of type %d",
  283. pHeader->type));
  284. }
  285. return pGraphic;
  286. }
  287. //
  288. //
  289. // Function: CopyGraphic
  290. //
  291. // Purpose: Construct a graphic from a pointer. This function makes a
  292. // complete internal copy of the graphic data.
  293. //
  294. //
  295. DCWbGraphic* DCWbGraphic::CopyGraphic(PWB_GRAPHIC pHeader)
  296. {
  297. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::CopyGraphic(PWB_GRAPHIC)");
  298. // Construct the graphic
  299. DCWbGraphic* pGraphic = DCWbGraphic::ConstructGraphic(pHeader);
  300. // Copy the extra data
  301. if (pGraphic != NULL)
  302. {
  303. pGraphic->CopyExtra(pHeader);
  304. }
  305. return pGraphic;
  306. }
  307. //
  308. //
  309. // Function: DCWbGraphic constructor
  310. //
  311. // Purpose: Construct a new graphic object.
  312. //
  313. //
  314. DCWbGraphic::DCWbGraphic(PWB_GRAPHIC pHeader)
  315. {
  316. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::DCWbGraphic");
  317. // Do basic initialization
  318. Initialize();
  319. // Convert the external data header to the internal member variables
  320. if (pHeader != NULL)
  321. {
  322. ReadHeader(pHeader);
  323. // Convert the extra data for the specific object
  324. // (not all objects have extra data).
  325. ReadExtra(pHeader);
  326. }
  327. }
  328. DCWbGraphic::DCWbGraphic(WB_PAGE_HANDLE hPage, WB_GRAPHIC_HANDLE hGraphic)
  329. {
  330. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::DCWbGraphic");
  331. // Do the basic initialization
  332. Initialize();
  333. ASSERT(hPage != WB_PAGE_HANDLE_NULL);
  334. m_hPage = hPage;
  335. ASSERT(hGraphic != NULL);
  336. m_hGraphic = hGraphic;
  337. // Read the header data
  338. ReadExternal();
  339. }
  340. DCWbGraphic::~DCWbGraphic( void )
  341. {
  342. // don't know if we are selected or not so just delete anyway
  343. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  344. {
  345. g_pDraw->m_pMarker->DeleteMarker( this );
  346. }
  347. }
  348. //
  349. //
  350. // Function: DCWbGraphic::ReadExternal
  351. //
  352. // Purpose: Read the graphic data from an externally stored graphic.
  353. // The external graphic to be used is specified by the
  354. // hGraphic member.
  355. //
  356. //
  357. void DCWbGraphic::ReadExternal(void)
  358. {
  359. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ReadExternal");
  360. ASSERT(m_hPage != WB_PAGE_HANDLE_NULL);
  361. ASSERT(m_hGraphic != NULL);
  362. // Lock the object data in the page
  363. PWB_GRAPHIC pHeader = PG_GetData(m_hPage, m_hGraphic);
  364. // Convert the external data header to the internal member variables
  365. ReadHeader(pHeader);
  366. // Convert the extra data for the specific object
  367. // (not all objects have extra data).
  368. ReadExtra(pHeader);
  369. // Release the data in the page
  370. g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, pHeader);
  371. // Show that we are no longer changed since last read/write
  372. m_bChanged = FALSE;
  373. }
  374. //
  375. //
  376. // Function: DCWbGraphic::ReadHeader
  377. //
  378. // Purpose: Convert the external representation of the graphic's header
  379. // to the internal format.
  380. //
  381. //
  382. void DCWbGraphic::ReadHeader(PWB_GRAPHIC pHeader)
  383. {
  384. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ReadHeader");
  385. // Get the length of the object
  386. m_dwExternalLength = pHeader->length;
  387. // Convert the external data header to the internal member variables
  388. // Bounding rectangle
  389. m_boundsRect.left = pHeader->rectBounds.left;
  390. m_boundsRect.top = pHeader->rectBounds.top;
  391. m_boundsRect.right = pHeader->rectBounds.right;
  392. m_boundsRect.bottom = pHeader->rectBounds.bottom;
  393. // Defining rectangle
  394. m_rect.left = pHeader->rect.left;
  395. m_rect.top = pHeader->rect.top;
  396. m_rect.right = pHeader->rect.right;
  397. m_rect.bottom = pHeader->rect.bottom;
  398. // Pen color
  399. m_clrPenColor = RGB(pHeader->color.red,
  400. pHeader->color.green,
  401. pHeader->color.blue);
  402. m_clrPenColor = SET_PALETTERGB( m_clrPenColor ); // make it do color matching
  403. // Pen width
  404. m_uiPenWidth = pHeader->penWidth;
  405. // Pen style
  406. m_iPenStyle = pHeader->penStyle;
  407. // Raster operation
  408. m_iPenROP = pHeader->rasterOp;
  409. // Get the lock indication
  410. m_uiLockState = pHeader->locked;
  411. // Get the drawing tool type
  412. if (pHeader->toolType == WBTOOL_TEXT)
  413. m_toolType = TOOLTYPE_TEXT;
  414. else
  415. m_toolType = TOOLTYPE_PEN;
  416. }
  417. //
  418. //
  419. // Function: DCWbGraphic::WriteExternal
  420. //
  421. // Purpose: Write the graphic's details to a flat WB_GRAPHIC structure
  422. //
  423. //
  424. void DCWbGraphic::WriteExternal(PWB_GRAPHIC pHeader)
  425. {
  426. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::WriteExternal");
  427. // Write the header
  428. WriteHeader(pHeader);
  429. // Write the extra data
  430. WriteExtra(pHeader);
  431. }
  432. //
  433. //
  434. // Function: DCWbGraphic::WriteHeader
  435. //
  436. // Purpose: Write the graphic's header details to a flat WB_GRAPHIC
  437. // structure.
  438. //
  439. //
  440. void DCWbGraphic::WriteHeader(PWB_GRAPHIC pHeader)
  441. {
  442. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::WriteHeader");
  443. // Convert the internal data to the external header format
  444. // Init struct
  445. FillMemory(pHeader, sizeof (WB_GRAPHIC), 0 );
  446. // Calculate the external length
  447. pHeader->length = CalculateExternalLength();
  448. // Set the type of graphic
  449. pHeader->type = (TSHR_UINT16)Type();
  450. // Assume that there is no extra data
  451. pHeader->dataOffset = sizeof(WB_GRAPHIC);
  452. // Bounding rectangle
  453. pHeader->rectBounds.left = (short)m_boundsRect.left;
  454. pHeader->rectBounds.top = (short)m_boundsRect.top;
  455. pHeader->rectBounds.right = (short)m_boundsRect.right;
  456. pHeader->rectBounds.bottom = (short)m_boundsRect.bottom;
  457. // Defining rectangle
  458. pHeader->rect.left = (short)m_rect.left;
  459. pHeader->rect.top = (short)m_rect.top;
  460. pHeader->rect.right = (short)m_rect.right;
  461. pHeader->rect.bottom = (short)m_rect.bottom;
  462. // Pen color
  463. pHeader->color.red = GetRValue(m_clrPenColor);
  464. pHeader->color.green = GetGValue(m_clrPenColor);
  465. pHeader->color.blue = GetBValue(m_clrPenColor);
  466. // Pen width
  467. pHeader->penWidth = (TSHR_UINT16)m_uiPenWidth;
  468. // Pen style
  469. pHeader->penStyle = (TSHR_UINT16)m_iPenStyle;
  470. // Raster operation
  471. pHeader->rasterOp = (TSHR_UINT16)m_iPenROP;
  472. // Set the lock indicator
  473. pHeader->locked = (BYTE) m_uiLockState;
  474. // Set the drawing method
  475. pHeader->smoothed = FALSE;
  476. // Set the drawing tool type
  477. if (m_toolType == TOOLTYPE_TEXT)
  478. pHeader->toolType = WBTOOL_TEXT;
  479. else
  480. pHeader->toolType = WBTOOL_PEN;
  481. }
  482. //
  483. //
  484. // Function: Initialize
  485. //
  486. // Purpose: Initialize the member variables
  487. //
  488. //
  489. void DCWbGraphic::Initialize(void)
  490. {
  491. m_hPage = WB_PAGE_HANDLE_NULL;
  492. m_hGraphic = NULL;
  493. m_bChanged = TRUE;
  494. m_uiLockState = WB_GRAPHIC_LOCK_NONE;
  495. //
  496. // Set default graphic attributes
  497. //
  498. ::SetRectEmpty(&m_boundsRect);
  499. ::SetRectEmpty(&m_rect);
  500. m_clrPenColor = RGB(0, 0, 0); // Black pen color
  501. m_uiPenWidth = 1; // One unit width
  502. m_iPenROP = R2_COPYPEN; // Standard drawing ROP
  503. m_iPenStyle = PS_INSIDEFRAME; // Solid pen to be used
  504. m_toolType = TOOLTYPE_PEN;
  505. }
  506. //
  507. //
  508. // Function: Copy
  509. //
  510. // Purpose: Return a copy of the graphic. The graphic returned has all
  511. // its data read into local memory. The returned graphic has
  512. // the same page as the copied graphic, but a NULL handle.
  513. //
  514. //
  515. DCWbGraphic* DCWbGraphic::Copy(void) const
  516. {
  517. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Copy");
  518. // Get a pointer to the external graphic data
  519. // (Throws an exception if any errors occur)
  520. PWB_GRAPHIC pHeader = PG_GetData(m_hPage, m_hGraphic);
  521. // Construct the graphic
  522. DCWbGraphic* pGraphic = DCWbGraphic::CopyGraphic(pHeader);
  523. // If we got the graphic, set its page and handle
  524. if (pGraphic != NULL)
  525. {
  526. pGraphic->m_hPage = m_hPage;
  527. pGraphic->m_hGraphic = NULL;
  528. }
  529. // Release the data
  530. g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, pHeader);
  531. return pGraphic;
  532. }
  533. //
  534. //
  535. // Function: DCWbGraphic::SetBoundsRect
  536. //
  537. // Purpose: Set the bounding rectangle of the object
  538. //
  539. //
  540. void DCWbGraphic::SetBoundsRect(LPCRECT lprc)
  541. {
  542. m_boundsRect = *lprc;
  543. }
  544. //
  545. //
  546. // Function: DCWbGraphic::SetRect
  547. //
  548. // Purpose: Set the defining rectangle of the object
  549. //
  550. //
  551. void DCWbGraphic::SetRect(LPCRECT lprc)
  552. {
  553. m_rect = *lprc;
  554. NormalizeRect(&m_rect);
  555. // Show that we have been changed
  556. m_bChanged = TRUE;
  557. }
  558. void DCWbGraphic::SetRectPts(POINT point1, POINT point2)
  559. {
  560. RECT rc;
  561. rc.left = point1.x;
  562. rc.top = point1.y;
  563. rc.right = point2.x;
  564. rc.bottom = point2.y;
  565. SetRect(&rc);
  566. }
  567. //
  568. //
  569. // Function: DCWbGraphic::PointInBounds
  570. //
  571. // Purpose: Return TRUE if the specified point lies in the bounding
  572. // rectangle of the graphic object.
  573. //
  574. //
  575. BOOL DCWbGraphic::PointInBounds(POINT point)
  576. {
  577. return(::PtInRect(&m_boundsRect, point));
  578. }
  579. //
  580. //
  581. // Function: DCWbGraphic::MoveBy
  582. //
  583. // Purpose: Translate the object by the offset specified
  584. //
  585. //
  586. void DCWbGraphic::MoveBy(int cx, int cy)
  587. {
  588. // Move the bounding rectangle
  589. ::OffsetRect(&m_boundsRect, cx, cy);
  590. // Show that we have been changed
  591. m_bChanged = TRUE;
  592. }
  593. //
  594. //
  595. // Function: DCWbGraphic::MoveTo
  596. //
  597. // Purpose: Move the object to an absolute position
  598. //
  599. //
  600. void DCWbGraphic::MoveTo(int x, int y)
  601. {
  602. // Calculate the offset needed to translate the object from its current
  603. // position to the required position.
  604. x -= m_boundsRect.left;
  605. y -= m_boundsRect.top;
  606. MoveBy(x, y);
  607. }
  608. //
  609. //
  610. // Function: DCWbGraphic::GetPosition
  611. //
  612. // Purpose: Return the top left corner of the object's bounding
  613. // rectangle
  614. //
  615. //
  616. void DCWbGraphic::GetPosition(LPPOINT lppt)
  617. {
  618. lppt->x = m_boundsRect.left;
  619. lppt->y = m_boundsRect.top;
  620. }
  621. //
  622. //
  623. // Function: DCWbGraphic::NormalizeRect
  624. //
  625. // Purpose: Normalize a rectangle ensuring that the top left is above
  626. // and to the left of the bottom right.
  627. //
  628. //
  629. void DCWbGraphic::NormalizeRect(LPRECT lprc)
  630. {
  631. int tmp;
  632. if (lprc->right < lprc->left)
  633. {
  634. tmp = lprc->left;
  635. lprc->left = lprc->right;
  636. lprc->right = tmp;
  637. }
  638. if (lprc->bottom < lprc->top)
  639. {
  640. tmp = lprc->top;
  641. lprc->top = lprc->bottom;
  642. lprc->bottom = tmp;
  643. }
  644. }
  645. //
  646. //
  647. // Function: DCWbGraphic::SetColor
  648. //
  649. // Purpose: Set the object color.
  650. //
  651. //
  652. void DCWbGraphic::SetColor(COLORREF color)
  653. {
  654. color = SET_PALETTERGB( color ); // make it use color matching
  655. if (m_clrPenColor != color)
  656. {
  657. // Save the new color
  658. m_clrPenColor = color;
  659. // Show that we have been changed
  660. m_bChanged = TRUE;
  661. }
  662. }
  663. //
  664. //
  665. // Function: DCWbGraphic::SetROP
  666. //
  667. // Purpose: Set the object raster operation
  668. //
  669. //
  670. void DCWbGraphic::SetROP(int iPenROP)
  671. {
  672. // If the new ROP is different
  673. if (m_iPenROP != iPenROP)
  674. {
  675. // Save the new ROP
  676. m_iPenROP = iPenROP;
  677. // Show that we have been changed
  678. m_bChanged = TRUE;
  679. }
  680. }
  681. //
  682. //
  683. // Function: DCWbGraphic::SetPenStyle
  684. //
  685. // Purpose: Set the object pen style
  686. //
  687. //
  688. void DCWbGraphic::SetPenStyle(int iPenStyle)
  689. {
  690. // If the new style is different
  691. if (m_iPenStyle != iPenStyle)
  692. {
  693. // Save the new pen style
  694. m_iPenStyle = iPenStyle;
  695. // Show that the graphic has been changed
  696. m_bChanged = TRUE;
  697. }
  698. }
  699. //
  700. //
  701. // Function: DCWbGraphic::SetPenWidth
  702. //
  703. // Purpose: Set the pen width for the object.
  704. //
  705. //
  706. void DCWbGraphic::SetPenWidth(UINT uiWidth)
  707. {
  708. // If the new width is different
  709. if (m_uiPenWidth != uiWidth)
  710. {
  711. // Save the width given
  712. m_uiPenWidth = uiWidth;
  713. // Update the bounding rectangle
  714. CalculateBoundsRect();
  715. // Show that we have been changed
  716. m_bChanged = TRUE;
  717. }
  718. }
  719. //
  720. //
  721. // Function: IsTopmost
  722. //
  723. // Purpose: Return TRUE if this graphic is topmost on its page
  724. //
  725. //
  726. BOOL DCWbGraphic::IsTopmost(void)
  727. {
  728. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::IsTopmost");
  729. ASSERT(m_hGraphic != NULL);
  730. return PG_IsTopmost(m_hPage, this);
  731. }
  732. //
  733. //
  734. // Function: AddToPageLast
  735. //
  736. // Purpose: Add the graphic to the specified page
  737. //
  738. //
  739. void DCWbGraphic::AddToPageLast(WB_PAGE_HANDLE hPage)
  740. {
  741. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::AddToPageLast");
  742. ASSERT(m_hGraphic == NULL);
  743. // Get the length of the flat representation
  744. DWORD length = CalculateExternalLength();
  745. // Allocate memory for the graphic
  746. PWB_GRAPHIC pHeader = PG_AllocateGraphic(hPage, length);
  747. if(pHeader == NULL)
  748. {
  749. return;
  750. }
  751. // Write the graphic details to the memory
  752. WriteExternal(pHeader);
  753. // Add the flat representation to the page
  754. WB_GRAPHIC_HANDLE hGraphic = NULL;
  755. UINT uiReturn;
  756. uiReturn = g_pwbCore->WBP_GraphicAddLast(hPage, pHeader, &hGraphic);
  757. if (uiReturn != 0)
  758. {
  759. DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
  760. return;
  761. }
  762. // Show that we have not changed since the last write
  763. m_bChanged = FALSE;
  764. // Save the page to which this graphic now belongs
  765. m_hPage = hPage;
  766. m_hGraphic = hGraphic;
  767. }
  768. //
  769. //
  770. // Function: ForceReplace
  771. //
  772. // Purpose: Write the object to external storage, replacing what is
  773. // already there, even if the object hasn't changed.
  774. //
  775. //
  776. void DCWbGraphic::ForceReplace(void)
  777. {
  778. if( Type() != 0 )
  779. {
  780. m_bChanged = TRUE;
  781. this->Replace();
  782. }
  783. }
  784. //
  785. //
  786. // Function: Replace
  787. //
  788. // Purpose: Write the object to external storage, replacing what is
  789. // already there.
  790. //
  791. //
  792. void DCWbGraphic::Replace(void)
  793. {
  794. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Replace");
  795. ASSERT(m_hGraphic != NULL);
  796. // Only do the replace if we have been changed
  797. if (m_bChanged == TRUE)
  798. {
  799. TRACE_MSG(("Replacing the graphic in the page"));
  800. // Get the length of the flat representation
  801. DWORD length = CalculateExternalLength();
  802. // Allocate memory for the graphic
  803. PWB_GRAPHIC pHeader = PG_AllocateGraphic(m_hPage, length);
  804. if(pHeader == NULL)
  805. {
  806. return;
  807. }
  808. // Write the graphic details to the memory
  809. WriteExternal(pHeader);
  810. // Replace the graphic
  811. PG_GraphicReplace(m_hPage, &m_hGraphic, pHeader);
  812. // Show that we have not changed since the last update
  813. m_bChanged = FALSE;
  814. }
  815. }
  816. //
  817. //
  818. // Function: ReplaceConfirm
  819. //
  820. // Purpose: Confirm the replace of the graphic
  821. //
  822. //
  823. void DCWbGraphic::ReplaceConfirm(void)
  824. {
  825. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::ReplaceConfirm");
  826. ASSERT(m_hGraphic != NULL);
  827. // Confirm the update
  828. g_pwbCore->WBP_GraphicReplaceConfirm(m_hPage, m_hGraphic);
  829. // Read the new details
  830. ReadExternal();
  831. }
  832. void DCWbGraphic::ForceUpdate(void)
  833. {
  834. if ((Type() != 0) && m_hGraphic)
  835. {
  836. m_bChanged = TRUE;
  837. this->Update();
  838. }
  839. }
  840. //
  841. //
  842. // Function: Update
  843. //
  844. // Purpose: Write the header of the graphic to external storage
  845. //
  846. //
  847. void DCWbGraphic::Update(void)
  848. {
  849. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Update");
  850. ASSERT(m_hGraphic != NULL);
  851. // Only make the update if the graphic has changed
  852. if (m_bChanged)
  853. {
  854. // Allocate memory for the update graphic
  855. TRACE_MSG(("Graphic has changed"));
  856. DWORD length = sizeof(WB_GRAPHIC);
  857. PWB_GRAPHIC pHeader;
  858. if( (pHeader = PG_AllocateGraphic(m_hPage, length)) != NULL )
  859. {
  860. // Write the header details to the allocated memory
  861. pHeader->type = (TSHR_UINT16)Type();
  862. WriteHeader(pHeader);
  863. // Update the header in the page
  864. PG_GraphicUpdate(m_hPage, &m_hGraphic, pHeader);
  865. }
  866. // Show that we have not changed since the last update
  867. m_bChanged = FALSE;
  868. }
  869. }
  870. //
  871. //
  872. // Function: UpdateConfirm
  873. //
  874. // Purpose: Confirm the update of the graphic
  875. //
  876. //
  877. void DCWbGraphic::UpdateConfirm(void)
  878. {
  879. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::UpdateConfirm");
  880. ASSERT(m_hGraphic != NULL);
  881. // Confirm the update
  882. g_pwbCore->WBP_GraphicUpdateConfirm(m_hPage, m_hGraphic);
  883. // Read the new details
  884. ReadExternal();
  885. }
  886. //
  887. //
  888. // Function: Delete
  889. //
  890. // Purpose: Remove the graphic from its page
  891. //
  892. //
  893. void DCWbGraphic::Delete(void)
  894. {
  895. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Delete");
  896. ASSERT(m_hPage != WB_PAGE_HANDLE_NULL);
  897. ASSERT(m_hGraphic != NULL);
  898. // Delete the graphic
  899. PG_GraphicDelete(m_hPage, *this);
  900. // Reset the handles for this graphic - it is now deleted
  901. m_hPage = WB_PAGE_HANDLE_NULL;
  902. m_hGraphic = NULL;
  903. // Show that we have changed (an add is required to save the graphic)
  904. m_bChanged = TRUE;
  905. }
  906. //
  907. //
  908. // Function: DeleteConfirm
  909. //
  910. // Purpose: Confirm the delete of the graphic
  911. //
  912. //
  913. void DCWbGraphic::DeleteConfirm(void)
  914. {
  915. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::DeleteConfirm");
  916. ASSERT(m_hGraphic != NULL);
  917. // Confirm the update
  918. g_pwbCore->WBP_GraphicDeleteConfirm(m_hPage, m_hGraphic);
  919. // Reset the graphic page and handle (they are no longer useful)
  920. m_hPage = WB_PAGE_HANDLE_NULL;
  921. m_hGraphic = NULL;
  922. }
  923. //
  924. //
  925. // Function: Lock
  926. //
  927. // Purpose: Lock the graphic
  928. //
  929. //
  930. void DCWbGraphic::Lock(void)
  931. {
  932. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Lock");
  933. // If we are not already locked
  934. if( Type() != 0 )
  935. {
  936. if (m_uiLockState == WB_GRAPHIC_LOCK_NONE)
  937. {
  938. m_bChanged = TRUE;
  939. m_uiLockState = WB_GRAPHIC_LOCK_LOCAL;
  940. }
  941. }
  942. }
  943. //
  944. //
  945. // Function: Unlock
  946. //
  947. // Purpose: Unlock the graphic
  948. //
  949. //
  950. void DCWbGraphic::Unlock(void)
  951. {
  952. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphic::Unlock");
  953. // If we are currently locked
  954. if( Type() != 0 )
  955. {
  956. if (m_uiLockState == WB_GRAPHIC_LOCK_LOCAL)
  957. {
  958. // Lock & release
  959. PWB_GRAPHIC pHeader = PG_GetData(m_hPage, m_hGraphic);
  960. g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, pHeader);
  961. m_uiLockState = WB_GRAPHIC_LOCK_NONE;
  962. g_pwbCore->WBP_GraphicUnlock(m_hPage, m_hGraphic);
  963. }
  964. }
  965. }
  966. //
  967. //
  968. // Function: DCWbGraphicMarker::DCWbGraphicMarker
  969. //
  970. // Purpose: Constructors for marker objects
  971. //
  972. //
  973. DCWbGraphicMarker::DCWbGraphicMarker()
  974. {
  975. HBITMAP hBmpMarker;
  976. // Set up a checked pattern to draw the marker rect with
  977. WORD bits[] = {204, 204, 51, 51, 204, 204, 51, 51};
  978. // Create the brush to be used to draw the marker rectangle
  979. hBmpMarker = ::CreateBitmap(8, 8, 1, 1, bits);
  980. m_hMarkerBrush = ::CreatePatternBrush(hBmpMarker);
  981. ::DeleteBitmap(hBmpMarker);
  982. MarkerList.EmptyList();
  983. ::SetRectEmpty(&m_rect);
  984. m_bMarkerPresent = FALSE;
  985. }
  986. DCWbGraphicMarker::~DCWbGraphicMarker()
  987. {
  988. if (m_hMarkerBrush != NULL)
  989. {
  990. DeleteBrush(m_hMarkerBrush);
  991. m_hMarkerBrush = NULL;
  992. }
  993. }
  994. //
  995. //
  996. // Function: DCWbGraphicMarker::SetRect
  997. //
  998. // Purpose: Set the rectangle for the object
  999. //
  1000. //
  1001. BOOL DCWbGraphicMarker::SetRect(LPCRECT lprc,
  1002. DCWbGraphic *pGraphic,
  1003. BOOL bRedraw,
  1004. BOOL bLockObject )
  1005. {
  1006. DCWbGraphic *pMarker;
  1007. BOOL bGraphicAdded = FALSE;
  1008. LPRECT pmMarker;
  1009. // Save the new rectangle
  1010. m_rect = *lprc;
  1011. NormalizeRect(&m_rect);
  1012. // Calculate the new bounding rectangle of the entire marker
  1013. CalculateBoundsRect();
  1014. // Calculate the marker rectangles
  1015. CalculateMarkerRectangles();
  1016. if( (pMarker = HasAMarker( pGraphic )) != NULL )
  1017. delete pMarker;
  1018. // allow select only if object is not locked - bug 2185
  1019. if( !pGraphic->Locked())
  1020. {
  1021. // add/replace pGraphic|markerrect pair to list
  1022. pmMarker = new RECT;
  1023. if (!pmMarker)
  1024. {
  1025. ERROR_OUT(("Failed to create RECT object"));
  1026. }
  1027. else
  1028. {
  1029. *pmMarker = m_markerRect;
  1030. MarkerList.SetAt( (void *)pGraphic, pmMarker);
  1031. ASSERT(g_pDraw);
  1032. DrawRect(g_pDraw->GetCachedDC(), pmMarker, FALSE, NULL );
  1033. bGraphicAdded = TRUE;
  1034. }
  1035. if( bLockObject )
  1036. {
  1037. // lock the object if we don't already have it locked
  1038. // to keep anybody else from selecting it
  1039. if( !pGraphic->GotLock() )
  1040. {
  1041. pGraphic->Lock();
  1042. if( pGraphic->Handle() != NULL )
  1043. pGraphic->ForceUpdate(); // if valid object force lock NOW
  1044. }
  1045. }
  1046. }
  1047. if( bRedraw && m_bMarkerPresent )
  1048. {
  1049. ASSERT(g_pDraw);
  1050. ::UpdateWindow(g_pDraw->m_hwnd);
  1051. }
  1052. // set m_boundsRect to real bounds
  1053. GetBoundsRect(&m_boundsRect);
  1054. return( bGraphicAdded );
  1055. }
  1056. //
  1057. //
  1058. // Function: DCWbGraphicMarker::CalculateBoundsRect
  1059. //
  1060. // Purpose: Calculate the bounding rectangle of the object
  1061. //
  1062. //
  1063. void DCWbGraphicMarker::CalculateBoundsRect(void)
  1064. {
  1065. // Generate the new bounding rectangle
  1066. m_boundsRect = m_rect;
  1067. NormalizeRect(&m_boundsRect);
  1068. ::InflateRect(&m_boundsRect, m_uiPenWidth, m_uiPenWidth);
  1069. }
  1070. //
  1071. //
  1072. // Function: DCWbGraphicMarker::CalculateMarkerRectangles
  1073. //
  1074. // Purpose: Calculate the rectangles for the marker handles
  1075. //
  1076. //
  1077. void DCWbGraphicMarker::CalculateMarkerRectangles(void)
  1078. {
  1079. m_markerRect = m_boundsRect;
  1080. ::InflateRect(&m_markerRect, 1-m_uiPenWidth, 1-m_uiPenWidth);
  1081. }
  1082. //
  1083. //
  1084. // Function: DCWbGraphicMarker::PointInMarker
  1085. //
  1086. // Purpose: Calculate whether the given point is in one of the marker
  1087. // rectangles.
  1088. //
  1089. //
  1090. int DCWbGraphicMarker::PointInMarker(POINT point)
  1091. {
  1092. return(NO_HANDLE);
  1093. }
  1094. void DCWbGraphicMarker::DrawRect
  1095. (
  1096. HDC hDC,
  1097. LPCRECT pMarkerRect,
  1098. BOOL bDrawObject,
  1099. DCWbGraphic * pGraphic
  1100. )
  1101. {
  1102. int nOldROP;
  1103. COLORREF crOldTextColor;
  1104. COLORREF crOldBkColor;
  1105. nOldROP = ::SetROP2(hDC, R2_COPYPEN);
  1106. crOldTextColor = ::SetTextColor(hDC, RGB(0, 0, 0));
  1107. ASSERT(g_pDraw);
  1108. crOldBkColor = ::SetBkColor(hDC, ::GetSysColor(COLOR_WINDOW));
  1109. if (pMarkerRect != NULL)
  1110. {
  1111. if( bDrawObject )
  1112. pGraphic->Draw(hDC ); // draw object instead of rect
  1113. else
  1114. ::FrameRect(hDC, pMarkerRect, m_hMarkerBrush); // draw rect
  1115. }
  1116. ::SetROP2(hDC, nOldROP);
  1117. ::SetTextColor(hDC, crOldTextColor);
  1118. ::SetBkColor(hDC, crOldBkColor);
  1119. }
  1120. //
  1121. //
  1122. // Function: DCWbGraphicMarker::Draw
  1123. //
  1124. // Purpose: Draw the marker object
  1125. //
  1126. //
  1127. void DCWbGraphicMarker::Draw(HDC hDC, BOOL bDrawObjects)
  1128. {
  1129. POSITION posNext;
  1130. DCWbGraphic *pGraphic;
  1131. LPRECT pMarkerRect;
  1132. // if marker is not up, do nuthin
  1133. if( !m_bMarkerPresent )
  1134. return;
  1135. posNext = MarkerList.GetHeadPosition();
  1136. while( posNext != NULL )
  1137. {
  1138. MarkerList.GetNextAssoc( posNext, (void *&)pGraphic, (void *&)pMarkerRect );
  1139. DrawRect(hDC, pMarkerRect, bDrawObjects, pGraphic );
  1140. }
  1141. }
  1142. void DCWbGraphicMarker::UndrawRect
  1143. (
  1144. HDC hDC,
  1145. WbDrawingArea * pDrawingArea,
  1146. LPCRECT pMarkerRect
  1147. )
  1148. {
  1149. int nOldROP;
  1150. COLORREF crOldTextColor;
  1151. COLORREF crOldBkColor;
  1152. if (pMarkerRect != NULL)
  1153. {
  1154. // set up context to erase marker rect
  1155. nOldROP = ::SetROP2(hDC, R2_COPYPEN);
  1156. ASSERT(g_pDraw);
  1157. crOldTextColor = ::SetTextColor(hDC, ::GetSysColor(COLOR_WINDOW));
  1158. crOldBkColor = ::SetBkColor(hDC, ::GetSysColor(COLOR_WINDOW));
  1159. ::FrameRect(hDC, pMarkerRect, m_hMarkerBrush);
  1160. UndrawMarker( pMarkerRect ); // invalidate so underlying objects will repair window
  1161. ::SetROP2(hDC, nOldROP);
  1162. ::SetTextColor(hDC, crOldTextColor);
  1163. ::SetBkColor(hDC, crOldBkColor);
  1164. }
  1165. }
  1166. //
  1167. //
  1168. // Function: DCWbGraphicMarker::Undraw
  1169. //
  1170. // Purpose: Undraw the marker object
  1171. //
  1172. //
  1173. void DCWbGraphicMarker::Undraw(HDC hDC, WbDrawingArea * pDrawingArea)
  1174. {
  1175. POSITION posNext;
  1176. DCWbGraphic *pGraphic;
  1177. LPRECT pMarkerRect;
  1178. posNext = MarkerList.GetHeadPosition();
  1179. while( posNext != NULL )
  1180. {
  1181. MarkerList.GetNextAssoc( posNext, (void *&)pGraphic, (void *&)pMarkerRect );
  1182. UndrawRect(hDC, pDrawingArea, pMarkerRect);
  1183. }
  1184. }
  1185. void DCWbGraphicMarker::DeleteAllMarkers( DCWbGraphic *pLastSelectedGraphic,
  1186. BOOL bLockLastSelectedGraphic )
  1187. {
  1188. POSITION posFirst;
  1189. DCWbGraphic *pGraphic;
  1190. LPRECT pMarkerRect;
  1191. BOOL bAddLastBack = FALSE;
  1192. if( MarkerList.IsEmpty() )
  1193. return; // nuthin to do
  1194. // let each object clean itself up
  1195. posFirst = MarkerList.GetHeadPosition();
  1196. while( posFirst != NULL )
  1197. {
  1198. MarkerList.GetNextAssoc( posFirst,
  1199. (void *&)pGraphic, (void *&)pMarkerRect );
  1200. if( pGraphic != NULL )
  1201. {
  1202. if( pGraphic == pLastSelectedGraphic )
  1203. {
  1204. // have to put this one back since somebody up there needs it
  1205. bAddLastBack = TRUE;
  1206. // delete key but don't delete object
  1207. DeleteMarker( pGraphic );
  1208. }
  1209. else
  1210. {
  1211. // obj will call DeleteMarker()
  1212. delete pGraphic;
  1213. }
  1214. }
  1215. else
  1216. {
  1217. // nobody home, remove key ourselves
  1218. DeleteMarker( pGraphic );
  1219. }
  1220. }
  1221. // put last selected object back if needed
  1222. if( bAddLastBack && (pLastSelectedGraphic != NULL) )
  1223. {
  1224. RECT rcT;
  1225. pLastSelectedGraphic->GetBoundsRect(&rcT);
  1226. SetRect(&rcT, pLastSelectedGraphic, FALSE, bLockLastSelectedGraphic );
  1227. }
  1228. // if marker is not up, don't redraw immediately
  1229. if( !m_bMarkerPresent )
  1230. return;
  1231. ASSERT(g_pDraw);
  1232. if (g_pDraw->m_hwnd != NULL )
  1233. ::UpdateWindow(g_pDraw->m_hwnd);
  1234. }
  1235. //
  1236. // Deletes DCWbGraphic/LPRECT pair corresponding to pGraphic
  1237. //
  1238. void DCWbGraphicMarker::DeleteMarker( DCWbGraphic *pGraphic )
  1239. {
  1240. LPRECT pMarkerRect;
  1241. if( MarkerList.IsEmpty() )
  1242. return;
  1243. if( MarkerList.Lookup( (void *)pGraphic, (void *&)pMarkerRect ) )
  1244. {
  1245. if( pMarkerRect != NULL )
  1246. {
  1247. ASSERT(g_pDraw);
  1248. UndrawRect(g_pDraw->GetCachedDC(), g_pDraw, pMarkerRect );
  1249. delete pMarkerRect;
  1250. }
  1251. MarkerList.RemoveKey( (void *)pGraphic );
  1252. // set m_boundsRect to real bounds
  1253. GetBoundsRect(&m_boundsRect);
  1254. // pGraphic should be locked by us since it was selected
  1255. // but check to be sure since this might be coming from
  1256. // another user that beat us to the lock.
  1257. if( pGraphic->GotLock() )
  1258. {
  1259. pGraphic->Unlock();
  1260. if( pGraphic->Handle() != NULL )
  1261. pGraphic->ForceUpdate();
  1262. }
  1263. }
  1264. // if marker is not up, don't redraw immediately
  1265. if( !m_bMarkerPresent )
  1266. return;
  1267. }
  1268. //
  1269. // Sees if pGraphic->Handle() is in marker list and returns obj
  1270. //
  1271. DCWbGraphic *DCWbGraphicMarker::HasAMarker( DCWbGraphic *pGraphic )
  1272. {
  1273. POSITION posNext;
  1274. DCWbGraphic *pSearchGraphic;
  1275. LPRECT pMarkerRect;
  1276. if( MarkerList.IsEmpty() )
  1277. return( NULL );
  1278. posNext = MarkerList.GetHeadPosition();
  1279. while( posNext != NULL )
  1280. {
  1281. MarkerList.GetNextAssoc( posNext,
  1282. (void *&)pSearchGraphic, (void *&)pMarkerRect );
  1283. if( (pSearchGraphic != NULL)&&
  1284. (pSearchGraphic->Handle() == pGraphic->Handle()) )
  1285. {
  1286. return( pSearchGraphic );
  1287. }
  1288. }
  1289. return( NULL );
  1290. }
  1291. //
  1292. // Gets last marker
  1293. //
  1294. DCWbGraphic *DCWbGraphicMarker::LastMarker( void )
  1295. {
  1296. POSITION posNext;
  1297. DCWbGraphic *pGraphic;
  1298. LPRECT pMarkerRect;
  1299. pGraphic = NULL;
  1300. if( !MarkerList.IsEmpty() )
  1301. {
  1302. // this isn't eactly right, just return head of list for now
  1303. posNext = MarkerList.GetHeadPosition();
  1304. if( posNext != NULL )
  1305. MarkerList.GetNextAssoc( posNext,
  1306. (void *&)pGraphic, (void *&)pMarkerRect );
  1307. }
  1308. return( pGraphic );
  1309. }
  1310. void DCWbGraphicMarker::UndrawMarker(LPCRECT pMarkerRect )
  1311. {
  1312. RECT rect;
  1313. ASSERT(g_pDraw);
  1314. if( (pMarkerRect != NULL) && (g_pDraw->m_hwnd != NULL) )
  1315. {
  1316. rect = *pMarkerRect;
  1317. g_pDraw->SurfaceToClient(&rect);
  1318. ::InvalidateRect(g_pDraw->m_hwnd, &rect, FALSE);
  1319. }
  1320. }
  1321. int DCWbGraphicMarker::GetNumMarkers( void )
  1322. {
  1323. int count = 0;
  1324. POSITION pos;
  1325. pos = MarkerList.GetHeadPosition();
  1326. while(pos)
  1327. {
  1328. count ++;
  1329. MarkerList.GetNext(pos);
  1330. }
  1331. return count;
  1332. }
  1333. void DCWbGraphicMarker::MoveBy(int cx, int cy)
  1334. {
  1335. POSITION posNext;
  1336. DCWbGraphic *pGraphic;
  1337. LPRECT pMarkerRect;
  1338. if( !MarkerList.IsEmpty() )
  1339. {
  1340. // Call MoveBy for each selected obj
  1341. posNext = MarkerList.GetHeadPosition();
  1342. while( posNext != NULL )
  1343. {
  1344. MarkerList.GetNextAssoc( posNext,
  1345. (void *&)pGraphic, (void *&)pMarkerRect );
  1346. if( pGraphic != NULL )
  1347. {
  1348. pGraphic->MoveBy(cx, cy);
  1349. }
  1350. }
  1351. }
  1352. DCWbGraphic::MoveBy(cx, cy); // move marker too
  1353. }
  1354. void DCWbGraphicMarker::Update( void )
  1355. {
  1356. POSITION posNext;
  1357. DCWbGraphic *pGraphic;
  1358. LPRECT pMarkerRect;
  1359. if( !MarkerList.IsEmpty() )
  1360. {
  1361. // Call Update for each selected obj
  1362. posNext = MarkerList.GetHeadPosition();
  1363. while( posNext != NULL )
  1364. {
  1365. MarkerList.GetNextAssoc( posNext,
  1366. (void *&)pGraphic, (void *&)pMarkerRect );
  1367. if( pGraphic != NULL )
  1368. pGraphic->Update();
  1369. }
  1370. }
  1371. }
  1372. BOOL DCWbGraphicMarker::PointInBounds(POINT pt)
  1373. {
  1374. POSITION posNext;
  1375. DCWbGraphic *pGraphic;
  1376. LPRECT pMarkerRect;
  1377. RECT rectHit;
  1378. if( !MarkerList.IsEmpty() )
  1379. {
  1380. // Call Update for each selected obj
  1381. posNext = MarkerList.GetHeadPosition();
  1382. while( posNext != NULL )
  1383. {
  1384. MarkerList.GetNextAssoc( posNext,
  1385. (void *&)pGraphic, (void *&)pMarkerRect );
  1386. if( pGraphic != NULL )
  1387. {
  1388. MAKE_HIT_RECT(rectHit, pt );
  1389. if( pGraphic->PointInBounds(pt)&&
  1390. pGraphic->CheckReallyHit( &rectHit )
  1391. )
  1392. return( TRUE );
  1393. }
  1394. }
  1395. }
  1396. return( FALSE );
  1397. }
  1398. //
  1399. // Returns a rect that is the union of all the items in the marker
  1400. //
  1401. void DCWbGraphicMarker::GetBoundsRect(LPRECT lprc)
  1402. {
  1403. POSITION posNext;
  1404. DCWbGraphic *pGraphic;
  1405. LPRECT pMarkerRect;
  1406. RECT rc;
  1407. ::SetRectEmpty(lprc);
  1408. if( !MarkerList.IsEmpty())
  1409. {
  1410. posNext = MarkerList.GetHeadPosition();
  1411. while( posNext != NULL )
  1412. {
  1413. MarkerList.GetNextAssoc( posNext,
  1414. (void *&)pGraphic, (void *&)pMarkerRect );
  1415. if( pGraphic != NULL )
  1416. {
  1417. pGraphic->GetBoundsRect(&rc);
  1418. ::UnionRect(lprc, lprc, &rc);
  1419. }
  1420. }
  1421. }
  1422. }
  1423. void DCWbGraphicMarker::SetColor(COLORREF color)
  1424. {
  1425. POSITION posNext;
  1426. DCWbGraphic *pGraphic;
  1427. LPRECT pMarkerRect;
  1428. if( !MarkerList.IsEmpty() )
  1429. {
  1430. // Call Update for each selected obj
  1431. posNext = MarkerList.GetHeadPosition();
  1432. while( posNext != NULL )
  1433. {
  1434. MarkerList.GetNextAssoc( posNext,
  1435. (void *&)pGraphic, (void *&)pMarkerRect );
  1436. if( pGraphic != NULL )
  1437. pGraphic->SetColor( color );
  1438. }
  1439. }
  1440. }
  1441. void DCWbGraphicMarker::SetPenWidth(UINT uiWidth)
  1442. {
  1443. POSITION posNext;
  1444. DCWbGraphic *pGraphic;
  1445. LPRECT pMarkerRect;
  1446. if( !MarkerList.IsEmpty() )
  1447. {
  1448. // Call Update for each selected obj
  1449. posNext = MarkerList.GetHeadPosition();
  1450. while( posNext != NULL )
  1451. {
  1452. MarkerList.GetNextAssoc( posNext,
  1453. (void *&)pGraphic, (void *&)pMarkerRect );
  1454. if( pGraphic != NULL )
  1455. pGraphic->SetPenWidth(uiWidth);
  1456. }
  1457. }
  1458. }
  1459. void DCWbGraphicMarker::SetSelectionFont(HFONT hFont)
  1460. {
  1461. POSITION posNext;
  1462. DCWbGraphic *pGraphic;
  1463. LPRECT pMarkerRect;
  1464. if( !MarkerList.IsEmpty() )
  1465. {
  1466. // Call Update for each selected obj
  1467. posNext = MarkerList.GetHeadPosition();
  1468. while( posNext != NULL )
  1469. {
  1470. MarkerList.GetNextAssoc( posNext,
  1471. (void *&)pGraphic, (void *&)pMarkerRect );
  1472. if( (pGraphic != NULL)&&
  1473. pGraphic->IsGraphicTool() == enumGraphicText)
  1474. {
  1475. // Change the font of the object
  1476. ((DCWbGraphicText*)pGraphic)->SetFont(hFont);
  1477. // Replace the object
  1478. pGraphic->Replace();
  1479. }
  1480. }
  1481. }
  1482. }
  1483. //
  1484. // Deletes each marker obj for all connections
  1485. //
  1486. void DCWbGraphicMarker::DeleteSelection( void )
  1487. {
  1488. POSITION posNext;
  1489. DCWbGraphic *pGraphic;
  1490. DCWbGraphic *pGraphicCopy;
  1491. LPRECT pMarkerRect;
  1492. if( !MarkerList.IsEmpty() )
  1493. {
  1494. // Call Update for each selected obj
  1495. posNext = MarkerList.GetHeadPosition();
  1496. while( posNext != NULL )
  1497. {
  1498. MarkerList.GetNextAssoc( posNext,
  1499. (void *&)pGraphic, (void *&)pMarkerRect );
  1500. if( pGraphic != NULL )
  1501. {
  1502. // make a copy for trash can
  1503. pGraphicCopy = pGraphic->Copy();
  1504. // throw in trash
  1505. if( pGraphicCopy != NULL )
  1506. {
  1507. g_pMain->m_LastDeletedGraphic.CollectTrash( pGraphicCopy );
  1508. }
  1509. // delete obj
  1510. g_pDraw->DeleteGraphic( pGraphic );
  1511. }
  1512. }
  1513. DeleteAllMarkers( NULL );
  1514. }
  1515. }
  1516. //
  1517. // Brings eaach marker obj to top
  1518. //
  1519. void DCWbGraphicMarker::BringToTopSelection( void )
  1520. {
  1521. POSITION posNext;
  1522. DCWbGraphic *pGraphic;
  1523. LPRECT pMarkerRect;
  1524. if( !MarkerList.IsEmpty() )
  1525. {
  1526. // Call Update for each selected obj
  1527. posNext = MarkerList.GetHeadPosition();
  1528. while( posNext != NULL )
  1529. {
  1530. MarkerList.GetNextAssoc( posNext,
  1531. (void *&)pGraphic, (void *&)pMarkerRect );
  1532. if( pGraphic != NULL )
  1533. {
  1534. // move obj to top
  1535. UINT uiReturn;
  1536. uiReturn = g_pwbCore->WBP_GraphicMove(g_pDraw->Page(),
  1537. pGraphic->Handle(), LAST);
  1538. if (uiReturn != 0)
  1539. {
  1540. DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
  1541. return;
  1542. }
  1543. }
  1544. }
  1545. }
  1546. }
  1547. //
  1548. // Sends each marker object to back
  1549. //
  1550. void DCWbGraphicMarker::SendToBackSelection( void )
  1551. {
  1552. POSITION posNext;
  1553. DCWbGraphic *pGraphic;
  1554. LPRECT pMarkerRect;
  1555. if( !MarkerList.IsEmpty() )
  1556. {
  1557. // Call Update for each selected obj
  1558. posNext = MarkerList.GetHeadPosition();
  1559. while( posNext != NULL )
  1560. {
  1561. MarkerList.GetNextAssoc( posNext,
  1562. (void *&)pGraphic, (void *&)pMarkerRect );
  1563. if( pGraphic != NULL )
  1564. {
  1565. UINT uiReturn;
  1566. // move obj to top
  1567. uiReturn = g_pwbCore->WBP_GraphicMove(g_pDraw->Page(),
  1568. pGraphic->Handle(), FIRST);
  1569. if (uiReturn != 0)
  1570. {
  1571. DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
  1572. return;
  1573. }
  1574. }
  1575. }
  1576. }
  1577. }
  1578. //
  1579. // Copy marker to clipboard using CLIPBOARD_PRIVATE_MULTI_OBJ format:
  1580. // [ RECT : marker rect ]
  1581. // [ DWORD : number of objects ]
  1582. // [ DWORD : byte length of 1st object ]
  1583. // [ WB_GRAPHIC : header data for first object ]
  1584. // [ DWORD : byte length of 2nd object ]
  1585. // [ WB_GRAPHIC : header data for 2nd object ]
  1586. // :
  1587. // :
  1588. // [ DWORD : byte length of last object ]
  1589. // [ WB_GRAPHIC : header data for last object ]
  1590. // [ DWORD : 0 (marks end of object data) ]
  1591. //
  1592. BOOL DCWbGraphicMarker::RenderPrivateMarkerFormat( void )
  1593. {
  1594. POSITION posNext;
  1595. DCWbGraphic *pGraphic;
  1596. LPRECT pMarkerRect;
  1597. DWORD nBufSize;
  1598. DWORD nObjSize;
  1599. DWORD nNumObjs;
  1600. BYTE *buf;
  1601. BYTE *pbuf;
  1602. HANDLE hbuf;
  1603. PWB_GRAPHIC pHeader;
  1604. WB_GRAPHIC_HANDLE hGraphic;
  1605. if( MarkerList.IsEmpty() )
  1606. return( TRUE ); // nuthin to do
  1607. // Have to make two passes. The first one figures out how much
  1608. // data we have, the second copies the data.
  1609. // figure out how much data we've got
  1610. nBufSize = sizeof (RECT) + sizeof (DWORD); // marker rect and object
  1611. // count are first
  1612. nNumObjs = 0;
  1613. posNext = MarkerList.GetHeadPosition();
  1614. while( posNext != NULL )
  1615. {
  1616. MarkerList.GetNextAssoc( posNext,
  1617. (void *&)pGraphic, (void *&)pMarkerRect );
  1618. if( (pGraphic != NULL)&&
  1619. ((hGraphic = pGraphic->Handle()) != NULL)&&
  1620. ((pHeader = PG_GetData(pGraphic->Page(), hGraphic )) != NULL) )
  1621. {
  1622. nBufSize += (DWORD)(pHeader->length + sizeof(DWORD));
  1623. g_pwbCore->WBP_GraphicRelease(pGraphic->Page(), hGraphic, pHeader);
  1624. // count objects instead of using MarkerList.GetCount()
  1625. // in case we have an error or something (bad object,
  1626. // leaky core, who knows...)
  1627. nNumObjs++;
  1628. }
  1629. }
  1630. // Add one more DWORD at end. This will be set to 0 below
  1631. // to mark the end of the buffer.
  1632. nBufSize += sizeof(DWORD);
  1633. // Make object buffer. Use GlobalDiddle instead of new so we
  1634. // can pass a mem handle to the clipboard later.
  1635. hbuf = ::GlobalAlloc( GHND, nBufSize );
  1636. if( hbuf == NULL )
  1637. return( FALSE ); // couldn't make room
  1638. buf = (BYTE *)::GlobalLock( hbuf );
  1639. if( buf == NULL )
  1640. {
  1641. ::GlobalFree( hbuf );
  1642. return( FALSE ); // couldn't find the room
  1643. }
  1644. pbuf = buf;
  1645. // set marker rect
  1646. CopyMemory(pbuf, &m_boundsRect, sizeof(RECT));
  1647. pbuf += sizeof (RECT);
  1648. // set number of objects
  1649. *((DWORD *)pbuf) = nNumObjs;
  1650. pbuf += sizeof (DWORD);
  1651. // copy each obj to buf + a length DWORD
  1652. posNext = MarkerList.GetHeadPosition();
  1653. while( posNext != NULL )
  1654. {
  1655. MarkerList.GetNextAssoc( posNext,
  1656. (void *&)pGraphic, (void *&)pMarkerRect );
  1657. if( (pGraphic != NULL)&&
  1658. ((hGraphic = pGraphic->Handle()) != NULL)&&
  1659. ((pHeader = PG_GetData(pGraphic->Page(), hGraphic )) != NULL) )
  1660. {
  1661. // save length of this obj first
  1662. nObjSize = (DWORD)pHeader->length;
  1663. *((DWORD *)pbuf) = nObjSize;
  1664. pbuf += sizeof (DWORD);
  1665. // copy obj to buf
  1666. CopyMemory( pbuf, (CONST VOID *)pHeader, nObjSize );
  1667. // make sure copy isn't "locked" (bug 474)
  1668. ((PWB_GRAPHIC)pbuf)->locked = WB_GRAPHIC_LOCK_NONE;
  1669. // set up for next obj
  1670. pbuf += nObjSize;
  1671. g_pwbCore->WBP_GraphicRelease(pGraphic->Page(), hGraphic, pHeader );
  1672. }
  1673. }
  1674. // cork it up
  1675. *((DWORD *)pbuf) = 0;
  1676. // give it to the clipboard
  1677. ::GlobalUnlock( hbuf );
  1678. if( ::SetClipboardData(
  1679. g_ClipboardFormats[ CLIPBOARD_PRIVATE_MULTI_OBJ ], hbuf
  1680. )
  1681. == NULL )
  1682. {
  1683. // clipboard choked, clean up mess
  1684. ::GlobalFree( hbuf );
  1685. return( FALSE );
  1686. }
  1687. // zillions of shared clipboards all over the planet are receiving this
  1688. // thing about now...
  1689. return( TRUE );
  1690. }
  1691. //
  1692. // Decodes CLIPBOARD_PRIVATE_MULTI_OBJ format and pastes objects
  1693. // to Whiteboard. See DCWbGraphicMarker::RenderPrivateMarkerFormat
  1694. // for details of format.
  1695. //
  1696. void DCWbGraphicMarker::Paste( HANDLE handle )
  1697. {
  1698. BYTE *pbuf;
  1699. DWORD nNumObjs;
  1700. DWORD nObjSize;
  1701. DCWbGraphic *pGraphic;
  1702. DCWbGraphic *pSelectedGraphic;
  1703. SIZE PasteOffset;
  1704. RECT rectMarker;
  1705. // blow off current selection
  1706. g_pMain->m_drawingArea.RemoveMarker(NULL);
  1707. DeleteAllMarkers( NULL );
  1708. pSelectedGraphic = NULL;
  1709. // get data
  1710. pbuf = (BYTE *)::GlobalLock( handle );
  1711. if( pbuf == NULL )
  1712. return; // can't get the door open
  1713. // get marker's original coords and figure offset
  1714. CopyMemory( &rectMarker, (CONST VOID *)pbuf, sizeof (RECT) );
  1715. pbuf += sizeof (RECT);
  1716. RECT rcVis;
  1717. g_pMain->m_drawingArea.GetVisibleRect(&rcVis);
  1718. PasteOffset.cx = rcVis.left - rectMarker.left;
  1719. PasteOffset.cy = rcVis.top - rectMarker.top;
  1720. // get num objects
  1721. nNumObjs = *((DWORD *)pbuf);
  1722. pbuf += sizeof (DWORD);
  1723. // get each object
  1724. while( (nObjSize = *((DWORD *)pbuf)) != 0 )
  1725. {
  1726. pbuf += sizeof (DWORD);
  1727. // Add the object to the page and current selection
  1728. pGraphic = DCWbGraphic::CopyGraphic( (PWB_GRAPHIC)pbuf );
  1729. pbuf += nObjSize;
  1730. if( pGraphic != NULL )
  1731. {
  1732. pGraphic->MoveBy( PasteOffset.cx, PasteOffset.cy );
  1733. pGraphic->AddToPageLast( g_pMain->GetCurrentPage() );
  1734. g_pMain->m_drawingArea.SelectGraphic( pGraphic, TRUE, TRUE );
  1735. }
  1736. }
  1737. ::GlobalUnlock( handle );
  1738. GetBoundsRect(&m_boundsRect);
  1739. }
  1740. DCWbGraphicLine::~DCWbGraphicLine( void )
  1741. {
  1742. // Have to make sure marker is cleaned up before we vanish
  1743. // don't know if we are selected or not so just delete anyway
  1744. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  1745. {
  1746. g_pDraw->m_pMarker->DeleteMarker( this );
  1747. }
  1748. }
  1749. //
  1750. //
  1751. // Function: DCWbGraphicLine::CalculateBoundsRect
  1752. //
  1753. // Purpose: Calculate the bounding rectangle of the line
  1754. //
  1755. //
  1756. void DCWbGraphicLine::CalculateBoundsRect()
  1757. {
  1758. // Create the basic bounding rectangle from the start and end points
  1759. m_boundsRect = m_rect;
  1760. NormalizeRect(&m_boundsRect);
  1761. // Expand the rectangle by the pen width used for drawing
  1762. int iInflate = (m_uiPenWidth + 1) / 2;
  1763. ::InflateRect(&m_boundsRect, iInflate, iInflate);
  1764. }
  1765. //
  1766. //
  1767. // Function: DCWbGraphicLine::SetStart
  1768. //
  1769. // Purpose: Set the start point of the line
  1770. //
  1771. //
  1772. void DCWbGraphicLine::SetStart(POINT pointFrom)
  1773. {
  1774. // Only do anything if the start point has changed
  1775. if (!EqualPoint(*((LPPOINT)&m_rect.left), pointFrom))
  1776. {
  1777. // Save the new start point
  1778. m_rect.left = pointFrom.x;
  1779. m_rect.top = pointFrom.y;
  1780. // Show that the graphic has changed
  1781. m_bChanged = TRUE;
  1782. }
  1783. // Update the bounding rectangle
  1784. CalculateBoundsRect();
  1785. }
  1786. //
  1787. //
  1788. // Function: DCWbGraphicLine::SetEnd
  1789. //
  1790. // Purpose: Set the start point of the line
  1791. //
  1792. //
  1793. void DCWbGraphicLine::SetEnd(POINT pointTo)
  1794. {
  1795. // Only do anything if the end point has changed
  1796. if (!EqualPoint(*((LPPOINT)&m_rect.right), pointTo))
  1797. {
  1798. // Save the new end point
  1799. m_rect.right = pointTo.x;
  1800. m_rect.bottom = pointTo.y;
  1801. // Show that the graphic has changed
  1802. m_bChanged = TRUE;
  1803. }
  1804. // Update the bounding rectangle
  1805. CalculateBoundsRect();
  1806. }
  1807. //
  1808. //
  1809. // Function: DCWbGraphicLine::Draw
  1810. //
  1811. // Purpose: Draw the line.
  1812. //
  1813. //
  1814. void DCWbGraphicLine::Draw(HDC hDC)
  1815. {
  1816. HPEN hPen;
  1817. HPEN hOldPen;
  1818. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicLine::Draw");
  1819. // Select the required pen
  1820. hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
  1821. hOldPen = SelectPen(hDC, hPen);
  1822. if (hOldPen != NULL)
  1823. {
  1824. // Select the raster operation
  1825. int iOldROP = ::SetROP2(hDC, m_iPenROP);
  1826. // Draw the line
  1827. ::MoveToEx(hDC, m_rect.left, m_rect.top, NULL);
  1828. ::LineTo(hDC, m_rect.right, m_rect.bottom);
  1829. // De-select the pen and ROP
  1830. ::SetROP2(hDC, iOldROP);
  1831. SelectPen(hDC, hOldPen);
  1832. }
  1833. if (hPen != NULL)
  1834. {
  1835. ::DeletePen(hPen);
  1836. }
  1837. }
  1838. //
  1839. //
  1840. // Function: DCWbGraphicLine::MoveBy
  1841. //
  1842. // Purpose: Move the line.
  1843. //
  1844. //
  1845. void DCWbGraphicLine::MoveBy(int cx, int cy)
  1846. {
  1847. // Move the start and end points
  1848. ::OffsetRect(&m_rect, cx, cy);
  1849. // Move the other object attributes
  1850. DCWbGraphic::MoveBy(cx, cy);
  1851. }
  1852. //
  1853. // Checks object for an actual overlap with pRectHit. Assumes m_boundsRect
  1854. // has already been compared.
  1855. //
  1856. BOOL DCWbGraphicLine::CheckReallyHit(LPCRECT pRectHit)
  1857. {
  1858. return(LineHit(m_rect.left, m_rect.top, m_rect.right, m_rect.bottom,
  1859. m_uiPenWidth, TRUE, TRUE, pRectHit));
  1860. }
  1861. //
  1862. //
  1863. // Function: DCWbGraphicFreehand::DCWbGraphicFreehand
  1864. //
  1865. // Purpose: Constructor
  1866. //
  1867. //
  1868. DCWbGraphicFreehand::DCWbGraphicFreehand(void) : DCWbGraphic()
  1869. {
  1870. }
  1871. DCWbGraphicFreehand::DCWbGraphicFreehand(PWB_GRAPHIC pHeader)
  1872. : DCWbGraphic()
  1873. {
  1874. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::DCWbGraphicFreehand");
  1875. // Note that we do everything in this constructor because of the
  1876. // call to ReadExternal. If we let the DCWbGraphic base constructor
  1877. // do it the wrong version of ReadExtra will be called (the one
  1878. // in DCWbGraphic instead of the one in DCWbGraphicFreehand);
  1879. // Do the basic initialization
  1880. Initialize();
  1881. // Set up the page and graphic handle
  1882. ASSERT(pHeader != NULL);
  1883. // Read the header data
  1884. ReadHeader(pHeader);
  1885. // Read the extra data
  1886. ReadExtra(pHeader);
  1887. }
  1888. DCWbGraphicFreehand::DCWbGraphicFreehand
  1889. (
  1890. WB_PAGE_HANDLE hPage,
  1891. WB_GRAPHIC_HANDLE hGraphic
  1892. ) : DCWbGraphic()
  1893. {
  1894. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::DCWbGraphicFreehand");
  1895. // Note that we do everything in this constructor because of the
  1896. // call to ReadExternal. If we let the DCWbGraphic base constructor
  1897. // do it the wrong version of ReadExtra will be called (the one
  1898. // in DCWbGraphic instead of the one in DCWbGraphicFreehand);
  1899. // Do the basic initialization
  1900. Initialize();
  1901. ASSERT(hPage != WB_PAGE_HANDLE_NULL);
  1902. m_hPage = hPage;
  1903. ASSERT(hGraphic != NULL);
  1904. m_hGraphic = hGraphic;
  1905. // Read the header data
  1906. ReadExternal();
  1907. }
  1908. DCWbGraphicFreehand::~DCWbGraphicFreehand( void )
  1909. {
  1910. // don't know if we are selected or not so just delete anyway
  1911. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  1912. {
  1913. g_pDraw->m_pMarker->DeleteMarker( this );
  1914. }
  1915. }
  1916. //
  1917. //
  1918. // Function: DCWbGraphicFreehand::MoveBy
  1919. //
  1920. // Purpose: Move the polyline.
  1921. //
  1922. //
  1923. void DCWbGraphicFreehand::MoveBy(int cx, int cy)
  1924. {
  1925. // Move the base point of the freehand object
  1926. m_rect.left += cx;
  1927. m_rect.top += cy;
  1928. // Move the other object attributes
  1929. DCWbGraphic::MoveBy(cx, cy);
  1930. }
  1931. //
  1932. //
  1933. // Function: DCWbGraphicFreehand::Draw
  1934. //
  1935. // Purpose: Draw the polyline.
  1936. //
  1937. //
  1938. void DCWbGraphicFreehand::Draw(HDC hDC)
  1939. {
  1940. RECT clipBox;
  1941. int iOldROP;
  1942. HPEN hPen;
  1943. HPEN hOldPen;
  1944. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand:Draw");
  1945. // NFC, SFR 5922. Check the return code from GetClipBox.
  1946. // If we fail to get it, just draw everything
  1947. if (::GetClipBox(hDC, &clipBox) == ERROR)
  1948. {
  1949. WARNING_OUT(("Failed to get clip box"));
  1950. }
  1951. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  1952. {
  1953. TRACE_MSG(("No clip/bounds intersection"));
  1954. return;
  1955. }
  1956. // Select the required pen
  1957. hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
  1958. hOldPen = SelectPen(hDC, hPen);
  1959. // Select the raster operation
  1960. iOldROP = ::SetROP2(hDC, m_iPenROP);
  1961. if (hOldPen != NULL)
  1962. {
  1963. // All points are relative to the first point in the list.
  1964. // We update the origin of the DC temporarily to account for this.
  1965. POINT origin;
  1966. ::GetWindowOrgEx(hDC, &origin);
  1967. ::SetWindowOrgEx(hDC, origin.x - m_rect.left, origin.y - m_rect.top, NULL);
  1968. // Call the appropriate drawing function, according to whether
  1969. // we're smooth or not
  1970. DrawUnsmoothed(hDC);
  1971. // Restore the origin
  1972. ::SetWindowOrgEx(hDC, origin.x, origin.y, NULL);
  1973. ::SetROP2(hDC, iOldROP);
  1974. SelectPen(hDC, hOldPen);
  1975. }
  1976. if (hPen != NULL)
  1977. {
  1978. ::DeletePen(hPen);
  1979. }
  1980. }
  1981. //
  1982. //
  1983. // Function: DCWbGraphicFreehand::DrawUnsmoothed
  1984. //
  1985. // Purpose: Draw the complete graphic, not using smoothing.
  1986. //
  1987. //
  1988. void DCWbGraphicFreehand::DrawUnsmoothed(HDC hDC)
  1989. {
  1990. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehandDrawUnsmoothed");
  1991. // Set up the count and pointer to the points data. We use the
  1992. // external data if we have a handle, otherwise internal data is used.
  1993. int iCount = points.GetSize();
  1994. if (iCount < 2)
  1995. {
  1996. POINT point;
  1997. point.x = points[0]->x;
  1998. point.y = points[0]->y;
  1999. points.Add(point);
  2000. iCount = points.GetSize();
  2001. }
  2002. RECT clipBox;
  2003. if (::GetClipBox(hDC, &clipBox) == ERROR)
  2004. {
  2005. WARNING_OUT(("Failed to get clip box"));
  2006. }
  2007. // Draw all the line segments stored
  2008. ::MoveToEx(hDC, points[0]->x, points[0]->y, NULL);
  2009. for ( int iIndex = 1; iIndex < iCount; iIndex++)
  2010. {
  2011. // Draw the line
  2012. ::LineTo(hDC, points[iIndex]->x, points[iIndex]->y);
  2013. }
  2014. }
  2015. //
  2016. //
  2017. // Function: DCWbGraphicFreehand::CalculateBoundsRect
  2018. //
  2019. // Purpose: Calculate the bounding rectangle of the line
  2020. //
  2021. //
  2022. void DCWbGraphicFreehand::CalculateBoundsRect(void)
  2023. {
  2024. // Reset the bounds rectangle
  2025. ::SetRectEmpty(&m_boundsRect);
  2026. // Add each of the points in the line to the bounding rectangle
  2027. int iCount = points.GetSize();
  2028. for ( int iIndex = 0; iIndex < iCount; iIndex++)
  2029. {
  2030. AddPointToBounds(points[iIndex]->x, points[iIndex]->y);
  2031. }
  2032. //
  2033. // Since the points are inclusive, we need to add one to the top &
  2034. // bottom sides.
  2035. //
  2036. ::InflateRect(&m_boundsRect, 0, 1);
  2037. ::OffsetRect(&m_boundsRect, m_rect.left, m_rect.top);
  2038. }
  2039. //
  2040. //
  2041. // Function: DCWbGraphicFreehand::AddPointToBounds
  2042. //
  2043. // Purpose: Add a single point into the bounding rectangle. The point is
  2044. // expected to be in surface co-ordinates.
  2045. //
  2046. //
  2047. void DCWbGraphicFreehand::AddPointToBounds(int x, int y)
  2048. {
  2049. // Create a rectangle containing the point just added (expanded
  2050. // by the width of the pen being used).
  2051. RECT rect;
  2052. int iInflate = (m_uiPenWidth + 1) / 2;
  2053. rect.left = x - iInflate;
  2054. rect.top = y - iInflate;
  2055. rect.right = x + iInflate;
  2056. rect.bottom = y + iInflate;
  2057. ::UnionRect(&m_boundsRect, &m_boundsRect, &rect);
  2058. }
  2059. //
  2060. //
  2061. // Function: DCWbGraphicFreehand::AddPoint
  2062. //
  2063. // Purpose: Add a point to the poly line, returning BOOL indicating
  2064. // success.
  2065. //
  2066. //
  2067. BOOL DCWbGraphicFreehand::AddPoint(POINT point)
  2068. {
  2069. BOOL bSuccess = TRUE;
  2070. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::AddPoint");
  2071. // if we've reached the maximum number of points then quit with failure
  2072. if (points.GetSize() >= MAX_FREEHAND_POINTS)
  2073. {
  2074. bSuccess = FALSE;
  2075. TRACE_MSG(("Maximum number of points for freehand object reached."));
  2076. return(bSuccess);
  2077. }
  2078. // If this is the first point - all others are taken relative to it.
  2079. if (points.GetSize() == 0)
  2080. {
  2081. // Save the first point here.
  2082. m_rect.left = point.x;
  2083. m_rect.top = point.y;
  2084. }
  2085. // Add the new point to the array - surround with exception handler
  2086. // to catch memory errors
  2087. POINT newpoint;
  2088. newpoint.x = point.x - m_rect.left;
  2089. newpoint.y = point.y - m_rect.top;
  2090. points.Add((newpoint));
  2091. // Add the new point into the accumulated bounds rectangle.
  2092. AddPointToBounds(point.x, point.y);
  2093. // Show that the graphic has changed
  2094. m_bChanged = TRUE;
  2095. return(bSuccess);
  2096. }
  2097. //
  2098. //
  2099. // Function: DCWbGraphicFreehand::CalculateExternalLength
  2100. //
  2101. // Purpose: Return the length of the external representation of the
  2102. // graphic.
  2103. //
  2104. //
  2105. DWORD DCWbGraphicFreehand::CalculateExternalLength(void)
  2106. {
  2107. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFreehand::CalculateExternalLength");
  2108. // Calculate the total length of the flat representation of the graphic
  2109. return (DWORD) ( sizeof(WB_GRAPHIC_FREEHAND)
  2110. + (points.GetSize() * sizeof(POINT)));
  2111. }
  2112. //
  2113. //
  2114. // Function: DCWbGraphicFreehand::WriteExtra
  2115. //
  2116. // Purpose: Write the extra (non-header) data to the flat representation
  2117. // of the graphic.
  2118. //
  2119. //
  2120. void DCWbGraphicFreehand::WriteExtra(PWB_GRAPHIC pHeader)
  2121. {
  2122. // Allocate the memory
  2123. PWB_GRAPHIC_FREEHAND pFreehand = (PWB_GRAPHIC_FREEHAND) pHeader;
  2124. // Copy the extra details into place
  2125. pFreehand->pointCount = (TSHR_UINT16)points.GetSize();
  2126. for ( int iIndex = 0; iIndex < pFreehand->pointCount; iIndex++)
  2127. {
  2128. pFreehand->points[iIndex].x = (short)points[iIndex]->x;
  2129. pFreehand->points[iIndex].y = (short)points[iIndex]->y;
  2130. }
  2131. }
  2132. //
  2133. //
  2134. // Function: DCWbGraphicFreehand::ReadExtra
  2135. //
  2136. // Purpose: Read the extra (non-header) data from the flat
  2137. // representation of the graphic.
  2138. //
  2139. //
  2140. void DCWbGraphicFreehand::ReadExtra(PWB_GRAPHIC pHeader)
  2141. {
  2142. // Allocate the memory
  2143. PWB_GRAPHIC_FREEHAND pFreehand = (PWB_GRAPHIC_FREEHAND) pHeader;
  2144. // Get the number of points
  2145. int iCount = pFreehand->pointCount;
  2146. // Set the size of the points array
  2147. points.SetSize(iCount);
  2148. // Copy the points from the external memory to internal
  2149. int iPointIndex = 0;
  2150. while (iPointIndex < iCount)
  2151. {
  2152. points[iPointIndex]->x = pFreehand->points[iPointIndex].x;
  2153. points[iPointIndex]->y = pFreehand->points[iPointIndex].y;
  2154. iPointIndex++;
  2155. }
  2156. }
  2157. //
  2158. // Checks object for an actual overlap with pRectHit. This
  2159. // function assumes that the boundingRect has already been
  2160. // compared with pRectHit.
  2161. //
  2162. BOOL DCWbGraphicFreehand::CheckReallyHit(LPCRECT pRectHit)
  2163. {
  2164. POINT *lpPoints;
  2165. int iCount;
  2166. int i;
  2167. POINT ptLast;
  2168. UINT uRadius;
  2169. RECT rectHit;
  2170. iCount = points.GetSize();
  2171. lpPoints = (POINT *)points.GetBuffer();
  2172. if( iCount == 0 )
  2173. return( FALSE );
  2174. // addjust hit rect to lpPoints coord space.
  2175. rectHit = *pRectHit;
  2176. ::OffsetRect(&rectHit, -m_rect.left, -m_rect.top);
  2177. if( (iCount > 0)&&(iCount < 2) )
  2178. {
  2179. // only one point, just hit check it
  2180. uRadius = m_uiPenWidth >> 1; // m_uiPenWidth/2
  2181. return(
  2182. CircleHit( lpPoints->x, lpPoints->y, uRadius, &rectHit, TRUE )
  2183. );
  2184. }
  2185. // look for a hit on each line segment body
  2186. ptLast = *lpPoints++;
  2187. for( i=1; i<iCount; i++ )
  2188. {
  2189. if( LineHit( ptLast.x, ptLast.y,
  2190. lpPoints->x, lpPoints->y, m_uiPenWidth,
  2191. FALSE, FALSE,
  2192. &rectHit )
  2193. )
  2194. return( TRUE ); // got a hit
  2195. ptLast = *lpPoints++;
  2196. }
  2197. // now, look for a hit on the line endpoints if m_uiPenWidth > 1
  2198. if( m_uiPenWidth > 1 )
  2199. {
  2200. uRadius = m_uiPenWidth >> 1; // m_uiPenWidth/2
  2201. lpPoints = (POINT *)points.GetBuffer();
  2202. for( i=0; i<iCount; i++, lpPoints++ )
  2203. {
  2204. if( CircleHit( lpPoints->x, lpPoints->y, uRadius, &rectHit, FALSE )
  2205. )
  2206. return( TRUE ); // got a hit
  2207. }
  2208. }
  2209. return( FALSE ); // no hits
  2210. }
  2211. DCWbGraphicRectangle::~DCWbGraphicRectangle( void )
  2212. {
  2213. // don't know if we are selected or not so just delete anyway
  2214. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  2215. {
  2216. g_pDraw->m_pMarker->DeleteMarker( this );
  2217. }
  2218. }
  2219. //
  2220. //
  2221. // Function: DCWbGraphicRectangle::SetRect
  2222. //
  2223. // Purpose: Set the rectangle size/position
  2224. //
  2225. //
  2226. void DCWbGraphicRectangle::SetRect(LPCRECT lprect)
  2227. {
  2228. DCWbGraphic::SetRect(lprect);
  2229. // Generate the new bounding rectangle
  2230. CalculateBoundsRect();
  2231. }
  2232. //
  2233. //
  2234. // Function: DCWbGraphicRectangle::MoveBy
  2235. //
  2236. // Purpose: Move the rectangle
  2237. //
  2238. //
  2239. void DCWbGraphicRectangle::MoveBy(int cx, int cy)
  2240. {
  2241. // Move the rectangle
  2242. ::OffsetRect(&m_rect, cx, cy);
  2243. // Move the other object attributes
  2244. DCWbGraphic::MoveBy(cx, cy);
  2245. }
  2246. //
  2247. //
  2248. // Function: DCWbGraphicRectangle::CalculateBoundsRect
  2249. //
  2250. // Purpose: Calculate the bounding rectangle of the object
  2251. //
  2252. //
  2253. void DCWbGraphicRectangle::CalculateBoundsRect(void)
  2254. {
  2255. // Generate the new bounding rectangle
  2256. m_boundsRect = m_rect;
  2257. NormalizeRect(&m_boundsRect);
  2258. ::InflateRect(&m_boundsRect, m_uiPenWidth, m_uiPenWidth);
  2259. }
  2260. //
  2261. //
  2262. // Function: DCWbGraphicRectangle::Draw
  2263. //
  2264. // Purpose: Draw the rectangle
  2265. //
  2266. //
  2267. void DCWbGraphicRectangle::Draw(HDC hDC)
  2268. {
  2269. int iOldROP;
  2270. RECT clipBox;
  2271. HPEN hPen;
  2272. HPEN hOldPen;
  2273. HBRUSH hOldBrush;
  2274. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicRectangle::Draw");
  2275. // Only draw anything if the bounding rectangle intersects
  2276. // the current clip box.
  2277. if (::GetClipBox(hDC, &clipBox) == ERROR)
  2278. {
  2279. WARNING_OUT(("Failed to get clip box"));
  2280. }
  2281. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  2282. {
  2283. TRACE_MSG(("No clip/bounds intersection"));
  2284. return;
  2285. }
  2286. // Select the pen
  2287. hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
  2288. hOldPen = SelectPen(hDC, hPen);
  2289. hOldBrush = SelectBrush(hDC, ::GetStockObject(NULL_BRUSH));
  2290. // Select the raster operation
  2291. iOldROP = ::SetROP2(hDC, m_iPenROP);
  2292. // Draw the rectangle
  2293. ::Rectangle(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
  2294. m_boundsRect.bottom);
  2295. ::SetROP2(hDC, iOldROP);
  2296. SelectPen(hDC, hOldPen);
  2297. if (hPen != NULL)
  2298. {
  2299. ::DeletePen(hPen);
  2300. }
  2301. }
  2302. //
  2303. // Checks object for an actual overlap with pRectHit. This
  2304. // function assumes that the boundingRect has already been
  2305. // compared with pRectHit.
  2306. //
  2307. BOOL DCWbGraphicRectangle::CheckReallyHit(LPCRECT pRectHit)
  2308. {
  2309. RECT rectEdge;
  2310. RECT rectHit;
  2311. // check left edge
  2312. rectEdge.left = m_rect.left - m_uiPenWidth;
  2313. rectEdge.top = m_rect.top - m_uiPenWidth;
  2314. rectEdge.right = m_rect.left;
  2315. rectEdge.bottom = m_rect.bottom + m_uiPenWidth;
  2316. if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
  2317. return( TRUE );
  2318. // check right edge
  2319. rectEdge.left = m_rect.right;
  2320. rectEdge.right = m_rect.right + m_uiPenWidth;
  2321. if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
  2322. return( TRUE );
  2323. // check top edge
  2324. rectEdge.left = m_rect.left;
  2325. rectEdge.right = m_rect.right;
  2326. rectEdge.bottom = m_rect.top;
  2327. if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
  2328. return( TRUE );
  2329. // check bottom edge
  2330. rectEdge.top = m_rect.bottom;
  2331. rectEdge.bottom = m_rect.bottom + m_uiPenWidth;
  2332. if (::IntersectRect(&rectHit, &rectEdge, pRectHit))
  2333. return( TRUE );
  2334. return( FALSE );
  2335. }
  2336. DCWbGraphicFilledRectangle::~DCWbGraphicFilledRectangle( void )
  2337. {
  2338. // don't know if we are selected or not so just delete anyway
  2339. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  2340. {
  2341. g_pDraw->m_pMarker->DeleteMarker( this );
  2342. }
  2343. }
  2344. //
  2345. //
  2346. // Function: DCWbGraphicFilledRectangle::CalculateBoundsRect
  2347. //
  2348. // Purpose: Calculate the bounding rectangle of the object
  2349. //
  2350. //
  2351. void DCWbGraphicFilledRectangle::CalculateBoundsRect(void)
  2352. {
  2353. // Generate the new bounding rectangle
  2354. // This is one greater than the rectangle to include the drawing rectangle
  2355. m_boundsRect = m_rect;
  2356. NormalizeRect(&m_boundsRect);
  2357. ::InflateRect(&m_boundsRect, 1, 1);
  2358. }
  2359. //
  2360. //
  2361. // Function: DCWbGraphicFilledRectangle::Draw
  2362. //
  2363. // Purpose: Draw the rectangle
  2364. //
  2365. //
  2366. void DCWbGraphicFilledRectangle::Draw(HDC hDC)
  2367. {
  2368. HPEN hPen;
  2369. HPEN hOldPen;
  2370. HBRUSH hBrush;
  2371. HBRUSH hOldBrush;
  2372. int iOldROP;
  2373. RECT clipBox;
  2374. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFilledRectangle::Draw");
  2375. // Only draw anything if the bounding rectangle intersects
  2376. // the current clip box.
  2377. if (::GetClipBox(hDC, &clipBox) == ERROR)
  2378. {
  2379. WARNING_OUT(("Failed to get clip box"));
  2380. }
  2381. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  2382. {
  2383. TRACE_MSG(("No clip/bounds intersection"));
  2384. return;
  2385. }
  2386. // Select the pen
  2387. hPen = ::CreatePen(m_iPenStyle, 2, m_clrPenColor);
  2388. hOldPen = SelectPen(hDC, hPen);
  2389. hBrush = ::CreateSolidBrush(m_clrPenColor);
  2390. hOldBrush = SelectBrush(hDC, hBrush);
  2391. // Select the raster operation
  2392. iOldROP = ::SetROP2(hDC, m_iPenROP);
  2393. // Draw the rectangle
  2394. ::Rectangle(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
  2395. m_boundsRect.bottom);
  2396. // Restore the ROP mode
  2397. ::SetROP2(hDC, iOldROP);
  2398. SelectBrush(hDC, hOldBrush);
  2399. if (hBrush != NULL)
  2400. {
  2401. ::DeleteBrush(hBrush);
  2402. }
  2403. SelectPen(hDC, hOldPen);
  2404. if (hPen != NULL)
  2405. {
  2406. ::DeletePen(hPen);
  2407. }
  2408. }
  2409. //
  2410. // Checks object for an actual overlap with pRectHit. This
  2411. // function assumes that the boundingRect has already been
  2412. // compared with pRectHit.
  2413. //
  2414. BOOL DCWbGraphicFilledRectangle::CheckReallyHit(LPCRECT pRectHit)
  2415. {
  2416. return( TRUE );
  2417. }
  2418. //
  2419. // Draws a tracking rect for every marker obj in marker
  2420. // (DCWbGraphicSelectTrackingRectangle is a friend of DCWbGraphicMarker
  2421. // and WbDrawingArea)
  2422. //
  2423. void DCWbGraphicSelectTrackingRectangle::Draw(HDC hDC)
  2424. {
  2425. POSITION posNext;
  2426. DCWbGraphic *pGraphic;
  2427. LPRECT pMarkerRect;
  2428. RECT rectTracker;
  2429. CPtrToPtrList *pMList;
  2430. // don't draw at start point or XOR will get out of sync
  2431. if( (m_Offset.cx == 0)&&(m_Offset.cy == 0) )
  2432. return;
  2433. ASSERT(g_pDraw);
  2434. pMList = &(g_pDraw->m_pMarker->MarkerList);
  2435. if( pMList->IsEmpty() )
  2436. return;
  2437. posNext = pMList->GetHeadPosition();
  2438. while( posNext != NULL )
  2439. {
  2440. pMList->GetNextAssoc( posNext, (void *&)pGraphic, (void *&)pMarkerRect );
  2441. if( pMarkerRect != NULL )
  2442. {
  2443. rectTracker = *pMarkerRect;
  2444. ::OffsetRect(&rectTracker, m_Offset.cx, m_Offset.cy);
  2445. SetRect(&rectTracker);
  2446. DCWbGraphicRectangle::Draw(hDC);
  2447. }
  2448. }
  2449. }
  2450. void DCWbGraphicSelectTrackingRectangle::MoveBy(int cx, int cy)
  2451. {
  2452. m_Offset.cx += cx;
  2453. m_Offset.cy += cy;
  2454. }
  2455. DCWbGraphicEllipse::~DCWbGraphicEllipse( void )
  2456. {
  2457. // don't know if we are selected or not so just delete anyway
  2458. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  2459. {
  2460. g_pDraw->m_pMarker->DeleteMarker( this );
  2461. }
  2462. }
  2463. //
  2464. //
  2465. // Function: DCWbGraphicEllipse::SetRect
  2466. //
  2467. // Purpose: Set the ellipse size/position
  2468. //
  2469. //
  2470. void DCWbGraphicEllipse::SetRect(LPCRECT lprc)
  2471. {
  2472. DCWbGraphic::SetRect(lprc);
  2473. // Generate the new bounding rectangle
  2474. CalculateBoundsRect();
  2475. }
  2476. //
  2477. //
  2478. // Function: DCWbGraphicEllipse::CalculateBoundsRect
  2479. //
  2480. // Purpose: Calculate the bounding rectangle of the object
  2481. //
  2482. //
  2483. void DCWbGraphicEllipse::CalculateBoundsRect(void)
  2484. {
  2485. // Generate the new bounding rectangle
  2486. // This includes all the line, since we draw inside the bounds
  2487. m_boundsRect = m_rect;
  2488. NormalizeRect(&m_boundsRect);
  2489. ::InflateRect(&m_boundsRect, m_uiPenWidth, m_uiPenWidth);
  2490. }
  2491. //
  2492. //
  2493. // Function: DCWbGraphicEllipse::MoveBy
  2494. //
  2495. // Purpose: Move the ellipse
  2496. //
  2497. //
  2498. void DCWbGraphicEllipse::MoveBy(int cx, int cy)
  2499. {
  2500. // Move the ellipse
  2501. ::OffsetRect(&m_rect, cx, cy);
  2502. // Move the other object attributes
  2503. DCWbGraphic::MoveBy(cx, cy);
  2504. }
  2505. //
  2506. //
  2507. // Function: DCWbGraphicEllipse::Draw
  2508. //
  2509. // Purpose: Draw the ellipse
  2510. //
  2511. //
  2512. void DCWbGraphicEllipse::Draw(HDC hDC)
  2513. {
  2514. HPEN hPen;
  2515. HPEN hOldPen;
  2516. HBRUSH hOldBrush;
  2517. int iOldROP;
  2518. RECT clipBox;
  2519. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicEllipse::Draw");
  2520. // Only draw anything if the bounding rectangle intersects
  2521. // the current clip box.
  2522. if (::GetClipBox(hDC, &clipBox) == ERROR)
  2523. {
  2524. WARNING_OUT(("Failed to get clip box"));
  2525. }
  2526. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  2527. {
  2528. TRACE_MSG(("No clip/bounds intersection"));
  2529. return;
  2530. }
  2531. // Select the pen
  2532. hPen = ::CreatePen(m_iPenStyle, m_uiPenWidth, m_clrPenColor);
  2533. hOldPen = SelectPen(hDC, hPen);
  2534. hOldBrush = SelectBrush(hDC, ::GetStockObject(NULL_BRUSH));
  2535. // Select the raster operation
  2536. iOldROP = ::SetROP2(hDC, m_iPenROP);
  2537. // Draw the rectangle
  2538. ::Ellipse(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
  2539. m_boundsRect.bottom);
  2540. ::SetROP2(hDC, iOldROP);
  2541. SelectBrush(hDC, hOldBrush);
  2542. SelectPen(hDC, hOldPen);
  2543. if (hPen != NULL)
  2544. {
  2545. ::DeletePen(hPen);
  2546. }
  2547. }
  2548. //
  2549. // Checks object for an actual overlap with pRectHit. This
  2550. // function assumes that the boundingRect has already been
  2551. // compared with pRectHit.
  2552. //
  2553. BOOL DCWbGraphicEllipse::CheckReallyHit(LPCRECT pRectHit)
  2554. {
  2555. return( EllipseHit( &m_rect, TRUE, m_uiPenWidth, pRectHit ) );
  2556. }
  2557. DCWbGraphicFilledEllipse::~DCWbGraphicFilledEllipse( void )
  2558. {
  2559. // don't know if we are selected or not so just delete anyway
  2560. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  2561. {
  2562. g_pDraw->m_pMarker->DeleteMarker( this );
  2563. }
  2564. }
  2565. //
  2566. //
  2567. // Function: DCWbGraphicFilledEllipse::CalculateBoundsRect
  2568. //
  2569. // Purpose: Calculate the bounding rectangle of the object
  2570. //
  2571. //
  2572. void DCWbGraphicFilledEllipse::CalculateBoundsRect(void)
  2573. {
  2574. // Generate the new bounding rectangle
  2575. // This is one greater than the rectangle to include the drawing rectangle
  2576. m_boundsRect = m_rect;
  2577. NormalizeRect(&m_boundsRect);
  2578. ::InflateRect(&m_boundsRect, 1, 1);
  2579. }
  2580. //
  2581. //
  2582. // Function: DCWbGraphicFilledEllipse::Draw
  2583. //
  2584. // Purpose: Draw the ellipse
  2585. //
  2586. //
  2587. void DCWbGraphicFilledEllipse::Draw(HDC hDC)
  2588. {
  2589. RECT clipBox;
  2590. HPEN hPen;
  2591. HPEN hOldPen;
  2592. HBRUSH hBrush;
  2593. HBRUSH hOldBrush;
  2594. int iOldROP;
  2595. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicFilledEllipse::Draw");
  2596. // Only draw anything if the bounding rectangle intersects
  2597. // the current clip box.
  2598. if (::GetClipBox(hDC, &clipBox) == ERROR)
  2599. {
  2600. WARNING_OUT(("Failed to get clip box"));
  2601. }
  2602. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  2603. {
  2604. TRACE_MSG(("No clip/bounds intersection"));
  2605. return;
  2606. }
  2607. // Select the pen
  2608. hPen = ::CreatePen(m_iPenStyle, 2, m_clrPenColor);
  2609. hOldPen = SelectPen(hDC, hPen);
  2610. hBrush = ::CreateSolidBrush(m_clrPenColor);
  2611. hOldBrush = SelectBrush(hDC, hBrush);
  2612. // Select the raster operation
  2613. iOldROP = ::SetROP2(hDC, m_iPenROP);
  2614. // Draw the rectangle
  2615. ::Ellipse(hDC, m_boundsRect.left, m_boundsRect.top, m_boundsRect.right,
  2616. m_boundsRect.bottom);
  2617. ::SetROP2(hDC, iOldROP);
  2618. SelectBrush(hDC, hOldBrush);
  2619. if (hBrush != NULL)
  2620. {
  2621. ::DeleteBrush(hBrush);
  2622. }
  2623. SelectPen(hDC, hOldPen);
  2624. if (hPen != NULL)
  2625. {
  2626. ::DeletePen(hPen);
  2627. }
  2628. }
  2629. //
  2630. // Checks object for an actual overlap with pRectHit. This
  2631. // function assumes that the boundingRect has already been
  2632. // compared with pRectHit.
  2633. //
  2634. BOOL DCWbGraphicFilledEllipse::CheckReallyHit(LPCRECT pRectHit)
  2635. {
  2636. return( EllipseHit( &m_rect, FALSE, 0, pRectHit ) );
  2637. }
  2638. //
  2639. //
  2640. // Function: DCWbGraphicText::DCWbGraphicText
  2641. //
  2642. // Purpose: Initialize a new drawn text object.
  2643. //
  2644. //
  2645. DCWbGraphicText::DCWbGraphicText(void)
  2646. {
  2647. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::DCWbGraphicText");
  2648. m_hFontThumb = NULL;
  2649. m_hFont = ::CreateFont(0,0,0,0,FW_NORMAL,0,0,0,0,OUT_TT_PRECIS,
  2650. CLIP_DFA_OVERRIDE,
  2651. DRAFT_QUALITY,
  2652. FF_SWISS,NULL);
  2653. // Add an empty line to the text array
  2654. strTextArray.Add(_T(""));
  2655. // Show that the graphic has not changed
  2656. m_bChanged = FALSE;
  2657. m_nKerningOffset = 0; // added for bug 469
  2658. }
  2659. DCWbGraphicText::DCWbGraphicText(PWB_GRAPHIC pHeader)
  2660. : DCWbGraphic()
  2661. {
  2662. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::DCWbGraphicText");
  2663. ASSERT(pHeader != NULL);
  2664. m_hFont = NULL;
  2665. m_hFontThumb = NULL;
  2666. // Note that we do everything in this constructor because of the
  2667. // calls to ReadHeader and ReadExtra. If we let the DCWbGraphic base
  2668. // constructor do it the wrong version of ReadExtra will be called
  2669. // (the one in DCWbGraphic instead of the one in DCWbGraphicText).
  2670. // Add an empty line to the text array
  2671. strTextArray.Add(_T(""));
  2672. // Read the data
  2673. ReadHeader(pHeader);
  2674. ReadExtra(pHeader);
  2675. // Show that the graphic has not changed
  2676. m_bChanged = FALSE;
  2677. }
  2678. DCWbGraphicText::DCWbGraphicText
  2679. (
  2680. WB_PAGE_HANDLE hPage,
  2681. WB_GRAPHIC_HANDLE hGraphic
  2682. ) : DCWbGraphic()
  2683. {
  2684. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::DCWbGraphicText");
  2685. // Note that we do everything in this constructor because of the
  2686. // call to ReadExternal. If we let the DCWbGraphic base constructor
  2687. // do it the wrong version of ReadExtra will be called (the one
  2688. // in DCWbGraphic instead of the one in DCWbGraphicText);
  2689. // Set up the page and graphic handle
  2690. ASSERT(hPage != WB_PAGE_HANDLE_NULL);
  2691. m_hPage = hPage;
  2692. ASSERT(hGraphic != NULL);
  2693. m_hGraphic = hGraphic;
  2694. m_hFont = NULL;
  2695. m_hFontThumb = NULL;
  2696. // Add an empty line to the text array
  2697. strTextArray.Add(_T(""));
  2698. // Read the data
  2699. ReadExternal();
  2700. // Show that the graphic has not changed
  2701. m_bChanged = FALSE;
  2702. }
  2703. //
  2704. //
  2705. // Function: DCWbGraphicText:: ~DCWbGraphicText
  2706. //
  2707. // Purpose: Destruct a text object
  2708. //
  2709. //
  2710. DCWbGraphicText::~DCWbGraphicText()
  2711. {
  2712. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::~DCWbGraphicText");
  2713. // don't know if we are selected or not so just delete anyway
  2714. if(g_pDraw != NULL && g_pDraw->m_pMarker != NULL)
  2715. {
  2716. g_pDraw->m_pMarker->DeleteMarker( this );
  2717. }
  2718. // Ensure that the DC does not contain our fonts
  2719. if(g_pDraw != NULL)
  2720. {
  2721. g_pDraw->UnPrimeFont(g_pDraw->GetCachedDC());
  2722. }
  2723. if (m_hFontThumb != NULL)
  2724. {
  2725. ::DeleteFont(m_hFontThumb);
  2726. m_hFontThumb = NULL;
  2727. }
  2728. if (m_hFont != NULL)
  2729. {
  2730. ::DeleteFont(m_hFont);
  2731. m_hFont = NULL;
  2732. }
  2733. }
  2734. StrCspn(char * string, char * control)
  2735. {
  2736. char *str = string;
  2737. char *ctrl = control;
  2738. unsigned char map[32];
  2739. int count;
  2740. /* Clear out bit map */
  2741. for (count=0; count<32; count++)
  2742. map[count] = 0;
  2743. /* Set bits in control map */
  2744. while (*ctrl)
  2745. {
  2746. map[*ctrl >> 3] |= (1 << (*ctrl & 7));
  2747. ctrl++;
  2748. }
  2749. count=0;
  2750. map[0] |= 1; /* null chars not considered */
  2751. while (!(map[*str >> 3] & (1 << (*str & 7))))
  2752. {
  2753. count++;
  2754. str++;
  2755. }
  2756. return(count);
  2757. }
  2758. //
  2759. //
  2760. // Function: DCWbGraphicText::SetText
  2761. //
  2762. // Purpose: Set the text of the object
  2763. //
  2764. //
  2765. void DCWbGraphicText::SetText(TCHAR * strText)
  2766. {
  2767. // Remove all the current stored text
  2768. strTextArray.RemoveAll();
  2769. // Scan the text for carriage return and new-line characters
  2770. int iNext = 0;
  2771. int iLast = 0;
  2772. int textSize = lstrlen(strText);
  2773. TCHAR savedChar[1];
  2774. //
  2775. // In this case, we don't know how many lines there will be. So we
  2776. // use Add() from the StrArray class.
  2777. //
  2778. while (iNext < textSize)
  2779. {
  2780. // Find the next carriage return or line feed
  2781. iNext += StrCspn(strText + iNext, "\r\n");
  2782. // Extract the text before the terminator
  2783. // and add it to the current list of text lines.
  2784. savedChar[0] = strText[iNext];
  2785. strText[iNext] = 0;
  2786. strTextArray.Add((strText+iLast));
  2787. strText[iNext] = savedChar[0];
  2788. if (iNext < textSize)
  2789. {
  2790. // Skip the carriage return
  2791. if (strText[iNext] == '\r')
  2792. iNext++;
  2793. // Skip a following new line (if there is one)
  2794. if (strText[iNext] == '\n')
  2795. iNext++;
  2796. // Update the index of the start of the next line
  2797. iLast = iNext;
  2798. }
  2799. }
  2800. // Calculate the bounding rectangle for the new text
  2801. CalculateBoundsRect();
  2802. // Show that the graphic has not changed
  2803. m_bChanged = TRUE;
  2804. }
  2805. //
  2806. //
  2807. // Function: DCWbGraphicText::SetText
  2808. //
  2809. // Purpose: Set the text of the object
  2810. //
  2811. //
  2812. void DCWbGraphicText::SetText(const StrArray& _strTextArray)
  2813. {
  2814. // Scan the text for carriage return and new-line characters
  2815. int iSize = _strTextArray.GetSize();
  2816. //
  2817. // In this case we know how many lines, so set that # then use SetAt()
  2818. // to stick text there.
  2819. //
  2820. strTextArray.RemoveAll();
  2821. strTextArray.SetSize(iSize);
  2822. int iNext = 0;
  2823. for ( ; iNext < iSize; iNext++)
  2824. {
  2825. strTextArray.SetAt(iNext, _strTextArray[iNext]);
  2826. }
  2827. // Calculate the new bounding rectangle
  2828. CalculateBoundsRect();
  2829. // Show that the graphic has changed
  2830. m_bChanged = TRUE;
  2831. }
  2832. //
  2833. //
  2834. // Function: DCWbGraphicText::SetFont
  2835. //
  2836. // Purpose: Set the font to be used for drawing
  2837. //
  2838. //
  2839. void DCWbGraphicText::SetFont(HFONT hFont)
  2840. {
  2841. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::SetFont");
  2842. // Get the font details
  2843. LOGFONT lfont;
  2844. ::GetObject(hFont, sizeof(LOGFONT), &lfont);
  2845. //
  2846. // Pass the logical font into the SetFont() function
  2847. //
  2848. SetFont(&lfont);
  2849. }
  2850. //
  2851. //
  2852. // Function: DCWbGraphicText::SetFont(metrics)
  2853. //
  2854. // Purpose: Set the font to be used for drawing
  2855. //
  2856. //
  2857. void DCWbGraphicText::SetFont(LOGFONT *pLogFont, BOOL bReCalc )
  2858. {
  2859. HFONT hOldFont;
  2860. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::SetFont");
  2861. // Ensure that the font can be resized by the zoom function
  2862. // (proof quality prevents font scaling).
  2863. pLogFont->lfQuality = DRAFT_QUALITY;
  2864. //zap FontAssociation mode (bug 3258)
  2865. pLogFont->lfClipPrecision |= CLIP_DFA_OVERRIDE;
  2866. // Always work in cell coordinates to get scaling right
  2867. TRACE_MSG(("Setting font height %d, width %d, face %s, family %d, precis %d",
  2868. pLogFont->lfHeight,pLogFont->lfWidth,pLogFont->lfFaceName,
  2869. pLogFont->lfPitchAndFamily, pLogFont->lfOutPrecision));
  2870. hOldFont = m_hFont;
  2871. m_hFont = ::CreateFontIndirect(pLogFont);
  2872. if (!m_hFont)
  2873. {
  2874. // Could not create the font
  2875. ERROR_OUT(("Failed to create font"));
  2876. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  2877. return;
  2878. }
  2879. // Calculate the line height for this font
  2880. if(g_pDraw != NULL)
  2881. {
  2882. HDC hDC = g_pDraw->GetCachedDC();
  2883. g_pDraw->PrimeFont(hDC, m_hFont, &m_textMetrics);
  2884. }
  2885. // We are now guaranteed to be able to delete the old font
  2886. if (hOldFont != NULL)
  2887. {
  2888. ::DeleteFont(hOldFont);
  2889. }
  2890. // Set up the thumbnail font, forcing truetype if not currently TT
  2891. if (!(m_textMetrics.tmPitchAndFamily & TMPF_TRUETYPE))
  2892. {
  2893. pLogFont->lfFaceName[0] = 0;
  2894. pLogFont->lfOutPrecision = OUT_TT_PRECIS;
  2895. TRACE_MSG(("Non-True type font"));
  2896. }
  2897. if (m_hFontThumb != NULL)
  2898. {
  2899. ::DeleteFont(m_hFontThumb);
  2900. }
  2901. m_hFontThumb = ::CreateFontIndirect(pLogFont);
  2902. if (!m_hFontThumb)
  2903. {
  2904. // Could not create the font
  2905. ERROR_OUT(("Failed to create thumbnail font"));
  2906. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  2907. return;
  2908. }
  2909. // Calculate the bounding rectangle, accounting for the new font
  2910. if( bReCalc )
  2911. CalculateBoundsRect();
  2912. // Show that the graphic has changed
  2913. m_bChanged = TRUE;
  2914. }
  2915. //
  2916. //
  2917. // Function: DCWbGraphicText::GetTextABC
  2918. //
  2919. // Purpose: Calculate the ABC numbers for a string of text
  2920. //
  2921. // COMMENT BY RAND: The abc returned is for the whole string, not just one
  2922. // char. I.e, ABC.abcA is the offset to the first glyph in
  2923. // the string, ABC.abcB is the sum of all of the glyphs and
  2924. // ABC.abcC is the trailing space after the last glyph.
  2925. // ABC.abcA + ABC.abcB + ABC.abcC is the total rendered
  2926. // length including overhangs.
  2927. //
  2928. // Note - we never use the A spacing so it is always 0
  2929. //
  2930. ABC DCWbGraphicText::GetTextABC( LPCTSTR pText,
  2931. int iStartX,
  2932. int iStopX)
  2933. {
  2934. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::GetTextABC");
  2935. ABC abcResult;
  2936. HDC hDC;
  2937. BOOL rc = FALSE;
  2938. ABC abcFirst;
  2939. ABC abcLast;
  2940. BOOL zoomed = g_pDraw->Zoomed();
  2941. int nCharLast;
  2942. int i;
  2943. LPCTSTR pScanStr;
  2944. ZeroMemory( (PVOID)&abcResult, sizeof abcResult );
  2945. ZeroMemory( (PVOID)&abcFirst, sizeof abcFirst );
  2946. ZeroMemory( (PVOID)&abcLast, sizeof abcLast );
  2947. // Get the standard size measure of the text
  2948. LPCTSTR pABC = (pText + iStartX);
  2949. int pABCLength = iStopX - iStartX;
  2950. hDC = g_pDraw->GetCachedDC();
  2951. g_pDraw->PrimeFont(hDC, m_hFont, &m_textMetrics);
  2952. //
  2953. // We must temporarily unzoom if we are currently zoomed since the
  2954. // weird Windows font handling will not give us the same answer for
  2955. // the text extent in zoomed mode for some TrueType fonts
  2956. //
  2957. if (zoomed)
  2958. {
  2959. ::ScaleViewportExtEx(hDC, 1, g_pDraw->ZoomFactor(), 1, g_pDraw->ZoomFactor(), NULL);
  2960. }
  2961. DWORD size = ::GetTabbedTextExtent(hDC, pABC, pABCLength, 0, NULL);
  2962. // We now have the advance width of the text
  2963. abcResult.abcB = LOWORD(size);
  2964. TRACE_MSG(("Basic text width is %d",abcResult.abcB));
  2965. // Allow for C space (or overhang)
  2966. if (iStopX > iStartX)
  2967. {
  2968. if (m_textMetrics.tmPitchAndFamily & TMPF_TRUETYPE)
  2969. {
  2970. if(GetSystemMetrics( SM_DBCSENABLED ))
  2971. {
  2972. // have to handle DBCS on both ends
  2973. if( IsDBCSLeadByte( (BYTE)pABC[0] ) )
  2974. {
  2975. // pack multi byte char into a WORD for GetCharABCWidths
  2976. WORD wMultiChar = MAKEWORD( pABC[1], pABC[0] );
  2977. rc = ::GetCharABCWidths(hDC, wMultiChar, wMultiChar, &abcFirst);
  2978. }
  2979. else
  2980. {
  2981. // first char is SBCS
  2982. rc = ::GetCharABCWidths(hDC, pABC[0], pABC[0], &abcFirst );
  2983. }
  2984. // Check for DBCS as last char. Have to scan whole string to be sure
  2985. pScanStr = pABC;
  2986. nCharLast = 0;
  2987. for( i=0; i<pABCLength; i++, pScanStr++ )
  2988. {
  2989. nCharLast = i;
  2990. if( IsDBCSLeadByte( (BYTE)*pScanStr ) )
  2991. {
  2992. i++;
  2993. pScanStr++;
  2994. }
  2995. }
  2996. if( IsDBCSLeadByte( (BYTE)pABC[nCharLast] ) )
  2997. {
  2998. // pack multi byte char into a WORD for GetCharABCWidths
  2999. ASSERT( (nCharLast+1) < pABCLength );
  3000. WORD wMultiChar = MAKEWORD( pABC[nCharLast+1], pABC[nCharLast] );
  3001. rc = ::GetCharABCWidths(hDC, wMultiChar, wMultiChar, &abcLast);
  3002. }
  3003. else
  3004. {
  3005. // last char is SBCS
  3006. rc = ::GetCharABCWidths(hDC, pABC[nCharLast], pABC[nCharLast], &abcLast );
  3007. }
  3008. }
  3009. else
  3010. {
  3011. // SBCS, no special fiddling, just call GetCharABCWidths()
  3012. rc = ::GetCharABCWidths(hDC, pABC[0], pABC[0], &abcFirst );
  3013. nCharLast = pABCLength-1;
  3014. rc = rc && ::GetCharABCWidths(hDC, pABC[nCharLast], pABC[nCharLast], &abcLast );
  3015. }
  3016. TRACE_MSG(("abcFirst: rc=%d, a=%d, b=%d, c=%d",
  3017. rc, abcFirst.abcA, abcFirst.abcB, abcFirst.abcC) );
  3018. TRACE_MSG(("abcLast: rc=%d, a=%d, b=%d, c=%d",
  3019. rc, abcLast.abcA, abcLast.abcB, abcLast.abcC) );
  3020. }
  3021. if( rc )
  3022. {
  3023. // The text was trutype and we got good abcwidths
  3024. // Give the C space of the last characters from
  3025. // the string as the C space of the text.
  3026. abcResult.abcA = abcFirst.abcA;
  3027. abcResult.abcC = abcLast.abcC;
  3028. }
  3029. else
  3030. {
  3031. //
  3032. // Mock up C value for a non TT font by taking some of overhang as
  3033. // the negative C value.
  3034. //
  3035. //TRACE_MSG(("Using overhang -%d as C space",m_textMetrics.tmOverhang/2));
  3036. // Adjust B by -overhang to make update rect schoot
  3037. // far enough to the left so that the toes of italic cap A's
  3038. // don't get clipped. Ignore comment above.
  3039. abcResult.abcB -= m_textMetrics.tmOverhang;
  3040. }
  3041. }
  3042. //
  3043. // If we temporarily unzoomed then restore it now
  3044. //
  3045. if (zoomed)
  3046. {
  3047. ::ScaleViewportExtEx(hDC, g_pDraw->ZoomFactor(), 1, g_pDraw->ZoomFactor(), 1, NULL);
  3048. }
  3049. TRACE_MSG(("Final text width is %d, C space %d",abcResult.abcB,abcResult.abcC));
  3050. return abcResult;
  3051. }
  3052. //
  3053. //
  3054. // Function: DCWbGraphicText::GetTextRectangle
  3055. //
  3056. // Purpose: Calculate the bounding rectangle of a portion of the object
  3057. //
  3058. //
  3059. void DCWbGraphicText::GetTextRectangle(int iStartY,
  3060. int iStartX,
  3061. int iStopX,
  3062. LPRECT lprc)
  3063. {
  3064. // ABC structures for text sizing
  3065. ABC abcText1;
  3066. ABC abcText2;
  3067. int iLeftOffset = 0;
  3068. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::GetTextRect");
  3069. // Here we calculate the width of the text glyphs in which we
  3070. // are interested. In case there are tabs involved we must start
  3071. // with position 0 and get two lengths then subtract them
  3072. abcText1 = GetTextABC(strTextArray[iStartY], 0, iStopX);
  3073. if (iStartX > 0)
  3074. {
  3075. // The third param used to be iStartX-1 which is WRONG. It
  3076. // has to point to the first char pos past the string
  3077. // we are using.
  3078. abcText2 = GetTextABC(strTextArray[iStartY], 0, iStartX);
  3079. // Just use B part for offset. Adding A snd/or C to it moves the update
  3080. // rectangle too far to the right and clips the char
  3081. iLeftOffset = abcText2.abcB;
  3082. }
  3083. else
  3084. {
  3085. ZeroMemory( &abcText2, sizeof abcText2 );
  3086. }
  3087. //
  3088. // We need to allow for A and C space in the bounding rectangle. Use
  3089. // ABS function just to make sure we get a large enough rectangle.
  3090. //
  3091. // Move A and C from original offset calc to here for width of update
  3092. // rectangle. Add in tmOverhang (non zero for non-tt fonts) to compensate
  3093. // for the kludge in GetTextABC()....THIS EDITBOX CODE HAS GOT TO GO...
  3094. abcText1.abcB = abcText1.abcB - iLeftOffset +
  3095. abs(abcText2.abcA) + abs(abcText2.abcC) +
  3096. abs(abcText1.abcA) + abs(abcText1.abcC) +
  3097. m_textMetrics.tmOverhang;
  3098. TRACE_DEBUG(("Left offset %d",iLeftOffset));
  3099. TRACE_DEBUG(("B width now %d",abcText1.abcB));
  3100. // Build the result rectangle.
  3101. // Note that we never return an empty rectangle. This allows for the
  3102. // fact that the Windows rectangle functions will ignore empty
  3103. // rectangles completely. This would cause the bounding rectangle
  3104. // calculation (for instance) to go wrong if the top or bottom lines
  3105. // in a text object were empty.
  3106. int iLineHeight = m_textMetrics.tmHeight + m_textMetrics.tmExternalLeading;
  3107. lprc->left = 0;
  3108. lprc->top = 0;
  3109. lprc->right = max(1, abcText1.abcB);
  3110. lprc->bottom = iLineHeight;
  3111. ::OffsetRect(lprc, iLeftOffset, iLineHeight * iStartY);
  3112. // rect is the correct width at this point but it might need to be schooted to
  3113. // the left a bit to allow for kerning of 1st letter (bug 469)
  3114. if( abcText1.abcA < 0 )
  3115. {
  3116. ::OffsetRect(lprc, abcText1.abcA, 0);
  3117. m_nKerningOffset = -abcText1.abcA;
  3118. }
  3119. else
  3120. m_nKerningOffset = 0;
  3121. POINT pt;
  3122. GetPosition(&pt);
  3123. ::OffsetRect(lprc, pt.x, pt.y);
  3124. }
  3125. //
  3126. //
  3127. // Function: DCWbGraphicText::CalculateRect
  3128. //
  3129. // Purpose: Calculate the bounding rectangle of a portion of the object
  3130. //
  3131. //
  3132. void DCWbGraphicText::CalculateRect(int iStartX,
  3133. int iStartY,
  3134. int iStopX,
  3135. int iStopY,
  3136. LPRECT lprcResult)
  3137. {
  3138. RECT rcResult;
  3139. RECT rcT;
  3140. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::CalculateRect");
  3141. //
  3142. // NOTE:
  3143. // We must use an intermediate rectangle, so as not to disturb the
  3144. // contents of the passed-in one until done. lprcResult may be pointing
  3145. // to the current bounds rect, and we call functions from here that
  3146. // may need its current value.
  3147. //
  3148. // Initialize the result rectangle
  3149. ::SetRectEmpty(&rcResult);
  3150. // Allow for special limit values and ensure that the start and stop
  3151. // character positions are in range.
  3152. if (iStopY == LAST_LINE)
  3153. {
  3154. iStopY = strTextArray.GetSize() - 1;
  3155. }
  3156. iStopY = min(iStopY, strTextArray.GetSize() - 1);
  3157. iStopY = max(iStopY, 0);
  3158. if (iStopX == LAST_CHAR)
  3159. {
  3160. iStopX = lstrlen(strTextArray[iStopY]);
  3161. }
  3162. iStopX = min(iStopX, lstrlen(strTextArray[iStopY]));
  3163. iStopX = max(iStopX, 0);
  3164. // Loop through the text strings, adding each to the rectangle
  3165. for (int iIndex = iStartY; iIndex <= iStopY; iIndex++)
  3166. {
  3167. int iLeftX = ((iIndex == iStartY) ? iStartX : 0);
  3168. int iRightX = ((iIndex == iStopY)
  3169. ? iStopX : lstrlen(strTextArray[iIndex]));
  3170. GetTextRectangle(iIndex, iLeftX, iRightX, &rcT);
  3171. ::UnionRect(&rcResult, &rcResult, &rcT);
  3172. }
  3173. *lprcResult = rcResult;
  3174. }
  3175. //
  3176. //
  3177. // Function: DCWbGraphicText::CalculateBoundsRect
  3178. //
  3179. // Purpose: Calculate the bounding rectangle of the object
  3180. //
  3181. //
  3182. void DCWbGraphicText::CalculateBoundsRect(void)
  3183. {
  3184. // Set the new bounding rectangle
  3185. CalculateRect(0, 0, LAST_CHAR, LAST_LINE, &m_boundsRect);
  3186. }
  3187. //
  3188. //
  3189. // Function: DCWbGraphicText::Draw
  3190. //
  3191. // Purpose : Draw the object onto the specified DC
  3192. //
  3193. //
  3194. void DCWbGraphicText::Draw(HDC hDC, BOOL thumbNail)
  3195. {
  3196. RECT clipBox;
  3197. BOOL dbcsEnabled = GetSystemMetrics(SM_DBCSENABLED);
  3198. INT *tabArray;
  3199. UINT ch;
  3200. int i,j;
  3201. BOOL zoomed = g_pDraw->Zoomed();
  3202. int oldBkMode = 0;
  3203. int iIndex = 0;
  3204. POINT pointPos;
  3205. int nLastTab;
  3206. ABC abc;
  3207. int iLength;
  3208. TCHAR * strLine;
  3209. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::Draw");
  3210. //
  3211. // Only draw anything if the bounding rectangle intersects the current
  3212. // clip box.
  3213. //
  3214. if (::GetClipBox(hDC, &clipBox) == ERROR)
  3215. {
  3216. WARNING_OUT(("Failed to get clip box"));
  3217. }
  3218. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  3219. {
  3220. TRACE_MSG(("No clip/bounds intersection"));
  3221. return;
  3222. }
  3223. //
  3224. // Select the font.
  3225. //
  3226. if (thumbNail)
  3227. {
  3228. TRACE_MSG(("Using thumbnail font"));
  3229. g_pDraw->PrimeFont(hDC, m_hFontThumb, &m_textMetrics);
  3230. }
  3231. else
  3232. {
  3233. TRACE_MSG(("Using standard font"));
  3234. g_pDraw->PrimeFont(hDC, m_hFont, &m_textMetrics);
  3235. }
  3236. //
  3237. // Set the color and mode for drawing.
  3238. //
  3239. ::SetTextColor(hDC, m_clrPenColor);
  3240. //
  3241. // Set the background to be transparent
  3242. //
  3243. oldBkMode = ::SetBkMode(hDC, TRANSPARENT);
  3244. //
  3245. // Calculate the bounding rectangle, accounting for the new font.
  3246. //
  3247. CalculateBoundsRect();
  3248. //
  3249. // Get the start point for the text.
  3250. //
  3251. pointPos.x = m_boundsRect.left + m_nKerningOffset;
  3252. pointPos.y = m_boundsRect.top;
  3253. //
  3254. // Loop through the text strings drawing each as we go.
  3255. //
  3256. for (iIndex = 0; iIndex < strTextArray.GetSize(); iIndex++)
  3257. {
  3258. //
  3259. // Get a reference to the line to be printed for convenience.
  3260. //
  3261. strLine = (LPTSTR)strTextArray[iIndex];
  3262. iLength = lstrlen(strLine);
  3263. //
  3264. // Only draw the line if there are any characters in it.
  3265. //
  3266. if (iLength > 0)
  3267. {
  3268. if (zoomed)
  3269. {
  3270. // if new fails just skip it
  3271. tabArray = new INT[iLength+1];
  3272. if( tabArray == NULL )
  3273. {
  3274. ERROR_OUT(("Failed to allocate tabArray"));
  3275. continue;
  3276. }
  3277. // We are zoomed. Must calculate char spacings
  3278. // ourselfs so that they end up proportionally
  3279. // in the right places. TabbedTextOut will not
  3280. // do this right so we have to use ExtTextOut with
  3281. // a tab array.
  3282. // figure out tab array
  3283. j = 0;
  3284. nLastTab = 0;
  3285. for (i=0; i < iLength; i++)
  3286. {
  3287. ch = strLine[(int)i]; //Don't worry about DBCS here...
  3288. abc = GetTextABC(strLine, 0, i);
  3289. if( j > 0 )
  3290. tabArray[j-1] = abc.abcB - nLastTab;
  3291. nLastTab = abc.abcB;
  3292. j++;
  3293. }
  3294. // Now, strip out any tab chars so they don't interact
  3295. // in an obnoxious manner with the tab array we just
  3296. // made and so they don't make ugly little
  3297. // blocks when they are drawn.
  3298. for (i=0; i < iLength; i++)
  3299. {
  3300. ch = strLine[(int)i];
  3301. if ((dbcsEnabled) && (IsDBCSLeadByte((BYTE)ch)))
  3302. i++;
  3303. else
  3304. if(strLine[(int)i] == '\t')
  3305. strLine[i] = ' '; // blow off tab, tab array
  3306. // will compensate for this
  3307. }
  3308. // do it
  3309. ::ExtTextOut(hDC, pointPos.x,
  3310. pointPos.y,
  3311. 0,
  3312. NULL,
  3313. strLine,
  3314. iLength,
  3315. tabArray);
  3316. delete [] tabArray;
  3317. }
  3318. else
  3319. {
  3320. POINT ptPos;
  3321. GetPosition(&ptPos);
  3322. // Not zoomed, just do it
  3323. ::TabbedTextOut(hDC, pointPos.x,
  3324. pointPos.y,
  3325. strLine,
  3326. iLength,
  3327. 0,
  3328. NULL,
  3329. ptPos.x);
  3330. }
  3331. }
  3332. //
  3333. // Move to the next line.
  3334. //
  3335. pointPos.y += (m_textMetrics.tmHeight);
  3336. }
  3337. //
  3338. // Restore the old background mode.
  3339. //
  3340. ::SetBkMode(hDC, oldBkMode);
  3341. g_pDraw->UnPrimeFont(hDC);
  3342. }
  3343. //
  3344. //
  3345. // Function: DCWbGraphicText::CalculateExternalLength
  3346. //
  3347. // Purpose: Return the length of the external representation of the
  3348. // graphic.
  3349. //
  3350. //
  3351. DWORD DCWbGraphicText::CalculateExternalLength(void)
  3352. {
  3353. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::CalculateExternalLength");
  3354. // Loop through the text strings, adding the size of each as we go
  3355. DWORD length = sizeof(WB_GRAPHIC_TEXT);
  3356. int iCount = strTextArray.GetSize();
  3357. for (int iIndex = 0; iIndex < iCount; iIndex++)
  3358. {
  3359. // Allow extra bytes per string for NULL term
  3360. length += lstrlen(strTextArray[iIndex]) + 2;
  3361. }
  3362. return length;
  3363. }
  3364. //
  3365. //
  3366. // Function: DCWbGraphicText::WriteExtra
  3367. //
  3368. // Purpose: Write the extra (non-header) data to the flat representation
  3369. // of the graphic.
  3370. //
  3371. //
  3372. void DCWbGraphicText::WriteExtra(PWB_GRAPHIC pHeader)
  3373. {
  3374. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::WriteExtra");
  3375. // Allocate the memory
  3376. PWB_GRAPHIC_TEXT pText = (PWB_GRAPHIC_TEXT) pHeader;
  3377. // Get the font face name
  3378. LOGFONT lfont;
  3379. ::GetObject(m_hFont, sizeof(LOGFONT), &lfont);
  3380. // Copy the face name into the flat object representation
  3381. // The other information comes from the logical font details
  3382. TRACE_MSG(("Font details height %d, avwidth %d, family %d, face %s",
  3383. lfont.lfHeight,
  3384. lfont.lfWidth,
  3385. lfont.lfPitchAndFamily,
  3386. lfont.lfFaceName));
  3387. _tcscpy(pText->faceName, lfont.lfFaceName);
  3388. pText->charHeight = (short)lfont.lfHeight;
  3389. pText->averageCharWidth = (short)lfont.lfWidth;
  3390. pText->strokeWeight = (short)lfont.lfWeight;
  3391. pText->italic = lfont.lfItalic;
  3392. pText->underline = lfont.lfUnderline;
  3393. pText->strikeout = lfont.lfStrikeOut;
  3394. pText->pitch = lfont.lfPitchAndFamily;
  3395. //COMMENT BY RAND
  3396. // Original DCL apps ignore WB_GRAPHIC_TEXT::codePage. I am using it here
  3397. // to pass around the fonts script (character set). This might change later.
  3398. // Apps that ignore this have set it to 0 which will be interpreted as an
  3399. // ANSI_CHARSET.
  3400. pText->codePage = lfont.lfCharSet;
  3401. // Loop through the text strings, adding each as we go
  3402. char* pDest = pText->text;
  3403. int iCount = strTextArray.GetSize();
  3404. for (int iIndex = 0; iIndex < iCount; iIndex++)
  3405. {
  3406. _tcscpy(pDest, strTextArray[iIndex]);
  3407. pDest += lstrlen(strTextArray[iIndex]);
  3408. // Add the null terminator
  3409. *pDest++ = '\0';
  3410. }
  3411. // Save the number of strings
  3412. pText->stringCount = (TSHR_UINT16)iCount;
  3413. }
  3414. //
  3415. //
  3416. // Function: DCWbGraphicText::ReadExtra
  3417. //
  3418. // Purpose: Read the extra (non-header) data from the flat
  3419. // representation of the graphic.
  3420. //
  3421. //
  3422. void DCWbGraphicText::ReadExtra(PWB_GRAPHIC pHeader)
  3423. {
  3424. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicText::ReadExtra");
  3425. // Allocate the memory
  3426. PWB_GRAPHIC_TEXT pText = (PWB_GRAPHIC_TEXT) pHeader;
  3427. // Get the font details
  3428. LOGFONT lfont;
  3429. lfont.lfHeight = (short)pText->charHeight;
  3430. //
  3431. lfont.lfWidth = pText->averageCharWidth;
  3432. lfont.lfEscapement = 0;
  3433. lfont.lfOrientation = 0;
  3434. lfont.lfWeight = pText->strokeWeight;
  3435. lfont.lfItalic = pText->italic;
  3436. lfont.lfUnderline = pText->underline;
  3437. lfont.lfStrikeOut = pText->strikeout;
  3438. //COMMENT BY RAND
  3439. // Original DCL apps ignore WB_GRAPHIC_TEXT::codePage. I am using it here
  3440. // to pass around the fonts script (character set). This might change later.
  3441. // Apps that ignore this have set it to 0 which will be interpreted as an
  3442. // ANSI_CHARSET.
  3443. lfont.lfCharSet = (BYTE)pText->codePage;
  3444. lfont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  3445. lfont.lfClipPrecision = CLIP_DEFAULT_PRECIS | CLIP_DFA_OVERRIDE;
  3446. lfont.lfQuality = DRAFT_QUALITY;
  3447. lfont.lfPitchAndFamily = pText->pitch;
  3448. _tcscpy(lfont.lfFaceName, pText->faceName);
  3449. TRACE_MSG(("Setting height to %d, width %d, pitch %d, face %s",
  3450. pText->charHeight, pText->averageCharWidth, pText->pitch, pText->faceName));
  3451. // Loop through the text strings, retrieving each as we go
  3452. TCHAR* pString = pText->text;
  3453. int iCount = pText->stringCount;
  3454. // Remove all the current stored text
  3455. strTextArray.RemoveAll();
  3456. strTextArray.SetSize(iCount);
  3457. for (int iIndex = 0; iIndex < iCount; iIndex++)
  3458. {
  3459. strTextArray.SetAt(iIndex, pString);
  3460. pString += lstrlen(pString);
  3461. // Skip the null terminator
  3462. pString++;
  3463. }
  3464. // Set the current font
  3465. SetFont(&lfont);
  3466. }
  3467. //
  3468. //
  3469. // Function: InvalidateMetrics
  3470. //
  3471. // Purpose: Mark the metrics need retrieving again
  3472. //
  3473. //
  3474. void DCWbGraphicText::InvalidateMetrics(void)
  3475. {
  3476. }
  3477. //
  3478. // Checks object for an actual overlap with pRectHit. This
  3479. // function assumes that the boundingRect has already been
  3480. // compared with pRectHit.
  3481. //
  3482. BOOL DCWbGraphicText::CheckReallyHit(LPCRECT pRectHit )
  3483. {
  3484. return( TRUE );
  3485. }
  3486. // version of Position() that compensates for kerning (bug 469)
  3487. void DCWbGraphicText::GetPosition(LPPOINT lppt)
  3488. {
  3489. lppt->x = m_boundsRect.left + m_nKerningOffset;
  3490. lppt->y = m_boundsRect.top;
  3491. }
  3492. //
  3493. //
  3494. // Function: DCWbGraphicDIB::DCWbGraphicDIB
  3495. //
  3496. // Purpose: Initialize a new drawn bitmap object.
  3497. //
  3498. //
  3499. DCWbGraphicDIB::DCWbGraphicDIB(void)
  3500. {
  3501. // Show that we have no internal image
  3502. m_lpbiImage = NULL;
  3503. }
  3504. DCWbGraphicDIB::DCWbGraphicDIB(PWB_GRAPHIC pHeader)
  3505. : DCWbGraphic(pHeader)
  3506. {
  3507. // Show that we have no internal image
  3508. m_lpbiImage = NULL;
  3509. }
  3510. DCWbGraphicDIB::DCWbGraphicDIB
  3511. (
  3512. WB_PAGE_HANDLE hPage,
  3513. WB_GRAPHIC_HANDLE hGraphic
  3514. ) : DCWbGraphic(hPage, hGraphic)
  3515. {
  3516. // Show that we have no internal image
  3517. m_lpbiImage = NULL;
  3518. }
  3519. //
  3520. //
  3521. // Function: DCWbGraphicDIB::~DCWbGraphicDIB
  3522. //
  3523. // Purpose: Destruct a drawn bitmap object.
  3524. //
  3525. //
  3526. DCWbGraphicDIB::~DCWbGraphicDIB(void)
  3527. {
  3528. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::~DCWbGraphicDIB");
  3529. // don't know if we are selected or not so just delete anyway
  3530. if(g_pDraw->m_pMarker != NULL)
  3531. {
  3532. g_pDraw->m_pMarker->DeleteMarker( this );
  3533. }
  3534. DeleteImage();
  3535. }
  3536. //
  3537. //
  3538. // Function: DCWbGraphicDIB::SetImage
  3539. //
  3540. // Purpose: Set the image of the object
  3541. //
  3542. //
  3543. void DCWbGraphicDIB::SetImage(LPBITMAPINFOHEADER lpbi)
  3544. {
  3545. // Delete any current bits
  3546. DeleteImage();
  3547. // Save the DIB bits--this is a COPY we now own
  3548. m_lpbiImage = lpbi;
  3549. // Update the bounds rectangle
  3550. CalculateBoundsRect();
  3551. // Show that the graphic has changed
  3552. m_bChanged = TRUE;
  3553. }
  3554. //
  3555. //
  3556. // Function: DCWbGraphicDIB::CalculateBoundsRect
  3557. //
  3558. // Purpose: Calculate the bounding rectangle of the bitmap
  3559. //
  3560. //
  3561. void DCWbGraphicDIB::CalculateBoundsRect()
  3562. {
  3563. // If there is no bitmap set up, the bounding rectangle is empty
  3564. if (m_lpbiImage == NULL)
  3565. {
  3566. ::SetRectEmpty(&m_boundsRect);
  3567. }
  3568. else
  3569. {
  3570. // Calculate the bounding rectangle from the size of the bitmap
  3571. m_boundsRect.right = m_boundsRect.left + m_lpbiImage->biWidth;
  3572. m_boundsRect.bottom = m_boundsRect.top + m_lpbiImage->biHeight;
  3573. }
  3574. }
  3575. //
  3576. //
  3577. // Function: DCWbGraphicDIB::CalculateExternalLength
  3578. //
  3579. // Purpose: Return the length of the external representation of the
  3580. // graphic.
  3581. //
  3582. //
  3583. DWORD DCWbGraphicDIB::CalculateExternalLength(void)
  3584. {
  3585. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::CalculateExternalLength");
  3586. // Use the internal representation to calculate the external length.
  3587. DWORD dwLength = sizeof(WB_GRAPHIC_DIB);
  3588. if (m_lpbiImage != NULL)
  3589. {
  3590. dwLength += DIB_TotalLength(m_lpbiImage);
  3591. }
  3592. else
  3593. {
  3594. // If we have got an external form already, use its length
  3595. if (m_hGraphic != NULL)
  3596. {
  3597. dwLength = m_dwExternalLength;
  3598. }
  3599. }
  3600. return dwLength;
  3601. }
  3602. //
  3603. //
  3604. // Function: DCWbGraphicDIB::WriteExtra
  3605. //
  3606. // Purpose: Write the data above and beyond the header to the pointer
  3607. // passed.
  3608. //
  3609. //
  3610. void DCWbGraphicDIB::WriteExtra(PWB_GRAPHIC pHeader)
  3611. {
  3612. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::WriteExtra");
  3613. // Nothing more to do if we do not have an image
  3614. if (m_lpbiImage != NULL)
  3615. {
  3616. // Copy the data into place
  3617. memcpy(((BYTE *) pHeader) + pHeader->dataOffset, m_lpbiImage,
  3618. DIB_TotalLength(m_lpbiImage));
  3619. }
  3620. }
  3621. //
  3622. //
  3623. // Function: DCWbGraphicDIB::ReadExtra
  3624. //
  3625. // Purpose: Read the data above and beyond the header to the pointer
  3626. // passed.
  3627. //
  3628. //
  3629. //
  3630. // DCWbGraphicDIB does not have a ReadExtra function. The Draw function
  3631. // uses the external data (if there is any) and the local data if there is
  3632. // not.
  3633. //
  3634. //
  3635. //
  3636. // Function: DCWbGraphicDIB::CopyExtra
  3637. //
  3638. // Purpose: Copy the data above and beyond the header into this object.
  3639. //
  3640. //
  3641. void DCWbGraphicDIB::CopyExtra(PWB_GRAPHIC pHeader)
  3642. {
  3643. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::CopyExtra");
  3644. // Get a pointer to the DIB data
  3645. LPBITMAPINFOHEADER lpbi;
  3646. lpbi = (LPBITMAPINFOHEADER) (((BYTE *) pHeader) + pHeader->dataOffset);
  3647. // Make a DIB copy
  3648. ASSERT(m_lpbiImage == NULL);
  3649. m_lpbiImage = DIB_Copy(lpbi);
  3650. // Show that the graphic has changed
  3651. m_bChanged = TRUE;
  3652. }
  3653. //
  3654. //
  3655. // Function: DCWbGraphicDIB::FromScreenArea
  3656. //
  3657. // Purpose: Set the content of the object from an area of the screen
  3658. //
  3659. //
  3660. void DCWbGraphicDIB::FromScreenArea(LPCRECT lprcScreen)
  3661. {
  3662. LPBITMAPINFOHEADER lpbiNew;
  3663. lpbiNew = DIB_FromScreenArea(lprcScreen);
  3664. if (lpbiNew != NULL)
  3665. {
  3666. // Set this as our current bits
  3667. SetImage(lpbiNew);
  3668. }
  3669. else
  3670. {
  3671. ::Message(NULL, (UINT)IDS_MSG_CAPTION, (UINT)IDS_CANTGETBMP, (UINT)MB_OK );
  3672. }
  3673. }
  3674. //
  3675. //
  3676. // Function: DCWbGraphicDIB::DeleteImage
  3677. //
  3678. // Purpose: Delete the internal image
  3679. //
  3680. //
  3681. void DCWbGraphicDIB::DeleteImage(void)
  3682. {
  3683. // If we have DIB bits, delete
  3684. if (m_lpbiImage != NULL)
  3685. {
  3686. ::GlobalFree((HGLOBAL)m_lpbiImage);
  3687. m_lpbiImage = NULL;
  3688. }
  3689. // Show our contents have changed
  3690. m_bChanged = TRUE;
  3691. }
  3692. //
  3693. //
  3694. // Function: DCWbGraphicDIB::GetDIBData
  3695. //
  3696. // Purpose: Return a pointer to the DIB data
  3697. //
  3698. //
  3699. BOOL DCWbGraphicDIB::GetDIBData(HOLD_DATA& hold)
  3700. {
  3701. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::GetDIBData");
  3702. // Pointer to image data (set up below depending on whether
  3703. // we have an internal or external image).
  3704. hold.lpbi = NULL;
  3705. hold.pHeader = NULL;
  3706. // Draw depending on whether the DIB data is internal or external
  3707. if (m_hGraphic == NULL)
  3708. {
  3709. // Do nothing if we do not have an image at all
  3710. if (m_lpbiImage != NULL)
  3711. {
  3712. hold.lpbi = m_lpbiImage;
  3713. }
  3714. }
  3715. else
  3716. {
  3717. // Lock the object data in the page
  3718. hold.pHeader = (PWB_GRAPHIC) PG_GetData(m_hPage, m_hGraphic);
  3719. if (hold.pHeader != NULL)
  3720. {
  3721. hold.lpbi = (LPBITMAPINFOHEADER) (((BYTE *) hold.pHeader)
  3722. + hold.pHeader->dataOffset);
  3723. }
  3724. }
  3725. return (hold.lpbi != NULL);
  3726. }
  3727. //
  3728. //
  3729. // Function: DCWbGraphicDIB::ReleaseDIBData
  3730. //
  3731. // Purpose: Release DIB data previously obtained with GetDIBData
  3732. //
  3733. //
  3734. void DCWbGraphicDIB::ReleaseDIBData(HOLD_DATA& hold)
  3735. {
  3736. if ((m_hGraphic != NULL) && (hold.pHeader != NULL))
  3737. {
  3738. // Release external memory
  3739. g_pwbCore->WBP_GraphicRelease(m_hPage, m_hGraphic, hold.pHeader);
  3740. hold.pHeader = NULL;
  3741. }
  3742. // Reset the hold bitmap info pointer
  3743. hold.lpbi = NULL;
  3744. }
  3745. //
  3746. //
  3747. // Function: DCWbGraphicDIB::Draw
  3748. //
  3749. // Purpose: Draw the object onto the specified DC
  3750. //
  3751. //
  3752. void DCWbGraphicDIB::Draw(HDC hDC)
  3753. {
  3754. RECT clipBox;
  3755. MLZ_EntryOut(ZONE_FUNCTION, "DCWbGraphicDIB::Draw");
  3756. // Only draw anything if the bounding rectangle intersects
  3757. // the current clip box.
  3758. if (::GetClipBox(hDC, &clipBox) == ERROR)
  3759. {
  3760. WARNING_OUT(("Failed to get clip box"));
  3761. }
  3762. else if (!::IntersectRect(&clipBox, &clipBox, &m_boundsRect))
  3763. {
  3764. TRACE_MSG(("No clip/bounds intersection"));
  3765. return;
  3766. }
  3767. // Pointer to image data (set up below depending on whether
  3768. // we have an internal or external image.
  3769. HOLD_DATA hold;
  3770. if (GetDIBData(hold))
  3771. {
  3772. // Set the stretch mode to be used so that scan lines are deleted
  3773. // rather than combined. This will tend to preserve color better.
  3774. int iOldStretchMode = ::SetStretchBltMode(hDC, STRETCH_DELETESCANS);
  3775. // Draw the bitmap
  3776. BOOL bResult = ::StretchDIBits(hDC,
  3777. m_boundsRect.left,
  3778. m_boundsRect.top,
  3779. m_boundsRect.right - m_boundsRect.left,
  3780. m_boundsRect.bottom - m_boundsRect.top,
  3781. 0,
  3782. 0,
  3783. (UINT) hold.lpbi->biWidth,
  3784. (UINT) hold.lpbi->biHeight,
  3785. (VOID FAR *) DIB_Bits(hold.lpbi),
  3786. (LPBITMAPINFO)hold.lpbi,
  3787. DIB_RGB_COLORS,
  3788. SRCCOPY);
  3789. // Restore the stretch mode
  3790. ::SetStretchBltMode(hDC, iOldStretchMode);
  3791. // Release external memory
  3792. ReleaseDIBData(hold);
  3793. }
  3794. }
  3795. //
  3796. // Checks object for an actual overlap with pRectHit. This
  3797. // function assumes that the boundingRect has already been
  3798. // compared with pRectHit.
  3799. //
  3800. BOOL DCWbGraphicDIB::CheckReallyHit(LPCRECT pRectHit)
  3801. {
  3802. return( TRUE );
  3803. }
  3804. ObjectTrashCan::~ObjectTrashCan(void)
  3805. {
  3806. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::~ObjectTrashCan");
  3807. BurnTrash();
  3808. }
  3809. BOOL ObjectTrashCan::GotTrash( void )
  3810. {
  3811. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::GotTrash");
  3812. return(!Trash.IsEmpty());
  3813. }
  3814. void ObjectTrashCan::BurnTrash( void )
  3815. {
  3816. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::BurnTrash");
  3817. int nObjects;
  3818. int i;
  3819. // zap objects
  3820. POSITION pos = Trash.GetHeadPosition();
  3821. while (pos != NULL)
  3822. {
  3823. delete Trash.GetNext(pos);
  3824. }
  3825. // zap pointers
  3826. EmptyTrash();
  3827. }
  3828. void ObjectTrashCan::CollectTrash( DCWbGraphic *pGObj )
  3829. {
  3830. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::CollectTrash");
  3831. Trash.AddTail(pGObj); // stuff it in the sack
  3832. m_hPage = pGObj->Page();
  3833. }
  3834. void
  3835. ObjectTrashCan::EmptyTrash( void )
  3836. {
  3837. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::EmptyTrash");
  3838. // zap pointers but leave objects scattered about the room
  3839. Trash.EmptyList();
  3840. }
  3841. void ObjectTrashCan::AddToPageLast
  3842. (
  3843. WB_PAGE_HANDLE hPage
  3844. )
  3845. {
  3846. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::AddToPageLast");
  3847. int nObjects;
  3848. int i;
  3849. POSITION posNext = Trash.GetHeadPosition();
  3850. while( posNext != NULL )
  3851. {
  3852. ((DCWbGraphic *)(Trash.GetNext(posNext)))->AddToPageLast(hPage);
  3853. }
  3854. }
  3855. void
  3856. ObjectTrashCan::SelectTrash( void )
  3857. {
  3858. MLZ_EntryOut(ZONE_FUNCTION, "ObjectTrashCan::SelectTrash");
  3859. int nObjects;
  3860. int i;
  3861. BOOL bForceAdd;
  3862. DCWbGraphic *pGObj;
  3863. // Zap current selection with first object and then add remaining
  3864. // objects to current selection
  3865. bForceAdd = FALSE;
  3866. POSITION posNext = Trash.GetHeadPosition();
  3867. while( posNext != NULL )
  3868. {
  3869. pGObj = (DCWbGraphic *)(Trash.GetNext(posNext));
  3870. g_pMain->m_drawingArea.SelectGraphic( pGObj, TRUE, bForceAdd );
  3871. bForceAdd = TRUE;
  3872. }
  3873. }
  3874. CPtrToPtrList::CPtrToPtrList( void )
  3875. {
  3876. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::CPtrToPtrList");
  3877. }// CPtrToPtrList::CPtrToPtrList
  3878. CPtrToPtrList::~CPtrToPtrList( void )
  3879. {
  3880. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::~CPtrToPtrList");
  3881. RemoveAll();
  3882. }// CPtrToPtrList::~CPtrToPtrList
  3883. void
  3884. CPtrToPtrList::RemoveAll( void )
  3885. {
  3886. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::RemoveAll");
  3887. POSITION pos;
  3888. stPtrPair *pPp;
  3889. // clean up pairs
  3890. pos = GetHeadPosition();
  3891. while( pos != NULL )
  3892. {
  3893. pPp = (stPtrPair *)GetNext( pos );
  3894. if( pPp != NULL )
  3895. delete pPp;
  3896. }
  3897. COBLIST::EmptyList();
  3898. }// CPtrToPtrList::~CPtrToPtrList
  3899. void
  3900. CPtrToPtrList::SetAt( void *key, void *newValue )
  3901. {
  3902. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::SetAt");
  3903. stPtrPair *pPp;
  3904. // see if key is already there
  3905. pPp = FindMainThingPair( key, NULL );
  3906. if( pPp != NULL )
  3907. {
  3908. // it's there, we're just updating its value
  3909. pPp->pRelatedThing = newValue;
  3910. }
  3911. else
  3912. {
  3913. // this is a new entry
  3914. pPp = new stPtrPair;
  3915. if( pPp != NULL )
  3916. {
  3917. pPp->pMainThing = key;
  3918. pPp->pRelatedThing = newValue;
  3919. AddTail(pPp);
  3920. }
  3921. else
  3922. {
  3923. ERROR_OUT( ("CPtrToPtrList: can't alloc stPtrPair") );
  3924. }
  3925. }
  3926. }// CPtrToPtrList::SetAt
  3927. BOOL
  3928. CPtrToPtrList::RemoveKey( void *key )
  3929. {
  3930. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::RemoveKey");
  3931. POSITION pos;
  3932. stPtrPair *pPp;
  3933. pPp = FindMainThingPair( key, &pos );
  3934. if( pPp != NULL )
  3935. {
  3936. RemoveAt( pos );
  3937. delete pPp;
  3938. return( TRUE );
  3939. }
  3940. else
  3941. return( FALSE );
  3942. }// CPtrToPtrList::RemoveKey
  3943. void
  3944. CPtrToPtrList::GetNextAssoc( POSITION &rNextPosition, void *&rKey, void *&rValue )
  3945. {
  3946. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::GetNextAssoc");
  3947. stPtrPair *pPp;
  3948. pPp = (stPtrPair *)GetNext( rNextPosition );
  3949. if( pPp != NULL )
  3950. {
  3951. rKey = pPp->pMainThing;
  3952. rValue = pPp->pRelatedThing;
  3953. }
  3954. else
  3955. {
  3956. rKey = NULL;
  3957. rValue = NULL;
  3958. }
  3959. }// CPtrToPtrList::GetNextAssoc
  3960. BOOL
  3961. CPtrToPtrList::Lookup( void *key, void *&rValue )
  3962. {
  3963. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::Lookup");
  3964. stPtrPair *pPp;
  3965. pPp = FindMainThingPair( key, NULL );
  3966. if( pPp != NULL )
  3967. {
  3968. rValue = pPp->pRelatedThing;
  3969. return( TRUE );
  3970. }
  3971. else
  3972. {
  3973. rValue = NULL;
  3974. return( FALSE );
  3975. }
  3976. }// CPtrToPtrList::Lookup
  3977. CPtrToPtrList::stPtrPair *
  3978. CPtrToPtrList::FindMainThingPair( void *pMainThing, POSITION *pPos )
  3979. {
  3980. MLZ_EntryOut(ZONE_FUNCTION, "CPtrToPtrList::FindMainThingPair");
  3981. POSITION pos;
  3982. POSITION lastpos;
  3983. stPtrPair *pPp;
  3984. if( pPos != NULL )
  3985. *pPos = NULL;
  3986. // look for pair containing pMainThing
  3987. pos = GetHeadPosition();
  3988. while( pos != NULL )
  3989. {
  3990. lastpos = pos;
  3991. pPp = (stPtrPair *)GetNext( pos );
  3992. if( pPp->pMainThing == pMainThing )
  3993. {
  3994. if( pPos != NULL )
  3995. *pPos = lastpos;
  3996. return( pPp );
  3997. }
  3998. }
  3999. // didn't find it
  4000. return( NULL );
  4001. }// CPtrToPtrList::FindMainThingPair
  4002. #define ARRAY_INCREMENT 0x200
  4003. DCDWordArray::DCDWordArray()
  4004. {
  4005. MLZ_EntryOut(ZONE_FUNCTION, "DCDWordArray::DCDWordArray");
  4006. m_Size = 0;
  4007. m_MaxSize = ARRAY_INCREMENT;
  4008. m_pData = new POINT[ARRAY_INCREMENT];
  4009. if (!m_pData)
  4010. {
  4011. ERROR_OUT(("Failed to allocate m_pData POINT array"));
  4012. }
  4013. }
  4014. DCDWordArray::~DCDWordArray()
  4015. {
  4016. MLZ_EntryOut(ZONE_FUNCTION, "DCDWordArray::~DCDWordArray");
  4017. delete[] m_pData;
  4018. }
  4019. //
  4020. // We need to increase the size of the array
  4021. //
  4022. BOOL DCDWordArray::ReallocateArray(void)
  4023. {
  4024. POINT *pOldArray = m_pData;
  4025. m_pData = new POINT[m_MaxSize];
  4026. if(m_pData)
  4027. {
  4028. TRACE_DEBUG((">>>>>Increasing size of array to hold %d points", m_MaxSize));
  4029. // copy new data from old
  4030. memcpy( m_pData, pOldArray, (m_Size) * sizeof(POINT));
  4031. TRACE_DEBUG(("Deleting array of points %x", pOldArray));
  4032. delete[] pOldArray;
  4033. return TRUE;
  4034. }
  4035. else
  4036. {
  4037. ERROR_OUT(("Failed to allocate new POINT array of size %d", m_MaxSize));
  4038. m_pData = pOldArray;
  4039. return FALSE;
  4040. }
  4041. }
  4042. //
  4043. // Add a new point to the array
  4044. //
  4045. void DCDWordArray::Add(POINT point)
  4046. {
  4047. MLZ_EntryOut(ZONE_FUNCTION, "DCDWordArray::Add");
  4048. TRACE_DEBUG(("Adding point(%d,%d) at %d", point.x, point.y, m_Size));
  4049. TRACE_DEBUG(("Adding point at %x", &m_pData[m_Size]));
  4050. if(m_pData == NULL)
  4051. {
  4052. return;
  4053. }
  4054. m_pData[m_Size].x = point.x;
  4055. m_pData[m_Size].y = point.y;
  4056. m_Size++;
  4057. //
  4058. // if we want more points, we need to re allocate the array
  4059. //
  4060. if(m_Size == m_MaxSize)
  4061. {
  4062. m_MaxSize +=ARRAY_INCREMENT;
  4063. if(ReallocateArray() == FALSE)
  4064. {
  4065. m_Size--;
  4066. }
  4067. }
  4068. }
  4069. //
  4070. // Return the number of points in the array
  4071. //
  4072. UINT DCDWordArray::GetSize(void)
  4073. {
  4074. return m_Size;
  4075. }
  4076. //
  4077. // Sets the size of the array
  4078. //
  4079. void DCDWordArray::SetSize(UINT size)
  4080. {
  4081. int newSize;
  4082. //
  4083. // if we want more points, we need to re allocate the array
  4084. //
  4085. if (size > m_MaxSize)
  4086. {
  4087. m_MaxSize= ((size/ARRAY_INCREMENT)+1)*ARRAY_INCREMENT;
  4088. if(ReallocateArray() == FALSE)
  4089. {
  4090. return;
  4091. }
  4092. }
  4093. m_Size = size;
  4094. }
  4095.