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

Caolán McNamara (via logerrit) logerrit at kemper.freedesktop.org
Sat Apr 4 17:52:16 UTC 2020


 include/vcl/svlbitm.hxx             |    3 
 include/vcl/treelistbox.hxx         |   11 +
 include/vcl/weld.hxx                |   26 ++
 include/vcl/weldutils.hxx           |    4 
 vcl/source/app/salvtables.cxx       |   52 ++++-
 vcl/source/treelist/svlbitm.cxx     |   30 ++-
 vcl/source/treelist/treelistbox.cxx |   10 +
 vcl/source/window/builder.cxx       |   19 +
 vcl/unx/gtk3/gtk3gtkinst.cxx        |  347 ++++++++++++++++++++++++++++++++++++
 9 files changed, 493 insertions(+), 9 deletions(-)

New commits:
commit 338403833ec43539728d7609e243ae6070aafb3f
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Fri Apr 3 19:30:00 2020 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Sat Apr 4 19:51:52 2020 +0200

    add ability to have custom renderer treeview rows
    
    Change-Id: Ia085242dee0aaa19f9aefa2a3cf71bc827fcca73
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91658
    Tested-by: Jenkins
    Tested-by: Caolán McNamara <caolanm at redhat.com>
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/include/vcl/svlbitm.hxx b/include/vcl/svlbitm.hxx
index dc8cde9bcb02..abe2446ade11 100644
--- a/include/vcl/svlbitm.hxx
+++ b/include/vcl/svlbitm.hxx
@@ -105,6 +105,7 @@ class VCL_DLLPUBLIC SvLBoxString : public SvLBoxItem
 {
 private:
     bool mbEmphasized;
+    bool mbCustom;
     double mfAlign;
 protected:
     OUString maText;
@@ -126,6 +127,8 @@ public:
     void Emphasize(bool bEmphasize) { mbEmphasized = bEmphasize; }
     bool IsEmphasized() const { return mbEmphasized; }
 
+    void SetCustomRender() { mbCustom = true; }
+
     const OUString& GetText() const
     {
         return maText;
diff --git a/include/vcl/treelistbox.hxx b/include/vcl/treelistbox.hxx
index 179f27fe4cb6..e56fd1081fb2 100644
--- a/include/vcl/treelistbox.hxx
+++ b/include/vcl/treelistbox.hxx
@@ -177,6 +177,9 @@ namespace o3tl
 
 struct SvTreeListBoxImpl;
 
+typedef std::pair<vcl::RenderContext&, const SvTreeListEntry&> svtree_measure_args;
+typedef std::tuple<vcl::RenderContext&, const tools::Rectangle&, const SvTreeListEntry&> svtree_render_args;
+
 class VCL_DLLPUBLIC SvTreeListBox
                 :public Control
                 ,public SvListView
@@ -186,6 +189,7 @@ class VCL_DLLPUBLIC SvTreeListBox
                 ,public vcl::ISearchableStringList
 {
     friend class SvImpLBox;
+    friend class SvLBoxString;
     friend class IconViewImpl;
     friend class TreeControlPeer;
     friend class SalInstanceIconView;
@@ -201,6 +205,8 @@ class VCL_DLLPUBLIC SvTreeListBox
     Link<SvTreeListBox*,void>  aDeselectHdl;
     Link<const CommandEvent&, bool> aPopupMenuHdl;
     Link<const HelpEvent&, bool> aTooltipHdl;
+    Link<svtree_render_args, void> aCustomRenderHdl;
+    Link<svtree_measure_args, Size> aCustomMeasureHdl;
 
     Image           aPrevInsertedExpBmp;
     Image           aPrevInsertedColBmp;
@@ -269,6 +275,9 @@ private:
     // autowidth for the 1st checkbox column
     VCL_DLLPRIVATE void CheckBoxInserted(SvTreeListEntry* pEntry);
 
+    VCL_DLLPRIVATE void DrawCustomEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const SvTreeListEntry& rEntry);
+    VCL_DLLPRIVATE Size MeasureCustomEntry(vcl::RenderContext& rRenderContext, const SvTreeListEntry& rEntry);
+
 protected:
 
     bool            CheckDragAndDropMode( SvTreeListBox const * pSource, sal_Int8 );
@@ -434,6 +443,8 @@ public:
     void            SetExpandedHdl(const Link<SvTreeListBox*,void>& rNewHdl){aExpandedHdl=rNewHdl;}
     void SetPopupMenuHdl(const Link<const CommandEvent&, bool>& rLink) { aPopupMenuHdl = rLink; }
     void SetTooltipHdl(const Link<const HelpEvent&, bool>& rLink) { aTooltipHdl = rLink; }
+    void SetCustomRenderHdl(const Link<svtree_render_args, void>& rLink) { aCustomRenderHdl = rLink; }
+    void SetCustomMeasureHdl(const Link<svtree_measure_args, Size>& rLink) { aCustomMeasureHdl = rLink; }
 
     virtual void    ExpandedHdl();
     virtual bool    ExpandingHdl();
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 15dd5ad91de8..eda59f01783f 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -729,6 +729,12 @@ protected:
     Link<bool&, bool> m_aDragBeginHdl;
     std::function<int(const weld::TreeIter&, const weld::TreeIter&)> m_aCustomSort;
 
+public:
+    typedef std::pair<vcl::RenderContext&, const OUString&> get_size_args;
+    typedef std::tuple<vcl::RenderContext&, const tools::Rectangle&, bool, const OUString&>
+        render_args;
+
+protected:
     std::vector<int> m_aRadioIndexes;
 
     void signal_changed() { m_aChangeHdl.Call(*this); }
@@ -758,6 +764,21 @@ protected:
     Link<const TreeIter&, OUString> m_aQueryTooltipHdl;
     OUString signal_query_tooltip(const TreeIter& rIter) { return m_aQueryTooltipHdl.Call(rIter); }
 
+    Link<render_args, void> m_aRenderHdl;
+    void signal_custom_render(vcl::RenderContext& rDevice, const tools::Rectangle& rRect,
+                              bool bSelected, const OUString& rId)
+    {
+        m_aRenderHdl.Call(
+            std::tuple<vcl::RenderContext&, const tools::Rectangle, bool, const OUString&>(
+                rDevice, rRect, bSelected, rId));
+    }
+
+    Link<get_size_args, Size> m_aGetSizeHdl;
+    Size signal_custom_get_size(vcl::RenderContext& rDevice, const OUString& rId)
+    {
+        return m_aGetSizeHdl.Call(std::pair<vcl::RenderContext&, const OUString&>(rDevice, rId));
+    }
+
 public:
     virtual void connect_query_tooltip(const Link<const TreeIter&, OUString>& rLink)
     {
@@ -1068,6 +1089,11 @@ public:
     OUString const& get_saved_value() const { return m_sSavedValue; }
     bool get_value_changed_from_saved() const { return m_sSavedValue != get_selected_text(); }
 
+    // for custom rendering a cell
+    virtual void set_column_custom_renderer(int nColumn) = 0;
+    void connect_custom_get_size(const Link<get_size_args, Size>& rLink) { m_aGetSizeHdl = rLink; }
+    void connect_custom_render(const Link<render_args, void>& rLink) { m_aRenderHdl = rLink; }
+
     // for dnd
     virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult) = 0;
     virtual tools::Rectangle get_row_area(const weld::TreeIter& rIter) const = 0;
diff --git a/include/vcl/weldutils.hxx b/include/vcl/weldutils.hxx
index 077dab0fa414..cb04f2d74915 100644
--- a/include/vcl/weldutils.hxx
+++ b/include/vcl/weldutils.hxx
@@ -153,7 +153,11 @@ public:
     }
 };
 
