include/svtools/scrolladaptor.hxx        |    2 +
 include/vcl/toolkit/scrbar.hxx           |    3 ++
 include/vcl/weld.hxx                     |    1 
 sc/source/ui/inc/tabview.hxx             |    2 -
 sc/source/ui/view/tabview.cxx            |   22 +++++++++++++--
 sc/source/ui/view/tabview4.cxx           |   45 +++++++++++++++++++++++++------
 svtools/source/control/scrolladaptor.cxx |    2 +
 vcl/source/app/salvtables.cxx            |    2 +
 vcl/source/control/scrbar.cxx            |    6 ++--
 vcl/unx/gtk3/gtkinst.cxx                 |    5 +++
 10 files changed, 76 insertions(+), 14 deletions(-)

New commits:
commit 227e51b6b4b3e6664c6ed9cc72c85ff3c3d03ab9
Author:     Patrick Luby <guibmac...@gmail.com>
AuthorDate: Sun Mar 17 19:04:21 2024 -0400
Commit:     Adolfo Jayme Barrientos <fit...@ubuntu.com>
CommitDate: Thu Mar 21 21:56:23 2024 +0100

    tdf#93352 Fix horizontal swiping and scrolling when using an RTL UI
    
    Starting with commit bfa21ce5fa08f2c634ccb6162914be55aef9f3c2,
    horizontal swiping in Calc moved in the wrong direction scrollbars
    were drawn mirrored.
    
    So, revert parts of commit bfa21ce5fa08f2c634ccb6162914be55aef9f3c2
    so that we are using Calc's previous "negative scrollbar range"
    implementation for RTL UIs, but only for horizontal scrollbars since
    vertical scrollbars are the same in LTR and RTL UIs.
    
    Also, always disable RTL for scrollbars. Enabling RTL causes the
    following bugs when clicking or dragging the mouse in scrollbars in
    Calc's RTL UI:
    - Click or drag events get mirrored so you must click or drag in
      unexpected locations to move the scrollbar thumb in the desired
      direction
    - Repeatedly dragging the scrollbar thumb leftward can only move
      no highter than the R, S, or T columns
    
    Note: even though RTL is always disabled for Calc scrollbars, the arrows
    must still be swapped in vcl's ScrollBar class.
    
    Change-Id: I85aac94ffaf7df2eeb251a3ff150cc0363b5d770
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164959
    Reviewed-by: Stéphane Guillou <stephane.guil...@libreoffice.org>
    Tested-by: Jenkins
    Reviewed-by: Patrick Luby <guibomac...@gmail.com>
    (cherry picked from commit ac1024765d203496bc7d28cb3ed3a6d2215c53ad)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/165116
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

diff --git a/include/svtools/scrolladaptor.hxx 
b/include/svtools/scrolladaptor.hxx
index cdc507078cf8..1eba1dfdf844 100644
--- a/include/svtools/scrolladaptor.hxx
+++ b/include/svtools/scrolladaptor.hxx
@@ -71,6 +71,8 @@ public:
 
     void SetThickness(int nThickness);
 
+    void SetSwapArrows(bool bSwap = true);
+
     ScrollAdaptor(vcl::Window* pParent, bool bHori);
     virtual void dispose() override;
 };
diff --git a/include/vcl/toolkit/scrbar.hxx b/include/vcl/toolkit/scrbar.hxx
index 6981b64fa622..363755fc4168 100644
--- a/include/vcl/toolkit/scrbar.hxx
+++ b/include/vcl/toolkit/scrbar.hxx
@@ -57,6 +57,7 @@ private:
     ScrollType      meScrollType;
     bool            mbCalcSize;
     bool            mbFullDrag;
+    bool            mbSwapArrows;
     Link<ScrollBar*,void>       maScrollHdl;
     Link<ScrollBar*,void>       maEndScrollHdl;
 
@@ -132,6 +133,8 @@ public:
     void            SetEndScrollHdl( const Link<ScrollBar*,void>& rLink ) { 
maEndScrollHdl = rLink; }
 
     virtual Size    GetOptimalSize() const override;
+
+    void            SetSwapArrows( bool bSwap ) { mbSwapArrows = bSwap; }
 };
 
 
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 2d8c4db085d6..fc585bdb1071 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -2576,6 +2576,7 @@ public:
 
     virtual int get_scroll_thickness() const = 0;
     virtual void set_scroll_thickness(int nThickness) = 0;
+    virtual void set_scroll_swap_arrows(bool bSwap) = 0;
 
     virtual ScrollType get_scroll_type() const = 0;
 
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index 66bbc010eae1..e13488e3026a 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -241,7 +241,7 @@ private:
     void            UpdateVarZoom();
 
     static void     SetScrollBar( ScrollAdaptor& rScroll, tools::Long 
nRangeMax, tools::Long nVisible, tools::Long nPos, bool bLayoutRTL );
-    static tools::Long     GetScrollBarPos( const ScrollAdaptor& rScroll );
+    static tools::Long     GetScrollBarPos( const ScrollAdaptor& rScroll, bool 
bLayoutRTL );
 
     void            GetAreaMoveEndPosition(SCCOL nMovX, SCROW nMovY, 
ScFollowMode eMode,
                                            SCCOL& rAreaX, SCROW& rAreaY, 
ScFollowMode& rMode,
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
index 9eff50195e84..a69ab1447f6c 100644
--- a/sc/source/ui/view/tabview.cxx
+++ b/sc/source/ui/view/tabview.cxx
@@ -1091,7 +1091,7 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
         nViewPos = aViewData.GetPosY( (pScroll == aVScrollTop.get()) ?
                                         SC_SPLIT_TOP : SC_SPLIT_BOTTOM );
 
-    bool bLayoutRTL = aViewData.GetDocument().IsLayoutRTL( 
aViewData.GetTabNo() );
+    bool bLayoutRTL = bHoriz && aViewData.GetDocument().IsLayoutRTL( 
aViewData.GetTabNo() );
 
     ScrollType eType = pScroll->GetScrollType();
     if ( eType == ScrollType::Drag )
@@ -1129,7 +1129,7 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
                 nScrollMin = aViewData.GetFixPosX();
             if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == 
aVScrollBottom.get() )
                 nScrollMin = aViewData.GetFixPosY();
-            tools::Long nScrollPos = GetScrollBarPos( *pScroll ) + nScrollMin;
+            tools::Long nScrollPos = GetScrollBarPos( *pScroll, bLayoutRTL ) + 
nScrollMin;
 
             OUString aHelpStr;
             tools::Rectangle aRect;
@@ -1162,6 +1162,22 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
     else
         bDragging = false;
 
+    if ( bHoriz && bLayoutRTL )
+    {
+        // change scroll type so visible/previous cells calculation below 
remains the same
+        switch ( eType )
+        {
+            case ScrollType::LineUp:   eType = ScrollType::LineDown; break;
+            case ScrollType::LineDown: eType = ScrollType::LineUp;   break;
+            case ScrollType::PageUp:   eType = ScrollType::PageDown; break;
+            case ScrollType::PageDown: eType = ScrollType::PageUp;   break;
+            default:
+            {
+                // added to avoid warnings
+            }
+        }
+    }
+
     tools::Long nDelta(0);
     switch ( eType )
     {
@@ -1194,7 +1210,7 @@ void ScTabView::ScrollHdl(ScrollAdaptor* pScroll)
                 if ( aViewData.GetVSplitMode()==SC_SPLIT_FIX && pScroll == 
aVScrollBottom.get() )
                     nScrollMin = aViewData.GetFixPosY();
 
-                tools::Long nScrollPos = GetScrollBarPos( *pScroll ) + 
nScrollMin;
+                tools::Long nScrollPos = GetScrollBarPos( *pScroll, bLayoutRTL 
) + nScrollMin;
                 nDelta = nScrollPos - nViewPos;
 
                 // tdf#152406 Disable anti-jitter code for scroll wheel events
diff --git a/sc/source/ui/view/tabview4.cxx b/sc/source/ui/view/tabview4.cxx
index a7de6bdf67d2..5c19b6cf0794 100644
--- a/sc/source/ui/view/tabview4.cxx
+++ b/sc/source/ui/view/tabview4.cxx
@@ -352,16 +352,45 @@ void ScTabView::SetScrollBar( ScrollAdaptor& rScroll, 
tools::Long nRangeMax, too
     if ( nVisible == 0 )
         nVisible = 1;       // #i59893# don't use visible size 0
 
-    rScroll.SetRange( Range( 0, nRangeMax ) );
-    rScroll.SetVisibleSize( nVisible );
-    rScroll.SetThumbPos( nPos );
+    //  RTL layout uses a negative range to simulate a mirrored scroll bar.
+    //  SetScrollBar/GetScrollBarPos hide this so outside of these functions 
normal cell
+    //  addresses can be used.
+    if ( bLayoutRTL )
+    {
+        rScroll.SetRange( Range( -nRangeMax, 0 ) );
+        rScroll.SetVisibleSize( nVisible );
+        rScroll.SetThumbPos( -nPos - nVisible );
+    }
+    else
+    {
+        rScroll.SetRange( Range( 0, nRangeMax ) );
+        rScroll.SetVisibleSize( nVisible );
+        rScroll.SetThumbPos( nPos );
+    }
 
-    rScroll.EnableRTL( bLayoutRTL );
+    // Related: tdf#93352 always disable RTL for scrollbars
+    // Enabling RTL causes the following bugs when clicking or
+    // dragging the mouse in scrollbars in Calc's RTL UI:
+    // - Click or drag events get mirrored so you must click or
+    //   drag in unexpected locations to move the scrollbar thumb
+    //   in the desired direction
+    // - Repeatedly dragging the scrollbar thumb leftward can only
+    //   move no highter than the R, S, or T columns
+    rScroll.EnableRTL( false );
+
+    // Related: tdf#93352 swap arrows if layout is RTL
+    // We cannot use EnableRTL(true) to signal that the arrows
+    // should be swapped (see comment above) so explicitly enable
+    // or disable arrow swapping.
+    rScroll.SetSwapArrows( bLayoutRTL );
 }
 
-tools::Long ScTabView::GetScrollBarPos( const ScrollAdaptor& rScroll )
+tools::Long ScTabView::GetScrollBarPos( const ScrollAdaptor& rScroll, bool 
bLayoutRTL )
 {
-    return rScroll.GetThumbPos();
+    if ( bLayoutRTL )
+        return -rScroll.GetThumbPos() - rScroll.GetVisibleSize();
+    else
+        return rScroll.GetThumbPos();
 }
 
 //  UpdateScrollBars - set visible area and scroll width of scroll bars
@@ -425,7 +454,7 @@ void ScTabView::UpdateScrollBars( HeaderType eHeaderType )
 
     nVisYB = aViewData.VisibleCellsY( SC_SPLIT_BOTTOM );
     tools::Long nMaxYB = lcl_GetScrollRange( nUsedY, 
aViewData.GetPosY(SC_SPLIT_BOTTOM), nVisYB, rDoc.MaxRow(), nStartY );
-    SetScrollBar( *aVScrollBottom, nMaxYB, nVisYB, aViewData.GetPosY( 
SC_SPLIT_BOTTOM ) - nStartY, bLayoutRTL );
+    SetScrollBar( *aVScrollBottom, nMaxYB, nVisYB, aViewData.GetPosY( 
SC_SPLIT_BOTTOM ) - nStartY, false );
 
     if (bRight)
     {
@@ -438,7 +467,7 @@ void ScTabView::UpdateScrollBars( HeaderType eHeaderType )
     {
         nVisYT = aViewData.VisibleCellsY( SC_SPLIT_TOP );
         tools::Long nMaxYT = lcl_GetScrollRange( nUsedY, 
aViewData.GetPosY(SC_SPLIT_TOP), nVisYT, rDoc.MaxRow(), 0 );
-        SetScrollBar( *aVScrollTop, nMaxYT, nVisYT, aViewData.GetPosY( 
SC_SPLIT_TOP ), bLayoutRTL );
+        SetScrollBar( *aVScrollTop, nMaxYT, nVisYT, aViewData.GetPosY( 
SC_SPLIT_TOP ), false );
     }
 
     //      test the range
diff --git a/svtools/source/control/scrolladaptor.cxx 
b/svtools/source/control/scrolladaptor.cxx
index 6d01e9d414d7..8c2725c1715d 100644
--- a/svtools/source/control/scrolladaptor.cxx
+++ b/svtools/source/control/scrolladaptor.cxx
@@ -122,4 +122,6 @@ tools::Long ScrollAdaptor::DoScroll(tools::Long nNewPos)
 
 void ScrollAdaptor::SetThickness(int nThickness) { 
m_xScrollBar->set_scroll_thickness(nThickness); }
 
+void ScrollAdaptor::SetSwapArrows(bool bSwap) { 
m_xScrollBar->set_scroll_swap_arrows(bSwap); }
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 50ecd194bdcd..faf645fc7943 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -2592,6 +2592,8 @@ public:
         else
             m_xScrollBar->set_width_request(nThickness);
     }
+
+    virtual void set_scroll_swap_arrows(bool bSwap) override { 
m_xScrollBar->SetSwapArrows(bSwap); }
 };
 }
 
