diff options
author | dec05eba <dec05eba@protonmail.com> | 2022-11-08 19:07:13 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2022-11-08 19:07:13 +0100 |
commit | 840b87c42bb55ae6f47acc7576b3b40af4c6a68c (patch) | |
tree | d2c9f51f2ab84e88f2edcd8e3d3efcc1b4d38454 /src | |
parent | c2219fdf1f741a33f415124459de69054313de57 (diff) |
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)
Diffstat (limited to 'src')
-rw-r--r-- | src/AsyncImageLoader.cpp | 2 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 8 | ||||
-rw-r--r-- | src/Text.cpp | 97 |
3 files changed, 72 insertions, 35 deletions
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<ThumbnailData> 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<ThumbnailData>(); 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<TextElement> 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) |