+// get the row the iterator is on
 VCL_DLLPUBLIC size_t GetAbsPos(const weld::TreeView& rTreeView, const weld::TreeIter& rIter);
+
+// an entry is visible if all parents are expanded
+VCL_DLLPUBLIC bool IsEntryVisible(const weld::TreeView& rTreeView, const weld::TreeIter& rIter);
 }
 
 #endif
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index d43dda8ffec1..1ae61d3ee21a 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -3263,6 +3263,8 @@ private:
     // currently expanding parent that logically, but not currently physically,
     // contain placeholders
     o3tl::sorted_vector<SvTreeListEntry*> m_aExpandingPlaceHolderParents;
+    // which columns should be custom rendered
+    o3tl::sorted_vector<int> m_aCustomRenders;
     bool m_bDisableCheckBoxAutoWidth;
     int m_nSortColumn;
 
@@ -3283,6 +3285,8 @@ private:
     DECL_LINK(CompareHdl, const SvSortData&, sal_Int32);
     DECL_LINK(PopupMenuHdl, const CommandEvent&, bool);
     DECL_LINK(TooltipHdl, const HelpEvent&, bool);
+    DECL_LINK(CustomRenderHdl, svtree_render_args, void);
+    DECL_LINK(CustomMeasureHdl, svtree_measure_args, Size);
 
     bool IsDummyEntry(SvTreeListEntry* pEntry) const
     {
@@ -3309,6 +3313,14 @@ private:
             pEntry->SetTextColor(rColor);
     }
 
