summaryrefslogtreecommitdiff
path: root/editeng
diff options
context:
space:
mode:
authorArmin Le Grand <Armin.Le.Grand@cib.de>2017-08-04 18:56:43 +0200
committerArmin Le Grand <Armin.Le.Grand@cib.de>2017-08-10 15:17:58 +0200
commitf06b48a5dddab20fd1bbf9b5f3e8543593f5e590 (patch)
treece3bb9e57cdb21a8414a49bf919b1c442d2687ea /editeng
parent2ae717f2d722d78b29b51dc40194b64ab3bb5bc8 (diff)
editviewoverlay: Allow EditView to run in Overlay
This is the first basic functionality to get the active EditView with EditEngine work in the Overlay which all Apps support. Reason is that the current EditEngine 'plugs' into the Window and uses Invalidate() calls to repaint deeply everything under a text change. While this is acceptable for simple cases it can get very slow when there are excessive, expensive to paint objects in the background, e.g. MasterPages in Draw/Impress with gradients and other stuff. This was avoided in older versions (LO51) by 'guessing' a good BackgrundColor by the EditEngine, not invalidating but painting actively using that guess (with better or worse results) which someone removed. For the future it is anyways the better way to get the EditEngine functionality to Overlay and using Primitives, this will be a first step. This may enable Text Editing without repainting the Background (fast), using a non-XOR selection paint and more. It will need thorough testing and further experimenting due to EditEngine being used in many places (DrawObjects, Calc Cells, Formular Fields, Controls, ...) Change-Id: Ib9eb0f3999fd61a82ddf7a60ab1ea6ccda3a60da
Diffstat (limited to 'editeng')
-rw-r--r--editeng/source/editeng/editview.cxx33
-rw-r--r--editeng/source/editeng/impedit.cxx82
-rw-r--r--editeng/source/editeng/impedit.hxx21
-rw-r--r--editeng/source/editeng/impedit3.cxx5
4 files changed, 124 insertions, 17 deletions
diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx
index 4bcc257fc0e4..db7ff1951767 100644
--- a/editeng/source/editeng/editview.cxx
+++ b/editeng/source/editeng/editview.cxx
@@ -153,8 +153,12 @@ LanguageType EditView::CheckLanguage(
return nLang;
}
-// class EditView
+// class EditViewCallbacks
+EditViewCallbacks::~EditViewCallbacks()
+{
+}
+// class EditView
EditView::EditView( EditEngine* pEng, vcl::Window* pWindow )
{
pImpEditView.reset( new ImpEditView( this, pEng, pWindow ) );
@@ -164,6 +168,16 @@ EditView::~EditView()
{
}
+void EditView::setEditViewCallbacks(const EditViewCallbacks* pEditViewCallbacks)
+{
+ pImpEditView->setEditViewCallbacks(pEditViewCallbacks);
+}
+
+bool EditView::hasEditViewCallbacks() const
+{
+ return pImpEditView->hasEditViewCallbacks();
+}
+
ImpEditEngine* EditView::GetImpEditEngine() const
{
return pImpEditView->pEditEngine->pImpEditEngine.get();
@@ -190,6 +204,23 @@ tools::Rectangle EditView::GetInvalidateRect() const
}
}
+void EditView::InvalidateWindow(const tools::Rectangle& rClipRect)
+{
+ if (pImpEditView->hasEditViewCallbacks())
+ {
+ // 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
+ pImpEditView->mpEditViewCallbacks->EditViewInvalidate();
+ }
+ else
+ {
+ // classic mode: invalidate and trigger full repaint
+ // of the changed area
+ GetWindow()->Invalidate(rClipRect);
+ }
+}
+
void EditView::InvalidateOtherViewWindows( const tools::Rectangle& rInvRect )
{
if (comphelper::LibreOfficeKit::isActive())
diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx
index 22efd056dbee..fc8ee6745a3a 100644
--- a/editeng/source/editeng/impedit.cxx
+++ b/editeng/source/editeng/impedit.cxx
@@ -83,6 +83,7 @@ ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindo
bClickedInSelection = false;
eSelectionMode = EESelectionMode::TxtOnly;
eAnchorMode = EEAnchorMode::TopLeft;
+ mpEditViewCallbacks = nullptr;
nInvMore = 1;
nTravelXPos = TRAVEL_X_DONTKNOW;
nControl = EVControlBits::AUTOSCROLL | EVControlBits::ENABLEPASTE;
@@ -185,6 +186,35 @@ void lcl_translateTwips(vcl::Window const & rParent, vcl::Window& rChild)
void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, OutputDevice* pTargetDevice )
{
+ if (hasEditViewCallbacks() && !pRegion)
+ {
+ // when we have an own mechanism for painting EditViews, collect the Selection
+ // in a basegfx::B2DRange vector and hand over. To do so, call GetSelectionRectangles
+ // which recursively calls ImpEditView::DrawSelection, but with nullptr != pRegion
+ std::vector<tools::Rectangle> aLogicRects;
+ std::vector<basegfx::B2DRange> aLogicRanges;
+ OutputDevice* pTarget = pTargetDevice ? pTargetDevice : pOutWin;
+ const Point aPixel(pTarget ? pTarget->LogicToPixel(Point(1, 1)) : Point(1, 1));
+
+ GetSelectionRectangles(aLogicRects);
+
+ for (const auto& aRect : aLogicRects)
+ {
+ // convert from logic Rectangles to logic Ranges, do not forget to add
+ // one Unit (in this case logical unit, thus calculate first)
+ aLogicRanges.push_back(
+ basegfx::B2DRange(
+ aRect.Left(), aRect.Top(),
+ aRect.Right() + aPixel.X(), aRect.Bottom() + aPixel.Y()));
+ }
+
+ // use callback to tell about change in selection visualisation
+ mpEditViewCallbacks->EditViewSelectionChange(aLogicRanges);
+
+ // we are done, do *not* visualize self
+ return;
+ }
+
if ( eSelectionMode == EESelectionMode::Hidden )
return;
@@ -449,16 +479,9 @@ void ImpEditView::DrawSelection( EditSelection aTmpSel, vcl::Region* pRegion, Ou
void ImpEditView::GetSelectionRectangles(std::vector<tools::Rectangle>& rLogicRects)
{
- bool bMm100ToTwip = pOutWin->GetMapMode().GetMapUnit() == MapUnit::Map100thMM;
vcl::Region aRegion;
DrawSelection(aEditSelection, &aRegion);
aRegion.GetRegionRectangles(rLogicRects);
-
- for (tools::Rectangle& rRectangle : rLogicRects)
- {
- if (bMm100ToTwip)
- rRectangle = OutputDevice::LogicToLogic(rRectangle, MapUnit::Map100thMM, MapUnit::MapTwip);
- }
}
void ImpEditView::ImplDrawHighlightRect( OutputDevice* _pTarget, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, tools::PolyPolygon* pPolyPoly )
@@ -627,6 +650,23 @@ void ImpEditView::SetOutputArea( const tools::Rectangle& rRect )
SetScrollDiffX( (sal_uInt16)aOutArea.GetWidth() * 2 / 10 );
}
+void ImpEditView::InvalidateAtWindow(const tools::Rectangle& rRect)
+{
+ if (hasEditViewCallbacks())
+ {
+ // 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
+ mpEditViewCallbacks->EditViewInvalidate();
+ }
+ else
+ {
+ // classic mode: invalidate and trigger full repaint
+ // of the changed area
+ GetWindow()->Invalidate(rRect);
+ }
+}
+
void ImpEditView::ResetOutputArea( const tools::Rectangle& rRect )
{
// remember old out area
@@ -643,38 +683,46 @@ void ImpEditView::ResetOutputArea( const tools::Rectangle& rRect )
if(aOldArea.Left() > aOutArea.Left())
{
- GetWindow()->Invalidate(tools::Rectangle(aOutArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Left(), aOldArea.Bottom() + nMore));
+ const tools::Rectangle aRect(aOutArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Left(), aOldArea.Bottom() + nMore);
+ InvalidateAtWindow(aRect);
}
else if(aOldArea.Left() < aOutArea.Left())
{
- GetWindow()->Invalidate(tools::Rectangle(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOutArea.Left(), aOldArea.Bottom() + nMore));
+ const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOutArea.Left(), aOldArea.Bottom() + nMore);
+ InvalidateAtWindow(aRect);
}
if(aOldArea.Right() > aOutArea.Right())
{
- GetWindow()->Invalidate(tools::Rectangle(aOutArea.Right(), aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Bottom() + nMore));
+ const tools::Rectangle aRect(aOutArea.Right(), aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
+ InvalidateAtWindow(aRect);
}
else if(aOldArea.Right() < aOutArea.Right())
{
- GetWindow()->Invalidate(tools::Rectangle(aOldArea.Right(), aOldArea.Top() - nMore, aOutArea.Right() + nMore, aOldArea.Bottom() + nMore));
+ const tools::Rectangle aRect(aOldArea.Right(), aOldArea.Top() - nMore, aOutArea.Right() + nMore, aOldArea.Bottom() + nMore);
+ InvalidateAtWindow(aRect);
}
if(aOldArea.Top() > aOutArea.Top())
{
- GetWindow()->Invalidate(tools::Rectangle(aOldArea.Left() - nMore, aOutArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Top()));
+ const tools::Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Top() - nMore, aOldArea.Right() + nMore, aOldArea.Top());
+ InvalidateAtWindow(aRect);
}
else if(aOldArea.Top() < aOutArea.Top())
{
- GetWindow()->Invalidate(tools::Rectangle(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOutArea.Top()));
+ const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Top() - nMore, aOldArea.Right() + nMore, aOutArea.Top());
+ InvalidateAtWindow(aRect);
}
if(aOldArea.Bottom() > aOutArea.Bottom())
{
- GetWindow()->Invalidate(tools::Rectangle(aOldArea.Left() - nMore, aOutArea.Bottom(), aOldArea.Right() + nMore, aOldArea.Bottom() + nMore));
+ const tools::Rectangle aRect(aOldArea.Left() - nMore, aOutArea.Bottom(), aOldArea.Right() + nMore, aOldArea.Bottom() + nMore);
+ InvalidateAtWindow(aRect);
}
else if(aOldArea.Bottom() < aOutArea.Bottom())
{
- GetWindow()->Invalidate(tools::Rectangle(aOldArea.Left() - nMore, aOldArea.Bottom(), aOldArea.Right() + nMore, aOutArea.Bottom() + nMore));
+ const tools::Rectangle aRect(aOldArea.Left() - nMore, aOldArea.Bottom(), aOldArea.Right() + nMore, aOutArea.Bottom() + nMore);
+ InvalidateAtWindow(aRect);
}
}
}
@@ -1629,6 +1677,10 @@ void ImpEditView::DeselectAll()
pEditEngine->SetInSelectionMode(false);
DrawSelection();
GetEditSelection().Min() = GetEditSelection().Max();
+
+ // Selection is empty, still need to draw it due to new forward selection
+ // functionality. When without that, nothing will be drawn (since it's empty)
+ DrawSelection();
}
bool ImpEditView::IsSelectionAtPoint( const Point& rPosPixel )
diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx
index 4d7365d49221..89cf8947d7c8 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -257,6 +257,27 @@ private:
EditSelection aEditSelection;
EEAnchorMode eAnchorMode;
+ /// mechanism to change from the classic refresh mode that simply
+ // invalidates the area where text was changed. When set, the invalidate
+ // and the direct repaint of the Window-plugged EditView will be suppressed.
+ // Instead, a consumer that has registered using a EditViewCallbacks
+ // incarnation has to handle that. Used e.g. to represent the edited text
+ // in Draw/Impres in an OverlayObject which avoids evtl. expensive full
+ // repaints of the EditView(s)
+ const EditViewCallbacks* mpEditViewCallbacks;
+
+ bool hasEditViewCallbacks() const
+ {
+ return nullptr != mpEditViewCallbacks;
+ }
+
+ void setEditViewCallbacks(const EditViewCallbacks* pEditViewCallbacks)
+ {
+ mpEditViewCallbacks = pEditViewCallbacks;
+ }
+
+ void InvalidateAtWindow(const tools::Rectangle& rRect);
+
protected:
// DragAndDropClient
diff --git a/editeng/source/editeng/impedit3.cxx b/editeng/source/editeng/impedit3.cxx
index 372e0993723f..e07312e4aa05 100644
--- a/editeng/source/editeng/impedit3.cxx
+++ b/editeng/source/editeng/impedit3.cxx
@@ -287,7 +287,10 @@ void ImpEditEngine::UpdateViews( EditView* pCurView )
{
// convert to window coordinates ....
aClipRect = pView->pImpEditView->GetWindowPos( aClipRect );
- pView->GetWindow()->Invalidate( aClipRect );
+
+ // moved to one executing method to allow finer control
+ pView->InvalidateWindow(aClipRect);
+
pView->InvalidateOtherViewWindows( aClipRect );
}
}