Source code of Windows XP (NT5)
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.

3779 lines
82 KiB

  1. //
  2. // DRAW.CPP
  3. // Main Drawing Window
  4. //
  5. // Copyright Microsoft 1998-
  6. //
  7. // PRECOMP
  8. #include "precomp.h"
  9. #include "nmwbobj.h"
  10. static const TCHAR szDrawClassName[] = "T126WB_DRAW";
  11. //
  12. //
  13. // Function: Constructor
  14. //
  15. // Purpose: Initialize the drawing area object
  16. //
  17. //
  18. WbDrawingArea::WbDrawingArea(void)
  19. {
  20. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::WbDrawingArea");
  21. g_pDraw = this;
  22. m_hwnd = NULL;
  23. m_hDCWindow = NULL;
  24. m_hDCCached = NULL;
  25. m_originOffset.cx = 0;
  26. m_originOffset.cy = 0;
  27. m_posScroll.x = 0;
  28. m_posScroll.y = 0;
  29. // Show that the drawing area is not zoomed
  30. m_iZoomFactor = 1;
  31. m_iZoomOption = 1;
  32. // Show that the left mouse button is up
  33. m_bLButtonDown = FALSE;
  34. m_bIgnoreNextLClick = FALSE;
  35. m_bBusy = FALSE;
  36. m_bLocked = FALSE;
  37. m_HourGlass = FALSE;
  38. m_bSync = TRUE;
  39. // Indicate that the cached zoom scroll position is invalid
  40. m_zoomRestoreScroll = FALSE;
  41. // Show that we are not currently editing text
  42. m_bGotCaret = FALSE;
  43. m_bTextEditorActive = FALSE;
  44. m_pTextEditor = NULL;
  45. // Show that no graphic object is in progress
  46. m_pGraphicTracker = NULL;
  47. // Show that the marker is not present.
  48. m_bMarkerPresent = FALSE;
  49. m_bNewMarkedGraphic = FALSE;
  50. m_pSelectedGraphic = NULL;
  51. m_bTrackingSelectRect = FALSE;
  52. // Show that no area is currently marked
  53. ::SetRectEmpty(&m_rcMarkedArea);
  54. // Show we haven't got a tool yet
  55. m_pToolCur = NULL;
  56. // Show that we dont have a page attached yet
  57. g_pCurrentWorkspace = NULL;
  58. g_pConferenceWorkspace = NULL;
  59. DBG_SAVE_FILE_LINE
  60. m_pMarker = new DrawObj(rectangle_chosen, TOOLTYPE_SELECT);
  61. m_pMarker->SetPenColor(RGB(0,0,0), TRUE);
  62. m_pMarker->SetFillColor(RGB(255,255,255), FALSE);
  63. m_pMarker->SetLineStyle(PS_DOT);
  64. m_pMarker->SetPenThickness(1);
  65. // Set up a checked pattern to draw the marker rect with
  66. WORD bits[] = {204, 204, 51, 51, 204, 204, 51, 51};
  67. // Create the brush to be used to draw the marker rectangle
  68. HBITMAP hBmpMarker = ::CreateBitmap(8, 8, 1, 1, bits);
  69. m_hMarkerBrush = ::CreatePatternBrush(hBmpMarker);
  70. ::DeleteBitmap(hBmpMarker);
  71. RECT rect;
  72. ::SetRectEmpty(&rect);
  73. m_pMarker->SetRect(&rect);
  74. m_pMarker->SetBoundsRect(&rect);
  75. }
  76. //
  77. //
  78. // Function: Destructor
  79. //
  80. // Purpose: Close down the drawing area
  81. //
  82. //
  83. WbDrawingArea::~WbDrawingArea(void)
  84. {
  85. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::~WbDrawingArea");
  86. if (m_pTextEditor != NULL)
  87. {
  88. m_pTextEditor->AbortEditGently();
  89. }
  90. if (m_pMarker != NULL)
  91. {
  92. delete m_pMarker;
  93. m_pMarker = NULL;
  94. }
  95. if (m_hMarkerBrush != NULL)
  96. {
  97. DeleteBrush(m_hMarkerBrush);
  98. m_hMarkerBrush = NULL;
  99. }
  100. if (m_hwnd != NULL)
  101. {
  102. ::DestroyWindow(m_hwnd);
  103. ASSERT(m_hwnd == NULL);
  104. }
  105. ::UnregisterClass(szDrawClassName, g_hInstance);
  106. g_pDraw = NULL;
  107. }
  108. //
  109. // WbDrawingArea::Create()
  110. //
  111. BOOL WbDrawingArea::Create(HWND hwndParent, LPCRECT lprect)
  112. {
  113. WNDCLASSEX wc;
  114. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Create");
  115. // Get our cursor
  116. m_hCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( PENFREEHANDCURSOR));
  117. //
  118. // Register the window class
  119. //
  120. ZeroMemory(&wc, sizeof(wc));
  121. wc.cbSize = sizeof(wc);
  122. wc.style = CS_OWNDC;
  123. wc.lpfnWndProc = DrawWndProc;
  124. wc.hInstance = g_hInstance;
  125. wc.hCursor = m_hCursor;
  126. wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  127. wc.lpszClassName = szDrawClassName;
  128. if (!::RegisterClassEx(&wc))
  129. {
  130. ERROR_OUT(("WbDraw::Create register class failed"));
  131. return(FALSE);
  132. }
  133. //
  134. // Create our window
  135. //
  136. ASSERT(m_hwnd == NULL);
  137. if (!::CreateWindowEx(WS_EX_CLIENTEDGE, szDrawClassName, NULL,
  138. WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER |
  139. WS_CLIPCHILDREN,
  140. lprect->left, lprect->top, lprect->right - lprect->left,
  141. lprect->bottom - lprect->top,
  142. hwndParent, NULL, g_hInstance, this))
  143. {
  144. ERROR_OUT(("Error creating drawing area window"));
  145. return(FALSE);
  146. }
  147. ASSERT(m_hwnd != NULL);
  148. //
  149. // Initialize remaining data members
  150. //
  151. ASSERT(!m_bBusy);
  152. ASSERT(!(m_bLocked && g_pNMWBOBJ->m_LockerID != g_MyMemberID));
  153. ASSERT(!m_HourGlass);
  154. // Start and end points of the last drawing operation
  155. m_ptStart.x = m_originOffset.cx;
  156. m_ptStart.y = m_originOffset.cy;
  157. m_ptEnd = m_ptStart;
  158. // Get the zoom factor to be used
  159. m_iZoomOption = DRAW_ZOOMFACTOR;
  160. m_hDCWindow = ::GetDC(m_hwnd);
  161. m_hDCCached = m_hDCWindow;
  162. PrimeDC(m_hDCCached);
  163. ::SetWindowOrgEx(m_hDCCached, m_originOffset.cx, m_originOffset.cy, NULL);
  164. return(TRUE);
  165. }
  166. //
  167. // DrawWndProc()
  168. // Message handler for the drawing area
  169. //
  170. LRESULT CALLBACK DrawWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  171. {
  172. LRESULT lResult = 0;
  173. WbDrawingArea * pDraw = (WbDrawingArea *)::GetWindowLongPtr(hwnd, GWLP_USERDATA);
  174. switch (message)
  175. {
  176. case WM_NCCREATE:
  177. pDraw = (WbDrawingArea *)(((LPCREATESTRUCT)lParam)->lpCreateParams);
  178. ASSERT(pDraw);
  179. pDraw->m_hwnd = hwnd;
  180. ::SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)pDraw);
  181. goto DefWndProc;
  182. break;
  183. case WM_NCDESTROY:
  184. ASSERT(pDraw);
  185. //
  186. // When you call GetDC(), the HDC you get back is only valid
  187. // as long as the HWND it refers to is. So we must release
  188. // it here.
  189. //
  190. pDraw->ShutDownDC();
  191. pDraw->m_hwnd = NULL;
  192. break;
  193. case WM_PAINT:
  194. ASSERT(pDraw);
  195. pDraw->OnPaint();
  196. break;
  197. case WM_MOUSEMOVE:
  198. ASSERT(pDraw);
  199. pDraw->OnMouseMove((UINT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
  200. break;
  201. case WM_LBUTTONDOWN:
  202. ASSERT(pDraw);
  203. pDraw->DeleteSelection();
  204. pDraw->OnLButtonDown((UINT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
  205. break;
  206. case WM_LBUTTONUP:
  207. ASSERT(pDraw);
  208. pDraw->OnLButtonUp((UINT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
  209. break;
  210. case WM_CONTEXTMENU:
  211. ASSERT(pDraw);
  212. pDraw->OnContextMenu((short)LOWORD(lParam), (short)HIWORD(lParam));
  213. break;
  214. case WM_SIZE:
  215. ASSERT(pDraw);
  216. pDraw->OnSize((UINT)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));
  217. break;
  218. case WM_HSCROLL:
  219. ASSERT(pDraw);
  220. pDraw->OnHScroll(GET_WM_HSCROLL_CODE(wParam, lParam),
  221. GET_WM_HSCROLL_POS(wParam, lParam));
  222. break;
  223. case WM_MOUSEWHEEL:
  224. ASSERT(pDraw);
  225. lParam = 0;
  226. if((short) HIWORD(wParam) > 0)
  227. {
  228. wParam = SB_LINEUP;
  229. }
  230. else
  231. {
  232. wParam = SB_LINEDOWN;
  233. }
  234. pDraw->OnVScroll(GET_WM_VSCROLL_CODE(wParam, lParam),
  235. GET_WM_VSCROLL_POS(wParam, lParam));
  236. wParam = SB_ENDSCROLL;
  237. //
  238. // Just work like a vertical scroll
  239. //
  240. case WM_VSCROLL:
  241. ASSERT(pDraw);
  242. pDraw->OnVScroll(GET_WM_VSCROLL_CODE(wParam, lParam),
  243. GET_WM_VSCROLL_POS(wParam, lParam));
  244. break;
  245. case WM_CTLCOLOREDIT:
  246. ASSERT(pDraw);
  247. lResult = pDraw->OnEditColor((HDC)wParam);
  248. break;
  249. case WM_SETFOCUS:
  250. ASSERT(pDraw);
  251. pDraw->OnSetFocus();
  252. break;
  253. case WM_ACTIVATE:
  254. ASSERT(pDraw);
  255. pDraw->OnActivate(GET_WM_ACTIVATE_STATE(wParam, lParam));
  256. break;
  257. case WM_SETCURSOR:
  258. ASSERT(pDraw);
  259. lResult = pDraw->OnCursor((HWND)wParam, LOWORD(lParam), HIWORD(lParam));
  260. break;
  261. case WM_CANCELMODE:
  262. ASSERT(pDraw);
  263. pDraw->OnCancelMode();
  264. break;
  265. case WM_TIMER:
  266. ASSERT(pDraw);
  267. pDraw->OnTimer((UINT)wParam);
  268. break;
  269. default:
  270. DefWndProc:
  271. lResult = DefWindowProc(hwnd, message, wParam, lParam);
  272. break;
  273. }
  274. return(lResult);
  275. }
  276. //
  277. //
  278. // Function: RealizePalette
  279. //
  280. // Purpose: Realize the drawing area palette
  281. //
  282. //
  283. void WbDrawingArea::RealizePalette( BOOL bBackground )
  284. {
  285. UINT entriesChanged;
  286. HDC hdc = m_hDCCached;
  287. if (g_pCurrentWorkspace != NULL)
  288. {
  289. HPALETTE hPalette = PG_GetPalette();
  290. if (hPalette != NULL)
  291. {
  292. // get our 2cents in
  293. m_hOldPalette = ::SelectPalette(hdc, hPalette, bBackground);
  294. entriesChanged = ::RealizePalette(hdc);
  295. // if mapping changes go repaint
  296. if (entriesChanged > 0)
  297. ::InvalidateRect(m_hwnd, NULL, TRUE);
  298. }
  299. }
  300. }
  301. LRESULT WbDrawingArea::OnEditColor(HDC hdc)
  302. {
  303. HPALETTE hPalette = PG_GetPalette();
  304. if (hPalette != NULL)
  305. {
  306. ::SelectPalette(hdc, hPalette, FALSE);
  307. ::RealizePalette(hdc);
  308. }
  309. COLORREF rgb;
  310. m_pTextEditor->GetPenColor(&rgb);
  311. ::SetTextColor(hdc, SET_PALETTERGB( rgb) );
  312. return((LRESULT)::GetSysColorBrush(COLOR_WINDOW));
  313. }
  314. //
  315. //
  316. // Function: OnPaint
  317. //
  318. // Purpose: Paint the window. This routine is called whenever Windows
  319. // issues a WM_PAINT message for the Whiteboard window.
  320. //
  321. //
  322. void WbDrawingArea::OnPaint(void)
  323. {
  324. RECT rcUpdate;
  325. RECT rcTmp;
  326. RECT rcBounds;
  327. HDC hSavedDC;
  328. HPEN hSavedPen;
  329. HBRUSH hSavedBrush;
  330. HPALETTE hSavedPalette;
  331. HPALETTE hPalette;
  332. HFONT hSavedFont;
  333. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnPaint");
  334. // Get the update rectangle
  335. ::GetUpdateRect(m_hwnd, &rcUpdate, FALSE);
  336. if (Zoomed())
  337. {
  338. ::InflateRect(&rcUpdate, 1, 1);
  339. InvalidateSurfaceRect(&rcUpdate, TRUE);
  340. }
  341. // Start painting
  342. PAINTSTRUCT ps;
  343. ::BeginPaint(m_hwnd, &ps);
  344. hSavedDC = m_hDCCached;
  345. hSavedFont = m_hOldFont;
  346. hSavedPen = m_hOldPen;
  347. hSavedBrush = m_hOldBrush;
  348. hSavedPalette = m_hOldPalette;
  349. TRACE_MSG(("Flipping cache to paint DC"));
  350. m_hDCCached = ps.hdc;
  351. PrimeDC(m_hDCCached);
  352. // Only draw anything if we have a valid page attached
  353. if (g_pCurrentWorkspace != NULL )
  354. {
  355. // set palette
  356. hPalette = PG_GetPalette();
  357. if (hPalette != NULL)
  358. {
  359. m_hOldPalette = ::SelectPalette(m_hDCCached, hPalette, FALSE );
  360. ::RealizePalette(m_hDCCached);
  361. }
  362. T126Obj * pObj = NULL;
  363. WBPOSITION pos;
  364. pObj = PG_First(g_pCurrentWorkspace, &rcUpdate, FALSE);
  365. if(pObj)
  366. {
  367. pos = pObj->GetMyPosition();
  368. if(pos)
  369. {
  370. g_pCurrentWorkspace->GetNextObject(pos);
  371. }
  372. }
  373. while (pObj != NULL)
  374. {
  375. pObj->Draw(NULL, TRUE);
  376. // Get the next one
  377. if(pos)
  378. {
  379. pObj = PG_Next(g_pCurrentWorkspace, pos, &rcUpdate, FALSE);
  380. }
  381. else
  382. {
  383. break;
  384. }
  385. }
  386. if (hPalette != NULL)
  387. {
  388. ::SelectPalette(m_hDCCached, m_hOldPalette, TRUE);
  389. }
  390. // fixes painting problems for bug 2185
  391. if( TextEditActive() )
  392. {
  393. RedrawTextEditbox();
  394. }
  395. //
  396. // Draw the tracking graphic
  397. //
  398. if ((m_pGraphicTracker != NULL) && !EqualPoint(m_ptStart, m_ptEnd))
  399. {
  400. TRACE_MSG(("Drawing the tracking graphic"));
  401. m_pGraphicTracker->Draw(NULL, FALSE);
  402. }
  403. }
  404. //
  405. // Restore the DC to its original state
  406. //
  407. UnPrimeDC(m_hDCCached);
  408. m_hOldFont = hSavedFont;
  409. m_hOldPen = hSavedPen;
  410. m_hOldBrush = hSavedBrush;
  411. m_hOldPalette = hSavedPalette;
  412. m_hDCCached = hSavedDC;
  413. // Finish painting
  414. ::EndPaint(m_hwnd, &ps);
  415. }
  416. //
  417. // Selects all graphic objs contained in rectSelect. If rectSelect is
  418. // NULL then ALL objs are selected
  419. //
  420. void WbDrawingArea::SelectMarkerFromRect(LPCRECT lprcSelect)
  421. {
  422. T126Obj* pGraphic;
  423. RECT rc;
  424. ::SetRectEmpty(&rc);
  425. m_HourGlass = TRUE;
  426. SetCursorForState();
  427. WBPOSITION pos;
  428. pGraphic = NULL;
  429. pGraphic = PG_First(g_pCurrentWorkspace, lprcSelect, TRUE);
  430. if(pGraphic)
  431. {
  432. pos = pGraphic->GetMyPosition();
  433. if(pos)
  434. {
  435. g_pCurrentWorkspace->GetNextObject(pos);
  436. }
  437. }
  438. while (pGraphic != NULL)
  439. {
  440. if(pGraphic->GraphicTool() == TOOLTYPE_REMOTEPOINTER && // if it is a pointer and it is not local
  441. (!pGraphic->IAmTheOwner() || // we can't select it. Or this was a select all
  442. (pGraphic->IAmTheOwner() && lprcSelect == NULL)))
  443. {
  444. ; // don't select it
  445. }
  446. else
  447. {
  448. SelectGraphic(pGraphic, TRUE, TRUE);
  449. //
  450. // Calculate de size of the total selection
  451. //
  452. RECT selctRect;
  453. pGraphic->GetBoundsRect(&selctRect);
  454. ::UnionRect(&rc,&selctRect,&rc);
  455. }
  456. // Get the next one
  457. pGraphic = PG_Next(g_pCurrentWorkspace, pos, lprcSelect, TRUE );
  458. }
  459. m_pMarker->SetRect(&rc);
  460. m_HourGlass = FALSE;
  461. SetCursorForState();
  462. g_pMain->OnUpdateAttributes();
  463. }
  464. //
  465. //
  466. // Function: OnTimer
  467. //
  468. // Purpose: Process a timer event. These are used to update freehand and
  469. // text objects while they are being drawn/edited and to
  470. // update the remote pointer position when the mouse stops.
  471. //
  472. //
  473. void WbDrawingArea::OnTimer(UINT idTimer)
  474. {
  475. TRACE_TIMER(("WbDrawingArea::OnTimer"));
  476. // We are only interested if the user is drawing something or editing
  477. if (m_bLButtonDown == TRUE)
  478. {
  479. if(idTimer == TIMER_REMOTE_POINTER_UPDATE)
  480. {
  481. ASSERT(g_pMain->m_pLocalRemotePointer);
  482. if(g_pMain->m_pLocalRemotePointer)
  483. {
  484. if(g_pMain->m_pLocalRemotePointer->HasAnchorPointChanged())
  485. {
  486. g_pMain->m_pLocalRemotePointer->OnObjectEdit();
  487. g_pMain->m_pLocalRemotePointer->ResetAttrib();
  488. }
  489. }
  490. return;
  491. }
  492. // If the user is dragging an object or drawing a freehand line
  493. if (m_pGraphicTracker != NULL)
  494. {
  495. if(m_pGraphicTracker->HasAnchorPointChanged() || m_pGraphicTracker->HasPointListChanged())
  496. {
  497. //
  498. // If we are not added to the workspace
  499. //
  500. if(!m_pGraphicTracker->GetMyWorkspace())
  501. {
  502. m_pGraphicTracker->AddToWorkspace();
  503. }
  504. else
  505. {
  506. m_pGraphicTracker->OnObjectEdit();
  507. }
  508. }
  509. }
  510. }
  511. }
  512. //
  513. //
  514. // Function: OnSize
  515. //
  516. // Purpose: The window has been resized.
  517. //
  518. //
  519. void WbDrawingArea::OnSize(UINT nType, int cx, int cy)
  520. {
  521. // Only process this message if the window is not minimized
  522. if ( (nType == SIZEFULLSCREEN)
  523. || (nType == SIZENORMAL))
  524. {
  525. if (TextEditActive())
  526. {
  527. TextEditParentResize();
  528. }
  529. // Set the new scroll range (based on the new client area)
  530. SetScrollRange(cx, cy);
  531. // Ensure that the scroll position lies in the new scroll range
  532. ValidateScrollPos();
  533. // make page move if needed
  534. ScrollWorkspace();
  535. // Update the scroll bars
  536. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  537. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  538. }
  539. }
  540. //
  541. //
  542. // Function: SetScrollRange
  543. //
  544. // Purpose: Set the current scroll range. The range is based on the
  545. // work surface size and the size of the client area.
  546. //
  547. //
  548. void WbDrawingArea::SetScrollRange(int cx, int cy)
  549. {
  550. SCROLLINFO scinfo;
  551. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SetScrollRange");
  552. // If we are in zoom mode, then allow for the magnification
  553. ASSERT(m_iZoomFactor != 0);
  554. cx /= m_iZoomFactor;
  555. cy /= m_iZoomFactor;
  556. ZeroMemory( &scinfo, sizeof (SCROLLINFO) );
  557. scinfo.cbSize = sizeof (SCROLLINFO);
  558. scinfo.fMask = SIF_PAGE | SIF_RANGE|
  559. SIF_DISABLENOSCROLL;
  560. // Set the horizontal scroll range and proportional thumb size
  561. scinfo.nMin = 0;
  562. scinfo.nMax = DRAW_WIDTH - 1;
  563. scinfo.nPage = cx;
  564. ::SetScrollInfo(m_hwnd, SB_HORZ, &scinfo, FALSE);
  565. // Set the vertical scroll range and proportional thumb size
  566. scinfo.nMin = 0;
  567. scinfo.nMax = DRAW_HEIGHT - 1;
  568. scinfo.nPage = cy;
  569. ::SetScrollInfo(m_hwnd, SB_VERT, &scinfo, FALSE);
  570. }
  571. //
  572. //
  573. // Function: ValidateScrollPos
  574. //
  575. // Purpose: Ensure that the current scroll position is within the bounds
  576. // of the current scroll range. The scroll range is set to
  577. // ensure that the window on the worksurface never extends
  578. // beyond the surface boundaries.
  579. //
  580. //
  581. void WbDrawingArea::ValidateScrollPos()
  582. {
  583. int iMax;
  584. SCROLLINFO scinfo;
  585. // Validate the horixontal scroll position using proportional settings
  586. scinfo.cbSize = sizeof(scinfo);
  587. scinfo.fMask = SIF_ALL;
  588. ::GetScrollInfo(m_hwnd, SB_HORZ, &scinfo);
  589. iMax = scinfo.nMax - scinfo.nPage;
  590. m_posScroll.x = max(m_posScroll.x, 0);
  591. m_posScroll.x = min(m_posScroll.x, iMax);
  592. // Validate the vertical scroll position using proportional settings
  593. scinfo.cbSize = sizeof(scinfo);
  594. scinfo.fMask = SIF_ALL;
  595. ::GetScrollInfo(m_hwnd, SB_VERT, &scinfo);
  596. iMax = scinfo.nMax - scinfo.nPage;
  597. m_posScroll.y = max(m_posScroll.y, 0);
  598. m_posScroll.y = min(m_posScroll.y, iMax);
  599. }
  600. //
  601. //
  602. // Function: ScrollWorkspace
  603. //
  604. // Purpose: Scroll the workspace to the position set in the member
  605. // variable m_posScroll.
  606. //
  607. //
  608. void WbDrawingArea::ScrollWorkspace(void)
  609. {
  610. RECT rc;
  611. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::ScrollWorkspace");
  612. // Do the scroll
  613. DoScrollWorkspace();
  614. if(Zoomed())
  615. {
  616. // Tell the parent that the scroll position has changed
  617. HWND hwndParent;
  618. hwndParent = ::GetParent(m_hwnd);
  619. if (hwndParent != NULL)
  620. {
  621. ::PostMessage(hwndParent, WM_USER_PRIVATE_PARENTNOTIFY, WM_VSCROLL, 0L);
  622. }
  623. }
  624. }
  625. //
  626. //
  627. // Function: DoScrollWorkspace
  628. //
  629. // Purpose: Scroll the workspace to the position set in the member
  630. // variable m_posScroll.
  631. //
  632. //
  633. void WbDrawingArea::DoScrollWorkspace()
  634. {
  635. // Validate the scroll position
  636. ValidateScrollPos();
  637. // Set the scroll box position
  638. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  639. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  640. // Only update the screen if the scroll position has changed
  641. if ( (m_originOffset.cy != m_posScroll.y)
  642. || (m_originOffset.cx != m_posScroll.x) )
  643. {
  644. // Calculate the amount to scroll
  645. INT iVScrollAmount = m_originOffset.cy - m_posScroll.y;
  646. INT iHScrollAmount = m_originOffset.cx - m_posScroll.x;
  647. // Save the new position (for UpdateWindow)
  648. m_originOffset.cx = m_posScroll.x;
  649. m_originOffset.cy = m_posScroll.y;
  650. ::SetWindowOrgEx(m_hDCCached, m_originOffset.cx, m_originOffset.cy, NULL);
  651. // Scroll and redraw the newly invalidated portion of the window
  652. ::ScrollWindow(m_hwnd, iHScrollAmount, iVScrollAmount, NULL, NULL);
  653. ::UpdateWindow(m_hwnd);
  654. }
  655. }
  656. //
  657. //
  658. // Function: GotoPosition
  659. //
  660. // Purpose: Move the top-left corner of the workspace to the specified
  661. // position in the workspace.
  662. //
  663. //
  664. void WbDrawingArea::GotoPosition(int x, int y)
  665. {
  666. // Set the new scroll position
  667. m_posScroll.x = x;
  668. m_posScroll.y = y;
  669. // Scroll to the new position
  670. DoScrollWorkspace();
  671. // Invalidate the zoom scroll cache if we scroll when unzoomed.
  672. if (!Zoomed())
  673. {
  674. m_zoomRestoreScroll = FALSE;
  675. }
  676. }
  677. //
  678. //
  679. // Function: OnVScroll
  680. //
  681. // Purpose: Process a WM_VSCROLL messages.
  682. //
  683. //
  684. void WbDrawingArea::OnVScroll(UINT nSBCode, UINT nPos)
  685. {
  686. RECT rcClient;
  687. // Get the current client rectangle HEIGHT
  688. ::GetClientRect(m_hwnd, &rcClient);
  689. ASSERT(rcClient.top == 0);
  690. rcClient.bottom -= rcClient.top;
  691. // Act on the scroll code
  692. switch(nSBCode)
  693. {
  694. // Scroll to bottom
  695. case SB_BOTTOM:
  696. m_posScroll.y = DRAW_HEIGHT - rcClient.bottom;
  697. break;
  698. // Scroll down a line
  699. case SB_LINEDOWN:
  700. m_posScroll.y += DRAW_LINEVSCROLL;
  701. break;
  702. // Scroll up a line
  703. case SB_LINEUP:
  704. m_posScroll.y -= DRAW_LINEVSCROLL;
  705. break;
  706. // Scroll down a page
  707. case SB_PAGEDOWN:
  708. m_posScroll.y += rcClient.bottom / m_iZoomFactor;
  709. break;
  710. // Scroll up a page
  711. case SB_PAGEUP:
  712. m_posScroll.y -= rcClient.bottom / m_iZoomFactor;
  713. break;
  714. // Scroll to the top
  715. case SB_TOP:
  716. m_posScroll.y = 0;
  717. break;
  718. // Track the scroll box
  719. case SB_THUMBPOSITION:
  720. case SB_THUMBTRACK:
  721. m_posScroll.y = nPos; // don't round
  722. break;
  723. default:
  724. break;
  725. }
  726. // Validate the scroll position
  727. ValidateScrollPos();
  728. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  729. // If this message is informing us of the end of scrolling,
  730. // update the window
  731. if (nSBCode == SB_ENDSCROLL)
  732. {
  733. // Scroll the window
  734. ScrollWorkspace();
  735. }
  736. // Invalidate the zoom scroll cache if we scroll when unzoomed.
  737. if (!Zoomed())
  738. {
  739. m_zoomRestoreScroll = FALSE;
  740. }
  741. }
  742. //
  743. //
  744. // Function: OnHScroll
  745. //
  746. // Purpose: Process a WM_HSCROLL messages.
  747. //
  748. //
  749. void WbDrawingArea::OnHScroll(UINT nSBCode, UINT nPos)
  750. {
  751. RECT rcClient;
  752. // Get the current client rectangle WIDTH
  753. ::GetClientRect(m_hwnd, &rcClient);
  754. ASSERT(rcClient.left == 0);
  755. rcClient.right -= rcClient.left;
  756. switch(nSBCode)
  757. {
  758. // Scroll to the far right
  759. case SB_BOTTOM:
  760. m_posScroll.x = DRAW_WIDTH - rcClient.right;
  761. break;
  762. // Scroll right a line
  763. case SB_LINEDOWN:
  764. m_posScroll.x += DRAW_LINEHSCROLL;
  765. break;
  766. // Scroll left a line
  767. case SB_LINEUP:
  768. m_posScroll.x -= DRAW_LINEHSCROLL;
  769. break;
  770. // Scroll right a page
  771. case SB_PAGEDOWN:
  772. m_posScroll.x += rcClient.right / m_iZoomFactor;
  773. break;
  774. // Scroll left a page
  775. case SB_PAGEUP:
  776. m_posScroll.x -= rcClient.right / m_iZoomFactor;
  777. break;
  778. // Scroll to the far left
  779. case SB_TOP:
  780. m_posScroll.x = 0;
  781. break;
  782. // Track the scroll box
  783. case SB_THUMBPOSITION:
  784. case SB_THUMBTRACK:
  785. m_posScroll.x = nPos; // don't round
  786. break;
  787. default:
  788. break;
  789. }
  790. // Validate the scroll position
  791. ValidateScrollPos();
  792. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  793. // If this message is informing us of the end of scrolling,
  794. // update the window
  795. if (nSBCode == SB_ENDSCROLL)
  796. {
  797. // Scroll the window
  798. ScrollWorkspace();
  799. }
  800. // Invalidate the zoom scroll cache if we scroll when unzoomed.
  801. if (!Zoomed())
  802. {
  803. m_zoomRestoreScroll = FALSE;
  804. }
  805. }
  806. //
  807. //
  808. // Function: AutoScroll
  809. //
  810. // Purpose: Auto-scroll the window to bring the position passed as
  811. // parameter into view.
  812. //
  813. //
  814. BOOL WbDrawingArea::AutoScroll
  815. (
  816. int xSurface,
  817. int ySurface,
  818. BOOL bMoveCursor,
  819. int xCaret,
  820. int yCaret
  821. )
  822. {
  823. int nXPSlop, nYPSlop;
  824. int nXMSlop, nYMSlop;
  825. int nDeltaHScroll, nDeltaVScroll;
  826. BOOL bDoScroll = FALSE;
  827. nXPSlop = 0;
  828. nYPSlop = 0;
  829. nXMSlop = 0;
  830. nYMSlop = 0;
  831. if( TextEditActive() )
  832. {
  833. POINT ptDirTest;
  834. ptDirTest.x = xSurface - xCaret;
  835. ptDirTest.y = ySurface - yCaret;
  836. // set up for text editbox
  837. if( ptDirTest.x > 0 )
  838. nXPSlop = m_pTextEditor->m_textMetrics.tmMaxCharWidth;
  839. else
  840. if( ptDirTest.x < 0 )
  841. nXMSlop = -m_pTextEditor->m_textMetrics.tmMaxCharWidth;
  842. if( ptDirTest.y > 0 )
  843. nYPSlop = m_pTextEditor->m_textMetrics.tmHeight;
  844. else
  845. if( ptDirTest.y < 0 )
  846. nYMSlop = -m_pTextEditor->m_textMetrics.tmHeight;
  847. nDeltaHScroll = m_pTextEditor->m_textMetrics.tmMaxCharWidth;
  848. nDeltaVScroll = m_pTextEditor->m_textMetrics.tmHeight;
  849. }
  850. else
  851. {
  852. // set up for all other objects
  853. nDeltaHScroll = DRAW_LINEHSCROLL;
  854. nDeltaVScroll = DRAW_LINEVSCROLL;
  855. }
  856. // Get the current visible surface rectangle
  857. RECT visibleRect;
  858. GetVisibleRect(&visibleRect);
  859. // Check for pos + slop being outside visible area
  860. if( (xSurface + nXPSlop) >= visibleRect.right )
  861. {
  862. bDoScroll = TRUE;
  863. m_posScroll.x +=
  864. (((xSurface + nXPSlop) - visibleRect.right) + nDeltaHScroll);
  865. }
  866. if( (xSurface + nXMSlop) <= visibleRect.left )
  867. {
  868. bDoScroll = TRUE;
  869. m_posScroll.x -=
  870. ((visibleRect.left - (xSurface + nXMSlop)) + nDeltaHScroll);
  871. }
  872. if( (ySurface + nYPSlop) >= visibleRect.bottom)
  873. {
  874. bDoScroll = TRUE;
  875. m_posScroll.y +=
  876. (((ySurface + nYPSlop) - visibleRect.bottom) + nDeltaVScroll);
  877. }
  878. if( (ySurface + nYMSlop) <= visibleRect.top)
  879. {
  880. bDoScroll = TRUE;
  881. m_posScroll.y -=
  882. ((visibleRect.top - (ySurface + nYMSlop)) + nDeltaVScroll);
  883. }
  884. if( !bDoScroll )
  885. return( FALSE );
  886. // Indicate that scrolling has completed (in both directions)
  887. ScrollWorkspace();
  888. // Update the mouse position (if required)
  889. if (bMoveCursor)
  890. {
  891. POINT screenPos;
  892. screenPos.x = xSurface;
  893. screenPos.y = ySurface;
  894. SurfaceToClient(&screenPos);
  895. ::ClientToScreen(m_hwnd, &screenPos);
  896. ::SetCursorPos(screenPos.x, screenPos.y);
  897. }
  898. return( TRUE );
  899. }
  900. //
  901. //
  902. // Function: OnCursor
  903. //
  904. // Purpose: Process a WM_SETCURSOR messages.
  905. //
  906. //
  907. LRESULT WbDrawingArea::OnCursor(HWND hwnd, UINT uiHit, UINT uMsg)
  908. {
  909. BOOL bResult = FALSE;
  910. // Check that this message is for the main window
  911. if (hwnd == m_hwnd)
  912. {
  913. // If the cursor is now in the client area, set the cursor
  914. if (uiHit == HTCLIENT)
  915. {
  916. bResult = SetCursorForState();
  917. }
  918. else
  919. {
  920. // Restore the cursor to the standard arrow. Set m_hCursor to NULL
  921. // to indicate that we have not set a special cursor.
  922. m_hCursor = NULL;
  923. ::SetCursor(::LoadCursor(NULL, IDC_ARROW));
  924. bResult = TRUE;
  925. }
  926. }
  927. // Return result indicating whether we processed the message or not
  928. return bResult;
  929. }
  930. //
  931. //
  932. // Function: SetCursorForState
  933. //
  934. // Purpose: Set the cursor for the current state
  935. //
  936. //
  937. BOOL WbDrawingArea::SetCursorForState(void)
  938. {
  939. BOOL bResult = FALSE;
  940. m_hCursor = NULL;
  941. // If the drawing area is locked, use the "locked" cursor
  942. if (m_HourGlass)
  943. {
  944. m_hCursor = ::LoadCursor( NULL, IDC_WAIT );
  945. }
  946. else if (m_bLocked && g_pNMWBOBJ->m_LockerID != g_MyMemberID)
  947. {
  948. // Return the cursor for the tool
  949. m_hCursor = ::LoadCursor(g_hInstance, MAKEINTRESOURCE( LOCKCURSOR ));
  950. }
  951. else if (m_pToolCur != NULL)
  952. {
  953. // Get the cursor for the tool currently in use
  954. m_hCursor = m_pToolCur->GetCursorForTool();
  955. }
  956. if (m_hCursor != NULL)
  957. {
  958. ::SetCursor(m_hCursor);
  959. bResult = TRUE;
  960. }
  961. // Return result indicating whether we set the cursor or not
  962. return bResult;
  963. }
  964. //
  965. //
  966. // Function: Lock
  967. //
  968. // Purpose: Lock the drawing area, preventing further updates
  969. //
  970. //
  971. void WbDrawingArea::Lock(void)
  972. {
  973. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Lock");
  974. // Check whether the drawing area is busy - this is not allowed
  975. ASSERT(!m_bBusy);
  976. // Stop any drawing we are doing.
  977. CancelDrawingMode();
  978. // Deselect any selected graphic
  979. ClearSelection();
  980. // Show that we are now locked
  981. m_bLocked = TRUE;
  982. TRACE_MSG(("Drawing area is now locked"));
  983. // Set the cursor for the drawing mode, but only if we should be drawing
  984. // a special cursor (if m_hCursor != the current cursor, then the cursor
  985. // is out of the client area).
  986. if (::GetCursor() == m_hCursor)
  987. {
  988. SetCursorForState();
  989. }
  990. }
  991. //
  992. //
  993. // Function: Unlock
  994. //
  995. // Purpose: Unlock the drawing area, preventing further updates
  996. //
  997. //
  998. void WbDrawingArea::Unlock(void)
  999. {
  1000. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Unlock");
  1001. // Check whether the drawing area is busy - this is not allowed
  1002. ASSERT(!m_bBusy);
  1003. // Show that we are now unlocked
  1004. m_bLocked = FALSE;
  1005. TRACE_MSG(("Drawing area is now UNlocked"));
  1006. // Set the cursor for the drawing mode, but only if we should be drawing
  1007. // a special cursor (if m_hCursor != the current cursor, then the cursor
  1008. // is out of the client area).
  1009. if (::GetCursor() == m_hCursor)
  1010. {
  1011. SetCursorForState();
  1012. }
  1013. }
  1014. //
  1015. //
  1016. // Function: PageCleared
  1017. //
  1018. // Purpose: The page has been cleared
  1019. //
  1020. //
  1021. void WbDrawingArea::PageCleared(void)
  1022. {
  1023. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PageCleared");
  1024. // Check whether the drawing area is busy - this is not allowed
  1025. ASSERT(!m_bBusy);
  1026. // Discard any text being edited
  1027. if (m_bTextEditorActive)
  1028. {
  1029. if (m_bLocked && g_pNMWBOBJ->m_LockerID != g_MyMemberID)
  1030. {
  1031. DeactivateTextEditor();
  1032. }
  1033. else
  1034. {
  1035. EndTextEntry(FALSE);
  1036. }
  1037. }
  1038. // Remove the copy of the marked graphic and the marker
  1039. ClearSelection();
  1040. // Invalidate the whole window
  1041. ::InvalidateRect(m_hwnd, NULL, TRUE);
  1042. }
  1043. //
  1044. //
  1045. // Function: InvalidateSurfaceRect
  1046. //
  1047. // Purpose: Invalidate the window rectangle corresponding to the given
  1048. // drawing surface rectangle.
  1049. //
  1050. //
  1051. void WbDrawingArea::InvalidateSurfaceRect(LPCRECT lprc, BOOL bErase)
  1052. {
  1053. RECT rc;
  1054. // Convert the surface co-ordinates to client window and invalidate
  1055. // the rectangle.
  1056. rc = *lprc;
  1057. SurfaceToClient(&rc);
  1058. ::InvalidateRect(m_hwnd, &rc, bErase);
  1059. }
  1060. //
  1061. //
  1062. // Function: PrimeFont
  1063. //
  1064. // Purpose: Insert the supplied font into our DC and return the
  1065. // text metrics
  1066. //
  1067. //
  1068. void WbDrawingArea::PrimeFont(HDC hDC, HFONT hFont, TEXTMETRIC* pTextMetrics)
  1069. {
  1070. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PrimeFont");
  1071. //
  1072. // temporarily unzoom to get the font that we want
  1073. //
  1074. if (Zoomed())
  1075. {
  1076. ::ScaleViewportExtEx(m_hDCCached, 1, m_iZoomFactor, 1, m_iZoomFactor, NULL);
  1077. }
  1078. HFONT hOldFont = SelectFont(hDC, hFont);
  1079. if (hOldFont == NULL)
  1080. {
  1081. WARNING_OUT(("Failed to select font into DC"));
  1082. }
  1083. if (pTextMetrics != NULL)
  1084. {
  1085. ::GetTextMetrics(hDC, pTextMetrics);
  1086. }
  1087. //
  1088. // restore the zoom state
  1089. //
  1090. if (Zoomed())
  1091. {
  1092. ::ScaleViewportExtEx(m_hDCCached, m_iZoomFactor, 1, m_iZoomFactor, 1, NULL);
  1093. }
  1094. }
  1095. //
  1096. //
  1097. // Function: UnPrimeFont
  1098. //
  1099. // Purpose: Remove the specified font from the DC and clear cache
  1100. // variable
  1101. //
  1102. //
  1103. void WbDrawingArea::UnPrimeFont(HDC hDC)
  1104. {
  1105. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::UnPrimeFont");
  1106. if (hDC != NULL)
  1107. {
  1108. SelectFont(hDC, ::GetStockObject(SYSTEM_FONT));
  1109. }
  1110. }
  1111. //
  1112. //
  1113. // Function: PrimeDC
  1114. //
  1115. // Purpose: Set up a DC for drawing
  1116. //
  1117. //
  1118. void WbDrawingArea::PrimeDC(HDC hDC)
  1119. {
  1120. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::PrimeDC");
  1121. ::SetMapMode(hDC, MM_ANISOTROPIC);
  1122. ::SetBkMode(hDC, TRANSPARENT);
  1123. ::SetTextAlign(hDC, TA_LEFT | TA_TOP);
  1124. }
  1125. //
  1126. //
  1127. // Function: UnPrimeDC
  1128. //
  1129. // Purpose: Reset the DC to default state
  1130. //
  1131. //
  1132. void WbDrawingArea::UnPrimeDC(HDC hDC)
  1133. {
  1134. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::UnPrimeDC");
  1135. SelectPen(hDC, (HPEN)::GetStockObject(BLACK_PEN));
  1136. SelectBrush(hDC, (HBRUSH)::GetStockObject(BLACK_BRUSH));
  1137. UnPrimeFont(hDC);
  1138. }
  1139. //
  1140. // WbDrawingArea::OnContextMenu()
  1141. //
  1142. void WbDrawingArea::OnContextMenu(int xScreen, int yScreen)
  1143. {
  1144. POINT pt;
  1145. RECT rc;
  1146. pt.x = xScreen;
  1147. pt.y = yScreen;
  1148. ::ScreenToClient(m_hwnd, &pt);
  1149. ::GetClientRect(m_hwnd, &rc);
  1150. if (::PtInRect(&rc, pt))
  1151. {
  1152. // Complete drawing action, if any
  1153. OnLButtonUp(0, pt.x, pt.y);
  1154. // Ask main window to put up context menu
  1155. g_pMain->PopupContextMenu(pt.x, pt.y);
  1156. }
  1157. }
  1158. //
  1159. // WbDrawingArea::OnLButtonDown()
  1160. //
  1161. void WbDrawingArea::OnLButtonDown(UINT flags, int x, int y)
  1162. {
  1163. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnLButtonDown");
  1164. if( m_bIgnoreNextLClick )
  1165. {
  1166. TRACE_MSG( ("Ignoring WM_LBUTTONDOWN") );
  1167. return;
  1168. }
  1169. // Set the focus to this window. This is done to ensure that we trap
  1170. // the text edit keys and the delete key when they are used.
  1171. ::SetFocus(m_hwnd);
  1172. // Save the operation start point (and current end point)
  1173. // Adjust the mouse position to allow for the zoom factor
  1174. m_ptStart.x = x;
  1175. m_ptStart.y = y;
  1176. ClientToSurface(&m_ptStart);
  1177. m_ptEnd = m_ptStart;
  1178. // Show that the mouse button is now down
  1179. m_bLButtonDown = TRUE;
  1180. // Show that the drawing area is now busy
  1181. m_bBusy = TRUE;
  1182. // Only allow the action to take place if the drawing area is unlocked,
  1183. // and we have a valid tool
  1184. if ((m_bLocked && g_pNMWBOBJ->m_LockerID != g_MyMemberID) || (m_pToolCur == NULL))
  1185. {
  1186. // Tidy up the state and leave now
  1187. m_bLButtonDown = FALSE;
  1188. m_bBusy = FALSE;
  1189. return;
  1190. }
  1191. // Call the relevant initialization routine
  1192. if (m_pToolCur->ToolType() != TOOLTYPE_SELECT)
  1193. {
  1194. // dump selection if not select tool
  1195. ClearSelection();
  1196. }
  1197. INT border = 1;
  1198. switch (m_pToolCur->ToolType())
  1199. {
  1200. case TOOLTYPE_TEXT:
  1201. break;
  1202. case TOOLTYPE_HIGHLIGHT:
  1203. case TOOLTYPE_PEN:
  1204. case TOOLTYPE_LINE:
  1205. case TOOLTYPE_BOX:
  1206. case TOOLTYPE_FILLEDBOX:
  1207. case TOOLTYPE_ELLIPSE:
  1208. case TOOLTYPE_FILLEDELLIPSE:
  1209. BeginDrawingMode(m_ptStart);
  1210. break;
  1211. case TOOLTYPE_ERASER:
  1212. BeginSelectMode(m_ptStart, TRUE);
  1213. break;
  1214. case TOOLTYPE_SELECT:
  1215. border = -2;
  1216. BeginSelectMode(m_ptStart, FALSE);
  1217. break;
  1218. // Do nothing if we do not recognise the pen type
  1219. default:
  1220. ERROR_OUT(("Bad tool type"));
  1221. break;
  1222. }
  1223. // Clamp the cursor to the drawing window
  1224. RECT rcClient;
  1225. ::GetClientRect(m_hwnd, &rcClient);
  1226. ::MapWindowPoints(m_hwnd, NULL, (LPPOINT)&rcClient.left, 2);
  1227. ::InflateRect(&rcClient, border, border);
  1228. ::ClipCursor(&rcClient);
  1229. }
  1230. //
  1231. //
  1232. // Function: SelectPreviousGraphicAt
  1233. //
  1234. // Purpose: Select the previous graphic (in the Z-order) at the position
  1235. // specified, and starting at a specified graphic. If the
  1236. // graphic pointer given is NULL the search starts from the
  1237. // top. If the point specified is outside the bounding
  1238. // rectangle of the specified graphic the search starts at the
  1239. // top and chooses the first graphic which contains the point.
  1240. //
  1241. // The search process will loop back to the top of the Z-order
  1242. // if it gets to the bottom having failed to find a graphic.
  1243. //
  1244. // Graphics which are locked are ignored by the search.
  1245. //
  1246. //
  1247. T126Obj* WbDrawingArea::SelectPreviousGraphicAt
  1248. (
  1249. T126Obj* pStartGraphic,
  1250. POINT point
  1251. )
  1252. {
  1253. // Set the result to "none found" initially
  1254. T126Obj* pResultGraphic = NULL;
  1255. // If a starting point has been specified
  1256. if (pStartGraphic != NULL)
  1257. {
  1258. RECT rectHit;
  1259. MAKE_HIT_RECT(rectHit, point);
  1260. // If the reference point is within the start graphic
  1261. if ( pStartGraphic->PointInBounds(point) &&
  1262. pStartGraphic->CheckReallyHit( &rectHit ) )
  1263. {
  1264. WBPOSITION pos = pStartGraphic->GetMyPosition();
  1265. g_pCurrentWorkspace->GetPreviousObject(pos);
  1266. while (pos)
  1267. {
  1268. pResultGraphic = g_pCurrentWorkspace->GetPreviousObject(pos);
  1269. if( pResultGraphic && pResultGraphic->CheckReallyHit( &rectHit ) )
  1270. {
  1271. if(m_pMarker)
  1272. {
  1273. RECT rect;
  1274. pResultGraphic->GetRect(&rect);
  1275. m_pMarker->SetRect(&rect);
  1276. }
  1277. break;
  1278. }
  1279. pResultGraphic = NULL;
  1280. }
  1281. }
  1282. }
  1283. // If we have not got a result graphic yet. (This catches two cases:
  1284. // - where no start graphic has been given so that we want to start
  1285. // from the top,
  1286. // - where we have searched back from the start graphic and reached
  1287. // the bottom of the Z-order without finding a suitable graphic.
  1288. if (pResultGraphic == NULL)
  1289. {
  1290. // Get the topmost graphic that contains the point specified
  1291. pResultGraphic = PG_SelectLast(g_pCurrentWorkspace, point);
  1292. }
  1293. // If we have found an object, draw the marker
  1294. if (pResultGraphic != NULL)
  1295. {
  1296. //
  1297. // If we are already selected and we didn't select it
  1298. // some other node has the control over this graphic don't select it
  1299. // in this case
  1300. // Or if we are trying to select a remote pointer that is not ours
  1301. //
  1302. if(pResultGraphic->IsSelected() && pResultGraphic->WasSelectedRemotely()
  1303. || (pResultGraphic->GraphicTool() == TOOLTYPE_REMOTEPOINTER && !pResultGraphic->IAmTheOwner()))
  1304. {
  1305. pResultGraphic = NULL;
  1306. }
  1307. else
  1308. {
  1309. // Select the new one
  1310. SelectGraphic(pResultGraphic);
  1311. }
  1312. }
  1313. return pResultGraphic;
  1314. }
  1315. //
  1316. //
  1317. // Function: BeginSelectMode
  1318. //
  1319. // Purpose: Process a mouse button down in select mode
  1320. //
  1321. //
  1322. void WbDrawingArea::BeginSelectMode(POINT surfacePos, BOOL bDontDrag )
  1323. {
  1324. RECT rc;
  1325. // Assume we do not start dragging a graphic
  1326. m_pGraphicTracker = NULL;
  1327. // Assume that we do not mark a new graphic
  1328. m_bNewMarkedGraphic = FALSE;
  1329. // turn off TRACK-SELECT-RECT
  1330. m_bTrackingSelectRect = FALSE;
  1331. // Check whether there is currently an object marked, and
  1332. // whether we are clicking inside the same object. If we are then
  1333. // we do nothing here - the click will be handled by the tracking or
  1334. // completion routines for select mode.
  1335. if ( (GraphicSelected() == FALSE)
  1336. || (m_pMarker->PointInBounds(surfacePos) == FALSE))
  1337. {
  1338. ::SetRectEmpty(&g_pDraw->m_selectorRect);
  1339. // We are selecting a new object if bDontDrag == FALSE, find it.
  1340. // otherwise just turn on the select rect
  1341. T126Obj* pGraphic;
  1342. if( bDontDrag )
  1343. pGraphic = NULL;
  1344. else
  1345. pGraphic = SelectPreviousGraphicAt(NULL, surfacePos);
  1346. // If we have found an object, draw the marker
  1347. if (pGraphic != NULL)
  1348. {
  1349. if(pGraphic->IsSelected() && pGraphic->WasSelectedRemotely())
  1350. {
  1351. return;
  1352. }
  1353. // Show that a new graphic has now been marked.
  1354. m_bNewMarkedGraphic = TRUE;
  1355. }
  1356. else
  1357. {
  1358. if( (GetAsyncKeyState( VK_SHIFT ) >= 0) &&
  1359. (GetAsyncKeyState( VK_CONTROL ) >= 0) )
  1360. {
  1361. // clicked on dead air, remove all selections
  1362. ClearSelection();
  1363. }
  1364. //TRACK-SELECT-RECT
  1365. m_bTrackingSelectRect = TRUE;
  1366. BeginDrawingMode(surfacePos);
  1367. return;
  1368. }
  1369. }
  1370. if(GraphicSelected())
  1371. {
  1372. m_pMarker->SetRect(&m_selectorRect);
  1373. m_pMarker->SetBoundsRect(&m_selectorRect);
  1374. m_pGraphicTracker = m_pMarker;
  1375. }
  1376. // Get all mouse input directed to the this window
  1377. ::SetCapture(m_hwnd);
  1378. }
  1379. //
  1380. //
  1381. // Function: TrackSelectMode
  1382. //
  1383. // Purpose: Process a mouse move event in select mode
  1384. //
  1385. //
  1386. void WbDrawingArea::TrackSelectMode(POINT surfacePos)
  1387. {
  1388. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::TrackSelectMode");
  1389. if( m_bTrackingSelectRect )
  1390. TrackDrawingMode(surfacePos);
  1391. else
  1392. {
  1393. // In this case we must be dragging a marked object
  1394. if(!EqualPoint(surfacePos, m_ptEnd))
  1395. {
  1396. MoveSelectedGraphicBy(surfacePos.x - m_ptEnd.x, surfacePos.y - m_ptEnd.y);
  1397. }
  1398. m_ptEnd = surfacePos;
  1399. }
  1400. }
  1401. void WbDrawingArea::BeginDeleteMode(POINT mousePos )
  1402. {
  1403. // turn off object dragging
  1404. BeginSelectMode( mousePos, TRUE );
  1405. }
  1406. void WbDrawingArea::TrackDeleteMode( POINT mousePos )
  1407. {
  1408. TrackSelectMode( mousePos );
  1409. }
  1410. //
  1411. //
  1412. // Function: BeginTextMode
  1413. //
  1414. // Purpose: Process a mouse button down in text mode
  1415. //
  1416. //
  1417. void WbDrawingArea::BeginTextMode(POINT surfacePos)
  1418. {
  1419. RECT rc;
  1420. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::BeginTextMode");
  1421. //
  1422. // Get a DC for passing into the text editor
  1423. //
  1424. HDC hDC = m_hDCCached;
  1425. // If we are already editing a text object, we just move the text cursor
  1426. if (m_bTextEditorActive)
  1427. {
  1428. // If the mouse has been clicked in the currently active object
  1429. // we just move the cursor within the object, otherwise we end the
  1430. // edit for the current object and move to a new one.
  1431. m_pTextEditor->GetRect(&rc);
  1432. if (::PtInRect(&rc, surfacePos))
  1433. {
  1434. // Set the new position for the cursor
  1435. m_pTextEditor->SetCursorPosFromPoint(surfacePos);
  1436. }
  1437. else
  1438. {
  1439. // Complete the text entry accepting the changes
  1440. EndTextEntry(TRUE);
  1441. // LAURABU BOGUS:
  1442. // It would be cooler to now return, that way you don't get
  1443. // another text object just cuz you ended the current editing
  1444. // session.
  1445. }
  1446. }
  1447. // If we are not editing an object we check to see whether there is
  1448. // a text object under the cursor or whether we must start a new one.
  1449. if (!m_bTextEditorActive)
  1450. {
  1451. // Check whether we are clicking over a text object. If we are
  1452. // start editing the object, otherwise we start a new text object.
  1453. // Look back through the Z-order for a text object
  1454. T126Obj* pGraphic = PG_SelectLast(g_pCurrentWorkspace, surfacePos);
  1455. T126Obj* pNextGraphic = NULL;
  1456. WBPOSITION pos;
  1457. if(pGraphic)
  1458. {
  1459. pos = pGraphic->GetMyPosition();
  1460. }
  1461. while ( (pGraphic != NULL) && pGraphic->GraphicTool() != TOOLTYPE_TEXT)
  1462. {
  1463. // Get the next one
  1464. pNextGraphic = PG_SelectPrevious(g_pCurrentWorkspace, pos, surfacePos);
  1465. // Use the next one
  1466. pGraphic = pNextGraphic;
  1467. }
  1468. // Check whether this graphic object is already being edited by
  1469. // another user in the call.
  1470. if (pGraphic != NULL && !pGraphic->WasSelectedRemotely() && pGraphic->GraphicTool() == TOOLTYPE_TEXT)
  1471. {
  1472. // We found a text object under the mouse pointer...
  1473. // ...edit it
  1474. m_pTextEditor = (WbTextEditor*)pGraphic;
  1475. m_pTextEditor->SetTextObject(m_pTextEditor);
  1476. // Make sure the tool reflects the new information
  1477. if (m_pToolCur != NULL)
  1478. {
  1479. m_pToolCur->SelectGraphic(pGraphic);
  1480. }
  1481. HWND hwndParent = ::GetParent(m_hwnd);
  1482. if (hwndParent != NULL)
  1483. {
  1484. ASSERT(g_pMain);
  1485. ASSERT(g_pMain->m_hwnd == hwndParent);
  1486. ::PostMessage(hwndParent, WM_USER_UPDATE_ATTRIBUTES, 0, 0);
  1487. }
  1488. // Show that we are now gathering text but dont put up cursor
  1489. // yet. Causes cursor droppings later (bug 2505)
  1490. //ActivateTextEditor( FALSE );
  1491. RECT rect;
  1492. m_pTextEditor->GetRect(&rect);
  1493. m_pTextEditor->Create();
  1494. // init editbox size
  1495. m_pTextEditor->GetText();
  1496. //
  1497. // Tell the other nodes they can't edit this object now
  1498. //
  1499. m_pTextEditor->SetViewState(selected_chosen);
  1500. m_pTextEditor->OnObjectEdit();
  1501. ActivateTextEditor( TRUE );
  1502. ::BringWindowToTop(m_pTextEditor->m_pEditBox->m_hwnd);
  1503. //
  1504. // Account for scrolling
  1505. //
  1506. SurfaceToClient(&rect);
  1507. ::MoveWindow(m_pTextEditor->m_pEditBox->m_hwnd, rect.left, rect.top,
  1508. rect.right - rect.left, rect.bottom - rect.top, TRUE);
  1509. // Set the initial cursor position for the edit
  1510. m_pTextEditor->SetCursorPosFromPoint(surfacePos);
  1511. }
  1512. else
  1513. {
  1514. RECT rect;
  1515. rect.top = m_ptEnd.y;
  1516. rect.left = m_ptEnd.x;
  1517. rect.bottom = m_ptEnd.y;
  1518. rect.right = m_ptEnd.x;
  1519. DBG_SAVE_FILE_LINE
  1520. m_pTextEditor = new WbTextEditor();
  1521. m_pTextEditor->SetRect(&rect);
  1522. m_pTextEditor->SetAnchorPoint(m_ptEnd.x, m_ptEnd.y);
  1523. m_pTextEditor->SetViewState(selected_chosen);
  1524. // There are no text objects under the mouse pointer...
  1525. // ...start a new one
  1526. // Clear any old text out of the editor, and reset its graphic
  1527. // handle. This prevents us from replacing an old text object when
  1528. // we next save the text editor contents.
  1529. if (!m_pTextEditor->New())
  1530. {
  1531. DefaultExceptionHandler(WBFE_RC_WINDOWS, 0);
  1532. return;
  1533. }
  1534. // Set the attributes of the text
  1535. m_pTextEditor->SetFont(m_pToolCur->GetFont());
  1536. m_pTextEditor->SetPenColor(m_pToolCur->GetColor(), TRUE);
  1537. // We need to reselect a font now into our DC
  1538. SelectFont(hDC, m_pTextEditor->GetFont());
  1539. // Set the position of the new object
  1540. SIZE sizeCursor;
  1541. m_pTextEditor->GetCursorSize(&sizeCursor);
  1542. m_pTextEditor->CalculateBoundsRect();
  1543. m_pTextEditor->MoveTo(m_ptEnd.x, m_ptEnd.y - sizeCursor.cy);
  1544. // Show that we are now gathering text
  1545. ActivateTextEditor( TRUE );
  1546. }
  1547. }
  1548. }
  1549. void WbDrawingArea::BeginDrawingMode(POINT surfacePos)
  1550. {
  1551. if(!g_pCurrentWorkspace)
  1552. {
  1553. TRACE_DEBUG(("Can't draw without a workspace"));
  1554. return;
  1555. }
  1556. //
  1557. // Get all mouse input directed to the this window
  1558. //
  1559. ::SetCapture(m_hwnd);
  1560. //
  1561. // We shouldn't be using the tracker
  1562. //
  1563. ASSERT(!m_pGraphicTracker);
  1564. UINT drawingType;
  1565. BOOL sendBeforefinished = FALSE;
  1566. BOOL highlight = FALSE;
  1567. UINT lineStyle = PS_SOLID;
  1568. UINT toolType = m_pToolCur->ToolType();
  1569. switch (toolType)
  1570. {
  1571. case TOOLTYPE_HIGHLIGHT:
  1572. highlight = TRUE;
  1573. case TOOLTYPE_PEN:
  1574. sendBeforefinished = TRUE;
  1575. case TOOLTYPE_LINE:
  1576. drawingType = openPolyLine_chosen;
  1577. break;
  1578. case TOOLTYPE_SELECT:
  1579. case TOOLTYPE_ERASER:
  1580. m_pGraphicTracker = m_pMarker;
  1581. return;
  1582. break;
  1583. case TOOLTYPE_FILLEDBOX:
  1584. case TOOLTYPE_BOX:
  1585. drawingType = rectangle_chosen;
  1586. break;
  1587. case TOOLTYPE_FILLEDELLIPSE:
  1588. case TOOLTYPE_ELLIPSE:
  1589. drawingType = ellipse_chosen;
  1590. break;
  1591. }
  1592. DBG_SAVE_FILE_LINE
  1593. m_pGraphicTracker = new DrawObj(drawingType, toolType);
  1594. //
  1595. // Use black for the tracking rectangle unless it is pen or highlighter
  1596. //
  1597. if(m_pToolCur->ToolType() == TOOLTYPE_PEN || m_pToolCur->ToolType() == TOOLTYPE_HIGHLIGHT)
  1598. {
  1599. m_pGraphicTracker->SetPenColor(m_pToolCur->GetColor(), TRUE);
  1600. }
  1601. else
  1602. {
  1603. m_pGraphicTracker->SetPenColor(RGB(0,0,0), TRUE);
  1604. }
  1605. m_pGraphicTracker->SetFillColor(RGB(255,255,255), FALSE);
  1606. m_pGraphicTracker->SetLineStyle(lineStyle);
  1607. m_pGraphicTracker->SetAnchorPoint(surfacePos.x, surfacePos.y);
  1608. m_pGraphicTracker->SetHighlight(highlight);
  1609. m_pGraphicTracker->SetViewState(unselected_chosen);
  1610. m_pGraphicTracker->SetZOrder(front);
  1611. //
  1612. // Start a timer if we want it to send intermidiate drawings
  1613. //
  1614. if(sendBeforefinished)
  1615. {
  1616. RECT rect;
  1617. rect.left = surfacePos.x;
  1618. rect.top = surfacePos.y;
  1619. rect.right = surfacePos.x;
  1620. rect.bottom = surfacePos.y;
  1621. m_pGraphicTracker->SetRect(&rect);
  1622. m_pGraphicTracker->SetBoundsRect(&rect);
  1623. surfacePos.x = 0;
  1624. surfacePos.y = 0;
  1625. m_pGraphicTracker->AddPoint(surfacePos);
  1626. //
  1627. // Select the final ROP
  1628. //
  1629. if (highlight)
  1630. {
  1631. m_pGraphicTracker->SetROP(R2_MASKPEN);
  1632. }
  1633. else
  1634. {
  1635. m_pGraphicTracker->SetROP(R2_COPYPEN);
  1636. }
  1637. //
  1638. // Use the tools width for pen or highlight
  1639. //
  1640. m_pGraphicTracker->SetPenThickness(m_pToolCur->GetWidth());
  1641. // Start the timer for updating the graphic (this is only for updating
  1642. // the graphic when the user stops moving the pointer but keeps the
  1643. // mouse button down).
  1644. ::SetTimer(m_hwnd, TIMER_GRAPHIC_UPDATE, DRAW_GRAPHICUPDATEDELAY, NULL);
  1645. // Save the current time (used to determine when to update
  1646. // the external graphic pointer information while the mouse is
  1647. // being moved).
  1648. m_dwTickCount = ::GetTickCount();
  1649. m_pGraphicTracker->SetViewState(selected_chosen);
  1650. }
  1651. else
  1652. {
  1653. m_pGraphicTracker->SetPenThickness(1);
  1654. }
  1655. }
  1656. //
  1657. //
  1658. // Function: TrackDrawingMode
  1659. //
  1660. // Purpose: Process a mouse move event in drawing mode
  1661. //
  1662. //
  1663. void WbDrawingArea::TrackDrawingMode(POINT surfacePos)
  1664. {
  1665. HPALETTE hPal;
  1666. HPALETTE hOldPal = NULL;
  1667. if(!m_pGraphicTracker)
  1668. {
  1669. return;
  1670. }
  1671. if(EqualPoint(surfacePos, m_ptEnd))
  1672. {
  1673. return;
  1674. }
  1675. // Get a device context for tracking
  1676. HDC hDC = m_hDCCached;
  1677. // set up palette
  1678. if ((g_pCurrentWorkspace != NULL) && ((hPal = PG_GetPalette()) != NULL) )
  1679. {
  1680. hOldPal = ::SelectPalette(hDC, hPal, FALSE );
  1681. ::RealizePalette(hDC);
  1682. }
  1683. // Erase the last ellipse (using XOR property)
  1684. if (!EqualPoint(m_ptStart, m_ptEnd))
  1685. {
  1686. // Draw the rectangle
  1687. m_pGraphicTracker->Draw();
  1688. }
  1689. // Draw the new rectangle (XORing it onto the display)
  1690. if (!EqualPoint(m_ptStart, surfacePos))
  1691. {
  1692. //
  1693. // If we are using a pen or highlighter
  1694. // Tracking in draw mode is a special case. We draw directly to the client
  1695. // area of the window and to the recording device context.
  1696. if( m_pToolCur->ToolType() == TOOLTYPE_HIGHLIGHT || m_pToolCur->ToolType() == TOOLTYPE_PEN)
  1697. {
  1698. POINT deltaPoint;
  1699. deltaPoint.x = surfacePos.x - m_ptEnd.x;
  1700. deltaPoint.y = surfacePos.y - m_ptEnd.y;
  1701. // Save the point, checking there aren't too many points
  1702. if (m_pGraphicTracker->AddPoint(deltaPoint) == FALSE)
  1703. {
  1704. // too many points so end the freehand object
  1705. OnLButtonUp(0, surfacePos.x, surfacePos.y);
  1706. goto cleanUp;
  1707. }
  1708. m_pGraphicTracker->SetRectPts(m_ptEnd, surfacePos);
  1709. m_pGraphicTracker->AddPointToBounds(surfacePos.x, surfacePos.y);
  1710. m_ptEnd = surfacePos;
  1711. }
  1712. else
  1713. {
  1714. // Save the new box end point
  1715. m_ptEnd = surfacePos;
  1716. // Draw the rectangle
  1717. m_pGraphicTracker->SetRectPts(m_ptStart, m_ptEnd);
  1718. }
  1719. m_pGraphicTracker->Draw();
  1720. }
  1721. cleanUp:
  1722. if (hOldPal != NULL)
  1723. {
  1724. ::SelectPalette(hDC, hOldPal, TRUE);
  1725. }
  1726. }
  1727. //
  1728. // WbDrawingArea::OnMouseMove
  1729. //
  1730. void WbDrawingArea::OnMouseMove(UINT flags, int x, int y)
  1731. {
  1732. if(!g_pCurrentWorkspace)
  1733. {
  1734. return;
  1735. }
  1736. POINT surfacePos;
  1737. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnMouseMove");
  1738. surfacePos.x = x;
  1739. surfacePos.y = y;
  1740. // Check if the left mouse button is down
  1741. if (m_bLButtonDown)
  1742. {
  1743. // Calculate the worksurface position
  1744. // Adjust the mouse position to allow for the zoom factor
  1745. ClientToSurface(&surfacePos);
  1746. // Make sure the point is a valid surface position
  1747. MoveOntoSurface(&surfacePos);
  1748. // Check whether the window needs to be scrolled to get the
  1749. // current position into view.
  1750. AutoScroll(surfacePos.x, surfacePos.y, FALSE, 0, 0);
  1751. // Action taken depends on the tool type
  1752. switch(m_pToolCur->ToolType())
  1753. {
  1754. case TOOLTYPE_HIGHLIGHT:
  1755. case TOOLTYPE_PEN:
  1756. case TOOLTYPE_LINE:
  1757. case TOOLTYPE_BOX:
  1758. case TOOLTYPE_FILLEDBOX:
  1759. case TOOLTYPE_ELLIPSE:
  1760. case TOOLTYPE_FILLEDELLIPSE:
  1761. TrackDrawingMode(surfacePos);
  1762. break;
  1763. case TOOLTYPE_ERASER:
  1764. case TOOLTYPE_SELECT:
  1765. TrackSelectMode(surfacePos);
  1766. break;
  1767. case TOOLTYPE_TEXT:
  1768. // JOSEF add functionality
  1769. break;
  1770. default:
  1771. ERROR_OUT(("Unknown tool type"));
  1772. break;
  1773. }
  1774. }
  1775. }
  1776. //
  1777. //
  1778. // Function: CancelDrawingMode
  1779. //
  1780. // Purpose: Cancels a drawing operation after an error.
  1781. //
  1782. //
  1783. void WbDrawingArea::CancelDrawingMode(void)
  1784. {
  1785. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::CancelDrawingMode");
  1786. //
  1787. // Quit if there's nothing to cancel.
  1788. //
  1789. if (!m_bBusy && !m_bTextEditorActive)
  1790. {
  1791. TRACE_DEBUG(("Drawing area not busy and text editor not active..."));
  1792. return;
  1793. }
  1794. // The drawing area is no longer busy
  1795. m_bBusy = FALSE;
  1796. //
  1797. // Redraw the object - we need to discard any local updates which we
  1798. // weren't able to write to the object we are editing. Ideally we should
  1799. // just invalidate the object itself but because some of the co-ordinates
  1800. // we have already drawn on the page may have been lost, we dont know
  1801. // exactly how big the object is.
  1802. //
  1803. ::InvalidateRect(m_hwnd, NULL, TRUE);
  1804. m_bLButtonDown = FALSE;
  1805. // Release the mouse capture
  1806. if (::GetCapture() == m_hwnd)
  1807. {
  1808. ::ReleaseCapture();
  1809. }
  1810. //
  1811. // Perform any tool specific processing.
  1812. //
  1813. switch(m_pToolCur->ToolType())
  1814. {
  1815. case TOOLTYPE_HIGHLIGHT:
  1816. case TOOLTYPE_PEN:
  1817. CompleteDrawingMode();
  1818. break;
  1819. case TOOLTYPE_SELECT:
  1820. // Stop the pointer update timer
  1821. ::KillTimer(m_hwnd, TIMER_GRAPHIC_UPDATE);
  1822. break;
  1823. case TOOLTYPE_TEXT:
  1824. if (m_bTextEditorActive)
  1825. {
  1826. m_pTextEditor->AbortEditGently();
  1827. }
  1828. break;
  1829. default:
  1830. break;
  1831. }
  1832. // Show that we are no longer tracking an object
  1833. if (m_pGraphicTracker != NULL)
  1834. {
  1835. m_pGraphicTracker = NULL; // We don't delete the tracker, because it is also the drawing
  1836. }
  1837. }
  1838. //
  1839. // WbDrawingArea::OnLButtonUp()
  1840. //
  1841. void WbDrawingArea::OnLButtonUp(UINT flags, int x, int y)
  1842. {
  1843. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnLButtonUp");
  1844. if (m_bIgnoreNextLClick)
  1845. {
  1846. TRACE_MSG( ("Ignoring WM_LBUTTONUP") );
  1847. m_bIgnoreNextLClick = FALSE;
  1848. return;
  1849. }
  1850. // Only process the event if we saw the button down event
  1851. if (m_bLButtonDown)
  1852. {
  1853. TRACE_MSG(("End of drawing operation"));
  1854. m_bLButtonDown = FALSE;
  1855. // The drawing area is no longer busy
  1856. m_bBusy = FALSE;
  1857. if (m_pGraphicTracker == NULL)
  1858. {
  1859. // Calculate the work surface position
  1860. // Adjust the mouse position to allow for the zoom factor
  1861. POINT surfacePos;
  1862. surfacePos.x = x;
  1863. surfacePos.y = y;
  1864. ClientToSurface(&surfacePos);
  1865. MoveOntoSurface(&surfacePos);
  1866. m_ptEnd = surfacePos;
  1867. }
  1868. // Release the mouse capture
  1869. if (::GetCapture() == m_hwnd)
  1870. {
  1871. ::ReleaseCapture();
  1872. }
  1873. // Check the page is valid - might not be if it has been deleted
  1874. // while the object was being drawn - we would not have been
  1875. // alerted to this because m_bBusy was true.
  1876. if (g_pCurrentWorkspace != NULL)
  1877. {
  1878. // surround in an exception handler in case of lock errors, etc -
  1879. // we need to remove the graphic tracker
  1880. // Action taken depends on the current tool type
  1881. switch(m_pToolCur->ToolType())
  1882. {
  1883. case TOOLTYPE_HIGHLIGHT:
  1884. case TOOLTYPE_PEN:
  1885. case TOOLTYPE_LINE:
  1886. case TOOLTYPE_BOX:
  1887. case TOOLTYPE_FILLEDBOX:
  1888. case TOOLTYPE_ELLIPSE:
  1889. case TOOLTYPE_FILLEDELLIPSE:
  1890. CompleteDrawingMode();
  1891. break;
  1892. case TOOLTYPE_SELECT:
  1893. CompleteSelectMode();
  1894. break;
  1895. case TOOLTYPE_ERASER:
  1896. CompleteDeleteMode();
  1897. break;
  1898. case TOOLTYPE_TEXT:
  1899. m_ptStart.x = x;
  1900. m_ptStart.y = y;
  1901. ClientToSurface(&m_ptStart);
  1902. BeginTextMode(m_ptStart);
  1903. break;
  1904. default:
  1905. ERROR_OUT(("Unknown pen type"));
  1906. break;
  1907. }
  1908. }
  1909. // Show that we are no longer tracking an object
  1910. if (m_pGraphicTracker != NULL)
  1911. {
  1912. m_pGraphicTracker = NULL; // Don't delete the tracker since it is the drawing object
  1913. }
  1914. }
  1915. // unclamp cursor (bug 589)
  1916. ClipCursor(NULL);
  1917. }
  1918. //
  1919. //
  1920. // Function: CompleteSelectMode
  1921. //
  1922. // Purpose: Complete a select mode operation
  1923. //
  1924. //
  1925. void WbDrawingArea::CompleteSelectMode()
  1926. {
  1927. // If an object is being dragged
  1928. //if (m_pGraphicTracker != NULL)
  1929. {
  1930. // Check if we were dragging a pointer. Pointers track
  1931. // themselves i.e. the original copy of the pointer is not
  1932. // left on the page. We want to leave the last drawn image on
  1933. // the page as this is the new pointer position.
  1934. if( m_bTrackingSelectRect && (!EqualPoint(m_ptStart, m_ptEnd)))
  1935. {
  1936. CompleteMarkAreaMode();
  1937. SelectMarkerFromRect( &m_rcMarkedArea );
  1938. }
  1939. else
  1940. {
  1941. // If we need to remove the rubber band box
  1942. if (!EqualPoint(m_ptStart, m_ptEnd))
  1943. {
  1944. EraseInitialDrawFinal(m_ptStart.x - m_ptEnd.x , m_ptStart.y - m_ptEnd.y, TRUE);
  1945. InvalidateSurfaceRect(&g_pDraw->m_selectorRect,TRUE);
  1946. }
  1947. else
  1948. {
  1949. // Start and end points were the same, in this case the object has
  1950. // not been moved. We treat this as a request to move the marker
  1951. // back through the stack of objects.
  1952. if (m_bNewMarkedGraphic == FALSE)
  1953. {
  1954. SelectPreviousGraphicAt(m_pSelectedGraphic, m_ptEnd);
  1955. }
  1956. }
  1957. m_bTrackingSelectRect = TRUE;
  1958. }
  1959. //
  1960. // Make sure to delete the saved bitmap
  1961. //
  1962. if(m_pSelectedGraphic && m_pSelectedGraphic->GraphicTool() == TOOLTYPE_REMOTEPOINTER)
  1963. {
  1964. ((BitmapObj*)m_pSelectedGraphic)->DeleteSavedBitmap();
  1965. }
  1966. }
  1967. }
  1968. void WbDrawingArea::CompleteDeleteMode()
  1969. {
  1970. // select object(s)
  1971. CompleteSelectMode();
  1972. //
  1973. // If we are draging the remote pointer do nothing
  1974. //
  1975. if(m_pSelectedGraphic && m_pSelectedGraphic->GraphicTool() == TOOLTYPE_REMOTEPOINTER)
  1976. {
  1977. return;
  1978. }
  1979. // nuke 'em
  1980. ::PostMessage(g_pMain->m_hwnd, WM_COMMAND, MAKELONG(IDM_DELETE, BN_CLICKED), 0);
  1981. }
  1982. //
  1983. //
  1984. // Function: CompleteMarkAreaMode
  1985. //
  1986. // Purpose: Process a mouse button up event in mark area mode
  1987. //
  1988. //
  1989. void WbDrawingArea::CompleteMarkAreaMode(void)
  1990. {
  1991. // Get a device context for tracking
  1992. HDC hDC = m_hDCCached;
  1993. // Erase the last ellipse (using XOR property)
  1994. if (!EqualPoint(m_ptStart, m_ptEnd))
  1995. {
  1996. // Draw the rectangle
  1997. m_pGraphicTracker->Draw();
  1998. // Use normalized coords
  1999. if (m_ptEnd.x < m_ptStart.x)
  2000. {
  2001. m_rcMarkedArea.left = m_ptEnd.x;
  2002. m_rcMarkedArea.right = m_ptStart.x;
  2003. }
  2004. else
  2005. {
  2006. m_rcMarkedArea.left = m_ptStart.x;
  2007. m_rcMarkedArea.right = m_ptEnd.x;
  2008. }
  2009. if (m_ptEnd.y < m_ptStart.y)
  2010. {
  2011. m_rcMarkedArea.top = m_ptEnd.y;
  2012. m_rcMarkedArea.bottom = m_ptStart.y;
  2013. }
  2014. else
  2015. {
  2016. m_rcMarkedArea.top = m_ptStart.y;
  2017. m_rcMarkedArea.bottom = m_ptEnd.y;
  2018. }
  2019. }
  2020. }
  2021. //
  2022. //
  2023. // Function: CompleteTextMode
  2024. //
  2025. // Purpose: Complete a text mode operation
  2026. //
  2027. //
  2028. void WbDrawingArea::CompleteTextMode()
  2029. {
  2030. // Not much to for text mode. Main text mode actions are taken
  2031. // as a result of a WM_CHAR message and not on mouse events.
  2032. // Just deselect our font if it is still selected
  2033. UnPrimeFont(m_hDCCached);
  2034. }
  2035. //
  2036. //
  2037. // Function: CompleteDrawingMode
  2038. //
  2039. // Purpose: Complete a draw mode operation
  2040. //
  2041. //
  2042. void WbDrawingArea::CompleteDrawingMode()
  2043. {
  2044. // Only draw the line if it has non-zero length
  2045. if (!EqualPoint(m_ptStart, m_ptEnd))
  2046. {
  2047. DrawObj *pObj;
  2048. pObj = m_pGraphicTracker;
  2049. //
  2050. // Erase the last traking
  2051. //
  2052. pObj->Draw();
  2053. if(m_pToolCur->ToolType() == TOOLTYPE_PEN || m_pToolCur->ToolType() == TOOLTYPE_HIGHLIGHT)
  2054. {
  2055. // DO nothing because we drew it already and all the attributes are also already set
  2056. // Stop the update timer
  2057. ::KillTimer(m_hwnd, TIMER_GRAPHIC_UPDATE);
  2058. }
  2059. else
  2060. {
  2061. RECT rect;
  2062. rect.left = m_ptStart.x;
  2063. rect.top = m_ptStart.y;
  2064. rect.right = m_ptEnd.x;
  2065. rect.bottom = m_ptEnd.y;
  2066. pObj->SetRect(&rect);
  2067. pObj->SetPenThickness(m_pToolCur->GetWidth());
  2068. ::InflateRect(&rect, m_pToolCur->GetWidth()/2, m_pToolCur->GetWidth()/2);
  2069. pObj->SetBoundsRect(&rect);
  2070. pObj->SetPenColor(m_pToolCur->GetColor(), TRUE);
  2071. pObj->SetFillColor(m_pToolCur->GetColor(), (m_pToolCur->ToolType() == TOOLTYPE_FILLEDELLIPSE || m_pToolCur->ToolType() == TOOLTYPE_FILLEDBOX));
  2072. pObj->SetROP(m_pToolCur->GetROP());
  2073. POINT deltaPoint;
  2074. deltaPoint.x = m_ptEnd.x - m_ptStart.x;
  2075. deltaPoint.y = m_ptEnd.y - m_ptStart.y;
  2076. pObj->AddPoint(deltaPoint);
  2077. //
  2078. // Draw the object
  2079. //
  2080. pObj->Draw();
  2081. }
  2082. //
  2083. // We are done with this drawing
  2084. //
  2085. pObj->SetIsCompleted(TRUE);
  2086. pObj->SetViewState(unselected_chosen);
  2087. //
  2088. // If the object was alredy added just send an edit
  2089. //
  2090. if(pObj->GetMyWorkspace())
  2091. {
  2092. pObj->OnObjectEdit();
  2093. }
  2094. else
  2095. {
  2096. // Add the object to the list of objects
  2097. pObj->AddToWorkspace();
  2098. }
  2099. }
  2100. else
  2101. {
  2102. delete m_pGraphicTracker;
  2103. }
  2104. m_pGraphicTracker =NULL;
  2105. }
  2106. //
  2107. //
  2108. // Function: EndTextEntry
  2109. //
  2110. // Purpose: The user has finished entering a text object. The parameter
  2111. // indicates whether the changes are to be accepted or
  2112. // discarded.
  2113. //
  2114. //
  2115. void WbDrawingArea::EndTextEntry(BOOL bAccept)
  2116. {
  2117. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::EndTextEntry");
  2118. WorkspaceObj * pWorkspace = m_pTextEditor->GetMyWorkspace();
  2119. // Deactivate the text editor
  2120. DeactivateTextEditor();
  2121. if(bAccept &&( m_pTextEditor->strTextArray.GetSize()) )
  2122. {
  2123. if(!pWorkspace && m_pTextEditor->strTextArray.GetSize())
  2124. {
  2125. m_pTextEditor->AddToWorkspace();
  2126. }
  2127. else
  2128. {
  2129. if(m_pTextEditor->HasTextChanged())
  2130. {
  2131. m_pTextEditor->OnObjectEdit();
  2132. }
  2133. }
  2134. //
  2135. // Tell the other nodes they can edit this object now
  2136. //
  2137. m_pTextEditor->SetViewState(unselected_chosen);
  2138. m_pTextEditor->OnObjectEdit();
  2139. }
  2140. else
  2141. {
  2142. //
  2143. // if we were already added by a WM_TIMER message
  2144. //
  2145. if(pWorkspace)
  2146. {
  2147. //
  2148. // Tell the other nodes we deleted this text.
  2149. //
  2150. m_pTextEditor->OnObjectDelete();
  2151. //
  2152. // If we delete localy we add this object to the trash can, but we really want to delete it
  2153. //
  2154. m_pTextEditor->ClearDeletionFlags();
  2155. pWorkspace->RemoveT126Object(m_pTextEditor);
  2156. }
  2157. else
  2158. {
  2159. delete m_pTextEditor;
  2160. }
  2161. }
  2162. m_pTextEditor = NULL;
  2163. }
  2164. //
  2165. //
  2166. // Function: Zoom
  2167. //
  2168. // Purpose: Toggle the zoom state of the drawing area
  2169. //
  2170. //
  2171. void WbDrawingArea::Zoom(void)
  2172. {
  2173. RECT rcClient;
  2174. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::Zoom");
  2175. // We zoom focusing on the centre of the window
  2176. ::GetClientRect(m_hwnd, &rcClient);
  2177. long xOffset = (rcClient.right - (rcClient.right / m_iZoomOption)) / 2;
  2178. long yOffset = (rcClient.bottom - (rcClient.bottom / m_iZoomOption)) / 2;
  2179. if (m_iZoomFactor != 1)
  2180. {
  2181. // We are already zoomed move back to unzoomed state
  2182. // First save the scroll position in case we return to zoom immediately
  2183. m_posZoomScroll = m_posScroll;
  2184. m_zoomRestoreScroll = TRUE;
  2185. m_posScroll.x -= xOffset;
  2186. m_posScroll.y -= yOffset;
  2187. ::ScaleViewportExtEx(m_hDCCached, 1, m_iZoomFactor, 1, m_iZoomFactor, NULL);
  2188. m_iZoomFactor = 1;
  2189. }
  2190. else
  2191. {
  2192. // We are not zoomed so do it
  2193. if (m_zoomRestoreScroll)
  2194. {
  2195. m_posScroll = m_posZoomScroll;
  2196. }
  2197. else
  2198. {
  2199. m_posScroll.x += xOffset;
  2200. m_posScroll.y += yOffset;
  2201. }
  2202. m_iZoomFactor = m_iZoomOption;
  2203. ::ScaleViewportExtEx(m_hDCCached, m_iZoomFactor, 1, m_iZoomFactor, 1, NULL);
  2204. // ADDED BY RAND - don't allow text editing in zoom mode
  2205. if( (m_pToolCur == NULL) || (m_pToolCur->ToolType() == TOOLTYPE_TEXT) )
  2206. ::SendMessage(g_pMain->m_hwnd, WM_COMMAND, IDM_TOOLS_START, 0 );
  2207. }
  2208. TRACE_MSG(("Set zoom factor to %d", m_iZoomFactor));
  2209. // Update the scroll information
  2210. SetScrollRange(rcClient.right, rcClient.bottom);
  2211. ValidateScrollPos();
  2212. ::SetScrollPos(m_hwnd, SB_HORZ, m_posScroll.x, TRUE);
  2213. ::SetScrollPos(m_hwnd, SB_VERT, m_posScroll.y, TRUE);
  2214. // Update the origin offset from the scroll position
  2215. m_originOffset.cx = m_posScroll.x;
  2216. m_originOffset.cy = m_posScroll.y;
  2217. ::SetWindowOrgEx(m_hDCCached, m_originOffset.cx, m_originOffset.cy, NULL);
  2218. // Tell the parent that the scroll position has changed
  2219. ::PostMessage(g_pMain->m_hwnd, WM_USER_PRIVATE_PARENTNOTIFY, WM_VSCROLL, 0L);
  2220. //
  2221. // Update the tool/menu item states, since our zoom state has changed
  2222. // and that will enable/disable some tools, etc.
  2223. //
  2224. g_pMain->SetMenuStates(::GetSubMenu(::GetMenu(g_pMain->m_hwnd), 3));
  2225. // Redraw the window
  2226. ::InvalidateRect(m_hwnd, NULL, TRUE);
  2227. }
  2228. //
  2229. //
  2230. // Function: SelectTool
  2231. //
  2232. // Purpose: Set the current tool
  2233. //
  2234. //
  2235. void WbDrawingArea::SelectTool(WbTool* pToolNew)
  2236. {
  2237. if(pToolNew == m_pToolCur)
  2238. {
  2239. return;
  2240. }
  2241. // If we are leaving text mode, complete the text entry
  2242. if (m_bTextEditorActive && (m_pToolCur->ToolType() == TOOLTYPE_TEXT)
  2243. && (pToolNew->ToolType() != TOOLTYPE_TEXT))
  2244. {
  2245. // End text entry accepting the changes
  2246. EndTextEntry(TRUE);
  2247. }
  2248. // If we are no longer in select mode, and the marker is present,
  2249. // then remove it and let the tool know it's no longer selected
  2250. if (m_pToolCur != NULL)
  2251. {
  2252. RemoveMarker();
  2253. m_pSelectedGraphic = NULL;
  2254. }
  2255. // Save the new tool
  2256. m_pToolCur = pToolNew;
  2257. }
  2258. //
  2259. //
  2260. // Function: SetSelectionColor
  2261. //
  2262. // Purpose: Set the color of the selected object
  2263. //
  2264. //
  2265. void WbDrawingArea::SetSelectionColor(COLORREF clr)
  2266. {
  2267. RECT rc;
  2268. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SetSelectionColor");
  2269. if(g_pCurrentWorkspace)
  2270. {
  2271. RECT rect;
  2272. T126Obj* pObj;
  2273. WBPOSITION pos = g_pCurrentWorkspace->GetHeadPosition();
  2274. while(pos)
  2275. {
  2276. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2277. if(pObj && pObj->WasSelectedLocally())
  2278. {
  2279. //
  2280. // Set the new pen color
  2281. //
  2282. pObj->SetPenColor(clr, TRUE);
  2283. pObj->SetFillColor(clr, (pObj->GraphicTool() == TOOLTYPE_FILLEDELLIPSE || pObj->GraphicTool() == TOOLTYPE_FILLEDBOX));
  2284. pObj->UnDraw();
  2285. pObj->DrawRect();
  2286. //
  2287. // Send it to other nodes
  2288. //
  2289. pObj->OnObjectEdit();
  2290. //
  2291. // Draw it locally
  2292. //
  2293. pObj->Draw();
  2294. }
  2295. }
  2296. }
  2297. // If the text editor is active - redraw the text in the new color
  2298. if (m_bTextEditorActive)
  2299. {
  2300. // Change the color being used by the editor
  2301. m_pTextEditor->SetPenColor(clr, TRUE);
  2302. // Update the screen
  2303. m_pTextEditor->GetBoundsRect(&rc);
  2304. InvalidateSurfaceRect(&rc, TRUE);
  2305. }
  2306. }
  2307. //
  2308. //
  2309. // Function: SetSelectionWidth
  2310. //
  2311. // Purpose: Set the nib width used to draw the currently selected object
  2312. //
  2313. //
  2314. void WbDrawingArea::SetSelectionWidth(UINT uiWidth)
  2315. {
  2316. if(g_pCurrentWorkspace)
  2317. {
  2318. RECT rect;
  2319. T126Obj* pObj;
  2320. WBPOSITION pos = g_pCurrentWorkspace->GetHeadPosition();
  2321. while(pos)
  2322. {
  2323. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2324. if(pObj && pObj->WasSelectedLocally())
  2325. {
  2326. //
  2327. // Undraw the object
  2328. //
  2329. pObj->UnDraw();
  2330. pObj->DrawRect();
  2331. //
  2332. // Get the correct width for each object
  2333. //
  2334. WbTool* pSelectedTool = g_pMain->m_ToolArray[pObj->GraphicTool()];
  2335. pSelectedTool->SetWidthIndex(uiWidth);
  2336. pObj->SetPenThickness(pSelectedTool->GetWidth());
  2337. //
  2338. // Send it to other nodes
  2339. //
  2340. pObj->OnObjectEdit();
  2341. //
  2342. // Draw it locally
  2343. //
  2344. pObj->Draw();
  2345. }
  2346. }
  2347. }
  2348. }
  2349. //
  2350. //
  2351. // Function: SetSelectionFont
  2352. //
  2353. // Purpose: Set the font used by the currently selected object
  2354. //
  2355. //
  2356. void WbDrawingArea::SetSelectionFont(HFONT hFont)
  2357. {
  2358. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SetSelectionFont");
  2359. // Define rectangles for redrawing
  2360. RECT rcOldBounds;
  2361. RECT rcNewBounds;
  2362. // Pass the font onto the text editor
  2363. // If the text editor is active - redraw the text in the new font
  2364. if (m_bTextEditorActive)
  2365. {
  2366. m_pTextEditor->GetBoundsRect(&rcOldBounds);
  2367. m_pTextEditor->SetFont(hFont);
  2368. // Get the new rectangle of the text
  2369. m_pTextEditor->GetBoundsRect(&rcNewBounds);
  2370. // Remove and destroy the text cursor to ensure that it
  2371. // gets re-drawn with the new size for the font
  2372. // Update the screen
  2373. InvalidateSurfaceRect(&rcOldBounds, TRUE);
  2374. InvalidateSurfaceRect(&rcNewBounds, TRUE);
  2375. // get the text cursor back
  2376. ActivateTextEditor( TRUE );
  2377. }
  2378. if(g_pCurrentWorkspace)
  2379. {
  2380. T126Obj* pObj;
  2381. WBPOSITION pos = g_pCurrentWorkspace->GetHeadPosition();
  2382. while(pos)
  2383. {
  2384. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2385. if(pObj && pObj->WasSelectedLocally() && pObj->GraphicTool() == TOOLTYPE_TEXT)
  2386. {
  2387. //
  2388. // Set the new pen color
  2389. //
  2390. ((TextObj*)pObj)->SetFont(hFont);
  2391. pObj->UnDraw();
  2392. pObj->DrawRect();
  2393. //
  2394. // Send it to other nodes
  2395. //
  2396. pObj->OnObjectEdit();
  2397. //
  2398. // Draw it locally
  2399. //
  2400. pObj->Draw();
  2401. }
  2402. }
  2403. }
  2404. }
  2405. //
  2406. //
  2407. // Function: OnSetFocus
  2408. //
  2409. // Purpose: The window is getting the focus
  2410. //
  2411. //
  2412. void WbDrawingArea::OnSetFocus(void)
  2413. {
  2414. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::OnSetFocus");
  2415. //
  2416. // If we are in text mode, we must make the text cursor visible.
  2417. //
  2418. if (m_bTextEditorActive && (m_pToolCur->ToolType() == TOOLTYPE_TEXT))
  2419. {
  2420. ActivateTextEditor(TRUE);
  2421. }
  2422. }
  2423. //
  2424. //
  2425. // Function: OnActivate
  2426. //
  2427. // Purpose: The window is being activated or deactivated
  2428. //
  2429. //
  2430. void WbDrawingArea::OnActivate(UINT uiState)
  2431. {
  2432. // Check if we are being activated or deactivated
  2433. if (uiState)
  2434. {
  2435. // We are being activated, get the focus as well
  2436. ::SetFocus(m_hwnd);
  2437. // If we are in text mode, we must make the text cursor visible
  2438. if (m_bTextEditorActive && (m_pToolCur->ToolType() == TOOLTYPE_TEXT))
  2439. {
  2440. ActivateTextEditor(TRUE);
  2441. }
  2442. }
  2443. else
  2444. {
  2445. // We are being deactivated
  2446. DeactivateTextEditor();
  2447. }
  2448. }
  2449. //
  2450. //
  2451. // Function: DeleteSelection
  2452. //
  2453. // Purpose: Delete the currently selected object
  2454. //
  2455. //
  2456. void WbDrawingArea::DeleteSelection()
  2457. {
  2458. m_pSelectedGraphic = NULL;
  2459. }
  2460. //
  2461. //
  2462. // Function: GetSelection
  2463. //
  2464. // Purpose: Return the currently selected graphic (or NULL if none).
  2465. //
  2466. //
  2467. T126Obj* WbDrawingArea::GetSelection()
  2468. {
  2469. T126Obj* pGraphic = NULL;
  2470. // If there is an object currently selected...
  2471. if (GraphicSelected())
  2472. {
  2473. // ...return it
  2474. pGraphic = m_pSelectedGraphic;
  2475. }
  2476. return pGraphic;
  2477. }
  2478. //
  2479. //
  2480. // Function: BringToTopSelection
  2481. //
  2482. // Purpose: Bring the currently selected object to the top
  2483. //
  2484. //
  2485. LRESULT WbDrawingArea::BringToTopSelection(BOOL editedLocally, T126Obj * pT126Obj)
  2486. {
  2487. T126Obj* pObj;
  2488. WBPOSITION posTail;
  2489. WBPOSITION pos;
  2490. WBPOSITION myPos;
  2491. WorkspaceObj *pWorkspace;
  2492. if(pT126Obj)
  2493. {
  2494. pos = pT126Obj->GetMyPosition();
  2495. pWorkspace = pT126Obj->GetMyWorkspace();
  2496. }
  2497. else
  2498. {
  2499. pos = g_pCurrentWorkspace->GetHeadPosition();
  2500. pWorkspace = g_pCurrentWorkspace;
  2501. }
  2502. posTail = pWorkspace->GetTailPosition();
  2503. while(pos && pos != posTail)
  2504. {
  2505. pObj = pWorkspace->GetNextObject(pos);
  2506. //
  2507. // If the graphic is selected
  2508. //
  2509. if( pObj && (pObj->IsSelected() &&
  2510. //
  2511. // We were called locally and the graphic is selected locally
  2512. //
  2513. ((editedLocally && pObj->WasSelectedLocally()) ||
  2514. //
  2515. // We were called because the graphic got edited remotely
  2516. // and it is selected remotely
  2517. ((!editedLocally && pObj->WasSelectedRemotely())))))
  2518. {
  2519. myPos = pObj->GetMyPosition();
  2520. pObj = pWorkspace->RemoveAt(myPos);
  2521. pWorkspace->AddTail(pObj);
  2522. if(pT126Obj)
  2523. {
  2524. ::InvalidateRect(m_hwnd, NULL, TRUE);
  2525. return S_OK;
  2526. }
  2527. //
  2528. // send change of z order
  2529. //
  2530. pObj->ResetAttrib();
  2531. pObj->SetZOrder(front);
  2532. pObj->OnObjectEdit();
  2533. //
  2534. // Unselect it
  2535. //
  2536. pObj->UnselectDrawingObject();
  2537. RECT rect;
  2538. pObj->GetBoundsRect(&rect);
  2539. InvalidateSurfaceRect(&rect,TRUE);
  2540. }
  2541. }
  2542. return S_OK;
  2543. }
  2544. //
  2545. //
  2546. // Function: SendToBackSelection
  2547. //
  2548. // Purpose: Send the currently marked object to the back
  2549. //
  2550. //
  2551. LRESULT WbDrawingArea::SendToBackSelection(BOOL editedLocally, T126Obj * pT126Obj)
  2552. {
  2553. // If there is an object currently selected...
  2554. T126Obj* pObj;
  2555. WBPOSITION posHead;
  2556. WBPOSITION myPos;
  2557. WBPOSITION pos;
  2558. WorkspaceObj *pWorkspace;
  2559. if(pT126Obj)
  2560. {
  2561. pos = pT126Obj->GetMyPosition();
  2562. pWorkspace = pT126Obj->GetMyWorkspace();
  2563. }
  2564. else
  2565. {
  2566. pos = g_pCurrentWorkspace->GetTailPosition();
  2567. pWorkspace = g_pCurrentWorkspace;
  2568. }
  2569. posHead = pWorkspace->GetHeadPosition();
  2570. while(pos && pos != posHead)
  2571. {
  2572. pObj = pWorkspace->GetPreviousObject(pos);
  2573. //
  2574. // If the graphic is selected
  2575. //
  2576. if( (pObj->IsSelected() &&
  2577. //
  2578. // We were called locally and the graphic is selected locally
  2579. //
  2580. ((editedLocally && pObj->WasSelectedLocally()) ||
  2581. //
  2582. // We were called because the graphic got edited remotely
  2583. // and it is selected remotely
  2584. ((!editedLocally && pObj->WasSelectedRemotely())))))
  2585. {
  2586. myPos = pObj->GetMyPosition();
  2587. pObj = pWorkspace->RemoveAt(myPos);
  2588. pWorkspace->AddHead(pObj);
  2589. if(pT126Obj)
  2590. {
  2591. ::InvalidateRect(m_hwnd, NULL, TRUE);
  2592. return S_OK;
  2593. }
  2594. //
  2595. // send change of z order
  2596. //
  2597. pObj->ResetAttrib();
  2598. pObj->SetZOrder(back);
  2599. pObj->OnObjectEdit();
  2600. //
  2601. // Unselect it
  2602. //
  2603. pObj->UnselectDrawingObject();
  2604. RECT rect;
  2605. pObj->GetBoundsRect(&rect);
  2606. ::InvalidateRect(m_hwnd, NULL , TRUE);
  2607. }
  2608. }
  2609. return S_OK;
  2610. }
  2611. //
  2612. //
  2613. // Function: Clear
  2614. //
  2615. // Purpose: Clear the drawing area.
  2616. //
  2617. //
  2618. void WbDrawingArea::Clear()
  2619. {
  2620. // Remove the recorded objects
  2621. // PG_Clear(m_hPage);
  2622. // The page will be redrawn after an event generated by the clear request
  2623. }
  2624. //
  2625. //
  2626. // Function: Attach
  2627. //
  2628. // Purpose: Change the page the window is displaying
  2629. //
  2630. //
  2631. void WbDrawingArea::Attach(WorkspaceObj* pNewWorkspace)
  2632. {
  2633. // Accept any text being edited
  2634. if (m_bTextEditorActive)
  2635. {
  2636. EndTextEntry(TRUE);
  2637. }
  2638. // finish any drawing operation now
  2639. if (m_bLButtonDown)
  2640. {
  2641. OnLButtonUp(0, m_ptStart.x, m_ptStart.y);
  2642. }
  2643. // Get rid of the selection
  2644. ClearSelection();
  2645. // Save the new page details
  2646. g_pCurrentWorkspace = pNewWorkspace;
  2647. if(IsSynced())
  2648. {
  2649. g_pConferenceWorkspace = g_pCurrentWorkspace;
  2650. }
  2651. // Force a redraw of the window to show the new contents
  2652. ::InvalidateRect(m_hwnd, NULL, TRUE);
  2653. }
  2654. //
  2655. //
  2656. // Function: DrawMarker
  2657. //
  2658. // Purpose: Draw the graphic object marker
  2659. //
  2660. //
  2661. void WbDrawingArea::DrawMarker(HDC hDC)
  2662. {
  2663. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::DrawMarker");
  2664. // Draw the marker
  2665. m_pMarker->Draw();
  2666. }
  2667. //
  2668. //
  2669. // Function: PutMarker
  2670. //
  2671. // Purpose: Draw the graphic object marker
  2672. //
  2673. //
  2674. void WbDrawingArea::PutMarker(HDC hDC, BOOL bDraw)
  2675. {
  2676. }
  2677. //
  2678. //
  2679. // Function: RemoveMarker
  2680. //
  2681. // Purpose: Remove the graphic object marker
  2682. //
  2683. //
  2684. void WbDrawingArea::RemoveMarker()
  2685. {
  2686. if(g_pCurrentWorkspace)
  2687. {
  2688. T126Obj* pObj;
  2689. WBPOSITION pos;
  2690. pos = g_pCurrentWorkspace->GetHeadPosition();
  2691. while(pos)
  2692. {
  2693. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2694. if(pObj && pObj->WasSelectedLocally())
  2695. {
  2696. pObj->UnselectDrawingObject();
  2697. }
  2698. }
  2699. }
  2700. }
  2701. //
  2702. //
  2703. // Function: ActivateTextEditor
  2704. //
  2705. // Purpose: Start a text editing session
  2706. //
  2707. //
  2708. void WbDrawingArea::ActivateTextEditor( BOOL bPutUpCusor )
  2709. {
  2710. // Record that the editor is now active
  2711. m_bTextEditorActive = TRUE;
  2712. // show editbox
  2713. m_pTextEditor->ShowBox( SW_SHOW );
  2714. // Start the timer for updating the text
  2715. m_pTextEditor->SetTimer( DRAW_GRAPHICUPDATEDELAY);
  2716. }
  2717. //
  2718. //
  2719. // Function: DeactivateTextEditor
  2720. //
  2721. // Purpose: End a text editing session
  2722. //
  2723. //
  2724. void WbDrawingArea::DeactivateTextEditor(void)
  2725. {
  2726. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::DeactivateTextEditor");
  2727. // Stop the update timer
  2728. m_pTextEditor->KillTimer();
  2729. // Show that we are not editing any text
  2730. m_bTextEditorActive = FALSE;
  2731. // hide editbox
  2732. m_pTextEditor->ShowBox( SW_HIDE );
  2733. }
  2734. //
  2735. //
  2736. // Function: SurfaceToClient
  2737. //
  2738. // Purpose: Convert a point in surface co-ordinates to client
  2739. // co-ordinates (taking account of the current zoom factor).
  2740. //
  2741. //
  2742. void WbDrawingArea::SurfaceToClient(LPPOINT lppoint)
  2743. {
  2744. lppoint->x -= m_originOffset.cx;
  2745. lppoint->x *= m_iZoomFactor;
  2746. lppoint->y -= m_originOffset.cy;
  2747. lppoint->y *= m_iZoomFactor;
  2748. }
  2749. //
  2750. //
  2751. // Function: ClientToSurface
  2752. //
  2753. // Purpose: Convert a point in client co-ordinates to surface
  2754. // co-ordinates (taking account of the current zoom factor).
  2755. //
  2756. //
  2757. void WbDrawingArea::ClientToSurface(LPPOINT lppoint)
  2758. {
  2759. ASSERT(m_iZoomFactor != 0);
  2760. lppoint->x /= m_iZoomFactor;
  2761. lppoint->x += m_originOffset.cx;
  2762. lppoint->y /= m_iZoomFactor;
  2763. lppoint->y += m_originOffset.cy;
  2764. }
  2765. //
  2766. //
  2767. // Function: SurfaceToClient
  2768. //
  2769. // Purpose: Convert a rectangle in surface co-ordinates to client
  2770. // co-ordinates (taking account of the current zoom factor).
  2771. //
  2772. //
  2773. void WbDrawingArea::SurfaceToClient(LPRECT lprc)
  2774. {
  2775. SurfaceToClient((LPPOINT)&lprc->left);
  2776. SurfaceToClient((LPPOINT)&lprc->right);
  2777. }
  2778. //
  2779. //
  2780. // Function: ClientToSurface
  2781. //
  2782. // Purpose: Convert a rectangle in client co-ordinates to surface
  2783. // co-ordinates (taking account of the current zoom factor).
  2784. //
  2785. //
  2786. void WbDrawingArea::ClientToSurface(LPRECT lprc)
  2787. {
  2788. ClientToSurface((LPPOINT)&lprc->left);
  2789. ClientToSurface((LPPOINT)&lprc->right);
  2790. }
  2791. //
  2792. //
  2793. // Function: GraphicSelected
  2794. //
  2795. // Purpose: Return TRUE if a graphic is currently selected
  2796. //
  2797. //
  2798. BOOL WbDrawingArea::GraphicSelected(void)
  2799. {
  2800. if(g_pCurrentWorkspace)
  2801. {
  2802. T126Obj* pObj;
  2803. WBPOSITION pos = g_pCurrentWorkspace->GetHeadPosition();
  2804. while(pos)
  2805. {
  2806. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2807. if(pObj && pObj->WasSelectedLocally())
  2808. {
  2809. m_pSelectedGraphic = pObj;
  2810. return TRUE;
  2811. }
  2812. }
  2813. }
  2814. return FALSE;
  2815. }
  2816. BOOL WbDrawingArea::MoveSelectedGraphicBy(LONG x, LONG y)
  2817. {
  2818. T126Obj* pObj;
  2819. WBPOSITION pos = g_pCurrentWorkspace->GetHeadPosition();
  2820. while(pos)
  2821. {
  2822. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2823. if(pObj && pObj->WasSelectedLocally())
  2824. {
  2825. pObj->MoveBy(x, y);
  2826. }
  2827. }
  2828. return FALSE;
  2829. }
  2830. void WbDrawingArea::EraseSelectedDrawings(void)
  2831. {
  2832. T126Obj* pObj;
  2833. //
  2834. // Burn trash
  2835. //
  2836. pObj = (T126Obj *)g_pTrash->RemoveTail();
  2837. while (pObj != NULL)
  2838. {
  2839. delete pObj;
  2840. pObj = (T126Obj *) g_pTrash->RemoveTail();
  2841. }
  2842. WBPOSITION pos = g_pCurrentWorkspace->GetHeadPosition();
  2843. while(pos)
  2844. {
  2845. pObj = (T126Obj*)g_pCurrentWorkspace->GetNextObject(pos);
  2846. if(pObj && pObj->WasSelectedLocally() && pObj->GraphicTool() != TOOLTYPE_REMOTEPOINTER)
  2847. {
  2848. pObj->DeletedLocally();
  2849. g_pCurrentWorkspace->RemoveT126Object(pObj);
  2850. }
  2851. }
  2852. }
  2853. void WbDrawingArea::EraseInitialDrawFinal(LONG x, LONG y, BOOL editedLocally, T126Obj* pObj)
  2854. {
  2855. T126Obj* pGraphic;
  2856. WorkspaceObj * pWorkspace; WBPOSITION pos;
  2857. if(pObj)
  2858. {
  2859. pWorkspace = pObj->GetMyWorkspace();
  2860. pGraphic = pObj;
  2861. }
  2862. else
  2863. {
  2864. pWorkspace = g_pCurrentWorkspace;
  2865. }
  2866. //
  2867. // Check if the objects workspace is valid or if there is a current workspace
  2868. //
  2869. if(pWorkspace == NULL)
  2870. {
  2871. return;
  2872. }
  2873. pos = pWorkspace->GetHeadPosition();
  2874. while(pos)
  2875. {
  2876. // if we are talking about an specifc object
  2877. if(!pObj)
  2878. {
  2879. pGraphic = (T126Obj*)pWorkspace->GetNextObject(pos);
  2880. }
  2881. //
  2882. // If the graphic is selected
  2883. //
  2884. if(pGraphic &&
  2885. //
  2886. // We were called locally and the graphic is selected locally
  2887. //
  2888. ((editedLocally && pGraphic->WasSelectedLocally()) ||
  2889. //
  2890. // We were called because the graphic got edited remotely
  2891. // and it is selected remotely
  2892. //
  2893. (!editedLocally)))
  2894. {
  2895. POINT finalAnchorPoint;
  2896. RECT initialRect;
  2897. RECT rect;
  2898. RECT initialBoundsRect;
  2899. RECT boundsRect;
  2900. //
  2901. // Get The final Rects
  2902. //
  2903. pGraphic->GetRect(&rect);
  2904. pGraphic->GetBoundsRect(&boundsRect);
  2905. initialRect = rect;
  2906. initialBoundsRect = boundsRect;
  2907. pGraphic->GetAnchorPoint(&finalAnchorPoint);
  2908. //
  2909. // Find out were the drawing was
  2910. //
  2911. ::OffsetRect(&initialRect, x, y);
  2912. ::OffsetRect(&initialBoundsRect, x, y);
  2913. pGraphic->SetRect(&initialRect);
  2914. pGraphic->SetBoundsRect(&initialBoundsRect);
  2915. pGraphic->SetAnchorPoint(finalAnchorPoint.x + x, finalAnchorPoint.y + y);
  2916. //
  2917. // Erase initial drawing
  2918. //
  2919. pGraphic->UnDraw();
  2920. //
  2921. //Erase the selection rectangle only if we selected locally
  2922. //
  2923. if(editedLocally)
  2924. {
  2925. pGraphic->DrawRect();
  2926. }
  2927. //
  2928. // The only attributes we want to send unselected and anchorpoint
  2929. //
  2930. pGraphic->ResetAttrib();
  2931. //
  2932. // Restore rectangles and draw the object in the final position
  2933. //
  2934. pGraphic->SetRect(&rect);
  2935. pGraphic->SetBoundsRect(&boundsRect);
  2936. pGraphic->SetAnchorPoint(finalAnchorPoint.x, finalAnchorPoint.y);
  2937. pGraphic->Draw(FALSE);
  2938. //
  2939. // Don't send it if it was not created locally
  2940. //
  2941. if(editedLocally)
  2942. {
  2943. pGraphic->EditedLocally();
  2944. //
  2945. // Sends the final drawing to the other nodes
  2946. //
  2947. pGraphic->OnObjectEdit();
  2948. //
  2949. // This will remove the selection box and send a
  2950. // edit PDU telling other nodes the object is not selected
  2951. //
  2952. pGraphic->UnselectDrawingObject();
  2953. }
  2954. }
  2955. //
  2956. // Just moved one specifc object
  2957. //
  2958. if(pObj != NULL)
  2959. {
  2960. return;
  2961. }
  2962. }
  2963. }
  2964. //
  2965. //
  2966. // Function: SelectGraphic
  2967. //
  2968. // Purpose: Select a graphic - save the pointer to the graphic and
  2969. // draw the marker on it.
  2970. //
  2971. //
  2972. void WbDrawingArea::SelectGraphic(T126Obj* pGraphic,
  2973. BOOL bEnableForceAdd,
  2974. BOOL bForceAdd )
  2975. {
  2976. BOOL bZapCurrentSelection;
  2977. RECT rc;
  2978. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::SelectGraphic");
  2979. if(pGraphic->IsSelected() && pGraphic->WasSelectedLocally())
  2980. {
  2981. pGraphic->UnselectDrawingObject();
  2982. return;
  2983. }
  2984. else if(pGraphic->IsSelected() && pGraphic->WasSelectedRemotely())
  2985. {
  2986. return;
  2987. }
  2988. else
  2989. {
  2990. // new selection, add to list or replace list?
  2991. if( bEnableForceAdd )
  2992. {
  2993. bZapCurrentSelection = !bForceAdd;
  2994. }
  2995. else
  2996. {
  2997. bZapCurrentSelection = ((GetAsyncKeyState( VK_SHIFT ) >= 0) && (GetAsyncKeyState( VK_CONTROL ) >= 0));
  2998. }
  2999. if( bZapCurrentSelection )
  3000. {
  3001. // replace list
  3002. RemoveMarker();
  3003. }
  3004. }
  3005. // Update the attributes window to show graphic is selected
  3006. m_pToolCur->SelectGraphic(pGraphic);
  3007. pGraphic->SelectDrawingObject();
  3008. HWND hwndParent = ::GetParent(m_hwnd);
  3009. if (hwndParent != NULL)
  3010. {
  3011. ::PostMessage(hwndParent, WM_USER_UPDATE_ATTRIBUTES, 0, 0);
  3012. }
  3013. }
  3014. //
  3015. //
  3016. // Function: DeselectGraphic
  3017. //
  3018. // Purpose: Deselect a graphic - remove the marker and delete the
  3019. // graphic object associated with it.
  3020. //
  3021. //
  3022. void WbDrawingArea::DeselectGraphic(void)
  3023. {
  3024. HWND hwndParent = ::GetParent(m_hwnd);
  3025. if (hwndParent != NULL)
  3026. {
  3027. ::PostMessage(hwndParent, WM_USER_UPDATE_ATTRIBUTES, 0, 0);
  3028. }
  3029. }
  3030. //
  3031. //
  3032. // Function: GetVisibleRect
  3033. //
  3034. // Purpose: Return the rectangle of the surface currently visible in the
  3035. // drawing area window.
  3036. //
  3037. //
  3038. void WbDrawingArea::GetVisibleRect(LPRECT lprc)
  3039. {
  3040. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::VisibleRect");
  3041. // Get the client rectangle
  3042. ::GetClientRect(m_hwnd, lprc);
  3043. // Convert to surface co-ordinates
  3044. ClientToSurface(lprc);
  3045. }
  3046. //
  3047. //
  3048. // Function: MoveOntoSurface
  3049. //
  3050. // Purpose: If a given point is outwith the surface rect, move it on
  3051. //
  3052. //
  3053. void WbDrawingArea::MoveOntoSurface(LPPOINT lppoint)
  3054. {
  3055. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::MoveOntoSurface");
  3056. //
  3057. // Make sure that the position is within the surface rect
  3058. //
  3059. if (lppoint->x < 0)
  3060. {
  3061. lppoint->x = 0;
  3062. }
  3063. else if (lppoint->x >= DRAW_WIDTH)
  3064. {
  3065. lppoint->x = DRAW_WIDTH - 1;
  3066. }
  3067. if (lppoint->y < 0)
  3068. {
  3069. lppoint->y = 0;
  3070. }
  3071. else if (lppoint->y >= DRAW_HEIGHT)
  3072. {
  3073. lppoint->y = DRAW_HEIGHT - 1;
  3074. }
  3075. }
  3076. //
  3077. //
  3078. // Function: GetOrigin
  3079. //
  3080. // Purpose: Provide current origin of display
  3081. //
  3082. //
  3083. void WbDrawingArea::GetOrigin(LPPOINT lppoint)
  3084. {
  3085. lppoint->x = m_originOffset.cx;
  3086. lppoint->y = m_originOffset.cy;
  3087. }
  3088. void WbDrawingArea::ShutDownDC(void)
  3089. {
  3090. UnPrimeDC(m_hDCCached);
  3091. if (m_hDCWindow != NULL)
  3092. {
  3093. ::ReleaseDC(m_hwnd, m_hDCWindow);
  3094. m_hDCWindow = NULL;
  3095. }
  3096. m_hDCCached = NULL;
  3097. }
  3098. void WbDrawingArea::ClearSelection( void )
  3099. {
  3100. MLZ_EntryOut(ZONE_FUNCTION, "WbDrawingArea::ClearSelection");
  3101. RemoveMarker();
  3102. g_pMain->OnUpdateAttributes();
  3103. }
  3104. void WbDrawingArea::OnCancelMode( void )
  3105. {
  3106. // We were dragging but lost mouse control, gracefully end the drag (NM4db:573)
  3107. POINT pt;
  3108. ::GetCursorPos(&pt);
  3109. ::ScreenToClient(m_hwnd, &pt);
  3110. OnLButtonUp(0, pt.x, pt.y);
  3111. m_bLButtonDown = FALSE;
  3112. }