[Libreoffice-commits] core.git: include/vcl vcl/inc vcl/source vcl/unx

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Tue Jun 2 14:21:01 UTC 2020


 include/vcl/treelistentry.hxx   |    4 -
 include/vcl/weld.hxx            |    3 
 vcl/inc/strings.hrc             |    2 
 vcl/source/app/salvtables.cxx   |  121 ++++++++++++++++++++++++----------------
 vcl/source/treelist/svlbitm.cxx |   33 ++++++++++
 vcl/unx/gtk3/gtk3gtkinst.cxx    |   79 +++++++++++++++++++-------
 6 files changed, 171 insertions(+), 71 deletions(-)

New commits:
commit 9b498e2b88ffae77717bab2f7a308b83d0a7ae80
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Mon Jun 1 10:39:30 2020 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Tue Jun 2 16:20:18 2020 +0200

    add separators to TreeView
    
    Change-Id: I5e49913dfac82c1243d16ed0a0267a3647f51311
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/95270
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/include/vcl/treelistentry.hxx b/include/vcl/treelistentry.hxx
index 8cc808bb09c1..093fa1751d8e 100644
--- a/include/vcl/treelistentry.hxx
+++ b/include/vcl/treelistentry.hxx
@@ -39,13 +39,15 @@ enum class SvTLEntryFlags
     DISABLE_DROP        = 0x0002,
     // is set if RequestingChildren has not set any children
     NO_NODEBMP          = 0x0004,
+    // is set if this is a separator line
+    IS_SEPARATOR        = 0x0008,
     // entry had or has children
     HAD_CHILDREN        = 0x0010,
     SEMITRANSPARENT     = 0x8000,      // draw semi-transparent entry bitmaps
 };
 namespace o3tl
 {
-    template<> struct typed_flags<SvTLEntryFlags> : is_typed_flags<SvTLEntryFlags, 0x8017> {};
+    template<> struct typed_flags<SvTLEntryFlags> : is_typed_flags<SvTLEntryFlags, 0x801f> {};
 }
 
 class VCL_DLLPUBLIC SvTreeListEntry
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 9d01a0fc7022..d8d6b1a0492d 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -888,6 +888,9 @@ public:
         insert(nullptr, -1, &rStr, &rId, nullptr, &rImage, nullptr, false, nullptr);
     }
 
