📄 disp.cpp
字号:
RECT rcView, rcClient, rcRender;
CTxtSelection *psel = _ped->GetSelNC();
// Get client rect
if(!prcClient)
{
AssertSz(_ped->_fInPlaceActive,
"CDisplay::GetViewRect() - Not in-place and !prcClient");
_ped->TxGetClientRect(&rcClient);
prcClient = &rcClient;
}
if (NULL == prcWBounds)
{
// No metafile, so just set the rendering DC
if (!SetDC(hdcDraw))
{
hr = E_FAIL;
goto Cleanup;
}
}
else
{
// We are rendering to a metafile
hdcMeasure = _ped->CreateMeasureDC(hdcDraw, prcClient, FALSE, prcWBounds->left,
prcWBounds->top, prcWBounds->right, prcWBounds->bottom,
&xMeasurePerInch, &yMeasurePerInch);
SetMetafileDC(hdcDraw, hdcMeasure, xMeasurePerInch, yMeasurePerInch);
}
// Compute view rectangle from client rectangle
Assert(prcClient);
GetViewRect(rcView, prcClient);
// If this view is not active and it is not to be recalc'd then
// we only decide to use it if the size matches and return S_FALSE
// if it doesn't so the caller can create a new display to use for
// drawing.
if (!IsActive() && !_fNeedRecalc)
{
if ((rcView.right - rcView.left != GetViewWidth())
|| (rcView.bottom - rcView.top != GetViewHeight()))
{
hr = S_FALSE;
goto Cleanup;
}
}
// Make sure our client rectangle is set correctly.
_yHeightClient = prcClient->bottom - prcClient->top;
// Recalc view
if( !RecalcView(rcView) )
{
goto Cleanup;
}
if (dwDepthThisDraw != _pdi->GetDrawDepth())
{
// A draw happend recursively to this draw. Therefore,
// the screen has already been rendered so we don't need
// to do anything more here.
goto Cleanup;
}
// Compute rect to render
if(!prcUpdate)
{
// update full view
rcRender = *prcClient;
}
else
{
// Clip rendering to the client rect
if(!IntersectRect(&rcRender, prcClient, prcUpdate))
goto Cleanup;
}
if (psel)
{
psel->ClearCchPending();
}
if (IsMain())
{
_ped->TxNotify( EN_UPDATE, NULL );
}
// Now render
Render(rcView, rcRender);
// Update the cursor if we need to
if (_fUpdateCaret)
{
// The caret only belongs in an active view with
// a selection on a control that has the focus
if (IsActive() && (psel != NULL) && _ped->_fFocus)
{
// Update the caret if there is a selection object.
// Note: we only scroll the caret into view, if
// it was previously in the view. This avoids having
// window pop to caret if it is resized and the
// caret is not in the view.
psel->UpdateCaret(psel->IsCaretInView());
}
_fUpdateCaret = FALSE;
}
Cleanup:
if (hdcMeasure)
{
_ped->TxReleaseMeasureDC(hdcMeasure);
}
// Reset DC in device descriptor
ResetDC();
// Restore fonts to DCs
if (hFontDraw != NULL)
{
SelectObject(hdcDraw, hFontDraw);
}
return hr;
}
//==================================== View Recalc ===================================
/*
* CDisplay::UpdateViewRectState(prcClient)
*
* @mfunc Compares new view to cached and updates the view as well as the
* what type of view recalculation needs to occur.
*/
void CDisplay::UpdateViewRectState(
const RECT *prcClient) //@parm New client rectangle
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::UpdateViewRectState");
// Check whether the view rect has changed since last rendering
// If width has changed, need complete line recalc.
// If height has changed, recalc all visible and update scrollbars
if(prcClient->right - prcClient->left != _xWidthView)
{
_xWidthView = (SHORT)(prcClient->right - prcClient->left);
_fViewChanged = TRUE;
_fNeedRecalc = TRUE; // need full recalc
}
if(prcClient->bottom - prcClient->top != _yHeightView)
{
_yHeightView = prcClient->bottom - prcClient->top;
// The height can go negative when there is an inset and
// the client rect is very small. We just set it to 0 because
// that is the smallest the view can actually get.
if (_yHeightView < 0)
{
_yHeightView = 0;
}
_fViewChanged = TRUE;
}
}
/*
* CDisplay::ReDrawOnRectChange
*
* @mfunc Compares new view to cached and updates the display both
* internal and visible state appropriately.
*/
void CDisplay::ReDrawOnRectChange(
HDC hicTarget, //@param Target device
const RECT *prcClient) //@param New client rectangle
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::ReDrawOnRectChange");
_TEST_INVARIANT_
RECT rcView;
// Convert client rect to our view rect
GetViewRect(rcView, prcClient);
// Update the x and y coordinates of the view based on the client rect
UpdateViewRectState(&rcView);
if (_fNeedRecalc || _fViewChanged)
{
// The client rect changed in some way so lets update our client
// rect height for zoom.
_yHeightClient = prcClient->bottom - prcClient->top;
// Remeasure but don't update scroll bars now.
RecalcView(FALSE);
// Forms does not want the screen to reflect what the user clicked on
// or moved the cursor to so we oblige them by not updating the screen
// here but waiting for some future action to do so.
}
}
/*
* CDisplay::RecalcView(rcView)
*
* @mfunc
* RecalcView after the view rect changed
*
* @rdesc
* TRUE if success
*/
BOOL CDisplay::RecalcView (
const RECT &rcView)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::RecalcView");
_TEST_INVARIANT_
// Update the x and y coordinates of the view based on the client rect
UpdateViewRectState(&rcView);
// Ensure lines are recalced
if(_fNeedRecalc)
{
// Display got recalculated so the caret needs to be repositioned.
_fUpdateCaret = TRUE;
return RecalcView(TRUE);
}
if (_fViewChanged)
{
// The scroll bars are up to date so we can turn off the notification.
_fViewChanged = FALSE;
// A height change was noticed in UpdateViewRectState so make sure
// the horizontal scroll bar (if any is correct).
UpdateScrollBar(SB_HORZ);
}
return WaitForRecalcView();
}
//==================================== View Update ===================================
/*
* CDisplay::UpdateView()
*
* Purpose:
* Fully recalc all lines and update the visible part of the display
* (the "view") on the screen.
*
* Returns:
* TRUE if success
*/
BOOL CDisplay::UpdateView()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::UpdateView");
_TEST_INVARIANT_
BOOL fReturn = TRUE;
if(_fNoUpdateView)
return TRUE;
if(!_ped->_fInPlaceActive)
{
// If not active, just invalidate everything
InvalidateRecalc();
_ped->TxInvalidateRect(NULL, FALSE);
_ped->TxUpdateWindow();
return TRUE;
}
// If we get here, we are updating some general characteristic of the display
// and so we want the cursor updated as well as the general change otherwise
// the cursor will land up in the wrong place.
_fUpdateCaret = TRUE;
RECT rcView;
// Get the view rectangle
GetViewRect(rcView, NULL);
// Update the size of the view which could have changed
UpdateViewRectState(&rcView);
// From here on we better be in place
Assert(_ped->_fInPlaceActive);
if (!CDevDesc::IsValid())
{
// Make our device valid
SetDC(NULL);
}
// Recalc everything
#ifdef PWD_JUPITER
// GuyBark: Watch for RecalcView failing...
fReturn =
#endif // PWD_JUPITER
RecalcView(TRUE);
// invalidate entire view
_ped->TxInvalidateRect (NULL, FALSE);
_ped->TxUpdateWindow();
// Check if IME has hide the caret.
// FUTURE: (v-honwch) - This is a work around the problem that
// _fShowCaret is not being tested in CTxtSelection::Update()
// as it always displays the caret, messing up IME composition.
// It is an open issue as to whether Update should be paying
// attention to the _fShowCaret. It is far too dangerous to
// change this at this point in the release cycle, so we will
// examine this in the future.
{
if ( _ped->IsIMEComposition() )
{
CTxtSelection *psel;
psel = _ped->GetSel();
if ( psel && !psel->IsCaretShown() )
_ped->TxShowCaret(FALSE);
}
}
return fReturn;
}
/*
* CDisplay::RoundToLine(hdc, pheight)
*
* @mfunc
* Calculate number of default lines to fit in input height
*
* @rdesc
* S_OK - Call completed successfully <nl>
*/
HRESULT CDisplay::RoundToLine(
HDC hdc, //@parm DC for the window
LONG width, //@parm in - width of window; out max width
LONG *pheight) //@parm in - proposed height; out - actual
{
// Set the DC
SetDC(hdc);
// Set the height temporarily so the zoom factor will work out
LONG yOrigHeightClient = SetClientHeight((SHORT) *pheight);
// Use this to adjust for the inset height
LONG yAdjForInset = *pheight;
// Get the rectangle adjusted for insets
GetViewDim(width, *pheight);
// Save the proposed height
LONG yProposed = *pheight;
// Calc inset adjusted height
yAdjForInset -= yProposed;
// Get the font
const CCharFormat *pcf = _ped->GetCharFormat(-1);
if (NULL == pcf)
{
Assert(pcf);
return E_OUTOFMEMORY;
}
// Get the font cache object
CCcs *pccs = fc().GetCcs(hdc, pcf, GetZoomNumerator(),
GetZoomDenominator(), GetDeviceCaps(hdc, LOGPIXELSY));
// Get the height of the font
LONG yHeight = pccs->_yHeight;
// All we wanted is the height and we have got it so dump the
// font cache entry
pccs->Release();
// Figure out how many lines fit into the input height
LONG cLines = yProposed / yHeight;
// See if we need to round up
if ((yProposed % yHeight != 0) || (0 == cLines))
{
cLines++;
}
// Set the height to the new value
*pheight = yHeight * cLines + yAdjForInset;
// Set the client height back to what it was
SetClientHeight(yOrigHeightClient);
// Reset the DC
ResetDC();
return NOERROR;
}
//============================= Client and view rectangles ===========================
/*
* CDisplay::OnClientRectChange(&rcClient, &rcView)
*
* Purpose:
* Update when either the client rectangle changes
* >>> Should be called only when in-place active <<<
*
* Arguments:
* rcClient new client rectangle
*/
void CDisplay::OnClientRectChange(const RECT &rcClient)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::OnClientRectChange");
_TEST_INVARIANT_
RECT rcView;
AssertSz(_ped->_fInPlaceActive, "CDisplay::OnClientRectChange() called when not in-place active");
// Make sure our client rectangle is set correctly.
_yHeightClient = rcClient.bottom - rcClient.top;
// Use the view rect change notification
GetViewRect(rcView);
// Make sure that we will have a selection object at this point
_ped->GetSel();
// Update when the view rectangle changes
OnViewRectChange(rcView);
}
/*
* CDisplay::OnViewRectChange(&rcView)
*
* Purpose:
* Update when either the view rectangle changes
*
* Arguments:
* rcView new view rectangle, in:
* - log units (twips) rel. to top/left of client rect if not in-place
* - containing window client coords if in-place active
*/
VOID CDisplay::OnViewRectChange(const RECT &rcView)
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::OnViewRectChange");
_TEST_INVARIANT_
if(!_ped->_fInPlaceActive)
// We'll adjust the view rect during next Draw.
return;
CTxtSelection *psel = _ped->GetSelNC();
const BOOL fCaretShowing = psel ? psel->ShowCaret(FALSE) : FALSE;
const BOOL fCaretInView = fCaretShowing ? psel->IsCaretInView() : FALSE;
RECT rcV = rcView;
COleObject *pipo;
// Factor in selection bar space
rcV.left += GetSelBarInPixels();
// Recalc with new view rectangle
// ??? What if this fails ?
RecalcView(rcView);
// Repaint window before showing the caret
_ped->TxInvalidateRect(NULL, FALSE); // ??? for now, we could be smarter
_ped->TxUpdateWindow();
// Reposition the caret
if(fCaretShowing)
{
Assert(psel);
psel->ShowCaret(TRUE);
psel->UpdateCaret(fCaretInView);
}
// FUTURE: since we're now repositioning in place active
// objects every time we draw, this call seems to be
// superfluous (AndreiB)
// Tell object subsystem to reposition any in place objects
if( _ped->HasObjects() )
{
pipo = _ped->GetObjectMgr()->GetInPlaceActiveObject();
if (NULL != pipo)
{
pipo->OnReposition( 0, 0 );
}
}
}
/*
* CDisplay::RequestResize()
*
* Purpose:
* Forces the control to resize vertically so that all text fit into it
*/
HRESULT CDisplay::RequestResize()
{
TRACEBEGIN(TRCSUBSYSDISP, TRCSCOPEINTERN, "CDisplay::RequestResize");
_TEST_INVARIANT_
if (_ped->TxGetAutoSize())
{
REQRESIZE resize;
// if word wrapping is on, then the width is the normal
// client width. Otherwise, it's the width of the longest
// line plus the width of the caret.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -