From 840b87c42bb55ae6f47acc7576b3b40af4c6a68c Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 8 Nov 2022 19:07:13 +0100 Subject: Fix emoji drawn outside border when max lines set, username autocomplete caret not moving to end of text, multiple images on the same page with different sizes (downscaled) --- depends/mglpp | 2 +- include/Text.hpp | 1 + src/AsyncImageLoader.cpp | 2 +- src/QuickMedia.cpp | 8 ++-- src/Text.cpp | 97 +++++++++++++++++++++++++++++++++--------------- 5 files changed, 74 insertions(+), 36 deletions(-) diff --git a/depends/mglpp b/depends/mglpp index d04c987..0108af4 160000 --- a/depends/mglpp +++ b/depends/mglpp @@ -1 +1 @@ -Subproject commit d04c98708fd46524c0861baf65e9e4ff62d48792 +Subproject commit 0108af496da089dbee70ce80d778dfb5c238460b diff --git a/include/Text.hpp b/include/Text.hpp index 601f1a2..daf0d46 100644 --- a/include/Text.hpp +++ b/include/Text.hpp @@ -172,6 +172,7 @@ namespace QuickMedia float font_get_real_height(mgl::Font *font); float get_text_quad_left_side(const VertexRef &vertex_ref) const; float get_text_quad_right_side(const VertexRef &vertex_ref) const; + float get_text_quad_bottom_side(const VertexRef &vertex_ref) const; // If the index is past the end, then the caret offset is the right side of the last character, rather than the left side float get_caret_offset_by_caret_index(int index) const; VertexRef& get_vertex_ref_clamp(int index); diff --git a/src/AsyncImageLoader.cpp b/src/AsyncImageLoader.cpp index d12f9af..4021c55 100644 --- a/src/AsyncImageLoader.cpp +++ b/src/AsyncImageLoader.cpp @@ -313,7 +313,7 @@ namespace QuickMedia { std::shared_ptr AsyncImageLoader::get_thumbnail(const std::string &url, bool local, mgl::vec2i resize_target_size) { // TODO: Instead of generating a new hash everytime to access thumbnail, cache the hash of the thumbnail url - auto &thumbnail_data = thumbnails[url]; + auto &thumbnail_data = thumbnails[url + "_" + std::to_string(resize_target_size.x) + "x" + std::to_string(resize_target_size.y)]; if(!thumbnail_data) thumbnail_data = std::make_shared(); thumbnail_data->counter = counter; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 1f5e775..72df6eb 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -6001,11 +6001,11 @@ namespace QuickMedia { if(mention.visible) { BodyItem *selected_mention_item = tabs[USERS_TAB_INDEX].body->get_selected(); if(selected_mention_item) { - std::string str_to_append = selected_mention_item->get_description(); - if(!str_to_append.empty()) - str_to_append.erase(0, 1); + std::string str_to_append = Text::to_printable_string(selected_mention_item->get_description()); str_to_append += " "; - chat_input.replace(chat_input.get_caret_index() - mention.filter.size(), mention.filter.size(), str_to_append); + const int filter_size = (int)mention.filter.size() + 1; + int start_index = chat_input.get_caret_index() - filter_size; + chat_input.replace(std::max(0, start_index), filter_size, str_to_append); mention.hide(); } return false; diff --git a/src/Text.cpp b/src/Text.cpp index 6bc777d..44bf73c 100644 --- a/src/Text.cpp +++ b/src/Text.cpp @@ -228,13 +228,42 @@ namespace QuickMedia return characterSize; } + static size_t utf8_get_num_codepoints(const char *str, size_t size) { + size_t codepoint_index = 0; + for(size_t i = 0; i < size;) { + unsigned char *cp = (unsigned char*)&str[i]; + uint32_t codepoint; + size_t clen; + if(!mgl::utf8_decode(cp, size - i, &codepoint, &clen)) { + codepoint = *cp; + clen = 1; + } + + i += clen; + ++codepoint_index; + } + return codepoint_index; + } + void Text::replace(size_t start_index, size_t length, const std::string &insert_str) { - int string_diff = (int)insert_str.size() - (int)length; + const bool at_end = start_index == str.size(); str.replace(start_index, length, insert_str); dirty = true; dirtyText = true; - if(caretIndex >= (int)start_index) { - caretIndex += string_diff; + if(!at_end) { + std::vector new_text_elements; + Text::split_text_by_type(new_text_elements, insert_str, 0.0f); + int caret_advance = 0; + for(auto &text_element : new_text_elements) { + if(text_element.type == TextElement::Type::IMAGE || text_element.text_type == TextElement::TextType::EMOJI) { + caret_advance += 1; + } else { + caret_advance += utf8_get_num_codepoints(text_element.text.data(), text_element.text.size()); + } + } + + fprintf(stderr, "old caret index: %d, advance: %d\n", caretIndex, caret_advance); + caretIndex += caret_advance; dirtyCaret = true; } } @@ -556,6 +585,10 @@ namespace QuickMedia return vertices[vertex_ref.vertices_index][vertex_ref.index + 5].position.x; } + float Text::get_text_quad_bottom_side(const VertexRef &vertex_ref) const { + return vertices[vertex_ref.vertices_index][vertex_ref.index + 4].position.y; + } + float Text::get_caret_offset_by_caret_index(int index) const { const int num_vertices = vertices_linear.size(); if(num_vertices == 0) @@ -603,23 +636,6 @@ namespace QuickMedia static mgl::vec2f vec2f_floor(mgl::vec2f value) { return mgl::vec2f((int)value.x, (int)value.y); } - - static size_t utf8_get_num_codepoints(const char *str, size_t size) { - size_t codepoint_index = 0; - for(size_t i = 0; i < size;) { - unsigned char *cp = (unsigned char*)&str[i]; - uint32_t codepoint; - size_t clen; - if(!mgl::utf8_decode(cp, size - i, &codepoint, &clen)) { - codepoint = *cp; - clen = 1; - } - - i += clen; - ++codepoint_index; - } - return codepoint_index; - } void Text::updateGeometry(bool update_even_if_not_dirty) { if(dirtyText) { @@ -652,9 +668,10 @@ namespace QuickMedia latin_font = FontLoader::get_font(FontLoader::FontType::LATIN, characterSize); const float latin_font_width = latin_font->get_glyph(' ').advance; - const float hspace = latin_font_width + characterSpacing; + const float hspace_latin = latin_font_width + characterSpacing; const float vspace = font_get_real_height(latin_font); const float emoji_spacing = 2.0f; + int hspace_monospace = 0; const mgl::Color url_color = get_theme().url_text_color; size_t url_range_index = 0; @@ -792,6 +809,8 @@ namespace QuickMedia clen = 1; } + float hspace = hspace_latin; + // TODO: CJK monospace if(is_symbol_codepoint(codepoint)) { ff = FontLoader::get_font(FontLoader::FontType::SYMBOLS, characterSize); @@ -802,6 +821,9 @@ namespace QuickMedia } else if(monospace) { ff = FontLoader::get_font(FontLoader::FontType::LATIN_MONOSPACE, characterSize); vertices_index = FONT_INDEX_MONOSPACE; + if(hspace_monospace == 0) + hspace_monospace = ff->get_glyph(' ').advance + characterSpacing; + hspace = hspace_monospace; } else { ff = latin_font; vertices_index = FONT_INDEX_LATIN; @@ -1003,6 +1025,9 @@ namespace QuickMedia const VertexRef &vertex_ref = vertices_linear[textElement.vertex_ref_index]; const mgl::vec2f top_left_vertex_pos = vertices[vertex_ref.vertices_index][vertex_ref.index + 1].position; textElement.pos = { (int)top_left_vertex_pos.x, (int)top_left_vertex_pos.y }; + // Hide images by drawing them far away if we should cut them... + if(cut_lines && textElement.vertex_ref_index >= vertices_linear_index) + textElement.pos.y = 9999.0f; } } @@ -1024,10 +1049,22 @@ namespace QuickMedia } boundingBox.size.x = 0.0f; + boundingBox.size.y = 0.0f; for(VertexRef &vertex_ref : vertices_linear) { boundingBox.size.x = std::max(boundingBox.size.x, get_text_quad_right_side(vertex_ref)); + //boundingBox.size.y = std::max(boundingBox.size.y, get_text_quad_bottom_side(vertex_ref)); } + boundingBox.size.y = num_lines * line_height; + //boundingBox.size.y = text_offset_y; + + // TODO: + + //if(vertices_linear.empty()) + // boundingBox.size.y = line_height; + + //if(editable) + // boundingBox.size.y = num_lines * line_height; // TODO: Clear |vertices| somehow even with editable text for(size_t i = 0; i < FONT_ARRAY_SIZE; ++i) { @@ -1241,6 +1278,15 @@ namespace QuickMedia void Text::processEvent(mgl::Window &window, const mgl::Event &event) { if(!editable) return; + + // TODO: Dont do this here! it's slow, but it's needed to process the change before the next event + updateGeometry(); + + if(dirtyCaret || caretMoveDirection != CaretMoveDirection::NONE) { + updateCaret(); + dirtyCaret = false; + caretMoveDirection = CaretMoveDirection::NONE; + } if(caretIndex > (int)vertices_linear.size()) caretIndex = vertices_linear.size(); @@ -1366,15 +1412,6 @@ namespace QuickMedia dirtyText = true; dirtyCaret = true; } - - // TODO: Dont do this here! it's slow, but it's needed to process the change before the next event - updateGeometry(); - - if(dirtyCaret || caretMoveDirection != CaretMoveDirection::NONE) { - updateCaret(); - dirtyCaret = false; - caretMoveDirection = CaretMoveDirection::NONE; - } } bool Text::draw(mgl::Window &target) -- cgit v1.2.3