+    virtual void insert_separator(int pos, const OUString& rId) = 0;
+    void append_separator(const OUString& rId) { insert_separator(-1, rId); }
+
     void connect_changed(const Link<TreeView&, void>& rLink) { m_aChangeHdl = rLink; }
 
     /* A row is "activated" when the user double clicks a treeview row. It may
diff --git a/vcl/inc/strings.hrc b/vcl/inc/strings.hrc
index e378b54814bd..d97ef387d9f4 100644
--- a/vcl/inc/strings.hrc
+++ b/vcl/inc/strings.hrc
@@ -153,6 +153,8 @@
 #define STR_WIZDLG_NEXT                              NC_("STR_WIZDLG_NEXT", "~Next >")
 #define STR_WIZDLG_PREVIOUS                          NC_("STR_WIZDLG_PREVIOUS", "< Bac~k")
 
+#define STR_SEPARATOR                                NC_("STR_SEPARATOR", "Separator")
+
 #endif // INCLUDED_VCL_INC_STRINGS_HRC
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index 1f0c05e292db..2b0e1c9c28cb 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -3258,6 +3258,71 @@ private:
         pEntry->AddItem(std::move(xCell));
     }
 
+    void do_insert(const weld::TreeIter* pParent, int pos, const OUString* pStr,
+                   const OUString* pId, const OUString* pIconName,
+                   VirtualDevice* pImageSurface, const OUString* pExpanderName,
+                   bool bChildrenOnDemand, weld::TreeIter* pRet, bool bIsSeparator)
+    {
+        disable_notify_events();
+        const SalInstanceTreeIter* pVclIter = static_cast<const SalInstanceTreeIter*>(pParent);
+        SvTreeListEntry* iter = pVclIter ? pVclIter->iter : nullptr;
+        auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
+        void* pUserData;
+        if (pId)
+        {
+            m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
+            pUserData = m_aUserData.back().get();
+        }
+        else
+            pUserData = nullptr;
+
+        SvTreeListEntry* pEntry = new SvTreeListEntry;
+        if (bIsSeparator)
+            pEntry->SetFlags(pEntry->GetFlags() | SvTLEntryFlags::IS_SEPARATOR);
+        if (pIconName || pImageSurface)
+        {
+            Image aImage(pIconName ? createImage(*pIconName) : createImage(*pImageSurface));
+            pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage, false));
+        }
+        else
+        {
+            Image aDummy;
+            pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
+        }
+        if (pStr)
+            AddStringItem(pEntry, *pStr, 0);
+        pEntry->SetUserData(pUserData);
+        m_xTreeView->Insert(pEntry, iter, nInsertPos);
+
+        if (pExpanderName)
+        {
+            Image aImage(createImage(*pExpanderName));
+            m_xTreeView->SetExpandedEntryBmp(pEntry, aImage);
+            m_xTreeView->SetCollapsedEntryBmp(pEntry, aImage);
+        }
+
+        if (pRet)
+        {
+            SalInstanceTreeIter* pVclRetIter = static_cast<SalInstanceTreeIter*>(pRet);
+            pVclRetIter->iter = pEntry;
+        }
+
+        if (bChildrenOnDemand)
+        {
+            SvTreeListEntry* pPlaceHolder = m_xTreeView->InsertEntry("<dummy>", pEntry, false, 0, nullptr);
+            SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder);
+            pViewData->SetSelectable(false);
+        }
+
+        if (bIsSeparator)
+        {
+            SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
+            pViewData->SetSelectable(false);
+        }
+
+        enable_notify_events();
+    }
+
 public:
     SalInstanceTreeView(SvTabListBox* pTreeView, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
         : SalInstanceContainer(pTreeView, pBuilder, bTakeOwnership)
@@ -3433,55 +3498,15 @@ public:
                         VirtualDevice* pImageSurface, const OUString* pExpanderName,
                         bool bChildrenOnDemand, weld::TreeIter* pRet) override
     {
-        disable_notify_events();
-        const SalInstanceTreeIter* pVclIter = static_cast<const SalInstanceTreeIter*>(pParent);
-        SvTreeListEntry* iter = pVclIter ? pVclIter->iter : nullptr;
-        auto nInsertPos = pos == -1 ? TREELIST_APPEND : pos;
-        void* pUserData;
-        if (pId)
-        {
-            m_aUserData.emplace_back(std::make_unique<OUString>(*pId));
-            pUserData = m_aUserData.back().get();
-        }
-        else
-            pUserData = nullptr;
-
-        SvTreeListEntry* pEntry = new SvTreeListEntry;
-        if (pIconName || pImageSurface)
-        {
-            Image aImage(pIconName ? createImage(*pIconName) : createImage(*pImageSurface));
-            pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aImage, aImage, false));
-        }
-        else
-        {
-            Image aDummy;
-            pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
-        }
-        if (pStr)
-            AddStringItem(pEntry, *pStr, 0);
-        pEntry->SetUserData(pUserData);
-        m_xTreeView->Insert(pEntry, iter, nInsertPos);
-
-        if (pExpanderName)
-        {
-            Image aImage(createImage(*pExpanderName));
-            m_xTreeView->SetExpandedEntryBmp(pEntry, aImage);
-            m_xTreeView->SetCollapsedEntryBmp(pEntry, aImage);
-        }
-
-        if (pRet)
-        {
-            SalInstanceTreeIter* pVclRetIter = static_cast<SalInstanceTreeIter*>(pRet);
-            pVclRetIter->iter = pEntry;
-        }
+        do_insert(pParent, pos, pStr, pId, pIconName, pImageSurface, pExpanderName,
+                  bChildrenOnDemand, pRet, false);
+    }
 
-        if (bChildrenOnDemand)
-        {
-            SvTreeListEntry* pPlaceHolder = m_xTreeView->InsertEntry("<dummy>", pEntry, false, 0, nullptr);
-            SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pPlaceHolder);
-            pViewData->SetSelectable(false);
-        }
-        enable_notify_events();
+    virtual void insert_separator(int pos, const OUString& /*rId*/) override
+    {
+        OUString sSep(VclResId(STR_SEPARATOR));
+        do_insert(nullptr, pos, &sSep, nullptr, nullptr, nullptr, nullptr,
+                  false, nullptr, true);
     }
 
     virtual void
