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

Reply via email to