summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorDennis Francis <dennis.francis@collabora.com>2020-04-14 14:49:23 +0530
committerDennis Francis <dennis.francis@collabora.com>2020-04-23 09:35:51 +0200
commit0aaf94d75410cb41b572a64935db767f586ffa73 (patch)
tree9f6e7b7277dbd1143e1b258e97b6f0bf6afa4a36 /sc
parent7b9878671a74dc9043d0cdc93e019fdd7d622e8c (diff)
lokit: fix edit-text/view-cursor position
in case of views with heterogeneous zooms. 1. EditText render position fix The EditView has an 'output-area' which is used to clip the rectangle we pass to the Paint() call. It also holds on to the ScGridWindow instance where the edit started. The 'output-area' of the EditView is in the coordinates/units of the MapMode of the ScGridWindow it holds. So we need to temporarily change the MapMode and 'output-area' of the EditView in agreement to the device(with the current view's zoom settings) where we are going to paint to. After we call the Paint(), we rollback the original settings of the EditView. 2. EditViewCursor position fix Before this change the cursor position in twips (calculated based on pixel aligned cell position in the view where editing occurred) is broadcasted to all the client-views. If the clients have different zooms, then simply scaling this common cursor position in the client for its zoom is not going to be accurate enough (due to the non-linear Logic->Pixel->Logic transformation involving pixel rounding). This is very visible if you are editing far away from A1 (like Z50). The fix is to turn off this broadcast for calc-cell editing and send view specific edit-cursor invalidation messages. This is accompanied by a online.git patch that removes unnessecary broadcast of view-cursor invalidation messages which messes up things again. "Do not broadcast view-cursor invalidation messages" (cherry picked from commit d58f1e334245f9e136750fbba267c2a941a213cc) Conflicts: editeng/source/editeng/impedit.cxx editeng/source/editeng/impedit.hxx Change-Id: Ib2fbbe4b6f93f26fc85d6adaa8684dd4397d886f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92631 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com> Reviewed-by: Michael Meeks <michael.meeks@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92721 Tested-by: Jenkins Reviewed-by: Dennis Francis <dennis.francis@collabora.com>
Diffstat (limited to 'sc')
-rw-r--r--sc/source/ui/inc/gridwin.hxx15
-rw-r--r--sc/source/ui/view/gridwin4.cxx125
-rw-r--r--sc/source/ui/view/viewdata.cxx1
3 files changed, 134 insertions, 7 deletions
diff --git a/sc/source/ui/inc/gridwin.hxx b/sc/source/ui/inc/gridwin.hxx
index 6369e5fcf159..e712e3dcf634 100644
--- a/sc/source/ui/inc/gridwin.hxx
+++ b/sc/source/ui/inc/gridwin.hxx
@@ -131,6 +131,17 @@ class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::Window, public DropTargetHel
VisibleRange maVisibleRange;
+ struct LOKCursorEntry
+ {
+ Fraction aScaleX;
+ Fraction aScaleY;
+ tools::Rectangle aRect;
+ };
+
+ // Stores the last cursor position in twips for all
+ // zoom levels demanded from a ScGridWindow instance.
+ std::vector<LOKCursorEntry> maLOKLastCursor;
+
std::unique_ptr<sc::SpellCheckContext> mpSpellCheckCxt;
ScViewData* pViewData;
@@ -291,6 +302,10 @@ class SAL_DLLPUBLIC_RTTI ScGridWindow : public vcl::Window, public DropTargetHel
::std::vector< tools::Rectangle >& rPixelRects ) const;
void UpdateKitSelection(const std::vector<tools::Rectangle>& rRectangles,
std::vector<tools::Rectangle>* pLogicRects = nullptr);
+ bool NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY);
+ void InvalidateLOKViewCursor(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY);
protected:
virtual void PrePaint(vcl::RenderContext& rRenderContext) override;
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 49008ed28f4f..8c60a5c9efc3 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -301,6 +301,59 @@ void ScGridWindow::PrePaint(vcl::RenderContext& /*rRenderContext*/)
}
}
+bool ScGridWindow::NeedLOKCursorInvalidation(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY)
+{
+ // Don't see the need for a map as there will be only a few zoom levels
+ // and as of now X and Y zooms in online are the same.
+ for (auto& rEntry : maLOKLastCursor)
+ {
+ if (aScaleX == rEntry.aScaleX && aScaleY == rEntry.aScaleY)
+ {
+ if (rCursorRect == rEntry.aRect)
+ return false; // No change
+
+ // Update and allow invalidate.
+ rEntry.aRect = rCursorRect;
+ return true;
+ }
+ }
+
+ maLOKLastCursor.push_back(LOKCursorEntry{aScaleX, aScaleY, rCursorRect});
+ return true;
+}
+
+void ScGridWindow::InvalidateLOKViewCursor(const tools::Rectangle& rCursorRect,
+ const Fraction aScaleX, const Fraction aScaleY)
+{
+ if (!NeedLOKCursorInvalidation(rCursorRect, aScaleX, aScaleY))
+ return;
+
+ ScTabViewShell* pThisViewShell = pViewData->GetViewShell();
+ SfxViewShell* pViewShell = SfxViewShell::GetFirst();
+
+ while (pViewShell)
+ {
+ if (pViewShell != pThisViewShell)
+ {
+ ScTabViewShell* pOtherViewShell = dynamic_cast<ScTabViewShell*>(pViewShell);
+ if (pOtherViewShell)
+ {
+ ScViewData& rOtherViewData = pOtherViewShell->GetViewData();
+ Fraction aZoomX = rOtherViewData.GetZoomX();
+ Fraction aZoomY = rOtherViewData.GetZoomY();
+ if (aZoomX == aScaleX && aZoomY == aScaleY)
+ {
+ SfxLokHelper::notifyOtherView(pThisViewShell, pOtherViewShell,
+ LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", rCursorRect.toString());
+ }
+ }
+ }
+
+ pViewShell = SfxViewShell::GetNext(*pViewShell);
+ }
+}
+
void ScGridWindow::Paint( vcl::RenderContext& /*rRenderContext*/, const tools::Rectangle& rRect )
{
ScDocument* pDoc = pViewData->GetDocument();
@@ -922,13 +975,11 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI
{
long nScreenX = aOutputData.nScrX;
long nScreenY = aOutputData.nScrY;
- long nScreenW = aOutputData.GetScrW();
- long nScreenH = aOutputData.GetScrH();
rDevice.SetLineColor();
rDevice.SetFillColor(pOtherEditView->GetBackgroundColor());
- Point aStart = rOtherViewData.GetScrPos( nCol1, nRow1, eOtherWhich );
- Point aEnd = rOtherViewData.GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
+ Point aStart = pViewData->GetScrPos( nCol1, nRow1, eOtherWhich );
+ Point aEnd = pViewData->GetScrPos( nCol2+1, nRow2+1, eOtherWhich );
// don't overwrite grid
long nLayoutSign = bLayoutRTL ? -1 : 1;
@@ -956,8 +1007,24 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI
// paint the background
rDevice.DrawRect(rDevice.PixelToLogic(aBackground));
- tools::Rectangle aEditRect(Point(nScreenX, nScreenY), Size(nScreenW, nScreenH));
+ tools::Rectangle aEditRect(aBackground);
+ aEditRect.AdjustLeft(1);
+ aEditRect.AdjustTop(1);
+
+ // EditView has an 'output area' which is used to clip the 'paint area' we provide below.
+ // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
+ // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
+ // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
+ vcl::Window* pOtherWin = pOtherEditView->GetWindow();
+ const tools::Rectangle aOrigOutputArea(pOtherEditView->GetOutputArea()); // Not in pixels.
+ const MapMode aOrigMapMode = pOtherWin->GetMapMode();
+ pOtherWin->SetMapMode(rDevice.GetMapMode());
+ pOtherEditView->SetOutputArea(rDevice.PixelToLogic(aEditRect));
pOtherEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+
+ // Rollback the mapmode and 'output area'.
+ pOtherWin->SetMapMode(aOrigMapMode);
+ pOtherEditView->SetOutputArea(aOrigOutputArea);
rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
}
}
@@ -1001,6 +1068,8 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI
// set the correct mapmode
tools::Rectangle aBackground(aStart, aEnd);
+ tools::Rectangle aBGAbs(aStart, aEnd);
+
if (bIsTiledRendering)
{
// Need to draw the background in absolute coords.
@@ -1036,8 +1105,50 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI
rDevice.DrawRect(aLogicRect);
// paint the editeng text
- tools::Rectangle aEditRect(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
- pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+ if (bIsTiledRendering)
+ {
+ tools::Rectangle aEditRect(aBackground);
+ aEditRect.AdjustLeft(1);
+ aEditRect.AdjustTop(1);
+ // EditView has an 'output area' which is used to clip the paint area we provide below.
+ // So they need to be in the same coordinates/units. This is tied to the mapmode of the gridwin
+ // attached to the EditView, so we have to change its mapmode too (temporarily). We save the
+ // original mapmode and 'output area' and roll them back when we finish painting to rDevice.
+ const tools::Rectangle aOrigOutputArea(pEditView->GetOutputArea()); // Not in pixels.
+ const MapMode aOrigMapMode = GetMapMode();
+ SetMapMode(rDevice.GetMapMode());
+ pEditView->SetOutputArea(rDevice.PixelToLogic(aEditRect));
+ pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+
+ // Now we need to get relative cursor position within the editview.
+ // This is for sending the absolute twips position of the cursor to the specific views with
+ // the same given zoom level.
+ tools::Rectangle aCursorRect = pEditView->GetEditCursor();
+ Point aCursPos = OutputDevice::LogicToLogic(aCursorRect.TopLeft(), MapMode(MapUnit::Map100thMM), MapMode(MapUnit::MapTwip));
+
+ // Rollback the mapmode and 'output area'.
+ SetMapMode(aOrigMapMode);
+ pEditView->SetOutputArea(aOrigOutputArea);
+
+ const MapMode& rDevMM = rDevice.GetMapMode();
+ MapMode aMM(MapUnit::MapTwip);
+ aMM.SetScaleX(rDevMM.GetScaleX());
+ aMM.SetScaleY(rDevMM.GetScaleY());
+
+ aBGAbs.AdjustLeft(1);
+ aBGAbs.AdjustTop(1);
+ aCursorRect = OutputDevice::PixelToLogic(aBGAbs, aMM);
+ aCursorRect.setWidth(0);
+ aCursorRect.Move(aCursPos.getX(), 0);
+ // Sends view cursor position to views of all matching zooms if needed (avoids duplicates).
+ InvalidateLOKViewCursor(aCursorRect, aMM.GetScaleX(), aMM.GetScaleY());
+ }
+ else
+ {
+ tools::Rectangle aEditRect(Point(nScrX, nScrY), Size(aOutputData.GetScrW(), aOutputData.GetScrH()));
+ pEditView->Paint(rDevice.PixelToLogic(aEditRect), &rDevice);
+ }
+
rDevice.SetMapMode(MapMode(MapUnit::MapPixel));
// restore the cursor it was originally visible
diff --git a/sc/source/ui/view/viewdata.cxx b/sc/source/ui/view/viewdata.cxx
index cef40898bce6..f4462eb7262c 100644
--- a/sc/source/ui/view/viewdata.cxx
+++ b/sc/source/ui/view/viewdata.cxx
@@ -1460,6 +1460,7 @@ void ScViewData::SetEditEngine( ScSplitPos eWhich,
if (comphelper::LibreOfficeKit::isActive())
{
+ pEditView[eWhich]->SetBroadcastLOKViewCursor(false);
pEditView[eWhich]->RegisterViewShell(pViewShell);
}
}