Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2649 lines
64 KiB

  1. /*
  2. * DISP.CPP
  3. *
  4. * Purpose:
  5. * CDisplay class
  6. *
  7. * Owner:
  8. * Original RichEdit code: David R. Fulmer
  9. * Christian Fortini
  10. * Murray Sargent
  11. * Jon Matousek - smooth scrolling.
  12. * Keith Curtis - cleanup metafile handling, generalized textflow support,
  13. * changed our clipping model to work better with italics.
  14. *
  15. *
  16. * Copyright (c) 1995-2000 Microsoft Corporation. All rights reserved.
  17. */
  18. #include "_common.h"
  19. #include "_disp.h"
  20. #include "_edit.h"
  21. #include "_select.h"
  22. #include "_font.h"
  23. #include "_measure.h"
  24. #include "_osdc.h"
  25. #include "_dfreeze.h"
  26. ASSERTDATA
  27. // Decimal point precision of smooth scrolling calculations.
  28. #define SMOOTH_PRECISION (100000L)
  29. // =========================== Invariant stuff ======================================================
  30. #define DEBUG_CLASSNAME CDisplay
  31. #include "_invar.h"
  32. #ifdef DEBUG
  33. BOOL
  34. CDisplay::Invariant( void ) const
  35. {
  36. AssertSz(_dvpView >= 0, "CDisplay::Invariant invalid _dvpView");
  37. AssertSz(_dvpClient >= 0,
  38. "CDisplay::Invariant invalid _dvpClient");
  39. return TRUE;
  40. }
  41. #endif
  42. // Auto scroll constants
  43. #define dwAutoScrollUp 1
  44. #define dwAutoScrollDown 2
  45. #define dwAutoScrollLeft 3
  46. #define dwAutoScrollRight 4
  47. //Text flow utility functions
  48. void GetDupDvpFromRect(const RECT &rc, TFLOW tflow, LONG &dup, LONG &dvp)
  49. {
  50. LONG dxp = rc.right - rc.left;
  51. LONG dyp = rc.bottom - rc.top;
  52. if (!IsUVerticalTflow(tflow)) //Normal case
  53. {
  54. dup = dxp;
  55. dvp = dyp;
  56. }
  57. else
  58. {
  59. dup = dyp;
  60. dvp = dxp;
  61. }
  62. }
  63. void GetDxpDypFromDupDvp(LONG dup, LONG dvp, TFLOW tflow, LONG &dxp, LONG &dyp)
  64. {
  65. switch(tflow)
  66. {
  67. case tflowES:
  68. dxp = dup;
  69. dyp = dvp;
  70. break;
  71. case tflowSW:
  72. dxp = -dvp;
  73. dyp = dup;
  74. break;
  75. case tflowWN:
  76. dyp = -dvp;
  77. dxp = -dup;
  78. break;
  79. case tflowNE:
  80. dyp = -dup;
  81. dxp = dvp;
  82. break;
  83. default:
  84. Assert(0);
  85. }
  86. }
  87. void GetDxpDypFromRectuv(const RECTUV &rc, TFLOW tflow, LONG &dxp, LONG &dyp)
  88. {
  89. LONG dup = rc.right - rc.left;
  90. LONG dvp = rc.bottom - rc.top;
  91. if (!IsUVerticalTflow(tflow)) //Normal case
  92. {
  93. dxp = dup;
  94. dyp = dvp;
  95. }
  96. else
  97. {
  98. dxp = dvp;
  99. dyp = dup;
  100. }
  101. }
  102. // =========================== CLed =====================================================
  103. void CLed::SetMax(const CDisplay * const pdp)
  104. {
  105. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CLed::SetMax");
  106. _cpMatchNew = _cpMatchOld = pdp->_ped->GetTextLength();
  107. _iliMatchNew = _iliMatchOld = max(0, pdp->LineCount() - 1);
  108. _vpMatchNew = _vpMatchOld = pdp->GetHeight();
  109. }
  110. // =========================== CDisplay =====================================================
  111. DWORD CDisplay::_dwTimeScrollNext; // time for next scroll step
  112. DWORD CDisplay::_dwScrollLast; // last scroll action
  113. /*
  114. * CDisplay::ConvertScrollToUPos(uPos)
  115. *
  116. * @mfunc
  117. * Calculate real scroll position from scroll position
  118. *
  119. * @rdesc
  120. * X position from scroll
  121. *
  122. * @devnote
  123. * This routine exists because the thumb position messages
  124. * are limited to 16-bits so we extrapolate when the Y position
  125. * gets greater than that.
  126. */
  127. LONG CDisplay::ConvertScrollToUPos(
  128. LONG uPos) //@parm Scroll position
  129. {
  130. LONG uMax = GetMaxUScroll();
  131. // Has maximum scroll range exceeded 16-bits?
  132. if (uMax >= _UI16_MAX)
  133. {
  134. // Yes - Extrapolate to the "real" x Positioin
  135. uPos = MulDiv(uPos, uMax, _UI16_MAX);
  136. }
  137. return uPos;
  138. }
  139. /*
  140. * CDisplay::ConvertUPosToScrollPos(uPos)
  141. *
  142. * @mfunc
  143. * Calculate scroll position from X position in document.
  144. *
  145. * @rdesc
  146. * Scroll position from X position
  147. *
  148. * @devnote
  149. * This routine exists because the thumb position messages
  150. * are limited to 16-bits so we extrapolate when the Y position
  151. * gets greater than that.
  152. *
  153. */
  154. LONG CDisplay::ConvertUPosToScrollPos(
  155. LONG uPos) //@parm Y position in document
  156. {
  157. LONG uMax = GetMaxUScroll();
  158. // Has maximum scroll range exceeded 16-bits?
  159. if(uMax >= _UI16_MAX)
  160. {
  161. // Yes - Extrapolate to the scroll bar position
  162. uPos = MulDiv(uPos, _UI16_MAX, uMax);
  163. }
  164. return uPos;
  165. }
  166. /*
  167. * CDisplay::ConvertVPosToMax(vPos)
  168. *
  169. * @mfunc
  170. * Calculate the real scroll position from the scroll position
  171. *
  172. * @rdesc
  173. * V position from scroll
  174. *
  175. * @devnote
  176. * This routine exists because the thumb position messages
  177. * are limited to 16-bits so we extrapolate when the V position
  178. * gets greater than that.
  179. */
  180. LONG CDisplay::ConvertVPosToScrollPos(
  181. LONG vPos) //@parm Scroll position
  182. {
  183. // Default is single line edit control which cannot have Y-Scroll bars
  184. return 0;
  185. }
  186. CDisplay::CDisplay (CTxtEdit* ped) :
  187. CDevDesc (ped)
  188. {
  189. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::CDisplay");
  190. _TEST_INVARIANT_
  191. _fRecalcDone = TRUE;
  192. }
  193. CDisplay::~CDisplay()
  194. {
  195. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::~CDisplay");
  196. _TEST_INVARIANT_
  197. CNotifyMgr *pnm = _ped->GetNotifyMgr();
  198. if(pnm)
  199. pnm->Remove(this);
  200. CheckRemoveSmoothVScroll();
  201. if (_padc)
  202. delete _padc;
  203. #ifndef NOLINESERVICES
  204. if (g_pols)
  205. g_pols->DestroyLine(this);
  206. #endif
  207. }
  208. /*
  209. * CDisplay::InitFromDisplay(pdp)
  210. *
  211. * @mfunc initialize this display from another display instance.
  212. *
  213. * @comment
  214. * copy *only* the members that will remain constant
  215. * between two different display instances. Currently, that
  216. * is only the view variables and device descriptor info.
  217. */
  218. void CDisplay::InitFromDisplay(
  219. const CDisplay *pdp)
  220. {
  221. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::InitFromDisplay");
  222. _dupView = pdp->_dupView;
  223. _dvpView = pdp->_dvpView;
  224. _dvpClient = pdp->_dvpClient;
  225. // Don't save DC; just coordinate information.
  226. _dxpInch = pdp->_dxpInch;
  227. _dypInch = pdp->_dypInch;
  228. SetTflow(pdp->GetTflow());
  229. // If display we are copying from is active display,
  230. // then this new display is the active display.
  231. _fActive = pdp->_fActive;
  232. }
  233. /*
  234. * CDisplay::Init()
  235. *
  236. * @mfunc Initializes CDisplay
  237. *
  238. * @rdesc
  239. * TRUE iff initialization succeeded
  240. */
  241. BOOL CDisplay::Init()
  242. {
  243. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::Init");
  244. CNotifyMgr *pnm = _ped->GetNotifyMgr();
  245. if(pnm)
  246. pnm->Add(this);
  247. return TRUE;
  248. }
  249. /*
  250. * CDisplay::GetSelBarInPixels()
  251. *
  252. * @mfunc
  253. * Helper that returns size of selection bar in device units.
  254. *
  255. * @rdesc
  256. * Size of selection bar (is 0 if none).
  257. */
  258. LONG CDisplay::GetSelBarInPixels() const
  259. {
  260. return HimetricUtoDU(_ped->TxGetSelectionBarWidth());
  261. }
  262. //================================ Device drivers ===================================
  263. /*
  264. * CDisplay::SetMainTargetDC(hdc, dulTarget)
  265. *
  266. * @mfunc
  267. * Sets a target device for this display and updates view
  268. *
  269. * Note:
  270. * No support for targetDC in the base CDisplay class.
  271. *
  272. * Note:
  273. * Target device can't be a metafile (can get char width out of a
  274. * metafile)
  275. *
  276. * @rdesc
  277. * TRUE if success
  278. */
  279. BOOL CDisplay::SetMainTargetDC(
  280. HDC hdc, //@parm Target DC, NULL for same as rendering device
  281. LONG dulTarget) //@parm Max width of lines (not used if target device is screen)
  282. {
  283. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::SetMainTargetDC");
  284. _TEST_INVARIANT_
  285. return TRUE;
  286. }
  287. BOOL CDisplay::SetTargetDC(
  288. HDC hdc, LONG dxpInch, LONG dypInch)
  289. {
  290. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::SetTargetDC");
  291. _TEST_INVARIANT_
  292. return TRUE;
  293. }
  294. /*
  295. * CDisplay::SetDrawInfo(pdi, dwDrawAspect, lindex, pvAspect, ptd, hicTargetDev)
  296. *
  297. * @mfunc
  298. * Sets the drawing information into the display
  299. *
  300. * @rdesc
  301. * void - this cannot fail
  302. *
  303. * @devnote
  304. * The key point to this routine is that the caller of this routine
  305. * is the owner of the memory for the drawing information. It is the
  306. * callers responsiblity to call ReleaseDrawInfo to tell the display
  307. * that it is done with the drawing information.
  308. */
  309. void CDisplay::SetDrawInfo(
  310. CDrawInfo *pdi, //@parm memory for draw info if there is not one already
  311. DWORD dwDrawAspect, //@parm draw aspect
  312. LONG lindex, //@parm currently unused
  313. void *pvAspect, //@parm info for drawing optimizations (OCX 96)
  314. DVTARGETDEVICE *ptd,//@parm information on target device
  315. HDC hicTargetDev) //@parm target information context
  316. {
  317. HDC hicTargetToUse = hicTargetDev;
  318. const CDevDesc *pdd;
  319. // Set up the target device if we need to use the default
  320. if ((NULL == hicTargetToUse))
  321. {
  322. pdd = GetDdTarget();
  323. if(pdd)
  324. hicTargetToUse = pdd->GetDC();
  325. }
  326. if (NULL == _pdi)
  327. {
  328. // Draw structure not yet allocated so use the one
  329. // passed in
  330. _pdi = pdi;
  331. }
  332. // Reset the parameters
  333. _pdi->Init(
  334. dwDrawAspect,
  335. lindex,
  336. pvAspect,
  337. ptd,
  338. hicTargetToUse);
  339. }
  340. /*
  341. * CDisplay::ReleaseDrawInfo ()
  342. *
  343. * @mfunc
  344. * Releases drawing information from display
  345. *
  346. * @rdesc
  347. * void - this cannot fail
  348. *
  349. * @devnote
  350. * Since the display does not own the memory for the drawing information,
  351. * this only NULLs out the pointer in the drawing information pointer. It
  352. * is the responsiblity of the caller to free the memory for the drawing
  353. * information.
  354. */
  355. void CDisplay::ReleaseDrawInfo()
  356. {
  357. if(_pdi && !_pdi->Release())
  358. {
  359. // This object is no longer referenced so we toss our reference.
  360. _pdi = NULL;
  361. }
  362. }
  363. /*
  364. * CDisplay::GetTargetDev ()
  365. *
  366. * @mfunc
  367. * Get the target device if one is available
  368. *
  369. * @rdesc
  370. * Pointer to device description object or NULL if none is available.
  371. *
  372. * @devnote
  373. * This uses the draw info if it is available and then the main target DC
  374. * if it is available.
  375. */
  376. const CDevDesc*CDisplay::GetTargetDev() const
  377. {
  378. const CDevDesc *pdd = NULL;
  379. if(_pdi && _pdi->GetTargetDD())
  380. pdd = _pdi->GetTargetDD();
  381. return pdd ? pdd : GetDdTarget();
  382. }
  383. //================================ Background Recalc ===================================
  384. /*
  385. * CDisplay::StepBackgroundRecalc()
  386. *
  387. * @mfunc
  388. * Steps background line recalc (at GetCp()CalcMax position)
  389. * Called by timer proc. No effect for base class
  390. *
  391. * ??? CF - Should use an idle thread
  392. */
  393. void CDisplay::StepBackgroundRecalc()
  394. {
  395. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::StepBackgroundRecalc");
  396. _TEST_INVARIANT_
  397. }
  398. /*
  399. * CDisplay::WaitForRecalc(cpMax, vpMax)
  400. *
  401. * @mfunc
  402. * Ensures that lines are recalced until a specific character
  403. * position or vPos. Always TRUE for base CDisplay class.
  404. *
  405. * @rdesc
  406. * TRUE if success
  407. */
  408. BOOL CDisplay::WaitForRecalc(
  409. LONG cpMax, //@parm Position recalc up to (-1 to ignore)
  410. LONG vpMax) //@parm vPos to recalc up to (-1 to ignore)
  411. {
  412. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::WaitForRecalc");
  413. _TEST_INVARIANT_
  414. return TRUE;
  415. }
  416. /*
  417. * CDisplay::WaitForRecalcIli(ili)
  418. *
  419. * @mfunc
  420. * Returns TRUE if lines were recalc'd up to ili
  421. * Always the case for base CDisplay class.
  422. */
  423. BOOL CDisplay::WaitForRecalcIli(
  424. LONG ili)
  425. {
  426. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::WaitForRecalcIli");
  427. _TEST_INVARIANT_
  428. return TRUE;
  429. }
  430. /*
  431. * CDisplay::WaitForRecalcView()
  432. *
  433. * Purpose
  434. * Ensure visible lines are completly recalced
  435. * Always the case for base CDisplay class
  436. */
  437. BOOL CDisplay::WaitForRecalcView()
  438. {
  439. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::WaitForRecalcView");
  440. _TEST_INVARIANT_
  441. return TRUE;
  442. }
  443. //==================================== Rendering =======================================
  444. /*
  445. * CDisplay::Draw(hdcDraw, hicTargetDev, prcClient, prcWBounds,
  446. * prcUpdate, pfnContinue, dwContinue)
  447. * @mfunc
  448. * General drawing method called by IViewObject::Draw() or in
  449. * response to WM_PAINT
  450. *
  451. * @rdesc
  452. * HRESULT
  453. */
  454. HRESULT CDisplay::Draw(
  455. HDC hdcDraw, //@parm Rendering device context
  456. HDC hicTargetDev, //@parm Target information context
  457. LPCRECT prcClient, //@parm Bounding (client) rectangle
  458. LPCRECT prcWBounds, //@parm Clipping rect for metafiles
  459. LPCRECT prcUpdate, //@parm Dirty rect inside prcClient
  460. BOOL (CALLBACK *pfnContinue)(DWORD),//@parm Callback for interrupting
  461. // long display (currently unused)
  462. DWORD dwContinue) //@parm Param to pass to pfnContinue
  463. {
  464. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::Draw");
  465. _TEST_INVARIANT_
  466. HRESULT hr = S_OK;
  467. // Store current depth in drawing locally so we can tell
  468. // whether we need to actually render.
  469. DWORD dwDepthThisDraw = _pdi->GetDrawDepth();
  470. RECTUV rcView, rcClient, rcRender;
  471. CTxtSelection *psel = _ped->GetSelNC();
  472. if(!prcWBounds) // No metafile, so just set rendering DC
  473. {
  474. if(!SetDC(hdcDraw))
  475. {
  476. hr = E_FAIL;
  477. goto Cleanup;
  478. }
  479. }
  480. else // Rendering to a metafile
  481. {
  482. //Forms^3 draws using screen resolution, while OLE specifies HIMETRIC
  483. long dxpInch = GetPed()->fInOurHost() ? 2540 : W32->GetXPerInchScreenDC();
  484. long dypInch = GetPed()->fInOurHost() ? 2540 : W32->GetYPerInchScreenDC();
  485. SetWindowOrgEx(hdcDraw, prcWBounds->left, prcWBounds->top, NULL);
  486. SetWindowExtEx(hdcDraw, prcWBounds->right, prcWBounds->bottom, NULL);
  487. SetMetafileDC(hdcDraw, dxpInch, dypInch);
  488. }
  489. // Get client rect
  490. if(prcClient)
  491. RectuvFromRect(rcClient, *prcClient);
  492. else
  493. {
  494. AssertSz(_ped->_fInPlaceActive,
  495. "CDisplay::GetViewRect() - Not in-place and !prcClient");
  496. _ped->TxGetClientRect(&rcClient);
  497. }
  498. // Compute view rectangle (rcView) from client rectangle (account for
  499. // inset and selection bar width)
  500. GetViewRect(rcView, &rcClient);
  501. // If this view is not active and it is not to be recalc'd then
  502. // we only decide to use it if the size matches and return S_FALSE
  503. // if it doesn't so the caller can create a new display to use for
  504. // drawing.
  505. if(!IsActive() && !_fNeedRecalc)
  506. {
  507. if (rcView.right - rcView.left != GetDupView() ||
  508. rcView.bottom - rcView.top != GetDvpView())
  509. {
  510. hr = S_FALSE;
  511. goto Cleanup;
  512. }
  513. }
  514. // Make sure our client rectangle is set correctly.
  515. _dvpClient = rcClient.bottom - rcClient.top;
  516. // Recalc view
  517. // bug fix #5521
  518. // RecalcView can potentially call RequestResize which would
  519. // change the client rect. Send rect down to update the client rect
  520. if(!RecalcView(rcView, &rcClient))
  521. goto Cleanup;
  522. if(dwDepthThisDraw != _pdi->GetDrawDepth())
  523. {
  524. // A draw happened recursively to this draw. Therefore,
  525. // the screen has already been rendered so we don't need
  526. // to do anything more here.
  527. goto Cleanup;
  528. }
  529. // Compute rect to render
  530. if(!prcUpdate) // Update full view
  531. rcRender = rcClient;
  532. else // Clip rendering to client rect
  533. {
  534. RECTUV rcUpdate;
  535. RectuvFromRect(rcUpdate, *prcUpdate);
  536. if(!IntersectRect(&rcRender, &rcClient, &rcUpdate))
  537. goto Cleanup;
  538. }
  539. if(psel)
  540. psel->ClearCchPending();
  541. if(IsMain())
  542. _ped->TxNotify(EN_UPDATE, NULL);
  543. // Now render
  544. Render(rcView, rcRender);
  545. // Update cursor if we need to
  546. if(_fUpdateCaret)
  547. {
  548. // The caret only belongs in an active view with
  549. // a selection on a control that has the focus
  550. if (IsActive() && psel && _ped->_fFocus)
  551. {
  552. // Update the caret if there is a selection object.
  553. // Note: we only scroll the caret into view, if
  554. // it was previously in the view. This avoids having
  555. // window pop to caret if it is resized and the
  556. // caret is not in the view.
  557. psel->UpdateCaret(psel->IsCaretInView());
  558. }
  559. _fUpdateCaret = FALSE;
  560. }
  561. Cleanup:
  562. // Reset DC in device descriptor
  563. ResetDC();
  564. return hr;
  565. }
  566. //==================================== View Recalc ===================================
  567. /*
  568. * CDisplay::UpdateViewRectState(prcClient)
  569. *
  570. * @mfunc Compares new view to cached and updates the view as well as the
  571. * what type of view recalculation needs to occur.
  572. */
  573. void CDisplay::UpdateViewRectState(
  574. const RECTUV *prcClient) //@parm New client rectangle
  575. {
  576. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::UpdateViewRectState");
  577. LONG dupView = prcClient->right - prcClient->left;
  578. LONG dvpView = prcClient->bottom - prcClient->top;
  579. // Check whether the view rect has changed since last rendering
  580. // If width has changed, need complete line recalc.
  581. // If height has changed, recalc all visible and update scrollbars
  582. if(dupView != _dupView)
  583. {
  584. _dupView = dupView;
  585. _fViewChanged = TRUE;
  586. _fNeedRecalc = TRUE; // need full recalc
  587. }
  588. if(dvpView != _dvpView)
  589. {
  590. _dvpView = dvpView;
  591. // The height can go negative when there is an inset and
  592. // the client rect is very small. We just set it to 0 because
  593. // that is the smallest the view can actually get.
  594. if (_dvpView < 0)
  595. _dvpView = 0;
  596. _fViewChanged = TRUE;
  597. }
  598. }
  599. /*
  600. * CDisplay::RecalcView(rcView)
  601. *
  602. * @mfunc
  603. * RecalcView after the view rect changed
  604. *
  605. * @rdesc
  606. * TRUE if success
  607. */
  608. BOOL CDisplay::RecalcView (
  609. const RECTUV &rcView, RECTUV* prcClient)
  610. {
  611. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::RecalcView");
  612. _TEST_INVARIANT_
  613. // Update the x and y coordinates of the view based on the client rect
  614. UpdateViewRectState(&rcView);
  615. // Ensure lines are recalced
  616. if(_fNeedRecalc)
  617. {
  618. // Display got recalculated so the caret needs to be repositioned.
  619. _fUpdateCaret = TRUE;
  620. return RecalcView(TRUE, prcClient);
  621. }
  622. if(_fViewChanged)
  623. {
  624. // The scroll bars are up to date so we can turn off the notification.
  625. _fViewChanged = FALSE;
  626. // A height change was noticed in UpdateViewRectState so make sure
  627. // the horizontal scroll bar (if any is correct).
  628. UpdateScrollBar(SB_VERT);
  629. }
  630. return WaitForRecalcView();
  631. }
  632. //==================================== View Update ===================================
  633. /*
  634. * CDisplay::UpdateView()
  635. *
  636. * @mfunc
  637. * Fully recalc all lines and update the visible part of the display
  638. * (the "view") on the screen.
  639. *
  640. * Returns:
  641. * TRUE if success
  642. */
  643. BOOL CDisplay::UpdateView()
  644. {
  645. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::UpdateView");
  646. _TEST_INVARIANT_
  647. if(_fNoUpdateView)
  648. return TRUE;
  649. if(!_ped->_fInPlaceActive)
  650. {
  651. // If not active, just invalidate everything
  652. InvalidateRecalc();
  653. _ped->TxInvalidate();
  654. _ped->TxUpdateWindow();
  655. return TRUE;
  656. }
  657. if(_ped->_pdp->IsFrozen())
  658. {
  659. _ped->_pdp->SetNeedRedisplayOnThaw(TRUE);
  660. return TRUE;
  661. }
  662. // If we get here, we are updating some general characteristic of the
  663. // display and so we want the cursor updated as well as the general
  664. // change; otherwise the cursor will land up in the wrong place.
  665. _fUpdateCaret = TRUE;
  666. RECTUV rcView;
  667. // Get view rectangle
  668. GetViewRect(rcView);
  669. // Update size of view, which could have changed
  670. UpdateViewRectState(&rcView);
  671. if(!CDevDesc::IsValid())
  672. {
  673. // Make our device valid
  674. SetDC(NULL);
  675. }
  676. // Recalc everything
  677. RecalcView(TRUE);
  678. // Invalidate entire view
  679. _ped->TxInvalidate();
  680. return TRUE;
  681. }
  682. /*
  683. * CDisplay::RoundToLine(hdc, width, pheight)
  684. *
  685. * @mfunc
  686. * Calculate number of default lines to fit in input height
  687. *
  688. * @rdesc
  689. * S_OK - Call completed successfully <nl>
  690. */
  691. HRESULT CDisplay::RoundToLine(
  692. HDC hdc, //@parm DC for the window
  693. LONG dup, //@parm in - width of window; out max width
  694. LONG *pdvp) //@parm in - proposed height; out - actual
  695. {
  696. CLock lock; // Uses global (shared) FontCache
  697. SetDC(hdc); // Set DC
  698. // Set height temporarily so zoom factor will work out
  699. LONG dvpOrigHeightClient = SetClientHeight(*pdvp);
  700. // Use this to adjust for inset height
  701. LONG dvpAdjForInset = *pdvp;
  702. // Get rectangle adjusted for insets
  703. GetViewDim(dup, *pdvp);
  704. // Save proposed height
  705. LONG dvpProposed = *pdvp;
  706. // Calc inset adjusted height
  707. dvpAdjForInset -= dvpProposed;
  708. // Get font
  709. const CCharFormat *pCF = _ped->GetCharFormat(-1);
  710. Assert(pCF);
  711. // Get font cache object
  712. LONG dvpInch = GetDeviceCaps(hdc, LOGPIXELSY);
  713. dvpInch = Zoom(dvpInch);
  714. CCcs *pccs = _ped->GetCcs(pCF, dvpInch);
  715. LONG dvpAdjustFE = pccs->AdjustFEHeight(!_ped->fUseUIFont() && IsMultiLine());
  716. // Get height of font
  717. LONG dvpFont = pccs->_yHeight + (dvpAdjustFE << 1);
  718. pccs->Release();
  719. // Figure out how many lines fit into the input height
  720. LONG cLines = dvpProposed / dvpFont;
  721. // See if we need to round up
  722. if(dvpProposed % dvpFont|| !cLines)
  723. cLines++;
  724. // Set height to new value
  725. *pdvp = dvpFont * cLines + dvpAdjForInset;
  726. // Set client height back to what it was
  727. SetClientHeight(dvpOrigHeightClient);
  728. // Reset the DC
  729. ResetDC();
  730. return NOERROR;
  731. }
  732. /*
  733. * CDisplay::RequestResize()
  734. *
  735. * @mfunc
  736. * Forces the control to resize vertically so that all text fit into it
  737. *
  738. * @rdesc
  739. * HRESULT = (autosize) ? TxNotify(EN_REQUESTRESIZE, &resize) : S_OK
  740. */
  741. HRESULT CDisplay::RequestResize()
  742. {
  743. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::RequestResize");
  744. _TEST_INVARIANT_
  745. CTxtEdit * ped = GetPed();
  746. if (IsActive())
  747. ped->TxShowCaret(FALSE);
  748. if(ped->TxGetAutoSize())
  749. {
  750. REQRESIZE resize;
  751. LONG dup, dvp;
  752. // If word wrapping is on, then the width is the normal
  753. // client width. Otherwise, it's the width of the longest
  754. // line.
  755. dup = GetWordWrap() ? _dupView : GetDupLineMax() + ped->GetCaretWidth();
  756. // Get view inset for adjusting width
  757. RECTUV rcInset;
  758. ped->TxGetViewInset(&rcInset, this);
  759. resize.nmhdr.hwndFrom = NULL;
  760. resize.nmhdr.idFrom = NULL;
  761. resize.nmhdr.code = EN_REQUESTRESIZE;
  762. resize.rc.top = resize.rc.left = 0;
  763. dvp = GetResizeHeight();
  764. // 1.0 COMPATABILITY
  765. // 1.0 included the borders when requesting resize
  766. if (ped->Get10Mode())
  767. {
  768. AssertSz(ped->fInplaceActive(), "In 1.0 mode but not inplace active!!");
  769. HWND hwnd = NULL;
  770. ped->TxGetWindow(&hwnd);
  771. if (hwnd)
  772. {
  773. RECT rcClient, rcWindow;
  774. ped->TxGetClientRect(&rcClient);
  775. GetWindowRect(hwnd, &rcWindow);
  776. dvp += max(rcWindow.bottom - rcWindow.top - rcClient.bottom, 0);
  777. dvp += rcInset.bottom + rcInset.top;
  778. dup = rcWindow.right - rcWindow.left;
  779. }
  780. }
  781. else
  782. {
  783. // Adjust width by inset and selection bar
  784. dup += rcInset.left + rcInset.right + GetSelBarInPixels();
  785. }
  786. if (IsUVerticalTflow(GetTflow()))
  787. {
  788. resize.rc.right = dvp;
  789. resize.rc.bottom = dup;
  790. }
  791. else
  792. {
  793. resize.rc.right = dup;
  794. resize.rc.bottom = dvp;
  795. }
  796. return ped->TxNotify(EN_REQUESTRESIZE, &resize);
  797. }
  798. return S_OK;
  799. }
  800. /*
  801. * CDisplay::GetViewRect(RECTUV &rcView, LPCRECT prcClient)
  802. *
  803. * @mfunc
  804. * Compute and return the view rectangle in window's client
  805. * area coordinates.
  806. *
  807. * @comm
  808. * prcClient is client rect (in window's client coords), which can be
  809. * NULL if we are in-place.
  810. */
  811. void CDisplay::GetViewRect(
  812. RECTUV &rcView, //@parm Reference to rect to return
  813. const RECTUV *prcClient) //@parm Client rect (in window's client coords)
  814. {
  815. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::GetViewRect");
  816. _TEST_INVARIANT_
  817. RECTUV rcInset;
  818. // If client rect wasn't passed in, get it from host
  819. if(prcClient)
  820. rcView = *prcClient;
  821. else
  822. {
  823. AssertSz(_ped->_fInPlaceActive, "CDisplay::GetViewRect() - Not in-place and !prcClient");
  824. _ped->TxGetClientRect(&rcView);
  825. }
  826. //REVIEW (keithcu) GetViewRect has side affects?!
  827. _dvpClient = rcView.bottom - rcView.top;
  828. _ped->TxGetViewInset(&rcInset, this);
  829. rcView.left += rcInset.left; // Add in inset offsets
  830. rcView.top += rcInset.top; // rcView is in device coords
  831. rcView.right -= rcInset.right;
  832. rcView.bottom -= rcInset.bottom;
  833. // Add in selection bar space
  834. long dupSelBar = GetSelBarInPixels();
  835. if (_ped->IsSelectionBarRight())
  836. rcView.right -= dupSelBar;
  837. else
  838. rcView.left += dupSelBar;
  839. }
  840. //=============================== Scrolling ==============================
  841. /*
  842. * CDisplay::VScroll(wCode, vPos)
  843. *
  844. * @mfunc
  845. * Scroll the view vertically in response to a scrollbar event
  846. * >>> Should be called when in-place active only <<<
  847. *
  848. * Note:
  849. * No support for vertical scroll in base CDisplay. No action.
  850. *
  851. * @rdesc
  852. * LRESULT formatted for WM_VSCROLL message
  853. */
  854. LRESULT CDisplay::VScroll(
  855. WORD wCode, //@parm Scrollbar event code
  856. LONG vPos) //@parm Thumb position (vPos < 0 for EM_SCROLL behavior)
  857. {
  858. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::VScroll");
  859. _TEST_INVARIANT_
  860. return 0;
  861. }
  862. /*
  863. * CDisplay::UScroll(wCode, uPos)
  864. *
  865. * @mfunc
  866. * Scroll uPos in response to a scrollbar event
  867. * >>> Should be called when in-place active only <<<
  868. */
  869. void CDisplay::UScroll(
  870. WORD wCode, //@parm Scrollbar event code
  871. LONG uPos) //@parm Thumb position
  872. {
  873. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::UScroll");
  874. _TEST_INVARIANT_
  875. BOOL fTracking = FALSE;
  876. LONG upScroll = _upScroll;
  877. if (uPos != 0)
  878. {
  879. // Convert x position from scroll bar to offset horizontally
  880. // in the document.
  881. uPos = ConvertScrollToUPos(uPos);
  882. }
  883. AssertSz(_ped->_fInPlaceActive, "CDisplay::UScroll() called when not in place");
  884. switch(wCode)
  885. {
  886. case SB_BOTTOM:
  887. upScroll = GetDupLineMax();
  888. break;
  889. case SB_LINEDOWN:
  890. // Future: Make this depend on a the current first visible character
  891. upScroll += GetDupSystemFont();
  892. break;
  893. case SB_LINEUP:
  894. // Future: Make this depend on a the current first visible character
  895. upScroll -= GetDupSystemFont();
  896. break;
  897. case SB_PAGEDOWN:
  898. upScroll += _dupView;
  899. break;
  900. case SB_PAGEUP:
  901. upScroll -= _dupView;
  902. break;
  903. case SB_THUMBTRACK:
  904. case SB_THUMBPOSITION:
  905. if(uPos < 0)
  906. return;
  907. upScroll = uPos;
  908. fTracking = TRUE;
  909. break;
  910. case SB_TOP:
  911. upScroll = 0;
  912. break;
  913. case SB_ENDSCROLL:
  914. UpdateScrollBar(SB_HORZ);
  915. return;
  916. default:
  917. return;
  918. }
  919. if (upScroll < 0)
  920. {
  921. // upScroll is the new proposed scrolling position and
  922. // therefore cannot be less than 0.
  923. upScroll = 0;
  924. }
  925. ScrollView(upScroll, -1, fTracking, FALSE);
  926. // force position update if we just finished a track
  927. if(wCode == SB_THUMBPOSITION)
  928. UpdateScrollBar(SB_HORZ);
  929. }
  930. /*
  931. * CDisplayML::SmoothVScroll ( int direction, WORD cLines,
  932. * int speedNum, int speedDenom, BOOL fAdditive )
  933. *
  934. * @mfunc
  935. * Setup to handle fractional scrolls, at a particular speed. This was
  936. * probably initiated via a Magellan mouse roller movement, or a MButton
  937. * down message.
  938. */
  939. void CDisplay::SmoothVScroll ( int direction, WORD cLines, int speedNum, int speedDenom, BOOL fMouseRoller )
  940. {
  941. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CDisplay::SmoothVScroll");
  942. int vDelta;
  943. int cLinesAndDir;
  944. int smoothVDelta;
  945. Assert ( speedDenom );
  946. if ( IsVScrollEnabled() ) // Can scroll vertically?
  947. {
  948. _fFinishSmoothVScroll = FALSE; // We're smoothing again.
  949. // Get total pixels.
  950. if ( CheckInstallSmoothVScroll() ) // Install periodic update
  951. {
  952. _totalSmoothVScroll = 0;
  953. _nextSmoothVScroll = 0;
  954. }
  955. // Pixels per epoch
  956. cLinesAndDir = (direction < 0) ? cLines : -cLines;
  957. if( cLines )
  958. {
  959. vDelta = CalcVLineScrollDelta ( cLinesAndDir, FALSE );
  960. }
  961. else
  962. {
  963. vDelta = (direction < 0 ) ? _dvpClient : -_dvpClient;
  964. cLines = 1; // for the MulDiv calculation below.
  965. }
  966. if ( vDelta ) // If something to scroll.
  967. {
  968. smoothVDelta = MulDiv( SMOOTH_PRECISION,// NB-Because no FLOAT type
  969. MulDiv(vDelta, speedNum, speedDenom), cLines);
  970. _smoothVDelta = smoothVDelta;
  971. if ( fMouseRoller ) // roller event.
  972. { // -> additive.
  973. _totalSmoothVScroll += vDelta;
  974. _continuedsmoothVDelta = 0;
  975. _continuedSmoothVScroll = 0;
  976. } // mButton event
  977. else
  978. {
  979. if ( 0 == _totalSmoothVScroll )
  980. _totalSmoothVScroll = vDelta;
  981. _continuedsmoothVDelta = smoothVDelta;
  982. _continuedSmoothVScroll = vDelta;
  983. }
  984. }
  985. }
  986. }
  987. /*
  988. * CDisplay::SmoothVScrollUpdate()
  989. *
  990. * @mfunc
  991. * Supports SmoothVScroll. Scroll a small number of pixels.
  992. * We are called via a periodic timing task.
  993. */
  994. void CDisplay::SmoothVScrollUpdate()
  995. {
  996. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CDisplay::SmoothVScrollUpdate");
  997. LONG vDelta; // Magellan mouse.
  998. BOOL fImmediateUpdate = FALSE;
  999. _nextSmoothVScroll += _smoothVDelta;
  1000. // Remove fractional amt.
  1001. vDelta = _nextSmoothVScroll / SMOOTH_PRECISION;
  1002. // Don't overshoot.
  1003. if ( 0 == _continuedSmoothVScroll
  1004. && ( (_totalSmoothVScroll <= 0 && vDelta < _totalSmoothVScroll)
  1005. || (_totalSmoothVScroll >= 0 && vDelta > _totalSmoothVScroll)) )
  1006. {
  1007. vDelta = _totalSmoothVScroll;
  1008. }
  1009. if ( vDelta ) // Scroll vDelta, the
  1010. { // integral amount.
  1011. _totalSmoothVScroll -= vDelta;
  1012. _nextSmoothVScroll -= vDelta * SMOOTH_PRECISION;
  1013. FractionalScrollView( vDelta );
  1014. }
  1015. else if ( 0 == _totalSmoothVScroll ) // Starting to wind down?
  1016. {
  1017. _nextSmoothVScroll -= _smoothVDelta;
  1018. fImmediateUpdate = TRUE;
  1019. }
  1020. // Finished scrolling?
  1021. if ( (vDelta <= 0 && _totalSmoothVScroll >= 0) || (vDelta >= 0 && _totalSmoothVScroll <= 0 ) )
  1022. {
  1023. LONG cLinesAndDir;
  1024. if ( _continuedsmoothVDelta ) // mButton continuation.
  1025. {
  1026. _smoothVDelta = _continuedsmoothVDelta;
  1027. _totalSmoothVScroll += _continuedSmoothVScroll;
  1028. }
  1029. else
  1030. {
  1031. if ( _continuedSmoothVScroll )
  1032. {
  1033. _fFinishSmoothVScroll = TRUE; // Winding down scroll.
  1034. _continuedSmoothVScroll = 0;
  1035. // Last line's remainder...
  1036. cLinesAndDir = _smoothVDelta < 0 ? -1 : 1;
  1037. _totalSmoothVScroll = CalcVLineScrollDelta ( cLinesAndDir, TRUE );
  1038. // check for line boundry.
  1039. if ( _totalSmoothVScroll
  1040. == CalcVLineScrollDelta ( cLinesAndDir, FALSE ) )
  1041. {
  1042. _totalSmoothVScroll = 0;
  1043. }
  1044. if ( fImmediateUpdate ) // do 'this' epochs scroll.
  1045. SmoothVScrollUpdate();
  1046. }
  1047. else
  1048. {
  1049. CheckRemoveSmoothVScroll(); // All done, remove timer.
  1050. }
  1051. }
  1052. }
  1053. }
  1054. /*
  1055. * CDisplay::FinishSmoothVScroll
  1056. *
  1057. * @mfunc
  1058. * Cause smooth scroll to finish off the last fractional lines worth of
  1059. * scrolling and then stop.
  1060. */
  1061. VOID CDisplay::FinishSmoothVScroll( )
  1062. {
  1063. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CDisplay::FinishSmoothVScroll");
  1064. // any non-zero value.
  1065. if ( !_fFinishSmoothVScroll && _totalSmoothVScroll )
  1066. {
  1067. _fFinishSmoothVScroll = TRUE;
  1068. _continuedSmoothVScroll = 1;
  1069. _continuedsmoothVDelta = 0; // So smooth scroll stops.
  1070. _totalSmoothVScroll = 0;
  1071. }
  1072. }
  1073. /*
  1074. * CTxtEdit::CheckInstallSmoothScroll()
  1075. *
  1076. * @mfunc
  1077. * Install a new smooth scroll timer if not already scrolling.
  1078. */
  1079. BOOL CDisplay::CheckInstallSmoothVScroll()
  1080. {
  1081. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CDisplay::CheckInstallSmoothVScroll");
  1082. _TEST_INVARIANT_
  1083. BOOL fJustInstalled = FALSE;
  1084. if(!_fSmoothVScroll && _ped->TxSetTimer(RETID_SMOOTHSCROLL, 25))
  1085. {
  1086. _fSmoothVScroll = TRUE;
  1087. fJustInstalled = TRUE;
  1088. }
  1089. return fJustInstalled;
  1090. }
  1091. /*
  1092. * CTxtEdit::CheckRemoveSmoothVScroll ( )
  1093. *
  1094. * @mfunc
  1095. * Finish smooth scroll. If not a forced stop, then check
  1096. * to see if smooth scrolling should continue, and if so, setup
  1097. * to continue smooth scrolling.
  1098. */
  1099. VOID CDisplay::CheckRemoveSmoothVScroll ( )
  1100. {
  1101. TRACEBEGIN(TRCSUBSYSEDIT, TRCSCOPEINTERN, "CDisplay::CheckRemoveSmoothVScroll");
  1102. _TEST_INVARIANT_
  1103. if( _fSmoothVScroll )
  1104. {
  1105. ScrollToLineStart( _continuedSmoothVScroll ); // Ensure stopped on a line.
  1106. _ped->TxKillTimer(RETID_SMOOTHSCROLL);
  1107. _fSmoothVScroll = FALSE;
  1108. }
  1109. }
  1110. /*
  1111. * CDisplay::LineScroll(cli, cch)
  1112. *
  1113. * @mfunc
  1114. * Scroll the view horizontally in response to a scrollbar event
  1115. *
  1116. * Note:
  1117. * No support for vertical scroll in base CDisplay. No action.
  1118. */
  1119. void CDisplay::LineScroll(
  1120. LONG cli, //@parm Count of lines to scroll vertically
  1121. LONG cch) //@parm Count of chars to scroll horizontally
  1122. {
  1123. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::LineScroll");
  1124. _TEST_INVARIANT_
  1125. return;
  1126. }
  1127. void CDisplay::FractionalScrollView (
  1128. LONG vDelta )
  1129. {
  1130. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::FractionalScrollView");
  1131. _TEST_INVARIANT_
  1132. return;
  1133. }
  1134. VOID CDisplay::ScrollToLineStart ( LONG iDirection )
  1135. {
  1136. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::ScrollToLineStart");
  1137. _TEST_INVARIANT_
  1138. return;
  1139. }
  1140. LONG CDisplay::CalcVLineScrollDelta ( LONG cli, BOOL fFractionalFirst )
  1141. {
  1142. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::CalcVLineScrollDelta");
  1143. _TEST_INVARIANT_
  1144. return 0;
  1145. }
  1146. /*
  1147. * CDisplay::DragScroll(ppt)
  1148. *
  1149. * @mfunc
  1150. * Auto scroll when dragging the mouse out of the visible view
  1151. *
  1152. * Arguments:
  1153. * ppt mouse position (in client coordinates)
  1154. */
  1155. BOOL CDisplay::DragScroll(const POINT * ppt)
  1156. {
  1157. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::DragScroll");
  1158. _TEST_INVARIANT_
  1159. const DWORD dwTime = GetTickCount();
  1160. BOOL fScrolled = FALSE;
  1161. DWORD dwScroll = 0;
  1162. RECTUV rc;
  1163. int nScrollInset;
  1164. AssertSz(_ped->_fInPlaceActive, "CDisplay::DragScroll() called when not in-place");
  1165. GetViewRect(rc);
  1166. nScrollInset = (int)W32->GetScrollInset();
  1167. InflateRect((RECT*)&rc, - nScrollInset, - nScrollInset);
  1168. if(_fVScrollEnabled && (_ped->TxGetScrollBars() & ES_AUTOVSCROLL))
  1169. {
  1170. const vpScroll = ConvertVPosToScrollPos(GetVpScroll());
  1171. if(ppt->y <= rc.top)
  1172. {
  1173. dwScroll = dwAutoScrollUp;
  1174. }
  1175. else if(ppt->y > rc.bottom)
  1176. {
  1177. LONG vpMax = GetScrollRange(SB_VERT);
  1178. if(vpScroll < vpMax)
  1179. dwScroll = dwAutoScrollDown;
  1180. }
  1181. }
  1182. if(!dwScroll && _fUScrollEnabled && (_ped->TxGetScrollBars() & ES_AUTOHSCROLL))
  1183. {
  1184. const upScroll = ConvertUPosToScrollPos(GetUpScroll());
  1185. if((ppt->x <= rc.left) && (upScroll > 0))
  1186. {
  1187. dwScroll = dwAutoScrollLeft;
  1188. }
  1189. else if(ppt->x > rc.right)
  1190. {
  1191. LONG xMax = GetScrollRange(SB_HORZ);
  1192. if(upScroll < xMax)
  1193. dwScroll = dwAutoScrollRight;
  1194. }
  1195. }
  1196. if(dwScroll)
  1197. {
  1198. if(_dwScrollLast != dwScroll)
  1199. {
  1200. // entered or moved to a different auto scroll area
  1201. // reset delay counter
  1202. TRACEINFOSZ("enter auto scroll area");
  1203. _dwTimeScrollNext = dwTime + cmsecScrollDelay;
  1204. }
  1205. else if(dwTime >= _dwTimeScrollNext)
  1206. {
  1207. WORD wScrollCode = SB_LINEDOWN;
  1208. switch(dwScroll)
  1209. {
  1210. case dwAutoScrollUp:
  1211. wScrollCode = SB_LINEUP;
  1212. // fall through to dwAutoScrollDown
  1213. case dwAutoScrollDown:
  1214. // OnVScroll() doesn't scroll enough for our desires
  1215. VScroll(wScrollCode, 0);
  1216. VScroll(wScrollCode, 0);
  1217. break;
  1218. case dwAutoScrollLeft:
  1219. wScrollCode = SB_LINEUP;
  1220. // fall through to dwAutoScrollRight
  1221. case dwAutoScrollRight:
  1222. // UScroll() doesn't scroll enough for our desires
  1223. UScroll(wScrollCode, 0);
  1224. UScroll(wScrollCode, 0);
  1225. UScroll(wScrollCode, 0);
  1226. UScroll(wScrollCode, 0);
  1227. break;
  1228. #ifdef DEBUG
  1229. default:
  1230. Tracef(TRCSEVWARN, "Unexpected dwScroll %lx", dwScroll);
  1231. TRACEERRSZSC("Unexpected dwScroll", E_INVALIDARG);
  1232. break;
  1233. #endif
  1234. }
  1235. // reset interval counter
  1236. _dwTimeScrollNext = dwTime + cmsecScrollInterval;
  1237. fScrolled = TRUE;
  1238. }
  1239. }
  1240. #if !defined(NOFULLDEBUG) && defined(DEBUG)
  1241. else if(_dwScrollLast)
  1242. TRACEINFOSZ("moved out of auto scroll area");
  1243. #endif
  1244. _dwScrollLast = dwScroll;
  1245. return fScrolled;
  1246. }
  1247. /*
  1248. * CDisplay::AutoScroll(pt, upScrollInset, vpScrollInset)
  1249. *
  1250. * @mfunc:
  1251. * Given the current point, determine whether we need to
  1252. * scroll the client area.
  1253. *
  1254. * Requires:
  1255. * This function should only be called during a drag drop
  1256. * operation.
  1257. *
  1258. * @rdesc
  1259. * True if we are in the drag scrolling hot zone, false otherwise.
  1260. *
  1261. */
  1262. #define ScrollUp 0x0001 //These eight macros indicate the areas
  1263. #define ScrollDown 0x0010 //of the drag scrolling hot zone that tell
  1264. #define ScrollLeft 0x0100 //which direction to scroll.
  1265. #define ScrollRight 0x1000 //The last four are ambiguous (the corners)
  1266. #define ScrollUL 0x0101 //and require a little extra work.
  1267. #define ScrollUR 0x1001
  1268. #define ScrollDL 0x0110
  1269. #define ScrollDR 0x1010
  1270. BOOL CDisplay::AutoScroll(
  1271. POINTUV pt, //@parm Cursor location in client coordinates
  1272. const WORD upScrollInset,
  1273. const WORD vpScrollInset)
  1274. {
  1275. TRACEBEGIN(TRCSUBSYSDTE, TRCSCOPEINTERN, "CDisplay::AutoScroll");
  1276. static DWORD hotticks = 0; //Ticks when we entered hot zone.
  1277. static DWORD lastscrollticks = 0; //Ticks when we last scroll.
  1278. static DWORD lastticks = 0; //Ticks when last called.
  1279. DWORD delta; //Ticks since last called.
  1280. DWORD ticks; //GetTickCount ticks.
  1281. RECT rcClient; //Client rect of control.
  1282. WORD wScrollDir = 0; //Scroll direction.
  1283. BOOL fScroll = FALSE; //TRUE if we should try to scroll this time.
  1284. BOOL fEnabled = FALSE; //TRUE if scrolling is possible
  1285. //Get the current ticks and calculate ticks since last called.
  1286. //Note that if _drags does not have valid data this will be a
  1287. //bogus value, but that is handled later.
  1288. ticks = GetTickCount();
  1289. delta = ticks - lastticks;
  1290. lastticks = ticks;
  1291. //Don't do anything if no ticks since last time we were called.
  1292. if (delta)
  1293. {
  1294. // Get our client rect.
  1295. _ped->TxGetClientRect(&rcClient);
  1296. //Find out if we are in the hot zone.
  1297. //Note that if we are in one of the corners
  1298. //we will indicate two scrolling directions.
  1299. //This ambiguity will be sorted out later.
  1300. //For now we just want to know if we are in
  1301. //the zone.
  1302. if (pt.u <= (LONG)(rcClient.left + upScrollInset))
  1303. wScrollDir |= (WORD)ScrollLeft;
  1304. else if (pt.u >= (LONG)(rcClient.right - upScrollInset))
  1305. wScrollDir |= (WORD)ScrollRight;
  1306. if (pt.v <= (LONG)(rcClient.top + vpScrollInset))
  1307. wScrollDir |= (WORD)ScrollUp;
  1308. else if (pt.v >= (LONG)(rcClient.bottom - vpScrollInset))
  1309. wScrollDir |= (WORD)ScrollDown;
  1310. //If we are somewhere in the hot zone.
  1311. if (wScrollDir)
  1312. {
  1313. //If we just entered hotzone remember the current ticks.
  1314. if (!hotticks)
  1315. hotticks = ticks;
  1316. //If we have been in the hot zone long enough, and
  1317. //the required interval since the last scroll has elapsed
  1318. //allow another scroll. Note that if we haven't scrolled yet,
  1319. //lastscrollticks will be zero so the delta is virtually
  1320. //guaranteed to be greater than ScrollInterval.
  1321. if ((ticks - hotticks) >= (DWORD)W32->GetScrollDelay() &&
  1322. (ticks - lastscrollticks) >= (DWORD)W32->GetScrollInterval())
  1323. fScroll = TRUE;
  1324. //If we are in one of the corners, we scroll
  1325. //in the direction of the edge we are closest
  1326. //to.
  1327. switch (wScrollDir)
  1328. {
  1329. case ScrollUL:
  1330. {
  1331. if ((pt.v - rcClient.top) <= (pt.u - rcClient.left))
  1332. wScrollDir = ScrollUp;
  1333. else
  1334. wScrollDir = ScrollLeft;
  1335. break;
  1336. }
  1337. case ScrollUR:
  1338. {
  1339. if ((pt.v - rcClient.top) <= (rcClient.right - pt.u))
  1340. wScrollDir = ScrollUp;
  1341. else
  1342. wScrollDir = ScrollRight;
  1343. break;
  1344. }
  1345. case ScrollDL:
  1346. {
  1347. if ((rcClient.bottom - pt.v) <= (pt.u - rcClient.left))
  1348. wScrollDir = ScrollDown;
  1349. else
  1350. wScrollDir = ScrollLeft;
  1351. break;
  1352. }
  1353. case ScrollDR:
  1354. {
  1355. if ((rcClient.bottom - pt.v) <= (rcClient.right - pt.u))
  1356. wScrollDir = ScrollDown;
  1357. else
  1358. wScrollDir = ScrollRight;
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. else
  1364. {
  1365. //We aren't in the hot zone so reset hotticks as a
  1366. //flag so we know the first time we reenter it.
  1367. hotticks = 0;
  1368. }
  1369. //Do processing for horizontal scrolling if necessary
  1370. if (wScrollDir == ScrollLeft || wScrollDir == ScrollRight)
  1371. {
  1372. LONG xRange, upScroll, dx;
  1373. upScroll = ConvertUPosToScrollPos(GetUpScroll());
  1374. xRange = GetScrollRange(SB_HORZ);
  1375. dx = W32->GetScrollHAmount();
  1376. fEnabled = IsUScrollEnabled();
  1377. if (wScrollDir == ScrollLeft)
  1378. {
  1379. fEnabled = fEnabled && (upScroll > 0);
  1380. upScroll -= dx;
  1381. upScroll = max(upScroll, 0);
  1382. }
  1383. else
  1384. {
  1385. fEnabled = fEnabled && (upScroll < xRange);
  1386. upScroll += dx;
  1387. upScroll = min(upScroll, xRange);
  1388. }
  1389. //Do the actual scrolling if necessary.
  1390. if (fEnabled && fScroll)
  1391. {
  1392. UScroll(SB_THUMBPOSITION, upScroll);
  1393. lastscrollticks = ticks;
  1394. }
  1395. }
  1396. //Do processing for Vertical scrolling if necessary
  1397. else if (wScrollDir == ScrollUp || wScrollDir == ScrollDown)
  1398. {
  1399. LONG yRange, vpScroll, dy;
  1400. vpScroll = ConvertVPosToScrollPos(GetVpScroll());
  1401. yRange = GetScrollRange(SB_VERT);
  1402. dy = W32->GetScrollVAmount();
  1403. fEnabled = IsVScrollEnabled();
  1404. if (wScrollDir == ScrollUp)
  1405. {
  1406. fEnabled = fEnabled && (vpScroll > 0);
  1407. vpScroll -= dy;
  1408. vpScroll = max(vpScroll, 0);
  1409. }
  1410. else
  1411. {
  1412. fEnabled = fEnabled && (vpScroll < yRange);
  1413. vpScroll += dy;
  1414. vpScroll = min(vpScroll, yRange);
  1415. }
  1416. //Do the actual scrolling if necessary.
  1417. if (fEnabled && fScroll)
  1418. {
  1419. // We need to scroll fractionally because the scroll logic tries
  1420. // to put a full line on the top and if the scroll amount is less
  1421. // than a full line, the scrolling will get stuck on that line.
  1422. ScrollView(_upScroll, vpScroll, FALSE, TRUE);
  1423. lastscrollticks = ticks;
  1424. }
  1425. }
  1426. }
  1427. return fEnabled;
  1428. }
  1429. /*
  1430. * CDisplay::AdjustToDisplayLastLine(yBase, vpScroll)
  1431. *
  1432. * @mfunc
  1433. * Calculate the yscroll necessary to get the last line to display
  1434. *
  1435. * @rdesc
  1436. * Updated vpScroll
  1437. *
  1438. * @devnote:
  1439. * This method is only really useful for ML displays. This method
  1440. * here is a placeholder which does nothing which is useful for
  1441. * all other displays.
  1442. */
  1443. LONG CDisplay::AdjustToDisplayLastLine(
  1444. LONG yBase, //@parm Actual vpScroll to display
  1445. LONG vpScroll) //@parm Proposed amount to scroll
  1446. {
  1447. return vpScroll;
  1448. }
  1449. /*
  1450. * CDisplay::GetScrollRange(nBar)
  1451. *
  1452. * @mfunc
  1453. * Returns the max part of a scrollbar range
  1454. * No scrollbar support in the base class: returns 0.
  1455. *
  1456. * @rdesc
  1457. * LONG max part of scrollbar range
  1458. */
  1459. LONG CDisplay::GetScrollRange(
  1460. INT nBar) const
  1461. {
  1462. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::GetScrollRange");
  1463. _TEST_INVARIANT_
  1464. return 0;
  1465. }
  1466. /*
  1467. * CDisplay::UpdateScrollBar(nBar, fUpdateRange)
  1468. *
  1469. * @mfunc
  1470. * Update either the horizontal or vertial scroll bar
  1471. * Also figure whether the scroll bar should be visible or not
  1472. * No scrollbar support in the base class: no action.
  1473. *
  1474. * @rdesc
  1475. * BOOL
  1476. */
  1477. BOOL CDisplay::UpdateScrollBar(
  1478. INT nBar,
  1479. BOOL fUpdateRange)
  1480. {
  1481. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::UpdateScrollBar");
  1482. _TEST_INVARIANT_
  1483. return TRUE;
  1484. }
  1485. /*
  1486. * CDisplay::GetZoomDenominator()
  1487. *
  1488. * @mfunc
  1489. * Get zoom denominator
  1490. *
  1491. * @rdesc
  1492. * Returns zoom denominator
  1493. *
  1494. * @devnote:
  1495. * FUTURE: (Ricksa) we should investigate how to cache this data since
  1496. * the display needs to keep a temporary zoom denominator anyway.
  1497. */
  1498. LONG CDisplay::GetZoomDenominator() const
  1499. {
  1500. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::GetZoomDenominator");
  1501. if(_ped->GetZoomDenominator()) // Simple EM_SETZOOM API
  1502. return _ped->GetZoomDenominator(); // supercedes complicated
  1503. // Forms^3 API
  1504. // Default zoom to error case. The error case is a very low
  1505. // probability event that we can do nothing to recover. So we
  1506. // just set the value to something reasonable and continue.
  1507. LONG lZoomDenominator = _dvpClient;
  1508. // Is temporary zoom denominator set?
  1509. if(INVALID_ZOOM_DENOMINATOR == _lTempZoomDenominator)
  1510. {
  1511. // No - Get extent size from host
  1512. SIZEL sizelExtent;
  1513. if(SUCCEEDED(_ped->TxGetExtent(&sizelExtent)))
  1514. {
  1515. // Convert height to device units. Note that by definition, we
  1516. // can ignore horizontal extents so we do. Use CDevDesc conversion
  1517. // to avoid infinite recursion
  1518. lZoomDenominator = CDevDesc::HimetricYtoDY(
  1519. IsUVerticalTflow(GetTflow()) ? sizelExtent.cx : sizelExtent.cy);
  1520. }
  1521. }
  1522. else // Temporary zoom denominator is set: use it
  1523. lZoomDenominator = CDevDesc::HimetricYtoDY(_lTempZoomDenominator);
  1524. return lZoomDenominator > 0 ? lZoomDenominator : 1;
  1525. }
  1526. /*
  1527. * CDisplay::GetZoomNumerator()
  1528. *
  1529. * @mfunc
  1530. * Get zoom numerator
  1531. *
  1532. * @rdesc
  1533. * Returns zoom numerator
  1534. */
  1535. LONG CDisplay::GetZoomNumerator() const
  1536. {
  1537. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::GetZoomNumerator");
  1538. if(_ped->GetZoomNumerator()) // Simple EM_SETZOOM API
  1539. return _ped->GetZoomNumerator(); // supercedes complicated
  1540. // Forms^3 API
  1541. return _dvpClient > 0 ? _dvpClient : 1;
  1542. }
  1543. /*
  1544. * CDisplay::Zoom(x)
  1545. *
  1546. * @mfunc
  1547. * Get zoomed x
  1548. *
  1549. * @rdesc
  1550. * Returns zoomed x
  1551. */
  1552. // REVIEW (keithcu) Why does Zoom do anything when we are in print preview?
  1553. LONG CDisplay::Zoom(LONG x) const
  1554. {
  1555. return MulDiv(x, GetZoomNumerator(), GetZoomDenominator());
  1556. }
  1557. /*
  1558. * CDisplay::UnZoom(x)
  1559. *
  1560. * @mfunc
  1561. * Get unzoomed x
  1562. *
  1563. * @rdesc
  1564. * Returns unzoomed x
  1565. */
  1566. LONG CDisplay::UnZoom(LONG x) const
  1567. {
  1568. return MulDiv(x, GetZoomDenominator(), GetZoomNumerator());
  1569. }
  1570. /*
  1571. * CDisplay::HimetricUtoDU(u)
  1572. *
  1573. * @mfunc
  1574. * Get device u coordinate corresponding to Himetric u coordinate
  1575. *
  1576. * @rdesc
  1577. * Returns device coordinate
  1578. */
  1579. LONG CDisplay::HimetricUtoDU(
  1580. LONG u) const
  1581. {
  1582. u = Zoom(u);
  1583. if (!IsUVerticalTflow(GetTflow()))
  1584. return CDevDesc::HimetricXtoDX(u);
  1585. else
  1586. return CDevDesc::HimetricYtoDY(u);
  1587. }
  1588. /*
  1589. * CDisplay::HimetricVtoDV(v)
  1590. *
  1591. * @mfunc
  1592. * Get device v coordinate corresponding to Himetric v coordinate
  1593. *
  1594. * @rdesc
  1595. * Returns device coordinate
  1596. */
  1597. LONG CDisplay::HimetricVtoDV(
  1598. LONG v) const
  1599. {
  1600. v = Zoom(v);
  1601. if (!IsUVerticalTflow(GetTflow()))
  1602. return CDevDesc::HimetricYtoDY(v);
  1603. else
  1604. return CDevDesc::HimetricXtoDX(v);
  1605. }
  1606. /*
  1607. * CDisplay::DUtoHimetricU(du)
  1608. *
  1609. * @mfunc
  1610. * Get Himetric u coordinate corresponding to device u coordinate
  1611. *
  1612. * @rdesc
  1613. * Returns Himetric coordinate
  1614. */
  1615. LONG CDisplay::DUtoHimetricU(
  1616. LONG du) const
  1617. {
  1618. if (!IsUVerticalTflow(GetTflow()))
  1619. du = CDevDesc::DXtoHimetricX(du);
  1620. else
  1621. du = CDevDesc::DYtoHimetricY(du);
  1622. return UnZoom(du);
  1623. }
  1624. /*
  1625. * CDisplay::DVtoHimetricV(dv)
  1626. *
  1627. * @mfunc
  1628. * Get Himetric v coordinate corresponding to device v coordinate
  1629. *
  1630. * @rdesc
  1631. * Returns Himetric coordinate
  1632. */
  1633. LONG CDisplay::DVtoHimetricV(
  1634. LONG dv) const
  1635. {
  1636. if (!IsUVerticalTflow(GetTflow()))
  1637. dv = CDevDesc::DYtoHimetricY(dv);
  1638. else
  1639. dv = CDevDesc::DXtoHimetricX(dv);
  1640. return UnZoom(dv);
  1641. }
  1642. /*
  1643. * CDisplay::SetClientHeight(yNewClientHeight)
  1644. *
  1645. * @mfunc
  1646. * Reset height of client rectangle
  1647. *
  1648. * @rdesc
  1649. * Returns previous height of the client rectangle
  1650. */
  1651. LONG CDisplay::SetClientHeight(
  1652. LONG yNewClientHeight) //@parm New height for the client rectangle.
  1653. {
  1654. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::SetClientHeight");
  1655. LONG yOldHeight = _dvpClient;
  1656. _dvpClient = yNewClientHeight;
  1657. return yOldHeight;
  1658. }
  1659. /*
  1660. * CDisplay::GetCachedSize(pdupClient, pdvpClient)
  1661. *
  1662. * @mfunc calculates the client size
  1663. *
  1664. * @rdesc
  1665. * HRESULT = NOERROR
  1666. */
  1667. HRESULT CDisplay::GetCachedSize(
  1668. LONG *pdupClient, //@parm where to put the width
  1669. LONG *pdvpClient) //@parm where to put the height
  1670. const
  1671. {
  1672. RECTUV rcInset;
  1673. _ped->TxGetViewInset(&rcInset, this);
  1674. *pdvpClient = _dvpClient;
  1675. *pdupClient = _dupView + rcInset.left + rcInset.right + GetSelBarInPixels();
  1676. return NOERROR;
  1677. }
  1678. /*
  1679. * CDisplay::TransparentHitTest(hdc, prcClient, pt, pHitResult)
  1680. *
  1681. * @mfunc
  1682. * Determine if the hit is on a transparent control
  1683. *
  1684. * @rdesc
  1685. * Returns HRESULT of call usually S_OK.
  1686. *
  1687. * @devnote
  1688. * FUTURE: This code needs to be investigated for possible optimizations.
  1689. *
  1690. * This code is assumes that all remeasuring needed has been done before
  1691. * this routine is called.
  1692. */
  1693. // How close hit needs to be to the text
  1694. const int HIT_CLOSE_RECT_INC = 5;
  1695. HRESULT CDisplay::TransparentHitTest(
  1696. HDC hdc, //@parm DC for actual drawing
  1697. LPCRECT prcClient, //@parm Client rectangle for rendering
  1698. POINTUV pt, //@parm Point to hittest against
  1699. DWORD * pHitResult) //@parm Result of the hit test see TXTHITRESULT
  1700. {
  1701. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::TransparentHitTest");
  1702. COLORREF crBackground = _ped->TxGetBackColor();
  1703. HDC hdcMem = NULL;
  1704. HRESULT hr = E_FAIL;
  1705. int uRow, vCol;
  1706. COffscreenDC osdc;
  1707. RECTUV rcClient, rcRender, rcView;
  1708. RECT rcxyClient;
  1709. rcxyClient.left = rcxyClient.top = 0;
  1710. rcxyClient.right = prcClient->right - prcClient->left;
  1711. rcxyClient.bottom = prcClient->bottom - prcClient->top;
  1712. // Render view to a memory DC
  1713. // Compute zero based client rectangle
  1714. RectuvFromRect(rcClient, rcxyClient);
  1715. // Create a memory DC
  1716. hdcMem = osdc.Init(hdc, rcxyClient.right - rcxyClient.left, rcxyClient.bottom - rcxyClient.top, crBackground);
  1717. if(!hdcMem)
  1718. goto Cleanup;
  1719. // Initialize display
  1720. osdc.FillBitmap(rcxyClient.bottom, rcxyClient.right);
  1721. // Set the DC to the memory DC
  1722. SetDC(hdcMem);
  1723. // Get view rectangle that we need for rendering
  1724. GetViewRect(rcView, &rcClient);
  1725. // Adjust point to be relative to the memory display
  1726. pt.u -= prcClient->left;
  1727. pt.v -= prcClient->top;
  1728. // Initalize box around point. Note that we only really need to render
  1729. // the data inside this box because this is the only area that we will
  1730. // test.
  1731. rcRender.top = pt.v - HIT_CLOSE_RECT_INC;
  1732. if (rcRender.top < 0)
  1733. rcRender.top = 0;
  1734. rcRender.bottom = pt.v + HIT_CLOSE_RECT_INC;
  1735. if (rcRender.bottom > rcClient.bottom)
  1736. rcRender.bottom = rcClient.bottom;
  1737. rcRender.left = pt.u - HIT_CLOSE_RECT_INC;
  1738. if (rcRender.left < 0)
  1739. rcRender.left = 0;
  1740. rcRender.right = pt.u + HIT_CLOSE_RECT_INC;
  1741. if (rcRender.right > rcClient.right)
  1742. rcRender.right = rcClient.right;
  1743. // Now render
  1744. Render(rcView, rcRender);
  1745. // Hit test
  1746. // Assume no hit
  1747. *pHitResult = TXTHITRESULT_TRANSPARENT;
  1748. // At this point we won't fail this
  1749. hr = S_OK;
  1750. // Is there an exact hit?
  1751. POINT ptxy;
  1752. PointFromPointuv(ptxy, pt);
  1753. if (GetPixel(hdcMem, ptxy.x, ptxy.y) != crBackground)
  1754. {
  1755. *pHitResult = TXTHITRESULT_HIT;
  1756. goto Cleanup;
  1757. }
  1758. // Is it close? We determine closeness by putting
  1759. // a 10 x 10 pixel box around the hit point and
  1760. // seeing if there is a hit there.
  1761. // Loop examining each bit in the box to see if it is on.
  1762. for (uRow = rcRender.top; uRow <= rcRender.bottom; uRow++)
  1763. {
  1764. for (vCol = rcRender.left; vCol <= rcRender.right; vCol++)
  1765. {
  1766. pt.u = uRow;
  1767. pt.v = vCol;
  1768. PointFromPointuv(ptxy, pt);
  1769. if (GetPixel(hdcMem, ptxy.x, ptxy.y) != crBackground)
  1770. {
  1771. *pHitResult = TXTHITRESULT_CLOSE;
  1772. goto Cleanup;
  1773. }
  1774. }
  1775. }
  1776. Cleanup:
  1777. ResetDC(); //REVIEW (keithcu) shouldn't be needed!
  1778. return hr;
  1779. }
  1780. //============================ ITxNotify Interface ==========================
  1781. /*
  1782. * CDisplay::OnPreReplaceRange(cp, cchDel, cchNew, cpFormatMin, cpFormatMax, pNotifyData)
  1783. *
  1784. * @mfunc
  1785. * Preprocess a change in backing store
  1786. *
  1787. * @devnote
  1788. * This display doesn't care about before changes
  1789. */
  1790. void CDisplay::OnPreReplaceRange(
  1791. LONG cp, //@parm cp where ReplaceRange starts ("cpMin")
  1792. LONG cchDel, //@parm Count of chars after cp that are deleted
  1793. LONG cchNew, //@parm Count of chars inserted after cp
  1794. LONG cpFormatMin, //@parm cpMin for a formatting change
  1795. LONG cpFormatMax, //@parm cpMost for a formatting change
  1796. NOTIFY_DATA *pNotifyData) //@parm special data to indicate changes
  1797. {
  1798. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::OnPreReplaceRange");
  1799. // Display doesn't care about before the fact
  1800. }
  1801. /*
  1802. * CDisplay::OnPostReplaceRange(cp, cchDel, cchNew, cpFormatMin, cpFormatMax, pNotifyData)
  1803. *
  1804. * @mfunc
  1805. * Process a change to the backing store as it applies to the display
  1806. */
  1807. void CDisplay::OnPostReplaceRange(
  1808. LONG cp, //@parm cp where ReplaceRange starts ("cpMin")
  1809. LONG cchDel, //@parm Count of chars after cp that are deleted
  1810. LONG cchNew, //@parm Count of chars inserted after cp
  1811. LONG cpFormatMin, //@parm cpMin for a formatting change
  1812. LONG cpFormatMax, //@parm cpMost for a formatting change
  1813. NOTIFY_DATA *pNotifyData) //@parm special data to indicate changes
  1814. {
  1815. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::OnPostReplaceRange");
  1816. // There is one NO-OP's for the display:
  1817. // currently loading a file.
  1818. //
  1819. // We NO-OP the load case because loading an RTF file can consist
  1820. // of potentially very many small actions as we peice together
  1821. // the various bits of formatted text. Once done, the load code
  1822. // will go through and do an update-all to the display.
  1823. Assert (cp != CONVERT_TO_PLAIN); // Handled with PreReplace notifications
  1824. // Figure out range needed to update
  1825. LONG cpNew = min(cp, cpFormatMin);
  1826. if(CP_INFINITE == cpNew)
  1827. {
  1828. // If both cp's are infinite we don't need to bother with
  1829. // this operation.
  1830. return;
  1831. }
  1832. if(!_ped->_fInPlaceActive)
  1833. {
  1834. // If not active, just invalidate everything
  1835. InvalidateRecalc();
  1836. _ped->TxInvalidate();
  1837. _ped->TxUpdateWindow();
  1838. return;
  1839. }
  1840. // Adjust cp for further calculations
  1841. if(CP_INFINITE == cp)
  1842. cp = 0;
  1843. // find the new max end of the original region.
  1844. LONG cpForEnd = max( (cp + cchDel), cpFormatMax);
  1845. // Number of deleted characters is the difference between the previous two
  1846. LONG cchDelForDisplay = cpForEnd - cpNew;
  1847. // The number deleted is simply number of new characters adjusted by
  1848. // the change in the number of characters.
  1849. LONG cchNewForDisplay = cchDelForDisplay + (cchNew - cchDel);
  1850. #ifndef NOLINESERVICES
  1851. if (g_pols)
  1852. g_pols->DestroyLine(this);
  1853. #endif
  1854. if(_padc)
  1855. {
  1856. // Display is frozen so accumulate the change instead of actually
  1857. // displaying it on the screen.
  1858. _padc->UpdateRecalcRegion(cpNew, cchDelForDisplay, cchNewForDisplay);
  1859. return;
  1860. }
  1861. // Tell display to update
  1862. CRchTxtPtr rtp(_ped, cpNew);
  1863. UpdateView(rtp, cchDelForDisplay, cchNewForDisplay);
  1864. }
  1865. /*
  1866. * CDisplay::SetWordWrap(fWordWrap)
  1867. *
  1868. * @mfunc
  1869. * Sets the no wrap flag
  1870. *
  1871. * @devnote
  1872. * We will always allow the property to be set but we will not
  1873. * necessarily pay attention. In other words, word wrap has no
  1874. * effect on a single line edit control.
  1875. */
  1876. void CDisplay::SetWordWrap(
  1877. BOOL fWordWrap) //@param TRUE - turn on word wrap.
  1878. {
  1879. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::SetWordWrap");
  1880. AssertSz((fWordWrap == TRUE) || (fWordWrap == FALSE),
  1881. "CDisplay::SetWordWrap bad input flag");
  1882. // Set nowrap to whatever is coming in.
  1883. _fWordWrap = fWordWrap;
  1884. }
  1885. /*
  1886. * CDisplay::GetWordWrap()
  1887. *
  1888. * @mfunc
  1889. * Return state of word wrap property
  1890. *
  1891. * @rdesc
  1892. * TRUE - word wrap is on
  1893. * FALSE - word wrap is is off.
  1894. *
  1895. * @devnote
  1896. * Derived classes such as CDisplaySL override this.
  1897. */
  1898. BOOL CDisplay::GetWordWrap() const
  1899. {
  1900. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::GetWordWrap");
  1901. return _fWordWrap;
  1902. }
  1903. /*
  1904. * CDisplay::GetViewDim(dup, dvp)
  1905. *
  1906. * @mfunc
  1907. * Return the height & width of view adjusted for view inset
  1908. */
  1909. void CDisplay::GetViewDim(
  1910. LONG& dup, //@parm Where to return the width
  1911. LONG& dvp) //@parm Where to return the height
  1912. {
  1913. // We build a client rectangle to take advantage of GetViewRect routine
  1914. // which really does all the work for us.
  1915. RECTUV rcClient;
  1916. rcClient.left = 0;
  1917. rcClient.top = 0;
  1918. rcClient.right = dup;
  1919. rcClient.bottom = dvp;
  1920. // Take into account inset and selection bar. The parameters here are a bit
  1921. // of a trick. The second parameter gets copied into the first and since
  1922. // we don't need the original client rect we save a rect off the stack.
  1923. GetViewRect(rcClient, &rcClient);
  1924. dup = rcClient.right - rcClient.left;
  1925. dvp = rcClient.bottom - rcClient.top;
  1926. }
  1927. /*
  1928. * CDisplay::SaveUpdateCaret (fScrollIntoView)
  1929. *
  1930. * @mfunc Save UpdateCaret parameter so update caret can be called
  1931. * after the display is thawed.
  1932. *
  1933. * @rdesc None.
  1934. *
  1935. * @devnote
  1936. * This should only be called if IsFrozen is true.
  1937. */
  1938. void CDisplay::SaveUpdateCaret(
  1939. BOOL fScrollIntoView)
  1940. {
  1941. #ifdef DEBUG
  1942. if (_padc == NULL)
  1943. {
  1944. TRACEERRORSZ("CDisplay::SaveUpdateCaret called on thawed display");
  1945. }
  1946. #endif // DEBUG
  1947. if(_padc)
  1948. _padc->SaveUpdateCaret(fScrollIntoView);
  1949. }
  1950. /*
  1951. * CDisplay::SetNeedRedisplayOnThaw
  1952. *
  1953. * @mfunc
  1954. * Automatically redisplay control on thaw
  1955. */
  1956. void CDisplay::SetNeedRedisplayOnThaw(BOOL fNeedRedisplay)
  1957. {
  1958. Assert (_padc);
  1959. _padc->SetNeedRedisplayOnThaw(fNeedRedisplay);
  1960. }
  1961. /*
  1962. * CDisplay::Freeze
  1963. *
  1964. * @mfunc
  1965. * Prevent any updates from occuring in the display
  1966. */
  1967. void CDisplay::Freeze()
  1968. {
  1969. if(NULL == _padc)
  1970. {
  1971. // Allocate object to keep track of changes
  1972. _padc = new CAccumDisplayChanges();
  1973. // We can now return because the accum object has a reference
  1974. // or the memory allocation failed. If the memory allocation
  1975. // failed, This really isn't a catastrophe because all it means
  1976. // is that things will get displayed ugly temporarily, so we can
  1977. // pretend it didn't happen.
  1978. return;
  1979. }
  1980. // Tell object that an additional freeze has occurred.
  1981. _padc->AddRef();
  1982. }
  1983. /*
  1984. * CDisplay::Thaw()
  1985. *
  1986. * @mfunc
  1987. * If this is the last thaw, then cause display to be updated.
  1988. *
  1989. */
  1990. void CDisplay::Thaw()
  1991. {
  1992. BOOL fUpdateCaret, fScrollIntoView, fNeedRedisplay;
  1993. LONG cp, cchNew, cchDel;
  1994. CTxtSelection *psel;
  1995. if(_padc)
  1996. {
  1997. // Release reference to accum object
  1998. if(_padc->Release() == 0)
  1999. {
  2000. // Last thaw so we need to update display
  2001. // Get the changes
  2002. _padc->GetUpdateRegion(&cp, &cchDel, &cchNew,
  2003. &fUpdateCaret, &fScrollIntoView, &fNeedRedisplay);
  2004. // Clear the object - note we do this before
  2005. // the update just on the off chance that
  2006. // a new freeze manages to get in during the
  2007. // update of the display.
  2008. delete _padc;
  2009. _padc = NULL;
  2010. if(cp != CP_INFINITE)
  2011. {
  2012. // Display changed
  2013. if(!_ped->fInplaceActive())
  2014. {
  2015. // Are not inplace active so we need to put this operation
  2016. // off till a more appropriate time.
  2017. InvalidateRecalc();
  2018. _ped->TxInvalidate();
  2019. _ped->TxUpdateWindow();
  2020. return;
  2021. }
  2022. // Update display
  2023. CRchTxtPtr rtp(_ped, cp);
  2024. if(!UpdateView(rtp, cchDel, cchNew))
  2025. return; // Update failed
  2026. }
  2027. if (fNeedRedisplay)
  2028. _ped->TxInvalidate();
  2029. // Did selection request a caret update?
  2030. if(fUpdateCaret && _ped->fInplaceActive())
  2031. {
  2032. psel = _ped->GetSel();
  2033. psel->UpdateCaret(fScrollIntoView);
  2034. }
  2035. }
  2036. }
  2037. }
  2038. /*
  2039. * CDisplay::IsPrinter
  2040. *
  2041. * @mfunc
  2042. * Returns whether this is a printer
  2043. *
  2044. * @rdesc
  2045. * TRUE - is a display to a printer
  2046. * FALSE - is not a display to a printer
  2047. *
  2048. * @devnote
  2049. * No display except a display CDisplayPrinter should
  2050. * ever have a chance to return TRUE to this function.
  2051. */
  2052. BOOL CDisplay::IsPrinter() const
  2053. {
  2054. return FALSE;
  2055. }
  2056. /*
  2057. * CDisplay::Zombie ()
  2058. *
  2059. * @mfunc
  2060. * Turn this object into a zombie
  2061. */
  2062. void CDisplay::Zombie ()
  2063. {
  2064. TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CDisplay::Zombie");
  2065. }
  2066. /*
  2067. * CDisplay::IsUScrollEnabled ()
  2068. *
  2069. * @mfunc
  2070. * Return whether horizontal scroll bar is enabled
  2071. *
  2072. * @rdesc
  2073. * TRUE - yes
  2074. * FALSE - no
  2075. *
  2076. * @devnote
  2077. * The reason for this routine is that _fUScrollEnabled means
  2078. * to scroll text and can be set even if there is no scroll
  2079. * bar. Therefore, we need to look at the host properties
  2080. * as well to tell use whether this means there are scroll
  2081. * bars.
  2082. */
  2083. BOOL CDisplay::IsUScrollEnabled()
  2084. {
  2085. return _fUScrollEnabled && ((_ped->TxGetScrollBars() & WS_HSCROLL) != 0);
  2086. }
  2087. /*
  2088. * CDisplayML::GetPage(piPage, dwFlags, pcrg)
  2089. *
  2090. * @mfunc
  2091. * Get page number for first visible line
  2092. *
  2093. * @rdesc
  2094. * HRESULT = E_FAIL
  2095. */
  2096. HRESULT CDisplay::GetPage(
  2097. LONG *piPage, //@parm Out parm for page number
  2098. DWORD dwFlags, //@parm Flags for which page to use
  2099. CHARRANGE *pcrg) //@parm Out parm for CHARRANGE for page
  2100. {
  2101. return E_FAIL;
  2102. }
  2103. /*
  2104. * CDisplay::SetPage(iPage)
  2105. *
  2106. * @mfunc
  2107. * Set page number for _iliFirstVisible
  2108. */
  2109. HRESULT CDisplay::SetPage (
  2110. LONG iPage)
  2111. {
  2112. return E_FAIL;
  2113. }
  2114. /*
  2115. * CDisplay::Paginate(ili)
  2116. *
  2117. * @mfunc
  2118. * Recompute page breaks from iLineFirst on
  2119. *
  2120. * @rdesc
  2121. * TRUE if success
  2122. */
  2123. BOOL CDisplay::Paginate (
  2124. LONG ili, //@parm Line to redo pagination from
  2125. BOOL fRebindFirstVisible) //@parm If TRUE, call RebindFirstVisible()
  2126. {
  2127. return FALSE; // Only ML displays can paginate
  2128. }
  2129. /*
  2130. * CDisplay::PointFromPointuv(pt, ptuv)
  2131. *
  2132. * @mfunc
  2133. * convert a pointuv to a point.
  2134. * fExtTextOutBug is to work around a display bug in Windows. This might not happen
  2135. * on all platforms...
  2136. *
  2137. */
  2138. void CDisplay::PointFromPointuv(POINT &pt, const POINTUV &ptuv, BOOL fExtTextOut) const
  2139. {
  2140. TFLOW tflow = GetTflow();
  2141. if (tflow == tflowES)
  2142. {
  2143. memcpy(&pt, &ptuv, sizeof(pt));
  2144. return;
  2145. }
  2146. long dupClient, dvpClient;
  2147. GetCachedSize(&dupClient, &dvpClient);
  2148. switch(tflow)
  2149. {
  2150. case tflowSW:
  2151. pt.x = dvpClient - ptuv.v - 1;
  2152. pt.y = ptuv.u;
  2153. break;
  2154. case tflowWN:
  2155. pt.x = dupClient - ptuv.u - 1;
  2156. pt.y = dvpClient - ptuv.v - 1;
  2157. break;
  2158. case tflowNE:
  2159. pt.x = ptuv.v + fExtTextOut ? 1 : 0;
  2160. pt.y = dupClient - ptuv.u - 1;
  2161. break;
  2162. }
  2163. }
  2164. /*
  2165. * CDisplay::PointuvFromPoint(ptuv, pt)
  2166. *
  2167. * @mfunc
  2168. * convert a point to a pointuv.
  2169. *
  2170. */
  2171. void CDisplay::PointuvFromPoint(POINTUV &ptuv, const POINT &pt) const
  2172. {
  2173. TFLOW tflow = GetTflow();
  2174. if (tflow == tflowES)
  2175. {
  2176. memcpy(&ptuv, &pt, sizeof(pt));
  2177. return;
  2178. }
  2179. long dupClient, dvpClient;
  2180. GetCachedSize(&dupClient, &dvpClient);
  2181. switch(tflow)
  2182. {
  2183. case tflowSW:
  2184. ptuv.u = pt.y;
  2185. ptuv.v = dvpClient - pt.x - 1;
  2186. break;
  2187. case tflowWN:
  2188. ptuv.u = dupClient - pt.x - 1;
  2189. ptuv.v = dvpClient - pt.y - 1;
  2190. break;
  2191. case tflowNE:
  2192. ptuv.u = dupClient - pt.y - 1;
  2193. ptuv.v = pt.x;
  2194. break;
  2195. }
  2196. }
  2197. /*
  2198. * CDisplay::RectFromRectuv(rc, rcuv)
  2199. *
  2200. * @mfunc
  2201. * convert a RECT from a RECTUV.
  2202. *
  2203. */
  2204. void CDisplay::RectFromRectuv(RECT& rc, const RECTUV& rcuv) const
  2205. {
  2206. TFLOW tflow = GetTflow();
  2207. if (tflow == tflowES)
  2208. {
  2209. memcpy(&rc, &rcuv, sizeof(rcuv));
  2210. return;
  2211. }
  2212. long dvp = rcuv.bottom - rcuv.top;
  2213. long dup = rcuv.right - rcuv.left;
  2214. long dupClient, dvpClient;
  2215. GetCachedSize(&dupClient, &dvpClient);
  2216. switch(tflow)
  2217. {
  2218. case tflowSW:
  2219. rc.left = dvpClient - rcuv.bottom;
  2220. rc.top = rcuv.left;
  2221. rc.right = rc.left + dvp;
  2222. rc.bottom = rc.top + dup;
  2223. break;
  2224. case tflowWN:
  2225. rc.right = dupClient - rcuv.left;
  2226. rc.bottom = dvpClient - rcuv.top;
  2227. rc.left = rc.right - dup;
  2228. rc.top = rc.bottom - dvp;
  2229. break;
  2230. case tflowNE:
  2231. rc.left = rcuv.top;
  2232. rc.top = dupClient - rcuv.right;
  2233. rc.right = rc.left + dvp;
  2234. rc.bottom = rc.top + dup;
  2235. break;
  2236. }
  2237. }
  2238. /*
  2239. * CDisplay::RectFromRectuv(rc, rcuv)
  2240. *
  2241. * @mfunc
  2242. * convert a RECTUV from a RECT.
  2243. *
  2244. */
  2245. void CDisplay::RectuvFromRect(RECTUV &rcuv, const RECT& rc) const
  2246. {
  2247. TFLOW tflow = GetTflow();
  2248. if (tflow == tflowES)
  2249. {
  2250. memcpy(&rcuv, &rc, sizeof(rcuv));
  2251. return;
  2252. }
  2253. long dyp = rc.bottom - rc.top;
  2254. long dxp = rc.right - rc.left;
  2255. long dupClient, dvpClient;
  2256. GetCachedSize(&dupClient, &dvpClient);
  2257. switch(tflow)
  2258. {
  2259. case tflowSW:
  2260. rcuv.left = rc.top;
  2261. rcuv.top = dvpClient - rc.right;
  2262. rcuv.right = rcuv.left + dyp;
  2263. rcuv.bottom = rcuv.top + dxp;
  2264. break;
  2265. case tflowWN:
  2266. rcuv.left = dupClient - rc.right;
  2267. rcuv.top = dvpClient - rc.bottom;
  2268. rcuv.right = rcuv.left + dxp;
  2269. rcuv.bottom = rcuv.top + dyp;
  2270. break;
  2271. case tflowNE:
  2272. rcuv.left = dupClient - rc.bottom;
  2273. rcuv.top = rc.left;
  2274. rcuv.right = rcuv.left + dyp;
  2275. rcuv.bottom = rcuv.top + dxp;
  2276. break;
  2277. }
  2278. }