+    void AddStringItem(SvTreeListEntry* pEntry, const OUString& rStr, int nCol)
+    {
+        auto xCell = std::make_unique<SvLBoxString>(rStr);
+        if (m_aCustomRenders.count(nCol))
+            xCell->SetCustomRender();
+        pEntry->AddItem(std::move(xCell));
+    }
+
 public:
     SalInstanceTreeView(SvTabListBox* pTreeView, SalInstanceBuilder* pBuilder, bool bTakeOwnership)
         : SalInstanceContainer(pTreeView, pBuilder, bTakeOwnership)
@@ -3325,6 +3337,8 @@ public:
         m_xTreeView->SetDoubleClickHdl(LINK(this, SalInstanceTreeView, DoubleClickHdl));
         m_xTreeView->SetExpandingHdl(LINK(this, SalInstanceTreeView, ExpandingHdl));
         m_xTreeView->SetPopupMenuHdl(LINK(this, SalInstanceTreeView, PopupMenuHdl));
+        m_xTreeView->SetCustomRenderHdl(LINK(this, SalInstanceTreeView, CustomRenderHdl));
+        m_xTreeView->SetCustomMeasureHdl(LINK(this, SalInstanceTreeView, CustomMeasureHdl));
         const long aTabPositions[] = { 0 };
         m_xTreeView->SetTabs(SAL_N_ELEMENTS(aTabPositions), aTabPositions);
         LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get());
@@ -3452,6 +3466,11 @@ public:
         }
     }
 
+    virtual void set_column_custom_renderer(int nColumn) override
+    {
+        m_aCustomRenders.insert(nColumn);
+    }
+
     virtual void show() override
     {
         if (LclHeaderTabListBox* pHeaderBox = dynamic_cast<LclHeaderTabListBox*>(m_xTreeView.get()))
@@ -3496,7 +3515,7 @@ public:
             pEntry->AddItem(std::make_unique<SvLBoxContextBmp>(aDummy, aDummy, false));
         }
         if (pStr)
-            pEntry->AddItem(std::make_unique<SvLBoxString>(*pStr));
+            AddStringItem(pEntry, *pStr, 0);
         pEntry->SetUserData(pUserData);
         m_xTreeView->Insert(pEntry, iter, nInsertPos);
 
@@ -3744,11 +3763,11 @@ public:
 
         // blank out missing entries
         for (int i = pEntry->ItemCount(); i < col; ++i)
-            pEntry->AddItem(std::make_unique<SvLBoxString>(""));
+            AddStringItem(pEntry, "", i - 1);
 
         if (static_cast<size_t>(col) == pEntry->ItemCount())
         {
-            pEntry->AddItem(std::make_unique<SvLBoxString>(rText));
+            AddStringItem(pEntry, rText, col - 1);
             SvViewDataEntry* pViewData = m_xTreeView->GetViewDataEntry(pEntry);
             m_xTreeView->InitViewData(pViewData, pEntry);
         }
@@ -3833,7 +3852,7 @@ public:
 
         // blank out missing entries
         for (int i = pEntry->ItemCount(); i < col; ++i)
-            pEntry->AddItem(std::make_unique<SvLBoxString>(""));
+            AddStringItem(pEntry, "", i - 1);
 
         if (static_cast<size_t>(col) == pEntry->ItemCount())
         {
@@ -3989,7 +4008,7 @@ public:
 
         // blank out missing entries
         for (int i = pEntry->ItemCount(); i < col; ++i)
-            pEntry->AddItem(std::make_unique<SvLBoxString>(""));
+            AddStringItem(pEntry, "", i - 1);
 
         if (static_cast<size_t>(col) == pEntry->ItemCount())
         {
@@ -4598,6 +4617,8 @@ public:
         m_xTreeView->SetDeselectHdl(Link<SvTreeListBox*, void>());
         m_xTreeView->SetScrolledHdl(Link<SvTreeListBox*, void>());
         m_xTreeView->SetTooltipHdl(Link<const HelpEvent&, bool>());
+        m_xTreeView->SetCustomRenderHdl(Link<svtree_render_args, void>());
+        m_xTreeView->SetCustomMeasureHdl(Link<svtree_measure_args, Size>());
     }
 };
 
@@ -4621,6 +4642,27 @@ IMPL_LINK(SalInstanceTreeView, TooltipHdl, const HelpEvent&, rHEvt, bool)
     return true;
 }
 
+IMPL_LINK(SalInstanceTreeView, CustomRenderHdl, svtree_render_args, payload, void)
+{
+    vcl::RenderContext& rRenderDevice = std::get<0>(payload);
+    const tools::Rectangle& rRect = std::get<1>(payload);
+    const SvTreeListEntry& rEntry = std::get<2>(payload);
+    const OUString* pId = static_cast<const OUString*>(rEntry.GetUserData());
+    if (!pId)
+        return;
+    signal_custom_render(rRenderDevice, rRect, m_xTreeView->IsSelected(&rEntry), *pId);
+}
+
+IMPL_LINK(SalInstanceTreeView, CustomMeasureHdl, svtree_measure_args, payload, Size)
+{
+    vcl::RenderContext& rRenderDevice = payload.first;
+    const SvTreeListEntry& rEntry = payload.second;
+    const OUString* pId = static_cast<const OUString*>(rEntry.GetUserData());
+    if (!pId)
+        return Size();
+    return signal_custom_get_size(rRenderDevice, *pId);
+}
+
 IMPL_LINK(SalInstanceTreeView, CompareHdl, const SvSortData&, rSortData, sal_Int32)
 {
     const SvTreeListEntry* pLHS = rSortData.pLeft;
diff --git a/vcl/source/treelist/svlbitm.cxx b/vcl/source/treelist/svlbitm.cxx
index 20407f71af2b..8fff9071dcdb 100644
--- a/vcl/source/treelist/svlbitm.cxx
+++ b/vcl/source/treelist/svlbitm.cxx
@@ -174,6 +174,7 @@ bool SvLBoxButtonData::IsRadio() const {
 
 SvLBoxString::SvLBoxString(const OUString& rStr)
     : mbEmphasized(false)
+    , mbCustom(false)
     , mfAlign(0.0)
     , maText(rStr)
 {
@@ -181,6 +182,7 @@ SvLBoxString::SvLBoxString(const OUString& rStr)
 
 SvLBoxString::SvLBoxString()
     : mbEmphasized(false)
+    , mbCustom(false)
     , mfAlign(0.0)
 {
 }
@@ -235,7 +237,12 @@ void SvLBoxString::Paint(
         rRenderContext.SetFont(aFont);
     }
 
-    rRenderContext.DrawText(tools::Rectangle(rPos, aSize), maText, nStyle);
+    tools::Rectangle aRect(rPos, aSize);
+
+    if (mbCustom)
+        rDev.DrawCustomEntry(rRenderContext, aRect, rEntry);
+    else
+        rRenderContext.DrawText(aRect, maText, nStyle);
 
     if (mbEmphasized)
         rRenderContext.Pop();
@@ -248,6 +255,7 @@ std::unique_ptr<SvLBoxItem> SvLBoxString::Clone(SvLBoxItem const * pSource) cons
     const SvLBoxString* pOther = static_cast<const SvLBoxString*>(pSource);
     pNew->maText = pOther->maText;
     pNew->mbEmphasized = pOther->mbEmphasized;
+    pNew->mbCustom = pOther->mbCustom;
     pNew->mfAlign = pOther->mfAlign;
 
     return std::unique_ptr<SvLBoxItem>(pNew.release());
@@ -267,8 +275,17 @@ void SvLBoxString::InitViewData(
         pView->Control::SetFont( aFont );
     }
 
-    pViewData->mnWidth = -1; // calc on demand
-    pViewData->mnHeight = pView->GetTextHeight();
+    if (mbCustom)
+    {
+        Size aSize = pView->MeasureCustomEntry(*pView, *pEntry);
+        pViewData->mnWidth = aSize.Width();
+        pViewData->mnHeight = aSize.Height();
+    }
+    else
+    {
+        pViewData->mnWidth = -1; // calc on demand
+        pViewData->mnHeight = pView->GetTextHeight();
+    }
 
     if (mbEmphasized)
         pView->Pop();
diff --git a/vcl/source/treelist/treelistbox.cxx b/vcl/source/treelist/treelistbox.cxx
index a57b0e45b24e..f54e184356d4 100644
--- a/vcl/source/treelist/treelistbox.cxx
+++ b/vcl/source/treelist/treelistbox.cxx
@@ -2868,6 +2868,16 @@ void SvTreeListBox::PreparePaint(vcl::RenderContext& /*rRenderContext*/, SvTreeL
 {
 }
 
+void SvTreeListBox::DrawCustomEntry(vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect, const SvTreeListEntry& rEntry)
+{
+    aCustomRenderHdl.Call(std::tuple<vcl::RenderContext&, const tools::Rectangle&, const SvTreeListEntry&>(rRenderContext, rRect, rEntry));
+}
+
+Size SvTreeListBox::MeasureCustomEntry(vcl::RenderContext& rRenderContext, const SvTreeListEntry& rEntry)
+{
+    return aCustomMeasureHdl.Call(std::pair<vcl::RenderContext&, const SvTreeListEntry&>(rRenderContext, rEntry));
+}
+
 tools::Rectangle SvTreeListBox::GetFocusRect(const SvTreeListEntry* pEntry, long nLine )
 {
     pImpl->UpdateContextBmpWidthMax( pEntry );
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index f3ed31051d94..a7ea94053e7c 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -441,6 +441,25 @@ namespace weld
 
         return nAbsPos;
     }
+
+    bool IsEntryVisible(const weld::TreeView& rTreeView, const weld::TreeIter& rIter)
+    {
+        // short circuit for the common case
+        if (rTreeView.get_iter_depth(rIter) == 0)
+            return true;
+
+        std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(&rIter));
+        bool bRetVal = false;
+        do
+        {
+            if (rTreeView.get_iter_depth(*xEntry) == 0)
+            {
+                bRetVal = true;
+                break;
+            }
+        }  while (rTreeView.iter_parent(*xEntry) && rTreeView.get_row_expanded(*xEntry));
+        return bRetVal;
+    }
 }
 
 VclBuilder::VclBuilder(vcl::Window* pParent, const OUString& sUIDir, const OUString& sUIFile,
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index c804670dda7c..63f5e710f817 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -5298,6 +5298,218 @@ GType crippled_viewport_get_type()
     return type;
 }
 
+#define CUSTOM_TYPE_CELL_RENDERER_SURFACE             (custom_cell_renderer_surface_get_type())
+#define CUSTOM_CELL_RENDERER_SURFACE(obj)             (G_TYPE_CHECK_INSTANCE_CAST((obj),  CUSTOM_TYPE_CELL_RENDERER_SURFACE, CustomCellRendererSurface))
+
+namespace {
+
+    struct CustomCellRendererSurface
+    {
+        GtkCellRendererText parent;
+        VclPtr<VirtualDevice> device;
+        gchar *id;
+        gpointer instance;
+    };
+
+    struct CustomCellRendererSurfaceClass
+    {
+        GtkCellRendererTextClass parent_class;
+    };
+
+    enum
+    {
+        PROP_ID = 10000,
+        PROP_INSTANCE_TREE_VIEW = 10001
+    };
+}
+
+static gpointer custom_cell_renderer_surface_parent_class;
+
+static GType custom_cell_renderer_surface_get_type();
+static void custom_cell_renderer_surface_class_init(CustomCellRendererSurfaceClass *klass);
+
+GType custom_cell_renderer_surface_get_type()
+{
+    static GType type = 0;
+
+    if (!type)
+    {
+        static const GTypeInfo tinfo =
+        {
+            sizeof (CustomCellRendererSurfaceClass),
+            nullptr, /* base init */
+            nullptr, /* base finalize */
+            reinterpret_cast<GClassInitFunc>(custom_cell_renderer_surface_class_init), /* class init */
+            nullptr, /* class finalize */
+            nullptr, /* class data */
+            sizeof (CustomCellRendererSurface), /* instance size */
+            0,       /* nb preallocs */
+            nullptr, /* instance init */
+            nullptr  /* value table */
+        };
+
+        // inherit from GtkCellRendererText so we can set the "text" property and get a11y support for that
+        type = g_type_register_static(GTK_TYPE_CELL_RENDERER_TEXT, "CustomCellRendererSurface",
+                                      &tinfo, GTypeFlags(0));
+    }
+
+    return type;
+}
+
+static void custom_cell_renderer_surface_get_property(GObject *object,
+                                                      guint param_id,
+                                                      GValue *value,
+                                                      GParamSpec *pspec)
+{
+    CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(object);
+
+    switch (param_id)
+    {
+        case PROP_ID:
+            g_value_set_string(value, cellsurface->id);
+            break;
+        case PROP_INSTANCE_TREE_VIEW:
+            g_value_set_pointer(value, cellsurface->instance);
+            break;
+        default:
+            G_OBJECT_CLASS(custom_cell_renderer_surface_parent_class)->get_property(object, param_id, value, pspec);
+            break;
+    }
+}
+
+static void custom_cell_renderer_surface_set_property(GObject *object,
+                                                      guint param_id,
+                                                      const GValue *value,
+                                                      GParamSpec *pspec)
+{
+    CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(object);
+
+    switch (param_id)
+    {
+        case PROP_ID:
+            g_free(cellsurface->id);
+            cellsurface->id = g_value_dup_string(value);
+            break;
+        case PROP_INSTANCE_TREE_VIEW:
+            cellsurface->instance = g_value_get_pointer(value);
+            break;
+        default:
+            G_OBJECT_CLASS(custom_cell_renderer_surface_parent_class)->set_property(object, param_id, value, pspec);
+            break;
+    }
+}
+
+static bool custom_cell_renderer_surface_get_preferred_size(GtkCellRenderer *cell,
+                                                            GtkOrientation orientation,
+                                                            gint *minimum_size,
+                                                            gint *natural_size);
+
+static void custom_cell_renderer_surface_render(GtkCellRenderer* cell,
+                                                cairo_t* cr,
+                                                GtkWidget* widget,
+                                                const GdkRectangle* background_area,
+                                                const GdkRectangle* cell_area,
+                                                GtkCellRendererState flags);
+
+static void custom_cell_renderer_surface_finalize(GObject *object)
+{
+    CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(object);
+
+    g_free(cellsurface->id);
+    cellsurface->device.disposeAndClear();
+
+    G_OBJECT_CLASS(custom_cell_renderer_surface_parent_class)->finalize(object);
+}
+
+static void custom_cell_renderer_surface_get_preferred_width(GtkCellRenderer *cell,
+                                                             GtkWidget *widget,
+                                                             gint *minimum_size,
+                                                             gint *natural_size)
+{
+    if (!custom_cell_renderer_surface_get_preferred_size(cell, GTK_ORIENTATION_HORIZONTAL,
+                                                         minimum_size, natural_size))
+    {
+        // fallback to parent if we're empty
+        GTK_CELL_RENDERER_CLASS(custom_cell_renderer_surface_parent_class)->get_preferred_width(cell,
+            widget, minimum_size, natural_size);
+    }
+}
+
+static void custom_cell_renderer_surface_get_preferred_height(GtkCellRenderer *cell,
+                                                              GtkWidget *widget,
+                                                              gint *minimum_size,
+                                                              gint *natural_size)
+{
+    if (!custom_cell_renderer_surface_get_preferred_size(cell, GTK_ORIENTATION_VERTICAL,
+                                                         minimum_size, natural_size))
+    {
+        // fallback to parent if we're empty
+        GTK_CELL_RENDERER_CLASS(custom_cell_renderer_surface_parent_class)->get_preferred_height(cell,
+            widget, minimum_size, natural_size);
+    }
+
+}
+
+static void custom_cell_renderer_surface_get_preferred_height_for_width(GtkCellRenderer *cell,
+                                                                        GtkWidget *widget,
+                                                                        gint /*width*/,
+                                                                        gint *minimum_height,
+                                                                        gint *natural_height)
+{
+    gtk_cell_renderer_get_preferred_height(cell, widget, minimum_height, natural_height);
+}
+
+static void custom_cell_renderer_surface_get_preferred_width_for_height(GtkCellRenderer *cell,
+                                                                        GtkWidget *widget,
+                                                                        gint /*height*/,
+                                                                        gint *minimum_width,
+                                                                        gint *natural_width)
+{
+    gtk_cell_renderer_get_preferred_width(cell, widget, minimum_width, natural_width);
+}
+
+void custom_cell_renderer_surface_class_init(CustomCellRendererSurfaceClass *klass)
+{
+    GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS(klass);
+    GObjectClass *object_class = G_OBJECT_CLASS(klass);
+
+    /* Hook up functions to set and get our custom cell renderer properties */
+    object_class->get_property = custom_cell_renderer_surface_get_property;
+    object_class->set_property = custom_cell_renderer_surface_set_property;
+
+    custom_cell_renderer_surface_parent_class = g_type_class_peek_parent(klass);
+    object_class->finalize = custom_cell_renderer_surface_finalize;
+
+    cell_class->get_preferred_width = custom_cell_renderer_surface_get_preferred_width;
+    cell_class->get_preferred_height = custom_cell_renderer_surface_get_preferred_height;
+    cell_class->get_preferred_width_for_height = custom_cell_renderer_surface_get_preferred_width_for_height;
+    cell_class->get_preferred_height_for_width = custom_cell_renderer_surface_get_preferred_height_for_width;
+
+    cell_class->render = custom_cell_renderer_surface_render;
+
+    g_object_class_install_property(object_class,
+                                   PROP_ID,
+                                   g_param_spec_string("id",
+                                                       "ID",
+                                                       "The ID of the custom data",
+                                                       nullptr,
+                                                       G_PARAM_READWRITE));
+
+    g_object_class_install_property(object_class,
+                                   PROP_INSTANCE_TREE_VIEW,
+                                   g_param_spec_pointer("instance",
+                                                        "Instance",
+                                                        "The GtkInstanceTreeView",
+                                                        G_PARAM_READWRITE));
+
+    gtk_cell_renderer_class_set_accessible_type(cell_class, GTK_TYPE_TEXT_CELL_ACCESSIBLE);
+}
+
+static GtkCellRenderer* custom_cell_renderer_surface_new()
+{
+    return GTK_CELL_RENDERER(g_object_new(CUSTOM_TYPE_CELL_RENDERER_SURFACE, nullptr));
+}
+
 static VclPolicyType GtkToVcl(GtkPolicyType eType)
 {
     VclPolicyType eRet(VclPolicyType::NEVER);
@@ -9455,6 +9667,21 @@ public:
         gtk_tree_view_column_set_title(pColumn, OUStringToOString(rTitle, RTL_TEXTENCODING_UTF8).getStr());
     }
 
+    virtual void set_column_custom_renderer(int nColumn) override
+    {
+        GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(g_list_nth_data(m_pColumns, nColumn));
+        assert(pColumn && "wrong count");
+        gtk_cell_layout_clear(GTK_CELL_LAYOUT(pColumn));
+        GtkCellRenderer *pRenderer = custom_cell_renderer_surface_new();
+        GValue value = G_VALUE_INIT;
+        g_value_init(&value, G_TYPE_POINTER);
+        g_value_set_pointer(&value, static_cast<gpointer>(this));
+        g_object_set_property(G_OBJECT(pRenderer), "instance", &value);
+        gtk_tree_view_column_pack_start(pColumn, pRenderer, true);
+        gtk_tree_view_column_add_attribute(pColumn, pRenderer, "text", m_nTextCol);
+        gtk_tree_view_column_add_attribute(pColumn, pRenderer, "id", m_nIdCol);
+    }
+
     virtual void insert(const weld::TreeIter* pParent, int pos, const OUString* pText, const OUString* pId, const OUString* pIconName,
                         VirtualDevice* pImageSurface, const OUString* pExpanderName,
                         bool bChildrenOnDemand, weld::TreeIter* pRet) override
@@ -10897,6 +11124,16 @@ public:
         enable_notify_events();
     }
 
+    void call_signal_custom_render(VirtualDevice& rOutput, const tools::Rectangle& rRect, bool bSelected, const OUString& rId)
+    {
+        signal_custom_render(rOutput, rRect, bSelected, rId);
+    }
+
+    Size call_signal_custom_get_size(VirtualDevice& rOutput, const OUString& rId)
+    {
+        return signal_custom_get_size(rOutput, rId);
+    }
+
     virtual ~GtkInstanceTreeView() override
     {
         if (m_pChangeEvent)
@@ -10930,6 +11167,116 @@ public:
     }
 };
 
+void ensure_device(CustomCellRendererSurface *cellsurface, weld::TreeView* pTreeView)
+{
+    if (!cellsurface->device)
+    {
+        cellsurface->device = VclPtr<VirtualDevice>::Create();
+        cellsurface->device->SetBackground(COL_TRANSPARENT);
+        // expand the point size of the desired font to the equivalent pixel size
+        if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
+            pDefaultDevice->SetPointFont(*cellsurface->device, pTreeView->get_font());
+    }
+}
+
+}
+
+bool custom_cell_renderer_surface_get_preferred_size(GtkCellRenderer *cell,
+                                                     GtkOrientation orientation,
+                                                     gint *minimum_size,
+                                                     gint *natural_size)
+{
+    GValue value = G_VALUE_INIT;
+    g_value_init(&value, G_TYPE_STRING);
+    g_object_get_property(G_OBJECT(cell), "id", &value);
+
+    const char* pStr = g_value_get_string(&value);
+
+    if (!pStr)
+    {
+        // this happens if we're empty
+        return false;
+    }
+
+    OUString sId(pStr, strlen(pStr), RTL_TEXTENCODING_UTF8);
+
+    value = G_VALUE_INIT;
+    g_value_init(&value, G_TYPE_POINTER);
+    g_object_get_property(G_OBJECT(cell), "instance", &value);
+
+    CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell);
+
+    GtkInstanceTreeView* pTreeView = static_cast<GtkInstanceTreeView*>(g_value_get_pointer(&value));
+
+    ensure_device(cellsurface, pTreeView);
+
+    Size aSize = pTreeView->call_signal_custom_get_size(*cellsurface->device, sId);
+
+    if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    {
+        if (minimum_size)
+            *minimum_size = aSize.Width();
+
+        if (natural_size)
+            *natural_size = aSize.Width();
+    }
+    else
+    {
+        if (minimum_size)
+            *minimum_size = aSize.Height();
+
+        if (natural_size)
+            *natural_size = aSize.Height();
+    }
+
+    return true;
+}
+
+void custom_cell_renderer_surface_render(GtkCellRenderer* cell,
+                                         cairo_t* cr,
+                                         GtkWidget* /*widget*/,
+                                         const GdkRectangle* /*background_area*/,
+                                         const GdkRectangle* cell_area,
+                                         GtkCellRendererState flags)
+{
+    GValue value = G_VALUE_INIT;
+    g_value_init(&value, G_TYPE_STRING);
+    g_object_get_property(G_OBJECT(cell), "id", &value);
+
+    const char* pStr = g_value_get_string(&value);
+    OUString sId(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
+
+    value = G_VALUE_INIT;
+    g_value_init(&value, G_TYPE_POINTER);
+    g_object_get_property(G_OBJECT(cell), "instance", &value);
+
+    CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell);
+
+    GtkInstanceTreeView* pTreeView = static_cast<GtkInstanceTreeView*>(g_value_get_pointer(&value));
+
+    ensure_device(cellsurface, pTreeView);
+
+    Size aSize(cell_area->width, cell_area->height);
+    // false to not bother setting the bg on resize as we'll do that
+    // ourself via cairo
+    cellsurface->device->SetOutputSizePixel(aSize, false);
+
+    cairo_surface_t* pSurface = get_underlying_cairo_surface(*cellsurface->device);
+
+    // fill surface as transparent so it can be blended with the potentially
+    // selected background
+    cairo_t* tempcr = cairo_create(pSurface);
+    cairo_set_source_rgba(tempcr, 0, 0, 0, 0);
+    cairo_set_operator(tempcr, CAIRO_OPERATOR_SOURCE);
+    cairo_paint(tempcr);
+    cairo_destroy(tempcr);
+    cairo_surface_flush(pSurface);
+
+    pTreeView->call_signal_custom_render(*cellsurface->device, tools::Rectangle(Point(0, 0), aSize), flags & GTK_CELL_RENDERER_SELECTED, sId);
+    cairo_surface_mark_dirty(pSurface);
+
+    cairo_set_source_surface(cr, pSurface, cell_area->x, cell_area->y);
+    cairo_paint(cr);
 }
 
 IMPL_LINK_NOARG(GtkInstanceTreeView, async_signal_changed, void*, void)
commit 6ff081689573217621a4ef012755fc5e351359af
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Thu Apr 2 15:36:28 2020 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Sat Apr 4 19:51:37 2020 +0200

    fix SvLBoxString::Clone wrt newly added entries
    
    Change-Id: I31d0b0af25fb6062b518f4c1ace25715a784ad81
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91657
    Tested-by: Jenkins
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/vcl/source/treelist/svlbitm.cxx b/vcl/source/treelist/svlbitm.cxx
index cd7fbae06b97..20407f71af2b 100644
--- a/vcl/source/treelist/svlbitm.cxx
+++ b/vcl/source/treelist/svlbitm.cxx
@@ -244,7 +244,12 @@ void SvLBoxString::Paint(
 std::unique_ptr<SvLBoxItem> SvLBoxString::Clone(SvLBoxItem const * pSource) const
 {
     std::unique_ptr<SvLBoxString> pNew(new SvLBoxString);
-    pNew->maText = static_cast<SvLBoxString const *>(pSource)->maText;
+
+    const SvLBoxString* pOther = static_cast<const SvLBoxString*>(pSource);
+    pNew->maText = pOther->maText;
+    pNew->mbEmphasized = pOther->mbEmphasized;
+    pNew->mfAlign = pOther->mfAlign;
+
     return std::unique_ptr<SvLBoxItem>(pNew.release());
 }
 


More information about the Libreoffice-commits mailing list