📄 select.cpp
字号:
LONG cpMin, cpMost, cchLast;
GetRange(cpMin, cpMost);
rp.RpSetCp(cpMin, FALSE); // Selections can't start at EOL
cch = rp.RpGetIch();
rp.RpSetCp(cpMost, TRUE); // Selections can't end at BOL
// now remove the trailing EOP (if it exists and isn't
// already selected).
cchLast = rp.GetAdjustedLineLength() - rp.RpGetIch();
if( cchLast > 0 )
{
cch += cchLast;
}
}
return cch;
}
/*
* CTxtSelection::ShowSelection(fShow)
*
* @mfunc
* Update, hide or show selection on screen
*
* @rdesc
* TRUE iff selection was previously shown
*/
BOOL CTxtSelection::ShowSelection (
BOOL fShow) //@parm TRUE for showing, FALSE for hiding
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::ShowSelection");
_TEST_INVARIANT_
const BOOL fShowPrev = _fShowSelection;
const BOOL fInplaceActive = GetPed()->fInplaceActive();
LONG cpSelSave = _cpSel;
LONG cchSelSave = _cchSel;
// Sleep(1000);
_fShowSelection = fShow;
if(fShowPrev && !fShow)
{
if(cchSelSave) // Hide old selection
{
// Set up selection before telling the display to update
_cpSel = 0;
_cchSel = 0;
if (fInplaceActive)
{
_pdp->InvertRange(cpSelSave, cchSelSave, selSetNormal);
}
}
}
else if(!fShowPrev && fShow)
{
if(_cch) // Show new selection
{
// Set up selection before telling the display to update
_cpSel = GetCp();
_cchSel = _cch;
if (fInplaceActive)
{
_pdp->InvertRange(GetCp(), _cch, selSetHiLite);
}
}
}
return fShowPrev;
}
/*
* CTxtSelection::UpdateSelection()
*
* @mfunc
* Updates selection on screen
*
* Note:
* This method inverts the delta between old and new selections
*/
void CTxtSelection::UpdateSelection()
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::UpdateSelection");
_TEST_INVARIANT_
LONG cp = GetCp();
LONG cpNA = cp - _cch;
LONG cpSelNA = _cpSel - _cchSel;
LONG cpMin, cpMost, cpMinSel, cpMostSel;
CObjectMgr* pobjmgr = NULL;
LONG NumObjInSel = 0, NumObjInOldSel = 0;
LONG cpSelSave = _cpSel;
LONG cchSelSave = _cchSel;
GetRange(cpMin, cpMost);
//We need to know if there were objects is the previous and current
//selections to determine how they should be selected.
if (GetPed()->HasObjects())
{
pobjmgr = GetPed()->GetObjectMgr();
if (pobjmgr)
{
CTxtRange tr(GetPed(), _cpSel, _cchSel);
tr.GetRange(cpMinSel, cpMostSel);
NumObjInSel = pobjmgr->CountObjectsInRange(cpMin, cpMost);
NumObjInOldSel = pobjmgr->CountObjectsInRange(cpMinSel, cpMostSel);
}
}
//If the old selection contained a single object and nothing else
//we need to notify the object manager that this is no longer the
//case if the selection is changing.
if (NumObjInOldSel && (abs(_cchSel) == 1) &&
!(cpMin == cpMinSel && cpMost == cpMostSel))
{
if (pobjmgr)
{
pobjmgr->HandleSingleSelect(GetPed(), cpMinSel, /* fHilite */ FALSE);
}
}
// Update selection data before the invert so the selection can be
// painted by the render
_cpSel = GetCp();
_cchSel = _cch;
if( _fShowSelection )
{
if( !_cch || !cchSelSave || // Old/new selection missing,
cpMost < min(cpSelSave, cpSelNA) || // or new preceeds old,
cpMin > max(cpSelSave, cpSelNA)) // or new follows old, so
{ // they don't intersect
if(_cch)
_pdp->InvertRange(cp, _cch, selSetHiLite);
if(cchSelSave)
_pdp->InvertRange(cpSelSave, cchSelSave, selSetNormal);
}
else
{
if(cpNA != cpSelNA) // Old & new dead ends differ
{ // Invert text between them
_pdp->InvertRange(cpNA, cpNA - cpSelNA, selUpdateNormal);
}
if(cp != cpSelSave) // Old & new active ends differ
{ // Invert text between them
_pdp->InvertRange(cp, cp - cpSelSave, selUpdateHiLite);
}
}
}
//If the new selection contains a single object and nothing else
//we need to notify the object manager as long as it's not the same
//object.
if (NumObjInSel && (abs(_cch) == 1) &&
!(cpMin == cpMinSel && cpMost == cpMostSel))
{
if (pobjmgr)
{
pobjmgr->HandleSingleSelect(GetPed(), cpMin, /* fHiLite */ TRUE);
}
}
}
/*
* CTxtSelection::SetSelection(cpFirst, cpMost)
*
* @mfunc
* Set selection between two cp's
*
* @devnote
* <p cpFirst> and <p cpMost> must be greater than 0, but may extend
* past the current max cp. In that case, the cp will be truncated to
* the max cp (at the end of the text).
*/
void CTxtSelection::SetSelection (
LONG cpMin, //@parm Start of selection and dead end
LONG cpMost) //@parm End of selection and active end
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::SetSelection");
_TEST_INVARIANT_
StopGroupTyping();
_fCaretNotAtBOL = FALSE; // Put caret for ambiguous cp at BOL
Set(cpMost, cpMost - cpMin); // Set() validates cpMin, cpMost
if (GetPed()->fInplaceActive())
{
// Inplace active - update the selection now.
Update(TRUE);
}
else
{
// Update the selection data used for screen display
// so whenever we get displayed the selection will be
// displayed.
_cpSel = GetCp();
_cchSel = _cch;
if (!GetPed()->fHideSelection())
{
// Selection is not hidden so tell container to
// update the display when it feels like.
GetPed()->TxInvalidateRect(NULL, FALSE);
GetPed()->TxUpdateWindow();
}
}
CancelModes(); // Cancel word selection mode
}
/*
* CTxtSelection::PointInSel(pt, prcClient)
*
* @mfunc
* Figures whether a given point is within the selection
*
* @rdesc
* TRUE if point inside selection, FALSE otherwise
*/
BOOL CTxtSelection::PointInSel (
const POINT pt, //@parm Point in containing window client coords
const RECT *prcClient, //@parm Client rectangle can be NULL if active
HITTEST Hit) const //@parm Possibly computer Hit value
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::PointInSel");
LONG cp;
LONG cpMin, cpMost;
POINT temppt;
CRchTxtPtr rtp(GetPed(), 0);
_TEST_INVARIANT_
if (!_cch || Hit && Hit < HT_Text) // Degenerate range (no selection):
return FALSE; // mouse can't be in, or Hit not
// in text
cp = _pdp->CpFromPoint(pt, prcClient, NULL, NULL, FALSE, &Hit);
if(Hit < HT_Text)
return FALSE;
GetRange(cpMin, cpMost);
// we have to test boundary cases separately--we want to make
// sure the point is in the bounding box of the selection, but cp
// from point will artificially extend that bounding box to half of
// the next/previous character. Think of it this way, when you click
// in the middle of a character, the insertion point has to go
// somewhere to the left or the right.
if( cp > cpMin && cp < cpMost )
{
return TRUE;
}
else if( cp == cpMin )
{
rtp.SetCp(cp);
_pdp->PointFromTp(rtp, prcClient, FALSE, temppt, NULL, TA_TOP);
if( pt.x >= temppt.x )
{
return TRUE;
}
}
else if( cp == cpMost )
{
rtp.SetCp(cp);
_pdp->PointFromTp(rtp, prcClient, TRUE, temppt, NULL, TA_TOP);
if( pt.x <= temppt.x )
{
return TRUE;
}
}
return FALSE;
}
////////////////////////////////// Selection with the mouse ///////////////////////////////////
/*
* CTxtSelection::SetCaret(pt, fUpdate)
*
* @mfunc
* Sets caret at a given point
*
* @devnote
* In the plain-text case, placing the caret at the beginning of the
* line following the final EOP requires some extra code, since the
* underlying rich-text engine doesn't assign a line to a final EOP
* (plain-text doesn't currently have the rich-text final EOP). We
* handle this by checking to see if the count of lines times the
* plain-text line height is below the actual y position. If so, we
* move the cp to the end of the story.
*/
void CTxtSelection::SetCaret(
const POINT pt, //@parm Point of click
BOOL fUpdate) //@parm If TRUE, update the selection/caret
{
TRACEBEGIN(TRCSUBSYSSEL, TRCSCOPEINTERN, "CTxtSelection::SetCaret");
_TEST_INVARIANT_
LONG cp;
RECT rcView;
CLinePtr rp(_pdp);
CRchTxtPtr rtp(GetPed());
LONG y;
StopGroupTyping();
// Set caret at point
if (_pdp->CpFromPoint(pt, NULL, &rtp, &rp, FALSE) >= 0)
{
// Set the selection to the correct location. If plain-text
// multiline control, we need to check to see if pt.y is below
// the last line of text. If so and if the text ends with an EOP,
// we need to set the cp at the end of the story and set up to
// display the caret at the beginning of the line below the last
// line of text
cp = rtp.GetCp();
if (!GetPed()->IsRich() && // Plain-text,
GetPed()->TxGetMultiLine()) // multiline control
{
_pdp->GetViewRect(rcView, NULL);
y = pt.y + _pdp->GetYScroll() - rcView.top;
if(y > (LONG)rp.Count()*rp->_yHeight) // Below last line of
{ // text
rtp.Advance(tomForward); // Move rtp to end of text
if(rtp._rpTX.IsAfterEOP()) // If text ends with an
{ // EOP, set up to move
cp = rtp.GetCp(); // selection there
rp.AdvanceCp(-(LONG)rp.GetIch());// Set rp._ich = 0 to
} // set _fCaretNotAtBOL
} // = FALSE to display
} // caret at next BOL
#ifndef TARGET_NT
// GuyBark JupiterJ IME:
// We must take action to ensure the ime knows the caret's moved.
if(GetPed()->IsIMEComposition())
{
// Select another clause if necessary. If we do highlight
// another clause, then don't set the IME caret position.
// Otherwise the IME caret setting action interferes with
// the clause highlighting.
if(SetIMEHighlight(&cp, pt, &rtp))
{
// Didn't highlight another clause. We may freeze the
// display beneath here, until we've finished walking
// the caret if we need to.
SetIMECaret(&cp);
// Store the final caret cp here, so we can move any candidate
// list to that position if necessary later.
_pdp->PointFromTp(rtp, NULL, FALSE, GetPed()->_ime->_pt, NULL, TA_TOP);
}
}
#endif // !TARGET_NT
Set(cp, 0);
_fCaretNotAtBOL = rp.RpGetIch() != 0; // Caret OK at BOL if click
if(fUpdate)
Update(TRUE);
else
UpdateForAutoWord();
_SelMode = smNone; // Cancel word selection mode
}
}
#ifndef TARGET_NT
/*
* CTxtSelection::SetIMECaret(pcpNew)
*
* GUYBARK ADD THIS!
*
* Without this, RichEdit know the caret's moved, but the ime doesn't.
*
* Returns FALSE if no errors, else TRUE
*/
BOOL CTxtSelection::SetIMECaret(LONG *pcpNew)
{
LONG cpMin, cpMost, cpMove, cpUndeterminedStart, cchUndetermined;
UINT vkCode;
HWND hWndRE;
UINT nShift;
UINT chCode;
CTxtEdit *ped;
if(!pcpNew || !(ped = GetPed()))
{
return TRUE;
}
// Don't do anything here if we're not in undetermined text.
if(!ped->IsIMEComposition())
{
// No errors.
return FALSE;
}
// Get the current cp.
GetRange(cpMin, cpMost);
// Force the caret to stay in the undetermined text.
if(ped->_ime->GetUndeterminedInfo((INT*)&cpUndeterminedStart, (INT*)&cchUndetermined))
{
return TRUE;
}
if(*pcpNew < cpUndeterminedStart)
{
*pcpNew = cpUndeterminedStart;
}
else if(*pcpNew > cpUndeterminedStart + cchUndetermined)
{
*pcpNew = cpUndeterminedStart + cchUndetermined;
}
// Get the offset to the new caret position.
cpMove = *pcpNew - cpMin;
// Is the caret moving left or right?
vkCode = cpMove < 0 ? VK_LEFT : VK_RIGHT;
// Get the RichEdit window handle.
if(ped->TxGetWindow(&hWndRE) != NOERROR)
{
return TRUE;
}
// Don't need to do anything if the user's tapped where the caret already sits.
if(cpMove != 0)
{
HIMC hIMC = ped->TxImmGetContext();
if(!hIMC || !ImmEscape((HKL)NULL, hIMC, IME_ESC_SETCURSOR, (LPVOID)cpMove))
{
// Now loop through as though the user pressed the arrow keys.
cpMove = abs(cpMove);
// Freeze the display to stop the caret running around. This
// gets thawed later when we process the last key up.
_pdp->Freeze();
ped->_fDisplayFrozen = TRUE;
for(; cpMove > 0; cpMove-- )
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -