diff options
-rw-r--r-- | editeng/source/editeng/editview.cxx | 10 | ||||
-rw-r--r-- | editeng/source/editeng/impedit.cxx | 99 | ||||
-rw-r--r-- | editeng/source/editeng/impedit.hxx | 10 | ||||
-rw-r--r-- | include/editeng/editview.hxx | 2 | ||||
-rw-r--r-- | sc/source/ui/inc/gridwin.hxx | 15 | ||||
-rw-r--r-- | sc/source/ui/view/gridwin4.cxx | 125 | ||||
-rw-r--r-- | sc/source/ui/view/viewdata.cxx | 1 |
7 files changed, 224 insertions, 38 deletions
diff --git a/editeng/source/editeng/editview.cxx b/editeng/source/editeng/editview.cxx index 531fad3e12c2..34509b4d4e74 100644 --- a/editeng/source/editeng/editview.cxx +++ b/editeng/source/editeng/editview.cxx @@ -470,6 +470,16 @@ void EditView::Command( const CommandEvent& rCEvt ) pImpEditView->Command( rCEvt ); } +void EditView::SetBroadcastLOKViewCursor(bool bSet) +{ + pImpEditView->SetBroadcastLOKViewCursor(bSet); +} + +tools::Rectangle EditView::GetEditCursor() const +{ + return pImpEditView->GetEditCursor(); +} + void EditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor, bool bActivate ) { if ( !pImpEditView->pEditEngine->HasView( this ) ) diff --git a/editeng/source/editeng/impedit.cxx b/editeng/source/editeng/impedit.cxx index e0ee7a52b24d..b5be152d6ece 100644 --- a/editeng/source/editeng/impedit.cxx +++ b/editeng/source/editeng/impedit.cxx @@ -81,7 +81,8 @@ ImpEditView::ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindo aOutArea( Point(), pEng->GetPaperSize() ), eSelectionMode(EESelectionMode::Std), eAnchorMode(EEAnchorMode::TopLeft), - mpEditViewCallbacks(nullptr) + mpEditViewCallbacks(nullptr), + mbBroadcastLOKViewCursor(comphelper::LibreOfficeKit::isActive()) { aEditSelection.Min() = pEng->GetEditDoc().GetStartPaM(); aEditSelection.Max() = pEng->GetEditDoc().GetEndPaM(); @@ -913,6 +914,69 @@ OString buildHyperlinkJSON(const OUString& sText, const OUString& sLink) } // End of anon namespace +tools::Rectangle ImpEditView::ImplGetEditCursor(EditPaM& aPaM, GetCursorFlags nShowCursorFlags, sal_Int32& nTextPortionStart, + const ParaPortion* pParaPortion) const +{ + tools::Rectangle aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, nShowCursorFlags ); + if ( !IsInsertMode() && !aEditSelection.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( pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GetCursorFlags::TextOnly|GetCursorFlags::PreferPortionStart ).Left() ); + aEditCursor.SetRight( aEditCursor.Left() ); + + sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, true ); + const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion]; + if ( rTextPortion.GetKind() == PortionKind::TAB ) + { + aEditCursor.AdjustRight(rTextPortion.GetSize().Width() ); + } + else + { + EditPaM aNext = pEditEngine->CursorRight( aPaM ); + tools::Rectangle aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly ); + if ( aTmpRect.Top() != aEditCursor.Top() ) + aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly|GetCursorFlags::EndOfLine ); + aEditCursor.SetRight( aTmpRect.Left() ); + } + } + } + + long nMaxHeight = !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth(); + if ( aEditCursor.GetHeight() > nMaxHeight ) + { + aEditCursor.SetBottom( aEditCursor.Top() + nMaxHeight - 1 ); + } + + return aEditCursor; +} + +tools::Rectangle ImpEditView::GetEditCursor() const +{ + EditPaM aPaM( aEditSelection.Max() ); + + sal_Int32 nTextPortionStart = 0; + sal_Int32 nPara = pEditEngine->GetEditDoc().GetPos( aPaM.GetNode() ); + if (nPara == EE_PARA_NOT_FOUND) // #i94322 + return tools::Rectangle(); + + const ParaPortion* pParaPortion = pEditEngine->GetParaPortions()[nPara]; + + GetCursorFlags nShowCursorFlags = nExtraCursorFlags | GetCursorFlags::TextOnly; + + // Use CursorBidiLevel 0/1 in meaning of + // 0: prefer portion end, normal mode + // 1: prefer portion start + + if ( ( GetCursorBidiLevel() != CURSOR_BIDILEVEL_DONTKNOW ) && GetCursorBidiLevel() ) + { + nShowCursorFlags |= GetCursorFlags::PreferPortionStart; + } + + return ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion); +} + void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor ) { // No ShowCursor in an empty View ... @@ -957,36 +1021,8 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor ) nShowCursorFlags |= GetCursorFlags::PreferPortionStart; } - tools::Rectangle aEditCursor = pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, nShowCursorFlags ); - if ( !IsInsertMode() && !aEditSelection.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( pEditEngine->pImpEditEngine->PaMtoEditCursor( aPaM, GetCursorFlags::TextOnly|GetCursorFlags::PreferPortionStart ).Left() ); - aEditCursor.SetRight( aEditCursor.Left() ); + tools::Rectangle aEditCursor = ImplGetEditCursor(aPaM, nShowCursorFlags, nTextPortionStart, pParaPortion); - sal_Int32 nTextPortion = pParaPortion->GetTextPortions().FindPortion( aPaM.GetIndex(), nTextPortionStart, true ); - const TextPortion& rTextPortion = pParaPortion->GetTextPortions()[nTextPortion]; - if ( rTextPortion.GetKind() == PortionKind::TAB ) - { - aEditCursor.AdjustRight(rTextPortion.GetSize().Width() ); - } - else - { - EditPaM aNext = pEditEngine->CursorRight( aPaM ); - tools::Rectangle aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly ); - if ( aTmpRect.Top() != aEditCursor.Top() ) - aTmpRect = pEditEngine->pImpEditEngine->PaMtoEditCursor( aNext, GetCursorFlags::TextOnly|GetCursorFlags::EndOfLine ); - aEditCursor.SetRight( aTmpRect.Left() ); - } - } - } - long nMaxHeight = !IsVertical() ? aOutArea.GetHeight() : aOutArea.GetWidth(); - if ( aEditCursor.GetHeight() > nMaxHeight ) - { - aEditCursor.SetBottom( aEditCursor.Top() + nMaxHeight - 1 ); - } if ( bGotoCursor ) // && (!pEditEngine->pImpEditEngine->GetStatus().AutoPageSize() ) ) { // check if scrolling is necessary... @@ -1177,7 +1213,8 @@ void ImpEditView::ShowCursor( bool bGotoCursor, bool bForceVisCursor ) } SfxLokHelper::notifyVisCursorInvalidation(mpViewShell, sRect, bIsWrong, sHyperlink); - mpViewShell->NotifyOtherViews(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect); + if (mbBroadcastLOKViewCursor) + mpViewShell->NotifyOtherViews(LOK_CALLBACK_INVALIDATE_VIEW_CURSOR, "rectangle", sRect); } } diff --git a/editeng/source/editeng/impedit.hxx b/editeng/source/editeng/impedit.hxx index 0eaf70f5ae26..bf6196953ea6 100644 --- a/editeng/source/editeng/impedit.hxx +++ b/editeng/source/editeng/impedit.hxx @@ -262,6 +262,7 @@ private: // in Draw/Impress in an OverlayObject which avoids evtl. expensive full // repaints of the EditView(s) const EditViewCallbacks* mpEditViewCallbacks; + bool mbBroadcastLOKViewCursor; const EditViewCallbacks* getEditViewCallbacks() const { @@ -278,6 +279,11 @@ private: css::uno::Reference<css::datatransfer::clipboard::XClipboard> GetClipboard() const; css::uno::Reference<css::datatransfer::clipboard::XClipboard> GetSelection() const; + void SetBroadcastLOKViewCursor(bool bSet) + { + mbBroadcastLOKViewCursor = bSet; + } + protected: // DragAndDropClient @@ -292,6 +298,8 @@ protected: void HideDDCursor(); void ImplDrawHighlightRect( OutputDevice* _pTarget, const Point& rDocPosTopLeft, const Point& rDocPosBottomRight, tools::PolyPolygon* pPolyPoly ); + tools::Rectangle ImplGetEditCursor(EditPaM& aPaM, GetCursorFlags nShowCursorFlags, + sal_Int32& nTextPortionStart, const ParaPortion* pParaPortion) const; public: ImpEditView( EditView* pView, EditEngine* pEng, vcl::Window* pWindow ); @@ -370,6 +378,8 @@ public: void CalcAnchorPoint(); void RecalcOutputArea(); + tools::Rectangle GetEditCursor() const; + void ShowCursor( bool bGotoCursor, bool bForceVisCursor ); Pair Scroll( long ndX, long ndY, ScrollRangeCheck nRangeCheck = ScrollRangeCheck::NoNegative ); diff --git a/include/editeng/editview.hxx b/include/editeng/editview.hxx index 0f76948c3ffc..441dcb99c794 100644 --- a/include/editeng/editview.hxx +++ b/include/editeng/editview.hxx @@ -160,6 +160,8 @@ public: void Invalidate(); Pair Scroll( long nHorzScroll, long nVertScroll, ScrollRangeCheck nRangeCheck = ScrollRangeCheck::NoNegative ); + void SetBroadcastLOKViewCursor(bool bSet); + tools::Rectangle GetEditCursor() const; void ShowCursor( bool bGotoCursor = true, bool bForceVisCursor = true, bool bActivate = false ); void HideCursor( bool bDeactivate = false ); 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); } } |