diff --git a/vcl/source/control/scrbar.cxx b/vcl/source/control/scrbar.cxx
index b652360139c4..7218b1485bbb 100644
--- a/vcl/source/control/scrbar.cxx
+++ b/vcl/source/control/scrbar.cxx
@@ -85,6 +85,7 @@ void ScrollBar::ImplInit( vcl::Window* pParent, WinBits 
nStyle )
     meScrollType        = ScrollType::DontKnow;
     mbCalcSize          = true;
     mbFullDrag          = false;
+    mbSwapArrows        = false;
 
     ImplInitStyle( nStyle );
     Control::ImplInit( pParent, nStyle, nullptr );
@@ -240,6 +241,7 @@ void ScrollBar::ImplCalc( bool bUpdate )
 
         const tools::Rectangle aControlRegion( Point(0,0), aSize );
         tools::Rectangle aBtn1Region, aBtn2Region, aTrackRegion, 
aBoundingRegion;
+        const bool bSwapArrows = mbSwapArrows || IsRTLEnabled();
 
         // reset rectangles to empty *and* (0,0) position
         maThumbRect = tools::Rectangle();
@@ -248,9 +250,9 @@ void ScrollBar::ImplCalc( bool bUpdate )
 
         if ( GetStyle() & WB_HORZ )
         {
-            if ( GetNativeControlRegion( ControlType::Scrollbar, 
IsRTLEnabled()? ControlPart::ButtonRight: ControlPart::ButtonLeft,
+            if ( GetNativeControlRegion( ControlType::Scrollbar, bSwapArrows? 
ControlPart::ButtonRight: ControlPart::ButtonLeft,
                         aControlRegion, ControlState::NONE, 
ImplControlValue(), aBoundingRegion, aBtn1Region ) &&
-                 GetNativeControlRegion( ControlType::Scrollbar, 
IsRTLEnabled()? ControlPart::ButtonLeft: ControlPart::ButtonRight,
+                 GetNativeControlRegion( ControlType::Scrollbar, bSwapArrows? 
ControlPart::ButtonLeft: ControlPart::ButtonRight,
                         aControlRegion, ControlState::NONE, 
ImplControlValue(), aBoundingRegion, aBtn2Region ) )
             {
                 maBtn1Rect = aBtn1Region;
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index b8da4f7b7a27..036493239217 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -8745,6 +8745,11 @@ public:
             gtk_widget_set_size_request(GTK_WIDGET(m_pScrollbar), nThickness, 
-1);
     }
 
+    virtual void set_scroll_swap_arrows(bool /* bSwap */) override
+    {
+        // Related: tdf#93352 do nothing since GtkScrollbar has no arrows
+    }
+
     virtual ~GtkInstanceScrollbar() override
     {
         g_signal_handler_disconnect(m_pAdjustment, m_nAdjustChangedSignalId);

Reply via email to