Quellcode durchsuchen

[Complex Text Layouts] Refactor TextEdit and CodeEdit controls.

bruvzg vor 5 Jahren
Ursprung
Commit
3be31c4960

+ 1 - 0
doc/classes/CodeEdit.xml

@@ -3,6 +3,7 @@
 	<brief_description>
 	</brief_description>
 	<description>
+		[b]Note[/b]: By default [CodeEdit] always use left-to-right text direction to correcly display source code.
 	</description>
 	<tutorials>
 	</tutorials>

+ 86 - 15
editor/code_editor.cpp

@@ -731,20 +731,10 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
 
 	Ref<InputEventMagnifyGesture> magnify_gesture = p_event;
 	if (magnify_gesture.is_valid()) {
-		/*
-		Ref<DynamicFont> font = text_editor->get_theme_font("font");
+		font_size = text_editor->get_theme_font_size("font_size");
+		font_size *= powf(magnify_gesture->get_factor(), 0.25);
 
-		if (font.is_valid()) {
-			if (font->get_size() != (int)font_size) {
-				font_size = font->get_size();
-			}
-
-			font_size *= powf(magnify_gesture->get_factor(), 0.25);
-
-			_add_font_size((int)font_size - font->get_size());
-		}
-		*/
-		//TODO move size to draw functions
+		_add_font_size((int)font_size - text_editor->get_theme_font_size("font_size"));
 		return;
 	}
 
@@ -767,15 +757,23 @@ void CodeTextEditor::_text_editor_gui_input(const Ref<InputEvent> &p_event) {
 
 void CodeTextEditor::_zoom_in() {
 	font_resize_val += MAX(EDSCALE, 1.0f);
+	_zoom_changed();
 }
 
 void CodeTextEditor::_zoom_out() {
 	font_resize_val -= MAX(EDSCALE, 1.0f);
+	_zoom_changed();
+}
+
+void CodeTextEditor::_zoom_changed() {
+	if (font_resize_timer->get_time_left() == 0) {
+		font_resize_timer->start();
+	}
 }
 
 void CodeTextEditor::_reset_zoom() {
-	font_resize_val = 1.0f;
-	//TODO MOVE size to draw functions
+	EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14);
+	text_editor->add_theme_font_size_override("font_size", 14 * EDSCALE);
 }
 
 void CodeTextEditor::_line_col_changed() {
@@ -884,6 +882,24 @@ Ref<Texture2D> CodeTextEditor::_get_completion_icon(const ScriptCodeCompletionOp
 	return tex;
 }
 
+void CodeTextEditor::_font_resize_timeout() {
+	if (_add_font_size(font_resize_val)) {
+		font_resize_val = 0;
+	}
+}
+
+bool CodeTextEditor::_add_font_size(int p_delta) {
+	int old_size = text_editor->get_theme_font_size("font_size");
+	int new_size = CLAMP(old_size + p_delta, 8 * EDSCALE, 96 * EDSCALE);
+
+	if (new_size != old_size) {
+		EditorSettings::get_singleton()->set("interface/editor/code_font_size", new_size / EDSCALE);
+		text_editor->add_theme_font_size_override("font_size", new_size);
+	}
+
+	return true;
+}
+
 void CodeTextEditor::update_editor_settings() {
 	completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color");
 	completion_string_color = EDITOR_GET("text_editor/highlighting/string_color");
@@ -1479,6 +1495,31 @@ void CodeTextEditor::_on_settings_change() {
 
 	font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
 
+	int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures");
+	switch (ot_mode) {
+		case 1: { // Disable ligatures.
+			text_editor->clear_opentype_features();
+			text_editor->set_opentype_feature("calt", 0);
+		} break;
+		case 2: { // Custom.
+			text_editor->clear_opentype_features();
+			Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(",");
+			Dictionary ftrs;
+			for (int i = 0; i < subtag.size(); i++) {
+				Vector<String> subtag_a = subtag[i].split("=");
+				if (subtag_a.size() == 2) {
+					text_editor->set_opentype_feature(subtag_a[0], subtag_a[1].to_int());
+				} else if (subtag_a.size() == 1) {
+					text_editor->set_opentype_feature(subtag_a[0], 1);
+				}
+			}
+		} break;
+		default: { // Default.
+			text_editor->clear_opentype_features();
+			text_editor->set_opentype_feature("calt", 1);
+		} break;
+	}
+
 	// Auto brace completion.
 	text_editor->set_auto_brace_completion(
 			EDITOR_GET("text_editor/completion/auto_brace_complete"));
@@ -1663,6 +1704,31 @@ CodeTextEditor::CodeTextEditor() {
 	add_child(text_editor);
 	text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
 
+	int ot_mode = EditorSettings::get_singleton()->get("interface/editor/code_font_contextual_ligatures");
+	switch (ot_mode) {
+		case 1: { // Disable ligatures.
+			text_editor->clear_opentype_features();
+			text_editor->set_opentype_feature("calt", 0);
+		} break;
+		case 2: { // Custom.
+			text_editor->clear_opentype_features();
+			Vector<String> subtag = String(EditorSettings::get_singleton()->get("interface/editor/code_font_custom_opentype_features")).split(",");
+			Dictionary ftrs;
+			for (int i = 0; i < subtag.size(); i++) {
+				Vector<String> subtag_a = subtag[i].split("=");
+				if (subtag_a.size() == 2) {
+					text_editor->set_opentype_feature(subtag_a[0], subtag_a[1].to_int());
+				} else if (subtag_a.size() == 1) {
+					text_editor->set_opentype_feature(subtag_a[0], 1);
+				}
+			}
+		} break;
+		default: { // Default.
+			text_editor->clear_opentype_features();
+			text_editor->set_opentype_feature("calt", 1);
+		} break;
+	}
+
 	// Added second so it opens at the bottom, so it won't shift the entire text editor when opening.
 	find_replace_bar = memnew(FindReplaceBar);
 	add_child(find_replace_bar);
@@ -1764,6 +1830,11 @@ CodeTextEditor::CodeTextEditor() {
 
 	font_resize_val = 0;
 	font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size");
+	font_resize_timer = memnew(Timer);
+	add_child(font_resize_timer);
+	font_resize_timer->set_one_shot(true);
+	font_resize_timer->set_wait_time(0.07);
+	font_resize_timer->connect("timeout", callable_mp(this, &CodeTextEditor::_font_resize_timeout));
 
 	EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &CodeTextEditor::_on_settings_change));
 }

+ 4 - 0
editor/code_editor.h

@@ -151,6 +151,7 @@ class CodeTextEditor : public VBoxContainer {
 	Timer *idle;
 	Timer *code_complete_timer;
 
+	Timer *font_resize_timer;
 	int font_resize_val;
 	real_t font_size;
 
@@ -163,11 +164,14 @@ class CodeTextEditor : public VBoxContainer {
 	void _update_font();
 	void _complete_request();
 	Ref<Texture2D> _get_completion_icon(const ScriptCodeCompletionOption &p_option);
+	void _font_resize_timeout();
+	bool _add_font_size(int p_delta);
 
 	void _input(const Ref<InputEvent> &event);
 	void _text_editor_gui_input(const Ref<InputEvent> &p_event);
 	void _zoom_in();
 	void _zoom_out();
+	void _zoom_changed();
 	void _reset_zoom();
 
 	Color completion_font_color;

+ 3 - 1
editor/plugins/script_text_editor.cpp

@@ -912,6 +912,7 @@ void ScriptTextEditor::update_toggle_scripts_button() {
 
 void ScriptTextEditor::_update_connected_methods() {
 	CodeEdit *text_edit = code_editor->get_text_editor();
+	text_edit->set_gutter_width(connection_gutter, text_edit->get_row_height());
 	for (int i = 0; i < text_edit->get_line_count(); i++) {
 		if (text_edit->get_line_gutter_metadata(i, connection_gutter) == "") {
 			continue;
@@ -1352,7 +1353,8 @@ void ScriptTextEditor::_change_syntax_highlighter(int p_idx) {
 
 void ScriptTextEditor::_notification(int p_what) {
 	switch (p_what) {
-		case NOTIFICATION_THEME_CHANGED: {
+		case NOTIFICATION_THEME_CHANGED:
+		case NOTIFICATION_ENTER_TREE: {
 			code_editor->get_text_editor()->set_gutter_width(connection_gutter, code_editor->get_text_editor()->get_row_height());
 		} break;
 		default:

+ 14 - 8
scene/gui/code_edit.cpp

@@ -34,9 +34,9 @@ void CodeEdit::_notification(int p_what) {
 	switch (p_what) {
 		case NOTIFICATION_THEME_CHANGED:
 		case NOTIFICATION_ENTER_TREE: {
-			set_gutter_width(main_gutter, cache.row_height);
-			set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0').width);
-			set_gutter_width(fold_gutter, cache.row_height / 1.2);
+			set_gutter_width(main_gutter, get_row_height());
+			set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0', 0, cache.font_size).width);
+			set_gutter_width(fold_gutter, get_row_height() / 1.2);
 
 			breakpoint_color = get_theme_color("breakpoint_color");
 			breakpoint_icon = get_theme_icon("breakpoint");
@@ -234,14 +234,16 @@ bool CodeEdit::is_line_numbers_zero_padded() const {
 }
 
 void CodeEdit::_line_number_draw_callback(int p_line, int p_gutter, const Rect2 &p_region) {
-	String fc = String::num(p_line + 1).lpad(line_number_digits, line_number_padding);
-
-	int yofs = p_region.position.y + (cache.row_height - cache.font->get_height()) / 2;
+	String fc = TS->format_number(String::num(p_line + 1).lpad(line_number_digits, line_number_padding));
+	Ref<TextLine> tl;
+	tl.instance();
+	tl->add_string(fc, cache.font, cache.font_size);
+	int yofs = p_region.position.y + (get_row_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;
 	}
-	cache.font->draw_string(get_canvas_item(), Point2(p_region.position.x, yofs + cache.font->get_ascent()), fc, HALIGN_LEFT, -1, cache.font_size, number_color);
+	tl->draw(get_canvas_item(), Point2(p_region.position.x, yofs), number_color);
 }
 
 /* Fold Gutter */
@@ -368,7 +370,7 @@ void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
 	while (lc /= 10) {
 		line_number_digits++;
 	}
-	set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0').width);
+	set_gutter_width(line_number_gutter, (line_number_digits + 1) * cache.font->get_char_size('0', 0, cache.font_size).width);
 
 	int from_line = MIN(p_from_line, p_to_line);
 	int line_count = (p_to_line - p_from_line);
@@ -410,6 +412,10 @@ void CodeEdit::_update_gutter_indexes() {
 }
 
 CodeEdit::CodeEdit() {
+	/* Text Direction */
+	set_layout_direction(LAYOUT_DIRECTION_LTR);
+	set_text_direction(TEXT_DIRECTION_LTR);
+
 	/* Gutters */
 	int gutter_idx = 0;
 

Datei-Diff unterdrückt, da er zu groß ist
+ 425 - 347
scene/gui/text_edit.cpp


+ 97 - 19
scene/gui/text_edit.h

@@ -36,6 +36,7 @@
 #include "scene/gui/scroll_bar.h"
 #include "scene/main/timer.h"
 #include "scene/resources/syntax_highlighter.h"
+#include "scene/resources/text_paragraph.h"
 
 class TextEdit : public Control {
 	GDCLASS(TextEdit, Control);
@@ -87,47 +88,68 @@ private:
 		struct Line {
 			Vector<Gutter> gutters;
 
-			int32_t width_cache;
+			String data;
+			Vector<Vector2i> bidi_override;
+			Ref<TextParagraph> data_buf;
+
 			bool marked;
 			bool hidden;
-			int32_t wrap_amount_cache;
-			String data;
+
 			Line() {
-				width_cache = 0;
+				data_buf.instance();
+
 				marked = false;
 				hidden = false;
-				wrap_amount_cache = 0;
 			}
 		};
 
 	private:
 		mutable Vector<Line> text;
 		Ref<Font> font;
+		int font_size = -1;
+
+		Dictionary opentype_features;
+		String language;
+		TextServer::Direction direction = TextServer::DIRECTION_AUTO;
+		bool draw_control_chars = false;
+
+		int width = -1;
+
 		int indent_size = 4;
 		int gutter_count = 0;
 
-		void _update_line_cache(int p_line) const;
-
 	public:
 		void set_indent_size(int p_indent_size);
 		void set_font(const Ref<Font> &p_font);
+		void set_font_size(int p_font_size);
+		void set_font_features(const Dictionary &p_features);
+		void set_direction_and_language(TextServer::Direction p_direction, String p_language);
+		void set_draw_control_chars(bool p_draw_control_chars);
+
+		int get_line_height(int p_line, int p_wrap_index) const;
 		int get_line_width(int p_line) const;
 		int get_max_width(bool p_exclude_hidden = false) const;
-		int get_char_width(char32_t c, char32_t next_c, int px) const;
-		void set_line_wrap_amount(int p_line, int p_wrap_amount) const;
+
+		void set_width(float p_width);
 		int get_line_wrap_amount(int p_line) const;
-		void set(int p_line, const String &p_text);
+		Vector<Vector2i> get_line_wrap_ranges(int p_line) const;
+		const Ref<TextParagraph> get_line_data(int p_line) const;
+
+		void set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override);
 		void set_marked(int p_line, bool p_marked) { text.write[p_line].marked = p_marked; }
 		bool is_marked(int p_line) const { return text[p_line].marked; }
 		void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; }
 		bool is_hidden(int p_line) const { return text[p_line].hidden; }
-		void insert(int p_at, const String &p_text);
+		void insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override);
 		void remove(int p_at);
 		int size() const { return text.size(); }
 		void clear();
-		void clear_width_cache();
-		void clear_wrap_cache();
-		_FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
+
+		void invalidate_cache(int p_line, int p_column = -1, const String &p_ime_text = String(), const Vector<Vector2i> &p_bidi_override = Vector<Vector2i>());
+		void invalidate_all();
+		void invalidate_all_lines();
+
+		_FORCE_INLINE_ const String &operator[](int p_line) const;
 
 		/* Gutters. */
 		void add_gutter(int p_at);
@@ -260,6 +282,14 @@ private:
 	// data
 	Text text;
 
+	Dictionary opentype_features;
+	String language;
+	TextDirection text_direction = TEXT_DIRECTION_AUTO;
+	TextDirection input_direction = TEXT_DIRECTION_LTR;
+	Control::StructuredTextParser st_parser = STRUCTURED_TEXT_DEFAULT;
+	Array st_args;
+	bool draw_control_chars = false;
+
 	uint32_t version;
 	uint32_t saved_version;
 
@@ -275,6 +305,7 @@ private:
 	bool window_has_focus;
 	bool block_caret;
 	bool right_click_moves_caret;
+	bool mid_grapheme_caret_enabled = false;
 
 	bool wrap_enabled;
 	int wrap_at;
@@ -356,7 +387,7 @@ private:
 	int _get_minimap_visible_rows() const;
 
 	void update_cursor_wrap_offset();
-	void _update_wrap_at();
+	void _update_wrap_at(bool p_force = false);
 	bool line_wraps(int line) const;
 	int times_line_wraps(int line) const;
 	Vector<String> get_wrap_rows_text(int p_line) const;
@@ -376,8 +407,6 @@ private:
 
 	int get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const;
 	int get_column_x_offset_for_line(int p_char, int p_line) const;
-	int get_char_pos_for(int p_px, String p_str) const;
-	int get_column_x_offset(int p_char, String p_str) const;
 
 	void adjust_viewport_to_cursor();
 	double get_scroll_line_diff() const;
@@ -405,6 +434,8 @@ private:
 	Size2 get_minimum_size() const override;
 	int _get_control_height() const;
 
+	Point2 _get_local_mouse_pos() const;
+
 	void _reset_caret_blink_timer();
 	void _toggle_draw_caret();
 
@@ -425,6 +456,8 @@ private:
 	Dictionary _search_bind(const String &p_key, uint32_t p_search_flags, int p_from_line, int p_from_column) const;
 
 	PopupMenu *menu;
+	PopupMenu *menu_dir;
+	PopupMenu *menu_ctl;
 
 	void _clear();
 	void _cancel_completion();
@@ -465,11 +498,9 @@ protected:
 		Color search_result_border_color;
 		Color background_color;
 
-		int row_height;
 		int line_spacing;
 		int minimap_width;
 		Cache() {
-			row_height = 0;
 			line_spacing = 0;
 			minimap_width = 0;
 		}
@@ -488,6 +519,10 @@ protected:
 
 	static void _bind_methods();
 
+	bool _set(const StringName &p_name, const Variant &p_value);
+	bool _get(const StringName &p_name, Variant &r_ret) const;
+	void _get_property_list(List<PropertyInfo> *p_list) const;
+
 public:
 	/* Syntax Highlighting. */
 	Ref<SyntaxHighlighter> get_syntax_highlighter();
@@ -542,6 +577,27 @@ public:
 		MENU_SELECT_ALL,
 		MENU_UNDO,
 		MENU_REDO,
+		MENU_DIR_INHERITED,
+		MENU_DIR_AUTO,
+		MENU_DIR_LTR,
+		MENU_DIR_RTL,
+		MENU_DISPLAY_UCC,
+		MENU_INSERT_LRM,
+		MENU_INSERT_RLM,
+		MENU_INSERT_LRE,
+		MENU_INSERT_RLE,
+		MENU_INSERT_LRO,
+		MENU_INSERT_RLO,
+		MENU_INSERT_PDF,
+		MENU_INSERT_ALM,
+		MENU_INSERT_LRI,
+		MENU_INSERT_RLI,
+		MENU_INSERT_FSI,
+		MENU_INSERT_PDI,
+		MENU_INSERT_ZWJ,
+		MENU_INSERT_ZWNJ,
+		MENU_INSERT_WJ,
+		MENU_INSERT_SHY,
 		MENU_MAX
 
 	};
@@ -565,6 +621,25 @@ public:
 
 	bool is_insert_text_operation();
 
+	void set_text_direction(TextDirection p_text_direction);
+	TextDirection get_text_direction() const;
+
+	void set_opentype_feature(const String &p_name, int p_value);
+	int get_opentype_feature(const String &p_name) const;
+	void clear_opentype_features();
+
+	void set_language(const String &p_language);
+	String get_language() const;
+
+	void set_draw_control_chars(bool p_draw_control_chars);
+	bool get_draw_control_chars() const;
+
+	void set_structured_text_bidi_override(Control::StructuredTextParser p_parser);
+	Control::StructuredTextParser get_structured_text_bidi_override() const;
+
+	void set_structured_text_bidi_override_options(Array p_args);
+	Array get_structured_text_bidi_override_options() const;
+
 	void set_highlighted_word(const String &new_word);
 	void set_text(String p_text);
 	void insert_text_at_cursor(const String &p_text);
@@ -617,6 +692,9 @@ public:
 
 	void center_viewport_to_cursor();
 
+	void set_mid_grapheme_caret_enabled(const bool p_enabled);
+	bool get_mid_grapheme_caret_enabled() const;
+
 	void cursor_set_column(int p_col, bool p_adjust_viewport = true);
 	void cursor_set_line(int p_row, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0);
 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.