diff --git a/desktop_version/src/CustomLevels.cpp b/desktop_version/src/CustomLevels.cpp index feaaa500..7d882e1d 100644 --- a/desktop_version/src/CustomLevels.cpp +++ b/desktop_version/src/CustomLevels.cpp @@ -227,6 +227,7 @@ TAG_FINDER(find_desc2, "Desc2") TAG_FINDER(find_desc3, "Desc3") TAG_FINDER(find_website, "website") TAG_FINDER(find_font, "font") +TAG_FINDER(find_rtl, "rtl") /* For CliPlaytestArgs */ TAG_FINDER(find_playtest, "Playtest") @@ -315,6 +316,7 @@ bool customlevelclass::getLevelMetaDataAndPlaytestArgs(const std::string& _path, { _data.level_main_font_idx = font::get_font_idx_8x8(); } + _data.rtl = help.Int(find_rtl(buf).c_str()); if (pt_args != NULL) @@ -1037,6 +1039,7 @@ bool customlevelclass::load(std::string _path) version = 0; level_font_name = "font"; + rtl = false; for (pElem = hDoc .FirstChildElement() @@ -1104,6 +1107,11 @@ bool customlevelclass::load(std::string _path) { level_font_name = pText_; } + + if(SDL_strcmp(pKey_, "rtl") == 0) + { + rtl = help.Int(pText_); + } } } @@ -1524,6 +1532,20 @@ bool customlevelclass::save(const std::string& _path) } } + if (rtl) + { + xml::update_tag(msg, "rtl", rtl); + } + else + { + // Also get rid of this one... + tinyxml2::XMLElement* element; + while ((element = msg->FirstChildElement("rtl")) != NULL) + { + doc.DeleteNode(element); + } + } + xml::update_tag(data, "mapwidth", mapwidth); xml::update_tag(data, "mapheight", mapheight); diff --git a/desktop_version/src/CustomLevels.h b/desktop_version/src/CustomLevels.h index fe3aa9d6..ac9fcdf4 100644 --- a/desktop_version/src/CustomLevels.h +++ b/desktop_version/src/CustomLevels.h @@ -66,6 +66,7 @@ struct LevelMetaData /* This is for the metadata in the levels list, * so it will only be a main font (no custom ones). */ uint8_t level_main_font_idx; + bool rtl; }; struct CliPlaytestArgs @@ -161,6 +162,7 @@ public: int mapwidth, mapheight; //Actual width and height of stage std::string level_font_name; + bool rtl; int version; diff --git a/desktop_version/src/Font.cpp b/desktop_version/src/Font.cpp index b0009d40..abffcb6a 100644 --- a/desktop_version/src/Font.cpp +++ b/desktop_version/src/Font.cpp @@ -85,6 +85,7 @@ struct PrintFlags bool align_right; bool cjk_low; bool cjk_high; + bool rtl; }; static FontContainer fonts_main = {}; @@ -558,6 +559,8 @@ void set_level_font(const char* name) } } } + + cl.rtl = SDL_strcmp(name, "font_ar") == 0; // FIXME: make different menu options for choosing LTR/RTL of the same font } void set_level_font_interface(void) @@ -590,6 +593,7 @@ void set_level_font_new(void) } cl.level_font_name = get_main_font_name(font_idx_level); + cl.rtl = cl.level_font_name == "font_ar"; // FIXME: make different menu options for choosing LTR/RTL of the same font } static void fill_map_name_idx(FontContainer* container) @@ -763,13 +767,19 @@ static Font* container_get(FontContainer* container, uint8_t idx) return NULL; } -static Font* fontsel_to_font(int sel) +static Font* fontsel_to_font(int sel, bool* rtl) { /* Take font selection integer (0-31) and turn it into the correct Font * 0: PR_FONT_INTERFACE - use interface font * 1: PR_FONT_LEVEL - use level font * 2: PR_FONT_8X8 - use 8x8 font no matter what - * 3-31: - use (main) font index 0-28 */ + * 3-31: - use (main) font index 0-28 + * + * rtl will be set depending on whether we're requesting the interface + * font (take it from the lang attributes) or level font (take it from + * the level attributes), or false otherwise. */ + + *rtl = false; if (sel < 0) { @@ -782,6 +792,7 @@ static Font* fontsel_to_font(int sel) case 1: if (!font_level_is_interface) { + *rtl = cl.rtl; if (font_idx_level_is_custom) { return container_get(&fonts_custom, font_idx_level); @@ -793,6 +804,7 @@ static Font* fontsel_to_font(int sel) } SDL_FALLTHROUGH; case 0: + *rtl = loc::get_langmeta()->rtl; return container_get(&fonts_main, loc::get_langmeta()->font_idx); case 2: return container_get(&fonts_main, font_idx_8x8); @@ -806,7 +818,11 @@ static PrintFlags decode_print_flags(uint32_t flags) { PrintFlags pf; pf.scale = FLAG_PART(0, 3) + 1; - pf.font_sel = fontsel_to_font(FLAG_PART(3, 5)); + pf.font_sel = fontsel_to_font(FLAG_PART(3, 5), &pf.rtl); + if (flags & PR_RTL_FORCE) + { + pf.rtl = true; + } pf.brightness = ~FLAG_PART(8, 8) & 0xff; pf.border = flags & PR_BOR; pf.full_border = flags & PR_FULLBOR; @@ -1206,9 +1222,9 @@ int len(const uint32_t flags, const char* text) { PrintFlags pf = decode_print_flags(flags); - if (bidi_should_transform(text)) + if (bidi_should_transform(pf.rtl, text)) { - text = bidi_transform(text); + text = bidi_transform(pf.rtl, text); } int text_len = 0; @@ -1313,9 +1329,9 @@ void print( y -= h_diff_8/2; } - if (bidi_should_transform(text)) + if (bidi_should_transform(pf.rtl, text)) { - text = bidi_transform(text); + text = bidi_transform(pf.rtl, text); } int position = 0; diff --git a/desktop_version/src/Font.h b/desktop_version/src/Font.h index afdebdbd..8b6c86d6 100644 --- a/desktop_version/src/Font.h +++ b/desktop_version/src/Font.h @@ -42,7 +42,8 @@ #define PR_FONT_INTERFACE (0 << 3) /* default, use interface font */ #define PR_FONT_LEVEL (1 << 3) /* use level-specific font (room names, cutscene dialogue, etc) */ #define PR_FONT_8X8 (2 << 3) /* use 8x8 font no matter what */ -#define PR_FONT_IDX(idx) ((SDL_clamp(idx, 0, 28) + 3) << 3) /* use given font index */ +#define PR_FONT_IDX(idx, rtl) /* use given font index */\ + (((SDL_clamp(idx, 0, 28) + 3) << 3) | (rtl ? PR_RTL_FORCE : 0)) #define PR_BRIGHTNESS(value) /* use this brightness 0-255 for the text (accounts for button glyphs correctly) */\ (((~SDL_clamp((int)(value), 0, 255) & 0xff) << 8)) #define PR_FULLBOR (1 << 16) /* draw a black border around the text, filling in the corners (for the map legend) */ @@ -53,6 +54,7 @@ #define PR_CJK_CEN (0 << 20) /* default, larger fonts should stick out on top and bottom compared to 8x8 font */ #define PR_CJK_LOW (1 << 20) /* larger fonts should stick out fully on the bottom (draw at Y) */ #define PR_CJK_HIGH (2 << 20) /* larger fonts should stick out fully on the top */ +#define PR_RTL_FORCE (1 << 22) /* force the RTL flag, not needed if the font is set to INTERFACE or LEVEL */ namespace font diff --git a/desktop_version/src/FontBidi.cpp b/desktop_version/src/FontBidi.cpp index 199c1797..582bc032 100644 --- a/desktop_version/src/FontBidi.cpp +++ b/desktop_version/src/FontBidi.cpp @@ -282,11 +282,16 @@ bool is_joiner(const uint32_t codepoint) return codepoint == 0x200C || codepoint == 0x200D; } -bool bidi_should_transform(const char* text) +bool bidi_should_transform(const bool rtl, const char* text) { /* Just as an optimization, only run the whole bidi machinery if the * language is actually an RTL one, _or_ if an RTL character is found. */ + if (rtl) + { + return true; + } + const char* text_ptr = text; uint32_t ch; while ((ch = UTF8_next(&text_ptr))) @@ -313,7 +318,7 @@ bool bidi_should_transform(const char* text) return false; } -const char* bidi_transform(const char* text) +const char* bidi_transform(const bool rtl, const char* text) { uint32_t utf32_in[1024]; int n_codepoints = 0; @@ -345,7 +350,12 @@ const char* bidi_transform(const char* text) { return text; } - SBParagraphRef paragraph = SBAlgorithmCreateParagraph(algorithm, 0, INT32_MAX, SBLevelDefaultRTL); + SBParagraphRef paragraph = SBAlgorithmCreateParagraph( + algorithm, + 0, + INT32_MAX, + rtl ? SBLevelDefaultRTL : SBLevelDefaultLTR + ); SDL_assert(paragraph != NULL); SBUInteger paragraph_len = SBParagraphGetLength(paragraph); SBLineRef paragraph_line = SBParagraphCreateLine(paragraph, 0, paragraph_len); diff --git a/desktop_version/src/FontBidi.h b/desktop_version/src/FontBidi.h index 6824dd51..bad7ed09 100644 --- a/desktop_version/src/FontBidi.h +++ b/desktop_version/src/FontBidi.h @@ -10,8 +10,8 @@ void bidi_init(void); void bidi_destroy(void); bool is_directional_character(uint32_t codepoint); bool is_joiner(uint32_t codepoint); -bool bidi_should_transform(const char* text); -const char* bidi_transform(const char* text); +bool bidi_should_transform(bool rtl, const char* text); +const char* bidi_transform(bool rtl, const char* text); } // namespace font diff --git a/desktop_version/src/Game.cpp b/desktop_version/src/Game.cpp index e3017e25..2a64171e 100644 --- a/desktop_version/src/Game.cpp +++ b/desktop_version/src/Game.cpp @@ -6357,7 +6357,7 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) text, true, cl.ListOfMetaData[i].title_is_gettext ? PR_FONT_INTERFACE : PR_FONT_IDX( - cl.ListOfMetaData[i].level_main_font_idx + cl.ListOfMetaData[i].level_main_font_idx, cl.ListOfMetaData[i].rtl ) ); } @@ -6487,7 +6487,7 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) for (uint8_t i = 0; i < font::font_idx_options_n; i++) { uint8_t idx = font::font_idx_options[i]; - option(font::get_main_font_display_name(idx), true, PR_FONT_IDX(idx)); + option(font::get_main_font_display_name(idx), true, PR_FONT_IDX(idx, false)); if (font::level_font_is_main_idx(idx)) { option_match = i; @@ -6586,9 +6586,17 @@ void Game::createmenu( enum Menu::MenuName t, bool samemenu/*= false*/ ) for (size_t i = 0; i < loc::languagelist.size(); i++) { if (loc::languagelist[i].nativename.empty()) + { option(loc::languagelist[i].code.c_str()); + } else - option(loc::languagelist[i].nativename.c_str(), true, PR_FONT_IDX(loc::languagelist[i].font_idx)); + { + option( + loc::languagelist[i].nativename.c_str(), + true, + PR_FONT_IDX(loc::languagelist[i].font_idx, loc::languagelist[i].rtl) + ); + } } menuyoff = 70-(menuoptions.size()*10); diff --git a/desktop_version/src/LocalizationMaint.cpp b/desktop_version/src/LocalizationMaint.cpp index 926ba86b..88c8a872 100644 --- a/desktop_version/src/LocalizationMaint.cpp +++ b/desktop_version/src/LocalizationMaint.cpp @@ -64,7 +64,7 @@ static void sync_lang_file(const std::string& langcode) loadtext(false); uint8_t glyph_w = 8, glyph_h = 8; - font::glyph_dimensions(PR_FONT_IDX(langmeta.font_idx), &glyph_w, &glyph_h); + font::glyph_dimensions(PR_FONT_IDX(langmeta.font_idx, langmeta.rtl), &glyph_w, &glyph_h); bool max_local_needed = glyph_w != 8 || glyph_h != 8; tinyxml2::XMLDocument doc; diff --git a/desktop_version/src/LocalizationStorage.cpp b/desktop_version/src/LocalizationStorage.cpp index 57783b73..9632f46d 100644 --- a/desktop_version/src/LocalizationStorage.cpp +++ b/desktop_version/src/LocalizationStorage.cpp @@ -311,7 +311,7 @@ static bool max_check_string(const char* str, const char* max) } uint8_t font_idx = get_langmeta()->font_idx; - uint32_t print_flags = PR_FONT_IDX(font_idx) | PR_CJK_LOW; + uint32_t print_flags = PR_FONT_IDX(font_idx, get_langmeta()->rtl) | PR_CJK_LOW; uint8_t font_w = 8; uint8_t font_h = 8; font::glyph_dimensions(print_flags, &font_w, &font_h); diff --git a/desktop_version/src/Render.cpp b/desktop_version/src/Render.cpp index 52f40b1b..ae8f7eea 100644 --- a/desktop_version/src/Render.cpp +++ b/desktop_version/src/Render.cpp @@ -266,7 +266,10 @@ static void menurender(void) } else { - uint32_t level_flags = PR_FONT_IDX(cl.ListOfMetaData[tmp].level_main_font_idx); + uint32_t level_flags = PR_FONT_IDX( + cl.ListOfMetaData[tmp].level_main_font_idx, + cl.ListOfMetaData[tmp].rtl + ); uint32_t title_flags = cl.ListOfMetaData[tmp].title_is_gettext ? PR_FONT_INTERFACE : level_flags; uint32_t creator_flags = cl.ListOfMetaData[tmp].creator_is_gettext ? PR_FONT_INTERFACE : level_flags; diff --git a/desktop_version/src/main.cpp b/desktop_version/src/main.cpp index 6c928cf7..52674f0a 100644 --- a/desktop_version/src/main.cpp +++ b/desktop_version/src/main.cpp @@ -937,7 +937,7 @@ static void unfocused_run(void) #define FLIP_PR_CJK_HIGH (graphics.flipmode ? PR_CJK_LOW : PR_CJK_HIGH) /* The pause screen can also appear on the language screen, where highlighting * a language changes the used language metadata but not the loaded strings... */ - uint32_t flags = PR_CEN | PR_BOR | PR_FONT_IDX(loc::langmeta.font_idx); + uint32_t flags = PR_CEN | PR_BOR | PR_FONT_IDX(loc::langmeta.font_idx, loc::langmeta.rtl); font::print(flags | FLIP_PR_CJK_HIGH, -1, FLIP(110), loc::gettext("Game paused"), 196 - help.glow, 255 - help.glow, 196 - help.glow); if (BUTTONGLYPHS_keyboard_is_available())