luebking / virtuality

Qt4/Qt5 widget style
GNU General Public License v2.0
19 stars 6 forks source link

Invert icons in toolbar if toolbar is inverted #31

Open beojan opened 8 years ago

beojan commented 8 years ago

With KF5, icon themes are using monochrome toolbar icons. Because these icons are also used in the main window in some applications (e.g, kwrite's find bar), when the toolbar is inverted, neither the light background version nor the dark background version of the themes are satisfactory.

Can you invert the icons if the toolbar is inverted, so the light version can be used?

luebking commented 8 years ago

With KF5, icon themes "Icon theme" - Breeze in particular. And it's heavily critized for its complete lack of inner contrast.

Can you invert the icons if the toolbar is inverted To a certain degree. You probably noticed the monochromatically tinted hover effect. This can applied with any (the foreground of the toolbar) color, but a) There's nothing such as a perfect monochromatizing. b) It of course implies some CPU overhead.

Assuming (b) is of no major concern, the remaining problem is (a) You might have noticed that not all breeze icons are strictly black/white. Sometimes colored variants will just show up in the toolbar and sometimes the toolbar icon is actually colored (usually red)

This is a qnd hack to do this (it's not configurable and not very efficient either, but you can see the result)

diff --git a/toolbars.cpp b/toolbars.cpp
index a1a75da..7b0f6b4 100644
--- a/toolbars.cpp
+++ b/toolbars.cpp
@@ -169,6 +169,7 @@ Style::drawToolButtonLabel(const QStyleOption *option, QPainter *painter, const
         const int style = config.btn.tool.disabledStyle;
 //         const QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
         pm = toolbutton->icon.pixmap(RECT.size().boundedTo(pmSize), isEnabled || style ? QIcon::Normal : QIcon::Disabled, QIcon::Off);
+        pm = FX::tintedIcon(pm, 1, 1, text);
 #if 0   // this is -in a way- the way it should be done..., but KIconLoader gives a shit on this or anything else
         if (!isEnabled)
             pm = generatedIconPixmap(QIcon::Disabled, pm, toolbutton);
beojan commented 8 years ago

This seems to work with Breeze, but weirdly, not with Papirus (icons in toolbar are completely dark).

luebking commented 8 years ago

Papirus With what? Link?

beojan commented 8 years ago

https://github.com/varlesh/papirus-pack-kde/tree/master/icons

luebking commented 8 years ago

Ah, ok - I figured it would be some icon theme.

As mentione, such as a perfect monochromatizing does not exist, the algorithm I implemented favors bright colors (for tinting, dark colors rather turn translucent - the thing was done for icon highlighting)

The icon theme uses fully back icons with a 50% opacity where this fails miserably - the icons turn entirely transparent.

diff --git a/FX.cpp b/FX.cpp
index 95eed4b..118f727 100644
--- a/FX.cpp
+++ b/FX.cpp
@@ -109,16 +109,40 @@ FX::tintedIcon(QPixmap &pix, int step, int maxSteps, QColor tint)
         int size = img.width() * img.height();
         QRgb *pixel = (QRgb*)img.bits();
         const int r = tint.red(), g = tint.green(), b = tint.blue();
+        int minV = 255, maxV = 0;
+        bool mono = true;
         for (int i = 0; i < size; ++i) {
-            if (int a = qAlpha(*pixel)) {
+            if (qAlpha(*pixel) > 24) {
                 const int v = qGray(*pixel);
-                // stretch alpha
-                a = 255 - v*a/255;
-                a = 255 - a*a/255;
-                *pixel = qRgba(r, g, b, a);
+                maxV = qMax(v, maxV);
+                minV = qMin(v, minV);
+                if (maxV - minV > 10) {
+                    mono = false;
+                    break;
+                }
             }
             ++pixel;
         }
+        pixel = (QRgb*)img.bits();
+        if (mono) {
+            for (int i = 0; i < size; ++i) {
+                if (int a = qAlpha(*pixel)) {
+                    *pixel = qRgba(r, g, b, qAlpha(*pixel));
+                }
+                ++pixel;
+            }
+        } else {
+            for (int i = 0; i < size; ++i) {
+                if (int a = qAlpha(*pixel)) {
+                    const int v = qGray(*pixel);
+                    // stretch alpha
+                    a = 255 - v*a/255;
+                    a = 255 - a*a/255;
+                    *pixel = qRgba(r, g, b, a);
+                }
+                ++pixel;
+            }
+        }
         tintedIcon[1] = QPixmap::fromImage(img);
         lastIconPix[1] = pix.cacheKey();
     }
diff --git a/toolbars.cpp b/toolbars.cpp
index a1a75da..7b0f6b4 100644
--- a/toolbars.cpp
+++ b/toolbars.cpp
@@ -169,6 +169,7 @@ Style::drawToolButtonLabel(const QStyleOption *option, QPainter *painter, const
         const int style = config.btn.tool.disabledStyle;
 //         const QIcon::State state = toolbutton->state & State_On ? QIcon::On : QIcon::Off;
         pm = toolbutton->icon.pixmap(RECT.size().boundedTo(pmSize), isEnabled || style ? QIcon::Normal : QIcon::Disabled, QIcon::Off);
+        pm = FX::tintedIcon(pm, 1, 1, text);
 #if 0   // this is -in a way- the way it should be done..., but KIconLoader gives a shit on this or anything else
         if (!isEnabled)
             pm = generatedIconPixmap(QIcon::Disabled, pm, toolbutton);
beojan commented 8 years ago

That works well (though it appears icons need to be inverted everywhere there is an inverted background [e.g. modal dialogs]).

Thanks.

luebking commented 8 years ago

Yeah, and especially modal dialogs are pretty much when this approach will reach its limitations.

The style doesn't paint all icons in ann elements that can reside in a modal dialog, nor does it necessarily know "this icon will show up in a modal dialog" when it paints it (and checking that when posible isn't for free either) On top of that, one might not even want to tint the icons which eg. reside in the icon view of a file dialog (one could catch that to a certain degree by tinting monochromatic sources only)

Whenever an icon theme comes with icons w/o inner contrast it pretty much says "use me in a color environment that I was especially designed for or not at all" - that's why breeze is heavily critizised :-(