📄 rtext.cpp
字号:
BOOL CRchTxtPtr::Check_rpCF()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::Check_rpCF");
if(_rpCF.IsValid())
return TRUE;
if( !IsRich() && !IsIMERich() )
return FALSE;
if( !_rpCF.InitRuns (GetCp(), GetTextLength(),
&(GetPed()->GetTxtStory()->_pCFRuns)) )
{
return FALSE;
}
CNotifyMgr *pnm = GetPed()->GetNotifyMgr(); // For notifying of changes
if( pnm )
pnm->NotifyPostReplaceRange( // Notify interested parties
(ITxNotify *)this, INFINITE, // that
0, 0, INFINITE, INFINITE);
return TRUE;
}
/*
* CRchTxtPtr::Check_rpPF()
*
* @mfunc
* enable _rpPF if it's not already enabled
*
* @rdesc
* TRUE if _rpPF is enabled
*/
BOOL CRchTxtPtr::Check_rpPF()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::Check_rpPF");
if(_rpPF.IsValid())
return TRUE;
if( !IsRich() )
return FALSE;
if( !_rpPF.InitRuns (GetCp(), GetTextLength(),
&(GetPed()->GetTxtStory()->_pPFRuns)) )
{
return FALSE;
}
CNotifyMgr *pnm = GetPed()->GetNotifyMgr(); // For notifying of changes
if( pnm )
pnm->NotifyPostReplaceRange( // Notify interested parties
(ITxNotify *)this, INFINITE, // of the change.
0, 0, INFINITE, INFINITE);
return TRUE;
}
/*
* CRchTxtPtr::FindWordBreak(action, cpMost)
*
* @mfunc
* Same as CTxtPtr::FindWordBreak(), but moves the whole rich text ptr
*
* @rdesc
* cch this rich text ptr is moved
*/
LONG CRchTxtPtr::FindWordBreak(
INT action, //@parm Kind of word break to find
LONG cpMost) //@parm Limiting character position
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::FindWordBreak");
LONG cch = _rpTX.FindWordBreak(action, cpMost);
_rpCF.AdvanceCp(cch);
_rpPF.AdvanceCp(cch);
return cch;
}
/*
* CRchTxtPtr::BindToCp(dwNewCp)
*
* @mfunc
* Set cp to new value and recalculate that new position.
*/
void CRchTxtPtr::BindToCp(
DWORD cp) // @parm new cp for rich text
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::BindToCp");
cp = _rpTX.BindToCp(cp); // Recalculate cp for plain text
// use the InitRunPtrs routine so that the run pointers will get
// re-initialized and rebound with the correct run array. The
// run array formerly used (if any at all) is not necessary valid
// when this function is called.
InitRunPtrs(cp);
// Do invariant testing at end because this fixes up the rich text
// pointer in the face of backing store changes.
_TEST_INVARIANT_
}
/*
* CRchTxtPtr::CheckFormatRuns ()
*
* @mfunc
* Check the format runs against what's in CTxtStory. If
* different, forces a rebind to <p cp>
*/
void CRchTxtPtr::CheckFormatRuns( )
{
CTxtStory *pStory = GetPed()->GetTxtStory();
if( (pStory->GetCFRuns() != (CFormatRuns *)_rpCF._prgRun) ||
(pStory->GetPFRuns() != (CFormatRuns *)_rpPF._prgRun) )
{
InitRunPtrs(GetCp());
}
_TEST_INVARIANT_
}
/*
* CRchTxtPtr::ChangeCase(cch, Type, publdr)
*
* @mfunc
* Change case of cch chars starting at this text ptr according to Type,
* which has the possible values:
*
* tomSentenceCase = 0: capitalize first letter of each sentence
* tomLowerCase = 1: change all letters to lower case
* tomUpperCase = 2: change all letters to upper case
* tomTitleCase = 3: capitalize the first letter of each word
* tomToggleCase = 4: toggle the case of each letter
*
* @rdesc
* TRUE iff a change occurred
*
* @devnote
* Since this routine only changes the case of characters, it has no
* effect on rich-text formatting. However it is part of the CRchTxtPtr
* class in order to notify the display of changes. CTxtRanges are also
* notified just in case the text blocks are modified.
*/
BOOL CRchTxtPtr::ChangeCase (
LONG cch, //@parm # chars to change case for
LONG Type, //@parm Type of change case command
IUndoBuilder *publdr) //@parm UndoBuilder to receive anti-event
// for any replacements
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::ChangeCase");
_TEST_INVARIANT_
#define BUFFERLEN 256
LONG cchChunk, cchFirst, cchFormat, cchGet, cchLast;
BOOL fAlpha, fToUpper, fUpper; // Flags controling case change
BOOL fChange = FALSE; // No change yet
BOOL fStart = TRUE; // Start of Word/Sentence
TCHAR * pch; // Ptr to walk rgCh with
WORD * pType; // Ptr to walk rgType with
WCHAR rgCh[BUFFERLEN]; // Char buffer to work in
WORD rgType[BUFFERLEN]; // C1_TYPE array for rgCh
if( GetCp() )
{
if( Type == tomSentenceCase )
{
fStart = _rpTX.IsAtBOSentence();
}
else if( Type == tomTitleCase )
{
// check to see if we are at the beginning of
// a word. This is the case if the character preceeding
// our current position is white space.
fStart = IsWhiteSpace(_rpTX.GetPrevChar());
}
}
while(cch > 0) // Do 'em all (or as many as
{ // in story)
cchChunk = min(BUFFERLEN, cch); // Get next bufferful
if(_rpCF.IsValid()) // Make sure it stays within
{ // current char/paraformat
cchFormat = _rpCF.GetCchLeft(); // runs to simplify changing
cchChunk = min(cchChunk, cchFormat);// text with undo
}
if(_rpPF.IsValid())
{
cchFormat = _rpPF.GetCchLeft();
cchChunk = min(cchChunk, cchFormat);
}
cch -= cchChunk; // Decrement the count
cchGet = _rpTX.GetText(cchChunk, rgCh); // Manipulate chars in buffer
if(cchGet < cchChunk) // (for undo, need to use
{ // ReplaceRange())
cch = 0; // No more chars in story,
if(!cchGet) // so we'll be done
break; // We're done already
cchChunk = cchGet; // Something in this chunk
}
if (0 == W32->GetStringTypeEx(0, CT_CTYPE1, rgCh, // Find out whether chars are
cchChunk, rgType)) // UC, LC, or neither
{
TRACEWARNSZ("GetStringTypeEx failed");
return FALSE;
}
cchLast = 0; // Default nothing to replace
cchFirst = -1;
for(pch = rgCh, pType = rgType; // Process buffered chars
cchChunk;
cchChunk--, pch++, pType++)
{
fAlpha = *pType & (C1_UPPER | C1_LOWER); // Nonzero if UC or LC
fUpper = (*pType & C1_UPPER) != 0; // TRUE if UC
fToUpper = fStart ? TRUE : fUpper; // capitalize first letter of a
// sentence
switch(Type)
{ // Decide whether to change
case tomLowerCase: // case and determine start
fToUpper = FALSE; // of word/sentence for title
break; // and sentence cases
case tomUpperCase:
fToUpper = TRUE;
break;
case tomToggleCase:
fToUpper = !fUpper;
break;
case tomSentenceCase:
if(*pch == TEXT('.')) // If sentence terminator,
fStart = TRUE; // capitalize next alpha
if(fAlpha) // If this char is alpha, next
fStart = FALSE; // char can't start a
break; // sentence
case tomTitleCase: // If this char is alpha, next
fStart = (fAlpha == 0); // char can't start a word
break;
default:
return FALSE;
}
if(fAlpha && (fToUpper ^ fUpper)) // Only change case if it
{ // makes a difference (saves
if(fToUpper) // on system calls and undos)
CharUpperBuff(pch, 1);
else
CharLowerBuff(pch, 1);
fChange = TRUE; // Return value: change made
if( cchFirst == -1 ) // Save cch of unchanged
cchFirst = cchGet-cchChunk; // leading string
cchLast = cchChunk - 1; // Save cch of unchanged
} // trailing string
}
if( cchFirst == -1 )
{
Assert(cchLast == 0);
cchFirst = cchGet;
}
Advance(cchFirst); // Skip unchanged leading
cchGet -= cchFirst + cchLast; // string. cchGet = cch of
_rpCF.AdjustForward(); // changed span. Adjust in
// case cchFirst = 0
ReplaceRange(cchGet, cchGet, rgCh
+ cchFirst, publdr, _rpCF.GetFormat());
Advance(cchLast); // Skip unchanged trailing
} // string
return fChange;
}
// The following defines a mask for Units implemented by UnitCounter()
#define IMPL ((1 << tomCharacter) + (1 << tomWord) + (1 << tomSentence) + \
(1 << tomParagraph) + (1 << tomLine) + (1 << tomStory) + \
(1 << tomCharFormat) + (1 << tomParaFormat) + (1 << tomObject))
/*
* CRchTxtPtr::UnitCounter (Unit, &cUnit, cchMax)
*
* @mfunc
* Helper function to count chars in <p cUnit> Units defined by <p Unit>
* <p cUnit> is a signed count. If it extends beyond either end of the
* story, count up to that end and update <p cUnit> accordingly. If
* <p cchMax> is nonzero, stop counting when the count exceeds <p cchMax>
* in magnitude.
*
* @rdesc
* If unit is implemented, return cch corresponding to the units counted
* (up to a maximum magnitude of <p cchMax>) and update cUnit;
* else return tomForward to signal unit not implemented and cUnit = 0.
* If unit is implemented but unavailable, e.g., tomObject with no
* embedded objects, return tomBackward.
*
* @devnote
* This is the basic engine used by the TOM CTxtRange::Move() and Index()
* methods.
*/
LONG CRchTxtPtr::UnitCounter (
LONG Unit, //@parm Type of unit to count
LONG & cUnit, //@parm Count of units to count chars for
LONG cchMax) //@parm Maximum character count
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEINTERN, "CRchTxtPtr::UnitCounter");
LONG action; // Gives direction and tomWord commands
LONG cch; // Collects cch counted
LONG cchText = GetTextLength();
LONG cp = GetCp();
LONG iDir = cUnit > 0 ? 1 : -1;
LONG j; // For-loop index
CDisplay *pdp; // Used for tomLine case
if(!cUnit) // Nothing to count
{
return ((DWORD)Unit > tomObject || !((IMPL >> Unit) & 1))
? tomForward : 0; // Indicate Unit not
} // implemented
if(cchMax <= 0)
cchMax = tomForward; // No cch limit
switch(Unit)
{
case tomCharacter: // Smallest Unit
cp += cUnit; // Requested new cp
ValidateCp(cp); // Make sure it's OK
cch = cUnit = cp - GetCp(); // How many cch, cUnits
break; // actually moved
case tomStory: // Largest Unit
cch = (cUnit > 0) ? cchText - cp : -cp; // cch to start of story
cUnit = cch ? iDir : 0; // If already at end/start,
break; // of story, no count
case tomCharFormat: // Constant CHARFORMAT
cch = _rpCF.CountRuns(cUnit, cchMax, cchText);
break;
case tomParaFormat: // Constant PARAFORMAT
cch = _rpPF.CountRuns(cUnit, cchMax, cchText);
break;
case tomObject:
if(!GetObjectCount()) // No objects: can't move, so
{
cUnit = 0; // set cUnit = 0 and
return tomBackward; // signal Unit unavailable
}
cch = GetPed()->_pobjmgr->CountObjects(cUnit, GetCp());
break;
case tomLine:
pdp = GetPed()->_pdp;
if(pdp) // If this story has a display
{ // use a CLinePtr
CLinePtr rp(pdp);
pdp->WaitForRecalc(cp, -1);
rp.RpSetCp(cp, FALSE);
cch = rp.CountRuns(cUnit, cchMax, cchText);
break;
} // Else fall thru to treat as
// tomPara
default: // tp dependent cases
{ // Block to contain tp() which
CTxtPtr tp(_rpTX); // takes time to construct
if (cUnit < 0) // Counting backward
{
action = (Unit == tomWord)
? WB_MOVEWORDLEFT : tomBackward;
}
else // Counting forward
{
action = (Unit == tomWord)
? WB_MOVEWORDRIGHT : tomForward;
}
for (cch = 0, j = cUnit; j && abs(cch) < cchMax; j -= iDir)
{
cp = tp.GetCp(); // Save starting cp for
switch (Unit) // calculating cch for this
{ // Unit
case tomWord:
tp.FindWordBreak(action);
break;
case tomSentence:
tp.FindBOSentence(action);
break;
case tomLine: // Story has no line array:
case tomParagraph: // treat as tomParagraph
tp.FindEOP(action);
break;
default:
cUnit = 0;
return tomForward; // Return error
}
if(tp.GetCp() - cp == 0) // No count:
break; // don't decrement cUnit
cch += tp.GetCp() - cp;
}
cUnit -= j; // Discount any runs not
} // counted if |cch| >= cchMax
}
if(abs(cch) > cchMax) // Keep cch within requested
{ // limit
cch = cch > 0 ? cchMax : -cchMax;
if(Unit == tomCharacter)
cUnit = cch;
}
Advance(cch); // Move to new position
return cch; // Total cch counted
}
/*
* CRchTxtPtr::Zombie ()
*
* @mfunc
* Turn this object into a zombie by NULLing out its _ped member
*/
void CRchTxtPtr::Zombie ()
{
TRACEBEGIN(TRCSUBSYSBACK, TRCSCOPEINTERN, "CRchTxtPtr::Zombie");
_rpTX.Zombie();
_rpCF.SetToNull();
_rpPF.SetToNull();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -