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.

4675 lines
123 KiB

  1. //
  2. // DRAW.CPP
  3. // Main Drawing Window
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. static const TCHAR szDrawClassName[] = "WB_DRAW";
  10. //
  11. //
  12. // Function: Constructor
  13. //
  14. // Purpose: Initialize the drawing area object
  15. //
  16. //
  17. WbDrawingArea::WbDrawingArea(void)
  18. {
  19. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::WbDrawingArea");
  20. g_pDraw = this;
  21. m_hwnd = NULL;
  22. m_hDCWindow = NULL;
  23. m_hDCCached = NULL;
  24. m_originOffset.cx = 0;
  25. m_originOffset.cy = 0;
  26. m_posScroll.x = 0;
  27. m_posScroll.y = 0;
  28. // Show that the drawing area is not zoomed
  29. m_iZoomFactor = 1;
  30. m_iZoomOption = 1;
  31. // Show that the left mouse button is up
  32. m_bLButtonDown = FALSE;
  33. m_bIgnoreNextLClick = FALSE;
  34. m_bBusy = FALSE;
  35. m_bLocked = FALSE;
  36. m_HourGlass = FALSE;
  37. // Indicate that the cached zoom scroll position is invalid
  38. m_zoomRestoreScroll = FALSE;
  39. // Show that we are not currently editing text
  40. m_bGotCaret = FALSE;
  41. m_bTextEditorActive = FALSE;
  42. m_pActiveText = NULL;
  43. // Show that no graphic object is in progress
  44. m_pGraphicTracker = NULL;
  45. // Show that the marker is not present.
  46. m_bMarkerPresent = FALSE;
  47. m_bNewMarkedGraphic = FALSE;
  48. m_pSelectedGraphic = NULL;
  49. m_bTrackingSelectRect = FALSE;
  50. // Show that no area is currently marked
  51. ::SetRectEmpty(&m_rcMarkedArea);
  52. // Show we haven't got a tool yet
  53. m_pToolCur = NULL;
  54. // Show that we dont have a page attached yet
  55. m_hPage = WB_PAGE_HANDLE_NULL;
  56. m_hStartPaintGraphic = NULL;
  57. m_pMarker = new DCWbGraphicMarker;
  58. if (!m_pMarker)
  59. {
  60. ERROR_OUT(("Failed to create m_pMarker in WbDrawingArea object constructor"));
  61. }
  62. }
  63. //
  64. //
  65. // Function: Destructor
  66. //
  67. // Purpose: Close down the drawing area
  68. //
  69. //
  70. WbDrawingArea::~WbDrawingArea(void)
  71. {
  72. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::~WbDrawingArea");
  73. if (m_pActiveText != NULL)
  74. {
  75. delete m_pActiveText;
  76. m_pActiveText = NULL;
  77. }
  78. if (m_hDCWindow != NULL)
  79. {
  80. ::ReleaseDC(m_hwnd, m_hDCWindow);
  81. m_hDCWindow = NULL;
  82. }
  83. m_hDCCached = NULL;
  84. if (m_pMarker != NULL)
  85. {
  86. delete m_pMarker;
  87. m_pMarker = NULL;
  88. }
  89. if (m_hwnd != NULL)
  90. {
  91. ::DestroyWindow(m_hwnd);
  92. ASSERT(m_hwnd == NULL);
  93. }
  94. ::UnregisterClass(szDrawClassName, g_hInstance);
  95. g_pDraw = NULL;
  96. //
  97. // Clean the pointer lists
  98. //
  99. m_allPointers.EmptyList();
  100. m_undrawnPointers.EmptyList();
  101. }
  102. //
  103. // WbDrawingArea::Create()
  104. //
  105. BOOL WbDrawingArea::Create(HWND hwndParent, LPCRECT lprect)
  106. {
  107. WNDCLASSEX wc;
  108. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Create");
  109. if (!m_pMarker)
  110. {
  111. ERROR_OUT(("Failing WbDrawingArea::Create; couldn't allocate m_pMarker"));
  112. return(FALSE);
  113. }
  114. // Get our cursor
  115. m_hCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( PENFREEHANDCURSOR));
  116. //
  117. // Register the window class
  118. //
  119. ZeroMemory(&wc, sizeof(wc));
  120. wc.cbSize = sizeof(wc);
  121. wc.style = CS_OWNDC;
  122. wc.lpfnWndProc = DrawWndProc;
  123. wc.hInstance = g_hInstance;
  124. wc.hCursor = m_hCursor;
  125. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  126. wc.lpszClassName = szDrawClassName;
  127. if (!::RegisterClassEx(&wc))
  128. {
  129. ERROR_OUT(("WbDraw::Create register class failed"));
  130. return(FALSE);
  131. }
  132. //
  133. // Create our window
  134. //
  135. ASSERT(m_hwnd == NULL);
  136. if (!::CreateWindowEx(WS_EX_CLIENTEDGE, szDrawClassName, NULL,
  137. WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER |
  138. WS_CLIPCHILDREN,
  139. lprect->left, lprect->top, lprect->right - lprect->left,
  140. lprect->bottom - lprect->top,
  141. hwndParent, NULL, g_hInstance, this))
  142. {
  143. ERROR_OUT(("Error creating drawing area window"));
  144. return(FALSE);
  145. }
  146. ASSERT(m_hwnd != NULL);
  147. //
  148. // Initialize remaining data members
  149. //
  150. ASSERT(!m_bBusy);
  151. ASSERT(!m_bLocked);
  152. ASSERT(!m_HourGlass);
  153. // Start and end points of the last drawing operation
  154. m_ptStart.x = m_originOffset.cx;
  155. m_ptStart.y = m_originOffset.cy;
  156. m_ptEnd = m_ptStart;
  157. // Set the width to be used for marker handles.
  158. ASSERT(m_pMarker);
  159. m_pMarker->SetPenWidth(DRAW_HANDLESIZE);
  160. // Get the zoom factor to be used
  161. m_iZoomOption = DRAW_ZOOMFACTOR;
  162. m_hDCWindow = ::GetDC(m_hwnd);
  163. m_hDCCached = m_hDCWindow;
  164. PrimeDC(m_hDCCached);
  165. ::SetWindowOrgEx(m_hDCCached, m_originOffset.cx, m_originOffset.cy, NULL);
  166. return(TRUE);
  167. }
  168. //
  169. // DrawWndProc()
  170. // Message handler for the drawing area
  171. //
  172. LRESULT CALLBACK DrawWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  173. {
  174. LRESULT lResult = 0;
  175. WbDrawingArea * pDraw = (WbDrawingArea *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  176. switch (message)
  177. {
  178. case WM_NCCREATE:
  179. pDraw = (WbDrawingArea *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  180. ASSERT(pDraw);
  181. pDraw->m_hwnd = hwnd;
  182. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pDraw);
  183. goto DefWndProc;
  184. break;
  185. case WM_NCDESTROY:
  186. ASSERT(pDraw);
  187. pDraw->m_hwnd = NULL;
  188. break;
  189. case WM_PAINT:
  190. ASSERT(pDraw);
  191. pDraw->OnPaint();
  192. break;
  193. case WM_MOUSEMOVE:
  194. ASSERT(pDraw);
  195. pDraw->OnMouseMove((UINT)wParam, LOWORD(lParam), HIWORD(lParam));
  196. break;
  197. case WM_LBUTTONDOWN:
  198. ASSERT(pDraw);
  199. pDraw->OnLButtonDown((UINT)wParam, LOWORD(lParam), HIWORD(lParam));
  200. break;
  201. case WM_LBUTTONUP:
  202. ASSERT(pDraw);
  203. pDraw->OnLButtonUp((UINT)wParam, LOWORD(lParam), HIWORD(lParam));
  204. break;
  205. case WM_CONTEXTMENU:
  206. ASSERT(pDraw);
  207. pDraw->OnContextMenu(LOWORD(lParam), HIWORD(lParam));
  208. break;
  209. case WM_SIZE:
  210. ASSERT(pDraw);
  211. pDraw->OnSize((UINT)wParam, LOWORD(lParam), HIWORD(lParam));
  212. break;
  213. case WM_HSCROLL:
  214. ASSERT(pDraw);
  215. pDraw->OnHScroll(GET_WM_HSCROLL_CODE(wParam, lParam),
  216. GET_WM_HSCROLL_POS(wParam, lParam));
  217. break;
  218. case WM_VSCROLL:
  219. ASSERT(pDraw);
  220. pDraw->OnVScroll(GET_WM_VSCROLL_CODE(wParam, lParam),
  221. GET_WM_VSCROLL_POS(wParam, lParam));
  222. break;
  223. case WM_CTLCOLOREDIT:
  224. ASSERT(pDraw);
  225. lResult = pDraw->OnEditColor((HDC)wParam);
  226. break;
  227. case WM_SETFOCUS:
  228. ASSERT(pDraw);
  229. pDraw->OnSetFocus();
  230. break;
  231. case WM_ACTIVATE:
  232. ASSERT(pDraw);
  233. pDraw->OnActivate(GET_WM_ACTIVATE_STATE(wParam, lParam));
  234. break;
  235. case WM_SETCURSOR:
  236. ASSERT(pDraw);
  237. lResult = pDraw->OnCursor((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  238. break;
  239. case WM_CANCELMODE:
  240. ASSERT(pDraw);
  241. pDraw->OnCancelMode();
  242. break;
  243. default:
  244. DefWndProc:
  245. lResult = DefWindowProc(hwnd, message, wParam, lParam);
  246. break;
  247. }
  248. return(lResult);
  249. }
  250. //
  251. //
  252. // Function: RealizePalette
  253. //
  254. // Purpose: Realize the drawing area palette
  255. //
  256. //
  257. void WbDrawingArea::RealizePalette( BOOL bBackground )
  258. {
  259. UINT entriesChanged;
  260. HDC hdc = m_hDCCached;
  261. if (m_hPage != WB_PAGE_HANDLE_NULL)
  262. {
  263. HPALETTE hPalette = PG_GetPalette();
  264. if (hPalette != NULL)
  265. {
  266. // get our 2cents in
  267. m_hOldPalette = ::SelectPalette(hdc, hPalette, bBackground);
  268. entriesChanged = ::RealizePalette(hdc);
  269. // if mapping changes go repaint
  270. if (entriesChanged > 0)
  271. ::InvalidateRect(m_hwnd, NULL, TRUE);
  272. }
  273. }
  274. }
  275. LRESULT WbDrawingArea::OnEditColor(HDC hdc)
  276. {
  277. HPALETTE hPalette = PG_GetPalette();
  278. if (hPalette != NULL)
  279. {
  280. ::SelectPalette(hdc, hPalette, FALSE);
  281. ::RealizePalette(hdc);
  282. }
  283. ::SetTextColor(hdc, SET_PALETTERGB( m_textEditor.m_clrPenColor ) );
  284. return((LRESULT)::GetSysColorBrush(COLOR_WINDOW));
  285. }
  286. //
  287. //
  288. // Function: OnPaint
  289. //
  290. // Purpose: Paint the window. This routine is called whenever Windows
  291. // issues a WM_PAINT message for the Whiteboard window.
  292. //
  293. //
  294. void WbDrawingArea::OnPaint(void)
  295. {
  296. RECT rcUpdate;
  297. RECT rcTmp;
  298. RECT rcBounds;
  299. HDC hSavedDC;
  300. HPEN hSavedPen;
  301. HBRUSH hSavedBrush;
  302. HPALETTE hSavedPalette;
  303. HPALETTE hPalette;
  304. HFONT hSavedFont;
  305. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnPaint");
  306. // Get the update rectangle
  307. ::GetUpdateRect(m_hwnd, &rcUpdate, FALSE);
  308. if (Zoomed())
  309. {
  310. ::InflateRect(&rcUpdate, 1, 1);
  311. InvalidateSurfaceRect(&rcUpdate);
  312. }
  313. // Can only do any painting if we have a valid page
  314. if (m_hPage != WB_PAGE_HANDLE_NULL)
  315. {
  316. // Determine whether any of the remote pointers are to be redrawn.
  317. // If they are they must be added to the update region to allow them
  318. // to redraw correctly. This is because they save the bits underneath
  319. // them and blit them back onto the screen as they are moved.
  320. if (m_allPointers.IsEmpty() == FALSE)
  321. {
  322. TRACE_MSG(("Remote pointer is dispayed"));
  323. POSITION pos = m_allPointers.GetHeadPosition();
  324. while (pos != NULL)
  325. {
  326. DCWbGraphicPointer* pPointer
  327. = (DCWbGraphicPointer*) m_allPointers.GetNext(pos);
  328. pPointer->GetBoundsRect(&rcBounds);
  329. if (::IntersectRect(&rcTmp, &rcBounds, &rcUpdate))
  330. {
  331. TRACE_MSG(("Invalidating remote pointer"));
  332. InvalidateSurfaceRect(&rcBounds);
  333. }
  334. }
  335. }
  336. }
  337. // Start painting
  338. PAINTSTRUCT ps;
  339. ::BeginPaint(m_hwnd, &ps);
  340. hSavedDC = m_hDCCached;
  341. hSavedFont = m_hOldFont;
  342. hSavedPen = m_hOldPen;
  343. hSavedBrush = m_hOldBrush;
  344. hSavedPalette = m_hOldPalette;
  345. TRACE_MSG(("Flipping cache to paint DC"));
  346. m_hDCCached = ps.hdc;
  347. PrimeDC(m_hDCCached);
  348. // Only draw anything if we have a valid page attached
  349. if (m_hPage != WB_PAGE_HANDLE_NULL)
  350. {
  351. // set palette
  352. hPalette = PG_GetPalette();
  353. if (hPalette != NULL)
  354. {
  355. m_hOldPalette = ::SelectPalette(m_hDCCached, hPalette, FALSE );
  356. ::RealizePalette(m_hDCCached);
  357. }
  358. //
  359. // Draw the graphic objects
  360. //
  361. DCWbGraphic* pGraphic;
  362. WB_GRAPHIC_HANDLE hStart;
  363. if( m_hStartPaintGraphic != NULL )
  364. {
  365. hStart = m_hStartPaintGraphic;
  366. m_hStartPaintGraphic = NULL;
  367. pGraphic = DCWbGraphic::ConstructGraphic(m_hPage, hStart);
  368. }
  369. else
  370. {
  371. pGraphic = PG_First(m_hPage, &hStart, &rcUpdate);
  372. }
  373. while (pGraphic != NULL)
  374. {
  375. ASSERT(pGraphic->Handle() == hStart);
  376. // Do not draw the active text graphic yet (it is drawn topmost)
  377. if (!m_bTextEditorActive || (hStart != m_textEditor.Handle()))
  378. {
  379. TRACE_MSG(("Drawing a normal graphic"));
  380. pGraphic->Draw(m_hDCCached, this);
  381. }
  382. // Release the current graphic
  383. delete pGraphic;
  384. // Get the next one
  385. pGraphic = PG_Next(m_hPage, &hStart, &rcUpdate);
  386. }
  387. //
  388. // Draw the marker
  389. //
  390. if (GraphicSelected() == TRUE)
  391. {
  392. TRACE_MSG(("Drawing the marker"));
  393. DrawMarker(m_hDCCached);
  394. }
  395. //
  396. // Draw the remote pointers that are on this page
  397. //
  398. if (m_allPointers.IsEmpty() == FALSE)
  399. {
  400. POSITION pos = m_allPointers.GetHeadPosition();
  401. while (pos != NULL)
  402. {
  403. DCWbGraphicPointer* pPointer
  404. = (DCWbGraphicPointer*) m_allPointers.GetNext(pos);
  405. pPointer->GetBoundsRect(&rcTmp);
  406. if (::IntersectRect(&rcTmp, &rcTmp, &rcUpdate))
  407. {
  408. TRACE_MSG(("Drawing remote pointer"));
  409. pPointer->DrawSave(m_hDCCached, this);
  410. }
  411. }
  412. }
  413. //
  414. // Draw the tracking graphic
  415. // But not if it is a remote pointer since this has already been done
  416. // above and Draw() is not the correct function to use for Rem Ptr
  417. //
  418. if ((m_pGraphicTracker != NULL) &&
  419. !EqualPoint(m_ptStart, m_ptEnd) &&
  420. !(m_pGraphicTracker->IsGraphicTool() == enumGraphicPointer))
  421. {
  422. TRACE_MSG(("Drawing the tracking graphic"));
  423. m_pGraphicTracker->Draw(m_hDCCached, this);
  424. }
  425. if (hPalette != NULL)
  426. {
  427. ::SelectPalette(m_hDCCached, m_hOldPalette, TRUE);
  428. }
  429. // fixes painting problems for bug 2185
  430. if( TextEditActive() )
  431. {
  432. RedrawTextEditbox();
  433. }
  434. }
  435. //
  436. // Restore the DC to its original state
  437. //
  438. UnPrimeDC(m_hDCCached);
  439. m_hOldFont = hSavedFont;
  440. m_hOldPen = hSavedPen;
  441. m_hOldBrush = hSavedBrush;
  442. m_hOldPalette = hSavedPalette;
  443. m_hDCCached = hSavedDC;
  444. // Finish painting
  445. ::EndPaint(m_hwnd, &ps);
  446. }
  447. //
  448. // Selects all graphic objs contained in rectSelect. If rectSelect is
  449. // NULL then ALL objs are selected
  450. //
  451. void WbDrawingArea::SelectMarkerFromRect(LPCRECT lprcSelect)
  452. {
  453. BOOL bSomethingWasPicked = FALSE;
  454. DCWbGraphic* pGraphic;
  455. WB_GRAPHIC_HANDLE hStart;
  456. RECT rc;
  457. if (g_pwbCore->WBP_PageCountGraphics(m_hPage) <= 0 )
  458. return;
  459. m_HourGlass = TRUE;
  460. SetCursorForState();
  461. RemoveMarker( NULL );
  462. pGraphic = PG_First(m_hPage, &hStart, lprcSelect, TRUE);
  463. while (pGraphic != NULL)
  464. {
  465. // add obj to marker list if its not locked - bug 2185
  466. pGraphic->GetBoundsRect(&rc);
  467. ASSERT(m_pMarker);
  468. if (m_pMarker->SetRect(&rc, pGraphic, FALSE))
  469. {
  470. m_pSelectedGraphic = pGraphic;
  471. bSomethingWasPicked = TRUE;
  472. }
  473. // Get the next one
  474. pGraphic = PG_Next(m_hPage, &hStart, lprcSelect, TRUE );
  475. }
  476. if( bSomethingWasPicked )
  477. PutMarker( NULL );
  478. m_HourGlass = FALSE;
  479. SetCursorForState();
  480. }
  481. //
  482. //
  483. // Function: OnTimer
  484. //
  485. // Purpose: Process a timer event. These are used to update freehand and
  486. // text objects while they are being drawn/edited and to
  487. // update the remote pointer position when the mouse stops.
  488. //
  489. //
  490. void WbDrawingArea::OnTimer(UINT idTimer)
  491. {
  492. TRACE_TIMER(("WbDrawingArea::OnTimer"));
  493. // We are only interested if the user is drawing something or editing
  494. if (m_bLButtonDown == TRUE)
  495. {
  496. // If the user is dragging an object or drawing a freehand line
  497. if (m_pGraphicTracker != NULL)
  498. {
  499. // If the user is drawing a freehand line
  500. if (m_pGraphicTracker->IsGraphicTool() == enumGraphicFreeHand)
  501. {
  502. // The update only writes the new version if changes have been made
  503. if (m_pGraphicTracker->Handle() == NULL)
  504. {
  505. m_pGraphicTracker->AddToPageLast(m_hPage);
  506. }
  507. else
  508. {
  509. m_pGraphicTracker->Replace();
  510. }
  511. }
  512. //
  513. // If the user is dragging a remote pointer (have to check
  514. // m_pGraphicTracker for NULL again in case OnLButtonUp was
  515. // called (bug 4685))
  516. //
  517. if ( m_pGraphicTracker != NULL )
  518. {
  519. if (m_pGraphicTracker->IsGraphicTool() == enumGraphicPointer)
  520. {
  521. // The update only writes the new version if changes have been made
  522. m_pGraphicTracker->Update();
  523. }
  524. }
  525. }
  526. }
  527. }
  528. //
  529. //
  530. // Function: OnSize
  531. //
  532. // Purpose: The window has been resized.
  533. //
  534. //
  535. void WbDrawingArea::OnSize(UINT nType, int cx, int cy)
  536. {
  537. // Only process this message if the window is not minimized
  538. if ( (nType == SIZEFULLSCREEN)
  539. || (nType == SIZENORMAL))
  540. {
  541. if (TextEditActive())
  542. {
  543. TextEditParentResize();
  544. }
  545. // Set the new scroll range (based on the new client area)
  546. SetScrollRange(cx, cy);
  547. // Ensure that the scroll position lies in the new scroll range
  548. ValidateScrollPos();
  549. // make page move if needed
  550. ScrollWorkspace();
  551. // Update the scroll bars
  552. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  553. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  554. }
  555. }
  556. //
  557. //
  558. // Function: SetScrollRange
  559. //
  560. // Purpose: Set the current scroll range. The range is based on the
  561. // work surface size and the size of the client area.
  562. //
  563. //
  564. void WbDrawingArea::SetScrollRange(int cx, int cy)
  565. {
  566. SCROLLINFO scinfo;
  567. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SetScrollRange");
  568. // If we are in zoom mode, then allow for the magnification
  569. ASSERT(m_iZoomFactor != 0);
  570. cx /= m_iZoomFactor;
  571. cy /= m_iZoomFactor;
  572. ZeroMemory( &scinfo, sizeof (SCROLLINFO) );
  573. scinfo.cbSize = sizeof (SCROLLINFO);
  574. scinfo.fMask = SIF_PAGE | SIF_RANGE|
  575. SIF_DISABLENOSCROLL;
  576. // Set the horizontal scroll range and proportional thumb size
  577. scinfo.nMin = 0;
  578. scinfo.nMax = DRAW_WIDTH - 1;
  579. scinfo.nPage = cx;
  580. ::SetScrollInfo(m_hwnd, SB_HORZ, &scinfo, FALSE);
  581. // Set the vertical scroll range and proportional thumb size
  582. scinfo.nMin = 0;
  583. scinfo.nMax = DRAW_HEIGHT - 1;
  584. scinfo.nPage = cy;
  585. ::SetScrollInfo(m_hwnd, SB_VERT, &scinfo, FALSE);
  586. }
  587. //
  588. //
  589. // Function: ValidateScrollPos
  590. //
  591. // Purpose: Ensure that the current scroll position is within the bounds
  592. // of the current scroll range. The scroll range is set to
  593. // ensure that the window on the worksurface never extends
  594. // beyond the surface boundaries.
  595. //
  596. //
  597. void WbDrawingArea::ValidateScrollPos()
  598. {
  599. int iMax;
  600. SCROLLINFO scinfo;
  601. // Validate the horixontal scroll position using proportional settings
  602. scinfo.cbSize = sizeof(scinfo);
  603. scinfo.fMask = SIF_ALL;
  604. ::GetScrollInfo(m_hwnd, SB_HORZ, &scinfo);
  605. iMax = scinfo.nMax - scinfo.nPage + 1;
  606. m_posScroll.x = max(m_posScroll.x, 0);
  607. m_posScroll.x = min(m_posScroll.x, iMax);
  608. // Validate the vertical scroll position using proportional settings
  609. scinfo.cbSize = sizeof(scinfo);
  610. scinfo.fMask = SIF_ALL;
  611. ::GetScrollInfo(m_hwnd, SB_VERT, &scinfo);
  612. iMax = scinfo.nMax - scinfo.nPage + 1;
  613. m_posScroll.y = max(m_posScroll.y, 0);
  614. m_posScroll.y = min(m_posScroll.y, iMax);
  615. }
  616. //
  617. //
  618. // Function: ScrollWorkspace
  619. //
  620. // Purpose: Scroll the workspace to the position set in the member
  621. // variable m_posScroll.
  622. //
  623. //
  624. void WbDrawingArea::ScrollWorkspace(void)
  625. {
  626. RECT rc;
  627. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::ScrollWorkspace");
  628. //
  629. // Determine whether any of the remote pointers are to be redrawn. If
  630. // they are they must be added to the update region to allow them to
  631. // redraw correctly. This is because they save the bits underneath them
  632. // and blit them back onto the screen as they are moved.
  633. //
  634. if (!m_allPointers.IsEmpty())
  635. {
  636. TRACE_MSG(("Remote pointer is dispayed - invalidate before scroll"));
  637. POSITION pos = m_allPointers.GetHeadPosition();
  638. while (pos != NULL)
  639. {
  640. DCWbGraphicPointer* pPointer
  641. = (DCWbGraphicPointer*) m_allPointers.GetNext(pos);
  642. TRACE_MSG(("Invalidating remote pointer"));
  643. pPointer->GetBoundsRect(&rc);
  644. InvalidateSurfaceRect(&rc);
  645. }
  646. }
  647. // Do the scroll
  648. DoScrollWorkspace();
  649. // Tell the parent that the scroll position has changed
  650. HWND hwndParent;
  651. hwndParent = ::GetParent(m_hwnd);
  652. if (hwndParent != NULL)
  653. {
  654. ::PostMessage(hwndParent, WM_USER_PRIVATE_PARENTNOTIFY, WM_VSCROLL, 0L);
  655. }
  656. }
  657. //
  658. //
  659. // Function: DoScrollWorkspace
  660. //
  661. // Purpose: Scroll the workspace to the position set in the member
  662. // variable m_posScroll.
  663. //
  664. //
  665. void WbDrawingArea::DoScrollWorkspace()
  666. {
  667. // Validate the scroll position
  668. ValidateScrollPos();
  669. // Set the scroll box position
  670. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  671. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  672. // Only update the screen if the scroll position has changed
  673. if ( (m_originOffset.cy != m_posScroll.y)
  674. || (m_originOffset.cx != m_posScroll.x) )
  675. {
  676. // Calculate the amount to scroll
  677. INT iVScrollAmount = m_originOffset.cy - m_posScroll.y;
  678. INT iHScrollAmount = m_originOffset.cx - m_posScroll.x;
  679. // Save the new position (for UpdateWindow)
  680. m_originOffset.cx = m_posScroll.x;
  681. m_originOffset.cy = m_posScroll.y;
  682. ::SetWindowOrgEx(m_hDCCached, m_originOffset.cx, m_originOffset.cy, NULL);
  683. // Scroll and redraw the newly invalidated portion of the window
  684. ::ScrollWindow(m_hwnd, iHScrollAmount, iVScrollAmount, NULL, NULL);
  685. ::UpdateWindow(m_hwnd);
  686. }
  687. }
  688. //
  689. //
  690. // Function: GotoPosition
  691. //
  692. // Purpose: Move the top-left corner of the workspace to the specified
  693. // position in the workspace.
  694. //
  695. //
  696. void WbDrawingArea::GotoPosition(int x, int y)
  697. {
  698. // Set the new scroll position
  699. m_posScroll.x = x;
  700. m_posScroll.y = y;
  701. // Scroll to the new position
  702. DoScrollWorkspace();
  703. // Invalidate the zoom scroll cache if we scroll when unzoomed.
  704. if (!Zoomed())
  705. {
  706. m_zoomRestoreScroll = FALSE;
  707. }
  708. }
  709. //
  710. //
  711. // Function: OnVScroll
  712. //
  713. // Purpose: Process a WM_VSCROLL messages.
  714. //
  715. //
  716. void WbDrawingArea::OnVScroll(UINT nSBCode, UINT nPos)
  717. {
  718. RECT rcClient;
  719. // Get the current client rectangle HEIGHT
  720. ::GetClientRect(m_hwnd, &rcClient);
  721. ASSERT(rcClient.top == 0);
  722. rcClient.bottom -= rcClient.top;
  723. // Act on the scroll code
  724. switch(nSBCode)
  725. {
  726. // Scroll to bottom
  727. case SB_BOTTOM:
  728. m_posScroll.y = DRAW_HEIGHT - rcClient.bottom;
  729. break;
  730. // Scroll down a line
  731. case SB_LINEDOWN:
  732. m_posScroll.y += DRAW_LINEVSCROLL;
  733. break;
  734. // Scroll up a line
  735. case SB_LINEUP:
  736. m_posScroll.y -= DRAW_LINEVSCROLL;
  737. break;
  738. // Scroll down a page
  739. case SB_PAGEDOWN:
  740. m_posScroll.y += rcClient.bottom / m_iZoomFactor;
  741. break;
  742. // Scroll up a page
  743. case SB_PAGEUP:
  744. m_posScroll.y -= rcClient.bottom / m_iZoomFactor;
  745. break;
  746. // Scroll to the top
  747. case SB_TOP:
  748. m_posScroll.y = 0;
  749. break;
  750. // Track the scroll box
  751. case SB_THUMBPOSITION:
  752. case SB_THUMBTRACK:
  753. m_posScroll.y = nPos; // don't round
  754. break;
  755. default:
  756. break;
  757. }
  758. // Validate the scroll position
  759. ValidateScrollPos();
  760. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  761. // If this message is informing us of the end of scrolling,
  762. // update the window
  763. if (nSBCode == SB_ENDSCROLL)
  764. {
  765. // Scroll the window
  766. ScrollWorkspace();
  767. }
  768. // Invalidate the zoom scroll cache if we scroll when unzoomed.
  769. if (!Zoomed())
  770. {
  771. m_zoomRestoreScroll = FALSE;
  772. }
  773. }
  774. //
  775. //
  776. // Function: OnHScroll
  777. //
  778. // Purpose: Process a WM_HSCROLL messages.
  779. //
  780. //
  781. void WbDrawingArea::OnHScroll(UINT nSBCode, UINT nPos)
  782. {
  783. RECT rcClient;
  784. // Get the current client rectangle WIDTH
  785. ::GetClientRect(m_hwnd, &rcClient);
  786. ASSERT(rcClient.left == 0);
  787. rcClient.right -= rcClient.left;
  788. switch(nSBCode)
  789. {
  790. // Scroll to the far right
  791. case SB_BOTTOM:
  792. m_posScroll.x = DRAW_WIDTH - rcClient.right;
  793. break;
  794. // Scroll right a line
  795. case SB_LINEDOWN:
  796. m_posScroll.x += DRAW_LINEHSCROLL;
  797. break;
  798. // Scroll left a line
  799. case SB_LINEUP:
  800. m_posScroll.x -= DRAW_LINEHSCROLL;
  801. break;
  802. // Scroll right a page
  803. case SB_PAGEDOWN:
  804. m_posScroll.x += rcClient.right / m_iZoomFactor;
  805. break;
  806. // Scroll left a page
  807. case SB_PAGEUP:
  808. m_posScroll.x -= rcClient.right / m_iZoomFactor;
  809. break;
  810. // Scroll to the far left
  811. case SB_TOP:
  812. m_posScroll.x = 0;
  813. break;
  814. // Track the scroll box
  815. case SB_THUMBPOSITION:
  816. case SB_THUMBTRACK:
  817. m_posScroll.x = nPos; // don't round
  818. break;
  819. default:
  820. break;
  821. }
  822. // Validate the scroll position
  823. ValidateScrollPos();
  824. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  825. // If this message is informing us of the end of scrolling,
  826. // update the window
  827. if (nSBCode == SB_ENDSCROLL)
  828. {
  829. // Scroll the window
  830. ScrollWorkspace();
  831. }
  832. // Invalidate the zoom scroll cache if we scroll when unzoomed.
  833. if (!Zoomed())
  834. {
  835. m_zoomRestoreScroll = FALSE;
  836. }
  837. }
  838. //
  839. //
  840. // Function: AutoScroll
  841. //
  842. // Purpose: Auto-scroll the window to bring the position passed as
  843. // parameter into view.
  844. //
  845. //
  846. BOOL WbDrawingArea::AutoScroll
  847. (
  848. int xSurface,
  849. int ySurface,
  850. BOOL bMoveCursor,
  851. int xCaret,
  852. int yCaret
  853. )
  854. {
  855. int nXPSlop, nYPSlop;
  856. int nXMSlop, nYMSlop;
  857. int nDeltaHScroll, nDeltaVScroll;
  858. BOOL bDoScroll = FALSE;
  859. nXPSlop = 0;
  860. nYPSlop = 0;
  861. nXMSlop = 0;
  862. nYMSlop = 0;
  863. if( TextEditActive() )
  864. {
  865. POINT ptDirTest;
  866. ptDirTest.x = xSurface - xCaret;
  867. ptDirTest.y = ySurface - yCaret;
  868. // set up for text editbox
  869. if( ptDirTest.x > 0 )
  870. nXPSlop = m_textEditor.m_textMetrics.tmMaxCharWidth;
  871. else
  872. if( ptDirTest.x < 0 )
  873. nXMSlop = -m_textEditor.m_textMetrics.tmMaxCharWidth;
  874. if( ptDirTest.y > 0 )
  875. nYPSlop = m_textEditor.m_textMetrics.tmHeight;
  876. else
  877. if( ptDirTest.y < 0 )
  878. nYMSlop = -m_textEditor.m_textMetrics.tmHeight;
  879. nDeltaHScroll = m_textEditor.m_textMetrics.tmMaxCharWidth;
  880. nDeltaVScroll = m_textEditor.m_textMetrics.tmHeight;
  881. }
  882. else
  883. {
  884. // set up for all other objects
  885. nDeltaHScroll = DRAW_LINEHSCROLL;
  886. nDeltaVScroll = DRAW_LINEVSCROLL;
  887. }
  888. // Get the current visible surface rectangle
  889. RECT visibleRect;
  890. GetVisibleRect(&visibleRect);
  891. // Check for pos + slop being outside visible area
  892. if( (xSurface + nXPSlop) >= visibleRect.right )
  893. {
  894. bDoScroll = TRUE;
  895. m_posScroll.x +=
  896. (((xSurface + nXPSlop) - visibleRect.right) + nDeltaHScroll);
  897. }
  898. if( (xSurface + nXMSlop) < visibleRect.left )
  899. {
  900. bDoScroll = TRUE;
  901. m_posScroll.x -=
  902. ((visibleRect.left - (xSurface + nXMSlop)) + nDeltaHScroll);
  903. }
  904. if( (ySurface + nYPSlop) >= visibleRect.bottom)
  905. {
  906. bDoScroll = TRUE;
  907. m_posScroll.y +=
  908. (((ySurface + nYPSlop) - visibleRect.bottom) + nDeltaVScroll);
  909. }
  910. if( (ySurface + nYMSlop) < visibleRect.top)
  911. {
  912. bDoScroll = TRUE;
  913. m_posScroll.y -=
  914. ((visibleRect.top - (ySurface + nYMSlop)) + nDeltaVScroll);
  915. }
  916. if( !bDoScroll )
  917. return( FALSE );
  918. // Indicate that scrolling has completed (in both directions)
  919. ScrollWorkspace();
  920. // Update the mouse position (if required)
  921. if (bMoveCursor)
  922. {
  923. POINT screenPos;
  924. screenPos.x = xSurface;
  925. screenPos.y = ySurface;
  926. SurfaceToClient(&screenPos);
  927. ::ClientToScreen(m_hwnd, &screenPos);
  928. ::SetCursorPos(screenPos.x, screenPos.y);
  929. }
  930. return( TRUE );
  931. }
  932. //
  933. //
  934. // Function: OnCursor
  935. //
  936. // Purpose: Process a WM_SETCURSOR messages.
  937. //
  938. //
  939. LRESULT WbDrawingArea::OnCursor(HWND hwnd, UINT uiHit, UINT uMsg)
  940. {
  941. BOOL bResult = FALSE;
  942. // Check that this message is for the main window
  943. if (hwnd == m_hwnd)
  944. {
  945. // If the cursor is now in the client area, set the cursor
  946. if (uiHit == HTCLIENT)
  947. {
  948. bResult = SetCursorForState();
  949. }
  950. else
  951. {
  952. // Restore the cursor to the standard arrow. Set m_hCursor to NULL
  953. // to indicate that we have not set a special cursor.
  954. m_hCursor = NULL;
  955. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  956. bResult = TRUE;
  957. }
  958. }
  959. // Return result indicating whether we processed the message or not
  960. return bResult;
  961. }
  962. //
  963. //
  964. // Function: SetCursorForState
  965. //
  966. // Purpose: Set the cursor for the current state
  967. //
  968. //
  969. BOOL WbDrawingArea::SetCursorForState(void)
  970. {
  971. BOOL bResult = FALSE;
  972. m_hCursor = NULL;
  973. // If the drawing area is locked, use the "locked" cursor
  974. if (m_HourGlass)
  975. {
  976. m_hCursor = ::LoadCursor( NULL, IDC_WAIT );
  977. }
  978. else if (m_bLocked)
  979. {
  980. // Return the cursor for the tool
  981. m_hCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( LOCKCURSOR ));
  982. }
  983. else if (m_pToolCur != NULL)
  984. {
  985. // Get the cursor for the tool currently in use
  986. m_hCursor = m_pToolCur->GetCursorForTool();
  987. }
  988. if (m_hCursor != NULL)
  989. {
  990. ::SetCursor(m_hCursor);
  991. bResult = TRUE;
  992. }
  993. // Return result indicating whether we set the cursor or not
  994. return bResult;
  995. }
  996. //
  997. //
  998. // Function: Lock
  999. //
  1000. // Purpose: Lock the drawing area, preventing further updates
  1001. //
  1002. //
  1003. void WbDrawingArea::Lock(void)
  1004. {
  1005. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Lock");
  1006. // Check whether the drawing area is busy - this is not allowed
  1007. ASSERT(!m_bBusy);
  1008. // Stop any drawing we are doing.
  1009. CancelDrawingMode();
  1010. // Deselect any selected graphic
  1011. ClearSelection();
  1012. // Show that we are now locked
  1013. m_bLocked = TRUE;
  1014. TRACE_MSG(("Drawing area is now locked"));
  1015. // Set the cursor for the drawing mode, but only if we should be drawing
  1016. // a special cursor (if m_hCursor != the current cursor, then the cursor
  1017. // is out of the client area).
  1018. if (::GetCursor() == m_hCursor)
  1019. {
  1020. SetCursorForState();
  1021. }
  1022. }
  1023. //
  1024. //
  1025. // Function: Unlock
  1026. //
  1027. // Purpose: Unlock the drawing area, preventing further updates
  1028. //
  1029. //
  1030. void WbDrawingArea::Unlock(void)
  1031. {
  1032. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Unlock");
  1033. // Check whether the drawing area is busy - this is not allowed
  1034. ASSERT(!m_bBusy);
  1035. // Show that we are now unlocked
  1036. m_bLocked = FALSE;
  1037. TRACE_MSG(("Drawing area is now UNlocked"));
  1038. // Set the cursor for the drawing mode, but only if we should be drawing
  1039. // a special cursor (if m_hCursor != the current cursor, then the cursor
  1040. // is out of the client area).
  1041. if (::GetCursor() == m_hCursor)
  1042. {
  1043. SetCursorForState();
  1044. }
  1045. }
  1046. //
  1047. //
  1048. // Function: GraphicAdded
  1049. //
  1050. // Purpose: A graphic has been added to the page - update the drawing
  1051. // area.
  1052. //
  1053. //
  1054. void WbDrawingArea::GraphicAdded(DCWbGraphic* pAddedGraphic)
  1055. {
  1056. HPALETTE hPal;
  1057. HPALETTE hOldPal = NULL;
  1058. HDC hDC;
  1059. RECT rcUpdate;
  1060. RECT rcBounds;
  1061. RECT rcT;
  1062. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::GraphicAdded");
  1063. // Check whether the drawing area is busy - this is not allowed
  1064. ASSERT(!m_bBusy);
  1065. // Get the current update rectangle
  1066. ::GetUpdateRect(m_hwnd, &rcUpdate, FALSE);
  1067. // Check if the object is the uppermost in the page,
  1068. // if it is we can draw it onto the window without
  1069. // playing the whole contents of the page.
  1070. // (If there the invalid part of the window touches the rectangle of
  1071. // the graphic which has just been added, we just invalidate the area
  1072. // occupied by the new graphic to get it drawn.)
  1073. pAddedGraphic->GetBoundsRect(&rcBounds);
  1074. if ((pAddedGraphic->IsTopmost()) &&
  1075. !::IntersectRect(&rcT, &rcUpdate, &rcBounds))
  1076. {
  1077. // Get a device context for drawing
  1078. hDC = m_hDCCached;
  1079. // set up palette
  1080. if ( (m_hPage != WB_PAGE_HANDLE_NULL) && ((hPal = PG_GetPalette()) != NULL) )
  1081. {
  1082. hOldPal = ::SelectPalette(hDC, hPal, FALSE);
  1083. ::RealizePalette(hDC);
  1084. }
  1085. // Remove the remote pointers from the affected area
  1086. RemovePointers(hDC, &rcBounds);
  1087. // Remove the marker and save whether it is to be restored later
  1088. BOOL bSaveMarkerPresent = m_bMarkerPresent;
  1089. RemoveMarker(NULL);
  1090. // Play the new graphic into the context
  1091. pAddedGraphic->Draw(hDC);
  1092. // Restore the marker (if necessary)
  1093. if (bSaveMarkerPresent == TRUE)
  1094. {
  1095. PutMarker(NULL);
  1096. }
  1097. // Restore the remote pointers
  1098. PutPointers(hDC);
  1099. // If we are editting some text, make editbox redraw
  1100. if (m_bTextEditorActive && (m_textEditor.Handle() != NULL))
  1101. {
  1102. RECT rcText;
  1103. m_textEditor.GetBoundsRect(&rcText);
  1104. // Include the client border
  1105. InflateRect(&rcText, ::GetSystemMetrics(SM_CXEDGE),
  1106. ::GetSystemMetrics(SM_CYEDGE));
  1107. InvalidateSurfaceRect(&rcText);
  1108. }
  1109. if (hOldPal != NULL)
  1110. {
  1111. ::SelectPalette(hDC, hOldPal, TRUE);
  1112. }
  1113. }
  1114. else
  1115. {
  1116. // Update the area occupied by the object
  1117. InvalidateSurfaceRect(&rcBounds);
  1118. }
  1119. }
  1120. //
  1121. //
  1122. // Function: PointerUpdated
  1123. //
  1124. // Purpose: A remote pointer has been added, removed or updated - make
  1125. // the change on the screen.
  1126. //
  1127. //
  1128. void WbDrawingArea::PointerUpdated
  1129. (
  1130. DCWbGraphicPointer* pPointer,
  1131. BOOL bForcedRemove
  1132. )
  1133. {
  1134. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PointerUpdated");
  1135. ASSERT(pPointer != NULL);
  1136. // Check whether the drawing area is busy - this is not allowed
  1137. ASSERT(!m_bBusy);
  1138. // Determine whether the pointer has been added, removed, or just updated
  1139. DCWbGraphicPointer* pUndrawFrom = pPointer;
  1140. POSITION posBefore = m_allPointers.Lookup(pPointer);
  1141. POSITION posAfter = NULL;
  1142. if (posBefore == NULL)
  1143. {
  1144. // The pointer is not currently drawn
  1145. // Check whether the pointer is active
  1146. if ((pPointer->IsActive()) && !bForcedRemove)
  1147. {
  1148. // Determine where the pointer should go on the drawn list
  1149. if ( (pPointer->IsLocalPointer())
  1150. || (m_allPointers.IsEmpty() == TRUE))
  1151. {
  1152. // The local pointer always goes at the end
  1153. posAfter = m_allPointers.AddTail(pPointer);
  1154. }
  1155. else
  1156. {
  1157. // Find the next active pointer on the page (we already
  1158. // know that allPointers is not empty from the test above).
  1159. posAfter = m_allPointers.GetTailPosition();
  1160. pUndrawFrom = (DCWbGraphicPointer*) m_allPointers.GetFromPosition(posAfter);
  1161. if (!pUndrawFrom->IsLocalPointer())
  1162. {
  1163. pUndrawFrom = PG_NextPointer(m_hPage, pPointer);
  1164. }
  1165. posAfter = m_allPointers.AddTail(pPointer);
  1166. }
  1167. }
  1168. }
  1169. else
  1170. {
  1171. // The pointer is already in our list
  1172. pUndrawFrom = pPointer;
  1173. }
  1174. // If we have something to do
  1175. if ((posBefore != NULL) || (posAfter != NULL))
  1176. {
  1177. if (pUndrawFrom != NULL)
  1178. {
  1179. // Undraw all pointers in the vicinity of the updated pointer
  1180. RECT rcT;
  1181. RECT rcBounds;
  1182. pPointer->GetDrawnRect(&rcT);
  1183. pPointer->GetBoundsRect(&rcBounds);
  1184. ::UnionRect(&rcT, &rcT, &rcBounds);
  1185. RemovePointers(NULL, pUndrawFrom, &rcT);
  1186. }
  1187. // If the updated pointer is no longer active we do not want
  1188. // to redraw it, and want to remove it from the active pointer
  1189. // list.
  1190. POSITION posUndrawn = m_undrawnPointers.Lookup(pPointer);
  1191. if ((pPointer->IsActive() == FALSE) || (bForcedRemove == TRUE))
  1192. {
  1193. // Remove it from the undrawn pointers list (so it does not
  1194. // get drawn again).
  1195. if (posUndrawn != NULL)
  1196. {
  1197. m_undrawnPointers.RemoveAt(posUndrawn);
  1198. }
  1199. // Remove it from the list of all active pointers on the page.
  1200. posUndrawn = m_allPointers.Lookup(pPointer);
  1201. if (posUndrawn != NULL)
  1202. {
  1203. m_allPointers.RemoveAt(posUndrawn);
  1204. }
  1205. }
  1206. else
  1207. {
  1208. // If this pointer was not previously active it will not
  1209. // be in the undrawn list and will therefore not get redrawn. So
  1210. // add it to the list to get it drawn. (It goes at the head of the
  1211. // list because we have undrawn all pointers above it.)
  1212. if (posUndrawn == NULL)
  1213. {
  1214. m_undrawnPointers.AddTail(pPointer);
  1215. }
  1216. }
  1217. // Restore all the remote pointers that were removed
  1218. PutPointers(NULL);
  1219. }
  1220. }
  1221. //
  1222. //
  1223. // Function: RemovePointers
  1224. //
  1225. // Purpose: Remove all remote pointers that are above and overlap
  1226. // the specified pointer.
  1227. //
  1228. //
  1229. void WbDrawingArea::RemovePointers
  1230. (
  1231. HDC hPassedDC,
  1232. DCWbGraphicPointer* pPointerUpdate
  1233. )
  1234. {
  1235. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::RemovePointers");
  1236. // Show that we have not removed any pointers yet
  1237. m_undrawnPointers.EmptyList();
  1238. // Do nothing if the pointer specified is NULL
  1239. if (pPointerUpdate != NULL)
  1240. {
  1241. RECT rcUpdate;
  1242. ::SetRectEmpty(&rcUpdate);
  1243. RemovePointers(hPassedDC, pPointerUpdate, &rcUpdate);
  1244. }
  1245. }
  1246. //
  1247. //
  1248. // Function: RemovePointers
  1249. //
  1250. // Purpose: Remove all remote pointers that overlap a rectangle on the
  1251. // surface.
  1252. //
  1253. //
  1254. void WbDrawingArea::RemovePointers
  1255. (
  1256. HDC hPassedDC,
  1257. LPCRECT lprc
  1258. )
  1259. {
  1260. RECT rcT;
  1261. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::RemovePointers");
  1262. // Show that we have not removed any pointers yet
  1263. m_undrawnPointers.EmptyList();
  1264. // Only do anything if the rectangle given is visible
  1265. GetVisibleRect(&rcT);
  1266. if (::IntersectRect(&rcT, &rcT, lprc))
  1267. {
  1268. RemovePointers(hPassedDC, NULL, lprc);
  1269. }
  1270. }
  1271. //
  1272. //
  1273. // Function: RemovePointers
  1274. //
  1275. // Purpose: Remove all remote pointers that overlap a rectangle on the
  1276. // surface.
  1277. //
  1278. //
  1279. void WbDrawingArea::RemovePointers
  1280. (
  1281. HDC hDC,
  1282. DCWbGraphicPointer* pPointerStart,
  1283. LPCRECT lprcOverlap
  1284. )
  1285. {
  1286. RECT rcT;
  1287. RECT rcT2;
  1288. RECT rcDrawn;
  1289. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::RemovePointers");
  1290. // Show that we have not removed any pointers yet
  1291. m_undrawnPointers.EmptyList();
  1292. // Get our own DC (if necessary)
  1293. if (!hDC)
  1294. hDC = m_hDCCached;
  1295. // We needn't do anything if the pointer and rectangles given
  1296. // are both off-screen.
  1297. GetVisibleRect(&rcT);
  1298. BOOL bNeedCheck = FALSE;
  1299. if (pPointerStart != NULL)
  1300. {
  1301. pPointerStart->GetDrawnRect(&rcT2);
  1302. if (::IntersectRect(&rcT2, &rcT2, &rcT))
  1303. {
  1304. bNeedCheck = TRUE;
  1305. }
  1306. }
  1307. // A NULL overlap rect means empty
  1308. if (::IntersectRect(&rcT, &rcT, lprcOverlap))
  1309. {
  1310. bNeedCheck = TRUE;
  1311. }
  1312. if (bNeedCheck)
  1313. {
  1314. // Get a list of all pointers on the page (with the local
  1315. // pointer last in the list).
  1316. POSITION allPos = m_allPointers.GetHeadPosition();
  1317. // We must undraw pointers in decreasing Z-order.
  1318. // With more than two pointers the effect of removing
  1319. // a pointer can require another pointer to be removed also:
  1320. // (pointer A overlaps pointer B, and B overlaps C without A and
  1321. // C overlapping each other directly). To get round this we build
  1322. // a list of pointers to be removed (and redrawn) as we go.
  1323. // If we are starting from a pointer
  1324. if (pPointerStart != NULL)
  1325. {
  1326. // Get the position of the start pointer
  1327. POSITION startPos = m_allPointers.Lookup(pPointerStart);
  1328. // If the pointer was not found, this is an error
  1329. ASSERT(startPos != NULL);
  1330. // Save the start position for the search
  1331. m_allPointers.GetNext(startPos);
  1332. allPos = startPos;
  1333. // Add the updated pointer to the remove list
  1334. m_undrawnPointers.AddTail(pPointerStart);
  1335. // If the rectangle passed in is empty, set it to the rectangle
  1336. // of the pointer passed in.
  1337. if (::IsRectEmpty(lprcOverlap))
  1338. {
  1339. pPointerStart->GetDrawnRect(&rcDrawn);
  1340. lprcOverlap = &rcDrawn;
  1341. }
  1342. }
  1343. // For each pointer above the start, check whether it overlaps
  1344. // any pointer in the list already built, or the rectangle passed in.
  1345. DCWbGraphicPointer* pPointerCheck;
  1346. while (allPos != NULL)
  1347. {
  1348. // Get the pointer to be tested
  1349. pPointerCheck = (DCWbGraphicPointer*) m_allPointers.GetNext(allPos);
  1350. // Get the rectangle it is currently occupying on the surface
  1351. // Check for overlap with the passed rectangle
  1352. pPointerCheck->GetDrawnRect(&rcT2);
  1353. if (::IntersectRect(&rcT, &rcT2, lprcOverlap))
  1354. {
  1355. m_undrawnPointers.AddTail(pPointerCheck);
  1356. }
  1357. }
  1358. // Create a reversed list
  1359. CWBOBLIST worklist;
  1360. DCWbGraphicPointer* pPointer;
  1361. POSITION pos = m_undrawnPointers.GetHeadPosition();
  1362. while (pos != NULL)
  1363. {
  1364. pPointer = (DCWbGraphicPointer*) m_undrawnPointers.GetNext(pos);
  1365. worklist.AddHead(pPointer);
  1366. }
  1367. // Now remove the pointers, walking through the reverde list
  1368. pos = worklist.GetHeadPosition();
  1369. while (pos != NULL)
  1370. {
  1371. // Remove it
  1372. pPointer = (DCWbGraphicPointer*) worklist.GetNext(pos);
  1373. pPointer->Undraw(hDC, this);
  1374. }
  1375. worklist.EmptyList();
  1376. }
  1377. }
  1378. //
  1379. //
  1380. // Function: PutPointers
  1381. //
  1382. // Purpose: Draw all remote pointers in the pointer redraw list.
  1383. //
  1384. //
  1385. void WbDrawingArea::PutPointers
  1386. (
  1387. HDC hDC,
  1388. COBLIST* pUndrawList
  1389. )
  1390. {
  1391. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PutPointers");
  1392. if (!hDC)
  1393. hDC = m_hDCCached;
  1394. // Get the start position in the list for drawing
  1395. if (pUndrawList == NULL)
  1396. {
  1397. pUndrawList = &m_undrawnPointers;
  1398. }
  1399. // Do the redrawing
  1400. DCWbGraphicPointer* pPointer;
  1401. POSITION pos = pUndrawList->GetHeadPosition();
  1402. while (pos != NULL)
  1403. {
  1404. // Get the next pointer
  1405. pPointer = (DCWbGraphicPointer*) pUndrawList->GetNext(pos);
  1406. pPointer->Redraw(hDC, this);
  1407. }
  1408. }
  1409. //
  1410. //
  1411. // Function: PageCleared
  1412. //
  1413. // Purpose: The page has been cleared
  1414. //
  1415. //
  1416. void WbDrawingArea::PageCleared(void)
  1417. {
  1418. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PageCleared");
  1419. // Check whether the drawing area is busy - this is not allowed
  1420. ASSERT(!m_bBusy);
  1421. // Discard any text being edited
  1422. if (m_bTextEditorActive)
  1423. {
  1424. if (m_bLocked)
  1425. {
  1426. DeactivateTextEditor();
  1427. }
  1428. else
  1429. {
  1430. EndTextEntry(FALSE);
  1431. }
  1432. }
  1433. // Remove the copy of the marked graphic and the marker
  1434. ClearSelection();
  1435. // Invalidate the whole window
  1436. ::InvalidateRect(m_hwnd, NULL, TRUE);
  1437. }
  1438. //
  1439. //
  1440. // Function: GraphicDeleted
  1441. //
  1442. // Purpose: A graphic has been removed from the page - update the
  1443. // drawing area.
  1444. //
  1445. //
  1446. void WbDrawingArea::GraphicDeleted(DCWbGraphic* pDeletedGraphic)
  1447. {
  1448. DCWbGraphic* pDeletedMarker;
  1449. RECT rcBounds;
  1450. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::GraphicDeleted");
  1451. // Check whether the drawing area is busy - this is not allowed
  1452. ASSERT(!m_bBusy);
  1453. // Check whether the graphic being deleted is selected
  1454. ASSERT(m_pMarker);
  1455. if( GraphicSelected() &&
  1456. ((pDeletedMarker = m_pMarker->HasAMarker( pDeletedGraphic )) != NULL) )
  1457. {
  1458. // remove marker corresponding to the deleted graphic
  1459. delete pDeletedMarker;
  1460. // if deleted graphic was also the last selection, use prev selection
  1461. // (carefull...m_pSelectedGraphic is invalid now if this is true)
  1462. if( m_pSelectedGraphic == pDeletedMarker ) //only safe comparision
  1463. m_pSelectedGraphic = m_pMarker->LastMarker();
  1464. }
  1465. // Invalidate the area occupied by the object
  1466. pDeletedGraphic->GetBoundsRect(&rcBounds);
  1467. InvalidateSurfaceRect(&rcBounds);
  1468. }
  1469. //
  1470. //
  1471. // Function: GraphicUpdated
  1472. //
  1473. // Purpose: A graphic in the page has been updated - update the
  1474. // drawing area.
  1475. //
  1476. //
  1477. void WbDrawingArea::GraphicUpdated
  1478. (
  1479. DCWbGraphic* pUpdatedGraphic,
  1480. BOOL bUpdateMarker,
  1481. BOOL bErase
  1482. )
  1483. {
  1484. DCWbGraphic* pUpdatedMarker;
  1485. BOOL bWasEqual;
  1486. RECT rcBounds;
  1487. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::GraphicUpdated");
  1488. // Check whether the drawing area is busy - this is not allowed
  1489. ASSERT(!m_bBusy);
  1490. // If the graphic being updated is selected update marker status
  1491. ASSERT(m_pMarker);
  1492. if( bUpdateMarker && GraphicSelected() &&
  1493. ((pUpdatedMarker = m_pMarker->HasAMarker( pUpdatedGraphic )) != NULL) )
  1494. {
  1495. // must zap lock flag for old object to prevent UnLock loops
  1496. pUpdatedMarker->ClearLockFlag();
  1497. delete pUpdatedMarker;
  1498. // If the graphic is now locked deselect it
  1499. if (pUpdatedGraphic->Locked() == TRUE)
  1500. {
  1501. if( m_pSelectedGraphic == pUpdatedMarker ) //only safe comparision
  1502. m_pSelectedGraphic = m_pMarker->LastMarker();
  1503. }
  1504. else
  1505. {
  1506. // the graphic isn't locked, re-select it
  1507. bWasEqual = (m_pSelectedGraphic == pUpdatedMarker);
  1508. pUpdatedMarker = DCWbGraphic::ConstructGraphic(m_hPage, pUpdatedGraphic->Handle());
  1509. pUpdatedMarker->GetBoundsRect(&rcBounds);
  1510. m_pMarker->SetRect(&rcBounds, pUpdatedMarker, FALSE );
  1511. if( bWasEqual ) //only safe comparision
  1512. m_pSelectedGraphic = pUpdatedMarker;
  1513. }
  1514. }
  1515. if (TextEditActive() &&
  1516. (m_textEditor.Handle() == pUpdatedGraphic->Handle()) )
  1517. {
  1518. return; // skip update if object is currently being text edited
  1519. // (fix for bug 3059)
  1520. }
  1521. pUpdatedGraphic->GetBoundsRect(&rcBounds);
  1522. InvalidateSurfaceRect(&rcBounds, bErase);
  1523. }
  1524. //
  1525. //
  1526. // Function : GraphicFreehandUpdated
  1527. //
  1528. // Purpose : A freehand graphic has been updated
  1529. //
  1530. //
  1531. void WbDrawingArea::GraphicFreehandUpdated(DCWbGraphic* pGraphic)
  1532. {
  1533. HPALETTE hPal;
  1534. HPALETTE hOldPal = NULL;
  1535. RECT rc;
  1536. // Draw the object
  1537. HDC hDC = m_hDCCached;
  1538. if ((m_hPage != WB_PAGE_HANDLE_NULL) && ((hPal = PG_GetPalette()) != NULL) )
  1539. {
  1540. hOldPal = ::SelectPalette(hDC, hPal, FALSE );
  1541. ::RealizePalette(hDC);
  1542. }
  1543. // Remove the remote pointers from the affected area
  1544. pGraphic->GetBoundsRect(&rc);
  1545. RemovePointers(hDC, &rc);
  1546. // Play the new graphic into the context
  1547. pGraphic->Draw(hDC);
  1548. // Restore the remote pointers
  1549. PutPointers(hDC);
  1550. // Get the intersection of the graphic and any objects covering it - if
  1551. // there are any objects over the freehand object, we have to redraw them
  1552. PG_GetObscuringRect(m_hPage, pGraphic, &rc);
  1553. if (!::IsRectEmpty(&rc))
  1554. {
  1555. // The graphic is at least partially obscured - force an update
  1556. InvalidateSurfaceRect(&rc, TRUE);
  1557. }
  1558. if (hOldPal != NULL )
  1559. {
  1560. ::SelectPalette(hDC, hOldPal, TRUE);
  1561. }
  1562. }
  1563. //
  1564. //
  1565. // Function: InvalidateSurfaceRect
  1566. //
  1567. // Purpose: Invalidate the window rectangle corresponding to the given
  1568. // drawing surface rectangle.
  1569. //
  1570. //
  1571. void WbDrawingArea::InvalidateSurfaceRect(LPCRECT lprc, BOOL bErase)
  1572. {
  1573. RECT rc;
  1574. // Convert the surface co-ordinates to client window and invalidate
  1575. // the rectangle.
  1576. rc = *lprc;
  1577. SurfaceToClient(&rc);
  1578. ::InvalidateRect(m_hwnd, &rc, bErase);
  1579. }
  1580. //
  1581. //
  1582. // Function: UpdateRectangles
  1583. //
  1584. // Purpose: Updates have affected a region of the drawing area - force
  1585. // a redraw now.
  1586. //
  1587. //
  1588. void WbDrawingArea::UpdateRectangles
  1589. (
  1590. LPCRECT lprc1,
  1591. LPCRECT lprc2,
  1592. BOOL bRepaint
  1593. )
  1594. {
  1595. // Remove the marker and save whether it is to be restored later
  1596. BOOL bSaveMarkerPresent = m_bMarkerPresent;
  1597. RemoveMarker(NULL);
  1598. // Invalidate the bounding rectangles specifying that the background
  1599. // is to be erased when painted.
  1600. if (!::IsRectEmpty(lprc1))
  1601. {
  1602. InvalidateSurfaceRect(lprc1, bRepaint);
  1603. }
  1604. if (!::IsRectEmpty(lprc2))
  1605. {
  1606. InvalidateSurfaceRect(lprc2, bRepaint);
  1607. }
  1608. // Repaint the invalidated regions
  1609. ::UpdateWindow(m_hwnd);
  1610. // Restore the marker (if necessary)
  1611. if (bSaveMarkerPresent)
  1612. {
  1613. PutMarker(NULL);
  1614. }
  1615. }
  1616. //
  1617. //
  1618. // Function: PrimeFont
  1619. //
  1620. // Purpose: Insert the supplied font into our DC and return the
  1621. // text metrics
  1622. //
  1623. //
  1624. void WbDrawingArea::PrimeFont(HDC hDC, HFONT hFont, TEXTMETRIC* pTextMetrics)
  1625. {
  1626. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PrimeFont");
  1627. //
  1628. // temporarily unzoom to get the font that we want
  1629. //
  1630. if (Zoomed())
  1631. {
  1632. ::ScaleViewportExtEx(m_hDCCached, 1, m_iZoomFactor, 1, m_iZoomFactor, NULL);
  1633. }
  1634. HFONT hOldFont = SelectFont(hDC, hFont);
  1635. if (hOldFont == NULL)
  1636. {
  1637. WARNING_OUT(("Failed to select font into DC"));
  1638. }
  1639. if (pTextMetrics != NULL)
  1640. {
  1641. ::GetTextMetrics(hDC, pTextMetrics);
  1642. }
  1643. //
  1644. // restore the zoom state
  1645. //
  1646. if (Zoomed())
  1647. {
  1648. ::ScaleViewportExtEx(m_hDCCached, m_iZoomFactor, 1, m_iZoomFactor, 1, NULL);
  1649. }
  1650. }
  1651. //
  1652. //
  1653. // Function: UnPrimeFont
  1654. //
  1655. // Purpose: Remove the specified font from the DC and clear cache
  1656. // variable
  1657. //
  1658. //
  1659. void WbDrawingArea::UnPrimeFont(HDC hDC)
  1660. {
  1661. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::UnPrimeFont");
  1662. if (hDC != NULL)
  1663. {
  1664. SelectFont(hDC, ::GetStockObject(SYSTEM_FONT));
  1665. }
  1666. }
  1667. //
  1668. //
  1669. // Function: PrimeDC
  1670. //
  1671. // Purpose: Set up a DC for drawing
  1672. //
  1673. //
  1674. void WbDrawingArea::PrimeDC(HDC hDC)
  1675. {
  1676. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PrimeDC");
  1677. ::SetMapMode(hDC, MM_ANISOTROPIC);
  1678. ::SetBkMode(hDC, TRANSPARENT);
  1679. ::SetTextAlign(hDC, TA_LEFT | TA_TOP);
  1680. }
  1681. //
  1682. //
  1683. // Function: UnPrimeDC
  1684. //
  1685. // Purpose: Reset the DC to default state
  1686. //
  1687. //
  1688. void WbDrawingArea::UnPrimeDC(HDC hDC)
  1689. {
  1690. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::UnPrimeDC");
  1691. SelectPen(hDC, (HPEN)::GetStockObject(BLACK_PEN));
  1692. SelectBrush(hDC, (HBRUSH)::GetStockObject(BLACK_BRUSH));
  1693. UnPrimeFont(hDC);
  1694. }
  1695. //
  1696. // WbDrawingArea::OnContextMenu()
  1697. //
  1698. void WbDrawingArea::OnContextMenu(int xScreen, int yScreen)
  1699. {
  1700. POINT pt;
  1701. RECT rc;
  1702. pt.x = xScreen;
  1703. pt.y = yScreen;
  1704. ::ScreenToClient(m_hwnd, &pt);
  1705. ::GetClientRect(m_hwnd, &rc);
  1706. if (::PtInRect(&rc, pt))
  1707. {
  1708. // Complete drawing action, if any
  1709. OnLButtonUp(0, pt.x, pt.y);
  1710. // Ask main window to put up context menu
  1711. g_pMain->PopupContextMenu(pt.x, pt.y);
  1712. }
  1713. }
  1714. //
  1715. // WbDrawingArea::OnLButtonDown()
  1716. //
  1717. void WbDrawingArea::OnLButtonDown(UINT flags, int x, int y)
  1718. {
  1719. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnLButtonDown");
  1720. if( m_bIgnoreNextLClick )
  1721. {
  1722. TRACE_MSG( ("Ignoring WM_LBUTTONDOWN") );
  1723. return;
  1724. }
  1725. // Set the focus to this window. This is done to ensure that we trap
  1726. // the text edit keys and the delete key when they are used.
  1727. ::SetFocus(m_hwnd);
  1728. // Save the operation start point (and current end point)
  1729. // Adjust the mouse position to allow for the zoom factor
  1730. m_ptStart.x = x;
  1731. m_ptStart.y = y;
  1732. ClientToSurface(&m_ptStart);
  1733. m_ptEnd = m_ptStart;
  1734. // Show that the mouse button is now down
  1735. m_bLButtonDown = TRUE;
  1736. // Show that the drawing area is now busy
  1737. m_bBusy = TRUE;
  1738. // User's can drag their own remote pointer even if the drawing area
  1739. // is locked. So we check before the test for the lock.
  1740. if (m_pToolCur->ToolType() == TOOLTYPE_SELECT)
  1741. {
  1742. if (RemotePointerSelect(m_ptStart))
  1743. {
  1744. return;
  1745. }
  1746. }
  1747. // Only allow the action to take place if the drawing area is unlocked,
  1748. // and we have a valid tool
  1749. if (m_bLocked || (m_pToolCur == NULL))
  1750. {
  1751. // Tidy up the state and leave now
  1752. m_bLButtonDown = FALSE;
  1753. m_bBusy = FALSE;
  1754. return;
  1755. }
  1756. // Call the relevant initialization routine
  1757. if (m_pToolCur->ToolType() != TOOLTYPE_SELECT)
  1758. {
  1759. // dump selection if not select tool
  1760. ClearSelection();
  1761. }
  1762. switch (m_pToolCur->ToolType())
  1763. {
  1764. case TOOLTYPE_SELECT:
  1765. BeginSelectMode(m_ptStart);
  1766. break;
  1767. case TOOLTYPE_ERASER:
  1768. BeginDeleteMode(m_ptStart);
  1769. break;
  1770. case TOOLTYPE_TEXT:
  1771. break;
  1772. case TOOLTYPE_HIGHLIGHT:
  1773. case TOOLTYPE_PEN:
  1774. BeginFreehandMode(m_ptStart);
  1775. break;
  1776. case TOOLTYPE_LINE:
  1777. BeginLineMode(m_ptStart);
  1778. break;
  1779. case TOOLTYPE_BOX:
  1780. case TOOLTYPE_FILLEDBOX:
  1781. BeginRectangleMode(m_ptStart);
  1782. break;
  1783. case TOOLTYPE_ELLIPSE:
  1784. case TOOLTYPE_FILLEDELLIPSE:
  1785. BeginEllipseMode(m_ptStart);
  1786. break;
  1787. // Do nothing if we do not recognise the pen type
  1788. default:
  1789. ERROR_OUT(("Bad tool type"));
  1790. break;
  1791. }
  1792. // Clamp the cursor to the drawing window
  1793. RECT rcClient;
  1794. ::GetClientRect(m_hwnd, &rcClient);
  1795. ::MapWindowPoints(m_hwnd, NULL, (LPPOINT)&rcClient.left, 2);
  1796. ::InflateRect(&rcClient, 1, 1);
  1797. ::ClipCursor(&rcClient);
  1798. }
  1799. //
  1800. //
  1801. // Function: RemotePointerSelect
  1802. //
  1803. // Purpose: Check for the user clicking inside their own remote pointer.
  1804. //
  1805. //
  1806. BOOL WbDrawingArea::RemotePointerSelect
  1807. (
  1808. POINT surfacePos
  1809. )
  1810. {
  1811. BOOL bResult = FALSE;
  1812. DCWbGraphicPointer* pPointer;
  1813. // Check we have a valid page
  1814. if (m_hPage == WB_PAGE_HANDLE_NULL)
  1815. {
  1816. return(bResult);
  1817. }
  1818. // Assume we do not start dragging a graphic
  1819. m_pGraphicTracker = NULL;
  1820. // Check if we are clicking in the local user's pointer
  1821. pPointer = PG_LocalPointer(m_hPage);
  1822. if ( (pPointer != NULL)
  1823. && (pPointer->PointInBounds(surfacePos)))
  1824. {
  1825. // The user is clicking in their pointer
  1826. m_pGraphicTracker = pPointer;
  1827. // Save the current time (used to determine when to update
  1828. // the external remote pointer information).
  1829. m_dwTickCount = ::GetTickCount();
  1830. // Hide the mouse (helps prevent flicker)
  1831. ::ShowCursor(FALSE);
  1832. // Get all mouse input directed to the this window
  1833. ::SetCapture(m_hwnd);
  1834. // Start the timer for updating the pointer (this is only for updating
  1835. // the pointer position when the user stops moving the pointer but
  1836. // keeps the mouse button down).
  1837. ::SetTimer(m_hwnd, TIMER_GRAPHIC_UPDATE, DRAW_GRAPHICUPDATEDELAY, NULL);
  1838. // Show that we have selected a pointer
  1839. bResult = TRUE;
  1840. }
  1841. return(bResult);
  1842. }
  1843. //
  1844. //
  1845. // Function: SelectPreviousGraphicAt
  1846. //
  1847. // Purpose: Select the previous graphic (in the Z-order) at the position
  1848. // specified, and starting at a specified graphic. If the
  1849. // graphic pointer given is NULL the search starts from the
  1850. // top. If the point specified is outside the bounding
  1851. // rectangle of the specified graphic the search starts at the
  1852. // top and chooses the first graphic which contains the point.
  1853. //
  1854. // The search process will loop back to the top of the Z-order
  1855. // if it gets to the bottom having failed to find a graphic.
  1856. //
  1857. // Graphics which are locked are ignored by the search.
  1858. //
  1859. //
  1860. DCWbGraphic* WbDrawingArea::SelectPreviousGraphicAt
  1861. (
  1862. DCWbGraphic* pStartGraphic,
  1863. POINT point
  1864. )
  1865. {
  1866. // Set the result to "none found" initially
  1867. DCWbGraphic* pResultGraphic = NULL;
  1868. // If a starting point has been specified
  1869. if (pStartGraphic != NULL)
  1870. {
  1871. RECT rectHit;
  1872. MAKE_HIT_RECT(rectHit, point);
  1873. // If the reference point is within the start graphic
  1874. if ( pStartGraphic->PointInBounds(point) &&
  1875. pStartGraphic->CheckReallyHit( &rectHit ) )
  1876. {
  1877. // Start from the specified graphic
  1878. pResultGraphic = pStartGraphic;
  1879. // Look for the previous one (that is not locked)
  1880. do
  1881. {
  1882. pResultGraphic = PG_SelectPrevious(m_hPage, *pResultGraphic, point);
  1883. }
  1884. while ( (pResultGraphic != NULL)
  1885. && (pResultGraphic->Locked()));
  1886. }
  1887. else
  1888. {
  1889. // We are not looking within the currently selected graphic.
  1890. // Deselect the current one. The start pointer and handle are
  1891. // left at NULL.
  1892. ;
  1893. }
  1894. }
  1895. // If we have not got a result graphic yet. (This catches two cases:
  1896. // - where no start graphic has been given so that we want to start
  1897. // from the top,
  1898. // - where we have searched back from the start graphic and reached
  1899. // the bottom of the Z-order without finding a suitable graphic.
  1900. if (pResultGraphic == NULL)
  1901. {
  1902. // Get the topmost graphic that contains the point specified
  1903. pResultGraphic = PG_SelectLast(m_hPage, point);
  1904. // Ensure that we have not got a locked graphic
  1905. while ( (pResultGraphic != NULL)
  1906. && (pResultGraphic->Locked()))
  1907. {
  1908. pResultGraphic = PG_SelectPrevious(m_hPage, *pResultGraphic, point);
  1909. }
  1910. }
  1911. // If we have found an object, draw the marker
  1912. if (pResultGraphic != NULL)
  1913. {
  1914. // Select the new one
  1915. SelectGraphic(pResultGraphic);
  1916. }
  1917. return pResultGraphic;
  1918. }
  1919. //
  1920. //
  1921. // Function: BeginSelectMode
  1922. //
  1923. // Purpose: Process a mouse button down in select mode
  1924. //
  1925. //
  1926. void WbDrawingArea::BeginSelectMode(POINT surfacePos, BOOL bDontDrag )
  1927. {
  1928. RECT rc;
  1929. // Assume we do not start dragging a graphic
  1930. m_pGraphicTracker = NULL;
  1931. // Assume that we do not mark a new graphic
  1932. m_bNewMarkedGraphic = FALSE;
  1933. // turn off TRACK-SELECT-RECT
  1934. m_bTrackingSelectRect = FALSE;
  1935. // Check whether there is currently an object marked, and
  1936. // whether we are clicking inside the same object. If we are then
  1937. // we do nothing here - the click will be handled by the tracking or
  1938. // completion routines for select mode.
  1939. ASSERT(m_pMarker);
  1940. if ( (GraphicSelected() == FALSE)
  1941. || (m_pMarker->PointInBounds(surfacePos) == FALSE))
  1942. {
  1943. // We are selecting a new object if bDontDrag == FALSE, find it.
  1944. // otherwise just turn on the select rect
  1945. DCWbGraphic* pGraphic;
  1946. if( bDontDrag )
  1947. pGraphic = NULL;
  1948. else
  1949. pGraphic = SelectPreviousGraphicAt(NULL, surfacePos);
  1950. // If we have found an object, draw the marker
  1951. if (pGraphic != NULL)
  1952. {
  1953. // Show that a new graphic has now been marked.
  1954. m_bNewMarkedGraphic = TRUE;
  1955. }
  1956. else
  1957. {
  1958. if( (GetAsyncKeyState( VK_SHIFT ) >= 0) &&
  1959. (GetAsyncKeyState( VK_CONTROL ) >= 0) )
  1960. {
  1961. // clicked on dead air, remove all selections
  1962. ClearSelection();
  1963. }
  1964. //TRACK-SELECT-RECT
  1965. m_bTrackingSelectRect = TRUE;
  1966. BeginRectangleMode(surfacePos);
  1967. return;
  1968. }
  1969. }
  1970. // If we now have a selected graphic, and we are clicking inside it
  1971. if ( (GraphicSelected())
  1972. && (m_pMarker->PointInBounds(surfacePos)))
  1973. {
  1974. // Create a rectangle object for tracking the drag
  1975. DCWbGraphicSelectTrackingRectangle* pRectangle
  1976. = new DCWbGraphicSelectTrackingRectangle();
  1977. m_pSelectedGraphic->GetBoundsRect(&rc);
  1978. if (!pRectangle)
  1979. {
  1980. ERROR_OUT(("BeginSelectMode failed; couldn't create tracking rect object"));
  1981. }
  1982. else
  1983. {
  1984. pRectangle->SetRect(&rc);
  1985. pRectangle->SetColor(RGB(0, 0, 0));
  1986. pRectangle->SetPenWidth(1);
  1987. }
  1988. m_pGraphicTracker = pRectangle;
  1989. // We do not draw the tracking rectangle yet as the user has not yet
  1990. // dragged it anywhere. A single click within an object will then
  1991. // not cause a tracking rectangle to flash on the screen.
  1992. }
  1993. // Get all mouse input directed to the this window
  1994. ::SetCapture(m_hwnd);
  1995. }
  1996. void WbDrawingArea::BeginDeleteMode(POINT mousePos )
  1997. {
  1998. // turn off object dragging
  1999. BeginSelectMode( mousePos, TRUE );
  2000. }
  2001. //
  2002. //
  2003. // Function: BeginTextMode
  2004. //
  2005. // Purpose: Process a mouse button down in text mode
  2006. //
  2007. //
  2008. void WbDrawingArea::BeginTextMode(POINT surfacePos)
  2009. {
  2010. RECT rc;
  2011. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::BeginTextMode");
  2012. //
  2013. // Get a DC for passing into the text editor
  2014. //
  2015. HDC hDC = m_hDCCached;
  2016. // If we are already editing a text object, we just move the text cursor
  2017. if (m_bTextEditorActive)
  2018. {
  2019. // If the mouse has been clicked in the currently active object
  2020. // we just move the cursor within the object, otherwise we end the
  2021. // edit for the current object and move to a new one.
  2022. m_textEditor.GetBoundsRect(&rc);
  2023. if (::PtInRect(&rc, surfacePos))
  2024. {
  2025. // Set the new position for the cursor
  2026. m_textEditor.SetCursorPosFromPoint(surfacePos);
  2027. }
  2028. else
  2029. {
  2030. // Complete the text entry accepting the changes
  2031. EndTextEntry(TRUE);
  2032. // LAURABU BOGUS:
  2033. // It would be cooler to now return, that way you don't get
  2034. // another text object just cuz you ended the current editing
  2035. // session.
  2036. }
  2037. }
  2038. // If we are not editing an object we check to see whether there is
  2039. // a text object under the cursor or whether we must start a new one.
  2040. if (!m_bTextEditorActive)
  2041. {
  2042. // Check whether we are clicking over a text object. If we are
  2043. // start editing the object, otherwise we start a new text object.
  2044. // Look back through the Z-order for a text object
  2045. DCWbGraphic* pGraphic = PG_SelectLast(m_hPage, surfacePos);
  2046. DCWbGraphic* pNextGraphic = NULL;
  2047. while ( (pGraphic != NULL)
  2048. && (pGraphic->IsGraphicTool() != enumGraphicText))
  2049. {
  2050. // Get the next one
  2051. pNextGraphic = PG_SelectPrevious(m_hPage, *pGraphic, surfacePos);
  2052. // Release the previous graphic
  2053. delete pGraphic;
  2054. // Use the next one
  2055. pGraphic = pNextGraphic;
  2056. }
  2057. if (pGraphic != NULL)
  2058. {
  2059. // Check whether this graphic object is already being edited by
  2060. // another user in the call.
  2061. if (!pGraphic->Locked())
  2062. {
  2063. // We found a text object under the mouse pointer...
  2064. // ...edit it
  2065. m_pActiveText = (DCWbGraphicText*) pGraphic;
  2066. // Transfer the text from the object into the text editor
  2067. if (!m_textEditor.SetTextObject(m_pActiveText))
  2068. {
  2069. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  2070. return;
  2071. }
  2072. // Make sure the tool reflects the new information
  2073. if (m_pToolCur != NULL)
  2074. {
  2075. m_pToolCur->SelectGraphic(pGraphic);
  2076. }
  2077. HWND hwndParent = ::GetParent(m_hwnd);;
  2078. if (hwndParent != NULL)
  2079. {
  2080. ::PostMessage(hwndParent, WM_USER_UPDATE_ATTRIBUTES, 0, 0L);
  2081. }
  2082. // Lock the graphic to prevent other users editing it.
  2083. // (This is not currently a real lock but a flag in the object
  2084. // header. There is a window in which two users can start editing
  2085. // the same text object at the same time.)
  2086. m_textEditor.Lock();
  2087. m_textEditor.Update();
  2088. // Show that we are now gathering text but dont put up cursor
  2089. // yet. Causes cursor droppings later (bug 2505)
  2090. //ActivateTextEditor( FALSE );
  2091. ActivateTextEditor( TRUE );
  2092. // Set the initial cursor position for the edit
  2093. m_textEditor.SetCursorPosFromPoint(surfacePos);
  2094. // If this is not the topmost object we must redraw to get
  2095. // it to the top so it is visible for editing
  2096. if (PG_IsTopmost(m_hPage, m_pActiveText))
  2097. {
  2098. m_pActiveText->GetBoundsRect(&rc);
  2099. InvalidateSurfaceRect(&rc);
  2100. ::UpdateWindow(m_hwnd);
  2101. }
  2102. }
  2103. else
  2104. delete pGraphic;
  2105. }
  2106. else
  2107. {
  2108. // There are no text objects under the mouse pointer...
  2109. // ...start a new one
  2110. // Clear any old text out of the editor, and reset its graphic
  2111. // handle. This prevents us from replacing an old text object when
  2112. // we next save the text editor contents.
  2113. if (!m_textEditor.New())
  2114. {
  2115. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  2116. return;
  2117. }
  2118. // Lock the text editor to prevent other users editing the object.
  2119. // (The object will be added to the page when the update timer pops
  2120. // or when the user hits space or return.)
  2121. m_textEditor.Lock();
  2122. // Set the attributes of the text
  2123. m_textEditor.SetFont(m_pToolCur->GetFont());
  2124. m_textEditor.SetColor(m_pToolCur->GetColor());
  2125. m_textEditor.GraphicTool(m_pToolCur->ToolType());
  2126. // We need to reselect a font now into our DC
  2127. SelectFont(hDC, m_textEditor.GetFont());
  2128. // Set the position of the new object
  2129. SIZE sizeCursor;
  2130. m_textEditor.GetCursorSize(&sizeCursor);
  2131. m_textEditor.CalculateBoundsRect();
  2132. m_textEditor.MoveTo(m_ptEnd.x, m_ptEnd.y - sizeCursor.cy);
  2133. // We are not editing an active text object
  2134. ASSERT(m_pActiveText == NULL);
  2135. // Show that we are now gathering text
  2136. ActivateTextEditor( TRUE );
  2137. }
  2138. }
  2139. }
  2140. //
  2141. //
  2142. // Function: BeginFreehandMode
  2143. //
  2144. // Purpose: Process a mouse button down event in draw mode
  2145. //
  2146. //
  2147. void WbDrawingArea::BeginFreehandMode(POINT surfacePos)
  2148. {
  2149. // Tracking in draw mode is a special case. We draw directly to the client
  2150. // area of the window and create an object to record the points on the
  2151. // line that we are drawing.
  2152. m_pGraphicTracker = new DCWbGraphicFreehand();
  2153. if (!m_pGraphicTracker)
  2154. {
  2155. ERROR_OUT(("BeginFreehandMode failing; can't create graphic freehand object"));
  2156. }
  2157. else
  2158. {
  2159. ((DCWbGraphicFreehand*) m_pGraphicTracker)->AddPoint(surfacePos);
  2160. m_pGraphicTracker->SetColor(m_pToolCur->GetColor());
  2161. m_pGraphicTracker->SetPenWidth(m_pToolCur->GetWidth());
  2162. m_pGraphicTracker->SetROP(m_pToolCur->GetROP());
  2163. m_pGraphicTracker->GraphicTool(m_pToolCur->ToolType());
  2164. m_pGraphicTracker->Lock();
  2165. }
  2166. // Get all mouse input directed to the this window
  2167. ::SetCapture(m_hwnd);
  2168. // Start the timer for updating the graphic (this is only for updating
  2169. // the graphic when the user stops moving the pointer but keeps the
  2170. // mouse button down).
  2171. ::SetTimer(m_hwnd, TIMER_GRAPHIC_UPDATE, DRAW_GRAPHICUPDATEDELAY, NULL);
  2172. // Save the current time (used to determine when to update
  2173. // the external graphic pointer information while the mouse is
  2174. // being moved).
  2175. m_dwTickCount = ::GetTickCount();
  2176. }
  2177. //
  2178. //
  2179. // Function: BeginLineMode
  2180. //
  2181. // Purpose: Process a mouse button down event in line mode
  2182. //
  2183. //
  2184. void WbDrawingArea::BeginLineMode(POINT surfacePos)
  2185. {
  2186. // Get all mouse input directed to the this window
  2187. ::SetCapture(m_hwnd);
  2188. // Create the object to be used for tracking
  2189. DCWbGraphicTrackingLine* pGraphicLine = new DCWbGraphicTrackingLine();
  2190. if (!pGraphicLine)
  2191. {
  2192. ERROR_OUT(("BeginLineMode failing; can't create tracking line object"));
  2193. }
  2194. else
  2195. {
  2196. pGraphicLine->SetColor(m_pToolCur->GetColor());
  2197. pGraphicLine->SetPenWidth(1);
  2198. pGraphicLine->SetStart(surfacePos);
  2199. pGraphicLine->SetEnd(surfacePos);
  2200. }
  2201. m_pGraphicTracker = pGraphicLine;
  2202. }
  2203. //
  2204. //
  2205. // Function: BeginRectangleMode
  2206. //
  2207. // Purpose: Process a mouse button down event in box mode
  2208. //
  2209. //
  2210. void WbDrawingArea::BeginRectangleMode(POINT surfacePos)
  2211. {
  2212. // Get all mouse input directed to the this window
  2213. ::SetCapture(m_hwnd);
  2214. // Create the object to be used for tracking
  2215. DCWbGraphicTrackingRectangle* pGraphicRectangle
  2216. = new DCWbGraphicTrackingRectangle();
  2217. if (!pGraphicRectangle)
  2218. {
  2219. ERROR_OUT(("BeginRectangleMode failing; can't create tracking rect object"));
  2220. }
  2221. else
  2222. {
  2223. pGraphicRectangle->SetColor( CLRPANE_BLACK );
  2224. pGraphicRectangle->SetPenWidth(1);
  2225. pGraphicRectangle->SetRectPts(surfacePos, surfacePos);
  2226. }
  2227. m_pGraphicTracker = pGraphicRectangle;
  2228. }
  2229. //
  2230. //
  2231. // Function: BeginEllipseMode
  2232. //
  2233. // Purpose: Process a mouse button down event in ellipse mode
  2234. //
  2235. //
  2236. void WbDrawingArea::BeginEllipseMode(POINT surfacePos)
  2237. {
  2238. // Get all mouse input directed to the this window
  2239. ::SetCapture(m_hwnd);
  2240. // Create the object to be used for tracking
  2241. DCWbGraphicTrackingEllipse* pGraphicEllipse
  2242. = new DCWbGraphicTrackingEllipse();
  2243. if (!pGraphicEllipse)
  2244. {
  2245. ERROR_OUT(("BeginEllipseMode failing; can't create tracking ellipse object"));
  2246. }
  2247. else
  2248. {
  2249. pGraphicEllipse->SetColor(m_pToolCur->GetColor());
  2250. pGraphicEllipse->SetPenWidth(1);
  2251. pGraphicEllipse->SetRectPts(surfacePos, surfacePos);
  2252. }
  2253. m_pGraphicTracker = pGraphicEllipse;
  2254. }
  2255. //
  2256. // WbDrawingArea::OnMouseMove
  2257. //
  2258. void WbDrawingArea::OnMouseMove(UINT flags, int x, int y)
  2259. {
  2260. POINT surfacePos;
  2261. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnMouseMove");
  2262. surfacePos.x = x;
  2263. surfacePos.y = y;
  2264. // Check if the left mouse button is down
  2265. if (m_bLButtonDown)
  2266. {
  2267. // Calculate the worksurface position
  2268. // Adjust the mouse position to allow for the zoom factor
  2269. ClientToSurface(&surfacePos);
  2270. // Make sure the point is a valid surface position
  2271. MoveOntoSurface(&surfacePos);
  2272. // Check whether the window needs to be scrolled to get the
  2273. // current position into view.
  2274. AutoScroll(surfacePos.x, surfacePos.y, TRUE, 0, 0);
  2275. // Action taken depends on the tool type
  2276. switch(m_pToolCur->ToolType())
  2277. {
  2278. case TOOLTYPE_HIGHLIGHT:
  2279. case TOOLTYPE_PEN:
  2280. TrackFreehandMode(surfacePos);
  2281. break;
  2282. case TOOLTYPE_LINE:
  2283. TrackLineMode(surfacePos);
  2284. break;
  2285. case TOOLTYPE_BOX:
  2286. case TOOLTYPE_FILLEDBOX:
  2287. TrackRectangleMode(surfacePos);
  2288. break;
  2289. case TOOLTYPE_ELLIPSE:
  2290. case TOOLTYPE_FILLEDELLIPSE:
  2291. TrackEllipseMode(surfacePos);
  2292. break;
  2293. case TOOLTYPE_SELECT:
  2294. TrackSelectMode(surfacePos);
  2295. break;
  2296. case TOOLTYPE_ERASER:
  2297. TrackDeleteMode(surfacePos);
  2298. break;
  2299. case TOOLTYPE_TEXT:
  2300. break;
  2301. default:
  2302. ERROR_OUT(("Unknown tool type"));
  2303. break;
  2304. }
  2305. }
  2306. }
  2307. //
  2308. //
  2309. // Function: CancelDrawingMode
  2310. //
  2311. // Purpose: Cancels a drawing operation after an error.
  2312. //
  2313. //
  2314. void WbDrawingArea::CancelDrawingMode(void)
  2315. {
  2316. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::CancelDrawingMode");
  2317. //
  2318. // Quit if there's nothing to cancel.
  2319. //
  2320. if (!m_bBusy && !m_bTextEditorActive)
  2321. {
  2322. TRACE_DEBUG(("Drawing area not busy and text editor not active..."));
  2323. return;
  2324. }
  2325. // The drawing area is no longer busy
  2326. m_bBusy = FALSE;
  2327. //
  2328. // Redraw the object - we need to discard any local updates which we
  2329. // weren't able to write to the object we are editing. Ideally we should
  2330. // just invalidate the object itself but because some of the co-ordinates
  2331. // we have already drawn on the page may have been lost, we dont know
  2332. // exactly how big the object is.
  2333. //
  2334. ::InvalidateRect(m_hwnd, NULL, TRUE);
  2335. m_bLButtonDown = FALSE;
  2336. // Release the mouse capture
  2337. if (::GetCapture() == m_hwnd)
  2338. {
  2339. ::ReleaseCapture();
  2340. }
  2341. //
  2342. // Perform any tool specific processing.
  2343. //
  2344. switch(m_pToolCur->ToolType())
  2345. {
  2346. case TOOLTYPE_HIGHLIGHT:
  2347. case TOOLTYPE_PEN:
  2348. CompleteFreehandMode();
  2349. break;
  2350. case TOOLTYPE_SELECT:
  2351. // Stop the pointer update timer
  2352. ::KillTimer(m_hwnd, TIMER_GRAPHIC_UPDATE);
  2353. break;
  2354. case TOOLTYPE_TEXT:
  2355. if (m_bTextEditorActive)
  2356. {
  2357. m_textEditor.AbortEditGently();
  2358. }
  2359. break;
  2360. default:
  2361. break;
  2362. }
  2363. // Show that we are no longer tracking an object
  2364. if (m_pGraphicTracker != NULL)
  2365. {
  2366. delete m_pGraphicTracker;
  2367. m_pGraphicTracker = NULL;
  2368. }
  2369. }
  2370. //
  2371. //
  2372. // Function: TrackSelectMode
  2373. //
  2374. // Purpose: Process a mouse move event in select mode
  2375. //
  2376. //
  2377. void WbDrawingArea::TrackSelectMode(POINT surfacePos)
  2378. {
  2379. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::TrackSelectMode");
  2380. // If an object is being dragged
  2381. if (m_pGraphicTracker != NULL)
  2382. {
  2383. // Get a device context for the window
  2384. HDC hDC = m_hDCCached;
  2385. // Check whether the marked object is the local pointer
  2386. if (m_pGraphicTracker->IsGraphicTool() == enumGraphicPointer)
  2387. {
  2388. DCWbGraphicPointer* pPointer = (DCWbGraphicPointer*) m_pGraphicTracker;
  2389. // Move the pointer to its new position
  2390. pPointer->MoveBy(surfacePos.x - m_ptEnd.x, surfacePos.y - m_ptEnd.y);
  2391. // Draw the new pointer
  2392. pPointer->Redraw(hDC, this);
  2393. // Save the new box end point (top right)
  2394. m_ptEnd = surfacePos;
  2395. // Check whether we need to update the external remote pointer
  2396. // information. (Based on the time. We will miss one update
  2397. // when the time wraps.)
  2398. DWORD dwNewTickCount = ::GetTickCount();
  2399. if (dwNewTickCount > m_dwTickCount + DRAW_REMOTEPOINTERDELAY)
  2400. {
  2401. TRACE_DEBUG(("Updating pointer - tick count exceeded"));
  2402. // Update the pointer
  2403. pPointer->Update();
  2404. // Set the saved tick count to the new count
  2405. m_dwTickCount = dwNewTickCount;
  2406. }
  2407. }
  2408. else
  2409. {
  2410. if( m_bTrackingSelectRect )
  2411. TrackRectangleMode(surfacePos);
  2412. else
  2413. {
  2414. // In this case we must be dragging a marked object
  2415. ASSERT(GraphicSelected());
  2416. // We never draw the tracking rectangle in the start position of
  2417. // the graphic. This gives the user some feedback when they have
  2418. // positioned the graphic back at its original place.
  2419. if (!EqualPoint(m_ptStart, m_ptEnd))
  2420. {
  2421. // Erase the last box (using XOR property)
  2422. m_pGraphicTracker->Draw(hDC);
  2423. }
  2424. // Save the new box end point (top left)
  2425. m_pGraphicTracker->MoveBy(surfacePos.x - m_ptEnd.x, surfacePos.y - m_ptEnd.y);
  2426. m_ptEnd = surfacePos;
  2427. // Draw the new rectangle (XORing it onto the display)
  2428. if (!EqualPoint(m_ptStart, m_ptEnd))
  2429. {
  2430. // Draw the rectangle
  2431. m_pGraphicTracker->Draw(hDC);
  2432. }
  2433. }
  2434. }
  2435. }
  2436. }
  2437. void WbDrawingArea::TrackDeleteMode( POINT mousePos )
  2438. {
  2439. TrackSelectMode( mousePos );
  2440. }
  2441. //
  2442. //
  2443. // Function: TrackFreehandMode
  2444. //
  2445. // Purpose: Process a mouse move event in draw mode
  2446. //
  2447. //
  2448. void WbDrawingArea::TrackFreehandMode(POINT surfacePos)
  2449. {
  2450. HPALETTE hPal = NULL;
  2451. HPALETTE hOldPal = NULL;
  2452. HPEN hPen = NULL;
  2453. HPEN hOldPen = NULL;
  2454. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::TrackFreehandMode");
  2455. // Get a device context for the client area
  2456. HDC hDC = m_hDCCached;
  2457. // set up palette
  2458. if ((m_hPage != WB_PAGE_HANDLE_NULL) && ((hPal = PG_GetPalette()) != NULL) )
  2459. {
  2460. hOldPal = ::SelectPalette(hDC, hPal, FALSE);
  2461. ::RealizePalette(hDC);
  2462. }
  2463. // Tracking in draw mode is a special case. We draw directly to the client
  2464. // area of the window and to the recording device context.
  2465. // Save the point, checking there aren't too many points
  2466. if (!m_pGraphicTracker ||
  2467. (((DCWbGraphicFreehand*) m_pGraphicTracker)->AddPoint(surfacePos) == FALSE))
  2468. {
  2469. // too many points so end the freehand object
  2470. OnLButtonUp(0, surfacePos.x, surfacePos.y);
  2471. goto TrackFreehandCleanup;
  2472. }
  2473. // Set the DC attributes
  2474. ASSERT(m_pGraphicTracker != NULL);
  2475. hPen = ::CreatePen(m_pGraphicTracker->GetPenStyle(),
  2476. m_pGraphicTracker->GetPenWidth(),
  2477. m_pGraphicTracker->GetColor());
  2478. if (!hPen)
  2479. {
  2480. ERROR_OUT(("Couldn't create pen in track freehand mode"));
  2481. goto TrackFreehandCleanup;
  2482. }
  2483. hOldPen = SelectPen(hDC, hPen);
  2484. if (hOldPen != NULL)
  2485. {
  2486. int iOldROP = ::SetROP2(hDC, m_pGraphicTracker->GetROP());
  2487. // Draw the next segment of the freehand line into the recording context
  2488. // and the client area, and save the new start point.
  2489. ::MoveToEx(hDC, m_ptStart.x, m_ptStart.y, NULL);
  2490. ::LineTo(hDC, surfacePos.x, surfacePos.y);
  2491. // Update the start point for the next line segment
  2492. m_ptStart = surfacePos;
  2493. // Restore the DC attributes
  2494. ::SetROP2(hDC, iOldROP);
  2495. // Check whether we need to update the external graphic information.
  2496. // (Based on the time. We will miss one update when the time wraps.)
  2497. DWORD dwNewTickCount = ::GetTickCount();
  2498. if (dwNewTickCount > m_dwTickCount + DRAW_GRAPHICUPDATEDELAY)
  2499. {
  2500. TRACE_DEBUG(("Updating freehand - tick count exceeded"));
  2501. // Update the pointer
  2502. if (m_pGraphicTracker->Handle() == NULL)
  2503. {
  2504. m_pGraphicTracker->AddToPageLast(m_hPage);
  2505. }
  2506. else
  2507. {
  2508. m_pGraphicTracker->Replace();
  2509. }
  2510. // Set the saved tick count to the new count
  2511. m_dwTickCount = dwNewTickCount;
  2512. }
  2513. }
  2514. TrackFreehandCleanup:
  2515. if (hOldPen != NULL)
  2516. {
  2517. SelectPen(hDC, hOldPen);
  2518. }
  2519. if (hPen != NULL)
  2520. {
  2521. ::DeletePen(hPen);
  2522. }
  2523. if (hOldPal != NULL)
  2524. {
  2525. ::SelectPalette(hDC, hOldPal, TRUE);
  2526. }
  2527. }
  2528. //
  2529. //
  2530. // Function: TrackLineMode
  2531. //
  2532. // Purpose: Process a mouse move event in line mode
  2533. //
  2534. //
  2535. void WbDrawingArea::TrackLineMode(POINT surfacePos)
  2536. {
  2537. HPALETTE hPal;
  2538. HPALETTE hOldPal = NULL;
  2539. // Get a device context for tracking
  2540. HDC hDC = m_hDCCached;
  2541. // set up palette
  2542. if ((m_hPage != WB_PAGE_HANDLE_NULL) && ((hPal = PG_GetPalette()) != NULL) )
  2543. {
  2544. hOldPal = ::SelectPalette(hDC, hPal, FALSE );
  2545. ::RealizePalette(hDC);
  2546. }
  2547. // Erase the last line drawn (using XOR property)
  2548. if (!EqualPoint(m_ptStart, m_ptEnd))
  2549. {
  2550. if (m_pGraphicTracker != NULL)
  2551. {
  2552. m_pGraphicTracker->Draw(hDC);
  2553. }
  2554. }
  2555. // Draw the new line (XORing it onto the display)
  2556. if (!EqualPoint(m_ptStart, surfacePos))
  2557. {
  2558. m_ptEnd = surfacePos;
  2559. if (m_pGraphicTracker != NULL)
  2560. {
  2561. ((DCWbGraphicTrackingLine*) m_pGraphicTracker)->SetEnd(m_ptEnd);
  2562. m_pGraphicTracker->Draw(hDC);
  2563. }
  2564. }
  2565. if (hOldPal != NULL)
  2566. {
  2567. ::SelectPalette(hDC, hOldPal, TRUE);
  2568. }
  2569. }
  2570. //
  2571. //
  2572. // Function: TrackRectangleMode
  2573. //
  2574. // Purpose: Process a mouse move event in box or filled box mode
  2575. //
  2576. //
  2577. void WbDrawingArea::TrackRectangleMode(POINT surfacePos)
  2578. {
  2579. HPALETTE hPal;
  2580. HPALETTE hOldPal = NULL;
  2581. // Get a device context for tracking
  2582. HDC hDC = m_hDCCached;
  2583. // set up palette
  2584. if ((m_hPage != WB_PAGE_HANDLE_NULL) && ((hPal = PG_GetPalette()) != NULL) )
  2585. {
  2586. hOldPal = ::SelectPalette(hDC, hPal, FALSE );
  2587. ::RealizePalette(hDC);
  2588. }
  2589. // Erase the last ellipse (using XOR property)
  2590. if (!EqualPoint(m_ptStart, m_ptEnd))
  2591. {
  2592. // Draw the rectangle
  2593. if (m_pGraphicTracker != NULL)
  2594. {
  2595. m_pGraphicTracker->Draw(hDC);
  2596. }
  2597. }
  2598. // Draw the new rectangle (XORing it onto the display)
  2599. if (!EqualPoint(m_ptStart, surfacePos))
  2600. {
  2601. // Save the new box end point (top right)
  2602. m_ptEnd = surfacePos;
  2603. // Draw the rectangle
  2604. if (m_pGraphicTracker != NULL)
  2605. {
  2606. ((DCWbGraphicTrackingRectangle*) m_pGraphicTracker)->SetRectPts(m_ptStart, m_ptEnd);
  2607. m_pGraphicTracker->Draw(hDC);
  2608. }
  2609. }
  2610. if (hOldPal != NULL)
  2611. {
  2612. ::SelectPalette(hDC, hOldPal, TRUE);
  2613. }
  2614. }
  2615. //
  2616. //
  2617. // Function: TrackEllipseMode
  2618. //
  2619. // Purpose: Process a mouse move event in ellipse or filled ellipse mode
  2620. //
  2621. //
  2622. void WbDrawingArea::TrackEllipseMode(POINT surfacePos)
  2623. {
  2624. HPALETTE hPal;
  2625. HPALETTE hOldPal = NULL;
  2626. // Get a device context for tracking
  2627. HDC hDC = m_hDCCached;
  2628. // set up palette
  2629. if( (m_hPage != WB_PAGE_HANDLE_NULL) && ((hPal = PG_GetPalette()) != NULL) )
  2630. {
  2631. hOldPal = ::SelectPalette(hDC, hPal, FALSE);
  2632. ::RealizePalette(hDC);
  2633. }
  2634. // Erase the last ellipse (using XOR property)
  2635. if (!EqualPoint(m_ptStart, m_ptEnd))
  2636. {
  2637. if (m_pGraphicTracker != NULL)
  2638. {
  2639. m_pGraphicTracker->Draw(hDC);
  2640. }
  2641. }
  2642. // Draw the new ellipse (XORing it onto the display)
  2643. if (!EqualPoint(m_ptStart, surfacePos))
  2644. {
  2645. // Update the end point of the operation
  2646. m_ptEnd = surfacePos;
  2647. if (m_pGraphicTracker != NULL)
  2648. {
  2649. ((DCWbGraphicTrackingEllipse*) m_pGraphicTracker)->SetRectPts(m_ptStart, m_ptEnd);
  2650. m_pGraphicTracker->Draw(hDC);
  2651. }
  2652. }
  2653. if (hOldPal != NULL)
  2654. {
  2655. ::SelectPalette(hDC, hOldPal, TRUE );
  2656. }
  2657. }
  2658. //
  2659. // WbDrawingArea::OnLButtonUp()
  2660. //
  2661. void WbDrawingArea::OnLButtonUp(UINT flags, int x, int y)
  2662. {
  2663. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnLButtonUp");
  2664. if (m_bIgnoreNextLClick)
  2665. {
  2666. TRACE_MSG( ("Ignoring WM_LBUTTONUP") );
  2667. m_bIgnoreNextLClick = FALSE;
  2668. return;
  2669. }
  2670. // Only process the event if we saw the button down event
  2671. if (m_bLButtonDown)
  2672. {
  2673. TRACE_MSG(("End of drawing operation"));
  2674. m_bLButtonDown = FALSE;
  2675. // The drawing area is no longer busy
  2676. m_bBusy = FALSE;
  2677. if (m_pGraphicTracker == NULL)
  2678. {
  2679. // Calculate the work surface position
  2680. // Adjust the mouse position to allow for the zoom factor
  2681. POINT surfacePos;
  2682. surfacePos.x = x;
  2683. surfacePos.y = y;
  2684. ClientToSurface(&surfacePos);
  2685. MoveOntoSurface(&surfacePos);
  2686. m_ptEnd = surfacePos;
  2687. }
  2688. // Release the mouse capture
  2689. if (::GetCapture() == m_hwnd)
  2690. {
  2691. ::ReleaseCapture();
  2692. }
  2693. // Check the page is valid - might not be if it has been deleted
  2694. // while the object was being drawn - we would not have been
  2695. // alerted to this because m_bBusy was true.
  2696. if (m_hPage != WB_PAGE_HANDLE_NULL)
  2697. {
  2698. // surround in an exception handler in case of lock errors, etc -
  2699. // we need to remove the graphic tracker
  2700. // Action taken depends on the current tool type
  2701. ASSERT(m_pToolCur != NULL);
  2702. switch(m_pToolCur->ToolType())
  2703. {
  2704. case TOOLTYPE_HIGHLIGHT:
  2705. case TOOLTYPE_PEN:
  2706. CompleteFreehandMode();
  2707. break;
  2708. case TOOLTYPE_LINE:
  2709. CompleteLineMode();
  2710. break;
  2711. case TOOLTYPE_BOX:
  2712. CompleteRectangleMode();
  2713. break;
  2714. case TOOLTYPE_FILLEDBOX:
  2715. CompleteFilledRectangleMode();
  2716. break;
  2717. case TOOLTYPE_ELLIPSE:
  2718. CompleteEllipseMode();
  2719. break;
  2720. case TOOLTYPE_FILLEDELLIPSE:
  2721. CompleteFilledEllipseMode();
  2722. break;
  2723. case TOOLTYPE_SELECT:
  2724. CompleteSelectMode();
  2725. break;
  2726. case TOOLTYPE_ERASER:
  2727. CompleteDeleteMode();
  2728. break;
  2729. case TOOLTYPE_TEXT:
  2730. m_ptStart.x = x;
  2731. m_ptStart.y = y;
  2732. ClientToSurface(&m_ptStart);
  2733. BeginTextMode(m_ptStart);
  2734. break;
  2735. default:
  2736. ERROR_OUT(("Unknown pen type"));
  2737. break;
  2738. }
  2739. }
  2740. // Show that we are no longer tracking an object
  2741. if (m_pGraphicTracker != NULL)
  2742. {
  2743. delete m_pGraphicTracker;
  2744. m_pGraphicTracker = NULL;
  2745. }
  2746. }
  2747. // unclamp cursor (bug 589)
  2748. ClipCursor(NULL);
  2749. }
  2750. //
  2751. //
  2752. // Function: CompleteSelectMode
  2753. //
  2754. // Purpose: Complete a select mode operation
  2755. //
  2756. //
  2757. void WbDrawingArea::CompleteSelectMode()
  2758. {
  2759. // If an object is being dragged
  2760. if (m_pGraphicTracker != NULL)
  2761. {
  2762. // Check if we were dragging a pointer. Pointers track
  2763. // themselves i.e. the original copy of the pointer is not
  2764. // left on the page. We want to leave the last drawn image on
  2765. // the page as this is the new pointer position.
  2766. if (m_pGraphicTracker->IsGraphicTool() == enumGraphicPointer)
  2767. {
  2768. DCWbGraphicPointer* pPointer = (DCWbGraphicPointer*) m_pGraphicTracker;
  2769. // Show the mouse
  2770. ::ShowCursor(TRUE);
  2771. // Update the object's position (if necessary)
  2772. if (!EqualPoint(m_ptStart, m_ptEnd))
  2773. {
  2774. pPointer->Update();
  2775. }
  2776. // We do not want to delete the graphic pointer (it belongs to
  2777. // the page object that created it). So reset the graphic tracker
  2778. // pointer to prevent it being deleted in OnLButtonUp.
  2779. m_pGraphicTracker = NULL;
  2780. // Stop the pointer update timer
  2781. ::KillTimer(m_hwnd, TIMER_GRAPHIC_UPDATE);
  2782. }
  2783. else
  2784. {
  2785. if( m_bTrackingSelectRect && (!EqualPoint(m_ptStart, m_ptEnd)))
  2786. {
  2787. CompleteMarkAreaMode();
  2788. SelectMarkerFromRect( &m_rcMarkedArea );
  2789. }
  2790. else
  2791. {
  2792. // The select item is a real graphic - not a pointer
  2793. // If we need to remove the rubber band box
  2794. if (!EqualPoint(m_ptStart, m_ptEnd))
  2795. {
  2796. // Erase the last box (using XOR property).
  2797. // Get a device context for tracking
  2798. HDC hDC = m_hDCCached;
  2799. // Draw the rectangle
  2800. m_pGraphicTracker->Draw(hDC);
  2801. // Move selection
  2802. m_HourGlass = TRUE;
  2803. SetCursorForState();
  2804. RemoveMarker( NULL );
  2805. m_pMarker->MoveBy(m_ptEnd.x - m_ptStart.x, m_ptEnd.y - m_ptStart.y);
  2806. m_pMarker->Update();
  2807. PutMarker( NULL, FALSE );
  2808. m_HourGlass = FALSE;
  2809. SetCursorForState();
  2810. // The tracking object will be deleted by OnLButtonUp
  2811. }
  2812. else
  2813. {
  2814. // Start and end points were the same, in this case the object has
  2815. // not been moved. We treat this as a request to move the marker
  2816. // back through the stack of objects.
  2817. if (m_bNewMarkedGraphic == FALSE)
  2818. {
  2819. SelectPreviousGraphicAt(m_pSelectedGraphic, m_ptEnd);
  2820. }
  2821. }
  2822. }
  2823. }
  2824. }
  2825. }
  2826. void WbDrawingArea::CompleteDeleteMode()
  2827. {
  2828. // select object(s)
  2829. CompleteSelectMode();
  2830. // nuke 'em
  2831. ::PostMessage(g_pMain->m_hwnd, WM_COMMAND, MAKELONG(IDM_DELETE, BN_CLICKED), 0);
  2832. }
  2833. //
  2834. //
  2835. // Function: CompleteMarkAreaMode
  2836. //
  2837. // Purpose: Process a mouse button up event in mark area mode
  2838. //
  2839. //
  2840. void WbDrawingArea::CompleteMarkAreaMode(void)
  2841. {
  2842. // Get a device context for tracking
  2843. HDC hDC = m_hDCCached;
  2844. // Erase the last ellipse (using XOR property)
  2845. if (!EqualPoint(m_ptStart, m_ptEnd))
  2846. {
  2847. // Draw the rectangle
  2848. if (m_pGraphicTracker != NULL)
  2849. {
  2850. m_pGraphicTracker->Draw(hDC);
  2851. }
  2852. // Use normalized coords
  2853. if (m_ptEnd.x < m_ptStart.x)
  2854. {
  2855. m_rcMarkedArea.left = m_ptEnd.x;
  2856. m_rcMarkedArea.right = m_ptStart.x;
  2857. }
  2858. else
  2859. {
  2860. m_rcMarkedArea.left = m_ptStart.x;
  2861. m_rcMarkedArea.right = m_ptEnd.x;
  2862. }
  2863. if (m_ptEnd.y < m_ptStart.y)
  2864. {
  2865. m_rcMarkedArea.top = m_ptEnd.y;
  2866. m_rcMarkedArea.bottom = m_ptStart.y;
  2867. }
  2868. else
  2869. {
  2870. m_rcMarkedArea.top = m_ptStart.y;
  2871. m_rcMarkedArea.bottom = m_ptEnd.y;
  2872. }
  2873. }
  2874. }
  2875. //
  2876. //
  2877. // Function: CompleteTextMode
  2878. //
  2879. // Purpose: Complete a text mode operation
  2880. //
  2881. //
  2882. void WbDrawingArea::CompleteTextMode()
  2883. {
  2884. // Not much to for text mode. Main text mode actions are taken
  2885. // as a result of a WM_CHAR message and not on mouse events.
  2886. // Just deselect our font if it is still selected
  2887. UnPrimeFont(m_hDCCached);
  2888. }
  2889. //
  2890. //
  2891. // Function: CompleteFreehandMode
  2892. //
  2893. // Purpose: Complete a draw mode operation
  2894. //
  2895. //
  2896. void WbDrawingArea::CompleteFreehandMode(void)
  2897. {
  2898. // Add the freehand object created during the drawing to the page
  2899. if (m_pGraphicTracker != NULL)
  2900. {
  2901. if (m_pGraphicTracker->Handle() == NULL)
  2902. {
  2903. m_pGraphicTracker->ClearLockFlag();
  2904. m_pGraphicTracker->AddToPageLast(m_hPage);
  2905. }
  2906. else
  2907. {
  2908. // clear lock flag and let ForceReplace propagate it (fix
  2909. // for NT bug 4744(new bug#... )
  2910. m_pGraphicTracker->ClearLockFlag();
  2911. m_pGraphicTracker->ForceReplace();
  2912. }
  2913. }
  2914. // Stop the update timer
  2915. ::KillTimer(m_hwnd, TIMER_GRAPHIC_UPDATE);
  2916. }
  2917. //
  2918. //
  2919. // Function: CompleteLineMode
  2920. //
  2921. // Purpose: Complete a line mode operation
  2922. //
  2923. //
  2924. void WbDrawingArea::CompleteLineMode(void)
  2925. {
  2926. // Only draw the line if it has non-zero length
  2927. if (!EqualPoint(m_ptStart, m_ptEnd))
  2928. {
  2929. DCWbGraphicLine line;
  2930. line.SetStart(m_ptStart);
  2931. line.SetEnd(m_ptEnd);
  2932. line.SetColor(m_pToolCur->GetColor());
  2933. line.SetPenWidth(m_pToolCur->GetWidth());
  2934. line.SetROP(m_pToolCur->GetROP());
  2935. line.GraphicTool(m_pToolCur->ToolType());
  2936. // Add the object to the list of recorded graphics
  2937. line.AddToPageLast(m_hPage);
  2938. }
  2939. }
  2940. //
  2941. //
  2942. // Function: CompleteRectangleMode
  2943. //
  2944. // Purpose: Complete a box mode operation
  2945. //
  2946. //
  2947. void WbDrawingArea::CompleteRectangleMode(void)
  2948. {
  2949. // Only draw the box if it is not null
  2950. if (!EqualPoint(m_ptStart, m_ptEnd))
  2951. {
  2952. DCWbGraphicRectangle rectangle;
  2953. rectangle.SetRectPts(m_ptStart, m_ptEnd);
  2954. rectangle.SetPenWidth(m_pToolCur->GetWidth());
  2955. rectangle.SetColor(m_pToolCur->GetColor());
  2956. rectangle.SetROP(m_pToolCur->GetROP());
  2957. rectangle.GraphicTool(m_pToolCur->ToolType());
  2958. // Add the object to the list of recorded graphics
  2959. rectangle.AddToPageLast(m_hPage);
  2960. }
  2961. }
  2962. //
  2963. //
  2964. // Function: CompleteFilledRectangleMode
  2965. //
  2966. // Purpose: Complete a filled box mode operation
  2967. //
  2968. //
  2969. void WbDrawingArea::CompleteFilledRectangleMode(void)
  2970. {
  2971. // Draw the new rectangle
  2972. if (!EqualPoint(m_ptStart, m_ptEnd))
  2973. {
  2974. DCWbGraphicFilledRectangle rectangle;
  2975. rectangle.SetRectPts(m_ptStart, m_ptEnd);
  2976. rectangle.SetPenWidth(m_pToolCur->GetWidth());
  2977. rectangle.SetColor(m_pToolCur->GetColor());
  2978. rectangle.SetROP(m_pToolCur->GetROP());
  2979. rectangle.GraphicTool(m_pToolCur->ToolType());
  2980. // Add the object to the list of recorded graphics
  2981. rectangle.AddToPageLast(m_hPage);
  2982. }
  2983. }
  2984. //
  2985. //
  2986. // Function: CompleteEllipseMode
  2987. //
  2988. // Purpose: Complete an ellipse mode operation
  2989. //
  2990. //
  2991. void WbDrawingArea::CompleteEllipseMode(void)
  2992. {
  2993. // Only draw the ellipse if it is not null
  2994. if (!EqualPoint(m_ptStart, m_ptEnd))
  2995. {
  2996. // The ellipse was defined by taking using start point as the center
  2997. // but was changed to use the bounding tracking rectangle - bug 1608
  2998. // Create the ellipse object
  2999. DCWbGraphicEllipse ellipse;
  3000. ellipse.SetRectPts(m_ptStart, m_ptEnd);
  3001. ellipse.SetColor(m_pToolCur->GetColor());
  3002. ellipse.SetPenWidth(m_pToolCur->GetWidth());
  3003. ellipse.SetROP(m_pToolCur->GetROP());
  3004. ellipse.GraphicTool(m_pToolCur->ToolType());
  3005. // Add the object to the list of recorded graphics
  3006. ellipse.AddToPageLast(m_hPage);
  3007. }
  3008. }
  3009. //
  3010. //
  3011. // Function: CompleteFilledEllipseMode
  3012. //
  3013. // Purpose: Complete a filled ellipse mode operation
  3014. //
  3015. //
  3016. void WbDrawingArea::CompleteFilledEllipseMode(void)
  3017. {
  3018. // Only draw the ellipse if it is not null
  3019. if (!EqualPoint(m_ptStart, m_ptEnd))
  3020. {
  3021. // Create the ellipse object
  3022. DCWbGraphicFilledEllipse ellipse;
  3023. ellipse.SetRectPts(m_ptStart, m_ptEnd);
  3024. ellipse.SetColor(m_pToolCur->GetColor());
  3025. ellipse.SetPenWidth(m_pToolCur->GetWidth());
  3026. ellipse.SetROP(m_pToolCur->GetROP());
  3027. ellipse.GraphicTool(m_pToolCur->ToolType());
  3028. // Add the object to the list of recorded graphics
  3029. ellipse.AddToPageLast(m_hPage);
  3030. }
  3031. }
  3032. //
  3033. //
  3034. // Function: EndTextEntry
  3035. //
  3036. // Purpose: The user has finished entering a text object. The parameter
  3037. // indicates whether the changes are to be accepted or
  3038. // discarded.
  3039. //
  3040. //
  3041. void WbDrawingArea::EndTextEntry(BOOL bAccept)
  3042. {
  3043. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::EndTextEntry");
  3044. // Only take action if the text editor is active
  3045. if (m_bTextEditorActive)
  3046. {
  3047. RECT rcBounds;
  3048. // We must at least redraw the bounding rectangle of the
  3049. // text object as it now stands (as it will not longer be
  3050. // on top).
  3051. m_textEditor.GetBoundsRect(&rcBounds);
  3052. // If we are editing an existing text object
  3053. if (m_pActiveText != NULL)
  3054. {
  3055. TRACE_MSG(("Editing an existing object"));
  3056. //
  3057. // If we are not accepting the edited text we must redraw
  3058. // both the old and new rectangles to ensure that everything
  3059. // is shown correctly.
  3060. //
  3061. if (!bAccept)
  3062. {
  3063. //
  3064. // Write the active text object back to restore it. This object
  3065. // will have the same handle as the text editor object if we have
  3066. // written it to the page - we must not delete the text editor
  3067. // object.
  3068. //
  3069. m_pActiveText->ForceReplace();
  3070. m_textEditor.ZapHandle(); // prevent editor from stepping on m_pActiveText
  3071. }
  3072. else
  3073. {
  3074. // If the object is now empty
  3075. if (m_textEditor.IsEmpty())
  3076. {
  3077. // Remove the object from the list
  3078. PG_GraphicDelete(m_hPage, *m_pActiveText);
  3079. m_textEditor.ZapHandle(); // text object is gone now, invalidate
  3080. }
  3081. else
  3082. {
  3083. // Do a replace to save the final version
  3084. m_textEditor.Replace();
  3085. }
  3086. }
  3087. // We have finished with the text object now so get rid of it
  3088. // and the fonts it holds
  3089. TRACE_MSG(("Deleting the active object"));
  3090. delete m_pActiveText;
  3091. m_pActiveText = NULL;
  3092. }
  3093. else
  3094. {
  3095. // We were adding a new text object
  3096. TRACE_MSG(("Adding a new object"));
  3097. // If we want to discard the object, or it is empty
  3098. if (!bAccept || (m_textEditor.IsEmpty()))
  3099. {
  3100. // If we have added the text editor to the page, remove it
  3101. if (m_textEditor.Handle() != NULL)
  3102. {
  3103. m_textEditor.Delete();
  3104. }
  3105. }
  3106. else
  3107. {
  3108. // Check whether we have already added the object to the page
  3109. if (m_textEditor.Handle() == NULL)
  3110. {
  3111. // Create and add a new object to the page
  3112. // (No redrawing is required)
  3113. m_textEditor.AddToPageLast(m_hPage);
  3114. }
  3115. else
  3116. {
  3117. // Replace the object to send the final version
  3118. m_textEditor.Replace();
  3119. }
  3120. }
  3121. }
  3122. // Deactivate the text editor
  3123. DeactivateTextEditor();
  3124. // Redraw any altered parts of the screen
  3125. InvalidateSurfaceRect(&rcBounds);
  3126. }
  3127. }
  3128. //
  3129. //
  3130. // Function: Zoom
  3131. //
  3132. // Purpose: Toggle the zoom state of the drawing area
  3133. //
  3134. //
  3135. void WbDrawingArea::Zoom(void)
  3136. {
  3137. RECT rcClient;
  3138. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Zoom");
  3139. // We zoom focusing on the centre of the window
  3140. ::GetClientRect(m_hwnd, &rcClient);
  3141. long xOffset = (rcClient.right - (rcClient.right / m_iZoomOption)) / 2;
  3142. long yOffset = (rcClient.bottom - (rcClient.bottom / m_iZoomOption)) / 2;
  3143. if (m_iZoomFactor != 1)
  3144. {
  3145. // We are already zoomed move back to unzoomed state
  3146. // First save the scroll position in case we return to zoom immediately
  3147. m_posZoomScroll = m_posScroll;
  3148. m_zoomRestoreScroll = TRUE;
  3149. m_posScroll.x -= xOffset;
  3150. m_posScroll.y -= yOffset;
  3151. ::ScaleViewportExtEx(m_hDCCached, 1, m_iZoomFactor, 1, m_iZoomFactor, NULL);
  3152. m_iZoomFactor = 1;
  3153. }
  3154. else
  3155. {
  3156. // We are not zoomed so do it
  3157. if (m_zoomRestoreScroll)
  3158. {
  3159. m_posScroll = m_posZoomScroll;
  3160. }
  3161. else
  3162. {
  3163. m_posScroll.x += xOffset;
  3164. m_posScroll.y += yOffset;
  3165. }
  3166. m_iZoomFactor = m_iZoomOption;
  3167. ::ScaleViewportExtEx(m_hDCCached, m_iZoomFactor, 1, m_iZoomFactor, 1, NULL);
  3168. // ADDED BY RAND - don't allow text editing in zoom mode
  3169. if( (m_pToolCur == NULL) || (m_pToolCur->ToolType() == TOOLTYPE_TEXT) )
  3170. ::SendMessage(g_pMain->m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0 );
  3171. }
  3172. TRACE_MSG(("Set zoom factor to %d", m_iZoomFactor));
  3173. // Update the scroll information
  3174. SetScrollRange(rcClient.right, rcClient.bottom);
  3175. ValidateScrollPos();
  3176. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  3177. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  3178. // Update the origin offset from the scroll position
  3179. m_originOffset.cx = m_posScroll.x;
  3180. m_originOffset.cy = m_posScroll.y;
  3181. ::SetWindowOrgEx(m_hDCCached, m_originOffset.cx, m_originOffset.cy, NULL);
  3182. // Tell the parent that the scroll position has changed
  3183. ::PostMessage(g_pMain->m_hwnd, WM_USER_PRIVATE_PARENTNOTIFY, WM_VSCROLL, 0L);
  3184. g_pMain->SetMenuStates(::GetSubMenu(::GetMenu(g_pMain->m_hwnd), 3));
  3185. // Redraw the window
  3186. ::InvalidateRect(m_hwnd, NULL, TRUE);
  3187. }
  3188. //
  3189. //
  3190. // Function: SelectTool
  3191. //
  3192. // Purpose: Set the current tool
  3193. //
  3194. //
  3195. void WbDrawingArea::SelectTool(WbTool* pToolNew)
  3196. {
  3197. // If we are leaving text mode, complete the text entry
  3198. if (m_bTextEditorActive && (m_pToolCur->ToolType() == TOOLTYPE_TEXT)
  3199. && (pToolNew->ToolType() != TOOLTYPE_TEXT))
  3200. {
  3201. // End text entry accepting the changes
  3202. EndTextEntry(TRUE);
  3203. }
  3204. ASSERT(m_pMarker);
  3205. // If we are no longer in select mode, and the marker is present,
  3206. // then remove it and let the tool know it's no longer selected
  3207. if ( (m_pToolCur != NULL)
  3208. && (m_pToolCur->ToolType() == TOOLTYPE_SELECT)
  3209. && (pToolNew->ToolType() != TOOLTYPE_SELECT))
  3210. {
  3211. m_pToolCur->DeselectGraphic();
  3212. RemoveMarker(NULL);
  3213. m_pMarker->DeleteAllMarkers( m_pSelectedGraphic );
  3214. delete m_pSelectedGraphic;
  3215. m_pSelectedGraphic = NULL;
  3216. }
  3217. else if ( (m_pToolCur != NULL)
  3218. && (m_pToolCur->ToolType() == TOOLTYPE_ERASER)
  3219. && (pToolNew->ToolType() != TOOLTYPE_ERASER))
  3220. {
  3221. m_pToolCur->DeselectGraphic();
  3222. RemoveMarker(NULL);
  3223. m_pMarker->DeleteAllMarkers( m_pSelectedGraphic );
  3224. delete m_pSelectedGraphic;
  3225. m_pSelectedGraphic = NULL;
  3226. }
  3227. // Save the new tool
  3228. m_pToolCur = pToolNew;
  3229. }
  3230. //
  3231. //
  3232. // Function: SetSelectionColor
  3233. //
  3234. // Purpose: Set the color of the selected object
  3235. //
  3236. //
  3237. void WbDrawingArea::SetSelectionColor(COLORREF clr)
  3238. {
  3239. RECT rc;
  3240. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SetSelectionColor");
  3241. // If the text editor is active - redraw the text in the new color
  3242. if (m_bTextEditorActive)
  3243. {
  3244. // Change the color being used by the editor
  3245. m_textEditor.SetColor(clr);
  3246. // Update the screen
  3247. m_textEditor.GetBoundsRect(&rc);
  3248. InvalidateSurfaceRect(&rc);
  3249. }
  3250. // If there is a currently marked object
  3251. if (GraphicSelected())
  3252. {
  3253. // Change color of the selected objects
  3254. ASSERT(m_pMarker);
  3255. m_pMarker->SetColor(clr);
  3256. // Update the objects
  3257. m_pMarker->Update();
  3258. }
  3259. m_textEditor.ForceUpdate();
  3260. }
  3261. //
  3262. //
  3263. // Function: SetSelectionWidth
  3264. //
  3265. // Purpose: Set the nib width used to draw the currently selected object
  3266. //
  3267. //
  3268. void WbDrawingArea::SetSelectionWidth(UINT uiWidth)
  3269. {
  3270. // If there is a currently marked object
  3271. if (GraphicSelected())
  3272. {
  3273. ASSERT(m_pMarker);
  3274. // Change the width of the object
  3275. m_pMarker->SetPenWidth(uiWidth);
  3276. // Update the object
  3277. m_pMarker->Update();
  3278. }
  3279. }
  3280. //
  3281. //
  3282. // Function: SetSelectionFont
  3283. //
  3284. // Purpose: Set the font used by the currently selected object
  3285. //
  3286. //
  3287. void WbDrawingArea::SetSelectionFont(HFONT hFont)
  3288. {
  3289. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SetSelectionFont");
  3290. // Define rectangles for redrawing
  3291. RECT rcOldBounds;
  3292. RECT rcNewBounds;
  3293. m_textEditor.GetBoundsRect(&rcOldBounds);
  3294. // Pass the font onto the text editor
  3295. // If the text editor is active - redraw the text in the new font
  3296. if (m_bTextEditorActive)
  3297. {
  3298. m_textEditor.SetFont(hFont);
  3299. // Get the new rectangle of the text
  3300. m_textEditor.GetBoundsRect(&rcNewBounds);
  3301. // Remove and destroy the text cursor to ensure that it
  3302. // gets re-drawn with the new size for the font
  3303. // Update the screen
  3304. InvalidateSurfaceRect(&rcOldBounds);
  3305. InvalidateSurfaceRect(&rcNewBounds);
  3306. // get the text cursor back
  3307. ActivateTextEditor( TRUE );
  3308. }
  3309. // If there is a currently marked object
  3310. if (GraphicSelected())
  3311. {
  3312. ASSERT(m_pMarker);
  3313. m_pMarker->SetSelectionFont(hFont);
  3314. }
  3315. }
  3316. //
  3317. //
  3318. // Function: OnSetFocus
  3319. //
  3320. // Purpose: The window is getting the focus
  3321. //
  3322. //
  3323. void WbDrawingArea::OnSetFocus(void)
  3324. {
  3325. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnSetFocus");
  3326. //
  3327. // If we are in text mode, we must make the text cursor visible.
  3328. //
  3329. if (m_bTextEditorActive && (m_pToolCur->ToolType() == TOOLTYPE_TEXT))
  3330. {
  3331. ActivateTextEditor(TRUE);
  3332. }
  3333. }
  3334. //
  3335. //
  3336. // Function: OnActivate
  3337. //
  3338. // Purpose: The window is being activated or deactivated
  3339. //
  3340. //
  3341. void WbDrawingArea::OnActivate(UINT uiState)
  3342. {
  3343. // Check if we are being activated or deactivated
  3344. if (uiState)
  3345. {
  3346. // We are being activated, get the focus as well
  3347. ::SetFocus(m_hwnd);
  3348. // If we are in text mode, we must make the text cursor visible
  3349. if (m_bTextEditorActive && (m_pToolCur->ToolType() == TOOLTYPE_TEXT))
  3350. {
  3351. ActivateTextEditor(TRUE);
  3352. }
  3353. }
  3354. else
  3355. {
  3356. // We are being deactivated
  3357. DeactivateTextEditor();
  3358. }
  3359. }
  3360. //
  3361. //
  3362. // Function: DeleteGraphic
  3363. //
  3364. // Purpose: Remove an object from the page.
  3365. //
  3366. //
  3367. void WbDrawingArea::DeleteGraphic(DCWbGraphic* pObject)
  3368. {
  3369. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::DeleteGraphic");
  3370. ASSERT(pObject != NULL);
  3371. // Delete the object from the recorded list. This is an asynchronous
  3372. // function, completed when a WBP_EVENT_GRAPHIC_DELETED event is received.
  3373. PG_GraphicDelete(m_hPage, *pObject);
  3374. // The caller is responsible for deleting the graphic object.
  3375. }
  3376. //
  3377. //
  3378. // Function: DeleteSelection
  3379. //
  3380. // Purpose: Delete the currently selected object
  3381. //
  3382. //
  3383. void WbDrawingArea::DeleteSelection()
  3384. {
  3385. // If there is an object currently selected...
  3386. if (GraphicSelected())
  3387. {
  3388. ASSERT(m_pMarker);
  3389. // ...delete it
  3390. m_pMarker->DeleteSelection();
  3391. m_pSelectedGraphic = NULL;
  3392. }
  3393. }
  3394. //
  3395. //
  3396. // Function: GetSelection
  3397. //
  3398. // Purpose: Return the currently selected graphic (or NULL if none).
  3399. //
  3400. //
  3401. DCWbGraphic* WbDrawingArea::GetSelection()
  3402. {
  3403. DCWbGraphic* pGraphic = NULL;
  3404. // If there is an object currently selected...
  3405. if (GraphicSelected())
  3406. {
  3407. // ...return it
  3408. pGraphic = m_pSelectedGraphic;
  3409. }
  3410. return pGraphic;
  3411. }
  3412. //
  3413. //
  3414. // Function: BringToTopSelection
  3415. //
  3416. // Purpose: Bring the currently selected object to the top
  3417. //
  3418. //
  3419. void WbDrawingArea::BringToTopSelection()
  3420. {
  3421. // If there is an object currently selected...
  3422. if (GraphicSelected())
  3423. {
  3424. ASSERT(m_pMarker);
  3425. // Bring it to the top
  3426. m_pMarker->BringToTopSelection();
  3427. // The update will be made in the window from the event generated
  3428. // by the change to the page.
  3429. }
  3430. }
  3431. //
  3432. //
  3433. // Function: SendToBackSelection
  3434. //
  3435. // Purpose: Send the currently marked object to the back
  3436. //
  3437. //
  3438. void WbDrawingArea::SendToBackSelection()
  3439. {
  3440. // If there is an object currently selected...
  3441. if (GraphicSelected())
  3442. {
  3443. ASSERT(m_pMarker);
  3444. // Send it to the back
  3445. m_pMarker->SendToBackSelection();
  3446. // The update will be made in the window from the event generated
  3447. // by the change to the page.
  3448. }
  3449. }
  3450. //
  3451. //
  3452. // Function: Clear
  3453. //
  3454. // Purpose: Clear the drawing area.
  3455. //
  3456. //
  3457. void WbDrawingArea::Clear()
  3458. {
  3459. // Remove the recorded objects
  3460. PG_Clear(m_hPage);
  3461. // The page will be redrawn after an event generated by the clear request
  3462. }
  3463. //
  3464. //
  3465. // Function: Attach
  3466. //
  3467. // Purpose: Change the page the window is displaying
  3468. //
  3469. //
  3470. void WbDrawingArea::Attach(WB_PAGE_HANDLE hPage)
  3471. {
  3472. // Remove any pointers on the current page. We are really only doing this
  3473. // to tell the pointers they are no longer drawn as they keep a record
  3474. // of whether they are in order to undraw correctly.
  3475. if (m_allPointers.IsEmpty() == FALSE)
  3476. {
  3477. // Get a DC for drawing
  3478. HDC hDC = m_hDCCached;
  3479. // Remove the pointers, reversing through the list
  3480. DCWbGraphicPointer* pPointer;
  3481. POSITION pos = m_allPointers.GetHeadPosition();
  3482. while (pos != NULL)
  3483. {
  3484. // Remove it
  3485. pPointer = (DCWbGraphicPointer*) m_allPointers.GetNext(pos);
  3486. pPointer->Undraw(hDC, this);
  3487. }
  3488. }
  3489. m_allPointers.EmptyList();
  3490. m_undrawnPointers.EmptyList();
  3491. // Accept any text being edited
  3492. if (m_bTextEditorActive)
  3493. {
  3494. EndTextEntry(TRUE);
  3495. }
  3496. // finish any drawing operation now
  3497. if (m_bLButtonDown)
  3498. {
  3499. OnLButtonUp(0, m_ptStart.x, m_ptStart.y);
  3500. }
  3501. // Get rid of the selection
  3502. ClearSelection();
  3503. // Save the new page details
  3504. m_hPage = hPage;
  3505. // If the new page we are attaching is not the empty page, set up
  3506. // the list of pointers for the new page.
  3507. if (m_hPage != WB_PAGE_HANDLE_NULL)
  3508. {
  3509. // Get the list of active pointers on the new page. The local
  3510. // pointer must be last in the list so that it is drawn topmost.
  3511. POM_OBJECT hUserNext;
  3512. DCWbGraphicPointer* pPointer = PG_FirstPointer(m_hPage, &hUserNext);
  3513. while (pPointer != NULL)
  3514. {
  3515. // Check whether we should add this pointer to the list
  3516. if (!pPointer->IsLocalPointer())
  3517. {
  3518. m_allPointers.AddTail(pPointer);
  3519. }
  3520. // Get the next pointer
  3521. pPointer = PG_NextPointer(m_hPage, &hUserNext);
  3522. }
  3523. // Check if the local pointer should also be added
  3524. pPointer = PG_LocalPointer(m_hPage);
  3525. if (pPointer != NULL)
  3526. {
  3527. m_allPointers.AddTail(pPointer);
  3528. }
  3529. }
  3530. // Force a redraw of the window to show the new contents
  3531. ::InvalidateRect(m_hwnd, NULL, TRUE);
  3532. }
  3533. //
  3534. //
  3535. // Function: DrawMarker
  3536. //
  3537. // Purpose: Draw the graphic object marker
  3538. //
  3539. //
  3540. void WbDrawingArea::DrawMarker(HDC hDC)
  3541. {
  3542. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::DrawMarker");
  3543. ASSERT(m_pMarker);
  3544. if (!hDC)
  3545. hDC = m_hDCCached;
  3546. // Draw the marker
  3547. m_pMarker->Draw(hDC);
  3548. }
  3549. //
  3550. //
  3551. // Function: PutMarker
  3552. //
  3553. // Purpose: Draw the graphic object marker
  3554. //
  3555. //
  3556. void WbDrawingArea::PutMarker(HDC hDC, BOOL bDraw)
  3557. {
  3558. ASSERT(m_pMarker);
  3559. // If the marker is not already present, draw it
  3560. if (!m_bMarkerPresent)
  3561. {
  3562. m_pMarker->Present( TRUE );
  3563. // Draw the marker (using XOR)
  3564. if( bDraw )
  3565. DrawMarker(hDC);
  3566. // Show that the marker is present
  3567. m_bMarkerPresent = TRUE;
  3568. }
  3569. }
  3570. //
  3571. //
  3572. // Function: RemoveMarker
  3573. //
  3574. // Purpose: Remove the graphic object marker
  3575. //
  3576. //
  3577. void WbDrawingArea::RemoveMarker(HDC hDC)
  3578. {
  3579. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::RemoveMarker");
  3580. ASSERT(m_pMarker);
  3581. if (!hDC)
  3582. hDC = m_hDCCached;
  3583. // If the marker is not already present, draw it
  3584. if (m_bMarkerPresent)
  3585. {
  3586. // Draw the marker (it is XORed so this removes it)
  3587. m_pMarker->Undraw(hDC, this);
  3588. m_pMarker->Present( FALSE );
  3589. // Show that the marker is no longer present
  3590. m_bMarkerPresent = FALSE;
  3591. }
  3592. }
  3593. //
  3594. //
  3595. // Function: ActivateTextEditor
  3596. //
  3597. // Purpose: Start a text editing session
  3598. //
  3599. //
  3600. void WbDrawingArea::ActivateTextEditor( BOOL bPutUpCusor )
  3601. {
  3602. // Record that the editor is now active
  3603. m_bTextEditorActive = TRUE;
  3604. // show editbox
  3605. m_textEditor.ShowBox( SW_SHOW );
  3606. // reset our DBCS sync
  3607. // Start the timer for updating the text
  3608. m_textEditor.SetTimer( DRAW_GRAPHICUPDATEDELAY);
  3609. }
  3610. //
  3611. //
  3612. // Function: DeactivateTextEditor
  3613. //
  3614. // Purpose: End a text editing session
  3615. //
  3616. //
  3617. void WbDrawingArea::DeactivateTextEditor(void)
  3618. {
  3619. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::DeactivateTextEditor");
  3620. // Stop the update timer
  3621. m_textEditor.KillTimer();
  3622. // Ensure the object is unlocked, if it was ever added to the page
  3623. if (m_textEditor.Handle() != NULL)
  3624. {
  3625. m_textEditor.Unlock();
  3626. // Sync up across all connections - FIXES BUG 521
  3627. m_textEditor.ForceReplace();
  3628. UINT uiReturn;
  3629. uiReturn = g_pwbCore->WBP_GraphicMove(m_hPage, m_textEditor.Handle(),
  3630. LAST);
  3631. if (uiReturn != 0)
  3632. {
  3633. DefaultExceptionHandler(WBFE_RC_WB, uiReturn);
  3634. return;
  3635. }
  3636. //////////////////////////
  3637. }
  3638. // Show that we are not editing any text
  3639. m_bTextEditorActive = FALSE;
  3640. // hide editbox
  3641. m_textEditor.ShowBox( SW_HIDE );
  3642. }
  3643. //
  3644. //
  3645. // Function: SurfaceToClient
  3646. //
  3647. // Purpose: Convert a point in surface co-ordinates to client
  3648. // co-ordinates (taking account of the current zoom factor).
  3649. //
  3650. //
  3651. void WbDrawingArea::SurfaceToClient(LPPOINT lppoint)
  3652. {
  3653. lppoint->x -= m_originOffset.cx;
  3654. lppoint->x *= m_iZoomFactor;
  3655. lppoint->y -= m_originOffset.cy;
  3656. lppoint->y *= m_iZoomFactor;
  3657. }
  3658. //
  3659. //
  3660. // Function: ClientToSurface
  3661. //
  3662. // Purpose: Convert a point in client co-ordinates to surface
  3663. // co-ordinates (taking account of the current zoom factor).
  3664. //
  3665. //
  3666. void WbDrawingArea::ClientToSurface(LPPOINT lppoint)
  3667. {
  3668. ASSERT(m_iZoomFactor != 0);
  3669. lppoint->x /= m_iZoomFactor;
  3670. lppoint->x += m_originOffset.cx;
  3671. lppoint->y /= m_iZoomFactor;
  3672. lppoint->y += m_originOffset.cy;
  3673. }
  3674. //
  3675. //
  3676. // Function: SurfaceToClient
  3677. //
  3678. // Purpose: Convert a rectangle in surface co-ordinates to client
  3679. // co-ordinates (taking account of the current zoom factor).
  3680. //
  3681. //
  3682. void WbDrawingArea::SurfaceToClient(LPRECT lprc)
  3683. {
  3684. SurfaceToClient((LPPOINT)&lprc->left);
  3685. SurfaceToClient((LPPOINT)&lprc->right);
  3686. }
  3687. //
  3688. //
  3689. // Function: ClientToSurface
  3690. //
  3691. // Purpose: Convert a rectangle in client co-ordinates to surface
  3692. // co-ordinates (taking account of the current zoom factor).
  3693. //
  3694. //
  3695. void WbDrawingArea::ClientToSurface(LPRECT lprc)
  3696. {
  3697. ClientToSurface((LPPOINT)&lprc->left);
  3698. ClientToSurface((LPPOINT)&lprc->right);
  3699. }
  3700. //
  3701. //
  3702. // Function: GraphicSelected
  3703. //
  3704. // Purpose: Return TRUE if a graphic is currently selected
  3705. //
  3706. //
  3707. BOOL WbDrawingArea::GraphicSelected(void)
  3708. {
  3709. ASSERT(m_pMarker);
  3710. BOOL bSelected = (m_bMarkerPresent) && (m_pMarker->GetNumMarkers() > 0);
  3711. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::GraphicSelected");
  3712. if( bSelected )
  3713. {
  3714. ASSERT(m_pSelectedGraphic != NULL);
  3715. }
  3716. return( bSelected );
  3717. }
  3718. //
  3719. //
  3720. // Function: SelectGraphic
  3721. //
  3722. // Purpose: Select a graphic - save the pointer to the graphic and
  3723. // draw the marker on it.
  3724. //
  3725. //
  3726. void WbDrawingArea::SelectGraphic(DCWbGraphic* pGraphic,
  3727. BOOL bEnableForceAdd,
  3728. BOOL bForceAdd )
  3729. {
  3730. BOOL bZapCurrentSelection;
  3731. RECT rc;
  3732. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SelectGraphic");
  3733. ASSERT(m_pMarker);
  3734. if (pGraphic->Locked() == FALSE)
  3735. {
  3736. // Save the pointer to the selected graphic
  3737. m_pSelectedGraphic = pGraphic;
  3738. if( (pGraphic = m_pMarker->HasAMarker( m_pSelectedGraphic )) != NULL )
  3739. {
  3740. // toggle marker (unselect pGraphic)
  3741. delete pGraphic;
  3742. delete m_pSelectedGraphic;
  3743. m_pSelectedGraphic = m_pMarker->LastMarker();
  3744. }
  3745. else
  3746. {
  3747. // new selection, add to list or replace list?
  3748. if( bEnableForceAdd )
  3749. bZapCurrentSelection = !bForceAdd;
  3750. else
  3751. bZapCurrentSelection =
  3752. ((GetAsyncKeyState( VK_SHIFT ) >= 0) &&
  3753. (GetAsyncKeyState( VK_CONTROL ) >= 0));
  3754. if( bZapCurrentSelection )
  3755. {
  3756. // replace list
  3757. RemoveMarker(NULL);
  3758. m_pMarker->DeleteAllMarkers( m_pSelectedGraphic, TRUE );
  3759. }
  3760. // Add the object rect to the marker rect list
  3761. m_pSelectedGraphic->GetBoundsRect(&rc);
  3762. m_pMarker->SetRect(&rc, m_pSelectedGraphic, FALSE );
  3763. }
  3764. // Draw the marker
  3765. PutMarker(NULL);
  3766. // Update the attributes window to show graphic is selected
  3767. if( m_pSelectedGraphic != NULL )
  3768. m_pToolCur->SelectGraphic(m_pSelectedGraphic);
  3769. HWND hwndParent = ::GetParent(m_hwnd);
  3770. if (hwndParent != NULL)
  3771. {
  3772. ::PostMessage(hwndParent, WM_USER_UPDATE_ATTRIBUTES, 0, 0L);
  3773. }
  3774. }
  3775. else
  3776. {
  3777. // we can delete the graphic now, because we're not selecting it
  3778. delete pGraphic;
  3779. m_pSelectedGraphic = NULL;
  3780. TRACE_MSG(("Tried to select a locked graphic - ignored"));
  3781. }
  3782. }
  3783. //
  3784. //
  3785. // Function: DeselectGraphic
  3786. //
  3787. // Purpose: Deselect a graphic - remove the marker and delete the
  3788. // graphic object associated with it.
  3789. //
  3790. //
  3791. void WbDrawingArea::DeselectGraphic(void)
  3792. {
  3793. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::DeselectGraphic");
  3794. //
  3795. // Quit if no graphic selected.
  3796. //
  3797. if( m_pSelectedGraphic == NULL )
  3798. {
  3799. return;
  3800. }
  3801. // Remove the marker
  3802. RemoveMarker(NULL);
  3803. // Delete the graphic object
  3804. delete m_pSelectedGraphic;
  3805. m_pSelectedGraphic = NULL;
  3806. // Update the attributes window to show graphic is unselected
  3807. m_pToolCur->DeselectGraphic();
  3808. HWND hwndParent = ::GetParent(m_hwnd);
  3809. if (hwndParent != NULL)
  3810. {
  3811. ::PostMessage(hwndParent, WM_USER_UPDATE_ATTRIBUTES, 0, 0L);
  3812. }
  3813. }
  3814. //
  3815. //
  3816. // Function: GetVisibleRect
  3817. //
  3818. // Purpose: Return the rectangle of the surface currently visible in the
  3819. // drawing area window.
  3820. //
  3821. //
  3822. void WbDrawingArea::GetVisibleRect(LPRECT lprc)
  3823. {
  3824. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::VisibleRect");
  3825. // Get the client rectangle
  3826. ::GetClientRect(m_hwnd, lprc);
  3827. // Convert to surface co-ordinates
  3828. ClientToSurface(lprc);
  3829. }
  3830. //
  3831. //
  3832. // Function: MoveOntoSurface
  3833. //
  3834. // Purpose: If a given point is outwith the surface rect, move it on
  3835. //
  3836. //
  3837. void WbDrawingArea::MoveOntoSurface(LPPOINT lppoint)
  3838. {
  3839. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::MoveOntoSurface");
  3840. //
  3841. // Make sure that the position is within the surface rect
  3842. //
  3843. if (lppoint->x < 0)
  3844. {
  3845. lppoint->x = 0;
  3846. }
  3847. else if (lppoint->x >= DRAW_WIDTH)
  3848. {
  3849. lppoint->x = DRAW_WIDTH - 1;
  3850. }
  3851. if (lppoint->y < 0)
  3852. {
  3853. lppoint->y = 0;
  3854. }
  3855. else if (lppoint->y >= DRAW_HEIGHT)
  3856. {
  3857. lppoint->y = DRAW_HEIGHT - 1;
  3858. }
  3859. }
  3860. //
  3861. //
  3862. // Function: GetOrigin
  3863. //
  3864. // Purpose: Provide current origin of display
  3865. //
  3866. //
  3867. void WbDrawingArea::GetOrigin(LPPOINT lppoint)
  3868. {
  3869. lppoint->x = m_originOffset.cx;
  3870. lppoint->y = m_originOffset.cy;
  3871. }
  3872. void WbDrawingArea::ShutDownDC(void)
  3873. {
  3874. UnPrimeDC(m_hDCCached);
  3875. if (m_hDCWindow != NULL)
  3876. {
  3877. ::ReleaseDC(m_hwnd, m_hDCWindow);
  3878. m_hDCWindow = NULL;
  3879. }
  3880. m_hDCCached = NULL;
  3881. }
  3882. void WbDrawingArea::ClearSelection( void )
  3883. {
  3884. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::ClearSelection");
  3885. ASSERT(m_pMarker);
  3886. RemoveMarker( NULL );
  3887. m_pMarker->DeleteAllMarkers( m_pSelectedGraphic );
  3888. DeselectGraphic();
  3889. }
  3890. void WbDrawingArea::OnCancelMode( void )
  3891. {
  3892. // We were dragging but lost mouse control, gracefully end the drag (NM4db:573)
  3893. POINT pt;
  3894. ::GetCursorPos(&pt);
  3895. ::ScreenToClient(m_hwnd, &pt);
  3896. OnLButtonUp(0, pt.x, pt.y);
  3897. m_bLButtonDown = FALSE;
  3898. }
  3899.