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.

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