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 <m.weghorn@posteo.de>
    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 7d1647bdb7
    Author: Michael Weghorn <m.weghorn@posteo.de>
    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<comphelper::OAccessible> (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 7d1647bdb7,
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 <m.weghorn@posteo.de>
This commit is contained in:
Michael Weghorn
2026-04-18 07:05:03 +02:00
parent 2b80a73681
commit 701cea2393
8 changed files with 315 additions and 195 deletions
+3 -2
View File
@@ -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]
+5 -8
View File
@@ -20,11 +20,10 @@
#include "SvxPresetListBox.hxx"
#include <svtools/valueset.hxx>
#include <svx/ColorIconView.hxx>
#include <svx/dlgctrl.hxx>
#include <svx/xflasit.hxx>
#include <svx/tabarea.hxx>
#include <svx/SvxColorValueSet.hxx>
#include <svx/PaletteManager.hxx>
#include <svx/svdview.hxx>
#include <vcl/hexcolorcontrol.hxx>
@@ -677,8 +676,8 @@ private:
PaletteManager maPaletteManager;
SvxXRectPreview m_aCtlPreviewOld;
SvxXRectPreview m_aCtlPreviewNew;
std::unique_ptr<SvxColorValueSet> m_xValSetColorList;
std::unique_ptr<SvxColorValueSet> m_xValSetRecentList;
ColorIconView m_aColorIconView;
ColorIconView m_aRecentIconView;
std::unique_ptr<weld::ComboBox> m_xSelectPalette;
std::unique_ptr<weld::RadioButton> m_xRbRGB;
std::unique_ptr<weld::RadioButton> m_xRbCMYK;
@@ -708,8 +707,6 @@ 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;
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);
+39 -64
View File
@@ -22,6 +22,7 @@
#include <vcl/ColorDialog.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weld/Builder.hxx>
#include <vcl/weld/IconView.hxx>
#include <vcl/weld/ScrolledWindow.hxx>
#include <vcl/weld/MessageDialog.hxx>
#include <vcl/weld/weld.hxx>
@@ -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<weld::SpinButton&,void> 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<comphelper::ConfigurationChanges> 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<sal_Int32>(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));
}
+47 -27
View File
@@ -37,6 +37,16 @@
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
<object class="GtkTreeStore" id="coloriconviewmodel">
<columns>
<!-- column-name pixbuf -->
<column type="GdkPixbuf"/>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name tooltip -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkImage" id="image1">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -47,6 +57,16 @@
<property name="can-focus">False</property>
<property name="icon-name">res/sc10350.png</property>
</object>
<object class="GtkTreeStore" id="recentcoloriconviewmodel">
<columns>
<!-- column-name pixbuf -->
<column type="GdkPixbuf"/>
<!-- column-name id -->
<column type="gchararray"/>
<!-- column-name tooltip -->
<column type="gchararray"/>
</columns>
</object>
<object class="GtkBox" id="ColorPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
@@ -59,6 +79,7 @@
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="label-xalign">0</property>
<property name="shadow-type">none</property>
<child>
@@ -67,9 +88,9 @@
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="valign">start</property>
<property name="margin-start">12</property>
<property name="margin-top">6</property>
<property name="vexpand">True</property>
<property name="row-spacing">6</property>
<child>
<object class="GtkBox" id="box7">
@@ -139,7 +160,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">recentcoloriconview</property>
<property name="xalign">0</property>
</object>
<packing>
@@ -149,17 +170,20 @@
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="recentcolorset">
<object class="GtkIconView" id="recentcoloriconview">
<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="margin">6</property>
<property name="model">recentcoloriconviewmodel</property>
<property name="columns">12</property>
<property name="pixbuf-column">0</property>
<property name="tooltip-column">2</property>
<property name="activate-on-single-click">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
<property name="position">2</property>
</packing>
</child>
</object>
@@ -241,7 +265,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">coloriconview</property>
<property name="xalign">0</property>
</object>
<packing>
@@ -260,35 +284,31 @@
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">start</property>
<property name="vexpand">True</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="colorsetwin">
<object class="GtkScrolledWindow">
<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="shadow-type">in</property>
<child>
<object class="GtkViewport">
<object class="GtkIconView" id="coloriconview">
<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="margin">6</property>
<property name="model">coloriconviewmodel</property>
<property name="columns">12</property>
<property name="pixbuf-column">0</property>
<property name="tooltip-column">2</property>
<property name="activate-on-single-click">True</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
@@ -311,7 +331,7 @@
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
+60
View File
@@ -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 <svx/IColorSet.hxx>
#include <svx/svxdllapi.h>
#include <vcl/weld/ItemView.hxx>
namespace vcl
{
class VirtualDevice;
}
namespace weld
{
class IconView;
}
class SVXCORE_DLLPUBLIC ColorIconView : public IColorSet
{
std::unique_ptr<weld::IconView> m_pIconView;
Link<const Color&, void> m_aColorActivatedHdl;
DECL_LINK(ItemActivatedHdl, const weld::TreeIter&, bool);
public:
ColorIconView(std::unique_ptr<weld::IconView> 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<const Color&, void>& rLink)
{
m_aColorActivatedHdl = rLink;
}
private:
ScopedVclPtr<VirtualDevice> createIcon(const Color& rColor);
};
/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
@@ -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)
+1
View File
@@ -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 \
+86
View File
@@ -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 <svx/ColorIconView.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/virdev.hxx>
#include <vcl/weld/IconView.hxx>
ColorIconView::ColorIconView(std::unique_ptr<weld::IconView> 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<VirtualDevice> 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<VirtualDevice> 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<VirtualDevice> 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: */