Logo ROOT   6.18/05
Reference Guide
RColor.cxx
Go to the documentation of this file.
1/// \file RColor.cxx
2/// \ingroup Gpad ROOT7
3/// \author Axel Naumann <axel@cern.ch>
4/// \date 2017-09-27
5/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
6/// is welcome!
7
8/*************************************************************************
9 * Copyright (C) 1995-2017, Rene Brun and Fons Rademakers. *
10 * All rights reserved. *
11 * *
12 * For the licensing terms see $ROOTSYS/LICENSE. *
13 * For the list of contributors see $ROOTSYS/README/CREDITS. *
14 *************************************************************************/
15
16#include "ROOT/RColor.hxx"
17
18#include <ROOT/RLogger.hxx>
19
20#include <algorithm>
21#include <cctype>
22#include <cmath>
23#include <exception>
24#include <iomanip>
25#include <sstream>
26#include <unordered_map>
27
28using namespace ROOT::Experimental;
29
30// RColor constexpr values:
31constexpr RColor::Alpha RColor::kOpaque;
32constexpr RColor::Alpha RColor::kTransparent;
38constexpr RColor::RGBA RColor::kInvisible;
39constexpr RColor::AutoTag RColor::kAuto;
40
41
42float RColor::GetPaletteOrdinal() const
43{
45 throw std::runtime_error("This color does not represent a palette ordinal!");
46 return fRedOrPalettePos;
47}
48
50{
52 throw std::runtime_error("This color does not represent a palette ordinal!");
53 return false;
54 }
55 return true;
56}
57
58namespace {
59 static RColor ParseRGBToColor(const std::string &strval, const std::string &name)
60 {
61 auto rgbalen = strval.length() - 1;
62 if (rgbalen != 3 && rgbalen != 4 && rgbalen != 6 && rgbalen != 8) {
63 R__ERROR_HERE("Graf2d") << "Invalid value for RColor default style " << name
64 << " with value \"" << strval
65 << "\": expect '#' followed by 3, 4, 6 or 8 hex digits (#rgb, #rgba, #rrggbbaa or #rrggbb).";
66 return RColor::kBlack;
67 }
68 std::size_t pos;
69 long long rgbaLL = std::stoll(strval.substr(1), &pos, /*base*/ 16);
70 if (pos != 3 && pos != 4 && pos != 6 && pos != 8) {
71 R__ERROR_HERE("Graf2d") << "Invalid value while parsing default style value for RColor " << name
72 << " with value \"" << strval
73 << "\": expect '#' followed by 3, 4, 6 or 8 hex digits (#rgb, #rgba, #rrggbbaa or #rrggbb).";
74 return RColor::kBlack;
75 }
76 if (pos != rgbalen) {
77 R__WARNING_HERE("Graf2d") << "Leftover characters while parsing default style value for RColor " << name
78 << " with value \"" << strval << "\", remainder: \"" << strval.substr(pos - 1) << "\"";
79 return RColor::kBlack;
80 }
81 std::array<float, 4> rgba = {0., 0., 0., 1.};
82 const bool haveAlpha = pos == 4 || pos == 8;
83 // #rrggbb[aa] has 8 bits per channel, #rgb[a] has 4.
84 const int bitsPerChannel = (pos > 4) ? 8 : 4;
85 const int bitMask = (1 << bitsPerChannel) - 1;
86 const float bitMaskFloat = static_cast<float>(bitMask);
87 for (int i = haveAlpha ? 3 : 2; i >= 0; --i) {
88 rgba[i] = (rgbaLL & bitMask) / bitMaskFloat;
89 rgbaLL >>= bitsPerChannel;
90 }
91 return RColor(rgba);
92 }
93
94 RColor ParseColorNameToColor(const std::string &strval, const std::string &name)
95 {
96 std::string nameLow = strval;
97 std::transform(nameLow.begin(), nameLow.end(), nameLow.begin(),
98 // tolower has undef behavior for char argument; cast it.
99 // And must not take &stdlib function, so lambda it is.
100 [](char c) { return std::tolower(static_cast<unsigned char>(c)); });
101 using namespace std::string_literals;
102 static const std::unordered_map<std::string, RColor> mapNamesToColor {
103 {"red"s, RColor{RColor::kRed}},
104 {"green"s, RColor{RColor::kGreen}},
105 {"blue"s, RColor{RColor::kBlue}},
106 {"white"s, RColor{RColor::kWhite}},
107 {"black"s, RColor{RColor::kBlack}},
108 {"invisible"s, RColor{RColor::kInvisible}},
109 {"auto"s, RColor{RColor::kAuto}}
110 };
111 auto itMap = mapNamesToColor.find(nameLow);
112 if (itMap == mapNamesToColor.end()) {
113 R__WARNING_HERE("Graf2d") << "Cannot parse RColor " << name
114 << " with value \"" << strval << "\": unknown color name.";
115 return RColor::kBlack;
116 }
117 return itMap->second;
118 }
119} // unnamed namespace
120
121////////////////////////////////////////////////////////////////////////////////
122/// Initialize a RColor from a string value.
123/// Colors can be specified as RGBA (red green blue alpha) or RRGGBBAA:
124/// %fa7f %ffa07bff # hash introduces a comment!
125/// For all predefined colors in RColor, colors can be specified as name without leading 'k', e.g. `red` for
126/// `RColor::kRed`.
127/// Prints an error and returns `RColor::kBlack` if the attribute string cannot be parsed or if the attribute has no
128/// entry in `fAttrs`.
129///
130///\param name - the attribute name (for diagnostic purposes).
131///\param strval - the attribute value as a string.
133{
134 if (strval[0] == '#') {
135 return ParseRGBToColor(strval, name);
136 }
137 return ParseColorNameToColor(strval, name);
138}
139
140////////////////////////////////////////////////////////////////////////////////
141/// Return a `std::string` representation of a RColor, suitable as input to ColorFromString().
142///
143///\param val - the color to be "stringified".
145{
146 // For now, always create "#RRGGBBAA".
147 std::string ret("#");
148 ret.reserve(9);
149 std::array<float, 4> arr{ val.GetRed(), val.GetGreen(), val.GetBlue(), val.GetAlpha() };
150 auto toHex = [](int i) { return i > 9 ? 'A' - 10 + i : '0' + i; };
151 for (auto &component: arr) {
152 int comp8Bit = static_cast<int>(std::round(255 * component));
153 ret.push_back(toHex(comp8Bit / 16));
154 ret.push_back(toHex(comp8Bit % 16));
155 }
156 return ret;
157}
#define R__ERROR_HERE(GROUP)
Definition: RLogger.hxx:183
#define R__WARNING_HERE(GROUP)
Definition: RLogger.hxx:184
#define c(i)
Definition: RSha256.hxx:101
@ kRed
Definition: Rtypes.h:64
@ kBlack
Definition: Rtypes.h:63
@ kGreen
Definition: Rtypes.h:64
@ kWhite
Definition: Rtypes.h:63
@ kBlue
Definition: Rtypes.h:64
char name[80]
Definition: TGX11.cxx:109
Used to signal that this color shall be automatically chosen by the drawing routines,...
Definition: RColor.hxx:93
A color: Red|Green|Blue|Alpha, or a position in a RPalette.
Definition: RColor.hxx:28
static constexpr RGBA kInvisible
Definition: RColor.hxx:259
bool AssertNotPalettePos() const
throw an exception if the color isn't specified as kRGBA or kAuto, the two cases where asking for RBG...
Definition: RColor.cxx:49
float GetAlpha() const
For RGBA or auto colors, get the alpha component (0..1).
Definition: RColor.hxx:148
@ kPalettePos
The color is defined as a value in the RFrame's RPalette.
float GetRed() const
For RGBA or auto colors, get the red component (0..1).
Definition: RColor.hxx:127
static constexpr AutoTag kAuto
Definition: RColor.hxx:260
float GetBlue() const
For RGBA or auto colors, get the blue component (0..1).
Definition: RColor.hxx:141
EKind fKind
How the color is defined.
Definition: RColor.hxx:64
std::array< float, 4 > RGBA
Definition: RColor.hxx:71
static constexpr RGBA kWhite
Definition: RColor.hxx:257
float GetGreen() const
For RGBA or auto colors, get the green component (0..1).
Definition: RColor.hxx:134
static constexpr RGBA kBlue
Definition: RColor.hxx:256
static constexpr RGBA kGreen
Definition: RColor.hxx:255
static constexpr RGBA kBlack
Definition: RColor.hxx:258
static constexpr RGBA kRed
Definition: RColor.hxx:254
float fRedOrPalettePos
The "R" in RGBA (0 <= R <= 1), or the palette pos if fKind is kPalettePos.
Definition: RColor.hxx:51
std::string ToAttributeString(const RColor &val)
Return a std::string representation of a RColor, suitable as input to ColorFromString().
Definition: RColor.cxx:144
RColor FromAttributeString(const std::string &str, const std::string &name, RColor *)
Initialize a RColor from a string value.
Definition: RColor.cxx:132
static constexpr double s