File indexing completed on 2024-04-28 05:32:14

0001 /*
0002     this file is part of the oxygen gtk engine
0003     SPDX-FileCopyrightText: 2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
0004 
0005     inspired notably from kdelibs/kdeui/color/kcolorutils.h
0006     SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0007     SPDX-FileCopyrightText: 2007 Thomas Zander <zander@kde.org>
0008     SPDX-FileCopyrightText: 2007 Zack Rusin <zack@kde.org>
0009 
0010     SPDX-License-Identifier: LGPL-2.0-or-later
0011 */
0012 
0013 #include "oxygenrgba.h"
0014 
0015 #include <cassert>
0016 #include <cmath>
0017 
0018 namespace Oxygen
0019 {
0020 
0021     //___________________________________________________________
0022     ColorUtils::Rgba ColorUtils::Rgba::light( int factor ) const
0023     {
0024 
0025         if( factor <= 0 ) return *this;
0026         else if( factor < 100 ) return dark( 10000 / factor );
0027 
0028         double h, s, v;
0029         toHsv( h, s, v );
0030         v = (v*factor)/100;
0031         if( v > 1 )
0032         {
0033             // overflow. Adjust saturation
0034             s -= v - 1;
0035             if( s < 0 ) s = 0;
0036             v = 1.0;
0037         }
0038 
0039         return Rgba( *this ).fromHsv( h, s, v );
0040     }
0041 
0042     //___________________________________________________________
0043     ColorUtils::Rgba ColorUtils::Rgba::dark( int factor ) const
0044     {
0045         if( factor <= 0 ) return *this;
0046         else if( factor < 100 ) return light( 10000/ factor );
0047 
0048         double h, s, v;
0049         toHsv( h, s, v );
0050         v = (v*100.0)/factor;
0051         return Rgba( *this ).fromHsv( h, s, v );
0052     }
0053 
0054     //___________________________________________________________
0055     ColorUtils::Rgba ColorUtils::Rgba::fromKdeOption( std::string value )
0056     {
0057 
0058         Rgba out;
0059 
0060         // parse using regular expression
0061         // two formats are supported: html style (#rrggbb), and KDE style (r,g,b).
0062         GRegex* regex = g_regex_new(
0063             "(?:#((?:\\d|[a-f])+))|"
0064             "(?:(\\d+),(\\d+),(\\d+)(?:,(\\d+))?)",
0065             G_REGEX_CASELESS, (GRegexMatchFlags)0, 0L );
0066 
0067         GMatchInfo* matchInfo(0L);
0068         g_regex_match( regex, value.c_str(), (GRegexMatchFlags)0, &matchInfo);
0069         const int matchCount( g_match_info_get_match_count( matchInfo ) );
0070         if( matchCount == 2 )
0071         {
0072 
0073             // convert to hex number
0074             gchar* matchedString( g_match_info_fetch( matchInfo, 1 ) );
0075             std::istringstream in( matchedString );
0076             int colorValue = 0;
0077             in >> std::hex >> colorValue;
0078 
0079             out.setBlue( double(colorValue&0xff)/255 );
0080             out.setGreen( double( (colorValue>>=8)&0xff)/255 );
0081             out.setRed( double( (colorValue>>=8)&0xff)/255 );
0082 
0083             g_free( matchedString );
0084 
0085         } else if( matchCount >= 5 ) {
0086 
0087             for( int index = 0; index < matchCount-2; ++index )
0088             {
0089 
0090                 gchar* matchedString( g_match_info_fetch( matchInfo, index+2 ) );
0091                 std::istringstream in( matchedString );
0092                 int colorValue;
0093                 if( !(in >> colorValue) ) break;
0094 
0095                 if( index == 0 ) out.setRed( double(colorValue)/255 );
0096                 else if( index == 1 ) out.setGreen( double(colorValue)/255 );
0097                 else if( index == 2 ) out.setBlue( double(colorValue)/255 );
0098                 else if( index == 3 ) out.setAlpha( double(colorValue)/255 );
0099 
0100                 g_free( matchedString );
0101 
0102             }
0103 
0104         }
0105 
0106         // cleanup
0107         g_match_info_free (matchInfo);
0108         g_regex_unref( regex );
0109         return out;
0110 
0111     }
0112 
0113     //___________________________________________________________
0114     void ColorUtils::Rgba::toHsv( double& hue, double& saturation, double& value ) const
0115     {
0116 
0117         if( !isValid() ) return;
0118 
0119         const color_t max =  std::max( _red, std::max( _green, _blue ) );
0120         const color_t min =  std::min( _red, std::min( _green, _blue ) );
0121         const color_t delta = max-min;
0122         value = double(max)/USHRT_MAX;
0123 
0124         if( delta <= 0 )
0125         {
0126             hue = -1;
0127             saturation = 0;
0128             return;
0129 
0130         }
0131 
0132         saturation = double(delta)/max;
0133         if( _red == max ) hue =  double(_green - _blue )/delta;
0134         else if( _green == max ) hue = 2.0 + double(_blue-_red)/delta;
0135         else if( _blue == max ) hue = 4.0 + double(_red-_green)/delta;
0136         else assert( false );
0137 
0138         hue *= 60.0;
0139         if( hue < 0 ) hue += 360;
0140         return;
0141 
0142     }
0143 
0144     //___________________________________________________________
0145     ColorUtils::Rgba& ColorUtils::Rgba::fromHsv( double hue, double saturation, double value )
0146     {
0147 
0148         if( hue < 0 )
0149         {
0150             setRed( value );
0151             setGreen( value );
0152             setBlue( value );
0153             return *this;
0154         }
0155 
0156         const double h = hue/60;
0157         const double c = value*saturation*USHRT_MAX;
0158         const double x = c*(1 - std::abs((h-2*int(h/2)) - 1 ));
0159 
0160         if( h>=0 && h<1 ) { _red = (color_t) c; _green = (color_t) x; _blue = 0; }
0161         else if( h>=1 && h<2 ) { _red = (color_t) x; _green = (color_t) c; _blue = 0; }
0162         else if( h>=2 && h<3 ) { _red = 0; _green = (color_t) c; _blue = (color_t) x; }
0163         else if( h>=3 && h<4 ) { _red = 0; _green = (color_t) x; _blue = (color_t) c; }
0164         else if( h>=4 && h<5 ) { _red = (color_t) x; _green = 0; _blue = (color_t) c; }
0165         else { _red = (color_t) c; _green = 0; _blue = (color_t) x; }
0166 
0167         double m = value*USHRT_MAX - c;
0168         _red += (color_t) m;
0169         _green += (color_t) m;
0170         _blue += (color_t) m;
0171 
0172         _mask |= RGB;
0173 
0174         return *this;
0175     }
0176 
0177 }