diff options
author | Caolán McNamara <caolanm@redhat.com> | 2020-06-01 10:39:30 +0100 |
---|---|---|
committer | Caolán McNamara <caolanm@redhat.com> | 2020-06-02 16:20:18 +0200 |
commit | 9b498e2b88ffae77717bab2f7a308b83d0a7ae80 (patch) | |
tree | 95fb45488469794f16ede46f7ce764cd5497620a /vcl | |
parent | b4f7a08ea5d5fd39057f2a6c7f9a8c015370557f (diff) |
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@redhat.com>
Diffstat (limited to 'vcl')
-rw-r--r-- | vcl/inc/strings.hrc | 2 | ||||
-rw-r--r-- | vcl/source/app/salvtables.cxx | 121 | ||||
-rw-r--r-- | vcl/source/treelist/svlbitm.cxx | 33 | ||||
-rw-r--r-- | vcl/unx/gtk3/gtk3gtkinst.cxx | 79 |
4 files changed, 165 insertions, 70 deletions
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) |