tdf#122970 Fix direct cursor leaving screen trail

Previously, an old method using RasterOp::Xor rendering (see tdf#38844)
was used to draw the extra triangle left or right of the mouse pointer
in direct cursor mode. Now, instead of drawing it manually, we change
the cursor type to somewhat similar pointer type.

There is no perfect match for the previous mouse pointer shape, so now
instead of left triangle, PointerStyle::AutoScrollW is used. Also instead
of right triangle, PointerStyle::AutoScrollE is used.

Change-Id: Iadb955f9fcee0978a190e0b8920186a2579f3a4b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153099
Tested-by: Jenkins
Reviewed-by: Hossein <hossein@libreoffice.org>
diff --git a/sw/source/uibase/docvw/edtwin.cxx b/sw/source/uibase/docvw/edtwin.cxx
index ba62bb8..65ec052 100644
--- a/sw/source/uibase/docvw/edtwin.cxx
+++ b/sw/source/uibase/docvw/edtwin.cxx
@@ -634,6 +634,14 @@ void SwEditWin::UpdatePointer(const Point &rLPt, sal_uInt16 nModifier )
                eStyle = PointerStyle::HideWhitespace;
        }

        if( m_pShadCursor )
        {
            if( text::HoriOrientation::LEFT == m_eOrient )    // Arrow to the right
                eStyle = PointerStyle::AutoScrollE;
            else    // Arrow to the left
                eStyle = PointerStyle::AutoScrollW;
        }

        SetPointer( eStyle );
    }
}
@@ -4537,16 +4545,16 @@ void SwEditWin::MouseMove(const MouseEvent& _rMEvt)
                    !rSh.HasSelection() && !GetOutDev()->GetConnectMetaFile() )
                {
                    SwRect aRect;
                    sal_Int16 eOrient;

                    SwFillMode eMode = rSh.GetViewOptions()->GetShdwCursorFillMode();
                    if( rSh.GetShadowCursorPos( aDocPt, eMode, aRect, eOrient ))
                    if( rSh.GetShadowCursorPos( aDocPt, eMode, aRect, m_eOrient ))
                    {
                        if( !m_pShadCursor )
                            m_pShadCursor.reset( new SwShadowCursor( *this,
                                rSh.GetViewOptions()->GetDirectCursorColor() ) );
                        if( text::HoriOrientation::RIGHT != eOrient && text::HoriOrientation::CENTER != eOrient )
                            eOrient = text::HoriOrientation::LEFT;
                        m_pShadCursor->SetPos( aRect.Pos(), aRect.Height(), static_cast< sal_uInt16 >(eOrient) );
                        if( text::HoriOrientation::RIGHT != m_eOrient && text::HoriOrientation::CENTER != m_eOrient )
                            m_eOrient = text::HoriOrientation::LEFT;
                        m_pShadCursor->SetPos( aRect.Pos(), aRect.Height(), static_cast< sal_uInt16 >(m_eOrient) );
                        bDelShadCursor = false;
                    }
                }
diff --git a/sw/source/uibase/docvw/edtwin2.cxx b/sw/source/uibase/docvw/edtwin2.cxx
index bafd957..6e09ffd 100644
--- a/sw/source/uibase/docvw/edtwin2.cxx
+++ b/sw/source/uibase/docvw/edtwin2.cxx
@@ -660,24 +660,6 @@ void SwEditWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle
    SwWrtShell* pWrtShell = GetView().GetWrtShellPtr();
    if(!pWrtShell)
        return;
    bool bPaintShadowCursor = false;
    if( m_pShadCursor )
    {
        tools::Rectangle aRect( m_pShadCursor->GetRect());
        // fully resides inside?
        if( rRect.Contains( aRect ) )
        {
            // then cancel
            m_pShadCursor.reset();
        }
        else if( rRect.Overlaps( aRect ))
        {
            // resides somewhat above, then everything is clipped outside
            // and we have to make the "inner part" at the end of the
            // Paint visible again. Otherwise Paint errors occur!
            bPaintShadowCursor = true;
        }
    }

    if ( GetView().GetVisArea().GetWidth()  <= 0 ||
              GetView().GetVisArea().GetHeight() <= 0 )
@@ -698,9 +680,6 @@ void SwEditWin::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle
        }
        pWrtShell->setOutputToWindow(false);
    }

    if( bPaintShadowCursor )
        m_pShadCursor->Paint();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/uibase/inc/edtwin.hxx b/sw/source/uibase/inc/edtwin.hxx
index aac86d4..714e6bc 100644
--- a/sw/source/uibase/inc/edtwin.hxx
+++ b/sw/source/uibase/inc/edtwin.hxx
@@ -93,6 +93,7 @@ class SW_DLLPUBLIC SwEditWin final : public vcl::DocWindow,
    std::unique_ptr<SdrDropMarkerOverlay> m_pUserMarker;
    SdrObject               *m_pUserMarkerObj;
    std::unique_ptr<SwShadowCursor, o3tl::default_delete<SwShadowCursor>> m_pShadCursor;
    sal_Int16 m_eOrient;
    std::optional<Point>                m_xRowColumnSelectionStart; // save position where table row/column selection has been started

    SwView         &m_rView;
