include/vcl/toolkit/treelistbox.hxx  |    2 
 include/vcl/weld.hxx                 |    4 
 vcl/inc/iconview.hxx                 |    7 
 vcl/inc/jsdialog/jsdialogbuilder.hxx |    3 
 vcl/inc/salvtables.hxx               |    2 
 vcl/inc/svimpbox.hxx                 |    2 
 vcl/jsdialog/jsdialogbuilder.cxx     |    6 
 vcl/source/app/salvtables.cxx        |   23 +
 vcl/source/treelist/iconview.cxx     |   75 ++---
 vcl/source/treelist/iconviewimpl.cxx |  523 +++++++++++++++++++++--------------
 vcl/source/treelist/iconviewimpl.hxx |   28 +
 vcl/source/treelist/svimpbox.cxx     |    4 
 vcl/source/treelist/treelistbox.cxx  |    8 
 vcl/unx/gtk3/gtkinst.cxx             |    6 
 14 files changed, 442 insertions(+), 251 deletions(-)

New commits:
commit c2253f587b68f7277f30259160155f2bbf7adc78
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Mon May 30 10:37:53 2022 +0300
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Jun 1 16:30:11 2022 +0200

    Introduce weld::IconView::insert_separator
    
    Needed to eventual re-implementation of starmath's SmElementsControl
    using IconView.
    
    This required re-implementation of IconViewImpl, to layout entries
    by iteration, because now it's impossible to find an entry position
    just based on its index.
    
    This coincidentally fixed some visual glitches in non-gtk IconView
    implementation from commit 5813660e7bfe128ac076e592fe31de64a6863780
      Author Szymon Kłos <eszka...@gmail.com>
      Date   Tue Feb 16 16:03:30 2016 +0100
        icon view for RemoteFilesDialog
    
    where any selected element could become first in row when scrolling.
    
    SvTreeListBox::SetEntryHeight taking a SvTreeListEntry const* had to
    be renamed to CalcEntryHeight, to avoid both virtual and non-virtual
    overloads, additionally having different accessibility.
    
    A TODO is implement separators in GtkInstanceIconView. I couldn't
    find a GTK API for separators in IconView, so possibly a workaround
    would be needed with some non-selectable narrow elements.
    
    Change-Id: Ie8dc35d94049a1c48e4eb49697681ffbe93c17f4
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135112
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/include/vcl/toolkit/treelistbox.hxx 
b/include/vcl/toolkit/treelistbox.hxx
index 685540b2d858..7e21dfda21e7 100644
--- a/include/vcl/toolkit/treelistbox.hxx
+++ b/include/vcl/toolkit/treelistbox.hxx
@@ -476,7 +476,7 @@ public:
 
 protected:
 
-    VCL_DLLPRIVATE void         SetEntryHeight( SvTreeListEntry const * pEntry 
);
+    virtual void                CalcEntryHeight(SvTreeListEntry const* pEntry);
                    void         AdjustEntryHeight( const Image& rBmp );
     VCL_DLLPRIVATE void         AdjustEntryHeight();
 
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index dba513870818..528405643716 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -1361,6 +1361,8 @@ public:
                         const VirtualDevice* pIcon, TreeIter* pRet)
         = 0;
 
+    virtual void insert_separator(int pos, const OUString* pId) = 0;
+
     void append(const OUString& rId, const OUString& rStr, const OUString& 
rImage)
     {
         insert(-1, &rStr, &rId, &rImage, nullptr);
@@ -1371,6 +1373,8 @@ public:
         insert(-1, &rStr, &rId, pImage, nullptr);
     }
 
+    void append_separator(const OUString& rId) { insert_separator(-1, &rId); }
+
     void connect_selection_changed(const Link<IconView&, void>& rLink)
     {
         m_aSelectionChangeHdl = rLink;
diff --git a/vcl/inc/iconview.hxx b/vcl/inc/iconview.hxx
index c1e62bc2ec65..971a638cc6ef 100644
--- a/vcl/inc/iconview.hxx
+++ b/vcl/inc/iconview.hxx
@@ -27,15 +27,20 @@ class IconView final : public SvTreeListBox
 public:
     IconView(vcl::Window* pParent, WinBits nBits);
 
+    Size GetEntrySize(const SvTreeListEntry&) const;
+
     virtual void Resize() override;
 
-    virtual tools::Rectangle GetFocusRect(const SvTreeListEntry*, tools::Long 
nEntryPos) override;
+    virtual tools::Rectangle GetFocusRect(const SvTreeListEntry*, tools::Long) 
override;
 
     void PaintEntry(SvTreeListEntry&, tools::Long nX, tools::Long nY,
                     vcl::RenderContext& rRenderContext);
 
     virtual FactoryFunction GetUITestFactory() const override;
     virtual void DumpAsPropertyTree(tools::JsonWriter& rJsonWriter) override;
+
+protected:
+    virtual void CalcEntryHeight(SvTreeListEntry const* pEntry) override;
 };
 
 #endif
diff --git a/vcl/inc/jsdialog/jsdialogbuilder.hxx 
b/vcl/inc/jsdialog/jsdialogbuilder.hxx
index a25aeac55c10..5e7437b2725a 100644
--- a/vcl/inc/jsdialog/jsdialogbuilder.hxx
+++ b/vcl/inc/jsdialog/jsdialogbuilder.hxx
@@ -670,6 +670,9 @@ public:
 
     virtual void insert(int pos, const OUString* pStr, const OUString* pId,
                         const VirtualDevice* pIcon, weld::TreeIter* pRet) 
override;
+
+    virtual void insert_separator(int pos, const OUString* pId) override;
+
     virtual void clear() override;
     virtual void select(int pos) override;
     virtual void unselect(int pos) override;
diff --git a/vcl/inc/salvtables.hxx b/vcl/inc/salvtables.hxx
index 45e9700ad2c8..9628744fb087 100644
--- a/vcl/inc/salvtables.hxx
+++ b/vcl/inc/salvtables.hxx
@@ -1774,6 +1774,8 @@ public:
     virtual void insert(int pos, const OUString* pStr, const OUString* pId,
                         const VirtualDevice* pIcon, weld::TreeIter* pRet) 
override;
 
+    virtual void insert_separator(int pos, const OUString* pId) override;
+
     virtual void connect_query_tooltip(const Link<const weld::TreeIter&, 
OUString>& rLink) override;
 
     virtual OUString get_selected_id() const override;
diff --git a/vcl/inc/svimpbox.hxx b/vcl/inc/svimpbox.hxx
index 994a25f095ee..1acd895743fd 100644
--- a/vcl/inc/svimpbox.hxx
+++ b/vcl/inc/svimpbox.hxx
@@ -92,7 +92,6 @@ private:
     SvTreeListEntry*     m_pActiveEntry;
     SvLBoxTab*           m_pActiveTab;
 
-    VclPtr<ScrollBar>    m_aHorSBar;
     VclPtr<ScrollBarBox> m_aScrBarBox;
 
     ::vcl::AccessibleFactoryAccess
@@ -185,6 +184,7 @@ private:
 
 protected:
     VclPtr<SvTreeListBox>   m_pView;
+    VclPtr<ScrollBar>       m_aHorSBar;
     VclPtr<ScrollBar>       m_aVerSBar;
     SvTreeListEntry*        m_pCursor;
     SvTreeListEntry*        m_pCursorOld;
diff --git a/vcl/jsdialog/jsdialogbuilder.cxx b/vcl/jsdialog/jsdialogbuilder.cxx
index 3648d33b3ebc..ab1fdf7636c0 100644
--- a/vcl/jsdialog/jsdialogbuilder.cxx
+++ b/vcl/jsdialog/jsdialogbuilder.cxx
@@ -1702,6 +1702,12 @@ void JSIconView::insert(int pos, const OUString* pStr, 
const OUString* pId,
     sendUpdate();
 }
 
+void JSIconView::insert_separator(int pos, const OUString* pId)
+{
+    SalInstanceIconView::insert_separator(pos, pId);
+    sendUpdate();
+}
+
 void JSIconView::clear()
 {
     SalInstanceIconView::clear();
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 4432b4c5afe6..ba759d0fa3d5 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -4437,7 +4437,7 @@ void SalInstanceTreeView::set_image(SvTreeListEntry* 
pEntry, const Image& rImage
         static_cast<SvLBoxContextBmp&>(rItem).SetBitmap2(rImage);
     }
 
-    m_xTreeView->SetEntryHeight(pEntry);
+    m_xTreeView->CalcEntryHeight(pEntry);
     InvalidateModelEntry(pEntry);
 }
 
@@ -5309,7 +5309,11 @@ SalInstanceIconView::SalInstanceIconView(::IconView* 
pIconView, SalInstanceBuild
 }
 
 int SalInstanceIconView::get_item_width() const { return 
m_xIconView->GetEntryWidth(); }
-void SalInstanceIconView::set_item_width(int width) { 
m_xIconView->SetEntryWidth(width); }
+void SalInstanceIconView::set_item_width(int width)
+{
+    m_xIconView->SetEntryWidth(width);
+    m_xIconView->Resize();
+}
 
 void SalInstanceIconView::freeze()
 {
@@ -5407,6 +5411,21 @@ void SalInstanceIconView::insert(int pos, const 
OUString* pStr, const OUString*
     enable_notify_events();
 }
 
+void SalInstanceIconView::insert_separator(int pos, const OUString* /* pId */)
+{
+    const auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
+    const OUString sSep(VclResId(STR_SEPARATOR));
+    SvTreeListEntry* pEntry = new SvTreeListEntry;
+    pEntry->SetFlags(pEntry->GetFlags() | SvTLEntryFlags::IS_SEPARATOR);
+    const Image aDummy;
+    pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+    pEntry->AddItem(std::make_unique<SvLBoxString>(sSep));
+    pEntry->SetUserData(nullptr);
+    m_xIconView->Insert(pEntry, nullptr, nInsertPos);
+    SvViewDataEntry* pViewData = m_xIconView->GetViewDataEntry(pEntry);
+    pViewData->SetSelectable(false);
+}
+
 IMPL_LINK(SalInstanceIconView, TooltipHdl, const HelpEvent&, rHEvt, bool)
 {
     if (notify_events_disabled())
diff --git a/vcl/source/treelist/iconview.cxx b/vcl/source/treelist/iconview.cxx
index f54616e7fad7..6b8a193fde11 100644
--- a/vcl/source/treelist/iconview.cxx
+++ b/vcl/source/treelist/iconview.cxx
@@ -28,17 +28,54 @@
 #include <vcl/cvtgrf.hxx>
 #include <comphelper/base64.hxx>
 
+namespace
+{
+const int separatorHeight = 10;
+const int nSpacing = 5; // 5 pixels from top, from bottom, between icon and 
label
+}
+
 IconView::IconView(vcl::Window* pParent, WinBits nBits)
     : SvTreeListBox(pParent, nBits)
 {
     nColumns = 1;
     mbCenterAndClipText = true;
-    SetEntryHeight(100);
     SetEntryWidth(100);
 
     pImpl.reset(new IconViewImpl(this, GetModel(), GetStyle()));
 }
 
+Size IconView::GetEntrySize(const SvTreeListEntry& entry) const
+{
+    if (entry.GetFlags() & SvTLEntryFlags::IS_SEPARATOR)
+        return { GetEntryWidth() * GetColumnsCount(), separatorHeight };
+    return { GetEntryWidth(), GetEntryHeight() };
+}
+
+void IconView::CalcEntryHeight(SvTreeListEntry const* pEntry)
+{
+    int nHeight = nSpacing * 2;
+    SvViewDataEntry* pViewData = GetViewDataEntry(pEntry);
+    const size_t nCount = pEntry->ItemCount();
+    bool bHasIcon = false;
+    for (size_t nCur = 0; nCur < nCount; ++nCur)
+    {
+        nHeight += SvLBoxItem::GetHeight(pViewData, nCur);
+
+        if (!bHasIcon && pEntry->GetItem(nCur).GetType() == 
SvLBoxItemType::ContextBmp)
+            bHasIcon = true;
+    }
+
+    if (bHasIcon && nCount > 1)
+        nHeight += nSpacing; // between icon and label
+
+    if (nHeight > nEntryHeight)
+    {
+        nEntryHeight = nHeight;
+        Control::SetFont(GetFont());
+        pImpl->SetEntryHeight();
+    }
+}
+
 void IconView::Resize()
 {
     Size aBoxSize = Control::GetOutputSizePixel();
@@ -46,46 +83,24 @@ void IconView::Resize()
     if (!aBoxSize.Width())
         return;
 
-    nColumns = aBoxSize.Width() / nEntryWidth;
+    nColumns = nEntryWidth ? aBoxSize.Width() / nEntryWidth : 1;
 
     SvTreeListBox::Resize();
 }
 
-tools::Rectangle IconView::GetFocusRect(const SvTreeListEntry*, tools::Long 
nEntryPos)
+tools::Rectangle IconView::GetFocusRect(const SvTreeListEntry* pEntry, 
tools::Long)
 {
-    Size aSize;
-    aSize.setHeight(nEntryHeight);
-    aSize.setWidth(nEntryWidth);
-
-    Point aPos;
-    aPos.setX(0);
-    aPos.setY(0);
-
-    tools::Rectangle aRect;
-
-    short nCols = GetColumnsCount();
-
-    if (nCols)
-    {
-        aPos.setY((nEntryPos / nCols) * nEntryHeight);
-        aPos.setX((nEntryPos % nCols) * nEntryWidth);
-    }
-
-    aRect.SetPos(aPos);
-    aRect.SetSize(aSize);
-
-    return aRect;
+    return { GetEntryPosition(pEntry), GetEntrySize(*pEntry) };
 }
 
 void IconView::PaintEntry(SvTreeListEntry& rEntry, tools::Long nX, tools::Long 
nY,
                           vcl::RenderContext& rRenderContext)
 {
-    const int nSpacing = 5; // 5 pixels from top, from bottom, between icon 
and label
-
     pImpl->UpdateContextBmpWidthMax(&rEntry);
 
-    short nTempEntryHeight = GetEntryHeight();
-    short nTempEntryWidth = GetEntryWidth();
+    const Size entrySize = GetEntrySize(rEntry);
+    short nTempEntryHeight = entrySize.Height();
+    short nTempEntryWidth = entrySize.Width();
 
     Point aEntryPos(nX, nY);
 
diff --git a/vcl/source/treelist/iconviewimpl.cxx 
b/vcl/source/treelist/iconviewimpl.cxx
index 319a0d7c899e..c350eb49c151 100644
--- a/vcl/source/treelist/iconviewimpl.cxx
+++ b/vcl/source/treelist/iconviewimpl.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <vcl/svapp.hxx>
+#include <vcl/toolkit/treelistentry.hxx>
 #include <tools/debug.hxx>
 #include <iconview.hxx>
 #include "iconviewimpl.hxx"
@@ -27,29 +28,177 @@ IconViewImpl::IconViewImpl( SvTreeListBox* pTreeListBox, 
SvTreeList* pTreeList,
 {
 }
 
-void IconViewImpl::CursorUp()
+static bool IsSeparator(const SvTreeListEntry* entry)
 {
-    if (!m_pStartEntry)
+    return entry && entry->GetFlags() & SvTLEntryFlags::IS_SEPARATOR;
+}
+
+Size IconViewImpl::GetEntrySize(const SvTreeListEntry& entry) const
+{
+    return static_cast<const IconView*>(m_pView.get())->GetEntrySize(entry);
+}
+
+void IconViewImpl::IterateVisibleEntryAreas(const IterateEntriesFunc& f, bool 
fromStartEntry) const
+{
+    tools::Long x = 0, y = 0;
+    short column = 0;
+    const tools::Long rowWidth = m_pView->GetEntryWidth() * 
m_pView->GetColumnsCount();
+    tools::Long nPrevHeight = 0;
+    for (auto entry = fromStartEntry ? m_pStartEntry : 
m_pView->FirstVisible(); entry;
+         entry = m_pView->NextVisible(entry))
+    {
+        const Size s = GetEntrySize(*entry);
+        if (x >= rowWidth || IsSeparator(entry))
+        {
+            column = 0;
+            x = 0;
+            y += nPrevHeight;
+        }
+        EntryAreaInfo info{ entry, column, tools::Rectangle{ Point{ x, y }, s 
} };
+        const auto result = f(info);
+        if (result == CallbackResult::Stop)
+            return;
+        ++column;
+        x += s.Width();
+        nPrevHeight = s.Height();
+    }
+}
+
+tools::Long IconViewImpl::GetEntryRow(const SvTreeListEntry* entry) const
+{
+    tools::Long nEntryRow = -1;
+    auto GetRow = [entry, &nEntryRow, row = -1](const EntryAreaInfo& info) 
mutable
+    {
+        if (info.column == 0 && !IsSeparator(info.entry))
+            ++row;
+        if (info.entry != entry)
+            return CallbackResult::Continue;
+        nEntryRow = row;
+        return CallbackResult::Stop;
+    };
+    IterateVisibleEntryAreas(GetRow);
+    return nEntryRow;
+}
+
+void IconViewImpl::SetStartEntry(SvTreeListEntry* entry)
+{
+    const tools::Long max = m_aVerSBar->GetRangeMax() - 
m_aVerSBar->GetVisibleSize();
+    tools::Long row = -1;
+    auto GetEntryAndRow = [&entry, &row, max, found = entry](const 
EntryAreaInfo& info) mutable
+    {
+        if (info.column == 0 && !IsSeparator(info.entry))
+        {
+            found = info.entry;
+            ++row;
+        }
+        if (row >= max || info.entry == entry)
+        {
+            entry = found;
+            return CallbackResult::Stop;
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(GetEntryAndRow);
+
+    m_pStartEntry = entry;
+    m_aVerSBar->SetThumbPos(row);
+    m_pView->Invalidate(GetVisibleArea());
+}
+
+void IconViewImpl::ScrollTo(SvTreeListEntry* entry)
+{
+    if (!m_aVerSBar->IsVisible())
         return;
+    const tools::Long entryRow = GetEntryRow(entry);
+    const tools::Long oldStartRow = m_aVerSBar->GetThumbPos();
+    if (entryRow < oldStartRow)
+        IconViewImpl::SetStartEntry(entry);
+    const tools::Long visibleRows = m_aVerSBar->GetVisibleSize();
+    const tools::Long posRelativeToBottom = entryRow - (oldStartRow + 
visibleRows) + 1;
+    if (posRelativeToBottom > 0)
+        IconViewImpl::SetStartEntry(GoToNextRow(m_pStartEntry, 
posRelativeToBottom));
+}
 
-    SvTreeListEntry* pPrevFirstToDraw = m_pStartEntry;
+SvTreeListEntry* IconViewImpl::GoToPrevRow(SvTreeListEntry* pEntry, int nRows) 
const
+{
+    SvTreeListEntry* pPrev = pEntry;
+    auto FindPrev = [this, pEntry, nRows, &pPrev,
+                     prevs = std::vector<SvTreeListEntry*>()](const 
EntryAreaInfo& info) mutable
+    {
+        if (info.column == 0 && !IsSeparator(info.entry))
+            prevs.push_back(info.entry);
+        if (pEntry == info.entry)
+        {
+            if (prevs.size() > 1)
+            {
+                int i = std::max(0, static_cast<int>(prevs.size()) - nRows - 
1);
+                pPrev = prevs[i];
+                for (short column = info.column; column; --column)
+                {
+                    SvTreeListEntry* pNext = m_pView->NextVisible(pPrev);
+                    if (!pNext || IsSeparator(pNext))
+                        break;
+                    pPrev = pNext;
+                }
+            }
+            return CallbackResult::Stop;
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(FindPrev);
 
-    for(short i = 0; i < m_pView->GetColumnsCount() && pPrevFirstToDraw; i++)
-        pPrevFirstToDraw = m_pView->PrevVisible(pPrevFirstToDraw);
+    return pPrev;
+}
+
+SvTreeListEntry* IconViewImpl::GoToNextRow(SvTreeListEntry* pEntry, int nRows) 
const
+{
+    SvTreeListEntry* pNext = pEntry;
+    auto FindNext
+        = [pEntry, nRows, &pNext, column = -1](const EntryAreaInfo& info) 
mutable
+    {
+        if (info.column <= column && !IsSeparator(info.entry))
+        {
+            if (info.column == 0 && --nRows < 0)
+                return CallbackResult::Stop;
+            pNext = info.entry;
+            if (info.column == column && nRows == 0)
+                return CallbackResult::Stop;
+        }
+        else if (pEntry == info.entry)
+        {
+            column = info.column;
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(FindNext);
 
-    if( !pPrevFirstToDraw )
+    return pNext;
+}
+
+SvTreeListEntry* IconViewImpl::GetFirstInRow(SvTreeListEntry* pEntry) const
+{
+    SvTreeListEntry* pFirst = nullptr;
+    auto FindFirst = [pEntry, &pFirst](const EntryAreaInfo& info)
+    {
+        if (info.column == 0)
+            pFirst = info.entry;
+        return pEntry == info.entry ? CallbackResult::Stop : 
CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(FindFirst);
+
+    return pFirst;
+}
+
+void IconViewImpl::CursorUp()
+{
+    if (!m_pStartEntry)
         return;
 
+    SvTreeListEntry* pPrevFirstToDraw = GoToPrevRow(m_pStartEntry, 1);
+
     m_nFlags &= ~LBoxFlags::Filling;
-    tools::Long nEntryHeight = m_pView->GetEntryHeight();
     ShowCursor( false );
-    m_pView->PaintImmediately();
-    m_pStartEntry = pPrevFirstToDraw;
-    tools::Rectangle aArea( GetVisibleArea() );
-    if (aArea.GetHeight() > nEntryHeight)
-        aArea.AdjustBottom(-nEntryHeight);
-    m_pView->Scroll( 0, nEntryHeight, aArea, ScrollFlags::NoChildren );
-    m_pView->PaintImmediately();
+    SetStartEntry(pPrevFirstToDraw);
     ShowCursor( true );
     m_pView->NotifyScrolled();
 }
@@ -59,92 +208,47 @@ void IconViewImpl::CursorDown()
     if (!m_pStartEntry)
         return;
 
-    SvTreeListEntry* pNextFirstToDraw = m_pStartEntry;
+    SvTreeListEntry* pNextFirstToDraw = GoToNextRow(m_pStartEntry, 1);
 
-    for(short i = 0; i < m_pView->GetColumnsCount(); i++)
-        pNextFirstToDraw = m_pView->NextVisible(pNextFirstToDraw);
-
-    if( pNextFirstToDraw )
-    {
-        m_nFlags &= ~LBoxFlags::Filling;
-        ShowCursor( false );
-        m_pView->PaintImmediately();
-        m_pStartEntry = pNextFirstToDraw;
-        tools::Rectangle aArea( GetVisibleArea() );
-        m_pView->Scroll( 0, -(m_pView->GetEntryHeight()), aArea, 
ScrollFlags::NoChildren );
-        m_pView->PaintImmediately();
-        ShowCursor( true );
-        m_pView->NotifyScrolled();
-    }
+    m_nFlags &= ~LBoxFlags::Filling;
+    ShowCursor( false );
+    SetStartEntry(pNextFirstToDraw);
+    ShowCursor( true );
+    m_pView->NotifyScrolled();
 }
 
 void IconViewImpl::PageDown( sal_uInt16 nDelta )
 {
-    sal_uInt16 nRealDelta = nDelta * m_pView->GetColumnsCount();
-
     if( !nDelta )
         return;
 
     if (!m_pStartEntry)
         return;
 
-    SvTreeListEntry* pNext = m_pView->NextVisible(m_pStartEntry, nRealDelta);
-    if( pNext == m_pStartEntry )
-        return;
+    SvTreeListEntry* pNext = GoToNextRow(m_pStartEntry, nDelta);
 
     ShowCursor( false );
 
     m_nFlags &= ~LBoxFlags::Filling;
-    m_pStartEntry = pNext;
-
-    if( nRealDelta >= m_nVisibleCount )
-    {
-        m_pView->Invalidate( GetVisibleArea() );
-    }
-    else
-    {
-        tools::Rectangle aArea( GetVisibleArea() );
-        tools::Long nScroll = m_pView->GetEntryHeight() * 
static_cast<tools::Long>(nRealDelta);
-        nScroll = -nScroll;
-        m_pView->PaintImmediately();
-        m_pView->Scroll( 0, nScroll, aArea, ScrollFlags::NoChildren );
-        m_pView->PaintImmediately();
-        m_pView->NotifyScrolled();
-    }
+    SetStartEntry(pNext);
 
     ShowCursor( true );
 }
 
 void IconViewImpl::PageUp( sal_uInt16 nDelta )
 {
-    sal_uInt16 nRealDelta = nDelta * m_pView->GetColumnsCount();
     if( !nDelta )
         return;
 
     if (!m_pStartEntry)
         return;
 
-    SvTreeListEntry* pPrev = m_pView->PrevVisible(m_pStartEntry, nRealDelta);
-    if( pPrev == m_pStartEntry )
-        return;
+    SvTreeListEntry* pPrev = GoToPrevRow(m_pStartEntry, nDelta);
 
     m_nFlags &= ~LBoxFlags::Filling;
     ShowCursor( false );
 
-    m_pStartEntry = pPrev;
-    if( nRealDelta >= m_nVisibleCount )
-    {
-        m_pView->Invalidate( GetVisibleArea() );
-    }
-    else
-    {
-        tools::Long nEntryHeight = m_pView->GetEntryHeight();
-        tools::Rectangle aArea( GetVisibleArea() );
-        m_pView->PaintImmediately();
-        m_pView->Scroll( 0, nEntryHeight*nRealDelta, aArea, 
ScrollFlags::NoChildren );
-        m_pView->PaintImmediately();
-        m_pView->NotifyScrolled();
-    }
+    SetStartEntry(pPrev);
 
     ShowCursor( true );
 }
@@ -160,14 +264,11 @@ void IconViewImpl::KeyDown( bool bPageDown )
     else
         nDelta = 1;
 
-    tools::Long nThumbPos = m_aVerSBar->GetThumbPos();
-
     if( nDelta <= 0 )
         return;
 
     m_nFlags &= ~LBoxFlags::Filling;
 
-    m_aVerSBar->SetThumbPos( nThumbPos+nDelta );
     if( bPageDown )
         PageDown( static_cast<short>(nDelta) );
     else
@@ -185,17 +286,8 @@ void IconViewImpl::KeyUp( bool bPageUp )
     else
         nDelta = 1;
 
-    tools::Long nThumbPos = m_aVerSBar->GetThumbPos();
-
-    if( nThumbPos < nDelta )
-        nDelta = nThumbPos;
-
-    if( nDelta < 0 )
-        return;
-
     m_nFlags &= ~LBoxFlags::Filling;
 
-    m_aVerSBar->SetThumbPos( nThumbPos - nDelta );
     if( bPageUp )
         PageUp( static_cast<short>(nDelta) );
     else
@@ -207,21 +299,27 @@ tools::Long IconViewImpl::GetEntryLine(const 
SvTreeListEntry* pEntry) const
     if(!m_pStartEntry )
         return -1; // invisible position
 
-    tools::Long nFirstVisPos = m_pView->GetVisiblePos( m_pStartEntry );
-    tools::Long nEntryVisPos = m_pView->GetVisiblePos( pEntry );
-    nFirstVisPos = nEntryVisPos - nFirstVisPos;
-
-    return nFirstVisPos;
+    return IconViewImpl::GetEntryPosition(pEntry).Y();
 }
 
 Point IconViewImpl::GetEntryPosition(const SvTreeListEntry* pEntry) const
 {
-    const int pos = m_pView->GetAbsPos( pEntry );
+    Point result{ -m_pView->GetEntryWidth(), -m_pView->GetEntryHeight() }; // 
invisible
+    auto FindEntryPos = [pEntry, &result](const EntryAreaInfo& info)
+    {
+        if (pEntry == info.entry)
+        {
+            result = info.area.TopLeft();
+            return CallbackResult::Stop;
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(FindEntryPos, true);
 
-    return Point( ( pos % m_pView->GetColumnsCount() ) * 
m_pView->GetEntryWidth(),
-                 ( pos / m_pView->GetColumnsCount() ) * 
m_pView->GetEntryHeight() );
+    return result;
 }
 
+// Returns the last entry (in respective row) if position is just past the 
last entry
 SvTreeListEntry* IconViewImpl::GetClickedEntry( const Point& rPoint ) const
 {
     DBG_ASSERT( m_pView->GetModel(), "IconViewImpl::GetClickedEntry: how can 
this ever happen?" );
@@ -230,11 +328,25 @@ SvTreeListEntry* IconViewImpl::GetClickedEntry( const 
Point& rPoint ) const
     if( m_pView->GetEntryCount() == 0 || !m_pStartEntry || 
!m_pView->GetEntryHeight() || !m_pView->GetEntryWidth())
         return nullptr;
 
-    sal_uInt16 nY = static_cast<sal_uInt16>(rPoint.Y() / 
m_pView->GetEntryHeight() );
-    sal_uInt16 nX = static_cast<sal_uInt16>(rPoint.X() / 
m_pView->GetEntryWidth() );
-    sal_uInt16 nTemp = nY * m_pView->GetColumnsCount() + nX;
-
-    SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
+    SvTreeListEntry* pEntry = nullptr;
+    auto FindEntryByPos = [&pEntry, &rPoint](const EntryAreaInfo& info)
+    {
+        if (info.area.Contains(rPoint))
+        {
+            pEntry = info.entry;
+            return CallbackResult::Stop;
+        }
+        else if (info.area.Top() > rPoint.Y())
+        {
+            return CallbackResult::Stop; // we are already below the clicked 
row
+        }
+        else if (info.area.Bottom() > rPoint.Y())
+        {
+            pEntry = info.entry; // Same row; store the entry in case the 
click is past all entries
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(FindEntryByPos, true);
 
     return pEntry;
 }
@@ -245,16 +357,15 @@ bool IconViewImpl::IsEntryInView( SvTreeListEntry* pEntry 
) const
     if( !m_pView->IsEntryVisible(pEntry) )
         return false;
 
-    tools::Long nY = GetEntryLine( pEntry ) / m_pView->GetColumnsCount() * 
m_pView->GetEntryHeight();
+    tools::Long nY = GetEntryLine( pEntry );
     if( nY < 0 )
         return false;
 
-    tools::Long nMax = m_nVisibleCount / m_pView->GetColumnsCount() * 
m_pView->GetEntryHeight();
-    if( nY >= nMax )
+    tools::Long height = GetEntrySize(*pEntry).Height();
+    if (nY + height > m_aOutputSize.Height())
         return false;
 
-    tools::Long nStart = GetEntryLine( pEntry ) - GetEntryLine( m_pStartEntry 
);
-    return nStart >= 0;
+    return true;
 }
 
 void IconViewImpl::AdjustScrollBars( Size& rSize )
@@ -270,20 +381,36 @@ void IconViewImpl::AdjustScrollBars( Size& rSize )
     const WinBits nWindowStyle = m_pView->GetStyle();
     bool bVerSBar = ( nWindowStyle & WB_VSCROLL ) != 0;
 
-    // number of entries that are not collapsed
-    sal_uLong nTotalCount = m_pView->GetVisibleCount();
-
     // number of entries visible within the view
-    m_nVisibleCount = aOSize.Height() / nEntryHeight * 
m_pView->GetColumnsCount();
+    const tools::Long nVisibleRows = aOSize.Height() / nEntryHeight;
+    m_nVisibleCount = nVisibleRows * m_pView->GetColumnsCount();
 
-    tools::Long nRows = ( nTotalCount / m_pView->GetColumnsCount() ) + 1;
+    tools::Long nTotalRows = 0;
+    tools::Long totalHeight = 0;
+    auto CountRowsAndHeight = [&nTotalRows, &totalHeight](const EntryAreaInfo& 
info)
+    {
+        totalHeight = std::max(totalHeight, info.area.Bottom());
+        if (info.column == 0 && !IsSeparator(info.entry))
+            ++nTotalRows;
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(CountRowsAndHeight);
 
     // do we need a vertical scrollbar?
-    if( bVerSBar || nTotalCount > m_nVisibleCount )
+    if( bVerSBar || totalHeight > aOSize.Height())
     {
         nResult = 1;
     }
 
+    // do we need a Horizontal scrollbar?
+    bool bHorSBar = (nWindowStyle & WB_HSCROLL) != 0;
+    if (bHorSBar || m_pView->GetEntryWidth() > aOSize.Width())
+    {
+        nResult += 2;
+        m_aHorSBar->SetRange(Range(0, m_pView->GetEntryWidth()));
+        m_aHorSBar->SetVisibleSize(aOSize.Width());
+    }
+
     PositionScrollBars( aOSize, nResult );
 
     // adapt Range, VisibleRange etc.
@@ -296,8 +423,9 @@ void IconViewImpl::AdjustScrollBars( Size& rSize )
     // vertical scrollbar
     if( !m_bInVScrollHdl )
     {
-        m_aVerSBar->SetPageSize( nTotalCount );
-        m_aVerSBar->SetVisibleSize( nTotalCount - nRows );
+        m_aVerSBar->SetRange(Range(0, nTotalRows));
+        m_aVerSBar->SetPageSize(nVisibleRows);
+        m_aVerSBar->SetVisibleSize(nVisibleRows);
     }
     else
     {
@@ -309,6 +437,11 @@ void IconViewImpl::AdjustScrollBars( Size& rSize )
     else
         m_aVerSBar->Hide();
 
+    if (nResult & 0x0002)
+        m_aHorSBar->Show();
+    else
+        m_aHorSBar->Hide();
+
     rSize = aOSize;
 }
 
@@ -321,29 +454,33 @@ SvTreeListEntry* IconViewImpl::GetEntry( const Point& 
rPoint ) const
         || !m_pView->GetEntryWidth())
         return nullptr;
 
-    sal_uInt16 nClickedEntry = static_cast<sal_uInt16>(rPoint.Y() / 
m_pView->GetEntryHeight() * m_pView->GetColumnsCount() + rPoint.X() / 
m_pView->GetEntryWidth() );
-    sal_uInt16 nTemp = nClickedEntry;
-    SvTreeListEntry* pEntry = m_pView->NextVisible(m_pStartEntry, nTemp);
-    if( nTemp != nClickedEntry )
-        pEntry = nullptr;
+    SvTreeListEntry* pEntry = nullptr;
+    auto FindEntryByPos = [&pEntry, &rPoint](const EntryAreaInfo& info)
+    {
+        if (info.area.Contains(rPoint))
+        {
+            pEntry = info.entry;
+            return CallbackResult::Stop;
+        }
+        else if (info.area.Top() > rPoint.Y())
+        {
+            return CallbackResult::Stop; // we are already below the clicked 
row
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(FindEntryByPos, true);
+
     return pEntry;
 }
 
 void IconViewImpl::SyncVerThumb()
 {
-    if( m_pStartEntry )
-    {
-        tools::Long nEntryPos = m_pView->GetVisiblePos( m_pStartEntry );
-        m_aVerSBar->SetThumbPos( nEntryPos );
-    }
-    else
-        m_aVerSBar->SetThumbPos( 0 );
+    m_aVerSBar->SetThumbPos(GetEntryRow(m_pStartEntry));
 }
 
 void IconViewImpl::UpdateAll( bool bInvalidateCompleteView )
 {
     FindMostRight();
-    m_aVerSBar->SetRange( Range( 0, m_pView->GetVisibleCount() ) );
     SyncVerThumb();
     FillView();
     ShowVerSBar();
@@ -384,25 +521,6 @@ void IconViewImpl::Paint(vcl::RenderContext& 
rRenderContext, const tools::Rectan
         m_pStartEntry = m_pView->First();
     }
 
-    tools::Long nRectHeight = rRect.GetHeight();
-    tools::Long nRectWidth = rRect.GetWidth();
-    tools::Long nEntryHeight = m_pView->GetEntryHeight();
-    tools::Long nEntryWidth = m_pView->GetEntryWidth();
-
-    // calculate area for the entries we want to draw
-    sal_uInt16 nStartId = static_cast<sal_uInt16>(rRect.Top() / nEntryHeight * 
m_pView->GetColumnsCount() + (rRect.Left() / nEntryWidth));
-    sal_uInt16 nCount = static_cast<sal_uInt16>(( nRectHeight / nEntryHeight + 
1 ) * nRectWidth / nEntryWidth);
-    nCount += 2; // don't miss an entry
-
-    tools::Long nY = nStartId / m_pView->GetColumnsCount() * nEntryHeight;
-    tools::Long nX = 0;
-    SvTreeListEntry* pEntry = m_pStartEntry;
-    while (nStartId && pEntry)
-    {
-        pEntry = m_pView->NextVisible(pEntry);
-        nStartId--;
-    }
-
     if (!m_pCursor && !mbNoAutoCurEntry)
     {
         // do not select if multiselection or explicit set
@@ -410,18 +528,20 @@ void IconViewImpl::Paint(vcl::RenderContext& 
rRenderContext, const tools::Rectan
         SetCursor(m_pStartEntry, bNotSelect);
     }
 
-    for(sal_uInt16 n = 0; n< nCount && pEntry; n++)
+    auto PaintEntry = [iconView = static_cast<IconView*>(m_pView.get()), 
&rRect,
+                       &rRenderContext](const EntryAreaInfo& info)
     {
-        static_cast<IconView*>(m_pView.get())->PaintEntry(*pEntry, nX, nY, 
rRenderContext);
-        nX += nEntryWidth;
-
-        if(nX + m_pView->GetEntryWidth() > nEntryWidth * 
m_pView->GetColumnsCount())
+        if (!info.area.GetIntersection(rRect).IsEmpty())
         {
-            nY += nEntryHeight;
-            nX = 0;
+            iconView->PaintEntry(*info.entry, info.area.Left(), 
info.area.Top(), rRenderContext);
         }
-        pEntry = m_pView->NextVisible(pEntry);
-    }
+        else if (info.area.Top() > rRect.Bottom())
+        {
+            return CallbackResult::Stop; // we are already below the last 
visible row
+        }
+        return CallbackResult::Continue;
+    };
+    IterateVisibleEntryAreas(PaintEntry, true);
 
     m_nFlags &= ~LBoxFlags::DeselectAll;
     rRenderContext.SetClipRegion();
@@ -432,16 +552,14 @@ void IconViewImpl::InvalidateEntry( tools::Long nId ) 
const
 {
     if( m_nFlags & LBoxFlags::InPaint )
         return;
+    if (nId < 0)
+        return;
 
+    // nId is a Y coordinate of the top of the element, coming from 
GetEntryLine
     tools::Rectangle aRect( GetVisibleArea() );
-    tools::Long nMaxBottom = aRect.Bottom();
-    aRect.SetTop( nId / m_pView->GetColumnsCount() * m_pView->GetEntryHeight() 
);
-    aRect.SetBottom( aRect.Top() ); 
aRect.AdjustBottom(m_pView->GetEntryHeight() );
-
-    if( aRect.Top() > nMaxBottom )
+    if (nId > aRect.Bottom())
         return;
-    if( aRect.Bottom() > nMaxBottom )
-        aRect.SetBottom( nMaxBottom );
+    aRect.SetTop(nId); // Invalidate everything below
     m_pView->Invalidate( aRect );
 }
 
@@ -468,9 +586,6 @@ bool IconViewImpl::KeyInput( const KeyEvent& rKEvt )
 
     bool bHandled = true;
 
-    tools::Long i;
-    tools::Long nColumns = m_pView->GetColumnsCount();
-
     switch( aCode )
     {
         case KEY_LEFT:
@@ -531,72 +646,68 @@ bool IconViewImpl::KeyInput( const KeyEvent& rKEvt )
 
         case KEY_UP:
         {
-            if( !IsEntryInView( m_pCursor ) )
-                MakeVisible( m_pCursor );
-
-            pNewCursor = m_pCursor;
-            for( i = 0; i < nColumns && pNewCursor; i++)
-            {
-                do
-                {
-                    pNewCursor = m_pView->PrevVisible(pNewCursor);
-                } while( pNewCursor && !IsSelectable(pNewCursor) );
-            }
-
-            // if there is no next entry, take the current one
-            // this ensures that in case of _one_ entry in the list, this 
entry is selected when pressing
-            // the cursor key
-            if ( !pNewCursor && m_pCursor )
-                pNewCursor = m_pCursor;
+            pNewCursor = GoToPrevRow(m_pCursor, 1);
 
             if( pNewCursor )
             {
                 m_aSelEng.CursorPosChanging( bShift, bMod1 );
                 SetCursor( pNewCursor, bMod1 );     // no selection, when Ctrl 
is on
-                if( !IsEntryInView( pNewCursor ) )
-                    KeyUp( false );
+                ScrollTo(pNewCursor);
             }
             break;
         }
 
         case KEY_DOWN:
         {
-            if( !IsEntryInView( m_pCursor ) )
-                MakeVisible( m_pCursor );
+            pNewCursor = GoToNextRow(m_pCursor, 1);
 
-            pNewCursor = m_pCursor;
-            for( i = 0; i < nColumns && pNewCursor; i++)
+            if( pNewCursor )
             {
-                do
-                {
-                    pNewCursor = m_pView->NextVisible(pNewCursor);
-                } while( pNewCursor && !IsSelectable(pNewCursor) );
+                m_aSelEng.CursorPosChanging( bShift, bMod1 );
+                ScrollTo(pNewCursor);
+                SetCursor(pNewCursor, bMod1); // no selection, when Ctrl is on
             }
+            else
+                KeyDown( false );   // because scrollbar range might still
+                                        // allow scrolling
+            break;
+        }
 
-            // if there is no next entry, take the current one
-            // this ensures that in case of _one_ entry in the list, this 
entry is selected when pressing
-            // the cursor key
-            if ( !pNewCursor && m_pCursor )
-                pNewCursor = m_pCursor;
+        case KEY_PAGEUP:
+            if (!bMod1)
+            {
+                const sal_uInt16 nDelta = m_aVerSBar->GetPageSize();
+                pNewCursor = GoToPrevRow(m_pCursor, nDelta);
 
-            if( pNewCursor )
+                if (pNewCursor)
+                {
+                    m_aSelEng.CursorPosChanging(bShift, bMod1);
+                    ScrollTo(pNewCursor);
+                    SetCursor(pNewCursor);
+                }
+            }
+            else
+                bHandled = false;
+            break;
+
+        case KEY_PAGEDOWN:
+            if (!bMod1)
             {
-                m_aSelEng.CursorPosChanging( bShift, bMod1 );
-                if( IsEntryInView( pNewCursor ) )
-                    SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl 
is on
-                else
+                const sal_uInt16 nDelta = m_aVerSBar->GetPageSize();
+                pNewCursor = GoToNextRow(m_pCursor, nDelta);
+
+                if (pNewCursor)
                 {
-                    if( m_pCursor )
-                        m_pView->Select( m_pCursor, false );
-                    KeyDown( false );
-                    SetCursor( pNewCursor, bMod1 ); // no selection, when Ctrl 
is on
+                    m_aSelEng.CursorPosChanging(bShift, bMod1);
+                    ScrollTo(pNewCursor);
+                    SetCursor(pNewCursor);
                 }
+                else
+                    KeyDown(false);
             }
             else
-                KeyDown( false );   // because scrollbar range might still
-                                        // allow scrolling
+                bHandled = false;
             break;
-        }
 
         case KEY_RETURN:
         {
@@ -613,19 +724,13 @@ bool IconViewImpl::KeyInput( const KeyEvent& rKEvt )
                 pNewCursor = m_pView->PrevVisible(pNewCursor);
             }
 
-            m_pStartEntry = pNewCursor;
-
-            while( m_pStartEntry && m_pView->GetAbsPos( m_pStartEntry ) % 
m_pView->GetColumnsCount() != 0 )
-            {
-                m_pStartEntry = m_pView->PrevVisible(m_pStartEntry);
-            }
+            SetStartEntry(pNewCursor);
 
             if( pNewCursor && pNewCursor != m_pCursor)
             {
 //              SelAllDestrAnch( false );
                 m_aSelEng.CursorPosChanging( bShift, bMod1 );
                 SetCursor( pNewCursor );
-                SyncVerThumb();
             }
 
             bHandled = true;
diff --git a/vcl/source/treelist/iconviewimpl.hxx 
b/vcl/source/treelist/iconviewimpl.hxx
index be038eee587d..144a5a3adbab 100644
--- a/vcl/source/treelist/iconviewimpl.hxx
+++ b/vcl/source/treelist/iconviewimpl.hxx
@@ -60,6 +60,34 @@ protected:
 
     void SyncVerThumb() override;
     void AdjustScrollBars(Size& rSize) override;
+
+private:
+    enum class CallbackResult
+    {
+        Continue,
+        Stop, // Stop iteration
+    };
+    struct EntryAreaInfo
+    {
+        SvTreeListEntry* entry;
+        short column;
+        tools::Rectangle area; // The area for the entry
+    };
+    using IterateEntriesFunc = std::function<CallbackResult(const 
EntryAreaInfo&)>;
+
+    void IterateVisibleEntryAreas(const IterateEntriesFunc& f, bool 
fromStartEntry = false) const;
+
+    Size GetEntrySize(const SvTreeListEntry& entry) const;
+    // Get first entry at most n rows above; nullptr if no rows above
+    SvTreeListEntry* GoToPrevRow(SvTreeListEntry* pEntry, int n) const;
+    // Get first entry at most n rows below; nullptr if no rows below
+    SvTreeListEntry* GoToNextRow(SvTreeListEntry* pEntry, int n) const;
+
+    SvTreeListEntry* GetFirstInRow(SvTreeListEntry* pEntry) const;
+
+    tools::Long GetEntryRow(const SvTreeListEntry* entry) const;
+    void SetStartEntry(SvTreeListEntry* entry);
+    void ScrollTo(SvTreeListEntry* entry);
 };
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/treelist/svimpbox.cxx b/vcl/source/treelist/svimpbox.cxx
index fd3f43263c45..cea89cdbd33c 100644
--- a/vcl/source/treelist/svimpbox.cxx
+++ b/vcl/source/treelist/svimpbox.cxx
@@ -49,11 +49,11 @@ Image*  SvImpLBox::s_pDefExpanded       = nullptr;
 oslInterlockedCount SvImpLBox::s_nImageRefCount   = 0;
 
 SvImpLBox::SvImpLBox( SvTreeListBox* pLBView, SvTreeList* pLBTree, WinBits 
nWinStyle)
-    : m_aHorSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_HSCROLL))
-    , m_aScrBarBox(VclPtr<ScrollBarBox>::Create(pLBView))
+    : m_aScrBarBox(VclPtr<ScrollBarBox>::Create(pLBView))
     , m_aFctSet(this, pLBView)
     , mbForceMakeVisible (false)
     , m_aEditIdle("SvImpLBox m_aEditIdle")
+    , m_aHorSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_HSCROLL))
     , m_aVerSBar(VclPtr<ScrollBar>::Create(pLBView, WB_DRAG | WB_VSCROLL))
     , m_aOutputSize(0, 0)
     , mbNoAutoCurEntry(false)
diff --git a/vcl/source/treelist/treelistbox.cxx 
b/vcl/source/treelist/treelistbox.cxx
index 5092c64cb83d..962dd60cf53b 100644
--- a/vcl/source/treelist/treelistbox.cxx
+++ b/vcl/source/treelist/treelistbox.cxx
@@ -1593,7 +1593,7 @@ void SvTreeListBox::SetExpandedEntryBmp( SvTreeListEntry* 
pEntry, const Image& a
     pItem->SetBitmap2( aBmp );
 
     ModelHasEntryInvalidated(pEntry);
-    SetEntryHeight( pEntry );
+    CalcEntryHeight( pEntry );
     Size aSize = aBmp.GetSizePixel();
     short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, 
static_cast<short>(aSize.Width()) );
     if( nWidth > nContextBmpWidthMax )
@@ -1611,7 +1611,7 @@ void SvTreeListBox::SetCollapsedEntryBmp(SvTreeListEntry* 
pEntry,const Image& aB
     pItem->SetBitmap1( aBmp );
 
     ModelHasEntryInvalidated(pEntry);
-    SetEntryHeight( pEntry );
+    CalcEntryHeight( pEntry );
     Size aSize = aBmp.GetSizePixel();
     short nWidth = pImpl->UpdateContextBmpWidthVector( pEntry, 
static_cast<short>(aSize.Width()) );
     if( nWidth > nContextBmpWidthMax )
@@ -1663,7 +1663,7 @@ void SvTreeListBox::ImpEntryInserted( SvTreeListEntry* 
pEntry )
             nTreeFlags |= SvTreeFlags::RECALCTABS;
         }
     }
-    SetEntryHeight( pEntry );
+    CalcEntryHeight( pEntry );
 
     if( !(nTreeFlags & SvTreeFlags::CHKBTN) )
         return;
@@ -1976,7 +1976,7 @@ void SvTreeListBox::SetDragDropMode( DragDropMode nDDMode 
)
     pImpl->SetDragDropMode( nDDMode );
 }
 
-void SvTreeListBox::SetEntryHeight( SvTreeListEntry const * pEntry )
+void SvTreeListBox::CalcEntryHeight( SvTreeListEntry const * pEntry )
 {
     short nHeightMax=0;
     sal_uInt16 nCount = pEntry->ItemCount();
diff --git a/vcl/unx/gtk3/gtkinst.cxx b/vcl/unx/gtk3/gtkinst.cxx
index 0575aa8c3c7a..6536a0b3ffea 100644
--- a/vcl/unx/gtk3/gtkinst.cxx
+++ b/vcl/unx/gtk3/gtkinst.cxx
@@ -16288,6 +16288,12 @@ public:
         enable_notify_events();
     }
 
+    virtual void insert_separator(int /* pos */, const OUString* /* pId */) 
override
+    {
+        // TODO: can't just copy from GtkInstanceTreeView, since there's
+        // no IconView analog for gtk_tree_view_get_row_separator_func
+    }
+
     virtual void connect_query_tooltip(const Link<const weld::TreeIter&, 
OUString>& rLink) override
     {
         weld::IconView::connect_query_tooltip(rLink);
commit 1dbf0f53e2e690a3914512785cad1a2f0f46e45d
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Thu May 26 22:28:47 2022 +0200
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Jun 1 16:29:57 2022 +0200

    Don't resize to parent window
    
    The parent may contain other controls (e.g. Fontworks dialog's grid
    contains also a label above the icon view). The control already has
    the correct size; just use it.
    
    Fixes vertical scrollbar being partially hidden behind control's
    bottom in non-GTK Fontworks dialog.
    
    Change-Id: I424999777f24bbb28619d07a9de782057f0257a0
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135003
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/vcl/source/treelist/iconview.cxx b/vcl/source/treelist/iconview.cxx
index c1ed4b028726..f54616e7fad7 100644
--- a/vcl/source/treelist/iconview.cxx
+++ b/vcl/source/treelist/iconview.cxx
@@ -41,13 +41,11 @@ IconView::IconView(vcl::Window* pParent, WinBits nBits)
 
 void IconView::Resize()
 {
-    Size aBoxSize = Control::GetParent()->GetOutputSizePixel();
+    Size aBoxSize = Control::GetOutputSizePixel();
 
     if (!aBoxSize.Width())
         return;
 
-    SetSizePixel(aBoxSize);
-
     nColumns = aBoxSize.Width() / nEntryWidth;
 
     SvTreeListBox::Resize();

Reply via email to