📄 select.cpp
字号:
DWORD dwScrollBars = ped->TxGetScrollBars();
if( ped->IsStreaming() )
{
// don't bother doing anything if we are loading in text or RTF
// data.
return FALSE;
}
_yCurrentDescent = -1;
// We better be inplace active if we get here
AssertSz(GetPed()->fInplaceActive(),
"CTxtSelection::UpdateCaret no inplace active");
// Get the client rectangle once to save various
// callers getting it.
GetPed()->TxGetClientRect(&rcClient);
_pdp->GetViewRect(rcView, &rcClient);
// View can be bigger than client rect because insets can be negative.
// We don't want the caret to be any bigger than the client view otherwise
// the caret will leave pixel dust on other windows.
yViewTop = max(rcView.top, rcClient.top);
yViewBottom = min(rcView.bottom, rcClient.bottom);
xWidthView = rcView.right - rcView.left;
yHeightView = yViewBottom - yViewTop;
if(fScrollIntoView)
{
fAutoVScroll = (dwScrollBars & ES_AUTOVSCROLL) != 0;
fAutoHScroll = (dwScrollBars & ES_AUTOHSCROLL) != 0;
// If we're not forcing a scroll, only scroll if window has focus
// or selection isn't hidden
fScrollIntoView = ped->_fFocus || !ped->fHideSelection();
}
if(!fScrollIntoView && (fAutoVScroll || fAutoHScroll))
{ // Would scroll but don't have
ped->_fScrollCaretOnFocus = TRUE; // focus. Signal to scroll
fAutoVScroll = fAutoHScroll = FALSE; // when we do get focus
}
if(_pdp->PointFromTp(*this, &rcClient, _fCaretNotAtBOL, pt, &rp,
TA_BASELINE) < 0 ||
!_cch && IsInOutlineView() && (GetPF()->wEffects & PFE_COLLAPSED))
{
goto not_visible;
}
// HACK ALERT - Because plain-text multiline controls do not have the
// automatic EOP, we need to special case their processing here because
// if you are at the end of the document and last character is an EOP,
// you need to be on the next line in the display not the current line.
if(CheckPlainTextFinalEOP()) // terminated by an EOP
{
if (GetPF()->wAlignment == PFA_CENTER)
pt.x = (rcView.left + rcView.right) >> 1;
else
// Set the x to the beginning of the line
pt.x = rcView.left;
pt.x -= xScroll; // Absolute coordinate
// Bump the y up a line. We get away with the calculation because
// the document is plain text so all lines have the same height.
// Also, note that the rp below is used only for height
// calculations, so it is perfectly valid for the same reason
// even though it is not actually pointing to the correct line.
// (I told you this is a hack.)
pt.y += rp->_yHeight;
}
_xCaret = (LONG) pt.x;
yBase = (LONG) pt.y;
// Compute caret height, ascent, and descent
yAscent = GetCaretHeight(&yDescent);
yAscent -= yDescent;
// Default to line empty case. Use what came back from the default
// calculation above.
yDescentLine = yDescent;
yAscentLine = yAscent;
if( rp.IsValid() )
{
if (rp->_yDescent != -1)
{
// Line has been measured so we can use the values in the
// line.
yDescentLine = rp->_yDescent;
yAscentLine = rp->_yHeight - yDescentLine;
}
}
if(yAscent + yDescent == 0)
{
yAscent = yAscentLine;
yDescent = yDescentLine;
}
else
{
// this is a bit counter-intuitive at first. Basically,
// even if the caret should be large (i.e. due to a
// large font at the insertion point), we can only make it
// as big as the line. If a character is inserted, then
// the line becomes bigger, and we can make the caret
// the correct size.
yAscent = min(yAscent, yAscentLine);
yDescent = min(yDescent, yDescentLine);
}
if(fAutoVScroll)
{
Assert(yDescentLine >= yDescent);
Assert(yAscentLine >= yAscent);
yBelow = yDescentLine - yDescent;
yAbove = yAscentLine - yAscent;
ySum = yAscent;
// Scroll as much as possible into view, giving priorities
// primarily to IP and secondarily ascents
if(ySum > yHeightView)
{
yAscent = yHeightView;
yDescent = 0;
yAbove = 0;
yBelow = 0;
}
else if((ySum += yDescent) > yHeightView)
{
yDescent = yHeightView - yAscent;
yAbove = 0;
yBelow = 0;
}
else if((ySum += yAbove) > yHeightView)
{
yAbove = yHeightView - (ySum - yAbove);
yBelow = 0;
}
else if((ySum += yBelow) > yHeightView)
yBelow = yHeightView - (ySum - yBelow);
}
#ifdef DEBUG
else
{
AssertSz(yAbove == 0, "yAbove non-zero");
AssertSz(yBelow == 0, "yBelow non-zero");
}
#endif
// Update real caret x pos (constant during vertical moves)
_xCaretReally = _xCaret - rcView.left + xScroll;
Assert(_xCaretReally >= 0);
if(_xCaret + GetCaretDelta() > rcView.right && // Caret off right edge,
!((dwScrollBars & ES_AUTOHSCROLL) || // not auto hscrolling
_pdp->IsHScrollEnabled())) // and no scrollbar:
{ // Back caret up to
_xCaret = rcView.right - dxCaret; // exactly the right edge
}
// From this point on we need a new caret
_fCaretCreated = FALSE;
if( ped->_fFocus)
ped->TxShowCaret(FALSE); // Hide old caret before
// making a new one
if(yBase + yDescent + yBelow > yViewTop &&
yBase - yAscent - yAbove < yViewBottom)
{
if(yBase - yAscent - yAbove < yViewTop) // Caret is partially
{ // visible
if(fAutoVScroll) // Top isn't visible
goto scrollit;
Assert(yAbove == 0);
yAscent = yBase - yViewTop; // Change ascent to amount
if(yBase < yViewTop) // visible
{ // Move base to top
yDescent += yAscent;
yAscent = 0;
yBase = yViewTop;
}
}
if(yBase + yDescent + yBelow > yViewBottom)
{
if(fAutoVScroll) // Bottom isn't visible
goto scrollit;
Assert(yBelow == 0);
yDescent = yViewBottom - yBase; // Change descent to amount
if(yBase > yViewBottom) // visible
{ // Move base to bottom
yAscent += yDescent;
yDescent = 0;
yBase = yViewBottom;
}
}
// Anything still visible?
if(yAscent <= 0 && yDescent <= 0)
goto not_visible;
// If left or right isn't visible, scroll or set non_visible
if (_xCaret <= rcView.left + CDisplay::GetXWidthSys() && xScroll // Left isn't visible
|| _xCaret + GetCaretDelta() > rcView.right) // Right isn't visible
{
if(fAutoHScroll)
goto scrollit;
goto not_visible;
}
_yCaret = yBase - yAscent;
_yHeightCaret = (INT) yAscent + yDescent;
_yCurrentDescent = yDescent;
}
else if(fAutoHScroll || fAutoVScroll) // Caret isn't visible
goto scrollit; // scroll it into view
else
{
not_visible:
// Caret isn't visible, don't show it
_xCaret = -32000;
_yCaret = -32000;
_yHeightCaret = 1;
}
// Now update caret for real on screen
// We only want to show the caret if it is in the view
// and there is no selection.
if((ped->_fFocus) && _fShowCaret && (0 == _cch))
{
CreateCaret();
ped->TxShowCaret(TRUE);
CheckChangeKeyboardLayout( FALSE );
}
#ifdef DBCS
UpdateIMEWindow();
FSetIMEFontH(ped->_hwnd, AttGetFontHandle(ped, ped->_cpCaret));
#endif
return FALSE;
scrollit:
if(fAutoVScroll)
{
// Scroll to top for cp = 0. This is important if the first line
// contains object(s) taller than the client area is high. The
// resulting behavior agrees with the Word UI in all ways except in
// Backspacing (deleting) the char at cp = 0 when it is followed by
// other chars that preceed the large object.
if(!GetCp())
yScroll = 0;
else if(yBase - yAscent - yAbove < yViewTop) // Top invisible
yScroll -= yViewTop - (yBase - yAscent - yAbove); // Make it so
else if(yBase + yDescent + yBelow > yViewBottom) // Bottom invisible
{
yScroll += yBase + yDescent + yBelow - yViewBottom; // Make it so
// Don't do following special adjust if the current line is bigger
// than the client area
if(rp->_yHeight < yViewBottom - yViewTop)
{
yScroll = _pdp->AdjustToDisplayLastLine(yBase + rp->_yHeight,
yScroll);
}
}
}
if(fAutoHScroll)
{
if(_xCaret <= (rcView.left + CDisplay::GetXWidthSys())) // Left invisible
{
xScroll -= rcView.left - _xCaret; // Make it visible
if(xScroll > 0) // Scroll left in
{ // chunks to make
xScroll -= xWidthView / 3; // typing faster
xScroll = max(0, xScroll);
}
}
else if(_xCaret + GetCaretDelta() > rcView.right) // right invisible
xScroll += _xCaret + dxCaret - rcView.left // Make it visible
- xWidthView; // We don't scroll
// in chunks because
// this more edit
// control like.
//- xWidthView * 2 / 3; // scrolling in
} // chunks
if(yScroll != _pdp->GetYScroll() || xScroll != _pdp->GetXScroll())
return _pdp->ScrollView(xScroll, yScroll, FALSE, FALSE);
#ifdef DBCS
VwUpdateIMEWindow(ped);
FSetIMEFontH(ped->_hwnd, AttGetFontHandle(ped, ped->_cpCaret));
#endif
return FALSE;
}
/*
* CTxtSelection::GetCaretHeight(pyDescent)
*
* @mfunc
* Add a given amount to _xCaret (to make special case of inserting
* a character nice and fast)
*
* @rdesc
* Caret height, <lt> 0 if failed
*/
INT CTxtSelection::GetCaretHeight (
INT *pyDescent) const //@parm Out parm to receive caret descent
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::GetCaretHeight");
// (undefined if the return value is <lt> 0)
_TEST_INVARIANT_
const CCharFormat *pcf = GetPed()->GetCharFormat(_iFormat);
const CDevDesc *pdd = _pdp->GetDdRender();
INT CaretHeight = -1;
HDC hdc;
CCcs * pccs;
if ((NULL == pdd) || (NULL == pcf))
return CaretHeight;
hdc = pdd->GetDC();
if(!hdc)
return -1;
pccs = fc().GetCcs(hdc, pcf, _pdp->GetZoomNumerator(),
_pdp->GetZoomDenominator(), GetDeviceCaps(hdc, LOGPIXELSY));
if(!pccs)
goto ret;
if(pyDescent)
*pyDescent = (INT) pccs->_yDescent;
CaretHeight = pccs->_yHeight;
pccs->Release();
ret:
pdd->ReleaseDC(hdc);
return CaretHeight;
}
/*
* CTxtSelection::ShowCaret(fShow)
*
* @mfunc
* Hide or show caret
*
* @rdesc
* TRUE if caret was previously shown, FALSE if it was hidden
*/
BOOL CTxtSelection::ShowCaret (
BOOL fShow) //@parm TRUE for showing, FALSE for hiding
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::ShowCaret");
_TEST_INVARIANT_
const BOOL fRet = _fShowCaret;
if(fRet != fShow)
{
_fShowCaret = fShow;
if (GetPed()->_fFocus)
{
if (fShow && !_fCaretCreated)
{
CreateCaret();
}
GetPed()->TxShowCaret(fShow);
}
}
return fRet;
}
/*
* CTxtSelection::IsCaretInView()
*
* @mfunc
* Returns TRUE iff caret is inside visible view
*/
BOOL CTxtSelection::IsCaretInView() const
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::IsCaretInView");
_TEST_INVARIANT_
RECT rc;
_pdp->GetViewRect(rc);
return (_xCaret + dxCaret > rc.left) &&
(_xCaret < rc.right) &&
(_yCaret + _yHeightCaret > rc.top) &&
(_yCaret < rc.bottom);
}
/*
* CTxtSelection::CaretNotAtBOL()
*
* @mfunc
* Returns TRUE iff caret is not allowed at BOL
*/
BOOL CTxtSelection::CaretNotAtBOL() const
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::CaretNotAtBOL");
_TEST_INVARIANT_
return _cch ? (_cch > 0) : _fCaretNotAtBOL;
}
/*
* CTxtSelection::LineLength()
*
* @mfunc
* get # unselected chars on lines touched by current selection
*
* @rdesc
* said number of chars
*/
LONG CTxtSelection::LineLength() const
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::LineLength");
_TEST_INVARIANT_
LONG cch;
CLinePtr rp(_pdp);
if(!_cch) // Insertion point
{
rp.RpSetCp(GetCp(), _fCaretNotAtBOL);
cch = rp.GetAdjustedLineLength();
}
else
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -