关于imgui的richtext,issue有一篇文章一直讨论这个的,但是好像也没有特别好的办法
两种实现
自己参考了两个实现[1],做了下,大体思想是在imgui 渲染的地方根据字符串中特别标识的字段重新获取颜色出来。两种方法差不多,只是特别标识用的方法不太一样
用##aabbccdd这种颜色标识
实现代码
bool ParseColor(const char* s, ImU32* col) {
*col = 0;
if (s[0] != '#' || s[1] != '#') {
return false;
}
else {
for (int i = 0; i < 8; ++i) {
*col *= 16;
char c = s[i + 2];
if (c >= '0' && c <= '9') {
*col += c - '0';
}
else if (c >= 'A' && c <= 'F') {
*col += c - 'A' + 10;
}
else if (c >= 'a' && c <= 'f') {
*col += c - 'a' + 10;
}
else {
return false;
}
}
ImU32 flip_col = 0;
for (int i = 0; i < 4; ++i) {
flip_col <<= 8;
flip_col += (*col >> 8 * i) & 0x000000FF;
}
*col = flip_col;
return true;
}
}
然后在RenderText里面根据这个标识把颜色取出来
void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
// 省略...
{
int index = 0;
int chain = 0;
const char* s = text_begin;
ImU32 temp_col;
while (s < text_end) {
if (s < text_end - 10 && ParseColor(s, &temp_col)) {
col = temp_col;
s += 10;
}
else {
char_buf[index] = *s;
col_buf[index] = col;
++index;
++s;
}
}
text_begin = &char_buf[0];
text_end = &char_buf[index];
}
使用的时候如下:
ImGui::Text("##FF0000FFdear imgui says hello. (%s)", IMGUI_VERSION);
第二种做法是用Xterm color
代码实现和上面其实差不多,也是主要识别出那些字符是表示颜色的,然后把颜色摘出来不去绘制
// 识别颜色标识
bool ParseColor(const char* s, ImU32* col, int* skipChars)
{
if (s[0] != '\033' || s[1] != '[') {
return false;
}
if (s[2] == 'm') {
*col = 0xffcccccc;
*skipChars = 3;
return true;
}
if (s[2] == '0' && s[3] == 'm') {
*col = 0xffcccccc;
*skipChars = 4;
return true;
}
const char* seqEnd = &s[2];
while (*seqEnd != 'm') {
seqEnd++;
}
std::string seq{ &s[2], seqEnd };
std::string colorStr;
for (const auto& el : jet::split(seq, ";")) {
if (el[0] == '3' && el.size() == 2) {
colorStr = el;
break;
}
}
if (!colorStr.empty()) {
switch (colorStr[1]) {
case '0': *col = 0xffcccccc; break;
case '1': *col = 0xff7a77f2; break;
case '2': *col = 0xff99cc99; break;
case '3': *col = 0xff66ccff; break;
case '4': *col = 0xffcc9966; break;
case '5': *col = 0xffcc99cc; break;
case '6': *col = 0xffcccc66; break;
case '7': *col = 0xff2d2d2d; break;
default: return false;
}
}
*skipChars = static_cast<int>(seqEnd - s + 1);
return true;
}
// 渲染时候调用处理
{
for (int i = 0; i < text_end - text_begin; i++) {
char_skip[i] = false;
}
int index = 0;
int skipChars = 0;
const char* sLocal = s;
ImU32 temp_col = col;
while (sLocal < text_end) {
if (sLocal < text_end - 4 && ParseColor(sLocal, &temp_col, &skipChars)) {
sLocal += skipChars;
for (int i = 0; i < skipChars; i++) {
char_skip[index + i] = true;
}
index += skipChars;
}
else {
char_buf[index] = *sLocal;
col_buf[index] = temp_col;
char_skip[index] = false;
++index;
++sLocal;
}
}
}
使用代码
ImGui::TextRichColored(ImVec4(1, 0, 0, 1), "xxxxxxxxxxxx\033[48;5;34m xxxxxxxx \033[48;5;35m yyyy");
说明:
- 这里的ParseColor里面可以看到只支持一部分颜色,这是处理的不太好的地方,其实还有很多,可以看下参考[2][3]里面的256种颜色还是有很多的。最主要的是,他这里的颜色和真正的xterm颜色好像木有对上
ANSI and xterm color maps
参考[2]里面介绍了下Xterm的东东,大概是这种标识符不仅可以表示颜色,还可以表示一些控制的东东。但是有一部分标识码是用来表示256种颜色的
^[[99999S^[[99999;1HSystem colors (0..15 from xterm palette):
^[[48;5;0m ^[[48;5;1m ^[[48;5;2m ^[[48;5;3m ^[[48;5;4m ^[[48;5;5m ^[[48;5;6m ^[[48;5;7m ^[[0m
^[[48;5;8m ^[[48;5;9m ^[[48;5;10m ^[[48;5;11m ^[[48;5;12m ^[[48;5;13m ^[[48;5;14m ^[[48;5;15m ^[[0m
Color cube, 6x6x6 (16..231 from xterm palette):
^[[48;5;16m ^[[48;5;17m ^[[48;5;18m ^[[48;5;19m ^[[48;5;20m ^[[48;5;21m ^[[0m ^[[48;5;52m ^[[48;5;53m ^[[48;5;54m ^[[48;5;55m ^[[48;5;56m ^[[48;5;57m ^[[0m ^[[48;5;88m ^[[48;5;89m ^[[48;5;90m ^[[48;5;91m ^[[48;5;92m ^[[48;5;93m ^[[0m ^[[48;5;124m ^[[48;5;125m ^[[48;5;126m ^[[48;5;127m ^[[48;5;128m ^[[48;5;129m ^[[0m ^[[48;5;160m ^[[48;5;161m ^[[48;5;162m ^[[48;5;163m ^[[48;5;164m ^[[48;5;165m ^[[0m ^[[48;5;196m ^[[48;5;197m ^[[48;5;198m ^[[48;5;199m ^[[48;5;200m ^[[48;5;201m ^[[0m
^[[48;5;22m ^[[48;5;23m ^[[48;5;24m ^[[48;5;25m ^[[48;5;26m ^[[48;5;27m ^[[0m ^[[48;5;58m ^[[48;5;59m ^[[48;5;60m ^[[48;5;61m ^[[48;5;62m ^[[48;5;63m ^[[0m ^[[48;5;94m ^[[48;5;95m ^[[48;5;96m ^[[48;5;97m ^[[48;5;98m ^[[48;5;99m ^[[0m ^[[48;5;130m ^[[48;5;131m ^[[48;5;132m ^[[48;5;133m ^[[48;5;134m ^[[48;5;135m ^[[0m ^[[48;5;166m ^[[48;5;167m ^[[48;5;168m ^[[48;5;169m ^[[48;5;170m ^[[48;5;171m ^[[0m ^[[48;5;202m ^[[48;5;203m ^[[48;5;204m ^[[48;5;205m ^[[48;5;206m ^[[48;5;207m ^[[0m
^[[48;5;28m ^[[48;5;29m ^[[48;5;30m ^[[48;5;31m ^[[48;5;32m ^[[48;5;33m ^[[0m ^[[48;5;64m ^[[48;5;65m ^[[48;5;66m ^[[48;5;67m ^[[48;5;68m ^[[48;5;69m ^[[0m ^[[48;5;100m ^[[48;5;101m ^[[48;5;102m ^[[48;5;103m ^[[48;5;104m ^[[48;5;105m ^[[0m ^[[48;5;136m ^[[48;5;137m ^[[48;5;138m ^[[48;5;139m ^[[48;5;140m ^[[48;5;141m ^[[0m ^[[48;5;172m ^[[48;5;173m ^[[48;5;174m ^[[48;5;175m ^[[48;5;176m ^[[48;5;177m ^[[0m ^[[48;5;208m ^[[48;5;209m ^[[48;5;210m ^[[48;5;211m ^[[48;5;212m ^[[48;5;213m ^[[0m
^[[48;5;34m ^[[48;5;35m ^[[48;5;36m ^[[48;5;37m ^[[48;5;38m ^[[48;5;39m ^[[0m ^[[48;5;70m ^[[48;5;71m ^[[48;5;72m ^[[48;5;73m ^[[48;5;74m ^[[48;5;75m ^[[0m ^[[48;5;106m ^[[48;5;107m ^[[48;5;108m ^[[48;5;109m ^[[48;5;110m ^[[48;5;111m ^[[0m ^[[48;5;142m ^[[48;5;143m ^[[48;5;144m ^[[48;5;145m ^[[48;5;146m ^[[48;5;147m ^[[0m ^[[48;5;178m ^[[48;5;179m ^[[48;5;180m ^[[48;5;181m ^[[48;5;182m ^[[48;5;183m ^[[0m ^[[48;5;214m ^[[48;5;215m ^[[48;5;216m ^[[48;5;217m ^[[48;5;218m ^[[48;5;219m ^[[0m
^[[48;5;40m ^[[48;5;41m ^[[48;5;42m ^[[48;5;43m ^[[48;5;44m ^[[48;5;45m ^[[0m ^[[48;5;76m ^[[48;5;77m ^[[48;5;78m ^[[48;5;79m ^[[48;5;80m ^[[48;5;81m ^[[0m ^[[48;5;112m ^[[48;5;113m ^[[48;5;114m ^[[48;5;115m ^[[48;5;116m ^[[48;5;117m ^[[0m ^[[48;5;148m ^[[48;5;149m ^[[48;5;150m ^[[48;5;151m ^[[48;5;152m ^[[48;5;153m ^[[0m ^[[48;5;184m ^[[48;5;185m ^[[48;5;186m ^[[48;5;187m ^[[48;5;188m ^[[48;5;189m ^[[0m ^[[48;5;220m ^[[48;5;221m ^[[48;5;222m ^[[48;5;223m ^[[48;5;224m ^[[48;5;225m ^[[0m
^[[48;5;46m ^[[48;5;47m ^[[48;5;48m ^[[48;5;49m ^[[48;5;50m ^[[48;5;51m ^[[0m ^[[48;5;82m ^[[48;5;83m ^[[48;5;84m ^[[48;5;85m ^[[48;5;86m ^[[48;5;87m ^[[0m ^[[48;5;118m ^[[48;5;119m ^[[48;5;120m ^[[48;5;121m ^[[48;5;122m ^[[48;5;123m ^[[0m ^[[48;5;154m ^[[48;5;155m ^[[48;5;156m ^[[48;5;157m ^[[48;5;158m ^[[48;5;159m ^[[0m ^[[48;5;190m ^[[48;5;191m ^[[48;5;192m ^[[48;5;193m ^[[48;5;194m ^[[48;5;195m ^[[0m ^[[48;5;226m ^[[48;5;227m ^[[48;5;228m ^[[48;5;229m ^[[48;5;230m ^[[48;5;231m ^[[0m
Grayscale ramp (232..255 from xterm palette):
^[[48;5;232m ^[[48;5;233m ^[[48;5;234m ^[[48;5;235m ^[[48;5;236m ^[[48;5;237m ^[[48;5;238m ^[[48;5;239m ^[[48;5;240m ^[[48;5;241m ^[[48;5;242m ^[[48;5;243m ^[[48;5;244m ^[[48;5;245m ^[[48;5;246m ^[[48;5;247m ^[[48;5;248m ^[[48;5;249m ^[[48;5;250m ^[[48;5;251m ^[[48;5;252m ^[[48;5;253m ^[[48;5;254m ^[[48;5;255m ^[[0m
其中,这个^[是ascii种的ESC这个编码,也就是\033。
一开始看到这里的时候,其实我并不明白是啥意思,后来结合参考[3],大概明白了
(1) 从参考种的颜色xterm码来看,表示256种颜色不变的代码是**\033[48;5?m**,就把第三个数字换成0-255这个范围里面的字就是256种颜色
ANSI X3.64 and Xterm 256 colors in ConEmu
(2)参考[3]让我知道这个Xterm表示颜色的其实只有一个数字就表示了,他的范围是[00255],而还可以知道xterm和RGB对应的颜色
参考
[1]https://github.com/ocornut/imgui/issues/902
[2]https://conemu.github.io/en/AnsiEscapeCodes.html#SGR_Select_Graphic_Rendition_parameters
[3]https://jonasjacek.github.io/colors/