cui/qa/uitest/tabpages/tpcolor.py | 7 cui/source/inc/cuitabarea.hxx | 18 - cui/source/tabpages/tpcolor.cxx | 247 +++++++++-------- cui/uiconfig/ui/colorpage.ui | 69 +++- include/svx/Palette.hxx | 4 include/svx/PaletteManager.hxx | 5 include/svx/SvxColorIconView.hxx | 40 ++ sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py | 201 +++++++------ svx/Library_svxcore.mk | 1 svx/inc/palettes.hxx | 7 svx/source/tbxctrls/Palette.cxx | 79 +++++ svx/source/tbxctrls/PaletteManager.cxx | 140 +++++++++ svx/source/tbxctrls/SvxColorIconView.cxx | 112 +++++++ sw/uiconfig/swriter/ui/tocindexpage.ui | 3 14 files changed, 700 insertions(+), 233 deletions(-)
New commits: commit 5ac88a57a5b625dca5ba6c35b2b45a541df92eda Author: Parth Raiyani <[email protected]> AuthorDate: Tue Nov 25 00:06:04 2025 +0530 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Feb 24 15:35:38 2026 +0100 Remove misleading a11y relation from styles dropdown in TOC index page UI Signed-off-by: Parth Raiyani <[email protected]> Change-Id: Ibc7e08be5be906a4c0904250fb2b1cb23e0e856c Reviewed-on: https://gerrit.libreoffice.org/c/core/+/194476 Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-by: Szymon Kłos <[email protected]> Code-Style: Szymon Kłos <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200178 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/sw/uiconfig/swriter/ui/tocindexpage.ui b/sw/uiconfig/swriter/ui/tocindexpage.ui index d4f20f47e686..67ba9b72adb0 100644 --- a/sw/uiconfig/swriter/ui/tocindexpage.ui +++ b/sw/uiconfig/swriter/ui/tocindexpage.ui @@ -554,9 +554,6 @@ <property name="receives-default">True</property> <property name="halign">start</property> <property name="valign">center</property> - <accessibility> - <relation type="labelled-by" target="addstylescb"/> - </accessibility> <child internal-child="accessible"> <object class="AtkObject" id="styles-atkobject"> <property name="AtkObject::accessible-description" translatable="yes" context="tocindexpage|extended_tip|styles">Opens the Assign Styles dialog, where you can select the paragraph styles to include in the index by choosing the outline level for where the style should be placed.</property> commit e6b19f2e3590e3c4808eb2df2fa3b33cbc278eee Author: Parth Raiyani <[email protected]> AuthorDate: Wed Jul 16 22:54:03 2025 +0530 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Feb 24 15:35:27 2026 +0100 Switch to IconView in color selection for improved UI handling - Replaced SvxColorValueSet with weld::IconView for color selection in SvxColorTabPage. - Updated UI in colorpage.ui to include GtkIconView and GtkTreeStore for colors and recent colors. - Implemented new methods in Palette and PaletteManager to load color sets into IconView. - Added SvxColorIconView class to handle color entries and virtual device creation for color previews. - Adjusted event handling for color selection and tooltip queries in SvxColorTabPage. - Enhanced color management by providing methods to retrieve color lists from palettes and recent colors. - Updated FindInPalette method to find color from any palette - Added functionality to revert the New color preview to be same as Active color preview when no color is selected - Added caching color list and recent colors for performance improvement by reducing calls to GetColors() and GetRecentColors() - Fixed missing cases where "add" and "delete" buttons from custom palette should be disabled - Fixed unwanted selection appearing on both custom palette and recent colors palette when color is added from recent colors - Updated relevant test cases to work with iconview Change-Id: I2722a6351be7c1bca80caf8527fd92ee930f8446 Signed-off-by: Parth Raiyani <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187931 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200176 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/cui/qa/uitest/tabpages/tpcolor.py b/cui/qa/uitest/tabpages/tpcolor.py index 4e7b8261ff83..3a8fedbdd0e3 100644 --- a/cui/qa/uitest/tabpages/tpcolor.py +++ b/cui/qa/uitest/tabpages/tpcolor.py @@ -8,6 +8,7 @@ from libreoffice.uno.propertyvalue import mkPropertyValues from uitest.framework import UITestCase from uitest.uihelper.common import select_pos from uitest.uihelper.common import select_by_text +from uitest.uihelper.common import get_state_as_dict # Test for cui/source/tabpages/tpcolor.cxx. @@ -55,8 +56,10 @@ 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("iconview_colors") + color_element = colorSelector.getChild("4") + color_element.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(colorSelector)["SelectEntryText"], "Accent 1") # 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 8eca1094fb62..28522ff6e041 100644 --- a/cui/source/inc/cuitabarea.hxx +++ b/cui/source/inc/cuitabarea.hxx @@ -18,11 +18,10 @@ */ #pragma once -#include <svtools/valueset.hxx> #include <svx/dlgctrl.hxx> #include <svx/xflasit.hxx> #include <svx/tabarea.hxx> -#include <svx/SvxColorValueSet.hxx> +#include <svx/SvxColorIconView.hxx> #include <svx/SvxPresetListBox.hxx> #include <svx/PaletteManager.hxx> #include <svx/svdview.hxx> @@ -685,12 +684,13 @@ private: Color m_aPreviousColor; NamedColor m_aCurrentColor; + Color m_aActiveColor; PaletteManager maPaletteManager; SvxXRectPreview m_aCtlPreviewOld; SvxXRectPreview m_aCtlPreviewNew; - std::unique_ptr<SvxColorValueSet> m_xValSetColorList; - std::unique_ptr<SvxColorValueSet> m_xValSetRecentList; + std::unique_ptr<weld::IconView> m_xIconViewColorList; + std::unique_ptr<weld::IconView> m_xIconViewRecentList; std::unique_ptr<weld::ComboBox> m_xSelectPalette; std::unique_ptr<weld::RadioButton> m_xRbRGB; std::unique_ptr<weld::RadioButton> m_xRbCMYK; @@ -720,8 +720,9 @@ private: std::unique_ptr<weld::Button> m_xMoreColors; std::unique_ptr<weld::CustomWeld> m_xCtlPreviewOld; std::unique_ptr<weld::CustomWeld> m_xCtlPreviewNew; - std::unique_ptr<weld::CustomWeld> m_xValSetColorListWin; - std::unique_ptr<weld::CustomWeld> m_xValSetRecentListWin; + + std::vector<NamedColor> vColors; + std::vector<NamedColor> vRecentColors; static void ConvertColorValues (Color& rColor, ColorModel eModell); static void RgbToCmyk_Impl( Color& rColor, sal_uInt16& rK ); @@ -729,7 +730,6 @@ private: sal_uInt16 ColorToPercent_Impl( sal_uInt16 nColor ); sal_uInt16 PercentToColor_Impl( sal_uInt16 nPercent ); - void ImpColorCountChanged(); void FillPaletteLB(); DECL_LINK(ClickAddHdl_Impl, weld::Button&, void); @@ -738,7 +738,9 @@ private: DECL_LINK(OnMoreColorsClick, weld::Button&, void); DECL_LINK(SelectPaletteLBHdl, weld::ComboBox&, void); - DECL_LINK( SelectValSetHdl_Impl, ValueSet*, void ); + DECL_LINK( SelectionChangedHdl, weld::IconView&, void ); + DECL_LINK( QueryColorIVTooltipHdl, const weld::TreeIter&, OUString ); + DECL_LINK( QueryRecentIVTooltipHdl, const weld::TreeIter&, OUString ); DECL_LINK( SelectColorModeHdl_Impl, weld::Toggleable&, void ); void ChangeColor(const NamedColor &rNewColor, bool bUpdatePreset = true); void SetColorModel(ColorModel eModel); diff --git a/cui/source/tabpages/tpcolor.cxx b/cui/source/tabpages/tpcolor.cxx index 2313464991e7..61e9e713e224 100644 --- a/cui/source/tabpages/tpcolor.cxx +++ b/cui/source/tabpages/tpcolor.cxx @@ -50,8 +50,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_xIconViewColorList(m_xBuilder->weld_icon_view(u"iconview_colors"_ustr)) + , m_xIconViewRecentList(m_xBuilder->weld_icon_view(u"iconview_recent_colors"_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)) @@ -81,12 +81,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()); @@ -102,9 +99,12 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* // set handler m_xSelectPalette->connect_changed(LINK(this, SvxColorTabPage, SelectPaletteLBHdl)); - Link<ValueSet*, void> aValSelectLink = LINK(this, SvxColorTabPage, SelectValSetHdl_Impl); - m_xValSetColorList->SetSelectHdl(aValSelectLink); - m_xValSetRecentList->SetSelectHdl(aValSelectLink); + Link<weld::IconView&, void> aIVSelectionChangeLink = LINK(this, SvxColorTabPage, SelectionChangedHdl); + m_xIconViewColorList->connect_selection_changed(aIVSelectionChangeLink); + m_xIconViewRecentList->connect_selection_changed(aIVSelectionChangeLink); + + m_xIconViewColorList->connect_query_tooltip(LINK(this, SvxColorTabPage, QueryColorIVTooltipHdl)); + m_xIconViewRecentList->connect_query_tooltip(LINK(this, SvxColorTabPage, QueryRecentIVTooltipHdl)); Link<weld::SpinButton&,void> aSpinLink = LINK(this, SvxColorTabPage, SpinValueHdl_Impl); m_xRcustom->connect_value_changed(aSpinLink); @@ -138,18 +138,9 @@ 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()); + // IconView + maPaletteManager.ReloadRecentColorSet(*m_xIconViewRecentList); + vRecentColors = maPaletteManager.GetRecentColors(); // it is not possible to install color palette extensions in Online or mobile apps if(comphelper::LibreOfficeKit::isActive()) @@ -160,18 +151,8 @@ SvxColorTabPage::SvxColorTabPage(weld::Container* pPage, weld::DialogController* SvxColorTabPage::~SvxColorTabPage() { - m_xValSetRecentListWin.reset(); - m_xValSetRecentList.reset(); - m_xValSetColorListWin.reset(); - m_xValSetColorList.reset(); -} - -void SvxColorTabPage::ImpColorCountChanged() -{ - if (!m_pColorList.is()) - return; - m_xValSetColorList->SetColCount(SvxColorValueSet::getColumnCount()); - m_xValSetRecentList->SetColCount(SvxColorValueSet::getColumnCount()); + m_xIconViewRecentList.reset(); + m_xIconViewColorList.reset(); } void SvxColorTabPage::FillPaletteLB() @@ -195,7 +176,6 @@ void SvxColorTabPage::Construct() if (m_pColorList.is()) { FillPaletteLB(); - ImpColorCountChanged(); } } @@ -209,7 +189,7 @@ void SvxColorTabPage::ActivatePage( const SfxItemSet& ) m_aCtlPreviewOld.SetAttributes(m_aXFillAttr.GetItemSet()); m_aCtlPreviewOld.Invalidate(); - SelectValSetHdl_Impl(m_xValSetColorList.get()); + SelectionChangedHdl(*m_xIconViewColorList); } DeactivateRC SvxColorTabPage::DeactivatePage( SfxItemSet* _pSet ) @@ -222,10 +202,18 @@ DeactivateRC SvxColorTabPage::DeactivatePage( SfxItemSet* _pSet ) bool SvxColorTabPage::FillItemSet( SfxItemSet* rSet ) { - Color aColor = m_xValSetColorList->GetItemColor( m_xValSetColorList->GetSelectedItemId() ); + OUString sId = m_xIconViewColorList->get_selected_id(); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; + vColors = vColors.size() > 0 ? vColors : maPaletteManager.GetColors(); + NamedColor aColor(COL_BLACK, SvxResId(RID_SVXSTR_COLOR_BLACK)); //default black color + if(nPos >= 0 && o3tl::make_unsigned(nPos) < vColors.size()) + { + aColor = vColors[nPos]; + } + OUString sColorName; - if (m_aCurrentColor.m_aColor == aColor) - sColorName = m_xValSetColorList->GetItemText( m_xValSetColorList->GetSelectedItemId() ); + if (m_aCurrentColor.m_aColor == aColor.m_aColor) + sColorName = aColor.m_aName; else sColorName = "#" + m_aCurrentColor.m_aColor.AsRGBHexString().toAsciiUpperCase(); @@ -234,6 +222,7 @@ bool SvxColorTabPage::FillItemSet( SfxItemSet* rSet ) aColorItem.setComplexColor(m_aCurrentColor.getComplexColor()); rSet->Put(aColorItem); rSet->Put(XFillStyleItem(drawing::FillStyle_SOLID)); + vRecentColors = maPaletteManager.GetRecentColors(); return true; } @@ -368,12 +357,19 @@ 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 ); - m_xBtnDelete->set_sensitive(false); - m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR2) ); - ImpColorCountChanged(); + OUString sLastColorItemId = nSize > 0 ? m_xIconViewColorList->get_id(nSize - 1) : OUString(); + sal_Int32 nId = !sLastColorItemId.isEmpty() ? sLastColorItemId.toInt32() : -1; + VclPtr<VirtualDevice> pVDev = SvxColorIconView::createColorVirtualDevice(m_aCurrentColor.m_aColor); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); + OUString sId = OUString::number(nId + 1); + m_xIconViewColorList->insert( nId + 1, &aName, &sId, &aBmp, nullptr); + m_xIconViewColorList->select( nId + 1 ); + if (m_xIconViewRecentList) + m_xIconViewRecentList->unselect_all(); // needed if color is added from recent colors + vColors = maPaletteManager.GetColors(); + + m_xBtnDelete->set_sensitive(true); + m_xBtnDelete->set_tooltip_text(u""_ustr); } UpdateModified(); @@ -400,9 +396,9 @@ 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) + OUString sId = m_xIconViewColorList->get_selected_id(); + sal_Int32 nId = !sId.isEmpty() ? sId.toInt32() : -1; + if (m_xSelectPalette->get_active() != 0 || nId == -1) return; std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create()); @@ -411,7 +407,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<sal_Int32>(nPos);nIndex < nSize;nIndex++) + for(sal_Int32 nIndex = o3tl::make_unsigned(nId);nIndex < nSize;nIndex++) { aCustomColorListRange[nIndex] = aCustomColorList[nIndex+1]; aCustomColorNameListRange[nIndex] = aCustomColorNameList[nIndex+1]; @@ -421,26 +417,22 @@ 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) - { - nId = m_xValSetColorList->GetItemId(0); - m_xValSetColorList->SelectItem(nId); - SelectValSetHdl_Impl(m_xValSetColorList.get()); - } - else - { - m_xBtnDelete->set_sensitive(false); - m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR2) ); - } + m_xIconViewColorList->remove(nId); + maPaletteManager.ReloadColorSet(*m_xIconViewColorList); + vColors = maPaletteManager.GetColors(); + if (m_xIconViewColorList->n_children() != 0) + m_xIconViewColorList->select(0); + SelectionChangedHdl(*m_xIconViewColorList); // when there is no selection, SelectionChangedHdl will disable 'add' and 'delete' buttons and change selected color to default. } IMPL_LINK_NOARG(SvxColorTabPage, SelectPaletteLBHdl, weld::ComboBox&, void) { - m_xValSetColorList->Clear(); + m_xIconViewColorList->clear(); + vColors.clear(); sal_Int32 nPos = m_xSelectPalette->get_active(); maPaletteManager.SetPalette( nPos ); - maPaletteManager.ReloadColorSet(*m_xValSetColorList); + maPaletteManager.ReloadColorSet(*m_xIconViewColorList); + vColors = maPaletteManager.GetColors(); if(nPos != maPaletteManager.GetPaletteCount() - 1 && nPos != 0) { @@ -470,65 +462,68 @@ 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 + // select the 'Active' color in the m_xIconViewColorList if it has it if (const XFillColorItem* pFillColorItem = m_rOutAttrs.GetItemIfSet(GetWhich(XATTR_FILLCOLOR))) { SetColorModel(ColorModel::RGB); ChangeColorModel(); const Color aColor = pFillColorItem->GetColorValue(); + m_aActiveColor = aColor; NamedColor aNamedColor; aNamedColor.m_aColor = aColor; ChangeColor(aNamedColor); + sal_Int32 nPaletteIdx = FindInPalette(aColor); - if (sal_Int32 nPalettePos = maPaletteManager.GetPalette(); - /* theme colors palette */ maPaletteManager.IsThemePaletteSelected() || - /* document colors palette */ nPalettePos == maPaletteManager.GetPaletteCount() - 1 - || /* custom palette */ nPalettePos == 0) - { - for (size_t nItemPos = 0, nItemCount = m_xValSetColorList->GetItemCount(); - nItemPos < nItemCount; nItemPos++) - { - auto nItemId = m_xValSetColorList->GetItemId(nItemPos); - if (m_xValSetColorList->GetItemColor(nItemId) == aColor) - { - m_xValSetColorList->SelectItem(nItemId); - break; - } - } - } - else - { - m_pColorList = XPropertyList::AsColorList(XPropertyList::CreatePropertyListFromURL( - XPropertyListType::Color, maPaletteManager.GetSelectedPalettePath())); - if (m_pColorList->Load()) - { - auto nItemPos = FindInPalette(aColor); - if (nItemPos != -1) - m_xValSetColorList->SelectItem(m_xValSetColorList->GetItemId(nItemPos)); - } - } + if (nPaletteIdx != -1) + m_xIconViewColorList->select(nPaletteIdx); } } -IMPL_LINK(SvxColorTabPage, SelectValSetHdl_Impl, ValueSet*, pValSet, void) +IMPL_LINK(SvxColorTabPage, SelectionChangedHdl, weld::IconView&, rIconView, void) { - sal_Int32 nPos = pValSet->GetSelectedItemId(); - if( nPos == 0 ) + NamedColor aNamedColor; + OUString sId = rIconView.get_selected_id(); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; + if( nPos == -1 ) + { + m_rXFSet.Put( XFillColorItem( OUString(), m_aActiveColor ) ); + m_aCtlPreviewNew.SetAttributes( m_aXFillAttr.GetItemSet() ); + m_aCtlPreviewNew.Invalidate(); + + aNamedColor.m_aColor = m_aActiveColor; + ChangeColor(aNamedColor, false); + + m_xBtnAdd->set_sensitive(false); + m_xBtnDelete->set_sensitive(false); + m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR1) ); return; + } else { + m_xBtnAdd->set_sensitive(true); + } - Color aColor = pValSet->GetItemColor( nPos ); + std::vector< NamedColor > vColorList; + if(&rIconView == m_xIconViewRecentList.get()) { + vRecentColors = vRecentColors.size() > 0 ? vRecentColors : maPaletteManager.GetRecentColors(); + vColorList = vRecentColors; + } + else { + vColors = vColors.size() > 0 ? vColors : maPaletteManager.GetColors(); + vColorList = vColors; + } + + if(o3tl::make_unsigned(nPos) >= vColorList.size()) + return; + + Color aColor = vColorList[nPos].m_aColor; m_rXFSet.Put(XFillColorItem(OUString(), aColor)); m_aCtlPreviewNew.SetAttributes(m_aXFillAttr.GetItemSet()); m_aCtlPreviewNew.Invalidate(); - NamedColor aNamedColor; aNamedColor.m_aColor = aColor; - if (pValSet == m_xValSetColorList.get() && maPaletteManager.IsThemePaletteSelected()) + if (&rIconView == m_xIconViewColorList.get() && maPaletteManager.IsThemePaletteSelected()) { sal_uInt16 nThemeIndex; sal_uInt16 nEffectIndex; @@ -541,10 +536,12 @@ IMPL_LINK(SvxColorTabPage, SelectValSetHdl_Impl, ValueSet*, pValSet, void) ChangeColor(aNamedColor, false); - if (pValSet == m_xValSetColorList.get()) + if (&rIconView == m_xIconViewColorList.get()) { - m_xValSetRecentList->SetNoSelection(); - if (m_xSelectPalette->get_active() == 0 && m_xValSetColorList->GetSelectedItemId() != 0) + m_xIconViewRecentList->unselect_all(); + OUString selectedId = m_xIconViewColorList->get_selected_id(); + sal_Int32 nId = !selectedId.isEmpty() ? selectedId.toInt32() : -1; + if (m_xSelectPalette->get_active() == 0 && nId >= 0) { m_xBtnDelete->set_sensitive(true); m_xBtnDelete->set_tooltip_text(u""_ustr); @@ -555,14 +552,48 @@ IMPL_LINK(SvxColorTabPage, SelectValSetHdl_Impl, ValueSet*, pValSet, void) m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR1) ); } } - if (pValSet == m_xValSetRecentList.get()) + if (&rIconView == m_xIconViewRecentList.get()) { - m_xValSetColorList->SetNoSelection(); + m_xIconViewColorList->unselect_all(); m_xBtnDelete->set_sensitive(false); m_xBtnDelete->set_tooltip_text( CuiResId(RID_CUISTR_DELETEUSERCOLOR2) ); } } +IMPL_LINK(SvxColorTabPage, QueryColorIVTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sId = m_xIconViewColorList->get_id(rIter); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; + + if (nPos >= 0) + { + vColors = vColors.size() > 0 ? vColors : maPaletteManager.GetColors(); + if (o3tl::make_unsigned(nPos) < vColors.size()) + { + const NamedColor& rColor = vColors[nPos]; + return rColor.m_aName; + } + } + return OUString(); +} + +IMPL_LINK(SvxColorTabPage, QueryRecentIVTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sId = m_xIconViewRecentList->get_id(rIter); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; + + if (nPos >= 0) + { + vRecentColors = vRecentColors.size() > 0 ? vRecentColors : maPaletteManager.GetRecentColors(); + if (o3tl::make_unsigned(nPos) < vRecentColors.size()) + { + const NamedColor& rColor = vRecentColors[nPos]; + return rColor.m_aName; + } + } + return OUString(); +} + void SvxColorTabPage::ConvertColorValues (Color& rColor, ColorModel eModell) { switch (eModell) @@ -710,7 +741,17 @@ sal_Int32 SvxColorTabPage::FindInCustomColors(std::u16string_view aColorName) sal_Int32 SvxColorTabPage::FindInPalette( const Color& rColor ) { - return m_pColorList->GetIndexOfColor(rColor); + //GetColors() will return colors based on currently selected palette + vColors = vColors.size() > 0 ? vColors : maPaletteManager.GetColors(); + for( tools::Long i = 0, n = vColors.size(); i < n; ++i ) + { + const Color aColor = vColors[i].m_aColor; + + if (aColor == rColor ) + return i; + } + + return -1; } // A RGB value is converted to a CMYK value - not in an ideal way as diff --git a/cui/uiconfig/ui/colorpage.ui b/cui/uiconfig/ui/colorpage.ui index 672b60ea76e3..b75e55f1bcbd 100644 --- a/cui/uiconfig/ui/colorpage.ui +++ b/cui/uiconfig/ui/colorpage.ui @@ -47,6 +47,22 @@ <property name="can-focus">False</property> <property name="icon-name">res/sc10350.png</property> </object> + <object class="GtkTreeStore" id="colors_liststore"> + <columns> + <!-- column-name pixbuf --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkTreeStore" id="recent_colors_liststore"> + <columns> + <!-- column-name pixbuf --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> <object class="GtkBox" id="ColorPage"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -139,7 +155,7 @@ <property name="can-focus">False</property> <property name="label" translatable="yes" context="colorpage|label20">Recent Colors</property> <property name="use-underline">True</property> - <property name="mnemonic-widget">recentcolorset</property> + <property name="mnemonic-widget">iconview_recent_colors_win</property> <property name="xalign">0</property> </object> <packing> @@ -149,12 +165,27 @@ </packing> </child> <child> - <object class="GtkDrawingArea" id="recentcolorset"> + <object class="GtkScrolledWindow" id="iconview_recent_colors_win"> <property name="visible">True</property> <property name="can-focus">True</property> - <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> + <property name="hscrollbar-policy">never</property> + <property name="vscrollbar-policy">never</property> + <property name="shadow-type">in</property> + <property name="height-request">10</property> + <child> + <object class="GtkIconView" id="iconview_recent_colors"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="model">recent_colors_liststore</property> + <property name="pixbuf-column">0</property> + <property name="selection-mode">single</property> + <property name="item-orientation">horizontal</property> + <property name="columns">12</property> + <property name="row-spacing">1</property> + <property name="column-spacing">1</property> + <property name="item-padding">3</property> + </object> + </child> </object> <packing> <property name="expand">False</property> @@ -241,7 +272,7 @@ <property name="margin-bottom">3</property> <property name="label" translatable="yes" context="colorpage|label22">Custom Palette</property> <property name="use-underline">True</property> - <property name="mnemonic-widget">colorset</property> + <property name="mnemonic-widget">iconview_colors_win</property> <property name="xalign">0</property> </object> <packing> @@ -263,25 +294,25 @@ <property name="valign">start</property> <property name="orientation">vertical</property> <child> - <object class="GtkScrolledWindow" id="colorsetwin"> + <object class="GtkScrolledWindow" id="iconview_colors_win"> <property name="visible">True</property> <property name="can-focus">True</property> <property name="hscrollbar-policy">never</property> - <property name="vscrollbar-policy">never</property> + <property name="vscrollbar-policy">always</property> <property name="shadow-type">in</property> + <property name="height-request">180</property> <child> - <object class="GtkViewport"> + <object class="GtkIconView" id="iconview_colors"> <property name="visible">True</property> - <property name="can-focus">False</property> - <child> - <object class="GtkDrawingArea" id="colorset"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="events">GDK_BUTTON_MOTION_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_STRUCTURE_MASK</property> - <property name="hexpand">True</property> - <property name="vexpand">True</property> - </object> - </child> + <property name="can-focus">True</property> + <property name="model">colors_liststore</property> + <property name="pixbuf-column">0</property> + <property name="selection-mode">single</property> + <property name="item-orientation">horizontal</property> + <property name="columns">12</property> + <property name="row-spacing">1</property> + <property name="column-spacing">1</property> + <property name="item-padding">3</property> </object> </child> </object> diff --git a/include/svx/Palette.hxx b/include/svx/Palette.hxx index abc57423aca0..5839c7f23ef5 100644 --- a/include/svx/Palette.hxx +++ b/include/svx/Palette.hxx @@ -21,10 +21,12 @@ #include <sal/config.h> #include <sfx2/namedcolor.hxx> +#include <vcl/weld.hxx> #include <functional> class SvxColorValueSet; +class SvxColorIconView; typedef std::function<void(const OUString&, const NamedColor&)> ColorSelectFunction; @@ -39,6 +41,8 @@ public: virtual const OUString& GetName() = 0; virtual const OUString& GetPath() = 0; virtual void LoadColorSet(SvxColorValueSet& rColorSet) = 0; + virtual void LoadColorSet(weld::IconView& pIconView) = 0; + virtual std::vector< NamedColor > GetColorList() = 0; virtual bool IsValid() = 0; }; diff --git a/include/svx/PaletteManager.hxx b/include/svx/PaletteManager.hxx index 574dae22d679..943117eeb4aa 100644 --- a/include/svx/PaletteManager.hxx +++ b/include/svx/PaletteManager.hxx @@ -64,7 +64,9 @@ public: PaletteManager& operator=(const PaletteManager&) = delete; void LoadPalettes(); void ReloadColorSet(SvxColorValueSet& rColorSet); + void ReloadColorSet(weld::IconView& pIconView); void ReloadRecentColorSet(SvxColorValueSet& rColorSet); + void ReloadRecentColorSet(weld::IconView& pIconView); std::vector<OUString> GetPaletteList(); void SetPalette(sal_Int32 nPos, bool bPosOnly = false); sal_Int32 GetPalette() const; @@ -74,6 +76,9 @@ public: tools::Long GetColorCount() const; tools::Long GetRecentColorCount() const; + + std::vector< NamedColor > GetColors() const; + std::vector< NamedColor > GetRecentColors() const; void AddRecentColor(const Color& rRecentColor, const OUString& rColorName, bool bFront = true); void SetSplitButtonColor(const NamedColor& rColor); diff --git a/include/svx/SvxColorIconView.hxx b/include/svx/SvxColorIconView.hxx new file mode 100644 index 000000000000..aceaa7b4bddc --- /dev/null +++ b/include/svx/SvxColorIconView.hxx @@ -0,0 +1,40 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#pragma once + +#include <vcl/weld.hxx> +#include <svx/svxdllapi.h> +#include <set> + +class XColorList; + +class SVXCORE_DLLPUBLIC SvxColorIconView +{ +public: + static sal_uInt32 getEntryEdgeLength(); + static void addEntriesForXColorList(weld::IconView& pIconView, const XColorList& rXColorList, + sal_uInt32 nStartIndex = 0); + static void addEntriesForColorSet(weld::IconView& pIconView, const std::set<Color>& rColorSet, + std::u16string_view rNamePrefix); + + static VclPtr<VirtualDevice> createColorVirtualDevice(const Color& rColor); +}; + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ \ No newline at end of file diff --git a/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py b/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py index 1839545c7e88..550c180023e1 100644 --- a/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py +++ b/sc/qa/uitest/calc_tests/cellBackgroundColorSelector.py @@ -33,108 +33,109 @@ 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("iconview_colors") # 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 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 with id 1 + color_element2 = color_selector.getChild("1") + color_element2.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "1") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "1") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Chart 2") + + # Select Color with id 4 + color_element5 = color_selector.getChild("4") + color_element5.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "4") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "4") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Chart 5") # 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 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 with id 5 + color_element6 = color_selector.getChild("5") + color_element6.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "5") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "5") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "32") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Green Accent") + + # Select Color with id 29 + color_element30 = color_selector.getChild("29") + color_element30.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "29") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "29") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Yellow Accent") # 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 with id 0 + color_element1 = color_selector.getChild("0") + color_element1.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "0") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "0") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "139") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "White") + # Select Color with id 119 + color_element120 = color_selector.getChild("119") + color_element120.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "119") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "119") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "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 with id 987 + color_element988 = color_selector.getChild("987") + color_element988.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "987") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "987") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "1032") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "HLC 350 60 10") + # Select Color with id 574 + color_element575 = color_selector.getChild("574") + color_element575.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "574") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "574") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "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 with id 16 + color_element17 = color_selector.getChild("16") + color_element17.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "16") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "16") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "120") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Cyan 82%") + # Select Color with id 12 + color_element13 = color_selector.getChild("12") + color_element13.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "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 with id 8 + color_element9 = color_selector.getChild("8") + color_element9.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "8") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "8") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "228") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "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 with id 2 + color_element3 = color_selector.getChild("2") + color_element3.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "2") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "2") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "120") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Dark Gray 3") @@ -158,18 +159,22 @@ class CalcCellBackgroundColorSelector(UITestCase): # recent color selector xpaletteselector = xDialog.getChild("paletteselector") xColorpage = xDialog.getChild("ColorPage") - color_selector = xColorpage.getChild("colorset") + color_selector = xColorpage.getChild("iconview_colors") # 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 with id 1 + color_element2 = color_selector.getChild("1") + color_element2.executeAction("SELECT", mkPropertyValues({})) + print("Available properties:", list(get_state_as_dict(color_selector).keys())) + recent_state = get_state_as_dict(color_selector) + print("Parth see the following:") + for key, value in recent_state.items(): + print(f"{key}: {value}") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemId"], "1") + self.assertEqual(get_state_as_dict(color_selector)["SelectedItemPos"], "1") + self.assertEqual(get_state_as_dict(color_selector)["VisibleCount"], "12") + self.assertEqual(get_state_as_dict(color_selector)["SelectEntryText"], "Chart 2") # close the dialog after selection of the color @@ -184,14 +189,14 @@ class CalcCellBackgroundColorSelector(UITestCase): xbtncolor.executeAction("CLICK",tuple()) xColorpage = xDialog.getChild("ColorPage") - recent_color_selector = xColorpage.getChild("recentcolorset") - - # 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 = xColorpage.getChild("iconview_recent_colors") + + # Select Color with id 0 + recent_color_element1 = recent_color_selector.getChild("0") + recent_color_element1.executeAction("SELECT", mkPropertyValues({})) + self.assertEqual(get_state_as_dict(recent_color_selector)["SelectedItemId"], "0") + self.assertEqual(get_state_as_dict(recent_color_selector)["SelectedItemPos"], "0") + self.assertEqual(get_state_as_dict(recent_color_selector)["SelectEntryText"], "Chart 2") diff --git a/svx/Library_svxcore.mk b/svx/Library_svxcore.mk index e2d178b688f5..e185a9674223 100644 --- a/svx/Library_svxcore.mk +++ b/svx/Library_svxcore.mk @@ -437,6 +437,7 @@ $(eval $(call gb_Library_add_exception_objects,svxcore,\ svx/source/tbxctrls/tbcontrl \ svx/source/tbxctrls/tbxcolorupdate \ svx/source/tbxctrls/SvxColorValueSet \ + svx/source/tbxctrls/SvxColorIconView \ svx/source/tbxctrls/SvxPresetListBox \ svx/source/tbxctrls/StylesPreviewToolBoxControl \ svx/source/tbxctrls/StylesPreviewWindow \ diff --git a/svx/inc/palettes.hxx b/svx/inc/palettes.hxx index 7a3b8d1e1167..e555860a1dfb 100644 --- a/svx/inc/palettes.hxx +++ b/svx/inc/palettes.hxx @@ -21,6 +21,7 @@ #include <svx/Palette.hxx> #include <svx/SvxColorValueSet.hxx> +#include <svx/SvxColorIconView.hxx> #include <svx/xtable.hxx> class SvFileStream; @@ -45,6 +46,8 @@ public: virtual const OUString& GetName() override; virtual const OUString& GetPath() override; virtual void LoadColorSet(SvxColorValueSet& rColorSet) override; + virtual void LoadColorSet(weld::IconView& pIconView) override; + virtual std::vector< NamedColor > GetColorList() override; virtual bool IsValid() override; }; @@ -71,6 +74,8 @@ public: virtual const OUString& GetName() override; virtual const OUString& GetPath() override; virtual void LoadColorSet(SvxColorValueSet& rColorSet) override; + virtual void LoadColorSet(weld::IconView& pIconView) override; + virtual std::vector< NamedColor > GetColorList() override;; virtual bool IsValid() override; }; @@ -91,6 +96,8 @@ public: virtual const OUString& GetName() override; virtual const OUString& GetPath() override; virtual void LoadColorSet(SvxColorValueSet& rColorSet) override; + virtual void LoadColorSet(weld::IconView& pIconView) override; + virtual std::vector< NamedColor > GetColorList() override;; virtual bool IsValid() override; }; diff --git a/svx/source/tbxctrls/Palette.cxx b/svx/source/tbxctrls/Palette.cxx index 2f9afd67ce58..2e660abe6ccd 100644 --- a/svx/source/tbxctrls/Palette.cxx +++ b/svx/source/tbxctrls/Palette.cxx @@ -24,6 +24,8 @@ #include <palettes.hxx> #include <utility> +#include <vcl/virdev.hxx> + Palette::~Palette() { } @@ -51,6 +53,26 @@ void PaletteASE::LoadColorSet(SvxColorValueSet& rColorSet) } } +void PaletteASE::LoadColorSet(weld::IconView& pIconView) +{ + pIconView.clear(); + int nIx = 0; + for (const auto& rColor : maColors) + { + VclPtr<VirtualDevice> pColorVDev = SvxColorIconView::createColorVirtualDevice(rColor.m_aColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sColorName = rColor.m_aName; + OUString sId = OUString::number(nIx); + pIconView.insert(nIx, &sColorName, &sId, &aBmp, nullptr); + ++nIx; + } +} + +std::vector< NamedColor > PaletteASE::GetColorList() +{ + return maColors; +} + const OUString& PaletteASE::GetName() { return maASEPaletteName; @@ -307,6 +329,28 @@ void PaletteGPL::LoadColorSet(SvxColorValueSet& rColorSet) } } +void PaletteGPL::LoadColorSet(weld::IconView& pIconView) +{ + LoadPalette(); + + pIconView.clear(); + int nIx = 0; + for (const auto& rColor : maColors) + { + VclPtr<VirtualDevice> pColorVDev = SvxColorIconView::createColorVirtualDevice(rColor.m_aColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sColorName = rColor.m_aName; + OUString sId = OUString::number(nIx); + pIconView.insert(nIx, &sColorName, &sId, &aBmp, nullptr); + ++nIx; + } +} + +std::vector< NamedColor > PaletteGPL::GetColorList() +{ + return maColors; +} + bool PaletteGPL::IsValid() { return mbValidPalette; @@ -456,6 +500,41 @@ void PaletteSOC::LoadColorSet(SvxColorValueSet& rColorSet) rColorSet.addEntriesForXColorList( *mpColorList ); } +void PaletteSOC::LoadColorSet(weld::IconView& pIconView) +{ + if( !mbLoadedPalette ) + { + mbLoadedPalette = true; + mpColorList = XPropertyList::AsColorList(XPropertyList::CreatePropertyListFromURL(XPropertyListType::Color, maFPath)); + (void)mpColorList->Load(); + } + pIconView.clear(); + if( mpColorList.is() ) + SvxColorIconView::addEntriesForXColorList( pIconView, *mpColorList ); +} + +std::vector< NamedColor > PaletteSOC::GetColorList() +{ + std::vector<NamedColor> aColors; + if(!mpColorList.is()) + return aColors; + + const XColorList& rXColorList = *mpColorList; + const sal_uInt32 nColorCount(rXColorList.Count()); + + for(sal_uInt32 nIndex(0); nIndex < nColorCount; nIndex++) + { + const XColorEntry* pEntry = rXColorList.GetColor(nIndex); + + if(pEntry) + { + NamedColor aNamedColor(pEntry->GetColor(), pEntry->GetName()); + aColors.push_back(aNamedColor); + } + } + return aColors; +} + bool PaletteSOC::IsValid() { return true; diff --git a/svx/source/tbxctrls/PaletteManager.cxx b/svx/source/tbxctrls/PaletteManager.cxx index fb592d1b3a06..ca70b668fc89 100644 --- a/svx/source/tbxctrls/PaletteManager.cxx +++ b/svx/source/tbxctrls/PaletteManager.cxx @@ -33,6 +33,7 @@ #include <tbxcolorupdate.hxx> #include <vcl/svapp.hxx> #include <vcl/settings.hxx> +#include <vcl/virdev.hxx> #include <comphelper/sequence.hxx> #include <officecfg/Office/Common.hxx> #include <com/sun/star/frame/XDispatchProvider.hpp> @@ -245,6 +246,77 @@ void PaletteManager::ReloadColorSet(SvxColorValueSet &rColorSet) } } +void PaletteManager::ReloadColorSet(weld::IconView &pIconView) +{ + moThemePaletteCollection.reset(); + if( mnCurrentPalette == 0) + { + pIconView.clear(); + css::uno::Sequence< sal_Int32 > CustomColorList( officecfg::Office::Common::UserColors::CustomColor::get() ); + css::uno::Sequence< OUString > CustomColorNameList( officecfg::Office::Common::UserColors::CustomColorName::get() ); + for (int i = 0; i < CustomColorList.getLength(); ++i) + { + Color aColor(ColorTransparency, CustomColorList[i]); + VclPtr<VirtualDevice> pColorVDev = SvxColorIconView::createColorVirtualDevice(aColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sId = OUString::number(i); + OUString sColorName = CustomColorNameList[i]; + pIconView.insert(i, &sColorName, &sId, &aBmp, nullptr); + } + } + else if (IsThemePaletteSelected()) + { + SfxObjectShell* pObjectShell = SfxObjectShell::Current(); + if (pObjectShell) + { + auto pColorSet = pObjectShell->GetThemeColors(); + mnColorCount = 12; + pIconView.clear(); + sal_uInt16 nItemId = 0; + + if (!pColorSet) + return; + + svx::ThemeColorPaletteManager aThemeColorManager(pColorSet); + moThemePaletteCollection = aThemeColorManager.generate(); + + // Each row is one effect type (no effect + each type). + for (size_t nEffect : {0, 1, 2, 3, 4, 5}) + { + // Each column is one color type. + for (auto const& rColorData : moThemePaletteCollection->maColors) + { + auto const& rEffect = rColorData.maEffects[nEffect]; + Color aColor = rEffect.maColor; + VclPtr<VirtualDevice> pColorVDev = SvxColorIconView::createColorVirtualDevice(aColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sColorName = rEffect.maColorName; + OUString sId = OUString::number(nItemId); + pIconView.insert(nItemId, &sColorName, &sId, &aBmp, nullptr); + nItemId++; + } + } + } + } + else if( mnCurrentPalette == mnNumOfPalettes - 1 ) + { + // Add doc colors to palette + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + if (pDocSh) + { + std::set<Color> aColors = pDocSh->GetDocColors(); + mnColorCount = aColors.size(); + pIconView.clear(); + SvxColorIconView::addEntriesForColorSet(pIconView, aColors, Concat2View(SvxResId( RID_SVXSTR_DOC_COLOR_PREFIX ) + " ") ); + } + } + else + { + m_Palettes[mnCurrentPalette - 1]->LoadColorSet( pIconView ); + mnColorCount = pIconView.n_children(); + } +} + void PaletteManager::ReloadRecentColorSet(SvxColorValueSet& rColorSet) { maRecentColors.clear(); @@ -263,6 +335,27 @@ void PaletteManager::ReloadRecentColorSet(SvxColorValueSet& rColorSet) } } +void PaletteManager::ReloadRecentColorSet(weld::IconView& pIconView) +{ + maRecentColors.clear(); + pIconView.clear(); + css::uno::Sequence< sal_Int32 > Colorlist(officecfg::Office::Common::UserColors::RecentColor::get()); + css::uno::Sequence< OUString > ColorNamelist(officecfg::Office::Common::UserColors::RecentColorName::get()); + int nIx = 0; + const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength(); + for (int i = 0; i < Colorlist.getLength(); ++i) + { + Color aColor(ColorTransparency, Colorlist[i]); + VclPtr<VirtualDevice> pColorVDev = SvxColorIconView::createColorVirtualDevice(aColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase()); + maRecentColors.emplace_back(aColor, sColorName); + OUString sId = OUString::number(nIx); + pIconView.insert(nIx, &sColorName, &sId, &aBmp, nullptr); + ++nIx; + } +} + std::vector<OUString> PaletteManager::GetPaletteList() { std::vector<OUString> aPaletteNames @@ -339,6 +432,53 @@ const OUString & PaletteManager::GetSelectedPalettePath() return EMPTY_OUSTRING; } +std::vector<NamedColor> PaletteManager::GetColors() const +{ + std::vector<NamedColor> colors; + + if (mnCurrentPalette == 0) { + css::uno::Sequence<sal_Int32> CustomColorList(officecfg::Office::Common::UserColors::CustomColor::get()); + css::uno::Sequence<OUString> CustomColorNameList(officecfg::Office::Common::UserColors::CustomColorName::get()); + + for (int i = 0; i < CustomColorList.getLength(); ++i) { + Color aColor(ColorTransparency, CustomColorList[i]); + OUString colorName = (i < CustomColorNameList.getLength()) ? CustomColorNameList[i] : OUString(); + colors.emplace_back(aColor, colorName); + } + } + else if (IsThemePaletteSelected()) { + if (moThemePaletteCollection) { + for (size_t nEffect : {0, 1, 2, 3, 4, 5}) { + for (auto const& rColorData : moThemePaletteCollection->maColors) { + auto const& rEffect = rColorData.maEffects[nEffect]; + colors.emplace_back(rEffect.maColor, rEffect.maColorName); + } + } + } + } + else if (mnCurrentPalette == mnNumOfPalettes - 1) { + SfxObjectShell* pDocSh = SfxObjectShell::Current(); + if (pDocSh) { + std::set<Color> aColors = pDocSh->GetDocColors(); + OUString namePrefix = SvxResId(RID_SVXSTR_DOC_COLOR_PREFIX) + " "; + int index = 1; + for (const Color& color : aColors) { + colors.emplace_back(color, namePrefix + OUString::number(index++)); + } + } + } + else { + return m_Palettes[mnCurrentPalette - 1]->GetColorList(); + } + + return colors; +} + +std::vector< NamedColor > PaletteManager::GetRecentColors() const +{ + return std::vector< NamedColor >(maRecentColors.begin(), maRecentColors.end()); +} + tools::Long PaletteManager::GetColorCount() const { return mnColorCount; diff --git a/svx/source/tbxctrls/SvxColorIconView.cxx b/svx/source/tbxctrls/SvxColorIconView.cxx new file mode 100644 index 000000000000..6c95bd58fbf1 --- /dev/null +++ b/svx/source/tbxctrls/SvxColorIconView.cxx @@ -0,0 +1,112 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * 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/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <svx/SvxColorIconView.hxx> +#include <svx/xtable.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/virdev.hxx> +#include <vcl/bitmap.hxx> +#include <osl/diagnose.h> + +sal_uInt32 SvxColorIconView::getEntryEdgeLength() +{ + const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); + return rStyleSettings.GetListBoxPreviewDefaultPixelSize().Height() + 1; +} + +void SvxColorIconView::addEntriesForXColorList(weld::IconView& pIconView, + const XColorList& rXColorList, + sal_uInt32 nStartIndex) +{ + const sal_uInt32 nColorCount(rXColorList.Count()); + + for (sal_uInt32 nIndex(0); nIndex < nColorCount; nIndex++, nStartIndex++) + { + const XColorEntry* pEntry = rXColorList.GetColor(nIndex); + + if (pEntry) + { + VclPtr<VirtualDevice> pColorVDev = createColorVirtualDevice(pEntry->GetColor()); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sColorName = pEntry->GetName(); + OUString sId = OUString::number(nIndex); + pIconView.insert(nIndex, &sColorName, &sId, &aBmp, nullptr); + } + else + { + OSL_ENSURE(false, "OOps, XColorList with empty entries (!)"); + } + } +} + +void SvxColorIconView::addEntriesForColorSet(weld::IconView& pIconView, + const std::set<Color>& rColorSet, + std::u16string_view rNamePrefix) +{ + sal_uInt32 nStartIndex = 0; + if (!rNamePrefix.empty()) + { + for (const auto& rColor : rColorSet) + { + VclPtr<VirtualDevice> pColorVDev = createColorVirtualDevice(rColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sName = OUString::Concat(rNamePrefix) + OUString::number(nStartIndex); + OUString sId = OUString::number(nStartIndex); + pIconView.insert(nStartIndex, &sName, &sId, &aBmp, nullptr); + nStartIndex++; + } + } + else + { + for (const auto& rColor : rColorSet) + { + VclPtr<VirtualDevice> pColorVDev = createColorVirtualDevice(rColor); + Bitmap aBmp = pColorVDev->GetBitmap(Point(), pColorVDev->GetOutputSizePixel()); + OUString sId = OUString::number(nStartIndex); + OUString sName = u""_ustr; + pIconView.insert(nStartIndex, &sName, &sId, &aBmp, nullptr); + nStartIndex++; + } + } +} + +VclPtr<VirtualDevice> SvxColorIconView::createColorVirtualDevice(const Color& rColor) +{ + const sal_uInt32 nEdgeLength = getEntryEdgeLength() - 2; + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + pVDev->SetOutputSizePixel(Size(nEdgeLength, nEdgeLength)); + + // Fill with the color + pVDev->SetFillColor(rColor); + pVDev->SetLineColor(COL_BLACK); + pVDev->DrawRect(tools::Rectangle(Point(0, 0), Size(nEdgeLength, nEdgeLength))); + + Bitmap aPreviewBitmap = pVDev->GetBitmap(Point(0, 0), Size(nEdgeLength, nEdgeLength)); + const Point aNull(0, 0); + if (pVDev->GetDPIScaleFactor() > 1) + aPreviewBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor()); + const Size aSize(aPreviewBitmap.GetSizePixel()); + pVDev->SetOutputSizePixel(aSize); + pVDev->DrawBitmap(aNull, aPreviewBitmap); + + return pVDev; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
