c++imgui

How to Display Special Characters (₹,₤,₿..) in ImGui Window?


I'm working on an application using ImGui for the UI, and I'm having trouble displaying special characters like the Indian Rupee symbol (₹) in my ImGui windows. Currently, these characters are showing up as ? instead of the correct symbols.I'm specifically using OpenGL as the underlying renderer.

Here's what I've done so far:

  1. Loaded a Font: I made sure to load a font that should support special characters.

  2. Replacement Function: I have a function that replaces certain placeholder strings with special characters.

I have a function that replaces certain placeholder strings with special characters, including the Indian Rupee symbol. Here's the function:

  std::string replacedStr = str;
  std::map<std::string, std::string> replacements = {
    {"1397904493", "®"}, {"1397776754", "¶"}, {"1400073811", "§"},
    {"1396991858", "°"}, {"1396929140", "©"}, {"1398041963", "™"},
    {"1397059140", "–"}, {"1397058884", "—"}, {"1397969521", "’"},
    {"1397967985", "‘"}, {"1396986737", "\""}, {"1397969777", "'"},
    {"1397645907", " "}, {"1396984945", "“"}, {"1396986481", "”"},
    {"1396862068", "•"}, {"1397518451", "…"}, {"1398320179", "₹"}
  // Added mapping for the Indian Rupee symbol }; for (const auto &pair
  // : replacements) { size_t pos = replacedStr.find(pair.first); while
  // (pos != std::string::npos) { replacedStr.replace(pos,
  // pair.first.length(), pair.second); pos =
  // replacedStr.find(pair.first, pos + 1); } } return replacedStr; }

Im getting the following result for some special chars enter image description here

here you can see the code about conversion and rendering methods

enter image description here

or

for (size_t i = 0; i < contents.size();) {
 // Get the Unicode value of the current character and convert it to UTF-8
 uint32_t unicode = workose_studio_getUTF8Unicode(contents, i);
 std::string charStr = utf8::utf32to8(std::u32string(1, unicode));
 std::cout << " charStr :: " << charStr << " unicode :: " << unicode << std::endl;
 // Render the character
 draw_list->AddText(retrievedFont, retrievedFont->FontSize, adjusted_pen_pos, ImGui::GetColorU32(text_color), charStr.c_str(), NULL, 0.0f, NULL);
}

// Console output
// contents :: Char's : ₹ $ £ ¥ € ₠ ₡ ₤ ₥ ₦ ₧ ₨ ₩ ₪ ₫ € ₭ ₮ ₯ ₰ ₱ ₲ ₳ ₴ ₵ ₶ ₷ ₸ ₹ ₺ ₻ ₼ ₽ ₾ ₿
// charStr :: unicode :: 32
// charStr :: C unicode :: 67
// charStr :: h unicode :: 104
// charStr :: a unicode :: 97
// charStr :: r unicode :: 114
// charStr :: ' unicode :: 39
// charStr :: s unicode :: 115
// charStr :: unicode :: 32
// charStr :: : unicode :: 58
// charStr :: unicode :: 32
// charStr :: ₹ unicode :: 8377
// charStr :: unicode :: 32
// charStr :: $ unicode :: 36
// charStr :: unicode :: 32
// charStr :: £ unicode :: 163
// charStr :: unicode :: 32
// charStr :: ¥ unicode :: 165
// charStr :: unicode :: 32
// charStr :: € unicode :: 8364
// charStr :: unicode :: 32
// charStr :: ₠ unicode :: 8352
// charStr :: unicode :: 32
// charStr :: ₡ unicode :: 8353
// charStr :: unicode :: 32
// charStr :: ₤ unicode :: 8356
// charStr :: unicode :: 9
// charStr :: ₥ unicode :: 8357
// charStr :: unicode :: 32
// charStr :: ₦ unicode :: 8358
// charStr :: unicode :: 32
// charStr :: ₧ unicode :: 8359
// charStr :: unicode :: 9
// charStr :: ₨ unicode :: 8360
// charStr :: unicode :: 32
// charStr :: ₩ unicode :: 8361
// charStr :: unicode :: 32
// charStr :: ₪ unicode :: 8362
// charStr :: unicode :: 9
// charStr :: ₫ unicode :: 8363
// charStr :: unicode :: 32
// charStr :: € unicode :: 8364
// charStr :: unicode :: 32
// charStr :: ₭ unicode :: 8365
// charStr :: unicode :: 32
// charStr :: ₮ unicode :: 8366
// charStr :: unicode :: 32
// charStr :: ₯ unicode :: 8367
// charStr :: unicode :: 32
// charStr :: ₰ unicode :: 8368
// charStr :: unicode :: 32
// charStr :: ₱ unicode :: 8369
// charStr :: unicode :: 32
// charStr :: ₲ unicode :: 8370
// charStr :: unicode :: 32
// charStr :: ₳ unicode :: 8371
// charStr :: unicode :: 32
// charStr :: ₴ unicode :: 8372
// charStr :: unicode :: 32
// charStr :: ₵ unicode :: 8373
// charStr :: unicode :: 32
// charStr :: ₶ unicode :: 8374
// charStr :: unicode :: 32
// charStr :: ₷ unicode :: 8375

-------------------------------------- Font loading code ---------------------------------------

// Function to load fonts for ImGui in a custom application
void workose_studio_load_fonts()
{
   
    std::string defaultfont = workose_project_root_directory + "fonts/Roboto-Regular.ttf";

    // Get ImGui input/output configuration
    ImGuiIO &io = ImGui::GetIO();
    ImFontConfig config;

    // Get the default glyph range for the font
    const ImWchar *glyph_ranges = io.Fonts->GetGlyphRangesDefault();

    // Add the default font to ImGui with specified parameters
    ImFont *font = ImGui::GetIO().Fonts->AddFontFromFileTTF(
        defaultfont.c_str(),
        18,
        &config,
        glyph_ranges);

    // Store information about the default font
    workose_studio_font_data.font = font;
    workose_studio_font_data.path = defaultfont;

    // Map the default font information to the key "default"
    workose_studio_g_myFonts.fontMap["default"] = workose_studio_font_data;

    // Get the glyph range for Chinese characters
    const ImWchar *glyph_ranges1 = io.Fonts->GetGlyphRangesChineseFull();

    // Initialize an array to store font names
    std::vector<std::string> font_name;

    // Check if layout and element details are available
    if (workose_studio_get_layout_and_element_details.size() > 0)
    {
        // Iterate over layout elements
        for (nlohmann::json::iterator it = workose_studio_get_layout_and_element_details[0][0].begin(); it != workose_studio_get_layout_and_element_details[0][0].end(); ++it)
        {
            nlohmann::json layout_elements = it.value()["layout_elements"];

            // Iterate over layout element details
            for (nlohmann::json::iterator it = layout_elements.begin(); it != layout_elements.end(); ++it)
            {
                std::string element_type = it.value()["LAYOUT_ELEMENT_TYPE"];

                // Check if the element type is "text"
                if (element_type == "text")
                {
                    nlohmann::json paragraphs;
                    // Extract and decode element JSON style attributes
                    std::string element_json_style_attributes = it.value()["ELEMENT_JSON_STYLE_ATTRIBUTES"];
                    std::string decode_data = urldecode(element_json_style_attributes);
                    nlohmann::json json_data = nlohmann::json::parse(decode_data);

                    // Check for the presence of specific style attributes
                    if (json_data.find("frame_style") != json_data.end() && json_data["frame_style"].find("tableDetils") != json_data["frame_style"].end())
                    {

                        // Check if the "tableDetils" field is empty
                        if (json_data["frame_style"]["tableDetils"].empty())
                        {
                            nlohmann::json decoded_json = nlohmann::json::parse(decode_data);
                            // Check for the presence of "paragraphs" in the decoded JSON
                            if (decoded_json.contains("paragraphs"))
                            {
                                paragraphs = decoded_json["paragraphs"];
                                // Store used fonts from paragraphs
                                storeusedfonts(paragraphs);
                            }
                        }
                        else
                        {
                            // table condition
                            const nlohmann::json &frame_style = json_data["frame_style"];
                            // Check for the presence of "tableDetils" in "frame_style"
                            if (frame_style.contains("tableDetils"))
                            {
                                const nlohmann::json &table_details = frame_style["tableDetils"];
                                // Check for the presence of "tableContentArray" in "tableDetils"
                                if (table_details.contains("tableContentArray"))
                                {
                                    const nlohmann::json &table_content_array = table_details["tableContentArray"];
                                    size_t numColumns = table_content_array[std::to_string(0)].size();

                                    // Iterate over table columns and rows
                                    for (size_t x = 0; x < numColumns; ++x)
                                    {
                                        for (size_t j = 0; j < table_content_array.size(); ++j)
                                        {
                                            const nlohmann::json &row_j = table_content_array[std::to_string(j)];

                                            // Check for the presence of the current column in the current row
                                            if (row_j.contains(std::to_string(x)))
                                            {
                                                const nlohmann::json &cell_ij = row_j[std::to_string(x)];

                                                // Check for the presence of "style" in the cell
                                                if (cell_ij.contains("style"))
                                                {
                                                    const nlohmann::json &styleObj = cell_ij["style"];

                                                    // Check for the presence of "paragraphs" in the style
                                                    if (styleObj.contains("paragraphs"))
                                                    {
                                                        paragraphs = styleObj["paragraphs"];
                                                        // Store used fonts from paragraphs
                                                        storeusedfonts(paragraphs);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

Solution

  • The Rupee sign (U+20B9) is not covered by the ImGui default glyph range or the Chinese range. You need to construct a custom glyph range (just pairs of start and stop codepoints) and specify that when loading the font. Same for the other missing glyphs.

    The FAQ entry for this has the following examples:

    ImVector<ImWchar> ranges;
    ImFontGlyphRangesBuilder builder;
    builder.AddText("Hello world");                        // Add a string (here "Hello world" contains 7 unique characters)
    builder.AddChar(0x20B9);                               // Add a specific character
    builder.AddRanges(io.Fonts->GetGlyphRangesJapanese()); // Add one of the default ranges
    builder.BuildRanges(&ranges);                          // Build the final result (ordered ranges with all the unique characters submitted)
    io.Fonts->AddFontFromFileTTF("myfontfile.ttf", 16.0f, nullptr, ranges.Data);