From 1c06d46a9f4142ca61932bdbe776db174ede3fac Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 13 Dec 2024 23:44:19 +0100 Subject: [PATCH] Use CSS colour values in wxColourDatabase by default Allow reverting to using the traditional values for the conflicting colours by calling UseScheme(Traditional) if really needed. This is another attempt for changing wxColourDatabase to use more standard colour values, after the previous attempt in bb131fdbc5 (updated colour definitions to the new official X version (patch 771272), 2003-07-17) which was reverted almost immediately after in 5e2ab1ea5d (reverted the last change (colour values changes), it cerated too many problems, 2003-07-19), see #6031. Unlike the previous ones, it provides an escape hatch in the form of UseScheme() and also leaves traditional wx colour names not clashing with CSS ones still available. Also update the "drawing" sample to allow showing both colour schemes, and extend its view port to fit all the colour names vertically. See #23518. --- docs/changes.txt | 4 + include/wx/gdicmn.h | 12 ++ interface/wx/gdicmn.h | 51 ++++++++ samples/drawing/drawing.cpp | 16 ++- src/common/gdicmn.cpp | 228 +++++++++++++++++++++++++++++++++--- 5 files changed, 295 insertions(+), 16 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index c33c52f58c..3ffbd29f8a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -41,6 +41,10 @@ Changes in behaviour not resulting in compilation errors See wxCONFIG_USE_XDG and wxCONFIG_USE_HOME for how to customize this behaviour. You may also find wxFileConfig::MigrateLocalFile() useful. +- Values of many colours in wxColourDatabase have been changed to use the + values from the CSS standard. Use wxColourDatabase::UseScheme() to revert to + using the traditional values if your application appearance depends on them. + - As first mentioned in 3.0 release notes, the value of wxTHREAD_WAIT_DEFAULT, used by wxThread::Delete() and Wait() by default, has changed from wxTHREAD_WAIT_YIELD to wxTHREAD_WAIT_BLOCK for safety and consistency. diff --git a/include/wx/gdicmn.h b/include/wx/gdicmn.h index 17d510fc5b..e5ccf8087a 100644 --- a/include/wx/gdicmn.h +++ b/include/wx/gdicmn.h @@ -961,6 +961,16 @@ public: wxColourDatabase(); ~wxColourDatabase(); + // use the given colour scheme: CSS one is the default since 3.3.0, + // Traditional is the legacy colour scheme used by wxWidgets before it. + enum Scheme + { + CSS, + Traditional + }; + + void UseScheme(Scheme scheme); + // find colour by name or name for the given colour wxColour Find(const wxString& name) const; wxString FindName(const wxColour& colour) const; @@ -977,6 +987,8 @@ private: void Initialize(); wxStringToColourHashMap *m_map; + + Scheme m_scheme; }; #if WXWIN_COMPATIBILITY_3_2 diff --git a/interface/wx/gdicmn.h b/interface/wx/gdicmn.h index bef77ab9d4..de8a9c4832 100644 --- a/interface/wx/gdicmn.h +++ b/interface/wx/gdicmn.h @@ -816,6 +816,13 @@ const wxPoint wxDefaultPosition; using AddColour() and may use it to look up colours by names using Find() or find the names for the standard colour using FindName(). + It is also possible to switch between the colour values defined in the CSS + standard (see https://www.w3.org/TR/css-color-4/#named-colors) and the + traditional colour values which were used by wxWidgets versions earlier + than 3.3.0, which may be useful to preserve the appearance of the existing + code: if you need to do this, please call UseScheme() with @c Traditional + argument, but the use of new, standard colours is recommended. + There is one predefined, global instance of this class called ::wxTheColourDatabase. @@ -939,6 +946,50 @@ public: @since 3.3.0 */ wxVector GetAllNames() const; + + /** + Possible colour schemes for UseScheme(). + + @since 3.3.0 + */ + enum Scheme + { + CSS, ///< Use CSS standard colours, default since 3.3.0. + Traditional ///< Use traditional wxWidgets colours for compatibility. + }; + + /** + Select the colour scheme to use. + + By default, wxColourDatabase uses CSS scheme which returns the standard + values for the colours defined in the CSS specification, see + https://www.w3.org/TR/css-color-4/#named-colors + + If preserving compatibility with the behaviour and appearance of the + previous wxWidgets versions is important, you may switch to the + traditional colour scheme by using this function with @c Traditional + argument, e.g. call + + @code + wxTheColourDatabase->UseScheme(wxColourDatabase::Traditional); + @endcode + + during the application initialization. + + Note that the colour names defined only by wxWidgets, which notably + includes all colour variants with spaces in their names, are still + available in the default CSS colour scheme, with their traditional + values but the names of colours defined by CSS standard are taken from + it, e.g. "GREEN" corresponds to @c #00ff00 in the traditional scheme + but to @c #008000 in the CSS scheme. Similarly, CSS colour names that + were not defined by the previous wxWidgets versions are available even + when using the traditional scheme, the scheme choice only affects the + values of the colours defined by both wxWidgets and CSS with different + values. + + @since 3.3.0 + */ + void UseScheme(Scheme scheme); }; diff --git a/samples/drawing/drawing.cpp b/samples/drawing/drawing.cpp index 7e1bd4fe3c..3dfd820cbc 100644 --- a/samples/drawing/drawing.cpp +++ b/samples/drawing/drawing.cpp @@ -391,6 +391,9 @@ enum Colour_AppearanceLight, Colour_AppearanceDark, + Colour_DatabaseCSS, + Colour_DatabaseTraditional, + #if wxUSE_COLOURDLG Colour_TextForeground, Colour_TextBackground, @@ -2508,6 +2511,9 @@ MyFrame::MyFrame(const wxString& title) menuColour->AppendRadioItem(Colour_AppearanceLight, "Use &light appearance"); menuColour->AppendRadioItem(Colour_AppearanceDark, "Use &dark appearance"); menuColour->AppendSeparator(); + menuColour->AppendRadioItem(Colour_DatabaseCSS, "&Use CSS colours"); + menuColour->AppendRadioItem(Colour_DatabaseTraditional, "Use &traditional colours"); + menuColour->AppendSeparator(); #if wxUSE_COLOURDLG menuColour->Append( Colour_TextForeground, "Text &foreground..." ); menuColour->Append( Colour_TextBackground, "Text &background..." ); @@ -2559,7 +2565,7 @@ MyFrame::MyFrame(const wxString& title) m_textureBackground = false; m_canvas = new MyCanvas( this ); - m_canvas->SetScrollbars( 10, 10, 100, 240 ); + m_canvas->SetScrollbars( 10, 10, 100, 450 ); SetSize(FromDIP(wxSize(800, 700))); Center(wxBOTH); @@ -2835,6 +2841,14 @@ void MyFrame::OnOption(wxCommandEvent& event) Refresh(); break; + case Colour_DatabaseCSS: + case Colour_DatabaseTraditional: + wxTheColourDatabase->UseScheme(event.GetId() == Colour_DatabaseCSS + ? wxColourDatabase::CSS + : wxColourDatabase::Traditional); + Refresh(); + break; + #if wxUSE_COLOURDLG case Colour_TextForeground: m_colourForeground = SelectColour(); diff --git a/src/common/gdicmn.cpp b/src/common/gdicmn.cpp index d18bec8075..6b5876512d 100644 --- a/src/common/gdicmn.cpp +++ b/src/common/gdicmn.cpp @@ -264,6 +264,28 @@ wxRealPoint::wxRealPoint(const wxPoint& pt) // wxColourDatabase // ============================================================================ +namespace +{ + +struct wxColourDesc +{ + const char *name; + unsigned char r,g,b; +}; + +using wxColourMap = std::unordered_map; + +void AddColours(wxColourMap& map, const wxColourDesc* table, size_t len) +{ + for ( size_t n = 0; n < len; n++ ) + { + const wxColourDesc& cc = table[n]; + map[wxString::FromAscii(cc.name)] = wxColour(cc.r, cc.g, cc.b); + } +} + +} // anonymous namespace + // Due to a bug mentioned in wx/hashmap.h we have to use aggregation here and // define a simple accessor function below. // @@ -271,24 +293,17 @@ wxRealPoint::wxRealPoint(const wxPoint& pt) class wxStringToColourHashMap { public: - std::unordered_map m_colours; + wxColourMap m_colours; }; namespace { -inline std::unordered_map& -GetColours(wxStringToColourHashMap* map) +inline wxColourMap& GetColours(wxStringToColourHashMap* map) { return map->m_colours; } -struct wxColourDesc -{ - const char *name; - unsigned char r,g,b; -}; - } // anonymous namespace // ---------------------------------------------------------------------------- @@ -299,6 +314,8 @@ wxColourDatabase::wxColourDatabase () { // will be created on demand in Initialize() m_map = nullptr; + + m_scheme = CSS; } wxColourDatabase::~wxColourDatabase () @@ -317,7 +334,7 @@ void wxColourDatabase::Initialize() m_map = new wxStringToColourHashMap; - static const wxColourDesc wxColourTable[] = + static const wxColourDesc legacyColours[] = { {"AQUAMARINE",112, 219, 147}, {"BLACK",0, 0, 0}, @@ -397,12 +414,193 @@ void wxColourDatabase::Initialize() {"YELLOW GREEN", 153, 204, 50} }; - size_t n; - - for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) + // See https://www.w3.org/TR/css-color-4/#named-colors + static const wxColourDesc cssColours[] = { - const wxColourDesc& cc = wxColourTable[n]; - GetColours(m_map)[wxString::FromAscii(cc.name)] = wxColour(cc.r, cc.g, cc.b); + { "ALICEBLUE", 240, 248, 255 }, // #f0f8ff + { "ANTIQUEWHITE", 250, 235, 215 }, // #faebd7 + { "AQUA", 0, 255, 255 }, // #00ffff + { "AQUAMARINE", 127, 255, 212 }, // #7fffd4 + { "AZURE", 240, 255, 255 }, // #f0ffff + { "BEIGE", 245, 245, 220 }, // #f5f5dc + { "BISQUE", 255, 228, 196 }, // #ffe4c4 + { "BLACK", 0, 0, 0 }, // #000000 + { "BLANCHEDALMOND", 255, 235, 205 }, // #ffebcd + { "BLUE", 0, 0, 255 }, // #0000ff + { "BLUEVIOLET", 138, 43, 226 }, // #8a2be2 + { "BROWN", 165, 42, 42 }, // #a52a2a + { "BURLYWOOD", 222, 184, 135 }, // #deb887 + { "CADETBLUE", 95, 158, 160 }, // #5f9ea0 + { "CHARTREUSE", 127, 255, 0 }, // #7fff00 + { "CHOCOLATE", 210, 105, 30 }, // #d2691e + { "CORAL", 255, 127, 80 }, // #ff7f50 + { "CORNFLOWERBLUE", 100, 149, 237 }, // #6495ed + { "CORNSILK", 255, 248, 220 }, // #fff8dc + { "CRIMSON", 220, 20, 60 }, // #dc143c + { "CYAN", 0, 255, 255 }, // #00ffff + { "DARKBLUE", 0, 0, 139 }, // #00008b + { "DARKCYAN", 0, 139, 139 }, // #008b8b + { "DARKGOLDENROD", 184, 134, 11 }, // #b8860b + { "DARKGRAY", 169, 169, 169 }, // #a9a9a9 + { "DARKGREEN", 0, 100, 0 }, // #006400 + { "DARKGREY", 169, 169, 169 }, // #a9a9a9 + { "DARKKHAKI", 189, 183, 107 }, // #bdb76b + { "DARKMAGENTA", 139, 0, 139 }, // #8b008b + { "DARKOLIVEGREEN", 85, 107, 47 }, // #556b2f + { "DARKORANGE", 255, 140, 0 }, // #ff8c00 + { "DARKORCHID", 153, 50, 204 }, // #9932cc + { "DARKRED", 139, 0, 0 }, // #8b0000 + { "DARKSALMON", 233, 150, 122 }, // #e9967a + { "DARKSEAGREEN", 143, 188, 143 }, // #8fbc8f + { "DARKSLATEBLUE", 72, 61, 139 }, // #483d8b + { "DARKSLATEGRAY", 47, 79, 79 }, // #2f4f4f + { "DARKSLATEGREY", 47, 79, 79 }, // #2f4f4f + { "DARKTURQUOISE", 0, 206, 209 }, // #00ced1 + { "DARKVIOLET", 148, 0, 211 }, // #9400d3 + { "DEEPPINK", 255, 20, 147 }, // #ff1493 + { "DEEPSKYBLUE", 0, 191, 255 }, // #00bfff + { "DIMGRAY", 105, 105, 105 }, // #696969 + { "DIMGREY", 105, 105, 105 }, // #696969 + { "DODGERBLUE", 30, 144, 255 }, // #1e90ff + { "FIREBRICK", 178, 34, 34 }, // #b22222 + { "FLORALWHITE", 255, 250, 240 }, // #fffaf0 + { "FORESTGREEN", 34, 139, 34 }, // #228b22 + { "FUCHSIA", 255, 0, 255 }, // #ff00ff + { "GAINSBORO", 220, 220, 220 }, // #dcdcdc + { "GHOSTWHITE", 248, 248, 255 }, // #f8f8ff + { "GOLD", 255, 215, 0 }, // #ffd700 + { "GOLDENROD", 218, 165, 32 }, // #daa520 + { "GRAY", 128, 128, 128 }, // #808080 + { "GREEN", 0, 128, 0 }, // #008000 + { "GREENYELLOW", 173, 255, 47 }, // #adff2f + { "GREY", 128, 128, 128 }, // #808080 + { "HONEYDEW", 240, 255, 240 }, // #f0fff0 + { "HOTPINK", 255, 105, 180 }, // #ff69b4 + { "INDIANRED", 205, 92, 92 }, // #cd5c5c + { "INDIGO", 75, 0, 130 }, // #4b0082 + { "IVORY", 255, 255, 240 }, // #fffff0 + { "KHAKI", 240, 230, 140 }, // #f0e68c + { "LAVENDER", 230, 230, 250 }, // #e6e6fa + { "LAVENDERBLUSH", 255, 240, 245 }, // #fff0f5 + { "LAWNGREEN", 124, 252, 0 }, // #7cfc00 + { "LEMONCHIFFON", 255, 250, 205 }, // #fffacd + { "LIGHTBLUE", 173, 216, 230 }, // #add8e6 + { "LIGHTCORAL", 240, 128, 128 }, // #f08080 + { "LIGHTCYAN", 224, 255, 255 }, // #e0ffff + { "LIGHTGOLDENRODYELLOW", 250, 250, 210 }, // #fafad2 + { "LIGHTGRAY", 211, 211, 211 }, // #d3d3d3 + { "LIGHTGREEN", 144, 238, 144 }, // #90ee90 + { "LIGHTGREY", 211, 211, 211 }, // #d3d3d3 + { "LIGHTPINK", 255, 182, 193 }, // #ffb6c1 + { "LIGHTSALMON", 255, 160, 122 }, // #ffa07a + { "LIGHTSEAGREEN", 32, 178, 170 }, // #20b2aa + { "LIGHTSKYBLUE", 135, 206, 250 }, // #87cefa + { "LIGHTSLATEGRAY", 119, 136, 153 }, // #778899 + { "LIGHTSLATEGREY", 119, 136, 153 }, // #778899 + { "LIGHTSTEELBLUE", 176, 196, 222 }, // #b0c4de + { "LIGHTYELLOW", 255, 255, 224 }, // #ffffe0 + { "LIME", 0, 255, 0 }, // #00ff00 + { "LIMEGREEN", 50, 205, 50 }, // #32cd32 + { "LINEN", 250, 240, 230 }, // #faf0e6 + { "MAGENTA", 255, 0, 255 }, // #ff00ff + { "MAROON", 128, 0, 0 }, // #800000 + { "MEDIUMAQUAMARINE", 102, 205, 170 }, // #66cdaa + { "MEDIUMBLUE", 0, 0, 205 }, // #0000cd + { "MEDIUMORCHID", 186, 85, 211 }, // #ba55d3 + { "MEDIUMPURPLE", 147, 112, 219 }, // #9370db + { "MEDIUMSEAGREEN", 60, 179, 113 }, // #3cb371 + { "MEDIUMSLATEBLUE", 123, 104, 238 }, // #7b68ee + { "MEDIUMSPRINGGREEN", 0, 250, 154 }, // #00fa9a + { "MEDIUMTURQUOISE", 72, 209, 204 }, // #48d1cc + { "MEDIUMVIOLETRED", 199, 21, 133 }, // #c71585 + { "MIDNIGHTBLUE", 25, 25, 112 }, // #191970 + { "MINTCREAM", 245, 255, 250 }, // #f5fffa + { "MISTYROSE", 255, 228, 225 }, // #ffe4e1 + { "MOCCASIN", 255, 228, 181 }, // #ffe4b5 + { "NAVAJOWHITE", 255, 222, 173 }, // #ffdead + { "NAVY", 0, 0, 128 }, // #000080 + { "OLDLACE", 253, 245, 230 }, // #fdf5e6 + { "OLIVE", 128, 128, 0 }, // #808000 + { "OLIVEDRAB", 107, 142, 35 }, // #6b8e23 + { "ORANGE", 255, 165, 0 }, // #ffa500 + { "ORANGERED", 255, 69, 0 }, // #ff4500 + { "ORCHID", 218, 112, 214 }, // #da70d6 + { "PALEGOLDENROD", 238, 232, 170 }, // #eee8aa + { "PALEGREEN", 152, 251, 152 }, // #98fb98 + { "PALETURQUOISE", 175, 238, 238 }, // #afeeee + { "PALEVIOLETRED", 219, 112, 147 }, // #db7093 + { "PAPAYAWHIP", 255, 239, 213 }, // #ffefd5 + { "PEACHPUFF", 255, 218, 185 }, // #ffdab9 + { "PERU", 205, 133, 63 }, // #cd853f + { "PINK", 255, 192, 203 }, // #ffc0cb + { "PLUM", 221, 160, 221 }, // #dda0dd + { "POWDERBLUE", 176, 224, 230 }, // #b0e0e6 + { "PURPLE", 128, 0, 128 }, // #800080 + { "REBECCAPURPLE", 102, 51, 153 }, // #663399 + { "RED", 255, 0, 0 }, // #ff0000 + { "ROSYBROWN", 188, 143, 143 }, // #bc8f8f + { "ROYALBLUE", 65, 105, 225 }, // #4169e1 + { "SADDLEBROWN", 139, 69, 19 }, // #8b4513 + { "SALMON", 250, 128, 114 }, // #fa8072 + { "SANDYBROWN", 244, 164, 96 }, // #f4a460 + { "SEAGREEN", 46, 139, 87 }, // #2e8b57 + { "SEASHELL", 255, 245, 238 }, // #fff5ee + { "SIENNA", 160, 82, 45 }, // #a0522d + { "SILVER", 192, 192, 192 }, // #c0c0c0 + { "SKYBLUE", 135, 206, 235 }, // #87ceeb + { "SLATEBLUE", 106, 90, 205 }, // #6a5acd + { "SLATEGRAY", 112, 128, 144 }, // #708090 + { "SLATEGREY", 112, 128, 144 }, // #708090 + { "SNOW", 255, 250, 250 }, // #fffafa + { "SPRINGGREEN", 0, 255, 127 }, // #00ff7f + { "STEELBLUE", 70, 130, 180 }, // #4682b4 + { "TAN", 210, 180, 140 }, // #d2b48c + { "TEAL", 0, 128, 128 }, // #008080 + { "THISTLE", 216, 191, 216 }, // #d8bfd8 + { "TOMATO", 255, 99, 71 }, // #ff6347 + { "TURQUOISE", 64, 224, 208 }, // #40e0d0 + { "VIOLET", 238, 130, 238 }, // #ee82ee + { "WHEAT", 245, 222, 179 }, // #f5deb3 + { "WHITE", 255, 255, 255 }, // #ffffff + { "WHITESMOKE", 245, 245, 245 }, // #f5f5f5 + { "YELLOW", 255, 255, 0 }, // #ffff00 + { "YELLOWGREEN", 154, 205, 50 }, // #9acd32 + }; + + auto& map = GetColours(m_map); + + // We still use the legacy colour names in CSS scheme, but we add them + // first so any conflicting values are overwritten with the correct values + // in the CSS table. Similarly, we provide CSS colour names even in the + // traditional scheme -- but legacy colour values take precedence for the + // colours that used to be defined by wxWidgets. + switch ( m_scheme ) + { + case CSS: + AddColours(map, legacyColours, WXSIZEOF(legacyColours)); + AddColours(map, cssColours, WXSIZEOF(cssColours)); + break; + + case Traditional: + AddColours(map, cssColours, WXSIZEOF(cssColours)); + AddColours(map, legacyColours, WXSIZEOF(legacyColours)); + break; + } +} + +void wxColourDatabase::UseScheme(Scheme scheme) +{ + if ( scheme == m_scheme ) + return; + + m_scheme = scheme; + + // Reset the existing map for the different scheme, it will be re-filled on + // next use. + if ( m_map ) + { + delete m_map; + m_map = nullptr; } }