📄 tomrange.cpp
字号:
* (if <p Cset> valid) ? S_FALSE : E_INVALIDARG
*
* @devnote
* Argument validation of the MoveWhile and MoveUntil methods is done by
* the helper CTxtRange::Matcher (Cset, Count, pDelta, fExtend, fSpan)
*/
STDMETHODIMP CTxtRange::MoveWhile (
VARIANT * Cset, //@parm Character match set to use
long Count, //@parm Max number of characters to move past
long * pDelta) //@parm Out parm to receive actual count of
// characters end is moved
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::MoveWhile");
return Matcher(Cset, Count, pDelta, MOVE_IP, MATCH_WHILE);
}
/*
* CTxtRange::Paste (pVar, ClipboardFormat)
*
* @mfunc
* Paste the data object <p pVar> into this range. If
* <p pVar> is null, paste from the clipboard.
*
* @rdesc
* HRESULT = (WriteAccessDenied) ? E_ACCESSDENIED :
* (if success) ? NOERROR : E_OUTOFMEMORY
*/
STDMETHODIMP CTxtRange::Paste (
VARIANT *pVar, //@parm Data object to paste
long ClipboardFormat) //@parm Desired clipboard format
{
#ifndef PEGASUS
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::Paste");
if(IsZombie())
return CO_E_RELEASED;
CCallMgr callmgr(GetPed());
HRESULT hr;
IDataObject * pdo = NULL; // Default clipboard
CGenUndoBuilder undobldr(GetPed(), UB_AUTOCOMMIT );
if( WriteAccessDenied())
return E_ACCESSDENIED;
if(pVar)
if (pVar->vt == VT_UNKNOWN)
pVar->punkVal->QueryInterface(IID_IDataObject, (void **)&pdo);
else if (pVar->vt == (VT_UNKNOWN | VT_BYREF))
pdo = (IDataObject *)(*pVar->ppunkVal);
hr = GetPed()->PasteDataObjectToRange (pdo, this,
(WORD)ClipboardFormat, NULL, &undobldr, PDOR_NONE);
if(pdo && pVar->vt == VT_UNKNOWN)
pdo->Release();
Update(TRUE); // Update selection
return hr;
#else
return 0;
#endif
}
/*
* ITextRange::ScrollIntoView(long Code)
*
* @mfunc
* Method that scrolls this range into view according to the
* code Code defined below.
*
* @rdesc
* HRESULT = (if success) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtRange::ScrollIntoView (
long Code) //@parm Scroll code
{
#ifndef PEGASUS
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::ScrollIntoView");
// Validate parameter
if (Code != tomStart && Code != tomEnd)
{
return E_INVALIDARG;
}
if(IsZombie())
return CO_E_RELEASED;
// Get local copy of ped to save some indirections.
CTxtEdit *ped = GetPed();
if (!ped->fInplaceActive())
{
// If the control is not active, we can't get the information
// because no one knows what our client rect is.
return E_FAIL;
}
// Get a local copy of display to save some indirections.
CDisplay *pdp = ped->_pdp;
LONG cpStart;
LONG cpForEnd;
GetRange(cpStart, cpForEnd);
// Get the view rectangle so we can compute the absolute x/y
RECT rcView;
pdp->GetViewRect(rcView, NULL);
// Set up tp for PointFromTp call
CRchTxtPtr tp(ped, cpStart);
// Values used for making returned point locations absolute since
// PointFromTp adjusts the point returned to be relative to the
// display.
const LONG xScrollAdj = pdp->GetXScroll() - rcView.left;
const LONG yScrollAdj = pdp->GetYScroll() - rcView.top;
// Get the left/top for the start
CLinePtr rpStart(pdp);
POINT ptStart;
LONG iliStart =
pdp->PointFromTp(tp, NULL, TRUE, ptStart, &rpStart, TA_TOP + TA_LEFT);
ptStart.x += xScrollAdj;
ptStart.y += yScrollAdj;
// Get the right/bottom for the end
CLinePtr rpEnd(pdp);
POINT ptEnd;
tp.SetCp(cpForEnd);
LONG iliEnd =
pdp->PointFromTp(tp, NULL, TRUE, ptEnd, &rpEnd, TA_BOTTOM + TA_RIGHT);
ptEnd.x += xScrollAdj;
ptEnd.y += yScrollAdj;
//
// Calculate the yScroll
//
// The basic idea is to display both the start and the end if possible. But
// if it is not possible then display the requested end based on the input
// parameter.
LONG yHeightView = pdp->GetViewHeight();
LONG yScroll;
if (tomStart == Code)
{
// Scroll the Start cp to the top of the view
yScroll = ptStart.y;
}
else
{
// Scroll the End cp to the bottom of the view
yScroll = ptEnd.y - yHeightView;
}
//
// Calculate the X Scroll
//
// Default scroll to beginning of the line
LONG xScroll = 0;
// Make view local to save a number of indirections
LONG xWidthView = pdp->GetViewWidth();
if (iliStart == iliEnd)
{
// Entire selection is on the same line so we want to display as
// much of it as is possible.
LONG xWidthSel = ptEnd.x - ptStart.x;
if (xWidthSel > xWidthView)
{
// Selection length is greater than display width
if (tomStart == Code)
{
// Show Start requested - just start from beginning
// of selection
xScroll = ptStart.x;
}
else
{
// Show end requested - show as much of selection as
// possible, ending with last character in the
// selection.
xScroll = ptEnd.x - xWidthView;
}
}
else if (ptEnd.x > xWidthView)
{
// End of selection is outside the view starting
// at 0 so display as much as possible ending with
// End.
xScroll = ptEnd.x - xWidthView;
}
}
else
{
// Multiline selection. Display as much as possible of the requested
// end's line.
// Calc width of line
LONG xWidthLine = (tomStart == Code)
? rpStart->_xWidth + rpStart->_xLeft
: rpEnd->_xWidth + rpEnd->_xLeft;
// If line width is less than or equal to view, start at
// 0 otherwise we need to adjust starting position to
// show as much of the requested end's selection line
// as possible.
if (xWidthLine > xWidthView)
{
if (tomStart == Code)
{
// Start end to be displayed
if (xWidthLine - ptStart.x > xWidthView)
{
// Selection is bigger than the view
// so start at the beginning and display
// as much as possible.
xScroll = ptStart.x;
}
else
{
// Remember that this is a multiline selection so the
// selection on this line goes from ptStart.x to the
// end of line. Since the selection width is less than
// the width of the view, we just back up the width
// of view to show the entire selection.
xScroll = xWidthLine - xWidthView;
}
}
else
{
// Show the end of the selection. In the multiline case,
// this goes from the beginning of the line to End. So
// we only have to adjust if the End is beyond the view.
if (ptEnd.x > xWidthView)
{
// End beyond the view. Show as much as possible
// of the selection.
xScroll = ptEnd.x - xWidthView;
}
}
}
}
// Do the scroll
pdp->ScrollView(xScroll, yScroll, FALSE, FALSE);
return S_OK;
#else
return 0;
#endif
}
/*
* CTxtRange::Select ()
*
* @mfunc
* Copy this range's cp's and story ptr to the active selection.
*
* @rdesc
* HRESULT = (if selection exists) ? NOERROR : S_FALSE
*/
STDMETHODIMP CTxtRange::Select ()
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::Select");
if(IsZombie())
return CO_E_RELEASED;
LONG cpMin, cpMost;
CTxtSelection *pSel = GetPed()->GetSel();
if(pSel)
{
GetRange(cpMin, cpMost);
pSel->SetRange(cpMin, cpMost);
return NOERROR;
}
return S_FALSE;
}
/*
* CTxtRange::SetChar (Char)
*
* @mfunc
* Set char at cpFirst = <p Char>
*
* @rdesc
* HRESULT = (WriteAccessDenied) ? E_ACCESSDENIED :
* (char stored) ? NOERROR : S_FALSE
*
* @devnote
* Special cases could be much faster, e.g., just overtype the plain-
* text backing store unless at EOD or EOR. Code below uses a cloned
* range to handle all cases easily and preserve undo capability.
*/
STDMETHODIMP CTxtRange::SetChar (
long Char) //@parm New value for char at cpFirst
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::SetChar");
if(IsZombie())
return CO_E_RELEASED;
CTxtEdit * ped = GetPed();
CCallMgr callmgr(ped);
TCHAR ch = (TCHAR)Char; // Avoid endian problems
CTxtRange rg(*this);
CGenUndoBuilder undobldr(ped, UB_AUTOCOMMIT );
if( WriteAccessDenied())
return E_ACCESSDENIED;
if(!ped->TxGetMultiLine() && IsEOP(Char)) // EOPs are not allowed in
return FALSE; // single-line edit controls
undobldr.StopGroupTyping();
rg.Collapser(tomStart); // Collapse at cpMin
rg.SetExtend(TRUE); // Setup to select
rg.Advance(1); // Try to select char at IP
if(rg.ReplaceRange(1, &ch, &undobldr, SELRR_REMEMBERRANGE))
{
Update(TRUE); // Update selection
return NOERROR;
}
return S_FALSE;
}
/*
* CTxtRange::SetEnd (cp)
*
* @mfunc
* Set this range's End cp
*
* @rdesc
* HRESULT = (if change) ? NOERROR : S_FALSE
*
* @comm
* Note that setting this range's cpMost to <p cp> also sets cpMin to
* <p cp> if <p cp> < cpMin.
*/
STDMETHODIMP CTxtRange::SetEnd (
long cp) //@parm Desired new End cp
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::SetEnd");
if(IsZombie())
return CO_E_RELEASED;
LONG cpMin = GetCpMin();
ValidateCp(cp);
return SetRange(min(cpMin, cp), cp); // Active end is End
}
/*
* CTxtRange::SetFont (pFont)
*
* @mfunc
* Set this range's character attributes to those given by <p pFont>.
* This method is a "character format painter".
*
* @rdesc
* HRESULT = (!pFont) ? E_INVALIDARG :
* (if success) ? NOERROR :
* (protected) ? E_ACCESSDENIED : E_OUTOFMEMORY
*/
STDMETHODIMP CTxtRange::SetFont (
ITextFont * pFont) //@parm Font object with desired character formatting
{
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::SetFont");
if(!pFont)
return E_INVALIDARG;
if(IsZombie())
return CO_E_RELEASED;
ITextFont * pFontApply = (ITextFont *) new CTxtFont(this);
if(!pFontApply)
return E_OUTOFMEMORY;
HRESULT
hr = (*(LONG *)pFontApply == *(LONG *)pFont) // If same vtable, use
? CharFormatSetter(&((CTxtFont *)pFont)->_CF) // its _CF; else copy
: pFontApply->SetDuplicate(pFont); // to clone and apply
pFontApply->Release();
return hr;
}
/*
* CTxtRange::SetFormattedText (pRange)
*
* @mfunc
* Replace this range's text with formatted text given by <p pRange>.
* If <p pRange> is NULL, paste from the clipboard.
*
* @rdesc
* HRESULT = (WriteAccessDenied) ? E_ACCESSDENIED :
* (if success) ? NOERROR : E_OUTOFMEMORY
*
* @FUTURE
* Do this more efficiently if pRange points at a RichEdit range. This
* would also help with RichEdit D&D to RichEdit targets
*/
STDMETHODIMP CTxtRange::SetFormattedText (
ITextRange * pRange) //@parm Formatted text to replace this
// range's text
{
#ifndef PEGASUS
TRACEBEGIN(TRCSUBSYSTOM, TRCSCOPEEXTERN, "CTxtRange::SetFormattedText");
if(IsZombie())
return CO_E_RELEASED;
CCallMgr callmgr(GetPed());
LONG cpMin = GetCpMin();
HRESULT hr;
IUnknown * pdo = NULL;
VARIANT vr;
if(!pRange)
return NOERROR; // Nothing to paste
if( WriteAccessDenied())
return E_ACCESSDENIED;
pVariantInit(&vr);
vr.vt = VT_UNKNOWN | VT_BYREF;
vr.ppunkVal = &pdo;
hr = pRange->Copy(&vr);
if(hr == NOERROR)
{
hr = Paste(&vr, 0);
pdo->Release(); // Release the data object
_cch = GetCp() - cpMin; // Select the new text
}
return hr;
#else
return 0;
#endif
}
/*
* CTxtRange::SetIndex (Unit, Index, Extend)
*
* @mfunc
* If <p Extend> is zero, convert this range into an insertion point
* at the start of the <p Index>th <p Unit> in the current story. If
* <p Extend> is nonzero, set this range to consist of this unit. The
* start of the story corresponds to <p Index> = 0 for all units.
*
* Positive indices are 1-based and index relative to the beginning of
* the story. Negative indices are -1-based and index relative to the
* end of the story. So an index of 1 refers to the first Unit in the
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -