summaryrefslogtreecommitdiffstats
path: root/scene/gui/code_edit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/code_edit.cpp')
-rw-r--r--scene/gui/code_edit.cpp397
1 files changed, 270 insertions, 127 deletions
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 91c4fa3761..d83182c775 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -36,44 +36,10 @@
void CodeEdit::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_THEME_CHANGED:
- case NOTIFICATION_ENTER_TREE: {
- style_normal = get_theme_stylebox(SNAME("normal"));
-
- font = get_theme_font(SNAME("font"));
- font_size = get_theme_font_size(SNAME("font_size"));
-
- line_spacing = get_theme_constant(SNAME("line_spacing"));
-
+ case NOTIFICATION_THEME_CHANGED: {
set_gutter_width(main_gutter, get_line_height());
- set_gutter_width(line_number_gutter, (line_number_digits + 1) * font->get_char_size('0', font_size).width);
+ set_gutter_width(line_number_gutter, (line_number_digits + 1) * theme_cache.font->get_char_size('0', theme_cache.font_size).width);
set_gutter_width(fold_gutter, get_line_height() / 1.2);
-
- breakpoint_color = get_theme_color(SNAME("breakpoint_color"));
- breakpoint_icon = get_theme_icon(SNAME("breakpoint"));
-
- bookmark_color = get_theme_color(SNAME("bookmark_color"));
- bookmark_icon = get_theme_icon(SNAME("bookmark"));
-
- executing_line_color = get_theme_color(SNAME("executing_line_color"));
- executing_line_icon = get_theme_icon(SNAME("executing_line"));
-
- line_number_color = get_theme_color(SNAME("line_number_color"));
-
- folding_color = get_theme_color(SNAME("code_folding_color"));
- can_fold_icon = get_theme_icon(SNAME("can_fold"));
- folded_icon = get_theme_icon(SNAME("folded"));
-
- code_completion_max_width = get_theme_constant(SNAME("completion_max_width"));
- code_completion_max_lines = get_theme_constant(SNAME("completion_lines"));
- code_completion_scroll_width = get_theme_constant(SNAME("completion_scroll_width"));
- code_completion_scroll_color = get_theme_color(SNAME("completion_scroll_color"));
- code_completion_scroll_hovered_color = get_theme_color(SNAME("completion_scroll_hovered_color"));
- code_completion_background_color = get_theme_color(SNAME("completion_background_color"));
- code_completion_selected_color = get_theme_color(SNAME("completion_selected_color"));
- code_completion_existing_color = get_theme_color(SNAME("completion_existing_color"));
-
- line_length_guideline_color = get_theme_color(SNAME("line_length_guideline_color"));
} break;
case NOTIFICATION_DRAW: {
@@ -84,14 +50,14 @@ void CodeEdit::_notification(int p_what) {
const int row_height = get_line_height();
if (line_length_guideline_columns.size() > 0) {
- const int xmargin_beg = style_normal->get_margin(SIDE_LEFT) + get_total_gutter_width();
- const int xmargin_end = size.width - style_normal->get_margin(SIDE_RIGHT) - (is_drawing_minimap() ? get_minimap_width() : 0);
- const float char_size = font->get_char_size('0', font_size).width;
+ 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 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++) {
const int xoffset = xmargin_beg + char_size * (int)line_length_guideline_columns[i] - get_h_scroll();
if (xoffset > xmargin_beg && xoffset < xmargin_end) {
- Color guideline_color = (i == 0) ? line_length_guideline_color : line_length_guideline_color * Color(1, 1, 1, 0.5);
+ Color guideline_color = (i == 0) ? theme_cache.line_length_guideline_color : theme_cache.line_length_guideline_color * Color(1, 1, 1, 0.5);
if (rtl) {
RenderingServer::get_singleton()->canvas_item_add_line(ci, Point2(size.width - xoffset, 0), Point2(size.width - xoffset, size.height), guideline_color);
continue;
@@ -103,45 +69,42 @@ void CodeEdit::_notification(int p_what) {
bool code_completion_below = false;
if (caret_visible && code_completion_active && code_completion_options.size() > 0) {
- Ref<StyleBox> csb = get_theme_stylebox(SNAME("completion"));
-
const int code_completion_options_count = code_completion_options.size();
- const int lines = MIN(code_completion_options_count, code_completion_max_lines);
- const int icon_hsep = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
+ const int lines = MIN(code_completion_options_count, theme_cache.code_completion_max_lines);
const Size2 icon_area_size(row_height, row_height);
- code_completion_rect.size.width = code_completion_longest_line + icon_hsep + icon_area_size.width + 2;
+ code_completion_rect.size.width = code_completion_longest_line + theme_cache.code_completion_icon_separation + icon_area_size.width + 2;
code_completion_rect.size.height = lines * row_height;
const Point2 caret_pos = get_caret_draw_pos();
- const int total_height = csb->get_minimum_size().y + code_completion_rect.size.height;
+ const int total_height = theme_cache.code_completion_style->get_minimum_size().y + code_completion_rect.size.height;
const bool can_fit_completion_above = (caret_pos.y - row_height > total_height);
const bool can_fit_completion_below = (caret_pos.y + row_height + total_height <= get_size().height);
if (!can_fit_completion_below && can_fit_completion_above) {
- code_completion_rect.position.y = (caret_pos.y - total_height - row_height) + line_spacing;
+ code_completion_rect.position.y = (caret_pos.y - total_height - row_height) + theme_cache.line_spacing;
} else {
- code_completion_rect.position.y = caret_pos.y + (line_spacing / 2.0f);
+ code_completion_rect.position.y = caret_pos.y + (theme_cache.line_spacing / 2.0f);
code_completion_below = true;
}
- const int scroll_width = code_completion_options_count > code_completion_max_lines ? code_completion_scroll_width : 0;
- const int code_completion_base_width = font->get_string_size(code_completion_base, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width;
+ const int scroll_width = code_completion_options_count > theme_cache.code_completion_max_lines ? theme_cache.code_completion_scroll_width : 0;
+ const int code_completion_base_width = theme_cache.font->get_string_size(code_completion_base, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width;
if (caret_pos.x - code_completion_base_width + code_completion_rect.size.width + scroll_width > get_size().width) {
code_completion_rect.position.x = get_size().width - code_completion_rect.size.width - scroll_width;
} else {
code_completion_rect.position.x = caret_pos.x - code_completion_base_width;
}
- draw_style_box(csb, Rect2(code_completion_rect.position - csb->get_offset(), code_completion_rect.size + csb->get_minimum_size() + Size2(scroll_width, 0)));
- if (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)), code_completion_background_color);
+ 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)));
+ 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);
}
code_completion_scroll_rect.position = code_completion_rect.position + Vector2(code_completion_rect.size.width, 0);
code_completion_scroll_rect.size = Vector2(scroll_width, code_completion_rect.size.height);
code_completion_line_ofs = CLAMP((code_completion_force_item_center < 0 ? code_completion_current_selected : code_completion_force_item_center) - lines / 2, 0, code_completion_options_count - lines);
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), code_completion_selected_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(code_completion_rect.position.x, code_completion_rect.position.y + (code_completion_current_selected - code_completion_line_ofs) * row_height), Size2(code_completion_rect.size.width, row_height)), theme_cache.code_completion_selected_color);
for (int i = 0; i < lines; i++) {
int l = code_completion_line_ofs + i;
@@ -149,7 +112,7 @@ void CodeEdit::_notification(int p_what) {
Ref<TextLine> tl;
tl.instantiate();
- tl->add_string(code_completion_options[l].display, font, font_size);
+ tl->add_string(code_completion_options[l].display, theme_cache.font, theme_cache.font_size);
int yofs = (row_height - tl->get_size().y) / 2;
Point2 title_pos(code_completion_rect.position.x, code_completion_rect.position.y + i * row_height + yofs);
@@ -161,9 +124,9 @@ void CodeEdit::_notification(int p_what) {
Size2 icon_size = icon_area.size * 0.7;
icon->draw_rect(ci, Rect2(icon_area.position + (icon_area.size - icon_size) / 2, icon_size));
}
- title_pos.x = icon_area.position.x + icon_area.size.width + icon_hsep;
+ title_pos.x = icon_area.position.x + icon_area.size.width + theme_cache.code_completion_icon_separation;
- tl->set_width(code_completion_rect.size.width - (icon_area_size.x + icon_hsep));
+ 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);
@@ -176,14 +139,14 @@ void CodeEdit::_notification(int p_what) {
tl->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_LEFT);
}
- Point2 match_pos = Point2(code_completion_rect.position.x + icon_area_size.x + icon_hsep, code_completion_rect.position.y + i * row_height);
+ Point2 match_pos = Point2(code_completion_rect.position.x + icon_area_size.x + theme_cache.code_completion_icon_separation, code_completion_rect.position.y + i * row_height);
for (int j = 0; j < code_completion_options[l].matches.size(); j++) {
Pair<int, int> match = code_completion_options[l].matches[j];
- int match_offset = font->get_string_size(code_completion_options[l].display.substr(0, match.first), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width;
- int match_len = font->get_string_size(code_completion_options[l].display.substr(match.first, match.second), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width;
+ int match_offset = theme_cache.font->get_string_size(code_completion_options[l].display.substr(0, match.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.first, match.second), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width;
- draw_rect(Rect2(match_pos + Point2(match_offset, 0), Size2(match_len, row_height)), code_completion_existing_color);
+ draw_rect(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);
@@ -191,9 +154,9 @@ void CodeEdit::_notification(int p_what) {
/* Draw a small scroll rectangle to show a position in the options. */
if (scroll_width) {
- Color scroll_color = is_code_completion_scroll_hovered || is_code_completion_scroll_pressed ? code_completion_scroll_hovered_color : code_completion_scroll_color;
+ Color scroll_color = is_code_completion_scroll_hovered || is_code_completion_scroll_pressed ? theme_cache.code_completion_scroll_hovered_color : theme_cache.code_completion_scroll_color;
- float r = (float)code_completion_max_lines / code_completion_options_count;
+ 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);
}
@@ -201,31 +164,29 @@ void CodeEdit::_notification(int p_what) {
/* Code hint */
if (caret_visible && !code_hint.is_empty() && (!code_completion_active || (code_completion_below != code_hint_draw_below))) {
- const int font_height = font->get_height(font_size);
- Ref<StyleBox> sb = get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel"));
- Color color = get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"));
+ const int font_height = theme_cache.font->get_height(theme_cache.font_size);
Vector<String> code_hint_lines = code_hint.split("\n");
int line_count = code_hint_lines.size();
int max_width = 0;
for (int i = 0; i < line_count; i++) {
- max_width = MAX(max_width, font->get_string_size(code_hint_lines[i], HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x);
+ max_width = MAX(max_width, theme_cache.font->get_string_size(code_hint_lines[i], HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).x);
}
- Size2 minsize = sb->get_minimum_size() + Size2(max_width, line_count * font_height + (line_spacing * line_count - 1));
+ Size2 minsize = theme_cache.code_hint_style->get_minimum_size() + Size2(max_width, line_count * font_height + (theme_cache.line_spacing * line_count - 1));
- int offset = font->get_string_size(code_hint_lines[0].substr(0, code_hint_lines[0].find(String::chr(0xFFFF))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x;
+ int offset = theme_cache.font->get_string_size(code_hint_lines[0].substr(0, code_hint_lines[0].find(String::chr(0xFFFF))), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).x;
if (code_hint_xpos == -0xFFFF) {
code_hint_xpos = get_caret_draw_pos().x - offset;
}
Point2 hint_ofs = Vector2(code_hint_xpos, get_caret_draw_pos().y);
if (code_hint_draw_below) {
- hint_ofs.y += line_spacing / 2.0f;
+ hint_ofs.y += theme_cache.line_spacing / 2.0f;
} else {
- hint_ofs.y -= (minsize.y + row_height) - line_spacing;
+ hint_ofs.y -= (minsize.y + row_height) - theme_cache.line_spacing;
}
- draw_style_box(sb, Rect2(hint_ofs, minsize));
+ draw_style_box(theme_cache.code_hint_style, Rect2(hint_ofs, minsize));
int yofs = 0;
for (int i = 0; i < line_count; i++) {
@@ -234,34 +195,82 @@ void CodeEdit::_notification(int p_what) {
int begin = 0;
int end = 0;
if (line.contains(String::chr(0xFFFF))) {
- begin = font->get_string_size(line.substr(0, line.find(String::chr(0xFFFF))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x;
- end = font->get_string_size(line.substr(0, line.rfind(String::chr(0xFFFF))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x;
+ begin = theme_cache.font->get_string_size(line.substr(0, line.find(String::chr(0xFFFF))), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).x;
+ end = theme_cache.font->get_string_size(line.substr(0, line.rfind(String::chr(0xFFFF))), HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).x;
}
- Point2 round_ofs = hint_ofs + sb->get_offset() + Vector2(0, font->get_ascent(font_size) + font_height * i + yofs);
+ 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(font, round_ofs, line.replace(String::chr(0xFFFF), ""), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);
+ 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);
if (end > 0) {
// Draw an underline for the currently edited function parameter.
- const Vector2 b = hint_ofs + sb->get_offset() + Vector2(begin, font_height + font_height * i + yofs);
- draw_line(b, b + Vector2(end - begin, 0), color, 2);
+ 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);
// 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, color * Color(1, 1, 1, 0.2));
+ draw_rect(highlight_rect, theme_cache.code_hint_color * Color(1, 1, 1, 0.2));
}
- yofs += line_spacing;
+ yofs += theme_cache.line_spacing;
}
}
} break;
}
}
+void CodeEdit::_update_theme_item_cache() {
+ TextEdit::_update_theme_item_cache();
+
+ /* Gutters */
+ theme_cache.code_folding_color = get_theme_color(SNAME("code_folding_color"));
+ theme_cache.can_fold_icon = get_theme_icon(SNAME("can_fold"));
+ theme_cache.folded_icon = get_theme_icon(SNAME("folded"));
+ theme_cache.folded_eol_icon = get_theme_icon(SNAME("folded_eol_icon"));
+
+ theme_cache.breakpoint_color = get_theme_color(SNAME("breakpoint_color"));
+ theme_cache.breakpoint_icon = get_theme_icon(SNAME("breakpoint"));
+
+ theme_cache.bookmark_color = get_theme_color(SNAME("bookmark_color"));
+ theme_cache.bookmark_icon = get_theme_icon(SNAME("bookmark"));
+
+ theme_cache.executing_line_color = get_theme_color(SNAME("executing_line_color"));
+ theme_cache.executing_line_icon = get_theme_icon(SNAME("executing_line"));
+
+ theme_cache.line_number_color = get_theme_color(SNAME("line_number_color"));
+
+ /* Code Completion */
+ theme_cache.code_completion_style = get_theme_stylebox(SNAME("completion"));
+ theme_cache.code_completion_icon_separation = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
+
+ theme_cache.code_completion_max_width = get_theme_constant(SNAME("completion_max_width"));
+ theme_cache.code_completion_max_lines = get_theme_constant(SNAME("completion_lines"));
+ theme_cache.code_completion_scroll_width = get_theme_constant(SNAME("completion_scroll_width"));
+ theme_cache.code_completion_scroll_color = get_theme_color(SNAME("completion_scroll_color"));
+ theme_cache.code_completion_scroll_hovered_color = get_theme_color(SNAME("completion_scroll_hovered_color"));
+ theme_cache.code_completion_background_color = get_theme_color(SNAME("completion_background_color"));
+ theme_cache.code_completion_selected_color = get_theme_color(SNAME("completion_selected_color"));
+ theme_cache.code_completion_existing_color = get_theme_color(SNAME("completion_existing_color"));
+
+ /* Code hint */
+ theme_cache.code_hint_style = get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel"));
+ theme_cache.code_hint_color = get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"));
+
+ /* Line length guideline */
+ theme_cache.line_length_guideline_color = get_theme_color(SNAME("line_length_guideline_color"));
+
+ /* Other visuals */
+ theme_cache.style_normal = get_theme_stylebox(SNAME("normal"));
+
+ theme_cache.font = get_theme_font(SNAME("font"));
+ theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
+
+ theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing"));
+}
+
void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventMouseButton> mb = p_gui_input;
-
if (mb.is_valid()) {
/* Ignore mouse clicks in IME input mode. */
if (has_ime_text()) {
@@ -270,14 +279,24 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (is_code_completion_scroll_pressed && mb->get_button_index() == MouseButton::LEFT) {
is_code_completion_scroll_pressed = false;
+ accept_event();
+ queue_redraw();
+ return;
+ }
+
+ if (is_code_completion_drag_started && !mb->is_pressed()) {
+ is_code_completion_drag_started = false;
+ accept_event();
queue_redraw();
return;
}
if (code_completion_active && code_completion_rect.has_point(mb->get_position())) {
if (!mb->is_pressed()) {
+ accept_event();
return;
}
+ is_code_completion_drag_started = true;
switch (mb->get_button_index()) {
case MouseButton::WHEEL_UP: {
@@ -309,19 +328,23 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
+ accept_event();
return;
} else if (code_completion_active && code_completion_scroll_rect.has_point(mb->get_position())) {
if (mb->get_button_index() != MouseButton::LEFT) {
+ accept_event();
return;
}
if (mb->is_pressed()) {
+ is_code_completion_drag_started = true;
is_code_completion_scroll_pressed = true;
_update_scroll_selected_line(mb->get_position().y);
queue_redraw();
}
+ accept_event();
return;
}
@@ -342,7 +365,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
if (is_line_folded(line)) {
int wrap_index = get_line_wrap_index_at_column(line, col);
if (wrap_index == get_line_wrap_count(line)) {
- int eol_icon_width = folded_eol_icon->get_width();
+ int eol_icon_width = theme_cache.folded_eol_icon->get_width();
int left_margin = get_total_gutter_width() + eol_icon_width + get_line_width(line, wrap_index) - get_h_scroll();
if (mpos.x > left_margin && mpos.x <= left_margin + eol_icon_width + 3) {
unfold_line(line);
@@ -394,14 +417,21 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
bool scroll_hovered = code_completion_scroll_rect.has_point(mpos);
if (is_code_completion_scroll_hovered != scroll_hovered) {
is_code_completion_scroll_hovered = scroll_hovered;
+ accept_event();
queue_redraw();
}
if (is_code_completion_scroll_pressed) {
_update_scroll_selected_line(mpos.y);
+ accept_event();
queue_redraw();
return;
}
+
+ if (code_completion_active && code_completion_rect.has_point(mm->get_position())) {
+ accept_event();
+ return;
+ }
}
Ref<InputEventKey> k = p_gui_input;
@@ -412,16 +442,17 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
bool update_code_completion = false;
if (!k.is_valid()) {
- TextEdit::gui_input(p_gui_input);
+ // MouseMotion events should not be handled by TextEdit logic if we're
+ // currently clicking and dragging from the code completion panel.
+ if (!mm.is_valid() || !is_code_completion_drag_started) {
+ TextEdit::gui_input(p_gui_input);
+ }
return;
}
/* Ctrl + Hover symbols */
-#ifdef MACOS_ENABLED
- if (k->get_keycode() == Key::META) {
-#else
- if (k->get_keycode() == Key::CTRL) {
-#endif
+ bool mac_keys = OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios");
+ if ((mac_keys && k->get_keycode() == Key::META) || (!mac_keys && k->get_keycode() == Key::CTRL)) {
if (symbol_lookup_on_click_enabled) {
if (k->is_pressed() && !is_dragging_cursor()) {
symbol_lookup_new_word = get_word_at_pos(get_local_mouse_pos());
@@ -436,12 +467,12 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
/* If a modifier has been pressed, and nothing else, return. */
- if (!k->is_pressed() || k->get_keycode() == Key::CTRL || k->get_keycode() == Key::ALT || k->get_keycode() == Key::SHIFT || k->get_keycode() == Key::META) {
+ if (!k->is_pressed() || k->get_keycode() == Key::CTRL || k->get_keycode() == Key::ALT || k->get_keycode() == Key::SHIFT || k->get_keycode() == Key::META || k->get_keycode() == Key::CAPSLOCK) {
return;
}
- /* Allow unicode handling if: */
- /* No Modifiers are pressed (except shift) */
+ // Allow unicode handling if:
+ // No modifiers are pressed (except Shift and CapsLock)
bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
/* AUTO-COMPLETE */
@@ -475,14 +506,14 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
if (k->is_action("ui_page_up", true)) {
- code_completion_current_selected = MAX(0, code_completion_current_selected - code_completion_max_lines);
+ code_completion_current_selected = MAX(0, code_completion_current_selected - theme_cache.code_completion_max_lines);
code_completion_force_item_center = -1;
queue_redraw();
accept_event();
return;
}
if (k->is_action("ui_page_down", true)) {
- code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + code_completion_max_lines);
+ code_completion_current_selected = MIN(code_completion_options.size() - 1, code_completion_current_selected + theme_cache.code_completion_max_lines);
code_completion_force_item_center = -1;
queue_redraw();
accept_event();
@@ -553,7 +584,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- // Override new line actions, for auto indent
+ // Override new line actions, for auto indent.
if (k->is_action("ui_text_newline_above", true)) {
_new_line(false, true);
accept_event();
@@ -570,7 +601,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
return;
}
- /* Remove shift otherwise actions will not match. */
+ // Remove shift, otherwise actions will not match.
k = k->duplicate();
k->set_shift_pressed(false);
@@ -611,7 +642,7 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
if (line != -1 && is_line_folded(line)) {
int wrap_index = get_line_wrap_index_at_column(line, col);
if (wrap_index == get_line_wrap_count(line)) {
- int eol_icon_width = folded_eol_icon->get_width();
+ int eol_icon_width = theme_cache.folded_eol_icon->get_width();
int left_margin = get_total_gutter_width() + eol_icon_width + get_line_width(line, wrap_index) - get_h_scroll();
if (p_pos.x > left_margin && p_pos.x <= left_margin + eol_icon_width + 3) {
return CURSOR_POINTING_HAND;
@@ -743,8 +774,7 @@ void CodeEdit::_backspace_internal(int p_caret) {
}
}
- // For space indentation we need to do a simple unindent if there are no chars to the left, acting in the
- // same way as tabs.
+ // For space indentation we need to do a basic unindent if there are no chars to the left, acting the same way as tabs.
if (indent_using_spaces && cc != 0) {
if (get_first_non_whitespace_column(cl) >= cc) {
prev_column = cc - _calculate_spaces_till_next_left_indent(cc);
@@ -977,6 +1007,116 @@ void CodeEdit::unindent_lines() {
queue_redraw();
}
+void CodeEdit::convert_indent(int p_from_line, int p_to_line) {
+ if (!is_editable()) {
+ return;
+ }
+
+ // Check line range.
+ p_from_line = (p_from_line < 0) ? 0 : p_from_line;
+ p_to_line = (p_to_line < 0) ? get_line_count() - 1 : p_to_line;
+
+ ERR_FAIL_COND(p_from_line >= get_line_count());
+ ERR_FAIL_COND(p_to_line >= get_line_count());
+ ERR_FAIL_COND(p_to_line < p_from_line);
+
+ // Store caret states.
+ Vector<int> caret_columns;
+ Vector<Pair<int, int>> from_selections;
+ Vector<Pair<int, int>> to_selections;
+ caret_columns.resize(get_caret_count());
+ from_selections.resize(get_caret_count());
+ to_selections.resize(get_caret_count());
+ for (int c = 0; c < get_caret_count(); c++) {
+ caret_columns.write[c] = get_caret_column(c);
+
+ // Set "selection_from_line" to -1 to allow checking if there was a selection later.
+ if (!has_selection(c)) {
+ from_selections.write[c].first = -1;
+ continue;
+ }
+ from_selections.write[c].first = get_selection_from_line(c);
+ from_selections.write[c].second = get_selection_from_column(c);
+ to_selections.write[c].first = get_selection_to_line(c);
+ to_selections.write[c].second = get_selection_to_column(c);
+ }
+
+ // Check lines within range.
+ const char32_t from_indent_char = indent_using_spaces ? '\t' : ' ';
+ int size_diff = indent_using_spaces ? indent_size - 1 : -(indent_size - 1);
+ bool changed_indentation = false;
+ for (int i = p_from_line; i <= p_to_line; i++) {
+ String line = get_line(i);
+
+ if (line.length() <= 0) {
+ continue;
+ }
+
+ // Check chars in the line.
+ int j = 0;
+ int space_count = 0;
+ bool line_changed = false;
+ while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) {
+ if (line[j] != from_indent_char) {
+ space_count = 0;
+ j++;
+ continue;
+ }
+ space_count++;
+
+ if (!indent_using_spaces && space_count != indent_size) {
+ j++;
+ continue;
+ }
+
+ line_changed = true;
+ if (!changed_indentation) {
+ begin_complex_operation();
+ changed_indentation = true;
+ }
+
+ // Calculate new caret state.
+ for (int c = 0; c < get_caret_count(); c++) {
+ if (get_caret_line(c) != i || caret_columns[c] <= j) {
+ continue;
+ }
+ caret_columns.write[c] += size_diff;
+
+ if (from_selections.write[c].first == -1) {
+ continue;
+ }
+ from_selections.write[c].second = from_selections[c].first == i ? from_selections[c].second + size_diff : from_selections[c].second;
+ to_selections.write[c].second = to_selections[c].first == i ? to_selections[c].second + size_diff : to_selections[c].second;
+ }
+
+ // Calculate new line.
+ line = line.left(j + ((size_diff < 0) ? size_diff : 0)) + indent_text + line.substr(j + 1);
+
+ space_count = 0;
+ j += size_diff;
+ }
+
+ if (line_changed) {
+ set_line(i, line);
+ }
+ }
+
+ if (!changed_indentation) {
+ return;
+ }
+
+ // Restore caret states.
+ for (int c = 0; c < get_caret_count(); c++) {
+ set_caret_column(caret_columns[c], c == 0, c);
+ if (from_selections.write[c].first != -1) {
+ select(from_selections.write[c].first, from_selections.write[c].second, to_selections.write[c].first, to_selections.write[c].second, c);
+ }
+ }
+ merge_overlapping_carets();
+ end_complex_operation();
+ queue_redraw();
+}
+
int CodeEdit::_calculate_spaces_till_next_left_indent(int p_column) const {
int spaces_till_indent = p_column % indent_size;
if (spaces_till_indent == 0) {
@@ -1041,7 +1181,7 @@ void CodeEdit::_new_line(bool p_split_current_line, bool p_above) {
for (; line_col < cc; line_col++) {
char32_t c = line[line_col];
- if (auto_indent_prefixes.has(c)) {
+ if (auto_indent_prefixes.has(c) && is_in_comment(cl, line_col) == -1) {
should_indent = true;
indent_char = c;
continue;
@@ -1222,7 +1362,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) {
- if (draw_breakpoints && breakpoint_icon.is_valid()) {
+ if (draw_breakpoints && theme_cache.breakpoint_icon.is_valid()) {
bool breakpointed = is_line_breakpointed(p_line);
bool hovering = p_region.has_point(get_local_mouse_pos());
bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
@@ -1230,18 +1370,18 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
if (breakpointed || (hovering && !is_dragging_cursor() && !shift_pressed)) {
int padding = p_region.size.x / 6;
- Color use_color = breakpoint_color;
+ Color use_color = theme_cache.breakpoint_color;
if (hovering && !shift_pressed) {
use_color = breakpointed ? use_color.lightened(0.3) : use_color.darkened(0.5);
}
Rect2 icon_region = p_region;
icon_region.position += Point2(padding, padding);
icon_region.size -= Point2(padding, padding) * 2;
- breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
+ theme_cache.breakpoint_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
- if (draw_bookmarks && bookmark_icon.is_valid()) {
+ if (draw_bookmarks && theme_cache.bookmark_icon.is_valid()) {
bool bookmarked = is_line_bookmarked(p_line);
bool hovering = p_region.has_point(get_local_mouse_pos());
bool shift_pressed = Input::get_singleton()->is_key_pressed(Key::SHIFT);
@@ -1250,25 +1390,25 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
int horizontal_padding = p_region.size.x / 2;
int vertical_padding = p_region.size.y / 4;
- Color use_color = bookmark_color;
+ Color use_color = theme_cache.bookmark_color;
if (hovering && shift_pressed) {
use_color = bookmarked ? use_color.lightened(0.3) : use_color.darkened(0.5);
}
Rect2 icon_region = p_region;
icon_region.position += Point2(horizontal_padding, 0);
icon_region.size -= Point2(horizontal_padding * 1.1, vertical_padding);
- bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
+ theme_cache.bookmark_icon->draw_rect(get_canvas_item(), icon_region, false, use_color);
}
}
- if (draw_executing_lines && is_line_executing(p_line) && executing_line_icon.is_valid()) {
+ if (draw_executing_lines && is_line_executing(p_line) && theme_cache.executing_line_icon.is_valid()) {
int horizontal_padding = p_region.size.x / 10;
int vertical_padding = p_region.size.y / 4;
Rect2 icon_region = p_region;
icon_region.position += Point2(horizontal_padding, vertical_padding);
icon_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
- executing_line_icon->draw_rect(get_canvas_item(), icon_region, false, executing_line_color);
+ theme_cache.executing_line_icon->draw_rect(get_canvas_item(), icon_region, false, theme_cache.executing_line_color);
}
}
@@ -1338,7 +1478,7 @@ PackedInt32Array CodeEdit::get_bookmarked_lines() const {
return ret;
}
-// executing lines
+// Executing lines
void CodeEdit::set_line_as_executing(int p_line, bool p_executing) {
int mask = get_line_gutter_metadata(p_line, main_gutter);
set_line_gutter_metadata(p_line, main_gutter, p_executing ? mask | MAIN_GUTTER_EXECUTING : mask & ~MAIN_GUTTER_EXECUTING);
@@ -1392,11 +1532,11 @@ void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2
}
Ref<TextLine> tl;
tl.instantiate();
- tl->add_string(fc, font, font_size);
+ tl->add_string(fc, theme_cache.font, theme_cache.font_size);
int yofs = p_region.position.y + (get_line_height() - tl->get_size().y) / 2;
Color number_color = get_line_gutter_item_color(p_line, line_number_gutter);
if (number_color == Color(1, 1, 1)) {
- number_color = line_number_color;
+ number_color = theme_cache.line_number_color;
}
tl->draw(get_canvas_item(), Point2(p_region.position.x, yofs), number_color);
}
@@ -1424,10 +1564,10 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi
p_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
if (can_fold_line(p_line)) {
- can_fold_icon->draw_rect(get_canvas_item(), p_region, false, folding_color);
+ theme_cache.can_fold_icon->draw_rect(get_canvas_item(), p_region, false, theme_cache.code_folding_color);
return;
}
- folded_icon->draw_rect(get_canvas_item(), p_region, false, folding_color);
+ theme_cache.folded_icon->draw_rect(get_canvas_item(), p_region, false, theme_cache.code_folding_color);
}
/* Line Folding */
@@ -1968,7 +2108,7 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
return;
}
- char32_t caret_last_completion_char;
+ char32_t caret_last_completion_char = 0;
begin_complex_operation();
Vector<int> caret_edit_order = get_caret_index_edit_order();
for (const int &i : caret_edit_order) {
@@ -2030,7 +2170,7 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
insert_text_at_caret(insert_text.substr(matching_chars), i);
}
- //* Handle merging of symbols eg strings, brackets.
+ // Handle merging of symbols eg strings, brackets.
const String line = get_line(caret_line);
char32_t next_char = line[get_caret_column(i)];
char32_t last_completion_char = insert_text[insert_text.length() - 1];
@@ -2084,6 +2224,7 @@ void CodeEdit::cancel_code_completion() {
}
code_completion_forced = false;
code_completion_active = false;
+ is_code_completion_drag_started = false;
queue_redraw();
}
@@ -2166,6 +2307,8 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("indent_lines"), &CodeEdit::indent_lines);
ClassDB::bind_method(D_METHOD("unindent_lines"), &CodeEdit::unindent_lines);
+ ClassDB::bind_method(D_METHOD("convert_indent", "from_line", "to_line"), &CodeEdit::convert_indent, DEFVAL(-1), DEFVAL(-1));
+
/* Auto brace completion */
ClassDB::bind_method(D_METHOD("set_auto_brace_completion_enabled", "enable"), &CodeEdit::set_auto_brace_completion_enabled);
ClassDB::bind_method(D_METHOD("is_auto_brace_completion_enabled"), &CodeEdit::is_auto_brace_completion_enabled);
@@ -2204,7 +2347,7 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_bookmarked_lines"), &CodeEdit::clear_bookmarked_lines);
ClassDB::bind_method(D_METHOD("get_bookmarked_lines"), &CodeEdit::get_bookmarked_lines);
- // executing lines
+ // Executing lines
ClassDB::bind_method(D_METHOD("set_line_as_executing", "line", "executing"), &CodeEdit::set_line_as_executing);
ClassDB::bind_method(D_METHOD("is_line_executing", "line"), &CodeEdit::is_line_executing);
ClassDB::bind_method(D_METHOD("clear_executing_lines"), &CodeEdit::clear_executing_lines);
@@ -2841,13 +2984,13 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
offset = line_height;
}
- if (font.is_valid()) {
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (theme_cache.font.is_valid()) {
+ max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
code_completion_options.push_back(option);
}
- code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
+ code_completion_longest_line = MIN(max_width, theme_cache.code_completion_max_width * theme_cache.font_size);
code_completion_current_selected = 0;
code_completion_force_item_center = -1;
code_completion_active = true;
@@ -2962,8 +3105,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
if (string_to_complete.length() == 0) {
code_completion_options.push_back(option);
- if (font.is_valid()) {
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (theme_cache.font.is_valid()) {
+ max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
continue;
}
@@ -3070,8 +3213,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
option.matches.append_array(ssq_matches);
completion_options_subseq.push_back(option);
}
- if (font.is_valid()) {
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (theme_cache.font.is_valid()) {
+ max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
} else if (!*ssq_lower) { // Matched the whole subsequence in s_lower.
option.matches.clear();
@@ -3089,8 +3232,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
option.matches.append_array(ssq_lower_matches);
completion_options_subseq_casei.push_back(option);
}
- if (font.is_valid()) {
- max_width = MAX(max_width, font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).width + offset);
+ if (theme_cache.font.is_valid()) {
+ max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
}
}
@@ -3113,7 +3256,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
return;
}
- code_completion_longest_line = MIN(max_width, code_completion_max_width * font_size);
+ code_completion_longest_line = MIN(max_width, theme_cache.code_completion_max_width * theme_cache.font_size);
code_completion_current_selected = 0;
code_completion_force_item_center = -1;
code_completion_active = true;
@@ -3149,8 +3292,8 @@ void CodeEdit::_text_changed() {
line_number_digits++;
}
- if (font.is_valid()) {
- set_gutter_width(line_number_gutter, (line_number_digits + 1) * font->get_char_size('0', font_size).width);
+ if (theme_cache.font.is_valid()) {
+ set_gutter_width(line_number_gutter, (line_number_digits + 1) * theme_cache.font->get_char_size('0', theme_cache.font_size).width);
}
lc = get_line_count();