📄 range.cpp
字号:
BOOL bRet = FALSE; // Default no object
LONG cpMin, cpMost;
CTxtPtr tp(_rpTX);
GetRange(cpMin, cpMost);
if(pcpMin)
{
tp.SetCp(cpMin);
if(tp.GetChar() != WCH_EMBEDDING)
{
cpMin = tp.FindExact(tomBackward, szEmbedding);
if(cpMin >= 0)
{
bRet = TRUE;
*pcpMin = cpMin;
}
}
}
if(pcpMost)
{
tp.SetCp(cpMost);
if (tp.PrevChar() != WCH_EMBEDDING &&
tp.FindExact(tomForward, szEmbedding) >= 0)
{
bRet = TRUE;
*pcpMost = tp.GetCp();
}
}
return bRet;
}
/*
* CTxtRange::FindCell(pcpMin, pcpMost)
*
* @mfunc
* Set *pcpMin = closest cell cpMin <lt>= range cpMin (see comment)
* Set *pcpMost = closest cell cpMost <gt>= range cpMost
*
* @comment
* This function does nothing if the range isn't completely in a table.
*/
void CTxtRange::FindCell (
LONG *pcpMin, // @parm Out parm for bounding-cell cpMin
LONG *pcpMost) const // @parm Out parm for bounding-cell cpMost
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::FindCell");
WCHAR ch;
LONG cpMin, cpMost;
CRchTxtPtr rtp(*this);
_TEST_INVARIANT_
GetRange(cpMin, cpMost);
if(pcpMin)
{
if(_cch > 0)
rtp.Advance(-_cch);
rtp._rpPF.AdjustBackward();
if(rtp.GetPF()->wEffects & PFE_TABLE)
{
while(rtp.GetCp())
{
rtp.BackupCRLF();
ch = rtp.GetChar();
if(ch == CR || ch == CELL)
{
rtp.AdvanceCRLF();
break;
}
Assert(rtp.GetPF()->wEffects & PFE_TABLE);
}
}
*pcpMin = rtp.GetCp();
}
if(pcpMost)
{
rtp.SetCp(cpMost);
if(rtp.GetPF()->wEffects & PFE_TABLE)
{
rtp.BackupCRLF();
do
{
ch = rtp.GetChar();
rtp.AdvanceCRLF();
Assert(rtp.GetPF()->wEffects & PFE_TABLE);
} while(ch && ch != CR && ch != CELL);
}
*pcpMost = rtp.GetCp();
}
}
/*
* CTxtRange::FindParagraph(pcpMin, pcpMost)
*
* @mfunc
* Set *pcpMin = closest paragraph cpMin <lt>= range cpMin (see comment)
* Set *pcpMost = closest paragraph cpMost <gt>= range cpMost
*
* @devnote
* If this range's cpMost follows an EOP, use it for bounding-paragraph
* cpMost unless 1) the range is an insertion point, and 2) pcpMin and
* pcpMost are both nonzero, in which case use the next EOP. Both out
* parameters are nonzero if FindParagraph() is used to expand to full
* paragraphs (else StartOf or EndOf is all that's requested). This
* behavior is consistent with the selection/IP UI. Note that FindEOP
* treats the beginning/end of document (BOD/EOD) as a BOP/EOP,
* respectively, but IsAfterEOP() does not.
*/
void CTxtRange::FindParagraph (
LONG *pcpMin, // @parm Out parm for bounding-paragraph cpMin
LONG *pcpMost) const // @parm Out parm for bounding-paragraph cpMost
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::FindParagraph");
LONG cpMin, cpMost;
CTxtPtr tp(_rpTX);
_TEST_INVARIANT_
GetRange(cpMin, cpMost);
if(pcpMin)
{
tp.SetCp(cpMin); // tp points at this range's cpMin
if(!tp.IsAfterEOP()) // Unless tp directly follows an
tp.FindEOP(tomBackward); // EOP, search backward for EOP
*pcpMin = cpMin = tp.GetCp();
}
if(pcpMost)
{
tp.SetCp(cpMost); // If range cpMost doesn't follow
if (!tp.IsAfterEOP() || // an EOP or else if expanding
(!cpMost || pcpMin) &&
cpMin == cpMost) // IP at paragraph beginning,
{
tp.FindEOP(tomForward); // search for next EOP
}
*pcpMost = tp.GetCp();
}
}
/*
* CTxtRange::FindSentence(pcpMin, pcpMost)
*
* @mfunc
* Set *pcpMin = closest sentence cpMin <lt>= range cpMin
* Set *pcpMost = closest sentence cpMost <gt>= range cpMost
*
* @devnote
* If this range's cpMost follows a sentence end, use it for bounding-
* sentence cpMost unless the range is an insertion point, in which case
* use the next sentence end. The routine takes care of aligning on
* sentence beginnings in the case of range ends that fall on whitespace
* in between sentences.
*/
void CTxtRange::FindSentence (
LONG *pcpMin, // @parm Out parm for bounding-sentence cpMin
LONG *pcpMost) const // @parm Out parm for bounding-sentence cpMost
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::FindSentence");
LONG cpMin, cpMost;
CTxtPtr tp(_rpTX);
_TEST_INVARIANT_
GetRange(cpMin, cpMost);
if(pcpMin) // Find sentence beginning
{
tp.SetCp(cpMin); // tp points at this range's cpMin
if(!tp.IsAtBOSentence()) // If not at beginning of sentence
tp.FindBOSentence(tomBackward); // search backward for one
*pcpMin = cpMin = tp.GetCp();
}
if(pcpMost) // Find sentence end
{ // Point tp at this range's cpLim
tp.SetCp(cpMost); // If cpMost isn't at sentence
if (!tp.IsAtBOSentence() || // beginning or if at story
(!cpMost || pcpMin) && // beginning or expanding
cpMin == cpMost) // IP at sentence beginning,
{ // find next sentence beginning
if(!tp.FindBOSentence(tomForward))
tp.SetCp(GetTextLength()); // End of story counts as
} // sentence end too
*pcpMost = tp.GetCp();
}
}
/*
* CTxtRange::FindVisibleRange(pcpMin, pcpMost)
*
* @mfunc
* Set *pcpMin = _pdp->_cpFirstVisible
* Set *pcpMost = _pdp->_cpLastVisible
*
* @rdesc
* TRUE iff calculated cp's differ from this range's cp's
*
* @devnote
* CDisplay::GetFirstVisible() and GetCliVisible() return the first cp
* on the first visible line and the last cp on the last visible line.
* These won't be visible if they are scrolled off the screen.
* FUTURE: A more general algorithm would CpFromPoint (0,0) and
* (right, bottom).
*/
BOOL CTxtRange::FindVisibleRange (
LONG *pcpMin, // @parm Out parm for cpFirstVisible
LONG *pcpMost) const // @parm Out parm for cpLastVisible
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::FindVisibleRange");
_TEST_INVARIANT_
CDisplay * pdp = GetPed()->_pdp;
if(!pdp)
return FALSE;
if(pcpMin)
*pcpMin = pdp->GetFirstVisibleCp();
pdp->GetCliVisible(pcpMost);
return TRUE;
}
/*
* CTxtRange::FindWord(pcpMin, pcpMost, type)
*
* @mfunc
* Set *pcpMin = closest word cpMin <lt>= range cpMin
* Set *pcpMost = closest word cpMost <gt>= range cpMost
*
* @comm
* There are two interesting cases for finding a word. The first,
* (FW_EXACT) finds the exact word, with no extraneous characters.
* This is useful for situations like applying formatting to a
* word. The second case, FW_INCLUDE_TRAILING_WHITESPACE does the
* obvious thing, namely includes the whitespace up to the next word.
* This is useful for the selection double-click semantics and TOM.
*/
void CTxtRange::FindWord(
LONG *pcpMin, //@parm Out parm to receive word's cpMin; NULL OK
LONG *pcpMost, //@parm Out parm to receive word's cpMost; NULL OK
FINDWORD_TYPE type) const //@parm Type of word to find
{
TRACEBEGIN(TRCSUBSYSRANG, TRCSCOPEINTERN, "CTxtRange::FindWord");
LONG cch, cch1;
LONG cpMin, cpMost;
CTxtPtr tp(_rpTX);
_TEST_INVARIANT_
Assert(type == FW_EXACT || type == FW_INCLUDE_TRAILING_WHITESPACE );
GetRange(cpMin, cpMost);
if(pcpMin)
{
tp.SetCp(cpMin);
if(!tp.IsAtBOWord()) // cpMin not at BOW:
cpMin += tp.FindWordBreak(WB_MOVEWORDLEFT); // go there
*pcpMin = cpMin;
Assert(cpMin >= 0 && cpMin <= GetTextLength());
}
if(pcpMost)
{
tp.SetCp(cpMost);
if (!tp.IsAtBOWord() || // If not at word strt
(!cpMost || pcpMin) && cpMin == cpMost) // or there but need
{ // to expand IP,
cch = tp.FindWordBreak(WB_MOVEWORDRIGHT); // move to next word
if(cch && type == FW_EXACT) // If moved and want
{ // word proper, move
cch1 = tp.FindWordBreak(WB_LEFTBREAK); // back to end of
if(cch + cch1 > 0) // preceding word
cch += cch1; // Only do so if were
} // not already at end
cpMost += cch;
}
*pcpMost = cpMost;
Assert(cpMost >= 0 && cpMost <= GetTextLength());
Assert(cpMin <= cpMost);
}
}
/*
* CTxtRange::CalcTextLenNotInRange()
*
* @mfunc
* Helper function that calculates the total length of text
* excluding the current range.
*
* @comm
* Used for limit testing. The problem being solved is that
* the range can contain the final EOP which is not included
* in the adjusted text length.
*/
LONG CTxtRange::CalcTextLenNotInRange()
{
LONG cchAdjLen = GetPed()->GetAdjustedTextLength();
LONG cchLen = cchAdjLen - abs(_cch);
LONG cpMost = GetCpMost();
if (cpMost > cchAdjLen)
{
// Selection extends beyond adjusted length. Put amount back in the
// selection as it has become too small by the difference.
cchLen += cpMost - cchAdjLen;
}
return cchLen;
}
/*
* CTxtRange::ExpandToLink()
*
* @mfunc
* helper function that expands this range to the bounding set of runs
* with CFE_LINK set
*
* @devnote FUTURE (alexgo): this should be recoded in the future to make
* it smaller && less demented. Potentially, we could use a
* generic "search for partial charformat" routine.
*/
void CTxtRange::ExpandToLink(void)
{
CTxtEdit *ped = GetPed();
LONG cpMin, cpMost;
const CCharFormat *pcf;
// do the easy check first
Expander(tomCharFormat, TRUE, NULL, &cpMin, &cpMost);
// make cpMin be the active end
if( _cch > 0 )
{
FlipRange();
}
SetExtend(TRUE);
CFormatRunPtr rp(_rpCF);
// go backwards until we don't see any more CFE_LINK bits
while( 1 )
{
rp.AdjustBackward();
pcf = ped->GetCharFormat(rp.GetFormat());
if( !pcf || !(pcf->dwEffects & CFE_LINK) )
{
break;
}
if( !Advance(-(LONG)rp.GetIch()) )
{
break;
}
rp.AdvanceCp(-(LONG)rp.GetIch());
}
// now flip the range around and go forwards until we
FlipRange();
rp = _rpCF;
while( 1 )
{
rp.AdjustForward();
pcf = ped->GetCharFormat(rp.GetFormat());
if( !pcf || !(pcf->dwEffects & CFE_LINK) )
{
break;
}
if( !Advance( rp.GetRun(0)->_cch ) )
{
break;
}
rp.AdvanceCp(rp.GetRun(0)->_cch);
}
SetExtend(FALSE);
}
////////////////////////// Outline Support //////////////////////////////////
/*
* CTxtRange::Promote(lparam, publdr)
*
* @mfunc
* Promote selected text according to:
*
* LOWORD(lparam) == 0 ==> promote to body-text
* LOWORD(lparam) != 0 ==> promote/demote current selection by
* LOWORD(lparam) levels
* @rdesc
* TRUE iff promotion occurred
*
* @devnote
* Changes this range
*/
HRESULT CTxtRange::Promote (
LPARAM lparam, //@parm 0 to body, < 0 demote, > 0 promote
IUndoBuilder *publdr) //@parm undo builder to receive antievents
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtRange::Promote");
if(abs(lparam) >= NHSTYLES)
return E_INVALIDARG;
if(publdr)
publdr->StopGroupTyping();
if(_cch > 0) // Point at cpMin
FlipRange();
LONG cchText = GetTextLength();
LONG cpEnd = GetCpMost();
LONG cpMin, cpMost;
BOOL fHeading = TRUE; // Default heading in range
HRESULT hr;
LONG Level = 0;
LONG nHeading = NHSTYLES; // Setup to find any heading
CParaFormat PF;
const CParaFormat *pPF;
CPFRunPtr rp(*this);
LONG cch = rp.FindHeading(abs(_cch), nHeading);
WORD wEffects;
if(!lparam) // Demote to subtext
{
if(cch) // Already in subtext so don't
return S_FALSE; // need to demote
CTxtPtr tp(_rpTX);
if(!tp.IsAfterEOP())
cch = tp.FindEOP(tomBackward);
nHeading = 1;
if(tp.GetCp()) // Get previous level and convert
{ // to heading to set up
rp.AdvanceCp(cch); // following Level code
rp.AdjustBackward();
nHeading = rp.GetOutlineLevel()/2 + 1;
}
}
else if(cch == tomBackward) // No heading in range
{ // Set up to promote to
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -