diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index afff885168..700b7d3afb 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -885,6 +885,7 @@ void TextEdit::_notification(int p_what) { } Point2 cursor_pos; + bool is_cursor_visible = false; int cursor_insert_offset_y = 0; // Get the highlighted words. @@ -1492,6 +1493,7 @@ void TextEdit::_notification(int p_what) { if (cursor.column == (last_wrap_column + j) && cursor.line == line && cursor_wrap_index == line_wrap_index && (char_ofs + char_margin) >= xmargin_beg) { + is_cursor_visible = true; cursor_pos = Point2i(char_ofs + char_margin + ofs_x, ofs_y); cursor_pos.y += (get_row_height() - cache.font->get_height()) / 2; @@ -1552,75 +1554,84 @@ void TextEdit::_notification(int p_what) { } bool completion_below = false; - if (completion_active && completion_options.size() > 0) { - // Code completion box. - Ref csb = get_stylebox("completion"); - int maxlines = get_constant("completion_lines"); - int cmax_width = get_constant("completion_max_width") * cache.font->get_char_size('x').x; - int scrollw = get_constant("completion_scroll_width"); - Color scrollc = get_color("completion_scroll_color"); + if (completion_active && is_cursor_visible && completion_options.size() > 0) { + // Completion panel + const Ref csb = get_stylebox("completion"); + const int maxlines = get_constant("completion_lines"); + const int cmax_width = get_constant("completion_max_width") * cache.font->get_char_size('x').x; + const Color scrollc = get_color("completion_scroll_color"); + + const int row_height = get_row_height(); const int completion_options_size = completion_options.size(); - int lines = MIN(completion_options_size, maxlines); - int w = 0; - int h = lines * get_row_height(); - int nofs = cache.font->get_string_size(completion_base).width; + const int row_count = MIN(completion_options_size, maxlines); + const int completion_rows_height = row_count * row_height; + const int completion_base_width = cache.font->get_string_size(completion_base).width; + int scroll_rectangle_width = get_constant("completion_scroll_width"); + int width = 0; + + // Compute max width of the panel based on the longest completion option if (completion_options_size < 50) { for (int i = 0; i < completion_options_size; i++) { - int w2 = MIN(cache.font->get_string_size(completion_options[i].display).x, cmax_width); - if (w2 > w) - w = w2; + int line_width = MIN(cache.font->get_string_size(completion_options[i].display).x, cmax_width); + if (line_width > width) { + width = line_width; + } } } else { - w = cmax_width; + width = cmax_width; } // Add space for completion icons. const int icon_hsep = get_constant("hseparation", "ItemList"); - Size2 icon_area_size(get_row_height(), get_row_height()); - w += icon_area_size.width + icon_hsep; + const Size2 icon_area_size(row_height, row_height); + const int icon_area_width = icon_area_size.width + icon_hsep; + width += icon_area_size.width + icon_hsep; - int line_from = CLAMP(completion_index - lines / 2, 0, completion_options_size - lines); + const int line_from = CLAMP(completion_index - row_count / 2, 0, completion_options_size - row_count); - for (int i = 0; i < lines; i++) { + for (int i = 0; i < row_count; i++) { int l = line_from + i; ERR_CONTINUE(l < 0 || l >= completion_options_size); if (completion_options[l].default_value.get_type() == Variant::COLOR) { - w += icon_area_size.width; + width += icon_area_size.width; break; } } - int th = h + csb->get_minimum_size().y; + // Position completion panel + completion_rect.size.width = width + 2; + completion_rect.size.height = completion_rows_height; - if (cursor_pos.y + get_row_height() + th > get_size().height) { - completion_rect.position.y = cursor_pos.y - th - (cache.line_spacing / 2.0f) - cursor_insert_offset_y; + if (completion_options_size <= maxlines) { + scroll_rectangle_width = 0; + } + + const Point2 csb_offset = csb->get_offset(); + const int total_height = completion_rect.size.height + csb->get_minimum_size().y; + const int ajdusted_cursor_y = cursor_pos.y - cursor_insert_offset_y - (get_row_height() - cache.font->get_height()) / 2; + + completion_rect.position.x = cursor_pos.x - completion_base_width - icon_area_width - csb_offset.x; + + if (ajdusted_cursor_y + row_height + total_height > get_size().height) { + // Completion panel above the cursor line + completion_rect.position.y = ajdusted_cursor_y - total_height; } else { - completion_rect.position.y = cursor_pos.y + cache.font->get_height() + (cache.line_spacing / 2.0f) + csb->get_offset().y - cursor_insert_offset_y; + // Completion panel below the cursor line + completion_rect.position.y = ajdusted_cursor_y + row_height; completion_below = true; } - if (cursor_pos.x - nofs + w + scrollw > get_size().width) { - completion_rect.position.x = get_size().width - w - scrollw; - } else { - completion_rect.position.x = cursor_pos.x - nofs; - } - - completion_rect.size.width = w + 2; - completion_rect.size.height = h; - if (completion_options_size <= maxlines) - scrollw = 0; - - draw_style_box(csb, Rect2(completion_rect.position - csb->get_offset(), completion_rect.size + csb->get_minimum_size() + Size2(scrollw, 0))); + draw_style_box(csb, Rect2(completion_rect.position - csb_offset, completion_rect.size + csb->get_minimum_size() + Size2(scroll_rectangle_width, 0))); if (cache.completion_background_color.a > 0.01) { - VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scrollw, 0)), cache.completion_background_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(completion_rect.position, completion_rect.size + Size2(scroll_rectangle_width, 0)), cache.completion_background_color); } VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(completion_rect.position.x, completion_rect.position.y + (completion_index - line_from) * get_row_height()), Size2(completion_rect.size.width, get_row_height())), cache.completion_selected_color); - draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(nofs, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color); + draw_rect(Rect2(completion_rect.position + Vector2(icon_area_size.x + icon_hsep, 0), Size2(MIN(completion_base_width, completion_rect.size.width - (icon_area_size.x + icon_hsep)), completion_rect.size.height)), cache.completion_existing_color); - for (int i = 0; i < lines; i++) { + for (int i = 0; i < row_count; i++) { int l = line_from + i; ERR_CONTINUE(l < 0 || l >= completion_options_size); @@ -1653,11 +1664,11 @@ void TextEdit::_notification(int p_what) { draw_string(cache.font, title_pos, completion_options[l].display, text_color, completion_rect.size.width - (icon_area_size.x + icon_hsep)); } - if (scrollw) { + if (scroll_rectangle_width) { // Draw a small scroll rectangle to show a position in the options. float r = (float)maxlines / completion_options_size; float o = (float)line_from / completion_options_size; - draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scrollw, completion_rect.size.y * r), scrollc); + draw_rect(Rect2(completion_rect.position.x + completion_rect.size.width, completion_rect.position.y + o * completion_rect.size.y, scroll_rectangle_width, completion_rect.size.y * r), scrollc); } completion_line_ofs = line_from; @@ -1665,7 +1676,7 @@ void TextEdit::_notification(int p_what) { // Check to see if the hint should be drawn. bool show_hint = false; - if (completion_hint != "") { + if (is_cursor_visible && completion_hint != "") { if (completion_active) { if (completion_below && !callhint_below) { show_hint = true; @@ -1706,7 +1717,7 @@ void TextEdit::_notification(int p_what) { completion_hint_offset = cursor_pos.x - offset; } - Point2 hint_ofs = Vector2(completion_hint_offset, cursor_pos.y) + callhint_offset; + Point2 hint_ofs = Vector2(completion_hint_offset, cursor_pos.y - cursor_insert_offset_y - (get_row_height() - cache.font->get_height()) / 2) + callhint_offset; if (callhint_below) { hint_ofs.y += get_row_height() + sb->get_offset().y;