📄 disp.cpp
字号:
COLORREF crBackground = _ped->TxGetBackColor();
COffScreenDC osdc;
//
// Render the view to a memory DC
//
// Compute the zero based client rectangle
rcClient.left = 0;
rcClient.top = 0;
rcClient.right = prcClient->right - prcClient->left;
rcClient.bottom = prcClient->bottom - prcClient->top;
// Create a memory DC
hdcMem = osdc.Init(hdc, rcClient.right, rcClient.bottom, crBackground);
if (NULL == hdcMem)
{
goto Cleanup;
}
// Initialize the display
osdc.FillBitmap(rcClient.bottom, crBackground);
// Set the DC to the memory DC
SetDC(hdcMem);
// Get the view rectangle that we need for rendering
GetViewRect(rcView, &rcClient);
// Adjust point to be relative to the memory display
pt.x -= prcClient->left;
pt.y -= prcClient->top;
// Initalize box around point. Note that we only really need to render
// the data inside this box because this is the only area that we will
// test.
rcRender.top = pt.y - HIT_CLOSE_RECT_INC;
if (rcRender.top < 0)
{
rcRender.top = 0;
}
rcRender.bottom = pt.y + HIT_CLOSE_RECT_INC;
if (rcRender.bottom > rcClient.bottom)
{
rcRender.bottom = rcClient.bottom;
}
rcRender.left = pt.x - HIT_CLOSE_RECT_INC;
if (rcRender.left < 0)
{
rcRender.left = 0;
}
rcRender.right = pt.x + HIT_CLOSE_RECT_INC;
if (rcRender.right > rcClient.right)
{
rcRender.right = rcClient.right;
}
// Now render
Render(rcView, rcRender);
//
// Hit test
//
// Assume no hit
*pHitResult = TXTHITRESULT_TRANSPARENT;
// At this point we won't fail this
hr = S_OK;
// Is there an exact hit?
if (GetPixel(hdcMem, pt.x, pt.y) != crBackground)
{
*pHitResult = TXTHITRESULT_HIT;
goto Cleanup;
}
// Is it close? We determine closeness by putting
// a 10 x 10 pixel box around the hit point and
// seeing if there is a hit there.
// Loop examining each bit in the box to see if it is on.
for (iRow = rcRender.top; iRow <= rcRender.bottom; iRow++)
{
for (int iCol = rcRender.left; iCol <= rcRender.right; iCol++)
{
if (GetPixel(hdcMem, iCol, iRow) != crBackground)
{
*pHitResult = TXTHITRESULT_CLOSE;
goto Cleanup;
}
}
}
Cleanup:
ResetDC();
return hr;
}
//=============================== ITxNotify Interface ===============================
/*
* CDisplay::OnPreReplaceRange
*
* @mfunc
* Preprocess a change in backing store
*
* @rdesc
* void
*
* @devnote
* This display doesn't care about before changes
*/
void CDisplay::OnPreReplaceRange(
DWORD cp,
DWORD cchDel,
DWORD cchNew,
DWORD cpFormatMin, DWORD cpFormatMax)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::OnPreReplaceRange");
// Display doesn't care about before the fact
}
/*
* CDisplay::OnPostReplaceRange()
*
* @mfunc
* Process a change to the backing store as it applies to the display
*
* @rdesc
* void
*
*/
void CDisplay::OnPostReplaceRange(
DWORD cp,
DWORD cchDel,
DWORD cchNew,
DWORD cpFormatMin,
DWORD cpFormatMax)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::OnPostReplaceRange");
// There is one NO-OP's for the display:
// currently loading a file.
//
// We NO-OP the load case because loading an RTF file can consist
// of potentially very many small actions as we peice together
// the various bits of formatted text. Once done, the load code
// will go through and do an update-all to the display.
Assert (cp != CONVERT_TO_PLAIN); // Handled with PreReplace notifications
// Figure out the range needed to update
DWORD cpNew = min(cp, cpFormatMin);
if (INFINITE == cpNew)
{
// If both cp's are infinite we don't need to bother with
// this operation.
return;
}
if(!_ped->_fInPlaceActive)
{
// If not active, just invalidate everything
InvalidateRecalc();
_ped->TxInvalidateRect(NULL, FALSE);
_ped->TxUpdateWindow();
return;
}
// Adjust cp for further calculations
if (INFINITE == cp)
{
cp = 0;
}
// find the new max end of the original region.
DWORD cpForEnd = max( (cp + cchDel), cpFormatMax);
// Number of deleted characters is the difference between the previous two
DWORD cchDelForDisplay = cpForEnd - cpNew;
// The number deleted is simply number of new characters adjusted by
// the change in the number of characters.
DWORD cchNewForDisplay = cchDelForDisplay + (cchNew - cchDel);
if (_padc != NULL)
{
// Display is frozen so accumulate the change instead of actually
// displaying it on the screen.
_padc->UpdateRecalcRegion(cpNew, cchDelForDisplay, cchNewForDisplay);
return;
}
// tell the display to update
CRchTxtPtr tp(_ped, cpNew);
UpdateView(tp, cchDelForDisplay, cchNewForDisplay);
}
/*
* CDisplay::SetWordWrap()
*
* @mfunc
* Sets the no wrap flag
*
* @rdesc
* void
*
* @devnote
* We will always allow the property to be set but we will not
* necessarily pay attention. In other words, word wrap has no
* effect on a single line edit control.
*/
void CDisplay::SetWordWrap(
BOOL fWordWrap //@param TRUE - turn on word wrap.
)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::SetWordWrap");
AssertSz((fWordWrap == TRUE) || (fWordWrap == FALSE),
"CDisplay::SetWordWrap bad input flag");
// Set nowrap to whatever is comming in.
_fWordWrap = fWordWrap;
}
/*
* CDisplay::GetWordWrap()
*
* @mfunc
* Return the state of word wrap property
*
* @rdesc
* TRUE - word wrap is on
* FALSE - word wrap is is off.
*
* @devnote
* Derived classes such as CDisplaySL override this.
*/
BOOL CDisplay::GetWordWrap() const
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::GetWordWrap");
return _fWordWrap;
}
/*
* CDisplay::GetViewDim()
*
* @mfunc
* Return the height & width of view adjusted for view inset
*
* @rdesc
* VOID
*
*/
void CDisplay::GetViewDim(
LONG& widthView, //@parm Where to return the width
LONG& heightView //@parm Where to return the height
)
{
// We build a client rectangle to take advantage of GetViewRect routine
// which really does all the work for us.
RECT rcClient;
rcClient.left = 0;
rcClient.top = 0;
rcClient.right = widthView;
rcClient.bottom = heightView;
// Take into account inset and selection bar. The parameters here are a bit
// of a trick. The second parameter gets copied into the first and since
// we don't need the orignal client rect we save a rect off the stack.
GetViewRect(rcClient, &rcClient);
widthView = rcClient.right - rcClient.left;
heightView = rcClient.bottom - rcClient.top;
}
/*
* CDisplay::ModeOffsetIntoChar
*
* @mfunc
* Calculates offset into character for given mode of TA_CENTER
* or TA_RIGHT.
*
* @rdesc
* Offset appropriate for the mode.
*
*/
LONG CDisplay::ModeOffsetIntoChar(
LONG taMode, //@parm Requested mode
const CRchTxtPtr& tp) //@parm text pointer to the character
{
AssertSz(taMode & TA_CENTER,
"CDisplay::ModeOffsetIntoChar called with invalid mode");
// Measure the single character
CMeasurer me(this, tp);
// And measure from there to where we are
me.NewLine(FALSE);
// Measure the character at the current cp
LONG xCharWidth = me.MeasureText(1);
if ((taMode & TA_CENTER) == TA_CENTER)
{
// Return offset to the middle of the character
xCharWidth >>= 1;
}
return xCharWidth;
}
/*
* CDisplay::SaveUpdateCaret
*
* @mfunc Save UpdateCaret parameter so update caret can be called
* after the display is thawed.
*
* @rdesc None.
*
* @devnote
* This should only be called if IsFrozen is true.
*
*/
void CDisplay::SaveUpdateCaret(
BOOL fScrollIntoView)
{
#ifdef DEBUG
if (_padc == NULL)
{
TRACEERRORSZ("CDisplay::SaveUpdateCaret called on thawed display");
}
#endif // DEBUG
if (_padc != NULL)
{
_padc->SaveUpdateCaret(fScrollIntoView);
}
}
/*
* CDisplay::Freeze
*
* @mfunc
* Prevent any updates from occuring in the display
*
* @rdesc
* None
*
*/
void CDisplay::Freeze()
{
if (NULL == _padc)
{
// Allocate object to keep track of changes
_padc = new CAccumDisplayChanges();
// We can now return because the accum object has a reference
// or the memory allocation failed. If the memory allocation
// failed, This really isn't a catastrophe because all it means
// is that things will get displayed ugly temporarily, so we can
// pretend it didn't happen.
return;
}
// Tell the object that that an additional freeze has occurred.
_padc->AddRef();
}
/*
* CDisplay::Thaw
*
* @mfunc
* If this is the last thaw, then cause display to be updated.
*
* @rdesc
* None
*
*/
void CDisplay::Thaw()
{
DWORD cp;
DWORD cchNew;
DWORD cchDel;
BOOL fUpdateCaret;
CTxtSelection *psel;
BOOL fScrollIntoView;
if (_padc != NULL)
{
// Release the reference to the accum object
if (_padc->Release() == 0)
{
// Last thaw so we need to update display
// Get the changes
_padc->GetUpdateRegion(&cp, &cchDel, &cchNew,
&fUpdateCaret, &fScrollIntoView);
// Clear the object - note we do this before
// the update just on the off chance that
// a new freeze manages to get in during the
// update of the display.
delete _padc;
_padc = NULL;
if( cp != INFINITE )
{
// Display changed
if (!_ped->fInplaceActive())
{
// Are not inplace active so we need to put this operation
// off till a more appropriate time.
InvalidateRecalc();
_ped->TxInvalidateRect(NULL, FALSE);
_ped->TxUpdateWindow();
return;
}
// Update the display
CRchTxtPtr rtp(_ped, cp);
if(!UpdateView(rtp, cchDel, cchNew))
return; // Update failed
}
// Did the selection request a caret update?
if (fUpdateCaret && _ped->fInplaceActive())
{
if (psel = _ped->GetSel())
{
psel->UpdateCaret(fScrollIntoView);
}
else
{
Assert(psel);
}
}
}
}
}
/*
* CDisplay::IsPrinter
*
* @mfunc
* Returns whether this is a printer
*
* @rdesc
* TRUE - is a display to a printer
* FALSE - is not a display to a printer
*
* @devnote
* No display except a display CDisplayPrinter should
* ever have a chance to return TRUE to this function.
*
*/
BOOL CDisplay::IsPrinter() const
{
return FALSE;
}
/*
* CDisplay::Zombie ()
*
* @mfunc
* Turn this object into a zombie
*/
void CDisplay::Zombie ()
{
TRACEBEGIN(TRCSUBSYSOLE, TRCSCOPEEXTERN, "CDisplay::Zombie");
}
/*
* CDisplay::IsHScrollEnabled ()
*
* @mfunc
* Return whether horizontal scroll bar is enabled
*
* @rdesc
* TRUE - yes
* FALSE - no
*
* @devnote
* The reason for this routine is that _fHScrollEnabled means
* to scroll text and can be set even if there is no scroll
* bar. Therefore, we need to look at the host properties
* as well to tell use whether this means there are scroll
* bars.
*/
BOOL CDisplay::IsHScrollEnabled()
{
return _fHScrollEnabled && ((_ped->TxGetScrollBars() & WS_HSCROLL) != 0);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -