From 44796bc8c0eaf26b8446b0d44ac28c232d20b80e Mon Sep 17 00:00:00 2001 From: Benau Date: Tue, 11 Jun 2019 15:05:46 +0800 Subject: [PATCH] Use a better way to erase top text --- lib/irrlicht/include/GlyphLayout.h | 32 +++++ lib/irrlicht/include/utfwrapping.h | 113 ------------------ src/network/protocols/client_lobby.cpp | 47 ++++---- .../online/networking_lobby.cpp | 63 +++++----- .../online/networking_lobby.hpp | 5 +- 5 files changed, 89 insertions(+), 171 deletions(-) delete mode 100644 lib/irrlicht/include/utfwrapping.h diff --git a/lib/irrlicht/include/GlyphLayout.h b/lib/irrlicht/include/GlyphLayout.h index 81e3e150d..74fbd687d 100644 --- a/lib/irrlicht/include/GlyphLayout.h +++ b/lib/irrlicht/include/GlyphLayout.h @@ -59,6 +59,38 @@ namespace Private f32 inverse_shaping, f32 scale, std::vector >& result); } +inline void eraseTopLargerThan(std::vector& gls, + f32 height_per_line, f32 max_height) +{ + if (max_height < height_per_line * 2.0f) + return; + + std::vector newline_positions; + for (unsigned i = 0; i < gls.size(); i++) + { + const GlyphLayout& glyph = gls[i]; + if ((glyph.flags & GLF_NEWLINE) != 0) + { + newline_positions.push_back(i); + continue; + } + } + + // Handle the first line + f32 total_height = height_per_line + + (f32)newline_positions.size() * height_per_line; + if (total_height > max_height) + { + u32 idx = (u32)((total_height - max_height) / height_per_line); + if (idx < newline_positions.size()) + { + auto end_it = gls.begin() + newline_positions[idx] + 1; + if (end_it != gls.end()) + gls.erase(gls.begin(), end_it); + } + } +} + inline core::dimension2d getGlyphLayoutsDimension( const std::vector& gls, s32 height_per_line, f32 inverse_shaping, f32 scale, s32 cluster = -1) diff --git a/lib/irrlicht/include/utfwrapping.h b/lib/irrlicht/include/utfwrapping.h deleted file mode 100644 index 1a4f4a348..000000000 --- a/lib/irrlicht/include/utfwrapping.h +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright (C) 2015 Ben Au -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -namespace irr -{ -namespace gui -{ - -//Here a list of characters that don't start or end a line for chinese/japanese/korean -//Only commonly use and full width characters are included -//You should use full width characters when writing CJK, like using "。"instead of a "." -//You can add more characters if needed -//For full list please visit http://webapp.docx4java.org/OnlineDemo/ecma376/WordML/kinsoku.html - -inline bool UtfNoStarting (wchar_t c) -{ - switch (c) - { - case 8217: //’ - return true; - case 8221: //” - return true; - case 12293: //々 - return true; - case 12297: //〉 - return true; - case 12299: //》 - return true; - case 12301: //」 - return true; - case 65373: //} - return true; - case 12309: //〕 - return true; - case 65289: //) - return true; - case 12303: //』 - return true; - case 12305: //】 - return true; - case 12311: //〗 - return true; - case 65281: //! - return true; - case 65285: //% - return true; - case 65311: //? - return true; - case 65344: //` - return true; - case 65292: //, - return true; - case 65306: //: - return true; - case 65307: //; - return true; - case 65294: //. - return true; - case 12290: //。 - return true; - case 12289: //、 - return true; - default: - return false; - } -} - -inline bool UtfNoEnding (wchar_t c) -{ - switch (c) - { - case 8216: //‘ - return true; - case 8220: //“ - return true; - case 12296: //〈 - return true; - case 12298: //《 - return true; - case 12300: //「 - return true; - case 65371: //{ - return true; - case 12308: //〔 - return true; - case 65288: //( - return true; - case 12302: //『 - return true; - case 12304: //【 - return true; - case 12310: //〖 - return true; - default: - return false; - } -} - -//Helper function - -inline bool breakable (wchar_t c) -{ - if ((c > 12287 && c < 40960) || //Common CJK words - (c > 44031 && c < 55204) || //Hangul - (c > 63743 && c < 64256) || //More Chinese - c == 173 || c == L' ' || //Soft hyphen and white space - c == 47 || c == 92) //Slash and blackslash - return true; - return false; -} -} // end namespace gui -} // end namespace irr diff --git a/src/network/protocols/client_lobby.cpp b/src/network/protocols/client_lobby.cpp index 9c964f071..a5d7b1239 100644 --- a/src/network/protocols/client_lobby.cpp +++ b/src/network/protocols/client_lobby.cpp @@ -633,35 +633,35 @@ void ClientLobby::handleServerInfo(Event* event) // At least 6 bytes should remain now if (!checkDataSize(event, 6)) return; + core::stringw str, total_lines; if (!m_first_connect) { - NetworkingLobby::getInstance() - ->addMoreServerInfo(L"--------------------"); + total_lines = L"--------------------"; + total_lines += L"\n"; } m_first_connect = false; NetworkString &data = event->data(); // Add server info - core::stringw str, each_line; uint8_t u_data; data.decodeStringW(&str); //I18N: In the networking lobby - each_line = _("Server name: %s", str); - NetworkingLobby::getInstance()->addMoreServerInfo(each_line); + total_lines += _("Server name: %s", str); + total_lines += L"\n"; u_data = data.getUInt8(); const core::stringw& difficulty_name = race_manager->getDifficultyName((RaceManager::Difficulty)u_data); race_manager->setDifficulty((RaceManager::Difficulty)u_data); //I18N: In the networking lobby - each_line = _("Difficulty: %s", difficulty_name); - NetworkingLobby::getInstance()->addMoreServerInfo(each_line); + total_lines += _("Difficulty: %s", difficulty_name); + total_lines += L"\n"; unsigned max_player = data.getUInt8(); //I18N: In the networking lobby - each_line = _("Max players: %d", (int)max_player); - NetworkingLobby::getInstance()->addMoreServerInfo(each_line); + total_lines += _("Max players: %d", (int)max_player); + total_lines += L"\n"; // Reserved for extra spectators u_data = data.getUInt8(); @@ -673,8 +673,8 @@ void ClientLobby::handleServerInfo(Event* event) //I18N: In the networking lobby core::stringw mode_name = ServerConfig::getModeName(u_data); - each_line = _("Game mode: %s", mode_name); - NetworkingLobby::getInstance()->addMoreServerInfo(each_line); + total_lines += _("Game mode: %s", mode_name); + total_lines += L"\n"; uint8_t extra_server_info = data.getUInt8(); bool grand_prix_started = false; @@ -691,8 +691,8 @@ void ClientLobby::handleServerInfo(Event* event) core::stringw sgt = u_data == 0 ? tl : gl; m_game_setup->setSoccerGoalTarget(u_data != 0); //I18N: In the networking lobby - each_line = _("Soccer game type: %s", sgt); - NetworkingLobby::getInstance()->addMoreServerInfo(each_line); + total_lines += _("Soccer game type: %s", sgt); + total_lines += L"\n"; break; } case 2: @@ -701,9 +701,9 @@ void ClientLobby::handleServerInfo(Event* event) grand_prix_started = cur_gp_track != 0; unsigned total_gp_track = data.getUInt8(); m_game_setup->setGrandPrixTrack(total_gp_track); - each_line = _("Grand prix progress: %d / %d", cur_gp_track, + total_lines += _("Grand prix progress: %d / %d", cur_gp_track, total_gp_track); - NetworkingLobby::getInstance()->addMoreServerInfo(each_line); + total_lines += L"\n"; break; } } @@ -716,13 +716,16 @@ void ClientLobby::handleServerInfo(Event* event) // MOTD core::stringw motd; data.decodeString16(&motd); - const std::vector& motd_line = StringUtils::split(motd, - '\n'); - if (!motd_line.empty()) - { - for (const core::stringw& motd : motd_line) - NetworkingLobby::getInstance()->addMoreServerInfo(motd); - } + if (!motd.empty()) + total_lines += motd; + + // Remove last newline added, network lobby will add it back later after + // removing old server info (with chat) + if (total_lines[total_lines.size() - 1] == L'\n') + total_lines.erase(total_lines.size() - 1); + + NetworkingLobby::getInstance()->addMoreServerInfo(total_lines); + bool server_config = data.getUInt8() == 1; NetworkingLobby::getInstance()->toggleServerConfigButton(server_config); m_server_live_joinable = data.getUInt8() == 1; diff --git a/src/states_screens/online/networking_lobby.cpp b/src/states_screens/online/networking_lobby.cpp index 05ab498b0..603cb6eb4 100644 --- a/src/states_screens/online/networking_lobby.cpp +++ b/src/states_screens/online/networking_lobby.cpp @@ -23,6 +23,7 @@ #include "config/user_config.hpp" #include "config/player_manager.hpp" +#include "font/font_manager.hpp" #include "graphics/irr_driver.hpp" #include "guiengine/CGUISpriteBank.hpp" #include "guiengine/scalable_font.hpp" @@ -51,8 +52,6 @@ #include "tracks/track.hpp" #include "utils/translation.hpp" -#include - using namespace Online; using namespace GUIEngine; @@ -234,41 +233,33 @@ void NetworkingLobby::init() void NetworkingLobby::addMoreServerInfo(core::stringw info) { const unsigned box_width = m_text_bubble->getDimension().Width; - while (GUIEngine::getFont()->getDimension(info.c_str()).Width > box_width) - { - core::stringw brokentext = info; - while (brokentext.size() > 0) - { - brokentext.erase(brokentext.size() - 1); - if (GUIEngine::getFont()->getDimension(brokentext.c_str()).Width < - box_width && gui::breakable(brokentext.lastChar())) - break; - } - if (brokentext.size() == 0) - break; - m_server_info.push_back(brokentext); - info = - info.subString(brokentext.size(), info.size() - brokentext.size()); - } - if (info.size() > 0) - { - m_server_info.push_back(info); - } - while ((int)m_server_info.size() * m_server_info_height > - m_text_bubble->getDimension().Height) - { - m_server_info.erase(m_server_info.begin()); - } + const float box_height = m_text_bubble->getDimension().Height; + // For future copy text from lobby chat + std::vector text_line; + std::vector cur_info; + font_manager->initGlyphLayouts(info, cur_info, &text_line); + gui::IGUIFont* font = GUIEngine::getFont(); + gui::breakGlyphLayouts(cur_info, box_width, + font->getInverseShaping(), font->getScale()); + m_server_info.insert(m_server_info.end(), cur_info.begin(), + cur_info.end()); + gui::eraseTopLargerThan(m_server_info, font->getHeightPerLine(), + box_height); + + // Don't take the newly added newline marker int layouts for linebreaking + // height calculation + gui::GlyphLayout new_line = { 0 }; + new_line.flags = gui::GLF_NEWLINE; + m_server_info.push_back(new_line); if (GUIEngine::getCurrentScreen() != this) return; - core::stringw total_msg; - for (auto& string : m_server_info) - { - total_msg += string; - total_msg += L"\n"; - } - m_text_bubble->setText(total_msg, true); + + gui::IGUIStaticText* st = + m_text_bubble->getIrrlichtElement(); + st->setUseGlyphLayoutsOnly(true); + st->setGlyphLayouts(m_server_info); + } // addMoreServerInfo // ---------------------------------------------------------------------------- @@ -451,6 +442,8 @@ void NetworkingLobby::onUpdate(float delta) if (m_state == LS_ADD_PLAYERS) { + m_text_bubble->getIrrlichtElement() + ->setUseGlyphLayoutsOnly(false); m_text_bubble->setText(_("Everyone:\nPress the 'Select' button to " "join the game"), false); m_start_button->setVisible(false); @@ -465,6 +458,8 @@ void NetworkingLobby::onUpdate(float delta) m_start_button->setVisible(false); if (!cl || !cl->isLobbyReady()) { + m_text_bubble->getIrrlichtElement() + ->setUseGlyphLayoutsOnly(false); core::stringw connect_msg; if (m_joined_server) { diff --git a/src/states_screens/online/networking_lobby.hpp b/src/states_screens/online/networking_lobby.hpp index 6212aa4d1..d9520203a 100644 --- a/src/states_screens/online/networking_lobby.hpp +++ b/src/states_screens/online/networking_lobby.hpp @@ -20,9 +20,9 @@ #include "guiengine/screen.hpp" #include "guiengine/widgets/text_box_widget.hpp" +#include "GlyphLayout.h" #include #include -#include #include class InputDevice; @@ -69,7 +69,8 @@ private: uint64_t m_ping_update_timer; std::map m_player_names; std::shared_ptr m_joined_server; - std::vector m_server_info; + + std::vector m_server_info; int m_server_info_height; core::stringw m_start_text, m_ready_text, m_live_join_text,