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 }