chart2/Library_chartcontroller.mk | 3 chart2/Library_chartcore.mk | 4 chart2/UIConfig_chart2.mk | 3 chart2/inc/ChartModel.hxx | 15 chart2/inc/strings.hrc | 1 chart2/source/controller/chartcontroller.component | 4 chart2/source/controller/dialogs/dlg_ObjectProperties.cxx | 14 chart2/source/controller/dialogs/tp_ChartColorPalette.cxx | 13 chart2/source/controller/dialogs/tp_ChartColorPalette.hxx | 3 chart2/source/controller/dialogs/tp_ChartGradients.cxx | 180 +++ chart2/source/controller/dialogs/tp_ChartGradients.hxx | 58 + chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx | 25 chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx | 3 chart2/source/controller/sidebar/Chart2PanelFactory.cxx | 3 chart2/source/controller/sidebar/ChartColorsPanel.cxx | 1 chart2/source/controller/sidebar/ChartGradientPaletteControl.cxx | 412 +++++++++ chart2/source/controller/sidebar/ChartGradientPaletteControl.hxx | 112 ++ chart2/source/controller/sidebar/ChartGradientsPanel.cxx | 337 +++++++ chart2/source/controller/sidebar/ChartGradientsPanel.hxx | 88 + chart2/source/inc/ChartGradientPaletteHelper.hxx | 51 + chart2/source/inc/ChartGradientPalettes.hxx | 56 + chart2/source/inc/chartview/ChartSfxItemIds.hxx | 8 chart2/source/model/main/ChartModel.cxx | 97 ++ chart2/source/tools/ChartGradientPaletteHelper.cxx | 456 ++++++++++ chart2/source/tools/ChartGradientPalettes.cxx | 128 ++ chart2/source/view/main/ChartItemPool.cxx | 5 chart2/uiconfig/ui/chartcolorpalettepopup.ui | 2 chart2/uiconfig/ui/chartgradientpalettepopup.ui | 155 +++ chart2/uiconfig/ui/sidebargradients.ui | 58 + chart2/uiconfig/ui/tp_ChartGradients.ui | 146 +++ include/svl/poolitem.hxx | 1 include/svx/ChartColorPaletteType.hxx | 2 include/svx/ChartGradientVariation.hxx | 64 + include/svx/chrtitem.hxx | 37 include/svx/unomid.hxx | 4 officecfg/registry/data/org/openoffice/Office/UI/Controller.xcu | 11 officecfg/registry/data/org/openoffice/Office/UI/Sidebar.xcu | 30 static/CustomTarget_emscripten_fs_image.mk | 2 svx/source/items/chrtitem.cxx | 88 + vcl/jsdialog/enabled.cxx | 3 40 files changed, 2675 insertions(+), 8 deletions(-)
New commits: commit 7effd3f672e89e5519879331a67bd0357d6e572c Author: Marco Cecchetti <[email protected]> AuthorDate: Tue Oct 7 14:57:06 2025 +0200 Commit: Tomaž Vajngerl <[email protected]> CommitDate: Mon Oct 27 14:03:40 2025 +0100 chart: gradient presets When a chart is active in the side panel there is a new section named Gradients which provides access to several gradient presets through a popup. The popup provides preview on mouse over. A Gradients tab page has been aslo added to the Format dialog for a chart. Change-Id: I90b4f5368a552eb9ba399337a39e79455ea99fe6 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192043 Reviewed-by: Tomaž Vajngerl <[email protected]> Tested-by: Jenkins CollaboraOffice <[email protected]> diff --git a/chart2/Library_chartcontroller.mk b/chart2/Library_chartcontroller.mk index 9dd9245280c9..a40fb21191e8 100644 --- a/chart2/Library_chartcontroller.mk +++ b/chart2/Library_chartcontroller.mk @@ -134,6 +134,7 @@ $(eval $(call gb_Library_add_exception_objects,chartcontroller,\ chart2/source/controller/dialogs/tp_AxisLabel \ chart2/source/controller/dialogs/tp_AxisPositions \ chart2/source/controller/dialogs/tp_ChartColorPalette \ + chart2/source/controller/dialogs/tp_ChartGradients \ chart2/source/controller/dialogs/tp_ChartType \ chart2/source/controller/dialogs/tp_DataLabel \ chart2/source/controller/dialogs/tp_DataPointOption \ @@ -202,6 +203,8 @@ $(eval $(call gb_Library_add_exception_objects,chartcontroller,\ chart2/source/controller/sidebar/ChartAreaPanel \ chart2/source/controller/sidebar/ChartColorsPanel \ chart2/source/controller/sidebar/ChartColorPaletteControl \ + chart2/source/controller/sidebar/ChartGradientsPanel \ + chart2/source/controller/sidebar/ChartGradientPaletteControl \ chart2/source/controller/sidebar/ChartAxisPanel \ chart2/source/controller/sidebar/ChartColorWrapper \ chart2/source/controller/sidebar/ChartElementsPanel \ diff --git a/chart2/Library_chartcore.mk b/chart2/Library_chartcore.mk index 207f8bd55648..da1cdef02085 100644 --- a/chart2/Library_chartcore.mk +++ b/chart2/Library_chartcore.mk @@ -27,6 +27,7 @@ $(eval $(call gb_Library_set_precompiled_header,chartcore,chart2/inc/pch/precomp $(eval $(call gb_Library_use_externals,chartcore,\ boost_headers \ + frozen \ libxml2 \ )) @@ -41,6 +42,7 @@ $(eval $(call gb_Library_use_libraries,chartcore,\ comphelper \ cppu \ cppuhelper \ + drawinglayercore \ drawinglayer \ editeng \ fwk \ @@ -185,6 +187,8 @@ $(eval $(call gb_Library_add_exception_objects,chartcore,\ chart2/source/tools/CharacterProperties \ chart2/source/tools/ChartColorPalettes \ chart2/source/tools/ChartColorPaletteHelper \ + chart2/source/tools/ChartGradientPalettes \ + chart2/source/tools/ChartGradientPaletteHelper \ chart2/source/tools/ChartColorScheme \ chart2/source/tools/ChartModelHelper \ chart2/source/tools/ChartTypeHelper \ diff --git a/chart2/UIConfig_chart2.mk b/chart2/UIConfig_chart2.mk index 12411d12801a..bedd85e57656 100644 --- a/chart2/UIConfig_chart2.mk +++ b/chart2/UIConfig_chart2.mk @@ -38,6 +38,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/schart,\ chart2/uiconfig/ui/3dviewdialog \ chart2/uiconfig/ui/attributedialog \ chart2/uiconfig/ui/chartcolorpalettepopup \ + chart2/uiconfig/ui/chartgradientpalettepopup \ chart2/uiconfig/ui/chartthemepopup \ chart2/uiconfig/ui/chardialog \ chart2/uiconfig/ui/chartdatadialog \ @@ -57,6 +58,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/schart,\ chart2/uiconfig/ui/paradialog \ chart2/uiconfig/ui/sidebaraxis \ chart2/uiconfig/ui/sidebarcolors \ + chart2/uiconfig/ui/sidebargradients \ chart2/uiconfig/ui/sidebartheme \ chart2/uiconfig/ui/sidebarelements \ chart2/uiconfig/ui/sidebarerrorbar \ @@ -71,6 +73,7 @@ $(eval $(call gb_UIConfig_add_uifiles,modules/schart,\ chart2/uiconfig/ui/tp_axisLabel \ chart2/uiconfig/ui/tp_AxisPositions \ chart2/uiconfig/ui/tp_ChartColorPalette \ + chart2/uiconfig/ui/tp_ChartGradients \ chart2/uiconfig/ui/tp_ChartType \ chart2/uiconfig/ui/tp_DataLabel \ chart2/uiconfig/ui/tp_DataPointOption \ diff --git a/chart2/inc/ChartModel.hxx b/chart2/inc/ChartModel.hxx index cb281a4aa242..32a0b4c60aac 100644 --- a/chart2/inc/ChartModel.hxx +++ b/chart2/inc/ChartModel.hxx @@ -54,6 +54,7 @@ #include <vcl/GraphicObject.hxx> #include <svl/lstner.hxx> #include <svx/ChartColorPaletteType.hxx> +#include <svx/ChartGradientVariation.hxx> #include <memory> @@ -184,8 +185,13 @@ private: ChartColorPaletteType m_eColorPaletteType; sal_uInt32 m_nColorPaletteIndex; + rtl::Reference<UnoChartStyle> m_aStyles; + ChartGradientVariation m_eGradientPaletteVariation; + ChartGradientType m_nGradientPaletteType; + std::vector<Color> m_aGradientBaseColors; + private: //private methods @@ -504,6 +510,15 @@ public: void applyColorPaletteToDataSeries(const ChartColorPalette& rColorPalette); void onDocumentThemeChanged(); + ChartGradientVariation getGradientPaletteVariation() const { return m_eGradientPaletteVariation; } + ChartGradientType getGradientPaletteType() const { return m_nGradientPaletteType; } + void setGradientPalette(ChartGradientVariation eVariation, ChartGradientType eType); + void clearGradientPalette(); + bool usesGradientPalette() const; + const std::vector<Color>& getDataSeriesColorsForGradient(bool bIsPreview = false); + std::optional<ChartGradientPalette> getCurrentGradientPalette() const; + void applyGradientPaletteToDataSeries(const ChartGradientPalette& rColorPalette); + private: void dumpAsXml(xmlTextWriterPtr pWriter) const; diff --git a/chart2/inc/strings.hrc b/chart2/inc/strings.hrc index d2aa4d9c275b..841d03afef96 100644 --- a/chart2/inc/strings.hrc +++ b/chart2/inc/strings.hrc @@ -49,6 +49,7 @@ #define STR_PAGE_ILLUMINATION NC_("STR_PAGE_ILLUMINATION", "Illumination") #define STR_PAGE_ASIAN NC_("STR_PAGE_ASIAN", "Asian Typography") #define STR_PAGE_COLOR_PALETTE NC_("STR_PAGE_COLOR_PALETTE", "Color Palette") +#define STR_PAGE_GRADIENT_PRESETS NC_("STR_PAGE_GRADIENT_PRESETS", "Gradients") #define STR_OBJECT_AVERAGE_LINE_WITH_PARAMETERS NC_("STR_OBJECT_AVERAGE_LINE_WITH_PARAMETERS", "Mean value line with value %AVERAGE_VALUE and standard deviation %STD_DEVIATION") #define STR_OBJECT_AXIS NC_("STR_OBJECT_AXIS", "Axis") #define STR_OBJECT_AXIS_X NC_("STR_OBJECT_AXIS_X", "X Axis") diff --git a/chart2/source/controller/chartcontroller.component b/chart2/source/controller/chartcontroller.component index cc1e9817f94b..c962ac284d7d 100644 --- a/chart2/source/controller/chartcontroller.component +++ b/chart2/source/controller/chartcontroller.component @@ -58,4 +58,8 @@ constructor="com_sun_star_comp_chart2_ChartThemeControl_get_implementation"> <service name="com.sun.star.frame.ToolbarController"/> </implementation> + <implementation name="com.sun.star.comp.chart2.ChartGradientPaletteControl" + constructor="com_sun_star_comp_chart2_ChartGradientPaletteControl_get_implementation"> + <service name="com.sun.star.frame.ToolbarController"/> + </implementation> </component> diff --git a/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx b/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx index db633f227249..243a8c433f4d 100644 --- a/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx +++ b/chart2/source/controller/dialogs/dlg_ObjectProperties.cxx @@ -37,6 +37,7 @@ #include "tp_DataPointOption.hxx" #include "tp_DataTable.hxx" #include "tp_ChartColorPalette.hxx" +#include "tp_ChartGradients.hxx" #include <ResId.hxx> #include <ViewElementListProvider.hxx> #include <ChartModelHelper.hxx> @@ -366,6 +367,7 @@ SchAttribTabDlg::SchAttribTabDlg(weld::Window* pParent, AddTabPage(u"area"_ustr, SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); AddTabPage(u"transparent"_ustr, SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); AddTabPage(u"colorpalette"_ustr, SchResId(STR_PAGE_COLOR_PALETTE), ChartColorPaletteTabPage::Create); + AddTabPage(u"gradients"_ustr, SchResId(STR_PAGE_GRADIENT_PRESETS), ChartGradientsTabPage::Create); AddTabPage(u"fontname"_ustr, SchResId(STR_PAGE_FONT), RID_SVXPAGE_CHAR_NAME); AddTabPage(u"effects"_ustr, SchResId(STR_PAGE_FONT_EFFECTS), RID_SVXPAGE_CHAR_EFFECTS); AddTabPage(u"legendpos"_ustr, SchResId(STR_PAGE_POSITION), SchLegendPosTabPage::Create); @@ -392,6 +394,7 @@ SchAttribTabDlg::SchAttribTabDlg(weld::Window* pParent, } AddTabPage(u"border"_ustr, SchResId( m_pParameter->HasAreaProperties() ? STR_PAGE_BORDER : STR_PAGE_LINE ), RID_SVXPAGE_LINE); AddTabPage(u"colorpalette"_ustr, SchResId(STR_PAGE_COLOR_PALETTE), ChartColorPaletteTabPage::Create); + AddTabPage(u"gradients"_ustr, SchResId(STR_PAGE_GRADIENT_PRESETS), ChartGradientsTabPage::Create); break; case OBJECTTYPE_DATA_LABEL: @@ -459,7 +462,10 @@ SchAttribTabDlg::SchAttribTabDlg(weld::Window* pParent, AddTabPage(u"area"_ustr, SchResId(STR_PAGE_AREA), RID_SVXPAGE_AREA); AddTabPage(u"transparent"_ustr, SchResId(STR_PAGE_TRANSPARENCY), RID_SVXPAGE_TRANSPARENCE); if (eType != OBJECTTYPE_DATA_STOCK_LOSS && eType != OBJECTTYPE_DATA_STOCK_GAIN) + { AddTabPage(u"colorpalette"_ustr, SchResId(STR_PAGE_COLOR_PALETTE), ChartColorPaletteTabPage::Create); + AddTabPage(u"gradients"_ustr, SchResId(STR_PAGE_GRADIENT_PRESETS), ChartGradientsTabPage::Create); + } break; case OBJECTTYPE_LEGEND_ENTRY: @@ -639,6 +645,14 @@ void SchAttribTabDlg::PageCreated(const OUString& rId, SfxTabPage &rPage) pColorPaletteTabPage->init(m_pParameter->getDocument()); } } + else if (rId == "gradients") + { + auto* pGradientsTabPage = dynamic_cast<ChartGradientsTabPage*>( &rPage ); + if (pGradientsTabPage) + { + pGradientsTabPage->init(m_pParameter->getDocument()); + } + } } IMPL_LINK(SchAttribTabDlg, OKPressed, weld::Button&, rButton, void) diff --git a/chart2/source/controller/dialogs/tp_ChartColorPalette.cxx b/chart2/source/controller/dialogs/tp_ChartColorPalette.cxx index fd5af1885ace..03f028f5a05c 100644 --- a/chart2/source/controller/dialogs/tp_ChartColorPalette.cxx +++ b/chart2/source/controller/dialogs/tp_ChartColorPalette.cxx @@ -59,11 +59,13 @@ void ChartColorPaletteTabPage::init(const rtl::Reference<ChartModel>& xChartMode { assert(xChartModel); mxChartModel = xChartModel; + meCurrentType = mxChartModel->getColorPaletteType(); + mnCurrentIndex = mxChartModel->getColorPaletteIndex(); const std::shared_ptr<model::Theme> pTheme = mxChartModel->getDocumentTheme(); mxHelper = std::make_unique<ChartColorPaletteHelper>(pTheme); - selectItem(mxChartModel->getColorPaletteType(), mxChartModel->getColorPaletteIndex() + 1); + selectItem(meCurrentType, mnCurrentIndex + 1); initColorPalettes(); } @@ -81,6 +83,12 @@ void ChartColorPaletteTabPage::initColorPalettes() const mxMonoPalettes->Fill(); } +bool ChartColorPaletteTabPage::isCurrentColorPalette(const ChartColorPaletteType eType, + const sal_uInt32 nIndex) const +{ + return eType == meCurrentType && nIndex == mnCurrentIndex; +} + void ChartColorPaletteTabPage::selectItem(const ChartColorPaletteType eType, const sal_uInt32 nIndex) const { @@ -118,7 +126,8 @@ bool ChartColorPaletteTabPage::FillItemSet(SfxItemSet* pOutAttrs) nIndex = mxMonoPalettes->GetSelectedItemId() - 1; } - pOutAttrs->Put(SvxChartColorPaletteItem(eType, nIndex, SCHATTR_COLOR_PALETTE)); + if (!isCurrentColorPalette(eType, nIndex)) + pOutAttrs->Put(SvxChartColorPaletteItem(eType, nIndex, SCHATTR_COLOR_PALETTE)); return true; } diff --git a/chart2/source/controller/dialogs/tp_ChartColorPalette.hxx b/chart2/source/controller/dialogs/tp_ChartColorPalette.hxx index 7f24977f6464..9886d5374c2c 100644 --- a/chart2/source/controller/dialogs/tp_ChartColorPalette.hxx +++ b/chart2/source/controller/dialogs/tp_ChartColorPalette.hxx @@ -46,6 +46,7 @@ public: void init(const rtl::Reference<ChartModel>& xChartModel); private: + bool isCurrentColorPalette(ChartColorPaletteType eType, sal_uInt32 nIndex) const; void selectItem(ChartColorPaletteType eType, sal_uInt32 nIndex) const; void initColorPalettes() const; @@ -54,6 +55,8 @@ private: std::unique_ptr<ChartColorPaletteHelper> mxHelper; std::unique_ptr<ChartColorPalettes> mxColorfulPalettes; std::unique_ptr<ChartColorPalettes> mxMonoPalettes; + ChartColorPaletteType meCurrentType; + sal_uInt32 mnCurrentIndex; DECL_LINK(SelectColorfulPaletteHdl, weld::IconView&, bool); DECL_LINK(SelectMonoPaletteHdl, weld::IconView&, bool); diff --git a/chart2/source/controller/dialogs/tp_ChartGradients.cxx b/chart2/source/controller/dialogs/tp_ChartGradients.cxx new file mode 100644 index 000000000000..0aa8f0b6d022 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ChartGradients.cxx @@ -0,0 +1,180 @@ +/* -*- 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/. + * + */ + +#include "tp_ChartGradients.hxx" + +#include <ChartGradientPaletteHelper.hxx> +#include <ChartModel.hxx> +#include <chartview/ChartSfxItemIds.hxx> +#include <o3tl/enumrange.hxx> +#include <svx/chrtitem.hxx> +#include <vcl/svapp.hxx> + +namespace chart +{ +ChartGradientsTabPage::ChartGradientsTabPage(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet& rInAttrs) + : SfxTabPage(pPage, pController, "modules/schart/ui/tp_ChartGradients.ui", "tp_ChartGradients", + &rInAttrs) + , mxLightPalettes(new ChartGradientPalettes(*m_xBuilder, "light_palettes", "lightwin")) + , mxDarkPalettes(new ChartGradientPalettes(*m_xBuilder, "dark_palettes", "darkwin")) +{ + mxLightPalettes->SetSelectHdl(LINK(this, ChartGradientsTabPage, SelectLightPaletteHdl)); + + mxDarkPalettes->SetSelectHdl(LINK(this, ChartGradientsTabPage, SelectDarkPaletteHdl)); +} + +ChartGradientsTabPage::~ChartGradientsTabPage() +{ + mxLightPalettes.reset(); + mxDarkPalettes.reset(); +} + +std::unique_ptr<SfxTabPage> ChartGradientsTabPage::Create(weld::Container* pPage, + weld::DialogController* pController, + const SfxItemSet* rInAttrs) +{ + return std::make_unique<ChartGradientsTabPage>(pPage, pController, *rInAttrs); +} + +void ChartGradientsTabPage::init(const rtl::Reference<ChartModel>& xChartModel) +{ + assert(xChartModel); + mxChartModel = xChartModel; + meCurrentVariation = mxChartModel->getGradientPaletteVariation(); + meCurrentType = mxChartModel->getGradientPaletteType(); + mxHelper = std::make_unique<ChartGradientPaletteHelper>( + mxChartModel->getDataSeriesColorsForGradient(false)); + + initGradientPalettes(); + selectItem(meCurrentVariation, meCurrentType); +} + +void ChartGradientsTabPage::initGradientPalettes() const +{ + if (!mxHelper) + return; + + for (auto type : o3tl::enumrange<ChartGradientType>()) + { + mxLightPalettes->insert( + mxHelper->getGradientSample(ChartGradientVariation::LightVariation, type)); + mxDarkPalettes->insert( + mxHelper->getGradientSample(ChartGradientVariation::DarkVariation, type)); + } + mxLightPalettes->Fill(); + mxDarkPalettes->Fill(); +} + +bool ChartGradientsTabPage::isCurrentGradientPreset(ChartGradientVariation eVariation, + ChartGradientType eType) const +{ + return eVariation == meCurrentVariation && eType == meCurrentType; +} + +void ChartGradientsTabPage::selectItem(const ChartGradientVariation eVariation, + const ChartGradientType eType) const +{ + const sal_uInt16 nIndex = static_cast<sal_uInt16>(eType) + 1; + + switch (eVariation) + { + default: + case ChartGradientVariation::Unknown: + mxLightPalettes->SetNoSelection(); + mxDarkPalettes->SetNoSelection(); + break; + case ChartGradientVariation::LightVariation: + mxLightPalettes->SelectItem(nIndex); + break; + case ChartGradientVariation::DarkVariation: + mxDarkPalettes->SelectItem(nIndex); + break; + } +} + +bool ChartGradientsTabPage::FillItemSet(SfxItemSet* pOutAttrs) +{ + ChartGradientVariation eVariation = ChartGradientVariation::Unknown; + ChartGradientType eType = ChartGradientType::Invalid; + sal_uInt32 nIndex = 0; + + if (!mxLightPalettes->IsNoSelection()) + { + eVariation = ChartGradientVariation::LightVariation; + nIndex = mxLightPalettes->GetSelectedItemId() - 1; + } + else if (!mxDarkPalettes->IsNoSelection()) + { + eVariation = ChartGradientVariation::DarkVariation; + nIndex = mxDarkPalettes->GetSelectedItemId() - 1; + } + + if (nIndex != static_cast<sal_uInt32>(-1)) + eType = static_cast<ChartGradientType>(nIndex); + + if (!isCurrentGradientPreset(eVariation, eType)) + pOutAttrs->Put(SvxChartGradientPresetItem(eVariation, eType, SCHATTR_GRADIENT_PRESET)); + + return true; +} + +void ChartGradientsTabPage::Reset(const SfxItemSet*) +{ + selectItem(mxChartModel->getGradientPaletteVariation(), mxChartModel->getGradientPaletteType()); +} + +DeactivateRC ChartGradientsTabPage::DeactivatePage(SfxItemSet* pItemSet) +{ + if (pItemSet) + FillItemSet(pItemSet); + + return DeactivateRC::LeavePage; +} + +IMPL_LINK_NOARG(ChartGradientsTabPage, SelectLightPaletteHdl, weld::IconView&, bool) +{ + sal_uInt32 nIndex = GetSelectedItem(mxLightPalettes); + if (nIndex != static_cast<sal_uInt32>(-1)) + { + mxDarkPalettes->SetNoSelection(); + } + return true; +} + +IMPL_LINK_NOARG(ChartGradientsTabPage, SelectDarkPaletteHdl, weld::IconView&, bool) +{ + sal_uInt32 nIndex = GetSelectedItem(mxDarkPalettes); + if (nIndex != static_cast<sal_uInt32>(-1)) + { + mxLightPalettes->SetNoSelection(); + } + return true; +} + +sal_uInt32 +ChartGradientsTabPage::GetSelectedItem(const std::unique_ptr<ChartGradientPalettes>& xPalettes) +{ + const sal_uInt32 nItemId = xPalettes->GetSelectedItemId(); + if (!nItemId) + return static_cast<sal_uInt32>(-1); + + const sal_uInt32 nIndex = nItemId - 1; + + if (const basegfx::BGradient* pPalette = xPalettes->getPalette(nIndex)) + { + return nIndex; + } + return static_cast<sal_uInt32>(-1); +} +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/tp_ChartGradients.hxx b/chart2/source/controller/dialogs/tp_ChartGradients.hxx new file mode 100644 index 000000000000..59d98d400d99 --- /dev/null +++ b/chart2/source/controller/dialogs/tp_ChartGradients.hxx @@ -0,0 +1,58 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <sfx2/tabdlg.hxx> +#include <ChartGradientPalettes.hxx> + +namespace chart +{ +class ChartModel; +class ChartGradientPaletteHelper; + +// This tab page is used to apply gradients to data series according to a given selected gradient. +// It is present in the Chart Format Dialog for several chart elements. +class ChartGradientsTabPage final : public SfxTabPage +{ +public: + ChartGradientsTabPage(weld::Container* pPage, weld::DialogController* pController, + const SfxItemSet& rInAttrs); + ~ChartGradientsTabPage() override; + + static std::unique_ptr<SfxTabPage> + Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rInAttrs); + + bool FillItemSet(SfxItemSet* pOutAttrs) override; + void Reset(const SfxItemSet* rInAttrs) override; + DeactivateRC DeactivatePage(SfxItemSet* pItemSet) override; + + void init(const rtl::Reference<ChartModel>& xChartModel); + +private: + bool isCurrentGradientPreset(ChartGradientVariation eVariation, ChartGradientType eType) const; + void selectItem(ChartGradientVariation eVariation, ChartGradientType eType) const; + void initGradientPalettes() const; + +private: + rtl::Reference<ChartModel> mxChartModel; + std::unique_ptr<ChartGradientPaletteHelper> mxHelper; + std::unique_ptr<ChartGradientPalettes> mxLightPalettes; + std::unique_ptr<ChartGradientPalettes> mxDarkPalettes; + ChartGradientVariation meCurrentVariation; + ChartGradientType meCurrentType; + + DECL_LINK(SelectLightPaletteHdl, weld::IconView&, bool); + DECL_LINK(SelectDarkPaletteHdl, weld::IconView&, bool); + static sal_uInt32 GetSelectedItem(const std::unique_ptr<ChartGradientPalettes>& xPalettes); +}; +} //namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx b/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx index a6fecfb39f85..db18df3a90a9 100644 --- a/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx +++ b/chart2/source/controller/itemsetwrapper/GraphicPropertyItemConverter.cxx @@ -174,7 +174,7 @@ const WhichRangesContainer& GraphicPropertyItemConverter::GetWhichPairs() const bool GraphicPropertyItemConverter::GetItemProperty( tWhichIdType nWhichId, tPropertyNameWithMemberId & rOutProperty ) const { - if (nWhichId == SCHATTR_COLOR_PALETTE) + if (nWhichId == SCHATTR_COLOR_PALETTE || nWhichId == SCHATTR_GRADIENT_PRESET) { return false; } @@ -759,7 +759,30 @@ bool GraphicPropertyItemConverter::ApplySpecialItem( m_xChartModel->setColorPalette(rItem.GetType(), rItem.GetIndex()); const auto oColorPalette = m_xChartModel->getCurrentColorPalette(); if (oColorPalette) + { + m_xChartModel->clearGradientPalette(); m_xChartModel->applyColorPaletteToDataSeries(*oColorPalette); + } + else + { + m_xChartModel->clearColorPalette(); + } + } + break; + case SCHATTR_GRADIENT_PRESET: + { + const auto& rItem = static_cast<const SvxChartGradientPresetItem&>(rItemSet.Get(nWhichId)); + m_xChartModel->setGradientPalette(rItem.GetVariation(), rItem.GetType()); + const auto oGradientPreset = m_xChartModel->getCurrentGradientPalette(); + if (oGradientPreset) + { + m_xChartModel->clearColorPalette(); + m_xChartModel->applyGradientPaletteToDataSeries(*oGradientPreset); + } + else + { + m_xChartModel->clearGradientPalette(); + } } break; } diff --git a/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx index 8216c4b32337..ba592b5be0d1 100644 --- a/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx +++ b/chart2/source/controller/itemsetwrapper/SchWhichPairs.hxx @@ -60,6 +60,7 @@ const WhichRangesContainer nGridWhichPairs(svl::Items< const WhichRangesContainer nLegendWhichPairs(svl::Items< SCHATTR_LEGEND_START, SCHATTR_LEGEND_END, // 3 - 3 sch/schattr.hxx SCHATTR_COLOR_PALETTE_START, SCHATTR_COLOR_PALETTE_END, // 107 - 107 + SCHATTR_GRADIENT_PRESET_START, SCHATTR_GRADIENT_PRESET_END, // 108 - 108 XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1018 - 1046 svx/xdef.hxx SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST, // 1067 - 1078 svx/svddef.hxx @@ -123,6 +124,7 @@ const WhichRangesContainer nRowWhichPairs(svl::Items< SCHATTR_BAR_OVERLAP,SCHATTR_BAR_CONNECT, /* 98 - 100 (incl. SCHATTR_GAPWIDTH) */ SCHATTR_GROUP_BARS_PER_AXIS,SCHATTR_AXIS_FOR_ALL_SERIES, SCHATTR_COLOR_PALETTE_START, SCHATTR_COLOR_PALETTE_END, // 107 - 107 + SCHATTR_GRADIENT_PRESET_START, SCHATTR_GRADIENT_PRESET_END, // 108 - 108 XATTR_LINE_FIRST, XATTR_LINE_LAST, /* 1000 - 1016 svx/xdef.hxx */ XATTR_FILL_FIRST, XATTR_FILL_LAST, /* 1018 - 1046 svx/xdef.hxx */ SDRATTR_3D_FIRST, SDRATTR_3D_LAST, /* 1244 - 1334 svx/svddef.hxx */ @@ -155,6 +157,7 @@ const WhichRangesContainer nLinePropertyWhichPairs(svl::Items< const WhichRangesContainer nLineAndFillPropertyWhichPairs(svl::Items< SCHATTR_COLOR_PALETTE_START, SCHATTR_COLOR_PALETTE_END, // 107 - 107 + SCHATTR_GRADIENT_PRESET_START, SCHATTR_GRADIENT_PRESET_END, // 108 - 108 XATTR_LINE_FIRST, XATTR_LINE_LAST, // 1000 - 1016 svx/xdef.hxx XATTR_FILL_FIRST, XATTR_FILL_LAST, // 1000 - 1016 svx/xdef.hxx SDRATTR_SHADOW_FIRST, SDRATTR_SHADOW_LAST // 1067 - 1078 svx/svddef.hxx diff --git a/chart2/source/controller/sidebar/Chart2PanelFactory.cxx b/chart2/source/controller/sidebar/Chart2PanelFactory.cxx index d4a91bab6fa5..2ebe00c6200e 100644 --- a/chart2/source/controller/sidebar/Chart2PanelFactory.cxx +++ b/chart2/source/controller/sidebar/Chart2PanelFactory.cxx @@ -37,6 +37,7 @@ #include "ChartColorsPanel.hxx" #include "ChartThemePanel.hxx" #include <officecfg/Office/Common.hxx> +#include "ChartGradientsPanel.hxx" using namespace css::uno; @@ -106,6 +107,8 @@ Reference<css::ui::XUIElement> SAL_CALL ChartPanelFactory::createUIElement ( else if (rsResourceURL.endsWith("/ThemePanel") && officecfg::Office::Common::Misc::ExperimentalMode::get()) xPanel = ChartThemePanel::Create(pParent, xFrame, pController); + else if (rsResourceURL.endsWith("/GradientsPanel")) + xPanel = ChartGradientsPanel::Create(pParent, xFrame, pController); if (xPanel) xElement = sfx2::sidebar::SidebarPanelBase::Create( diff --git a/chart2/source/controller/sidebar/ChartColorsPanel.cxx b/chart2/source/controller/sidebar/ChartColorsPanel.cxx index c4e71aac483b..fb255488cb1b 100644 --- a/chart2/source/controller/sidebar/ChartColorsPanel.cxx +++ b/chart2/source/controller/sidebar/ChartColorsPanel.cxx @@ -149,6 +149,7 @@ void ColorPaletteWrapper::restoreOriginalDiagram() void ColorPaletteWrapper::select(ChartColorPaletteType eType, const sal_uInt32 nIndex) { + mxModel->clearGradientPalette(); mxModel->setColorPalette(eType, nIndex); } diff --git a/chart2/source/controller/sidebar/ChartGradientPaletteControl.cxx b/chart2/source/controller/sidebar/ChartGradientPaletteControl.cxx new file mode 100644 index 000000000000..8f8a224c013e --- /dev/null +++ b/chart2/source/controller/sidebar/ChartGradientPaletteControl.cxx @@ -0,0 +1,412 @@ +/* -*- 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/. + * + */ + +#include <com/sun/star/drawing/FillStyle.hpp> + +#include <memory> +#include <utility> +#include <o3tl/enumrange.hxx> +#include <vcl/svapp.hxx> +#include <vcl/toolbox.hxx> +#include <vcl/virdev.hxx> + +#include <ChartGradientPaletteHelper.hxx> +#include "ChartGradientPaletteControl.hxx" + +#include <vcl/event.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/graph.hxx> + +using namespace css; + +namespace chart::sidebar +{ +constexpr tools::Long BORDER = ChartGradientPaletteLayout::ItemBorder; +constexpr tools::Long SIZE = ChartGradientPaletteLayout::ItemSize; + +ChartGradientPaletteControl::ChartGradientPaletteControl( + const uno::Reference<uno::XComponentContext>& rContext) + : PopupWindowController(rContext, nullptr, OUString()) + , meGradientVariation(ChartGradientVariation::Unknown) + , mnGradientType(ChartGradientType::Invalid) +{ +} + +ChartGradientPaletteControl::~ChartGradientPaletteControl() = default; + +void ChartGradientPaletteControl::initialize(const uno::Sequence<uno::Any>& rArguments) +{ + svt::PopupWindowController::initialize(rArguments); + + if (m_pToolbar) + { + mxPopoverContainer = std::make_unique<ToolbarPopupContainer>(m_pToolbar); + m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel()); + m_pToolbar->set_item_sensitive(m_aCommandURL, true); + } + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (getToolboxId(nId, &pToolBox)) + { + pToolBox->SetItemBits(nId, pToolBox->GetItemBits(nId) | ToolBoxItemBits::DROPDOWNONLY); + pToolBox->EnableItem(nId, true); + } +} + +void ChartGradientPaletteControl::execute(sal_Int16 /*nKeyModifier*/) +{ + if (m_pToolbar) + { + // Toggle the popup also when toolbutton is activated + m_pToolbar->set_menu_item_active(m_aCommandURL, + !m_pToolbar->get_menu_item_active(m_aCommandURL)); + } + else + { + // Open the popup also when Enter key is pressed. + createPopupWindow(); + } +} + +void ChartGradientPaletteControl::statusChanged(const frame::FeatureStateEvent& rEvent) +{ + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox) && !m_pToolbar) + return; + + if (rEvent.FeatureURL.Complete == m_aCommandURL) + { + updateStatus(); + } +} + +void ChartGradientPaletteControl::updateStatus(bool bForce) +{ + if (!mpHandler) + return; + + if (bForce || meGradientVariation != getGradientVariation() + || mnGradientType != getGradientType()) + { + meGradientVariation = getGradientVariation(); + mnGradientType = getGradientType(); + + ToolBox* pToolBox = nullptr; + ToolBoxItemId nId; + if (!getToolboxId(nId, &pToolBox) && !m_pToolbar) + return; + + auto pDev = VclPtr<VirtualDevice>::Create(); + renderSelectedGradientPalette(pDev); + auto aSelItemImg(pDev->GetBitmapEx(Point(), pDev->GetOutputSizePixel())); + if (m_pToolbar) + { + m_pToolbar->set_item_image(m_aCommandURL, Graphic(aSelItemImg).GetXGraphic()); + } + else + { + pToolBox->SetItemImage(nId, Image(aSelItemImg)); + } + } +} + +void ChartGradientPaletteControl::createDiagramSnapshot() const +{ + if (mpHandler) + mpHandler->createDiagramSnapshot(); +} + +void ChartGradientPaletteControl::restoreOriginalDiagram() const +{ + if (mpHandler) + mpHandler->restoreOriginalDiagram(); +} + +void ChartGradientPaletteControl::renderSelectedGradientPalette( + const VclPtr<VirtualDevice>& pDev) const +{ + if (!pDev) + return; + + const auto pHelper = getGradientPaletteHelper(); + if (!pHelper) + return; + + static constexpr Point aPosition(0, 0); + static constexpr Size aSize = { 2 * BORDER + SIZE, 2 * BORDER + SIZE }; + static constexpr tools::Rectangle aDrawArea(aPosition, aSize); + + pDev->SetOutputSizePixel(aSize, /*bErase*/ true, /*bAlphaMaskTransparent*/ true); + + if (getGradientVariation() == ChartGradientVariation::Unknown) + { + ChartGradientPaletteHelper::renderNoGradient(pDev, aDrawArea); + return; + } + + const basegfx::BGradient aGradientItem + = pHelper->getGradientSample(getGradientVariation(), getGradientType()); + ChartGradientPaletteHelper::renderGradientItem(pDev, aDrawArea, aGradientItem, true); +} + +void ChartGradientPaletteControl::setGradientPaletteHandler( + std::shared_ptr<IGradientPaletteHandler> rGradientPaletteHandler) +{ + if (!mpHandler) + { + mpHandler = rGradientPaletteHandler; + updateStatus(true); + } +} + +std::shared_ptr<ChartGradientPaletteHelper> +ChartGradientPaletteControl::getGradientPaletteHelper() const +{ + if (mpHandler) + return mpHandler->getHelper(); + return nullptr; +} + +ChartGradientVariation ChartGradientPaletteControl::getGradientVariation() const +{ + if (mpHandler) + return mpHandler->getVariation(); + return ChartGradientVariation::Unknown; +} + +ChartGradientType ChartGradientPaletteControl::getGradientType() const +{ + if (mpHandler) + return mpHandler->getType(); + return ChartGradientType::Invalid; +} + +void ChartGradientPaletteControl::dispatchGradientPaletteCommand( + const ChartGradientVariation eVariant, const ChartGradientType eType) const +{ + if (mpHandler) + mpHandler->select(eVariant, eType); +} + +void ChartGradientPaletteControl::applyGradientPalette(const ChartGradientVariation eVariation, + const ChartGradientType eType, + const bool bIsPreview) const +{ + if (!mpHandler) + return; + + mpHandler->setPreview(bIsPreview); + + if (const auto pGradientPaletteHelper = getGradientPaletteHelper()) + mpHandler->apply(pGradientPaletteHelper->getGradientPalette(eVariation, eType)); + + mpHandler->setPreview(false); +} + +std::unique_ptr<WeldToolbarPopup> ChartGradientPaletteControl::weldPopupWindow() +{ + return std::make_unique<ChartGradientPalettePopup>(this, m_pToolbar); +} + +VclPtr<vcl::Window> ChartGradientPaletteControl::createVclPopupWindow(vcl::Window* pParent) +{ + mxInterimPopover = VclPtr<InterimToolbarPopup>::Create( + getFrameInterface(), pParent, + std::make_unique<ChartGradientPalettePopup>(this, pParent->GetFrameWeld())); + + mxInterimPopover->Show(); + + return mxInterimPopover; +} + +OUString ChartGradientPaletteControl::getImplementationName() +{ + return "com.sun.star.comp.chart2.ChartGradientPaletteControl"; +} + +uno::Sequence<OUString> ChartGradientPaletteControl::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} + +extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface* +com_sun_star_comp_chart2_ChartGradientPaletteControl_get_implementation( + uno::XComponentContext* rContext, uno::Sequence<uno::Any> const&) +{ + return cppu::acquire(new ChartGradientPaletteControl(rContext)); +} + +ChartGradientPalettePopup::ChartGradientPalettePopup(ChartGradientPaletteControl* pControl, + weld::Widget* pParent) + : WeldToolbarPopup(pControl->getFrameInterface(), pParent, + "modules/schart/ui/chartgradientpalettepopup.ui", "GradientPaletteWindow") + , mxControl(pControl) + , mxLightPalettes(new ChartGradientPalettes(*m_xBuilder, "light_palettes", "lightwin")) + , mxDarkPalettes(new ChartGradientPalettes(*m_xBuilder, "dark_palettes", "darkwin")) + , meHighlightedItemVariation(mxControl->getGradientVariation()) + , mnHighlightedItemType(mxControl->getGradientType()) + , mbItemSelected(false) +{ + mxLightPalettes->SetSelectHdl(LINK(this, ChartGradientPalettePopup, SelectLightPaletteHdl)); + mxLightPalettes->setMouseMoveHdl( + LINK(this, ChartGradientPalettePopup, LightPaletteMouseMoveHdl)); + + mxDarkPalettes->SetSelectHdl(LINK(this, ChartGradientPalettePopup, SelectDarkPaletteHdl)); + mxDarkPalettes->setMouseMoveHdl(LINK(this, ChartGradientPalettePopup, DarkPaletteMouseMoveHdl)); + + initGradientPalettes(); + + selectItem(mxControl->getGradientVariation(), mxControl->getGradientType()); + + mxControl->createDiagramSnapshot(); +} + +ChartGradientPalettePopup::~ChartGradientPalettePopup() +{ + if (!mbItemSelected) + mxControl->restoreOriginalDiagram(); +} + +void ChartGradientPalettePopup::selectItem(const ChartGradientVariation eVariation, + const ChartGradientType eType) const +{ + const sal_uInt16 nIndex = static_cast<sal_uInt16>(eType) + 1; + + switch (eVariation) + { + default: + case ChartGradientVariation::Unknown: + mxLightPalettes->SetNoSelection(); + mxDarkPalettes->SetNoSelection(); + break; + case ChartGradientVariation::LightVariation: + mxLightPalettes->SelectItem(nIndex); + break; + case ChartGradientVariation::DarkVariation: + mxDarkPalettes->SelectItem(nIndex); + break; + } +} + +void ChartGradientPalettePopup::initGradientPalettes() const +{ + const auto pGradientPaletteHelper = mxControl->getGradientPaletteHelper(); + if (!pGradientPaletteHelper) + return; + + for (auto type : o3tl::enumrange<ChartGradientType>()) + { + mxLightPalettes->insert(pGradientPaletteHelper->getGradientSample( + ChartGradientVariation::LightVariation, type)); + mxDarkPalettes->insert( + pGradientPaletteHelper->getGradientSample(ChartGradientVariation::DarkVariation, type)); + } + mxLightPalettes->Fill(); + mxDarkPalettes->Fill(); +} + +void ChartGradientPalettePopup::GrabFocus() +{ + if (mxDarkPalettes->IsNoSelection()) + mxLightPalettes->GrabFocus(); + else + mxDarkPalettes->GrabFocus(); +} + +IMPL_LINK_NOARG(ChartGradientPalettePopup, SelectLightPaletteHdl, weld::IconView&, bool) +{ + sal_uInt32 nIndex = GetSelectedItem(mxLightPalettes); + if (nIndex != static_cast<sal_uInt32>(-1)) + { + const auto eType = static_cast<ChartGradientType>(nIndex); + mxControl->applyGradientPalette(ChartGradientVariation::LightVariation, eType); + mxControl->dispatchGradientPaletteCommand(ChartGradientVariation::LightVariation, eType); + mxDarkPalettes->SetNoSelection(); + mxControl->updateStatus(); + } + mxControl->EndPopupMode(); + return true; +} + +IMPL_LINK_NOARG(ChartGradientPalettePopup, SelectDarkPaletteHdl, weld::IconView&, bool) +{ + sal_uInt32 nIndex = GetSelectedItem(mxDarkPalettes); + if (nIndex != static_cast<sal_uInt32>(-1)) + { + const auto eType = static_cast<ChartGradientType>(nIndex); + mxControl->applyGradientPalette(ChartGradientVariation::DarkVariation, eType); + mxControl->dispatchGradientPaletteCommand(ChartGradientVariation::DarkVariation, eType); + mxLightPalettes->SetNoSelection(); + mxControl->updateStatus(); + } + mxControl->EndPopupMode(); + return true; +} + +sal_uInt32 +ChartGradientPalettePopup::GetSelectedItem(const std::unique_ptr<ChartGradientPalettes>& xPalettes) +{ + const sal_uInt32 nItemId = xPalettes->GetSelectedItemId(); + if (!nItemId) + return static_cast<sal_uInt32>(-1); + + const sal_uInt32 nIndex = nItemId - 1; + + if (const basegfx::BGradient* pPalette = xPalettes->getPalette(nIndex)) + { + mbItemSelected = true; + return nIndex; + } + return static_cast<sal_uInt32>(-1); +} + +IMPL_LINK_NOARG(ChartGradientPalettePopup, LightPaletteMouseMoveHdl, const MouseEvent&, bool) +{ + MouseMoveHdl(mxLightPalettes, ChartGradientVariation::LightVariation); + return true; +} + +IMPL_LINK_NOARG(ChartGradientPalettePopup, DarkPaletteMouseMoveHdl, const MouseEvent&, bool) +{ + MouseMoveHdl(mxDarkPalettes, ChartGradientVariation::DarkVariation); + return true; +} + +void ChartGradientPalettePopup::MouseMoveHdl( + const std::unique_ptr<ChartGradientPalettes>& xPalettes, + const ChartGradientVariation eHlItemVariation) +{ + const sal_uInt16 nHlId = xPalettes->GetHighlightedItemId(); + const ChartGradientType eHlType + = nHlId > 0 ? static_cast<ChartGradientType>(nHlId - 1) : ChartGradientType::Invalid; + if (eHlItemVariation == meHighlightedItemVariation && eHlType == mnHighlightedItemType) + return; + + if (nHlId > 0) + { + if (const basegfx::BGradient* pPalette = xPalettes->getPalette(nHlId - 1)) + { + mxControl->applyGradientPalette(eHlItemVariation, eHlType, true); + } + } + else + { + mxControl->restoreOriginalDiagram(); + } + + meHighlightedItemVariation = eHlItemVariation; + mnHighlightedItemType = eHlType; +} + +} // end namespace chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartGradientPaletteControl.hxx b/chart2/source/controller/sidebar/ChartGradientPaletteControl.hxx new file mode 100644 index 000000000000..e9ba04663132 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartGradientPaletteControl.hxx @@ -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/. + * + */ + +#pragma once + +#include <svtools/popupwindowcontroller.hxx> +#include <svtools/toolbarmenu.hxx> +#include <ChartGradientPalettes.hxx> + +namespace chart +{ +class ChartGradientPaletteHelper; + +namespace sidebar +{ +struct IGradientPaletteHandler +{ + virtual ~IGradientPaletteHandler() = default; + + virtual void createDiagramSnapshot() = 0; + virtual void restoreOriginalDiagram() = 0; + + virtual void select(ChartGradientVariation eVariant, ChartGradientType eType) = 0; + virtual void apply(const ChartGradientPalette& rGradientPalette) = 0; + virtual void setPreview(bool bFlag) = 0; + [[nodiscard]] virtual std::shared_ptr<ChartGradientPaletteHelper> getHelper() const = 0; + [[nodiscard]] virtual ChartGradientVariation getVariation() const = 0; + [[nodiscard]] virtual ChartGradientType getType() const = 0; +}; + +class ChartGradientPaletteControl final : public svt::PopupWindowController +{ + std::shared_ptr<IGradientPaletteHandler> mpHandler; + ChartGradientVariation meGradientVariation; + ChartGradientType mnGradientType; + +public: + explicit ChartGradientPaletteControl( + const css::uno::Reference<css::uno::XComponentContext>& rContext); + + // XInitialization + void SAL_CALL initialize(const css::uno::Sequence<css::uno::Any>& rArguments) override; + + // XServiceInfo + OUString SAL_CALL getImplementationName() override; + css::uno::Sequence<OUString> SAL_CALL getSupportedServiceNames() override; + + void SAL_CALL execute(sal_Int16 nKeyModifier) override; + void SAL_CALL statusChanged(const css::frame::FeatureStateEvent& rEvent) override; + + ~ChartGradientPaletteControl() override; + + void + setGradientPaletteHandler(std::shared_ptr<IGradientPaletteHandler> rGradientPaletteHandler); + std::shared_ptr<ChartGradientPaletteHelper> getGradientPaletteHelper() const; + ChartGradientVariation getGradientVariation() const; + ChartGradientType getGradientType() const; + void dispatchGradientPaletteCommand(ChartGradientVariation eVariation, + ChartGradientType eType) const; + void applyGradientPalette(ChartGradientVariation eVariation, ChartGradientType eType, + bool bIsPreview = false) const; + void updateStatus(bool bForce = false); + + void createDiagramSnapshot() const; + void restoreOriginalDiagram() const; + +private: + std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override; + VclPtr<vcl::Window> createVclPopupWindow(vcl::Window* pParent) override; + + void renderSelectedGradientPalette(const VclPtr<VirtualDevice>& pDev) const; +}; + +class ChartGradientPalettePopup final : public WeldToolbarPopup +{ + rtl::Reference<ChartGradientPaletteControl> mxControl; + std::unique_ptr<ChartGradientPalettes> mxLightPalettes; + std::unique_ptr<ChartGradientPalettes> mxDarkPalettes; + + ChartGradientVariation meHighlightedItemVariation; + ChartGradientType mnHighlightedItemType; + bool mbItemSelected; + + DECL_LINK(SelectLightPaletteHdl, weld::IconView&, bool); + DECL_LINK(SelectDarkPaletteHdl, weld::IconView&, bool); + sal_uInt32 GetSelectedItem(const std::unique_ptr<ChartGradientPalettes>& xPalettes); + + DECL_LINK(LightPaletteMouseMoveHdl, const MouseEvent&, bool); + DECL_LINK(DarkPaletteMouseMoveHdl, const MouseEvent&, bool); + void MouseMoveHdl(const std::unique_ptr<ChartGradientPalettes>& xPalettes, + ChartGradientVariation eHlItemVariation); + + void GrabFocus() override; + + void selectItem(ChartGradientVariation eVariation, ChartGradientType eType) const; + void initGradientPalettes() const; + +public: + ChartGradientPalettePopup(ChartGradientPaletteControl* pControl, weld::Widget* pParent); + ~ChartGradientPalettePopup() override; +}; +} // end namespace sidebar +} // end namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartGradientsPanel.cxx b/chart2/source/controller/sidebar/ChartGradientsPanel.cxx new file mode 100644 index 000000000000..eda311282d09 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartGradientsPanel.cxx @@ -0,0 +1,337 @@ +/* -*- 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/. + * + */ + +#include <sal/log.hxx> +#include <vcl/svapp.hxx> + +#include "ChartGradientsPanel.hxx" +#include "ChartGradientPaletteControl.hxx" + +#include <ChartGradientPaletteHelper.hxx> +#include <ChartController.hxx> +#include <ChartModel.hxx> +#include <DataSeries.hxx> +#include <Diagram.hxx> + +#include <com/sun/star/drawing/FillStyle.hpp> + +#include <sfx2/weldutils.hxx> +#include <svtools/toolbarmenu.hxx> + +#include <algorithm> + +using namespace css; + +namespace chart::sidebar +{ +namespace +{ +OUString getCID(const uno::Reference<frame::XModel>& xModel) +{ + const uno::Reference<frame::XController> xController(xModel->getCurrentController()); + uno::Reference<view::XSelectionSupplier> xSelectionSupplier(xController, uno::UNO_QUERY); + if (!xSelectionSupplier.is()) + return {}; + + uno::Any aAny = xSelectionSupplier->getSelection(); + if (!aAny.hasValue()) + { + // if no selection, default to diagram wall so sidebar can show some editable properties + if (auto* pController = dynamic_cast<ChartController*>(xController.get())) + { + pController->select( + uno::Any(ObjectIdentifier::createClassifiedIdentifier(OBJECTTYPE_PAGE, u""))); + xSelectionSupplier + = uno::Reference<css::view::XSelectionSupplier>(xController, uno::UNO_QUERY); + if (xSelectionSupplier.is()) + aAny = xSelectionSupplier->getSelection(); + } + + if (!aAny.hasValue()) + return {}; + } + + OUString aCID; + aAny >>= aCID; + return aCID; +} + +ChartGradientPaletteControl* +getChartGradientPaletteControl(const ToolbarUnoDispatcher& rToolBoxGradient) +{ + const uno::Reference<frame::XToolbarController> xController + = rToolBoxGradient.GetControllerForCommand(sUnoChartGradientPalette); + const auto pToolBoxLineStyleControl + = dynamic_cast<ChartGradientPaletteControl*>(xController.get()); + return pToolBoxLineStyleControl; +} +} // end unnamed namespace + +class GradientPaletteWrapper final : public IGradientPaletteHandler +{ +public: + GradientPaletteWrapper(rtl::Reference<ChartModel> mxModel, + ChartGradientPaletteControl* pControl); + + void updateModel(const rtl::Reference<ChartModel>& xModel); + void updateData() const; + + void createDiagramSnapshot() override; + void restoreOriginalDiagram() override; + + void select(ChartGradientVariation eVariant, ChartGradientType eType) override; + void apply(const ChartGradientPalette& rGradientPalette) override; + void setPreview(bool bFlag) override; + [[nodiscard]] std::shared_ptr<ChartGradientPaletteHelper> getHelper() const override; + [[nodiscard]] ChartGradientVariation getVariation() const override; + [[nodiscard]] ChartGradientType getType() const override; + +private: + rtl::Reference<ChartModel> mxModel; + ChartGradientPaletteControl* mpControl; + rtl::Reference<Diagram> mxDiagramSnapshot; + bool mbIsPreview; +}; + +GradientPaletteWrapper::GradientPaletteWrapper(rtl::Reference<ChartModel> xModel, + ChartGradientPaletteControl* pControl) + : mxModel(std::move(xModel)) + , mpControl(pControl) +{ +} + +void GradientPaletteWrapper::updateModel(const rtl::Reference<ChartModel>& xModel) +{ + mxModel = xModel; +} + +void GradientPaletteWrapper::updateData() const +{ + util::URL aUrl; + aUrl.Complete = sUnoChartGradientPalette; + + frame::FeatureStateEvent aEvent; + aEvent.FeatureURL = aUrl; + aEvent.IsEnabled = true; + + if (mpControl) + mpControl->statusChanged(aEvent); +} + +void GradientPaletteWrapper::createDiagramSnapshot() +{ + const rtl::Reference<Diagram> xDiagram = mxModel->getFirstChartDiagram(); + mxDiagramSnapshot = new ::chart::Diagram(*xDiagram); +} + +void GradientPaletteWrapper::restoreOriginalDiagram() +{ + if (mxDiagramSnapshot) + { + const rtl::Reference<Diagram> xDiagram = new ::chart::Diagram(*mxDiagramSnapshot); + // setDiagram didn't make a copy internally, so we need to pass a copy or + // the diagram snapshot would be modified on preview + mxModel->setFirstDiagram(xDiagram); + } +} + +void GradientPaletteWrapper::select(ChartGradientVariation eVariant, ChartGradientType eType) +{ + mxModel->clearColorPalette(); + mxModel->setGradientPalette(eVariant, eType); +} + +void GradientPaletteWrapper::apply(const ChartGradientPalette& rGradientPalette) +{ + mxModel->applyGradientPaletteToDataSeries(rGradientPalette); +} + +void GradientPaletteWrapper::setPreview(bool bFlag) { mbIsPreview = bFlag; } + +std::shared_ptr<ChartGradientPaletteHelper> GradientPaletteWrapper::getHelper() const +{ + return std::make_shared<ChartGradientPaletteHelper>( + mxModel->getDataSeriesColorsForGradient(mbIsPreview)); +} + +ChartGradientVariation GradientPaletteWrapper::getVariation() const +{ + return mxModel->getGradientPaletteVariation(); +} + +ChartGradientType GradientPaletteWrapper::getType() const +{ + return mxModel->getGradientPaletteType(); +} + +const std::vector<ObjectType> ChartGradientsPanel::maAcceptedTypes{ + OBJECTTYPE_PAGE, OBJECTTYPE_LEGEND, OBJECTTYPE_DIAGRAM, + OBJECTTYPE_DIAGRAM_WALL, OBJECTTYPE_DIAGRAM_FLOOR, OBJECTTYPE_DATA_SERIES, + OBJECTTYPE_DATA_POINT, +}; + +ChartGradientsPanel::ChartGradientsPanel(weld::Widget* pParent, + const uno::Reference<frame::XFrame>& rxFrame, + ChartController* pController) + : PanelLayout(pParent, "ChartGradientsPanel", "modules/schart/ui/sidebargradients.ui") + , mxModel(pController->getChartModel()) + , mxModifyListener(new ChartSidebarModifyListener(this)) + , mxSelectionListener(new ChartSidebarSelectionListener(this)) + , mbModelValid(true) + , mxGradientPaletteTB(m_xBuilder->weld_toolbar("gradientpalettetype")) + , mxGradientPaletteDispatch( + new ToolbarUnoDispatcher(*mxGradientPaletteTB, *m_xBuilder, rxFrame)) +{ + auto aAcceptedTypes(maAcceptedTypes); + mxSelectionListener->setAcceptedTypes(std::move(aAcceptedTypes)); + Initialize(); +} + +ChartGradientsPanel::~ChartGradientsPanel() +{ + doUpdateModel(nullptr); + mxGradientPaletteDispatch.reset(); + mxGradientPaletteTB.reset(); +} + +void ChartGradientsPanel::Initialize() +{ + mxModel->addModifyListener(mxModifyListener); + + uno::Reference<view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), + uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); + + ChartGradientPaletteControl* pGradientPaletteControl + = getChartGradientPaletteControl(*mxGradientPaletteDispatch); + assert(pGradientPaletteControl); + mxGradientPaletteWrapper + = std::make_shared<GradientPaletteWrapper>(mxModel, pGradientPaletteControl); + pGradientPaletteControl->setGradientPaletteHandler(mxGradientPaletteWrapper); + + updateData(); +} + +void ChartGradientsPanel::updateData() +{ + if (!mbModelValid) + return; + + const OUString aCID = getCID(mxModel); + if (aCID.isEmpty()) + return; + const ObjectType eType = ObjectIdentifier::getObjectType(aCID); + + if (std::find(maAcceptedTypes.begin(), maAcceptedTypes.end(), eType) == maAcceptedTypes.end()) + return; + + // if fill style is not a gradient clear palette selection + if (eType == OBJECTTYPE_DATA_SERIES || eType == OBJECTTYPE_DATA_POINT) + { + const uno::Reference<beans::XPropertySet> xPropSet + = ObjectIdentifier::getObjectPropertySet(aCID, mxModel); + if (!xPropSet.is()) + return; + + uno::Reference<beans::XPropertySetInfo> xInfo(xPropSet->getPropertySetInfo()); + if (!xInfo.is()) + return; + + SolarMutexGuard aGuard; + if (xInfo->hasPropertyByName("FillStyle")) + { + drawing::FillStyle eFillStyle = drawing::FillStyle_SOLID; + xPropSet->getPropertyValue("FillStyle") >>= eFillStyle; + if (eFillStyle != drawing::FillStyle_GRADIENT) + { + mxModel->clearGradientPalette(); + } + } + } + + mxGradientPaletteWrapper->updateData(); +} + +std::unique_ptr<PanelLayout> +ChartGradientsPanel::Create(weld::Widget* pParent, const uno::Reference<frame::XFrame>& rxFrame, + ChartController* pController) +{ + if (pParent == nullptr) + throw lang::IllegalArgumentException( + "no parent Window given to ChartGradientsPanel::Create", nullptr, 0); + if (!rxFrame.is()) + throw lang::IllegalArgumentException("no XFrame given to ChartGradientsPanel::Create", + nullptr, 1); + + return std::make_unique<ChartGradientsPanel>(pParent, rxFrame, pController); +} + +void ChartGradientsPanel::DataChanged(const DataChangedEvent& rEvent) +{ + PanelLayout::DataChanged(rEvent); + updateData(); +} + +void ChartGradientsPanel::HandleContextChange(const vcl::EnumContext&) { updateData(); } + +void ChartGradientsPanel::NotifyItemUpdate(sal_uInt16 /*nSID*/, SfxItemState /*eState*/, + const SfxPoolItem* /*pState*/) +{ +} + +void ChartGradientsPanel::modelInvalid() { mbModelValid = false; } + +void ChartGradientsPanel::doUpdateModel(const rtl::Reference<ChartModel>& xModel) +{ + if (mbModelValid) + { + mxModel->removeModifyListener(mxModifyListener); + + const uno::Reference<view::XSelectionSupplier> oldSelectionSupplier( + mxModel->getCurrentController(), uno::UNO_QUERY); + if (oldSelectionSupplier.is()) + { + oldSelectionSupplier->removeSelectionChangeListener(mxSelectionListener); + } + } + + mxModel = xModel; + mbModelValid = mxModel.is(); + + if (!mbModelValid) + return; + + mxGradientPaletteWrapper->updateModel(mxModel); + + mxModel->addModifyListener(mxModifyListener); + + uno::Reference<view::XSelectionSupplier> xSelectionSupplier(mxModel->getCurrentController(), + uno::UNO_QUERY); + if (xSelectionSupplier.is()) + xSelectionSupplier->addSelectionChangeListener(mxSelectionListener); +} + +void ChartGradientsPanel::updateModel(const uno::Reference<frame::XModel> xModel) +{ + const auto pModel = dynamic_cast<ChartModel*>(xModel.get()); + assert(!xModel || pModel); + doUpdateModel(pModel); +} + +void ChartGradientsPanel::selectionChanged(const bool bCorrectType) +{ + if (bCorrectType) + updateData(); +} + +} // end of namespace ::chart::sidebar + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/sidebar/ChartGradientsPanel.hxx b/chart2/source/controller/sidebar/ChartGradientsPanel.hxx new file mode 100644 index 000000000000..b2e322588f06 --- /dev/null +++ b/chart2/source/controller/sidebar/ChartGradientsPanel.hxx @@ -0,0 +1,88 @@ +/* -*- 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/. + * + */ + +#pragma once + +#include <com/sun/star/frame/XFrame.hpp> + +#include <sfx2/sidebar/ControllerItem.hxx> +#include <sfx2/sidebar/IContextChangeReceiver.hxx> +#include <sfx2/sidebar/SidebarModelUpdate.hxx> +#include <sfx2/sidebar/PanelLayout.hxx> +#include "ChartSidebarModifyListener.hxx" +#include "ChartSidebarSelectionListener.hxx" +#include <ChartGradientPalettes.hxx> + +class ToolbarUnoDispatcher; + +namespace chart +{ +class ChartController; + +namespace sidebar +{ +class GradientPaletteWrapper; + +class ChartGradientsPanel final : public PanelLayout, + public sfx2::sidebar::IContextChangeReceiver, + public sfx2::sidebar::ControllerItem::ItemUpdateReceiverInterface, + public sfx2::sidebar::SidebarModelUpdate, + public ChartSidebarModifyListenerParent, + public ChartSidebarSelectionListenerParent +{ +public: + static const std::vector<ObjectType> maAcceptedTypes; + + static std::unique_ptr<PanelLayout> + Create(weld::Widget* pParent, const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController); + + void DataChanged(const DataChangedEvent& rEvent) override; + + void HandleContextChange(const vcl::EnumContext& rContext) override; + + void NotifyItemUpdate(sal_uInt16 nSId, SfxItemState eState, const SfxPoolItem* pState) override; + + void GetControlState(const sal_uInt16 /*nSId*/, + boost::property_tree::ptree& /*rState*/) override + { + } + + // constructor/destructor + ChartGradientsPanel(weld::Widget* pParent, + const css::uno::Reference<css::frame::XFrame>& rxFrame, + ChartController* pController); + ~ChartGradientsPanel() override; + + void updateData() override; + void modelInvalid() override; + + void selectionChanged(bool bCorrectType) override; + + void updateModel(css::uno::Reference<css::frame::XModel> xModel) override; + +private: + rtl::Reference<ChartModel> mxModel; + css::uno::Reference<css::util::XModifyListener> mxModifyListener; + rtl::Reference<ChartSidebarSelectionListener> mxSelectionListener; + + bool mbModelValid; + + std::unique_ptr<weld::Toolbar> mxGradientPaletteTB; + std::unique_ptr<ToolbarUnoDispatcher> mxGradientPaletteDispatch; + std::shared_ptr<GradientPaletteWrapper> mxGradientPaletteWrapper; + + void Initialize(); + void doUpdateModel(const rtl::Reference<ChartModel>& xModel); +}; +} // end of namespace sidebar +} // end of namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartGradientPaletteHelper.hxx b/chart2/source/inc/ChartGradientPaletteHelper.hxx new file mode 100644 index 000000000000..c1dfb7dde905 --- /dev/null +++ b/chart2/source/inc/ChartGradientPaletteHelper.hxx @@ -0,0 +1,51 @@ +/* -*- 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/. + */ + +#pragma once + +#include "charttoolsdllapi.hxx" +#include <svx/svxdllapi.h> +#include <svx/ChartGradientVariation.hxx> +#include <docmodel/theme/Theme.hxx> +#include <tools/gen.hxx> + +#include <array> + +class OutputDevice; + +namespace chart +{ +class OOO_DLLPUBLIC_CHARTTOOLS ChartGradientPaletteHelper +{ +public: + static constexpr size_t PaletteSize = 6; + + ChartGradientPaletteHelper(const std::vector<Color>& aColorSet); + + basegfx::BGradient getGradientSample(ChartGradientVariation eVariation, + ChartGradientType eType) const; + ChartGradientPalette getGradientPalette(ChartGradientVariation eVariation, + ChartGradientType eType) const; + + static void renderGradientItem(OutputDevice* pDev, const tools::Rectangle& rDrawArea, + const basegfx::BGradient& rGradient, + bool bDrawItemBorder = false); + static void renderNoGradient(OutputDevice* pDev, const tools::Rectangle& rDrawArea); + +private: + const Color& getSampleColor() const; + static basegfx::BGradient createItem(const basegfx::BColorStops& rColorStops, + ChartGradientType eType); + + std::vector<Color> maColorSet; +}; + +} // end namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/ChartGradientPalettes.hxx b/chart2/source/inc/ChartGradientPalettes.hxx new file mode 100644 index 000000000000..5d96d3920330 --- /dev/null +++ b/chart2/source/inc/ChartGradientPalettes.hxx @@ -0,0 +1,56 @@ +/* -*- 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/. + */ + +#pragma once + +#include "charttoolsdllapi.hxx" + +#include <svx/ChartGradientVariation.hxx> +#include <svtools/valueset.hxx> + +namespace chart +{ +class OOO_DLLPUBLIC_CHARTTOOLS ChartGradientPalettes final +{ +public: + typedef Link<const MouseEvent&, bool> MouseEventHandler; + +private: + weld::Builder& mrBuilder; + std::unique_ptr<weld::IconView> mxIconView; + std::unique_ptr<weld::ScrolledWindow> mxWindow; + std::vector<basegfx::BGradient> maGradientSets; + sal_uInt16 mnHighlightedItemId; + MouseEventHandler maMouseMoveHdl; + +public: + ChartGradientPalettes(weld::Builder& rBuilder, const OUString& id, const OUString& winId); + + sal_uInt16 GetSelectedItemId(); + sal_uInt16 GetHighlightedItemId(); + void SetSelectHdl(const Link<weld::IconView&, bool>& rLink); + void SetNoSelection(); + void SelectItem(sal_uInt16 nItemId); + bool IsNoSelection(); + void GrabFocus(); + + void insert(basegfx::BGradient const& rGradientSet); + const basegfx::BGradient* getPalette(sal_uInt32 nItem) const; + void setMouseMoveHdl(const MouseEventHandler& rLink); + + void Fill(); + +private: + DECL_LINK(OnQueryTooltip, const weld::TreeIter&, OUString); + DECL_LINK(OnMouseMove, const MouseEvent&, bool); +}; + +} // end namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/chartview/ChartSfxItemIds.hxx b/chart2/source/inc/chartview/ChartSfxItemIds.hxx index 43341728d4da..eb19ba62441a 100644 --- a/chart2/source/inc/chartview/ChartSfxItemIds.hxx +++ b/chart2/source/inc/chartview/ChartSfxItemIds.hxx @@ -34,6 +34,7 @@ class SvxChartTextOrderItem; class SvxChartRegressItem; class SdrAngleItem; class SvxChartColorPaletteItem; +class SvxChartGradientPresetItem; // SCHATTR @@ -206,7 +207,12 @@ inline constexpr sal_uInt16 SCHATTR_COLOR_PALETTE_ST inline constexpr TypedWhichId<SvxChartColorPaletteItem> SCHATTR_COLOR_PALETTE (SCHATTR_COLOR_PALETTE_START); inline constexpr sal_uInt16 SCHATTR_COLOR_PALETTE_END (SCHATTR_COLOR_PALETTE); -inline constexpr sal_uInt16 SCHATTR_END (SCHATTR_COLOR_PALETTE_END); +inline constexpr sal_uInt16 SCHATTR_GRADIENT_PRESET_START (SCHATTR_COLOR_PALETTE_END + 1); +inline constexpr TypedWhichId<SvxChartGradientPresetItem> SCHATTR_GRADIENT_PRESET (SCHATTR_GRADIENT_PRESET_START); +inline constexpr sal_uInt16 SCHATTR_GRADIENT_PRESET_END (SCHATTR_GRADIENT_PRESET); + + +inline constexpr sal_uInt16 SCHATTR_END (SCHATTR_GRADIENT_PRESET_END); // values for Items diff --git a/chart2/source/model/main/ChartModel.cxx b/chart2/source/model/main/ChartModel.cxx index ada2b8f93dbc..18aee5fb8b14 100644 --- a/chart2/source/model/main/ChartModel.cxx +++ b/chart2/source/model/main/ChartModel.cxx @@ -32,8 +32,10 @@ #include <CloneHelper.hxx> #include <NameContainer.hxx> #include "UndoManager.hxx" +#include <docmodel/uno/UnoGradientTools.hxx> #include <ChartColorPaletteHelper.hxx> +#include <ChartGradientPaletteHelper.hxx> #include <ChartView.hxx> #include <PopupRequest.hxx> #include <ModifyListenerHelper.hxx> @@ -50,6 +52,7 @@ #include <svl/numformat.hxx> #include <svl/numuno.hxx> +#include <com/sun/star/awt/Gradient2.hpp> #include <com/sun/star/lang/DisposedException.hpp> #include <com/sun/star/view/XSelectionSupplier.hpp> #include <com/sun/star/embed/EmbedMapUnits.hpp> @@ -129,6 +132,8 @@ ChartModel::ChartModel(uno::Reference<uno::XComponentContext > xContext) , m_eColorPaletteType(ChartColorPaletteType::Unknown) , m_nColorPaletteIndex(0) , m_aStyles(new UnoChartStyle) + , m_eGradientPaletteVariation(ChartGradientVariation::Unknown) + , m_nGradientPaletteType(ChartGradientType::TopLeftToBottomRight) , mnStart(0) , mnEnd(0) { @@ -176,6 +181,8 @@ ChartModel::ChartModel( const ChartModel & rOther ) , m_xInternalDataProvider( rOther.m_xInternalDataProvider ) , m_eColorPaletteType(ChartColorPaletteType::Unknown) , m_nColorPaletteIndex(0) + , m_eGradientPaletteVariation(ChartGradientVariation::Unknown) + , m_nGradientPaletteType(ChartGradientType::TopLeftToBottomRight) , mnStart(rOther.mnStart) , mnEnd(rOther.mnEnd) { @@ -1508,6 +1515,96 @@ void ChartModel::onDocumentThemeChanged() } } +void ChartModel::setGradientPalette(ChartGradientVariation eVariation, ChartGradientType eType) +{ + m_eGradientPaletteVariation = eVariation; + m_nGradientPaletteType = eType; +} + +void ChartModel::clearGradientPalette() +{ + // Not reset the selected palette if user is just previewing a color + // for a data series or a data point + SfxViewShell* pCurrentShell = SfxViewShell::Current(); + if (pCurrentShell && pCurrentShell->IsLOKColorPreviewEnabled()) + return; + + setGradientPalette(ChartGradientVariation::Unknown, ChartGradientType::Invalid); + m_aGradientBaseColors.clear(); +} + +bool ChartModel::usesGradientPalette() const +{ + return m_eGradientPaletteVariation != ChartGradientVariation::Unknown; +} + +const std::vector<Color>& ChartModel::getDataSeriesColorsForGradient(bool bIsPreview) +{ + if (!m_aGradientBaseColors.empty() && (usesGradientPalette() || bIsPreview)) + return m_aGradientBaseColors; + + const rtl::Reference<Diagram> xDiagram = getFirstChartDiagram(); + if (!xDiagram.is()) + return m_aGradientBaseColors; + + const auto xDataSeriesArray = xDiagram->getDataSeries(); + for (size_t i = 0; i < xDataSeriesArray.size(); ++i) + { + Color aColor = ChartGradientPresetInvalidColor; + const uno::Reference<beans::XPropertySet> xPropSet = xDataSeriesArray[i]; + drawing::FillStyle eFillStyle = drawing::FillStyle_NONE; + if (xPropSet->getPropertyValue("FillStyle") >>= eFillStyle) + { + if (eFillStyle == drawing::FillStyle_SOLID) + { + xPropSet->getPropertyValue("FillColor") >>= aColor; + } + } + m_aGradientBaseColors.push_back(aColor); + } + return m_aGradientBaseColors; +} + +std::optional<ChartGradientPalette> ChartModel::getCurrentGradientPalette() const +{ + if (!usesGradientPalette()) + { + SAL_WARN("chart2", "ChartModel::getCurrentGradientPalette: no palette is in use"); + return std::nullopt; + } + + const std::vector<Color> aColorSet = const_cast<ChartModel*>(this)->getDataSeriesColorsForGradient(); + const ChartGradientPaletteHelper aGradientPaletteHelper(aColorSet); + return aGradientPaletteHelper.getGradientPalette(getGradientPaletteVariation(), getGradientPaletteType()); +} + + +void ChartModel::applyGradientPaletteToDataSeries(const ChartGradientPalette& rGradientPalette) +{ + const rtl::Reference<Diagram> xDiagram = getFirstChartDiagram(); + const auto xDataSeriesArray = xDiagram->getDataSeries(); + for (size_t i = 0; i < xDataSeriesArray.size(); ++i) + { + const uno::Reference<beans::XPropertySet> xPropSet = xDataSeriesArray[i]; + const size_t nPaletteIndex = i % rGradientPalette.size(); + xPropSet->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_GRADIENT)); + + // check if we have to skip this data set + const basegfx::BGradient& rGradient = rGradientPalette[nPaletteIndex]; + + if (rGradient.GetColorStops().empty()) + continue; + + awt::Gradient2 aPropGradient = model::gradient::createUnoGradient2(rGradient); + + // register a gradient and set it + css::uno::Any aGradientVal(aPropGradient); + OUString aNewName = PropertyHelper::addGradientUniqueNameToTable(aGradientVal, this, ""); + xPropSet->setPropertyValue(u"FillGradientName"_ustr, css::uno::Any(aNewName)); + } +} + + } // namespace chart extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * diff --git a/chart2/source/tools/ChartGradientPaletteHelper.cxx b/chart2/source/tools/ChartGradientPaletteHelper.cxx new file mode 100644 index 000000000000..cb180c7d99f0 --- /dev/null +++ b/chart2/source/tools/ChartGradientPaletteHelper.cxx @@ -0,0 +1,456 @@ +/* -*- 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/. + */ + +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <drawinglayer/attribute/fillgradientattribute.hxx> +#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> +#include <drawinglayer/geometry/viewinformation2d.hxx> +#include <drawinglayer/processor2d/processor2dtools.hxx> + +#include <ChartGradientPaletteHelper.hxx> +#include <ChartModel.hxx> +#include <sal/log.hxx> +#include <vcl/svapp.hxx> +#include <vcl/virdev.hxx> + +#include <frozen/bits/defines.h> +#include <frozen/bits/elsa_std.h> +#include <frozen/unordered_map.h> + +constexpr auto ChartGradientTypes + = frozen::make_unordered_map<ChartGradientType, ChartGradientProperties>({ + { ChartGradientType::TopLeftToBottomRight, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, -1350, 0, 0 } }, + { ChartGradientType::LinearDown, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, 1800, 0, 0 } }, + { ChartGradientType::TopRightToBottomLeft, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, 1350, 100, 0 } }, + { ChartGradientType::FromBottomRightCorner, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_RADIAL, 0, 100, 100 } }, + { ChartGradientType::FromBottomLeftCorner, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_RADIAL, 0, 0, 100 } }, + { ChartGradientType::LinearRight, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, -900, 0, 0 } }, + { ChartGradientType::FromCenter, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_RADIAL, 0, 50, 50 } }, + { ChartGradientType::LinearLeft, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, 900, 0, 0 } }, + { ChartGradientType::FromTopRightCorner, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_RADIAL, 0, 100, 0 } }, + { ChartGradientType::FromTopLeftCorner, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_RADIAL, 0, 0, 0 } }, + { ChartGradientType::BottomLeftToTopRight, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, -450, 0, 100 } }, + { ChartGradientType::LinearUp, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, 0, 0, 1000 } }, + { ChartGradientType::BottomRightToTopLeft, + ChartGradientProperties{ css::awt::GradientStyle::GradientStyle_LINEAR, 450, 100, 100 } }, + }); + +namespace chart +{ +constexpr tools::Long BORDER = ChartGradientPaletteLayout::ItemBorder; +constexpr tools::Long SIZE = ChartGradientPaletteLayout::ItemSize; + +namespace +{ +// Clamp helpers +double clamp01(double v) { return std::max(0.0, std::min(1.0, v)); } +double srgbToLinear(double u) +{ + u = clamp01(u); + if (u <= 0.04045) + return u / 12.92; + return std::pow((u + 0.055) / 1.055, 2.4); +} +double linearToSrgb(double u) +{ + if (u <= 0.0031308) + return 12.92 * u; + return 1.055 * std::pow(u, 1.0 / 2.4) - 0.055; +} + +struct RGBd +{ + double r, g, b; +}; + +RGBd hslToRgb(double hDeg, double s, double l) +{ + s = clamp01(s); + l = clamp01(l); + const double c = (1.0 - std::fabs(2.0 * l - 1.0)) * s; + double h = std::fmod(hDeg / 60.0, 6.0); + if (h < 0) + h += 6.0; + const double x = c * (1.0 - std::fabs(std::fmod(h, 2.0) - 1.0)); + + double r1 = 0, g1 = 0, b1 = 0; + if (0 <= h && h < 1) + { + r1 = c; + g1 = x; + b1 = 0; + } + else if (1 <= h && h < 2) + { + r1 = x; + g1 = c; + b1 = 0; + } + else if (2 <= h && h < 3) + { + r1 = 0; + g1 = c; + b1 = x; + } + else if (3 <= h && h < 4) + { + r1 = 0; + g1 = x; + b1 = c; + } + else if (4 <= h && h < 5) + { + r1 = x; + g1 = 0; + b1 = c; + } + else + { + r1 = c; + g1 = 0; + b1 = x; + } + + const double m = l - 0.5 * c; + return { clamp01(r1 + m), clamp01(g1 + m), clamp01(b1 + m) }; +} + +void rgbToHsl(const RGBd& rgb, double& hDeg, double& s, double& l) +{ + const double r = clamp01(rgb.r), g = clamp01(rgb.g), b = clamp01(rgb.b); + const double maxc = std::max(r, std::max(g, b)); + const double minc = std::min(r, std::min(g, b)); + const double d = maxc - minc; + l = 0.5 * (maxc + minc); + if (d == 0.0) + { + hDeg = 0.0; + s = 0.0; + return; + } + s = d / (1.0 - std::fabs(2.0 * l - 1.0)); + double h; + if (maxc == r) + { + h = (g - b) / d + (g < b ? 6.0 : 0.0); + } + else if (maxc == g) + { + h = (b - r) / d + 2.0; + } + else + { + h = (r - g) / d + 4.0; + } + hDeg = std::fmod(h * 60.0, 360.0); + if (hDeg < 0) + hDeg += 360.0; +} + +RGBd applyTintLinearRgb(const RGBd& rgb, double t) +{ + double rl = srgbToLinear(rgb.r); + double gl = srgbToLinear(rgb.g); + double bl = srgbToLinear(rgb.b); + rl = rl + (1.0 - rl) * t; + gl = gl + (1.0 - gl) * t; + bl = bl + (1.0 - bl) * t; + return { clamp01(linearToSrgb(rl)), clamp01(linearToSrgb(gl)), clamp01(linearToSrgb(bl)) }; +} + +RGBd applySatModHsl(const RGBd& rgb, double satMod) +{ + double h, s, l; + rgbToHsl(rgb, h, s, l); + s = clamp01(s * satMod); + return hslToRgb(h, s, l); +} + +// Convert tools::Color -> RGBd [0..1] +RGBd colorToRgbd(const Color& c) +{ + return { c.GetRed() / 255.0, c.GetGreen() / 255.0, c.GetBlue() / 255.0 }; +} + +basegfx::BColor toBColor(const RGBd& d) { return { clamp01(d.r), clamp01(d.g), clamp01(d.b) }; } + +// Compute 3 light-variation stops as basegfx::BColorStops (offsets 0.0, 0.5, 1.0) +basegfx::BColorStops ComputeLightVariationStops(const Color& rBase) +{ + // Tuned constants (match Python you validated) + static constexpr double TINTS[3] = { 0.235, 0.445, 0.660 }; // center→middle→edge + static constexpr double SATMOD = 1.6; // a:satMod + static constexpr double K_L = 0.16; // darkness-driven lift + static constexpr double L0_REF = 0.55; // small nudge above 0.5 + static constexpr double K_S = 0.07; // high-sat-driven lift + static constexpr double S0_REF = 0.80; // engage for high S + static constexpr double STOP_M[3] = { 1.65, 1.30, 0.95 }; // per-stop scaling + + // Base color as sRGB [0..1] + const RGBd baseRgb = colorToRgbd(rBase); + + // Base HSL (for L0/S0 gating) + double H0, S0, L0; + rgbToHsl(baseRgb, H0, S0, L0); + + basegfx::BColorStops stops; + stops.reserve(3); + + for (int i = 0; i < 3; ++i) + { + const double t = TINTS[i]; + const double mt = STOP_M[i]; + + // 1) Tint in linear-light sRGB toward white + RGBd tinted = applyTintLinearRgb(baseRgb, t); + + // 2) Post-tint lightness lift in HSL (no headroom term) + double h, s, l; + rgbToHsl(tinted, h, s, l); + const double darkness = std::max(0.0, L0_REF - L0); + const double satLift = std::max(0.0, S0_REF - S0); + if (darkness > 0.0 && t > 0.0) + { + l = clamp01(l + mt * (K_L * darkness) + K_S * satLift); + } + tinted = hslToRgb(h, s, l); + + // 3) Apply saturation modulation + RGBd finalRgb = applySatModHsl(tinted, SATMOD); + + // 4) Add stop (offsets 0.0, 0.5, 1.0) + const double offset = i == 0 ? 1.0 : (i == 1 ? 0.5 : 0.0); + stops.emplace_back(offset, toBColor(finalRgb)); + } + + return stops; +} + +// Shade toward black in linear-light sRGB +RGBd applyShadeLinearRgb(const RGBd& rgb, double shadeFactor) +{ + const double rl = srgbToLinear(rgb.r) * shadeFactor; + const double gl = srgbToLinear(rgb.g) * shadeFactor; + const double bl = srgbToLinear(rgb.b) * shadeFactor; + return { clamp01(linearToSrgb(rl)), clamp01(linearToSrgb(gl)), clamp01(linearToSrgb(bl)) }; +} + +// Given a base tools::Color, return the 3 “Dark variation” stops as basegfx::BColorStops +// at offsets 0.0 (center), 0.5 (mid), 1.0 (edge). +basegfx::BColorStops ComputeDarkVariationStops(const Color& rBase) +{ + // DrawingML parameters from the provided gradFill + static constexpr double kShade[3] = { 0.300, 0.675, 1.000 }; // center, middle, edge + static constexpr double kSatMod = 1.15; + + const RGBd base = colorToRgbd(rBase); + + basegfx::BColorStops stops; + stops.reserve(3); + + for (int i = 0; i < 3; ++i) + { + const double f = kShade[i]; + + // 1) shade in linear-light sRGB + RGBd shaded = applyShadeLinearRgb(base, f); + + // 2) saturation modulation in HSL + RGBd out = applySatModHsl(shaded, kSatMod); + + // 3) append stop at 0.0, 0.5, 1.0 + const double offset = i == 0 ? 1.0 : (i == 1 ? 0.5 : 0.0); + stops.emplace_back(offset, basegfx::BColor(out.r, out.g, out.b)); + } + + return stops; +} + +void drawBGradient(OutputDevice& rOutDev, const tools::Rectangle& rRect, + const basegfx::BGradient& rGrad) +{ + // 1) Rectangle → B2DRange (cover bottom/right pixel) + const double x0 = rRect.Left(); + const double y0 = rRect.Top(); + const double x1 = rRect.Right() + 1.0; + const double y1 = rRect.Bottom() + 1.0; + basegfx::B2DRange aRange(x0, y0, x1, y1); + + // 2) FillGradientAttribute expects: + // (css::awt::GradientStyle eStyle, double fBorder, double fOffsetX, + // double fOffsetY, double fAngleInRadians, const BColorStops&, sal_uInt16 nSteps) + const css::awt::GradientStyle eStyle = rGrad.GetGradientStyle(); // already UNO enum + const double fBorder = static_cast<double>(rGrad.GetBorder()) / 100.0; // normalize [0..1] + const double fOffsetX = rGrad.GetXOffset() / 100.0; + const double fOffsetY = rGrad.GetYOffset() / 100.0; + + // Convert Degree10 (tenths of degree) to radians + const double angleDeg10 = static_cast<sal_Int16>(rGrad.GetAngle()); // e.g. 900 => 90.0° + const double fAngleRad = (angleDeg10 / 10.0) * (M_PI / 180.0); // radians + + const basegfx::BColorStops& rStops = rGrad.GetColorStops(); + const sal_uInt16 nSteps = rGrad.GetSteps(); + + const drawinglayer::attribute::FillGradientAttribute aFillAttr( + eStyle, fBorder, fOffsetX, fOffsetY, fAngleRad, rStops, nSteps); + + // 3) Primitive container + drawinglayer::primitive2d::Primitive2DContainer aSeq; + aSeq.push_back(new drawinglayer::primitive2d::FillGradientPrimitive2D(aRange, aFillAttr)); + + // 4) Minimal view info and processor + const drawinglayer::geometry::ViewInformation2D aViewInfo; + const std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor( + drawinglayer::processor2d::createProcessor2DFromOutputDevice(rOutDev, aViewInfo)); + + if (pProcessor) + pProcessor->process(aSeq); +} +} // anonymous namespace end + +ChartGradientPaletteHelper::ChartGradientPaletteHelper(const std::vector<Color>& aColorSet) + : maColorSet(aColorSet) +{ +} + +const Color& ChartGradientPaletteHelper::getSampleColor() const +{ + for (const Color& rColor : maColorSet) + { + if (rColor != ChartGradientPresetInvalidColor) + return rColor; + } + return ChartGradientPresetDefaultColor; +} + +basegfx::BGradient ChartGradientPaletteHelper::createItem(const basegfx::BColorStops& rColorStops, + const ChartGradientType eType) +{ + const ChartGradientProperties& rType = ChartGradientTypes.at(eType); + + basegfx::BGradient aGradient(rColorStops, rType.style); + aGradient.SetAngle(Degree10(rType.angle)); + aGradient.SetXOffset(rType.offsetX); + aGradient.SetYOffset(rType.offsetY); + return aGradient; +} + +basegfx::BGradient +ChartGradientPaletteHelper::getGradientSample(const ChartGradientVariation eVariation, + const ChartGradientType eType) const +{ + switch (eVariation) + { + case ChartGradientVariation::LightVariation: + { + const auto aStopColors = ComputeLightVariationStops(getSampleColor()); + return createItem(aStopColors, eType); + } + case ChartGradientVariation::DarkVariation: + { + const auto aStopColors = ComputeDarkVariationStops(getSampleColor()); + return createItem(aStopColors, eType); + } + default: + SAL_WARN("chart2", "ChartGradientPaletteHelper::getGradientSample: unknown gradient " + "variation requested"); + return {}; + } +} + +ChartGradientPalette +ChartGradientPaletteHelper::getGradientPalette(const ChartGradientVariation eVariation, + const ChartGradientType eType) const +{ + ChartGradientPalette aPalette; + switch (eVariation) + { + case ChartGradientVariation::LightVariation: + for (const Color& rColor : maColorSet) + { + const basegfx::BColorStops aStopColors + = rColor == ChartGradientPresetInvalidColor + ? ComputeLightVariationStops(ChartGradientPresetDefaultColor) + : ComputeLightVariationStops(rColor); + + aPalette.push_back(createItem(aStopColors, eType)); + } + break; + case ChartGradientVariation::DarkVariation: + for (const Color& rColor : maColorSet) + { + const basegfx::BColorStops aStopColors + = rColor == ChartGradientPresetInvalidColor + ? ComputeDarkVariationStops(ChartGradientPresetDefaultColor) + : ComputeDarkVariationStops(rColor); + + aPalette.push_back(createItem(aStopColors, eType)); + } + break; + default: + SAL_WARN( + "chart2", + "ChartGradientPaletteHelper::getGradientPalette: unknown palette type requested"); + return {}; + } + return aPalette; +} + +void ChartGradientPaletteHelper::renderGradientItem(OutputDevice* pDev, + const tools::Rectangle& rDrawArea, + const basegfx::BGradient& rGradient, + const bool bDrawItemBorder) +{ + const Point aPosition = rDrawArea.GetPos(); + const Size aSize = rDrawArea.GetSize(); + + static constexpr Size aMin(2 * BORDER + SIZE, 2 * BORDER + SIZE); + + const tools::Long startX = (aSize.Width() - aMin.Width()) / 2.0; + const tools::Long startY = (aSize.Height() - aMin.Height()) / 2.0; + static constexpr tools::Long x = BORDER; + static constexpr tools::Long y = BORDER; + + if (bDrawItemBorder) + { + const tools::Rectangle aFrame(Point(aPosition.X() + startX, aPosition.Y() + startY), aMin); + pDev->SetFillColor(COL_LIGHTGRAY); + pDev->DrawRect(aFrame); + } + + pDev->SetFillColor(); + + const tools::Rectangle aRect(Point(aPosition.X() + startX + x, aPosition.Y() + startY + y), + Size(SIZE, SIZE)); + + drawBGradient(*pDev, aRect, rGradient); +} + +void ChartGradientPaletteHelper::renderNoGradient(OutputDevice* pDev, + const tools::Rectangle& rDrawArea) +{ + pDev->SetLineColor(COL_BLACK); + pDev->SetFillColor(Application::GetSettings().GetStyleSettings().GetFaceColor()); + pDev->DrawRect(rDrawArea); +} +} // end of namespace ::chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/ChartGradientPalettes.cxx b/chart2/source/tools/ChartGradientPalettes.cxx new file mode 100644 index 000000000000..824b6a6a835d --- /dev/null +++ b/chart2/source/tools/ChartGradientPalettes.cxx @@ -0,0 +1,128 @@ +/* -*- 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/. + */ + +#include <ChartGradientPalettes.hxx> +#include <ChartGradientPaletteHelper.hxx> +#include <vcl/event.hxx> +#include <vcl/virdev.hxx> + +namespace chart +{ +constexpr tools::Long BORDER = ChartGradientPaletteLayout::ItemBorder; +constexpr tools::Long SIZE = ChartGradientPaletteLayout::ItemSize; + +ChartGradientPalettes::ChartGradientPalettes(weld::Builder& rBuilder, const OUString& id, + const OUString& winId) + : mrBuilder(rBuilder) + , mxIconView(mrBuilder.weld_icon_view(id)) + , mxWindow(mrBuilder.weld_scrolled_window(winId)) + , mnHighlightedItemId(0) +{ + mxIconView->connect_mouse_move(LINK(this, ChartGradientPalettes, OnMouseMove)); + mxIconView->connect_query_tooltip(LINK(this, ChartGradientPalettes, OnQueryTooltip)); +} + +void ChartGradientPalettes::SetSelectHdl(const Link<weld::IconView&, bool>& rLink) +{ + mxIconView->connect_item_activated(rLink); +} + +sal_uInt16 ChartGradientPalettes::GetSelectedItemId() +{ + OUString sId = mxIconView->get_selected_id(); + if (sId.isEmpty()) + return 0; + return sId.toUInt32(); +} + +void ChartGradientPalettes::SelectItem(sal_uInt16 nItemId) { mxIconView->select(nItemId - 1); } + +void ChartGradientPalettes::SetNoSelection() { mxIconView->unselect_all(); } + +bool ChartGradientPalettes::IsNoSelection() { return mxIconView->get_selected_id().isEmpty(); } + +void ChartGradientPalettes::GrabFocus() { mxIconView->grab_focus(); } + +void ChartGradientPalettes::insert(basegfx::BGradient const& rGradientSet) +{ + maGradientSets.push_back(rGradientSet); +} + +const basegfx::BGradient* ChartGradientPalettes::getPalette(const sal_uInt32 nItem) const +{ + if (maGradientSets.size() > nItem) + { + return &maGradientSets[nItem]; + } + return nullptr; +} + +sal_uInt16 ChartGradientPalettes::GetHighlightedItemId() { return mnHighlightedItemId; } + +void ChartGradientPalettes::setMouseMoveHdl(const MouseEventHandler& rLink) +{ + maMouseMoveHdl = rLink; +} + +void ChartGradientPalettes::Fill() +{ + constexpr sal_uInt32 nColumns = 4; + static constexpr Size aSize(2 * BORDER + SIZE, 2 * BORDER + SIZE); + + sal_uInt32 nRows = maGradientSets.size() / nColumns; + if (maGradientSets.size() % nColumns != 0) + ++nRows; + + mxIconView->set_item_width(aSize.getWidth()); + mxIconView->set_size_request(nColumns * (aSize.getWidth() + 8), + nRows * (aSize.getHeight() + 8)); + + mxIconView->clear(); + + mxIconView->freeze(); + + VclPtr<VirtualDevice> pVDev = VclPtr<VirtualDevice>::Create(); + pVDev->SetOutputSizePixel(aSize); + + tools::Rectangle aDrawArea(0, 0, aSize.getWidth(), aSize.getHeight()); + for (size_t i = 0; i < maGradientSets.size(); ++i) + { + const basegfx::BGradient& rGradientSet = maGradientSets[i]; + pVDev->Erase(); + ChartGradientPaletteHelper::renderGradientItem(pVDev, aDrawArea, rGradientSet, true); + OUString sId = OUString::number(i + 1); + OUString sName = "Palette " + OUString::number(i + 1); + mxIconView->insert(-1, &sName, &sId, pVDev, nullptr); + } + + mxIconView->thaw(); + mnHighlightedItemId = 0; +} + +IMPL_LINK(ChartGradientPalettes, OnQueryTooltip, const weld::TreeIter&, rIter, OUString) +{ + OUString sId = mxIconView->get_id(rIter); + mnHighlightedItemId = sId.isEmpty() ? 0 : static_cast<sal_uInt16>(sId.toUInt32()); + + // Suppress actual tooltip text. + return {}; +} + +IMPL_LINK(ChartGradientPalettes, OnMouseMove, const MouseEvent&, rMouseEvent, bool) +{ + if (rMouseEvent.IsLeaveWindow()) + mnHighlightedItemId = 0; + if (maMouseMoveHdl.IsSet()) + return maMouseMoveHdl.Call(rMouseEvent); + return false; +} + +} // end namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/ChartItemPool.cxx b/chart2/source/view/main/ChartItemPool.cxx index 84903cd42609..3f06da026b09 100644 --- a/chart2/source/view/main/ChartItemPool.cxx +++ b/chart2/source/view/main/ChartItemPool.cxx @@ -28,6 +28,7 @@ #include <svx/svdpool.hxx> #include <svx/svx3ditems.hxx> #include <svx/ChartColorPaletteType.hxx> +#include <svx/ChartGradientVariation.hxx> #include <svl/intitem.hxx> #include <editeng/editeng.hxx> #include <editeng/brushitem.hxx> @@ -181,8 +182,8 @@ static ItemInfoPackage& getItemInfoPackageChart() { SCHATTR_DATA_TABLE_VERTICAL_BORDER, new SfxBoolItem(SCHATTR_DATA_TABLE_VERTICAL_BORDER, false), 0, SFX_ITEMINFOFLAG_NONE }, { SCHATTR_DATA_TABLE_OUTLINE, new SfxBoolItem(SCHATTR_DATA_TABLE_OUTLINE, false), 0, SFX_ITEMINFOFLAG_NONE }, { SCHATTR_DATA_TABLE_KEYS, new SfxBoolItem(SCHATTR_DATA_TABLE_KEYS, false), 0, SFX_ITEMINFOFLAG_NONE }, - { SCHATTR_COLOR_PALETTE, new SvxChartColorPaletteItem(ChartColorPaletteType::Unknown, 0, SCHATTR_COLOR_PALETTE), 0, SFX_ITEMINFOFLAG_NONE } - + { SCHATTR_COLOR_PALETTE, new SvxChartColorPaletteItem(ChartColorPaletteType::Unknown, 0, SCHATTR_COLOR_PALETTE), 0, SFX_ITEMINFOFLAG_NONE }, + { SCHATTR_GRADIENT_PRESET, new SvxChartGradientPresetItem(ChartGradientVariation::Unknown, ChartGradientType::Invalid, SCHATTR_GRADIENT_PRESET), 0, SFX_ITEMINFOFLAG_NONE } }}; virtual const ItemInfoStatic& getItemInfoStatic(size_t nIndex) const override { return maItemInfos[nIndex]; } diff --git a/chart2/uiconfig/ui/chartcolorpalettepopup.ui b/chart2/uiconfig/ui/chartcolorpalettepopup.ui index cf5265795d69..cdcec0cd0eb2 100644 --- a/chart2/uiconfig/ui/chartcolorpalettepopup.ui +++ b/chart2/uiconfig/ui/chartcolorpalettepopup.ui @@ -63,6 +63,7 @@ <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="shadow-type">in</property> + <property name="propagate-natural-width">True</property> <child> <object class="GtkIconView" id="colorful_palettes"> <property name="visible">True</property> @@ -114,6 +115,7 @@ <property name="hexpand">True</property> <property name="vexpand">True</property> <property name="shadow-type">in</property> + <property name="propagate-natural-width">True</property> <child> <object class="GtkIconView" id="monochromatic_palettes"> <property name="visible">True</property> diff --git a/chart2/uiconfig/ui/chartgradientpalettepopup.ui b/chart2/uiconfig/ui/chartgradientpalettepopup.ui new file mode 100644 index 000000000000..93bf05c53c3c --- /dev/null +++ b/chart2/uiconfig/ui/chartgradientpalettepopup.ui @@ -0,0 +1,155 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated with glade 3.40.0 --> +<interface domain="chart"> + <requires lib="gtk+" version="3.20"/> + <object class="GtkTreeStore" id="liststore1"> + <columns> + <!-- column-name pixbuf --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkTreeStore" id="liststore2"> + <columns> + <!-- column-name pixbuf --> + <column type="GdkPixbuf"/> + <!-- column-name id --> + <column type="gchararray"/> + </columns> + </object> + <object class="GtkPopover" id="GradientPaletteWindow"> + <property name="can-focus">False</property> + <child> + <object class="GtkBox" id="container"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="orientation">vertical</property> + <property name="spacing">6</property> + <child> + <!-- n-columns=1 n-rows=4 --> + <object class="GtkGrid" id="grid1"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="border-width">6</property> + <property name="row-spacing">3</property> + <property name="column-spacing">6</property> + <child> + <object class="GtkLabel" id="label1"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="margin-bottom">1</property> + <property name="label" translatable="yes" context="chartgradientpalettepopup|lightwin">Light Variations</property> + <attributes> + <attribute name="weight" value="bold"/> + </attributes> + <accessibility> + <relation type="label-for" target="light_palettes"/> + </accessibility> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">0</property> + </packing> + </child> + <child> + <object class="GtkScrolledWindow" id="lightwin"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="shadow-type">in</property> + <child> + <object class="GtkIconView" id="light_palettes"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="margin">0</property> + <property name="hexpand">True</property> + <property name="vexpand">True</property> + <property name="model">liststore1</property> + <property name="pixbuf-column">0</property> +<!-- <property name="columns">2</property>--> + <property name="row-spacing">0</property> + <property name="column-spacing">0</property> + <property name="item-padding">4</property> -e ... etc. - the rest is truncated