diff --git a/vcl/source/treelist/svlbitm.cxx b/vcl/source/treelist/svlbitm.cxx
index da5074283545..6467efcbf8ff 100644
--- a/vcl/source/treelist/svlbitm.cxx
+++ b/vcl/source/treelist/svlbitm.cxx
@@ -25,6 +25,7 @@
 #include <vcl/toolkit/button.hxx>
 #include <vcl/decoview.hxx>
 #include <vcl/salnativewidgets.hxx>
+#include <vcl/settings.hxx>
 
 struct SvLBoxButtonData_Impl
 {
@@ -196,12 +197,35 @@ SvLBoxItemType SvLBoxString::GetType() const
     return SvLBoxItemType::String;
 }
 
+namespace
+{
+    void drawSeparator(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRegion)
+    {
+        Color aOldLineColor(rRenderContext.GetLineColor());
+        const StyleSettings& rStyle = rRenderContext.GetSettings().GetStyleSettings();
+        Point aTmpPos = rRegion.TopLeft();
+        Size aSize = rRegion.GetSize();
+        aTmpPos.AdjustY(aSize.Height() / 2 );
+        rRenderContext.SetLineColor(rStyle.GetShadowColor());
+        rRenderContext.DrawLine(aTmpPos, Point(aSize.Width() + aTmpPos.X(), aTmpPos.Y()));
+        rRenderContext.SetLineColor(aOldLineColor);
+    }
+}
+
 void SvLBoxString::Paint(
     const Point& rPos, SvTreeListBox& rDev, vcl::RenderContext& rRenderContext,
     const SvViewDataEntry* /*pView*/, const SvTreeListEntry& rEntry)
 {
-    Size aSize;
     DrawTextFlags nStyle = (rDev.IsEnabled() && !mbDisabled) ? DrawTextFlags::NONE : DrawTextFlags::Disable;
+    if (bool(rEntry.GetFlags() & SvTLEntryFlags::IS_SEPARATOR))
+    {
+        Point aStartPos(0, rPos.Y() - 2);
+        tools::Rectangle aRegion(aStartPos, Size(rDev.GetSizePixel().Width(), 4));
+        drawSeparator(rRenderContext, aRegion);
+        return;
+    }
+
+    Size aSize;
     if (rDev.IsEntryMnemonicsEnabled())
         nStyle |= DrawTextFlags::Mnemonic;
     if (rDev.TextCenterAndClipEnabled())
@@ -267,6 +291,13 @@ void SvLBoxString::InitViewData(
     if( !pViewData )
         pViewData = pView->GetViewDataItem( pEntry, this );
 
+    if (bool(pEntry->GetFlags() & SvTLEntryFlags::IS_SEPARATOR))
+    {
+        pViewData->mnWidth = -1;
+        pViewData->mnHeight = 0;
+        return;
+    }
+
     if (mbEmphasized)
     {
         pView->Push();
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index c0bc216f0011..7e851797806c 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -9050,6 +9050,31 @@ tools::Rectangle get_row_area(GtkTreeView* pTreeView, GList* pColumns, GtkTreePa
     return aRet;
 }
 
+struct GtkTreeRowReferenceDeleter
+{
+    void operator()(GtkTreeRowReference* p) const
+    {
+        gtk_tree_row_reference_free(p);
+    }
+};
+
+bool separator_function(GtkTreePath* path, const std::vector<std::unique_ptr<GtkTreeRowReference, GtkTreeRowReferenceDeleter>>& rSeparatorRows)
+{
+    bool bFound = false;
+    for (auto& a : rSeparatorRows)
+    {
+        GtkTreePath* seppath = gtk_tree_row_reference_get_path(a.get());
+        if (seppath)
+        {
+            bFound = gtk_tree_path_compare(path, seppath) == 0;
+            gtk_tree_path_free(seppath);
+        }
+        if (bFound)
+            break;
+    }
+    return bFound;
+}
+
 class GtkInstanceTreeView : public GtkInstanceContainer, public virtual weld::TreeView
 {
 private:
@@ -9073,6 +9098,8 @@ private:
     // currently expanding parent that logically, but not currently physically,
     // contain placeholders
     o3tl::sorted_vector<GtkTreePath*, CompareGtkTreePath> m_aExpandingPlaceHolderParents;
+    // which rows are separators (rare)
+    std::vector<std::unique_ptr<GtkTreeRowReference, GtkTreeRowReferenceDeleter>> m_aSeparatorRows;
     std::vector<GtkSortType> m_aSavedSortTypes;
     std::vector<int> m_aSavedSortColumns;
     std::vector<int> m_aViewColToModelCol;
@@ -9183,6 +9210,20 @@ private:
         }
     }
 
+    bool separator_function(GtkTreePath* path)
+    {
+        return ::separator_function(path, m_aSeparatorRows);
+    }
+
+    static gboolean separatorFunction(GtkTreeModel* pTreeModel, GtkTreeIter* pIter, gpointer widget)
+    {
+        GtkInstanceTreeView* pThis = static_cast<GtkInstanceTreeView*>(widget);
+        GtkTreePath* path = gtk_tree_model_get_path(pTreeModel, pIter);
+        bool bRet = pThis->separator_function(path);
+        gtk_tree_path_free(path);
+        return bRet;
+    }
+
     OUString get(const GtkTreeIter& iter, int col) const
     {
         GtkTreeModel *pModel = GTK_TREE_MODEL(m_pTreeStore);
@@ -9942,6 +9983,20 @@ public:
         enable_notify_events();
     }
 
+    virtual void insert_separator(int pos, const OUString& rId) override
+    {
+        disable_notify_events();
+        GtkTreeIter iter;
+        if (!gtk_tree_view_get_row_separator_func(m_pTreeView))
+            gtk_tree_view_set_row_separator_func(m_pTreeView, separatorFunction, this, nullptr);
+        insert_row(iter, nullptr, pos, &rId, nullptr, nullptr, nullptr, nullptr);
+        GtkTreeModel* pTreeModel = GTK_TREE_MODEL(m_pTreeStore);
+        GtkTreePath* pPath = gtk_tree_model_get_path(pTreeModel, &iter);
+        m_aSeparatorRows.emplace_back(gtk_tree_row_reference_new(pTreeModel, pPath));
+        gtk_tree_path_free(pPath);
+        enable_notify_events();
+    }
+
     virtual void set_font_color(int pos, const Color& rColor) override
     {
         GtkTreeIter iter;
@@ -10018,6 +10073,8 @@ public:
     virtual void clear() override
     {
         disable_notify_events();
+        gtk_tree_view_set_row_separator_func(m_pTreeView, nullptr, nullptr, nullptr);
+        m_aSeparatorRows.clear();
         gtk_tree_store_clear(m_pTreeStore);
         enable_notify_events();
     }
@@ -12668,14 +12725,6 @@ GtkBuilder* makeComboBoxBuilder()
     return gtk_builder_new_from_file(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8).getStr());
 }
 
-struct GtkTreeRowReferenceDeleter
-{
-    void operator()(GtkTreeRowReference* p) const
-    {
-        gtk_tree_row_reference_free(p);
-    }
-};
-
 // pop down the toplevel combobox menu when something is activated from a custom
 // submenu, i.e. wysiwyg style menu
 class CustomRenderMenuButtonHelper : public MenuHelper
@@ -13077,19 +13126,7 @@ private:
 
     bool separator_function(GtkTreePath* path)
     {
-        bool bFound = false;
-        for (auto& a : m_aSeparatorRows)
-        {
-            GtkTreePath* seppath = gtk_tree_row_reference_get_path(a.get());
-            if (seppath)
-            {
-                bFound = gtk_tree_path_compare(path, seppath) == 0;
-                gtk_tree_path_free(seppath);
-            }
-            if (bFound)
-                break;
-        }
-        return bFound;
+        return ::separator_function(path, m_aSeparatorRows);
     }
 
     bool separator_function(int pos)


More information about the Libreoffice-commits mailing list