Add support CSS color text for class nana::color
This commit is contained in:
parent
fd5ff571a7
commit
81a50fd84f
@ -306,8 +306,16 @@ namespace nana
|
||||
color(unsigned red, unsigned green, unsigned blue);
|
||||
color(unsigned red, unsigned green, unsigned blue, double alpha);
|
||||
|
||||
/// Initializes the color with a CSS-like rgb string.
|
||||
color(std::string css_rgb);
|
||||
|
||||
color& alpha(double); ///< Sets alpha channel
|
||||
color& from_rgb(unsigned red, unsigned green, unsigned blue); ///< immutable alpha channel
|
||||
|
||||
/// Sets color with a HSL value.
|
||||
/// @param hue in range of [0, 360]
|
||||
/// @param saturation in range of [0, 1]
|
||||
/// @param lightness in range of [0, 1]
|
||||
color& from_hsl(double hue, double saturation, double lightness); ///< immutable alpha channel
|
||||
|
||||
color blend(const color& bgcolor, bool ignore_bgcolor_alpha) const;
|
||||
|
||||
@ -42,6 +42,14 @@ namespace nana
|
||||
std::size_t strlen(const char_t* str);
|
||||
double strtod(const char_t* str, char_t** endptr);
|
||||
char_t* strcpy(char_t* dest, const char_t* source);
|
||||
|
||||
//Workaround for no implemenation of std::stoi in MinGW.
|
||||
int stoi(const std::string&, std::size_t * pos = nullptr, int base = 10);
|
||||
int stoi(const std::wstring&, std::size_t* pos = nullptr, int base = 10);
|
||||
|
||||
//Workaround for no implemenation of std::stod in MinGW.
|
||||
double stod(const std::string&, std::size_t * pos = nullptr);
|
||||
double stod(const std::wstring&, std::size_t* pos = nullptr);
|
||||
}
|
||||
|
||||
#if defined(NANA_WINDOWS)
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
*/
|
||||
|
||||
#include <nana/basic_types.hpp>
|
||||
#include <regex>
|
||||
|
||||
namespace nana
|
||||
{
|
||||
@ -58,6 +59,168 @@ namespace nana
|
||||
a_ = 1.0;
|
||||
}
|
||||
|
||||
//Initializes the color with a CSS-like string
|
||||
//contributor: BigDave(mortis2007 at hotmail co uk)
|
||||
//date: February 3, 2015
|
||||
//maintainor: Jinhao, extended the support of CSS-spec
|
||||
color::color(std::string css_color)
|
||||
: a_(1.0)
|
||||
{
|
||||
const char * excpt_what = "color: invalid rgb format";
|
||||
|
||||
auto pos = css_color.find_first_not_of(' ');
|
||||
if (pos == css_color.npos)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
if ('#' == css_color[pos])
|
||||
{
|
||||
if (css_color.size() < pos + 4)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
auto endpos = css_color.find_first_not_of("0123456789abcdefABCDEF", pos + 1);
|
||||
if (endpos == css_color.npos)
|
||||
endpos = static_cast<decltype(endpos)>(css_color.size());
|
||||
|
||||
if ((endpos - pos != 4) && (endpos - pos != 7))
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
auto n = ::nana::stoi(css_color.substr(pos + 1, endpos - pos - 1), nullptr, 16);
|
||||
|
||||
if (endpos - pos == 4)
|
||||
{
|
||||
r_ = ((0xF00 & n) >> 4) | ((0xF00 & n) >> 8);
|
||||
g_ = (0xF0 & n) | ((0xF0 & n) >> 4);
|
||||
b_ = (0xF & n) | ((0xF & n) << 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
r_ = (0xFF0000 & n) >> 16;
|
||||
g_ = (0xFF00 & n) >> 8;
|
||||
b_ = (0xFF & n);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
std::transform(css_color.begin(), css_color.end(), css_color.begin(), std::tolower);
|
||||
auto endpos = css_color.find(' ', pos + 1);
|
||||
if (endpos == css_color.npos)
|
||||
endpos = css_color.size();
|
||||
|
||||
if ((endpos - pos == 11) && (css_color.substr(pos, 11) == "transparent"))
|
||||
{
|
||||
r_ = 0;
|
||||
g_ = 0;
|
||||
b_ = 0;
|
||||
a_ = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
auto type_end = css_color.find_first_of(" (", pos + 1);
|
||||
|
||||
if (type_end == css_color.npos || ((type_end - pos != 3) && (type_end - pos != 4))) //rgb/hsl = 3, rgba/hsla = 4
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
bool has_alpha = false;
|
||||
if (type_end - pos == 4) //maybe rgba/hsla
|
||||
{
|
||||
if (css_color[pos + 3] != 'a')
|
||||
throw std::invalid_argument(excpt_what);
|
||||
has_alpha = true;
|
||||
}
|
||||
|
||||
std::regex pat;
|
||||
std::regex_iterator<std::string::iterator> i, end;
|
||||
auto type_name = css_color.substr(pos, 3);
|
||||
if ("rgb" == type_name)
|
||||
{
|
||||
pat.assign("(\\d*\\.)?\\d+\\%?");
|
||||
i = std::regex_iterator<std::string::iterator>(css_color.begin() + pos, css_color.end(), pat);
|
||||
|
||||
if (i == end)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
std::vector<std::string> rgb;
|
||||
|
||||
rgb.emplace_back(i->str());
|
||||
|
||||
bool is_real;
|
||||
if (is_real = (rgb.back().back() == '%'))
|
||||
pat.assign("(\\d*\\.)?\\d+\\%");
|
||||
else
|
||||
pat.assign("\\d+");
|
||||
|
||||
for (++i; i != end; ++i)
|
||||
{
|
||||
rgb.emplace_back(i->str());
|
||||
if (rgb.size() == 3)
|
||||
break;
|
||||
}
|
||||
|
||||
if (rgb.size() != 3)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
if (is_real)
|
||||
{
|
||||
auto pr = ::nana::stod(rgb[0].substr(0, rgb[0].size() - 1));
|
||||
r_ = (pr > 100 ? 255.0 : 2.55 * pr);
|
||||
|
||||
pr = ::nana::stod(rgb[1].substr(0, rgb[1].size() - 1));
|
||||
g_ = (pr > 100 ? 255.0 : 2.55 * pr);
|
||||
|
||||
pr = ::nana::stod(rgb[2].substr(0, rgb[2].size() - 1));
|
||||
b_ = (pr > 100 ? 255.0 : 2.55 * pr);
|
||||
}
|
||||
else
|
||||
{
|
||||
r_ = ::nana::stod(rgb[0]);
|
||||
if (r_ > 255.0) r_ = 255;
|
||||
|
||||
g_ = ::nana::stod(rgb[1]);
|
||||
if (g_ > 255.0) g_ = 255;
|
||||
|
||||
b_ = ::nana::stod(rgb[2]);
|
||||
if (b_ > 255.0) b_ = 255;
|
||||
}
|
||||
}
|
||||
else if ("hsl" == type_name)
|
||||
{
|
||||
pat.assign("(\\d*\\.)?\\d+");
|
||||
i = std::regex_iterator<std::string::iterator>(css_color.begin() + pos, css_color.end(), pat);
|
||||
|
||||
if (i == end)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
auto h = ::nana::stod(i->str());
|
||||
|
||||
pat.assign("(\\d*\\.)?\\d+\\%");
|
||||
|
||||
if (++i == end)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
auto str = i->str();
|
||||
auto s = ::nana::stod(str.substr(0, str.size() - 1));
|
||||
|
||||
if (++i == end)
|
||||
throw std::invalid_argument(excpt_what);
|
||||
|
||||
str = i->str();
|
||||
auto l = ::nana::stod(str.substr(0, str.size() - 1));
|
||||
|
||||
from_hsl(h, s / 100, l / 100);
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument(excpt_what); //invalid color type
|
||||
|
||||
if (has_alpha)
|
||||
{
|
||||
pat.assign("(\\d*\\.)?\\d+");
|
||||
if (++i == end)
|
||||
throw std::invalid_argument(excpt_what); //invalid alpha value
|
||||
a_ = ::nana::stod(i->str());
|
||||
}
|
||||
}
|
||||
|
||||
color& color::from_rgb(unsigned red, unsigned green, unsigned blue)
|
||||
{
|
||||
r_ = red;
|
||||
@ -97,6 +260,7 @@ namespace nana
|
||||
|
||||
double var1 = 2.0 * lightness - var2;
|
||||
|
||||
hue /= 360;
|
||||
r_ = 255.0 * rgb_from_hue(var1, var2, hue + 0.33333);
|
||||
g_ = 255.0 * rgb_from_hue(var1, var2, hue);
|
||||
b_ = 255.0 * rgb_from_hue(var1, var2, hue - 0.33333);
|
||||
|
||||
@ -12,7 +12,8 @@
|
||||
*/
|
||||
|
||||
#include <nana/deploy.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <exception>
|
||||
#if defined(NANA_WINDOWS)
|
||||
#include <windows.h>
|
||||
#elif defined(NANA_LINUX)
|
||||
@ -49,6 +50,88 @@ namespace nana
|
||||
#endif
|
||||
}
|
||||
|
||||
int stoi(const std::string& str, std::size_t * pos, int base)
|
||||
{
|
||||
#if defined(NANA_MINGW)
|
||||
auto sptr = str.c_str();
|
||||
char *end;
|
||||
errno = 0;
|
||||
auto result = std::strtol(sptr, &end, base);
|
||||
|
||||
if (sptr == end)
|
||||
throw std::invalid_argument("invalid stoi argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoi argument out of range");
|
||||
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - sptr);
|
||||
return ((int)result);
|
||||
#else
|
||||
return std::stoi(str, pos, base);
|
||||
#endif
|
||||
}
|
||||
|
||||
int stoi(const std::wstring& str, std::size_t* pos, int base)
|
||||
{
|
||||
#if defined(NANA_MINGW)
|
||||
auto sptr = str.data();
|
||||
wchar_t *end;
|
||||
errno = 0;
|
||||
auto result = std::wcstol(sptr, &end, base);
|
||||
|
||||
if (sptr == end)
|
||||
throw std::invalid_argument("invalid stoi argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stoi argument out of range");
|
||||
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - sptr);
|
||||
return ((int)result);
|
||||
#else
|
||||
return std::stoi(str, pos, base);
|
||||
#endif
|
||||
}
|
||||
|
||||
double stod(const std::string& str, std::size_t * pos)
|
||||
{
|
||||
#ifdef NANA_MINGW
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
char *end;
|
||||
auto result = std::strtod(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stod argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
#else
|
||||
return std::stod(str, pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
double stod(const std::wstring& str, std::size_t* pos)
|
||||
{
|
||||
#ifdef NANA_MINGW
|
||||
auto *ptr = str.data();
|
||||
errno = 0;
|
||||
wchar_t *end;
|
||||
auto result = std::wcstod(ptr, &end);
|
||||
|
||||
if (ptr == end)
|
||||
throw std::invalid_argument("invalid stod argument");
|
||||
if (errno == ERANGE)
|
||||
throw std::out_of_range("stod argument out of range");
|
||||
if (pos)
|
||||
*pos = (std::size_t)(end - ptr);
|
||||
return result;
|
||||
#else
|
||||
return std::stod(str, pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool is_incomplete(const nana::string& str, unsigned pos)
|
||||
{
|
||||
#ifndef NANA_UNICODE
|
||||
|
||||
@ -611,22 +611,12 @@ namespace nana
|
||||
|
||||
int spinbox::to_int() const
|
||||
{
|
||||
//std::stoi is not defined by MinGW
|
||||
std::wstringstream ss;
|
||||
ss << value();
|
||||
int n = 0;
|
||||
ss >> n;
|
||||
return n;
|
||||
return ::nana::stoi(value());
|
||||
}
|
||||
|
||||
double spinbox::to_double() const
|
||||
{
|
||||
//std::stod is not defined by MinGW
|
||||
std::wstringstream ss;
|
||||
ss << value();
|
||||
double d = 0;
|
||||
ss >> d;
|
||||
return d;
|
||||
return ::nana::stod(value());
|
||||
}
|
||||
|
||||
void spinbox::set_accept(std::function<bool(::nana::char_t)> pred)
|
||||
|
||||
@ -343,12 +343,7 @@ namespace nana
|
||||
erase_n = str.size() - offset;
|
||||
|
||||
//If there is not a parameter for %argNNN, the %argNNN will be erased.
|
||||
|
||||
//a workaround, MinGW does not provide std::stoi
|
||||
std::wstringstream ss;
|
||||
std::size_t arg;
|
||||
ss<<str.substr(offset + 4, arg_n);
|
||||
ss>>arg;
|
||||
std::size_t arg = static_cast<std::size_t>(::nana::stoi(str.substr(offset + 4, arg_n)));
|
||||
|
||||
if (arg_strs && arg < arg_strs->size())
|
||||
str.replace(offset, erase_n, (*arg_strs)[arg]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user