pthom / imgui_bundle

Dear ImGui Bundle: an extensive set of Ready-to-use widgets and libraries, based on ImGui. Start your first app in 5 lines of code, or less. Whether you prefer Python or C++, this pack has your back!
https://pthom.github.io/imgui_bundle/
MIT License
666 stars 66 forks source link

How to load fonts with specific glyph ranges (e.g., Chinese, Japanese, Korean) using hello_imgui.load_font #196

Open inkydragon opened 6 months ago

inkydragon commented 6 months ago

env:

https://github.com/pthom/imgui_bundle/blob/541ed1a1a25437cd196e53926676ff0c75174fff/bindings/imgui_bundle/imgui/__init__.pyi#L9451-L9460

struct ImFontConfig
{
    // ...

    ImVec2          GlyphExtraSpacing;      // 0, 0     // Extra spacing (in pixels) between glyphs. Only X axis is supported for now.
    ImVec2          GlyphOffset;            // 0, 0     // Offset all glyphs from this font input.
    const ImWchar*  GlyphRanges;            // NULL     // THE ARRAY DATA NEEDS TO PERSIST AS LONG AS THE FONT IS ALIVE. Pointer to a user-provided list of Unicode range (2 value per range, values are inclusive, zero-terminated list).
    float           GlyphMinAdvanceX;       // 0        // Minimum AdvanceX for glyphs, set Min to align font icons, set both Min/Max to enforce mono-space font
    float           GlyphMaxAdvanceX;       // FLT_MAX  // Maximum AdvanceX for glyphs

    // ...
};

https://github.com/ocornut/imgui/blame/d3c3514a59bb31406c954c2b525f330e9d167845/imgui.h#L2889

Context

I want to load Chinese fonts and specify glyph_range.

test code ```cpp void LoadDefaultFont_WithFontAwesomeIcons() { std::string fontFilename = "fonts/SarasaUiSC-Regular.ttf"; if (HelloImGui::AssetExists(fontFilename)) { HelloImGui::FontLoadingParams fontLoadingParams; fontLoadingParams.mergeFontAwesome = true; // NOTE fontLoadingParams.fontConfig.GlyphRanges = ImGui::GetIO().Fonts->GetGlyphRangesChineseSimplifiedCommon(); ImFont* font = LoadFont(fontFilename, 15.f, fontLoadingParams); (void) font; } else { ImGui::GetIO().Fonts->AddFontDefault(); } } ``` ```py def load_default_font_with_fa_icon(): font_filename = "fonts/SarasaUiSC-Regular.ttf" if hello_imgui.asset_exists(font_filename): font_loading_params = hello_imgui.FontLoadingParams() font_loading_params.merge_font_awesome = True sc_cn_range = imgui.get_io().fonts.get_glyph_ranges_chinese_simplified_common() # font_loading_params.font_config.??? = sc_cn_range hello_imgui.load_font(font_filename, 15.0, font_loading_params) logger.info(f"Loaded font: {font_filename}") else: imgui.get_io().fonts.add_font_default() logger.info(f"Loaded default font.") ```
Workaround ```py def load_default_font_with_fa_icon(): font_filename = "fonts/SarasaUiSC-Regular.ttf" if hello_imgui.asset_exists(font_filename): sc_cn_range = imgui.get_io().fonts.get_glyph_ranges_chinese_simplified_common() imgui.get_io().fonts.add_font_from_file_ttf( hello_imgui.asset_file_full_path(font_filename), 24.0, glyph_ranges_as_int_list=sc_cn_range) # font_loading_params = hello_imgui.FontLoadingParams() # font_loading_params.merge_font_awesome = True # # font_loading_params.font_config.??? = sc_cn_range # hello_imgui.load_font(font_filename, 15.0, font_loading_params) logger.info(f"Loaded font: {font_filename}") else: imgui.get_io().fonts.add_font_default() logger.info(f"Loaded default font.") ```
pthom commented 6 months ago

I don't understand your question (there is none in your message, in fact). Does your work around work?

pthom commented 2 months ago

Hello,

I come back to this question after a few months, sorry for the delay.

I understand that you needed a way to translate the glyph ranges coming from Dear ImGui, into ranges used by hello_imgui.load_font.

This commit adds support for this.

Example usage:

"""Demonstrates how to load a font with Chinese characters and display them in the GUI,
using the common glyph ranges defined in by ImGui.
"""
from imgui_bundle import imgui, hello_imgui, imgui_ctx
from imgui_bundle.demos_python import demo_utils

demo_utils.set_hello_imgui_demo_assets_folder()

font_cn: imgui.ImFont = None

def load_font():
    global font_cn
    if not hello_imgui.asset_exists("fonts/NotoSerifSC-VariableFont_wght.ttf"):
        return

    # Note: this font is not provided with the ImGui bundle (too large).
    # You will need to provide it yourself, or use another font.
    font_filename = "fonts/NotoSerifSC-VariableFont_wght.ttf"

    # The range of Chinese characters is defined by ImGui as a single list of characters (List[ImWchar]), with a terminating 0.
    # (each range is a pair of successive characters in this list, with the second character being the last one in the range)
    cn_glyph_ranges_imgui = imgui.get_io().fonts.get_glyph_ranges_chinese_simplified_common()
    # We need to convert this list into a list of pairs (List[ImWcharPair]), where each pair is a range of characters.
    cn_glyph_ranges_pair = hello_imgui.translate_common_glyph_ranges(cn_glyph_ranges_imgui)

    font_loading_params = hello_imgui.FontLoadingParams()
    font_loading_params.glyph_ranges = cn_glyph_ranges_pair
    font_cn = hello_imgui.load_font(font_filename, 40.0, font_loading_params)

def gui():
    if font_cn is not None:
        with imgui_ctx.push_font(font_cn):
            imgui.text("Hello world")
            imgui.text("你好,世界")
    else:
        imgui.text("Font file not found")
        imgui.text_wrapped("""
        This font is not provided with the ImGui bundle (too large).
        You will need to provide it yourself, or use another font.
        """)

runner_params = hello_imgui.RunnerParams()
runner_params.callbacks.load_additional_fonts = load_font
runner_params.callbacks.show_gui = gui
hello_imgui.run(runner_params)
image