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.

1044 lines
24 KiB

  1. /*
  2. * @doc INTERNAL
  3. *
  4. * @module DISPSL.CPP -- CDisplaySL class |
  5. *
  6. * This is the Single-line display engine. See disp.c for the base class
  7. * methods and dispml.c for the Multi-line display engine.
  8. *
  9. * Owner:<nl>
  10. * Original RichEdit code: David R. Fulmer
  11. * Christian Fortini
  12. * Murray Sargent
  13. *
  14. * Copyright (c) 1995-2000, Microsoft Corporation. All rights reserved.
  15. */
  16. #include "_common.h"
  17. #include "_dispsl.h"
  18. #include "_measure.h"
  19. #include "_select.h"
  20. #include "_render.h"
  21. #include "_font.h"
  22. #include "_dfreeze.h"
  23. ASSERTDATA
  24. const LONG CALC_XSCROLL_FROM_FIRST_VISIBLE = -2;
  25. /*
  26. * CDisplaySL::CDisplaySL
  27. *
  28. * Purpose
  29. * Constructor
  30. */
  31. CDisplaySL::CDisplaySL ( CTxtEdit* ped )
  32. : CDisplay( ped )
  33. {
  34. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::CDisplaySL");
  35. Assert(!_fMultiLine);
  36. }
  37. /*
  38. * CDisplaySL::Init()
  39. *
  40. * @mfunc
  41. * Init this display for the screen
  42. *
  43. * @rdesc
  44. * TRUE iff initialization succeeded
  45. */
  46. BOOL CDisplaySL::Init()
  47. {
  48. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::Init");
  49. // Initialize our base class
  50. if(!CDisplay::Init())
  51. return FALSE;
  52. SetWordWrap(FALSE);
  53. return TRUE;
  54. }
  55. /*
  56. * CDisplaySL::InitVars()
  57. *
  58. */
  59. void CDisplaySL::InitVars()
  60. {
  61. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::InitVars");
  62. _upScroll = 0;
  63. SetCpFirstVisible(0);
  64. }
  65. /*
  66. * CDisplaySL::RecalcView(fUpdateScrollBars, prc)
  67. *
  68. * @mfunc
  69. * Recalc all lines breaks and update first visible line
  70. *
  71. * @rdesc
  72. * TRUE if success
  73. */
  74. BOOL CDisplaySL::RecalcView(
  75. BOOL fUpdateScrollBars, //@param TRUE - update scroll bars
  76. RECTUV* prc)
  77. {
  78. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::RecalcView");
  79. LONG dupOld = _dup;
  80. if(!RecalcLine())
  81. return FALSE;
  82. if(_fViewChanged)
  83. {
  84. if(IsActive() || _dup <= GetDupView())
  85. {
  86. _upScroll = 0;
  87. SetCpFirstVisible(0);
  88. }
  89. else if(CALC_XSCROLL_FROM_FIRST_VISIBLE == _upScroll)
  90. {
  91. // In this case we want to set our upScroll by a visible. The
  92. // only way to get here is if the active view has been cloned
  93. // for displaying an inactive view.
  94. _upScroll = 0; // Assume that first visible is 0
  95. if(GetFirstVisibleCp()) // Check first visible
  96. {
  97. CMeasurer me(this); // Start at cp 0
  98. me.NewLine(*this); // Measure from there to where we are
  99. // Scroll is length to character
  100. _upScroll = CLine::UpFromCch(me, GetFirstVisibleCp(), TA_TOP);
  101. }
  102. }
  103. if(fUpdateScrollBars)
  104. UpdateScrollBar(SB_HORZ, TRUE);
  105. _fViewChanged = FALSE;
  106. }
  107. // We only resize if width of single line control has changed.
  108. if(_dup != dupOld)
  109. {
  110. if (FAILED(RequestResize()))
  111. _ped->GetCallMgr()->SetOutOfMemory();
  112. else if (prc && _ped->_fInOurHost) /*bug fix# 5830, forms3 relies on old behavior*/
  113. _ped->TxGetClientRect(prc);
  114. }
  115. return TRUE;
  116. }
  117. /*
  118. * CDisplaySL::RecalcLine()
  119. *
  120. * @mfunc
  121. * Recalculate a line
  122. *
  123. * @rdesc
  124. * TRUE if success <nl>
  125. * FALSE if failure <nl>
  126. */
  127. BOOL CDisplaySL::RecalcLine()
  128. {
  129. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::RecalcLine");
  130. Assert( _ped );
  131. // Create a measurer starting at cp = 0
  132. CMeasurer me(this);
  133. LONG dupOld = _dup;
  134. BOOL fMeasured = CLine::Measure(me, MEASURE_FIRSTINPARA);
  135. if(!fMeasured)
  136. {
  137. Assert(FALSE); // Should succeed
  138. InitVars();
  139. return FALSE;
  140. }
  141. _fNeedRecalc = FALSE;
  142. _fRecalcDone = TRUE;
  143. if(dupOld != _dup)
  144. _fViewChanged = TRUE;
  145. _fLineRecalcErr = FALSE;
  146. return fMeasured;
  147. }
  148. /*
  149. * CDisplaySL::Render(rcView, rcRender)
  150. *
  151. * @mfunc
  152. * Renders this line
  153. */
  154. void CDisplaySL::Render(
  155. const RECTUV &rcView, //@parm View RECT
  156. const RECTUV &rcRender) //@parm RECT to render (must be contained in
  157. // client rect)
  158. {
  159. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::Render");
  160. POINTUV pt;
  161. _fRectInvalid = FALSE;
  162. CRenderer re(this);
  163. if(!re.StartRender(rcView, rcRender))
  164. return;
  165. // Set renderer at top/left of view rect
  166. pt.u = rcView.left - _upScroll;
  167. pt.v = rcView.top;
  168. re.SetCurPoint(pt);
  169. // Renderer is set at cp = 0 at the moment
  170. CLine::Render(re, TRUE);
  171. re.EndRender(this, this, 0, pt);
  172. if(_fOffscreenOnce)
  173. _fUseOffscreenDC = _fOffscreenOnce = FALSE;
  174. // If line metrics are not yet up to date, get them from renderer
  175. if(_dup == -1)
  176. {
  177. _dup = re._li._dup;
  178. _dvpHeight = re._li._dvpHeight;
  179. _dvpDescent = re._li._dvpDescent;
  180. }
  181. }
  182. /*
  183. * CDisplaySL::WaitForRecalcIli(ili)
  184. *
  185. * @mfunc
  186. * Wait until line array is recalculated up to line <p ili>
  187. *
  188. * @rdesc
  189. * Returns TRUE if lines were recalc'd up to ili (TRUE if ili == 0)
  190. */
  191. BOOL CDisplaySL::WaitForRecalcIli (
  192. LONG ili) //@parm Line index to recalculate line array up to
  193. {
  194. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::WaitForRecalcIli");
  195. return ili == 0;
  196. }
  197. /*
  198. * CDisplaySL::GetScrollRange(nBar)
  199. *
  200. * @mfunc
  201. * Returns the max part of a scrollbar range for scrollbar <p nBar>
  202. *
  203. * @rdesc
  204. * LONG max part of scrollbar range
  205. */
  206. LONG CDisplaySL::GetScrollRange(
  207. INT nBar) const //@parm Scroll bar to interrogate (SB_VERT or SB_HORZ)
  208. {
  209. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetScrollRange");
  210. Assert( IsMain() );
  211. LONG lRange = 0;
  212. if(nBar != SB_VERT && _fUScrollEnabled)
  213. {
  214. if(_ped->TxGetScrollBars() & WS_HSCROLL)
  215. {
  216. lRange = max(0, _dup + _ped->GetCaretWidth());
  217. lRange = min(lRange, _UI16_MAX);
  218. }
  219. }
  220. return lRange;
  221. }
  222. /*
  223. * CDisplaySL::UpdateScrollBar(nBar, fUpdateRange)
  224. *
  225. * @mfunc
  226. * Update horizontal scroll bar
  227. * Also figure whether the scroll bar should be visible or not
  228. *
  229. * @rdesc
  230. * BOOL
  231. */
  232. BOOL CDisplaySL::UpdateScrollBar (
  233. INT nBar, //@parm Which scrollbar: SB_HORZ or SB_VERT
  234. BOOL fUpdateRange) //@parm Should range be recomputed and updated
  235. {
  236. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::UpdateScrollBar");
  237. // Note: In the old days we didn't allow autosize & scroll bars, so to keep
  238. // forms working, we need this special logic with respect to autosize.
  239. if (!IsActive() || SB_VERT == nBar ||
  240. !_ped->fInOurHost() && _ped->TxGetAutoSize())
  241. {
  242. // Scroll bars are only updated on active views.
  243. return FALSE;
  244. }
  245. const DWORD dwScrollBars = _ped->TxGetScrollBars();
  246. const BOOL fHide = !(dwScrollBars & ES_DISABLENOSCROLL);
  247. BOOL fReturn = FALSE;
  248. BOOL fEnabled = TRUE;
  249. BOOL fEnabledOld = FALSE;
  250. LONG lScroll = 0;
  251. CTxtSelection *psel = _ped->GetSelNC();
  252. // Get scrolling position
  253. if(nBar == SB_HORZ)
  254. {
  255. if(!(dwScrollBars & WS_HSCROLL))
  256. {
  257. // even if we don't have scrollbars, we may allow horizontal
  258. // scrolling.
  259. if(!_fUScrollEnabled)
  260. _fUScrollEnabled = !!(dwScrollBars & ES_AUTOHSCROLL);
  261. return FALSE;
  262. }
  263. fEnabledOld = _fUScrollEnabled;
  264. lScroll = ConvertUPosToScrollPos(_upScroll);
  265. if(_dup <= _dupView)
  266. fEnabled = FALSE;
  267. }
  268. // !s beforehand because all true values aren't necessarily equal
  269. if(!fEnabled != !fEnabledOld)
  270. {
  271. if(_fDeferUpdateScrollBar)
  272. _fUpdateScrollBarDeferred = TRUE;
  273. else
  274. {
  275. if (nBar == SB_HORZ)
  276. _fUScrollEnabled = fEnabled;
  277. else
  278. _fVScrollEnabled = fEnabled;
  279. }
  280. if(!_fDeferUpdateScrollBar)
  281. {
  282. if(!fHide) // Don't hide scrollbar, just disable
  283. _ped->TxEnableScrollBar(nBar, fEnabled ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
  284. else
  285. {
  286. fReturn = TRUE;
  287. // Make sure to hide caret before showing scrollbar
  288. if(psel)
  289. psel->ShowCaret(FALSE);
  290. // Hide or show scroll bar
  291. _ped->TxShowScrollBar(nBar, fEnabled);
  292. if(psel)
  293. psel->ShowCaret(TRUE);
  294. }
  295. }
  296. }
  297. // Set scrollbar range and thumb position
  298. if(fEnabled)
  299. {
  300. if(fUpdateRange)
  301. {
  302. if(!_fDeferUpdateScrollBar)
  303. _ped->TxSetScrollRange(nBar, 0, GetScrollRange(nBar), FALSE);
  304. }
  305. if(_fDeferUpdateScrollBar)
  306. _fUpdateScrollBarDeferred = TRUE;
  307. else
  308. _ped->TxSetScrollPos(nBar, lScroll, TRUE);
  309. }
  310. else if (!_fDeferUpdateScrollBar)
  311. {
  312. // This turns off the scroll bar and only needs to happen when a change
  313. // occurs so we can count on the change in state check above to set
  314. // _fUpdateScrollBarDeferred.
  315. if (!fEnabled && fEnabledOld)
  316. _ped->TxSetScrollRange(nBar, 0, 0, FALSE);
  317. }
  318. return fReturn;
  319. }
  320. BOOL CDisplaySL::IsMain() const
  321. {
  322. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::IsMain");
  323. return TRUE;
  324. }
  325. LONG CDisplaySL::GetDupLineMax() const
  326. {
  327. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetWidth");
  328. return CLine::_dup;
  329. }
  330. LONG CDisplaySL::GetHeight() const
  331. {
  332. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetHeight");
  333. return CLine::_dvpHeight;
  334. }
  335. LONG CDisplaySL::GetResizeHeight() const
  336. {
  337. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetResizeHeight");
  338. return CLine::_dvpHeight;
  339. }
  340. LONG CDisplaySL::LineCount() const
  341. {
  342. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::LineCount");
  343. return 1;
  344. }
  345. /*
  346. * CDisplaySL::GetCliVisible()
  347. *
  348. * @mfunc
  349. * Get count of visible lines and update GetCp()MostVisible for PageDown()
  350. *
  351. * @rdesc
  352. * count of visible lines
  353. */
  354. LONG CDisplaySL::GetCliVisible (
  355. LONG* pcpMostVisible, //@parm Returns cpMostVisible
  356. BOOL fLastCharOfLastVisible) const //@parm Want cp of last visible char
  357. // (ignored here).
  358. {
  359. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetCliVisible");
  360. if (pcpMostVisible)
  361. *pcpMostVisible = CLine::_cch;
  362. return 1;
  363. }
  364. LONG CDisplaySL::GetFirstVisibleLine() const
  365. {
  366. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetFirstVisibleLine");
  367. return 0;
  368. }
  369. /*
  370. * CDisplaySL::GetLineText(ili, pchBuff, cchMost)
  371. *
  372. * @mfunc
  373. * Copy given line of this display into a character buffer
  374. *
  375. * @rdesc
  376. * number of character copied
  377. */
  378. LONG CDisplaySL::GetLineText (
  379. LONG ili, //@parm Line to get text of
  380. TCHAR * pchBuff, //@parm Buffer to stuff text into
  381. LONG cchMost) //@parm Length of buffer
  382. {
  383. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetLineText");
  384. if(ili == 0)
  385. {
  386. cchMost = min(cchMost, _ped->GetTextLength());
  387. if(cchMost > 0)
  388. {
  389. CTxtPtr tp(_ped, 0);
  390. return tp.GetText( cchMost, pchBuff );
  391. }
  392. }
  393. return 0;
  394. }
  395. /*
  396. * CDisplaySL::CpFromLine(ili, pdvp)
  397. *
  398. * @mfunc
  399. * Computes cp at start of given line
  400. * (and top of line position relative to this display)
  401. *
  402. * @rdesc
  403. * cp of given line; here always 0
  404. */
  405. LONG CDisplaySL::CpFromLine (
  406. LONG ili, //@parm Line we're interested in (if <lt> 0 means caret line)
  407. LONG *pdvp) //@parm Returns top of line relative to display
  408. {
  409. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::CpFromLine");
  410. // (NULL if don't want that info)
  411. Assert( ili == 0 );
  412. if(pdvp)
  413. *pdvp = 0;
  414. return 0;
  415. }
  416. /*
  417. * CDisplaySL::LineFromCp(cp, fAtEnd)
  418. *
  419. * @mfunc
  420. * Computes line containing given cp.
  421. *
  422. * @rdesc
  423. * index of line found; here returns 0 always
  424. */
  425. LONG CDisplaySL::LineFromCp(
  426. LONG cp, //@parm cp to look for
  427. BOOL fAtEnd) //@parm If true, return previous line for ambiguous cp
  428. {
  429. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::LineFromCp");
  430. return 0;
  431. }
  432. /*
  433. * CDisplaySL::CpFromPoint(pt, prcClient, ptp, prp, fAllowEOL, pHit, pdispdim)
  434. *
  435. * @mfunc
  436. * Determine cp at given point
  437. *
  438. * @devnote
  439. * --- Use when in-place active only ---
  440. *
  441. * @rdesc
  442. * Computed cp, -1 if failed
  443. */
  444. LONG CDisplaySL::CpFromPoint(
  445. POINTUV pt, //@parm Point to compute cp at (client coords)
  446. const RECTUV *prcClient,//@parm Client rectangle (can be NULL if active).
  447. CRchTxtPtr * const ptp, //@parm Returns text pointer at cp (may be NULL)
  448. CLinePtr * const prp, //@parm Returns line pointer at cp (may be NULL)
  449. BOOL fAllowEOL, //@parm Click at EOL returns cp after CRLF
  450. HITTEST * phit, //@parm Out parm for hit-test value
  451. CDispDim * pdispdim, //@parm Out parm for display dimensions
  452. LONG *pcpActual, //@parm Out cp that pt is above
  453. CLine * pliParent) //@parm Parent pli for table row displays
  454. {
  455. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::CpFromPoint");
  456. RECTUV rcView;
  457. LONG cp = 0;
  458. LONG cch = 0;
  459. HITTEST hit = HT_Nothing;
  460. GetViewRect(rcView, prcClient);
  461. if (pt.v >= rcView.top && pt.v <= rcView.bottom)
  462. {
  463. // Create measurer at cp(0)
  464. CMeasurer me(this);
  465. // Get character in the line
  466. pt.u += _upScroll - rcView.left; // Transform to galley coordinates
  467. pt.v -= rcView.top;
  468. cch = CLine::CchFromUp(me, pt, pdispdim, &hit, pcpActual);
  469. // Don't allow click at EOL to select EOL marker and take into account
  470. // single line edits as well
  471. if(!fAllowEOL && cch == CLine::_cch && CLine::_cchEOP)
  472. me._rpTX.BackupCRLF();
  473. cp = me.GetCp();
  474. }
  475. if (phit)
  476. *phit = hit;
  477. if(ptp)
  478. ptp->SetCp(cp);
  479. if(prp)
  480. prp->Set(0, cch);
  481. return cp;
  482. }
  483. /*
  484. * CDisplaySL::PointFromTp(tp, fAtEnd, pt, prp, taMode, pdx)
  485. *
  486. * @mfunc
  487. * Determine coordinates at given tp
  488. *
  489. * @devnote
  490. * --- Use when in-place active only ---
  491. *
  492. * @rdesc
  493. * line index at cp, -1 if error
  494. */
  495. LONG CDisplaySL::PointFromTp(
  496. const CRchTxtPtr &rtp, //@parm Text ptr to get coordinates at
  497. const RECTUV *prcClient,//@parm Client rectangle (can be NULL if active).
  498. BOOL fAtEnd, //@parm Return end of previous line for ambiguous cp
  499. POINTUV & pt, //@parm Returns point at cp in client coords
  500. CLinePtr * const prp, //@parm Returns line pointer at tp (may be null)
  501. UINT taMode, //@parm Text Align mode: top, baseline, bottom
  502. CDispDim * pdispdim) //@parm Out parm for display dimensions
  503. {
  504. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::PointFromTp");
  505. LONG dy = 0;
  506. RECTUV rcView;
  507. CLinePtr rp(this);
  508. if(!rp.SetCp(rtp.GetCp(), fAtEnd))
  509. return -1;
  510. AssertSz(_ped->_fInPlaceActive || prcClient,
  511. "CDisplaySL::PointFromTp() called with invalid client rect");
  512. GetViewRect(rcView, prcClient);
  513. pt.u = rcView.left - _upScroll;
  514. pt.v = rcView.top;
  515. CMeasurer me(this, rtp);
  516. me.Move(-rp.GetIch()); // Backup to start of line
  517. me.NewLine(*rp); // Measure from there to where we are
  518. pt.u += CLine::UpFromCch(me, rp.GetIch(), taMode, pdispdim, &dy);
  519. pt.v += dy;
  520. if(prp)
  521. *prp = rp;
  522. return rp;
  523. }
  524. /*
  525. * CDisplaySL::UpdateView(&tpFirst, cchOld, cchNew)
  526. *
  527. * @mfunc
  528. * Update visible part of display (the "view" on the screen).
  529. *
  530. * @devnote
  531. * --- Use when in-place active only ---
  532. *
  533. * @rdesc
  534. * TRUE if success
  535. */
  536. BOOL CDisplaySL::UpdateView(
  537. CRchTxtPtr &tpFirst, //@parm Text ptr where change happened
  538. LONG cchOld, //@parm Count of chars deleted
  539. LONG cchNew) //@parm Count of chars inserted
  540. {
  541. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::UpdateView");
  542. BOOL fUpdateScrollBarHorz = FALSE;
  543. BOOL fReturn = TRUE;
  544. RECTUV rcView;
  545. CTxtSelection *psel = _ped->GetSelNC();
  546. LONG dupOld = _dup;
  547. BOOL fScrollChanged = FALSE;
  548. RECTUV rcClient;
  549. RECTUV rc;
  550. LONG dvpOld = _dvpHeight;
  551. if (_fNoUpdateView)
  552. return fReturn;
  553. AssertSz(_ped->_fInPlaceActive, "CDisplaySL::UpdateView(...) called when inactive");
  554. _ped->TxGetClientRect(&rcClient);
  555. GetViewRect(rcView, &rcClient);
  556. if(psel && !psel->PuttingChar())
  557. psel->ClearCchPending();
  558. if(!RecalcLine())
  559. {
  560. // We're in deep crap now, the recalc failed. Let's try to get
  561. // out of this with our head still mostly attached
  562. fReturn = FALSE;
  563. }
  564. // An update has occurred. Go offscreen to be flicker-free.
  565. if(!_fUseOffscreenDC)
  566. _fUseOffscreenDC = _fOffscreenOnce = TRUE;
  567. //If we tried to go offscreen, but the edit changed the first
  568. //character, it might be the WM_SETTEXT case called when dialogs
  569. //are instantiated, and so it doesn't make sense to go offscreen there.
  570. if (_fOffscreenOnce && tpFirst.GetCp() == 0)
  571. _fOffscreenOnce = _fUseOffscreenDC = FALSE;
  572. if(_dup <= _dupView)
  573. {
  574. // x scroll range is smaller than the view width
  575. // force x scrolling position = 0
  576. _upScroll = 0;
  577. SetCpFirstVisible(0);
  578. _fViewChanged = TRUE;
  579. fUpdateScrollBarHorz = TRUE;
  580. }
  581. _fRectInvalid = TRUE;
  582. // Only resize a Single Line edit control if the width changes
  583. if(_dup != dupOld)
  584. {
  585. if(FAILED(RequestResize()))
  586. _ped->GetCallMgr()->SetOutOfMemory();
  587. }
  588. // If view changed, update scroll bars
  589. if(_fViewChanged)
  590. {
  591. _fViewChanged = FALSE;
  592. fScrollChanged = UpdateScrollBar(SB_HORZ);
  593. }
  594. // Scroll bar state did not change so we need to update screen
  595. // Build an invalidation rectangle.
  596. rc = rcClient;
  597. if(dvpOld == _dvpHeight)
  598. {
  599. // Height of control did not change so we can minimize the update
  600. // rectangle to the height of the control.
  601. rc.bottom = rcView.top + _dvpHeight;
  602. }
  603. // Tell display to update when it gets a chance
  604. _ped->TxInvalidateRect(&rc);
  605. return fReturn;
  606. }
  607. /*
  608. * CDisplaySL::ScrollView(upScroll, vpScroll, fTracking, fFractionalScroll)
  609. *
  610. * @mfunc
  611. * Scroll view to new x and y position
  612. *
  613. * @devnote
  614. * This method tries to adjust the y scroll pos before
  615. * scrolling to display complete line at top. x scroll
  616. * pos is adjusted to avoid scrolling all text off the
  617. * view rectangle.
  618. *
  619. * Must be able to handle vpScroll <gt> pdp->yHeight and vpScroll <lt> 0
  620. *
  621. * @rdesc
  622. * TRUE if actual scrolling occurred,
  623. * FALSE if no change
  624. */
  625. BOOL CDisplaySL::ScrollView (
  626. LONG upScroll, //@parm New x scroll position
  627. LONG vpScroll, //@parm New y scroll position
  628. BOOL fTracking, //@parm TRUE indicates we are tracking scrollbar thumb
  629. BOOL fFractionalScroll)
  630. {
  631. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::ScrollView");
  632. LONG dupMax;
  633. LONG dx = 0;
  634. RECTUV rcClient, rcClip;
  635. CTxtSelection *psel = _ped->GetSelNC();
  636. COleObject *pipo;
  637. AssertSz(_ped->_fInPlaceActive, "CDisplaySL::ScrollView() called when not in-place");
  638. if(upScroll == -1)
  639. return FALSE;
  640. //For scrolling purposes, we clip to rcView's top and bottom, but rcClient's left and right
  641. _ped->TxGetClientRect(&rcClient);
  642. GetViewRect(rcClip, &rcClient);
  643. rcClip.left = rcClient.left;
  644. rcClip.right = rcClient.right;
  645. // Determine horizontal scrolling pos.
  646. dupMax = _dup;
  647. upScroll = min(upScroll, dupMax);
  648. upScroll = max(0, upScroll);
  649. dx = _upScroll - upScroll;
  650. if(dx)
  651. {
  652. _upScroll = upScroll;
  653. // Calculate new first visible
  654. CMeasurer me(this); // Create measurer at cp(0)
  655. POINTUV pt = {upScroll, 0};
  656. CDispDim dispdim;
  657. HITTEST Hit;
  658. LONG cpActual;
  659. CLine::CchFromUp(me, pt, &dispdim, &Hit, &cpActual);
  660. SetCpFirstVisible(cpActual); // Save character position
  661. }
  662. AssertSz(IsMain(), "CDisplaySL::ScrollView non-main SL control");
  663. // Now perform the actual scrolling
  664. if(dx)
  665. {
  666. if(!_fRectInvalid)
  667. {
  668. // Scroll only if scrolling < view dimensions and we are in-place
  669. // Note that we only scroll the active view and we can be in-place
  670. // active and have multiple inactive views.
  671. if(IsActive() && !IsTransparent() && dx < _dupView)
  672. {
  673. if(psel)
  674. psel->ShowCaret(FALSE);
  675. RECT rcxyClip;
  676. RectFromRectuv(rcxyClip, rcClip);
  677. _ped->TxScrollWindowEx(dx, 0, NULL, &rcxyClip);
  678. if(psel)
  679. psel->ShowCaret(TRUE);
  680. }
  681. else
  682. _ped->TxInvalidateRect(&rcClip);
  683. }
  684. if(psel)
  685. psel->UpdateCaret(FALSE);
  686. if(!fTracking && dx)
  687. {
  688. _ped->SendScrollEvent(EN_HSCROLL);
  689. UpdateScrollBar(SB_HORZ);
  690. }
  691. _ped->TxUpdateWindow();
  692. // FUTURE: since we're now repositioning in place active
  693. // objects every time we draw, this call seems to be
  694. // superfluous (AndreiB)
  695. // Tell object subsystem to reposition any in place objects
  696. if(_ped->GetObjectCount())
  697. {
  698. pipo = _ped->GetObjectMgr()->GetInPlaceActiveObject();
  699. if(pipo)
  700. pipo->OnReposition();
  701. }
  702. }
  703. return dx;
  704. }
  705. /*
  706. * CDisplaySL::InvertRange(cp, cch, selAction)
  707. *
  708. * @mfunc
  709. * Invert a given range on screen (for selection)
  710. *
  711. * @devnote
  712. * --- Use when in-place active only ---
  713. *
  714. * @rdesc
  715. * TRUE if success
  716. */
  717. BOOL CDisplaySL::InvertRange (
  718. LONG cp, //@parm Active end of range to invert
  719. LONG cch, //@parm Signed length of range
  720. SELDISPLAYACTION selAction) //@parm What we are doing to the selection
  721. {
  722. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::InvertRange");
  723. if(cch < 0) //make cch negative, make cp the minimum
  724. cch = -cch;
  725. else
  726. cp -= cch;
  727. #ifndef NOLINESERVICES
  728. if (g_pols)
  729. g_pols->DestroyLine(this);
  730. #endif
  731. // If display is frozen, just update recalc region and move on.
  732. if(_padc)
  733. {
  734. AssertSz(cp >= 0, "CDisplayML::InvertRange: range (cp) goes below"
  735. "zero!!" );
  736. // Make sure these values are bounded.
  737. if(cp > _ped->GetTextLength()) // Don't bother updating region;
  738. return TRUE; // it's out of bounds
  739. if(cp + cch > _ped->GetTextLength())
  740. cch -= cp + cch - _ped->GetTextLength();
  741. _padc->UpdateRecalcRegion(cp, cch, cch);
  742. return TRUE;
  743. }
  744. // Ensure all visible lines are recalced
  745. if(!WaitForRecalcView())
  746. return FALSE;
  747. //REVIEW (keithcu) CDisplayML::InvertRange() has a different order WRT
  748. //frozen displays and OLE objects.
  749. // If an object is being inverted, and that is all that
  750. // is being inverted, delegate to the ObjectMgr.
  751. if (cch == 1 && _ped->GetObjectCount() &&
  752. (selAction == selSetNormal || selAction == selSetHiLite) )
  753. {
  754. CObjectMgr* pobjmgr = _ped->GetObjectMgr();
  755. CTxtPtr tp(_ped, cp);
  756. if(tp.GetChar() == WCH_EMBEDDING && pobjmgr)
  757. pobjmgr->HandleSingleSelect(_ped, cp, selAction == selSetHiLite);
  758. }
  759. // Get view rectangle
  760. AssertSz(_ped->_fInPlaceActive, "CDisplaySL::InvertRange() called when not in-place active");
  761. _ped->TxInvalidate();
  762. return TRUE;
  763. }
  764. /*
  765. * CDisplaySL::InitLinePtr (&lp)
  766. *
  767. * @mfunc
  768. * Initialize a CLinePtr properly
  769. */
  770. void CDisplaySL::InitLinePtr (
  771. CLinePtr & lp ) //@parm Ptr to line to initialize
  772. {
  773. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::InitLinePtr");
  774. lp.Init(*this);
  775. }
  776. /*
  777. * CDisplaySL::GetNaturalSize(hdcDraw, hicTarget, dwMode, pwidth, pheight)
  778. *
  779. * @mfunc
  780. * Recalculate display to input width & height
  781. *
  782. * @rdesc
  783. * S_OK - Call completed successfully <nl>
  784. */
  785. HRESULT CDisplaySL::GetNaturalSize(
  786. HDC hdcDraw, //@parm DC for drawing
  787. HDC hicTarget, //@parm DC for information
  788. DWORD dwMode, //@parm Type of natural size required
  789. LONG *pwidth, //@parm Input/output width parm
  790. LONG *pheight) //@parm Input/output height parm
  791. {
  792. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetNaturalSize");
  793. // Assume this won't work
  794. HRESULT hr = E_FAIL;
  795. // Set height temporarily so zoom factor will work out
  796. LONG yOrigHeightClient = SetClientHeight(*pheight);
  797. // Adjust height and width by view inset
  798. LONG widthView = *pwidth;
  799. LONG heightView = *pheight;
  800. GetViewDim(widthView, heightView);
  801. // Store adjustment so we can restore it to height & width
  802. LONG widthAdj = *pwidth - widthView;
  803. LONG heightAdj = *pheight - heightView;
  804. LONG uCaret = !_ped->fInOurHost() && !_ped->fInHost2() ? duCaret : 0;
  805. // Recalculate size needed
  806. // Create a measurer starting at cp = 0
  807. CMeasurer me(this);
  808. CLine liNew;
  809. if(liNew.Measure(me, MEASURE_FIRSTINPARA))
  810. {
  811. *pwidth = liNew._dup;
  812. if(dwMode == TXTNS_FITTOCONTENT2)
  813. *pwidth += liNew._upStart + me.GetRightIndent();
  814. *pheight = liNew._dvpHeight;
  815. hr = S_OK;
  816. }
  817. // Restore insets so output reflects true client rect needed
  818. *pwidth += widthAdj + uCaret;
  819. *pheight += heightAdj;
  820. // Restore client height to match current cache
  821. SetClientHeight(yOrigHeightClient);
  822. return hr;
  823. }
  824. /*
  825. * CDisplaySL::GetWordWrap()
  826. *
  827. * @mfunc
  828. * Gets the wrap flag
  829. *
  830. * @rdesc
  831. * TRUE - Word wrap
  832. * FALSE - No word Word wrap
  833. *
  834. * @devnote
  835. * Single line controls cannot word wrap.
  836. */
  837. BOOL CDisplaySL::GetWordWrap() const
  838. {
  839. TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplaySL::GetNoWrap");
  840. return FALSE;
  841. }
  842. /*
  843. * CDisplaySL::Clone()
  844. *
  845. * @mfunc
  846. * Make a copy of this object
  847. *
  848. * @rdesc
  849. * NULL - failed
  850. * CDisplay *
  851. */
  852. CDisplay *CDisplaySL::Clone() const
  853. {
  854. CDisplaySL *pdp = new CDisplaySL(_ped);
  855. if(pdp)
  856. {
  857. // Initialize our base class
  858. if(pdp->CDisplay::Init())
  859. {
  860. pdp->InitFromDisplay(this);
  861. // Setting scroll to 0 means use the first visible character
  862. pdp->_upScroll = CALC_XSCROLL_FROM_FIRST_VISIBLE;
  863. pdp->_fVScrollEnabled = _fVScrollEnabled;
  864. pdp->_fWordWrap = _fWordWrap;
  865. pdp->ResetDrawInfo(this);
  866. pdp->SetCpFirstVisible(GetFirstVisibleCp());
  867. // This can't be active view since it is a clone of some view
  868. pdp->SetActiveFlag(FALSE);
  869. }
  870. }
  871. return pdp;
  872. }
  873. /*
  874. * CDisplaySL::GetMaxUScroll()
  875. *
  876. * @mfunc
  877. * Get the maximum u scroll value
  878. *
  879. * @rdesc
  880. * Maximum u scroll value
  881. *
  882. */
  883. LONG CDisplaySL::GetMaxUScroll() const
  884. {
  885. LONG uCaret = !_ped->fInOurHost() && !_ped->fInHost2() ? duCaret : 0;
  886. return _dup + uCaret;
  887. }