1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-08-13 19:54:17 +02:00

Merge pull request #2813 from Laserlicht/textcolor

Textcolor support
This commit is contained in:
Nordsoft91
2023-09-16 14:12:17 +02:00
committed by GitHub
8 changed files with 283 additions and 4 deletions

View File

@@ -122,6 +122,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#include <optional>
#include <queue>
#include <random>
#include <regex>
#include <set>
#include <sstream>
#include <string>
@@ -147,6 +148,7 @@ static_assert(sizeof(bool) == 1, "Bool needs to be 1 byte in size.");
#define BOOST_ASIO_ENABLE_OLD_SERVICES
#endif
#include <boost/algorithm/hex.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/crc.hpp>
#include <boost/current_function.hpp>

View File

@@ -10,6 +10,7 @@
#include "StdInc.h"
#include "Colors.h"
#include "../../lib/JsonNode.h"
const ColorRGBA Colors::YELLOW = { 229, 215, 123, ColorRGBA::ALPHA_OPAQUE };
const ColorRGBA Colors::WHITE = { 255, 243, 222, ColorRGBA::ALPHA_OPAQUE };
@@ -23,3 +24,29 @@ const ColorRGBA Colors::RED = {255, 0, 0, ColorRGBA::ALPHA_OPAQUE};
const ColorRGBA Colors::PURPLE = {255, 75, 125, ColorRGBA::ALPHA_OPAQUE};
const ColorRGBA Colors::BLACK = {0, 0, 0, ColorRGBA::ALPHA_OPAQUE};
const ColorRGBA Colors::TRANSPARENCY = {0, 0, 0, ColorRGBA::ALPHA_TRANSPARENT};
std::optional<ColorRGBA> Colors::parseColor(std::string text)
{
std::smatch match;
std::regex expr("^#([0-9a-fA-F]{6})$");
ui8 rgb[3] = {0, 0, 0};
if(std::regex_search(text, match, expr))
{
std::string tmp = boost::algorithm::unhex(match[1].str());
std::copy(tmp.begin(), tmp.end(), rgb);
return ColorRGBA(rgb[0], rgb[1], rgb[2]);
}
static const JsonNode config(JsonPath::builtin("CONFIG/textColors"));
auto colors = config["colors"].Struct();
for(auto & color : colors) {
if(boost::algorithm::to_lower_copy(color.first) == boost::algorithm::to_lower_copy(text))
{
std::string tmp = boost::algorithm::unhex(color.second.String());
std::copy(tmp.begin(), tmp.end(), rgb);
return ColorRGBA(rgb[0], rgb[1], rgb[2]);
}
}
return std::nullopt;
}

View File

@@ -49,4 +49,7 @@ public:
static const ColorRGBA BLACK;
static const ColorRGBA TRANSPARENCY;
/// parse color
static std::optional<ColorRGBA> parseColor(std::string text);
};

View File

@@ -153,6 +153,17 @@ void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
//We should count delimiters length from string to correct centering later.
delimitersCount *= f->getStringWidth(delimeters)/2;
std::smatch match;
std::regex expr("\\{(.*?)\\|");
std::string::const_iterator searchStart( what.cbegin() );
while(std::regex_search(searchStart, what.cend(), match, expr))
{
std::string colorText = match[1].str();
if(auto c = Colors::parseColor(colorText))
delimitersCount += f->getStringWidth(colorText + "|");
searchStart = match.suffix().first;
}
// input is rect in which given text should be placed
// calculate proper position for top-left corner of the text
if(alignment == ETextAlignment::TOPLEFT)
@@ -189,8 +200,25 @@ void CTextContainer::blitLine(Canvas & to, Rect destRect, std::string what)
{
std::string toPrint = what.substr(begin, end - begin);
if(currDelimeter % 2) // Enclosed in {} text - set to yellow
if(currDelimeter % 2) // Enclosed in {} text - set to yellow or defined color
{
std::smatch match;
std::regex expr("^(.*?)\\|");
if(std::regex_search(toPrint, match, expr))
{
std::string colorText = match[1].str();
if(auto color = Colors::parseColor(colorText))
{
toPrint = toPrint.substr(colorText.length() + 1, toPrint.length() - colorText.length());
to.drawText(where, font, *color, ETextAlignment::TOPLEFT, toPrint);
}
else
to.drawText(where, font, Colors::YELLOW, ETextAlignment::TOPLEFT, toPrint);
}
else
to.drawText(where, font, Colors::YELLOW, ETextAlignment::TOPLEFT, toPrint);
}
else // Non-enclosed text, use default color
to.drawText(where, font, color, ETextAlignment::TOPLEFT, toPrint);

View File

@@ -131,6 +131,7 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWi
ui32 wordBreak = -1; //last position for line break (last space character)
ui32 currPos = 0; //current position in text
bool opened = false; //set to true when opening brace is found
std::string color = ""; //color found
size_t symbolSize = 0; // width of character, in bytes
size_t glyphWidth = 0; // width of printable glyph, pixels
@@ -147,9 +148,27 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWi
/* We don't count braces in string length. */
if (text[currPos] == '{')
{
opened=true;
std::smatch match;
std::regex expr("^\\{(.*?)\\|");
std::string tmp = text.substr(currPos);
if(std::regex_search(tmp, match, expr))
{
std::string colorText = match[1].str();
if(auto c = Colors::parseColor(colorText))
{
color = colorText + "|";
currPos += colorText.length() + 1;
}
}
}
else if (text[currPos]=='}')
{
opened=false;
color = "";
}
else
lineWidth += (ui32)glyphWidth;
currPos += (ui32)symbolSize;
@@ -196,7 +215,7 @@ std::vector<std::string> CMessage::breakText( std::string text, size_t maxLineWi
{
/* Add an opening brace for the next line. */
if (text.length() != 0)
text.insert(0, "{");
text.insert(0, "{" + color);
}
}

View File

@@ -16,6 +16,10 @@ struct SDL_Surface;
class CInfoWindow;
class CComponent;
VCMI_LIB_NAMESPACE_BEGIN
class ColorRGBA;
VCMI_LIB_NAMESPACE_END
/// Class which draws formatted text messages and generates chat windows
class CMessage

171
config/textColors.json Normal file
View File

@@ -0,0 +1,171 @@
{
"colors": {
"r": "F80000",
"g": "00FC00",
"b": "0000F8",
"y": "F8FC00",
"o": "F88000",
"p": "F800F8",
"c": "00FCF8",
"k": "000000",
"w": "FFFFFF",
"Regular": "F8F0D8",
"Highlight": "E8D478",
"H3Red": "F80000",
"H3Cyan": "00FCF8",
"H3Green": "00FC00",
"H3Blue": "0000F8",
"H3Yellow": "F8FC00",
"H3Orange": "F88000",
"H3Purple": "F800F8",
"H3Pink": "C07888",
"Black": "000000",
"Navy": "000080",
"DarkBlue": "00008B",
"MediumBlue": "0000CD",
"Blue": "0000FF",
"DarkGreen": "006400",
"Green": "008000",
"Teal": "008080",
"DarkCyan": "008B8B",
"DeepSkyBlue": "00BFFF",
"DarkTurquoise": "00CED1",
"MediumSpringGreen": "00FA9A",
"Lime": "00FF00",
"SpringGreen": "00FF7F",
"Aqua": "00FFFF",
"Cyan": "00FFFF",
"MidnightBlue": "191970",
"DodgerBlue": "1E90FF",
"LightSeaGreen": "20B2AA",
"ForestGreen": "228B22",
"SeaGreen": "2E8B57",
"DarkSlateGray": "2F4F4F",
"DarkSlateGrey": "2F4F4F",
"LimeGreen": "32CD32",
"MediumSeaGreen": "3CB371",
"Turquoise": "40E0D0",
"RoyalBlue": "4169E1",
"SteelBlue": "4682B4",
"DarkSlateBlue": "483D8B",
"MediumTurquoise": "48D1CC",
"Indigo": "4B0082",
"DarkOliveGreen": "556B2F",
"CadetBlue": "5F9EA0",
"CornflowerBlue": "6495ED",
"RebeccaPurple": "663399",
"MediumAquaMarine": "66CDAA",
"DimGray": "696969",
"DimGrey": "696969",
"SlateBlue": "6A5ACD",
"OliveDrab": "6B8E23",
"SlateGray": "708090",
"SlateGrey": "708090",
"LightSlateGray": "778899",
"LightSlateGrey": "778899",
"MediumSlateBlue": "7B68EE",
"LawnGreen": "7CFC00",
"Chartreuse": "7FFF00",
"Aquamarine": "7FFFD4",
"Maroon": "800000",
"Purple": "800080",
"Olive": "808000",
"Gray": "808080",
"Grey": "808080",
"SkyBlue": "87CEEB",
"LightSkyBlue": "87CEFA",
"BlueViolet": "8A2BE2",
"DarkRed": "8B0000",
"DarkMagenta": "8B008B",
"SaddleBrown": "8B4513",
"DarkSeaGreen": "8FBC8F",
"LightGreen": "90EE90",
"MediumPurple": "9370DB",
"DarkViolet": "9400D3",
"PaleGreen": "98FB98",
"DarkOrchid": "9932CC",
"YellowGreen": "9ACD32",
"Sienna": "A0522D",
"Brown": "A52A2A",
"DarkGray": "A9A9A9",
"DarkGrey": "A9A9A9",
"LightBlue": "ADD8E6",
"GreenYellow": "ADFF2F",
"PaleTurquoise": "AFEEEE",
"LightSteelBlue": "B0C4DE",
"PowderBlue": "B0E0E6",
"FireBrick": "B22222",
"DarkGoldenRod": "B8860B",
"MediumOrchid": "BA55D3",
"RosyBrown": "BC8F8F",
"DarkKhaki": "BDB76B",
"Silver": "C0C0C0",
"MediumVioletRed": "C71585",
"IndianRed": "CD5C5C",
"Peru": "CD853F",
"Chocolate": "D2691E",
"Tan": "D2B48C",
"LightGray": "D3D3D3",
"LightGrey": "D3D3D3",
"Thistle": "D8BFD8",
"Orchid": "DA70D6",
"GoldenRod": "DAA520",
"PaleVioletRed": "DB7093",
"Crimson": "DC143C",
"Gainsboro": "DCDCDC",
"Plum": "DDA0DD",
"BurlyWood": "DEB887",
"LightCyan": "E0FFFF",
"Lavender": "E6E6FA",
"DarkSalmon": "E9967A",
"Violet": "EE82EE",
"PaleGoldenRod": "EEE8AA",
"LightCoral": "F08080",
"Khaki": "F0E68C",
"AliceBlue": "F0F8FF",
"HoneyDew": "F0FFF0",
"Azure": "F0FFFF",
"SandyBrown": "F4A460",
"Wheat": "F5DEB3",
"Beige": "F5F5DC",
"WhiteSmoke": "F5F5F5",
"MintCream": "F5FFFA",
"GhostWhite": "F8F8FF",
"Salmon": "FA8072",
"AntiqueWhite": "FAEBD7",
"Linen": "FAF0E6",
"LightGoldenRodYellow": "FAFAD2",
"OldLace": "FDF5E6",
"Red": "FF0000",
"Fuchsia": "FF00FF",
"Magenta": "FF00FF",
"DeepPink": "FF1493",
"OrangeRed": "FF4500",
"Tomato": "FF6347",
"HotPink": "FF69B4",
"Coral": "FF7F50",
"DarkOrange": "FF8C00",
"LightSalmon": "FFA07A",
"Orange": "FFA500",
"LightPink": "FFB6C1",
"Pink": "FFC0CB",
"Gold": "FFD700",
"PeachPuff": "FFDAB9",
"NavajoWhite": "FFDEAD",
"Moccasin": "FFE4B5",
"Bisque": "FFE4C4",
"MistyRose": "FFE4E1",
"BlanchedAlmond": "FFEBCD",
"PapayaWhip": "FFEFD5",
"LavenderBlush": "FFF0F5",
"SeaShell": "FFF5EE",
"Cornsilk": "FFF8DC",
"LemonChiffon": "FFFACD",
"FloralWhite": "FFFAF0",
"Snow": "FFFAFA",
"Yellow": "FFFF00",
"LightYellow": "FFFFE0",
"Ivory": "FFFFF0",
"White": "FFFFFF"
}
}

View File

@@ -45,6 +45,31 @@ Some of H3 mechanics can't be straight considered as bug, but default VCMI behav
Mouse click on castle icon in the town screen open quick recruitment window, where we can purhase in fast way units.
## Color support
Additional color are supported for text fields (e.g. map description). Uses HTML color syntax (e.g. #abcdef) / HTML predefined colors (e.g. green).
##### Original Heroes III Support
`This is white`
<span style="color:white;background-color:black;">This is white</span>
`{This is yellow}`
<span style="color:yellow;background-color:black;">This is yellow</span>
##### New
`{#ff0000|This is red}`
<span style="color:red">This is red</span>
`{green|This is green}`
<span style="color:green">This is green</span>
# Manuals and guides
- https://heroes.thelazy.net//index.php/Main_Page Wiki that aims to be a complete reference to Heroes of Might and Magic III.
- https://heroes.thelazy.net/index.php/Main_Page Wiki that aims to be a complete reference to Heroes of Might and Magic III.