| 1 | /**************************************************************************/ |
| 2 | /* text_edit.h */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #ifndef TEXT_EDIT_H |
| 32 | #define TEXT_EDIT_H |
| 33 | |
| 34 | #include "scene/gui/control.h" |
| 35 | #include "scene/gui/popup_menu.h" |
| 36 | #include "scene/gui/scroll_bar.h" |
| 37 | #include "scene/main/timer.h" |
| 38 | #include "scene/resources/syntax_highlighter.h" |
| 39 | #include "scene/resources/text_paragraph.h" |
| 40 | |
| 41 | class TextEdit : public Control { |
| 42 | GDCLASS(TextEdit, Control); |
| 43 | |
| 44 | friend class CodeHighlighter; |
| 45 | |
| 46 | public: |
| 47 | /* Edit Actions. */ |
| 48 | enum EditAction { |
| 49 | ACTION_NONE, |
| 50 | ACTION_TYPING, |
| 51 | ACTION_BACKSPACE, |
| 52 | ACTION_DELETE, |
| 53 | }; |
| 54 | |
| 55 | /* Caret. */ |
| 56 | enum CaretType { |
| 57 | CARET_TYPE_LINE, |
| 58 | CARET_TYPE_BLOCK |
| 59 | }; |
| 60 | |
| 61 | /* Selection */ |
| 62 | enum SelectionMode { |
| 63 | SELECTION_MODE_NONE, |
| 64 | SELECTION_MODE_SHIFT, |
| 65 | SELECTION_MODE_POINTER, |
| 66 | SELECTION_MODE_WORD, |
| 67 | SELECTION_MODE_LINE |
| 68 | }; |
| 69 | |
| 70 | /* Line Wrapping.*/ |
| 71 | enum LineWrappingMode { |
| 72 | LINE_WRAPPING_NONE, |
| 73 | LINE_WRAPPING_BOUNDARY |
| 74 | }; |
| 75 | |
| 76 | /* Gutters. */ |
| 77 | enum GutterType { |
| 78 | GUTTER_TYPE_STRING, |
| 79 | GUTTER_TYPE_ICON, |
| 80 | GUTTER_TYPE_CUSTOM |
| 81 | }; |
| 82 | |
| 83 | /* Context Menu. */ |
| 84 | enum { |
| 85 | , |
| 86 | , |
| 87 | , |
| 88 | , |
| 89 | , |
| 90 | , |
| 91 | , |
| 92 | , |
| 93 | , |
| 94 | , |
| 95 | , |
| 96 | , |
| 97 | , |
| 98 | , |
| 99 | , |
| 100 | , |
| 101 | , |
| 102 | , |
| 103 | , |
| 104 | , |
| 105 | , |
| 106 | , |
| 107 | , |
| 108 | , |
| 109 | , |
| 110 | , |
| 111 | , |
| 112 | , |
| 113 | , |
| 114 | , |
| 115 | |
| 116 | |
| 117 | }; |
| 118 | |
| 119 | /* Search. */ |
| 120 | enum SearchFlags { |
| 121 | SEARCH_MATCH_CASE = 1, |
| 122 | SEARCH_WHOLE_WORDS = 2, |
| 123 | SEARCH_BACKWARDS = 4 |
| 124 | }; |
| 125 | |
| 126 | private: |
| 127 | struct GutterInfo { |
| 128 | GutterType type = GutterType::GUTTER_TYPE_STRING; |
| 129 | String name = "" ; |
| 130 | int width = 24; |
| 131 | bool draw = true; |
| 132 | bool clickable = false; |
| 133 | bool overwritable = false; |
| 134 | |
| 135 | Callable custom_draw_callback; |
| 136 | }; |
| 137 | |
| 138 | class Text { |
| 139 | public: |
| 140 | struct Gutter { |
| 141 | Variant metadata; |
| 142 | bool clickable = false; |
| 143 | |
| 144 | Ref<Texture2D> icon = Ref<Texture2D>(); |
| 145 | String text = "" ; |
| 146 | Color color = Color(1, 1, 1); |
| 147 | }; |
| 148 | |
| 149 | struct Line { |
| 150 | Vector<Gutter> gutters; |
| 151 | |
| 152 | String data; |
| 153 | Array bidi_override; |
| 154 | Ref<TextParagraph> data_buf; |
| 155 | |
| 156 | Color background_color = Color(0, 0, 0, 0); |
| 157 | bool hidden = false; |
| 158 | int height = 0; |
| 159 | int width = 0; |
| 160 | |
| 161 | Line() { |
| 162 | data_buf.instantiate(); |
| 163 | } |
| 164 | }; |
| 165 | |
| 166 | private: |
| 167 | bool is_dirty = false; |
| 168 | bool tab_size_dirty = false; |
| 169 | |
| 170 | mutable Vector<Line> text; |
| 171 | Ref<Font> font; |
| 172 | int font_size = -1; |
| 173 | int font_height = 0; |
| 174 | |
| 175 | String language; |
| 176 | TextServer::Direction direction = TextServer::DIRECTION_AUTO; |
| 177 | BitField<TextServer::LineBreakFlag> brk_flags = TextServer::BREAK_MANDATORY; |
| 178 | bool draw_control_chars = false; |
| 179 | |
| 180 | int line_height = -1; |
| 181 | int max_width = -1; |
| 182 | int width = -1; |
| 183 | |
| 184 | int tab_size = 4; |
| 185 | int gutter_count = 0; |
| 186 | |
| 187 | void _calculate_line_height(); |
| 188 | void _calculate_max_line_width(); |
| 189 | |
| 190 | public: |
| 191 | void set_tab_size(int p_tab_size); |
| 192 | int get_tab_size() const; |
| 193 | void set_font(const Ref<Font> &p_font); |
| 194 | void set_font_size(int p_font_size); |
| 195 | void set_direction_and_language(TextServer::Direction p_direction, const String &p_language); |
| 196 | void set_draw_control_chars(bool p_enabled); |
| 197 | |
| 198 | int get_line_height() const; |
| 199 | int get_line_width(int p_line, int p_wrap_index = -1) const; |
| 200 | int get_max_width() const; |
| 201 | |
| 202 | void set_width(float p_width); |
| 203 | float get_width() const; |
| 204 | void set_brk_flags(BitField<TextServer::LineBreakFlag> p_flags); |
| 205 | BitField<TextServer::LineBreakFlag> get_brk_flags() const; |
| 206 | int get_line_wrap_amount(int p_line) const; |
| 207 | |
| 208 | Vector<Vector2i> get_line_wrap_ranges(int p_line) const; |
| 209 | const Ref<TextParagraph> get_line_data(int p_line) const; |
| 210 | |
| 211 | void set(int p_line, const String &p_text, const Array &p_bidi_override); |
| 212 | void set_hidden(int p_line, bool p_hidden) { |
| 213 | if (text[p_line].hidden == p_hidden) { |
| 214 | return; |
| 215 | } |
| 216 | text.write[p_line].hidden = p_hidden; |
| 217 | if (!p_hidden && text[p_line].width > max_width) { |
| 218 | max_width = text[p_line].width; |
| 219 | } else if (p_hidden && text[p_line].width == max_width) { |
| 220 | _calculate_max_line_width(); |
| 221 | } |
| 222 | } |
| 223 | bool is_hidden(int p_line) const { return text[p_line].hidden; } |
| 224 | void insert(int p_at, const Vector<String> &p_text, const Vector<Array> &p_bidi_override); |
| 225 | void remove_range(int p_from_line, int p_to_line); |
| 226 | int size() const { return text.size(); } |
| 227 | void clear(); |
| 228 | |
| 229 | void invalidate_cache(int p_line, int p_column = -1, bool p_text_changed = false, const String &p_ime_text = String(), const Array &p_bidi_override = Array()); |
| 230 | void invalidate_font(); |
| 231 | void invalidate_all(); |
| 232 | void invalidate_all_lines(); |
| 233 | |
| 234 | _FORCE_INLINE_ const String &operator[](int p_line) const; |
| 235 | |
| 236 | /* Gutters. */ |
| 237 | void add_gutter(int p_at); |
| 238 | void remove_gutter(int p_gutter); |
| 239 | void move_gutters(int p_from_line, int p_to_line); |
| 240 | |
| 241 | void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata) { text.write[p_line].gutters.write[p_gutter].metadata = p_metadata; } |
| 242 | const Variant &get_line_gutter_metadata(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].metadata; } |
| 243 | |
| 244 | void set_line_gutter_text(int p_line, int p_gutter, const String &p_text) { text.write[p_line].gutters.write[p_gutter].text = p_text; } |
| 245 | const String &get_line_gutter_text(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].text; } |
| 246 | |
| 247 | void set_line_gutter_icon(int p_line, int p_gutter, const Ref<Texture2D> &p_icon) { text.write[p_line].gutters.write[p_gutter].icon = p_icon; } |
| 248 | const Ref<Texture2D> &get_line_gutter_icon(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].icon; } |
| 249 | |
| 250 | void set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color) { text.write[p_line].gutters.write[p_gutter].color = p_color; } |
| 251 | const Color &get_line_gutter_item_color(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].color; } |
| 252 | |
| 253 | void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable) { text.write[p_line].gutters.write[p_gutter].clickable = p_clickable; } |
| 254 | bool is_line_gutter_clickable(int p_line, int p_gutter) const { return text[p_line].gutters[p_gutter].clickable; } |
| 255 | |
| 256 | /* Line style. */ |
| 257 | void set_line_background_color(int p_line, const Color &p_color) { text.write[p_line].background_color = p_color; } |
| 258 | const Color get_line_background_color(int p_line) const { return text[p_line].background_color; } |
| 259 | }; |
| 260 | |
| 261 | /* Text */ |
| 262 | Text text; |
| 263 | |
| 264 | bool setting_text = false; |
| 265 | |
| 266 | bool alt_start = false; |
| 267 | uint32_t alt_code = 0; |
| 268 | |
| 269 | // Text properties. |
| 270 | String ime_text = "" ; |
| 271 | Point2 ime_selection; |
| 272 | |
| 273 | // Placeholder |
| 274 | String placeholder_text = "" ; |
| 275 | Array placeholder_bidi_override; |
| 276 | Ref<TextParagraph> placeholder_data_buf; |
| 277 | int placeholder_line_height = -1; |
| 278 | int placeholder_max_width = -1; |
| 279 | |
| 280 | Vector<String> placeholder_wraped_rows; |
| 281 | |
| 282 | void _update_placeholder(); |
| 283 | |
| 284 | /* Initialize to opposite first, so we get past the early-out in set_editable. */ |
| 285 | bool editable = false; |
| 286 | |
| 287 | TextDirection text_direction = TEXT_DIRECTION_AUTO; |
| 288 | TextDirection input_direction = TEXT_DIRECTION_LTR; |
| 289 | |
| 290 | String language = "" ; |
| 291 | |
| 292 | TextServer::StructuredTextParser st_parser = TextServer::STRUCTURED_TEXT_DEFAULT; |
| 293 | Array st_args; |
| 294 | |
| 295 | void _clear(); |
| 296 | void _update_caches(); |
| 297 | |
| 298 | // User control. |
| 299 | bool overtype_mode = false; |
| 300 | bool = true; |
| 301 | bool shortcut_keys_enabled = true; |
| 302 | bool virtual_keyboard_enabled = true; |
| 303 | bool middle_mouse_paste_enabled = true; |
| 304 | |
| 305 | // Overridable actions. |
| 306 | String cut_copy_line = "" ; |
| 307 | |
| 308 | // Context menu. |
| 309 | PopupMenu * = nullptr; |
| 310 | PopupMenu * = nullptr; |
| 311 | PopupMenu * = nullptr; |
| 312 | |
| 313 | Key (const String &p_action); |
| 314 | void (); |
| 315 | void (); |
| 316 | |
| 317 | /* Versioning */ |
| 318 | struct Caret; |
| 319 | struct TextOperation { |
| 320 | enum Type { |
| 321 | TYPE_NONE, |
| 322 | TYPE_INSERT, |
| 323 | TYPE_REMOVE |
| 324 | }; |
| 325 | Vector<Caret> start_carets; |
| 326 | Vector<Caret> end_carets; |
| 327 | |
| 328 | Type type = TYPE_NONE; |
| 329 | int from_line = 0; |
| 330 | int from_column = 0; |
| 331 | int to_line = 0; |
| 332 | int to_column = 0; |
| 333 | String text; |
| 334 | uint32_t prev_version = 0; |
| 335 | uint32_t version = 0; |
| 336 | bool chain_forward = false; |
| 337 | bool chain_backward = false; |
| 338 | }; |
| 339 | |
| 340 | bool undo_enabled = true; |
| 341 | int undo_stack_max_size = 50; |
| 342 | |
| 343 | EditAction current_action = EditAction::ACTION_NONE; |
| 344 | bool pending_action_end = false; |
| 345 | bool in_action = false; |
| 346 | |
| 347 | int complex_operation_count = 0; |
| 348 | bool next_operation_is_complex = false; |
| 349 | |
| 350 | TextOperation current_op; |
| 351 | List<TextOperation> undo_stack; |
| 352 | List<TextOperation>::Element *undo_stack_pos = nullptr; |
| 353 | |
| 354 | Timer *idle_detect = nullptr; |
| 355 | |
| 356 | uint32_t version = 0; |
| 357 | uint32_t saved_version = 0; |
| 358 | |
| 359 | void _push_current_op(); |
| 360 | void _do_text_op(const TextOperation &p_op, bool p_reverse); |
| 361 | void _clear_redo(); |
| 362 | |
| 363 | /* Search */ |
| 364 | String search_text = "" ; |
| 365 | uint32_t search_flags = 0; |
| 366 | |
| 367 | int _get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column) const; |
| 368 | |
| 369 | /* Tooltip. */ |
| 370 | Callable tooltip_callback; |
| 371 | |
| 372 | /* Mouse */ |
| 373 | struct LineDrawingCache { |
| 374 | int y_offset = 0; |
| 375 | Vector<int> first_visible_chars; |
| 376 | Vector<int> last_visible_chars; |
| 377 | }; |
| 378 | |
| 379 | HashMap<int, LineDrawingCache> line_drawing_cache; |
| 380 | |
| 381 | int _get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const; |
| 382 | |
| 383 | /* Caret. */ |
| 384 | struct Selection { |
| 385 | bool active = false; |
| 386 | bool shiftclick_left = false; |
| 387 | |
| 388 | int selecting_line = 0; |
| 389 | int selecting_column = 0; |
| 390 | int selected_word_beg = 0; |
| 391 | int selected_word_end = 0; |
| 392 | int selected_word_origin = 0; |
| 393 | |
| 394 | int from_line = 0; |
| 395 | int from_column = 0; |
| 396 | int to_line = 0; |
| 397 | int to_column = 0; |
| 398 | }; |
| 399 | |
| 400 | struct Caret { |
| 401 | Selection selection; |
| 402 | |
| 403 | Point2 draw_pos; |
| 404 | bool visible = false; |
| 405 | int last_fit_x = 0; |
| 406 | int line = 0; |
| 407 | int column = 0; |
| 408 | }; |
| 409 | |
| 410 | // Vector containing all the carets, index '0' is the "main caret" and should never be removed. |
| 411 | Vector<Caret> carets; |
| 412 | Vector<int> caret_index_edit_order; |
| 413 | |
| 414 | bool setting_caret_line = false; |
| 415 | bool caret_pos_dirty = false; |
| 416 | bool caret_index_edit_dirty = true; |
| 417 | |
| 418 | CaretType caret_type = CaretType::CARET_TYPE_LINE; |
| 419 | |
| 420 | bool draw_caret = true; |
| 421 | bool draw_caret_when_editable_disabled = false; |
| 422 | |
| 423 | bool caret_blink_enabled = false; |
| 424 | Timer *caret_blink_timer = nullptr; |
| 425 | |
| 426 | bool move_caret_on_right_click = true; |
| 427 | |
| 428 | bool caret_mid_grapheme_enabled = false; |
| 429 | |
| 430 | bool multi_carets_enabled = true; |
| 431 | |
| 432 | bool drag_action = false; |
| 433 | bool drag_caret_force_displayed = false; |
| 434 | |
| 435 | void _emit_caret_changed(); |
| 436 | |
| 437 | void _reset_caret_blink_timer(); |
| 438 | void _toggle_draw_caret(); |
| 439 | |
| 440 | int _get_column_x_offset_for_line(int p_char, int p_line, int p_column) const; |
| 441 | |
| 442 | /* Selection. */ |
| 443 | SelectionMode selecting_mode = SelectionMode::SELECTION_MODE_NONE; |
| 444 | |
| 445 | bool selecting_enabled = true; |
| 446 | bool deselect_on_focus_loss_enabled = true; |
| 447 | bool drag_and_drop_selection_enabled = true; |
| 448 | |
| 449 | bool use_selected_font_color = false; |
| 450 | |
| 451 | bool selection_drag_attempt = false; |
| 452 | bool dragging_selection = false; |
| 453 | |
| 454 | Timer *click_select_held = nullptr; |
| 455 | uint64_t last_dblclk = 0; |
| 456 | Vector2 last_dblclk_pos; |
| 457 | void _click_selection_held(); |
| 458 | |
| 459 | void _update_selection_mode_pointer(); |
| 460 | void _update_selection_mode_word(); |
| 461 | void _update_selection_mode_line(); |
| 462 | |
| 463 | void _pre_shift_selection(int p_caret); |
| 464 | void _post_shift_selection(int p_caret); |
| 465 | |
| 466 | /* Line wrapping. */ |
| 467 | LineWrappingMode line_wrapping_mode = LineWrappingMode::LINE_WRAPPING_NONE; |
| 468 | TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_WORD_SMART; |
| 469 | |
| 470 | int wrap_at_column = 0; |
| 471 | int wrap_right_offset = 10; |
| 472 | |
| 473 | void _update_wrap_at_column(bool p_force = false); |
| 474 | |
| 475 | /* Viewport. */ |
| 476 | HScrollBar *h_scroll = nullptr; |
| 477 | VScrollBar *v_scroll = nullptr; |
| 478 | |
| 479 | float content_height_cache = 0.0; |
| 480 | bool fit_content_height = false; |
| 481 | bool scroll_past_end_of_file_enabled = false; |
| 482 | |
| 483 | // Smooth scrolling. |
| 484 | bool smooth_scroll_enabled = false; |
| 485 | float target_v_scroll = 0.0; |
| 486 | float v_scroll_speed = 80.0; |
| 487 | |
| 488 | // Scrolling. |
| 489 | int first_visible_line = 0; |
| 490 | int first_visible_line_wrap_ofs = 0; |
| 491 | int first_visible_col = 0; |
| 492 | |
| 493 | bool scrolling = false; |
| 494 | bool updating_scrolls = false; |
| 495 | |
| 496 | void _update_scrollbars(); |
| 497 | int _get_control_height() const; |
| 498 | |
| 499 | void _v_scroll_input(); |
| 500 | void _scroll_moved(double p_to_val); |
| 501 | |
| 502 | double _get_visible_lines_offset() const; |
| 503 | double _get_v_scroll_offset() const; |
| 504 | |
| 505 | void _scroll_up(real_t p_delta); |
| 506 | void _scroll_down(real_t p_delta); |
| 507 | |
| 508 | void _scroll_lines_up(); |
| 509 | void _scroll_lines_down(); |
| 510 | |
| 511 | // Minimap. |
| 512 | bool draw_minimap = false; |
| 513 | |
| 514 | int minimap_width = 80; |
| 515 | Point2 minimap_char_size = Point2(1, 2); |
| 516 | int minimap_line_spacing = 1; |
| 517 | |
| 518 | // Minimap scroll. |
| 519 | bool minimap_clicked = false; |
| 520 | bool hovering_minimap = false; |
| 521 | bool dragging_minimap = false; |
| 522 | bool can_drag_minimap = false; |
| 523 | |
| 524 | double minimap_scroll_ratio = 0.0; |
| 525 | double minimap_scroll_click_pos = 0.0; |
| 526 | |
| 527 | void _update_minimap_hover(); |
| 528 | void _update_minimap_click(); |
| 529 | void _update_minimap_drag(); |
| 530 | |
| 531 | /* Gutters. */ |
| 532 | Vector<GutterInfo> gutters; |
| 533 | int gutters_width = 0; |
| 534 | int gutter_padding = 0; |
| 535 | Vector2i hovered_gutter = Vector2i(-1, -1); // X = gutter index, Y = row. |
| 536 | |
| 537 | void _update_gutter_width(); |
| 538 | |
| 539 | /* Syntax highlighting. */ |
| 540 | Ref<SyntaxHighlighter> syntax_highlighter; |
| 541 | |
| 542 | Dictionary _get_line_syntax_highlighting(int p_line); |
| 543 | |
| 544 | /* Visual. */ |
| 545 | struct ThemeCache { |
| 546 | float base_scale = 1.0; |
| 547 | |
| 548 | /* Search */ |
| 549 | Color search_result_color = Color(1, 1, 1); |
| 550 | Color search_result_border_color = Color(1, 1, 1); |
| 551 | |
| 552 | /* Caret */ |
| 553 | int caret_width = 1; |
| 554 | Color caret_color = Color(1, 1, 1); |
| 555 | Color caret_background_color = Color(0, 0, 0); |
| 556 | |
| 557 | /* Selection */ |
| 558 | Color font_selected_color = Color(0, 0, 0, 0); |
| 559 | Color selection_color = Color(1, 1, 1); |
| 560 | |
| 561 | /* Other visuals */ |
| 562 | Ref<StyleBox> style_normal; |
| 563 | Ref<StyleBox> style_focus; |
| 564 | Ref<StyleBox> style_readonly; |
| 565 | |
| 566 | Ref<Texture2D> tab_icon; |
| 567 | Ref<Texture2D> space_icon; |
| 568 | |
| 569 | Ref<Font> font; |
| 570 | int font_size = 16; |
| 571 | Color font_color = Color(1, 1, 1); |
| 572 | Color font_readonly_color = Color(1, 1, 1); |
| 573 | Color font_placeholder_color = Color(1, 1, 1, 0.6); |
| 574 | |
| 575 | int outline_size = 0; |
| 576 | Color outline_color = Color(1, 1, 1); |
| 577 | |
| 578 | int line_spacing = 1; |
| 579 | |
| 580 | Color background_color = Color(1, 1, 1); |
| 581 | Color current_line_color = Color(1, 1, 1); |
| 582 | Color word_highlighted_color = Color(1, 1, 1); |
| 583 | } theme_cache; |
| 584 | |
| 585 | bool window_has_focus = true; |
| 586 | bool first_draw = true; |
| 587 | |
| 588 | bool highlight_current_line = false; |
| 589 | bool highlight_all_occurrences = false; |
| 590 | bool draw_control_chars = false; |
| 591 | bool draw_tabs = false; |
| 592 | bool draw_spaces = false; |
| 593 | |
| 594 | /*** Super internal Core API. Everything builds on it. ***/ |
| 595 | bool text_changed_dirty = false; |
| 596 | void _text_changed_emit(); |
| 597 | |
| 598 | void _insert_text(int p_line, int p_char, const String &p_text, int *r_end_line = nullptr, int *r_end_char = nullptr); |
| 599 | void _remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column); |
| 600 | |
| 601 | void _base_insert_text(int p_line, int p_char, const String &p_text, int &r_end_line, int &r_end_column); |
| 602 | String _base_get_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) const; |
| 603 | void _base_remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column); |
| 604 | |
| 605 | /* Input actions. */ |
| 606 | void _swap_current_input_direction(); |
| 607 | void _new_line(bool p_split_current = true, bool p_above = false); |
| 608 | void _move_caret_left(bool p_select, bool p_move_by_word = false); |
| 609 | void _move_caret_right(bool p_select, bool p_move_by_word = false); |
| 610 | void _move_caret_up(bool p_select); |
| 611 | void _move_caret_down(bool p_select); |
| 612 | void _move_caret_to_line_start(bool p_select); |
| 613 | void _move_caret_to_line_end(bool p_select); |
| 614 | void _move_caret_page_up(bool p_select); |
| 615 | void _move_caret_page_down(bool p_select); |
| 616 | void _do_backspace(bool p_word = false, bool p_all_to_left = false); |
| 617 | void _delete(bool p_word = false, bool p_all_to_right = false); |
| 618 | void _move_caret_document_start(bool p_select); |
| 619 | void _move_caret_document_end(bool p_select); |
| 620 | bool _clear_carets_and_selection(); |
| 621 | |
| 622 | // Used in add_caret_at_carets |
| 623 | void _get_above_below_caret_line_column(int p_old_line, int p_old_wrap_index, int p_old_column, bool p_below, int &p_new_line, int &p_new_column, int p_last_fit_x = -1) const; |
| 624 | |
| 625 | protected: |
| 626 | void _notification(int p_what); |
| 627 | static void _bind_methods(); |
| 628 | |
| 629 | virtual void _update_theme_item_cache() override; |
| 630 | |
| 631 | /* Internal API for CodeEdit, pending public API. */ |
| 632 | // Brace matching. |
| 633 | struct BraceMatchingData { |
| 634 | int open_match_line = -1; |
| 635 | int open_match_column = -1; |
| 636 | bool open_matching = false; |
| 637 | bool open_mismatch = false; |
| 638 | int close_match_line = -1; |
| 639 | int close_match_column = -1; |
| 640 | bool close_matching = false; |
| 641 | bool close_mismatch = false; |
| 642 | }; |
| 643 | |
| 644 | bool highlight_matching_braces_enabled = false; |
| 645 | |
| 646 | // Line hiding. |
| 647 | bool hiding_enabled = false; |
| 648 | |
| 649 | void _set_hiding_enabled(bool p_enabled); |
| 650 | bool _is_hiding_enabled() const; |
| 651 | |
| 652 | void _set_line_as_hidden(int p_line, bool p_hidden); |
| 653 | bool _is_line_hidden(int p_line) const; |
| 654 | |
| 655 | void _unhide_all_lines(); |
| 656 | |
| 657 | // Symbol lookup. |
| 658 | String lookup_symbol_word; |
| 659 | void _set_symbol_lookup_word(const String &p_symbol); |
| 660 | |
| 661 | // Theme items. |
| 662 | virtual Color _get_brace_mismatch_color() const { return Color(); }; |
| 663 | virtual Color _get_code_folding_color() const { return Color(); }; |
| 664 | virtual Ref<Texture2D> _get_folded_eol_icon() const { return Ref<Texture2D>(); }; |
| 665 | |
| 666 | /* Text manipulation */ |
| 667 | |
| 668 | // Overridable actions |
| 669 | virtual void _handle_unicode_input_internal(const uint32_t p_unicode, int p_caret); |
| 670 | virtual void _backspace_internal(int p_caret); |
| 671 | |
| 672 | virtual void _cut_internal(int p_caret); |
| 673 | virtual void _copy_internal(int p_caret); |
| 674 | virtual void _paste_internal(int p_caret); |
| 675 | virtual void _paste_primary_clipboard_internal(int p_caret); |
| 676 | |
| 677 | GDVIRTUAL2(_handle_unicode_input, int, int) |
| 678 | GDVIRTUAL1(_backspace, int) |
| 679 | GDVIRTUAL1(_cut, int) |
| 680 | GDVIRTUAL1(_copy, int) |
| 681 | GDVIRTUAL1(_paste, int) |
| 682 | GDVIRTUAL1(_paste_primary_clipboard, int) |
| 683 | |
| 684 | public: |
| 685 | /* General overrides. */ |
| 686 | virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override; |
| 687 | virtual void gui_input(const Ref<InputEvent> &p_gui_input) override; |
| 688 | bool alt_input(const Ref<InputEvent> &p_gui_input); |
| 689 | virtual Size2 get_minimum_size() const override; |
| 690 | virtual bool is_text_field() const override; |
| 691 | virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override; |
| 692 | virtual Variant get_drag_data(const Point2 &p_point) override; |
| 693 | virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const override; |
| 694 | virtual void drop_data(const Point2 &p_point, const Variant &p_data) override; |
| 695 | virtual String get_tooltip(const Point2 &p_pos) const override; |
| 696 | void set_tooltip_request_func(const Callable &p_tooltip_callback); |
| 697 | |
| 698 | /* Text */ |
| 699 | // Text properties. |
| 700 | bool has_ime_text() const; |
| 701 | |
| 702 | void set_editable(const bool p_editable); |
| 703 | bool is_editable() const; |
| 704 | |
| 705 | void set_text_direction(TextDirection p_text_direction); |
| 706 | TextDirection get_text_direction() const; |
| 707 | |
| 708 | void set_language(const String &p_language); |
| 709 | String get_language() const; |
| 710 | |
| 711 | void set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser); |
| 712 | TextServer::StructuredTextParser get_structured_text_bidi_override() const; |
| 713 | void set_structured_text_bidi_override_options(Array p_args); |
| 714 | Array get_structured_text_bidi_override_options() const; |
| 715 | |
| 716 | void set_tab_size(const int p_size); |
| 717 | int get_tab_size() const; |
| 718 | |
| 719 | // User controls |
| 720 | void set_overtype_mode_enabled(const bool p_enabled); |
| 721 | bool is_overtype_mode_enabled() const; |
| 722 | |
| 723 | void (bool p_enabled); |
| 724 | bool () const; |
| 725 | |
| 726 | void set_shortcut_keys_enabled(bool p_enabled); |
| 727 | bool is_shortcut_keys_enabled() const; |
| 728 | |
| 729 | void set_virtual_keyboard_enabled(bool p_enabled); |
| 730 | bool is_virtual_keyboard_enabled() const; |
| 731 | |
| 732 | void set_middle_mouse_paste_enabled(bool p_enabled); |
| 733 | bool is_middle_mouse_paste_enabled() const; |
| 734 | |
| 735 | // Text manipulation |
| 736 | void clear(); |
| 737 | |
| 738 | void set_text(const String &p_text); |
| 739 | String get_text() const; |
| 740 | |
| 741 | int get_line_count() const; |
| 742 | |
| 743 | void set_placeholder(const String &p_text); |
| 744 | String get_placeholder() const; |
| 745 | |
| 746 | void set_line(int p_line, const String &p_new_text); |
| 747 | String get_line(int p_line) const; |
| 748 | |
| 749 | int get_line_width(int p_line, int p_wrap_index = -1) const; |
| 750 | int get_line_height() const; |
| 751 | |
| 752 | int get_indent_level(int p_line) const; |
| 753 | int get_first_non_whitespace_column(int p_line) const; |
| 754 | |
| 755 | void swap_lines(int p_from_line, int p_to_line); |
| 756 | |
| 757 | void insert_line_at(int p_at, const String &p_text); |
| 758 | void insert_text_at_caret(const String &p_text, int p_caret = -1); |
| 759 | |
| 760 | void remove_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column); |
| 761 | |
| 762 | int get_last_unhidden_line() const; |
| 763 | int get_next_visible_line_offset_from(int p_line_from, int p_visible_amount) const; |
| 764 | Point2i get_next_visible_line_index_offset_from(int p_line_from, int p_wrap_index_from, int p_visible_amount) const; |
| 765 | |
| 766 | // Overridable actions |
| 767 | void handle_unicode_input(const uint32_t p_unicode, int p_caret = -1); |
| 768 | void backspace(int p_caret = -1); |
| 769 | |
| 770 | void cut(int p_caret = -1); |
| 771 | void copy(int p_caret = -1); |
| 772 | void paste(int p_caret = -1); |
| 773 | void paste_primary_clipboard(int p_caret = -1); |
| 774 | |
| 775 | // Context menu. |
| 776 | PopupMenu *() const; |
| 777 | bool () const; |
| 778 | void (int p_option); |
| 779 | |
| 780 | /* Versioning */ |
| 781 | void start_action(EditAction p_action); |
| 782 | void end_action(); |
| 783 | EditAction get_current_action() const; |
| 784 | |
| 785 | void begin_complex_operation(); |
| 786 | void end_complex_operation(); |
| 787 | |
| 788 | bool has_undo() const; |
| 789 | bool has_redo() const; |
| 790 | void undo(); |
| 791 | void redo(); |
| 792 | void clear_undo_history(); |
| 793 | |
| 794 | bool is_insert_text_operation() const; |
| 795 | |
| 796 | void tag_saved_version(); |
| 797 | |
| 798 | uint32_t get_version() const; |
| 799 | uint32_t get_saved_version() const; |
| 800 | |
| 801 | /* Search */ |
| 802 | void set_search_text(const String &p_search_text); |
| 803 | void set_search_flags(uint32_t p_flags); |
| 804 | |
| 805 | Point2i search(const String &p_key, uint32_t p_search_flags, int p_from_line, int p_from_column) const; |
| 806 | |
| 807 | /* Mouse */ |
| 808 | Point2 get_local_mouse_pos() const; |
| 809 | |
| 810 | String get_word_at_pos(const Vector2 &p_pos) const; |
| 811 | |
| 812 | Point2i get_line_column_at_pos(const Point2i &p_pos, bool p_allow_out_of_bounds = true) const; |
| 813 | Point2i get_pos_at_line_column(int p_line, int p_column) const; |
| 814 | Rect2i get_rect_at_line_column(int p_line, int p_column) const; |
| 815 | |
| 816 | int get_minimap_line_at_pos(const Point2i &p_pos) const; |
| 817 | |
| 818 | bool is_dragging_cursor() const; |
| 819 | bool is_mouse_over_selection(bool p_edges = true, int p_caret = -1) const; |
| 820 | |
| 821 | /* Caret */ |
| 822 | void set_caret_type(CaretType p_type); |
| 823 | CaretType get_caret_type() const; |
| 824 | |
| 825 | void set_caret_blink_enabled(const bool p_enabled); |
| 826 | bool is_caret_blink_enabled() const; |
| 827 | |
| 828 | void set_caret_blink_interval(const float p_interval); |
| 829 | float get_caret_blink_interval() const; |
| 830 | |
| 831 | void set_draw_caret_when_editable_disabled(bool p_enable); |
| 832 | bool is_drawing_caret_when_editable_disabled() const; |
| 833 | |
| 834 | void set_move_caret_on_right_click_enabled(const bool p_enabled); |
| 835 | bool is_move_caret_on_right_click_enabled() const; |
| 836 | |
| 837 | void set_caret_mid_grapheme_enabled(const bool p_enabled); |
| 838 | bool is_caret_mid_grapheme_enabled() const; |
| 839 | |
| 840 | void set_multiple_carets_enabled(bool p_enabled); |
| 841 | bool is_multiple_carets_enabled() const; |
| 842 | |
| 843 | int add_caret(int p_line, int p_col); |
| 844 | void remove_caret(int p_caret); |
| 845 | void remove_secondary_carets(); |
| 846 | void merge_overlapping_carets(); |
| 847 | int get_caret_count() const; |
| 848 | void add_caret_at_carets(bool p_below); |
| 849 | |
| 850 | Vector<int> get_caret_index_edit_order(); |
| 851 | void adjust_carets_after_edit(int p_caret, int p_from_line, int p_from_col, int p_to_line, int p_to_col); |
| 852 | |
| 853 | bool is_caret_visible(int p_caret = 0) const; |
| 854 | Point2 get_caret_draw_pos(int p_caret = 0) const; |
| 855 | |
| 856 | void set_caret_line(int p_line, bool p_adjust_viewport = true, bool p_can_be_hidden = true, int p_wrap_index = 0, int p_caret = 0); |
| 857 | int get_caret_line(int p_caret = 0) const; |
| 858 | |
| 859 | void set_caret_column(int p_col, bool p_adjust_viewport = true, int p_caret = 0); |
| 860 | int get_caret_column(int p_caret = 0) const; |
| 861 | |
| 862 | int get_caret_wrap_index(int p_caret = 0) const; |
| 863 | |
| 864 | String get_word_under_caret(int p_caret = -1) const; |
| 865 | |
| 866 | /* Selection. */ |
| 867 | void set_selecting_enabled(const bool p_enabled); |
| 868 | bool is_selecting_enabled() const; |
| 869 | |
| 870 | void set_deselect_on_focus_loss_enabled(const bool p_enabled); |
| 871 | bool is_deselect_on_focus_loss_enabled() const; |
| 872 | |
| 873 | void set_drag_and_drop_selection_enabled(const bool p_enabled); |
| 874 | bool is_drag_and_drop_selection_enabled() const; |
| 875 | |
| 876 | void set_selection_mode(SelectionMode p_mode, int p_line = -1, int p_column = -1, int p_caret = 0); |
| 877 | SelectionMode get_selection_mode() const; |
| 878 | |
| 879 | void select_all(); |
| 880 | void select_word_under_caret(int p_caret = -1); |
| 881 | void add_selection_for_next_occurrence(); |
| 882 | void select(int p_from_line, int p_from_column, int p_to_line, int p_to_column, int p_caret = 0); |
| 883 | |
| 884 | bool has_selection(int p_caret = -1) const; |
| 885 | |
| 886 | String get_selected_text(int p_caret = -1); |
| 887 | |
| 888 | int get_selection_line(int p_caret = 0) const; |
| 889 | int get_selection_column(int p_caret = 0) const; |
| 890 | |
| 891 | int get_selection_from_line(int p_caret = 0) const; |
| 892 | int get_selection_from_column(int p_caret = 0) const; |
| 893 | int get_selection_to_line(int p_caret = 0) const; |
| 894 | int get_selection_to_column(int p_caret = 0) const; |
| 895 | |
| 896 | void deselect(int p_caret = -1); |
| 897 | void delete_selection(int p_caret = -1); |
| 898 | |
| 899 | /* Line wrapping. */ |
| 900 | void set_line_wrapping_mode(LineWrappingMode p_wrapping_mode); |
| 901 | LineWrappingMode get_line_wrapping_mode() const; |
| 902 | |
| 903 | void set_autowrap_mode(TextServer::AutowrapMode p_mode); |
| 904 | TextServer::AutowrapMode get_autowrap_mode() const; |
| 905 | |
| 906 | bool is_line_wrapped(int p_line) const; |
| 907 | int get_line_wrap_count(int p_line) const; |
| 908 | int get_line_wrap_index_at_column(int p_line, int p_column) const; |
| 909 | |
| 910 | Vector<String> get_line_wrapped_text(int p_line) const; |
| 911 | |
| 912 | /* Viewport. */ |
| 913 | // Scrolling. |
| 914 | void set_smooth_scroll_enabled(const bool p_enabled); |
| 915 | bool is_smooth_scroll_enabled() const; |
| 916 | |
| 917 | void set_scroll_past_end_of_file_enabled(const bool p_enabled); |
| 918 | bool is_scroll_past_end_of_file_enabled() const; |
| 919 | |
| 920 | VScrollBar *get_v_scroll_bar() const; |
| 921 | HScrollBar *get_h_scroll_bar() const; |
| 922 | |
| 923 | void set_v_scroll(double p_scroll); |
| 924 | double get_v_scroll() const; |
| 925 | |
| 926 | void set_h_scroll(int p_scroll); |
| 927 | int get_h_scroll() const; |
| 928 | |
| 929 | void set_v_scroll_speed(float p_speed); |
| 930 | float get_v_scroll_speed() const; |
| 931 | |
| 932 | void set_fit_content_height_enabled(const bool p_enabled); |
| 933 | bool is_fit_content_height_enabled() const; |
| 934 | |
| 935 | double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const; |
| 936 | |
| 937 | // Visible lines. |
| 938 | void set_line_as_first_visible(int p_line, int p_wrap_index = 0); |
| 939 | int get_first_visible_line() const; |
| 940 | |
| 941 | void set_line_as_center_visible(int p_line, int p_wrap_index = 0); |
| 942 | |
| 943 | void set_line_as_last_visible(int p_line, int p_wrap_index = 0); |
| 944 | int get_last_full_visible_line() const; |
| 945 | int get_last_full_visible_line_wrap_index() const; |
| 946 | |
| 947 | int get_visible_line_count() const; |
| 948 | int get_visible_line_count_in_range(int p_from, int p_to) const; |
| 949 | int get_total_visible_line_count() const; |
| 950 | |
| 951 | // Auto Adjust |
| 952 | void adjust_viewport_to_caret(int p_caret = 0); |
| 953 | void center_viewport_to_caret(int p_caret = 0); |
| 954 | |
| 955 | // Minimap |
| 956 | void set_draw_minimap(bool p_enabled); |
| 957 | bool is_drawing_minimap() const; |
| 958 | |
| 959 | void set_minimap_width(int p_minimap_width); |
| 960 | int get_minimap_width() const; |
| 961 | |
| 962 | int get_minimap_visible_lines() const; |
| 963 | |
| 964 | /* Gutters. */ |
| 965 | void add_gutter(int p_at = -1); |
| 966 | void remove_gutter(int p_gutter); |
| 967 | int get_gutter_count() const; |
| 968 | |
| 969 | void set_gutter_name(int p_gutter, const String &p_name); |
| 970 | String get_gutter_name(int p_gutter) const; |
| 971 | |
| 972 | void set_gutter_type(int p_gutter, GutterType p_type); |
| 973 | GutterType get_gutter_type(int p_gutter) const; |
| 974 | |
| 975 | void set_gutter_width(int p_gutter, int p_width); |
| 976 | int get_gutter_width(int p_gutter) const; |
| 977 | int get_total_gutter_width() const; |
| 978 | |
| 979 | void set_gutter_draw(int p_gutter, bool p_draw); |
| 980 | bool is_gutter_drawn(int p_gutter) const; |
| 981 | |
| 982 | void set_gutter_clickable(int p_gutter, bool p_clickable); |
| 983 | bool is_gutter_clickable(int p_gutter) const; |
| 984 | |
| 985 | void set_gutter_overwritable(int p_gutter, bool p_overwritable); |
| 986 | bool is_gutter_overwritable(int p_gutter) const; |
| 987 | |
| 988 | void merge_gutters(int p_from_line, int p_to_line); |
| 989 | |
| 990 | void set_gutter_custom_draw(int p_gutter, const Callable &p_draw_callback); |
| 991 | |
| 992 | // Line gutters. |
| 993 | void set_line_gutter_metadata(int p_line, int p_gutter, const Variant &p_metadata); |
| 994 | Variant get_line_gutter_metadata(int p_line, int p_gutter) const; |
| 995 | |
| 996 | void set_line_gutter_text(int p_line, int p_gutter, const String &p_text); |
| 997 | String get_line_gutter_text(int p_line, int p_gutter) const; |
| 998 | |
| 999 | void set_line_gutter_icon(int p_line, int p_gutter, const Ref<Texture2D> &p_icon); |
| 1000 | Ref<Texture2D> get_line_gutter_icon(int p_line, int p_gutter) const; |
| 1001 | |
| 1002 | void set_line_gutter_item_color(int p_line, int p_gutter, const Color &p_color); |
| 1003 | Color get_line_gutter_item_color(int p_line, int p_gutter) const; |
| 1004 | |
| 1005 | void set_line_gutter_clickable(int p_line, int p_gutter, bool p_clickable); |
| 1006 | bool is_line_gutter_clickable(int p_line, int p_gutter) const; |
| 1007 | |
| 1008 | // Line style |
| 1009 | void set_line_background_color(int p_line, const Color &p_color); |
| 1010 | Color get_line_background_color(int p_line) const; |
| 1011 | |
| 1012 | /* Syntax Highlighting. */ |
| 1013 | void set_syntax_highlighter(Ref<SyntaxHighlighter> p_syntax_highlighter); |
| 1014 | Ref<SyntaxHighlighter> get_syntax_highlighter() const; |
| 1015 | |
| 1016 | /* Visual. */ |
| 1017 | void set_highlight_current_line(bool p_enabled); |
| 1018 | bool is_highlight_current_line_enabled() const; |
| 1019 | |
| 1020 | void set_highlight_all_occurrences(const bool p_enabled); |
| 1021 | bool is_highlight_all_occurrences_enabled() const; |
| 1022 | |
| 1023 | void set_draw_control_chars(bool p_enabled); |
| 1024 | bool get_draw_control_chars() const; |
| 1025 | |
| 1026 | void set_draw_tabs(bool p_enabled); |
| 1027 | bool is_drawing_tabs() const; |
| 1028 | |
| 1029 | void set_draw_spaces(bool p_enabled); |
| 1030 | bool is_drawing_spaces() const; |
| 1031 | |
| 1032 | TextEdit(const String &p_placeholder = String()); |
| 1033 | }; |
| 1034 | |
| 1035 | VARIANT_ENUM_CAST(TextEdit::EditAction); |
| 1036 | VARIANT_ENUM_CAST(TextEdit::CaretType); |
| 1037 | VARIANT_ENUM_CAST(TextEdit::LineWrappingMode); |
| 1038 | VARIANT_ENUM_CAST(TextEdit::SelectionMode); |
| 1039 | VARIANT_ENUM_CAST(TextEdit::GutterType); |
| 1040 | VARIANT_ENUM_CAST(TextEdit::MenuItems); |
| 1041 | VARIANT_ENUM_CAST(TextEdit::SearchFlags); |
| 1042 | |
| 1043 | #endif // TEXT_EDIT_H |
| 1044 | |