📄 dispml.cpp
字号:
if(pli->_fCollapsed)
continue;
// Get a local copy of the height
yHeightForLine = pli->_yHeight;
if ((pli->_bFlags & fliUseOffScreenDC) != 0)
{
// We only want to set the height for the bitmap if this
// line needs off screen rendering. Otherwise, we can do
// just as well by rendering the line directly.
if (yHeightForLine > yHeightForBitmap)
{
// We want to figure out what is the height of the tallest
// line to be displayed off screen. The purpose of this is
// to allow the rendering to create a bit map big enough
// that it does not have to be reallocated during
// the rendering of the screen.
yHeightForBitmap = yHeightForLine;
}
}
yLi += yHeightForLine;
}
if ((0 != yHeightForBitmap) && (rcView.top > rcRender.top))
{
// Bit map for first line needs to be big enough to take into account
// the area above the first line so, add the difference between view
// and render start into the bitmap size.
yHeightForBitmap += (rcView.top - rcRender.top);
}
}
// Create renderer
CRenderer re(this);
// Prepare renderer
if(!re.StartRender(rcView, rcRender, yHeightForBitmap))
return;
// Init renderer at the start of the first line to render
re.SetCurPoint(pt);
re.SetCp(cp);
#ifdef DEBUG
LONG cpLi = re.GetCp();
yLi = pt.y;
#endif
if (fLinesToRender)
{
// Render each line in the update rectangle
for (; ili < lCount; ili++)
{
if(!re.RenderLine(GetAt(ili), ili == lCount - 1))
break;
#ifdef DEBUG
cpLi += Elem(ili)->_cch;
yLi += Elem(ili)->GetHeight();
// Rich controls with password characters do not process EOPs.
// Therefore, the following assert is only valid when the above
// is not the case.
if (!_ped->IsRich() || !_ped->fUsePassword())
{
AssertSz(re.GetCp() == cpLi,
"CDisplayML::RenderView() - cp out of sync. with line table");
}
AssertSz(re.GetCurPoint().y == yLi,
"CDisplayML::RenderView() - y out of sync. with line table");
#endif // DEBUG
}
}
re.EndRender(); // Finish rendering
}
//=================================== View Updating ===================================
/*
* CDisplayML::RecalcView(fUpdateScrollBars)
*
* @mfunc
* Recalc all lines breaks and update first visible line
*
* @rdesc
* TRUE if success
*/
BOOL CDisplayML::RecalcView(
BOOL fUpdateScrollBars)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::RecalcView");
BOOL fRet = TRUE;
const LONG cp = _cpFirstVisible;
LONG yHeightOld = _yHeight;
LONG yScrollHeightOld = GetMaxYScroll();
LONG xWidthOld = _xWidth;
// full recalc lines
if(!RecalcLines())
{
// the recalc failed
// let's try to get out of this with our head still mostly attached
InitVars();
fRet = FALSE;
goto Done;
}
if (_ped->GetTextLength() == 0)
{
// This is an empty control so create one empty line
CreateEmptyLine();
}
// force _xScroll = 0 if x scroll range is smaller than the view width
if(_xWidth <= _xWidthView)
{
_xScroll = 0;
}
// change first visible entries because CLinePtr::RpSetCp() and
// YPosFromLine() use them, but they're not valid
_dyFirstVisible = 0;
_cpFirstVisible = 0;
_iliFirstVisible = 0;
_yScroll = 0;
// recompute scrolling position and first visible values after edit
// force _yScroll = 0 if y scroll range is smaller than the view height
if(_yHeight > _yHeightView)
{
CLinePtr rp(this);
rp.RpSetCp(cp, FALSE);
_yScroll = YposFromLine(rp);
// we use rp.GetCp() instead of cp, because cp could now be
// woefully out of date. RpSetCp will set us to the closest
// available cp.
_cpFirstVisible = rp.GetCp() - rp.RpGetIch();
_iliFirstVisible = rp;
}
CheckView();
// We only need to resize if the size needed to display the object has
// changed.
if ((yHeightOld != _yHeight) || (yScrollHeightOld != GetMaxYScroll())
|| (xWidthOld != _xWidth))
{
if(FAILED(RequestResize()))
{
_ped->GetCallMgr()->SetOutOfMemory();
}
}
Done:
// Now update the scrollbars
if (fUpdateScrollBars)
{
RecalcScrollBars();
}
return fRet;
}
/*
* CDisplayML::UpdateView(&tpFirst, cchOld, cchNew)
*
* @mfunc
* Recalc lines and update the visible part of the display
* (the "view") on the screen.
*
* @devnote
* --- Use when in-place active only ---
*
* @rdesc
* TRUE if success
*/
BOOL CDisplayML::UpdateView(
const CRchTxtPtr &tpFirst, //@parm Text ptr where change happened
LONG cchOld, //@parm Count of chars deleted
LONG cchNew) //@parm Count of chars inserted
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::UpdateView");
BOOL fReturn = TRUE;
BOOL fRecalcVisible = TRUE;
RECT rcClient;
RECT rcView;
CLed led;
CTxtSelection *psel = _ped->GetSelNC();
LONG cpStartOfUpdate = tpFirst.GetCp();
BOOL fNeedViewChange = FALSE;
LONG yHeightOld = _yHeight;
LONG yScrollHeightOld = GetMaxYScroll();
LONG xWidthOld = _xWidth;
LONG yScrollOld = _yScroll;
LONG cpNewFirstVisible;
if (_fNoUpdateView)
return fReturn;
AssertSz(_ped->_fInPlaceActive, "CDisplayML::UpdateView(...) called when inactive");
if( tpFirst.GetCp() > _cpCalcMax || _fNeedRecalc)
{
// we haven't even calc'ed this far, so don't bother with updating
// here. Background recalc will eventually catch up to us.
return TRUE;
}
AssertSz(tpFirst.GetCp() <= _cpCalcMax, "CDisplayML::UpdateView(...) - tpFirst > _cpCaclMax");
_ped->TxGetClientRect(&rcClient);
GetViewRect(rcView, &rcClient);
if(psel && !psel->PuttingChar())
psel->ClearCchPending();
DeferUpdateScrollBar();
// In general, background recalc should not start until both the scroll
// position is beyond the visible view and the cp is beyond the first visible
// character. However, for the recalc we will only wait on the height.
// Later calls to WaitForRecalc will wait on cpFirstVisible if that is
// necessary.
_yWait = _yScroll + _yHeightView;
_cpWait = -1;
if(!RecalcLines(tpFirst, cchOld, cchNew, FALSE, TRUE, &led))
{
// we're in deep crap now, the recalc failed
// let's try to get out of this with our head still mostly attached
InitVars();
fRecalcVisible = TRUE;
fReturn = FALSE;
_ped->TxInvalidateRect (NULL, FALSE);
fNeedViewChange = TRUE;
goto Exit;
}
if(_ped->GetTextLength() == 0)
{
if(LineCount() != 0)
{
// There are currently elements in the line array, so zap them.
Clear(AF_DELETEMEM);
}
// This is an empty control so create one empty line
CreateEmptyLine();
}
if(_xWidth <= _xWidthView)
{
// x scroll range is smaller than the view width
// force x scrolling position = 0
_xScroll = 0;
}
if(led._yFirst >= _yScroll + _yHeightView)
{
// update is after the view, don't do anything
fRecalcVisible = FALSE;
Assert(VerifyFirstVisible());
goto finish;
}
else if(led._yMatchNew <= _yScroll + _dyFirstVisible &&
led._yMatchOld <= _yScroll + _dyFirstVisible)
{
// update is entirely before the view
// just update scroll position but don't touch the screen
_yScroll += led._yMatchNew - led._yMatchOld;
_iliFirstVisible += led._iliMatchNew - led._iliMatchOld;
_iliFirstVisible = max((LONG)_iliFirstVisible, 0);
_cpFirstVisible += led._cpMatchNew - led._cpMatchOld;
_cpFirstVisible = min((LONG)_ped->GetTextLength(), _cpFirstVisible);
_cpFirstVisible = max(0, _cpFirstVisible);
fRecalcVisible = FALSE;
Assert(VerifyFirstVisible());
}
else
{
// update overlaps the visible view
RECT rc = rcClient;
RECT rcUpdate;
RECT *prc = &rc;
// Do we need to resync the first visible? Note that this if check
// is mostly an optmization; we could decide to _always_ recompute
// this _iliFirstVisible if we wanted to.
if ( cpStartOfUpdate <= _cpFirstVisible ||
led._iliMatchOld <= _iliFirstVisible ||
led._iliMatchNew <= _iliFirstVisible ||
led._iliFirst <= _iliFirstVisible )
{
// Edit overlaps the first visible. We try to maintain
// approximately the same place in the file visible.
cpNewFirstVisible = _cpFirstVisible;
if (_iliFirstVisible - 1 == led._iliFirst)
{
// The edit occurred on the line before the visible view. Most
// likely this means that the the first character got pulled
// back to the previous line so we want that line to be
// visible.
cpNewFirstVisible = led._cpFirst;
}
// change first visible entries because CLinePtr::RpSetCp() and
// YPosFromLine() use them, but they're not valid
_dyFirstVisible = 0;
_cpFirstVisible = 0;
_iliFirstVisible = 0;
_yScroll = 0;
// with certain formatting changes, it's possible for
// cpNewFirstVisible to be less that what's been calculated so far
// in RecalcLines above. Wait for things to catch up.
WaitForRecalc(cpNewFirstVisible, -1);
// recompute scrolling position and first visible values after edit
CLinePtr rp(this);
rp.RpSetCp(cpNewFirstVisible, FALSE);
_yScroll = YposFromLine(rp);
_cpFirstVisible = rp.GetCp() - rp.RpGetIch();
_iliFirstVisible = rp;
Assert(VerifyFirstVisible());
}
Assert(VerifyFirstVisible());
// Is there a match in the display area? - this can only happen if the
// old match is on the screen and the new match will be on the screen
if ((led._yMatchOld < yScrollOld + _yHeightView)
&& (led._yMatchNew < _yScroll + _yHeightView))
{
// we have a match inside the visible view
// scroll the part that is below the old y pos of the match
// or invalidate if the new y of the match is now below the view
rc.top = rcView.top + (INT) (led._yMatchOld - yScrollOld);
if(rc.top < rc.bottom)
{
// Calculate difference between the new and old screen
// position.
const INT dy = (INT) ((led._yMatchNew - _yScroll))
- (led._yMatchOld - yScrollOld);
if(dy)
{
if(!_ped->_fTransparent)
{
_ped->TxScrollWindowEx(0, dy, &rc, &rcView,
NULL, &rcUpdate, 0);
_ped->TxInvalidateRect(&rcUpdate, FALSE);
fNeedViewChange = TRUE;
if(dy < 0)
{
rc.top = rc.bottom + dy;
_ped->TxInvalidateRect(&rc, FALSE);
fNeedViewChange = TRUE;
}
}
else
{
// adjust the rect since we are not doing
// scrolling for transparent mode
RECT rcInvalidate = rc;
rcInvalidate.top += dy;
_ped->TxInvalidateRect(&rcInvalidate, FALSE);
fNeedViewChange = TRUE;
}
}
}
else
{
rc.top = rcView.top + led._yMatchNew - _yScroll;
_ped->TxInvalidateRect(&rc, FALSE);
fNeedViewChange = TRUE;
}
// Because above it was determined that the new match fell
// within the screen, we can safely set the bottom to the
// new match since this is the most that can have changed.
rc.bottom = rcView.top
+ (INT) (max(led._yMatchNew, led._yMatchOld) - _yScroll);
}
rc.top = rcView.top + (INT) (led._yFirst - _yScroll);
// Set the first line edited to be rendered using off screen
// rendering.
if (led._iliFirst < (LONG) Count() && !_ped->_fTransparent
&& (Elem(led._iliFirst)->_bFlags & fliUseOffScreenDC) == 0)
{
Elem(led._iliFirst)->_bFlags |=
(fliOffScreenOnce | fliUseOffScreenDC);
_fUpdateOffScreen = TRUE;
}
// Invalidate part of update that is above match (if any)
_ped->TxInvalidateRect (&rc, FALSE);
fNeedViewChange = TRUE;
}
finish:
if(fRecalcVisible)
{
fReturn = WaitForRecalcView();
if( !fReturn )
{
goto Exit;
}
}
if (fNeedViewChange)
{
_ped->GetHost()->TxViewChange(FALSE);
}
CheckView();
// We only need to resize if the size needed to display the object has
// changed.
if ((yHeightOld != _yHeight) || (yScrollHeightOld != GetMaxYScroll())
|| (xWidthOld != _xWidth))
{
if(FAILED(RequestResize()))
{
_ped->GetCallMgr()->SetOutOfMemory();
}
}
if(DoDeferredUpdateScrollBar())
{
if(FAILED(RequestResize()))
_ped->GetCallMgr()->SetOutOfMemory();
DoDeferredUpdateScrollBar();
}
Exit:
return fReturn;
}
void CDisplayML::InitVars()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::InitVars");
_yScroll = _xScroll = 0;
_iliFirstVisible = 0;
_cpFirstVisible = _cpMin = 0;
_dyFirstVisible = 0;
}
/*
* CDisplayML::GetCliVisible(pcpMostVisible)
*
* @mfunc
* Get count of visible lines and update _cpMostVisible for PageDown()
*
* @rdesc
* count of visible lines
*/
LONG CDisplayML::GetCliVisible(
LONG* pcpMostVisible, //@parm Returns cpMostVisible
BOOL fLastCharOfLastVisible) const //@parm Want cp of last visible char
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplayML::GetCliVisible");
LONG cli = 0; // Initialize count
LONG ili = _iliFirstVisible; // Start with 1st visible line
LONG yHeight = _dyFirstVisible;
LONG cp;
LONG cchWhite = 0;
for(cp = _cpFirstVisible;
yHeight < _yHeightView && ili < (LONG)Count();
cli++, ili++)
{
const CLine* pli = Elem
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -