cui/qa/uitest/dialogs/chardlg.py       |    4 
 cui/source/tabpages/tpcolor.cxx        |    8 +
 include/svx/PaletteManager.hxx         |   25 ++++-
 include/svx/strings.hrc                |   15 +--
 svx/source/tbxctrls/PaletteManager.cxx |  155 +++++++++++++++++++++++++++------
 svx/source/tbxctrls/tbcontrl.cxx       |   14 +-
 6 files changed, 174 insertions(+), 47 deletions(-)

New commits:
commit e6215c7233c0fb437a81b51c8a8a30bb53eef65f
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Thu May 25 00:53:22 2023 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Thu Jun 1 18:25:58 2023 +0200

    tdf#153361 improve theme color generation in color picker
    
    The theme color generator needs to take color luminocity into
    account, so that the very dark or very light colors are properly
    shaded. Otherwise a too dark color will generate a too dark (almost
    black) color variant, or a too light a too light (almost white)
    color variant. However those colors aren't useful.
    
    Change-Id: Id803a8f6f1a79cbc822ed2d7faca9bec228c0188
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152237
    Tested-by: Tomaž Vajngerl <qui...@gmail.com>
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/cui/qa/uitest/dialogs/chardlg.py b/cui/qa/uitest/dialogs/chardlg.py
index 4a756cf6c979..85e60f766238 100644
--- a/cui/qa/uitest/dialogs/chardlg.py
+++ b/cui/qa/uitest/dialogs/chardlg.py
@@ -115,8 +115,8 @@ class Test(UITestCase):
             # AssertionError: 10000 != 2000
             # i.e. the effects where not applied, luminance modulation was the 
default instead of a
             # custom value.
-            self.assertEqual(portion.CharColorLumMod, 2000)
-            self.assertEqual(portion.CharColorLumOff, 8000)
+            self.assertEqual(portion.CharColorLumMod, 5000)
+            self.assertEqual(portion.CharColorLumOff, 5000)
 
     def testSvxCharEffectsPageWriter(self):
         # Start Writer.
diff --git a/cui/source/tabpages/tpcolor.cxx b/cui/source/tabpages/tpcolor.cxx
index 470b1c13a866..bdefcf10114d 100644
--- a/cui/source/tabpages/tpcolor.cxx
+++ b/cui/source/tabpages/tpcolor.cxx
@@ -522,7 +522,13 @@ IMPL_LINK(SvxColorTabPage, SelectValSetHdl_Impl, 
ValueSet*, pValSet, void)
     aNamedColor.m_aColor = aColor;
     if (bThemePaletteSelected)
     {
-        PaletteManager::GetThemeIndexLumModOff(nPos, 
aNamedColor.m_nThemeIndex, aNamedColor.m_nLumMod, aNamedColor.m_nLumOff);
+        sal_uInt16 nThemeIndex;
+        sal_uInt16 nEffectIndex;
+        if (PaletteManager::GetThemeAndEffectIndex(nPos, nThemeIndex, 
nEffectIndex))
+        {
+            aNamedColor.m_nThemeIndex = nThemeIndex;
+            maPaletteManager.GetLumModOff(nThemeIndex, nEffectIndex, 
aNamedColor.m_nLumMod, aNamedColor.m_nLumOff);
+        }
     }
 
     ChangeColor(aNamedColor, false);
diff --git a/include/svx/PaletteManager.hxx b/include/svx/PaletteManager.hxx
index c6d1712a12f4..37d22b92ec64 100644
--- a/include/svx/PaletteManager.hxx
+++ b/include/svx/PaletteManager.hxx
@@ -32,6 +32,26 @@ namespace com::sun::star::uno { class XComponentContext; }
 namespace svx { class ToolboxButtonColorUpdaterBase; }
 namespace weld { class Window; }
 
+enum class ThemePaletteColorType
+{
+    Black,
+    White,
+    Low,
+    High,
+    Normal
+};
+
+struct ThemePaletteData
+{
+    ThemePaletteColorType meType = ThemePaletteColorType::Normal;
+    Color maColor;
+};
+
+struct ThemePaletteCollection
+{
+    std::array<ThemePaletteData, 12> maData;
+};
+
 class SVXCORE_DLLPUBLIC PaletteManager
 {
     const sal_uInt16        mnMaxRecentColors;
@@ -49,6 +69,7 @@ class SVXCORE_DLLPUBLIC PaletteManager
     ColorSelectFunction maColorSelectFunction;
 
     std::unique_ptr<SvColorDialog> m_pColorDlg;
+    std::optional<ThemePaletteCollection> moThemePaletteCollection;
 
     PaletteManager(const PaletteManager* pClone);
 public:
@@ -79,8 +100,8 @@ public:
 
     PaletteManager* Clone() const;
 
-    static void GetThemeIndexLumModOff(sal_uInt16 nItemId, sal_Int16& 
rThemeIndex,
-                                       sal_Int16& rLumMod, sal_Int16& rLumOff);
+    static bool GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16& 
rThemeIndex, sal_uInt16& rEffectIndex);
+    bool GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, sal_Int16& 
rLumMod, sal_Int16& rLumOff);
 
     static void DispatchColorCommand(const OUString& aCommand, const 
NamedColor& rColor);
 };
diff --git a/include/svx/strings.hrc b/include/svx/strings.hrc
index e0573c485d99..249d01060a39 100644
--- a/include/svx/strings.hrc
+++ b/include/svx/strings.hrc
@@ -1120,10 +1120,10 @@
 #define RID_SVXSTR_DOC_COLORS                               
NC_("RID_SVXSTR_DOC_COLORS", "Document colors")
 #define RID_SVXSTR_THEME_COLORS                             
NC_("RID_SVXSTR_THEME_COLORS", "Theme colors")
 #define RID_SVXSTR_DOC_COLOR_PREFIX                         
NC_("RID_SVXSTR_DOC_COLOR_PREFIX", "Document Color")
-#define RID_SVXSTR_THEME_COLOR1                             
NC_("RID_SVXSTR_THEME_COLOR1", "Background - Dark 1")
-#define RID_SVXSTR_THEME_COLOR2                             
NC_("RID_SVXSTR_THEME_COLOR2", "Text - Light 1")
-#define RID_SVXSTR_THEME_COLOR3                             
NC_("RID_SVXSTR_THEME_COLOR3", "Background - Dark 2")
-#define RID_SVXSTR_THEME_COLOR4                             
NC_("RID_SVXSTR_THEME_COLOR4", "Text - Light 2")
+#define RID_SVXSTR_THEME_COLOR1                             
NC_("RID_SVXSTR_THEME_COLOR1", "Dark 1")
+#define RID_SVXSTR_THEME_COLOR2                             
NC_("RID_SVXSTR_THEME_COLOR2", "Light 1")
+#define RID_SVXSTR_THEME_COLOR3                             
NC_("RID_SVXSTR_THEME_COLOR3", "Dark 2")
+#define RID_SVXSTR_THEME_COLOR4                             
NC_("RID_SVXSTR_THEME_COLOR4", "Light 2")
 #define RID_SVXSTR_THEME_COLOR5                             
NC_("RID_SVXSTR_THEME_COLOR5", "Accent 1")
 #define RID_SVXSTR_THEME_COLOR6                             
NC_("RID_SVXSTR_THEME_COLOR6", "Accent 2")
 #define RID_SVXSTR_THEME_COLOR7                             
NC_("RID_SVXSTR_THEME_COLOR7", "Accent 3")
@@ -1132,11 +1132,8 @@
 #define RID_SVXSTR_THEME_COLOR10                            
NC_("RID_SVXSTR_THEME_COLOR10", "Accent 6")
 #define RID_SVXSTR_THEME_COLOR11                            
NC_("RID_SVXSTR_THEME_COLOR11", "Hyperlink")
 #define RID_SVXSTR_THEME_COLOR12                            
NC_("RID_SVXSTR_THEME_COLOR12", "Followed Hyperlink")
-#define RID_SVXSTR_THEME_EFFECT1                            
NC_("RID_SVXSTR_THEME_EFFECT1", "%1, 80% Lighter")
-#define RID_SVXSTR_THEME_EFFECT2                            
NC_("RID_SVXSTR_THEME_EFFECT2", "%1, 60% Lighter")
-#define RID_SVXSTR_THEME_EFFECT3                            
NC_("RID_SVXSTR_THEME_EFFECT3", "%1, 40% Lighter")
-#define RID_SVXSTR_THEME_EFFECT4                            
NC_("RID_SVXSTR_THEME_EFFECT4", "%1, 25% Darker")
-#define RID_SVXSTR_THEME_EFFECT5                            
NC_("RID_SVXSTR_THEME_EFFECT5", "%1, 50% Darker")
+#define RID_SVXSTR_THEME_EFFECT_LIGHTER                     
NC_("RID_SVXSTR_THEME_EFFECT_LIGHTER", "$THEME_NAME, $PERCENTAGE% Lighter")
+#define RID_SVXSTR_THEME_EFFECT_DARKER                      
NC_("RID_SVXSTR_THEME_EFFECT_DARKER", "$THEME_NAME, $PERCENTAGE% Darker")
 
 #define RID_SVX_EXTRUSION_BAR                               
NC_("RID_SVX_EXTRUSION_BAR", "Extrusion")
 #define RID_SVXSTR_UNDO_APPLY_EXTRUSION_ON_OFF              
NC_("RID_SVXSTR_UNDO_APPLY_EXTRUSION_ON_OFF", "Apply Extrusion On/Off")
diff --git a/svx/source/tbxctrls/PaletteManager.cxx 
b/svx/source/tbxctrls/PaletteManager.cxx
index 26df330b9501..1f3ab3345359 100644
--- a/svx/source/tbxctrls/PaletteManager.cxx
+++ b/svx/source/tbxctrls/PaletteManager.cxx
@@ -17,9 +17,9 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
-#include <memory>
 #include <svx/PaletteManager.hxx>
 
+#include <basegfx/color/bcolortools.hxx>
 #include <comphelper/propertyvalue.hxx>
 #include <tools/urlobj.hxx>
 #include <osl/file.hxx>
@@ -33,8 +33,6 @@
 #include <vcl/svapp.hxx>
 #include <vcl/settings.hxx>
 #include <comphelper/sequence.hxx>
-#include <stack>
-#include <set>
 #include <officecfg/Office/Common.hxx>
 #include <com/sun/star/frame/XDispatchProvider.hpp>
 #include <com/sun/star/frame/XDispatch.hpp>
@@ -48,15 +46,32 @@
 
 #include <palettes.hxx>
 
+#include <memory>
+#include <array>
+#include <stack>
+#include <set>
+
 namespace
 {
-// Luminance modulation for the 6 effect presets.
-// 10000 is the default.
-constexpr const std::array<sal_Int16, 6> g_aLumMods = { 10000, 2000, 4000, 
6000, 7500, 5000 };
+constexpr const std::array<sal_Int16, 6> g_aPercentBlack = {      0,    50,    
35,    25,    15,     5 };
+constexpr const std::array<sal_Int16, 6> g_aLumModsBlack = { 10'000, 5'000, 
6'500, 7'500, 8'500, 9'500 };
+constexpr const std::array<sal_Int16, 6> g_aLumOffsBlack = {      0, 5'000, 
3'500, 2'500, 1'500, 0'500 };
+
+constexpr const std::array<sal_Int16, 6> g_aPercentLow = {      0,    90,    
75,    50,    25,    10 };
+constexpr const std::array<sal_Int16, 6> g_aLumModsLow = { 10'000, 1'000, 
2'500, 5'000, 7'500, 9'000 };
+constexpr const std::array<sal_Int16, 6> g_aLumOffsLow = {      0, 9'000, 
7'500, 5'000, 2'500, 1'000 };
+
+constexpr const std::array<sal_Int16, 6> g_aPercent = {      0,    80,    60,  
  40,   -25,   -50 };
+constexpr const std::array<sal_Int16, 6> g_aLumMods = { 10'000, 2'000, 4'000, 
6'000, 7'500, 5'000 };
+constexpr const std::array<sal_Int16, 6> g_aLumOffs = {      0, 8'000, 6'000, 
4'000,     0,     0 };
 
-// Luminance offset for the 6 effect presets.
-// 0 is the default.
-constexpr const std::array<sal_Int16, 6> g_aLumOffs = { 0, 8000, 6000, 4000, 
0, 0 };
+constexpr const std::array<sal_Int16, 6> g_aPercentHigh = {      0,   -10,   
-25,   -50,   -75,   -90 };
+constexpr const std::array<sal_Int16, 6> g_aLumModsHigh = { 10'000, 9'000, 
7'500, 5'000, 2'500, 1'000 };
+constexpr const std::array<sal_Int16, 6> g_aLumOffsHigh = {      0,     0,     
0,     0,     0,     0 };
+
+constexpr const std::array<sal_Int16, 6> g_aPercentWhite = {      0,    -5,   
-15,   -25,   -35,   -50 };
+constexpr const std::array<sal_Int16, 6> g_aLumModsWhite = { 10'000, 9'500, 
8'500, 7'500, 6'500, 5'000 };
+constexpr const std::array<sal_Int16, 6> g_aLumOffsWhite = {      0,     0,    
 0,     0,     0,     0 };
 }
 
 PaletteManager::PaletteManager() :
@@ -66,6 +81,7 @@ PaletteManager::PaletteManager() :
     mnColorCount(0),
     mpBtnUpdater(nullptr),
     maColorSelectFunction(PaletteManager::DispatchColorCommand)
+
 {
     SfxObjectShell* pDocSh = SfxObjectShell::Current();
     if(pDocSh)
@@ -165,19 +181,53 @@ bool PaletteManager::IsThemePaletteSelected() const
     return mnCurrentPalette == mnNumOfPalettes - 2;
 }
 
-void PaletteManager::GetThemeIndexLumModOff(sal_uInt16 nItemId, sal_Int16& 
rThemeIndex,
-                                            sal_Int16& rLumMod, sal_Int16& 
rLumOff)
+bool PaletteManager::GetThemeAndEffectIndex(sal_uInt16 nItemId, sal_uInt16& 
rThemeIndex, sal_uInt16& rEffectIndex)
 {
-    // Each column is the same color with different effects.
+     // Each column is the same color with different effects.
     rThemeIndex = nItemId % 12;
 
-    // Each row is the same effect with different colors.
-    rLumMod = g_aLumMods[nItemId / 12];
-    rLumOff = g_aLumOffs[nItemId / 12];
+    rEffectIndex = nItemId / 12;
+    if (rEffectIndex > 5)
+        return false;
+    return true;
+}
+
+bool PaletteManager::GetLumModOff(sal_uInt16 nThemeIndex, sal_uInt16 nEffect, 
sal_Int16& rLumMod, sal_Int16& rLumOff)
+{
+    if (!moThemePaletteCollection)
+        return false;
+
+    auto const& aThemeColorData = 
moThemePaletteCollection->maData[nThemeIndex];
+
+    switch (aThemeColorData.meType)
+    {
+        case ThemePaletteColorType::Black:
+            rLumMod = g_aLumModsBlack[nEffect];
+            rLumOff = g_aLumOffsBlack[nEffect];
+            break;
+        case ThemePaletteColorType::White:
+            rLumMod = g_aLumModsWhite[nEffect];
+            rLumOff = g_aLumOffsWhite[nEffect];
+            break;
+        case ThemePaletteColorType::Low:
+            rLumMod = g_aLumModsLow[nEffect];
+            rLumOff = g_aLumOffsLow[nEffect];
+            break;
+        case ThemePaletteColorType::High:
+            rLumMod = g_aLumModsHigh[nEffect];
+            rLumOff = g_aLumOffsHigh[nEffect];
+            break;
+        case ThemePaletteColorType::Normal:
+            rLumMod = g_aLumMods[nEffect];
+            rLumOff = g_aLumOffs[nEffect];
+            break;
+    }
+    return true;
 }
 
 void PaletteManager::ReloadColorSet(SvxColorValueSet &rColorSet)
 {
+    moThemePaletteCollection.reset();
     if( mnCurrentPalette == 0)
     {
         rColorSet.Clear();
@@ -201,13 +251,7 @@ void PaletteManager::ReloadColorSet(SvxColorValueSet 
&rColorSet)
             rColorSet.Clear();
             if (aColors.size() >= 12)
             {
-                std::vector<OUString> aEffectNames = {
-                    SvxResId(RID_SVXSTR_THEME_EFFECT1),  
SvxResId(RID_SVXSTR_THEME_EFFECT2),
-                    SvxResId(RID_SVXSTR_THEME_EFFECT3),  
SvxResId(RID_SVXSTR_THEME_EFFECT4),
-                    SvxResId(RID_SVXSTR_THEME_EFFECT5),
-                };
-
-                std::vector<OUString> aColorNames = {
+                const std::array<OUString, 12> aColorNames = {
                     SvxResId(RID_SVXSTR_THEME_COLOR1),  
SvxResId(RID_SVXSTR_THEME_COLOR2),
                     SvxResId(RID_SVXSTR_THEME_COLOR3),  
SvxResId(RID_SVXSTR_THEME_COLOR4),
                     SvxResId(RID_SVXSTR_THEME_COLOR5),  
SvxResId(RID_SVXSTR_THEME_COLOR6),
@@ -217,22 +261,77 @@ void PaletteManager::ReloadColorSet(SvxColorValueSet 
&rColorSet)
                 };
 
                 sal_uInt16 nItemId = 0;
+
+                moThemePaletteCollection = ThemePaletteCollection();
+                for (size_t nColor = 0; nColor < aColorNames.size(); ++nColor)
+                {
+                    Color aColor = aColors[nColor];
+                    basegfx::BColor aBColor = 
basegfx::utils::rgb2hsl(aColor.getBColor());
+                    double aLuminanceValue = aBColor.getBlue() * 255.0;
+                    moThemePaletteCollection->maData[nColor].maColor = aColor;
+
+                    if (aLuminanceValue < 0.5)
+                        moThemePaletteCollection->maData[nColor].meType = 
ThemePaletteColorType::Black;
+                    else if (aLuminanceValue > 254.5)
+                        moThemePaletteCollection->maData[nColor].meType = 
ThemePaletteColorType::White;
+                    else if (aLuminanceValue < 50.5)
+                        moThemePaletteCollection->maData[nColor].meType = 
ThemePaletteColorType::Low;
+                    else if (aLuminanceValue > 203.5)
+                        moThemePaletteCollection->maData[nColor].meType = 
ThemePaletteColorType::High;
+                    else
+                        moThemePaletteCollection->maData[nColor].meType = 
ThemePaletteColorType::Normal;
+                }
+
                 // Each row is one effect type (no effect + each type).
-                for (size_t nEffect = 0; nEffect < aEffectNames.size() + 1; 
++nEffect)
+                for (size_t nEffect : {0, 1, 2, 3, 4, 5})
                 {
                     // Each column is one color type.
                     for (size_t nColor = 0; nColor < aColorNames.size(); 
++nColor)
                     {
-                        Color aColor = aColors[nColor];
-                        aColor.ApplyLumModOff(g_aLumMods[nEffect], 
g_aLumOffs[nEffect]);
+                        auto const& aThemeColorData = 
moThemePaletteCollection->maData[nColor];
+                        Color aColor = aThemeColorData.maColor;
+                        sal_Int16 nColorTemplateValue = 0;
+                        switch (aThemeColorData.meType)
+                        {
+                            case ThemePaletteColorType::Black:
+                                nColorTemplateValue = g_aPercentBlack[nEffect];
+                                break;
+                            case ThemePaletteColorType::White:
+                                nColorTemplateValue = g_aPercentWhite[nEffect];
+                                break;
+                            case ThemePaletteColorType::Low:
+                                nColorTemplateValue = g_aPercentLow[nEffect];
+                                break;
+                            case ThemePaletteColorType::High:
+                                nColorTemplateValue = g_aPercentHigh[nEffect];
+                                break;
+                            case ThemePaletteColorType::Normal:
+                                nColorTemplateValue = g_aPercent[nEffect];
+                                break;
+                        }
+
+                        sal_Int16 nLumMod = 10'000;
+                        sal_Int16 nLumOff = 0;
+                        GetLumModOff(nColor, nEffect, nLumMod, nLumOff);
+                        aColor.ApplyLumModOff(nLumMod, nLumOff);
+
                         OUString aColorName;
-                        if (nEffect == 0)
+                        if (nColorTemplateValue > 0)
                         {
-                            aColorName = aColorNames[nColor];
+                            OUString aTemplate = 
SvxResId(RID_SVXSTR_THEME_EFFECT_LIGHTER);
+                            aColorName = aTemplate.replaceAll("$THEME_NAME", 
aColorNames[nColor]);
+                            aColorName = aColorName.replaceAll("$PERCENTAGE", 
OUString::number(std::abs(nColorTemplateValue)));
+
+                        }
+                        else if (nColorTemplateValue < 0)
+                        {
+                            OUString aTemplate = 
SvxResId(RID_SVXSTR_THEME_EFFECT_DARKER);
+                            aColorName = aTemplate.replaceAll("$THEME_NAME", 
aColorNames[nColor]);
+                            aColorName = aColorName.replaceAll("$PERCENTAGE", 
OUString::number(std::abs(nColorTemplateValue)));
                         }
                         else
                         {
-                            aColorName = aEffectNames[nEffect - 
1].replaceAll("%1", aColorNames[nColor]);
+                            aColorName = aColorNames[nColor];
                         }
                         rColorSet.InsertItem(nItemId++, aColor, aColorName);
                     }
diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx
index c27216cdedd5..eb7ab2e61410 100644
--- a/svx/source/tbxctrls/tbcontrl.cxx
+++ b/svx/source/tbxctrls/tbcontrl.cxx
@@ -2236,14 +2236,18 @@ IMPL_LINK(ColorWindow, SelectHdl, ValueSet*, pColorSet, 
void)
     bool bThemePaletteSelected = mxPaletteManager->IsThemePaletteSelected();
     sal_uInt16 nSelectedItemId = pColorSet->GetSelectedItemId();
 
-    maMenuButton.set_inactive();
-
     if (bThemePaletteSelected)
     {
-        PaletteManager::GetThemeIndexLumModOff(nSelectedItemId, 
aNamedColor.m_nThemeIndex,
-                                               aNamedColor.m_nLumMod,
-                                               aNamedColor.m_nLumOff);
+        sal_uInt16 nThemeIndex;
+        sal_uInt16 nEffectIndex;
+        if (PaletteManager::GetThemeAndEffectIndex(nSelectedItemId, 
nThemeIndex, nEffectIndex))
+        {
+            aNamedColor.m_nThemeIndex = nThemeIndex;
+            mxPaletteManager->GetLumModOff(nThemeIndex, nEffectIndex, 
aNamedColor.m_nLumMod, aNamedColor.m_nLumOff);
+        }
     }
+
+    maMenuButton.set_inactive();
     aColorSelectFunction(sCommand, aNamedColor);
 }
 

Reply via email to