diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml index 9fada9db35eb..e3c76bf716f6 100644 --- a/doc/classes/TextEdit.xml +++ b/doc/classes/TextEdit.xml @@ -1274,7 +1274,6 @@ Set the type of caret to draw. - If [code]true[/code], a right-click displays the context menu. diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index c3287035ffce..8661e3d47dd9 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -55,15 +55,16 @@ void CodeEdit::_notification(int p_what) { } break; case NOTIFICATION_DRAW: { - RID ci = get_canvas_item(); + RID ci = _get_text_canvas_item(); const Size2 size = get_size(); const bool caret_visible = is_caret_visible(); const bool rtl = is_layout_rtl(); const int row_height = get_line_height(); if (line_length_guideline_columns.size() > 0) { + HScrollBar *v_scroll_bar = get_v_scroll_bar(); const int xmargin_beg = theme_cache.style_normal->get_margin(SIDE_LEFT) + get_total_gutter_width(); - const int xmargin_end = size.width - theme_cache.style_normal->get_margin(SIDE_RIGHT) - (is_drawing_minimap() ? get_minimap_width() : 0); + const int xmargin_end = size.width - theme_cache.style_normal->get_margin(SIDE_RIGHT) - (is_drawing_minimap() ? get_minimap_width() : 0) - (v_scroll_bar->is_visible_in_tree() ? v_scroll_bar->get_combined_minimum_size().width : 0); const float char_size = theme_cache.font->get_char_size('0', theme_cache.font_size).width; for (int i = 0; i < line_length_guideline_columns.size(); i++) { @@ -108,7 +109,7 @@ void CodeEdit::_notification(int p_what) { hint_ofs.y -= (code_hint_minsize.y + row_height) - theme_cache.line_spacing; } - draw_style_box(theme_cache.code_hint_style, Rect2(hint_ofs, code_hint_minsize)); + theme_cache.code_hint_style->draw(ci, Rect2(hint_ofs, code_hint_minsize)); int yofs = 0; for (int i = 0; i < line_count; i++) { @@ -123,17 +124,17 @@ void CodeEdit::_notification(int p_what) { Point2 round_ofs = hint_ofs + theme_cache.code_hint_style->get_offset() + Vector2(0, theme_cache.font->get_ascent(theme_cache.font_size) + font_height * i + yofs); round_ofs = round_ofs.round(); - draw_string(theme_cache.font, round_ofs, line.replace(String::chr(0xFFFF), ""), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size, theme_cache.code_hint_color); + theme_cache.font->draw_string(ci, round_ofs, line.replace(String::chr(0xFFFF), ""), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size, theme_cache.code_hint_color); if (end > 0) { // Draw an underline for the currently edited function parameter. const Vector2 b = hint_ofs + theme_cache.code_hint_style->get_offset() + Vector2(begin, font_height + font_height * i + yofs); - draw_line(b, b + Vector2(end - begin, 0), theme_cache.code_hint_color, 2); + RenderingServer::get_singleton()->canvas_item_add_line(ci, b, b + Vector2(end - begin, 0), theme_cache.code_hint_color, 2); // Draw a translucent text highlight as well. const Rect2 highlight_rect = Rect2( b - Vector2(0, font_height), Vector2(end - begin, font_height)); - draw_rect(highlight_rect, theme_cache.code_hint_color * Color(1, 1, 1, 0.2)); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, highlight_rect, theme_cache.code_hint_color * Color(1, 1, 1, 0.2)); } yofs += theme_cache.line_spacing; } @@ -182,7 +183,7 @@ void CodeEdit::_notification(int p_what) { code_completion_rect.position.x = caret_pos.x - code_completion_base_width; } - draw_style_box(theme_cache.code_completion_style, Rect2(code_completion_rect.position - theme_cache.code_completion_style->get_offset(), code_completion_rect.size + theme_cache.code_completion_style->get_minimum_size() + Size2(scroll_width, 0))); + theme_cache.code_completion_style->draw(ci, Rect2(code_completion_rect.position - theme_cache.code_completion_style->get_offset(), code_completion_rect.size + theme_cache.code_completion_style->get_minimum_size() + Size2(scroll_width, 0))); if (theme_cache.code_completion_background_color.a > 0.01) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(code_completion_rect.position, code_completion_rect.size + Size2(scroll_width, 0)), theme_cache.code_completion_background_color); } @@ -216,7 +217,7 @@ void CodeEdit::_notification(int p_what) { tl->set_width(code_completion_rect.size.width - (icon_area_size.x + theme_cache.code_completion_icon_separation)); if (rtl) { if (code_completion_options[l].default_value.get_type() == Variant::COLOR) { - draw_rect(Rect2(Point2(code_completion_rect.position.x, icon_area.position.y), icon_area_size), (Color)code_completion_options[l].default_value); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, icon_area.position.y), icon_area_size), (Color)code_completion_options[l].default_value); } tl->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT); } else { @@ -224,10 +225,10 @@ void CodeEdit::_notification(int p_what) { const Color color = code_completion_options[l].default_value; const Rect2 rect = Rect2(Point2(code_completion_rect.position.x + code_completion_rect.size.width - icon_area_size.x, icon_area.position.y), icon_area_size); if (color.a < 1.0) { - draw_texture_rect(theme_cache.completion_color_bg, rect, true); + RenderingServer::get_singleton()->canvas_item_add_texture_rect(ci, rect, theme_cache.completion_color_bg->get_rid(), true); } - draw_rect(rect, color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, color); } tl->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT); } @@ -239,7 +240,7 @@ void CodeEdit::_notification(int p_what) { int match_offset = theme_cache.font->get_string_size(code_completion_options[l].display.substr(0, match_segment.first), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width; int match_len = theme_cache.font->get_string_size(code_completion_options[l].display.substr(match_segment.first, match_segment.second), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width; - draw_rect(Rect2(match_pos + Point2(match_offset, 0), Size2(match_len, row_height)), theme_cache.code_completion_existing_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(match_pos + Point2(match_offset, 0), Size2(match_len, row_height)), theme_cache.code_completion_existing_color); } tl->draw(ci, title_pos, code_completion_options[l].font_color); } @@ -250,7 +251,7 @@ void CodeEdit::_notification(int p_what) { float r = (float)theme_cache.code_completion_max_lines / code_completion_options_count; float o = (float)code_completion_line_ofs / code_completion_options_count; - draw_rect(Rect2(code_completion_rect.position.x + code_completion_rect.size.width, code_completion_rect.position.y + o * code_completion_rect.size.y, scroll_width, code_completion_rect.size.y * r), scroll_color); + RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(code_completion_rect.position.x + code_completion_rect.size.width, code_completion_rect.position.y + o * code_completion_rect.size.y, scroll_width, code_completion_rect.size.y * r), scroll_color); } } } @@ -1298,6 +1299,7 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const { void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) { bool hovering = get_hovered_gutter() == Vector2i(main_gutter, p_line); + RID ci = _get_text_canvas_item(); if (draw_breakpoints && theme_cache.breakpoint_icon.is_valid()) { bool breakpointed = is_line_breakpointed(p_line); bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT); @@ -1312,7 +1314,7 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 Rect2 icon_region = p_region; icon_region.position += Point2(padding, padding); icon_region.size -= Point2(padding, padding) * 2; - theme_cache.breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color); + theme_cache.breakpoint_icon->draw_rect(ci, icon_region, false, use_color); } } @@ -1331,7 +1333,7 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 Rect2 icon_region = p_region; icon_region.position += Point2(horizontal_padding, 0); icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding); - theme_cache.bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color); + theme_cache.bookmark_icon->draw_rect(ci, icon_region, false, use_color); } } @@ -1342,7 +1344,7 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2 Rect2 icon_region = p_region; icon_region.position += Point2(horizontal_padding, vertical_padding); icon_region.size -= Point2(horizontal_padding, vertical_padding) * 2; - theme_cache.executing_line_icon->draw_rect(get_canvas_item(), icon_region, false, theme_cache.executing_line_color); + theme_cache.executing_line_icon->draw_rect(ci, icon_region, false, theme_cache.executing_line_color); } } @@ -1503,7 +1505,7 @@ void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 number_color = theme_cache.line_number_color; } - TS->shaped_text_draw(text_rid, get_canvas_item(), ofs, -1, -1, number_color); + TS->shaped_text_draw(text_rid, _get_text_canvas_item(), ofs, -1, -1, number_color); } void CodeEdit::_clear_line_number_text_cache() { @@ -1532,6 +1534,7 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi return; } set_line_gutter_clickable(p_line, fold_gutter, true); + RID ci = _get_text_canvas_item(); int horizontal_padding = p_region.size.x / 10; int vertical_padding = p_region.size.y / 6; @@ -1545,17 +1548,17 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi Color region_icon_color = theme_cache.folded_code_region_color; region_icon_color.a = MAX(region_icon_color.a, 0.4f); if (can_fold) { - theme_cache.can_fold_code_region_icon->draw_rect(get_canvas_item(), p_region, false, region_icon_color); + theme_cache.can_fold_code_region_icon->draw_rect(ci, p_region, false, region_icon_color); } else { - theme_cache.folded_code_region_icon->draw_rect(get_canvas_item(), p_region, false, region_icon_color); + theme_cache.folded_code_region_icon->draw_rect(ci, p_region, false, region_icon_color); } return; } if (can_fold) { - theme_cache.can_fold_icon->draw_rect(get_canvas_item(), p_region, false, theme_cache.code_folding_color); + theme_cache.can_fold_icon->draw_rect(ci, p_region, false, theme_cache.code_folding_color); return; } - theme_cache.folded_icon->draw_rect(get_canvas_item(), p_region, false, theme_cache.code_folding_color); + theme_cache.folded_icon->draw_rect(ci, p_region, false, theme_cache.code_folding_color); } /* Line Folding */ diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 687ca4d4d423..d67eb50f9233 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -605,6 +605,10 @@ void TextEdit::_notification(int p_what) { first_draw = false; } + RID ci = get_canvas_item(); + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + style->draw(ci, Rect2(Point2(), get_size())); + /* Prevent the resource getting lost between the editor and game. */ if (Engine::get_singleton()->is_editor_hint()) { if (syntax_highlighter.is_valid() && syntax_highlighter->get_text_edit() != this) { @@ -620,27 +624,29 @@ void TextEdit::_notification(int p_what) { _update_scrollbars(); - RID ci = get_canvas_item(); - int xmargin_beg = theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding; - - int xmargin_end = size.width - theme_cache.style_normal->get_margin(SIDE_RIGHT); - if (draw_minimap) { - xmargin_end -= minimap_width; + if (v_scroll->is_visible_in_tree()) { + size.width -= v_scroll->get_combined_minimum_size().width; + } + if (h_scroll->is_visible_in_tree()) { + size.height -= h_scroll->get_combined_minimum_size().height; } - // Let's do it easy for now. - theme_cache.style_normal->draw(ci, Rect2(Point2(), size)); + + RenderingServer::get_singleton()->canvas_item_clear(text_ci); + RenderingServer::get_singleton()->canvas_item_set_custom_rect(text_ci, !is_visibility_clip_disabled(), Rect2(style->get_offset(), size - style->get_minimum_size())); + RenderingServer::get_singleton()->canvas_item_set_clip(text_ci, true); + RenderingServer::get_singleton()->canvas_item_set_visibility_layer(text_ci, get_visibility_layer()); + + int xmargin_beg = style->get_margin(SIDE_LEFT) + gutters_width + gutter_padding; + int xmargin_end = size.width - style->get_margin(SIDE_RIGHT); + if (!editable) { - theme_cache.style_readonly->draw(ci, Rect2(Point2(), size)); draw_caret = is_drawing_caret_when_editable_disabled(); } - if (has_focus()) { - theme_cache.style_focus->draw(ci, Rect2(Point2(), size)); - } int visible_rows = get_visible_line_count() + 1; if (theme_cache.background_color.a > 0.01) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), theme_cache.background_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(Point2i(), get_size()), theme_cache.background_color); } Vector brace_matching; @@ -809,11 +815,12 @@ void TextEdit::_notification(int p_what) { } int first_vis_line = get_first_visible_line() - 1; - int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0); + int draw_amount = visible_rows + Math::ceil(_get_v_scroll_offset()); draw_amount += draw_placeholder ? placeholder_wraped_rows.size() - 1 : get_line_wrap_count(first_vis_line + 1); // Draw minimap. if (draw_minimap) { + xmargin_end -= minimap_width; int minimap_visible_lines = get_minimap_visible_lines(); int minimap_line_height = (minimap_char_size.y + minimap_line_spacing); int tab_size = text.get_tab_size(); @@ -822,13 +829,14 @@ void TextEdit::_notification(int p_what) { int viewport_height = (draw_amount - 1) * minimap_line_height; int control_height = _get_control_height() - viewport_height; int viewport_offset_y = round(get_scroll_pos_for_line(first_vis_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount)); + viewport_offset_y += style->get_margin(SIDE_TOP); // Calculate the first line. int num_lines_before = round((viewport_offset_y) / minimap_line_height); int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_vis_line; if (minimap_line >= 0) { minimap_line -= get_next_visible_line_index_offset_from(first_vis_line, 0, -num_lines_before).x; - minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0); + minimap_line -= (minimap_line > 0 && Math::ceil(_get_v_scroll_offset()) > 0 ? 1 : 0); } int minimap_draw_amount = minimap_visible_lines + get_line_wrap_count(minimap_line + 1); @@ -845,9 +853,9 @@ void TextEdit::_notification(int p_what) { } if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, viewport_offset_y, minimap_width, viewport_height), viewport_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end - minimap_width, viewport_offset_y, minimap_width, viewport_height), viewport_color); } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, minimap_width, viewport_height), viewport_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_end, viewport_offset_y, minimap_width, viewport_height), viewport_color); } for (int i = 0; i < minimap_draw_amount; i++) { @@ -906,22 +914,22 @@ void TextEdit::_notification(int p_what) { if (highlight_current_line && highlighted_lines.has(Pair(minimap_line, line_wrap_index))) { if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, i * 3, minimap_width, 2), theme_cache.current_line_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end - minimap_width, (i * minimap_line_height) + style->get_margin(SIDE_TOP), minimap_width, minimap_char_size.y), theme_cache.current_line_color); } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, minimap_width, 2), theme_cache.current_line_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_end, (i * minimap_line_height) + style->get_margin(SIDE_TOP), minimap_width, minimap_char_size.y), theme_cache.current_line_color); } } else if (line_background_color.a > 0) { if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, i * 3, minimap_width, 2), line_background_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end - minimap_width, (i * minimap_line_height) + style->get_margin(SIDE_TOP), minimap_width, minimap_char_size.y), line_background_color); } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, minimap_width, 2), line_background_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_end, (i * minimap_line_height) + style->get_margin(SIDE_TOP), minimap_width, minimap_char_size.y), line_background_color); } } Color next_color = current_color; int characters = 0; int tab_alignment = 0; - int xpos = xmargin_end + 2 + indent_px; + int xpos = xmargin_end + indent_px; for (int j = 0; j < str.length(); j++) { bool next_is_whitespace = false; bool next_is_tab = false; @@ -964,9 +972,9 @@ void TextEdit::_notification(int p_what) { if (characters > 0) { if (rtl) { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(size.width - xpos - minimap_char_size.x * characters, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(Point2(size.width - xpos - minimap_char_size.x * characters, (minimap_line_height * i) + style->get_margin(SIDE_TOP)), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); } else { - RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(xpos, minimap_line_height * i), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); + RenderingServer::get_singleton()->canvas_item_add_rect(text_ci, Rect2(Point2(xpos, (minimap_line_height * i) + style->get_margin(SIDE_TOP)), Point2(minimap_char_size.x * characters, minimap_char_size.y)), current_color); } } @@ -995,15 +1003,8 @@ void TextEdit::_notification(int p_what) { } } - int top_limit_y = 0; - int bottom_limit_y = get_size().height; - if (!editable) { - top_limit_y += theme_cache.style_readonly->get_margin(SIDE_TOP); - bottom_limit_y -= theme_cache.style_readonly->get_margin(SIDE_BOTTOM); - } else { - top_limit_y += theme_cache.style_normal->get_margin(SIDE_TOP); - bottom_limit_y -= theme_cache.style_normal->get_margin(SIDE_BOTTOM); - } + int top_limit_y = style->get_margin(SIDE_TOP); + int bottom_limit_y = get_size().height - style->get_margin(SIDE_BOTTOM); // Draw main text. line_drawing_cache.clear(); @@ -1053,17 +1054,8 @@ void TextEdit::_notification(int p_what) { const String &str = wrap_rows[line_wrap_index]; int char_margin = xmargin_beg - first_visible_col; - int ofs_x = 0; - int ofs_y = 0; - if (!editable) { - ofs_x = theme_cache.style_readonly->get_offset().x / 2; - ofs_x -= theme_cache.style_normal->get_offset().x / 2; - ofs_y = theme_cache.style_readonly->get_offset().y / 2; - } else { - ofs_y = theme_cache.style_normal->get_offset().y / 2; - } - - ofs_y += i * row_height + theme_cache.line_spacing / 2; + int ofs_y = style->get_margin(SIDE_TOP); + ofs_y += i * row_height; ofs_y -= first_visible_line_wrap_ofs * row_height; ofs_y -= _get_v_scroll_offset() * row_height; @@ -1082,18 +1074,18 @@ void TextEdit::_notification(int p_what) { if (text.get_line_background_color(line).a > 0.0) { if (rtl) { - RS::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line)); + RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line)); } else { - RS::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line)); + RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, row_height), text.get_line_background_color(line)); } } // Draw current line highlight. if (highlight_current_line && highlighted_lines.has(Pair(line, line_wrap_index))) { if (rtl) { - RS::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - ofs_x - xmargin_end, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(size.width - xmargin_end, ofs_y, xmargin_end - xmargin_beg, row_height), theme_cache.current_line_color); } else { - RS::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs_x, ofs_y, xmargin_end, row_height), theme_cache.current_line_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, row_height), theme_cache.current_line_color); } } @@ -1102,7 +1094,7 @@ void TextEdit::_notification(int p_what) { cache_entry.y_offset = ofs_y; - int gutter_offset = theme_cache.style_normal->get_margin(SIDE_LEFT); + int gutter_offset = style->get_margin(SIDE_LEFT); for (int g = 0; g < gutters.size(); g++) { const GutterInfo &gutter = gutters[g]; @@ -1123,9 +1115,9 @@ void TextEdit::_notification(int p_what) { int yofs = ofs_y + (row_height - tl->get_size().y) / 2; if (theme_cache.outline_size > 0 && theme_cache.outline_color.a > 0) { - tl->draw_outline(ci, Point2(gutter_offset + ofs_x, yofs), theme_cache.outline_size, theme_cache.outline_color); + tl->draw_outline(text_ci, Point2(gutter_offset, yofs), theme_cache.outline_size, theme_cache.outline_color); } - tl->draw(ci, Point2(gutter_offset + ofs_x, yofs), get_line_gutter_item_color(line, g)); + tl->draw(text_ci, Point2(gutter_offset, yofs), get_line_gutter_item_color(line, g)); } break; case GUTTER_TYPE_ICON: { const Ref icon = get_line_gutter_icon(line, g); @@ -1153,7 +1145,7 @@ void TextEdit::_notification(int p_what) { gutter_rect.position.x = size.width - gutter_rect.position.x - gutter_rect.size.x; } - icon->draw_rect(ci, gutter_rect, false, get_line_gutter_item_color(line, g)); + icon->draw_rect(text_ci, gutter_rect, false, get_line_gutter_item_color(line, g)); } break; case GUTTER_TYPE_CUSTOM: { if (gutter.custom_draw_callback.is_valid()) { @@ -1200,7 +1192,7 @@ void TextEdit::_notification(int p_what) { } for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, Math::ceil(sel[j].y) - sel[j].x, row_height); + Rect2 rect = Rect2(sel[j].x + char_margin, ofs_y, Math::ceil(sel[j].y) - sel[j].x, row_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -1211,7 +1203,7 @@ void TextEdit::_notification(int p_what) { if (rect.position.x + rect.size.x > xmargin_end) { rect.size.x = xmargin_end - rect.position.x; } - RS::get_singleton()->canvas_item_add_rect(ci, rect, theme_cache.selection_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.selection_color); } } } @@ -1223,7 +1215,7 @@ void TextEdit::_notification(int p_what) { while (search_text_col != -1) { const Vector sel = TS->shaped_text_get_selection(rid, search_text_col + start, search_text_col + search_text_len + start); for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, row_height); + Rect2 rect = Rect2(sel[j].x + char_margin, ofs_y, sel[j].y - sel[j].x, row_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -1233,7 +1225,7 @@ void TextEdit::_notification(int p_what) { } else if (rect.position.x + rect.size.x > xmargin_end) { rect.size.x = xmargin_end - rect.position.x; } - RS::get_singleton()->canvas_item_add_rect(ci, rect, theme_cache.search_result_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.search_result_color); draw_rect(rect, theme_cache.search_result_border_color, false); } @@ -1247,7 +1239,7 @@ void TextEdit::_notification(int p_what) { while (highlighted_text_col != -1) { const Vector sel = TS->shaped_text_get_selection(rid, highlighted_text_col + start, highlighted_text_col + highlighted_text_len + start); for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, row_height); + Rect2 rect = Rect2(sel[j].x + char_margin, ofs_y, sel[j].y - sel[j].x, row_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -1257,7 +1249,7 @@ void TextEdit::_notification(int p_what) { } else if (rect.position.x + rect.size.x > xmargin_end) { rect.size.x = xmargin_end - rect.position.x; } - RS::get_singleton()->canvas_item_add_rect(ci, rect, theme_cache.word_highlighted_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, rect, theme_cache.word_highlighted_color); } highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, highlighted_text_col + highlighted_text_len); @@ -1272,7 +1264,7 @@ void TextEdit::_notification(int p_what) { while (lookup_symbol_word_col != -1) { const Vector sel = TS->shaped_text_get_selection(rid, lookup_symbol_word_col + start, lookup_symbol_word_col + lookup_symbol_word_len + start); for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y + (theme_cache.line_spacing / 2), sel[j].y - sel[j].x, row_height); + Rect2 rect = Rect2(sel[j].x + char_margin, ofs_y + (theme_cache.line_spacing / 2), sel[j].y - sel[j].x, row_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -1284,7 +1276,7 @@ void TextEdit::_notification(int p_what) { } rect.position.y += ceil(TS->shaped_text_get_ascent(rid)) + ceil(theme_cache.font->get_underline_position(theme_cache.font_size)); rect.size.y = MAX(1, theme_cache.font->get_underline_thickness(theme_cache.font_size)); - RS::get_singleton()->canvas_item_add_rect(ci, rect, highlight_underline_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, rect, highlight_underline_color); } lookup_symbol_word_col = _get_column_pos_of_word(lookup_symbol_word, str, SEARCH_MATCH_CASE | SEARCH_WHOLE_WORDS, lookup_symbol_word_col + lookup_symbol_word_len); @@ -1308,7 +1300,7 @@ void TextEdit::_notification(int p_what) { for (int k = 0; k < glyphs[j].repeat; k++) { if ((char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) { if (glyphs[j].font_rid != RID()) { - TS->font_draw_glyph_outline(glyphs[j].font_rid, ci, glyphs[j].font_size, theme_cache.outline_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, theme_cache.outline_color); + TS->font_draw_glyph_outline(glyphs[j].font_rid, text_ci, glyphs[j].font_size, theme_cache.outline_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, theme_cache.outline_color); } } char_ofs += glyphs[j].advance; @@ -1343,7 +1335,7 @@ void TextEdit::_notification(int p_what) { } } - float char_pos = char_ofs + char_margin + ofs_x; + float char_pos = char_ofs + char_margin; if (char_pos >= xmargin_beg) { if (highlight_matching_braces_enabled) { for (int c = 0; c < get_caret_count(); c++) { @@ -1354,7 +1346,7 @@ void TextEdit::_notification(int p_what) { gl_color = _get_brace_mismatch_color(); } Rect2 rect = Rect2(char_pos, ofs_y + theme_cache.font->get_underline_position(theme_cache.font_size), glyphs[j].advance * glyphs[j].repeat, MAX(theme_cache.font->get_underline_thickness(theme_cache.font_size) * theme_cache.base_scale, 1)); - RS::get_singleton()->canvas_item_add_rect(ci, rect, gl_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, rect, gl_color); } if ((brace_match.close_match_line == line && brace_match.close_match_column == glyphs[j].start) || @@ -1363,18 +1355,18 @@ void TextEdit::_notification(int p_what) { gl_color = _get_brace_mismatch_color(); } Rect2 rect = Rect2(char_pos, ofs_y + theme_cache.font->get_underline_position(theme_cache.font_size), glyphs[j].advance * glyphs[j].repeat, MAX(theme_cache.font->get_underline_thickness(theme_cache.font_size) * theme_cache.base_scale, 1)); - RS::get_singleton()->canvas_item_add_rect(ci, rect, gl_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, rect, gl_color); } } } if (draw_tabs && ((glyphs[j].flags & TextServer::GRAPHEME_IS_TAB) == TextServer::GRAPHEME_IS_TAB)) { int yofs = (text_height - theme_cache.tab_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); - theme_cache.tab_icon->draw(ci, Point2(char_pos, ofs_y + yofs), gl_color); + theme_cache.tab_icon->draw(text_ci, Point2(char_pos, ofs_y + yofs), gl_color); } else if (draw_spaces && ((glyphs[j].flags & TextServer::GRAPHEME_IS_SPACE) == TextServer::GRAPHEME_IS_SPACE) && ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL)) { int yofs = (text_height - theme_cache.space_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); int xofs = (glyphs[j].advance * glyphs[j].repeat - theme_cache.space_icon->get_width()) / 2; - theme_cache.space_icon->draw(ci, Point2(char_pos + xofs, ofs_y + yofs), gl_color); + theme_cache.space_icon->draw(text_ci, Point2(char_pos + xofs, ofs_y + yofs), gl_color); } } @@ -1382,10 +1374,10 @@ void TextEdit::_notification(int p_what) { for (int k = 0; k < glyphs[j].repeat; k++) { if (!clipped && (char_ofs + char_margin) >= xmargin_beg && (char_ofs + glyphs[j].advance + char_margin) <= xmargin_end) { if (glyphs[j].font_rid != RID()) { - TS->font_draw_glyph(glyphs[j].font_rid, ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color); + TS->font_draw_glyph(glyphs[j].font_rid, text_ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color); had_glyphs_drawn = true; } else if (((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[j].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) { - TS->draw_hex_code_box(ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + ofs_x + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color); + TS->draw_hex_code_box(text_ci, glyphs[j].font_size, Vector2(char_margin + char_ofs + glyphs[j].x_off, ofs_y + glyphs[j].y_off), glyphs[j].index, gl_color); had_glyphs_drawn = true; } } @@ -1411,12 +1403,12 @@ void TextEdit::_notification(int p_what) { // is_line_folded if (line_wrap_index == line_wrap_amount && line < text.size() - 1 && _is_line_hidden(line + 1)) { - int xofs = char_ofs + char_margin + ofs_x + (_get_folded_eol_icon()->get_width() / 2); + int xofs = char_ofs + char_margin + (_get_folded_eol_icon()->get_width() / 2); if (xofs >= xmargin_beg && xofs < xmargin_end) { int yofs = (text_height - _get_folded_eol_icon()->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index); Color eol_color = _get_code_folding_color(); eol_color.a = 1; - _get_folded_eol_icon()->draw(ci, Point2(xofs, ofs_y + yofs), eol_color); + _get_folded_eol_icon()->draw(text_ci, Point2(xofs, ofs_y + yofs), eol_color); } } @@ -1439,7 +1431,7 @@ void TextEdit::_notification(int p_what) { int h = theme_cache.font->get_height(theme_cache.font_size); if (rtl) { ts_caret.l_dir = TextServer::DIRECTION_RTL; - ts_caret.l_caret = Rect2(Vector2(xmargin_end - char_margin + ofs_x, -h / 2), Size2(caret_width * 4, h)); + ts_caret.l_caret = Rect2(Vector2(xmargin_end - char_margin, -h / 2), Size2(caret_width * 4, h)); } else { ts_caret.l_dir = TextServer::DIRECTION_LTR; ts_caret.l_caret = Rect2(Vector2(char_ofs, -h / 2), Size2(caret_width * 4, h)); @@ -1447,9 +1439,9 @@ void TextEdit::_notification(int p_what) { } if ((ts_caret.l_caret != Rect2() && (ts_caret.l_dir == TextServer::DIRECTION_AUTO || ts_caret.l_dir == (TextServer::Direction)input_direction)) || (ts_caret.t_caret == Rect2())) { - carets.write[c].draw_pos.x = char_margin + ofs_x + ts_caret.l_caret.position.x; + carets.write[c].draw_pos.x = char_margin + ts_caret.l_caret.position.x; } else { - carets.write[c].draw_pos.x = char_margin + ofs_x + ts_caret.t_caret.position.x; + carets.write[c].draw_pos.x = char_margin + ts_caret.t_caret.position.x; } if (get_caret_draw_pos(c).x >= xmargin_beg && get_caret_draw_pos(c).x < xmargin_end) { @@ -1467,18 +1459,18 @@ void TextEdit::_notification(int p_what) { ts_caret.t_caret.position.y = -TS->shaped_text_get_ascent(rid); ts_caret.t_caret.size.y = h; } - ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y); + ts_caret.t_caret.position += Vector2(char_margin, ofs_y); draw_rect(ts_caret.t_caret, theme_cache.caret_color, overtype_mode); if (ts_caret.l_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) { // Draw split caret (leading part). - ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y); + ts_caret.l_caret.position += Vector2(char_margin, ofs_y); ts_caret.l_caret.size.x = caret_width; - RS::get_singleton()->canvas_item_add_rect(ci, ts_caret.l_caret, theme_cache.caret_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.l_caret, theme_cache.caret_color); // Draw extra direction marker on top of split caret. float d = (ts_caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3; Rect2 trect = Rect2(ts_caret.l_caret.position.x + d * caret_width, ts_caret.l_caret.position.y + ts_caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width); - RS::get_singleton()->canvas_item_add_rect(ci, trect, theme_cache.caret_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color); } } else { // End of the line. if (gl_size > 0) { @@ -1499,7 +1491,7 @@ void TextEdit::_notification(int p_what) { } else { ts_caret.l_caret.size.x = 3 * caret_width; } - ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y); + ts_caret.l_caret.position += Vector2(char_margin, ofs_y); if (ts_caret.l_dir == TextServer::DIRECTION_RTL) { ts_caret.l_caret.position.x -= ts_caret.l_caret.size.x; } @@ -1510,29 +1502,29 @@ void TextEdit::_notification(int p_what) { if (ts_caret.l_caret != Rect2() && ts_caret.l_dir == TextServer::DIRECTION_AUTO) { // Draw extra marker on top of mid caret. Rect2 trect = Rect2(ts_caret.l_caret.position.x - 2.5 * caret_width, ts_caret.l_caret.position.y, 6 * caret_width, caret_width); - trect.position += Vector2(char_margin + ofs_x, ofs_y); - RS::get_singleton()->canvas_item_add_rect(ci, trect, theme_cache.caret_color); + trect.position += Vector2(char_margin, ofs_y); + RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color); } else if (ts_caret.l_caret != Rect2() && ts_caret.t_caret != Rect2() && ts_caret.l_dir != ts_caret.t_dir) { // Draw extra direction marker on top of split caret. float d = (ts_caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3; Rect2 trect = Rect2(ts_caret.l_caret.position.x + d * caret_width, ts_caret.l_caret.position.y + ts_caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width); - trect.position += Vector2(char_margin + ofs_x, ofs_y); - RS::get_singleton()->canvas_item_add_rect(ci, trect, theme_cache.caret_color); + trect.position += Vector2(char_margin, ofs_y); + RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color); d = (ts_caret.t_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3; trect = Rect2(ts_caret.t_caret.position.x + d * caret_width, ts_caret.t_caret.position.y, 3 * caret_width, caret_width); - trect.position += Vector2(char_margin + ofs_x, ofs_y); - RS::get_singleton()->canvas_item_add_rect(ci, trect, theme_cache.caret_color); + trect.position += Vector2(char_margin, ofs_y); + RS::get_singleton()->canvas_item_add_rect(text_ci, trect, theme_cache.caret_color); } - ts_caret.l_caret.position += Vector2(char_margin + ofs_x, ofs_y); + ts_caret.l_caret.position += Vector2(char_margin, ofs_y); ts_caret.l_caret.size.x = caret_width; - RS::get_singleton()->canvas_item_add_rect(ci, ts_caret.l_caret, theme_cache.caret_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.l_caret, theme_cache.caret_color); - ts_caret.t_caret.position += Vector2(char_margin + ofs_x, ofs_y); + ts_caret.t_caret.position += Vector2(char_margin, ofs_y); ts_caret.t_caret.size.x = caret_width; - RS::get_singleton()->canvas_item_add_rect(ci, ts_caret.t_caret, theme_cache.caret_color); + RS::get_singleton()->canvas_item_add_rect(text_ci, ts_caret.t_caret, theme_cache.caret_color); } } } @@ -1542,7 +1534,7 @@ void TextEdit::_notification(int p_what) { // IME Intermediate text range. const Vector sel = TS->shaped_text_get_selection(rid, get_caret_column(c), get_caret_column(c) + ime_text.length()); for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height); + Rect2 rect = Rect2(sel[j].x + char_margin, ofs_y, sel[j].y - sel[j].x, text_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -1561,7 +1553,7 @@ void TextEdit::_notification(int p_what) { // IME caret. const Vector sel = TS->shaped_text_get_selection(rid, get_caret_column(c) + ime_selection.x, get_caret_column(c) + ime_selection.x + ime_selection.y); for (int j = 0; j < sel.size(); j++) { - Rect2 rect = Rect2(sel[j].x + char_margin + ofs_x, ofs_y, sel[j].y - sel[j].x, text_height); + Rect2 rect = Rect2(sel[j].x + char_margin, ofs_y, sel[j].y - sel[j].x, text_height); if (rect.position.x + rect.size.x <= xmargin_beg || rect.position.x > xmargin_end) { continue; } @@ -1587,6 +1579,7 @@ void TextEdit::_notification(int p_what) { } if (has_focus()) { + theme_cache.style_focus->draw(ci, Rect2(Point2(), get_size())); _update_ime_window_position(); } } break; @@ -1833,8 +1826,9 @@ void TextEdit::gui_input(const Ref &p_gui_input) { int line = pos.y; int col = pos.x; + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; // Gutters. - int left_margin = theme_cache.style_normal->get_margin(SIDE_LEFT); + int left_margin = style->get_margin(SIDE_LEFT); for (int i = 0; i < gutters.size(); i++) { if (!gutters[i].draw || gutters[i].width <= 0) { continue; @@ -2057,8 +2051,8 @@ void TextEdit::gui_input(const Ref &p_gui_input) { // Check if user is hovering a different gutter, and update if yes. Vector2i current_hovered_gutter = Vector2i(-1, -1); - - int left_margin = theme_cache.style_normal->get_margin(SIDE_LEFT); + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + int left_margin = style->get_margin(SIDE_LEFT); if (mpos.x <= left_margin + gutters_width + gutter_padding) { int hovered_row = get_line_column_at_pos(mpos).y; for (int i = 0; i < gutters.size(); i++) { @@ -3011,14 +3005,20 @@ void TextEdit::_show_virtual_keyboard() { /* General overrides. */ Size2 TextEdit::get_minimum_size() const { - Size2 size = theme_cache.style_normal->get_minimum_size(); + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + Size2 size = style->get_minimum_size(); + Size2 ms = Size2(); if (fit_content_height) { - size.y += content_size_cache.y; + size.height += content_size_cache.height; + } else if (v_scroll->is_visible_in_tree()) { + ms = v_scroll->get_combined_minimum_size(); } if (fit_content_width) { - size.x += content_size_cache.x; + size.width += content_size_cache.width; + } else if (h_scroll->is_visible_in_tree()) { + ms = ms.max(h_scroll->get_combined_minimum_size()); } - return size; + return size + ms; } bool TextEdit::is_text_field() const { @@ -3105,8 +3105,9 @@ void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) { Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { Point2i pos = get_line_column_at_pos(p_pos); int row = pos.y; + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; - int left_margin = theme_cache.style_normal->get_margin(SIDE_LEFT); + int left_margin = style->get_margin(SIDE_LEFT); int gutter = left_margin + gutters_width; if (p_pos.x < gutter) { for (int i = 0; i < gutters.size(); i++) { @@ -3124,7 +3125,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_ARROW; } - int xmargin_end = get_size().width - theme_cache.style_normal->get_margin(SIDE_RIGHT); + int xmargin_end = get_size().width - style->get_margin(SIDE_RIGHT); if (draw_minimap && p_pos.x > xmargin_end - minimap_width && p_pos.x <= xmargin_end) { return CURSOR_ARROW; } @@ -4395,11 +4396,8 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { } Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds) const { - float rows = p_pos.y - theme_cache.style_normal->get_margin(SIDE_TOP); - if (!editable) { - rows -= theme_cache.style_readonly->get_offset().y / 2; - rows += theme_cache.style_normal->get_offset().y / 2; - } + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + float rows = p_pos.y - style->get_margin(SIDE_TOP); rows /= get_line_height(); rows += _get_v_scroll_offset(); int first_vis_line = get_first_visible_line(); @@ -4427,12 +4425,8 @@ Point2i TextEdit::get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_ return Point2i(text[row].length(), row); } - int colx = p_pos.x - (theme_cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding); + int colx = p_pos.x - (style->get_margin(SIDE_LEFT) + gutters_width + gutter_padding); colx += first_visible_col; - if (!editable) { - colx -= theme_cache.style_readonly->get_offset().x / 2; - colx += theme_cache.style_normal->get_offset().x / 2; - } RID text_rid = text.get_line_data(row)->get_line_rid(wrap_index); float wrap_indent = (text.is_indent_wrapped_lines() && wrap_index > 0) ? get_indent_level(row) * theme_cache.font->get_char_size(' ', theme_cache.font_size).width : 0.0; @@ -4483,9 +4477,10 @@ Rect2i TextEdit::get_rect_at_line_column(int p_line, int p_column) const { return Rect2i(-1, -1, 0, 0); } + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; Point2i pos, size; pos.y = cache_entry.y_offset + get_line_height() * wrap_index; - pos.x = get_total_gutter_width() + theme_cache.style_normal->get_margin(SIDE_LEFT) - get_h_scroll(); + pos.x = get_total_gutter_width() + style->get_margin(SIDE_LEFT) - get_h_scroll(); RID text_rid = text.get_line_data(p_line)->get_line_rid(wrap_index); Vector2 col_bounds = TS->shaped_text_get_grapheme_bounds(text_rid, p_column); @@ -4507,7 +4502,7 @@ int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const { int minimap_visible_lines = get_minimap_visible_lines(); int visible_rows = get_visible_line_count() + 1; int first_vis_line = get_first_visible_line() - 1; - int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0); + int draw_amount = visible_rows + Math::ceil(_get_v_scroll_offset()); draw_amount += get_line_wrap_count(first_vis_line + 1); int minimap_line_height = (minimap_char_size.y + minimap_line_spacing); @@ -4515,13 +4510,14 @@ int TextEdit::get_minimap_line_at_pos(const Point2i &p_pos) const { int viewport_height = (draw_amount - 1) * minimap_line_height; int control_height = _get_control_height() - viewport_height; int viewport_offset_y = round(get_scroll_pos_for_line(first_vis_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount)); + viewport_offset_y += editable ? theme_cache.style_normal->get_margin(SIDE_TOP) : theme_cache.style_readonly->get_margin(SIDE_TOP); // Calculate the first line. int num_lines_before = round((viewport_offset_y) / minimap_line_height); int minimap_line = (v_scroll->get_max() <= minimap_visible_lines) ? -1 : first_vis_line; if (first_vis_line > 0 && minimap_line >= 0) { minimap_line -= get_next_visible_line_index_offset_from(first_vis_line, 0, -num_lines_before).x; - minimap_line -= (minimap_line > 0 && smooth_scroll_enabled ? 1 : 0); + minimap_line -= (minimap_line > 0 && Math::ceil(_get_v_scroll_offset()) > 0 ? 1 : 0); } if (minimap_line < 0) { @@ -5810,6 +5806,10 @@ bool TextEdit::is_scroll_past_end_of_file_enabled() const { return scroll_past_end_of_file_enabled; } +RID TextEdit::_get_text_canvas_item() const { + return text_ci; +} + VScrollBar *TextEdit::get_v_scroll_bar() const { return v_scroll; } @@ -6006,7 +6006,8 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) { set_line_as_last_visible(cur_line, cur_wrap); } - int visible_width = get_size().width - theme_cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding; + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + int visible_width = get_size().width - style->get_minimum_size().width - gutters_width - gutter_padding; if (draw_minimap) { visible_width -= minimap_width; } @@ -6060,7 +6061,8 @@ void TextEdit::center_viewport_to_caret(int p_caret) { minimap_clicked = false; set_line_as_center_visible(get_caret_line(p_caret), get_caret_wrap_index(p_caret)); - int visible_width = get_size().width - theme_cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding; + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + int visible_width = get_size().width - style->get_minimum_size().width - gutters_width - gutter_padding; if (draw_minimap) { visible_width -= minimap_width; } @@ -7887,7 +7889,8 @@ bool TextEdit::_selection_contains(int p_caret, int p_line, int p_column, bool p /* Line Wrapping */ void TextEdit::_update_wrap_at_column(bool p_force) { - int new_wrap_at = get_size().width - theme_cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding; + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + int new_wrap_at = get_size().width - style->get_minimum_size().width - gutters_width - gutter_padding; if (draw_minimap) { new_wrap_at -= minimap_width; } @@ -7937,14 +7940,6 @@ void TextEdit::_update_wrap_at_column(bool p_force) { /* Viewport. */ void TextEdit::_update_scrollbars() { Size2 size = get_size(); - Size2 hmin = h_scroll->get_combined_minimum_size(); - Size2 vmin = v_scroll->get_combined_minimum_size(); - - v_scroll->set_begin(Point2(size.width - vmin.width, theme_cache.style_normal->get_margin(SIDE_TOP))); - v_scroll->set_end(Point2(size.width, size.height - theme_cache.style_normal->get_margin(SIDE_TOP) - theme_cache.style_normal->get_margin(SIDE_BOTTOM))); - - h_scroll->set_begin(Point2(0, size.height - hmin.height)); - h_scroll->set_end(Point2(size.width - vmin.width, size.height)); bool draw_placeholder = _using_placeholder(); @@ -7954,25 +7949,23 @@ void TextEdit::_update_scrollbars() { total_rows += visible_rows - 1; } - int visible_width = size.width - theme_cache.style_normal->get_minimum_size().width; - int total_width = (draw_placeholder ? placeholder_max_width : text.get_max_width()) + gutters_width + gutter_padding; - - if (draw_minimap) { - total_width += minimap_width; - } + updating_scrolls = true; + bool update_min_size = false; - content_size_cache = Vector2i(total_width + 10, MAX(total_rows, 1) * get_line_height()); - if (fit_content_height || fit_content_width) { - update_minimum_size(); - } + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + int visible_width = size.width - style->get_minimum_size().width; + int total_width = (draw_placeholder ? placeholder_max_width : text.get_max_width()) + gutters_width + gutter_padding; - updating_scrolls = true; + int hmin = h_scroll->get_combined_minimum_size().height; + int vmin = v_scroll->get_combined_minimum_size().width; if (!fit_content_height && total_rows > visible_rows) { v_scroll->show(); + total_width += vmin; v_scroll->set_max(total_rows + _get_visible_lines_offset()); v_scroll->set_page(visible_rows + _get_visible_lines_offset()); set_v_scroll(get_v_scroll()); + update_min_size = true; } else { first_visible_line = 0; @@ -7980,6 +7973,11 @@ void TextEdit::_update_scrollbars() { v_scroll->set_value(0); v_scroll->set_max(0); v_scroll->hide(); + update_min_size = true; + } + + if (draw_minimap) { + total_width += minimap_width; } if (total_width > visible_width) { @@ -7992,20 +7990,39 @@ void TextEdit::_update_scrollbars() { if (fabs(h_scroll->get_value() - (double)first_visible_col) >= 1) { h_scroll->set_value(first_visible_col); } + update_min_size = true; } else { first_visible_col = 0; h_scroll->set_value(0); h_scroll->set_max(0); h_scroll->hide(); + update_min_size = true; + } + + h_scroll->set_begin(Point2(style->get_margin(SIDE_LEFT), size.height - style->get_margin(SIDE_BOTTOM) - hmin)); + v_scroll->set_begin(Point2(size.width - style->get_margin(SIDE_RIGHT) - vmin, style->get_margin(SIDE_TOP))); + + Point2 h_scroll_end = Point2(size.width - style->get_margin(SIDE_RIGHT), size.height - style->get_margin(SIDE_BOTTOM)); + Point2 v_scroll_end = Point2(size.width - style->get_margin(SIDE_RIGHT), size.height - style->get_margin(SIDE_BOTTOM)); + if (h_scroll->is_visible_in_tree() && v_scroll->is_visible_in_tree()) { + h_scroll_end.width -= vmin; + v_scroll_end.height -= hmin; + } + h_scroll->set_end(h_scroll_end); + v_scroll->set_end(v_scroll_end); + + content_size_cache = Vector2i(total_width + 10, MAX(total_rows, 1) * get_line_height()); + if (update_min_size || fit_content_height || fit_content_width) { + update_minimum_size(); } updating_scrolls = false; } int TextEdit::_get_control_height() const { - int control_height = get_size().height; - control_height -= theme_cache.style_normal->get_minimum_size().height; + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + int control_height = get_size().height - style->get_minimum_size().height; if (h_scroll->is_visible_in_tree()) { control_height -= h_scroll->get_size().height; } @@ -8167,7 +8184,8 @@ void TextEdit::_scroll_lines_down() { void TextEdit::_update_minimap_hover() { const Point2 mp = get_local_mouse_pos(); - const int xmargin_end = get_size().width - theme_cache.style_normal->get_margin(SIDE_RIGHT); + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; + const int xmargin_end = get_size().width - style->get_margin(SIDE_RIGHT); bool hovering_sidebar = mp.x > xmargin_end - minimap_width && mp.x < xmargin_end; if (!hovering_sidebar) { @@ -8193,8 +8211,9 @@ void TextEdit::_update_minimap_hover() { void TextEdit::_update_minimap_click() { Point2 mp = get_local_mouse_pos(); + Ref style = editable ? theme_cache.style_normal : theme_cache.style_readonly; - int xmargin_end = get_size().width - theme_cache.style_normal->get_margin(SIDE_RIGHT); + int xmargin_end = get_size().width - style->get_margin(SIDE_RIGHT); if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.x > xmargin_end)) { minimap_clicked = false; return; @@ -8204,7 +8223,7 @@ void TextEdit::_update_minimap_click() { int row = get_minimap_line_at_pos(mp); - if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) { + if (row >= get_first_visible_line() && (row <= get_last_full_visible_line() || row >= (text.size() - 1))) { minimap_scroll_ratio = v_scroll->get_as_ratio(); minimap_scroll_click_pos = mp.y; can_drag_minimap = true; @@ -8514,6 +8533,10 @@ TextEdit::TextEdit(const String &p_placeholder) { text.set_tab_size(text.get_tab_size()); + text_ci = RenderingServer::get_singleton()->canvas_item_create(); + RenderingServer::get_singleton()->canvas_item_set_parent(text_ci, get_canvas_item()); + RenderingServer::get_singleton()->canvas_item_set_use_parent_material(text_ci, true); + h_scroll = memnew(HScrollBar); v_scroll = memnew(VScrollBar); @@ -8548,6 +8571,9 @@ TextEdit::TextEdit(const String &p_placeholder) { set_placeholder(p_placeholder); - set_clip_contents(true); set_editable(true); } + +TextEdit::~TextEdit() { + RenderingServer::get_singleton()->free(text_ci); +} diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index c5f838020bd5..d9adcced0ad5 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -272,6 +272,7 @@ class TextEdit : public Control { /* Text */ Text text; + RID text_ci; bool setting_text = false; @@ -678,6 +679,8 @@ class TextEdit : public Control { // Line hiding. bool hiding_enabled = false; + RID _get_text_canvas_item() const; + void _set_hiding_enabled(bool p_enabled); bool _is_hiding_enabled() const; @@ -1112,6 +1115,7 @@ class TextEdit : public Control { #endif TextEdit(const String &p_placeholder = String()); + ~TextEdit(); }; VARIANT_ENUM_CAST(TextEdit::EditAction); diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h index 46a5046b21cc..2ef5f349a3da 100644 --- a/tests/scene/test_text_edit.h +++ b/tests/scene/test_text_edit.h @@ -7717,7 +7717,7 @@ TEST_CASE("[SceneTree][TextEdit] viewport") { CHECK(text_edit->get_h_scroll() == 0); text_edit->set_h_scroll(10000000); - CHECK(text_edit->get_h_scroll() == 306); + CHECK(text_edit->get_h_scroll() == 298 + text_edit->get_combined_minimum_size().width); CHECK(text_edit->get_h_scroll_bar()->get_combined_minimum_size().x == 8); text_edit->set_h_scroll(-100);