From 4690ba0cc66338b1f00e08fb6054ee95c1c0dcc6 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 23 Sep 2020 23:45:21 +0200 Subject: Fallback to cjk font, change font to system noto sans --- src/Body.cpp | 41 +++++++--- src/QuickMedia.cpp | 95 ++++++++++++++-------- src/Text.cpp | 200 +++++++++++++++++++++++++++++------------------ src/plugins/Fourchan.cpp | 2 +- src/plugins/Matrix.cpp | 2 +- 5 files changed, 218 insertions(+), 122 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index 3ebd11e..fd6ad07 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -15,7 +15,14 @@ const sf::Color front_color(32, 36, 42); const sf::Color back_color(33, 35, 37); namespace QuickMedia { - BodyItem::BodyItem(std::string _title): visible(true), dirty(false), dirty_description(false), thumbnail_is_local(false), title_color(sf::Color::White) { + BodyItem::BodyItem(std::string _title) : + visible(true), + dirty(false), + dirty_description(false), + dirty_author(false), + thumbnail_is_local(false), + title_color(sf::Color::White) + { set_title(std::move(_title)); } @@ -29,6 +36,7 @@ namespace QuickMedia { visible = other.visible; dirty = other.dirty; dirty_description = other.dirty_description; + dirty_author = other.dirty_author; thumbnail_is_local = other.thumbnail_is_local; if(other.title_text) title_text = std::make_unique(*other.title_text); @@ -43,9 +51,10 @@ namespace QuickMedia { title_color = other.title_color; } - Body::Body(Program *program, sf::Font *font, sf::Font *bold_font) : + Body::Body(Program *program, sf::Font *font, sf::Font *bold_font, sf::Font *cjk_font) : font(font), bold_font(bold_font), + cjk_font(cjk_font), progress_text("", *font, 14), author_text("", *bold_font, 16), replies_text("", *font, 14), @@ -355,26 +364,34 @@ namespace QuickMedia { thumbnail_it.second.referenced = false; } - // TODO: Change font size. Currently it doesn't work because it glitches out. Why does that happen?? for(auto &body_item : items) { if(body_item->dirty) { body_item->dirty = false; + // TODO: Find a way to optimize fromUtf8 + sf::String str = sf::String::fromUtf8(body_item->get_title().data(), body_item->get_title().data() + body_item->get_title().size()); if(body_item->title_text) - body_item->title_text->setString(body_item->get_title()); + body_item->title_text->setString(std::move(str)); else - body_item->title_text = std::make_unique(body_item->get_title(), font, 16, size.x - 50 - image_padding_x * 2.0f); + body_item->title_text = std::make_unique(std::move(str), font, cjk_font, 16, size.x - 50 - image_padding_x * 2.0f); body_item->title_text->setFillColor(body_item->title_color); body_item->title_text->updateGeometry(); } if(body_item->dirty_description) { - body_item->dirty_description = true; + body_item->dirty_description = false; + sf::String str = sf::String::fromUtf8(body_item->get_description().data(), body_item->get_description().data() + body_item->get_description().size()); if(body_item->description_text) - body_item->description_text->setString(body_item->get_description()); + body_item->description_text->setString(std::move(str)); else - body_item->description_text = std::make_unique(body_item->get_description(), font, 14, size.x - 50 - image_padding_x * 2.0f); + body_item->description_text = std::make_unique(std::move(str), font, cjk_font, 14, size.x - 50 - image_padding_x * 2.0f); body_item->description_text->updateGeometry(); } + + if(body_item->dirty_author) { + body_item->dirty_author = false; + sf::String str = sf::String::fromUtf8(body_item->get_author().data(), body_item->get_author().data() + body_item->get_author().size()); + author_text.setString(std::move(str)); + } } // Find the starting row that can be drawn to make selected row visible as well @@ -388,7 +405,7 @@ namespace QuickMedia { if(!item->get_title().empty()) { item_height += item->title_text->getHeight(); } - if(!item->author.empty()) { + if(!item->get_author().empty()) { item_height += author_text.getCharacterSize() + 2.0f; } if(item->description_text) { @@ -437,7 +454,7 @@ namespace QuickMedia { if(!item->get_title().empty()) { item_height += item->title_text->getHeight(); } - if(!item->author.empty()) { + if(!item->get_author().empty()) { item_height += author_text.getCharacterSize() + 2.0f; } if(item->description_text) { @@ -496,9 +513,7 @@ namespace QuickMedia { } } - if(!item->author.empty()) { - // TODO: Remove this call, should not be called every frame - author_text.setString(item->author); + if(!item->get_author().empty()) { author_text.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y)); window.draw(author_text); diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index f6b9d61..295749f 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -168,16 +168,47 @@ namespace QuickMedia { resources_root = "../../../"; } - if(!font.loadFromFile(resources_root + "fonts/NotoSans-Regular.ttf")) { - fprintf(stderr, "Failed to load font: NotoSans-Regular.ttf\n"); + const std::string noto_sans_directories[] = { + "/usr/share/fonts/noto", "/usr/share/fonts/truetype/noto", + "/usr/share/fonts/noto-cjk", "/usr/share/fonts/truetype/noto-cjk" + }; + for(const std::string ¬o_sans_dir : noto_sans_directories) { + if(!font) { + auto new_font = std::make_unique(); + if(new_font->loadFromFile(noto_sans_dir + "/NotoSans-Regular.ttf")) + font = std::move(new_font); + } + + if(!bold_font) { + auto new_font = std::make_unique(); + if(new_font->loadFromFile(noto_sans_dir + "/NotoSans-Bold.ttf")) + bold_font = std::move(new_font); + } + + if(!cjk_font) { + auto new_font = std::make_unique(); + if(new_font->loadFromFile(noto_sans_dir + "/NotoSansCJK-Regular.ttc")) + cjk_font = std::move(new_font); + } + } + + if(!font) { + fprintf(stderr, "Failed to find NotoSans-Regular.ttf in /usr/share/fonts/noto and /usr/share/fonts/truetype/noto\n"); + abort(); + } + + if(!bold_font) { + fprintf(stderr, "Failed to find NotoSans-Bold.ttf in /usr/share/fonts/noto and /usr/share/fonts/truetype/noto\n"); abort(); } - if(!bold_font.loadFromFile(resources_root + "fonts/NotoSans-Bold.ttf")) { - fprintf(stderr, "Failed to load font: NotoSans-Bold.ttf\n"); + + if(!cjk_font) { + fprintf(stderr, "Failed to find NotoSansCJK-Regular.ttc in /usr/share/fonts/noto and /usr/share/fonts/truetype/noto\n"); abort(); } - body = new Body(this, &font, &bold_font); - related_media_body = new Body(this, &font, &bold_font); + + body = new Body(this, font.get(), bold_font.get(), cjk_font.get()); + related_media_body = new Body(this, font.get(), bold_font.get(), cjk_font.get()); related_media_body->draw_thumbnails = true; struct sigaction action; @@ -454,7 +485,7 @@ namespace QuickMedia { if(search_placeholder.empty()) search_placeholder = "Search..."; - search_bar = std::make_unique(font, &plugin_logo, search_placeholder); + search_bar = std::make_unique(*font, &plugin_logo, search_placeholder); search_bar->text_autosearch_delay = current_plugin->get_search_delay(); while(window.isOpen()) { @@ -926,16 +957,16 @@ namespace QuickMedia { std::string autocomplete_text; bool autocomplete_running = false; - Body history_body(this, &font, &bold_font); + Body history_body(this, font.get(), bold_font.get(), cjk_font.get()); std::unique_ptr recommended_body; - sf::Text all_tab_text("All", font, tab_text_size); - sf::Text history_tab_text("History", font, tab_text_size); - sf::Text recommended_tab_text("Recommended", font, tab_text_size); - sf::Text login_tab_text("Login", font, tab_text_size); + sf::Text all_tab_text("All", *font, tab_text_size); + sf::Text history_tab_text("History", *font, tab_text_size); + sf::Text recommended_tab_text("Recommended", *font, tab_text_size); + sf::Text login_tab_text("Login", *font, tab_text_size); SearchBar *focused_login_input = nullptr; if(current_plugin->name == "youtube") { - recommended_body = std::make_unique(this, &font, &bold_font); + recommended_body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get()); recommended_body->draw_thumbnails = true; fill_recommended_items_from_json(load_recommended_json(current_plugin), recommended_body->items); } @@ -973,7 +1004,7 @@ namespace QuickMedia { if(recommended_body) tabs.push_back(Tab{recommended_body.get(), nullptr, SearchSuggestionTab::RECOMMENDED, &recommended_tab_text}); if(is_fourchan) { - tabs.push_back(Tab{nullptr, std::make_unique(font), SearchSuggestionTab::LOGIN, &login_tab_text}); + tabs.push_back(Tab{nullptr, std::make_unique(*font), SearchSuggestionTab::LOGIN, &login_tab_text}); focused_login_input = tabs.back().login_tab->username.get(); tabs.back().login_tab->username->caret_visible = true; @@ -1403,7 +1434,7 @@ namespace QuickMedia { sf::Vector2f related_media_window_size; bool related_media_window_visible = false; - sf::Text related_videos_text("Related videos", bold_font, 20); + sf::Text related_videos_text("Related videos", *bold_font, 20); const float related_videos_text_height = related_videos_text.getCharacterSize(); sf::WindowHandle video_player_window = None; @@ -1794,18 +1825,18 @@ namespace QuickMedia { chapters_tab.type = EpisodeListTabType::CHAPTERS; chapters_tab.body = body; chapters_tab.creator = nullptr; - chapters_tab.text = sf::Text("Chapters", font, tab_text_size); + chapters_tab.text = sf::Text("Chapters", *font, tab_text_size); tabs.push_back(std::move(chapters_tab)); const std::vector& creators = manga->get_creators(); for(const Creator &creator : creators) { EpisodeListTab tab; tab.type = EpisodeListTabType::CREATOR; - tab.body = new Body(this, &font, &bold_font); + tab.body = new Body(this, font.get(), bold_font.get(), cjk_font.get()); tab.body->draw_thumbnails = true; tab.creator = &creator; tab.creator_page_download_future = std::async(std::launch::async, download_creator_page, creator.url); - tab.text = sf::Text(creator.name, font, tab_text_size); + tab.text = sf::Text(creator.name, *font, tab_text_size); tabs.push_back(std::move(tab)); } @@ -2069,7 +2100,7 @@ namespace QuickMedia { sf::Texture image_texture; sf::Sprite image; - sf::Text error_message("", font, 30); + sf::Text error_message("", *font, 30); error_message.setFillColor(sf::Color::White); assert(current_plugin->is_manga()); @@ -2132,7 +2163,7 @@ namespace QuickMedia { bool redraw = true; sf::Event event; - sf::Text chapter_text(content_title + " | " + chapter_title + " | Page " + std::to_string(image_index + 1) + "/" + std::to_string(num_images), font, 14); + sf::Text chapter_text(content_title + " | " + chapter_title + " | Page " + std::to_string(image_index + 1) + "/" + std::to_string(num_images), *font, 14); if(image_index == num_images) chapter_text.setString(content_title + " | " + chapter_title + " | End"); chapter_text.setFillColor(sf::Color::White); @@ -2296,7 +2327,7 @@ namespace QuickMedia { json_chapter = Json::Value(Json::objectValue); } - ImageViewer image_viewer(image_plugin, images_url, content_title, chapter_title, image_index, content_cache_dir, &font); + ImageViewer image_viewer(image_plugin, images_url, content_title, chapter_title, image_index, content_cache_dir, font.get()); json_chapter["current"] = std::min(latest_read, image_viewer.get_num_pages()); json_chapter["total"] = image_viewer.get_num_pages(); @@ -2490,7 +2521,7 @@ namespace QuickMedia { search_bar->text_autosearch_delay = file_manager->get_search_delay(); Page previous_page = pop_page_stack(); - sf::Text current_dir_text(file_manager->get_current_dir().string(), bold_font, 18); + sf::Text current_dir_text(file_manager->get_current_dir().string(), *bold_font, 18); // TODO: Make asynchronous. // TODO: Automatically go to the parent if this fails (recursively). @@ -2664,7 +2695,7 @@ namespace QuickMedia { std::mutex attachment_load_mutex; GoogleCaptchaChallengeInfo challenge_info; - sf::Text challenge_description_text("", font, 24); + sf::Text challenge_description_text("", *font, 24); challenge_description_text.setFillColor(sf::Color::White); const size_t captcha_num_columns = 3; const size_t captcha_num_rows = 3; @@ -3050,11 +3081,11 @@ namespace QuickMedia { void Program::chat_login_page() { assert(current_plugin->name == "matrix"); - SearchBar login_input(font, nullptr, "Username"); - SearchBar password_input(font, nullptr, "Password", true); - SearchBar homeserver_input(font, nullptr, "Homeserver"); + SearchBar login_input(*font, nullptr, "Username"); + SearchBar password_input(*font, nullptr, "Password", true); + SearchBar homeserver_input(*font, nullptr, "Homeserver"); - sf::Text status_text("", font, 18); + sf::Text status_text("", *font, 18); const int num_inputs = 3; SearchBar *inputs[num_inputs] = { &login_input, &password_input, &homeserver_input }; @@ -3150,18 +3181,18 @@ namespace QuickMedia { ChatTab messages_tab; messages_tab.type = ChatTabType::MESSAGES; - messages_tab.body = std::make_unique(this, &font, &bold_font); + messages_tab.body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get()); messages_tab.body->draw_thumbnails = true; //messages_tab.body->line_seperator_color = sf::Color::Transparent; - messages_tab.text = sf::Text("Messages", font, tab_text_size); + messages_tab.text = sf::Text("Messages", *font, tab_text_size); tabs.push_back(std::move(messages_tab)); ChatTab rooms_tab; rooms_tab.type = ChatTabType::ROOMS; - rooms_tab.body = std::make_unique(this, &font, &bold_font); + rooms_tab.body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get()); rooms_tab.body->draw_thumbnails = true; //rooms_tab.body->line_seperator_color = sf::Color::Transparent; - rooms_tab.text = sf::Text("Rooms", font, tab_text_size); + rooms_tab.text = sf::Text("Rooms", *font, tab_text_size); tabs.push_back(std::move(rooms_tab)); const int MESSAGES_TAB_INDEX = 0; @@ -3206,7 +3237,7 @@ namespace QuickMedia { plugin_logo.setSmooth(true); } - SearchBar chat_input(font, &plugin_logo, "Send a message..."); + SearchBar chat_input(*font, &plugin_logo, "Send a message..."); chat_input.set_background_color(sf::Color::Transparent); // TODO: Filer for rooms and settings diff --git a/src/Text.cpp b/src/Text.cpp index 0517c15..bdd41c3 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -21,31 +21,12 @@ namespace QuickMedia return -1; } - Text::Text(const sf::Font *_font) : - font(_font), - characterSize(0), - vertices(sf::PrimitiveType::Quads), - maxWidth(0.0f), - color(sf::Color::White), - urlColor(URL_COLOR), - dirty(false), - dirtyText(false), - dirtyCaret(false), - plainText(false), - editable(false), - visible(true), - caretMoveDirection(CaretMoveDirection::NONE), - lineSpacing(0.0f), - characterSpacing(0.0f), - caretIndex(0) - { - - } + Text::Text(const sf::Font *_font, const sf::Font *_cjk_font) : Text("", _font, _cjk_font, 0, 0.0f, false) {} - Text::Text(const sf::String &_str, const sf::Font *_font, unsigned int _characterSize, float _maxWidth, bool _plainText) : + Text::Text(sf::String _str, const sf::Font *_font, const sf::Font *_cjk_font, unsigned int _characterSize, float _maxWidth, bool _plainText) : font(_font), + cjk_font(_cjk_font), characterSize(_characterSize), - vertices(sf::PrimitiveType::Quads), maxWidth(_maxWidth), color(sf::Color::White), urlColor(URL_COLOR), @@ -60,19 +41,21 @@ namespace QuickMedia characterSpacing(0.0f), caretIndex(0) { - setString(_str); + vertices[0].setPrimitiveType(sf::PrimitiveType::Quads); + vertices[1].setPrimitiveType(sf::PrimitiveType::Quads); + setString(std::move(_str)); } - void Text::setString(const sf::String &str) + void Text::setString(sf::String str) { if(str != this->str) { - this->str = str; + this->str = std::move(str); dirty = true; dirtyText = true; - if((int)str.getSize() < caretIndex) + if((int)this->str.getSize() < caretIndex) { - caretIndex = str.getSize(); + caretIndex = this->str.getSize(); dirtyCaret = true; } } @@ -177,22 +160,68 @@ namespace QuickMedia { return boundingBox.height; } + + // TODO: Is there a more efficient way to do this? maybe japanese characters have a specific bit-pattern? + static bool is_japanese_codepoint(sf::Uint32 codepoint) { + return (codepoint >= 0x2E80 && codepoint <= 0x2FD5) // Kanji radicals + || (codepoint >= 0x3000 && codepoint <= 0x303F) // Punctuation + || (codepoint >= 0x3041 && codepoint <= 0x3096) // Hiragana + || (codepoint >= 0x30A0 && codepoint <= 0x30FF) // Katakana + || (codepoint >= 0x31F0 && codepoint <= 0x31FF) // Miscellaneous symbols and characters 1 + || (codepoint >= 0x3220 && codepoint <= 0x3243) // Miscellaneous symbols and characters 2 + || (codepoint >= 0x3280 && codepoint <= 0x337F) // Miscellaneous symbols and characters 3 + || (codepoint >= 0x3400 && codepoint <= 0x4DB5) // Kanji 1 + || (codepoint >= 0x4E00 && codepoint <= 0x9FCB) // Kanji 2 + || (codepoint >= 0xF900 && codepoint <= 0xFA6A) // Kanji 3 + || (codepoint >= 0xFF01 && codepoint <= 0xFF5E) // Alphanumeric and punctuation (full width) + || (codepoint >= 0xFF5F && codepoint <= 0xFF9F); // Katakana and punctuation (half width) + } + + static size_t find_end_of_japanese(const sf::Uint32 *str, size_t size) { + for(size_t i = 0; i < size; ++i) { + if(!is_japanese_codepoint(str[i])) + return i; + } + return size; + } + + static size_t find_end_of_non_japanese(const sf::Uint32 *str, size_t size) { + for(size_t i = 0; i < size; ++i) { + if(is_japanese_codepoint(str[i])) + return i; + } + return size; + } + + void Text::splitTextByFont() { + textElements.clear(); + size_t index = 0; + size_t size = str.getSize(); + while(index < size) { + size_t offset; + bool is_japanese = is_japanese_codepoint(str[index]); + if(is_japanese) + offset = find_end_of_japanese(str.getData() + index + 1, size - index - 1); + else + offset = find_end_of_non_japanese(str.getData() + index + 1, size - index - 1); + textElements.push_back({ StringViewUtf32(str.getData() + index, offset + 1), TextElement::Type::TEXT }); + textElements.back().is_japanese = is_japanese; + index += 1 + offset; + } + } // Logic loosely based on https://github.com/SFML/SFML/wiki/Source:-CurvedText - void Text::updateGeometry(bool update_even_if_not_dirty) - { - if(dirtyText) - { - textElements.clear(); - StringViewUtf32 wholeStr(this->str.getData(), this->str.getSize()); - textElements.push_back({ wholeStr, TextElement::Type::TEXT }); + void Text::updateGeometry(bool update_even_if_not_dirty) { + if(dirtyText) { dirtyText = false; + splitTextByFont(); } if(!update_even_if_not_dirty && !dirty) return; - vertices.clear(); + vertices[0].clear(); + vertices[1].clear(); float hspace = font->getGlyph(' ', characterSize, false).advance + characterSpacing; float vspace = font->getLineSpacing(characterSize); @@ -205,14 +234,20 @@ namespace QuickMedia for(usize textElementIndex = 0; textElementIndex < textElements.size(); ++textElementIndex) { TextElement &textElement = textElements[textElementIndex]; + const sf::Font *ff = font; + size_t vertices_index = 0; + if(textElement.is_japanese) { + ff = cjk_font; + vertices_index = 1; + } - usize vertexOffset = vertices.getVertexCount(); - vertices.resize(vertices.getVertexCount() + 4 * (textElement.text.size + 1)); + usize vertexOffset = vertices[vertices_index].getVertexCount(); + vertices[vertices_index].resize(vertices[vertices_index].getVertexCount() + 4 * (textElement.text.size + 1)); textElement.position = glyphPos; for(size_t i = 0; i < textElement.text.size; ++i) { sf::Uint32 codePoint = textElement.text[i]; - float kerning = font->getKerning(prevCodePoint, codePoint, characterSize); + float kerning = ff->getKerning(prevCodePoint, codePoint, characterSize); prevCodePoint = codePoint; glyphPos.x += kerning; @@ -222,10 +257,10 @@ namespace QuickMedia { case ' ': { - vertices[vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; glyphPos.x += hspace; if(glyphPos.x > maxWidth * 0.5f) { @@ -236,10 +271,10 @@ namespace QuickMedia } case '\t': { - vertices[vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; glyphPos.x += (hspace * TAB_WIDTH); if(glyphPos.x > maxWidth * 0.5f) { @@ -250,17 +285,17 @@ namespace QuickMedia } case '\n': { - vertices[vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 1] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 2] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertexStart + 3] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() }; glyphPos.x = 0.0f; glyphPos.y += floor(vspace + lineSpacing); continue; } } - const sf::Glyph &glyph = font->getGlyph(codePoint, characterSize, false); + const sf::Glyph &glyph = ff->getGlyph(codePoint, characterSize, false); if(glyphPos.x + glyph.advance > maxWidth) { // If there was a space in the text and text width is too long, then we need to word wrap at space index instead, @@ -271,7 +306,7 @@ namespace QuickMedia { for(size_t k = 0; k < 4; ++k) { - sf::Vector2f &vertexPos = vertices[vertexOffset + j * 4 + k].position; + sf::Vector2f &vertexPos = vertices[vertices_index][vertexOffset + j * 4 + k].position; vertexPos.x -= lastSpacingAccumulatedOffset; vertexPos.y += floor(vspace + lineSpacing); } @@ -299,18 +334,18 @@ namespace QuickMedia sf::Color fontColor = (textElement.type == TextElement::Type::TEXT ? color : urlColor); - vertices[vertexStart + 0] = { vertexTopLeft, fontColor, textureTopLeft }; - vertices[vertexStart + 1] = { vertexTopRight, fontColor, textureTopRight }; - vertices[vertexStart + 2] = { vertexBottomRight, fontColor, textureBottomRight }; - vertices[vertexStart + 3] = { vertexBottomLeft, fontColor, textureBottomLeft }; + vertices[vertices_index][vertexStart + 0] = { vertexTopLeft, fontColor, textureTopLeft }; + vertices[vertices_index][vertexStart + 1] = { vertexTopRight, fontColor, textureTopRight }; + vertices[vertices_index][vertexStart + 2] = { vertexBottomRight, fontColor, textureBottomRight }; + vertices[vertices_index][vertexStart + 3] = { vertexBottomLeft, fontColor, textureBottomLeft }; glyphPos.x += glyph.advance + characterSpacing; } - vertices[vertices.getVertexCount() - 4] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertices.getVertexCount() - 3] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertices.getVertexCount() - 2] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; - vertices[vertices.getVertexCount() - 1] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertices[vertices_index].getVertexCount() - 4] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertices[vertices_index].getVertexCount() - 3] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertices[vertices_index].getVertexCount() - 2] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; + vertices[vertices_index][vertices[vertices_index].getVertexCount() - 1] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() }; prevCodePoint = 0; } @@ -318,16 +353,19 @@ namespace QuickMedia boundingBox.height = glyphPos.y + lineSpacing; boundingBox.height += vspace; - usize numVertices = vertices.getVertexCount(); - for(usize i = 0; i < numVertices; i += 4) - { - const sf::Vertex &bottomRight = vertices[i + 2]; - boundingBox.width = std::max(boundingBox.width, bottomRight.position.x); + for(size_t vertices_index = 0; vertices_index < 2; ++vertices_index) { + usize numVertices = vertices[vertices_index].getVertexCount(); + for(usize i = 0; i < numVertices; i += 4) + { + const sf::Vertex &bottomRight = vertices[vertices_index][i + 2]; + boundingBox.width = std::max(boundingBox.width, bottomRight.position.x); + } } dirty = false; } +#if 0 void Text::updateCaret() { assert(!dirty && !dirtyText); @@ -339,6 +377,7 @@ namespace QuickMedia return; } + switch(caretMoveDirection) { case CaretMoveDirection::UP: @@ -380,13 +419,13 @@ namespace QuickMedia caretPosition = topLeftVertex.position; } } - + bool Text::isCaretAtEnd() const { assert(!dirty && !dirtyText); return textElements[0].text.size == 0 || caretIndex == (int)textElements[0].text.size; } - + // TODO: This can be optimized by using binary search int Text::getStartOfLine(int startIndex) const { @@ -604,21 +643,22 @@ namespace QuickMedia dirtyCaret = true; } } - +#endif bool Text::draw(sf::RenderTarget &target) { updateGeometry(); +#if 0 if(dirtyCaret || caretMoveDirection != CaretMoveDirection::NONE) { updateCaret(); dirtyCaret = false; caretMoveDirection = CaretMoveDirection::NONE; } +#endif float vspace = font->getLineSpacing(characterSize); - sf::RenderStates states; sf::Vector2f pos = position; pos.y += floor(vspace); // Origin is at bottom left, we want it to be at top left @@ -633,22 +673,29 @@ namespace QuickMedia if(!editable && visible && lastSeenTimer.getElapsedTime().asMilliseconds() > 3000) { visible = false; - vertices.resize(0); + vertices[0].resize(0); + vertices[1].resize(0); } return false; } - if(!visible) + if(!visible) { + visible = true; updateGeometry(true); + } - states.transform.translate(pos); - states.texture = &font->getTexture(characterSize); - target.draw(vertices, states); + const sf::Font *fonts[] = { font, cjk_font }; + for(size_t i = 0; i < 2; ++i) { + sf::RenderStates states; + states.transform.translate(pos); + states.texture = &fonts[i]->getTexture(characterSize); + target.draw(vertices[i], states); + } lastSeenTimer.restart(); - visible = true; pos.y -= floor(vspace); +#if 0 if(!editable) return true; //float rows = floor(totalHeight / (vspace + lineSpacing)); @@ -659,5 +706,8 @@ namespace QuickMedia caretRect.setPosition(sf::Vector2f(floor(pos.x + caretPosition.x), floor(pos.y + caretRow * (vspace + lineSpacing)))); target.draw(caretRect); return true; +#else + return true; +#endif } } diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp index 4490f39..a70070e 100644 --- a/src/plugins/Fourchan.cpp +++ b/src/plugins/Fourchan.cpp @@ -519,7 +519,7 @@ namespace QuickMedia { html_unescape_sequences(comment_text); BodyItem *body_item = result_items[body_item_index].get(); body_item->set_title(std::move(comment_text)); - body_item->author = std::move(author_str); + body_item->set_author(std::move(author_str)); const Json::Value &ext = post["ext"]; const Json::Value &tim = post["tim"]; diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp index e806f39..1e8b927 100644 --- a/src/plugins/Matrix.cpp +++ b/src/plugins/Matrix.cpp @@ -190,7 +190,7 @@ namespace QuickMedia { result_items.back()->append_description(it->body); } else { auto body_item = std::make_unique(""); - body_item->author = user_info.display_name; + body_item->set_author(user_info.display_name); body_item->set_description(it->body); if(!it->thumbnail_url.empty()) body_item->thumbnail_url = it->thumbnail_url; -- cgit v1.2.3