diff --git a/sw/source/uibase/inc/shdwcrsr.hxx b/sw/source/uibase/inc/shdwcrsr.hxx
index bf7fec9..ec8a5f5 100644
--- a/sw/source/uibase/inc/shdwcrsr.hxx
+++ b/sw/source/uibase/inc/shdwcrsr.hxx
@@ -33,8 +33,7 @@ class SwShadowCursor
    tools::Long m_nOldHeight;
    sal_uInt16 m_nOldMode;

    void DrawTri( const Point& rPt, tools::Long nHeight, bool bLeft );
    void DrawCursor( const Point& rPt, tools::Long nHeight, sal_uInt16 nMode );
    void DrawCursor( sal_uInt16 nMode );

public:
    SwShadowCursor( vcl::Window& rWin, const Color& rCol )
@@ -43,8 +42,6 @@ public:

    void SetPos( const Point& rPt, tools::Long nHeight, sal_uInt16 nMode );

    void Paint();

    tools::Rectangle GetRect() const;
};

diff --git a/sw/source/uibase/utlui/shdwcrsr.cxx b/sw/source/uibase/utlui/shdwcrsr.cxx
index 4fea57d..71c2b6c 100644
--- a/sw/source/uibase/utlui/shdwcrsr.cxx
+++ b/sw/source/uibase/utlui/shdwcrsr.cxx
@@ -19,13 +19,14 @@

#include <com/sun/star/text/HoriOrientation.hpp>
#include <shdwcrsr.hxx>
#include <vcl/ptrstyle.hxx>

using namespace ::com::sun::star;

SwShadowCursor::~SwShadowCursor()
{
    if( USHRT_MAX != m_nOldMode )
        DrawCursor( m_aOldPt, m_nOldHeight, m_nOldMode );
        DrawCursor( m_nOldMode);
}

void SwShadowCursor::SetPos( const Point& rPt, tools::Long nHeight, sal_uInt16 nMode )
@@ -35,63 +36,21 @@ void SwShadowCursor::SetPos( const Point& rPt, tools::Long nHeight, sal_uInt16 n
    if( m_aOldPt != aPt || m_nOldHeight != nHeight || m_nOldMode != nMode )
    {
        if( USHRT_MAX != m_nOldMode )
            DrawCursor( m_aOldPt, m_nOldHeight, m_nOldMode );
            DrawCursor( m_nOldMode);

        DrawCursor( aPt, nHeight, nMode );
        DrawCursor( nMode);
        m_nOldMode = nMode;
        m_nOldHeight = nHeight;
        m_aOldPt = aPt;
    }
}

void SwShadowCursor::DrawTri( const Point& rPt, tools::Long nHeight, bool bLeft )
void SwShadowCursor::DrawCursor( sal_uInt16 nMode )
{
    tools::Long nLineDiff = nHeight / 2;
    tools::Long nLineDiffHalf = nLineDiff / 2;

    // Dot above
    Point aPt1( (bLeft ? rPt.X() - 3 : rPt.X() + 3),
                rPt.Y() + nLineDiffHalf );
    // Dot below
    Point aPt2( aPt1.X(), aPt1.Y() + nHeight - nLineDiff - 1 );
    tools::Long nDiff = bLeft ? -1 : 1;
    while( aPt1.Y() <= aPt2.Y() )
    {
        m_pWin->GetOutDev()->DrawLine( aPt1, aPt2 );
        aPt1.AdjustY( 1 );
        aPt2.AdjustY( -1 );
        aPt2.setX( aPt1.AdjustX(nDiff ) );
    }
}

void SwShadowCursor::DrawCursor( const Point& rPt, tools::Long nHeight, sal_uInt16 nMode )
{
    nHeight = (((nHeight / 4)+1) * 4) + 1;

    m_pWin->GetOutDev()->Push();

    m_pWin->SetMapMode(MapMode(MapUnit::MapPixel));
    m_pWin->GetOutDev()->SetRasterOp( RasterOp::Xor );

    m_pWin->GetOutDev()->SetLineColor( Color( ColorTransparency, sal_uInt32(m_aCol) ^ sal_uInt32(COL_WHITE) ) );

    // 1. The Line:
    m_pWin->GetOutDev()->DrawLine( Point( rPt.X(), rPt.Y() + 1),
              Point( rPt.X(), rPt.Y() - 2 + nHeight ));

    // 2. The Triangle
    if( text::HoriOrientation::LEFT == nMode || text::HoriOrientation::CENTER == nMode )    // Arrow to the right
        DrawTri( rPt, nHeight, false );
    if( text::HoriOrientation::RIGHT == nMode || text::HoriOrientation::CENTER == nMode )   // Arrow to the left
        DrawTri( rPt, nHeight, true );

    m_pWin->GetOutDev()->Pop();
}

void SwShadowCursor::Paint()
{
    if( USHRT_MAX != m_nOldMode )
        DrawCursor( m_aOldPt, m_nOldHeight, m_nOldMode );
    if( text::HoriOrientation::LEFT == nMode )    // Arrow to the right
        m_pWin->SetPointer(PointerStyle::AutoScrollE);
    else   // Arrow to the left
        m_pWin->SetPointer(PointerStyle::AutoScrollW);
}

tools::Rectangle SwShadowCursor::GetRect() const