Incorrect visual selection in ImGui::InputTextMultiline with Japanese.
Version/Branch of Dear ImGui:
master
Back-ends:
imgui_impl_glfw.cpp + imgui_impl_opengl2.cpp
Compiler, OS:
gcc (Rev3, Built by MSYS2 project) 14.2.0, Windows 10.
Full config/build information:
No response
Details:
If you wrap a line by characters, the visual selection will be on the next line, if you do not select from the beginning of the first line.
Screenshots/Video:
Minimal, Complete and Verifiable Example code:
ImGuiIO &io = ImGui::GetIO();
io.FontGlobalScale = 1.0;
ImVector<ImWchar> ranges;
ImFontGlyphRangesBuilder builder;
builder.AddRanges(io.Fonts->GetGlyphRangesCyrillic());
builder.AddRanges(io.Fonts->GetGlyphRangesJapanese());
builder.BuildRanges(&ranges);
io.Fonts->AddFontFromMemoryCompressedTTF(Unifont_compressed_data,
Unifont_compressed_size, 16, nullptr, ranges.Data); // unifont-16.0.02
io.Fonts->Build();
struct {
std::string selected_text;
int selection_start = 0;
int selection_end = 0;
} static selection;
const float wrap_width = ImGui::GetContentRegionAvail().x;
ImFont* font = ImGui::GetFont();
std::string text = u8" 誰も彼も眠った頃、夜の冷気で瞼を開ける。\r\n";
std::string wrapped_text;
const char* text_start = text.c_str();
const char* text_end = text_start + text.size();
while (text_start < text_end) {
const char* line_end = font->CalcWordWrapPositionA(1.0f,
text_start, text_end, wrap_width);
if (line_end == text_start) line_end++;
wrapped_text.append(text_start, line_end);
if (line_end < text_end && *line_end != '\n') {
wrapped_text += '\n';
}
text_start = line_end;
}
const float line_height = ImGui::GetTextLineHeightWithSpacing();
const float height = (std::count(wrapped_text.begin(),
wrapped_text.end(), '\n') + 1) * line_height;
ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0));
std::string input_id = "##input_1";
ImGui::InputTextMultiline(
input_id.c_str(),
const_cast<char*>(wrapped_text.c_str()),
wrapped_text.size() + 1,
ImVec2(wrap_width, height),
ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
ImGui::PopStyleColor();
if (ImGui::IsItemActive()) {
ImGuiInputTextState* state = ImGui::GetInputTextState(ImGui::GetItemID());
if (state && state->HasSelection()) {
selection.selection_start = state->GetSelectionStart();
selection.selection_end = state->GetSelectionEnd();
} else {
selection.selection_start = 0;
selection.selection_end = 0;
}
}
Could you try reducing your code to the required minimum, e.g. the wrapping logic doesn't need to be there, you can use the final wrapped string + see if it happens with another font (or even with the default font that doesn't have japanese glyphs?).
Sorry I posted an incorrect message, I had a theory and while investigating I discovered another thing, and posted the old draft.
I called ImGui::DebugTextEncoding(wrapped_text.c_str());:
And notice the wrapping code was wrong because it introduce \n in the middle of multibyte characters.
The U+3000 (0xE3 0x80 0x80) becomes 0xE3 0x0A 0x80 0x80 which are two invalid values.
And InputText() seems to have issue dealing with the invalid UTF-8 codepoints, which wouldn't be the first time (see #6397).
So there are multiple problems:
- (1) CalcWordWrapPosition didn't handle ideographic comma (、)and full stop (。) so the line was not wrapped. Fixed by b4bd596.
- (2) CalcWordWrapPosition has a fallback when there's no wrapping, that it moves by a single character, but it used +1 instead of coutning UTf-8 bytes. Fixed by fcab22f.
- (3) I am not sure I understand why the fallback in (2) is taken, I will investigate.
- (4) InputText() has a bug dealing with
\nand invalid UTF-8 codepoint, which were generated by the combinations of 1 and 2 above. I don't think this would affect you anymore, but I am going to investigate that too.
There are errors in my code. Can you tell me how to fix them?
There is no error in the code you posted above. You can update to get the 2 fixes I pushed already.
The issue in (3) could separately be improved but with the 2 fixes you shouldn't get that bug.
There are errors in my code.
Sorry maybe you read email notification for my first message (which I deleted now, it was a draft before I realized the culprit was an a combination of issues in CalcWordWrapPosition). Read the second message on GitHub topic.