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) --- src/Text.cpp | 97 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 67 insertions(+), 30 deletions(-) (limited to 'src/Text.cpp') 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