From 701cea2393ec524d41f07e1beb7fdac314fa44fc Mon Sep 17 00:00:00 2001 From: Michael Weghorn Date: Fri, 17 Apr 2026 09:45:29 +0200 Subject: [PATCH] tdf#130857 Introduce ColorIconView, port "Area" page's "Color" section to it Introduce new ColorIconView class as a new subclass of the abstract IColorSet class/interface introduced in earlier commit Change-Id: I20dd12f00effac7d510c092513cd457f1ea0bcb0 Author: Michael Weghorn Date: Fri Apr 17 09:25:36 2026 +0200 svx: Introduce new abstract IColorSet base for SvxColorValueSet , as a new implementation that uses weld::IconView instead of SvxColorValueSet to implement the logic. Port the "Color" section in the "Area" tab page to use that new implementation instead of SvxColorValueSet. Similar to earlier commit commit 7d1647bdb7793e1bafe012f6b9896934b55fb536 Author: Michael Weghorn Date: Thu Apr 16 11:46:45 2026 +0200 Port "Area" tab page's Gradient/Image/Pattern/Hatch sections to IconView that was porting other sections in the "Area" tab page from using ValueSet to using weld::IconView, this helps to be more consistent with other platform/toolkit widgets, reduces custom logic and e.g. also fixes the issue of triggering the following assert when using the gtk3 vcl plugin, the Orca screen reader is enabled and the color value set receives focus: soffice.bin: /home/michi/development/git/libreoffice/vcl/unx/gtk3/gtkinst.cxx:18237: virtual rtl::Reference (anonymous namespace)::GtkInstanceDrawingArea::get_accessible_parent(): Assertion `false && "get_accessible_parent should only be called on a vcl impl"' failed. This also prepares for supporting that tab page with native Qt widgets as it prevents another issue (continual resizing) seen when experimenting with the earlier implementation. The relevant UI using this can e.g. be triggered like this: * start Writer * "Format" -> "Page Style" * go to the "Area" tab page * switch to the "Color" tab page As described in more detail in the commit message of the above-mentioned 7d1647bdb7793e1bafe012f6b9896934b55fb536, spacing also changes for the color selector(s) with this change due to the switch to weld::IconView. (See the commit message of that commit for ideas on how spacing could be adjusted, if necessary.) Set the column count for the icon views to 14 in the UI file, which matches the previous default behavior. Tweak some properties in the .ui file to make the icon views use a proper size. Adjust the existing UI tests using the widget to use the IconView/SvTreeListBox UI test logic instead of the one for the previously used SvxColorValueSet. Change-Id: I70b9a62101c17bc3c392f7d395aca4eac0dcfc4b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/203809 Tested-by: Jenkins Reviewed-by: Michael Weghorn --- cui/qa/uitest/tabpages/tpcolor.py | 5 +- cui/source/inc/cuitabarea.hxx | 13 +- cui/source/tabpages/tpcolor.cxx | 103 ++++------- cui/uiconfig/ui/colorpage.ui | 74 +++++--- include/svx/ColorIconView.hxx | 60 +++++++ .../calc_tests/cellBackgroundColorSelector.py | 168 ++++++++---------- svx/Library_svxcore.mk | 1 + svx/source/tbxctrls/ColorIconView.cxx | 86 +++++++++ 8 files changed, 315 insertions(+), 195 deletions(-) create mode 100644 include/svx/ColorIconView.hxx create mode 100644 svx/source/tbxctrls/ColorIconView.cxx diff --git a/cui/qa/uitest/tabpages/tpcolor.py b/cui/qa/uitest/tabpages/tpcolor.py index 4e7b8261ff83..906b341f7d06 100644 --- a/cui/qa/uitest/tabpages/tpcolor.py +++ b/cui/qa/uitest/tabpages/tpcolor.py @@ -55,8 +55,9 @@ class Test(UITestCase): btnColor.executeAction("CLICK", tuple()) paletteSelector = xDialog.getChild("paletteselector") select_by_text(paletteSelector, "Theme colors") - colorSelector = xDialog.getChild("colorset") - colorSelector.executeAction("CHOOSE", mkPropertyValues({"POS": "4"})) + colorSelector = xDialog.getChild("coloriconview") + colorSelector.executeAction("SELECT", mkPropertyValues({"POS": "3"})) + colorSelector.executeAction("TYPE", mkPropertyValues({"KEYCODE": "RETURN"})) # Then make sure the doc model is updated accordingly: shape = drawPage[0] diff --git a/cui/source/inc/cuitabarea.hxx b/cui/source/inc/cuitabarea.hxx index 09b61b1a62ec..ba1a3000395f 100644 --- a/cui/source/inc/cuitabarea.hxx +++ b/cui/source/inc/cuitabarea.hxx @@ -20,11 +20,10 @@ #include "SvxPresetListBox.hxx" -#include +#include #include #include #include -#include #include #include #include @@ -677,8 +676,8 @@ private: PaletteManager maPaletteManager; SvxXRectPreview m_aCtlPreviewOld; SvxXRectPreview m_aCtlPreviewNew; - std::unique_ptr m_xValSetColorList; - std::unique_ptr m_xValSetRecentList; + ColorIconView m_aColorIconView; + ColorIconView m_aRecentIconView; std::unique_ptr m_xSelectPalette; std::unique_ptr m_xRbRGB; std::unique_ptr m_xRbCMYK; @@ -708,8 +707,6 @@ private: std::unique_ptr m_xMoreColors; std::unique_ptr m_xCtlPreviewOld; std::unique_ptr m_xCtlPreviewNew; - std::unique_ptr m_xValSetColorListWin; - std::unique_ptr m_xValSetRecentListWin; static void ConvertColorValues (Color& rColor, ColorModel eModell); static void RgbToCmyk_Impl( Color& rColor, sal_uInt16& rK ); @@ -725,8 +722,8 @@ private: DECL_LINK(OnMoreColorsClick, weld::Button&, void); DECL_LINK(SelectPaletteLBHdl, weld::ComboBox&, void); - DECL_LINK(SelectColorValSetHdl_Impl, ValueSet*, void); - DECL_LINK(SelectRecentValSetHdl_Impl, ValueSet*, void); + DECL_LINK(ActivatePaletteColorHdl, const Color&, void); + DECL_LINK(ActivateRecentColorHdl, const Color&, void); DECL_LINK( SelectColorModeHdl_Impl, weld::Toggleable&, void ); void UpdateToSelectedColor(const NamedColor& rNamedColor); void ChangeColor(const NamedColor &rNewColor, bool bUpdatePreset = true); diff --git a/cui/source/tabpages/tpcolor.cxx b/cui/source/tabpages/tpcolor.cxx index 5f055643acfa..46c7605f9afc 100644 --- a/cui/source/tabpages/tpcolor.cxx +++ b/cui/source/tabpages/tpcolor.cxx @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -54,8 +55,8 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* , m_aXFillAttr( rInAttrs.GetPool() ) , m_rXFSet( m_aXFillAttr.GetItemSet() ) , m_eCM( ColorModel::RGB ) - , m_xValSetColorList(new SvxColorValueSet(m_xBuilder->weld_scrolled_window(u"colorsetwin"_ustr, true))) - , m_xValSetRecentList(new SvxColorValueSet(nullptr)) + , m_aColorIconView(m_xBuilder->weld_icon_view(u"coloriconview"_ustr)) + , m_aRecentIconView(m_xBuilder->weld_icon_view(u"recentcoloriconview"_ustr)) , m_xSelectPalette(m_xBuilder->weld_combo_box(u"paletteselector"_ustr)) , m_xRbRGB(m_xBuilder->weld_radio_button(u"RGB"_ustr)) , m_xRbCMYK(m_xBuilder->weld_radio_button(u"CMYK"_ustr)) @@ -85,12 +86,9 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* , m_xMoreColors(m_xBuilder->weld_button(u"btnMoreColors"_ustr)) , m_xCtlPreviewOld(new weld::CustomWeld(*m_xBuilder, u"oldpreview"_ustr, m_aCtlPreviewOld)) , m_xCtlPreviewNew(new weld::CustomWeld(*m_xBuilder, u"newpreview"_ustr, m_aCtlPreviewNew)) - , m_xValSetColorListWin(new weld::CustomWeld(*m_xBuilder, u"colorset"_ustr, *m_xValSetColorList)) - , m_xValSetRecentListWin(new weld::CustomWeld(*m_xBuilder, u"recentcolorset"_ustr, *m_xValSetRecentList)) { Size aSize(m_xBtnWorkOn->get_approximate_digit_width() * 25, m_xBtnWorkOn->get_text_height() * 10); - m_xValSetColorList->set_size_request(aSize.Width(), aSize.Height()); aSize = Size(m_xBtnWorkOn->get_approximate_digit_width() * 8, m_xBtnWorkOn->get_text_height() * 3); m_aCtlPreviewOld.set_size_request(aSize.Width(), aSize.Height()); @@ -106,8 +104,8 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* // set handler m_xSelectPalette->connect_changed(LINK(this, SvxColorTabPage, SelectPaletteLBHdl)); - m_xValSetColorList->SetSelectHdl(LINK(this, SvxColorTabPage, SelectColorValSetHdl_Impl)); - m_xValSetRecentList->SetSelectHdl(LINK(this, SvxColorTabPage, SelectRecentValSetHdl_Impl)); + m_aColorIconView.setColorActivatedHdl(LINK(this, SvxColorTabPage, ActivatePaletteColorHdl)); + m_aRecentIconView.setColorActivatedHdl(LINK(this, SvxColorTabPage, ActivateRecentColorHdl)); Link aSpinLink = LINK(this, SvxColorTabPage, SpinValueHdl_Impl); m_xRcustom->connect_value_changed(aSpinLink); @@ -141,18 +139,7 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* m_xRGBpreset->set_sensitive(false); m_xCMYKpreset->set_sensitive(false); - // ValueSet - m_xValSetColorList->SetStyle(m_xValSetColorList->GetStyle() | - WB_FLATVALUESET | WB_ITEMBORDER | WB_NO_DIRECTSELECT | WB_TABSTOP); - m_xValSetColorList->Show(); - - m_xValSetRecentList->SetStyle(m_xValSetRecentList->GetStyle() | - WB_FLATVALUESET | WB_ITEMBORDER | WB_NO_DIRECTSELECT | WB_TABSTOP); - m_xValSetRecentList->Show(); - - maPaletteManager.ReloadRecentColorSet(*m_xValSetRecentList); - aSize = m_xValSetRecentList->layoutAllVisible(maPaletteManager.GetRecentColorCount()); - m_xValSetRecentList->set_size_request(aSize.Width(), aSize.Height()); + maPaletteManager.ReloadRecentColorSet(m_aRecentIconView); // it is not possible to install color palette extensions in Online or mobile apps if(comphelper::LibreOfficeKit::isActive()) @@ -161,13 +148,7 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* } } -SvxColorTabPage::~SvxColorTabPage() -{ - m_xValSetRecentListWin.reset(); - m_xValSetRecentList.reset(); - m_xValSetColorListWin.reset(); - m_xValSetColorList.reset(); -} +SvxColorTabPage::~SvxColorTabPage() {} void SvxColorTabPage::FillPaletteLB() { @@ -201,7 +182,11 @@ void SvxColorTabPage::ActivatePage( const SfxItemSet& ) m_aCtlPreviewOld.SetAttributes(m_aXFillAttr.GetItemSet()); m_aCtlPreviewOld.Invalidate(); - SelectColorValSetHdl_Impl(m_xValSetColorList.get()); + const int nSelectedIndex = m_aColorIconView.get_selected_index(); + if (nSelectedIndex < 0) + return; + + ActivatePaletteColorHdl(m_aColorIconView.getColor(nSelectedIndex)); } DeactivateRC SvxColorTabPage::DeactivatePage( SfxItemSet* _pSet ) @@ -214,10 +199,10 @@ DeactivateRC SvxColorTabPage::DeactivatePage( SfxItemSet* _pSet ) bool SvxColorTabPage::FillItemSet( SfxItemSet* rSet ) { - Color aColor = m_xValSetColorList->GetItemColor( m_xValSetColorList->GetSelectedItemId() ); + Color aColor = m_aColorIconView.getColor(m_aColorIconView.get_selected_index()); OUString sColorName; if (m_aCurrentColor.m_aColor == aColor) - sColorName = m_xValSetColorList->GetItemText(m_xValSetColorList->GetSelectedItemId()); + sColorName = m_aColorIconView.getColorName(m_aColorIconView.get_selected_index()); else sColorName = "#" + m_aCurrentColor.m_aColor.AsRGBHexString().toAsciiUpperCase(); @@ -359,9 +344,9 @@ IMPL_LINK_NOARG(SvxColorTabPage, ClickAddHdl_Impl, weld::Button&, void) officecfg::Office::Common::UserColors::CustomColor::set(aCustomColorList, batch); officecfg::Office::Common::UserColors::CustomColorName::set(aCustomColorNameList, batch); batch->commit(); - sal_uInt16 nId = m_xValSetColorList->GetItemId(nSize - 1); - m_xValSetColorList->InsertItem( nId + 1 , m_aCurrentColor.m_aColor, aName ); - m_xValSetColorList->SelectItem( nId + 1 ); + const int nCount = m_aColorIconView.getItemCount(); + m_aColorIconView.insert(nCount, m_aCurrentColor.m_aColor, aName); + m_aColorIconView.select(nCount); m_xBtnDelete->set_sensitive(false); m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR2) ); } @@ -390,9 +375,8 @@ IMPL_LINK_NOARG(SvxColorTabPage, ClickWorkOnHdl_Impl, weld::Button&, void) IMPL_LINK_NOARG(SvxColorTabPage, ClickDeleteHdl_Impl, weld::Button&, void) { - sal_uInt16 nId = m_xValSetColorList->GetSelectedItemId(); - size_t nPos = m_xValSetColorList->GetSelectItemPos(); - if (m_xSelectPalette->get_active() != 0 || nPos == VALUESET_ITEM_NOTFOUND) + const int nPos = m_aColorIconView.get_selected_index(); + if (m_xSelectPalette->get_active() != 0 || nPos < 0) return; std::shared_ptr batch(comphelper::ConfigurationChanges::create()); @@ -401,7 +385,7 @@ IMPL_LINK_NOARG(SvxColorTabPage, ClickDeleteHdl_Impl, weld::Button&, void) css::uno::Sequence< OUString > aCustomColorNameList(officecfg::Office::Common::UserColors::CustomColorName::get()); auto aCustomColorNameListRange = asNonConstRange(aCustomColorNameList); sal_Int32 nSize = aCustomColorList.getLength() - 1; - for(sal_Int32 nIndex = static_cast(nPos);nIndex < nSize;nIndex++) + for (sal_Int32 nIndex = nPos; nIndex < nSize; nIndex++) { aCustomColorListRange[nIndex] = aCustomColorList[nIndex+1]; aCustomColorNameListRange[nIndex] = aCustomColorNameList[nIndex+1]; @@ -411,12 +395,11 @@ IMPL_LINK_NOARG(SvxColorTabPage, ClickDeleteHdl_Impl, weld::Button&, void) officecfg::Office::Common::UserColors::CustomColor::set(aCustomColorList, batch); officecfg::Office::Common::UserColors::CustomColorName::set(aCustomColorNameList, batch); batch->commit(); - m_xValSetColorList->RemoveItem(nId); - if (m_xValSetColorList->GetItemCount() != 0) + m_aColorIconView.remove(nPos); + if (m_aColorIconView.getItemCount() > 0) { - nId = m_xValSetColorList->GetItemId(0); - m_xValSetColorList->SelectItem(nId); - SelectColorValSetHdl_Impl(m_xValSetColorList.get()); + m_aColorIconView.select(0); + ActivatePaletteColorHdl(m_aColorIconView.getColor(0)); } else { @@ -427,10 +410,10 @@ IMPL_LINK_NOARG(SvxColorTabPage, ClickDeleteHdl_Impl, weld::Button&, void) IMPL_LINK_NOARG(SvxColorTabPage, SelectPaletteLBHdl, weld::ComboBox&, void) { - m_xValSetColorList->Clear(); + m_aColorIconView.clear(); sal_Int32 nPos = m_xSelectPalette->get_active(); maPaletteManager.SetPalette( nPos ); - maPaletteManager.ReloadColorSet(*m_xValSetColorList); + maPaletteManager.ReloadColorSet(m_aColorIconView); if(nPos != maPaletteManager.GetPaletteCount() - 1 && nPos != 0) { @@ -460,8 +443,6 @@ IMPL_LINK_NOARG(SvxColorTabPage, SelectPaletteLBHdl, weld::ComboBox&, void) m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR1) ); } - m_xValSetColorList->Resize(); - // select the 'Active' color in the m_xValSetColorList if it has it if (const XFillColorItem* pFillColorItem = m_rOutAttrs.GetItemIfSet(GetWhich(XATTR_FILLCOLOR))) { @@ -478,13 +459,12 @@ IMPL_LINK_NOARG(SvxColorTabPage, SelectPaletteLBHdl, weld::ComboBox&, void) /* document colors palette */ nPalettePos == maPaletteManager.GetPaletteCount() - 1 || /* custom palette */ nPalettePos == 0) { - for (size_t nItemPos = 0, nItemCount = m_xValSetColorList->GetItemCount(); + for (size_t nItemPos = 0, nItemCount = m_aColorIconView.getItemCount(); nItemPos < nItemCount; nItemPos++) { - auto nItemId = m_xValSetColorList->GetItemId(nItemPos); - if (m_xValSetColorList->GetItemColor(nItemId) == aColor) + if (m_aColorIconView.getColor(nItemPos) == aColor) { - m_xValSetColorList->SelectItem(nItemId); + m_aColorIconView.select(nItemPos); break; } } @@ -497,7 +477,7 @@ IMPL_LINK_NOARG(SvxColorTabPage, SelectPaletteLBHdl, weld::ComboBox&, void) { auto nItemPos = FindInPalette(aColor); if (nItemPos != -1) - m_xValSetColorList->SelectItem(m_xValSetColorList->GetItemId(nItemPos)); + m_aColorIconView.select(nItemPos); } } } @@ -512,20 +492,19 @@ void SvxColorTabPage::UpdateToSelectedColor(const NamedColor& rNamedColor) ChangeColor(rNamedColor, false); } -IMPL_LINK_NOARG(SvxColorTabPage, SelectColorValSetHdl_Impl, ValueSet*, void) +IMPL_LINK(SvxColorTabPage, ActivatePaletteColorHdl, const Color&, rColor, void) { - const sal_uInt16 nId = m_xValSetColorList->GetSelectedItemId(); - if (nId == 0) + const int nPos = m_aColorIconView.get_selected_index(); + if (nPos < 0 || m_aColorIconView.getColor(nPos) != rColor) return; NamedColor aNamedColor; - aNamedColor.m_aColor = m_xValSetColorList->GetItemColor(nId); + aNamedColor.m_aColor = rColor; if (maPaletteManager.IsThemePaletteSelected()) { sal_uInt16 nThemeIndex; sal_uInt16 nEffectIndex; - sal_uInt16 nPos = m_xValSetColorList->GetItemPos(nId); if (PaletteManager::GetThemeAndEffectIndex(nPos, nThemeIndex, nEffectIndex)) { aNamedColor.m_nThemeIndex = nThemeIndex; @@ -535,8 +514,8 @@ IMPL_LINK_NOARG(SvxColorTabPage, SelectColorValSetHdl_Impl, ValueSet*, void) UpdateToSelectedColor(aNamedColor); - m_xValSetRecentList->SetNoSelection(); - if (m_xSelectPalette->get_active() == 0 && m_xValSetColorList->GetSelectedItemId() != 0) + m_aRecentIconView.unselect_all(); + if (m_xSelectPalette->get_active() == 0 && m_aColorIconView.get_selected_index() >= 0) { m_xBtnDelete->set_sensitive(true); m_xBtnDelete->set_tooltip_text(u""_ustr); @@ -548,18 +527,14 @@ IMPL_LINK_NOARG(SvxColorTabPage, SelectColorValSetHdl_Impl, ValueSet*, void) } } -IMPL_LINK_NOARG(SvxColorTabPage, SelectRecentValSetHdl_Impl, ValueSet*, void) +IMPL_LINK(SvxColorTabPage, ActivateRecentColorHdl, const Color&, rColor, void) { - sal_Int32 nPos = m_xValSetRecentList->GetSelectedItemId(); - if (nPos == 0) - return; - NamedColor aNamedColor; - aNamedColor.m_aColor = m_xValSetRecentList->GetItemColor(nPos); + aNamedColor.m_aColor = rColor; UpdateToSelectedColor(aNamedColor); - m_xValSetColorList->SetNoSelection(); + m_aColorIconView.unselect_all(); m_xBtnDelete->set_sensitive(false); m_xBtnDelete->set_tooltip_text(CuiResId(RID_CUISTR_DELETEUSERCOLOR2)); } diff --git a/cui/uiconfig/ui/colorpage.ui b/cui/uiconfig/ui/colorpage.ui index 672b60ea76e3..955c58d5c0de 100644 --- a/cui/uiconfig/ui/colorpage.ui +++ b/cui/uiconfig/ui/colorpage.ui @@ -37,6 +37,16 @@ 1 10 + + + + + + + + + + True False @@ -47,6 +57,16 @@ False res/sc10350.png + + + + + + + + + + True False @@ -59,6 +79,7 @@ True False True + True 0 none @@ -67,9 +88,9 @@ True False start - start 12 6 + True 6 @@ -139,7 +160,7 @@ False Recent Colors True - recentcolorset + recentcoloriconview 0 @@ -149,17 +170,20 @@ - + True True - GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - True - True + 6 + recentcoloriconviewmodel + 12 + 0 + 2 + True - False + True True - 1 + 2 @@ -241,7 +265,7 @@ 3 Custom Palette True - colorset + coloriconview 0 @@ -260,35 +284,31 @@ True False - start + True vertical - + True True never - never in - + True - False - - - True - True - GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK - True - True - - + True + 6 + coloriconviewmodel + 12 + 0 + 2 + True - False - False - 0 + True + True + 1 @@ -311,7 +331,7 @@ - False + True True 0 diff --git a/include/svx/ColorIconView.hxx b/include/svx/ColorIconView.hxx new file mode 100644 index 000000000000..d1adafc63397 --- /dev/null +++ b/include/svx/ColorIconView.hxx @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#pragma once + +#include +#include +#include + +namespace vcl +{ +class VirtualDevice; +} + +namespace weld +{ +class IconView; +} + +class SVXCORE_DLLPUBLIC ColorIconView : public IColorSet +{ + std::unique_ptr m_pIconView; + + Link m_aColorActivatedHdl; + + DECL_LINK(ItemActivatedHdl, const weld::TreeIter&, bool); + +public: + ColorIconView(std::unique_ptr pIconView); + virtual ~ColorIconView() = default; + + virtual void insert(int nIndex, const Color& rColor, const OUString& rColorName) override; + virtual int getItemCount() const override; + + Color getColor(int nIndex); + OUString getColorName(int nIndex) const; + + int get_selected_index() const; + void select(int nIndex); + void unselect_all(); + + void remove(int nIndex); + virtual void clear() override; + + void setColorActivatedHdl(const Link& rLink) + { + m_aColorActivatedHdl = rLink; + } + +private: + ScopedVclPtr createIcon(const Color& rColor); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py b/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py index 1839545c7e88..5b3cd63ca4f8 100644 --- a/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py +++ b/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py @@ -33,108 +33,90 @@ class CalcCellBackgroundColorSelector(UITestCase): # Now we have the ColorPage that we can get the color selector from it xColorpage = xDialog.getChild("ColorPage") - color_selector = xColorpage.getChild("colorset") + color_selector = xColorpage.getChild("coloriconview") # For chart-palettes colors select_by_text(xpaletteselector, "Chart Palettes") - # Select Color with id 2 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "2"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "2") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "1") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Chart 2") - self.assertEqual(get_state_as_dict(color_selector)["RGB"], "(255,66,14)") + # Select Color at index 1 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "1"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "1") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Chart 2") + # ID is the RGB color value in hex + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "FF420E") - # Select Color with id 5 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "5"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "5") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "4") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Chart 5") - self.assertEqual(get_state_as_dict(color_selector)["RGB"], "(126,0,33)") + # Select Color at index 4 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "4"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "4") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Chart 5") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "7E0021") # For libreoffice colors select_by_text(xpaletteselector, "LibreOffice") - # Select Color with id 6 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "6"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "6") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "5") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "32") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Green Accent") - self.assertEqual(get_state_as_dict(color_selector)["RGB"], "(44,238,14)") + # Select Color at index 5 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "5"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "5") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "32") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Green Accent") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "2CEE0E") - # Select Color with id 30 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "30"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "30") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "29") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Yellow Accent") - self.assertEqual(get_state_as_dict(color_selector)["RGB"], "(255,215,76)") + # Select Color at index 29 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "29"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "29") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Yellow Accent") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "FFD74C") # For html colors select_by_text(xpaletteselector, "HTML") - # Select Color with id 1 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "1"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "1") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "0") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "139") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "White") - # Select Color with id 120 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "120"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "120") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "119") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Navy") + # Select Color at index 0 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "0"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "0") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "139") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "White") + # Select Color at index 119 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "119"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "119") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Navy") # For freecolour-hlc colors select_by_text(xpaletteselector, "Freecolour HLC") - # Select Color with id 988 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "988"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "988") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "987") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "1032") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "HLC 350 60 10") - # Select Color with id 575 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "575"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "575") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "574") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "HLC 190 50 20") + # Select Color at index 987 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "987"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "987") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "1032") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "HLC 350 60 10") + # Select Color at index 574 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "574"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "574") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "HLC 190 50 20") # For tonal colors select_by_text(xpaletteselector, "Tonal") - # Select Color with id 17 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "17"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "17") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "16") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "120") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Cyan 82%") - # Select Color with id 13 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "13"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "13") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Magenta 82%") + # Select Color at index 16 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "16"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "16") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "120") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Cyan 82%") + # Select Color at index 12 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "12"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Magenta 82%") # For material colors select_by_text(xpaletteselector, "Material") - # Select Color with id 9 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "9"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "9") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "8") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "228") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Gray 800") + # Select Color at index 8 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "8"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "8") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "228") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Gray 800") # For standard colors select_by_text(xpaletteselector, "Standard") - # Select Color with id 3 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "3"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "3") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "2") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "120") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Dark Gray 3") + # Select Color at index 2 + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "2"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "2") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "120") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Dark Gray 3") @@ -158,18 +140,17 @@ class CalcCellBackgroundColorSelector(UITestCase): # recent color selector xpaletteselector = xDialog.getChild("paletteselector") xColorpage = xDialog.getChild("ColorPage") - color_selector = xColorpage.getChild("colorset") + color_selector = xColorpage.getChild("coloriconview") # For chart-palettes colors select_by_text(xpaletteselector, "Chart Palettes") - # Select Color with id 2 - color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "2"})) - self.assertEqual(get_state_as_dict(color_selector)["CurrColorId"], "2") - self.assertEqual(get_state_as_dict(color_selector)["CurrColorPos"], "1") - self.assertEqual(get_state_as_dict(color_selector)["ColorsCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColCount"], "12") - self.assertEqual(get_state_as_dict(color_selector)["ColorText"], "Chart 2") - xrgb = get_state_as_dict(color_selector)["RGB"] + # Select Color at index 1 and press Enter to activate + color_selector.executeAction("SELECT", mkPropertyValues({"POS": "1"})) + color_selector.executeAction("TYPE", mkPropertyValues({"KEYCODE": "RETURN"})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "1") + self.assertEqual(get_state_as_dict(color_selector)["Children"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectedEntryTooltip"], "Chart 2") + xrgb = get_state_as_dict(color_selector)["SelectedItemId"] # close the dialog after selection of the color @@ -184,14 +165,13 @@ class CalcCellBackgroundColorSelector(UITestCase): xbtncolor.executeAction("CLICK",tuple()) xColorpage = xDialog.getChild("ColorPage") - recent_color_selector = xColorpage.getChild("recentcolorset") + recent_color_selector = xColorpage.getChild("recentcoloriconview") # Select Color with id 1 - recent_color_selector.executeAction("CHOOSE", mkPropertyValues({"POS": "1"})) - self.assertEqual(get_state_as_dict(recent_color_selector)["CurrColorId"], "1") - self.assertEqual(get_state_as_dict(recent_color_selector)["CurrColorPos"], "0") - self.assertEqual(get_state_as_dict(recent_color_selector)["ColorText"], "Chart 2") - self.assertEqual(get_state_as_dict(recent_color_selector)["RGB"], xrgb) + recent_color_selector.executeAction("SELECT", mkPropertyValues({"POS": "0"})) + self.assertEqual(get_state_as_dict(recent_color_selector)["SelectedItemPos"], "0") + self.assertEqual(get_state_as_dict(recent_color_selector)["SelectedEntryTooltip"], "Chart 2") + self.assertEqual(get_state_as_dict(recent_color_selector)["SelectedItemId"], xrgb) diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk index 3c65096c2f5c..370a7bb8e48f 100644 --- a/svx/Library_svxcore.mk +++ b/svx/Library_svxcore.mk @@ -429,6 +429,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\ svx/source/table/viewcontactoftableobj \ svx/source/theme/ThemeColorChangerCommon \ svx/source/theme/ThemeColorPaletteManager \ + svx/source/tbxctrls/ColorIconView \ svx/source/tbxctrls/extrusioncontrols \ svx/source/tbxctrls/fontworkgallery \ svx/source/tbxctrls/IColorSet \ diff --git a/svx/source/tbxctrls/ColorIconView.cxx b/svx/source/tbxctrls/ColorIconView.cxx new file mode 100644 index 000000000000..739b2dbd1725 --- /dev/null +++ b/svx/source/tbxctrls/ColorIconView.cxx @@ -0,0 +1,86 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include +#include +#include +#include +#include + +ColorIconView::ColorIconView(std::unique_ptr pIconView) + : m_pIconView(std::move(pIconView)) +{ + m_pIconView->connect_item_activated(LINK(this, ColorIconView, ItemActivatedHdl)); +} + +void ColorIconView::insert(int nIndex, const Color& rColor, const OUString& rColorName) +{ + assert(nIndex >= 0 && nIndex <= m_pIconView->n_children() && "Invalid index"); + + const OUString* pNullIconName = nullptr; + m_pIconView->insert(nIndex, nullptr, nullptr, pNullIconName, nullptr); + ScopedVclPtr pIcon = createIcon(rColor); + m_pIconView->set_image(nIndex, *pIcon); + m_pIconView->set_item_tooltip_text(nIndex, rColorName); + m_pIconView->set_item_accessible_name(nIndex, rColorName); + m_pIconView->set_id(nIndex, rColor.AsRGBHEXString()); +} + +int ColorIconView::getItemCount() const { return m_pIconView->n_children(); } + +Color ColorIconView::getColor(int nIndex) +{ + if (nIndex < 0 || nIndex >= m_pIconView->n_children()) + return Color(); + + Color aColor; + color::createFromString("#" + m_pIconView->get_id(nIndex).toUtf8(), aColor); + return aColor; +} + +OUString ColorIconView::getColorName(int nIndex) const +{ + return m_pIconView->get_item_tooltip_text(nIndex); +} + +int ColorIconView::get_selected_index() const { return m_pIconView->get_selected_index(); } + +void ColorIconView::select(int nIndex) { m_pIconView->select(nIndex); }; + +void ColorIconView::unselect_all() { m_pIconView->unselect_all(); } + +void ColorIconView::remove(int nIndex) { m_pIconView->remove(nIndex); } + +void ColorIconView::clear() { m_pIconView->clear(); } + +IMPL_LINK(ColorIconView, ItemActivatedHdl, const weld::TreeIter&, rIter, bool) +{ + Color aColor = getColor(m_pIconView->get_iter_index_in_parent(rIter)); + m_aColorActivatedHdl.Call(aColor); + return true; +} + +ScopedVclPtr ColorIconView::createIcon(const Color& rColor) +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + + const tools::Long nEdgeLength = rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1; + const Size aSize(nEdgeLength, nEdgeLength); + + ScopedVclPtr pDev = m_pIconView->create_virtual_device(); + pDev->SetOutputSizePixel(aSize); + + pDev->SetFillColor(rColor); + pDev->SetLineColor(rStyleSettings.GetFieldTextColor()); + pDev->DrawRect(pDev->GetOutputRectPixel()); + + return pDev; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */