cui/qa/uitest/dialogs/chardlg.py | 11 - cui/qa/uitest/tabpages/tpcolor.py | 4 cui/source/inc/cuitabarea.hxx | 19 ++ cui/source/tabpages/border.cxx | 1 cui/source/tabpages/tphatch.cxx | 229 +++++++++++++++++++++++--------- cui/uiconfig/ui/hatchpage.ui | 30 ++-- include/svx/PaletteManager.hxx | 1 include/svx/colorwindow.hxx | 24 ++- sd/qa/uitest/impress_tests/tdf137729.py | 7 svx/source/tbxctrls/PaletteManager.cxx | 22 --- svx/source/tbxctrls/tbcontrl.cxx | 173 ++++++++++++++++-------- svx/uiconfig/ui/colorwindow.ui | 66 ++++++--- 12 files changed, 402 insertions(+), 185 deletions(-)
New commits: commit a68222c99ca6b63a86a6a743140f5cd97857072c Author: Parth Raiyani <[email protected]> AuthorDate: Wed Aug 6 19:40:48 2025 +0530 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Feb 24 17:14:47 2026 +0100 Switch to IconView in color selection for improved UI handling - Replaced SvxColorValueSet with weld::IconView for color selection in colorwindow - Updated UI in colorwindow.ui to include GtkIconView and GtkTreeStore for colors and recent colors - Adjusted event handling for color selection and tooltip queries in tbcontrl - Added caching color list and recent colors for performance improvement by reducing calls to GetColors() and GetRecentColors() - Removed unused method ReloadRecentColorSet having SvxColorValueSet param from PaletteManager - fixed import issue in border.cxx - removed the changes made as part of tdf#157034 as after iconview conversion nItemId will always begin with 0 - updated the affected test cases Change-Id: I82fec2a2e6fc1cfd1eb0051a03df445a9812ab5a Signed-off-by: Parth Raiyani <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188921 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200191 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/cui/qa/uitest/dialogs/chardlg.py b/cui/qa/uitest/dialogs/chardlg.py index ee754b3c0f3a..15b9aa15ccd6 100644 --- a/cui/qa/uitest/dialogs/chardlg.py +++ b/cui/qa/uitest/dialogs/chardlg.py @@ -93,9 +93,12 @@ class Test(UITestCase): floatWindow = self.xUITest.getFloatWindow() paletteSelector = floatWindow.getChild("palette_listbox") select_by_text(paletteSelector, "Theme colors") - colorSet = floatWindow.getChild("colorset") + colorIconView = floatWindow.getChild("colorwindow_iv_colors") # 4 would be accent1, +12 is the first from the effect variants. - colorSet.executeAction("CHOOSE", mkPropertyValues({"POS": "16"})) + color_element = colorIconView.getChild("16") + color_element.executeAction("SELECT", mkPropertyValues({})) + color_element.executeAction("DOUBLECLICK", tuple()) + self.assertEqual(get_state_as_dict(colorIconView)["SelectEntryText"], "Accent 1, 50% Lighter") # Then make sure the doc model has the correct color theme index: drawPage = component.getDrawPages()[0] @@ -106,9 +109,9 @@ class Test(UITestCase): portion = portions.nextElement() # Without the accompanying fix in place, this test would have failed with: - # AssertionError: -1 != 3 + # AssertionError: -1 != 4 # i.e. no theme index was set, instead of accent1 (index into the above color scheme). - self.assertEqual(portion.CharColorTheme, 3) + self.assertEqual(portion.CharColorTheme, 4) # Then make sure that '80% lighter' is lum-mod=2000 and lum-off=8000: # Without the accompanying fix in place, this test would have failed with: diff --git a/cui/qa/uitest/tabpages/tpcolor.py b/cui/qa/uitest/tabpages/tpcolor.py index 3a8fedbdd0e3..4a48c6f3f913 100644 --- a/cui/qa/uitest/tabpages/tpcolor.py +++ b/cui/qa/uitest/tabpages/tpcolor.py @@ -64,9 +64,9 @@ class Test(UITestCase): # Then make sure the doc model is updated accordingly: shape = drawPage[0] # Without the accompanying fix in place, this test would have failed with: - # AssertionError: -1 != 3 + # AssertionError: -1 != 4 # i.e. the theme metadata of the selected fill color was lost. - self.assertEqual(shape.FillColorTheme, 3) + self.assertEqual(shape.FillColorTheme, 4) # vim: set shiftwidth=4 softtabstop=4 expandtab: diff --git a/cui/source/tabpages/border.cxx b/cui/source/tabpages/border.cxx index 013bf2b6a78f..3897c1d1f39e 100644 --- a/cui/source/tabpages/border.cxx +++ b/cui/source/tabpages/border.cxx @@ -46,6 +46,7 @@ #include <comphelper/lok.hxx> #include <svtools/unitconv.hxx> #include <vcl/virdev.hxx> +#include <vcl/image.hxx> using namespace ::editeng; using ::com::sun::star::uno::Reference; diff --git a/include/svx/PaletteManager.hxx b/include/svx/PaletteManager.hxx index 943117eeb4aa..4236173ad36e 100644 --- a/include/svx/PaletteManager.hxx +++ b/include/svx/PaletteManager.hxx @@ -65,7 +65,6 @@ public: 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); diff --git a/include/svx/colorwindow.hxx b/include/svx/colorwindow.hxx index a08381711593..707c22f712fa 100644 --- a/include/svx/colorwindow.hxx +++ b/include/svx/colorwindow.hxx @@ -21,7 +21,7 @@ #include <svtools/toolbarmenu.hxx> #include <rtl/ustring.hxx> -#include <svx/SvxColorValueSet.hxx> +#include <svx/SvxColorIconView.hxx> #include <svx/Palette.hxx> #include <vcl/toolboxid.hxx> @@ -86,25 +86,31 @@ private: TopLevelParentFunction maTopLevelParentFunction; ColorSelectFunction maColorSelectFunction; - std::unique_ptr<SvxColorValueSet> mxColorSet; - std::unique_ptr<SvxColorValueSet> mxRecentColorSet; + std::unique_ptr<weld::IconView> mxColorIconView; + std::unique_ptr<weld::IconView> mxRecentColorIconView; std::unique_ptr<weld::ComboBox> mxPaletteListBox; std::unique_ptr<weld::Button> mxButtonAutoColor; std::unique_ptr<weld::Button> mxButtonNoneColor; std::unique_ptr<weld::Button> mxButtonPicker; std::unique_ptr<weld::Widget> mxAutomaticSeparator; - std::unique_ptr<weld::CustomWeld> mxColorSetWin; - std::unique_ptr<weld::CustomWeld> mxRecentColorSetWin; weld::Button* mpDefaultButton; - DECL_DLLPRIVATE_LINK(SelectHdl, ValueSet*, void); + std::vector<NamedColor> vColors; + std::vector<NamedColor> vRecentColors; + + DECL_DLLPRIVATE_LINK(SelectionChangedHdl, weld::IconView&, void); + DECL_DLLPRIVATE_LINK(ItemActivatedHdl, weld::IconView&, bool); DECL_DLLPRIVATE_LINK(SelectPaletteHdl, weld::ComboBox&, void); DECL_DLLPRIVATE_LINK(AutoColorClickHdl, weld::Button&, void); DECL_DLLPRIVATE_LINK(OpenPickerClickHdl, weld::Button&, void); + DECL_DLLPRIVATE_LINK(QueryColorIVTooltipHdl, const weld::TreeIter&, OUString); + DECL_DLLPRIVATE_LINK(QueryRecentIVTooltipHdl, const weld::TreeIter&, OUString); + OUString QueryTooltipHdl_Impl(weld::IconView* pIconView, std::u16string_view); - static bool SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor); - static NamedColor GetSelectEntryColor(ValueSet const * pColorSet); + bool SelectIconViewEntry(weld::IconView* pIconView, const Color& rColor); + NamedColor GetSelectEntryColor(weld::IconView* pIconView); NamedColor GetAutoColor() const; + std::vector<NamedColor> GetColors(weld::IconView* pIconView); public: ColorWindow(OUString rCommand, @@ -121,7 +127,7 @@ public: bool IsNoSelection() const; void SelectEntry(const NamedColor& rColor); void SelectEntry(const Color& rColor); - NamedColor GetSelectEntryColor() const; + NamedColor GetSelectEntryColor(); virtual void statusChanged( const css::frame::FeatureStateEvent& rEvent ) override; diff --git a/svx/source/tbxctrls/PaletteManager.cxx b/svx/source/tbxctrls/PaletteManager.cxx index ca70b668fc89..27a80461afda 100644 --- a/svx/source/tbxctrls/PaletteManager.cxx +++ b/svx/source/tbxctrls/PaletteManager.cxx @@ -157,10 +157,6 @@ bool PaletteManager::IsThemePaletteSelected() const bool PaletteManager::GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16& rThemeIndex, sal_uInt16& rEffectIndex) { - // tdf#157034, nItemId begins with 1 but list of themes begin with 0 - // so decrement nItemId - --nItemId; - // Each column is the same color with different effects. rThemeIndex = nItemId % 12; @@ -317,24 +313,6 @@ void PaletteManager::ReloadColorSet(weld::IconView &pIconView) } } -void PaletteManager::ReloadRecentColorSet(SvxColorValueSet& rColorSet) -{ - maRecentColors.clear(); - rColorSet.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 = 1; - const bool bHasColorNames = Colorlist.getLength() == ColorNamelist.getLength(); - for (int i = 0; i < Colorlist.getLength(); ++i) - { - Color aColor(ColorTransparency, Colorlist[i]); - OUString sColorName = bHasColorNames ? ColorNamelist[i] : ("#" + aColor.AsRGBHexString().toAsciiUpperCase()); - maRecentColors.emplace_back(aColor, sColorName); - rColorSet.InsertItem(nIx, aColor, sColorName); - ++nIx; - } -} - void PaletteManager::ReloadRecentColorSet(weld::IconView& pIconView) { maRecentColors.clear(); diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx index beda9d000c76..8bbdd1e3f3b9 100644 --- a/svx/source/tbxctrls/tbcontrl.cxx +++ b/svx/source/tbxctrls/tbcontrl.cxx @@ -2065,19 +2065,15 @@ ColorWindow::ColorWindow(OUString rCommand, , mrColorStatus(rColorStatus) , maTopLevelParentFunction(std::move(aTopLevelParentFunction)) , maColorSelectFunction(std::move(aColorSelectFunction)) - , mxColorSet(new SvxColorValueSet(m_xBuilder->weld_scrolled_window(u"colorsetwin"_ustr, true))) - , mxRecentColorSet(new SvxColorValueSet(nullptr)) + , mxColorIconView(m_xBuilder->weld_icon_view(u"colorwindow_iv_colors"_ustr)) + , mxRecentColorIconView(m_xBuilder->weld_icon_view(u"colorwindow_iv_recentcolors"_ustr)) , mxPaletteListBox(m_xBuilder->weld_combo_box(u"palette_listbox"_ustr)) , mxButtonAutoColor(m_xBuilder->weld_button(u"auto_color_button"_ustr)) , mxButtonNoneColor(m_xBuilder->weld_button(u"none_color_button"_ustr)) , mxButtonPicker(m_xBuilder->weld_button(u"color_picker_button"_ustr)) , mxAutomaticSeparator(m_xBuilder->weld_widget(u"separator4"_ustr)) - , mxColorSetWin(new weld::CustomWeld(*m_xBuilder, u"colorset"_ustr, *mxColorSet)) - , mxRecentColorSetWin(new weld::CustomWeld(*m_xBuilder, u"recent_colorset"_ustr, *mxRecentColorSet)) , mpDefaultButton(nullptr) { - mxColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); - mxRecentColorSet->SetStyle( WinBits(WB_FLATVALUESET | WB_ITEMBORDER | WB_3DLOOK | WB_NO_DIRECTSELECT | WB_TABSTOP) ); switch ( mnSlotId ) { @@ -2143,19 +2139,28 @@ ColorWindow::ColorWindow(OUString rCommand, mxButtonNoneColor->connect_clicked(LINK(this, ColorWindow, AutoColorClickHdl)); mxButtonPicker->connect_clicked(LINK(this, ColorWindow, OpenPickerClickHdl)); - mxColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl)); - mxRecentColorSet->SetSelectHdl(LINK( this, ColorWindow, SelectHdl)); - m_xTopLevel->set_help_id(HID_POPUP_COLOR); - mxColorSet->SetHelpId(HID_POPUP_COLOR_CTRL); + mxColorIconView->connect_selection_changed(LINK(this, ColorWindow, SelectionChangedHdl)); + mxColorIconView->connect_item_activated(LINK(this, ColorWindow, ItemActivatedHdl)); - mxPaletteManager->ReloadColorSet(*mxColorSet); - const sal_uInt32 nMaxItems(SvxColorValueSet::getMaxRowCount() * SvxColorValueSet::getColumnCount()); - Size aSize = mxColorSet->layoutAllVisible(nMaxItems); - mxColorSet->set_size_request(aSize.Width(), aSize.Height()); + mxRecentColorIconView->connect_selection_changed(LINK(this, ColorWindow, SelectionChangedHdl)); + mxRecentColorIconView->connect_item_activated(LINK(this, ColorWindow, ItemActivatedHdl)); - mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); - aSize = mxRecentColorSet->layoutAllVisible(mxPaletteManager->GetRecentColorCount()); - mxRecentColorSet->set_size_request(aSize.Width(), aSize.Height()); + // Avoid LibreOffice Kit crash: tooltip handlers cause segfault during JSDialog + // serialization when popup widgets are destroyed/recreated during character formatting resets. + // Tooltip event binding is not needed for LibreOffice Kit + if (!comphelper::LibreOfficeKit::isActive()) + { + mxColorIconView->connect_query_tooltip(LINK(this, ColorWindow, QueryColorIVTooltipHdl)); + mxRecentColorIconView->connect_query_tooltip(LINK(this, ColorWindow, QueryRecentIVTooltipHdl)); + } + + m_xTopLevel->set_help_id(HID_POPUP_COLOR); + mxColorIconView->set_help_id(HID_POPUP_COLOR_CTRL); + + mxPaletteManager->ReloadColorSet(*mxColorIconView); + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorIconView); + vColors = mxPaletteManager->GetColors(); + vRecentColors = mxPaletteManager->GetRecentColors(); AddStatusListener( u".uno:ColorTableState"_ustr ); AddStatusListener( maCommand ); @@ -2168,10 +2173,10 @@ ColorWindow::ColorWindow(OUString rCommand, void ColorWindow::GrabFocus() { - if (mxColorSet->IsNoSelection() && mpDefaultButton) + if (mxColorIconView->get_selected_id().isEmpty() && mpDefaultButton) mpDefaultButton->grab_focus(); else - mxColorSet->GrabFocus(); + mxColorIconView->grab_focus(); } void ColorWindow::ShowNoneButton() @@ -2183,11 +2188,18 @@ ColorWindow::~ColorWindow() { } -NamedColor ColorWindow::GetSelectEntryColor(ValueSet const * pColorSet) +NamedColor ColorWindow::GetSelectEntryColor(weld::IconView* pIconView) { - Color aColor = pColorSet->GetItemColor(pColorSet->GetSelectedItemId()); - const OUString& sColorName = pColorSet->GetItemText(pColorSet->GetSelectedItemId()); - return { aColor, sColorName }; + NamedColor aColor(COL_BLACK, SvxResId(RID_SVXSTR_COLOR_BLACK)); //default black color + + OUString sId = pIconView->get_selected_id(); + sal_Int32 nId = !sId.isEmpty() ? sId.toInt32() : -1; + + std::vector<NamedColor> vColorList = GetColors(pIconView); + if(nId > -1 && o3tl::make_unsigned(nId) < vColorList.size()) + aColor = vColorList[nId]; + + return aColor; } namespace @@ -2238,27 +2250,35 @@ namespace } } -NamedColor ColorWindow::GetSelectEntryColor() const +NamedColor ColorWindow::GetSelectEntryColor() { - if (!mxColorSet->IsNoSelection()) - return GetSelectEntryColor(mxColorSet.get()); - if (!mxRecentColorSet->IsNoSelection()) - return GetSelectEntryColor(mxRecentColorSet.get()); + if (!mxColorIconView->get_selected_id().isEmpty()) + return GetSelectEntryColor(mxColorIconView.get()); + if (!mxRecentColorIconView->get_selected_id().isEmpty()) + return GetSelectEntryColor(mxRecentColorIconView.get()); if (mxButtonNoneColor.get() == mpDefaultButton) return GetNoneColor(); return GetAutoColor(); } -IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void) +IMPL_LINK(ColorWindow, SelectionChangedHdl, weld::IconView&, rIconView, void) { - NamedColor aNamedColor = GetSelectEntryColor(pColorSet); + NamedColor aNamedColor = GetSelectEntryColor(&rIconView); - if (pColorSet != mxRecentColorSet.get()) + if (&rIconView != mxRecentColorIconView.get()) { - mxPaletteManager->AddRecentColor(aNamedColor.m_aColor, aNamedColor.m_aName); - if (!maMenuButton.get_active()) - mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); + mxPaletteManager->AddRecentColor(aNamedColor.m_aColor, aNamedColor.m_aName); + if (!maMenuButton.get_active()) + { + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorIconView); + vRecentColors = mxPaletteManager->GetRecentColors(); + } } +} + +IMPL_LINK(ColorWindow, ItemActivatedHdl, weld::IconView&, rIconView, bool) +{ + NamedColor aNamedColor = GetSelectEntryColor(&rIconView); mxPaletteManager->SetSplitButtonColor(aNamedColor); @@ -2268,13 +2288,14 @@ IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void) OUString sCommand(maCommand); // Same for querying IsTheme early. bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected(); - sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId(); + OUString sId = rIconView.get_selected_id(); if (bThemePaletteSelected) { + sal_Int32 nId = !sId.isEmpty() ? sId.toInt32() : 0; sal_uInt16 nThemeIndex; sal_uInt16 nEffectIndex; - if (PaletteManager::GetThemeAndEffectIndex(nSelectedItemId, nThemeIndex, nEffectIndex)) + if (PaletteManager::GetThemeAndEffectIndex(nId, nThemeIndex, nEffectIndex)) { aNamedColor.m_nThemeIndex = nThemeIndex; mxPaletteManager->GetLumModOff(nThemeIndex, nEffectIndex, aNamedColor.m_nLumMod, aNamedColor.m_nLumOff); @@ -2283,14 +2304,16 @@ IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, void) maMenuButton.set_inactive(); aColorSelectFunction(sCommand, aNamedColor); + + return true; } IMPL_LINK_NOARG(ColorWindow, SelectPaletteHdl, weld::ComboBox&, void) { int nPos = mxPaletteListBox->get_active(); mxPaletteManager->SetPalette( nPos ); - mxPaletteManager->ReloadColorSet(*mxColorSet); - mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount()); + mxPaletteManager->ReloadColorSet(*mxColorIconView); + vColors = mxPaletteManager->GetColors(); } NamedColor ColorWindow::GetAutoColor() const @@ -2302,8 +2325,8 @@ IMPL_LINK(ColorWindow, AutoColorClickHdl, weld::Button&, rButton, void) { NamedColor aNamedColor = &rButton == mxButtonAutoColor.get() ? GetAutoColor() : GetNoneColor(); - mxColorSet->SetNoSelection(); - mxRecentColorSet->SetNoSelection(); + mxColorIconView->unselect_all(); + mxRecentColorIconView->unselect_all(); mpDefaultButton = &rButton; mxPaletteManager->SetSplitButtonColor(aNamedColor); @@ -2331,18 +2354,57 @@ IMPL_LINK_NOARG(ColorWindow, OpenPickerClickHdl, weld::Button&, void) xPaletteManager->PopupColorPicker(pParentWindow, sCommand, nColor); } +IMPL_LINK(ColorWindow, QueryColorIVTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sId = mxColorIconView->get_id(rIter); + return QueryTooltipHdl_Impl(mxColorIconView.get(), sId); +} + +IMPL_LINK(ColorWindow, QueryRecentIVTooltipHdl, const weld::TreeIter&, rIter, OUString) +{ + OUString sId = mxRecentColorIconView->get_id(rIter); + return QueryTooltipHdl_Impl(mxRecentColorIconView.get(), sId); +} + +OUString ColorWindow::QueryTooltipHdl_Impl(weld::IconView* pIconView, std::u16string_view sId) +{ + if (sId.empty()) + return OUString(); + + const rtl::OUString aOUString(sId.data(), sId.length()); + const sal_Int32 nPos = aOUString.toInt32(); + + // Return the name of the color at position nPos, if valid. + const auto colorList = GetColors(pIconView); + if (o3tl::make_unsigned(nPos) < colorList.size()) + return colorList[nPos].m_aName; + + return OUString(); +} + +std::vector<NamedColor> ColorWindow::GetColors(weld::IconView* pIconView) +{ + if(mxRecentColorIconView.get() == pIconView) { + vRecentColors = vRecentColors.size() > 0 ? vRecentColors : mxPaletteManager->GetRecentColors(); + return vRecentColors; + } + + vColors = vColors.size() > 0 ? vColors : mxPaletteManager->GetColors(); + return vColors; +} + void ColorWindow::SetNoSelection() { - mxColorSet->SetNoSelection(); - mxRecentColorSet->SetNoSelection(); + mxColorIconView->unselect_all(); + mxRecentColorIconView->unselect_all(); mpDefaultButton = nullptr; } bool ColorWindow::IsNoSelection() const { - if (!mxColorSet->IsNoSelection()) + if (!mxColorIconView->get_selected_id().isEmpty()) return false; - if (!mxRecentColorSet->IsNoSelection()) + if (!mxRecentColorIconView->get_selected_id().isEmpty()) return false; return !mxButtonAutoColor->get_visible() && !mxButtonNoneColor->get_visible(); } @@ -2353,8 +2415,8 @@ void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent ) { if (rEvent.IsEnabled && mxPaletteManager->GetPalette() == 0) { - mxPaletteManager->ReloadColorSet(*mxColorSet); - mxColorSet->layoutToGivenHeight(mxColorSet->GetOutputSizePixel().Height(), mxPaletteManager->GetColorCount()); + mxPaletteManager->ReloadColorSet(*mxColorIconView); + vColors = mxPaletteManager->GetColors(); } } else @@ -2364,13 +2426,15 @@ void ColorWindow::statusChanged( const css::frame::FeatureStateEvent& rEvent ) } } -bool ColorWindow::SelectValueSetEntry(SvxColorValueSet* pColorSet, const Color& rColor) +bool ColorWindow::SelectIconViewEntry(weld::IconView* pIconView, const Color& rColor) { - for (size_t i = 1; i <= pColorSet->GetItemCount(); ++i) + std::vector<NamedColor> vNamedColors = GetColors(pIconView); + + for (size_t i = 0; i < vNamedColors.size(); ++i) { - if (rColor == pColorSet->GetItemColor(i)) + if (rColor == vNamedColors[i].m_aColor) { - pColorSet->SelectItem(i); + pIconView->select(i); return true; } } @@ -2396,10 +2460,10 @@ void ColorWindow::SelectEntry(const NamedColor& rNamedColor) } // try current palette - bool bFoundColor = SelectValueSetEntry(mxColorSet.get(), rColor); + bool bFoundColor = SelectIconViewEntry(mxColorIconView.get(), rColor); // try recently used if (!bFoundColor) - bFoundColor = SelectValueSetEntry(mxRecentColorSet.get(), rColor); + bFoundColor = SelectIconViewEntry(mxRecentColorIconView.get(), rColor); // if it's not there, add it there now to the end of the recently used // so its available somewhere handy, but not without trashing the // whole recently used @@ -2407,8 +2471,9 @@ void ColorWindow::SelectEntry(const NamedColor& rNamedColor) { const OUString& rColorName = rNamedColor.m_aName; mxPaletteManager->AddRecentColor(rColor, rColorName, false); - mxPaletteManager->ReloadRecentColorSet(*mxRecentColorSet); - SelectValueSetEntry(mxRecentColorSet.get(), rColor); + mxPaletteManager->ReloadRecentColorSet(*mxRecentColorIconView); + vRecentColors = mxPaletteManager->GetRecentColors(); + SelectIconViewEntry(mxRecentColorIconView.get(), rColor); } } diff --git a/svx/uiconfig/ui/colorwindow.ui b/svx/uiconfig/ui/colorwindow.ui index c36392e4c3d6..9f7f1cb7d1f8 100644 --- a/svx/uiconfig/ui/colorwindow.ui +++ b/svx/uiconfig/ui/colorwindow.ui @@ -24,6 +24,22 @@ <property name="border-width">4</property> <property name="constrain-to">none</property> <child> + <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="container"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -102,25 +118,27 @@ </packing> </child> <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="vscrollbar-policy">always</property> <property name="shadow-type">in</property> <property name="overlay-scrolling">False</property> + <property name="height-request">180</property> <child> - <object class="GtkViewport"> + <object class="GtkIconView" id="colorwindow_iv_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="receives-default">True</property> - <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</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> + <property name="activate-on-single-click">True</property> </object> </child> </object> @@ -147,7 +165,7 @@ <property name="can-focus">False</property> <property name="label" translatable="yes" context="colorwindow|label1">Recent</property> <property name="use-underline">True</property> - <property name="mnemonic-widget">recent_colorset</property> + <property name="mnemonic-widget">colorwindow_iv_recentcolors</property> <property name="xalign">0</property> </object> <packing> @@ -157,11 +175,27 @@ </packing> </child> <child> - <object class="GtkDrawingArea" id="recent_colorset"> + <object class="GtkScrolledWindow"> <property name="visible">True</property> <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_STRUCTURE_MASK</property> + <property name="hscrollbar-policy">never</property> + <property name="vscrollbar-policy">never</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkIconView" id="colorwindow_iv_recentcolors"> + <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> + <property name="activate-on-single-click">True</property> + </object> + </child> </object> <packing> <property name="expand">False</property> commit 8596a7d8dd887ed77dc6f7ff7056de2bcdd4cf20 Author: Parth Raiyani <[email protected]> AuthorDate: Tue Aug 5 15:08:32 2025 +0530 Commit: Caolán McNamara <[email protected]> CommitDate: Tue Feb 24 17:14:37 2026 +0100 Switch to IconView for hatch tab page for improved UI handling - Replaced ValueSet with IconView widget in hatch tab page - Updated hatchpage UI to include GtkIconView and GtkTreeStore for hatch - Added support to select and preview default when no item is selected - Always keep selected item and selection preview in sync - Updated relevant test case Change-Id: I7105fcac5e7195c6c2f4d51514ed241220586dfd Signed-off-by: Parth Raiyani <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/188240 Reviewed-by: Szymon Kłos <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/200190 Reviewed-by: Caolán McNamara <[email protected]> diff --git a/cui/source/inc/cuitabarea.hxx b/cui/source/inc/cuitabarea.hxx index 099b2b6ab78d..22d31f73bc1a 100644 --- a/cui/source/inc/cuitabarea.hxx +++ b/cui/source/inc/cuitabarea.hxx @@ -464,6 +464,8 @@ private: SfxItemSet& m_rXFSet; MapUnit m_ePoolUnit; + OUString sLastItemIdent; + Size aIconSize; SvxXRectPreview m_aCtlPreview; std::unique_ptr<weld::MetricSpinButton> m_xMtrDistance; @@ -473,14 +475,18 @@ private: std::unique_ptr<ColorListBox> m_xLbLineColor; std::unique_ptr<weld::CheckButton> m_xCbBackgroundColor; std::unique_ptr<ColorListBox> m_xLbBackgroundColor; - std::unique_ptr<SvxPresetListBox> m_xHatchLB; + std::unique_ptr<weld::IconView> m_xHatchLB; std::unique_ptr<weld::Button> m_xBtnAdd; std::unique_ptr<weld::Button> m_xBtnModify; std::unique_ptr<weld::CustomWeld> m_xHatchLBWin; std::unique_ptr<weld::CustomWeld> m_xCtlPreview; - DECL_LINK(ChangeHatchHdl, ValueSet*, void); + DECL_LINK(ChangeHatchHdl, weld::IconView&, void); void ChangeHatchHdl_Impl(); + DECL_LINK(MousePressHdl, const MouseEvent&, bool); + DECL_LINK(MenuSelectAsyncHdl, void*, void); + DECL_LINK(OnPopupEnd, const OUString&, void); + DECL_LINK(QueryTooltipHdl, const weld::TreeIter&, OUString); DECL_LINK( ModifiedEditHdl_Impl, weld::MetricSpinButton&, void ); DECL_LINK( ModifiedListBoxHdl_Impl, weld::ComboBox&, void ); DECL_LINK( ModifiedColorListBoxHdl_Impl, ColorListBox&, void ); @@ -490,13 +496,18 @@ private: void ModifiedHdl_Impl(void const *); DECL_LINK( ClickAddHdl_Impl, weld::Button&, void ); DECL_LINK( ClickModifyHdl_Impl, weld::Button&, void ); - DECL_LINK( ClickRenameHdl_Impl, SvxPresetListBox*, void ); - DECL_LINK( ClickDeleteHdl_Impl, SvxPresetListBox*, void ); sal_Int32 SearchHatchList(std::u16string_view rHatchName); void AddHatch(const OUString& aName, tools::Long nCount); void runNameDialog(VclPtr<AbstractSvxNameDialog> pDlg, tools::Long nCount); + static VclPtr<VirtualDevice> GetVirtualDevice(Bitmap aBitmap); + void FillPresetListBox(); + void ShowContextMenu(const Point& pPos); + void MenuSelect(const OUString& rIdent); + void HandleMenuSelect(std::u16string_view rIdent); + void ClickRenameHdl(); + void ClickDeleteHdl(); public: SvxHatchTabPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rInAttrs); diff --git a/cui/source/tabpages/tphatch.cxx b/cui/source/tabpages/tphatch.cxx index dc2b039e09dc..7502b6d7726d 100644 --- a/cui/source/tabpages/tphatch.cxx +++ b/cui/source/tabpages/tphatch.cxx @@ -42,6 +42,7 @@ #include <svx/svxids.hrc> #include <sal/log.hxx> #include <svtools/unitconv.hxx> +#include <comphelper/lok.hxx> using namespace com::sun::star; @@ -52,6 +53,7 @@ SvxHatchTabPage::SvxHatchTabPage(weld::Container* pPage, weld::DialogController* , m_pnColorListState(nullptr) , m_aXFillAttr(rInAttrs.GetPool()) , m_rXFSet(m_aXFillAttr.GetItemSet()) + , aIconSize(60, 64) , m_xMtrDistance(m_xBuilder->weld_metric_spin_button(u"distancemtr"_ustr, FieldUnit::MM)) , m_xMtrAngle(m_xBuilder->weld_metric_spin_button(u"anglemtr"_ustr, FieldUnit::DEGREE)) , m_xSliderAngle(m_xBuilder->weld_scale(u"angleslider"_ustr)) @@ -61,14 +63,12 @@ SvxHatchTabPage::SvxHatchTabPage(weld::Container* pPage, weld::DialogController* , m_xCbBackgroundColor(m_xBuilder->weld_check_button(u"backgroundcolor"_ustr)) , m_xLbBackgroundColor(new ColorListBox(m_xBuilder->weld_menu_button(u"backgroundcolorlb"_ustr), [this]{ return GetDialogController()->getDialog(); })) - , m_xHatchLB(new SvxPresetListBox(m_xBuilder->weld_scrolled_window(u"hatchpresetlistwin"_ustr, true))) + , m_xHatchLB(m_xBuilder->weld_icon_view(u"hatchpresetlist"_ustr)) , m_xBtnAdd(m_xBuilder->weld_button(u"add"_ustr)) , m_xBtnModify(m_xBuilder->weld_button(u"modify"_ustr)) - , m_xHatchLBWin(new weld::CustomWeld(*m_xBuilder, u"hatchpresetlist"_ustr, *m_xHatchLB)) , m_xCtlPreview(new weld::CustomWeld(*m_xBuilder, u"previewctl"_ustr, m_aCtlPreview)) { Size aSize = getDrawPreviewOptimalSize(m_aCtlPreview.GetDrawingArea()->get_ref_device()); - m_xHatchLBWin->set_size_request(aSize.Width(), aSize.Height()); m_xCtlPreview->set_size_request(aSize.Width(), aSize.Height()); // this page needs ExchangeSupport @@ -96,9 +96,9 @@ SvxHatchTabPage::SvxHatchTabPage(weld::Container* pPage, weld::DialogController* m_rXFSet.Put( XFillStyleItem(drawing::FillStyle_HATCH) ); m_rXFSet.Put( XFillHatchItem(OUString(), XHatch()) ); m_aCtlPreview.SetAttributes( m_aXFillAttr.GetItemSet() ); - m_xHatchLB->SetSelectHdl( LINK( this, SvxHatchTabPage, ChangeHatchHdl ) ); - m_xHatchLB->SetRenameHdl( LINK( this, SvxHatchTabPage, ClickRenameHdl_Impl ) ); - m_xHatchLB->SetDeleteHdl( LINK( this, SvxHatchTabPage, ClickDeleteHdl_Impl ) ); + m_xHatchLB->connect_selection_changed(LINK(this, SvxHatchTabPage, ChangeHatchHdl)); + m_xHatchLB->connect_mouse_press(LINK(this, SvxHatchTabPage, MousePressHdl)); + m_xHatchLB->connect_query_tooltip(LINK(this, SvxHatchTabPage, QueryTooltipHdl)); Link<weld::MetricSpinButton&,void> aLink = LINK( this, SvxHatchTabPage, ModifiedEditHdl_Impl ); Link<weld::ComboBox&,void> aLink2 = LINK( this, SvxHatchTabPage, ModifiedListBoxHdl_Impl ); @@ -114,15 +114,12 @@ SvxHatchTabPage::SvxHatchTabPage(weld::Container* pPage, weld::DialogController* m_xBtnAdd->connect_clicked( LINK( this, SvxHatchTabPage, ClickAddHdl_Impl ) ); m_xBtnModify->connect_clicked( LINK( this, SvxHatchTabPage, ClickModifyHdl_Impl ) ); - m_xHatchLB->SetStyle(WB_FLATVALUESET | WB_NO_DIRECTSELECT | WB_TABSTOP); - m_aCtlPreview.SetDrawMode(Application::GetSettings().GetStyleSettings().GetHighContrastMode() ? OUTPUT_DRAWMODE_CONTRAST : OUTPUT_DRAWMODE_COLOR); } SvxHatchTabPage::~SvxHatchTabPage() { m_xCtlPreview.reset(); - m_xHatchLBWin.reset(); m_xHatchLB.reset(); m_xLbBackgroundColor.reset(); m_xLbLineColor.reset(); @@ -141,7 +138,37 @@ SvxHatchTabPage::~SvxHatchTabPage() void SvxHatchTabPage::Construct() { - m_xHatchLB->FillPresetListBox(*m_pHatchingList); + FillPresetListBox(); +} + + +void SvxHatchTabPage::FillPresetListBox() +{ + m_xHatchLB->clear(); + + m_xHatchLB->freeze(); + for (tools::Long nId = 0; nId < m_pHatchingList->Count(); nId++) + { + const OUString aString(m_pHatchingList->GetHatch(nId)->GetName()); + + OUString sId = OUString::number(nId); + Bitmap aBitmap = m_pHatchingList->GetBitmapForPreview(nId, aIconSize); + VclPtr<VirtualDevice> aVDev = GetVirtualDevice(aBitmap); + Bitmap aBmp = aVDev->GetBitmap(Point(), aVDev->GetOutputSizePixel()); + + if (!m_xHatchLB->get_id(nId).isEmpty()) + { + m_xHatchLB->set_image(nId, *aVDev); + m_xHatchLB->set_id(nId, sId); + m_xHatchLB->set_text(nId, aString); + } + else + { + m_xHatchLB->insert(-1, &aString, &sId, &aBmp, nullptr); + } + } + + m_xHatchLB->thaw(); } void SvxHatchTabPage::ActivatePage( const SfxItemSet& rSet ) @@ -178,8 +205,7 @@ void SvxHatchTabPage::ActivatePage( const SfxItemSet& rSet ) sal_Int32 nPos = SearchHatchList( rSet.Get(XATTR_FILLHATCH).GetName() ); if( nPos != -1) { - sal_uInt16 nId = m_xHatchLB->GetItemId( static_cast<size_t>( nPos ) ); - m_xHatchLB->SelectItem( nId ); + m_xHatchLB->select( nPos ); } // colors could have been deleted ChangeHatchHdl_Impl(); @@ -237,11 +263,13 @@ bool SvxHatchTabPage::FillItemSet( SfxItemSet* rSet ) { std::unique_ptr<XHatch> pXHatch; OUString aString; - size_t nPos = m_xHatchLB->IsNoSelection() ? VALUESET_ITEM_NOTFOUND : m_xHatchLB->GetSelectItemPos(); - if( nPos != VALUESET_ITEM_NOTFOUND ) + OUString sId = m_xHatchLB->get_selected_id(); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; + + if( nPos != -1 ) { pXHatch.reset(new XHatch( m_pHatchingList->GetHatch( static_cast<sal_uInt16>(nPos) )->GetHatch() )); - aString = m_xHatchLB->GetItemText( m_xHatchLB->GetSelectedItemId() ); + aString = m_pHatchingList->GetHatch(nPos)->GetName(); } // unidentified hatch has been passed else @@ -292,13 +320,11 @@ IMPL_LINK( SvxHatchTabPage, ModifiedListBoxHdl_Impl, weld::ComboBox&, rListBox, { ModifiedHdl_Impl(&rListBox); // hatch params have changed, it is no longer one of the presets - m_xHatchLB->SetNoSelection(); } IMPL_LINK( SvxHatchTabPage, ModifiedColorListBoxHdl_Impl, ColorListBox&, rListBox, void ) { ModifiedHdl_Impl(&rListBox); - m_xHatchLB->SetNoSelection(); } IMPL_LINK_NOARG( SvxHatchTabPage, ToggleHatchBackgroundColor_Impl, weld::Toggleable&, void ) @@ -329,13 +355,11 @@ IMPL_LINK_NOARG( SvxHatchTabPage, ModifiedBackgroundHdl_Impl, ColorListBox&, voi IMPL_LINK( SvxHatchTabPage, ModifiedEditHdl_Impl, weld::MetricSpinButton&, rEdit, void ) { ModifiedHdl_Impl(&rEdit); - m_xHatchLB->SetNoSelection(); } IMPL_LINK( SvxHatchTabPage, ModifiedSliderHdl_Impl, weld::Scale&, rSlider, void ) { ModifiedHdl_Impl(&rSlider); - m_xHatchLB->SetNoSelection(); } void SvxHatchTabPage::ModifiedHdl_Impl( void const * p ) @@ -357,7 +381,7 @@ void SvxHatchTabPage::ModifiedHdl_Impl( void const * p ) m_aCtlPreview.Invalidate(); } -IMPL_LINK_NOARG(SvxHatchTabPage, ChangeHatchHdl, ValueSet*, void) +IMPL_LINK_NOARG(SvxHatchTabPage, ChangeHatchHdl, weld::IconView&, void) { ChangeHatchHdl_Impl(); } @@ -365,9 +389,10 @@ IMPL_LINK_NOARG(SvxHatchTabPage, ChangeHatchHdl, ValueSet*, void) void SvxHatchTabPage::ChangeHatchHdl_Impl() { std::unique_ptr<XHatch> pHatch; - size_t nPos = m_xHatchLB->GetSelectItemPos(); + OUString sId = m_xHatchLB->get_selected_id(); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; - if( nPos != VALUESET_ITEM_NOTFOUND ) + if( nPos != -1 ) pHatch.reset(new XHatch( m_pHatchingList->GetHatch( static_cast<sal_uInt16>(nPos) )->GetHatch() )); else { @@ -380,12 +405,10 @@ void SvxHatchTabPage::ChangeHatchHdl_Impl() pHatch.reset(new XHatch( pFillHatchItem->GetHatchValue() )); } } - if( !pHatch ) + if(!pHatch && m_xHatchLB->n_children() > 0) { - sal_uInt16 nPosition = m_xHatchLB->GetItemId( 0 ); - m_xHatchLB->SelectItem( nPosition ); - if( nPosition != 0 ) - pHatch.reset( new XHatch( m_pHatchingList->GetHatch( 0 )->GetHatch() ) ); + m_xHatchLB->select(0); + pHatch.reset( new XHatch( m_pHatchingList->GetHatch( 0 )->GetHatch() ) ); } } if( pHatch ) @@ -422,12 +445,16 @@ void SvxHatchTabPage::AddHatch(const OUString& aName, tools::Long nCount) m_pHatchingList->Insert(std::make_unique<XHatchEntry>(aXHatch, aName), nCount); - sal_Int32 nId = m_xHatchLB->GetItemId(nCount - 1); // calculate the last ID - Bitmap aBitmap = m_pHatchingList->GetBitmapForPreview( nCount, m_xHatchLB->GetIconSize() ); - // Insert the new entry at the next ID - m_xHatchLB->InsertItem( nId + 1, Image(aBitmap), aName ); - m_xHatchLB->SelectItem( nId + 1 ); - m_xHatchLB->Resize(); + OUString sId = nCount > 0 ? m_xHatchLB->get_id( nCount - 1 ) : OUString(); + sal_Int32 nId = !sId.isEmpty() ? sId.toInt32() : -1; + Bitmap aBitmap = m_pHatchingList->GetBitmapForPreview( nCount, aIconSize ); + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aBitmap); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); + + OUString sName(aName); + m_xHatchLB->insert( nId + 1, &sName, &sId, &aBmp, nullptr); + FillPresetListBox(); + m_xHatchLB->select( nId + 1 ); m_nHatchingListState |= ChangeType::MODIFIED; @@ -489,10 +516,10 @@ IMPL_LINK_NOARG(SvxHatchTabPage, ClickAddHdl_Impl, weld::Button&, void) IMPL_LINK_NOARG(SvxHatchTabPage, ClickModifyHdl_Impl, weld::Button&, void) { - sal_uInt16 nId = m_xHatchLB->GetSelectedItemId(); - size_t nPos = m_xHatchLB->GetSelectItemPos(); + OUString sId = m_xHatchLB->get_selected_id(); + sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; - if( nPos == VALUESET_ITEM_NOTFOUND ) + if ( nPos == -1 ) return; OUString aName( m_pHatchingList->GetHatch( static_cast<sal_uInt16>(nPos) )->GetName() ); @@ -504,10 +531,14 @@ IMPL_LINK_NOARG(SvxHatchTabPage, ClickModifyHdl_Impl, weld::Button&, void) m_pHatchingList->Replace(std::make_unique<XHatchEntry>(aXHatch, aName), nPos); - Bitmap aBitmap = m_pHatchingList->GetBitmapForPreview( static_cast<sal_uInt16>(nPos), m_xHatchLB->GetIconSize() ); - m_xHatchLB->RemoveItem( nId ); - m_xHatchLB->InsertItem( nId, Image(aBitmap), aName, static_cast<sal_uInt16>(nPos) ); - m_xHatchLB->SelectItem( nId ); + Bitmap aBitmap = m_pHatchingList->GetBitmapForPreview( static_cast<sal_uInt16>(nPos), aIconSize ); + VclPtr<VirtualDevice> pVDev = GetVirtualDevice(aBitmap); + Bitmap aBmp = pVDev->GetBitmap(Point(), pVDev->GetOutputSizePixel()); + + m_xHatchLB->remove( nPos ); + m_xHatchLB->insert( nPos, &aName, &sId, &aBmp, nullptr); + FillPresetListBox(); + m_xHatchLB->select( nPos ); // save values for changes recognition (-> method) m_xMtrDistance->save_value(); @@ -519,12 +550,91 @@ IMPL_LINK_NOARG(SvxHatchTabPage, ClickModifyHdl_Impl, weld::Button&, void) m_nHatchingListState |= ChangeType::MODIFIED; } -IMPL_LINK_NOARG(SvxHatchTabPage, ClickDeleteHdl_Impl, SvxPresetListBox*, void) +VclPtr<VirtualDevice> SvxHatchTabPage::GetVirtualDevice(Bitmap aBitmap) +{ + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + const Point aNull(0, 0); + if (pVDev->GetDPIScaleFactor() > 1) + aBitmap.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor()); + const Size aSize(aBitmap.GetSizePixel()); + pVDev->SetOutputSizePixel(aSize); + pVDev->DrawBitmap(aNull, aBitmap); + + return pVDev; +} + +IMPL_LINK(SvxHatchTabPage, QueryTooltipHdl, const weld::TreeIter&, rIter, OUString) { - const sal_uInt16 nId = m_xHatchLB->GetContextMenuItemId(); - const size_t nPos = m_xHatchLB->GetItemPos(nId); + OUString sId = m_xHatchLB->get_id(rIter); + sal_Int32 nId = !sId.isEmpty() ? sId.toInt32() : -1; - if( nPos == VALUESET_ITEM_NOTFOUND ) + if (nId >= 0) + { + return m_pHatchingList->GetHatch(nId)->GetName(); + } + return OUString(); +} + +IMPL_LINK(SvxHatchTabPage, MousePressHdl, const MouseEvent&, rMEvt, bool) +{ + if (!rMEvt.IsRight()) + return false; + + // Disable context menu for LibreOfficeKit mode + if (comphelper::LibreOfficeKit::isActive()) + return false; + + const Point& pPos = rMEvt.GetPosPixel(); + for (int i = 0; i < m_xHatchLB->n_children(); i++) + { + const ::tools::Rectangle aRect = m_xHatchLB->get_rect(i); + if (aRect.Contains(pPos)) + { + ShowContextMenu(pPos); + break; + } + } + return false; +} + +void SvxHatchTabPage::ShowContextMenu(const Point& pPos) +{ + ::tools::Rectangle aRect(pPos, Size(1, 1)); + std::unique_ptr<weld::Builder> xBuilder( + Application::CreateBuilder(m_xHatchLB.get(), u"svx/ui/presetmenu.ui"_ustr)); + std::unique_ptr<weld::Menu> xMenu(xBuilder->weld_menu(u"menu"_ustr)); + + xMenu->connect_activate(LINK(this, SvxHatchTabPage, OnPopupEnd)); + xMenu->popup_at_rect(m_xHatchLB.get(), aRect); +} + +IMPL_LINK(SvxHatchTabPage, OnPopupEnd, const OUString&, sCommand, void) +{ + sLastItemIdent = sCommand; + if (sLastItemIdent.isEmpty()) + return; + + Application::PostUserEvent(LINK(this, SvxHatchTabPage, MenuSelectAsyncHdl)); +} + +IMPL_LINK_NOARG(SvxHatchTabPage, MenuSelectAsyncHdl, void*, void) +{ + if (sLastItemIdent == u"rename") + { + ClickRenameHdl(); + } + else if (sLastItemIdent == u"delete") + { + ClickDeleteHdl(); + } +} + +void SvxHatchTabPage::ClickDeleteHdl() +{ + const OUString sId = m_xHatchLB->get_selected_id(); + const sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; + + if( nPos == -1 ) return; std::unique_ptr<weld::Builder> xBuilder(Application::CreateBuilder(GetFrameWeld(), u"cui/ui/querydeletehatchdialog.ui"_ustr)); @@ -532,27 +642,30 @@ IMPL_LINK_NOARG(SvxHatchTabPage, ClickDeleteHdl_Impl, SvxPresetListBox*, void) if (xQueryBox->run() != RET_YES) return; - const bool bDeletingSelectedItem(nId == m_xHatchLB->GetSelectedItemId()); m_pHatchingList->Remove(nPos); - m_xHatchLB->RemoveItem( nId ); - if (bDeletingSelectedItem) - { - m_xHatchLB->SelectItem(m_xHatchLB->GetItemId(/*Position=*/0)); - m_aCtlPreview.Invalidate(); - } - m_xHatchLB->Resize(); + m_xHatchLB->remove( nPos ); + + FillPresetListBox(); + + sal_Int32 nNextId = nPos; + if (nPos >= m_xHatchLB->n_children()) + nNextId = m_xHatchLB->n_children() - 1; + + if(m_xHatchLB->n_children() > 0) + m_xHatchLB->select(nNextId); + m_aCtlPreview.Invalidate(); ChangeHatchHdl_Impl(); m_nHatchingListState |= ChangeType::MODIFIED; } -IMPL_LINK_NOARG(SvxHatchTabPage, ClickRenameHdl_Impl, SvxPresetListBox*, void ) +void SvxHatchTabPage::ClickRenameHdl() { - const sal_uInt16 nId = m_xHatchLB->GetContextMenuItemId(); - const size_t nPos = m_xHatchLB->GetItemPos(nId); + const OUString sId = m_xHatchLB->get_selected_id(); + const sal_Int32 nPos = !sId.isEmpty() ? sId.toInt32() : -1; - if( nPos == VALUESET_ITEM_NOTFOUND ) + if ( nPos == -1 ) return; OUString aDesc( CuiResId( RID_CUISTR_DESC_HATCH ) ); @@ -566,14 +679,14 @@ IMPL_LINK_NOARG(SvxHatchTabPage, ClickRenameHdl_Impl, SvxPresetListBox*, void ) { aName = pDlg->GetName(); sal_Int32 nHatchPos = SearchHatchList( aName ); - bool bValidHatchName = (nHatchPos == static_cast<sal_Int32>(nPos) ) || (nHatchPos == -1); + bool bValidHatchName = (nHatchPos == nPos ) || (nHatchPos == -1); if(bValidHatchName) { bLoop = false; m_pHatchingList->GetHatch(nPos)->SetName(aName); - m_xHatchLB->SetItemText(nId, aName); + m_xHatchLB->set_text(nPos, aName); m_nHatchingListState |= ChangeType::MODIFIED; } diff --git a/cui/uiconfig/ui/hatchpage.ui b/cui/uiconfig/ui/hatchpage.ui index fafc49c764b6..39f3a075e5fe 100644 --- a/cui/uiconfig/ui/hatchpage.ui +++ b/cui/uiconfig/ui/hatchpage.ui @@ -16,6 +16,14 @@ <property name="upper">99</property> <property name="step_increment">100</property> </object> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name pixbuf --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> <object class="GtkBox" id="HatchPage"> <property name="visible">True</property> <property name="can_focus">False</property> @@ -43,20 +51,20 @@ <property name="can_focus">True</property> <property name="vexpand">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> <child> - <object class="GtkViewport"> + <object class="GtkIconView" id="hatchpresetlist"> <property name="visible">True</property> - <property name="can_focus">False</property> - <child> - <object class="GtkDrawingArea" id="hatchpresetlist"> - <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="vexpand">True</property> - </object> - </child> + <property name="item-padding">2</property> + <property name="can-focus">True</property> + <property name="hexpand">False</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="pixbuf-column">0</property> + <property name="margin">6</property> + <property name="columns">3</property> + <property name="activate-on-single-click">True</property> </object> </child> </object> diff --git a/sd/qa/uitest/impress_tests/tdf137729.py b/sd/qa/uitest/impress_tests/tdf137729.py index 1769b0510452..80175b66ab22 100644 --- a/sd/qa/uitest/impress_tests/tdf137729.py +++ b/sd/qa/uitest/impress_tests/tdf137729.py @@ -38,14 +38,13 @@ class tdf137729(UITestCase): self.assertEqual( document.DrawPages[0].Background.FillHatch.Color, 0) self.assertEqual( - document.DrawPages[0].Background.FillHatch.Distance, 152) + document.DrawPages[0].Background.FillHatch.Distance, 102) self.assertEqual( document.DrawPages[0].Background.FillHatch.Angle, 0) - # Without the patch in place, this test would have failed with - # AssertionError: '' != 'hatch' + # FillHatchName to match the first(default) preset's name self.assertEqual( - document.DrawPages[0].Background.FillHatchName, 'hatch') + document.DrawPages[0].Background.FillHatchName, 'Black 0 Degrees') # vim: set shiftwidth=4 softtabstop=4 expandtab:
