/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
void ImpEditView::SetEditSelection( const EditSelection& rEditSelection )
{ // set state before notification
maEditSelection = rEditSelection;
SelectionChanged();
if (comphelper::LibreOfficeKit::isActive())
{ // Tiled rendering: selections are only painted when we are in selection mode.
getEditEngine().SetInSelectionMode(maEditSelection.HasRange());
}
if (getImpEditEngine().IsFormatted())
{
EENotify aNotify(EE_NOTIFY_PROCESSNOTIFICATIONS);
getImpEditEngine().GetNotifyHdl().Call(aNotify);
}
}
/// Translate absolute <-> relative twips: LOK wants absolute coordinates as output and gives absolute coordinates as input. staticvoid lcl_translateTwips(const OutputDevice& rParent, OutputDevice& rChild)
{ // Don't translate if we already have a non-zero origin. // This prevents multiple translate calls that negate // one another. const Point aOrigin = rChild.GetMapMode().GetOrigin(); if (aOrigin.getX() != 0 || aOrigin.getY() != 0) return;
// Set map mode, so that callback payloads will contain absolute coordinates instead of relative ones.
Point aOffset(rChild.GetOutOffXPixel() - rParent.GetOutOffXPixel(), rChild.GetOutOffYPixel() - rParent.GetOutOffYPixel()); if (!rChild.IsMapModeEnabled())
{
MapMode aMapMode(rChild.GetMapMode());
aMapMode.SetMapUnit(MapUnit::MapTwip);
aMapMode.SetScaleX(rParent.GetMapMode().GetScaleX());
aMapMode.SetScaleY(rParent.GetMapMode().GetScaleY());
rChild.SetMapMode(aMapMode);
rChild.EnableMapMode();
}
aOffset = rChild.PixelToLogic(aOffset);
MapMode aMapMode(rChild.GetMapMode());
aMapMode.SetOrigin(aOffset);
aMapMode.SetMapUnit(rParent.GetMapMode().GetMapUnit());
rChild.SetMapMode(aMapMode);
rChild.EnableMapMode(false);
}
// EditView never had a central/secure place to react on SelectionChange since // Selection was changed in many places, often by not using SetEditSelection() // but (mis)using GetEditSelection() and manipulating this non-const return // value. Sorted this out now to have such a place, this is needed for safely // change/update the Selection visualization for enhanced mechanisms void ImpEditView::SelectionChanged()
{ if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
{ // use callback to tell about change in selection visualisation
pCallbacks->EditViewSelectionChange();
}
}
// This function is also called when a text's font || size is changed. Because its highlight rectangle must be updated. void ImpEditView::lokSelectionCallback(const std::optional<tools::PolyPolygon> &pPolyPoly, bool bStartHandleVisible, bool bEndHandleVisible) {
VclPtr<vcl::Window> pParent = mpOutputWindow->GetParentWithLOKNotifier();
vcl::Region aRegion( *pPolyPoly );
const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
std::vector<vcl::LOKPayloadItem> aItems;
aItems.emplace_back("rectangles", sRectangle);
aItems.emplace_back("startHandleVisible", OString::boolean(bStartHandleVisible));
aItems.emplace_back("endHandleVisible", OString::boolean(bEndHandleVisible));
pNotifier->notifyWindow(pParent->GetLOKWindowId(), u"text_selection"_ustr, aItems);
} elseif (mpViewShell)
{
mpOutputWindow->GetOutDev()->Push(vcl::PushFlags::MAPMODE); if (mpOutputWindow->GetMapMode().GetMapUnit() == MapUnit::MapTwip)
{ // Find the parent that is not right // on top of us to use its offset.
vcl::Window* parent = mpOutputWindow->GetParent(); while (parent &&
parent->GetOutOffXPixel() == mpOutputWindow->GetOutOffXPixel() &&
parent->GetOutOffYPixel() == mpOutputWindow->GetOutOffYPixel())
{
parent = parent->GetParent();
}
if (parent)
{
lcl_translateTwips(*parent->GetOutDev(), *mpOutputWindow->GetOutDev());
}
}
Point aOrigin; if (mpOutputWindow->GetMapMode().GetMapUnit() == MapUnit::MapTwip) // Writer comments: they use editeng, but are separate widgets.
aOrigin = mpOutputWindow->GetMapMode().GetOrigin();
OString sRectangle;
OString sRefPoint; if (mpLOKSpecialPositioning)
sRefPoint = mpLOKSpecialPositioning->GetRefPoint().toString();
if (mpOtherShell)
{ // Another shell wants to know about our existing selection. if (mpViewShell != mpOtherShell)
mpViewShell->NotifyOtherView(mpOtherShell, LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection"_ostr, sRectangle);
} else
{
mpViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_TEXT_SELECTION, sRectangle);
mpViewShell->NotifyOtherViews(LOK_CALLBACK_TEXT_VIEW_SELECTION, "selection"_ostr, sRectangle);
}
mpOutputWindow->GetOutDev()->Pop();
}
}
// renamed from DrawSelection to DrawSelectionXOR to better reflect what this // method was used for: Paint Selection in XOR, change it and again paint it in XOR. // This can be safely assumed due to the EditView only being capable of painting the // selection in XOR until today. // This also means that all places calling DrawSelectionXOR are thoroughly weighted // and chosen to make this fragile XOR-paint water-proof and thus contain some // information in this sense. // Someone thankfully expanded it to collect the SelectionRectangles when called with // the Region*, see GetSelectionRectangles below. void ImpEditView::DrawSelectionXOR( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
{ if (getEditViewCallbacks() && !pRegion && !comphelper::LibreOfficeKit::isActive())
{ // we are done, do *not* visualize self // CAUTION: do not use when comphelper::LibreOfficeKit::isActive() // due to event stuff triggered below. That *should* probably be moved // to SelectionChanged() which exists now, but I do not know enough about // that stuff to do it return;
}
if (meSelectionMode == EESelectionMode::Hidden) return;
// It must be ensured before rendering the selection, that the contents of // the window is completely valid! Must be here so that in any case if // empty, then later on two-Paint Events! Must be done even before the // query from bUpdate, if after Invalidate paints still in the queue, // but someone switches the update mode!
// pRegion: When not NULL, then only calculate Region.
if ( !pRegion && !comphelper::LibreOfficeKit::isActive())
{ if (!getImpEditEngine().IsUpdateLayout()) return; if (getImpEditEngine().IsInUndo()) return;
if ( !aTmpSel.HasRange() ) return;
// aTmpOutArea: if OutputArea > Paper width and // Text > Paper width ( over large fields )
tools::Rectangle aTmpOutArea(maOutputArea); if ( aTmpOutArea.GetWidth() > getImpEditEngine().GetPaperSize().Width() )
aTmpOutArea.SetRight( aTmpOutArea.Left() + getImpEditEngine().GetPaperSize().Width() );
rTarget.IntersectClipRegion( aTmpOutArea );
if (mpOutputWindow && mpOutputWindow->GetCursor())
mpOutputWindow->GetCursor()->Hide();
}
if (comphelper::LibreOfficeKit::isActive() || pRegion)
pPolyPoly = tools::PolyPolygon();
DBG_ASSERT(!getEditEngine().IsIdleFormatterActive(), "DrawSelectionXOR: Not formatted!");
aTmpSel.Adjust(getEditEngine().GetEditDoc());
auto DrawHighlight = [&, nStartLine = sal_Int32(0), nEndLine = sal_Int32(0)]( const ImpEditEngine::LineAreaInfo& rInfo) mutable { if (!rInfo.pLine) // Begin of ParaPortion
{ if (rInfo.nPortion < nStartPara) return ImpEditEngine::CallbackResult::SkipThisPortion; if (rInfo.nPortion > nEndPara) return ImpEditEngine::CallbackResult::Stop;
DBG_ASSERT(!rInfo.rPortion.IsInvalid(), "Portion in Selection not formatted!"); if (rInfo.rPortion.IsInvalid()) return ImpEditEngine::CallbackResult::SkipThisPortion;
// Now that we have Bidi, the first/last index doesn't have to be the 'most outside' position if (!bPartOfLine)
{
Range aLineXPosStartEnd = getEditEngine().GetLineXPosStartEnd(rInfo.rPortion, *rInfo.pLine);
aTmpRect.SetLeft(aLineXPosStartEnd.Min());
aTmpRect.SetRight(aLineXPosStartEnd.Max());
aTmpRect.Move(aLineOffset.Width(), 0);
ImplDrawHighlightRect(rTarget, aTmpRect.TopLeft(), aTmpRect.BottomRight(),
pPolyPoly ? &*pPolyPoly : nullptr, bLOKCalcRTL);
} else
{
sal_Int32 nTmpStartIndex = nStartIndex;
sal_Int32 nWritingDirStart, nTmpEndIndex;
while (nTmpStartIndex < nEndIndex)
{
getImpEditEngine().GetRightToLeft(rInfo.nPortion, nTmpStartIndex + 1,
&nWritingDirStart, &nTmpEndIndex); if (nTmpEndIndex > nEndIndex)
nTmpEndIndex = nEndIndex;
void ImpEditView::SetOutputArea( const tools::Rectangle& rRect )
{ // Here a PixelSnap was used before using GetOutputDevice() and // LogicToPixel/PixelToLogic (what was incorrect, would need // to take care of 1/2 pixel in logic for rounding). We do not // need that anymore, in fact it leads to text slightly // 'jumping' around by up to 1 pixel (of course). // We paint text nowadays using decomposed TextPrimitives // with sub-pixel precision and similar (using a shortcut) // for text in TextEdit on the Overlay, also using sub-pixel // precision. Just remove this to avoid Text being displayed // different in TextEdit and EditView paint visualizations // and assign given value to OutputArea unchanged.
maOutputArea = rRect;
if (!maOutputArea.IsWidthEmpty() && maOutputArea.Right() < maOutputArea.Left())
maOutputArea.SetRight(maOutputArea.Left()); if (!maOutputArea.IsHeightEmpty() && maOutputArea.Bottom() < maOutputArea.Top())
maOutputArea.SetBottom(maOutputArea.Top());
void ImpEditView::InvalidateAtWindow(const tools::Rectangle& rRect)
{ if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
{ // do not invalidate and trigger a global repaint, but forward // the need for change to the applied EditViewCallback, can e.g. // be used to visualize the active edit text in an OverlayObject
pCallbacks->EditViewInvalidate(mbNegativeX ? lcl_negateRectX(rRect) : rRect);
} else
{ // classic mode: invalidate and trigger full repaint // of the changed area
GetWindow()->Invalidate(mbNegativeX ? lcl_negateRectX(rRect) : rRect);
}
}
void ImpEditView::ResetOutputArea( const tools::Rectangle& rRect )
{ // remember old out area const tools::Rectangle aOldArea(maOutputArea);
// apply new one
SetOutputArea(rRect);
// invalidate surrounding areas if update is true if(aOldArea.IsEmpty() || !getImpEditEngine().IsUpdateLayout()) return;
// #i119885# use grown area if needed; do when getting bigger OR smaller const sal_Int32 nMore(DoInvalidateMore() ? GetOutputDevice().PixelToLogic(Size(mnInvalidateMore, 0)).Width() : 0);
void ImpEditView::RecalcOutputArea()
{
Point aNewTopLeft(maOutputArea.TopLeft());
Size aNewSz(maOutputArea.GetSize());
// X: if ( DoAutoWidth() )
{ if (getImpEditEngine().GetStatus().AutoPageWidth())
aNewSz.setWidth(getImpEditEngine().GetPaperSize().Width()); switch (meAnchorMode)
{ case EEAnchorMode::TopLeft: case EEAnchorMode::VCenterLeft: case EEAnchorMode::BottomLeft:
{
aNewTopLeft.setX(maAnchorPoint.X());
} break; case EEAnchorMode::TopHCenter: case EEAnchorMode::VCenterHCenter: case EEAnchorMode::BottomHCenter:
{
aNewTopLeft.setX(maAnchorPoint.X() - aNewSz.Width() / 2);
} break; case EEAnchorMode::TopRight: case EEAnchorMode::VCenterRight: case EEAnchorMode::BottomRight:
{
aNewTopLeft.setX(maAnchorPoint.X() - aNewSz.Width() - 1);
} break;
}
}
// Y: if ( DoAutoHeight() )
{ if (getImpEditEngine().GetStatus().AutoPageHeight())
aNewSz.setHeight(getImpEditEngine().GetPaperSize().Height()); switch (meAnchorMode)
{ case EEAnchorMode::TopLeft: case EEAnchorMode::TopHCenter: case EEAnchorMode::TopRight:
{
aNewTopLeft.setY(maAnchorPoint.Y());
} break; case EEAnchorMode::VCenterLeft: case EEAnchorMode::VCenterHCenter: case EEAnchorMode::VCenterRight:
{
aNewTopLeft.setY(maAnchorPoint.Y() - aNewSz.Height() / 2);
} break; case EEAnchorMode::BottomLeft: case EEAnchorMode::BottomHCenter: case EEAnchorMode::BottomRight:
{
aNewTopLeft.setY(maAnchorPoint.Y() - aNewSz.Height() - 1);
} break;
}
}
ResetOutputArea( tools::Rectangle( aNewTopLeft, aNewSz ) );
}
void ImpEditView::CalcAnchorPoint()
{ // GetHeight() and GetWidth() -1, because rectangle calculation not preferred.
// X: switch (meAnchorMode)
{ case EEAnchorMode::TopLeft: case EEAnchorMode::VCenterLeft: case EEAnchorMode::BottomLeft:
{
maAnchorPoint.setX(maOutputArea.Left());
} break; case EEAnchorMode::TopHCenter: case EEAnchorMode::VCenterHCenter: case EEAnchorMode::BottomHCenter:
{
maAnchorPoint.setX(maOutputArea.Left() + (maOutputArea.GetWidth() - 1) / 2);
} break; case EEAnchorMode::TopRight: case EEAnchorMode::VCenterRight: case EEAnchorMode::BottomRight:
{
maAnchorPoint.setX(maOutputArea.Right());
} break;
}
// Y: switch (meAnchorMode)
{ case EEAnchorMode::TopLeft: case EEAnchorMode::TopHCenter: case EEAnchorMode::TopRight:
{
maAnchorPoint.setY(maOutputArea.Top());
} break; case EEAnchorMode::VCenterLeft: case EEAnchorMode::VCenterHCenter: case EEAnchorMode::VCenterRight:
{
maAnchorPoint.setY(maOutputArea.Top() + (maOutputArea.GetHeight() - 1) / 2);
} break; case EEAnchorMode::BottomLeft: case EEAnchorMode::BottomHCenter: case EEAnchorMode::BottomRight:
{
maAnchorPoint.setY(maOutputArea.Bottom() - 1);
} break;
}
}
namespace
{
// For building JSON message to be sent to Online
boost::property_tree::ptree getHyperlinkPropTree(const OUString& sText, const OUString& sLink)
{
boost::property_tree::ptree aTree;
aTree.put("text", sText);
aTree.put("link", sLink); return aTree;
}
} // End of anon namespace
tools::Rectangle ImpEditView::ImplGetEditCursor(EditPaM const& aPaM,
CursorFlags const aShowCursorFlags, sal_Int32& nTextPortionStart,
ParaPortion const& rParaPortion) const
{
tools::Rectangle aEditCursor = getImpEditEngine().PaMtoEditCursor(aPaM, aShowCursorFlags); if (!IsInsertMode() && !maEditSelection.HasRange())
{ if ( aPaM.GetNode()->Len() && ( aPaM.GetIndex() < aPaM.GetNode()->Len() ) )
{ // If we are behind a portion, and the next portion has other direction, we must change position...
aEditCursor.SetLeft(getImpEditEngine().PaMtoEditCursor(aPaM, CursorFlags{.bTextOnly = true, .bPreferPortionStart = true}).Left());
aEditCursor.SetRight( aEditCursor.Left() );
if ( aEditCursor.Right() > aTmpVisArea.Right() )
{ // Scroll left, positive
nDocDiffX = aEditCursor.Right() - aTmpVisArea.Right(); // Can it be a little more? if ( aEditCursor.Right() < ( nMaxTextWidth - GetScrollDiffX() ) )
nDocDiffX += GetScrollDiffX(); else
{
tools::Long n = nMaxTextWidth - aEditCursor.Right(); // If MapMode != RefMapMode then the EditCursor can go beyond // the paper width!
nDocDiffX += ( n > 0 ? n : -n );
}
} elseif ( aEditCursor.Left() < aTmpVisArea.Left() )
{ // Scroll right, negative:
nDocDiffX = aEditCursor.Left() - aTmpVisArea.Left(); // Can it be a little more? if ( aEditCursor.Left() > ( - static_cast<tools::Long>(GetScrollDiffX()) ) )
nDocDiffX -= GetScrollDiffX(); else
nDocDiffX -= aEditCursor.Left();
} if (rPos.GetIndex() == 0) // needed for the Outliner
{ // But make sure that the cursor is not leaving visible area // because of this! if ( aEditCursor.Left() < aTmpVisArea.GetWidth() )
{
nDocDiffX = -aTmpVisArea.Left();
}
}
if ( ( aEditCursor.Top() + nOnePixel >= GetVisDocTop() ) &&
( aEditCursor.Bottom() - nOnePixel <= GetVisDocBottom() ) &&
( aEditCursor.Left() + nOnePixel >= GetVisDocLeft() ) &&
( aEditCursor.Right() - nOnePixel <= GetVisDocRight() ) )
{
tools::Rectangle aCursorRect = GetWindowPos( aEditCursor );
Size aCursorSz( aCursorRect.GetSize() ); // Rectangle is inclusive
aCursorSz.AdjustWidth( -1 );
aCursorSz.AdjustHeight( -1 ); if ( !aCursorSz.Width() || !aCursorSz.Height() )
{
tools::Long nCursorSz = rOutDev.GetSettings().GetStyleSettings().GetCursorSize();
nCursorSz = rOutDev.PixelToLogic( Size( nCursorSz, 0 ) ).Width(); if ( !aCursorSz.Width() )
aCursorSz.setWidth( nCursorSz ); if ( !aCursorSz.Height() )
aCursorSz.setHeight( nCursorSz );
} // #111036# Let VCL do orientation for cursor, otherwise problem when cursor has direction flag if ( IsVertical() )
{
Size aOldSz( aCursorSz );
aCursorSz.setWidth( aOldSz.Height() );
aCursorSz.setHeight( aOldSz.Width() ); // tdf#166602 the size is relative to the top right
aCursorRect.AdjustLeft(aCursorRect.GetWidth() - aCursorSz.Width());
}
aCursorRect.SetSize(aCursorSz); return {{aCursorRect, aEditCursor, aShowCursorFlags, nTextPortionStart}};
}
return {};
}
void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor )
{ // No ShowCursor in an empty View ... if (maOutputArea.IsEmpty()) return; if ( (maOutputArea.Left() >= maOutputArea.Right() ) && ( maOutputArea.Top() >= maOutputArea.Bottom() ) ) return;
getEditEngine().CheckIdleFormatter();
// For some reasons I end up here during the formatting, if the Outliner // is initialized in Paint, because no SetPool(); if (getImpEditEngine().IsFormatting()) return; if (!getImpEditEngine().IsUpdateLayout()) return; if (getImpEditEngine().IsInUndo()) return;
if (mpOutputWindow && mpOutputWindow->GetCursor() != GetCursor())
mpOutputWindow->SetCursor(GetCursor());
autoconst oCursor{ImplGetCursorRectAndMaybeScroll(aPaM, rParaPortion, bGotoCursor)}; if (oCursor)
{ autoconst [aCursorRect, aEditCursor, aShowCursorFlags, nTmp]{*oCursor}; auto nTextPortionStart{nTmp}; // this one can't be const
GetCursor()->SetPos( aCursorRect.TopLeft() );
Size aCursorSz( aCursorRect.GetSize() ); // #111036# Let VCL do orientation for cursor, otherwise problem when cursor has direction flag if ( IsVertical() )
{
GetCursor()->SetPos( aCursorRect.TopRight() );
GetCursor()->SetOrientation( Degree10(IsTopToBottom() ? 2700 : 900) );
} else // #i32593# Reset correct orientation in horizontal layout
GetCursor()->SetOrientation();
GetCursor()->SetSize( aCursorSz );
if (comphelper::LibreOfficeKit::isActive() && mpViewShell && !mbSuppressLOKMessages)
{
Point aPos = GetCursor()->GetPos();
boost::property_tree::ptree aMessageParams; const OutputDevice& rOutDev = GetOutputDevice(); if (mpLOKSpecialPositioning)
{ // Sending the absolute (pure) logical coordinates of the cursor to the client is not // enough for it to accurately reconstruct the corresponding tile-twips coordinates of the cursor. // This is because the editeng(doc) positioning is not pixel aligned for each cell involved in the output-area // (it better not be!). A simple solution is to send the coordinates of a point ('refpoint') in the output-area // along with the relative position of the cursor w.r.t this chosen 'refpoint'.
MapUnit eDevUnit = rOutDev.GetMapMode().GetMapUnit();
tools::Rectangle aCursorRectPureLogical(aEditCursor.TopLeft(), GetCursor()->GetSize()); // Get rectangle in window-coordinates from editeng(doc) coordinates in hmm.
aCursorRectPureLogical = GetWindowPos(aCursorRectPureLogical);
Point aRefPointLogical = GetOutputArea().TopLeft(); // Get the relative coordinates w.r.t refpoint in display hmm.
aCursorRectPureLogical.Move(-aRefPointLogical.X(), -aRefPointLogical.Y()); if (getEditEngine().IsRightToLeft(nPara) || mpLOKSpecialPositioning->IsLayoutRTL())
{
tools::Long nMirrorW = GetOutputArea().GetWidth();
tools::Long nLeft = aCursorRectPureLogical.Left(), nRight = aCursorRectPureLogical.Right();
aCursorRectPureLogical.SetLeft(nMirrorW - nRight);
aCursorRectPureLogical.SetRight(nMirrorW - nLeft);
} // Convert to twips.
aCursorRectPureLogical = OutputDevice::LogicToLogic(aCursorRectPureLogical, MapMode(eDevUnit), MapMode(MapUnit::MapTwip)); // "refpoint" in print twips. const Point aRefPoint = mpLOKSpecialPositioning->GetRefPoint();
aMessageParams.put("relrect", aCursorRectPureLogical.toString());
aMessageParams.put("refpoint", aRefPoint.toString());
}
if (mpOutputWindow && mpOutputWindow->IsChart())
{ const vcl::Window* pViewShellWindow = mpViewShell->GetEditWindowForActiveOLEObj(); if (pViewShellWindow && pViewShellWindow->IsAncestorOf(*mpOutputWindow))
{
Point aOffsetPx = mpOutputWindow->GetOffsetPixelFrom(*pViewShellWindow);
Point aLogicOffset = mpOutputWindow->PixelToLogic(aOffsetPx);
aPos.Move(aLogicOffset.getX(), aLogicOffset.getY());
}
}
// LOK output is always in twips, convert from mm100 if necessary. if (rOutDev.GetMapMode().GetMapUnit() == MapUnit::Map100thMM)
{
aRect = o3tl::convert(aRect, o3tl::Length::mm100, o3tl::Length::twip);
} elseif (rOutDev.GetMapMode().GetMapUnit() == MapUnit::MapTwip)
{ // Writer comments: they use editeng, but are separate widgets.
Point aOrigin = rOutDev.GetMapMode().GetOrigin(); // Move the rectangle, so that we output absolute twips.
aRect.Move(aOrigin.getX(), aOrigin.getY());
} // Let the LOK client decide the cursor width.
aRect.setWidth(0);
// call this so users of EditViewCallbacks can update their scrollbar state // so called when we have either scrolled to a new location // or the size of document has changed void ImpEditView::ScrollStateChange()
{ if (EditViewCallbacks* pCallbacks = getEditViewCallbacks())
pCallbacks->EditViewScrollStateChange();
}
#ifdef DBG_UTIL
tools::Rectangle aR(maOutputArea);
aR = rOutDev.LogicToPixel( aR );
aR = rOutDev.PixelToLogic( aR );
SAL_WARN_IF(aR != maOutputArea, "editeng", "OutArea before Scroll not aligned"); #endif
tools::Rectangle aNewVisArea( GetVisDocArea() );
// Vertical: if ( !IsVertical() )
{
aNewVisArea.AdjustTop( -ndY );
aNewVisArea.AdjustBottom( -ndY );
} else
{ if( IsTopToBottom() )
{
aNewVisArea.AdjustTop(ndX );
aNewVisArea.AdjustBottom(ndX );
} else
{
aNewVisArea.AdjustTop( -ndX );
aNewVisArea.AdjustBottom( -ndX );
}
} if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Bottom() > static_cast<tools::Long>(getImpEditEngine().GetTextHeight()) ) )
{ // GetTextHeight still optimizing!
tools::Long nDiff = getImpEditEngine().GetTextHeight() - aNewVisArea.Bottom(); // negative
aNewVisArea.Move( 0, nDiff ); // could end up in the negative area...
} if ( aNewVisArea.Top() < 0 )
aNewVisArea.Move( 0, -aNewVisArea.Top() );
// Horizontal: if ( !IsVertical() )
{
aNewVisArea.AdjustLeft( -ndX );
aNewVisArea.AdjustRight( -ndX );
} else
{ if (IsTopToBottom())
{
aNewVisArea.AdjustLeft( -ndY );
aNewVisArea.AdjustRight( -ndY );
} else
{
aNewVisArea.AdjustLeft(ndY );
aNewVisArea.AdjustRight(ndY );
}
} if ( ( nRangeCheck == ScrollRangeCheck::PaperWidthTextSize ) && ( aNewVisArea.Right() > static_cast<tools::Long>(getImpEditEngine().CalcTextWidth( false )) ) )
{
tools::Long nDiff = getImpEditEngine().CalcTextWidth( false ) - aNewVisArea.Right(); // negative
aNewVisArea.Move( nDiff, 0 ); // could end up in the negative area...
} if ( aNewVisArea.Left() < 0 )
aNewVisArea.Move( -aNewVisArea.Left(), 0 );
if ( nRealDiffX || nRealDiffY )
{
vcl::Cursor* pCrsr = GetCursor(); bool bVisCursor = pCrsr->IsVisible();
pCrsr->Hide(); if (mpOutputWindow)
mpOutputWindow->PaintImmediately(); if (!IsVertical())
maVisDocStartPos.Move(-nRealDiffX, -nRealDiffY); else
{ if (IsTopToBottom())
maVisDocStartPos.Move(-nRealDiffY, nRealDiffX); else
maVisDocStartPos.Move(nRealDiffY, -nRealDiffX);
} // Move by aligned value does not necessarily result in aligned // rectangle ...
maVisDocStartPos = rOutDev.LogicToPixel(maVisDocStartPos);
maVisDocStartPos = rOutDev.PixelToLogic(maVisDocStartPos);
tools::Rectangle aRect(maOutputArea);
if (mpOutputWindow)
{
mpOutputWindow->Scroll( nRealDiffX, nRealDiffY, aRect, ScrollFlags::Clip );
}
if (comphelper::LibreOfficeKit::isActive() || getEditViewCallbacks())
{ // Need to invalidate the window, otherwise no tile will be re-painted.
GetEditViewPtr()->Invalidate();
}
if (mpOutputWindow)
mpOutputWindow->PaintImmediately();
pCrsr->SetPos( pCrsr->GetPos() + Point( nRealDiffX, nRealDiffY ) ); if ( bVisCursor )
{
tools::Rectangle aCursorRect( pCrsr->GetPos(), pCrsr->GetSize() ); if (maOutputArea.Contains(aCursorRect))
pCrsr->Show();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.